【问题标题】:How to set libpng background transparency with palettes?如何使用调色板设置 libpng 背景透明度?
【发布时间】:2018-09-22 17:28:29
【问题描述】:

我对基本的 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 会得到以下图像:

我正在使用 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. 如何将调色板中的颜色分配给某个点的像素?

【问题讨论】:

  • 对于那些可能遇到同样问题的人。似乎如果您使用调色板作为颜色,则必须使用 tRNS 来实现透明度 - 根据规范。 “PNG 规范禁止对基于调色板的图像使用完整的 alpha 通道,但它确实允许通过透明度块 tRNS 实现‘便宜的 alpha’。”来自:libpng.org/pub/png/book/chapter08.html

标签: c libpng


【解决方案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](非透明条目)设置为红色。听起来你为了你的目的将它设置为黑色。

【讨论】:

  • 我接受了你的回答,因为它给了我一些工作的机会。但是,从您的代码中,我看到您正在做row[x]=0 or 1 - 表示当 1、0 表示透明时,那里的像素是彩色的。像素是如何从调色板中获得有关要使用的颜色的数据的?使用您的代码,它使用了正确的颜色,但为什么呢?
  • row[x]=0 or 1 表示使用调色板条目01,其颜色和透明度决定了像素的颜色和透明度。我关于设置条目透明度的代码很差 - 我已经替换了关于 trans 的两行,这应该更清晰
  • 特定调色板条目的颜色在palette数组中为RGB:png_color palette[] = { {0,0,0}, {100,0,0} }; # black, red
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-02
  • 2011-04-14
  • 1970-01-01
  • 1970-01-01
  • 2014-06-11
  • 2018-04-13
相关资源
最近更新 更多