java把png改为yuv图像_(转)图像解码之二——使用libpng解码png图片

4: png_read_info(png_ptr,

info_ptr);

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

b)查询图像信息

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

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函数来实现,例如如下代码:

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: png_set_read_user_transform_fn(png_ptr,

2: read_transform_fn);

read_transform_fn为用户自定义的数据转换函数。具体实现可以参考pngtest.c中的实现。

另外你可以通过png_set_user_transform_info告诉libpng你的转换函数的用户自定义数据结构和输出数据的详细信息,比如颜

色深度,颜色通道(channel)等等。你可能会问为什么要告诉libpng呢?libpng将会根据这些信息来更新png图片详细信息,后面会介绍。

定义如下:

1: png_set_user_transform_info(png_ptr, user_ptr,

2: user_depth, user_channels);

usr_ptr是用户自定义的数据结构,在用户自定义转换函数read_transform_fn中可以通过png_get_user_transform_ptr函数得到该数据结构,例如:

1: voidp read_user_transform_ptr =

2: png_get_user_transform_ptr(png_ptr);

d)更新png数据的详细信息

经过前面的设置png数据的图片信息肯定会有一些变化,则需要调用png_read_update_info函数更新图片的详细信息:

1: png_read_update_info(png_ptr, info_ptr);

该函数将会更新保存于info_ptr变量中的图片数据信息,然后可以再调用png_get_IHDR重新查询图片信息。

e)读取png数据

可以到用png_read_image函数,一次性把所有的数据读入内存,例如:

1: png_read_image(png_ptr, row_pointers);

也可以调用png_read_rows一次读入1行或多行到内存中,比如:

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数据,代码如下:

1:

2: png_read_end(png_ptr, info_ptr);

6、释放libpng的内存

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

1:

2: png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);

至此png数据解码,全部完成了。

总结:

通过上面的介绍,我们可以发现相对于libjpeg,libpng的扩展性非常好。我们基本上没有任何修改libpng库的需求,它的对外接口提供了足够的灵活性,允许我们扩展。从这个角度来讲,libpng库非常值得我们学习它的对外接口的定义。


版权声明:本文为weixin_30120049原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。