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)