How to get the width/height of jpeg file without u

2020-02-17 10:29发布

Firstly I want to say I tried many times to find the answer by using google search, and I found many results but I did not understand, because I don't know the idea of reading a binary file, and convert the value that Obtained to readable value.

What I tried doing it.

unsigned char fbuff[16];
FILE *file;
file = fopen("C:\\loser.jpg", "rb");
if(file != NULL){
   fseek(file, 0, SEEK_SET);
   fread(fbuff, 1, 16, file);
   printf("%d\n", fbuff[1]);
   fclose(file);
}else{
   printf("File does not exists.");
}

I want a simple explanation with example shows, how to get width/height of jpeg file from its header, and then convert that value to readable value.

7条回答
啃猪蹄的小仙女
2楼-- · 2020-02-17 10:56

Unfortunately, it doesn't seem to be simple for JPEG. You should look at the source to the jhead command line tool. It provides this information. When going through the source, you will see the function ReadJpegSections. This function scans through all the segments contained within the JPEG file to extract the desired information. The image width and height is obtained when processing the frames that have an SOFn marker.

I see the source is in the public domain, so I'll show the snippet that gets the image info:

static int Get16m(const void * Short)
{
    return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
}

static void process_SOFn (const uchar * Data, int marker)
{
    int data_precision, num_components;

    data_precision = Data[2];
    ImageInfo.Height = Get16m(Data+3);
    ImageInfo.Width = Get16m(Data+5);

From the source code, it is clear to me there is no single "header" with this information. You have to scan through the JPEG file, parsing each segment, until you find the segment with the information in it that you want. This is described in the wikipedia article:

A JPEG image consists of a sequence of segments, each beginning with a marker, each of which begins with a 0xFF byte followed by a byte indicating what kind of marker it is. Some markers consist of just those two bytes; others are followed by two bytes indicating the length of marker-specific payload data that follows.


A JPEG file consists of a sequence of segments:

SEGMENT_0
SEGMENT_1
SEGMENT_2
...

Each segment begins with a 2-byte marker. The first byte is 0xFF, the second byte determines the type of the segment. This is followed by an encoding of the length of the segment. Within the segment is data specific to that segment type.

The image width and height is found in a segment of type SOFn, or "Start of frame [n]", where "n" is some number that means something special to a JPEG decoder. It should be good enough to look only for a SOF0, and its byte designation is 0xC0. Once you find this frame, you can decode it to find the image height and width.

So the structure of a program to do what you want would look like:

file_data = the data in the file
data = &file_data[0]
while (data not at end of file_data)
    segment_type = decoded JPEG segment type at data
    if (type != SOF0)
        data += byte length for segment_type
        continue
    else
        get image height and width from segment
        return

This is essentially the structure found in Michael Petrov's get_jpeg_size() implementation.

查看更多
Melony?
3楼-- · 2020-02-17 11:00

then you have to find hight and width marker of jpeg that is [ffc0].

after finding ffc0 in binary formate, the the four,five bytes are hight and six and seven bytes are width.

eg: [ff c0] d8 c3 c2 [ff da] [00 ff]
                      |         |
                      |         |
                      ->height  ->width

int position;
unsigned char len_con[2];
/*Extract start of frame marker(FFC0) of width and hight and get the position*/
for(i=0;i<FILE_SIZE;i++)
{
    if((image_buffer[i]==FF) && (image_buffer[i+1]==c0) )
    {
        position=i;
    }
}
/*Moving to the particular byte position and assign byte value to pointer variable*/
position=position+5;
*height=buffer_src[position]<<8|buffer_src[position+1];
*width=buffer_src[position+2]<<8|buffer_src[position+3];

printf("height %d",*height);
printf("width %d",*width);
查看更多
4楼-- · 2020-02-17 11:01

Image dimensions in JPEG files can be found as follows:

1) Look for FF C0

2) At offsets +4 and +6 after this location are height and width (words), resp/ly.

In most cases, the absolute offsets of height and width are A3 and A5, resp/ly.

查看更多
何必那么认真
5楼-- · 2020-02-17 11:17

Here's some simple code I wrote which seems to work reliably.

#define MOTOSHORT(p) ((*(p))<<8) + *(p+1)
unsigned char cBuf[32];
int iBytes, i, j, iMarker, iFilesize;
unsigned char ucSubSample;
int iBpp, iHeight, iWidth;

         Seek(iHandle, 0, 0); // read the first 32 bytes
         iBytes = Read(iHandle, cBuf, 32);

         i = j = 2; /* Start at offset of first marker */
         iMarker = 0; /* Search for SOF (start of frame) marker */
         while (i < 32 && iMarker != 0xffc0 && j < iFileSize)
            {
            iMarker = MOTOSHORT(&cBuf[i]) & 0xfffc;
            if (iMarker < 0xff00) // invalid marker, could be generated by "Arles Image Web Page Creator" or Accusoft
               {
               i += 2;
               continue; // skip 2 bytes and try to resync
               }
            if (iMarker == 0xffc0) // the one we're looking for
               break;
            j += 2 + MOTOSHORT(&cBuf[i+2]); /* Skip to next marker */
            if (j < iFileSize) // need to read more
               {
               Seek(iHandle, j, 0); // read some more
               iBytes = Read(iHandle, cBuf, 32);
               i = 0;
               }
            else // error, abort
               break;
            } // while
         if (iMarker != 0xffc0)
            goto process_exit; // error - invalid file?
         else
            {
            iBpp = cBuf[i+4]; // bits per sample
            iHeight = MOTOSHORT(&cBuf[i+5]);
            iWidth = MOTOSHORT(&cBuf[i+7]);
            iBpp = iBpp * cBuf[i+9]; /* Bpp = number of components * bits per sample */
            ucSubSample = cBuf[i+11];
            }
查看更多
够拽才男人
6楼-- · 2020-02-17 11:18
int  GetJpegDimensions(
    char            *pImage,
    size_t          nSize,
    unsigned32      *u32Width,
    unsigned32      *u32Height,
    char            *szErrMsg)
{
    int             nIndex;
    int             nStartOfFrame;
    int             nError = NO_ERROR;
    bool            markerFound = false;
    unsigned char   ucWord0;
    unsigned char   ucWord1;

    // verify START OF IMAGE marker = FF D8
    nIndex = 0;
    ucWord0 = pImage[nIndex];
    ucWord1 = pImage[nIndex+1];

    // marker FF D8  starts a valid JPEG
    if ((ucWord0 == 0xFF)  && (ucWord1 == 0xD8))
    {
        // search for START OF FRAME 0  marker  FF C0
        for (nIndex = 2;
            (nIndex < nSize-2) && (markerFound == false);
             nIndex += 2)
        {
            ucWord0 = pImage[nIndex];
            ucWord1 = pImage[nIndex+1];
            if (ucWord0 == 0xFF)
            {
                if (ucWord1 == 0xC0)
                {
                    markerFound = true;
                    nStartOfFrame = nIndex;
                }
            }
            if (ucWord1 == 0xFF)
            {
                ucWord0 = pImage[nIndex+2];
                if (ucWord0 == 0xC0)
                {
                    markerFound = true;
                    nStartOfFrame = nIndex+1;
                }
            }
        } // while

        if (markerFound)
        {
            nError  = NO_ERROR;
            ucWord0 = pImage[nStartOfFrame+5];
            ucWord1 = pImage[nStartOfFrame+6];
            *u32Height = ucWord1 + (ucWord0 << 8);

            ucWord0 = pImage[nStartOfFrame+7];
            ucWord1 = pImage[nStartOfFrame+8];
            *u32Width =  ucWord1 + (ucWord0 << 8);
        }
        else
        {
            // start of frame 0 not found
            nError = -2;
            sprintf(szErrMsg,
              "Not a valid JPEG image. START OF FRAME 0 marker FFC0 not found");
        }
    }
    else   // START OF IMAGE marker not found
    {
        nError = -1;
        sprintf(szErrMsg,
          "Not a valid JPEG image. START OF IMAGE marker FFD8 not found");
    }
    return nError;
}
查看更多
对你真心纯属浪费
7楼-- · 2020-02-17 11:21

the question is old and the other answers are correct but their format is not the easiest one. I just use getc to quickly get the dimensions, while skipping irrelevant markers (it also supports Progressive JPEGs):

  int height, width;
  // start of image (SOI)
  getc(f);   // oxff
  getc(f);   // oxd8
  // Scan miscellaneous markers until we reach SOF0 marker (0xC0)
  for(;;) {
     // next marker
     int marker;
     while((marker = getc(f)) != 0xFF);
     while((marker = getc(f)) == 0xFF);
     // SOF
     if (marker == 0xC0 || marker == 0xC2) {
        getc(f);   // length (2 bytes)
        getc(f);   // #
        getc(f);   // bpp, usually 8
        height = (getc(f) << 8) + getc(f);   // height
        width = (getc(f) << 8) + getc(f);   // width
        break;
     }
  }
查看更多
登录 后发表回答