Determining the size of a JPEG (JFIF) image

后端 未结 4 1203
北荒
北荒 2020-12-23 14:36

I need to find the size of a JPEG (JFIF) image. The image is not saved as a stand-alone file, so I can\'t use GetFileSize or any other API such this one (the im

相关标签:
4条回答
  • 2020-12-23 14:43

    Maybe something like this

    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
    
    0 讨论(0)
  • 2020-12-23 14:50

    In python, you could just read the whole file into a string object and find the first occurrence of FF E0 and the last occurrence of FF D9. Presumably, these are the start and end that you are looking for?

    f = open("filename.jpg", "r")
    s = f.read()
    start = s.find("\xff\xe0")
    end = s.rfind("\xff\xd9")
    imagesize = end - start
    
    0 讨论(0)
  • 2020-12-23 14:57

    Since you don't have any language posted, I'm not sure that this will work, but:

    Can you Stream.Seek(0, StreamOffset.End); and then take the stream's position?

    Please be specific about what framework you are using.

    The real fact of the matter is, if the file header doesn't specify the expected size, you have to seek (or read) to the end of the image.

    EDIT

    Since you are trying to stream multiple files, you will want to use a streaming friendly container format.

    OGG should be a nice fit for this.

    JPEG is actually already streaming friendly, but you must guarantee that each file has a valid terminator before sending it down the stream or else you run the risk of crashing your app with unexpected input.

    0 讨论(0)
  • 2020-12-23 14:58

    The compressed data will not include SOI or EOI bytes, so you are safe there. But the comment, application data, or other headers might. Fortunately, you can identify and skip these sections as the length is given.

    The JPEG specification tells you what you need:
    http://www.w3.org/Graphics/JPEG/itu-t81.pdf

    Look at Table B.1, on page 32. The symbols that have an * do not have a length field following it (RST, SOI, EOI, TEM). The others do.

    You will need to skip over the various fields, but it is not too bad.

    How to go through:

    1. Start reading SOI (FFD8). This is the start. It should be the first thing in the stream.

      • Then, progress through the file, finding more markers and skipping over the headers:

      • SOI marker (FFD8): Corrupted image. You should have found an EOI already!

      • TEM (FF01): standalone marker, keep going.

      • RST (FFD0 through FFD7): standalone marker, keep going. You could validate that the restart markers count up from FFD0 through FFD7 and repeat, but that is not necessary for measuring the length.

      • EOI marker (FFD9): You're done!

      • Any marker that is not RST, SOI, EOI, TEM (FF01 through FFFE, minus the exceptions above): After the marker, read the next 2 bytes, this is the 16-bit big-endian length of that frame header (not including the 2-byte marker, but including the length field). Skip the given amount (typically length minus 2, since you already got those bytes).

      • If you get an end-of-file before EOI, then you've got a corrupted image.

      • Once you've got an EOI, you've gotten through the JPEG and should have the length. You can start again by reading another SOI if you expect more than one JPEG in your stream.

    0 讨论(0)
提交回复
热议问题