Ejercicio obligatorio 3

Fecha de entrega: Lunes 27 de octubre

Introducción

Se tiene un formato binario que representa una biblioteca de sprites monocromáticos. Un archivo consiste en una secuencia de longitud indefinida de sprites.

Cada sprite tiene una etiqueta que la identifica, un ancho, un alto y luego sus píxeles codificados como bits.

El contenido de cada sprite será entonces:

+-------------------+-------+-------+--------------------------------+
|      Etiqueta     | ancho | alto  |            pixeles             |
+-------------------+-------+-------+--------------------------------+

La etiqueta ocupa 20 bytes y es una cadena terminada con '\0'. Tanto el ancho como el alto ocupan un byte, por lo que una imagen no puede medir más de 255x255 pixeles. Luego los pixeles se codifican en paquetes de un byte, donde cada byte contiene 8 pixeles. El bit menos significativo será el primer pixel mientras que el más significativo será el octavo pixel del paquete. Los pixeles se agrupan por filas del sprite, por ejemplo, si un sprite tuviera 20 píxeles de ancho por 10 pixeles de alto, cada fila se va a representar utilizando 3 bytes, los cuales podrían almacenar hasta 24 pixeles. El primer byte de la fila almacena los píxeles entre la columna 0 y la 7, el segundo byte entre la columna 8 y la 15 y el tercero entre la columna 16 y la 19, quedando sin uso los 4 bits más significativos. Por ejemplo, si se tuvieran los bytes {0x96, 0x81, 0x05} esto representaría la secuencia de pixeles

0110 1001 1000 0001 1010. Así será cada fila, por lo tanto los

pixeles de este sprite ocuparán 10 filas de 3 bytes cada una totalizando 30 bytes. Nuestro sprite de ejemplo utilizará 20 + 1 + 1 + 30 = 52 bytes en total.

Como se dijo, un archivo de sprites será una sucesión de sprites hasta el final del archivo.

Trabajo

En este trabajo se deberán implementar dos TDAs con un juego de primitivas que van a definir su comportamiento. Se pueden implementar primitivas adicionales si así se evaluara necesario.

TDA sprite_t

El TDA sprite representa un sprite como se definió en la introducción, con sus atributos.

Se pide implementar un constructor sprite_t *sprite_crear(FILE *fi) que, siendo fi un archivo abierto en modo lectura binaria, lea del archivo uno (y sólo uno) sprite y lo devuelva. En caso de falla o de que el archivo se terminara debe devolverse NULL.

Nota

Se puede asumir que el archivo está bien formado. Es decir, con que se pueda leer tan solo un byte de la etiqueta se puede asumir que estarán los 19 restantes, los bytes del tamaño y todos los pixeles que correspondan con el ancho y alto.

Si no se puede leer ni un byte, es porque el archivo ya se terminó, lo cual no es un error.

Se pide implementar el destructor void sprite_destruir(sprite_t *s); que libere la memoria asociada al sprite s.

Se pide implementar la primitiva bool sprite_a_pbm(const sprite_t *s, FILE *fo); que dado un archivo fo abierto en modo escritura de texto genere un PBM (ver EJ1) con el contenido del sprite s en dicho archivo.

Se pide implementar los getters size_t sprite_ancho(const sprite_t *s);, size_t sprite_alto(const sprite_t *s); que devuelvan el ancho y el alto del sprite s respectivamente, el getter char *sprite_etiqueta(const sprite_t *s); que devuelva la etiqueta del sprite s y el getter bool sprite_obtener(const sprite_t *s, size_t fila, size_t col); que devuelva el valor del pixel de la coordenada (fila, col) del sprite s.

Implementar el setter bool sprite_establecer(sprite_t *s, size_t fila, size_t col, bool valor); que escriba el valor dado en el pixel de coordenada (fila, col) del sprite s.

TDA sprites_t

El TDA sprites es un contenedor que tiene dentro una cantidad indefinida de sprite_t los cuales se pueden recuperar según su etiqueta.

Implementar el constructor sprites_t *sprites_crear(const char *ruta); que dada la ruta de un archivo binario con la especificación dada en la introducción devuelva un TDA sprites que contenga todos los sprites del archivo.

Implementar el destructor void sprites_destruir(sprites_t *ss); que libere toda la memoria asociada al TDA.

Implementar el getter size_t sprites_cantidad(const sprites_t *ss); que devuelva la cantidad de sprites que hay dentro del TDA ss.

Implementar la primitiva sprite_t *sprites_obtener(const sprites_t *ss, const char *etiqueta); que dada la etiqueta de un sprite devuelva el sprite correspondiente del contenedor ss. Si no hubiera un sprite con esa etiqueta se devolverá NULL.

Nota

Notar que sprite_t y sprites_t son dos TDAs diferentes, no está permitido que la implementación de sprites_t acceda a la representación interna de sprite_t.

Programa

Implementar un programa que permita extraer un sprite determinado de un archivo binario de sprites a un archivo PBM.

El programa debe ejecutarse:

$ ./20252_ej3 <sprites> <etiqueta_sprite>

y generar un archivo etiqueta_sprite.pbm con el sprite seleccionado. Deben informarse los errores que hubiera. Si el usuario invoca el programa con una cantidad incorrecta de argumentos, se deberá mostrar una pequeña ayuda de invocación.

Se provee un archivo de sprites que se descarga acá 20252_ej3.bin

Con ese archivo si se invocara la aplicación como:

$ ./20252_ej3 20252_ej3.bin kuchipatchi

se debería generar el archivo kuchipatchi.pbm con la siguiente imagen:

../_images/20252_ej3.png

Entrega

Se deben entregar los TDAs desarrollados, no es obligatorio modularizar pero es deseable. En caso de modularizar entregar además de los archivos .c y .h el Makefile para compilar el proyecto.

El proyecto debe:

  1. Compilar correctamente con los flags:

    -Wall -Werror -std=c99 -pedantic
    
  2. pasar Valgrind correctamente,

La entrega se realiza a través del sistema de entregas.

El ejercicio es de entrega individual.