Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/python
- '''Decodes a paletted image and extracts the encoded file.
- NAME
- fpicdecode
- SYNOPSIS
- fpicdecode imagefile [decodedfile]
- DESCRIPTION
- The fpidencode script decodes a 256-colur image file and extracts
- the embedded with fpicencode.
- This script can be found on Pastebin.
- Encoder: http://pastebin.com/mysKcugD
- Decoder: http://pastebin.com/YKSSX9n7
- '''
- import sys
- import os.path
- from math import *
- from PIL import Image
- import zlib
- class Error (Exception):
- pass
- def rup2(x):
- return (x + 1) & ~1
- def chunkid(iff, ix):
- if ix > len(iff) - 4:
- raise Error('EOF in IFF chunk ID.')
- return ''.join([chr(x) for x in iff[ix : ix + 4]])
- def chunkint(iff, ix):
- if ix > len(iff) - 4:
- raise Error('EOF in IFF chunk integer.')
- r = 0
- for i in range(4):
- r += iff[ix + 3 - i] << (8 * i)
- return r
- def chunkhdr(iff, ix):
- if ix > len(iff) - 8:
- raise Error('Incomplete chunk header.')
- cid = chunkid(iff, ix)
- clen = chunkint(iff, ix + 4)
- tlen = 8 + rup2(clen)
- if ix + tlen > len(iff):
- raise Error('Incomplete chunk data.')
- return (cid, clen)
- def isdatamodulated(data):
- if chunkid(data, 0) == 'FORM':
- return False
- else:
- fourbytes = bytearray(
- [((data[2 * i] & 15) << 4) + (data[2 * i + 1] & 15) for i in range(4)]
- )
- return chunkid(fourbytes, 0) == 'FORM'
- def main():
- rc = 0 # Return code: 0 = OK
- iszipped = False
- # fetch arguments to set infname, outfname (and invoked command name).
- infname = 'source.png'
- outfname = ''
- args = list(sys.argv)
- cn = args[0]
- args = args[1:]
- if len(args) >= 1:
- infname = args[0]
- else:
- print cn + ': A source image filename is expected.'
- rc = 1
- if len(args) >= 2:
- outfname = args[1]
- if rc:
- return rc
- try:
- # Load the image and fetch the encoded data, a custom IFF FORM.
- # An IFF FORM has only four bytes of fixed data, the form type.
- # Standard FORMS include 'ILBM' and '8SVX'. Ours is 'Raw '.
- im = Image.open(infname)
- w, h = im.size
- if w < 8 or h < 4:
- raise Error('The image is far too small.')
- mdata = bytearray(w * h)
- for y in range(h):
- for x in range(w):
- mdata[x + w * y] = im.getpixel((x, y))
- if isdatamodulated(mdata[:8]):
- edata = bytearray(len(mdata) // 2)
- for i in range(len(edata)):
- mh = mdata[2 * i] & 15
- ml = mdata[2 * i + 1] & 15
- edata[i] = (mh << 4) + ml
- else:
- edata = mdata
- # Fetch the Raw Data HeaDer ('RDHD'), which has 20 bytes of fixed
- # data, the 'NAME' chunk (a C string for the default output filename)
- # and the 'DATA' chunk, which has the payload, compressed according
- # to the compression method indicated in the first byte of the header.
- hd = None
- nd = None
- cdata = None
- eid, elen = chunkhdr(edata, 0)
- edataend = 8 + elen
- if eid == 'FORM' and elen >= 4:
- fid = chunkid(edata, 8)
- if fid == 'Raw ':
- ix = 12
- while ix + 8 <= edataend:
- cid, clen = chunkhdr(edata, ix)
- chunkdata = bytearray(edata[ix + 8: ix + 8 + clen])
- if cid == 'RDHD':
- hd = chunkdata
- elif cid == 'NAME':
- nd = chunkdata
- elif cid == 'DATA':
- cdata = chunkdata
- ix += 8 + rup2(clen)
- if (hd is None) or (cdata is None):
- raise Error('No valid IFF file is encoded in the image.')
- if len(hd) < 20:
- raise Error('RDHD chunk is incomplete.')
- # Decompress the payload, if it is compressed. Though both GIFs
- # and PNGs are typically compressed, the benefit of a compressed
- # payload is compact image dimensions.
- compressionmethod = hd[0]
- if compressionmethod not in [0, 1]:
- raise Error('Unknown compression type indicated in IFF file.')
- iszipped = hd[0] == 1
- if iszipped:
- fdata = bytearray(zlib.decompress(str(cdata)))
- else:
- fdata = cdata
- # Protect the user from potentially malicious default output
- # filenames, such as those with paths before the filename or
- # those beginning with a "." (invisible on Unix-like systems).
- if outfname == '':
- fname = ''
- if nd is not None:
- fname = str(nd)
- while fname[-1] == chr(0):
- fname = fname[:-1]
- for i in range(len(fname)):
- if fname[i] < ' ':
- fname = ''
- break;
- fname = os.path.split(fname)[1]
- if fname[0 : 1] == '.':
- fname = 'dot-' + fname[1:]
- outfname = fname
- if outfname == '':
- outfname = 'decoded.dat'
- # Save the payload.
- fh = open(outfname, 'wb')
- try:
- fh.write(str(fdata))
- finally:
- fh.close()
- except (Error, Exception), E:
- print cn + ': ' + str(E)
- rc = 2
- return rc
- if __name__ == '__main__':
- sys.exit(main())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement