LZW壓縮算法-TIFF版本

LZW壓縮算法-TIFF版本
LZW壓縮算法-TIFF版本

LZW壓縮算法, 三位發眀家『Lemple』『Ziv』『Welch』首字母組合而蒞.

LZW『壓縮』『解壓』算法極高速無損,算法基於『字符串表string_table, 映射代碼Code』和『字符串string,重要它極易實現. 易於嵌入程式, 壓縮數據.

LZW壓縮

 

STRING

字符/數據, 文本代表字符, 圖像代表數值

prefix

前綴字符串

suffix

後綴字符串

+

連接字符串

code

代碼,字符串代碼編號.

string_table

字典/字符串表存放『代碼Code』和『字符串string

首先定義『STRING字符串』結构.

typedef struct LZW_STRING_TYP {

 

        int code;

代碼,代碼應盡量短,至多12Bit

        BYTE data[64];

字符/數據 

        int  length;

字符/數據長度

}LZW_STRING, * LZW_STRING_PTR;

 

CODE限制12BIT代碼, 字典至多4096個字符串.

#define   LZW_MAX_STRING      4096  

(2^12)

定義『LZW』結构.

typedef struct LZW_TYP

 

PBYTE   sour; 

蒞源數據

DWORD   sour_position;

蒞源數據當前位置

DWORD   sour_position_bit;

跟踪BIT邊界

DWORD   sour_length;

蒞源數據長度

PBYTE   dest;

目標數據緩存

DWORD   dest_size;

目標緩存長度

DWORD   dest_position;

目標數據當前位置

DWORD   dest_position_bit;

跟踪BIT邊界

int         string_count;

字典量

LZW_STRING  string_table[LZW_MAX_STRING];

字典/字符串表

}LZW, * LZW_PTR;

 

初始字典/字符串表,初值有256,編號係0~255, 字符/數據亦係0~255, 255之後定義兩個代碼『清除碼ClearCode=256 仝『結束碼EoiCode=257, 一共258.

#define   LZW_CODE_CLEAR      0x0100

0x0100(256) 清除碼 ClearCode

#define   LZW_CODE_EOI        0x0101

0x0101(257) 結束碼 EoiCode

初始字典/字符串表,

bool Init_StringTable_LZW(LZW_PTR lzw) {

        for (index = 0; index < 256; ++index){

lzw->string_table[index].code = index;

            lzw->string_table[index].length = 1;

                lzw->string_table[index].data[0] = index;

        }

        code = LZW_CODE_CLEAR;

        lzw->string_table[LZW_CODE_CLEAR].code = LZW_CODE_CLEAR;  // 清除碼

        lzw->string_table[LZW_CODE_CLEAR].length = 2;

    memcpy(lzw->string_table[LZW_CODE_CLEAR].data, &code, 2);

        code = LZW_CODE_EOI;

        lzw->string_table[LZW_CODE_EOI].code = LZW_CODE_EOI; // 結束碼

        lzw->string_table[LZW_CODE_EOI].length = 2;

        memcpy(lzw->string_table[LZW_CODE_EOI].data, &code, 2);

lzw->string_count = 258;

}

將代碼CODE寫入輸出流,首個代碼係『ClearCode#256, 以『EOICode#257』結束.

因為係壓縮數據,數據将吾以8BIT/16BIT對齊, 代碼Code以字典字符量跟踪Bit邊界.首個CODE將是9Bit代碼小於512. 字典量達係#510 之後10Bit代碼小於1024. #1022之後11Bit代碼小於2048. #2046之後12Bit代碼小於4096.代碼左移至高位,接連上個代碼.

bool Write_Code_LZW(LZW_PTR lzw, DWORD code) {

int bits = 9; 

PBYTE data;

        if (lzw->string_count <= LZW_MASK_9BIT)

                bits = 9;

        else

        if (lzw->string_count <= LZW_MASK_10BIT)

                bits = 10;

        else

        if (lzw->string_count <= LZW_MASK_11BIT)

                bits = 11;

        else

        if (lzw->string_count <= LZW_MASK_12BIT)

                bits = 12;

        int byte_offset = lzw->dest_position_bit / 8;

        int bis_offset = lzw->dest_position_bit % 8;

        code = code << (32 – bits);

        code = code >> bis_offset;

        data = (PBYTE) &code;

        for (int i = 0; i < 4; ++i){

                *(lzw->dest + byte_offset + i) = *(lzw->dest + byte_offset + i) | data[4 – i – 1];

                if (byte_offset + i >= lzw->sour_length)

                        break; // 數據尾,跳出

        }

        lzw->dest_position_bit = lzw->dest_position_bit + bits;// 蒞源數據當前位置

        lzw->dest_position = lzw->dest_position_bit / 8;// 蒞源數據當前位置

        return true;

}

加入字符串至字典.首個添加到字串將位於258.

bool Add_StringTable_LZW(LZW_PTR lzw, LZW_STRING_PTR string){

WORD index;

LZW_STRING_PTR str;

index = lzw->string_count;

++lzw->string_count;

str = &lzw->string_table[index];

        str->code = index;// 代碼應盡量短,至多12Bit

str->length = string->length;

        memcpy(str->data, string->data, string->length);

        return true;

}

讀蒞源CHAR字符, 未壓縮數據

bool Read_NextChar_LZW(LZW_PTR lzw, LZW_STRING_PTR string){ 

BYTE data;

        if (lzw->sour_position + 1 > lzw->sour_length)

                return false; // 

        data = *(lzw->sour + lzw->sour_position);

        lzw->sour_position = lzw->sour_position + 1;// 蒞源數據當前位置 

        string->data[0] = data;

        string->length = 1;

        return true;

}

壓縮算法步驟:

