Source

CCP2011 / stegano.py

Full commit
"""
Steganography plugin
insert text stream as alpha layer into image
Requires Python Imaging Library
Copyright 2007 by Flavio Codeco Coelho
license: GPL
""" 
import urlparse, urllib, urllib2, sys
from PIL import Image, ImageFile
import pylab as P
import numpy as np

class MsgImage:
    '''
    Image containing a message
    inserted by means of steganography.
    '''
    def __init__(self,carrier=None,msg=None):
        '''
        Image carrier is a local image.
        msg is the message
        it can be added later.
        '''
        self.capacity = 0
        self.im = None #empty image
        self.limg = None #loaded image
        if carrier:
            self._addCarrier(carrier)
            if msg:
                self.injectMsg(msg)
        print self.im.max()
        print self.im.min()
        
    def injectMsg(self,msg):
        """
        inject ascii stream into image
        data is injected in alpha channel
        """
        if self.im == None:
            print "No carrier image specified."
            return
        w = self.im.shape[0] # width of image
        h = self.im.shape[1] # height of image
        self.capacity = w*h
        beginstr = "MSGSTART"
        endstr = "MSGEND"
        fullload = beginstr+msg+endstr
        encMSG = map(ord, fullload)
        
        if len(fullload) > self.capacity:
            print "Message too long for this image"
            return
        msglayer = np.ones((w,h,1),int) #Create alpha layer
        #~ msglayer *=5
        #~ print self.im.shape, msglayer.shape
        for n,i in enumerate(encMSG):
            msglayer.ravel()[n] = i
        
        if self.im.shape[2] < 4:
            #add alpha layer with message
            self.im = np.concatenate((self.im,msglayer),axis=2) # concatenate along the third dimension
        else:
            #overwrite alpha layer with message
            self.im[:,:,3] = msglayer
        
        self.limg = self.im
        


        
    def _addCarrier(self, url):
        '''
        Add image to serve as message carrier.
        '''
        sch = urlparse.urlparse(url)
        if sch[0] == 'file':
            self.im = Image.open(sch[2])
        else:
            self.readImg(url)
    
    def saveLimg(self,fn):
        '''
        Save the image to file named fn
        '''
        self.limg.save(fn)
        
            
    def readImg(self,url):
        '''
        Read an image from an URL and try to extract a message
        '''
        sch = urlparse.urlparse(url)
        if sch[0] == 'file':
            self.addCarrier(sch[2])
        else:
            req = urllib2.Request(url)
            req.add_header('Referer', 'http://www.google.com/')
            req.add_header('User-agent', 'Mozilla/5.0')
            f = urllib2.urlopen(req)
            p = ImageFile.Parser()
            while 1:
                s = f.read(1024)
                if not s:
                    break
                p.feed(s)
            self.im = np.array(p.close())
        msg = self.extractMsg(self.im)
        if msg:
            self.limg  = self.im
            self.msg = msg

    def draw(self):
        P.figure()
        P.imshow(self.im,norm=None)

    def extractMsg(self,img):
        '''
        Check for MSG and
        extract MSG from image
        returning the string
        '''
        if img.shape[2] < 4:
            return

        data = img[:,:,3].ravel()
        txt = ''.join(map(chr,data))
        ms = txt.find('MSGSTART')
        me = txt.find('MSGEND')
        if ms < 0:
            return 'No message found'
        else:
            #return string without delimiters
            return txt[ms+8:me]

    
        
if __name__=="__main__":
    limg = MsgImage('http://images.fccoelho.multiply.com/image/5/photos/17/600x600/59/IMG_0243.JPG?et=12scnTIX6CHkewjVcdTHQA')
    limg.draw()    
    limg.injectMsg('Quem com ferro fere com ferro sera ferido')
    limg.draw()
    mess = limg.extractMsg(limg.im)
    print mess
    P.show()