这是一种使用PIL进行图像处理的方法,可将数据嵌入到每个通道8位RGB图像文件中像素的每个颜色通道的最低有效位。
下面的代码说明了Python中的位流处理。这是相当有效的(只要这样的操作 可以 使用Python高效的),但它牺牲效率使用的可读性和简单性,必要时。:)
#! /usr/bin/env python''' Steganography with PIL (really Pillow) Enpres / depres bits of a binary data file into the LSB of each color value of each pixel of a non-palette-mapped image. Written by PM 2Ring 2015.02.03'''import sysimport getoptimport structfrom PIL import Imagedef readbits(bytes): ''' Generate single bits from bytearray ''' r = range(7, -1, -1) for n in bytes: for m in r: yield (n>>m) & 1def enpre(image_bytes, mode, size, dname, oname): print 'Encoding...' with open(dname, 'rb') as dfile: payload = bytearray(dfile.read()) #Prepend enpred data length to payload datalen = len(payload) print 'Data length:', datalen #datalen = bytearray.fromhex(u'%06x' % datalen) datalen = bytearray(struct.pack('>L', datalen)[1:]) payload = datalen + payload databits = readbits(payload) for i, b in enumerate(databits): image_bytes[i] = (image_bytes[i] & 0xfe) | b img = Image.frombytes(mode, size, str(image_bytes)) img.save(oname)def bin8(i): return bin(i)[2:].zfill(8)bit_dict = dict((tuple(int(c) for c in bin8(i)), i) for i in xrange(256))def depre_bytes(data): return [bit_dict[t] for t in zip(*[iter(c&1 for c in data)] * 8)]def depre(image_bytes, dname): print 'Decoding...' t = depre_bytes(image_bytes[:24]) datalen = (t[0] << 16) | (t[1] << 8) | t[2] print 'Data length:', datalen t = depre_bytes(image_bytes[24:24 + 8*datalen]) with open(dname, 'wb') as dfile: dfile.write(str(bytearray(t)))def process(iname, dname, oname): with Image.open(iname) as img: mode = img.mode if mode == 'P': raise ValueError, '%s is a palette-mapped image' % fname size = img.size image_bytes = bytearray(img.tobytes()) #del img print 'Data capacity:', len(image_bytes) // 8 - 24 if oname: enpre(image_bytes, mode, size, dname, oname) elif dname: depre(image_bytes, dname)def main(): #input image filename iname = None #data filename dname = None #output image filename oname = None def usage(msg=None): s = msg + 'nn' if msg else '' s += '''Embed data into or extract data from the low-order bits of an image file.Usage:%s [-h] -i input_image [-d data_file] [-o output_image]To enpre, you must specify all 3 file names.To depre, just specify the input image and the data file names.If only the the input image is given, its capacity will be printed,i.e., the maximum size (in bytes) of data that it can hold.Uses PIL (Pillow) to read and write the image data.Do NOT use lossy image formats for output, eg JPEG, or the data WILL get scrambled.The program will abort if the input image is palette-mapped, as such imagesare not suitable.''' print >>sys.stderr, s % sys.argv[0] raise SystemExit, msg!=None try: opts, args = getopt.getopt(sys.argv[1:], "hi:d:o:") except getopt.GetoptError, e: usage(e.msg) for o, a in opts: if o == '-h': usage(None) elif o == '-i': iname = a elif o == '-d': dname = a elif o == '-o': oname = a if iname: print 'Input image:', iname else: usage('No input image specified!') if dname: print 'Data file:', dname if oname: print 'Output image:', oname process(iname, dname, oname)if __name__ == '__main__': main()


