分类:
2013-01-04 10:41:35
原文地址:png图片简单分析之获取图片宽度和高度(像素) 作者:HuangLei_LEGO
文件头数据块IHDR(header chunk) – 用于获取图片的宽度、高度、深度等基本信息!
IHDR |
文件头数据块 |
否 |
否 |
第一块 |
||
域的名称 |
字节数 |
说明 |
||||
Width |
4 bytes |
图像宽度,以像素为单位 |
||||
Height |
4 bytes |
图像高度,以像素为单位 |
||||
Bit depth |
1 byte |
图像深度: |
||||
ColorType |
1 byte |
颜色类型: |
||||
Compression method |
1 byte |
压缩方法(LZ77派生算法) |
||||
Filter method |
1 byte |
滤波器方法 |
||||
Interlace method |
1 byte |
隔行扫描方法: |
||||
针对以上信息,分析图片十六进制数据中对应信息(ASCII表 e表示扩展字符):
我将mypic.png图片在ubuntu下用hexdump –C > mypic.txt导入到了mypic.txt中,便于查看和分析!直接在windows下打开的话,很多都不正常显示。
粘出前5行:
00000000 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 |.PNG........IHDR|
00000010 00 00 00 80 00 00 00 80 08 06 00 00 00 c3 3e 61 |..............>a|
00000020 cb 00 00 20 00 49 44 41 54 78 9c ec bd 77 bc 64 |... .IDATx...w.d|
00000030 45 99 ff ff ae aa 73 3a f7 cd f7 4e 60 66 18 18 |E.....s:...N`f..|
00000040 24 08 8a 92 4c 28 18 70 d5 45 01 23 66 d7 b0 e6 |$...L(.p.E.#f...|
00000050 65 17 31 ed ea ee ca ba eb d7 35 eb ca ee cf c5 |e.1.......5.....|
00000060 35 20 2a 22 82 a8 08 82 02 92 04 19 82 64 66 98 |5 *".........df.|
PNG文件的标识
00000000 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 |.PNG........IHDR|
<对应> e P N G 回车 换行 替换 . I H D R
PNG文件的宽度(4 bytes)和高度(4 bytes) – 128 * 128(像素)
00000010 00 00 00 80 00 00 00 80 08 06 00 00 00 c3 3e 61 |..............>a|
128 128 2^16 = 32 06:带α通道数据的真彩色图像,8或16
00 c3 3e 61 CRC校验
后面的就是一些其他信息,我只需要获取宽度和高度等信息,所以其他的略过,分析都是类似的,如果需要改变颜色,可以试着往后分析,直接去改,这样省去了其他麻烦的修改方式!后面试着改变下颜色,所以分析下调色板:
00000030 45 99 ff ff ae aa 73 3a f7 cd f7 4e 60 66 18 18 |E.....s:...N`f..|
00000040 24 08 8a 92 4c 28 18 70 d5 45 01 23 66 d7 b0 e6 |$...L(.p.E.#f...|
00000050 65 17 31 ed ea ee ca ba eb d7 35 eb ca ee cf c5 |e.1.......5.....|
00000060 35 20 2a 22 82 a8 08 82 02 92 04 19 82 64 66 98 |5 *".........df.|
PNG文件格式中的数据块 |
||||
数据块符号 |
数据块名称 |
多数据块 |
可选否 |
位置限制 |
IHDR |
文件头数据块 |
否 |
否 |
第一块 |
cHRM |
基色和白色点数据块 |
否 |
是 |
在PLTE和IDAT之前 |
gAMA |
图像γ数据块 |
否 |
是 |
在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 |
(专用公共数据块) |
是 |
是 |
无限制 |
gIFg |
(专用公共数据块) |
是 |
是 |
无限制 |
gIFt |
(专用公共数据块) |
是 |
是 |
无限制 |
gIFx |
(专用公共数据块) |
是 |
是 |
无限制 |
IEND |
图像结束数据 |
否 |
否 |
最后一个数据块 |
这样我只需要读取00000010开始的8个字节就可以获取图片宽度和高度了!
开始吧….
/// < png图片信息
typedef struct _PNGImg
{
uint16_t wd; /// < png图片的宽度 - png图片最大支持256,uint16_t足够了!
uint16_t hg; /// < png图片的高度 - png图片最大支持256,uint16_t足够了!
}PNGImg;
/**
* @brief 获取png图片信息 (接口公司封装,和标准有差别)
*/
PNGImg * pngimggetInfo(const char * pImg)
{
PNGImg * pPNGImg = NULL;
File * pf = NULL;
unsigned char wtmp[4]={'0'}; /// < 文件宽度
unsigned char htmp[4]={'0'}; /// < 文件高度
if (!pImg) /// < 参数为空,直接返回
return NULL;
if (!fexist(pImg)) /// < 文件不存在,直接返回
return NULL;
pf = fopen(pImg, OFM_READ); /// < 自定义的!ó "r"
if (!pf)
return NULL;
pPNGImg = (PNGImg *)malloc(sizeof(PNGImg));
if (!pPNGImg)
{
fclose(pf);
return NULL;
}
fseek(pf,FST_START, 16L); /// < 自定义的!ó SEEK_SET
fread(pf, wtmp, 4); /// < example 00000080
fread(pf, htmp, 4); /// < example 00000080
fclose(pf);
pPNGImg->wd = ((int)(unsigned char)wtmp[2]) * 256 + (int)(unsigned char)wtmp[3];
pPNGImg->hg = ((int)(unsigned char)htmp[2]) * 256 + (int)(unsigned char)htmp[3];
return pPNGImg;
}