如何在不使用库的情况下获取jpeg文件的宽度/高度?

Lio*_*ing 8 c jpeg binaryfiles

首先我想说我多次尝试通过谷歌搜索找到答案,我发现很多结果但我不明白,因为我不知道读取二进制文件的想法,并将获得的值转换为可读的价值.

我尝试过做什么

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.");
}
Run Code Online (Sandbox Code Playgroud)

我想要一个简单的解释与示例显示,如何从其标头获取jpeg文件的宽度/高度,然后将该值转换为可读值.

jxh*_*jxh 15

不幸的是,JPEG似乎并不简单.您应该查看jhead命令行工具的源代码.它提供了这些信息.浏览源代码时,您将看到该函数ReadJpegSections.此功能扫描JPEG文件中包含的所有段以提取所需信息.处理具有SOFn标记的帧时获得图像宽度和高度.

我看到源是在公共域中,所以我将显示获取图像信息的片段:

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);
Run Code Online (Sandbox Code Playgroud)

从源代码中可以清楚地看到,这个信息没有单一的"标题".您必须扫描JPEG文件,解析每个段,直到找到包含所需信息的段.这在维基百科文章中有所描述:

JPEG图像由一系列段组成,每个段以标记开头,每个段以0xFF字节开头,后跟一个字节,表示它是什么类型的标记.有些标记只包含这两个字节; 其他后跟两个字节,表示随后的标记特定有效载荷数据的长度.


JPEG文件由一系列段组成:

SEGMENT_0
SEGMENT_1
SEGMENT_2
...
Run Code Online (Sandbox Code Playgroud)

每个段以2字节标记开头.第一个字节是0xFF,第二个字节确定段的类型.接下来是段的长度的编码.段内是特定于该段类型的数据.

图像的宽度和高度可以在一个类型的段中找到SOFn,或者"帧起始[n]",其中"n"是某个数字,表示JPEG解码器的特殊内容.它应该足够好只查看a SOF0,其字节名称是0xC0.找到此框架后,您可以对其进行解码以查找图像的高度和宽度.

所以你想做的事情的程序结构如下:

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
Run Code Online (Sandbox Code Playgroud)

这基本上是Michael Petrov get_jpeg_size()实施中的结构.


use*_*789 7

那么你必须找到jpeg的高度和宽度标记,即[ffc0].

在二进制格式中找到ffc0后,四个,五个字节是高,六个和七个字节是宽度.

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);
Run Code Online (Sandbox Code Playgroud)


use*_*479 5

这个问题很老,其他答案是正确的,但它们的格式不是最简单的。我只是getc用来快速获取尺寸,同时跳过不相关的标记(它还支持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;
     }
  }
Run Code Online (Sandbox Code Playgroud)