LIBPNG读写PNG文件

分享一下我使用的代码,以下是读取png图片文件的代码:

 
   
#include <stdio.h>
#include <png.h> 
#include <stdlib.h>
/******************************图片数据*********************************/
typedef struct _pic_data pic_data;
struct _pic_data
{
int width, height; /* 尺寸 */
int bit_depth; /* 位深 */
int flag; /* 一个标志,表示是否有alpha通道 */


unsigned char **rgba; /* 图片数组 */
};
/**********************************************************************/
#define PNG_BYTES_TO_CHECK 4
#define HAVE_ALPHA 1
#define NO_ALPHA 0


/* 用于解码png图片 */
int detect_png(char *filepath, pic_data *out){
FILE *pic_fp;
pic_fp = fopen(filepath, "rb");
/* 文件打开失败 */
if(pic_fp == NULL) 
return -1;
/* 初始化各种结构 */
png_structp png_ptr;
png_infop   info_ptr;
char buf[PNG_BYTES_TO_CHECK];
int temp;
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));

temp = fread(buf,1,PNG_BYTES_TO_CHECK,pic_fp);
temp = png_sig_cmp((void*)buf, (png_size_t)0, PNG_BYTES_TO_CHECK);
/*检测是否为png文件*/
if (temp!=0) return 1;
rewind(pic_fp);
/*开始读文件*/
png_init_io(png_ptr, pic_fp);
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0);
int color_type,channels;
/*获取宽度,高度,位深,颜色类型*/
channels = png_get_channels(png_ptr, info_ptr);
/*获取通道数*/
out->bit_depth = png_get_bit_depth(png_ptr, info_ptr);
/* 获取位深 */
color_type = png_get_color_type(png_ptr, info_ptr);
/*颜色类型*/
int i,j;
int size, pos = 0;
/* row_pointers里边就是rgba数据 */
png_bytep* row_pointers;row_pointers = png_get_rows(png_ptr, info_ptr);
out->width = png_get_image_width(png_ptr, info_ptr);
out->height = png_get_image_height(png_ptr, info_ptr);
size = out->width * out->height;
/* 计算图片的总像素点数量 */ 
if(channels == 4 || color_type == PNG_COLOR_TYPE_RGB_ALPHA){/*如果是RGB+alpha通道,或者RGB+其它字节*/ 
size *= (4*sizeof(unsigned char));
/* 每个像素点占4个字节内存 */
out->flag = HAVE_ALPHA;
/* 标记 */
out->rgba = (unsigned char**) malloc(size);
if(out->rgba == NULL){
/* 如果分配内存失败 */
fclose(pic_fp);
puts("错误(png):无法分配足够的内存供存储数据!");
return 1;
}
temp = (4 * out->width);
/* 每行有4 * out->width个字节 */
for(i = 0; i < out->height; i++){
for(j = 0; j < temp; j += 4){
/* 一个字节一个字节的赋值 */
out->rgba[0][pos] = row_pointers[i][j];
// redout->rgba[1][pos] = row_pointers[i][j+1];
// greenout->rgba[2][pos] = row_pointers[i][j+2];
// blueout->rgba[3][pos] = row_pointers[i][j+3];
// alpha++pos;
}
}
}else if(channels == 3 || color_type == PNG_COLOR_TYPE_RGB){
/* 如果是RGB通道 */
size *= (3*sizeof(unsigned char));
/* 每个像素点占3个字节内存 */
out->flag = NO_ALPHA;
/* 标记 */
out->rgba = (unsigned char**) malloc(size);
if(out->rgba == NULL){
/* 如果分配内存失败 */
fclose(pic_fp);
puts("错误(png):无法分配足够的内存供存储数据!");
return 1;
}
temp = (3 * out->width);
/* 每行有3 * out->width个字节 */
for(i = 0; i < out->height; i++){
for(j = 0; j < temp; j += 3){
/* 一个字节一个字节的赋值 */
out->rgba[0][pos] = row_pointers[i][j];
// redout->rgba[1][pos] = row_pointers[i][j+1];
// greenout->rgba[2][pos] = row_pointers[i][j+2];
// 
blue++pos;
}
}
}else{
return 1;
}

