PNG格式 初探

前文

翻以前的文章,发现了一篇讲png格式的引用,再次阅读,发现并没有想象中的那么难。今天就试着解析下一个png图片的格式。为了简化图片,我生成了一张 1*1 和黑色不透明的基准式png,转化为十六进制进行解析。具体生成方法和图片 base64_url,可见后文。

块格式

png 以格式为单位,而块格式如下:
png块格式

基准式

先处理成十六进制

89504e470d0a1a0a0000000d49484452
000000010000000108060000001f15c4
89000000097048597300000ec400000e
c401952b0e1b0000001049444154081d
010500faff00000000ff01040100a78f
db830000000049454e44ae426082

文件头标志

89504e470d0a1a0a

IHDR头块

块数据长度

0000000d

块类型 IHDR标识(ascii码为IHDR)

49484452

块类型内容
图像的宽

00000001

1像素,四字节无符号整数。零是无效值。

图像的高

00000001

1像素,四字节无符号整数。零是无效值。

色深

08

一个单字节整数,给出每个样本或每个调色板索引(而不是每个像素)的位数。有效值为 1、2、4、8 和 16,但并非所有颜色类型都允许使用所有值。2^8=256,即这是一个256色的图像,

颜色类型

06

一个单字节整数,用于定义 PNG 图像类型。有效值为 0、2、3、4 和 6。06为带α通道数据的真彩色图像

压缩方法

00

一个单字节整数,表示用于压缩图像数据的方法,有五种。

过滤方法

00

一个单字节整数,表示压缩前对图像数据应用的预处理方法

隔行方式

00

一个单字节整数,表示图像数据的传输顺序。本国际标准定义了两个值:0(无隔行)或 1(Adam7 隔行)

IHDR CRC校验

1f15c489

pHYs 物理像素尺寸

块数据长度

00000009

块类型

70485973

块内容——物理像素尺寸

的PHYS块指定预期的像素尺寸或纵横比用于图像的显示

字段信息
每单位像素,X 轴4 字节(PNG 无符号整数)
每单位像素,Y 轴4 字节(PNG 无符号整数)
单位说明符1 字节

00000ec4
00000ec4

单位说明
0单位未知
1单位是米

01

当单位说明符为 0 时,pHYs块只定义像素纵横比;像素的实际大小仍未指定。
如果pHYs块不存在,则假定像素为正方形,并且未指定每个像素的物理大小。

pHYs 块 CRC校验

952b0e1b

IDAT图像数据

块数据长度

00000010

块类型

49444154

块内容——图像数据

081d010500faff00000000ff01040100

涉及压缩和过滤,暂时看不懂

IDAT 块 CRC校验

a78fdb83

IEND数据块

块数据长度

00000000

块类型

49454e44

CRC校验

ae426082

因为块数据是空的,所以CRC校验是固定的。因此IEND数据块每个PNG都是一样的,

再把数据进行用表格记录,更加直观

数据含义
89504e470d0a1a0a文件头标志
0000000d块长度
49484452IHDR块 标志
00000001图像的宽
00000001图像的高
08色深
06颜色类型
00压缩方法
00过滤方法
00隔行方式
1f15c489IHDR块 CRC校验
00000009块长度
70485973pHYs块
00000ec4每单位像素,X 轴
00000ec4每单位像素,Y 轴
01单位说明符
952b0e1bpHYs 块 CRC校验
00000010块长度
49444154IDAT块类型
081d010500faff00000000ff01040100aIDAT数据
78fdb83IDAT 块 CRC校验
00000000IEND数据块长度
49454e44IEND数据块类型
ae426082IENDCRC校验

交错式(隔行扫描)

同一张png图片设置为交错式,数据如下

89504e470d0a1a0a0000000d49484452
000000010000000108060000016812f4
1f000000097048597300000ec400000e
c401952b0e1b0000001049444154081d
010500faff00000000ff01040100a78f
db830000000049454e44ae426082

其中 CRC校验码前的01则代表改图片为隔行扫描,其他数据一致

其他字段头补充

辅助块

透明度信息
tRNS 透明度

74524e53

色彩空间信息
CHRM 主要色度和白点

6348524d

GAMA 图像伽玛

67414d41

iCCP 嵌入式 ICC 配置文件

69434350

sBIT 有效位

73424954

sRGB 标准 RGB 色彩空间

73524742

文本信息
tEXT 文本数据

74455874

zTXt 压缩文本数据

