如何使用调色板设置libpng背景透明度?

时间:2018-04-12 14:00:59

标签: c libpng

我对基本的libpng概念缺乏了解,所以请耐心等待。我有以下源代码:

#include <png.h>
#include <stdio.h>
#include <stdint.h>
void cb() { printf("callbacked\n"); }
// write row
void wr_cb (png_structp png_ptr, png_uint_32 row, int pass) { 
//printf("wr cb");
}
int main(){

        FILE *fp = fopen("pic.png", "wb");
        png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp) cb, cb, cb);
        png_infop info_ptr = png_create_info_struct(png_ptr);
        png_color* palette = (png_color*) png_malloc(png_ptr, 2*sizeof(png_color));
        png_bytep* row_pointers;

        png_color_16 bgcolor;
        bgcolor.red = 255;
        bgcolor.green =255;
        bgcolor.blue = 255;
        //palette[]

        png_color *c1 = &palette[0];
        png_color *c2 = &palette[1];
        c1->red=255; c1->green=255; c1->blue=255;
        c2->red=0;   c2->green= 0;  c2->blue= 0;

        if (setjmp(png_jmpbuf(png_ptr))){
                png_destroy_write_struct(&png_ptr, &info_ptr);
                fclose(fp);
                printf("error: destroyed all\n");
        }
        png_init_io(png_ptr, fp);
        png_set_write_status_fn(png_ptr, wr_cb);
        png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
        png_set_IHDR(png_ptr, info_ptr, 500, 500, 1, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
        png_set_PLTE(png_ptr,info_ptr, palette, 2);
        png_write_info(png_ptr, info_ptr);


        row_pointers = (png_bytep*) malloc(500*sizeof(png_bytep));
        for (size_t l = 0; l < 500; l ++){ 
                row_pointers[l]= (png_byte*) malloc( png_get_rowbytes(png_ptr, info_ptr));
                //png_get_rowbytes(png_ptr, info_ptr) -> gives 63
                if (l==10)
                for (size_t k = 0; k < 70; k++){// NOTE_HERE
                        row_pointers[l][k] =150; // 255 - draws a line
                }
        }

        png_set_background(png_ptr, c2, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1);
        png_write_image(png_ptr, row_pointers);
        png_write_end(png_ptr, info_ptr);
        png_destroy_write_struct(&png_ptr, &info_ptr);
        png_free(png_ptr, palette);

}

我用gcc thefile.c -lpng -o png_maker编译它 运行png_maker会显示以下图像:

Image generated from png_maker

我正在使用PNG_COLOR_TYPE_PALETTE,因为我希望只使用两种颜色 - 我的假设是使用调色板会生成比不使用调色板更小的png文件 - 因为在我的用例中,我只需要两种像素颜色在图片中:黑色或白色/透明 - 这个假设是否正确?

3个问题:

  1. 从图像中可以看到顶部有黑色虚线。但是没有透明度。
  2. 在第二个for循环中(在代码中查找“NOTE_HERE”)。我正在检查k是否小于70(用于测试的硬编码数字,因为给它更大的数字我得到SIGSEGV)。 png_byte是unsigned char的typedef。所以我的猜测是png_get_row_bytes给它63个字节,我猜现在它正在使用1位1像素?如果是的话,我该怎么设置呢?
  3. 如何将调色板中的颜色指定给某个点的像素?

1 个答案:

答案 0 :(得分:1)

嗯,我的设置代码与你的设置代码非常相似。我使用png_write_row一次编写图像行,但它与png_write_image应该大致相同。

#include <stdio.h>
#include <stdlib.h>
#include <png.h>

int main(){
  png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

  if (!png_ptr) {
    exit (EXIT_FAILURE);
  }

  png_infop info_ptr = png_create_info_struct(png_ptr);

  if (!info_ptr) {
    png_destroy_write_struct(&png_ptr, NULL);
    exit (EXIT_FAILURE);
  }

  if(setjmp(png_jmpbuf(png_ptr))){
    printf ("PNG error\n");
    exit(EXIT_FAILURE);
  }

  FILE * fp = fopen("foo.png", "wb");
  if(fp==NULL){
    perror("opening output file");
    exit (EXIT_FAILURE);
  }
  png_init_io(png_ptr, fp);


  int width=100, height=100;

  png_set_IHDR(png_ptr,
           info_ptr,
           width,
           height,
           8, // bit_depth,
           PNG_COLOR_TYPE_PALETTE,
           PNG_INTERLACE_NONE,
           PNG_COMPRESSION_TYPE_BASE,
           PNG_FILTER_TYPE_BASE);

  png_color palette[] = {
    {0,0,0}, {100,0,0} 
  };

  png_set_PLTE(png_ptr, info_ptr, palette, 2);

  png_byte trans[] = {255, 128}; // entry 0 opaque, entry 1 half alpha
  png_set_tRNS(png_ptr, info_ptr, trans, 2, NULL);

  png_write_info(png_ptr, info_ptr);

  // write the image data, row by row
  for (int y=0; y<height; y++) {
    png_byte row[width];

    for (int x = 0; x < width; x++){
      row[x] = ((50-x)*(50-x) + (50-y)*(50-y)) < (50*50); // circle
    }

    png_write_row(png_ptr, row);
  }

  png_write_end(png_ptr, NULL);

  png_destroy_write_struct(&png_ptr, &info_ptr);

  png_free(png_ptr, palette);
  return 0;
}

请注意,仅为我的调试,palette[1](非透明条目)设置为red-ish。听起来你为了你的目的将它设置为黑色。