2012-12-24 68 views
1

好的,所以在Photoshop中,我創建了一個具有透明背景和一些文本的8位彩色圖像。然後我創建了一個具有透明背景和一些文本的16位彩色圖像。LibPng背景

我用鼠標右鍵單擊圖像和去屬性,它顯示了32位深度的兩種:L 所以我決定使用以下設置讀取與libpng的圖像:

typedef union RGB  //Holds all the pixels.. 
{ 
    uint32_t Color; 
    struct 
    { 
     unsigned char B, G, R, A; 
    } RGBA; 
} *PRGB; 


channels = png_get_channels(PngPointer, InfoPointer); 
    png_get_IHDR(PngPointer, InfoPointer, &width, &height, &bitdepth, &colortype, &interlacetype, nullptr, nullptr); 
    png_set_interlace_handling(PngPointer); 
    png_set_strip_16(PngPointer); 
    png_set_packing(PngPointer); 

    switch (colortype) 
    { 
     case PNG_COLOR_TYPE_GRAY: 
     { 
      png_set_expand_gray_1_2_4_to_8(PngPointer); 
      png_set_expand(PngPointer); 
      png_set_bgr(PngPointer); 
      break; 
     } 

     case PNG_COLOR_TYPE_PALETTE: 
     { 
      png_set_palette_to_rgb(PngPointer); 
      if (png_get_valid(PngPointer, InfoPointer, PNG_INFO_tRNS)) 
       png_set_tRNS_to_alpha(PngPointer); 
      png_set_filler(PngPointer, 0xFF, PNG_FILLER_AFTER); 
      png_set_bgr(PngPointer); 
     BitsPerPixel = 24; 
      break; 
     } 

     case PNG_COLOR_TYPE_GRAY_ALPHA: 
     { 
      png_set_gray_to_rgb(PngPointer); 
      break; 
     } 

     case PNG_COLOR_TYPE_RGB: 
     { 
      png_set_bgr(PngPointer); 
      png_set_filler(PngPointer, 0xFF, PNG_FILLER_AFTER); 
      BitsPerPixel = 24; 
      break; 
     } 

     case PNG_COLOR_TYPE_RGBA: 
     { 
      png_set_bgr(PngPointer); 
      BitsPerPixel = 32; 
      break; 
     } 

     default: png_destroy_read_struct(&PngPointer, &InfoPointer, nullptr); throw std::runtime_error("Error: Png Type not supported."); break; 
    } 

    //SET BACKGROUND 
    /*png_color_16 my_background, *image_background; 
    my_background.red = 255; 
    my_background.green = 255; 
    my_background.blue = 255; 
    image_background = &my_background; 

    if (png_get_bKGD(PngPointer, InfoPointer, &image_background)) 
    { 
     png_set_filler(PngPointer, 0xFF, PNG_FILLER_AFTER); 
     png_set_background(PngPointer, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); 
    } 
    else 
    { 
     png_set_filler(PngPointer, 0xFF, PNG_FILLER_AFTER); 
     png_set_background(PngPointer, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); 
    }*/ 
    //END SET BACKGROUND 

    png_read_update_info(PngPointer, InfoPointer); 
    channels = png_get_channels(PngPointer, InfoPointer); 
    png_get_IHDR(PngPointer, InfoPointer, &width, &height, &bitdepth, &colortype, &interlacetype, nullptr, nullptr); 

我保存的設置分別是:

png_set_write_fn(PngPointer, reinterpret_cast<void*>(&hFile), WriteToStream, nullptr); 
    png_set_IHDR (PngPointer, InfoPointer, width, height, bitdepth, BitsPerPixel == 24 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); 
    png_write_info(PngPointer, InfoPointer); 

    png_set_bgr(PngPointer); 
    png_set_packing(PngPointer); 
    png_set_interlace_handling(PngPointer); 
    if (colortype == PNG_COLOR_TYPE_RGB) png_set_filler(PngPointer, 0xFF, PNG_FILLER_AFTER); 

