You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

libpng加载单色图片时png_get_rows返回异常的解决及检测方法

解决libpng加载单色PNG时行指针复用及单色图检测问题

一、获取完整像素数据(即使是单色图)

libpng会对单色PNG做内存优化,比如让所有行指针指向同一块内存,但你可以手动将行数据复制到自己的缓冲区,确保拿到完整的所有像素数据。修改你的代码如下:

String path = PathHelper::GetAssetsPath();
path += name; // white.png

png_uint_32 width, height;
png_structp pngStruct{};
png_infop pngInfo{};
FILE* file = 0;
unsigned char* data = 0;

file = fopen(path, "rb");
FOG_ASSERT(file != 0);

pngStruct = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
FOG_ASSERT(pngStruct != 0);

pngInfo = png_create_info_struct(pngStruct);
FOG_ASSERT(pngInfo != 0);


if (setjmp(png_jmpbuf(pngStruct))) 
{
    png_destroy_read_struct(&pngStruct, &pngInfo, 0);
    fclose(file);
    FOG_ASSERT(false);
}

png_init_io(pngStruct, file);

int numBytes = 0;
png_set_sig_bytes(pngStruct, numBytes);

// 保留原有转换参数,确保颜色格式完全展开
png_read_png(pngStruct, pngInfo, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL);
png_get_IHDR(pngStruct, pngInfo, &width, &height, 0, 0, 0, 0, 0);

size_t row_bytes = png_get_rowbytes(pngStruct, pngInfo);
data = new unsigned char[row_bytes * height];

png_bytepp row_pointers = png_get_rows(pngStruct, pngInfo);

// 手动复制每一行数据到自定义缓冲区,规避行指针复用问题
for (png_uint_32 i = 0; i < height; ++i) {
    memcpy(data + i * row_bytes, row_pointers[i], row_bytes);
}

执行完这段代码后,data缓冲区就会存储所有像素的完整数据,不受libpng优化逻辑的影响。

二、检测PNG是否为单色图

提供两种检测方式,按需选择:

1. 基于PNG元信息快速判断(仅适用于特定格式单色图)

通过解析PNG的颜色类型、调色板等元数据快速判断:

  • 索引色格式(PNG_COLOR_TYPE_PALETTE):检查调色板颜色数量是否为1
  • 灰度格式(PNG_COLOR_TYPE_GRAY):结合位深度初步判断(1bit灰度图大概率是单色,但需进一步验证)
  • RGB/RGBA格式:无法通过元信息快速判断,必须遍历像素

代码示例:

bool isMonochrome = false;
int color_type = png_get_color_type(pngStruct, pngInfo);

if (color_type == PNG_COLOR_TYPE_PALETTE) {
    // 获取调色板颜色数量
    int palette_count = png_get_plte(pngStruct, pngInfo, NULL, NULL);
    if (palette_count == 1) {
        isMonochrome = true;
    }
} else if (color_type == PNG_COLOR_TYPE_GRAY) {
    png_byte bit_depth = png_get_bit_depth(pngStruct, pngInfo);
    // 1bit灰度图只有两种灰度值,若为单色图则所有像素值一致
    if (bit_depth == 1) {
        // 这里可结合行指针是否全部相同做初步判断,准确判断仍需遍历
        isMonochrome = true;
    }
}

2. 遍历像素检测(最可靠,支持所有格式)

直接获取第一个像素的颜色值,遍历所有像素逐一对比,是最准确的检测方式:

bool isMonochrome = true;
size_t pixel_size = row_bytes / width; // 每个像素的字节数(灰度=1,RGB=3,RGBA=4)

// 取第一个像素的颜色作为基准
unsigned char* base_pixel = data;

// 遍历所有像素
for (png_uint_32 y = 0; y < height; ++y) {
    unsigned char* current_row = data + y * row_bytes;
    for (png_uint_32 x = 0; x < width; ++x) {
        unsigned char* current_pixel = current_row + x * pixel_size;
        // 对比每个颜色通道
        for (size_t c = 0; c < pixel_size; ++c) {
            if (current_pixel[c] != base_pixel[c]) {
                isMonochrome = false;
                goto end_check; // 找到不同像素直接终止检测
            }
        }
    }
}
end_check:

内容的提问来源于stack exchange,提问作者DownloaderGames

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 13:05:23