3 ms·
The length would still come first in the PNG datastream. My idea is that those 4 bytes could have been added to the CRC after processing the chunk tag and data
by dalke 4y ago
The length would still come first in the PNG datastream.
My idea is that those 4 bytes could have been added to the CRC after processing the chunk tag and data. Here's an example:
class BlockWriter:
def __init__(self, output, chunk_type):
self.output = output
self._start = output.tell()
output.write(b"\0\0\0\0")
output.write(chunk_type)
self._crc = zlib.crc32(chunk_type)
self._chunk_length = 0
def write(self, data):
self.output.write(data)
self._crc = zlib.crc32(data, self._crc)
self._chunk_length += len(data)
def finish(self):
chunk_length_bytes = self._chunk_length.to_bytes(4, "big")
self._crc = zlib.crc32(chunk_length_bytes, self._crc) # !! NEW !!
crc_bytes = self._crc.to_bytes(4, "big")
self.output.write(crc_bytes)
# Go back and update the length
end = self.output.tell()
self.output.seek(self._start)
self.output.write(chunk_length_bytes)
self.output.seek(end)
It could be used like:
writer = BlockWriter(png_f, b"IDAT")
writer.write(b"shrdlu")
writer.write(b"etaoin")
writer.finish()
which produces the correct block structure:
'\x00\x00\x00\x0cIDATshrdluetaoin\xed?\xa6\xa4'
|--------------| four byte length = 12
|--| four byte character code 'IDAT'
|----------| = 12 bytes of payload
|------------| = four byte CRC
I'll show the CRC is in the order {tag}, {data}, {length}:
>>> zlib.crc32(b"IDAT" + b"shrdluetaoin" + b"\x00\x00\x00\x0c"
).to_bytes(4, "big")
b'\xed?\xa6\xa4'