7a545874

iTXt 国际文本数据

69545874

其他信息
本底 背景颜色

624b4744

HIST 图像直方图

68495354

pHYs 物理像素尺寸

70485973

sPLT 建议调色板

73504c54

时间戳信息
tIME 图像最后修改时间

74494d45

隔行扫描 C语言代码描述

当通过慢速传输链路接收图像时,用户可以通过逐步显示隔行图像来提高感知性能。这意味着当接收到每个缩小的图像时,会根据目前接收到的数据显示完整图像的近似值。通过扩展每个接收像素以填充覆盖接收像素下方和右侧的尚未传输像素位置的矩形,可以获得一种简单但令人欣喜的效果。

/*
    variables declared and initialized elsewhere in the code:
        height, width
    functions or macros defined elsewhere in the code:
        visit(), min()
 */

int starting_row[7]  = { 0, 0, 4, 0, 2, 0, 1 };
int starting_col[7]  = { 0, 4, 0, 2, 0, 1, 0 };
int row_increment[7] = { 8, 8, 8, 4, 4, 2, 2 };
int col_increment[7] = { 8, 8, 4, 4, 2, 2, 1 };
int block_height[7]  = { 8, 8, 4, 4, 2, 2, 1 };
int block_width[7]   = { 8, 4, 4, 2, 2, 1, 1 };

int pass;
long row, col;
   
pass = 0;
while (pass < 7)
{
    row = starting_row[pass];
    while (row < height)
    {
        col = starting_col[pass];
        while (col < width)
        {
            visit(row, col,
                  min(block_height[pass], height - row),
                  min(block_width[pass], width - col));
            col = col + col_increment[pass];
        }
        row = row + row_increment[pass];
    }
    pass = pass + 1;
}

函数visit(row,column,height,width)获取下一个传输的像素,并使用像素指示的颜色绘制一个指定高度和宽度的矩形,其左上角位于指定的行和列。请注意,行和列是从左上角的 0,0 开始测量的。

如果查看器将接收到的图像与背景图像合并,则仅绘制接收到的像素位置可能更方便(visit()函数仅设置指定行和列的像素,而不是整个矩形)。随着新图像逐渐取代旧图像,这会产生“淡入”效果。这种方法的一个优点是可以在替换每个像素时进行适当的 alpha 或透明度处理。如果最终为这些位置接收到的像素完全或部分透明,则如上所述绘制矩形将覆盖稍后可能需要的背景图像像素。只有当背景图像没有存储在屏幕外的任何地方时,这才是一个问题。

libpng.org 上的类型十进制处理成十六进制显示

//例如文件类型头
(('137 80 78 71 13 10 26 10'.split(' ')).map(function(item){return (item*1).toString(16)})).join('')
// "89504e47da1aa"

生成图片代码

$image = new \Imagine\Gd\Imagine();
$size = new \Imagine\Image\Box(1,1);
ob_start();
//\Imagine\Image\ImageInterface::INTERLACE_LINE 为基准式
$image->create($size,(new Imagine\Image\Palette\RGB())->color('#000', 100)) ->interlace(\Imagine\Image\ImageInterface::INTERLACE_NONE )->show('png',['quality'=>100]);
$content = ob_get_contents();
ob_clean();
header_remove();
$png_interlace_none = base64_encode($content);

用的是php Imagine类库,参考php图片处理Imagine常用例子

处理成十六进制代码

$png_interlace_none = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAEElEQVQIHQEFAPr/AAAAAP8BBAEAp4/bgwAAAABJRU5ErkJggg==';
$png_interlace_line = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAFoEvQfAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAEElEQVQIHQEFAPr/AAAAAP8BBAEAp4/bgwAAAABJRU5ErkJggg==';

echo  'fie_length '.strlen($png_interlace_line).' '.dechex(strlen($png_interlace_line)).PHP_EOL;
echo  'interlace_none'.PHP_EOL;
$str = unpack('H*',base64_decode($png_interlace_none))[1];
for ($i=0;$i<strlen($str);$i=$i+16){
    echo substr($str,$i,16).PHP_EOL;
}

echo  'interlace_line'.PHP_EOL;
$str = unpack('H*',base64_decode($png_interlace_line))[1];
for ($i=0;$i<strlen($str);$i=$i+16){
    echo substr($str,$i,16).PHP_EOL;
}


参考

PNG文件格式详解
Progressive-display

原文

png 格式 初探

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值