如何使用libpng库读取16位深度灰度图像的正确像素值
问题根源
你遇到的问题是类型使用错误导致只读取了16位像素的8位数值:
png_bytepp本质是unsigned char**类型,每个元素只能存储8位数据,16位灰度图每个像素占连续2字节的存储空间,你用rows[h][w]索引时只会取到第一个字节的数值,范围自然只能到255。- 额外的潜在问题:Windows平台下读取二进制文件需要用
rb模式打开,否则可能因换行符转换导致文件读取异常;原代码缺少必要的错误判断逻辑,遇到异常文件会直接崩溃。
修复方案
你需要将行指针转换为16位无符号整数类型指针,正确读取2字节的像素值,同时补充必要的校验逻辑,修复后的代码如下:
#include <stdio.h> #include <png.h> #include <stdint.h> int main(void) { // 二进制模式打开文件,兼容Windows平台 FILE *fp = fopen("sample.png", "rb"); if (!fp) { printf("文件打开失败\n"); return 1; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fclose(fp); return 1; } png_infop png_info = png_create_info_struct(png_ptr); if (!png_info) { png_destroy_read_struct(&png_ptr, NULL, NULL); fclose(fp); return 1; } // libpng错误跳转处理,读取失败时不会直接崩溃 if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &png_info, NULL); fclose(fp); return 1; } png_init_io(png_ptr, fp); png_read_png(png_ptr, png_info, PNG_TRANSFORM_IDENTITY, NULL); int WIDTH = png_get_image_width(png_ptr, png_info); int HEIGHT = png_get_image_height(png_ptr, png_info); int bit_depth = png_get_bit_depth(png_ptr, png_info); int color_type = png_get_color_type(png_ptr, png_info); // 校验图像格式是否为16位灰度图 if (color_type != PNG_COLOR_TYPE_GRAY || bit_depth != 16) { printf("图像不是16位灰度图\n"); png_destroy_read_struct(&png_ptr, &png_info, NULL); fclose(fp); return 1; } // 将行指针转换为16位无符号整数类型 png_uint_16pp rows = (png_uint_16pp)png_get_rows(png_ptr, png_info); for (int h = 0; h < HEIGHT; h++) { for (int w = 0; w < WIDTH; w++) { // 打印16位像素值,范围0~65535 printf("%u ", rows[h][w]); } printf("\n"); } // 释放资源 png_destroy_read_struct(&png_ptr, &png_info, NULL); fclose(fp); return 0; }
注意:libpng返回的16位像素值默认是大端字节序,如果你运行的平台是小端字节序(比如x86、x86_64架构),可以在
png_read_png的转换参数中加入PNG_TRANSFORM_SWAP_ENDIAN宏,自动转换为本地字节序,避免数值错误。
内容的提问来源于stack exchange,提问作者Phan Chính Quân
相关产品推荐
相关产品推荐

