LZW – Wikipédia, a enciclopédia livre

LZW (Lempel-Ziv-Welch) é um algoritmo de compressão de dados, derivado do algoritmo LZ78, baseado na localização e no registro das padronagens de uma estrutura. Foi desenvolvido e patenteado em 1984 por Terry Welch.[1] É geralmente utilizado em imagens em que não se pode perder a definição original. Nas imagens, o algoritmo lê os valores de pixels de uma imagem bitmap e elabora uma tabela de códigos onde se representam as padronagens repetidas dos pixels encontrados.

O codificador LZW reduz, pela compressão, os arquivos de imagens gráficas a 1/3 ou 1/4 de seu tamanho original.

Imagens com padronagem bem definidas — com grandes blocos de cor contínua ou repetidas de cores — podem reduzir para 1/10 o tamanho original do arquivo.

Formatos que utilizam o LZW[editar | editar código-fonte]

  • TIFF, por opção;
  • GIF, por padrão.

Algoritmo[editar | editar código-fonte]

Compressão e descompressão com LZW

O algoritmo LZW é uma variante do LZ78, que visa eliminar a necessidade de se emitir um caractere literal junto com o endereço de dicionário[2]. Para isso, o dicionário é inicializado com todos os símbolos do alfabeto (ao se usar codificação ASCII são 256 símbolos, de 0 a 255). A entrada é lida e acumulada em uma cadeia de caracteres que chamaremos de I. Sempre que a seqüência contida em I não estiver presente no dicionário emitimos o código correspondente a versão anterior de I (ou seja, I sem o último caractere) e adicionamos I ao dicionário. I volta a ser inicializado com o último caractere lido (o seu último caractere) e o processo continua até que não haja mais caracteres na entrada.

Pseudocódigo[editar | editar código-fonte]

1. No início o dicionário contém todas as raízes possíveis e I é vazio; 2. c <= próximo caractere da sequência de entrada; 3. A string I+c existe no dicionário? 	a. se sim, 		i. I <= I+c; 	b. se não, 		i. coloque a palavra código correspondente a I na sequência codificada; 		ii. adicione a string I+c ao dicionário; 		iii. I <= c; 4. Existem mais caracteres na sequência de entrada ? 	a. se sim, 		i. volte ao passo 2; 	b. se não, 		ii. coloque a palavra código correspondente a I na sequência codificada; 		iii. FIM. 

Pseudocódigo descompactação String[editar | editar código-fonte]

1. No início o dicionário contém todas as raízes possíveis; 2. cW <= primeira palavra código na sequência codificada (sempre é uma raiz); 3. Coloque a string(cW) na sequência de saída; 4. pW <= cW; 5. cW <= próxima palavra código da sequência codificada; 6. A string(cW) existe no dicionário ? 	a. se sim, 		i. coloque a string(cW) na sequência de saída; 		ii. P <= string(pW); 		iii. C <= primeiro caracter da string(cW); 		iv. adicione a string P+C ao dicionário; 	b. se não, 		i. P <= string(pW); 		ii. C <= primeiro caracter da string(pW); 		iii. coloque a string P+C na sequência de saída e adicione-a ao dicionário; 7. Existem mais palavras código na sequência codificada ? 	a. se sim, 		i. volte ao passo 4; 	b. se não, 		i. FIM. 

Exemplo[editar | editar código-fonte]

No quadro abaixo mostramos os passes da compressão da cadeia A_ASA_DA_CASA usando o método de LZW. A coluna I representa a cadeia lida na entrada desde que a última saída foi emitida. A coluna no dic? indica se a seqüência em I está presente no dicionário. a coluna nova entrada mostra o que será inserido no dicionário (como o dicionário já contém os 256 símbolos do código ASCII é impraticável mostrar todo seu conteúdo, por isso listamos apenas as novas entradas). E por fim a coluna saída mostra o código que será emitido na saída do programa, junto com o que ele representa no dicionário (entre parênteses).

I no dic? nova entrada saída
A S
A_ N 256:A_ 65 (A)
_ S
_A N 257:_A 95 (_)
A S
AS N 258:AS 65 (A)
S S
SA N 259:SA 83 (S)
A S
A_ S
A_D N 260:A_D 256 (A_)
D S
DA N 261:DA 68 (D)
A S
A_ S
A_C N 262:A_C 256 (A_)
C S
CA N 263:CA 67 (C)
A S
AS S
ASA N 264:ASA 258 (AS)
A S
- - - 65 (A)