的PNG看起來像: enter image description here

當我保存它通過C++的位圖,它看起來像(8位一個這樣做):enter image description here

將其保存爲PNG,它看起來完全像原始。 8和16都可以很好地保存。

問題是,如果我取消註釋「SetBackground」部分,它可以完美保存爲位圖,除非將其保存爲PNG時,背景不再透明,因爲代碼將其設置爲白色(255, 255,255)。

我該如何解決這個問題?

+1

如果您在使用'png_set_tRNS_to_alpha'你不應該使用'png_set_filler'(使用'png_set_filler'只有當圖像不包括透明度)。而且,當你將'png_set_filler'應用到RGB圖像時,你會得到一個32bpp圖像,所以_BitsPerPixel_應該是** 32 ** – Jigsore

+0

問題。我需要知道如何檢測是否存在Alpha通道。這樣我可以將背景設置爲白色,並將其保存回PNG時,將其設置爲透明。 我做了你所建議的。這並沒有解決它。 – Brandon

回答

2

我對你的代碼做了一些修改。 未經測試!

channels = png_get_channels(PngPointer, InfoPointer); 
png_get_IHDR(PngPointer, InfoPointer, &width, &height, &bitdepth, &colortype, &interlacetype, nullptr, nullptr); 
png_set_interlace_handling(PngPointer); 
png_set_strip_16(PngPointer); 
png_set_packing(PngPointer); 
bool BGneeded = (colortype > PNG_COLOR_TYPE_PALETTE); 
switch (colortype) 
{ 
    case PNG_COLOR_TYPE_GRAY: 
    { 
     png_set_expand_gray_1_2_4_to_8(PngPointer); 
     //png_set_expand(PngPointer); 
     //png_set_bgr(PngPointer); //R=G=B so there's no need to swap RGB values 
     png_set_gray_to_rgb(PngPointer); 
     break; 
    } 

    case PNG_COLOR_TYPE_PALETTE: 
    { 
     png_set_palette_to_rgb(PngPointer); 
     if (png_get_valid(PngPointer, InfoPointer, PNG_INFO_tRNS)) 
     { 
      png_set_tRNS_to_alpha(PngPointer); 
      BGneeded = true; 
     } 
     else 
      png_set_filler(PngPointer, 0xFF, PNG_FILLER_AFTER); 
     png_set_bgr(PngPointer); 
     BitsPerPixel = 32; 
     break; 
    } 

    case PNG_COLOR_TYPE_GRAY_ALPHA: 
    { 
     png_set_gray_to_rgb(PngPointer); 
     break; 
    } 

    case PNG_COLOR_TYPE_RGB: 
    { 
     png_set_bgr(PngPointer); 
     png_set_filler(PngPointer, 0xFF, PNG_FILLER_AFTER); 
     BitsPerPixel = 32; 
     break; 
    } 

    case PNG_COLOR_TYPE_RGBA: 
    { 
     png_set_bgr(PngPointer); 
     BitsPerPixel = 32; 
     break; 
    } 

    default: png_destroy_read_struct(&PngPointer, &InfoPointer, nullptr); throw std::runtime_error("Error: Png Type not supported."); break; 
} 

//SET BACKGROUND 
png_color_16 my_background; 
png_color_16p image_background; 

my_background.red = 255; 
my_background.green = 255; 
my_background.blue = 255; 

if (png_get_bKGD(PngPointer, InfoPointer, &image_background)) 
    png_set_background(PngPointer, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); 
else if (BGneeded) 
    png_set_background(PngPointer, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); 
//END SET BACKGROUND 

png_read_update_info(PngPointer, InfoPointer); 
channels = png_get_channels(PngPointer, InfoPointer); 
png_get_IHDR(PngPointer, InfoPointer, &width, &height, &bitdepth, &colortype, &interlacetype, nullptr, nullptr); 
+0

這工作。除了保存到PNG時,背景將變爲白色。我試圖將其保存爲加載圖像的完全副本。謝謝你嘗試。 – Brandon