Skip to content

Instantly share code, notes, and snippets.

@sfan5
Last active May 28, 2016 21:13
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save sfan5/7691388 to your computer and use it in GitHub Desktop.
Creates an APNG from PNGs (all PNGs need to have the same IHDR checksum for this to work)
#!/usr/bin/env python
import sys
import struct
import binascii
def mkchunk(tp, data):
return struct.pack("!L", len(data)) + tp + data + struct.pack("!L", binascii.crc32(tp + data) & 0xffffffff)
def getchunk(f, tp):
f.seek(0)
si = "\x89PNG\r\n\x1a\n"
if f.read(len(si)) != si:
print("Not a PNG file")
exit(1)
while True:
chklen = f.read(4)
if chklen == "" or chklen == "\0\0\0\0":
return ""
chklen = struct.unpack("!L", chklen)[0]
chktype = f.read(4)
chkdata = f.read(chklen)
f.read(4) # CRC
if chktype == tp:
return chkdata
def getidat_data(f):
data = ""
f.seek(0)
si = "\x89PNG\r\n\x1a\n"
if f.read(len(si)) != si:
print("Not a PNG file")
exit(1)
while True:
chklen = f.read(4)
if chklen == "" or chklen == "\0\0\0\0":
return data
chklen = struct.unpack("!L", chklen)[0]
chktype = f.read(4)
chkdata = f.read(chklen)
f.read(4) # CRC
if chktype == "IDAT":
data += chkdata
if len(sys.argv) <= 4:
print("Usage: %s <output> <fps> <inputs>" % sys.argv[0])
else:
fps = int(sys.argv[2])
inf = open(sys.argv[3], "rb")
wi, he = struct.unpack("!LLxxxxx", getchunk(inf, "IHDR"))
out = open(sys.argv[1], "wb")
out.write("\x89PNG\r\n\x1a\n")
out.write(mkchunk("IHDR", getchunk(inf, "IHDR")))
out.write(mkchunk("acTL", struct.pack("!LL", len(sys.argv) - 3, 0)))
out.write(mkchunk("fcTL", struct.pack("!LLLLLHHBB", 0, wi, he, 0, 0, 1, fps, 0, 1)))
out.write(mkchunk("IDAT", getidat_data(inf)))
out.flush()
inf.close()
sqn = 1
for infn in sys.argv[4:]:
inf = open(infn, "rb")
out.write(mkchunk("fcTL", struct.pack("!LLLLLHHBB", sqn, wi, he, 0, 0, 1, fps, 0, 1)))
out.write(mkchunk("fdAT", struct.pack("!L", sqn) + getidat_data(inf)))
out.flush()
inf.close()
sqn += 1
sys.stdout.write("%05d/%05d\r" % (sqn, len(sys.argv) - 3))
out.write(mkchunk("IEND", ""))
out.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment