fbpx
Wikipedia

LZSS

El algoritmo de compresión lz77 (acrónimo de Abraham Lempel, Jacob Ziv y 1977) pertenece a la familia de compresores sin pérdida, también llamados compresores de texto, a los cuales se les llama así porque no omiten información del archivo al comprimirlo, al contrario que los compresores que utilizan algoritmos del tipo lossy, que omiten algo de información pero que disminuyen considerablemente el tamaño del archivo original, el cual es el caso de los archivos MP3, MPG, jpeg, etc.

Características

Los compresores basados en algoritmos sin pérdida se utilizan cuando la información a comprimir es crítica y no se puede perder información, por ejemplo en los archivos ejecutables, tablas de bases de datos, o cualquier tipo de información que no admita pérdida.

El modelo lz77 es muy usado porque es fácil de implementar y es bastante eficiente.

En 1977 Abraham Lempel y Jacob Ziv presentaron su modelo de compresión basado en diccionario, para compresión de texto –compresión de texto se refiere a compresión sin pérdida para cualquier tipo de datos–. Hasta la fecha todos los algoritmos de compresión desarrollados eran básicamente compresores estáticos. El nuevo modelo fue llamado lz77. La salida consistía siempre en desplazamientos o corrimientos y tamaños del texto visto anteriormente. También se incluía en la salida el siguiente byte después de una coincidencia, porque el contexto (últimos bytes vistos) de este byte es la frase, y si no era parte de la frase (la coincidencia), luego tal vez no se había comprimido, así que, ¿para qué desperdiciar tiempo tratando de encontrar una coincidencia (o espacio) para él?

En 1982 James Storer y Thomas Szymanski basados en el trabajo de Lempel y Ziv, presentaron su modelo, el lzss. La diferencia principal es en la salida, lz77 siempre daba un par desplazamiento/tamaño, aun si la coincidencia era de un solo byte (en cuyo caso usaban más de ocho bits para representar un byte) de manera que el LZSS usa otro truco para mejorarlo: usa banderas (flags), que ocupan un solo bit y nos informan de lo que viene luego: una literal o un par desplazamiento/tamaño y este algoritmo es el que actualmente usamos, pero el lzss es comúnmente llamado lz77, así que lo llamaremos lz77 de este punto en adelante, pero es importante recordar que también puede ser llamado LZSS. LZSS también puede usar árboles binarios o árboles de sufijos para hacer búsquedas más eficientes.

La teoría es muy simple e intuitiva. Cuando se halla una coincidencia (también llamada frase o conjunto de bytes que ya han sido vistos en el archivo de entrada) en lugar de escribir dichos bytes se escribe el desplazamiento o tamaño de la repetición: dónde está y su longitud.

Éste es un modelo basado en diccionario, porque se mantiene un diccionario (que en este caso se conoce como “ventana corrediza”) y se hace referencia a ella con pares desplazamiento/tamaño. Esta versión de lz77, usa una ventana corrediza, la cual tiene un tamaño máximo, de manera que la ventana no puede ser el archivo completo, en su lugar, la ventana corrediza mantiene los últimos bytes “vistos”.

Comprimiendo

Imaginemos que estamos comprimiendo el texto “ab ab”, leemos hasta “ab ” y lo escribimos sin comprimir, luego leemos “ab” y escribimos lo siguiente: con el “desplazamiento” de 0 se halló una coincidencia de dos bytes repetidos.

Descomprimiendo

Es bastante simple. Primero leemos “ab ” y luego copiamos los bytes de ahí así:

Obtener ‘a’. “a” Obtener ‘b’. “ab” Obtener ‘ ‘. “ab ” Obtener desplazamiento/tamaño. Copiar dos bytes desde la posición 0. (“ab”) “ab ab” 

¿Cómo funciona?

Pero, ¿cómo sabe el descompresor si lo que lee es un par desplazamiento/tamaño o un byte sin comprimir?. La respuesta es simple, usamos un prefijo, un bit que actúa como una bandera, de forma similar a un interruptor con dos estados que nos permite saber qué tipo de datos vienen a continuación.

Si el prefijo es 0, entonces lo que viene es un byte sin comprimir. Si, por el contrario, el prefijo es 1, entonces lo que sigue a continuación es un par desplazamiento/tamaño. A estos prefijos también se les llama “banderas”.

El par desplazamiento/tamaño es llamado una palabra clave. Una palabra clave es un grupo de bits (o bytes) que contienen alguna clase de información usada por el compresor y el descompresor. La otra salida posible de lz77 es un literal, la cual es simplemente un byte sin comprimir, de manera que la salida de lz77 puede ser de tres formas:

  1. Literales: son simplemente bytes sin comprimir.
  2. Palabras clave: en nuestro caso son pares tamaño/desplazamiento.
  3. Banderas: simplemente nos indican si los datos que hay a continuación son literales o palabras clave.

Ahora, como ejemplo, veamos de nuevo nuestra cadena y una salida real de un algoritmo lz77:

Obtener ‘a’. Sin coincidencia. Bandera 0. Literal ’a’. Obtener ‘b’. Sin coincidencia. Bandera 0. Literal ’b’. Obtener ‘ ’. Sin coincidencia. Bandera 0. Literal ’ ’. Obtener ‘a’. Coincidencia. Bandera 1. Palabra clave: desplazamiento = 0, tamaño = 2. 

Como puede verse la bandera solo tiene dos estados posibles, de manera que solo necesitamos un bit para representarla. Ahora no deberíamos representar la banderas como bytes completos, deberíamos trabajar con bits. La salida de esta compresión es llamada un flujo de bits, porque es un flujo de símbolos de tamaño variable, y la unidad mínima es el bit.

Ventana Corrediza

Si se observa el ejemplo anterior nuevamente, uno podría preguntarse: ¿Dónde buscamos las coincidencias para una frase? La respuesta es buscar hacia atrás, en los datos que ya hemos procesado. Esto es conocido como la ventana corrediza. La ventana corrediza es un buffer que mantiene los bytes que están antes de la posición actual en el archivo. Todos los bytes no comprimidos de la salida (las literales) se añaden a la ventana corrediza y también los bytes que forman una coincidencia.

Veamos nuestro ejemplo nuevamente:

Obtener ‘a’. VC: “”. Sin coincidencia. Bandera 0. Literal ’a’. Obtener ‘b’. VC: “a”. Sin coincidencia. Bandera 0. Literal ’b’. Obtener ‘ ’. VC: “ab”. Sin coincidencia. Bandera 0. Literal ’ ’. Obtener ‘a’. VC: “ab ”. Coincidencia. Bandera 1. Palabra clave: desplazamiento = 0, tamaño = 2. 

Como puede verse, cuando buscamos coincidencias, comparamos los datos que tenemos en nuestra ventana corrediza (VC) con los datos en la posición actual.

¿Así que debemos mantener un buffer con los datos en la posición actual y un buffer con la ventana corrediza? En algunas implementaciones esto puede ser verdad, pero la implementación que se muestra aquí no es la forma en que se hacen las cosas; porque ambos, la ventana corrediza y los bytes en la posición actual, no son más que el archivo mismo. Solo mantenemos un buffer, el cual contiene al archivo. Luego solo debemos preocuparnos del puntero a la posición actual, y la ventana corrediza esta justo antes de dicho puntero. De hecho se recomienda tener el archivo completo (o al menos un bloque grande del mismo) y comprimirlo, de manera que no nos preocupamos de leer más bytes.

Hablemos ahora sobre la ventana corrediza, ¿qué tamaño debería tener? Podríamos trabajar con el archivo completo, pero debemos pensar en el desplazamiento necesario para especificar la posición o la coincidencia. Este desplazamiento no es desde la posición 0 (el principio del archivo) a la coincidencia, es desde la posición actual hacia atrás. De manera que en el ejemplo el desplazamiento debe ser de 3 en lugar de 0 (de manera que, cuando se descomprime, el descompresor obtiene un tres y lo resta del desplazamiento actual). Como es de esperar, cuanto mayor sea el tamaño de la ventana, mayor número de bits necesitaremos para almacenar el puntero, de manera que debemos elegir un tamaño para la ventana corrediza. 4K es un tamaño utilizado normalmente, pero se sabe que cuanto mayor es la ventana corrediza, mejor es la compresión. De manera que cuando se implementa se puede escoger cualquier tamaño y considerar que si, por ejemplo, elegimos un tamaño de 8K necesitaremos 13 bits para el desplazamiento.

Tamaños

Otro aspecto que debemos elegir es el tamaño de la longitud. Así que, ¿cuántos bits utilizamos para la longitud? Podemos elegir cualquier tamaño que deseemos, pero debemos considerar que afinar los bits del tamaño de la longitud y los bits del puntero de desplazamiento podemos mejorar la compresión en algunos archivos y empeorarla en otros, así que si estamos diseñando un compresor para un único archivo, deberían encontrarse los valores más apropiados, de lo contrario usaremos un tamaño de 0-32, de solo 5 bits.

Otro aspecto importante es la longitud mínima de una coincidencia. En nuestro caso hemos elegido utilizar 13 bits en el desplazamiento y 5 en la longitud de la coincidencia, 18 bits en total, de manera que una coincidencia debería ser de, por lo menos, 3 bytes. Porque si codificamos una coincidencia con dos bytes (16 bits) y utilizamos 18 bits para almacenar la cadena estamos utilizando 2 bits más que si lo guardamos como un literal.

Luego se levanta otra pregunta. ¿Si nunca tendremos coincidencias de 0, 1 o 2 bytes, entonces por qué tenemos espacio para ellas en la longitud?

Para sacar el mayor provecho posible. Nuestro tamaño aún será representado con 5 bits, pero su rango en lugar de ser 0-32 será 3-35. ¿Cómo hacemos esto? Simplemente restamos al tamaño (antes de guardarlo) 3, y el descompresor lo leerá y añadirá 3.

Marcador de Fin

Ahora que sabemos cómo se realiza la descompresión debemos notar que el descompresor debería saber cómo terminar o cuándo parar. Esto puede realizarse de dos formas:

  • Se tiene un símbolo que marca el final de los datos.
  • Se guarda junto a la cadena de bits el tamaño del archivo de entrada.

Tal vez el segundo método sea preferible. Es un poco más lento, pero al mismo tiempo que se usa para conocer el final de los datos. Puede ser utilizado en una posible interfaz y puede ayudarnos a evitar algunos problemas. De cualquier manera, si se desea utilizar un marcador de fin de datos podríamos usar tamaño cero para ello. La forma en que se hace es la siguiente:

  • El rango será de 3-34, en este caso debemos restar al tamaño (cuando lo guardamos) 2. De manera que el rango 1-32 se convierte 3-34, y el compresor solo debe ocuparse de esto al comprimir el archivo, una vez la compresión es finalizada, la salida desplazamiento/tamaño tiene tamaño de 0.
  • El descompresor debe entonces verificar cada vez que lee un tamaño si este tamaño es 0, para saber si se ha alcanzado el final del archivo.

Trabajando con Bits

Como puede verse, los desplazamientos y tamaños son de longitud variable, y las banderas toman únicamente un bit, de manera que debemos usar bits en lugar de bytes. Esto es muy importante en la mayoría de los algoritmos de compresión.

La mayoría de operaciones trabajan con bytes y cuando se escribe información a un archivo la unidad mínima es el byte, entonces, para escribir bits hacemos un uso inteligente de algunas instrucciones.

Para realizar esto podemos usar ASM, o si no, puede ser implementado en C. Continuaremos las operaciones con bits en ASM. La idea principal es mantener un byte y un contador con los bits escritos, luego cuando tenemos 8 bits, escribimos ese byte al archivo y comenzamos de nuevo con el siguiente byte. A continuación se presenta un ejemplo utilizando instrucciones de ASM.

@@put_bits_loop: push cx ;el número de bits a escribir mov bh,_byte_out ;el byte de salida (dónde escribir) mov bl,_byte_in ;el byte de entrada (los bytes a escribir) mov al, bl ;al ;almacenamos el byte a leer en al shr al,1 ;desplazamos al a la derecha, first bit in the carry flag xor ah, ah ;ah=0 adc ah,0 ;ah 0 y el acarreo mov bl, al ;guarda el byte de entrada mov cl,_total_bits ;bits que hemos escrito shl ah, cl ;pone el bit en su posición desplazando a la izquierda or bh, al ;pone el bit en el byte de salida mov _byte_out,bh ;guardarlo inc _total_bits ;bits escritos cmp _total_bits,8  ;¿Tenemos que escribir todo el byte? jne @@no_write_byte ;nop E-) mov di,ptr_buffer ;el puntero al buffer mov es:[di],bh ;el byte (es el segmento del buffer) inc di ;byte en el buffer mov ptr_buffer,di ;guardado para la próxima vez inc bytes_writed ;cuando el buffer está lleno escribir mov _byte_out,0 ;a file or something like that so the next time is clear @@no_write_byte: ;lo hemos guardado pop cx  ;¿más bits para escribir? dec cx ;sí, repetir todo jnz @@put_bits_loop 

Se presenta la rutina putbits, los nombres de las variables se explican por sí solos pero aún y todo presentamos aquí una descripción:

  • _byte_out: el byte que será escrito en el buffer de salida, mantiene los bits que estamos escribiendo actualmente.
  • _byte_in: el byte que contiene los bits que deseamos escribir.
  • _total_bits: el número de bits que se han escrito actualmente, cero al principio.
  • Ptr_buffer: desplazamiento del buffer.

