import sys from typing import List, Tuple def flatten(l): for i in l: if isinstance(i, list): yield from flatten(i) else: yield i from common import * def encode_RLE(data: List[bool]) -> bytes: out = b"" " values is a list of tuples where the first element is the count and the second is the value " " the count can only go upto 7 bit " values: List[Tuple[int,bool]] = [] for i in range(len(data)): if i == 0: values.append((1, data[i])) elif data[i] != data[i-1]: values.append((1, data[i])) else: last = values[-1][0] if last < 127: values[-1] = (last+1, data[i]) else: values.append((1, data[i])) for v in values: # high bit is set if value is true v = v[0] << 1 | int(v[1]) out += v.to_bytes(1, "little") return out stats = { "avg_frame_size": 0, "min_frame_size": float("inf"), "max_frame_size": 0, "total_size": 0, } def diff_encode(frames: List[List[List[bool]]]) -> bytes: out = b"" for i, frame in enumerate(frames): if i > 0: last_frame = frames[i-1] frame = diff(last_frame, frame) o = encode_RLE(list(flatten(frame))) out += o sz_b = len(o) #print(f"Frame {i} size: {sz_b}") stats["min_frame_size"] = min(stats["min_frame_size"], sz_b) stats["max_frame_size"] = max(stats["max_frame_size"], sz_b) return out def rle_encode(frames: List[List[List[bool]]]) -> bytes: out = b"" for frame in frames: o = encode_RLE(list(flatten(frame))) out += o stats["min_frame_size"] = min(stats["min_frame_size"], len(o)) stats["max_frame_size"] = max(stats["max_frame_size"], len(o)) return out def get_frame(f): pixels = [] for y in range(res[1]): b = f.read(4) if len(b) < 4: return None row = [ int(a) == 1 for a in bin(int.from_bytes(b, "little"))[2:].zfill(32)] pixels.append(row) return pixels def encode(): f = open("badapple_input.bin", "rb") frames = [] i = 0 while True: i += 1 pixels = get_frame(f) if not pixels: break if i % frameskip == 0: frames.append(pixels) stats["frame_count"] = len(frames) with open("out_diff.bin", "wb") as fo: o = diff_encode(frames) stats["avg_frame_size"] = len(o) / len(frames) stats["total_size"] = len(o) fo.write(o) print("diff", stats) with open("out_rle.bin", "wb") as fo: o = rle_encode(frames) stats["avg_frame_size"] = len(o) / len(frames) stats["total_size"] = len(o) fo.write(o) print("rle", stats) if __name__ == "__main__": frameskip = int(sys.argv[1]) encode()