From 9df722cadd3bd51c02b2cc378682143fc372ff88 Mon Sep 17 00:00:00 2001 From: grub-basket Date: Wed, 29 Jul 2026 23:18:44 -0700 Subject: [PATCH] Fix PICT pixel decoding for 32-bit planar and cicn icons Two decoding bugs in pict.py: 1. unpack4() used a 3-plane row stride (y*w*3) in the 4-plane (32-bit ARGB planar) branch, even though the buffer holds numplanes*w*h == 4*w*h bytes with rows 4*w wide. Any packtype-4 PICT with cmpcount==4 decoded with rows sliding out of alignment (scrambled colors/alpha). Use y*w*4 as the row base. 24-bit (3-plane) was already correct. 2. read_cicn() read the black-and-white icon bitmap using the mask bitmap's height (maskbm.height) instead of the B&W icon bitmap's own height. When the two BitMaps have different bounds, the unpacker advanced by the wrong byte count and the following read_colortable() read from the wrong offset, corrupting the palette. Use bwiconbm.height. --- rsrcdump/pict.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rsrcdump/pict.py b/rsrcdump/pict.py index d4226a1..efe9e3b 100644 --- a/rsrcdump/pict.py +++ b/rsrcdump/pict.py @@ -467,10 +467,10 @@ def unpack4(u: Unpacker, w: int, h: int, rowbytes: int, numplanes: int) -> bytes else: for y in range(h): for x in range(w): - a = unpacked[y*w*3 + x + w*0] - r = unpacked[y*w*3 + x + w*1] - g = unpacked[y*w*3 + x + w*2] - b = unpacked[y*w*3 + x + w*3] + a = unpacked[y*w*4 + x + w*0] + r = unpacked[y*w*4 + x + w*1] + g = unpacked[y*w*4 + x + w*2] + b = unpacked[y*w*4 + x + w*3] dst.write(struct.pack(">BBBB", b,g,r,a)) return dst.getvalue() @@ -903,7 +903,7 @@ def convert_cicn_to_image(data: bytes) -> tuple[int, int, bytes]: assert isinstance(maskbm, Bitmap) assert isinstance(bwiconbm, Bitmap) maskbits = u.read(maskbm.rowbytes * maskbm.height) - bwiconbits = u.read(bwiconbm.rowbytes * maskbm.height) + bwiconbits = u.read(bwiconbm.rowbytes * bwiconbm.height) mask8 = convert_to_8bit(maskbits, 1) bwicon8 = convert_to_8bit(bwiconbits, 1)