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:
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:
Compilar correctamente con los flags:
-Wall -Werror -std=c99 -pedantic
pasar Valgrind correctamente,
La entrega se realiza a través del sistema de entregas.
El ejercicio es de entrega individual.