解压缩Deflate

时间:2014-03-24 04:29:37

标签: c++ deflate

我正在开发一个可以解压缩deflate压缩的函数,所以我可以在我的c ++程序中读取/绘制png文件。但是,在某些方面,deflate规范并不十分明确。

所以我的主要问题是: 第3.2.7段。使用规范的动态霍夫曼代码(BTYPE = 10)进行压缩 距离代码遵循文字/长度

但它没有说明距离代码占用了多少位,是整个字节吗? 距离代码是如何关联的?它是什么用的,真的吗?

任何人都有一般性的解释吗?因为规范有点缺乏清晰度。 我在这里找到的规范: http://www.ietf.org/rfc/rfc1951.txt

编辑(以下是我使用粉扑膨胀代码的以下代码。)

首先是标题(ConceptApp.h)

#include "resource.h"

#ifdef _WIN64
typedef unsigned long long SIZE_PTR;
#else
typedef unsigned long SIZE_PTR;
#endif

typedef struct _IMAGE {
DWORD Width;           //Width in pixels.
DWORD Height;          //Height in pixels.
DWORD BitsPerPixel;    //24 (RGB), 32 (RGBA).
DWORD Planes;          //Count of color planes
PBYTE Pixels;          //Pointer to the first pixel of the image.
} IMAGE, *PIMAGE;

typedef DWORD LodePNGColorType;

typedef struct _LodePNGColorMode {
DWORD colortype;
DWORD bitdepth;
} LodePNGColorMode;

typedef struct LodePNGInfo
{
/*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/
unsigned compression_method;/*compression method of the original file. Always 0.*/
unsigned filter_method;     /*filter method of the original file*/
unsigned interlace_method;  /*interlace method of the original file*/
LodePNGColorMode color;     /*color type and bits, palette and transparency of the PNG file*/
} LodePNGInfo;

typedef struct _ZLIB {
BYTE CMF;
BYTE FLG;
//DWORD DICTID; //if FLG.FDICT (Bit 5) is set, this variable follows.
//Compressed data here...
} ZLIB, *PZLIB;

typedef struct _PNG_IHDR {
DWORD Width;
DWORD Height;
BYTE BitDepth;
BYTE ColourType;
BYTE CompressionMethod;
BYTE FilterMethod;
BYTE InterlaceMethod;
} PNG_IHDR, *PPNG_IHDR;

typedef struct _PNG_CHUNK {
DWORD Length;
CHAR ChuckType[4];
} PNG_CHUNK, *PPNG_CHUNK;

typedef struct _PNG {
BYTE Signature[8];
PNG_CHUNK FirstChunk;
} PNG, *PPNG;

代码.cpp文件: 主函数可以在文件的底部找到(LoadPng)