bool Compress_Data_LZW(PBYTE dest, DWORD* dest_length, PBYTE sour, DWORD sour_length){

LZW lzw;

        LZW_STRING prefix;// 前綴字符

        LZW_STRING suffix;// 後綴字符

        LZW_STRING string;

        WORD code;// 代碼

        Init_LZW(&lzw, dest, *dest_length, sour, sour_length); // 初始LZW

        Init_StringTable_LZW(&lzw); // 初始字典

        Write_Code_LZW(&lzw,LZW_CODE_CLEAR); // 寫目標

        Zero_String_LZW(&prefix);// 前綴字符串清零

while (Read_NextChar_LZW(&lzw, &suffix)) {       // 讀下一字符,後綴字符

Copy_String_LZW(&string, &prefix); // 前綴

  Cat_String_LZW(&string, &suffix);// 前綴+後綴

                if ( Find_StringTable_LZW(&lzw, &string, &code) ){ // 字符串查代碼

                        Cat_String_LZW(&prefix, &suffix);// 後綴 = 前綴+後綴

                }

else

                {

                Find_StringTable_LZW(&lzw, &prefix, &code);// 查找前綴

                        Write_Code_LZW(&lzw, code);// CODE代碼寫入輸出流

                        // 前綴+後綴

                        Copy_String_LZW(&string, &prefix); // 前綴

                        Cat_String_LZW(&string, &suffix);// 前綴+後綴

                        Add_StringTable_LZW(&lzw,&string);// 加入字符串至條目表

                        Copy_String_LZW(&prefix, &suffix); // 後綴變前綴

                }

        }

Find_StringTable_LZW(&lzw, &prefix, &code);// 查找前綴

        Write_Code_LZW(&lzw, code);// CODE代碼寫入輸出流

Write_Code_LZW(&lzw, LZW_CODE_EOI);// CODE代碼寫入輸出流

        *dest_length = lzw.dest_position;         // 輸出压缩長度

        if (lzw.dest_position_bit / 8 != 0)

                ++(*dest_length);

        return true;

}

讀壓縮CODE代碼,必須跟踪Bit邊界. 代碼右移至低位,提取代碼. 代碼Code以字典字符量跟踪Bit邊界.首個CODE將是9Bit代碼小於512. 字典量達係#510 之後10Bit代碼小於1024. #1022之後11Bit代碼小於2048. #2046之後12Bit代碼小於4096.

WORD Read_NextCode_LZW(LZW_PTR lzw){

        DWORD data;

        int bits = 9;   

        if (lzw->string_count <= LZW_MASK_9BIT) // 小於512

                bits = 9;

        else

       if (lzw->string_count <= LZW_MASK_10BIT) // 小於1024

                bits = 10;

        else

        if (lzw->string_count <= LZW_MASK_11BIT) // 小於2048

                bits = 11;

        else

        if (lzw->string_count <= LZW_MASK_12BIT) // 小於4096

                bits = 12;

        int byte_offset = lzw->sour_position_bit / 8;

        int bis_offset  = lzw->sour_position_bit % 8;

        data = (*(lzw->sour + byte_offset))     << (24+bis_offset) |

                   (*(lzw->sour + byte_offset + 1)) << (16+bis_offset) |

                   (*(lzw->sour + byte_offset + 2)) << ( 8+bis_offset) ;

        data = data >> (32 – bits);

        lzw->sour_position_bit = lzw->sour_position_bit + bits;// 蒞源數據當前位置

        lzw->sour_position  = lzw->sour_position_bit / 8;// 蒞源數據當前位置

        return (WORD)data;

}

壓縮算法步驟:

bool UnCompress_Data_LZW(PBYTE dest, DWORD* dest_length, PBYTE sour, DWORD sour_length){

        LZW lzw;

        WORD code = 0;

        WORD OldCode = 0;

        LZW_STRING string;

        LZW_STRING OldString;

        if ( dest == NULL || dest_length == NULL || sour == NULL || sour_length == 0)

                return false;

        Init_LZW(&lzw, dest, *dest_length, sour, sour_length); // 初始LZW

        while (TRUE)

        {

                code = Read_NextCode_LZW(&lzw);// 讀蒞源數據

                if (code == LZW_CODE_EOI)// 結束碼

                        break;// 數據結束

                if (code == LZW_CODE_CLEAR) {    // 清除碼

                         Init_StringTable_LZW(&lzw);// 初始字典

                         code = Read_NextCode_LZW(&lzw);// 讀蒞源數據

                         if (code == LZW_CODE_EOI)// 結束碼

                                 break;// 數據結束

                 Find_StringTable_LZW(&lzw, code, &string);

                         Write_String_LZW(&lzw, &string);// 將字符串寫入輸出流

                         OldCode = code;

                }

                else

                {  

// 代碼稳查字符串

          if (Find_StringTable_LZW(&lzw, code, &string)) {

                        Write_String_LZW(&lzw, &string); // 將字符串寫入輸出流

Find_StringTable_LZW(&lzw, OldCode, &OldString);        // 代碼稳查字符串

Cat_String_LZW(&OldString, &string, 1); // 連接字符串 

                   Add_StringTable_LZW(&lzw, &OldString); // 加入字符串至條目表

                        OldCode = code;

                }

        else{   // 代碼稳查字符串

                Find_StringTable_LZW(&lzw, OldCode, &OldString);

         Cat_String_LZW(&OldString, &OldString, 1); // 連接字符串 

Write_String_LZW(&lzw, &OldString); // 將字符串寫入輸出流

         Add_StringTable_LZW(&lzw, &OldString); // 加入字符串至條目表

                                OldCode = code;

                        }

                }

        }

        *dest_length = lzw.dest_position;         // 輸出压缩長度

        return true;

}

 

 

發佈留言