首先我想说我多次尝试通过谷歌搜索找到答案,我发现很多结果但我不明白,因为我不知道读取二进制文件的想法,并转换值获得了可读的价值。
我尝试过做什么。
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.");
}
我想通过示例节目进行简单的解释,如何从其标题中获取jpeg文件的宽度/高度,然后将该值转换为可读值。
答案 0 :(得分:14)
不幸的是,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);
从源代码中可以清楚地看到,这个信息没有单一的“标题”。您必须扫描JPEG文件,解析每个段,直到找到包含所需信息的段。这在wikipedia article:
中有所描述JPEG图像由一系列段组成,每个段以标记开头,每个段以0xFF字节开头,后跟一个字节,表示它是什么类型的标记。有些标记只包含这两个字节;其他后跟两个字节,表示随后的标记特定有效载荷数据的长度。
JPEG文件由一系列段组成:
SEGMENT_0
SEGMENT_1
SEGMENT_2
...
每个段以2字节标记开头。第一个字节是0xFF
,第二个字节决定了段的类型。接下来是段的长度的编码。该段内是特定于该段类型的数据。
图像宽度和高度位于SOFn
类型的段或“帧起始[n]”中,其中“n”是某个数字,表示JPEG解码器特有的。仅查找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
答案 1 :(得分: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);
答案 2 :(得分:2)
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;
}
}
答案 3 :(得分:0)
这是我编写的一些简单的代码,它似乎可靠地运行。
#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];
}
答案 4 :(得分:0)
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;
}
答案 5 :(得分:0)
这是我用Java编写的代码。适用于从相机中取出的jpeg。它扫描所有代码以找到最大的图像大小。我无法改进它以跳过每个块的长度,因为它不起作用。如果任何人都可以改进代码来做到这一点,那就太好了。
int getShort(byte[] p, int i)
{
int p0 = p[i] & 0xFF;
int p1 = p[i+1] & 0xFF;
return p1 | (p0 << 8);
}
int[] GetJpegDimensions(byte[] b)
{
int nIndex;
int height=0, width=0, size=0;
int nSize = b.length;
// marker FF D8 starts a valid JPEG
if (getShort(b,0) == 0xFFD8)
for (nIndex = 2; nIndex < nSize-1; nIndex += 4)
if (b[nIndex] == -1/*FF*/ && b[nIndex+1] == -64/*C0*/)
{
int w = getShort(b,nIndex+7);
int h = getShort(b,nIndex+5);
if (w*h > size)
{
size = w*h;
width = w;
height = h;
}
}
return new int[]{width,height};
}
答案 6 :(得分:0)
可以找到JPEG文件中的图像尺寸,如下所示:
1)寻找 FF C0
2)在此位置之后的偏移量+4和+6是高度和宽度(字),分别为/ ly。
在大多数情况下,高度和宽度的绝对偏移分别是A3和A5。