1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
| import os import sys import struct import binascii
directory = "outp/" signature = "" ihdr_header = "" fdat_chunk = "" idat_chunk = "" iend_chunk = "" ihdrs = []
parts = []
PNG_SIGN = b"\x89\x50\x4E\x47\x0D\x0A\x1A\x0A"
def is_png(png): """Test if @png is valid png file by checking signature
@png can be str of the filename, a file-like object, or a bytes object. """ if isinstance(png, str): with open(png, "rb") as f: png = f.read(8)
if hasattr(png, "read"): png = png.read(8)
return png[:8] == PNG_SIGN
def chunks(png): """Yield chunks from png.
@png can be a string of filename, a file-like object, or a bytes bject. """ if not is_png(png): if isinstance(png, bytes): with io.BytesIO(png) as f: with io.BytesIO() as f2: PIL.Image.open(f).save(f2, "PNG", optimize=True) png = f2.getvalue() else: with io.BytesIO() as f2: PIL.Image.open(png).save(f2, "PNG", optimize=True) png = f2.getvalue()
if isinstance(png, str): with open(png, "rb") as f: png = f.read()
if hasattr(png, "read"): png = png.read()
return chunks_read(png)
def make_chunk(type, data): """Create chunk with @type and chunk data @data. It will calculate length and crc for you. Return bytes. @type is str and @data is bytes. """ out = struct.pack("!I", len(data)) data = type.encode("latin-1") + data a = '%08x' % (binascii.crc32(data) % (1<<32)) out += data + a.decode('hex') return out
def chunks_read(b): """Parse PNG bytes into different chunks, yielding (type, data).
@type is a string of chunk type. @data is the bytes of the chunk. Including length, type, data, and crc. """ i = 8
while i < len(b): data_len, = struct.unpack("!I", b[i:i + 4]) type = b[i + 4:i + 8].decode("latin-1") yield type, b[i:i + data_len + 12] i += data_len + 12
if __name__ == '__main__': i = 0 t = 0 frame_chunks = [] frames = [] for ctype, data in list(chunks('p1ng/p1ng')): if ctype == "IHDR": ihdr_header = data hdr = ihdr_header elif ctype == "acTL": continue elif ctype == "fcTL": """ """ c = struct.unpack("!IIIIHHbb", data[12:-4]) width = 180 height = 76 if i in [11,12,13,2,9]: width = c[0] height = c[1] if i in [7,13,21,22]: width -= 1 if i == 6: width -= 2 print c ihdr = make_chunk("IHDR", struct.pack("!II", width + c[2], height+ c[3]) + hdr[16:-4]) ihdrs.append(ihdr) elif ctype == "IDAT": parts.append(("IDAT", data)) i += 1 elif ctype == "fdAT": parts.append(("IDAT", make_chunk("IDAT", data[12:-4]))) i += 1 elif ctype == "IEND": iend_chunk= data break
if not os.path.exists(directory): os.makedirs(directory) for i in range(len(parts)): f = open(directory + 'p1ng%d.png' % i, 'w+') if i == 0: ihdrs[i] = ihdr_header f.write(PNG_SIGN + ihdrs[i] + parts[i][1] + iend_chunk) f.close()
|