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

使用libpng 1.6.39渐进式读取时始终提示IDAT压缩数据截断

libpng渐进式读取报错"Truncated compressed data in IDAT"排查

我在Linux环境下使用libpng 1.6.39(搭配zlib 1.2.13、GCC/C++ 12)的渐进式读取功能,但无论读取哪张PNG图像,都会收到警告:

Truncated compressed data in IDAT
且完全无法获取图像数据。

我的代码如下:

#include "png.h"
#include <unistd.h>
#include <iostream>
#include <iomanip>
#include <cstring>

void errorFn(png_structp png_ptr, png_const_charp error_msg) {
    std::cout << "user_error_fn(): " << error_msg << std::endl;
    _exit(1);
}

void warningFn(png_structp png_ptr, png_const_charp warning_msg) {
    std::cout << "user_warning_fn(): " << warning_msg << std::endl;
}

void infoCallback(png_structp png_ptr, png_infop info) {
    std::cout << "infoCallback()" << std::endl;
}

void rowCallback(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, int pass) {
    std::cout << "rowCallback(): row_num=" << std::dec << row_num << " pass=" << std::dec << pass << std::endl;
}

void endCallback(png_structp png_ptr, png_infop info) {
    std::cout << "endCallback(): " << std::endl;
}

int main(int argc, char const *argv[]) {
    FILE *fp(fopen("./libpng/1.6.39/contrib/testpngs/rgb-8.png", "rb"));
    std::cout << "fp=" << static_cast<void const *>(fp) << std::endl;
    std::cout << "fseek: " << fseek(fp, 0, SEEK_END) << std::endl;
    size_t const size(ftell(fp));
    std::cout << "ftell: " << size << std::endl;
    fseek(fp, 0, SEEK_SET);
    png_bytep buf(new png_byte[size]);
    memset(buf, 0, size);
    std::cout << "fread: " << fread(buf, 1, size, fp) << std::endl;
    fclose(fp);

    png_structp png_ptr(png_create_read_struct(PNG_LIBPNG_VER_STRING, buf, errorFn, warningFn));
    png_infop info_ptr(png_create_info_struct(png_ptr));

    png_set_progressive_read_fn(png_ptr, buf, infoCallback, rowCallback, endCallback);
    png_process_data(png_ptr, info_ptr, buf, size);


    png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);

    delete[] buf;

    return 0;
}

程序输出示例如下:

fp=0x47eeb0
fseek: 0
ftell: 759
fread: 759
infoCallback()
user_warning_fn(): Truncated compressed data in IDAT
endCallback():

我原本预期rowCallback()会被多次调用,且不会出现任何警告或错误。请问我哪里操作有误?


问题排查与修正

你的核心错误有两个:错误复用图像缓冲区作为lib私有数据指针,以及未配置渐进式读取的必要解码参数,具体如下:

1. 私有数据指针误用

png_create_read_struct和png_set_progressive_read_fn的第二个参数是用户私有数据指针,你直接传入了存储图像数据的buf,这会导致libpng内部操作破坏原始图像数据,进而触发"Truncated compressed data"警告。

应该传入独立的用户数据(比如nullptr,如果不需要自定义数据的话),避免干扰图像缓冲区。

2. 缺少解码格式配置与初始化

渐进式读取需要在infoCallback中明确配置图像格式转换规则,并启动行读取初始化,否则libpng无法解码出行数据,rowCallback自然不会触发。

修正后的完整代码

#include "png.h"
#include <unistd.h>
#include <iostream>
#include <iomanip>
#include <cstring>

void errorFn(png_structp png_ptr, png_const_charp error_msg) {
    std::cout << "user_error_fn(): " << error_msg << std::endl;
    _exit(1);
}

void warningFn(png_structp png_ptr, png_const_charp warning_msg) {
    std::cout << "user_warning_fn(): " << warning_msg << std::endl;
}

void infoCallback(png_structp png_ptr, png_infop info) {
    std::cout << "infoCallback()" << std::endl;
    // 配置通用格式转换,适配多数PNG图像
    png_set_expand(png_ptr);
    png_set_strip_16(png_ptr);
    png_set_packing(png_ptr);
    png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); // 转换为RGBA格式
    // 初始化渐进式行读取缓冲区
    png_start_read_image(png_ptr);
}

void rowCallback(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, int pass) {
    std::cout << "rowCallback(): row_num=" << std::dec << row_num << " pass=" << std::dec << pass << std::endl;
}

void endCallback(png_structp png_ptr, png_infop info) {
    std::cout << "endCallback(): " << std::endl;
}

int main(int argc, char const *argv[]) {
    FILE *fp(fopen("./libpng/1.6.39/contrib/testpngs/rgb-8.png", "rb"));
    std::cout << "fp=" << static_cast<void const *>(fp) << std::endl;
    std::cout << "fseek: " << fseek(fp, 0, SEEK_END) << std::endl;
    size_t const size(ftell(fp));
    std::cout << "ftell: " << size << std::endl;
    fseek(fp, 0, SEEK_SET);
    png_bytep buf(new png_byte[size]);
    memset(buf, 0, size);
    std::cout << "fread: " << fread(buf, 1, size, fp) << std::endl;
    fclose(fp);

    // 私有数据指针改为nullptr,避免干扰图像缓冲区
    png_structp png_ptr(png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, errorFn, warningFn));
    png_infop info_ptr(png_create_info_struct(png_ptr));

    png_set_progressive_read_fn(png_ptr, nullptr, infoCallback, rowCallback, endCallback);
    png_process_data(png_ptr, info_ptr, buf, size);

    png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);

    delete[] buf;

    return 0;
}

修正说明

  • 将用户私有数据指针从buf改为nullptr,确保图像数据不被libpng误修改
  • 在infoCallback中添加格式转换规则,并调用png_start_read_image初始化行读取逻辑,保证rowCallback能正常触发

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 08:44:55