如何自动计算经4:2:2采样正常头修补的损坏JPEG的正确宽高
4:2:2采样JPEG错头尺寸自动计算修复方案
适用场景:已替换匹配的4:2:2色度采样JPEG通用文件头,仅帧头段宽高参数不匹配、压缩数据本身无截断的损坏文件。
核心逻辑
4:2:2采样的JPEG以MCU(最小编码单元)为单位做编码,单个MCU固定对应16像素宽、8像素高的原始画面区域;在量化表、哈夫曼表、采样参数完全固定的前提下,单个MCU压缩后的字节长度基本恒定,只要算出纯压缩数据里包含的MCU总个数,再枚举宽高方向的MCU排布组合,就能找到正确的尺寸参数。
实操步骤
- 提取纯压缩数据长度
用十六进制编辑器打开损坏文件,定位到SOS(扫描开始)标记FFDA,跳过SOS段的固定长度参数后,从后续第一个字节开始计数,一直到文件结束标记FFD9的前一个字节为止,统计得到的总字节数记为S。提示:如果
FFD9之前混杂了EXIF、缩略图等其他标记段(标记段特征是均以0xFF开头后跟非0、非D9的标记字节),要先跳过这些段再计数,不要把附加段的字节算进压缩数据长度里。 - 计算单个MCU的压缩长度
L
你用来替换的正常JPEG文件头本身来自一个可正常打开的4:2:2采样JPEG,直接对这个参考文件做同样的计数,拿到它的纯压缩数据长度S_ref,再算参考文件的MCU总数:N_ref = (参考文件宽度 / 16) * (参考文件高度 / 8),最后单MCU长度L = S_ref / N_ref,结果取整即可,少量余数是文件尾填充,不影响计算。 - 枚举合法尺寸组合
先算损坏文件的总MCU数N = S / L,结果取整(余数超过L的10%说明压缩数据有截断,该方法不适用)。总MCU数是横向MCU个数Wc和纵向MCU个数Hc的乘积,即N = Wc * Hc,枚举所有正整数因子对,每一组对应的实际画面尺寸为:实际宽度 = Wc * 16实际高度 = Hc * 8 - 校验得到正确尺寸
找到SOF0(帧开始,标记为FFC0)段,段内偏移5-6字节是高度值、7-8字节是宽度值,均为大端序存储。把枚举到的宽高逐组写入,保存后打开图片预览:画面没有错位、彩色斜纹、拉伸变形,内容连续自然的就是正确参数。
提速技巧
不用盲测所有因子对,先看错误参数下的预览效果:如果斜向撕裂纹路从左上延伸到右下,说明当前宽度设小了;如果纹路从右上延伸到左下,说明当前高度设小了,可以快速缩小枚举范围。如果N是质数,只需要测两次:要么宽16、高N8,要么高8、宽N16,很快就能出结果。
避坑提示
- 写入宽高时注意是大端序,比如宽度是4000像素,十六进制是0xFA0,要写成
0F A0两个字节,不要反过来写成A0 0F - 不要把文件头里的DQT(量化表)、DHT(哈夫曼表)段的字节算进压缩数据长度,否则L值计算会完全错误
- 部分相机会在压缩数据尾加几字节的私有填充,只要总长度余数在10字节以内都可以忽略,不影响MCU总数计算
内容的提问来源于stack exchange,提问作者Hanalog
相关产品推荐
相关产品推荐

