利用libpng中的函数读写png文件
来源:互联网 发布:ubuntu grub 修复启动 编辑:程序博客网 时间:2024/06/05 22:47
libpng 库的源码包中有个 example.c ,里面包含PNG文件读/写的示例代码,参考示例代码和注释(虽然是英文的),可以了解大致的用法。
以下是读取PNG图片的图像数据的代码,使用前还需要按自己的需求补充剩余代码。
#include <png.h>#define PNG_BYTES_TO_CHECK 4int load_png_image( const char *filepath, /* 其它参数 */ ){ FILE *fp; png_structp png_ptr; png_infop info_ptr; png_bytep* row_pointers; char buf[PNG_BYTES_TO_CHECK]; int w, h, x, y, temp, color_type; fp = fopen( filepath, "rb" ); if( fp == NULL ) { return /* 返回值 */; } png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ); info_ptr = png_create_info_struct( png_ptr ); setjmp( png_jmpbuf(png_ptr) ); /* 读取PNG_BYTES_TO_CHECK个字节的数据 */ temp = fread( buf, 1, PNG_BYTES_TO_CHECK, fp ); /* 若读到的数据并没有PNG_BYTES_TO_CHECK个字节 */ if( temp < PNG_BYTES_TO_CHECK ) { fclose(fp); png_destroy_read_struct( &png_ptr, &info_ptr, 0); return /* 返回值 */; } /* 检测数据是否为PNG的签名 */ temp = png_sig_cmp( (png_bytep)buf, (png_size_t)0, PNG_BYTES_TO_CHECK ); /* 如果不是PNG的签名,则说明该文件不是PNG文件 */ if( temp != 0 ) { fclose(fp); png_destroy_read_struct( &png_ptr, &info_ptr, 0); return /* 返回值 */; } /* 复位文件指针 */ rewind( fp ); /* 开始读文件 */ png_init_io( png_ptr, fp ); /* 读取PNG图片信息 */ png_read_png( png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0 ); /* 获取图像的色彩类型 */ color_type = png_get_color_type( png_ptr, info_ptr ); /* 获取图像的宽高 */ w = png_get_image_width( png_ptr, info_ptr ); h = png_get_image_height( png_ptr, info_ptr ); /* 获取图像的所有行像素数据,row_pointers里边就是rgba数据 */ row_pointers = png_get_rows( png_ptr, info_ptr ); /* 根据不同的色彩类型进行相应处理 */ switch( color_type ) { case PNG_COLOR_TYPE_RGB_ALPHA: for( y=0; y<h; ++y ) { for( x=0; x<w*4; ) { /* 以下是RGBA数据,需要自己补充代码,保存RGBA数据 */ /* 目标内存 */ = row_pointers[y][x++]; // red /* 目标内存 */ = row_pointers[y][x++]; // green /* 目标内存 */ = row_pointers[y][x++]; // blue /* 目标内存 */ = row_pointers[y][x++]; // alpha } } break; case PNG_COLOR_TYPE_RGB: for( y=0; y<h; ++y ) { for( x=0; x<w*3; ) { /* 目标内存 */ = row_pointers[y][x++]; // red /* 目标内存 */ = row_pointers[y][x++]; // green /* 目标内存 */ = row_pointers[y][x++]; // blue } } break; /* 其它色彩类型的图像就不读了 */ default: fclose(fp); png_destroy_read_struct( &png_ptr, &info_ptr, 0); return /* 返回值 */; } png_destroy_read_struct( &png_ptr, &info_ptr, 0); return 0;}
以下是生成png图片文件的代码,也就是照搬了 example.c 里的 write_png() 的代码,稍微翻译了主要的注释。
/* 写入 png 文件 */void write_png(char *file_name /* , ... 其他图像信息相关的参数 ... */){ FILE *fp; png_structp png_ptr; png_infop info_ptr; png_colorp palette; /* 打开需要写入的文件 */ fp = fopen(file_name, "wb"); if (fp == NULL) return (ERROR); /* 创建并初始化 png_struct 及其所需的错误处理函数,如果你想使用默 * 认的 stderr 和 longjump() 方法,你可以将最后三个参数设为 NULL, * 在使用动态链接库的情况下,我们也会检测函数库版本是否与在编译时 * 使用的版本是否兼容。(必要) */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, png_voidp user_error_ptr, user_error_fn, user_warning_fn); if (png_ptr == NULL) { fclose(fp); return (ERROR); } /* 分配内存并初始化图像信息数据。(必要)*/ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); png_destroy_write_struct(&png_ptr, NULL); return (ERROR); } /* 设置错误处理。如果你在调用 png_create_write_struct() 时没 * 有设置错误处理函数,那么这段代码是必须写的。*/ if (setjmp(png_jmpbuf(png_ptr))) { /* 如果程序跑到这里了,那么写入文件时出现了问题 */ fclose(fp); png_destroy_write_struct(&png_ptr, &info_ptr); return (ERROR); } /* 下面的 I/O 初始化函数有一个是必需的 */#ifdef streams /* I/O 初始化方法 1 */ /* 设置输出控制,如果你使用的是 C 的标准 I/O 流 */ png_init_io(png_ptr, fp);#else no_streams /* I/O 初始化方法 2 */ /* 如果你是要替换写入函数,而不想调用 png_init_io(),那么需要指定三个参数: * I/O相关的指针,假设为 user_io_ptr * 自定义的写入函数,假设为 user_write_fn * 自定义的I/O刷新函数,假设为 user_IO_flush_function */ png_set_write_fn(png_ptr, (void *)user_io_ptr, user_write_fn, user_IO_flush_function); /* 你需要在某个地方构造一个可用 user_io_ptr 给回调函数使用 */#endif no_streams /* 只能选择一种初始化方式 */#ifdef hilevel /* 这是一种简单的做法,前提是你已经已经有了全部图像信息。 * 你可以使用 | 运算符合并多个 PNG_TRANSFORM 标志到这个 * png_transforms 整型变量中 */ png_write_png(png_ptr, info_ptr, png_transforms, NULL);#else /* 这是一种复杂的做法 */ /* (必需)在这里设置图像的信息,宽度、高度的上限是 2^31。 * bit_depth 取值必需是 1、2、4、8 或者 16, 但是可用的值也依赖于 color_type。 * color_type 可选值有: PNG_COLOR_TYPE_GRAY、PNG_COLOR_TYPE_GRAY_ALPHA、 * PNG_COLOR_TYPE_PALETTE、PNG_COLOR_TYPE_RGB、PNG_COLOR_TYPE_RGB_ALPHA。 * interlace 可以是 PNG_INTERLACE_NONE 或 PNG_INTERLACE_ADAM7, * 而 compression_type 和 filter_type 目前必需是 PNG_COMPRESSION_TYPE_BASE * 和 and PNG_FILTER_TYPE_BASE。 */ png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_???, PNG_INTERLACE_????, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); /* 如果要调色板的话,在这里设置调色板,对于索引图像,这个是必需的 */ palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))); /* ... 设置调色板的颜色集 ... */ png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); /* 在销毁 png 结构前的这段期间,你不能释放调色板,因为 png_set_PLTE * 只是在你分配的调色板上建立引用,并未另外建立副本 */ /* 标注位(sBIT)块 */ png_color_8 sig_bit; /* 如果我们处理的是灰度图像,则这样 */ sig_bit.gray = true_bit_depth; /* 否则,我们处理的是彩色图像 */ sig_bit.red = true_red_bit_depth; sig_bit.green = true_green_bit_depth; sig_bit.blue = true_blue_bit_depth; /* 如果这个图像有 alpha 通道 */ sig_bit.alpha = true_alpha_bit_depth; png_set_sBIT(png_ptr, info_ptr, &sig_bit); /* (可选)如果你怀疑图像伽马值的正确性 */ png_set_gAMA(png_ptr, info_ptr, gamma); /* (可选)写注释文本到图像里 */ { png_text text_ptr[3]; char key0[]="Title"; char text0[]="Mona Lisa"; text_ptr[0].key = key0; text_ptr[0].text = text0; text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE; text_ptr[0].itxt_length = 0; text_ptr[0].lang = NULL; text_ptr[0].lang_key = NULL; char key1[]="Author"; char text1[]="Leonardo DaVinci"; text_ptr[1].key = key1; text_ptr[1].text = text1; text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE; text_ptr[1].itxt_length = 0; text_ptr[1].lang = NULL; text_ptr[1].lang_key = NULL; char key2[]="Description"; char text2[]="<long text>"; text_ptr[2].key = key2; text_ptr[2].text = text2; text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt; text_ptr[2].itxt_length = 0; text_ptr[2].lang = NULL; text_ptr[2].lang_key = NULL; png_set_text(write_ptr, write_info_ptr, text_ptr, 3); } /* Other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs */ /* Note that if sRGB is present the gAMA and cHRM chunks must be ignored * on read and, if your application chooses to write them, they must * be written in accordance with the sRGB profile */ /* 写入文件头部信息(必需) */ png_write_info(png_ptr, info_ptr); /* If you want, you can write the info in two steps, in case you need to * write your private chunk ahead of PLTE: * * png_write_info_before_PLTE(write_ptr, write_info_ptr); * write_my_chunk(); * png_write_info(png_ptr, info_ptr); * * However, given the level of known- and unknown-chunk support in 1.2.0 * and up, this should no longer be necessary. */ /* Once we write out the header, the compression type on the text * chunk gets changed to PNG_TEXT_COMPRESSION_NONE_WR or * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again * at the end. */ /* Set up the transformations you want. Note that these are * all optional. Only call them if you want them. */ /* Invert monochrome pixels */ png_set_invert_mono(png_ptr); /* Shift the pixels up to a legal bit depth and fill in * as appropriate to correctly scale the image. */ png_set_shift(png_ptr, &sig_bit); /* Pack pixels into bytes */ png_set_packing(png_ptr); /* Swap location of alpha bytes from ARGB to RGBA */ png_set_swap_alpha(png_ptr); /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into * RGB (4 channels -> 3 channels). The second parameter is not used. */ png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); /* Flip BGR pixels to RGB */ png_set_bgr(png_ptr); /* Swap bytes of 16-bit files to most significant byte first */ png_set_swap(png_ptr); /* Swap bits of 1, 2, 4 bit packed pixel formats */ png_set_packswap(png_ptr); /* 启用交错处理,如果你没有使用 png_write_image() */ if (interlacing != 0) number_passes = png_set_interlace_handling(png_ptr); else number_passes = 1; /* 这是最简单的图像写入方法。(你或许有不同的内存布局,因此你需要选择一个最适合你的方法) * 如果你自己不是逐行写入,则需要使用第一种方法。 */ png_uint_32 k, height, width; /* 在这个示例代码中,"image" 是一个一维的字节数组(每个元素占一个字节空间) */ png_byte image[height*width*bytes_per_pixel]; png_bytep row_pointers[height]; if (height > PNG_UINT_32_MAX/(sizeof (png_bytep))) png_error (png_ptr, "Image is too tall to process in memory"); /* 将这些像素行指针指向你的 "image" 字节数组中对应的位置,即:指向每行像素的起始处 */ for (k = 0; k < height; k++) row_pointers[k] = image + k*width*bytes_per_pixel; /* 必需在下面的输出方式中选择一个 */#ifdef entire /* 一次调用就将整个图像写进文件 */ png_write_image(png_ptr, row_pointers); /* 其他的写出方式:交错写出 */#else no_entire /* 用一个或多个扫描线写出图像数据 */ /* 扫描次数为 1 的是非交错的图像,其它的则是交错图像。*/ for (pass = 0; pass < number_passes; pass++) { /* 一次性写几行 */ png_write_rows(png_ptr, &row_pointers[first_row], number_of_rows); /* 如果你一次性只写一行像素,可以用下面的代码 */ for (y = 0; y < height; y++) png_write_rows(png_ptr, &row_pointers[y], 1); }#endif no_entire /*只能选择一种输出方式 */ /* You can write optional chunks like tEXt, zTXt, and tIME at the end * as well. Shouldn't be necessary in 1.2.0 and up as all the public * chunks are supported and you can use png_set_unknown_chunks() to * register unknown chunks into the info structure to be written out. */ /* 必需调用这个函数完成写入文件其余部分 */ png_write_end(png_ptr, info_ptr);#endif hilevel /* If you png_malloced a palette, free it here (don't free info_ptr->palette, * as recommended in versions 1.0.5m and earlier of this example; if * libpng mallocs info_ptr->palette, libpng will free it). If you * allocated it with malloc() instead of png_malloc(), use free() instead * of png_free(). */ png_free(png_ptr, palette); palette = NULL; /* Similarly, if you png_malloced any data that you passed in with * png_set_something(), such as a hist or trans array, free it here, * when you can be sure that libpng is through with it. */ png_free(png_ptr, trans); trans = NULL; /* Whenever you use png_free() it is a good idea to set the pointer to * NULL in case your application inadvertently tries to png_free() it * again. When png_free() sees a NULL it returns without action, thus * avoiding the double-free security problem. */ /* 写完后清理并释放已分配的内存 */ png_destroy_write_struct(&png_ptr, &info_ptr); /* 关闭文件 */ fclose(fp); /* That's it */ return (OK);}
删掉那些可选的代码,write_png() 的主要代码也就这些:
/* 写入 png 文件 */void write_png(char *file_name /* , ... 其他图像信息相关的参数 ... */){ FILE *fp; png_structp png_ptr; png_infop info_ptr; png_colorp palette; /* 打开需要写入的文件 */ fp = fopen(file_name, "wb"); if (fp == NULL) return (ERROR); /* 创建并初始化 png_struct 及其所需的错误处理函数,如果你想使用默 * 认的 stderr 和 longjump() 方法,你可以将最后三个参数设为 NULL, * 在使用动态链接库的情况下,我们也会检测函数库版本是否与在编译时 * 使用的版本是否兼容。(必要) */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fclose(fp); return (ERROR); } /* 分配内存并初始化图像信息数据。(必要)*/ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); png_destroy_write_struct(&png_ptr, NULL); return (ERROR); } /* 设置错误处理。如果你在调用 png_create_write_struct() 时没 * 有设置错误处理函数,那么这段代码是必须写的。*/ if (setjmp(png_jmpbuf(png_ptr))) { /* 如果程序跑到这里了,那么写入文件时出现了问题 */ fclose(fp); png_destroy_write_struct(&png_ptr, &info_ptr); return (ERROR); } /* 设置输出控制,如果你使用的是 C 的标准 I/O 流 */ png_init_io(png_ptr, fp); /* 这是一种复杂的做法 */ /* (必需)在这里设置图像的信息,宽度、高度的上限是 2^31。 * bit_depth 取值必需是 1、2、4、8 或者 16, 但是可用的值也依赖于 color_type。 * color_type 可选值有: PNG_COLOR_TYPE_GRAY、PNG_COLOR_TYPE_GRAY_ALPHA、 * PNG_COLOR_TYPE_PALETTE、PNG_COLOR_TYPE_RGB、PNG_COLOR_TYPE_RGB_ALPHA。 * interlace 可以是 PNG_INTERLACE_NONE 或 PNG_INTERLACE_ADAM7, * 而 compression_type 和 filter_type 目前必需是 PNG_COMPRESSION_TYPE_BASE * 和 and PNG_FILTER_TYPE_BASE。 */ png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_???, PNG_INTERLACE_????, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); /* 写入文件头部信息(必需) */ png_write_info(png_ptr, info_ptr); png_uint_32 k, height, width; /* 在这个示例代码中,"image" 是一个一维的字节数组(每个元素占一个字节空间) */ png_byte image[height*width*bytes_per_pixel]; png_bytep row_pointers[height]; if (height > PNG_UINT_32_MAX/(sizeof (png_bytep))) png_error (png_ptr, "Image is too tall to process in memory"); /* 将这些像素行指针指向你的 "image" 字节数组中对应的位置,即:指向每行像素的起始处 */ for (k = 0; k < height; k++) row_pointers[k] = image + k*width*bytes_per_pixel; /* 一次调用就将整个图像写进文件 */ png_write_image(png_ptr, row_pointers); /* 必需调用这个函数完成写入文件其余部分 */ png_write_end(png_ptr, info_ptr); /* 写完后清理并释放已分配的内存 */ png_destroy_write_struct(&png_ptr, &info_ptr); /* 关闭文件 */ fclose(fp); /* That's it */ return (OK);}
顺便引用其他相关文章:
《图像解码之一——使用libjpeg解码jpeg图片》
《图像解码之二——使用libpng解码png图片》
《图像解码之三——giflib解码gif图片》
- 利用libpng中的函数读写png文件
- 利用libpng中的函数读写png文件
- 利用libpng中的函数读写png文件
- 利用libpng中的函数读写png文件
- LIBPNG读写PNG文件
- LIBPNG读写PNG图像
- libpng用法,读写PNG图像
- libpng用法,读写PNG图像
- 利用LIBPNG实现显示png图像
- LIBPNG显示PNG图像
- libpng解码png
- C#中的读写文件操作函数总结
- 使用libpng读取png图像
- 使用libpng解码png图片
- 使用libpng显示png图片
- 使用libpng显示png图片
- C/C++二进制读写png文件
- 出现PNG文件错误的解决方案AAPT err(Facade for 1773557322): libpng error: Not a PNG file
- osg中实现文字显示和HUD
- Java 理论与实践: 并发集合类
- HDU 2870 最大子矩阵,联系1505, 1506
- DRP之旅第二站--核心业务
- 页面滚动颜色设置
- 利用libpng中的函数读写png文件
- 深掘XSS漏洞场景之XSS Rootkit[完整修订版]
- 初试.bat文件运行java程序
- ASP.NET语法小结。
- vim单词纠正
- UISegmentedControl控件
- 总有一种力量,能够让你思绪万千
- 吸心大法
- 在导航栏中添加UISegmentedControl