利用libpng中的函数读写png文件【转】
以下是读取png图片文件的代码:
1 #include <stdio.h> 2 #include <png.h> 3 #include <stdlib.h> 4 /******************************图片数据*********************************/ 5 typedef struct _pic_data pic_data; 6 struct _pic_data 7 { 8 int width, height; /* 尺寸 */ 9 int bit_depth; /* 位深 */ 10 int flag; /* 一个标志,表示是否有alpha通道 */ 11 12 unsigned char **rgba; /* 图片数组 */ 13 }; 14 /**********************************************************************/ 15 #define PNG_BYTES_TO_CHECK 4 16 #define HAVE_ALPHA 1 17 #define NO_ALPHA 0 18 19 20 int detect_png(char *filepath, pic_data *out) 21 /* 用于解码png图片 */ 22 { 23 FILE *pic_fp; 24 pic_fp = fopen(filepath, "rb"); 25 if(pic_fp == NULL) /* 文件打开失败 */ 26 return -1; 27 28 /* 初始化各种结构 */ 29 png_structp png_ptr; 30 png_infop info_ptr; 31 char buf[PNG_BYTES_TO_CHECK]; 32 int temp; 33 34 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); 35 info_ptr = png_create_info_struct(png_ptr); 36 37 setjmp(png_jmpbuf(png_ptr)); // 这句很重要 38 39 temp = fread(buf,1,PNG_BYTES_TO_CHECK,pic_fp); 40 temp = png_sig_cmp((void*)buf, (png_size_t)0, PNG_BYTES_TO_CHECK); 41 42 /*检测是否为png文件*/ 43 if (temp!=0) return 1; 44 45 rewind(pic_fp); 46 /*开始读文件*/ 47 png_init_io(png_ptr, pic_fp); 48 // 读文件了 49 png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0); 50 51 int color_type,channels; 52 53 /*获取宽度,高度,位深,颜色类型*/ 54 channels = png_get_channels(png_ptr, info_ptr); /*获取通道数*/ 55 out->bit_depth = png_get_bit_depth(png_ptr, info_ptr); /* 获取位深 */ 56 color_type = png_get_color_type(png_ptr, info_ptr); /*颜色类型*/ 57 58 int i,j; 59 int size, pos = 0; 60 /* row_pointers里边就是rgba数据 */ 61 png_bytep* row_pointers; 62 row_pointers = png_get_rows(png_ptr, info_ptr); 63 out->width = png_get_image_width(png_ptr, info_ptr); 64 out->height = png_get_image_height(png_ptr, info_ptr); 65 66 size = out->width * out->height; /* 计算图片的总像素点数量 */ 67 68 if(channels == 4 || color_type == PNG_COLOR_TYPE_RGB_ALPHA) 69 {/*如果是RGB+alpha通道,或者RGB+其它字节*/ 70 size *= (4*sizeof(unsigned char)); /* 每个像素点占4个字节内存 */ 71 out->flag = HAVE_ALPHA; /* 标记 */ 72 out->rgba = (unsigned char**) malloc(size); 73 if(out->rgba == NULL) 74 {/* 如果分配内存失败 */ 75 fclose(pic_fp); 76 puts("错误(png):无法分配足够的内存供存储数据!"); 77 return 1; 78 } 79 80 temp = (4 * out->width);/* 每行有4 * out->width个字节 */ 81 for(i = 0; i < out->height; i++) 82 { 83 for(j = 0; j < temp; j += 4) 84 {/* 一个字节一个字节的赋值 */ 85 out->rgba[0][pos] = row_pointers[i][j]; // red 86 out->rgba[1][pos] = row_pointers[i][j+1]; // green 87 out->rgba[2][pos] = row_pointers[i][j+2]; // blue 88 out->rgba[3][pos] = row_pointers[i][j+3]; // alpha 89 ++pos; 90 } 91 } 92 } 93 else if(channels == 3 || color_type == PNG_COLOR_TYPE_RGB) 94 {/* 如果是RGB通道 */ 95 size *= (3*sizeof(unsigned char)); /* 每个像素点占3个字节内存 */ 96 out->flag = NO_ALPHA; /* 标记 */ 97 out->rgba = (unsigned char**) malloc(size); 98 if(out->rgba == NULL) 99 {/* 如果分配内存失败 */ 100 fclose(pic_fp); 101 puts("错误(png):无法分配足够的内存供存储数据!"); 102 return 1; 103 } 104 105 temp = (3 * out->width);/* 每行有3 * out->width个字节 */ 106 for(i = 0; i < out->height; i++) 107 { 108 for(j = 0; j < temp; j += 3) 109 {/* 一个字节一个字节的赋值 */ 110 out->rgba[0][pos] = row_pointers[i][j]; // red 111 out->rgba[1][pos] = row_pointers[i][j+1]; // green 112 out->rgba[2][pos] = row_pointers[i][j+2]; // blue 113 ++pos; 114 } 115 } 116 } 117 else return 1; 118 119 /* 撤销数据占用的内存 */ 120 png_destroy_read_struct(&png_ptr, &info_ptr, 0); 121 return 0; 122 }
以下是生成png图片文件的代码:
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 }
浙公网安备 33010602011771号