png图片,背景替换成无颜色背景
Posted hanrp
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了png图片,背景替换成无颜色背景相关的知识,希望对你有一定的参考价值。
实验需要,加上好奇,使用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
以上是关于png图片,背景替换成无颜色背景的主要内容,如果未能解决你的问题,请参考以下文章