LZW算法PHP实现方法 lzw_decompress php

LZW算法简介


字符串和编码的对应关系是在压缩过程中动态生成的,并且隐含在压缩数据中,解压的时候根据表来进行恢复,算是一种无损压缩.


根据 Lempel-Ziv-Welch Encoding ,简称 LZW 的压缩算法,用任何一种语言来实现它.


LZW压缩算法[1]的基本概念:LZW压缩有三个重要的对象:数据流(CharStream)、编码流(CodeStream)和编译表(String Table)。在编码时,数据流是输入对象(文本文件的据序列),编码流就是输出对象(经过压缩运算的编码数据);在解码时,编码流则是输入对象,数据流 是输出对象;而编译表是在编码和解码时都须要用借助的对象。字符(Character):最基础的数据元素,在文本文件中就是一个字节,在光栅数据中就是 一个像素的颜色在指定的颜色列表中的索引值;字符串(String):由几个连续的字符组成; 前缀(Prefix):也是一个字符串,不过通常用在另一个字符的前面,而且它的长度可以为0;根(Root):一个长度的字符串;编码(Code):一 个数字,按照固定长度(编码长度)从编码流中取出,编译表的映射值;图案:一个字符串,按不定长度从数据流中读出,映射到编译表条目.

 

LZW压缩算法的基本原理:提取原始文本文件数据中的不同字符,基于这些字符创建一个编译表,然后用编译表中的字符的索引来替代原始文本文件数据中 的相应字符,减少原始数据大小。看起来和调色板图象的实现原理差不多,但是应该注意到的是,我们这里的编译表不是事先创建好的,而是根据原始文件数据动态 创建的,解码时还要从已编码的数据中还原出原来的编译表.

 

原版:

<?php
/** 
* @link http://code.google.com/p/php-lzw/
* @author Jakub Vrana, http://php.vrana.cz/
* @copyright 2009 Jakub Vrana
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
*/

/** LZW compression
* @param string data to compress
* @return string binary data
*/
function lzw_compress($string) {
	// compression
	$dictionary = array_flip(range("\0", "\xFF"));
	$word = "";
	$codes = array();
	for ($i=0; $i <= strlen($string); $i++) {
		$x = $string[$i];
		if (strlen($x) && isset($dictionary[$word . $x])) {
			$word .= $x;
		} elseif ($i) {
			$codes[] = $dictionary[$word];
			$dictionary[$word . $x] = count($dictionary);
			$word = $x;
		}
	}
	
	// convert codes to binary string
	$dictionary_count = 256;
	$bits = 8; // ceil(log($dictionary_count, 2))
	$return = "";
	$rest = 0;
	$rest_length = 0;
	foreach ($codes as $code) {
		$rest = ($rest << $bits) + $code;
		$rest_length += $bits;
		$dictionary_count++;
		if ($dictionary_count > (1 << $bits)) {
			$bits++;
		}
		while ($rest_length > 7) {
			$rest_length -= 8;
			$return .= chr($rest >> $rest_length);
			$rest &= (1 << $rest_length) - 1;
		}
	}
	return $return . ($rest_length ? chr($rest << (8 - $rest_length)) : "");
}

/** LZW decompression
* @param string compressed binary data
* @return string original data
*/
function lzw_decompress($binary) {
	// convert binary string to codes
	$dictionary_count = 256;
	$bits = 8; // ceil(log($dictionary_count, 2))
	$codes = array();
	$rest = 0;
	$rest_length = 0;
	for ($i=0; $i < strlen($binary); $i++) {
		$rest = ($rest << 8) + ord($binary[$i]);
		$rest_length += 8;
		if ($rest_length >= $bits) {
			$rest_length -= $bits;
			$codes[] = $rest >> $rest_length;
			$rest &= (1 << $rest_length) - 1;
			$dictionary_count++;
			if ($dictionary_count > (1 << $bits)) {
				$bits++;
			}
		}
	}
	
	// decompression
	$dictionary = range("\0", "\xFF");
	$return = "";
	foreach ($codes as $i => $code) {
		$element = $dictionary[$code];
		if (!isset($element)) {
			$element = $word . $word[0];
		}
		$return .= $element;
		if ($i) {
			$dictionary[] = $word . $element[0];
		}
		$word = $element;
	}
	return $return;
}

 

$data = "";
$compressed = lzw_compress($data);
var_dump($data === lzw_decompress($compressed));

 

 优化版:

<?php
function lzw_compress($string) {
    // compression
    $dict = array_flip(range("\\0", "\\xFF"));
    $dict_size = 256;
    $word = $string[0];
 
    $dict_count = 256;
    $bits = 8; 
    $bits_max = 256;
    $return = "";
    $rest = 0;
    $rest_length = 0;
 
    for ($i = 1, $j = strlen($string); $i < $j; $i++) {
        $x = $string[$i];
        $y = $word . $x;
        if (isset($dict[$y])) {
            $word .= $x;
        } else {
            $rest = ($rest << $bits) + $dict[$word];
            $rest_length += $bits;
            $dict_count++;
            if ($dict_count > $bits_max) {
                $bits_max = 1 << ++$bits;
            }
            while ($rest_length > 7) {
                $rest_length -= 8;
                $return .= chr($rest >> $rest_length);
                $rest &= (1 << $rest_length) - 1;
            }
            $dict[$y] = $dict_size++;
            $word = $x;
        }
    }
 
    $rest = ($rest << $bits) + $dict[$word];
    $rest_length += $bits;
    $dict_count++;
    if ($dict_count > $bits_max) {
        $bits_max = 1 << ++$bits;
    }
    while ($rest_length > 0) {
        if($rest_length>7){
            $rest_length -= 8;
            $return .= chr($rest >> $rest_length);
            $rest &= (1 << $rest_length) - 1;
        }else{
            $return .= chr($rest << (8 - $rest_length));
            $rest_length = 0;
        }
    }
 
    return $return;
}
 