BYTE LoadPng(PPNG PngFile, PIMAGE ImageData)
{
PDWORD Pixel = 0;
DWORD ChunkSize = 0;
PPNG_IHDR PngIhdr = (PPNG_IHDR) ((SIZE_PTR) &PngFile->FirstChunk + sizeof(PNG_CHUNK));
DWORD Png_Width = Png_ReadDword((PBYTE)&PngIhdr->Width);
DWORD Png_Height = Png_ReadDword((PBYTE)&PngIhdr->Height);
DWORD BufferSize = (Png_Width*Png_Height) * 8; //This just a guess right now, havent done the math yet. !!!
ChunkSize = Png_ReadDword((PBYTE)&PngFile->FirstChunk.Length);
PPNG_CHUNK ThisChunk = (PPNG_CHUNK) ((SIZE_PTR)&PngFile->FirstChunk + ChunkSize + 12); //12 is the length var itself, Chunktype and CRC.
PPNG_CHUNK NextChunk;
PBYTE UncompressedData = (PBYTE) malloc(BufferSize);
INT RetValue = 0;

do
{
    ChunkSize = Png_ReadDword((PBYTE)&ThisChunk->Length);
    NextChunk = (PPNG_CHUNK) ((SIZE_PTR)ThisChunk + ChunkSize + 12); //12 is the length var itself, Chunktype and CRC.

    if (Png_IsChunk(ThisChunk->ChuckType, "IDAT")) //Is IDAT ?
    {
        PZLIB iData = (PZLIB) ((SIZE_PTR)ThisChunk + 8); //8 is the length and chunkType.

        PBYTE FirstBlock; //ponter to the first 3 bits of the deflate stuff.

        if ((iData->CMF & 8) == 8) //deflate compression method.
        {
            if ((iData->FLG & 0x20) == 0x20)
            {
                FirstBlock = (PBYTE) ((SIZE_PTR)iData + 6); //DICTID Present.
            }
            else FirstBlock = (PBYTE) ((SIZE_PTR)iData + 2); //DICTID Not present.

            RetValue = puff(UncompressedData, &BufferSize, FirstBlock, &ChunkSize); //I belive chunksize should be fine.

            if (RetValue != 0)
            {
                WCHAR ErrorText[100];
                swprintf_s(ErrorText, 100, L"%u", RetValue); //Convert data into string.
                MessageBox(NULL, ErrorText, NULL, MB_OK);
            }
        }
    }
    ThisChunk = NextChunk;
} while (!Png_IsChunk(ThisChunk->ChuckType, "IEND"));

//LodePNGInfo ImageInfo;
//PBYTE Png_Real_Image = (PBYTE) malloc(BufferSize);
//ImageInfo.compression_method = PngIhdr->CompressionMethod;
//ImageInfo.filter_method = PngIhdr->FilterMethod;
//ImageInfo.interlace_method = PngIhdr->InterlaceMethod;
//ImageInfo.color.bitdepth = PngIhdr->BitDepth;
//ImageInfo.color.colortype = PngIhdr->ColourType;

//Remove Filter/crap blah blah.
//postProcessScanlines(Png_Real_Image, UncompressedData, Png_Width, Png_Height, &ImageInfo);

ImageData->Width = Png_Width;
ImageData->Height = Png_Height;
ImageData->Planes = 0; //Will need changed later.
ImageData->BitsPerPixel = 32; //Will need changed later.

ImageData->Pixels = 0;
//ImageData->Pixels = Png_Real_Image; //image not uncompressed yet.

return TRUE; //ret true for now. fix later.
}

3 个答案:

答案 0 :(得分:1)

问题不在于粉扑。 在调用puff之前,需要将png文件中的所有IDAT块放在一起。

看起来应该是这样的:

