IDAT块扫描线重建函数实现疑问(Python+zlib编写PNG阅读器)
PNG IDAT块解压缩后的Recon函数实现说明
Recon函数的作用
PNG为提升压缩率,会对图像行数据应用预测过滤:每行开头的1字节是过滤类型,后面的像素字节是原始像素与预测值的差值。Recon(重建)函数的核心作用就是根据过滤类型,把这些差值数据还原成原始的像素字节序列,最终得到可直接用于渲染或处理的图像像素数据。
完整实现参考
以下是修正并补全后的代码,修复了原代码中像素字节索引计算错误,同时实现了所有过滤类型的逻辑:
def IDAT(self, chunk_size): data = self.f.read(chunk_size) raw_colors = zlib.decompress(data) self.raw_color_values.extend(raw_colors) self.f.read(4) # 读取CRC校验值 self.processed_pixels = self.processIDAT() def processIDAT(self): Recon = [] bytes_per_pixel = self.bit_depth // 8 if self.color_type == 2: # RGB颜色类型 bytes_per_pixel *= 3 elif self.color_type == 3: # 索引颜色类型(如需支持可保留) bytes_per_pixel = 1 # 每行总字节数:1字节过滤符 + 宽度*每个像素字节数 bytes_per_scanline = 1 + self.file_width * bytes_per_pixel for y in range(self.file_height): scanline_start = y * bytes_per_scanline filter_type = self.raw_color_values[scanline_start] # 遍历当前行的所有像素字节 for byte_idx in range(bytes_per_scanline - 1): channel = byte_idx % bytes_per_pixel raw_byte = self.raw_color_values[scanline_start + 1 + byte_idx] # 计算各参考值,边界情况用0填充 a = Recon[-bytes_per_pixel] if (len(Recon) >= bytes_per_pixel and byte_idx >= bytes_per_pixel) else 0 b = Recon[scanline_start - bytes_per_scanline + 1 + byte_idx] if y > 0 else 0 c = Recon[scanline_start - bytes_per_scanline + 1 + byte_idx - bytes_per_pixel] if (y > 0 and byte_idx >= bytes_per_pixel) else 0 if filter_type == 0: # None过滤:直接取原始字节 recon_byte = raw_byte elif filter_type == 1: # Sub过滤:原始字节 + 左侧同通道字节 recon_byte = (raw_byte + a) & 0xff elif filter_type == 2: # Up过滤:原始字节 + 上方同通道字节 recon_byte = (raw_byte + b) & 0xff elif filter_type == 3: # Average过滤:原始字节 + (a + b)//2 recon_byte = (raw_byte + (a + b) // 2) & 0xff elif filter_type == 4: # Paeth过滤:原始字节 + Paeth预测值 recon_byte = (raw_byte + self.PaethPredictor(a, b, c)) & 0xff else: print(f"未知过滤类型: {filter_type}") recon_byte = raw_byte Recon.append(recon_byte) return Recon def PaethPredictor(self, a, b, c): p = a + b - c pa = abs(p - a) pb = abs(p - b) pc = abs(p - c) if pa <= pb and pa <= pc: return a elif pb <= pc: return b else: return c
关键逻辑说明
- 字节索引修正:原代码按像素数循环,忽略了多字节像素的情况,改为按字节遍历,确保每个通道字节都被正确处理。
- 参考值计算:针对不同过滤类型,正确获取左侧、上方、左上方的同通道重建字节,首行、首像素等边界位置缺失的参考值用0填充。
- 字节截断:所有计算结果用
& 0xff截断为单字节,符合PNG的字节数据要求。
内容的提问来源于stack exchange,提问作者Kre4
相关产品推荐
相关产品推荐

