REFLATE, also known as LZ77, is a lossless data compression algorithm developed by Abraham Lempel, Jacob Ziv, and Terry Welch. It's a dictionary-based compression method that works by finding repeated patterns in the data and replacing them with a reference to the previous occurrence.
# Replace stream index 2 with new compressed data xtool mpng-reflate original.png patched.png --replace 2:new_stream.zlib
import struct import zlib import sys from pathlib import Path xtool -mpng+reflate
Keep in mind that the specifics of the xtool command and its options might vary depending on the actual tool implementation and its intended use cases.
if != " main ": def setup_cli(subparsers): p = subparsers.add_parser('mpng-reflate', help='Reflate MPNG chunks') p.add_argument('input', help='Input PNG with MPNG chunks') p.add_argument('output', nargs='?', help='Output PNG path') p.add_argument('--recompress-level', type=int, default=6, help='zlib compression level 1-9') p.add_argument('--extract-only', action='store_true', help='Only extract streams, do not rebuild') p.add_argument('--replace', help='Replace stream: "idx:file.zlib" or "idx:file.raw"') p.set_defaults(func=mpng_reflate_cli) REFLATE, also known as LZ77, is a lossless
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}
xtool mpng-reflate game_assets.png --extract-only # Output: game_assets_stream_0.raw, game_assets_stream_1.raw help='Reflate MPNG chunks') p.add_argument('input'
PNG images often use the DEFLATE algorithm for compression, which is a combination of LZ77 and Huffman coding. DEFLATE is a widely used compression algorithm in various formats, including PNG, ZIP, and gzip.
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