我必须说我不太了解文件格式的工作原理。我的问题是,比如我有一个200像素乘以200像素的jpeg文件,如何计算出该文件在兆字节/字节方面的最大大小?
我认为导致这个问题的推理会帮助某个人回答我。我有一个Java小程序,将人们用它绘制的图像上传到我的服务器。我需要知道这个文件可能达到的最大大小。它始终将是200x200。
听起来很傻,但是是否有一些颜色占用比其他颜色更多的字节大小,如果有,最昂贵的是哪种颜色?
我必须说我不太了解文件格式的工作原理。我的问题是,比如我有一个200像素乘以200像素的jpeg文件,如何计算出该文件在兆字节/字节方面的最大大小?
我认为导致这个问题的推理会帮助某个人回答我。我有一个Java小程序,将人们用它绘制的图像上传到我的服务器。我需要知道这个文件可能达到的最大大小。它始终将是200x200。
听起来很傻,但是是否有一些颜色占用比其他颜色更多的字节大小,如果有,最昂贵的是哪种颜色?
有许多方法可以制作一个异常大的“病态”JPEG/JFIF文件。
在极端情况下,由于标准不限制某些类型的标记出现次数,因此大小没有上限 - 例如,一个充满了许多GB DRI(定义重启间隔)标记的JFIF文件,然后在末尾是一个8x8像素MCU,在技术上是有效的。
如果我们限制自己只使用“正常”的标记用法,则会找到如下的上限:
一些背景信息 -
JPEG将像素编码为8x8像素块(DCT块)的MCU(组),每个分量(Y,Cb,Cr)对应一个DCT块。
为获得最佳压缩(和最小大小),使用4:2:0色度子采样方案,其中省略了75%的色度信息。 为了获得最佳质量(和最大大小),文件是2/3的色度和1/3的亮度信息。
Huffman位流符号用于编码DCT分量,每个DCT块最多有65个符号(64个AC + 1个DC)。
Huffman符号可以从1到16位,编码器选择尽可能小的符号长度。 但是,符号长度的选择可以被指定。
最终的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倍。
一般而言,任何JPEG图像都不会比相同尺寸的32位位图更大。32位位图中每个像素将有4个字节,因此将图像的宽高相乘(例如200x200 = 40000),再将结果乘以4个字节(例如40000x4 = 160000),你就得到了一个上限大小(以字节计算)。对于你的例子来说,160000字节大约是156kb。
JPEG的最大尺寸应该在宽度 * 高度 * 12个比特位
左右。
JPEG将图像转换为不同的颜色空间(YCbCr),使用较少的比特位(确切地说是12个)来表示单个颜色。但实际上,图像的大小要比上述公式所示的要小得多。
如果我们仅使用无损压缩,文件大小会稍微小一些。即使如此,也没有人这样做,因此您的图像应该远低于该公式设置的限制。
简而言之:最多60 KB,但很可能远远低于此。
最终的字节数取决于所使用的编码质量设置和像素数量。在您的情况下,所有图像应该是相同的大小,因为您正在进行编码,而您的用户似乎被迫在200x200的区域上绘制。
根据维基百科的说法,每个像素的最大值大约为9位。
因此,200*200*9 = 360000位 = 45 kB
http://en.wikipedia.org/wiki/JPEG#Effects_of_JPEG_compression
我不确定这会有多大的帮助,但我相信它的绝对最大值可能是:
width * height * 4 (int 的大小)
你可能还应该加上一千字节的元数据... 但我怀疑图像永远不会达到那个大小(因为这就是 JPEG 压缩的全部意义)