Cuando se ingresa esta rutina cx debe tener el número de bits a escribir, y _bite_in los bits a escribir. Hay que tener cuidado, después de ingresar el ciclo hay que probar si cx es 0 porque si es cero y no se prueba escribirá un bit, luego haría cx - 1, lo que daría 255 con la consecuencia de escribir 255 bits.

Recuerde:

Test cx, cx jz@@put_bits_end 

Esta es la estructura (cómo son escritos los bits) para un byte:


Bit 8 Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1

Cuando se han escrito todos los bits (la compresión ha finalizado) debe probarse si hay aún bits esperando para ser escritos, así que si hay algunos (total_bits != 0) escribimos _byte_out, e incrementamos todos los punteros de manera que no dejemos datos sin escribir.

Archivo de Salida

Ahora debemos definir el formato del archivo de salida, el cual será simple, únicamente debe llenar nuestras necesidades, los datos comprimidos se verán como:

  • Primero una palabra con el tamaño del archivo original y si se desea algunos números como identificación.
  • Luego el flujo de bits, el cual constituye y contiene los datos comprimidos.

Pseudocódigo

Recordemos como trabaja lz77, uno se encuentra en una posición dada y trata de hallar hacia atrás (porque se está seguro de que el descompresor ya ha decodificado esos bytes cuando uno se encuentra en dicha posición) una coincidencia, bytes que son iguales a los bytes en la posición actual; si se encuentran se escribe una palabra clave, de otra forma se escribe una literal para poder seguir comprimiendo.

Secuencia básica: Compresor

  • Guardar el tamaño del archivo a comprimir.
  • Repetir hasta que no haya más bytes para comprimir.
  • Escanear el buffer de entrada comenzando en posición_actual - tamaño_de_ventana_corrediza hasta el byte actual que estamos comparando. (Notar que el descompresor no puede copiar bytes de una posición desde donde sus bytes no han sido previamente definidos).
  • ¿Hemos encontrado un byte igual al actual?
  • Caso Si:
    • Comparamos el siguiente byte desde la posición actual con el byte en la posición siguiente de donde encontramos un byte igual al primero.
    • Continuar comparando hasta que encontremos un byte que no es igual.
    • Se ha encontrado un byte que no es igual. ¿Es el número de bytes mayor que tres?
    • Caso Si:
      • Escribir el desplazamiento del PRIMER byte hallado y el número de bytes repetidos (tamaño).
      • Movemos el puntero a la posición con el número de bytes repetidos (porque no los hemos “salvado”) y seguimos buscando.
      • También se escribe una bandera 1.
    • Caso No:
      • Continúa la búsqueda.
  • Caso No:
    • Si no se encuentra ninguna coincidencia, simplemente se escribe un byte sin comprimir (también se escribe un literal si no hay datos en la ventana corrediza).
    • Debe recordar poner la bandera a 0.

Secuencia básica: Descompresor

  • Se lee el tamaño del archivo sin comprimir.
  • Se repite hasta que se ha descomprimido todo el archivo.
  • Se lee un bit (la bandera).
  • Si es 0:
    • Se leen 8 bits, se escriben al buffer de salida (recordar que son un byte descomprimido) y se incrementa el puntero a la salida.
  • Si es 1:
    • Se lee el desplazamiento completo (13 bits), luego el tamaño, copiar “tamaño” bytes de “desplazamiento” a la posición actual, y añadir al puntero a la salida “tamaño”.

Buscando Coincidencias

La forma en que se buscan las coincidencias es la siguiente: se mantiene un puntero a la posición actual. Al principio de cualquier iteración, se computa el desplazamiento a la ventana corrediza. Esto se puede hacer fácilmente obteniendo el puntero a la posición actual y restándole el tamaño de la ventana corrediza, en caso de que sea menos que cero (negativo) simplemente se ajusta a cero.

Digamos que tenemos una ventana corrediza de 4 bytes de largo (así que gastamos dos bits para especificar el desplazamiento) y tenemos la siguiente cadena: “1234567”

Pa:0. Pvc=0-4=0. Actual: "1234567" Ventana Corrediza: "..." Pa:1. Pvc=1-4=0. Actual: "234567" Ventana Corrediza: "1" Pa:2. Pvc=2-4=0. Actual: "34567" Ventana Corrediza: "12" Pa:3. Pvc=3-4=0. Actual: "4567" Ventana Corrediza: "123" Pa:4. Pvc=4-4=0. Actual: "567" Ventana Corrediza: "1234" Pa:5. Pvc=5-4=1. Actual: "67" Ventana Corrediza: "2345" Pa:6. Pvc=6-4=2. Actual: "7" Ventana Corrediza: "3456" 

