确定JPEG的大小(JFIF)图像(Determining the size of a JPEG (

2019-07-22 16:00发布

我需要找到一个JPEG(JFIF)图像的大小。 图像不保存为独立的文件,所以我不能使用GetFileSize或任何其他API这样这一个(图像被放置在一个流并且没有其他报头存在,则除了通常的JPEG / JFIF头(一个或多个))。

我做了一些研究,结果发现,JPEG图像是由不同部分,每个部分开头的帧标记(的0xFF 0xXX ),并且在该帧的大小。 使用这个信息,我能够从文件中解析了大量的信息。

问题是,我无法找到压缩数据的大小,因为它似乎没有为压缩的数据没有帧标记。 此外,似乎对压缩数据后面的SOS( FFDA )标记,并与最终图像的(EOI)(图像结束FFD9 )标记物。

实现这一点的方法是寻找从逐字节的EOI标记,但我认为压缩的数据可能包含的字节,这样的组合,对不对?

有一个简单且正确的方式找到图像的总大小? (我宁愿一些代码/想法,无需任何外部库

基本上,我需要图像开始(SOI-之间的距离(以字节为单位) FFE0 )和图像结束(EOI- FFD9 )。

Answer 1:

压缩后的数据将不包括SOI和EOI字节,所以你是安全的在那里。 但是,评论,应用数据,或其他可能头。 幸运的是,你可以识别并作为指定的长度为跳过这些章节。

JPEG规范的告诉你,你需要什么:
http://www.w3.org/Graphics/JPEG/itu-t81.pdf

看看表B.1,第32页上有一个*没有跟随它的长度字段(RST,SOI,EOI,TEM)的符号。 其他人做。

您需要跳过的各个领域,但它不是太糟糕了。

如何办理:

  1. 开始阅读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重新开始。



Answer 2:

既然你没有任何语言张贴的,我不知道这会工作,但:

你能Stream.Seek(0, StreamOffset.End); 然后取流的位置?

请具体谈谈您使用的是什么框架。

事情的真正的事实是,如果文件头不指定预期大小,你不得不寻求(或读取)到图像的结尾。

编辑

既然你想流多个文件,你会希望使用流媒体友好的容器格式。

OGG应该是一个很好的适合这个。

JPEG实际上已经流友好,但是你必须保证每一个文件都有一个有效的终止发送它往下流之前,否则你运行意外崩溃输入您的应用程序的风险。



Answer 3:

也许是这样的

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


Answer 4:

在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


文章来源: Determining the size of a JPEG (JFIF) image
标签: size jpeg