相关文章推荐
自信的数据线  ·  hive ...·  1 月前    · 

目录 (?) [-]

  1. libpng的数据结构
  2. libpng的使用
    1. 0判断是否为libpng数据
    2. 1初始化libpng
    3. 2创建图像信息png_infop变量
    4. 3设置错误返回点
    5. 4设置libpng的数据源
    6. 5png图像处理
      1. 高层处理
      2. 底层处理
    7. 6释放libpng的内存
  3. 总结

上文《 图像解码之一——使用libjpeg解码jpeg图片 》介绍了使用libjpeg解码jpeg图片。png图片应用也非常广泛,本文将会简单介绍怎样使用 开源libpng库 解码png图片。

libpng的数据结构

png_structp变量是在libpng初始化的时候创建,由libpng库内部使用,代表libpng的是调用上下文,库的使用者不应该对这个变量进行访问。调用libpng的API的时候,需要把这个参数作为第一个参数传入。

png_infop变量,初始化完成libpng之后,可以从libpng中获得该类型变量指针。这个变量保存了png图片数据的信息,库的使用者可以修 改和查阅该变量,比如:查阅图片信息,修改图片解码参数。在早期的版本中直接访问该变量的成员,最新的版本建议是通过API来访问这些成员。

libpng的使用

0、判断是否为libpng数据

这步是可选的,在利用libpng继续数据处理之前,可以调用png_sig_cmp函数来检查是否为png数据,请参阅 libpng手册 了解详细内容。

1、初始化libpng
[cpp] view plain
  1. /* Create and initialize the png_struct with the desired error handler
  2. * functions.  If you want to use the default stderr and longjump method,
  3. * you can supply NULL for the last three parameters.  We also supply the
  4. * the compiler header file version, so that we know if the application
  5. * was compiled with a compatible version of the library.  REQUIRED
  6. */
  7. png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
  8. 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
  1. png_structp png_ptr = png_create_read_struct_2
  2. (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
  3. user_error_fn, user_warning_fn, (png_voidp)
  4. user_mem_ptr, user_malloc_fn, user_free_fn)
2、创建图像信息——png_infop变量
[cpp] view plain
  1. /* Allocate/initialize the memory for image information.  REQUIRED. */
  2. info_ptr = png_create_info_struct(png_ptr);
  3. if (info_ptr == NULL)
  4. {
  5. png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
  6. return (ERROR);
  7. }

如前面所说,用户将会通过png_infop变量来获得图片的信息,设置图片解码参数等。

3、设置错误返回点

上文libjpeg解码jpeg图片中提到用setjmp/longjmp函数来处理异常。libpng库默认集成这种机制来完成异常处理,如下代码初始化错误返回点:

[cpp]
view plain
  1. /* Set error handling if you are using the setjmp/longjmp method (this is
  2. * the normal method of doing things with libpng).  REQUIRED unless you
  3. * set up your own error handlers in the png_create_read_struct() earlier.
  4. */
  5. if (setjmp(png_jmpbuf(png_ptr)))
  6. {
  7. /* Free all of the memory associated with the png_ptr and info_ptr */
  8. png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
  9. /* If we get here, we had a problem reading the file */
  10. return (ERROR);
  11. }

正如上面注释中提到情况,只有在初始化libpng的时候未指定用户自定义的错误处理函数情况下,才需要设置错误返回点。如果设置了用户自定义的错误处理函数,libpng将会调用用户自定义错误处理函数,而不会返回到这个调用点。

当libpng库出现错误的时候,libpng将会自动调用longjmp函数返回到这个点。在这个点我们可以进行必要的清理工作。

4、设置libpng的数据源

我在上文《 图像解码之一——使用libjpeg解码jpeg图片 》中提到,一个好的代码库应该能够运行用户输入各式各样的数据,而不能把输入数据定死。libpng在这方面做得非常的好,它提供了默认的文件输入流的支持,并且提供了用户自定义回调函数来完成png数据的输入。

对于文件流数据数据设置代码如下:

[cpp] view plain
  1. /* One of the following I/O initialization methods is REQUIRED */
  2. def streams /* PNG file I/O method 1 */
  3. /* Set up the input control if you are using standard C streams */
  4. png_init_io(png_ptr, fp);
用户自定义回调函数设置libpng数据源的代码如下:

如果你已经使用png_sig_cmp函数来检查了png数据,需要调用png_set_sig_bytes函数来告诉libpng库,这样库处理数据的时候将会跳过相应的数据,具体请参考 libpng手册

5、png图像处理

这步有两种设置方案一种称为高层处理,一种称为底层处理。

当用户的内存足够大,可以一次性读入所有的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
  1. /*
  2. * If you have enough memory to read in the entire image at once,
  3. * and you need to specify only transforms that can be controlled
  4. * with one of the PNG_TRANSFORM_* bits (this presently excludes
  5. * dithering, filling, setting background, and doing gamma
  6. * adjustment), then you can read the entire image (including
  7. * pixels) into the info structure with this call:
  8. */
  9. 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
  1. /* The call to png_read_info() gives us all of the information from the
  2. * PNG file before the first IDAT (image data chunk).  REQUIRED
  3. */
  4. png_read_info(png_ptr, info_ptr);

该函数将会把输入png数据的信息读入到info_ptr数据结构中。

b)查询图像信息

前面提到png_read_info将会把输入png数据的信息读入到info_ptr数据结构中,接下来需要调用API查询该信息。

[cpp] view plain
  1. png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
  2. &interlace_type, int_p_NULL, int_p_NULL);

c)设置png输出参数(转换参数)

这步非常重要,用户可以指定输出数据的格式,比如RGB888,ARGB8888等等输出数据格式。通过png_set_xxxxx函数来实现,例如如下代码:

[cpp] view plain
  1. // expand images of all color-type and bit-depth to 3x8 bit RGB images
  2. // let the library process things like alpha, transparency, background
  3. if (bit_depth == 16)
  4. png_set_strip_16(png_ptr);
  5. if (color_type == PNG_COLOR_TYPE_PALETTE)
  6. png_set_expand(png_ptr);
  7. if (bit_depth<8)
  8. png_set_expand(png_ptr);
  9. if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
  10. png_set_expand(png_ptr);
  11. if (color_type == PNG_COLOR_TYPE_GRAY ||
  12. color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
  13. png_set_gray_to_rgb(png_ptr);
如上代码将会把图像转换成RGB888的数据格式。这种转换函数还很多,请参阅libpng手册了解他们的作用。 虽然有很多设置输出参数的函数可以调用,但是用户的需求是无限的,很多输出格式libpng并不是原生支持的,比如YUV565,RGB565,YUYV 等等。幸好libpng提供了自定义转换函数的功能,可以让用户注册转换回调函数给libpng库,在libpng对输出数据进行转换的时候,先对 png_set_xxxxx函数设置的参数进行转换,最后将会调用用户自定义的转换函数进行转换。
  1. for (y = 0; y < height; y++)
  2. {
  3. png_read_rows(png_ptr, &row_pointers[y], png_bytepp_NULL, 1);
  4. }

f)结束读取数据

通过png_read_end结束读取png数据,代码如下:

[cpp] view plain
  1. /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */
  2. png_read_end(png_ptr, info_ptr);
6、释放libpng的内存

调用png_destroy_read_struct来释放libpng的内存,代码如下:

[cpp]
view plain
  1. /* Clean up after the read, and free any memory allocated - REQUIRED */
  2. 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为自定义的