LZW算法簡介php
字符串和編碼的對應關係是在壓縮過程當中動態生成的,而且隱含在壓縮數據中,解壓的時候根據表來進行恢復,算是一種無損壓縮.算法
根據 Lempel-Ziv-Welch Encoding ,簡稱 LZW 的壓縮算法,用任何一種語言來實現它.sql
LZW壓縮算法[1]的基本概念:LZW壓縮有三個重要的對象:數據流(CharStream)、編碼流(CodeStream)和編譯表(String Table)。在編碼時,數據流是輸入對象(文本文件的據序列),編碼流就是輸出對象(通過壓縮運算的編碼數據);在解碼時,編碼流則是輸入對象,數據流 是輸出對象;而編譯表是在編碼和解碼時都需要用藉助的對象。字符(Character):最基礎的數據元素,在文本文件中就是一個字節,在光柵數據中就是 一個像素的顏色在指定的顏色列表中的索引值;字符串(String):由幾個連續的字符組成; 前綴(Prefix):也是一個字符串,不過一般用在另外一個字符的前面,並且它的長度能夠爲0;根(Root):一個長度的字符串;編碼(Code):一 個數字,按照固定長度(編碼長度)從編碼流中取出,編譯表的映射值;圖案:一個字符串,按不定長度從數據流中讀出,映射到編譯表條目.apache
LZW壓縮算法的基本原理:提取原始文本文件數據中的不一樣字符,基於這些字符建立一個編譯表,而後用編譯表中的字符的索引來替代原始文本文件數據中 的相應字符,減小原始數據大小。看起來和調色板圖象的實現原理差很少,可是應該注意到的是,咱們這裏的編譯表不是事先建立好的,而是根據原始文件數據動態 建立的,解碼時還要從已編碼的數據中還原出原來的編譯表.google
<?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; }