1

我在加载一些特定的 png 图像时遇到了一些问题。这里有一些有用的图片。

  1. 图片 #1 www.silexars.com/image.png(无法正确加载)
  2. 图片 #2 www.silexars.com/image2.png(加载良好)
  3. 使用 OpenGL 渲染的图像 #1 的屏幕截图 http://www.silexars.com/screenshot.jpg
  4. 打开两个图像的 PNG 分析器的屏幕截图: http ://www.silexars.com/screenshot.png Image #1 @ Left,Image #2 @ Right

我注意到左边的图像有一个叫做 cHRM 的块,我相信我必须以某种方式转换它。有人会帮我解决这个问题吗?

我用于加载 png 文件的代码是:

uint8 Graphics::Image::loadPNG(FILE *fp) {
uint8 header[8];
fread(header,sizeof(header),1,fp);
if (png_sig_cmp(header,0,sizeof(header))) return INVALID_FILE;
png_structp png;
png_infop info;

png = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0);
if (!png) return FAILURE;
info = png_create_info_struct(png);
if (!info) {
    png_destroy_read_struct(&png,0,0);
    return FAILURE;
}

png_init_io(png,fp);\
png_set_sig_bytes(png,sizeof(header));

png_read_info(png,info);

delete[] data;
data = 0;

int32 bitdepth,colortype;
png_get_IHDR(png,info,&width,&height,&bitdepth,&colortype,0,0,0);

if (colortype == PNG_COLOR_TYPE_PALETTE) {
    png_set_palette_to_rgb(png);
}
if (colortype == PNG_COLOR_TYPE_GRAY && bitdepth < 8) {
    png_set_expand_gray_1_2_4_to_8(png);
}
if (colortype == PNG_COLOR_TYPE_GRAY || colortype == PNG_COLOR_TYPE_GRAY_ALPHA) {
    png_set_gray_to_rgb(png);
}
if (png_get_valid(png, info, PNG_INFO_tRNS)) {
    png_set_tRNS_to_alpha(png);
}
if (colortype == PNG_COLOR_TYPE_RGB) {
    png_set_filler(png, 0xff, PNG_FILLER_AFTER);
}
if (bitdepth == 16) {
    png_set_strip_16(png);
}
if (bitdepth < 8)
    png_set_packing(png);

png_read_update_info(png,info);
png_get_IHDR(png,info,&width,&height,0,0,0,0,0);

int32 rowbytes = png_get_rowbytes(png,info);

std::cout << rowbytes/bpp << std::endl;

data = new uint8[rowbytes*height];
png_bytep *row_pointers = new png_bytep[height*sizeof(png_bytep)];
for (int i = 0; i < height; i++)
    row_pointers[height-1-i] = data + i * rowbytes;

png_read_image(png, row_pointers);

png_read_end(png,0);

delete[] row_pointers;
png_destroy_read_struct(&png,&info,0);
return OK;
}

希望信息足够。但是,如果您需要任何额外的数据,请问我。

4

1 回答 1

1

第一个图像中的 cHRM 块与 iCCP 块中包含的颜色配置文件不一致。最好忽略 cHRM 块。但是您的代码已经忽略了 cHRM 和 iCCP 块。您可以使用 png_set_keep_unknown_chunks() 完全忽略它们,以防其中一个导致您看到的麻烦(即使您的代码忽略它们,libpng 也会处理它们,除非您使用 png_set_keep_unknown_chunks() 告诉 libpng 永远不要处理它们)。

例如,由于您忽略了应用程序中的所有辅助块,因此告诉 libpng 甚至不要处理它们:

`
    #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
    /* prepare the reader to ignore all recognized chunks whose data won't be
     * used, i.e., all chunks recognized by libpng except for IHDR, PLTE, IDAT,
     * IEND, tRNS, bKGD, gAMA, and sRGB (small performance improvement) */
    {
        /* These byte strings were copied from png.h.  If a future libpng
         * version recognizes more chunks, add them to this list.  If a
         * future version of readpng2.c recognizes more chunks, delete them
         * from this list. */
        static /* const */ png_byte chunks_to_ignore[] = {
             99,  72,  82,  77, '\0',  /* cHRM */
            104,  73,  83,  84, '\0',  /* hIST */
            105,  67,  67,  80, '\0',  /* iCCP */
            105,  84,  88, 116, '\0',  /* iTXt */
            111,  70,  70, 115, '\0',  /* oFFs */
            112,  67,  65,  76, '\0',  /* pCAL */
            112,  72,  89, 115, '\0',  /* pHYs */
            115,  66,  73,  84, '\0',  /* sBIT */
            115,  67,  65,  76, '\0',  /* sCAL */
            115,  80,  76,  84, '\0',  /* sPLT */
            115,  84,  69,  82, '\0',  /* sTER */
            116,  69,  88, 116, '\0',  /* tEXt */
            116,  73,  77,  69, '\0',  /* tIME */
            122,  84,  88, 116, '\0'   /* zTXt */
        };

        png_set_keep_unknown_chunks(png_ptr, 1 /* PNG_HANDLE_CHUNK_NEVER */,
          chunks_to_ignore, sizeof(chunks_to_ignore)/5);
    }
    #endif`

从 libpng-1.6.0 开始,它要容易得多。您可以通过在调用中放置“-1”而不是列出要忽略的块来忽略除 tRNS 块之外的所有辅助块:

`
    png_set_keep_unknown_chunks(png,PNG_HANDLE_CHUNK_NEVER, -1, NULL, -1);`

有关此示例,请参阅与 libpng 一起分发的“contrib/gregbook/readpng2.c”。

更新:cHRM 块不一定不一致。最新版本的 ImageMagick 报告它不一致,但这似乎是 ImageMagick 中的一个错误。尽管如此,最好使用 png_set_keep_unknown_chunks() 来避免对您不会使用的辅助块进行不必要的处理。

于 2013-02-24T03:24:38.213 回答