/** LZW decompression
 * @param string compressed binary data
 * @return string original data
 */
function lzw_decompress($binary) {
    // convert binary string to codes
    $rest = 0;
    $rest_length = 0;
    $out_count = 257;
    $bits = 9;
    $bits_max = 512;
      
    // decompression
    $dict = range("\\0", "\\xFF");
    $w = $binary[0];
    $return = $w;
      
    for ($i = 1, $j = strlen($binary); $i < $j; $i++) {
        $rest = ($rest << 8) + ord($binary[$i]);
        $rest_length += 8;
        if ($rest_length >= $bits) {
            $rest_length -= $bits;
              
            // decompression
            $e = $dict[$rest >> $rest_length];
            if (!isset($e)) {
                $e = $w . $w[0];
            }
            $return .= $e;
            $dict[] = $w . $e[0];
            $w = $e;
            //--decompression
              
            $rest &= (1 << $rest_length) - 1;
            if (++$out_count > $bits_max) {
                $bits_max = 1 << ++$bits;
            }
        }
    }
      
    return $return;
}
 
?> 

 

项目:https://code.google.com/p/php-lzw/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LZW算法是一种无损压缩算法,可以将重复出现的字符串替换为较短的编码,并且可以实现高压缩比。以下是在C语言中实现LZW算法的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define TABLE_SIZE 4096 // 编码表大小 typedef unsigned short code_t; // 编码类型 // 初始化编码表 void init_table(char **table) { for (int i = 0; i < 256; i++) { table[i] = (char *)malloc(2 * sizeof(char)); table[i][0] = (char)i; table[i][1] = '\0'; } for (int i = 256; i < TABLE_SIZE; i++) { table[i] = NULL; } } // 查找字符串在编码表中的位置 int find_string(char **table, char *str) { int i = 0; while (table[i] != NULL) { if (strcmp(table[i], str) == 0) { return i; } i++; } return -1; } // 将字符串插入编码表中 int insert_string(char **table, char *str) { int i = 0; while (table[i] != NULL) { i++; } if (i < TABLE_SIZE) { table[i] = (char *)malloc((strlen(str) + 1) * sizeof(char)); strcpy(table[i], str); } return i; } // LZW压缩函数 int lzw_compress(char *input, code_t *output) { char **table = (char **)malloc(TABLE_SIZE * sizeof(char *)); init_table(table); int input_len = strlen(input); char string[256]; int string_len = 0; int code = 0; int output_len = 0; for (int i = 0; i < input_len; i++) { string[string_len++] = input[i]; string[string_len] = '\0'; int index = find_string(table, string); if (index == -1) { output[output_len++] = code; code = insert_string(table, string); string_len = 1; string[0] = input[i]; string[1] = '\0'; } else { code = index; } } output[output_len++] = code; for (int i = 0; i < TABLE_SIZE; i++) { if (table[i] != NULL) { free(table[i]); } } free(table); return output_len; } // LZW解压函数 int lzw_decompress(code_t *input, int input_len, char *output) { char **table = (char **)malloc(TABLE_SIZE * sizeof(char *)); init_table(table); int output_len = 0; int code = input[0]; char *string = table[code]; int string_len = strlen(string); strcpy(output, string); output_len += string_len; for (int i = 1; i < input_len; i++) { code = input[i]; if (table[code] == NULL) { string = table[i]; string_len = strlen(string); strcat(output, string); output_len += string_len; table[code] = (char *)malloc((string_len + 1) * sizeof(char)); strcpy(table[code], string); } else { string = table[code]; string_len = strlen(string); strcat(output, string); output_len += string_len; char *prev_string = table[input[i - 1]]; int prev_string_len = strlen(prev_string); char new_string[256]; strcpy(new_string, prev_string); new_string[prev_string_len] = string[0]; new_string[prev_string_len + 1] = '\0'; table[TABLE_SIZE++] = (char *)malloc((strlen(new_string) + 1) * sizeof(char)); strcpy(table[TABLE_SIZE - 1], new_string); } } for (int i = 0; i < TABLE_SIZE; i++) { if (table[i] != NULL) { free(table[i]); } } free(table); return output_len; } int main() { char input[256] = "ababababab"; code_t output[256]; int output_len = lzw_compress(input, output); char decompressed[256]; int decompressed_len = lzw_decompress(output, output_len, decompressed); printf("Input: %s\n", input); printf("Output: "); for (int i = 0; i < output_len; i++) { printf("%d ", output[i]); } printf("\nDecompressed: %s\n", decompressed); return 0; } ``` 在此示例代码中,使用一个字符串数组作为编码表,并按字典序初始化前256个编码。在压缩过程中,先将第一个字符加入当前字符串,然后在编码表中查找是否有相同的字符串,若有则继续添加下一个字符,否则将当前字符串编码并加入编码序列中,然后将当前字符串重置为当前字符。在解压过程中,先将第一个编码对应的字符串加入输出中,然后按照编码序列逐个解码,若当前编码在编码表中不存在,则将前一个编码对应的字符串加上当前字符串的第一个字符,并添加到编码表中,然后将当前编码对应的字符串加入输出中。若当前编码在编码表中存在,则将其对应的字符串加入输出中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值