> 技术文档 > 【开源库 | libpng】使用 libpng 读写 png 文件详细教程(附带源码)

【开源库 | libpng】使用 libpng 读写 png 文件详细教程(附带源码)


😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍 🍭
😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你——泰戈尔🍭
⏰发布时间⏰:

本文未经允许,不得转发!!!

目录

  • 🎄一、概述
  • 🎄二、libpng 读取 png 图片文件步骤
    • ✨2.1、打开文件并检查是否png文件
    • ✨2.2、初始化libpng的数据结构 :png_ptr, info_ptr
    • ✨2.3、设置错误返回点
    • ✨2.4、初始化 io
    • ✨2.5、读取png文件信息
    • ✨2.6、读取实际的rgb数据
    • ✨2.7、释放一些相关的资源和内存
  • 🎄三、libpng 写入 png 图片文件步骤
    • ✨3.1、1、打开要写入的png文件
    • ✨2.2、初始化libpng的数据结构 :png_ptr, info_ptr
    • ✨2.3、设置错误返回点
    • ✨2.4、初始化 io
    • ✨2.5、设置图片属性
    • ✨2.6、写文件头
    • ✨2.7、写入实际的rgb数据
    • ✨2.8、写入文件尾
    • ✨2.9、释放一些相关的资源和内存
  • 🎄四、总结

在这里插入图片描述

【开源库 | libpng】使用 libpng 读写 png 文件详细教程(附带源码)

🎄一、概述

前面的文章介绍过怎么将 libpng 库进行编译、交叉编译。需要了解的可以参考:zlib-1.2.11库、libpng-1.6.36库编译及交叉编译。

这篇文章主要介绍怎么使用 libpng 库读写png图片文件。如果需要了解更多的关于 libpng 库的操作,可以看看 libpng 库源码中的 example.c 文件。


【开源库 | libpng】使用 libpng 读写 png 文件详细教程(附带源码)

🎄二、libpng 读取 png 图片文件步骤

✨2.1、打开文件并检查是否png文件

libpng 读取 png 图片文件的第一个步骤就是打开 png 图片,因为png图片文件最前面有8个字节的png标识,所以先使用png_sig_cmp函数检测一下当前文件是否是 png 文件。

// 1、打开文件并检查是否png文件/* Open the prospective PNG file. */if ((fp = fopen(file_name, \"rb\")) == NULL) goto read_end;/* Read in some of the signature bytes. */if (fread(buf, 1, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK) goto read_end;/* Compare the first PNG_BYTES_TO_CHECK bytes of the signature. * Return nonzero (true) if they match. */if (0 != png_sig_cmp((png_const_bytep)buf, 0, PNG_BYTES_TO_CHECK)) goto read_end;

✨2.2、初始化libpng的数据结构 :png_ptr, info_ptr

libpng库读取文件时需要用到两个指针png_structp, png_infop,分别标识 内部表述结构体png图片信息结构体,第二步需要初始化这两结构体。

// 2、初始化libpng的数据结构 :png_ptr, info_ptrpng_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);if (png_ptr == NULL){ goto read_end;}png_infop info_ptr = png_create_info_struct(png_ptr);if (info_ptr == NULL){ goto read_end;}

✨2.3、设置错误返回点

// 3、设置错误返回点if (setjmp(png_jmpbuf(png_ptr))){ /* Free all of the memory associated with the png_ptr and info_ptr. */ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); if (NULL != fp) { fclose(fp); fp = NULL; } /* If we get here, we had a problem reading the file. */ return -1; }

✨2.4、初始化 io

初始化 io, 把png结构体和文件流io进行绑定 。

// 4、初始化 io, 把png结构体和文件流io进行绑定png_init_io(png_ptr, fp);

✨2.5、读取png文件信息

读取文件信息,包括颜色类型、位深度、宽、高、通道数量等。

位深度,指 ARGB 单个通道的颜色占用了多少个bit,如 RGB888 的位深度是8,RGB555的位深度是5。

通道数量,指多少个颜色通道,ARGB是4,RGB是3。

// 5.读取文件信息png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0);int color_type = png_get_color_type(png_ptr, info_ptr); // 颜色类型p_pic_data->bit_depth = png_get_bit_depth(png_ptr, info_ptr); // 位深度p_pic_data->width = png_get_image_width(png_ptr, info_ptr); // 宽p_pic_data->height = png_get_image_height(png_ptr, info_ptr); // 高p_pic_data->channels = png_get_channels(png_ptr, info_ptr); // 通道数量

✨2.6、读取实际的rgb数据

libpng 库读取rgb数据的函数有如下几个:
png_get_rowbytes:获取每一行的 rgb 数据;
png_get_rows:获取整个图片的 rgb 数据;
png_read_row:读取一行的 rgb 数据;
png_read_rows:读取多行的 rgb 数据;
png_read_image:读取整个图片的 rgb 数据