/* 撤销数据占用的内存 */
png_destroy_read_struct(&png_ptr, &info_ptr, 0); return 0;
}
以下是生成png图片文件的代码:
[cpp]  view plain copy
  1. int write_png_file(char *file_name , pic_data *graph)  
  2. /* 功能:将LCUI_Graph结构中的数据写入至png文件 */  
  3. {  
  4.     int j, i, temp, pos;  
  5.     png_byte color_type;   
  6.   
  7.     png_structp png_ptr;  
  8.     png_infop info_ptr;   
  9.     png_bytep * row_pointers;  
  10.     /* create file */  
  11.     FILE *fp = fopen(file_name, "wb");  
  12.     if (!fp)  
  13.     {  
  14.         printf("[write_png_file] File %s could not be opened for writing", file_name);  
  15.         return -1;  
  16.     }  
  17.   
  18.   
  19.     /* initialize stuff */  
  20.     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);  
  21.   
  22.     if (!png_ptr)  
  23.     {  
  24.         printf("[write_png_file] png_create_write_struct failed");  
  25.         return -1;  
  26.     }  
  27.     info_ptr = png_create_info_struct(png_ptr);  
  28.     if (!info_ptr)  
  29.     {  
  30.         printf("[write_png_file] png_create_info_struct failed");  
  31.         return -1;  
  32.     }  
  33.     if (setjmp(png_jmpbuf(png_ptr)))  
  34.     {  
  35.         printf("[write_png_file] Error during init_io");  
  36.         return -1;  
  37.     }  
  38.     png_init_io(png_ptr, fp);  
  39.   
  40.   
  41.     /* write header */  
  42.     if (setjmp(png_jmpbuf(png_ptr)))  
  43.     {  
  44.         printf("[write_png_file] Error during writing header");  
  45.         return -1;  
  46.     }  
  47.     /* 判断要写入至文件的图片数据是否有透明度,来选择色彩类型 */  
  48.     if(graph->flag == HAVE_ALPHA) color_type = PNG_COLOR_TYPE_RGB_ALPHA;  
  49.     else color_type = PNG_COLOR_TYPE_RGB;  
  50.       
  51.     png_set_IHDR(png_ptr, info_ptr, graph->width, graph->height,  
  52.         graph->bit_depth, color_type, PNG_INTERLACE_NONE,  
  53.         PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);  
  54.   
  55.     png_write_info(png_ptr, info_ptr);  
  56.   
  57.   
  58.     /* write bytes */  
  59.     if (setjmp(png_jmpbuf(png_ptr)))  
  60.     {  
  61.         printf("[write_png_file] Error during writing bytes");  
  62.         return -1;  
  63.     }  
  64.     if(graph->flag == HAVE_ALPHA) temp = (4 * graph->width);  
  65.     else temp = (3 * graph->width);  
  66.       
  67.     pos = 0;  
  68.     row_pointers = (png_bytep*)malloc(graph->height*sizeof(png_bytep));  
  69.     for(i = 0; i < graph->height; i++)  
  70.     {  
  71.         row_pointers[i] = (png_bytep)malloc(sizeof(unsigned char)*temp);  
  72.         for(j = 0; j < temp; j += 4)  
  73.         {  
  74.             row_pointers[i][j]   = graph->rgba[0][pos]; // red  
  75.             row_pointers[i][j+1] = graph->rgba[1][pos]; // green  
  76.             row_pointers[i][j+2] = graph->rgba[2][pos];   // blue  
  77.             if(graph->flag == HAVE_ALPHA)   
  78.                 row_pointers[i][j+3] = graph->rgba[3][pos]; // alpha  
  79.             ++pos;  
  80.         }  
  81.     }  
  82.     png_write_image(png_ptr, row_pointers);  
  83.   
  84.     /* end write */  
  85.     if (setjmp(png_jmpbuf(png_ptr)))  
  86.     {  
  87.         printf("[write_png_file] Error during end of write");  
  88.         return -1;  
  89.     }  
  90.     png_write_end(png_ptr, NULL);  
  91.   
  92.     /* cleanup heap allocation */  
  93.     for (j=0; j<graph->height; j++)  
  94.         free(row_pointers[j]);  
  95.     free(row_pointers);  
  96.   
  97.     fclose(fp);  
  98.     return 0;  
  99. }  
