图像格式简单解析(BMP,WebP,JPEG,PNG,GIF)

xingyun86 16小时前 14

图像格式简单解析(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)详细信息的一个关键结构体。它紧跟在BITMAPINFOHEADER之后,为程序提供了足够的信息来理解和处理位图的像素数据。

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;
字段名大小(单位:字节)描述
biSize4本结构的大小,在windows中,此字段的值总为28h字节=40字节
biWidth4BMP图像的宽度,单位像素
biHeight4
biPlanes2总为0
biBitCount2BMP图像的色深,即一个像素用多少位表示,常见的有1、4、8、16、24和32,分别对应单色、16色、256色、16位高彩色、24位真彩色和32位增强型真彩色
biCompression4压缩方式,0表示不压缩,1表示RLE8压缩,2表示RLE4压缩,3表示每个像素值由指定的掩码决定
biSizeImage4BMP图像数据大小,必须是4的倍数,图像数据大小不是4的倍数时用0填充补足
biXPelsPerMeter4水平分辨率,单位像素/m
biYPelsPerMeter4垂直分辨率,单位像素/m
biClrUsed4BMP图像使用的颜色,0表示使用全部颜色,对于256色位图来说,此值为100h=256
biClrImportant4重要的颜色数,此值为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

名称字节数说明
段标识1FF
段类型1E0
段长度20010如果有缩略图=16+3n
以下为段内容
交换格式54A46494600JFIF的ASCII码
主版本号1
次版本号1
密度单位10=无单位;1=点数/英寸;2=点数/厘米
X像素密度2水平方向的密度
Y像素密码2垂直方向的密度
缩略图X像素1缩略图水平像素数目
缩略图Y像素1缩略图垂直像素数目
如果“缩略图X像素”和“缩略图Y像素”的值均>0,才有以下的数据
RGB缩略图3xNn=缩略图像素总数=缩略图X像素x缩略图Y像素

DQT定义量化表 FF DB

名称字节数说明
段标识1FF
段类型1DB
段长度243其值=3+n(当只有一个QT时)
以下为段内容
QT信息10-3位QT号
4-7位QT精度(0=8bit,1字节;否则=16bit,2字节)
QTnn=64xQT精度的字节数

SOF0图像基本信息(帧图像起始块)FF C0

名称字节数说明
段标识1FF
段类型1C0
段长度2其值=8+组件数量x3
以下为段内容
样本精度18每个样本位数(大多数软件不支持12和16)
图片高度2
图片宽度2
组件数量131=灰度图,3=YCbCr/YIQ彩色图,4=CMYK彩色图
组件ID11=Y,2=Cb,3=Cr,4=I,5=Q
采样系数10-3位:垂直采样系数

4-7位:水平采样系数
量化表号1

DHT定义huffman表 FF C4

名称字节数说明
段标识1FF
段类型1C4
段长度2其值=19+n(当只有一个HT表时)
HT信息10-3位:HT号

4位:HT类型,0=DC表,1=AC表

  5-7位:必须=0
HT位表16这16个数的和应该<=256
HT值表nn=表头16个数的和

SOS扫描行开始 FF DA

名称字节数说明
段标识1FF
段类型1DA
段长度2000C其值=6+2x扫描行内组件数量
扫描行内组件数量13必须>=1,<=4否则错误,通常=3
组件ID11=Y,2=Cb,3=Cr,4=I,5=Q
Huffman表号10-3位:AC表号(其值=0...3)

4-7位:DC表号(其值=0...3)
剩余3个字节3忽略

EOI文件尾 FF D9

名称字节数
段标识1FF
段类型1D9

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个字节组成,格式如下:

域的名称字节数说明
Width4图像宽度,以像素为单位
Height4图像高度,以像素为单位
Bit depth1图像深度:

索引彩色图像:1,2,4或8

灰度图像:1,2,4,8或16

真彩色图像:8或16
ColorType1颜色类型:

0:灰度图像

2:真彩色图像

3:索引彩色图像

4:带α通道数据的灰度图像

6:带α通道数据的真彩色图像
Compression method1压缩方法(LZ77派生算法)
Filter method1滤波器方法
Interlace method1隔行扫描方法:

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同上
压缩字节11位:全局颜色标识,如果存在则全局颜色表紧跟在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<Windows.h>
#include <iostream>
#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);
        }
}

转载:图像格式简单解析(BMP,WebP,JPEG,PNG,GIF) - 这种人 - 博客园

×
打赏作者
最新回复 (0)
查看全部
全部楼主
返回