// 6.读取实际的rgb数据int i, j, k;int size, pos = 0;png_bytepp row_pointers; // 实际存储rgb数据的bufrow_pointers = png_get_rows(png_ptr, info_ptr); // 也可以分别每一行获取png_get_rowbytes();size = p_pic_data->width * p_pic_data->height * p_pic_data->channels; // 申请内存先计算空间if (p_pic_data->channels == 4 || color_type == PNG_COLOR_TYPE_RGB_ALPHA) // 颜色深度32位,带有 Alpha 通道{ const int stride = 4; // 跨度,一个像素表示的字节数 p_pic_data->rgba = (png_bytep)malloc(size); if (NULL == p_pic_data->rgba) { printf(\"malloc rgba failed ...\\n\"); goto read_end; } // 从row_pointers里读出实际的rgba数据出来 for (i = 0; i < p_pic_data->height; i++) { for (j = 0; j < p_pic_data->width * stride; j += stride) { for (k = 0; k < stride; k++) { p_pic_data->rgba[pos++] = row_pointers[i][j + k]; } } }}

✨2.7、释放一些相关的资源和内存

读取完成后,需要释放相关的内存和资源。

read_end: // 释放一些相关的资源和内存 if (NULL != fp) { fclose(fp); fp = NULL; } if (png_ptr != NULL) { if (info_ptr == NULL) png_destroy_read_struct(&png_ptr, NULL, NULL); else png_destroy_read_struct(&png_ptr, &info_ptr, NULL); } return ret;

【开源库 | libpng】使用 libpng 读写 png 文件详细教程(附带源码)

🎄三、libpng 写入 png 图片文件步骤

✨3.1、1、打开要写入的png文件

首先,打开要写入的 png 文件,后面libpng库也会用到这个文件指针。

// 1、打开要写入的png文件if ((fp = fopen(file_name, \"wb+\")) == NULL) goto write_end;

✨2.2、初始化libpng的数据结构 :png_ptr, info_ptr

libpng库写文件时需要用到两个指针png_structp, png_infop,分别标识 内部表述结构体png图片信息结构体,第二步需要初始化这两结构体。

注意,这里使用的是 png_create_write_struct ,与读取时有区别。

// 2、初始化libpng的数据结构 :png_ptr, info_ptrpng_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);if (png_ptr == NULL){ goto write_end;}png_infop info_ptr = png_create_info_struct(png_ptr);if (info_ptr == NULL){ goto write_end;}

✨2.3、设置错误返回点

// 3、设置错误返回点if (setjmp(png_jmpbuf(png_ptr))){ goto write_end;}

✨2.4、初始化 io

初始化 io, 把png结构体和文件流io进行绑定 。

// 4、初始化 io, 把png结构体和文件流io进行绑定png_init_io(png_ptr, fp);

✨2.5、设置图片属性

设置图片属性:颜色类型、宽、高、位深等。

// 5、设置图片属性int color_type = PNG_COLOR_TYPE_RGB_ALPHA;int interlace = 0;png_set_IHDR(png_ptr, info_ptr, p_pic_data->width, p_pic_data->height, p_pic_data->bit_depth, color_type, (!interlace) ? PNG_INTERLACE_NONE : PNG_INTERLACE_ADAM7, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

✨2.6、写文件头

// 6、写文件头png_write_info(png_ptr, info_ptr);

✨2.7、写入实际的rgb数据

libpng 库写入rgb数据的函数有如下几个:
png_write_row:写入一行的 rgb 数据;
png_write_rows:写入多行的 rgb 数据;
png_write_image:写入整个图片的 rgb 数据;

// 7、写入图片信息png_bytep p_row_pointers;int i = 0;for (i = 0; i < p_pic_data->height; i++){ p_row_pointers = (png_bytep)(p_pic_data->rgba + (i * p_pic_data->width * p_pic_data->channels)); png_write_rows(png_ptr, &p_row_pointers, 1);}

✨2.8、写入文件尾

// 8、写入文件尾 png_write_end(png_ptr, info_ptr);

✨2.9、释放一些相关的资源和内存

写入完成后,需要释放相关的内存和资源。

write_end: // 释放一些相关的资源和内存 if (NULL != fp) { fclose(fp); fp = NULL; } if (png_ptr != NULL) { if (info_ptr == NULL) png_destroy_read_struct(&png_ptr, NULL, NULL); else png_destroy_read_struct(&png_ptr, &info_ptr, NULL); } return ret;

【开源库 | libpng】使用 libpng 读写 png 文件详细教程(附带源码)

🎄四、总结

本文先介绍了使用 libpng 库读取png文件的步骤,然后又介绍了使用 libpng 库写入png文件的步骤,最后给出了源码地址。

根据上面的步骤,你应该可以自己写一个读写png图片的 .c 源文件了,如果还有问题可以下载下面源码,本文源码地址:https://download.csdn.net/download/wkd_007/91134800。

在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

参考:
libpng库编码图片为png