目录
(?)
[-]
-
libpng的数据结构
-
libpng的使用
-
0判断是否为libpng数据
-
1初始化libpng
-
2创建图像信息png_infop变量
-
3设置错误返回点
-
4设置libpng的数据源
-
5png图像处理
-
高层处理
-
底层处理
-
6释放libpng的内存
-
总结
上文《
图像解码之一——使用libjpeg解码jpeg图片
》介绍了使用libjpeg解码jpeg图片。png图片应用也非常广泛,本文将会简单介绍怎样使用
开源libpng库
解码png图片。
png_structp变量是在libpng初始化的时候创建,由libpng库内部使用,代表libpng的是调用上下文,库的使用者不应该对这个变量进行访问。调用libpng的API的时候,需要把这个参数作为第一个参数传入。
png_infop变量,初始化完成libpng之后,可以从libpng中获得该类型变量指针。这个变量保存了png图片数据的信息,库的使用者可以修 改和查阅该变量,比如:查阅图片信息,修改图片解码参数。在早期的版本中直接访问该变量的成员,最新的版本建议是通过API来访问这些成员。
这步是可选的,在利用libpng继续数据处理之前,可以调用png_sig_cmp函数来检查是否为png数据,请参阅
libpng手册
了解详细内容。
[cpp]
view plain
-
-
-
-
-
-
-
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
-
png_voidp user_error_ptr, user_error_fn, user_warning_fn);
初始化libpng的时候,用户可以指定自定义错误处理函数,如果不需要指定自定义错误处理函数,则传NULL即可。 png_create_read_struct函数返回一个png_structp变量,前面已经提到该变量不应该被用户访问,应该在以后调用 libpng的函数时传递给libpng库。
如果你需要提供自定义内存管理模块则需要调用png_create_read_struct_2来完成对libpng的初始化:
[cpp]
view plain
-
png_structp png_ptr = png_create_read_struct_2
-
(PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
-
user_error_fn, user_warning_fn, (png_voidp)
-
user_mem_ptr, user_malloc_fn, user_free_fn)
[cpp]
view plain
-
-
info_ptr = png_create_info_struct(png_ptr);
-
if
(info_ptr == NULL)
-
{
-
png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
-
return
(ERROR);
-
}
如前面所说,用户将会通过png_infop变量来获得图片的信息,设置图片解码参数等。
上文libjpeg解码jpeg图片中提到用setjmp/longjmp函数来处理异常。libpng库默认集成这种机制来完成异常处理,如下代码初始化错误返回点:
[cpp]
view plain
-
-
-
-
-
if
(setjmp(png_jmpbuf(png_ptr)))
-
{
-
-
png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
-
-
return
(ERROR);
-
}
正如上面注释中提到情况,只有在初始化libpng的时候未指定用户自定义的错误处理函数情况下,才需要设置错误返回点。如果设置了用户自定义的错误处理函数,libpng将会调用用户自定义错误处理函数,而不会返回到这个调用点。
当libpng库出现错误的时候,libpng将会自动调用longjmp函数返回到这个点。在这个点我们可以进行必要的清理工作。
我在上文《
图像解码之一——使用libjpeg解码jpeg图片
》中提到,一个好的代码库应该能够运行用户输入各式各样的数据,而不能把输入数据定死。libpng在这方面做得非常的好,它提供了默认的文件输入流的支持,并且提供了用户自定义回调函数来完成png数据的输入。
对于文件流数据数据设置代码如下:
[cpp]
view plain
-
-
def streams
-
-
png_init_io(png_ptr, fp);
用户自定义回调函数设置libpng数据源的代码如下:
如果你已经使用png_sig_cmp函数来检查了png数据,需要调用png_set_sig_bytes函数来告诉libpng库,这样库处理数据的时候将会跳过相应的数据,具体请参考
libpng手册
。
这步有两种设置方案一种称为高层处理,一种称为底层处理。
当用户的内存足够大,可以一次性读入所有的png数据,并且输出数据格式为如下libpng预定义数据类型时,可以用高层函数,下libpng预定义数据类型为:
PNG_TRANSFORM_IDENTITY No transformation
PNG_TRANSFORM_STRIP_16 Strip 16-bit samples to
8 bits
PNG_TRANSFORM_STRIP_ALPHA Discard the alpha channel
PNG_TRANSFORM_PACKING Expand 1, 2 and 4-bit
samples to bytes
PNG_TRANSFORM_PACKSWAP Change order of packed
pixels to LSB first
PNG_TRANSFORM_EXPAND Perform set_expand()
PNG_TRANSFORM_INVERT_MONO Invert monochrome images
PNG_TRANSFORM_SHIFT Normalize pixels to the
sBIT depth
PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA
to BGRA
PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA
to AG
PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity
to transparency
PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples
PNG_TRANSFORM_GRAY_TO_RGB Expand grayscale samples
to RGB (or GA to RGBA)
高层读取函数如下:
[cpp]
view plain
-
-
-
-
-
-
-
-
-
png_read_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL);
该函数将会把所有的图片数据解码到info_ptr
数据结构
中。png_transforms为整型参数,为上面libpng预定义的数据类型进行or操作得到。调用了该函数,就不可以再调用png_set_transform函数来设置输出数据。
该函数相当于调用底层函数(下文将会介绍)如下调用顺序:
a)调用png_read_info函数获得图片信息。
b)根据png_transforms所指示的,调用png_set_transform设置输出格式转换的函数。
c)调用png_read_image来解码整个图片的数据到内存。
d)调用png_read_end结束图片解码。
当你调用png_read_png之后,则可以调用如下函数得到png数据:
[cpp]
view plain
-
-
-
-
png_read_info(png_ptr, info_ptr);
该函数将会把输入png数据的信息读入到info_ptr数据结构中。
b)查询图像信息
前面提到png_read_info将会把输入png数据的信息读入到info_ptr数据结构中,接下来需要调用API查询该信息。
[cpp]
view plain
-
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
-
&interlace_type, int_p_NULL, int_p_NULL);
c)设置png输出参数(转换参数)
这步非常重要,用户可以指定输出数据的格式,比如RGB888,ARGB8888等等输出数据格式。通过png_set_xxxxx函数来实现,例如如下代码:
[cpp]
view plain
-
-
-
if
(bit_depth == 16)
-
png_set_strip_16(png_ptr);
-
if
(color_type == PNG_COLOR_TYPE_PALETTE)
-
png_set_expand(png_ptr);
-
if
(bit_depth<8)
-
png_set_expand(png_ptr);
-
if
(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
-
png_set_expand(png_ptr);
-
if
(color_type == PNG_COLOR_TYPE_GRAY ||
-
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
-
png_set_gray_to_rgb(png_ptr);
如上代码将会把图像转换成RGB888的数据格式。这种转换函数还很多,请参阅libpng手册了解他们的作用。
虽然有很多设置输出参数的函数可以调用,但是用户的需求是无限的,很多输出格式libpng并不是原生支持的,比如YUV565,RGB565,YUYV 等等。幸好libpng提供了自定义转换函数的功能,可以让用户注册转换回调函数给libpng库,在libpng对输出数据进行转换的时候,先对 png_set_xxxxx函数设置的参数进行转换,最后将会调用用户自定义的转换函数进行转换。
-
for
(y = 0; y < height; y++)
-
{
-
png_read_rows(png_ptr, &row_pointers[y], png_bytepp_NULL, 1);
-
}
f)结束读取数据
通过png_read_end结束读取png数据,代码如下:
[cpp]
view plain
-
-
png_read_end(png_ptr, info_ptr);
调用png_destroy_read_struct来释放libpng的内存,代码如下:
[cpp]
view plain
-
-
png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
通过上面的介绍,我们可以发现相对于libjpeg,libpng的扩展性非常好。我们基本上没有任何修改libpng库的需求,它的对外接口提供了足够的灵活性,允许我们扩展。从这个角度来讲,libpng库非常值得我们学习它的对外接口的定义。
使用可以参考:
android5.1源码 bootable/recovery/minui/resources.c中函数
int res_create_multi_display_surface(const char* name, int* frames, gr_surface** pSurface)
http://www.cnblogs.com/xiaoxiaoboke/archive/2012/02/13/2349765.html
自己的实现
1 unsigned int component(
png
_const_bytep row,
png
_uint_32 x, unsigned int c, unsigned int bit_depth, unsigned int channels) {
2
png
_uint_32 bit_offset_hi = bit_depth * ((x >> 6...
JPEG
(Joint Photographic Experts Group)
JPEG
是
JPEG
标准的产物,该标准由国际标准化组织(ISO)制订,是面向连续色调静止
图像
的一种压缩标准。
JPEG
格式是最常用的
图像
文件格式,后缀名为.
jpg
或.
jpeg
。——百度百科
JPEG
图片
格式组成部分:SOI(文件头)+APP0(
图像
识别信息)+ DQT
1.
PNG
文件格式
PNG
图像
格式文件(或者称为数据流)由一个8字节的
PNG
文件署名(
PNG
file signature)域和按照特定结构组织的3个以上的数据块(chunk)组成。
PNG
定义了两种类型的数据块,一种是称为关键数据块(critical chunk),这是标准的数据块,另一种叫做辅助数据块(ancillary chunks),这是可选的数据块。
libpng
是一款C语言编写的比较底层的读写
PNG
文件的跨平台的库。借助它,你可以轻松读写
PNG
文件的每一行像素。
因为
PNG
文件是经过压缩而且格式复杂的图形文件(有的
PNG
文件甚至像GIF文件一样带动画效果)
而且
PNG
可以是带透明通道的真彩色
图像
、不带透明通道的真彩色
图像
、索引颜色、灰度颜色等各种格式,如果大家都自己写程序分析
PNG
文件就会显得很麻烦、很累。因此,通过
使用
libpng
你就能直接...
libpng
的库文件,
lib
文件,dll文件,
png
.
lib
libpng
d.
lib
z
lib
.
lib
z
lib
d.
lib
libpng
15d.dll z
lib
1d.dll
png
.h
png
conf.h zconf.h z
lib
.h
首先了解
png
,bmp文件格式的特点,本篇不详细介绍。
bmp
图片
是微软的
图片
格式,就是原始的像素数据加上bmp文件头组成,像素数据是倒装的,即第一个像素的(RGB)三个字节再原始文件的最后。
png
是原始数据压缩后加入
png
格式文件描述。
下载
libpng
和z
lib
的源码,放在同一个目录中
由于
libpng
实际上
使用
的是z
lib
的算法,
libpng
是zl
跟上一篇解析 显示解析并显示 bmp 类似,这次的对象是 24位(带rgba)的
png
.
不同的是 bmp 格式比较简单,是自己写代码解析的.
png
格式比较复杂,
使用
了
libpng
.
在此快速记录。
libpng
关键函数是
png
_get_rows() ,能取得
png
的 二维
图像
数据,然后自己想办法搞到自己 new 出来的 内存里即可
纯试验,没处理泄露,没考虑代
【2】解压源码并进入解压后的目录
【3】配置
./configure --prefix=/opt/
lib
decode --exec-prefix=/opt/
lib
decode --enable-shared --enable-static -build=i386 -host=arm
注:/opt/
lib
decode为自定义的