BYTE LoadPng(PPNG PngFile, PIMAGE ImageData)
{
PDWORD Pixel = 0;
DWORD ChunkSize = 0;
PPNG_IHDR PngIhdr = (PPNG_IHDR) ((SIZE_PTR) &PngFile->FirstChunk + sizeof(PNG_CHUNK));
DWORD Png_Width = Png_ReadDword((PBYTE)&PngIhdr->Width);
DWORD Png_Height = Png_ReadDword((PBYTE)&PngIhdr->Height);
DWORD BufferSize = (Png_Width*Png_Height) * 8; //This just a guess right now, havent done the math yet. !!!
ChunkSize = Png_ReadDword((PBYTE)&PngFile->FirstChunk.Length);
PPNG_CHUNK ThisChunk = (PPNG_CHUNK) ((SIZE_PTR)&PngFile->FirstChunk + ChunkSize + 12); //12 is the length var itself, Chunktype and CRC.
PPNG_CHUNK NextChunk;
PBYTE UncompressedData = (PBYTE) malloc(BufferSize);
PBYTE TempBuffer = (PBYTE) malloc(BufferSize); //Put all idat chunks together befor uncompressing.
DWORD DeflateSize = 0; //All IDAT Chunks Added.
PZLIB iData = NULL;
PBYTE FirstBlock = NULL; //ponter to the first 3 bits of the deflate stuff.
INT RetValue = 0;

do
{
    ChunkSize = Png_ReadDword((PBYTE)&ThisChunk->Length);
    NextChunk = (PPNG_CHUNK) ((SIZE_PTR)ThisChunk + ChunkSize + 12); //12 is the length var itself, Chunktype and CRC.

    if (Png_IsChunk(ThisChunk->ChuckType, "IDAT")) //Is IDAT ?
    {
        CopyMemory(&TempBuffer[DeflateSize], (PBYTE) ((SIZE_PTR)ThisChunk + 8), ChunkSize); //8 is the length and chunkType.
        DeflateSize += ChunkSize;
    }
    ThisChunk = NextChunk;
} while (!Png_IsChunk(ThisChunk->ChuckType, "IEND"));

iData = (PZLIB) TempBuffer;
if ((iData->CMF & 8) == 8) //deflate compression method.
{
    if ((iData->FLG & 0x20) == 0x20)
    {
        FirstBlock = (PBYTE) ((SIZE_PTR)iData + 6); //DICTID Present.
    }
    else FirstBlock = (PBYTE) ((SIZE_PTR)iData + 2); //DICTID Not present.
}

RetValue = puff(UncompressedData, &BufferSize, FirstBlock, &DeflateSize); //I belive chunksize should be fine.

if (RetValue != 0)
{
    WCHAR ErrorText[100];
    swprintf_s(ErrorText, 100, L"%u", RetValue);
    MessageBox(NULL, ErrorText, NULL, MB_OK);
}

//LodePNGInfo ImageInfo;
//PBYTE Png_Real_Image = (PBYTE) malloc(BufferSize);
//ImageInfo.compression_method = PngIhdr->CompressionMethod;
//ImageInfo.filter_method = PngIhdr->FilterMethod;
//ImageInfo.interlace_method = PngIhdr->InterlaceMethod;
//ImageInfo.color.bitdepth = PngIhdr->BitDepth;
//ImageInfo.color.colortype = PngIhdr->ColourType;

//Remove Filter/crap blah blah.
//postProcessScanlines(Png_Real_Image, UncompressedData, Png_Width, Png_Height, &ImageInfo);

ImageData->Width = Png_Width;
ImageData->Height = Png_Height;
ImageData->Planes = 0; //Will need changed later.
ImageData->BitsPerPixel = 32; //Will need changed later.

ImageData->Pixels = 0;
//ImageData->Pixels = Png_Real_Image; //image not uncompressed yet.

return TRUE; //ret true for now. fix later.
}

答案 1 :(得分:0)

你需要先阅读压缩,因为你有很多基本的东西没有得到。例如。 数据压缩书,作者:Nelson和Gailly。

由于它是一个代码,特别是一个霍夫曼代码,根据定义,位数是可变的。

如果你不知道距离是什么,那么你需要先了解LZ77 compression approach

最后,除了好奇心和自我教育之外,您无需了解deflate规范或编写自己的膨胀代码。这是zlib的用途。

答案 2 :(得分:0)

我希望能够更清楚地说明之前的内容 - 霍夫曼编码是一种使用可变位数编码值的方法。例如,在ASCII编码中,无论使用频率如何,每个字母都会获得相同的位数。在霍夫曼编码中,你可以制作" e"比#" X"。

的位数少

霍夫曼编码的技巧是代码如何加前缀。读取每个位后,解码器明确地知道它是否有值或需要读取另一位。

要理解放气过程,您需要了解LZ算法和霍夫曼编码。

就他们自己而言,这两种技巧都很简单。复杂性来自它们的组合方式。

LZ通过查找先前出现的字符串进行压缩。如果先前发生了字符串,则会通过引用前一个匹配项来压缩它。距离是前一次出现的偏移量。距离和长度指定该事件。