▷ 图像格式简单解析(BMP,WebP,JPEG,PNG,GIF)
Bitmap位图
介绍
位图(Bitmap),又称栅格图或点阵图,是使用像素阵列来表示的图像。根据位深度,可将位图分为1、4、8、16、24及32位图像等。每个像素使用的信息位数越多,可用的颜色就越多,颜色表现就越逼真,相应的数据量越大。
BMP文件是微软公司所开发的一种交换和存储数据的方法。BMP格式的缺点是,要占用较大的存储空间,文件尺寸太大。
BMP文件结构
BMP文件存储结构的格式可以在Windows中的WINGDI.h文件中找到定义。
BMP文件总体上由4部分组成,分别是位图文件头、位图信息头、调色板和图像数据。
位图文件头
位图信息头
彩色表/调色板
位图数据
解析
BITMAPFILEHEADER文件头
用于描述 Windows 位图(Bitmap)文件的文件头信息,包含了图像类型、图像大小、图像数据存放地址和两个保留未使用的字段,其定义如下
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
bfType:这是一个 16 位无符号整数,用于标识文件类型。对于位图文件,这个值通常是0x4D42,其对应的 ASCII 码是BM。通过检查这个值,程序可以快速判断一个文件是否可能是位图文件
bfSize:这是一个 32 位无符号整数,表示位图文件的大小,单位是字节。这个值包含了文件头、信息头、颜色表(如果有)和像素数据的全部大小。例如,如果一个位图文件的bfSize值为1024字节,那么从文件开始到结束总共的数据量是 1024 字节。
bfOffBits:这是一个 32 位无符号整数,表示从文件头的起始位置到实际像素数据的偏移量,单位是字节。这个偏移量包括了文件头和信息头(以及可能存在的颜色表)的大小。
BITMAPINFOHEADER位图信息头
BITMAPINFOHEADER是 Windows 图形编程中用于描述位图(Bitmap)详细信息的一个关键结构体。它紧跟在BITMAPFILEHEADER之后,为程序提供了足够的信息来理解和处理位图的像素数据。
typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;
字段名
大小(单位:字节)
描述
biSize
4
本结构的大小,在windows中,此字段的值总为28h字节=40字节
biWidth
4
BMP图像的宽度,单位像素
biHeight
4
biPlanes
2
总为0
biBitCount
2
BMP图像的色深,即一个像素用多少位表示,常见的有1、4、8、16、24和32,分别对应单色、16色、256色、16位高彩色、24位真彩色和32位增强型真彩色
biCompression
4
压缩方式,0表示不压缩,1表示RLE8压缩,2表示RLE4压缩,3表示每个像素值由指定的掩码决定
biSizeImage
4
BMP图像数据大小,必须是4的倍数,图像数据大小不是4的倍数时用0填充补足
biXPelsPerMeter
4
水平分辨率,单位像素/m
biYPelsPerMeter
4
垂直分辨率,单位像素/m
biClrUsed
4
BMP图像使用的颜色,0表示使用全部颜色,对于256色位图来说,此值为100h=256
biClrImportant
4
重要的颜色数,此值为0时所有颜色都重要,对于使用调色板的BMP图像来说,当显卡不能够显示所有颜色时,此值将辅助驱动程序显示颜色
彩色表/调色板(color table)
彩色表/调色板是是单色、16色和256色图像文件所特有的,相对应的调色板大小是2、16和256,调色板以4字节为单位,每4个字节存放一个颜色值,图像的数据是指向调色板的索引。
可以将调色板想象成一个数组,每个数组元素的大小为4字节,调色板的数据结构定义:
typedef struct tagRGBQUAD {
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
} RGBQUAD;
WebP
定义
WebP是由Google开发的一种现代图像格式,旨在提供更小的文件大小,同时保持较高的图像质量。它支持有损压缩和无损压缩,还支持透明背景(类似PNG)和动画(类似GIF)。
特点
压缩效率高
有损压缩比JPG文件小约25%~34%
无损压缩比PNG文件小约26%
支持透明背景(Alpha通道):无损和有损压缩都支持透明
支持动画:可以替代GIF格式
支持渐进加载(Progressive Decoding):提供更快的加载体验。
广泛支持:现代浏览器(如Chrome、Edge、Firefox、Safari等)都支持WebP
优点
高效压缩:相较JPG和PNG文件体积更小,节省带宽
多功能性:同时支持透明(类似PNG)、动画(类似GIF)和高质量压缩(类似JPG)。
提示网站性能:减少图像大小,提升页面加载速度。
下载链接
https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.4.0-windows-x64.zip
参考资料
https://developers.google.cn/speed/webp?hl=zh-cn
格式解析
RIFF文件格式
WebP文件格式基于RIFF(资源交换文件格式)文档格式
RIFF文件的基本元素是数据块。它由以下部分组成:
+++++++++++++++++++++
Chunk FourCC
+++++++++++++++++++++
Chunk Size
+++++++++++++++++++++
Chunk Payload
+++++++++++++++++++++
Chunk FourCC:32位
用于标识分块的四位ASCII代码
分块大小:32位
分块的大小,不包括此字段、区块标识符或填充
分块载荷:分块大小(字节)
数据载荷。如果Chunk Size(数据块大小)为奇数,则会添加一个填充字节(必须为0,以符合RIFF规范)。
注意:RIFF有一个惯例,即全大写的块FourCC是适用于任何RIFF文件格式的标准块,而特定于文件格式的FourCC全部采用小写形式。WebP不遵循此惯例。
WebP文件头
RIFF文件大小WEBP,统称为WebP文件头:WebP header,4个字节(RIFF),4个字节的文件大小,4个字节的标识(WEBP),总计12个字节。
https://developers.google.cn/speed/webp/docs/riff_container?hl=zh-cn
“RIFF”:32位
ASCII字符“R"”I"“F"”F"
文件大小:32位(uint32)
文件的大小(以字节为单位),从偏移量8开始。此字段的最大值为2^32减10字节,因此整个文件的大小不得超过4GiB减2字节。
“WEBP”:32位
ASCII字符“W"”E“”B""P"
WebP文件必须以包含FourCC"WEBP"的RIFF标头开头。标头中的文件大小是后续数据块的总大小加上“WEBP”FourCC的4字节。文件不应该在文件大小指定的数据后面包含任何数据。读取器可以解析此类文件,并忽略尾随数据。由于任何分块的大小都是偶数,因此RIFF标头给出的大小也是偶数。
JPEG
JPEG(Joint Photographic Experts Group)是同名专家小组开发的图像压缩技术标准,该标准由国际标准化组织(ISO)制订,是面向连续色调静止图像的一种压缩标准。JPEG格式是最常用的图像文件格式,后缀名为.jpg或.jpeg。其主要是采用预测编码(DPCM)、离散余弦变换(DCT)以及熵编码的联合编码方式,以去除冗余的图像和彩色数据,属于有损压缩格式,它能够将图像压缩在很小的存储空间,一定程度上会造成图像数据的损伤。
二进制文件
格式解析
JPEG文件头2字节 FF D8
FF D8标识JPEG文件头
APP0图像识别信息 FF E0
名称
字节数
值
说明
段标识
1
FF
段类型
1
E0
段长度
2
0010
如果有缩略图=16+3n
以下为段内容
交换格式
5
4A46494600
JFIF的ASCII码
主版本号
1
次版本号
1
密度单位
1
0=无单位;1=点数/英寸;2=点数/厘米
X像素密度
2
水平方向的密度
Y像素密码
2
垂直方向的密度
缩略图X像素
1
缩略图水平像素数目
缩略图Y像素
1
缩略图垂直像素数目
如果“缩略图X像素”和“缩略图Y像素”的值均>0,才有以下的数据
RGB缩略图
3xN
n=缩略图像素总数=缩略图X像素x缩略图Y像素
DQT定义量化表 FF DB
名称
字节数
值
说明
段标识
1
FF
段类型
1
DB
段长度
2
43
其值=3+n(当只有一个QT时)
以下为段内容
QT信息
1
0-3位
QT号
4-7位
QT精度(0=8bit,1字节;否则=16bit,2字节)
QT
n
n=64xQT精度的字节数
SOF0图像基本信息(帧图像起始块)FF C0
名称
字节数
值
说明
段标识
1
FF
段类型
1
C0
段长度
2
其值=8+组件数量x3
以下为段内容
样本精度
1
8
每个样本位数(大多数软件不支持12和16)
图片高度
2
图片宽度
2
组件数量
1
3
1=灰度图,3=YCbCr/YIQ彩色图,4=CMYK彩色图
组件ID
1
1=Y,2=Cb,3=Cr,4=I,5=Q
采样系数
1
0-3位:垂直采样系数4-7位:水平采样系数
量化表号
1
DHT定义huffman表 FF C4
名称
字节数
值
说明
段标识
1
FF
段类型
1
C4
段长度
2
其值=19+n(当只有一个HT表时)
HT信息
1
0-3位:HT号4位:HT类型,0=DC表,1=AC表 5-7位:必须=0
HT位表
16
这16个数的和应该<=256
HT值表
n
n=表头16个数的和
SOS扫描行开始 FF DA
名称
字节数
值
说明
段标识
1
FF
段类型
1
DA
段长度
2
000C
其值=6+2x扫描行内组件数量
扫描行内组件数量
1
3
必须>=1,<=4否则错误,通常=3
组件ID
1
1=Y,2=Cb,3=Cr,4=I,5=Q
Huffman表号
1
0-3位:AC表号(其值=0...3)4-7位:DC表号(其值=0...3)
剩余3个字节
3
忽略
EOI文件尾 FF D9
名称
字节数
值
段标识
1
FF
段类型
1
D9
PNG
PNG介绍
png是图像文件存储格式,其目的是试图替代GIF和TIFF文件格式,同时增加一些GIF文件格式所不具备的特性。流式网络图形格式(Portable Network Graphic Format,PNG)名称来源于非官方的“PNG‘s Not GIF",是一种位图文件存储格式。PNG用来存储灰度图像时,灰度图像的深度可多到16位,存储彩色图像时,彩色图像的深度可多到48位,并且还可存储多到16位的α通道数据。PNG使用从LZ77派生的无损数据压缩算法。
PNG文件结构
PNG图像格式文件由一个8字节的PNG文件署名域和按照特定结构组织的3个以上的数据块(chunk)组成。
PNG定义了两种类型的数据块,一种是称为关键数据块(critical chunk),这是标准的数据块,另一种叫做辅助数据块(ancillary chunks),这是可选的数据块。关键数据块定义了4个标准数据块,每个PNG文件都必须包含它们,PNG读写软件也都必须要支持这些数据块。
PNG文件署名域
在PNG文件前8字节的PNG文件署名域用来识别该文件是不是PNG文件。该域的值是:
89 50 4e 47 0d 0a 1a 0a
PNG数据块
PNG文件中的每个数据块都由表1所示的4个域组成。
名称
字节数
说明
Length(长度)
4字节
指定数据块中数据域的长度
Chunk Type Code(数据块类型码)
4字节
数据块类型码由ASCII字母(A-Z和a-z)组成
Chunk Data(数据块数据)
可变长度
存储按照Chunk Type Code指定的数据
CRC(循环冗余检测)
4字节
存储用来检测是否有错误的循环冗余码
PNG文件中的关键数据块的4个标准数据块分别是文件数据块、调色板数据块、图像数据块、图像结束数据块。
数据块符号
数据块名称
多数据块
可选
位置限制
IHDR
文件头数据块
否
否
第一块
cHRM
基色和白色点数据块
否
是
在PLTE和IDAT之前
gAMA
图像Y数据块
否
是
在PLTE和IDAT之前
sBIT
样本有效位数据块
否
是
在PLTE和IDAT之前
PLTE
调色板数据块
否
是
在IDAT之前
bKGD
背景颜色数据块
否
是
在PLTE之后IDAT之前
hIST
图像直方图数据块
否
是
在PLTE之后IDAT之前
tRNS
图像透明数据块
否
是
在PLTE之后IDAT之前
oFFs
专用公共数据块
否
是
在IDAT之前
pHYs
物理像素尺寸数据块
否
是
在IDAT之前
sCAL
专用公共数据块
否
是
在IDAT之前
IDAT
图像数据块
是
否
与其他IDAT连续
tIME
图像最后修改时间数据块
否
是
无限制
tEXt
文本信息数据块
是
是
无限制
zTXt
压缩文本数据块
是
是
无限制
fRAc
专用公共数据块
是
是
无限制
glFg
专用公共数据块
是
是
无限制
glFt
专用公共数据块
是
是
无限制
glFx
专用公共数据块
是
是
无限制
IEND
图像结束数据
否
否
最后一个数据块
文件头数据块
文件头数据块的数据块类型码为IHDR,它包含有PNG文件中存储的图像数据的基本信息,并作为第一个数据块出现在PNG数据流中,而且一个PNG数据流中只能有一个文件头数据块。文件头数据块由13个字节组成,格式如下:
域的名称
字节数
说明
Width
4
图像宽度,以像素为单位
Height
4
图像高度,以像素为单位
Bit depth
1
图像深度:索引彩色图像:1,2,4或8灰度图像:1,2,4,8或16真彩色图像:8或16
ColorType
1
颜色类型:0:灰度图像2:真彩色图像3:索引彩色图像4:带α通道数据的灰度图像6:带α通道数据的真彩色图像
Compression method
1
压缩方法(LZ77派生算法)
Filter method
1
滤波器方法
Interlace method
1
隔行扫描方法:0:非隔行扫描1:Adam7
GIF
介绍
GIF的全称是Graphics Interchange Format,可译为图形交换格式,用于以超文本标志语言方式显示索引彩色图像。
文件格式
文件头是一个带有识别GIF格式数据流的数据块,用以区分早期版本和新版本
逻辑屏幕描述区定义了与图像数据相关的图像平面尺寸、彩色深度,并指明后面的调色板数据区属于全局调色板还是局部调色板。若使用的是全局调色板,则生成一个24bit的RGB全局调色板,其中一个基色占用一个字节。
调色板数据区。分通用调色板和局部调色板。其中通用调色板适用于文件中所有图像,局部调色板只适用于某一个图像。
图像数据区的内容有两类,一类是纯粹的图像数据,一类是用于特殊目的的数据块(包含专用应用程序代码和不可打印的注释信息)。在GIF89a格式的图像文件中,如果一个文件中包含多个图像,图像数据区将依次重复数据块序列。
结束标志区的作用主要是标记整个数据流的结束。
Header
在文件头中总包含着magic number数据,标识当前的文件类型,对于gif而言,它的前三个字节总是 0x47,0x49,0x46,而后三个字节标识当前gif的版本,可能是87a也可能是89a,这是header中包含的全部信息。
LogicScreenDescriptor
紧随Header之后的是LogicScreenDescriptor,这里包含了整个gif文件的全局信息,固定7个字节。
名称
字节个数
说明
宽
2
小端形式存储
高
2
同上
压缩字节
1
1位:全局颜色标识,如果存在则全局颜色表紧跟在LogicScreenDescriptor后面出现。2-4位:色表中每个颜色通道的位深,111即表示每个颜色通道允许的最大值为255,也就是7+1位所能表示的最大值。5位:排序标识,标识色表中的颜色是否经过排序,排序按颜色出现的次数从高至低,也就是说越重要的颜色排在更前面。6-8位:全局色表的个数,记为n,则颜色个数为2(n+1)
索引
1
背景色在全局表中的索引,全局色表存在时有效,当图像不能完全占满gif的实际大小时,应显示背景色
宽高比
1
一般不设置
Global Color Table
全局颜色表,只有当全局颜色标识为1时才存在;gif中颜色以rgb格式排序,也就是说每个颜色三字节,128个颜色则占用384字节。
Extension
在gif中还存在着很多扩展块,这些块的格式都是固定的。
[0x21][flag][info]?[subdata]?[0x00]
固定值[0x21]标识这是一个扩展块
[flag]标识当前扩展块的类型
[info]是可选的,携带了所需的额外信息,它的第一个字节表示后续有多少个字节的数据
[subdata]同样是可选的,这是携带的实际数据,它的第一个字节表示后续有多少个字节的数据,如果跳过这些字节后遇到的字节值不是0x00,那么这个字节表示的依然是后续的数据子块大小
固定值[0x00]标识块结束
Comment Extension
评论扩展,存储额外的文字数据。这些数据不能被感知,也就是与图像渲染无关,大部分解析器会跳过它。该扩展块以0x21,0xfe开始,其后跟数据子块(subdata);GIF只支持ASCII表中的字符,也就是一字节表示一字符,如果遇到不能打印的ASCII字符时,gif规范建议用空格(0x20)代替。
该扩展块建议始终在文件头或文件尾,不打扰到更重要的数据(图像或文本)的解析。
Graphic Control Extension
图形控制扩展,顾名思义包含了可以控制图形展示的信息,它的作用范围是此块出现后的第一个Image或Plain Text Extension,固定7字节,其中0x21,0xf9占用两个字节。
Image Descriptor
图像描述符,描述了当前图像的信息。遇到此块时则表示着一个Image的开始,固定10个字节,其中第一个字节始终是0x2c。
Local Color Table
本地色表,同全局色表,在本地色表标识为1时存在,如果不存在则使用全局色表。如果想要gif重现真彩色,可以利用本地色表的特性,将一个完整的图片切割的足够小,并对它们应用不同的色表,但这在大部分时候没有必要,因为这会增加整个gif的体积。
Image Data
图像数据紧跟在本地色表(不存在则跟随Image Descriptor)后,实际是经过压缩后的颜色索引。在gif编码中将图像中出现的所有颜色经过算法压缩至256色内,然后将每个颜色替换为在色表中最接近的颜色的索引,最后通过lzw算法将这些索引字节压缩。
Plain Text Extension
纯文本扩展,存放ASCII文本数据,这些文本需要被渲染到gif中,虽然大部分解析器都忽略它。此块包含15字节的固定信息,其后是可变长度的数据子块,用于存放文本数据。
Trailer
文件结尾,包含固定值0x3b
示例
获取图片宽高
#include
#include
#include "webp/decode.h"
//下载地址https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.4.0-windows-x64.zip
#pragma comment(lib, "libwebp.lib")
using namespace std;
struct LogicScreenDescriptor
{
short width;
short height;
UCHAR yasuo;
char index;
char widthAndHeight;
};
void printResolution(UINT32 width, UINT32 height)
{
cout << "分辨率为:" << width << "x" << height << endl;
}
void printResolutionLeve(UINT32 x, UINT32 y)
{
cout << "水平分辨率为:" << x << ";垂直分辨率为:" << y << endl;
}
void readGif(PCHAR buffer, size_t len)
{
cout << "当前是GIF文件" << endl;
LogicScreenDescriptor* lsd = (LogicScreenDescriptor*)buffer;
printResolution(lsd->width, lsd->height);
}
uint32_t bigToLittleEndian(uint32_t bigEndianValue) {
return ((bigEndianValue & 0xff) << 24) |
((bigEndianValue & 0xff00) << 8) |
((bigEndianValue & 0xff0000) >> 8) |
((bigEndianValue & 0xff000000) >> 24);
}
void readPNG(PCHAR buffer, size_t len)
{
cout << "当前是PNG文件" << endl;
uint32_t length = bigToLittleEndian(*(uint32_t*)buffer);
const char* chunkTypeCode = (const char*)(buffer + 4);
char* data = (char*)malloc(length);
if (data == nullptr)
return;
memcpy(data, buffer + 8, length);
uint32_t width = bigToLittleEndian(*(uint32_t*)data);
uint32_t height = bigToLittleEndian(*(uint32_t*)(data + 4));
printResolution(width, height);
free(data);
}
short swapEndian_short(short value) {
return ((value & 0xff) << 8) | ((value & 0xff00) >> 8);
}
void readJPG(PCHAR buffer, int len)
{
cout << "当前是JPG文件" << endl;
while (len > 0)
{
char seg[2] = {};
memcpy(seg, buffer, 2);
short length = swapEndian_short(*(short*)(buffer + 2));
char app0[] = { 0xFF, 0xE0 };
char sof0[] = { 0xff, 0xc0 };
if (memcmp(buffer, app0, 2) == 0)
{
short length = (*(short*)(buffer + 2));
const char* type = (const char*)(buffer + 4);
char* mversion = (buffer + 9);
char* sversion = (buffer + 10);
char* danwei = (buffer + 11);
short width = swapEndian_short((*(short*)(buffer + 12)));
short height = swapEndian_short((*(short*)(buffer + 14)));
printResolutionLeve(width, height);
}
else if (memcmp(buffer, sof0, 2) == 0)
{
short heigth = swapEndian_short((*(short*)(buffer + 5)));
short width = swapEndian_short((*(short*)(buffer + 7)));
printResolution(width, heigth);
}
len -= length;
buffer = buffer + length + 2;
}
}
void readBMP(PCHAR buffer, int len)
{
cout << "当前是BMP文件" << endl;
BITMAPFILEHEADER* bitmapFileHeader = (PBITMAPFILEHEADER)buffer;
PBITMAPINFOHEADER bitmapInfoHeader = (PBITMAPINFOHEADER)(buffer + sizeof(BITMAPFILEHEADER));
printResolution(bitmapInfoHeader->biWidth, bitmapInfoHeader->biHeight);
}
void readWebP(const uint8_t* buffer, int len)
{
cout << "当前是WebP文件" << endl;
int width, height;
WebPGetInfo(buffer, len, &width, &height);
printResolution(width, height);
}
int main()
{
std::string fileName = R"(C:\Users\stdio\AppData\Roaming\Tencent\WeMeet\Global\Data\DynamicResource\3e1fa3ae1923bb4bacdabc661bc53ec5\remote_control_privilege_elevate_guide\remote_control_privilege_elevate_guide_zh-cn.gif)";
fileName = R"(C:\Users\stdio\AppData\Roaming\kingsoft\office6\wpsassist\onlinetemplates\online\54b472eceb9de061adafdfa33b11780c_ds.png)";
fileName = R"(C:\Users\stdio\Documents\WXWork\1688854706571334\Cache\Image\2024-11\海报.png)";
fileName = R"(C:\Users\stdio\Documents\WXWork\1688854706571334\Cache\Image\2024-12\2.1每日一句 (1)(5).jpg)";
fileName = R"(C:\Users\stdio\Documents\WXWork\1688854706571334\Avator\2024-12\d8142a10d6690d8f96a979eee418051c.jpg)";
fileName = R"(C:\Users\stdio\AppData\Local\Packages\Microsoft.Windows.Search_cw5n1h2txyewy\AC\INetCache\LUF4768K\th0PBG8C9P.jpg)";
fileName = R"(C:\Users\stdio\AppData\Local\Packages\Microsoft.Windows.Search_cw5n1h2txyewy\AC\INetCache\DY0N0B04\thQOHNB4RX.jpg)";
fileName = R"(C:\Users\stdio\Documents\WXWork\1688854706571334\Cache\Image\2024-12\企业微信截图_17338795688595.jpg)";
fileName = R"(D:\Github\TrafficMonitor-master\TrafficMonitor\skins\皮肤06\background.bmp)";
fileName = R"(D:\Downloads\CppGuide-master\articles\imgs\zhyz7.webp)";
fileName = R"(D:\Downloads\CppGuide-master\articles\imgs\zhyz25.webp)";
FILE* file = nullptr;
fopen_s(&file, fileName.c_str(), "rb");
if (file)
{
cout << "当前文件:" << fileName << endl;
fseek(file, 0, SEEK_END);
long len = ftell(file);
fseek(file, 0, SEEK_SET);
PCHAR buffer = (PCHAR)malloc(len);
if (buffer == nullptr)
return 1;
size_t rlen = fread(buffer, 1, len, file);
fclose(file);
char gif89a[] = "GIF89a";
size_t gif89aCount = sizeof(gif89a);
char pngFileHead[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
size_t pngFileHeadCount = sizeof(pngFileHead);
char jpgFileHead[] = { 0xff, 0xd8};
size_t jpgFileHeadCount = sizeof(jpgFileHead);
char bmpFileHead[] = { 0x42, 0x4d };
size_t bmpFileHeadCount = sizeof(bmpFileHead);
char webpFileHead[] = { 'R', 'I', 'F', 'F' };
size_t webpFileHeadCount = sizeof(webpFileHead);
if (memcmp(buffer, gif89a, gif89aCount) == 0)
{
readGif(buffer + gif89aCount, len - gif89aCount);
}
else if (memcmp(buffer, pngFileHead, pngFileHeadCount) == 0)
{
readPNG(buffer + pngFileHeadCount, len - pngFileHeadCount);
}
else if (memcmp(buffer, jpgFileHead, jpgFileHeadCount) == 0)
{
readJPG(buffer + jpgFileHeadCount, len - jpgFileHeadCount);
}
else if (memcmp(buffer, bmpFileHead, bmpFileHeadCount) == 0)
{
readBMP(buffer, len);
}
else if (memcmp(buffer, webpFileHead, webpFileHeadCount) == 0)
{
readWebP((const uint8_t*)buffer, len);
}
else
{
cout << "未知文件" << endl;
}
free(buffer);
}
}