JPEG 计算最大尺寸

14

我必须说我不太了解文件格式的工作原理。我的问题是,比如我有一个200像素乘以200像素的jpeg文件,如何计算出该文件在兆字节/字节方面的最大大小?

我认为导致这个问题的推理会帮助某个人回答我。我有一个Java小程序,将人们用它绘制的图像上传到我的服务器。我需要知道这个文件可能达到的最大大小。它始终将是200x200。

听起来很傻,但是是否有一些颜色占用比其他颜色更多的字节大小,如果有,最昂贵的是哪种颜色?


回答你问题的第二部分,每种颜色在JPEG中表示时占用相同的空间:在进行任何有损压缩之前为12位。 - Mike Bailey
那么TIFF文件格式怎么样? - Tegra Detra
Tiff是不同的。有多种压缩方案可用,更不用说可变位宽了。在无损情况下,每像素通常为32位,因此比位图稍微大一些,因为有额外的头数据。 - Mike Bailey
5个回答

29

有许多方法可以制作一个异常大的“病态”JPEG/JFIF文件。

在极端情况下,由于标准不限制某些类型的标记出现次数,因此大小没有上限 - 例如,一个充满了许多GB DRI(定义重启间隔)标记的JFIF文件,然后在末尾是一个8x8像素MCU,在技术上是有效的。

如果我们限制自己只使用“正常”的标记用法,则会找到如下的上限:

一些背景信息 -

  1. JPEG将像素编码为8x8像素块(DCT块)的MCU(组),每个分量(Y,Cb,Cr)对应一个DCT块。

  2. 为获得最佳压缩(和最小大小),使用4:2:0色度子采样方案,其中省略了75%的色度信息。 为了获得最佳质量(和最大大小),文件是2/3的色度和1/3的亮度信息。

  3. Huffman位流符号用于编码DCT分量,每个DCT块最多有65个符号(64个AC + 1个DC)。

  4. Huffman符号可以从1到16位,编码器选择尽可能小的符号长度。 但是,符号长度的选择可以被指定。

  5. 最终的Huffman位流编码必须完成以便可以唯一地识别标记。也就是说,输出中任何0xff字节的出现都必须被替换为两个字节 - 0xff,0x00。

使用所有这些信息,我们可以构建一个病态但有效的JPEG文件,libjpeg(最常见的JPEG解码器实现)可以成功解码。

首先,我们需要最长的可能的Huffman符号。 首先考虑定义一个最大长度的Huffman符号(16位),全部是1,会使用大部分空间,但是libjpeg拒绝处理全部为1的Huffman符号,这似乎没有被标准排除 - 因为它仍然是一个唯一的符号,因为其大小已知为16位,不像其他可变长度符号,确实有一些解码器可以处理它(JPEGSnoop)。

因此,我们定义了一个Huffman表,将最后两个符号设置为:

11111111_1111110  -> (0,0) (EOB - end of block value)
11111111_11111110 -> (0,15)

这样的哈夫曼表在JPEG文件中的呈现形式为:

0xFF, 0xC4 ; DHT - define huffman table
0x00, 35 ; length
0x00 ; DC 0
1,1,1,1,1,1,1,1,1,1, 1, 1, 1, 1, 1, 1 ; histogram
1,2,3,4,5,6,7,8,9,10,11,12,13,14,0,15 ; symbols

现在要编码一个最大长度的DCT块:

1 x DC of 31 bits  ( 11111111 11111110 11111111 1111111 )
64 x AC of 31 bits ( 11111111 11111110 11111111 1111111 )
= 2015 bits

由于MCU将包含3个DCT块(每个分量一个),因此MCU的大小将为6045位。

其中大部分字节都将是0xff,根据标准,这些字节将在输出流中被替换为0xff,0x00,以便与有效标记区分开来。

执行此映射,完整的DCT由以下字节模式的8个重复表示:

0xff,0x00,0xfe,0xff,0x00,0xff,0x00
0xff,0x00,0xfd,0xff,0x00,0xff,0x00
0xff,0x00,0xfb,0xff,0x00,0xff,0x00
0xff,0x00,0xf7,0xff,0x00,0xff,0x00
0xff,0x00,0xef,0xff,0x00,0xff,0x00
0xff,0x00,0xdf,0xff,0x00,0xff,0x00
0xff,0x00,0xbf,0xff,0x00,0xff,0x00
0xff,0x00,0x7f,0xff,0x00

