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
");
 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 ...
");
 40         return -1;
 41     }
 42     printf("launcher[%s] ...
", 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 ...
",
 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 ...
");
 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 ...
");
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_1(pic_data *in) //顺时针旋转90度
129 {
130     unsigned char * tempSrc = NULL; //临时的buf用来记录原始的图像(未旋转之前的图像)
131     int mSize = 0, i = 0, j = 0, k = 0, channel = 0;
132     int desW = 0;
133     int desH = 0;
134     int tmp1, tmp2;
135 
136     desW = in->height;
137     desH = in->width;
138     if(in->alpha_flag == HAVE_ALPHA)
139     {
140         channel = 4;
141     }
142     else
143     {
144         channel = 3;
145     }
146     mSize = (in->width) * (in->height) * sizeof(char) * (channel);
147  //   printf("start copy
");
148     tempSrc = (unsigned char *)malloc(mSize);
149     memcpy(tempSrc, in->rgba, mSize); //拷贝原始图像至tempbuf
150 //    printf("copy ok--------
");
151     for(i = 0; i < desH; i ++)
152     {
153         for(j = 0; j < desW; j ++)
154         {
155             for(k = 0; k < channel; k ++)
156             {
157                 tmp1 = (i * desW + j) * channel + k;
158                 tmp2 = (((in->height) - 1 - j) * (in->width) + i) * channel + k;
159                 in->rgba[(i * desW + j) * channel + k] = tempSrc[(((in->height) - 1 - j) * (in->width) + i) * channel + k]; //替换像素
160 //                printf("tmp1 = %d, tmp2 = %d
", tmp1, tmp2);
161             }
162         }
163     }
164     free(tempSrc);
165     in->height = desH;
166     in->width = desW;
167     return 0;
168 }
169 
170 // 统一格式,将png转换成具有ALPHA模式
171 int convert_to_alphamode(pic_data *in)      
172 {
173     unsigned char * tempSrc = NULL;         // 临时的buf用来记录原始的图像(未旋转之前的图像)
174     int temp;
175     int i, j, pos = 0, pos_out = 0;
176     unsigned char *pchar;
177 
178     if (in->alpha_flag == HAVE_ALPHA)
179     {
180         temp = (4 * in->width);
181         printf("already have alpha ...
");
182         return 1;
183     }
184     else
185     {
186         in->alpha_flag = HAVE_ALPHA;
187         temp = (3 * in->width);
188         printf("not have alpha ...
");
189     }
190     pchar = in->rgba;
191     in->rgba = (unsigned char *)malloc(sizeof(char) * (in->width) * (in->height) * 4);
192 
193     for (i = 0; i < in->height; i++)
194     {
195         for (j = 0; j < temp; j += 3)
196         {
197             in->rgba[pos_out++] = 0xFF;
198             in->rgba[pos_out++] = pchar[pos++];
199             in->rgba[pos_out++] = pchar[pos++];
200             in->rgba[pos_out++] = pchar[pos++];
201         }
202     }
203     free(pchar);
204     printf("change to alpha ok
");
205     return 2;
206 }
207 
208 // 将黑色设置成透明
209 int png_set_alpha(pic_data *in)
210 {
211     int temp;
212     int i, j, pos = 0;
213     if (in->alpha_flag != HAVE_ALPHA)
214     {
215         printf("png_set_alpha fail, change png to alpha mode first...
");
216         return -1;
217     }
218     temp = (4 * in->width);
219     for (i = 0; i < in->height; i++)
220     {
221         pos = i * (in->width) * 4;
222         for (j = 0; j < temp; j += 4)
223         {
224             if ((in->rgba[pos + j + 1] + in->rgba[pos + j + 2] + in->rgba[pos + j + 3]) < 60)       // 黑色区域都变成透明的
225             {
226                 //printf("i = %d, j = %d, pos = %d
", i, j, pos);
227                 in->rgba[pos + j + 0] = 0x00;
228             }
229             else        // 将有颜色的都变成白色
230             {
231                 in->rgba[pos + j + 0] = 0xFF;
232                 in->rgba[pos + j + 1] = 0xFF;
233                 in->rgba[pos + j + 2] = 0xFF;
234                 in->rgba[pos + j + 3] = 0xFF;
235             }
236         }
237     }
238     printf("png_set_alpha ok
");
239     return 1;
240 }
241 
242 // 将白色设置成透明
243 int png_set_alpha_1(pic_data *in)
244 {
245     int temp;
246     int i, j, pos = 0;
247     if (in->alpha_flag != HAVE_ALPHA)
248     {
249         printf("png_set_alpha fail, change png to alpha mode first...
");
250         return -1;
251     }
252     temp = (4 * in->width);
253     for (i = 0; i < in->height; i++)
254     {
255         pos = i * (in->width) * 4;
256         for (j = 0; j < temp; j += 4)
257         {
258             if ((in->rgba[pos + j + 1] + in->rgba[pos + j + 2] + in->rgba[pos + j + 3]) > 600)       // 白色区域都变成透明的
259             {
260                 //printf("i = %d, j = %d, pos = %d
", i, j, pos);
261                 in->rgba[pos + j + 0] = 0x00;       // 透明
262             }
263             else        // 将有颜色的都变成白色
264             {
265                 in->rgba[pos + j + 0] = 0xFF;       // 非透明
266                 in->rgba[pos + j + 1] = 0x00;
267                 in->rgba[pos + j + 2] = 0x00;
268                 in->rgba[pos + j + 3] = 0x00;
269             }
270         }
271     }
272     printf("png_set_alpha ok
");
273     return 1;
274 }
275 
276 // 截取图片
277 // 参数:
278 // startx: 新图片的起始x坐标
279 // starty: 新图片的起始y坐标
280 // new 新图片的宽度
281 // newheight: 新图片的高度
282 int screen_cut(pic_data *in, int startx, int starty, int newwidth, int newheight)
283 {
284     int temp = 0;
285     int channel = 0;
286     int i, j, k, pos = 0;
287     unsigned char *puchar;
288     if ((newwidth > in->width) || (newheight > in->height))
289     {
290         printf("error: newwidth or newheight error, -1
");
291         return -1;
292     }
293     if (((startx + newwidth) > in->width) || ((starty + newheight) > in->height))
294     {
295         printf("error: startx + newwidth or starty + newheight error, -2
");
296         return -2;
297     }
298     
299     if((startx < 0) || (starty < 0) || (newwidth < 1) || (newheight < 1))
300     {
301         printf("error: parameter error, -3
");
302         return -3;
303     }
304     
305     if (in->alpha_flag == HAVE_ALPHA)
306     {
307         channel = 4;
308     }
309     else
310     {
311         channel = 3;
312     }
313     temp = newwidth * newheight * sizeof(char) * channel;
314     puchar = in->rgba;
315     in->rgba = (unsigned char *)malloc(temp);
316     for(i = starty; i < (newheight + starty); i++)
317     {
318         temp = i * (in->width) * channel;
319         for(j = startx; j < (newwidth + startx); j++)
320         {
321             for(k = 0; k < channel; k++)
322             {
323                 in->rgba[((i - starty) * newwidth + (j - startx)) * channel + k] = puchar[temp + j*channel + k];
324             }
325         }
326     }
327     in->width = newwidth;
328     in->height = newheight;
329     free(puchar);
330     return 1;
331 }
332 
333 int write_png_file(const char *filename , pic_data *out) //生成一个新的png图像
334 {
335     png_structp png_ptr;
336     png_infop   info_ptr;
337     png_byte color_type;
338     png_bytep * row_pointers;
339     FILE *fp = fopen(filename, "wb");
340     if (NULL == fp) {
341         printf("open failed ...2
");
342         return -1;
343     }
344     //1: 初始化libpng结构体
345     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
346     if (!png_ptr) {
347         printf("png_create_write_struct failed ...
");
348         return -1;
349     }
350     //2: 初始化png_infop结构体 ,
351     //此结构体包含了图像的各种信息如尺寸,像素位深, 颜色类型等等
352     info_ptr = png_create_info_struct(png_ptr);
353     if (!info_ptr) {
354         printf("png_create_info_struct failed ...
");
355         return -1;
356     }
357     //3: 设置错误返回点
358     if (setjmp(png_jmpbuf(png_ptr))) {
359         printf("error during init_io ...
");
360         return -1;
361     }
362     //4:绑定文件IO到Png结构体
363     png_init_io(png_ptr, fp);
364     if (setjmp(png_jmpbuf(png_ptr))) {
365         printf("error during init_io ...
");
366         return -1;
367     }
368     if (out->alpha_flag == HAVE_ALPHA) color_type = PNG_COLOR_TYPE_RGB_ALPHA;
369     else color_type = PNG_COLOR_TYPE_RGB;
370     //5:设置以及写入头部信息到Png文件
371     png_set_IHDR(png_ptr, info_ptr, out->width, out->height, out->bit_depth,
372     color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
373     png_write_info(png_ptr, info_ptr);
374     if (setjmp(png_jmpbuf(png_ptr))) {
375         printf("error during init_io ...
");
376         return -1;
377     }
378     int channels, temp;
379     int i, j, pos = 0;
380     if (out->alpha_flag == HAVE_ALPHA) {
381         channels = 4;
382         temp = (4 * out->width);
383         printf("have alpha ...
");
384     } else {
385         channels = 3;
386         temp = (3 * out->width);
387         printf("not have alpha ...
");
388     }
389     // 顺时针旋转90度 , 旋转完了一定要把width 和height调换 不然得到的图像是花的  旋转三次就是逆时针旋转一次
390     //RotationRight90(out->rgba, &out->width, &out->height, channels);
391     //RotationRight90(out->rgba, out->height, out->width, channels);
392     //RotationRight90(out->rgba, out->width, out->height, channels);
393     row_pointers = (png_bytep*)malloc(out->height * sizeof(png_bytep));
394     for (i = 0; i < out->height; i++) {
395         row_pointers[i] = (png_bytep)malloc(temp* sizeof(unsigned char));
396         for (j = 0; j < temp; j += channels) {
397             if (channels == 4) {
398                 //if (out->alpha_flag == HAVE_ALPHA)
399                 row_pointers[i][j+3] = out->rgba[pos++];
400                 row_pointers[i][j+2] = out->rgba[pos++];
401                 row_pointers[i][j+1] = out->rgba[pos++];
402                 row_pointers[i][j+0] = out->rgba[pos++];
403                 //printf("----    i = %d, j = %d, %d, %d, %d, %d
", i, j, row_pointers[i][j + 0], row_pointers[i][j + 1],row_pointers[i][j + 2],row_pointers[i][j + 3]);
404                 //printf("----    i = %d, j = %d, %d, %d, %d, %d
", i, j, row_pointers[i][j + 0], row_pointers[i][j + 1],row_pointers[i][j + 2],row_pointers[i][j + 3]);
405             } else {
406                 row_pointers[i][j+2] = out->rgba[pos++];
407                 row_pointers[i][j+1] = out->rgba[pos++];
408                 row_pointers[i][j+0] = out->rgba[pos++];
409                 //printf("++++    i = %d, j = %d, %d, %d, %d, %d
", i, j, row_pointers[i][j + 0], row_pointers[i][j + 1],row_pointers[i][j + 2],row_pointers[i][j + 3]);
410             }
411         }
412     }
413     //6: 写入rgb数据到Png文件
414     png_write_image(png_ptr, (png_bytepp)row_pointers);
415     if (setjmp(png_jmpbuf(png_ptr))) {
416         printf("error during init_io ...
");
417         return -1;
418     }
419     //7: 写入尾部信息
420     png_write_end(png_ptr, NULL);
421     //8:释放内存 ,销毁png结构体
422     for (i = 0; i < out->height; i ++)
423         free(row_pointers[i]);
424     free(row_pointers);
425     png_destroy_write_struct(&png_ptr, &info_ptr);
426     fclose(fp);
427     return 0;
428 }
429 
430 int main(int argc, char **argv)
431 {
432     pic_data out;
433     
434     if(argc == 2)
435     {
436         if(strstr(argv[1],"help") != NULL)
437         {
438             printf("
===============================================================================
");
439             printf("    usage: %s -cmd parameter...
", argv[0]);
440             printf("    cmd1(change to alpha mode): %s 1 srcfilename outfilename
", argv[0]);
441             printf("    cmd2(screen cut): %s 2 srcfilename outfilename startx starty newwidth newheight
", argv[0]);
442             printf("    cmd3(change black to transparent): %s 3 srcfilename outfilename
", argv[0]);
443             printf("    cmd4(change write to transparent): %s 4 srcfilename outfilename
", argv[0]);
444             printf("===============================================================================

");
445             
446             return 0;
447         }
448     }
449     if(argc >= 4)
450     {
451         if(strcmp(argv[1],"1") == 0)        // cmd1
452         {
453             printf("    usage: %s 1 in.png out.png
", argv[0]);
454             decode_png(argv[2], &out);
455             convert_to_alphamode(&out);
456             write_png_file(argv[3], &out);
457             free(out.rgba);
458             return 1;
459         }
460         else if(strcmp(argv[1],"2") == 0)        // cmd2
461         {
462             printf("    usage: %s 2 in.png out.png startx starty newwidth newheight
", argv[0]);
463             printf("    startx = %d
", atoi(argv[4]));
464             printf("    starty = %d
", atoi(argv[5]));
465             printf("    newwidth = %d
", atoi(argv[6]));
466             printf("    newheight = %d
", atoi(argv[7]));
467 
468             if(argc != 8)
469             {
470                 printf("Error: parameter count not correct
");
471                 return -1;
472             }
473             decode_png(argv[2], &out);
474             screen_cut(&out, atoi(argv[4]), atoi(argv[5]), atoi(argv[6]), atoi(argv[7]));
475             write_png_file(argv[3], &out);
476         }
477         else if(strcmp(argv[1],"3") == 0)        // cmd3
478         {
479             printf("    usage: %s 3 in.png out.png
", argv[0]);
480             decode_png(argv[2], &out);
481             png_set_alpha(&out);
482             write_png_file(argv[3], &out);
483             free(out.rgba);
484         }
485         else if(strcmp(argv[1],"4") == 0)        // cmd4
486         {
487             printf("    usage: %s 4 in.png out.png
", argv[0]);
488             decode_png(argv[2], &out);
489             png_set_alpha_1(&out);
490             write_png_file(argv[3], &out);
491             free(out.rgba);
492         }
493     }
494     return 0;
495 }

 参考:https://blog.csdn.net/wang93IT/article/details/85003730

原文地址:https://www.cnblogs.com/hanrp/p/11419147.html