【问题标题】:Z_DATA_ERROR when trying to inflate png IDAT chunk尝试膨胀 png IDAT 块时出现 Z_DATA_ERROR
【发布时间】:2019-04-27 17:21:14
【问题描述】:

我无法将 png IDAT 块膨胀回 RGB 数据。

void PNG::IDAT()
{
    int index = 0;
    char CMF = m_data[index];
    index++;

    //big endian
    char CM = CMF & 0b00001111;
    char CINFO = CMF & 0b11110000; 
    //For CM = 8, CINFO is the base-2 logarithm of the LZ77 window  size, minus eight(CINFO = 7 indicates a 32K window size).

    char FLG = m_data[index];
    index++;

    char FCHECK = FLG & 0b00011111; 
    //The FCHECK value must be such that CMF and FLG, when viewed as a 16 - bit unsigned integer stored in MSB order(CMF * 256 + FLG),  is a multiple of 31. //effort
    char FDICT =  FLG & 0b00100000;
    char FLEVEl = FLG & 0b11000000;

    char DICTID[4];
    if (FDICT > 0)
    {
        memcpy(DICTID, &m_data[index], 4);
        index += 4;
    }

    uLong outputLength = compressBound(m_length); 
    char* output = new char[outputLength];


    z_stream infstream;
    infstream.zalloc = Z_NULL;
    infstream.zfree = Z_NULL;
    infstream.opaque = Z_NULL;
    infstream.avail_in = m_length; // size of input
    infstream.next_in = (Bytef *)m_data; // input char array
    infstream.avail_out = outputLength; // size of output
    infstream.next_out = (Bytef *)output; // output char array

    inflateInit2(&infstream, 16 + MAX_WBITS);
    inflate(&infstream, Z_NO_FLUSH);
    inflateEnd(&infstream);


    for (size_t i = 0; i < outputLength; i+= 3)
    {
        pixel temp;
        temp.r = output[i + 0];
        temp.g = output[i + 1];
        temp.b = output[i + 2];
        m_pixels.push_back(temp);
    }
}

Inflate 返回错误代码 -3,表示“Z_DATA_ERROR”。我遵循了 RFC-1950 和 RFC-1951 标准,但我对哪些字节实际上需要流式传输到 inflate 函数以及哪些需要被剥离感到困惑。 m_data 实际上只是块中的数据,没有长度、类型和 CRC。 m_length 又只是该块给定的长度。

输入也是纯 RGB,压缩模式 0,过滤模式 0 和隔行模式 0。

CM 是 8。

CMINFO 是 112。

FCHECK 为 30。

FDICT 为 0。

FLEVEL 为 64。

TL;DR: 究竟 zlib 中的 inflate 函数想要/需要什么?

这也是我正在尝试读取的图像的十六进制值的图片。 picture link because stackoverflow doesn't allow new users to post pics

【问题讨论】:

  • 该文本图片是否显示了您尝试解压缩的确切起点?它从其他一些未压缩的数据块开始。
  • @usr2564301 啊,我的错,这是全图link

标签: c++ binary png zlib inflate


【解决方案1】:

IDAT 之后的 78 5e ed d1 ... 是 zlib 流的开始。它长 288 字节,是一个有效的 zlib 流,与所有 PNG 数据一样。如果您已正确读取数据,输入正确的部分以进行膨胀,并提供足够的输出空间(请参阅下面的 #2),那么它将起作用。

您的代码中有一些 cmets:

  1. 您无需尝试解码 zlib 标头。只需喂饱整个东西就可以充气了。
  2. compressBound() 在这里没有用。那只是用于压缩,而不是解压缩。 228 字节的压缩数据解压缩为 47,234 字节。远远超出您分配的空间。
  3. 生成的解压缩数据不是原始 RGB 像素。图像的每一行都以一个过滤字节开始,行中剩余的字节需要进行相应的解释。
  4. 您需要检查 zlib 函数的返回码和错误。 总是检查返回码。总是。

【讨论】:

  • 但是您应该使用什么来查找输出缓冲区的大小?我想你可以根据头文件中的所有信息用PNG来计算它,但否则这只是一个疯狂的猜测,对吧?您是否只是应该获得很大的利润,以免达到限制,或者是否有某种最佳情况下的压缩率可以作为其大小的基础?
  • 你可以从header信息中精确计算出来。
  • 47234 == 113 * (1 + 139 * 3)。 1 是每一行的过滤字节。
猜你喜欢
  • 2018-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-14
  • 1970-01-01
  • 2019-12-07
  • 2017-09-19
相关资源
最近更新 更多