Donde Pa es el puntero al byte actual, y Pvc es el puntero al inicio de la ventana corrediza. Cuando se usan punteros al archivo de entrada completo, debemos cuidar el tamaño de la ventana corrediza.

Véase también

Enlaces externos

  • Lista de manuales de algoritmos de compresión sin pérdida (Español)
  •   Datos: Q2679

lzss, algoritmo, compresión, lz77, acrónimo, abraham, lempel, jacob, 1977, pertenece, familia, compresores, pérdida, también, llamados, compresores, texto, cuales, llama, así, porque, omiten, información, archivo, comprimirlo, contrario, compresores, utilizan,. El algoritmo de compresion lz77 acronimo de Abraham Lempel Jacob Ziv y 1977 pertenece a la familia de compresores sin perdida tambien llamados compresores de texto a los cuales se les llama asi porque no omiten informacion del archivo al comprimirlo al contrario que los compresores que utilizan algoritmos del tipo lossy que omiten algo de informacion pero que disminuyen considerablemente el tamano del archivo original el cual es el caso de los archivos MP3 MPG jpeg etc Indice 1 Caracteristicas 2 Comprimiendo 3 Descomprimiendo 4 Como funciona 5 Ventana Corrediza 6 Tamanos 7 Marcador de Fin 8 Trabajando con Bits 9 Archivo de Salida 10 Pseudocodigo 10 1 Secuencia basica Compresor 10 2 Secuencia basica Descompresor 11 Buscando Coincidencias 12 Vease tambien 13 Enlaces externosCaracteristicas EditarLos compresores basados en algoritmos sin perdida se utilizan cuando la informacion a comprimir es critica y no se puede perder informacion por ejemplo en los archivos ejecutables tablas de bases de datos o cualquier tipo de informacion que no admita perdida El modelo lz77 es muy usado porque es facil de implementar y es bastante eficiente En 1977 Abraham Lempel y Jacob Ziv presentaron su modelo de compresion basado en diccionario para compresion de texto compresion de texto se refiere a compresion sin perdida para cualquier tipo de datos Hasta la fecha todos los algoritmos de compresion desarrollados eran basicamente compresores estaticos El nuevo modelo fue llamado lz77 La salida consistia siempre en desplazamientos o corrimientos y tamanos del texto visto anteriormente Tambien se incluia en la salida el siguiente byte despues de una coincidencia porque el contexto ultimos bytes vistos de este byte es la frase y si no era parte de la frase la coincidencia luego tal vez no se habia comprimido asi que para que desperdiciar tiempo tratando de encontrar una coincidencia o espacio para el En 1982 James Storer y Thomas Szymanski basados en el trabajo de Lempel y Ziv presentaron su modelo el lzss La diferencia principal es en la salida lz77 siempre daba un par desplazamiento tamano aun si la coincidencia era de un solo byte en cuyo caso usaban mas de ocho bits para representar un byte de manera que el LZSS usa otro truco para mejorarlo usa banderas flags que ocupan un solo bit y nos informan de lo que viene luego una literal o un par desplazamiento tamano y este algoritmo es el que actualmente usamos pero el lzss es comunmente llamado lz77 asi que lo llamaremos lz77 de este punto en adelante pero es importante recordar que tambien puede ser llamado LZSS LZSS tambien puede usar arboles binarios o arboles de sufijos para hacer busquedas mas eficientes La teoria es muy simple e intuitiva Cuando se halla una coincidencia tambien llamada frase o conjunto de bytes que ya han sido vistos en el archivo de entrada en lugar de escribir dichos bytes se escribe el desplazamiento o tamano de la repeticion donde esta y su longitud Este es un modelo basado en diccionario porque se mantiene un diccionario que en este caso se conoce como ventana corrediza y se hace referencia a ella con pares desplazamiento tamano Esta version de lz77 usa una ventana corrediza la cual tiene un tamano maximo de manera que la ventana no puede ser el archivo completo en su lugar la ventana corrediza mantiene los ultimos bytes vistos Comprimiendo EditarImaginemos que estamos comprimiendo el texto ab ab leemos hasta ab y lo escribimos sin comprimir luego leemos ab y escribimos lo siguiente con el desplazamiento de 0 se hallo una coincidencia de dos bytes repetidos Descomprimiendo EditarEs bastante simple Primero leemos ab y luego copiamos los bytes de ahi asi Obtener a a Obtener b ab Obtener ab Obtener desplazamiento tamano Copiar dos bytes desde la posicion 0 ab ab ab Como funciona EditarPero como sabe el descompresor si lo que lee es un par desplazamiento tamano o un byte sin comprimir La respuesta es simple usamos un prefijo un bit que actua como una bandera de forma similar a un interruptor con dos estados que nos permite saber que tipo de datos vienen a continuacion Si el prefijo es 0 entonces lo que viene es un byte sin comprimir Si por el contrario el prefijo es 1 entonces lo que sigue a continuacion es un par desplazamiento tamano A estos prefijos tambien se les llama banderas El par desplazamiento tamano es llamado una palabra clave Una palabra clave es un grupo de bits o bytes que contienen alguna clase de informacion usada por el compresor y el descompresor La otra salida posible de lz77 es un literal la cual es simplemente un byte sin comprimir de manera que la salida de lz77 puede ser de tres formas Literales son simplemente bytes sin comprimir Palabras clave en nuestro caso son pares tamano desplazamiento Banderas simplemente nos indican si los datos que hay a continuacion son literales o palabras clave Ahora como ejemplo veamos de nuevo nuestra cadena y una salida real de un algoritmo lz77 Obtener a Sin coincidencia Bandera 0 Literal a Obtener b Sin coincidencia Bandera 0 Literal b Obtener Sin coincidencia Bandera 0 Literal Obtener a Coincidencia Bandera 1 Palabra clave desplazamiento 0 tamano 2 Como puede verse la bandera solo tiene dos estados posibles de manera que solo necesitamos un bit para representarla Ahora no deberiamos representar la banderas como bytes completos deberiamos trabajar con bits La salida de esta compresion es llamada un flujo de bits porque es un flujo de simbolos de tamano variable y la unidad minima es el bit Ventana Corrediza EditarSi se observa el ejemplo anterior nuevamente uno podria preguntarse Donde buscamos las coincidencias para una frase La respuesta es buscar hacia atras en los datos que ya hemos procesado Esto es conocido como la ventana corrediza La ventana corrediza es un buffer que mantiene los bytes que estan antes de la posicion actual en el archivo Todos los bytes no comprimidos de la salida las literales se anaden a la ventana corrediza y tambien los bytes que forman una coincidencia Veamos nuestro ejemplo nuevamente Obtener a VC Sin coincidencia Bandera 0 Literal a Obtener b VC a Sin coincidencia Bandera 0 Literal b Obtener VC ab Sin coincidencia Bandera 0 Literal Obtener a VC ab Coincidencia Bandera 1 Palabra clave desplazamiento 0 tamano 2 Como puede verse cuando buscamos coincidencias comparamos los datos que tenemos en nuestra ventana corrediza VC con los datos en la posicion actual Asi que debemos mantener un buffer con los datos en la posicion actual y un buffer con la ventana corrediza En algunas implementaciones esto puede ser verdad pero la implementacion que se muestra aqui no es la forma en que se hacen las cosas porque ambos la ventana corrediza y los bytes en la posicion actual no son mas que el archivo mismo Solo mantenemos un buffer el cual contiene al archivo Luego solo debemos preocuparnos del puntero a la posicion actual y la ventana corrediza esta justo antes de dicho puntero De hecho se recomienda tener el archivo completo o al menos un bloque grande del mismo y comprimirlo de manera que no nos preocupamos de leer mas bytes Hablemos ahora sobre la ventana corrediza que tamano deberia tener Podriamos trabajar con el archivo completo pero debemos pensar en el desplazamiento necesario para especificar la posicion o la coincidencia Este desplazamiento no es desde la posicion 0 el principio del archivo a la coincidencia es desde la posicion actual hacia atras De manera que en el ejemplo el desplazamiento debe ser de 3 en lugar de 0 de manera que cuando se descomprime el descompresor obtiene un tres y lo resta del desplazamiento actual Como es de esperar cuanto mayor sea el tamano de la ventana mayor numero de bits necesitaremos para almacenar el puntero de manera que debemos elegir un tamano para la ventana corrediza 4K es un tamano utilizado normalmente pero se sabe que cuanto mayor es la ventana corrediza mejor es la compresion De manera que cuando se implementa se puede escoger cualquier tamano y considerar que si por ejemplo elegimos un tamano de 8K necesitaremos 13 bits para el desplazamiento Tamanos EditarOtro aspecto que debemos elegir es el tamano de la longitud Asi que cuantos bits utilizamos para la longitud Podemos elegir cualquier tamano que deseemos pero debemos considerar que afinar los bits del tamano de la longitud y los bits del puntero de desplazamiento podemos mejorar la compresion en algunos archivos y empeorarla en otros asi que si estamos disenando un compresor para un unico archivo deberian encontrarse los valores mas apropiados de lo contrario usaremos un tamano de 0 32 de solo 5 bits Otro aspecto importante es la longitud minima de una coincidencia En nuestro caso hemos elegido utilizar 13 bits en el desplazamiento y 5 en la longitud de la coincidencia 18 bits en total de manera que una coincidencia deberia ser de por lo menos 3 bytes Porque si codificamos una coincidencia con dos bytes 16 bits y utilizamos 18 bits para almacenar la cadena estamos utilizando 2 bits mas que si lo guardamos como un literal Luego se levanta otra pregunta Si nunca tendremos coincidencias de 0 1 o 2 bytes entonces por que tenemos espacio para ellas en la longitud Para sacar el mayor provecho posible Nuestro tamano aun sera representado con 5 bits pero su rango en lugar de ser 0 32 sera 3 35 Como hacemos esto Simplemente restamos al tamano antes de guardarlo 3 y el descompresor lo leera y anadira 3 Marcador de Fin EditarAhora que sabemos como se realiza la descompresion debemos notar que el descompresor deberia saber como terminar o cuando parar Esto puede realizarse de dos formas Se tiene un simbolo que marca el final de los datos Se guarda junto a la cadena de bits el tamano del archivo de entrada Tal vez el segundo metodo sea preferible Es un poco mas lento pero al mismo tiempo que se usa para conocer el final de los datos Puede ser utilizado en una posible interfaz y puede ayudarnos a evitar algunos problemas De cualquier manera si se desea utilizar un marcador de fin de datos podriamos usar tamano cero para ello La forma en que se hace es la siguiente El rango sera de 3 34 en este caso debemos restar al tamano cuando lo guardamos 2 De manera que el rango 1 32 se convierte 3 34 y el compresor solo debe ocuparse de esto al comprimir el archivo una vez la compresion es finalizada la salida desplazamiento tamano tiene tamano de 0 El descompresor debe entonces verificar cada vez que lee un tamano si este tamano es 0 para saber si se ha alcanzado el final del archivo Trabajando con Bits EditarComo puede verse los desplazamientos y tamanos son de longitud variable y las banderas toman unicamente un bit de manera que debemos usar bits en lugar de bytes Esto es muy importante en la mayoria de los algoritmos de compresion La mayoria de operaciones trabajan con bytes y cuando se escribe informacion a un archivo la unidad minima es el byte entonces para escribir bits hacemos un uso inteligente de algunas instrucciones Para realizar esto podemos usar ASM o si no puede ser implementado en C Continuaremos las operaciones con bits en ASM La idea principal es mantener un byte y un contador con los bits escritos luego cuando tenemos 8 bits escribimos ese byte al archivo y comenzamos de nuevo con el siguiente byte A continuacion se presenta un ejemplo utilizando instrucciones de ASM put bits loop push cx el numero de bits a escribir mov bh byte out el byte de salida donde escribir mov bl byte in el byte de entrada los bytes a escribir mov al bl al almacenamos el byte a leer en al shr al 1 desplazamos al a la derecha first bit in the carry flag xor ah ah ah 0 adc ah 0 ah 0 y el acarreo mov bl al guarda el byte de entrada mov cl total bits bits que hemos escrito shl ah cl pone el bit en su posicion desplazando a la izquierda or bh al pone el bit en el byte de salida mov byte out bh guardarlo inc total bits bits escritos cmp total bits 8 Tenemos que escribir todo el byte jne no write byte nop E mov di ptr buffer el puntero al buffer mov es di bh el byte es el segmento del buffer inc di byte en el buffer mov ptr buffer di guardado para la proxima vez inc bytes writed cuando el buffer esta lleno escribir mov byte out 0 a file or something like that so the next time is clear no write byte lo hemos guardado pop cx mas bits para escribir dec cx si repetir todo jnz put bits loop Se presenta la rutina putbits los nombres de las variables se explican por si solos pero aun y todo presentamos aqui una descripcion byte out el byte que sera escrito en el buffer de salida mantiene los bits que estamos escribiendo actualmente byte in el byte que contiene los bits que deseamos escribir total bits el numero de bits que se han escrito actualmente cero al principio Ptr buffer desplazamiento del buffer Cuando se ingresa esta rutina cx debe tener el numero de bits a escribir y bite in los bits a escribir Hay que tener cuidado despues de ingresar el ciclo hay que probar si cx es 0 porque si es cero y no se prueba escribira un bit luego haria cx 1 lo que daria 255 con la consecuencia de escribir 255 bits Recuerde Test cx cx jz put bits end Esta es la estructura como son escritos los bits para un byte Bit 8 Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1Cuando se han escrito todos los bits la compresion ha finalizado debe probarse si hay aun bits esperando para ser escritos asi que si hay algunos total bits 0 escribimos byte out e incrementamos todos los punteros de manera que no dejemos datos sin escribir Archivo de Salida EditarAhora debemos definir el formato del archivo de salida el cual sera simple unicamente debe llenar nuestras necesidades los datos comprimidos se veran como Primero una palabra con el tamano del archivo original y si se desea algunos numeros como identificacion Luego el flujo de bits el cual constituye y contiene los datos comprimidos Pseudocodigo EditarRecordemos como trabaja lz77 uno se encuentra en una posicion dada y trata de hallar hacia atras porque se esta seguro de que el descompresor ya ha decodificado esos bytes cuando uno se encuentra en dicha posicion una coincidencia bytes que son iguales a los bytes en la posicion actual si se encuentran se escribe una palabra clave de otra forma se escribe una literal para poder seguir comprimiendo Secuencia basica Compresor Editar Guardar el tamano del archivo a comprimir Repetir hasta que no haya mas bytes para comprimir Escanear el buffer de entrada comenzando en posicion actual tamano de ventana corrediza hasta el byte actual que estamos comparando Notar que el descompresor no puede copiar bytes de una posicion desde donde sus bytes no han sido previamente definidos Hemos encontrado un byte igual al actual Caso Si Comparamos el siguiente byte desde la posicion actual con el byte en la posicion siguiente de donde encontramos un byte igual al primero Continuar comparando hasta que encontremos un byte que no es igual Se ha encontrado un byte que no es igual Es el numero de bytes mayor que tres Caso Si Escribir el desplazamiento del PRIMER byte hallado y el numero de bytes repetidos tamano Movemos el puntero a la posicion con el numero de bytes repetidos porque no los hemos salvado y seguimos buscando Tambien se escribe una bandera 1 Caso No Continua la busqueda Caso No Si no se encuentra ninguna coincidencia simplemente se escribe un byte sin comprimir tambien se escribe un literal si no hay datos en la ventana corrediza Debe recordar poner la bandera a 0 Secuencia basica Descompresor Editar Se lee el tamano del archivo sin comprimir Se repite hasta que se ha descomprimido todo el archivo Se lee un bit la bandera Si es 0 Se leen 8 bits se escriben al buffer de salida recordar que son un byte descomprimido y se incrementa el puntero a la salida Si es 1 Se lee el desplazamiento completo 13 bits luego el tamano copiar tamano bytes de desplazamiento a la posicion actual y anadir al puntero a la salida tamano Buscando Coincidencias EditarLa forma en que se buscan las coincidencias es la siguiente se mantiene un puntero a la posicion actual Al principio de cualquier iteracion se computa el desplazamiento a la ventana corrediza Esto se puede hacer facilmente obteniendo el puntero a la posicion actual y restandole el tamano de la ventana corrediza en caso de que sea menos que cero negativo simplemente se ajusta a cero Digamos que tenemos una ventana corrediza de 4 bytes de largo asi que gastamos dos bits para especificar el desplazamiento y tenemos la siguiente cadena 1234567 Pa 0 Pvc 0 4 0 Actual 1234567 Ventana Corrediza Pa 1 Pvc 1 4 0 Actual 234567 Ventana Corrediza 1 Pa 2 Pvc 2 4 0 Actual 34567 Ventana Corrediza 12 Pa 3 Pvc 3 4 0 Actual 4567 Ventana Corrediza 123 Pa 4 Pvc 4 4 0 Actual 567 Ventana Corrediza 1234 Pa 5 Pvc 5 4 1 Actual 67 Ventana Corrediza 2345 Pa 6 Pvc 6 4 2 Actual 7 Ventana Corrediza 3456 Donde Pa es el puntero al byte actual y Pvc es el puntero al inicio de la ventana corrediza Cuando se usan punteros al archivo de entrada completo debemos cuidar el tamano de la ventana corrediza Vease tambien EditarSistema de compresion Algoritmo de compresion Compresion digital Algoritmo de compresion sin perdida Algoritmo de compresion con perdida 7z Algoritmo de HuffmanEnlaces externos EditarLista de manuales de algoritmos de compresion sin perdida Espanol Datos Q2679 Obtenido de https es wikipedia org w index php title LZSS amp oldid 130538811, wikipedia, wiki, leyendo, leer, libro, biblioteca,

español

, española, descargar, gratis, descargar gratis, mp3, video, mp4, 3gp, jpg, jpeg, gif, png, imagen, música, canción, película, libro, juego, juegos