
前情概要(/t/835906):
本科毕设,用 Java 从零开始写一个 JPEG 编码器,v 友们的回答使我受益匪浅。
目前转换 YCC 、DCT 、量化已经完成用 ISO/IEC 10918-1:1993 中 K.3 推荐的 Huffman 表,可以完美运行。
然而,用固定的 Huffman 表压缩效果不一定是最好的,所以我打算根据单个图片本身生成一个新的表。
单个图片中,并不是所有 Run/Size 值都用得到,所以我只打算给用到的值分配 Huffman 编码。
(虽是变长编码,由于 JPEG 限制码长不得超过 16bit ,分配过多会导致权重大的值码长增加)
解码测试结果:
疑问:
和 libjpeg 比,我这个只是一个小玩具。但是本着敢于质疑的精神,提出了这个问题,希望有懂 JPEG 的大神解惑,非常感谢!
折腾了一下午,问题解决,在此记录一下:
答案:
可以不给没用到的值分配编码。我这么做是对的。
所以libjpeg报错,是我另外的问题。
既然libjpeg报错了,我就查了libjpeg源码,看看哪里判错了。
“Bogus Huffman table definition”,是在jdhuff.c第381行,
/* Figure C.2: generate the codes themselves */ /* We also validate that the counts represent a legal Huffman code tree. */ code = 0; si = huffsize[0]; p = 0; while (huffsize[p]) { while (((int) huffsize[p]) == si) { huffcode[p++] = code; code++; } /* code is now 1 more than the last code used for codelength si; but * it must still fit in si bits, since no code is allowed to be all ones. */ if (((INT32) code) >= (((INT32) 1) << si)) ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); code <<= 1; si++; } 然后我把报错的代码注释掉:
// if (((INT32) code) >= (((INT32) 1) << si)) // ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); 竟然能解码了!没有任何问题。(事实证明,ffmpeg能够解码的原因,是因为ffmpeg没有做这个验证。)
那 libjpeg 为什么要拦住我呢。
再看了眼注释:no code is allowed to be all ones.
原来JPEG里面用的Huffman编码,不能全为1。
所以将全1的编码长度往后推一个就行。
问题解决。