zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    iostream迭代器操作"txt文本文件"无法写入的思考
    Qt 相对路径 绝对路径
    "lambda"和“bind”的初步思考
    "partition"和“stable_partition”的思考
    "accumulate"的思考
    顺序容器“inset”的思考
    C++重载函数 const形参 引用指针 const_cast
    C++ 可变参数的函数
    JDK8流式处理常用例子
    JDK8时间新API
  • 原文地址:https://www.cnblogs.com/hanrp/p/11419147.html
Copyright © 2011-2022 走看看