Source code for pysteg.jsteg.f5
## $Id: f5.py 1494 2009-04-30 13:10:41Z css1hs $
## -*- coding: utf-8 -*-
"""
The F5 Algorithm
:Module: pysteg.jsteg.f5
:Date: $Date: 2010-07-16 10:43:38 +0100 (Fri, 16 Jul 2010) $
:Revision: $Revision: 1559 $
:Copyright: © 2009-10: University of Surrey, UK
:Author: Hans Georg Schaathun <georg@schaathun.net> (2009-2010)
This module supports steganographic embedding in JPEG using
Andreas Westfeld's F5 algorithm. Two versions are provided.
The :class:`f5coef` class follows Westfeld's paper and used
every non-zero coefficient. The :class:`f5v2` class follows
Westfeld's implementation, skiping every other \pm1 coefficient.
"""
from f4 import *
from exceptions import *
from message import message
from numpy import ceil
#
# The :class:`f5coef` Class
# =========================
#
# ::
[docs]class f5coef(f4coef):
"""The F5 object handles a list of JPEG AC coefficients and
embeds and extracts messages using F5."""
_code = (1,1)
# F5 Capacity
# -----------
#
# ::
[docs] def getcapacity(self):
R = self.f5capacity
R["Raw"] = self.capacity
return R
# The :class:`f5v2` Class
# =========================
#
# This version of F5 will skip every other \pm1 coefficient,
# like Westfeld's version does.
#
# ::
[docs]class f5v2(f5coef):
"""The F5 object handles a list of JPEG AC coefficients and
embeds and extracts messages using F5. This extends the
basic F5 class to skip every other \pm1. The F5 object
also gives full access to F4 methods."""
def _reset(self):
"""
Reset the object to allow subsequent embedding/extraction
from the start of the file.
"""
# Because _reset() calls checknext which is overridden,
# self.one and self.blockone must be set first.
#
# ::
self.one = 0 # Count the number of \pm1
self.blockone = 0 # Number of ones before current block
f5coef._reset(self)
# Override the stepping routines to skip every other ones.
#
# ::
def _auxstep(self):
"""Proceed to the next coefficient."""
# Count ones up to current point *exclusive*.
#
# ::
if abs(self[self.next]) == 1: self.one += 1
# Increment the pointer. Flip the morebits flag if we have
# reached the end of the signal.
#
# ::
self.next += 1
if self.next >= len(self): self.morebits = False
# The return value indicates whether we have reached the end or not.
#
# ::
return self.morebits
[docs] def checknext( self ):
"""Check that the next coefficient can be used.
Move pointer if necessary.
This method should always be called when the next pointer
has been updated, or a coefficient has been changed."""
if not self.morebits: return False
while self[self.next] == 0:
if not self._auxstep(): return False
if abs(self[self.next]) == 1:
if (self.one&1) == 1: self._step()
# assert self[self.next] != 0, "Bug in checknext()"
return self.morebits
# Block rewind/proceed - to redo a block in F5
# These are overridden to preserve the count of ones.
#
# ::
def _blockRewind(self):
"""Return to the start of the current block."""
self.next = self.blockstart
self.one = self.blockone
self.checknext()
# In case checknext() has moved the pointer, we need to call _blockProceed().
#
# ::
self._blockProceed()
# When a block has been successfully embedded with data, we call
# :func:`_blockProceed` to step to the next block.
#
# ::
def _blockProceed(self):
"""Proceed to the next block."""
self.blockstart = self.next
self.blockone = self.one
# The :class:`f5v2` Class
# =========================
#
# Mainly for completeness, we include a version of F4 using the same
# selection of coefficients as Westfeld's F5 software.
#
# ::
[docs]class f4v2(f5v2):
# The difference between F4 and F5 is governed by the code parameters.
#
# ::
_code = (0,0)
# Override F5 methods overridden in F5, to give F4 behaviour.
#
# ::
[docs] def getcapacity(self): return f4coef.getcapacity(self)