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

使用libpng读取PNG像素数据遇阻,寻求最后步骤解决方案

解决libpng读取像素数据失败的问题

核心问题分析

你的代码存在几个关键问题,导致无法正确读取像素数据:

  • 缺少libpng错误处理机制:libpng依赖setjmp/longjmp处理错误,未设置的话出错会直接终止程序,且无法获取具体错误信息。
  • 错误的API使用逻辑:png_read_png已经完成了像素数据的读取与内存分配,后续调用png_read_image属于重复操作且会触发错误;另外你尝试打印像素时用了%s格式符,会把单个字节当作字符串指针,引发未定义行为。
  • 内存分配缺失:使用png_read_image时,未给行指针数组分配有效内存空间。

修正后的完整代码

#include <png.h>
#include <pngconf.h>
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>

#define BYTES_TO_CHECK 8

// 全局错误跳转缓冲区
jmp_buf png_error_jmpbuf;

// libpng错误回调函数
void png_error_fn(png_structp png_ptr, png_const_charp msg) {
    fprintf(stderr, "PNG Error: %s\n", msg);
    longjmp(png_error_jmpbuf, 1);
}

// 校验PNG文件并返回文件指针
FILE *check_png(char *file_name) {
    char buffer[BYTES_TO_CHECK];
    FILE *fP = fopen(file_name, "rb");
    if (fP == NULL) {
        fprintf(stderr, "FILE NOT FOUND!\n");
        exit(EXIT_FAILURE);
    }
    size_t read_bytes = fread(buffer, 1, BYTES_TO_CHECK, fP);
    if (read_bytes != BYTES_TO_CHECK) {
        fprintf(stderr, "Failed to read PNG signature\n");
        fclose(fP);
        exit(EXIT_FAILURE);
    }
    int check = png_sig_cmp(buffer, 0, BYTES_TO_CHECK);
    if (check != 0) {
        fprintf(stderr, "NOT A PNG\n");
        fclose(fP);
        exit(EXIT_FAILURE);
    }
    return fP;
}

int main() {
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    png_uint_32 height, width;
    int bit_depth, color_type;
    png_bytepp row_pointers = NULL;

    printf("ASCII Generator\nPlease Enter the PNG file name\t");
    char file_name[100] = "google.png";
    // scanf("%s", file_name);
    FILE *fP = check_png(file_name);

    // 创建读取结构体,指定错误回调
    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, png_error_fn, NULL);
    if (png_ptr == NULL) {
        fprintf(stderr, "ERROR PNG POINTER IS NULL\n");
        fclose(fP);
        exit(EXIT_FAILURE);
    }

    // 创建信息结构体
    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
        fprintf(stderr, "ERROR INFO POINTER IS NULL\n");
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        fclose(fP);
        exit(EXIT_FAILURE);
    }

    // 设置错误跳转点,捕获libpng的错误
    if (setjmp(png_error_jmpbuf)) {
        // 发生错误时清理所有资源
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        fclose(fP);
        exit(EXIT_FAILURE);
    }

    // 初始化IO
    png_init_io(png_ptr, fP);
    png_set_sig_bytes(png_ptr, BYTES_TO_CHECK);

    // 读取PNG文件信息和像素数据(自动分配内存)
    png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);

    // 获取图像基本信息
    height = png_get_image_height(png_ptr, info_ptr);
    width = png_get_image_width(png_ptr, info_ptr);
    bit_depth = png_get_bit_depth(png_ptr, info_ptr);
    color_type = png_get_color_type(png_ptr, info_ptr);
    printf("Image Size: %ux%u\nBit Depth: %d\nColor Type: %d\n", width, height, bit_depth, color_type);

    // 获取由png_read_png分配好的像素行指针
    row_pointers = png_get_rows(png_ptr, info_ptr);
    if (row_pointers == NULL) {
        fprintf(stderr, "Failed to get row pointers\n");
        goto cleanup;
    }

    // 示例:打印第0行第50个像素的通道值(根据颜色类型适配)
    printf("Sample pixel data (row 0, column 50): ");
    if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
        int channel_count = (color_type == PNG_COLOR_TYPE_RGB) ? 3 : 4;
        png_byte r = row_pointers[0][50 * channel_count];
        png_byte g = row_pointers[0][50 * channel_count + 1];
        png_byte b = row_pointers[0][50 * channel_count + 2];
        printf("R: %u, G: %u, B: %u", r, g, b);
        if (channel_count == 4) {
            png_byte a = row_pointers[0][50 * 4 + 3];
            printf(", A: %u", a);
        }
        printf("\n");
    } else if (color_type == PNG_COLOR_TYPE_GRAY) {
        png_byte gray = row_pointers[0][50];
        printf("Gray: %u\n", gray);
    }

cleanup:
    // 统一清理资源
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    fclose(fP);
    return EXIT_SUCCESS;
}

关键修正点说明

  1. 添加错误处理机制:通过setjmp和自定义错误回调,捕获libpng的错误并友好退出,同时确保所有资源被正确释放。
  2. 正确使用png_read_png:该函数会自动完成像素数据的读取和内存分配,调用后直接通过png_get_rows获取行指针即可,无需再调用其他读取像素的API。
  3. 修复像素打印逻辑:根据图像的颜色类型(RGB、RGBA、灰度)计算通道偏移量,用%u格式符打印单个字节的数值,避免字符串指针错误。
  4. 版本号兼容性:用PNG_LIBPNG_VER_STRING宏代替硬编码的版本号,保证代码在不同libpng版本下的兼容性。
  5. 完善资源清理:所有代码分支都确保释放libpng结构体和关闭文件,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 08:09:57