我需要找到一个JPEG(JFIF)图像的大小。 图像不保存为独立的文件,所以我不能使用GetFileSize
或任何其他API这样这一个(图像被放置在一个流并且没有其他报头存在,则除了通常的JPEG / JFIF头(一个或多个))。
我做了一些研究,结果发现,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)的符号。 其他人做。
您需要跳过的各个领域,但它不是太糟糕了。
如何办理:
开始阅读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重新开始。
既然你没有任何语言张贴的,我不知道这会工作,但:
你能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