实验需要,加上好奇,使用libpng库将png文件的背景,由黑色,替换成无背景颜色。效果如下图:
替换前:
替换后:
黑色背景都没了,只剩下白色了,看不出来。。。。。。
步骤:
1. 下载png相关库,libpng,以及zlib压缩解压缩文件
libpng官网下载,Ubuntu下zlib下载安装: sudo apt-get install zlib1-dev
2. 代码:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <png.h> 5 6 7 #define PNG_BYTES_TO_CHECK 8 8 #define HAVE_ALPHA 1 9 #define NOT_HAVE_ALPHA 0 10 11 typedef struct _pic_data pic_data; 12 struct _pic_data { 13 int width, height; //长宽 14 int bit_depth; //位深度 15 int alpha_flag; //是否有透明通道 16 unsigned char *rgba;//实际rgb数据 17 }; 18 19 int check_is_png(FILE **fp, const char *filename) //检查是否png文件 20 { 21 char checkheader[PNG_BYTES_TO_CHECK]; //查询是否png头 22 *fp = fopen(filename, "rb"); 23 if (*fp == NULL) { 24 printf("open failed ...1\n"); 25 return -1; 26 } 27 if (fread(checkheader, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK) //读取png文件长度错误直接退出 28 return 0; 29 return png_sig_cmp(checkheader, 0, PNG_BYTES_TO_CHECK); //0正确, 非0错误 30 } 31 32 int decode_png(const char *filename, pic_data *out) //取出png文件中的rgb数据 33 { 34 png_structp png_ptr; //png文件句柄 35 png_infop info_ptr;//png图像信息句柄 36 int ret; 37 FILE *fp; 38 if (check_is_png(&fp, filename) != 0) { 39 printf("file is not png ...\n"); 40 return -1; 41 } 42 printf("launcher[%s] ...\n", PNG_LIBPNG_VER_STRING); //打印当前libpng版本号 43 44 //1: 初始化libpng的数据结构 :png_ptr, info_ptr 45 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 46 info_ptr = png_create_info_struct(png_ptr); 47 48 //2: 设置错误的返回点 49 setjmp(png_jmpbuf(png_ptr)); 50 rewind(fp); //等价fseek(fp, 0, SEEK_SET); 51 52 //3: 把png结构体和文件流io进行绑定 53 png_init_io(png_ptr, fp); 54 //4:读取png文件信息以及强转转换成RGBA:8888数据格式 55 png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0); //读取文件信息 56 int channels, color_type; 57 channels = png_get_channels(png_ptr, info_ptr); //通道数量 58 color_type = png_get_color_type(png_ptr, info_ptr);//颜色类型 59 out->bit_depth = png_get_bit_depth(png_ptr, info_ptr);//位深度 60 out->width = png_get_image_width(png_ptr, info_ptr);//宽 61 out->height = png_get_image_height(png_ptr, info_ptr);//高 62 63 //if(color_type == PNG_COLOR_TYPE_PALETTE) 64 // png_set_palette_to_rgb(png_ptr);//要求转换索引颜色到RGB 65 //if(color_type == PNG_COLOR_TYPE_GRAY && out->bit_depth < 8) 66 // png_set_expand_gray_1_2_4_to_8(png_ptr);//要求位深度强制8bit 67 //if(out->bit_depth == 16) 68 // png_set_strip_16(png_ptr);//要求位深度强制8bit 69 //if(png_get_valid(png_ptr,info_ptr,PNG_INFO_tRNS)) 70 // png_set_tRNS_to_alpha(png_ptr); 71 //if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) 72 // png_set_gray_to_rgb(png_ptr);//灰度必须转换成RG 73 printf("channels = %d color_type = %d bit_depth = %d width = %d height = %d ...\n", 74 channels, color_type, out->bit_depth, out->width, out->height); 75 76 int i, j, k; 77 int size, pos = 0; 78 int temp; 79 80 //5: 读取实际的rgb数据 81 png_bytepp row_pointers; //实际存储rgb数据的buf 82 row_pointers = png_get_rows(png_ptr, info_ptr); //也可以分别每一行获取png_get_rowbytes(); 83 size = out->width * out->height; //申请内存先计算空间 84 if (channels == 4 || color_type == PNG_COLOR_TYPE_RGB_ALPHA) { //判断是24位还是32位 85 out->alpha_flag = HAVE_ALPHA; //记录是否有透明通道 86 size *= (sizeof(unsigned char) * 4); //size = out->width * out->height * channel 87 out->rgba = (png_bytep)malloc(size); 88 if (NULL == out->rgba) { 89 printf("malloc rgba faile ...\n"); 90 png_destroy_read_struct(&png_ptr, &info_ptr, 0); 91 fclose(fp); 92 return -1; 93 } 94 //从row_pointers里读出实际的rgb数据出来 95 temp = channels - 1; 96 for (i = 0; i < out->height; i++) 97 for (j = 0; j < out->width * 4; j += 4) 98 for (k = temp; k >= 0; k--) 99 out->rgba[pos++] = row_pointers[i][j + k]; 100 } else if (channels == 3 || color_type == PNG_COLOR_TYPE_RGB) { //判断颜色深度是24位还是32位 101 out->alpha_flag = NOT_HAVE_ALPHA; 102 size *= (sizeof(unsigned char) * 3); 103 out->rgba = (png_bytep)malloc(size); 104 if (NULL == out->rgba) { 105 printf("malloc rgba faile ...\n"); 106 png_destroy_read_struct(&png_ptr, &info_ptr, 0); 107 fclose(fp); 108 return -1; 109 } 110 //从row_pointers里读出实际的rgb数据 111 temp = (3 * out->width); 112 for (i = 0; i < out->height; i ++) { 113 for (j = 0; j < temp; j += 3) { 114 out->rgba[pos++] = row_pointers[i][j+2]; 115 out->rgba[pos++] = row_pointers[i][j+1]; 116 out->rgba[pos++] = row_pointers[i][j+0]; 117 } 118 } 119 } else return -1; 120 //6:销毁内存 121 png_destroy_read_struct(&png_ptr, &info_ptr, 0); 122 fclose(fp); 123 //此时, 我们的out->rgba里面已经存储有实际的rgb数据了 124 //处理完成以后free(out->rgba) 125 return 0; 126 } 127 128 int RotationRight90(unsigned char * src, int srcW, int srcH, int channel) //顺时针旋转90度 129 { 130 unsigned char * tempSrc = NULL; //临时的buf用来记录原始的图像(未旋转之前的图像) 131 int mSize = srcW * srcH * sizeof(char) * channel; 132 int i = 0; 133 int j = 0; 134 int k = 0; 135 int l = 3; 136 int desW = 0; 137 int desH = 0; 138 139 desW = srcH; 140 desH = srcW; 141 142 tempSrc = (unsigned char *)malloc(sizeof(char) * srcW * srcH * channel); 143 memcpy(tempSrc, src, mSize); //拷贝原始图像至tempbuf 144 for(i = 0; i < desH; i ++) 145 { 146 for(j = 0; j < desW; j ++) 147 { 148 for(k = 0; k < channel; k ++) 149 { 150 src[(i * desW + j) * channel + k] = tempSrc[((srcH - 1 - j) * srcW + i) * channel + k]; //替换像素 151 } 152 } 153 } 154 free(tempSrc); 155 return 0; 156 } 157 158 int write_png_file(const char *filename , pic_data *out) //生成一个新的png图像 159 { 160 png_structp png_ptr; 161 png_infop info_ptr; 162 png_byte color_type; 163 png_bytep * row_pointers; 164 FILE *fp = fopen(filename, "wb"); 165 if (NULL == fp) { 166 printf("open failed ...2\n"); 167 return -1; 168 } 169 //1: 初始化libpng结构体 170 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); 171 if (!png_ptr) { 172 printf("png_create_write_struct failed ...\n"); 173 return -1; 174 } 175 //2: 初始化png_infop结构体 , 176 //此结构体包含了图像的各种信息如尺寸,像素位深, 颜色类型等等 177 info_ptr = png_create_info_struct(png_ptr); 178 if (!info_ptr) { 179 printf("png_create_info_struct failed ...\n"); 180 return -1; 181 } 182 //3: 设置错误返回点 183 if (setjmp(png_jmpbuf(png_ptr))) { 184 printf("error during init_io ...\n"); 185 return -1; 186 } 187 //4:绑定文件IO到Png结构体 188 png_init_io(png_ptr, fp); 189 if (setjmp(png_jmpbuf(png_ptr))) { 190 printf("error during init_io ...\n"); 191 return -1; 192 } 193 if (out->alpha_flag == HAVE_ALPHA) color_type = PNG_COLOR_TYPE_RGB_ALPHA; 194 else color_type = PNG_COLOR_TYPE_RGB; 195 //5:设置以及写入头部信息到Png文件 196 png_set_IHDR(png_ptr, info_ptr, out->width, out->height, out->bit_depth, 197 PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); 198 png_write_info(png_ptr, info_ptr); 199 if (setjmp(png_jmpbuf(png_ptr))) { 200 printf("error during init_io ...\n"); 201 return -1; 202 } 203 int channels, temp; 204 int i, j, pos = 0; 205 if (out->alpha_flag == HAVE_ALPHA) { 206 channels = 4; 207 temp = (4 * out->width); 208 printf("have alpha ...\n"); 209 } else { 210 channels = 4; 211 temp = (4 * out->width); 212 printf("not have alpha ...\n"); 213 } 214 // 顺时针旋转90度 , 旋转完了一定要把width 和height调换 不然得到的图像是花的 旋转三次就是逆时针旋转一次 215 //RotationRight90(out->rgba, out->width, out->height, channels); 216 //RotationRight90(out->rgba, out->height, out->width, channels); 217 //RotationRight90(out->rgba, out->width, out->height, channels); 218 row_pointers = (png_bytep*)malloc(out->height * sizeof(png_bytep)); 219 for (i = 0; i < out->height; i++) { 220 row_pointers[i] = (png_bytep)malloc(temp* sizeof(unsigned char)); 221 for (j = 0; j < temp; j += channels) { 222 if (channels == 4) { 223 if (out->alpha_flag == HAVE_ALPHA) 224 row_pointers[i][j+3] = out->rgba[pos++]; 225 //row_pointers[i][j+3] = 0x00; 226 row_pointers[i][j+2] = out->rgba[pos++]; 227 row_pointers[i][j+1] = out->rgba[pos++]; 228 row_pointers[i][j+0] = out->rgba[pos++]; 229 //printf("---- i = %d, j = %d, %d, %d, %d, %d\n", i, j, row_pointers[i][j + 0], row_pointers[i][j + 1],row_pointers[i][j + 2],row_pointers[i][j + 3]); 230 if((row_pointers[i][j+0] + row_pointers[i][j+1] + row_pointers[i][j+2]) < 100) 231 { 232 row_pointers[i][j+3] = 0x00; 233 row_pointers[i][j+2] = 0x00; 234 row_pointers[i][j+1] = 0x00; 235 row_pointers[i][j+0] = 0x00; 236 237 } 238 else 239 { 240 row_pointers[i][j+3] = 0xff; 241 row_pointers[i][j+2] = 0xff; 242 row_pointers[i][j+1] = 0xff; 243 row_pointers[i][j+0] = 0xff; 244 } 245 //printf("---- i = %d, j = %d, %d, %d, %d, %d\n", i, j, row_pointers[i][j + 0], row_pointers[i][j + 1],row_pointers[i][j + 2],row_pointers[i][j + 3]); 246 } else { 247 row_pointers[i][j+2] = out->rgba[pos++]; 248 row_pointers[i][j+1] = out->rgba[pos++]; 249 row_pointers[i][j+0] = out->rgba[pos++]; 250 if((row_pointers[i][j+0] + row_pointers[i][j+1] + row_pointers[i][j+2]) < 30) 251 { 252 row_pointers[i][j+3] = 0x00; 253 row_pointers[i][j+2] = 0x00; 254 row_pointers[i][j+1] = 0x00; 255 row_pointers[i][j+0] = 0x00; 256 257 } 258 else 259 { 260 row_pointers[i][j+3] = 0xff; 261 row_pointers[i][j+2] = 0xff; 262 row_pointers[i][j+1] = 0xff; 263 row_pointers[i][j+0] = 0xff; 264 } 265 // printf("++++ i = %d, j = %d, %d, %d, %d, %d\n", i, j, row_pointers[i][j + 0], row_pointers[i][j + 1],row_pointers[i][j + 2],row_pointers[i][j + 3]); 266 } 267 } 268 } 269 //6: 写入rgb数据到Png文件 270 png_write_image(png_ptr, (png_bytepp)row_pointers); 271 if (setjmp(png_jmpbuf(png_ptr))) { 272 printf("error during init_io ...\n"); 273 return -1; 274 } 275 //7: 写入尾部信息 276 png_write_end(png_ptr, NULL); 277 //8:释放内存 ,销毁png结构体 278 for (i = 0; i < out->height; i ++) 279 free(row_pointers[i]); 280 free(row_pointers); 281 png_destroy_write_struct(&png_ptr, &info_ptr); 282 fclose(fp); 283 return 0; 284 } 285 286 int main(int argc, char **argv) 287 { 288 pic_data out; 289 if (argc == 3) { 290 decode_png(argv[1], &out); 291 write_png_file(argv[2], &out); 292 free(out.rgba); 293 } else { 294 puts("please input two file, \nargv[1]:source.png argv[2]:dest.png"); 295 } 296 return 0; 297 }
参考:https://blog.csdn.net/wang93IT/article/details/85003730
原文地址:https://www.cnblogs.com/hanrp/p/11419147.html
时间: 2024-10-09 07:28:07