IN_BIN = r"K:\ghidra\Crusader_Decomp\binary\Crusader - No Remorse Memdump Weapons.bin" W,H = 1024,512 TOP, BOT = 44, 92 # y range (inclusive start, exclusive end) import os with open(IN_BIN,'rb') as f: data = f.read() count = min(len(data)//2, W*H) # build mask for this row range col_counts = [0]*W for y in range(TOP, BOT): for x in range(W): i = y*W + x if i < count: off = i*2 val = data[off] | (data[off+1]<<8) if val & 0x7fff: col_counts[x] += 1 # find runs where col_counts exceeds threshold maxc = max(col_counts) thr = max(3, int(maxc*0.2)) runs = [] inside=False for x,c in enumerate(col_counts): if c>thr and not inside: sx = x; inside=True if c<=thr and inside: ex = x-1; inside=False; runs.append((sx,ex)) if inside: runs.append((sx,W-1)) print('max per-col count', maxc, 'threshold', thr) print('runs:', runs) # compute byte offsets and produce crops (no PIL) import struct, zlib OUT_DIR = r"K:\ghidra\Crusader_Decomp\binary\hud_candidates" os.makedirs(OUT_DIR, exist_ok=True) with open(IN_BIN,'rb') as f: bin_data = f.read() # build full rows RGB rows = [] for y in range(H): row = bytearray() for x in range(W): i = y*W + x if i < count: off = i*2 val = bin_data[off] | (bin_data[off+1]<<8) b = (val & 0x1F) << 3 g = ((val >>5)&0x1F) << 3 r = ((val >>10)&0x1F) << 3 else: r=g=b=0 row.extend([r,g,b]) rows.append(bytes(row)) # for each run, create a crop with padding for i,(sx,ex) in enumerate(runs): pad = 8 x0 = max(0, sx-pad) x1 = min(W-1, ex+pad) y0 = TOP; y1 = BOT-1 w = x1 - x0 + 1 h = y1 - y0 + 1 rawrows = [] for y in range(y0, y1+1): rawrows.append(b"\x00" + rows[y][x0*3:(x0+w)*3]) raw = b"".join(rawrows) comp = zlib.compress(raw,9) def chunk(t,d): out = struct.pack('>I', len(d)) + t + d import zlib crc = zlib.crc32(t + d) & 0xffffffff out += struct.pack('>I', crc) return out png = b"\x89PNG\r\n\x1a\n" png += chunk(b'IHDR', struct.pack('>IIBBBBB', w, h, 8, 2, 0, 0, 0)) png += chunk(b'IDAT', comp) png += chunk(b'IEND', b'') out = os.path.join(OUT_DIR, f'cand_{i}_{x0}_{y0}.png') with open(out,'wb') as f: f.write(png) start_idx = y0*W + x0 end_idx = y1*W + x1 so = start_idx*2 eo = (end_idx+1)*2 -1 print(f'wrote {out} box=({x0},{y0})-({x1},{y1}) bytes=0x{so:06x}-0x{eo:06x} col_counts_max={max(col_counts[x0:x1+1])}') # also print top columns with counts top_cols = sorted(((c,x) for x,c in enumerate(col_counts)), reverse=True)[:30] print('\nTop columns (count,x):') for c,x in top_cols: print(c,x)