Chinaunix首页 | 论坛 | 博客
  • 博客访问: 504297
  • 博文数量: 401
  • 博客积分: 244
  • 博客等级: 入伍新兵
  • 技术积分: 2215
  • 用 户 组: 普通用户
  • 注册时间: 2012-08-04 10:02
文章分类

全部博文(401)

文章存档

2013年(37)

2012年(364)

分类:

2013-01-04 10:41:35

文件头数据块IHDR(header chunk) – 用于获取图片的宽度、高度、深度等基本信息!

IHDR

文件头数据块

第一块

域的名称

字节数

说明

Width

4 bytes

图像宽度,以像素为单位

Height

4 bytes

图像高度,以像素为单位

Bit depth

1 byte

图像深度: 
索引彩色图像:1248 
灰度图像:124816 
真彩色图像:816

ColorType

1 byte

颜色类型:
0
:灰度图像, 124816 
2
:真彩色图像,816 
3
:索引彩色图像,1248 
4
:带α通道数据的灰度图像,816 
6
:带α通道数据的真彩色图像,816

Compression method

1 byte

压缩方法(LZ77派生算法)

Filter method

1 byte

滤波器方法

Interlace method

1 byte

隔行扫描方法:
0
:非隔行扫描 
1
Adam7(Adam M. Costello开发的7遍隔行扫描方法)

针对以上信息,分析图片十六进制数据中对应信息(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:带α通道数据的真彩色图像,816

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

基色和白色点数据块

PLTEIDAT之前

gAMA

图像γ数据块

PLTEIDAT之前

sBIT

样本有效位数据块

PLTEIDAT之前

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图片最大支持256uint16_t足够了!

    uint16_t hg;    /// < png图片的高度 - png图片最大支持256uint16_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;

}

阅读(3152) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~