def write_chunk(f, chunk_type, data): """Write PNG chunk with CRC""" f.write(struct.pack('>I', len(data))) f.write(chunk_type) f.write(data) crc = zlib.crc32(chunk_type + data) & 0xffffffff f.write(struct.pack('>I', crc))
if extract_only: for idx, comp in streams: raw = zlib.decompress(comp) out_file = f"{Path(input_png).stem}_stream_{idx}.raw" Path(out_file).write_bytes(raw) print(f"Extracted stream {idx} to {out_file}") return xtool -mpng+reflate
def extract_mpng_streams(png_path): """Extract all zlib-compressed streams from MPNG chunks""" streams = [] with open(png_path, 'rb') as f: # Verify PNG signature if f.read(8) != PNG_SIGNATURE: raise ValueError("Not a valid PNG file") crc)) if extract_only: for idx
replace_map = None if replace_data: # Format: "idx:file.zlib" or "idx:file.raw" idx_str, path_str = replace_data.split(':') idx = int(idx_str) data = Path(path_str).read_bytes() # If raw, compress it if path_str.endswith('.raw'): data = zlib.compress(data, level) replace_map = {idx: data} data[:4])[0] compressed = data[4:] streams.append((idx
while True: chunk_type, data, _ = read_chunk(f) if chunk_type == CHUNK_TYPE_MPNG: # MPNG chunk structure: [index:4][compressed_data...] idx = struct.unpack('>I', data[:4])[0] compressed = data[4:] streams.append((idx, compressed)) elif chunk_type == CHUNK_TYPE_IEND: break return streams def reflate_stream(compressed_data, level=6, extract_only=False): """Reflate: decompress then recompress zlib stream""" decompressed = zlib.decompress(compressed_data) if extract_only: return decompressed # raw decompressed data recompressed = zlib.compress(decompressed, level) return recompressed
Here’s a solid, production-ready feature implementation for that adds support for MPNG (Multi-Piece PNG) + reflate (recompressing/zlib stream repair).