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图片,背景替换成无颜色背景的主要内容,如果未能解决你的问题,请参考以下文章

替换 PNG 文件中的颜色

ps如何把这个png换颜色

如何用matlab来更改登记照的背景颜色

如何根据行替换 UICollectiveViewCell 的背景颜色?

应用启动时将白屏背景替换成图片/颜色/动画等 仅供参考

如何用Photoshop修改PNG图片颜色,背景仍需透明,详细,徐步骤,谢谢!