这个代码是从libpng给的示例代码中修改而来的,你可以参考一下。

相关文章:

图像解码之一——使用libjpeg解码jpeg图片

图像解码之二——使用libpng解码png图片

图像解码之三——giflib解码gif图片

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用libpng库将png文件解码为bmp数组的步骤如下: 1. 安装libpng库。在Ubuntu上可以使用以下命令安装: ``` sudo apt-get install libpng-dev ``` 2. 编写C代码。下面是一个示例代码,可以将输入的png文件解码为bmp数组,并输出为另一个文件。 ```c #include <stdio.h> #include <stdlib.h> #include <png.h> int main(int argc, char *argv[]) { if (argc != 3) { printf("Usage: %s input_file.png output_file.bmp\n", argv[0]); return 1; } char *input_file = argv[1]; char *output_file = argv[2]; // 打开png文件 FILE *fp = fopen(input_file, "rb"); if (!fp) { printf("Error opening file %s\n", input_file); return 1; } // 读取png文件头信息 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { printf("Error creating read struct\n"); fclose(fp); return 1; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { printf("Error creating info struct\n"); fclose(fp); png_destroy_read_struct(&png_ptr, NULL, NULL); return 1; } if (setjmp(png_jmpbuf(png_ptr))) { printf("Error during setjmp\n"); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return 1; } png_init_io(png_ptr, fp); png_read_info(png_ptr, info_ptr); // 获取png文件信息 int width = png_get_image_width(png_ptr, info_ptr); int height = png_get_image_height(png_ptr, info_ptr); png_byte color_type = png_get_color_type(png_ptr, info_ptr); png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr); // 将png文件转换为bmp数组 if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); png_read_update_info(png_ptr, info_ptr); png_bytep *row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height); for (int y = 0; y < height; y++) { row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr, info_ptr)); } png_read_image(png_ptr, row_pointers); // 将bmp数组输出到文件 FILE *fout = fopen(output_file, "wb"); if (!fout) { printf("Error opening output file %s\n", output_file); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); for (int y = 0; y < height; y++) free(row_pointers[y]); free(row_pointers); return 1; } fwrite("BM", 1, 2, fout); int bmp_size = width * height * 3; int bmp_offset = 54; int file_size = bmp_offset + bmp_size; fwrite(&file_size, 4, 1, fout); fwrite("\0\0\0\0", 4, 1, fout); fwrite(&bmp_offset, 4, 1, fout); int header_size = 40; int planes = 1; int bits_per_pixel = 24; int compression = 0; int image_size = bmp_size; int x_pixels_per_meter = 2835; int y_pixels_per_meter = 2835; int total_colors = 0; int important_colors = 0; fwrite(&header_size, 4, 1, fout); fwrite(&width, 4, 1, fout); fwrite(&height, 4, 1, fout); fwrite(&planes, 2, 1, fout); fwrite(&bits_per_pixel, 2, 1, fout); fwrite(&compression, 4, 1, fout); fwrite(&image_size, 4, 1, fout); fwrite(&x_pixels_per_meter, 4, 1, fout); fwrite(&y_pixels_per_meter, 4, 1, fout); fwrite(&total_colors, 4, 1, fout); fwrite(&important_colors, 4, 1, fout); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { png_byte *ptr = &row_pointers[y][x * 3]; fwrite(ptr + 2, 1, 1, fout); fwrite(ptr + 1, 1, 1, fout); fwrite(ptr, 1, 1, fout); } } fclose(fout); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); for (int y = 0; y < height; y++) free(row_pointers[y]); free(row_pointers); return 0; } ``` 在终端中执行以下命令编译代码: ``` gcc png2bmp.c -o png2bmp -lpng ``` 3. 执行程序。在终端中输入以下命令,将png文件转换为bmp数组: ``` ./png2bmp input_file.png output_file.bmp ``` 其中,'input_file.png'为需要转换的png文件名,'output_file.bmp'为输出的bmp文件名。执行成功后,会在当前目录下生成一个bmp文件
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值