我需要找到JPEG(JFIF)图像的大小。图像不会保存为独立文件,因此我无法使用GetFileSize
或任何其他此类API(图像放在流中,除了通常的JPEG / JFIF标头外,不存在其他标头(s) ))。
我做了一些研究,发现JPEG图像由不同的部分组成,每个部分都以帧标记(0xFF 0xXX
)开始,以及该帧的大小。使用此信息,我能够从文件中解析大量信息。
问题是,我找不到压缩数据的大小,因为似乎压缩数据没有帧标记。此外,似乎压缩数据遵循SOS(FFDA
)标记,并且图像以图像结束(EOI)(FFD9
)标记结束。
实现这一目标的一种方法是从一个字节到另一个字节搜索EOI标记,但我认为压缩数据可能包含这个字节组合,对吧?
有没有一种简单而正确的方法来查找图像的总大小? (我更喜欢没有任何外部库的代码/想法)
基本上,我需要图像开始(SOI-FFE0
)和图像结束(EOI-FFD9
)之间的距离(以字节为单位)。
压缩数据不包括SOI或EOI字节,因此您在那里安全。但评论,应用程序数据或其他标题可能会。幸运的是,您可以在给出长度时识别并跳过这些部分。
JPEG规范告诉您需要什么: http://www.w3.org/Graphics/JPEG/itu-t81.pdf
请参见表B.1,第32页。具有*的符号后面没有长度字段(RST,SOI,EOI,TEM)。其他人呢。
你需要跳过各个领域,但这并不算太糟糕。
怎么办:
FFD8
)。这是一个开始。它应该是流中的第一件事。
然后,浏览文件,查找更多标记并跳过标题:
SOI标记(FFD8
):图像损坏。你应该已经找到了一个EOI!
TEM(FF01
):独立标记,继续前进。
RST(FFD0
通过FFD7
):独立标记,继续前进。您可以验证重启标记从FFD0
到FFD7
计数并重复,但这不是测量长度所必需的。
EOI标记(FFD9
):你已经完成了!
任何不是RST,SOI,EOI,TEM的标记(FF01
到FFFE
,减去上面的例外):在标记之后,读取接下来的2个字节,这是该帧头的16位大端长度(不包括2字节标记,但包括长度字段)。跳过给定的数量(通常长度减去2,因为你已经得到了这些字节)。
如果您在EOI之前收到文件结尾,那么您的图像已损坏。
一旦你有了EOI,你就已经完成了JPEG并且应该有长度。如果您希望流中有多个JPEG,则可以通过读取另一个SOI重新开始。由于您没有发布任何语言,我不确定这是否有效,但是:
你能Stream.Seek(0, StreamOffset.End);
,然后采取流的位置?
请具体说明您使用的框架。
事实上,如果文件头没有指定预期的大小,你必须寻找(或读取)到图像的末尾。
编辑
由于您尝试流式传输多个文件,因此您需要使用流式友好容器格式。
OGG应该很适合这个。
JPEG实际上已经是流媒体友好的,但您必须保证每个文件都有一个有效的终结符,然后再将其发送到流中,否则您可能会因意外输入而导致应用程序崩溃。
也许这样的事情
int GetJpgSize(unsigned char *pData, DWORD FileSizeLow, unsigned short *pWidth, unsigned short *pHeight)
{
unsigned int i = 0;
if ((pData[i] == 0xFF) && (pData[i + 1] == 0xD8) && (pData[i + 2] == 0xFF) && (pData[i + 3] == 0xE0)) {
i += 4;
// Check for valid JPEG header (null terminated JFIF)
if ((pData[i + 2] == 'J') && (pData[i + 3] == 'F') && (pData[i + 4] == 'I') && (pData[i + 5] == 'F')
&& (pData[i + 6] == 0x00)) {
//Retrieve the block length of the first block since the first block will not contain the size of file
unsigned short block_length = pData[i] * 256 + pData[i + 1];
while (i < FileSizeLow) {
//Increase the file index to get to the next block
i += block_length;
if (i >= FileSizeLow) {
//Check to protect against segmentation faults
return -1;
}
if (pData[i] != 0xFF) {
return -2;
}
if (pData[i + 1] == 0xC0) {
//0xFFC0 is the "Start of frame" marker which contains the file size
//The structure of the 0xFFC0 block is quite simple [0xFFC0][ushort length][uchar precision][ushort x][ushort y]
*pHeight = pData[i + 5] * 256 + pData[i + 6];
*pWidth = pData[i + 7] * 256 + pData[i + 8];
return 0;
}
else {
i += 2; //Skip the block marker
//Go to the next block
block_length = pData[i] * 256 + pData[i + 1];
}
}
//If this point is reached then no size was found
return -3;
}
else {
return -4;
} //Not a valid JFIF string
}
else {
return -5;
} //Not a valid SOI header
return -6;
} // GetJpgSize
在python中,您可以将整个文件读入字符串对象,并找到第一次出现的FF E0和最后出现的FF D9。据推测,这些是您正在寻找的起点和终点?
f = open("filename.jpg", "r")
s = f.read()
start = s.find("\xff\xe0")
end = s.rfind("\xff\xd9")
imagesize = end - start