O tamanho final é de 10 códigos,sendo 7 representados por 8 bits cada um e 3 código representados por 9 bits. Nesse caso temos na saída 83 bits, comparados com os 104 originais. Como podemos ver, o método LZW é ainda mais lento para fazer efeito que o método LZ78 devido ao fato de o dicionário já estar inicialmente povoado com todos os símbolos do alfabeto. Entretanto ele é mais simples de ser implementado e gera resultados semelhantes ou até melhores com cadeias de caracteres mais longas.

Problemas[editar | editar código-fonte]

Por ser uma variante do LZ78 o LZW sofre dos mesmos problemas enfrentados por este, que podem ser vistos em LZ78#Problemas.

Exemplo de implementação

#!/usr/bin/python # coding: utf-8  import sys  class lzw_encoder:     """         Classe usada para codificar um arquivo usando         o algoritmo LZW. Está é uma implementação de         exemplo que não leva em conta a representação         binária do arquivo de saída nem o estouro do         tamanho do dicionário. Este código foi baseado nas         informações contidas em      """     def __init__(self):         """             Faz a carga inicial do dicionário com os 256             caracteres ASCII possíveis.         """         self.next_code = 0         self.dictionary = dict()         for i in range(0,256):             self.add_to_dictionary(chr(i))     def add_to_dictionary(self, str):         """             Cria um novo código para uma dada "string" e a             insere sob esse código no dicionário         """         self.dictionary[str] = self.next_code         self.next_code = self.next_code + 1     def encode(self, str):         """             Corpo do algoritmo. lê sequencialmente os             caracteres e cria as cadeias a serem inseridas             no dicionário, emitindo os respectivos códigos             no arquivo de saída (representado pela lista "ret"         """         ret = [] # inicializa a lista (arquivo de saída)         buffer = '' # inicializa o acumulador de caracteres lidos         for i in range(0, len(str)):             c = str[i]             # enquanto a cadeia atual existir no dicionário,             # continuamos acresncentando caracteres a ela             # No caso da versao 3, troque a linha de baixo por:             # if len(buffer) == 0 or (buffer + c) in self.dictionary:             if len(buffer) == 0 or self.dictionary.has_key(buffer + c):                 buffer = buffer + c             else:                 # quando encontramos a maior cadeia presente                 # emitimos o código dessa cadeia e criamos uma                 # nova cadeia, acrescentando o último                 # caractere lido.                 code = self.dictionary[buffer]                 self.add_to_dictionary(buffer + c)                 buffer = c                 ret = ret + [code]         if buffer:             ret = ret + [self.dictionary[buffer]]         return ret  class lzw_decoder:     """         Classe usada para decodificar um arquivo         codificado com LZW. Segue as mesmas restrições         da classe  lzw_encoder     """     def __init__(self):         """             Faz a carga inicial do dicionário com os 256             caracteres ASCII possíveis.         """         self.next_code = 0         self.dictionary = dict()         for i in range(0,256):             self.add_to_dictionary(chr(i))     def add_to_dictionary(self, str):         """             Cria um novo código para uma dada "string" e a             insere sob esse código no dicionário         """         self.dictionary[self.next_code] = str         self.next_code = self.next_code + 1     def decode(self, symbols):         """             Decodifica o arquivo. Emite sequêncialmente             as cadeias correspondentes aos códigos lidos.             Caso a concatenação dos códigos lidos não             corresponda a uma cadeia existente, acrescenta no             dicionário como uma nova cadeia.         """         last_symbol = symbols[0]         ret = self.dictionary[last_symbol]         for symbol in symbols[1:]:             # No caso da versao 3, troque a linha de baixo por:             # if symbol in self.dictionary:             if self.dictionary.has_key(symbol):                 current = self.dictionary[symbol]                 previous = self.dictionary[last_symbol]                 to_add = current[0]                 self.add_to_dictionary(previous + to_add)                 ret = ret + current             else:                 previous = self.dictionary[last_symbol]                 to_add = previous[0]                 self.add_to_dictionary(previous + to_add)                 ret = ret + previous + to_add             last_symbol = symbol         return ret  if __name__ == "__main__":     str = ''     str = 'A_ASA_DA_CASA'     encoder = lzw_encoder()     encoded = encoder.encode(str)     print ('encoded:', encoded)      decoder = lzw_decoder()     decoded = decoder.decode(encoded)     print ('decoded:', decoded) 

Notas e referências[editar | editar código-fonte]

  1. SALOMON, David (2000). Data Compression. The Complete Reference 2 ed. Nova Iorque: Springer 
  2. Elimina-se o caractere c do par (Dseq, c) descrito em LZ78#Algoritmo.

Bibliografia[editar | editar código-fonte]

Ligaçoes externas[editar | editar código-fonte]

Ícone de esboço Este artigo sobre programação de computadores é um esboço. Você pode ajudar a Wikipédia expandindo-o.