我需要找到JPEG(JFIF)图像的大小。图像不会保存为独立文件,因此我无法使用GetFileSize
或此类任何其他API(图像放在流中,除了通常的JPEG /之外不存在其他标题JFIF标题)。
我做了一些研究,发现JPEG图像由不同的部分组成,每个部分都以帧标记(0xFF 0xXX
)开头,以及该帧的大小。使用这些信息,我能够解析文件中的大量信息。
问题是,我找不到压缩数据的大小,因为似乎压缩数据没有帧标记。此外,似乎压缩数据遵循SOS(FFDA
)标记,图像以图像结束(EOI)(FFD9
)标记结束。
实现这一目标的一种方法是从一个字节到另一个字节搜索EOI标记,但我认为压缩数据可能包含这个字节组合,对吗?
是否有一种简单而正确的方法来查找图像的总大小? (我更喜欢一些代码/想法没有任何外部库)
基本上,我需要图像起点(SOI - FFE0
)和图像结束(EOI - FFD9
)之间的距离(以字节为单位)。
答案 0 :(得分:38)
压缩数据不包含SOI或EOI字节,因此您可以安全使用。但评论,应用程序数据或其他标题可能会。幸运的是,您可以在给出长度时识别并跳过这些部分。
JPEG规范告诉您需要什么:
http://www.w3.org/Graphics/JPEG/itu-t81.pdf
请参阅第32页的表B.1。具有*的符号后面没有长度字段(RST,SOI,EOI,TEM)。其他人那样做。
您需要跳过各个字段,但这并不算太糟糕。
如何通过:
开始阅读SOI(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重新开始。
答案 1 :(得分:2)
由于您没有发布任何语言,我不确定这是否有效,但是:
你可以Stream.Seek(0, StreamOffset.End);
然后选择流的位置吗?
请具体说明您正在使用的框架。
事实上,如果文件标题没有指定预期的大小,你必须寻找(或读取)到图像的末尾。
修改强>
由于您尝试流式传输多个文件,因此您需要使用流式友好容器格式。
OGG应该非常适合这个。
JPEG实际上已经是流媒体友好的,但您必须保证每个文件都有一个有效的终结符,然后再将其发送到流中,否则您将面临意外输入导致应用程序崩溃的风险。
答案 2 :(得分:2)
也许是这样的
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
答案 3 :(得分:0)
在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