这些加起来总共是8*54 = 432字节。

将这一切加在一起,我们有: 3个组件 *(每个组件432字节) = 每个8x8像素点1296字节

需要一个339字节的标题来设置图像属性和哈夫曼表的SOI/DHT/DQT/SOS段,需要2字节的EOI标记来结束图像。

因为200x200像素的图像将是25x25 MCU,所以我们最终的大小为:

339 + (25 * 25 * 1296) + 2 = 810341字节

这相当于每个像素略大于20.25个字节,比未压缩的BMP/TGA文件大6倍。


+1 很好的小型运行,演示了最坏情况下的合成jpeg MCU。然而,我怀疑你是否能够让任何(现实中的)jpeg压缩器实际上产生这么多1的huffman流。 如果我们尝试实际构建最坏情况位图,并将其输入到huffman编码器中,也许有一种方法可以确定最坏情况huffman流的更紧密的上限? - Zuu
首先,我认为可以安全地假设您无法构建一个位图,使得libjpeg压缩后的大小大于源位图的大小(忽略头文件和维度是16的倍数)。因此,如果我们能够更接近实际的上限,那就太好了。 - Zuu
所有1位的限制来自ITU T.81标准的附录C: 应生成编码,以便任何长度的全1位码字保留为更长码字的前缀。 - Reinstate Monica
1
小修正:MCU 由 1 个 DC 系数和 63 个 AC 系数组成。 每个 8 × 8 块都会通过正向 DCT 转换为一组称为 DCT 系数的 64 个值。其中一个值被称为 DC 系数,另外 63 个则是 AC 系数。然后对这 64 个系数进行量化 <...> 量化后,DC 系数和 63 个 AC 系数将准备进行熵编码。规范(第19页) - shitpoet
此外,有可能创建具有许多精细扫描的多扫描渐进式JPEG。据我所知,JPEG标准没有限制最大扫描数。无论如何,我在某处读到过,理论上可以很容易地达到1000个扫描。我不确定是否可以按照规范无为地创建精细扫描。但如果可以的话,那么200x200 JPEG的最大理论大小将接近无穷大。 - shitpoet

12

一般而言,任何JPEG图像都不会比相同尺寸的32位位图更大。32位位图中每个像素将有4个字节,因此将图像的宽高相乘(例如200x200 = 40000),再将结果乘以4个字节(例如40000x4 = 160000),你就得到了一个上限大小(以字节计算)。对于你的例子来说,160000字节大约是156kb。


文件的最小边界有规定吗? - Tegra Detra
这有点太大了。像素的大小是12位,而不是32位。至少,一个JPEG文件会有1千字节左右。试着打开画图工具并将一张空白图片保存为JPEG格式。 - Mike Bailey
3
我从未说过JPEG使用32位来表示一个像素。我说的是32位位图(最常见的类型)使用32位来表示一个像素 - 而且JPEG始终比等效的位图要小(因为位图是最低效的格式之一)。 - Amber

3

JPEG的最大尺寸应该在宽度 * 高度 * 12个比特位左右。

JPEG将图像转换为不同的颜色空间(YCbCr),使用较少的比特位(确切地说是12个)来表示单个颜色。但实际上,图像的大小要比上述公式所示的要小得多。

如果我们仅使用无损压缩,文件大小会稍微小一些。即使如此,也没有人这样做,因此您的图像应该远低于该公式设置的限制。

简而言之:最多60 KB,但很可能远远低于此。


1

最终的字节数取决于所使用的编码质量设置和像素数量。在您的情况下,所有图像应该是相同的大小,因为您正在进行编码,而您的用户似乎被迫在200x200的区域上绘制。

根据维基百科的说法,每个像素的最大值大约为9位。

因此,200*200*9 = 360000位 = 45 kB

http://en.wikipedia.org/wiki/JPEG#Effects_of_JPEG_compression


0

我不确定这会有多大的帮助,但我相信它的绝对最大值可能是:

width * height * 4 (int 的大小) 你可能还应该加上一千字节的元数据... 但我怀疑图像永远不会达到那个大小(因为这就是 JPEG 压缩的全部意义)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接