Ejercicio obligatorio 3

Fecha de entrega: Domingo 9 de octubre

Nota

Nunca es buena idea empezar por un ejercicio integrador antes de tener practicados los temas que el trabajo integra.

Se sugiere antes de desarrollar este trabajo resolver, al menos, los siguientes ejercicios de la guía de Memoria dinámica:

  • Ejercicio 12 (combinar vectores).

  • Ejercicio 14.a (matriz identidad).

  • Ejercicio 16 con el 1.b y 1.c de la guía de estructuras (dirección y persona).

Introducción

Queremos modelar una imagen, para ello definimos la estructura:

typedef struct {
    pixel_t **pixeles;
    size_t ancho, alto;
} imagen_t;

que permite almacenar en memoria una imagen según el siguiente esquema:

../_images/20222_ej3.png

Trabajo

Creación y destrucción

Se pide implementar la función auxiliar imagen_t *_imagen_crear(size_t ancho, size_t alto); que genere la memoria necesaria para almacenar una imagen de ancho x alto píxeles. Los píxeles no deben ser inicializados. La función debe devolver la imagen creada o NULL en caso de falla.

Se pide implementar la función void imagen_destruir(imagen_t *imagen); que libere la memoria asociada a la imagen previamente creada.

Generación de imagen

Implementar una función imagen_t *imagen_generar(size_t ancho, size_t alto, pixel_t valor); que cree una imagen de ancho x alto con todos los pixeles inicializados en valor. La función debe retornar la imagen creada o NULL en caso de falla.

Lectura y escritura

Implementar la función imagen_t *imagen_leer_pgm(); que cargue una imagen PGM desde stdin y la devuelva. En caso de falla se debe devolver NULL.

Nota

Se puede asumir que la imagen tiene un formato como el siguiente:

P2
ancho alto
maximo
pixel1
pixel2
pixel3
...

es decir, luego del encabezado un pixel por línea.

La función debe validar que la primera línea sea exactamente "P2".

Implementar la función void imagen_imprimir_pgm(const imagen_t *imagen); que imprima la imagen por stdout según el formato PGM. En esta función asumir que el máximo vale 255.

Pegar y escalar

Implementar la función void imagen_pegar(imagen_t *destino, const imagen_t *origen, int x, int y); que pegue la imagen origen en la imagen destino, en las coordenadas (x, y). Los píxeles de valor 0 son transparentes y no deben ser pegados.

Implementar una función imagen_t *imagen_escalar(const imagen_t *origen, size_t ancho_destino, size_t alto_destino); que devuelva una nueva imagen de tamaño ancho_destino x alto_destino en base a escalar la imagen origen. La función debe devolver NULL en caso de falla.

Aplicación y validación

Se provee el código fuente de la función main() que realiza llamadas a cada una de estas funciones. Dicha función debe ser la que se entregue como parte del trabajo sin efectuarle modificaciones de ningún tipo

#include <stdint.h>
#include <assert.h>

typedef uint8_t pixel_t;

typedef struct {
    pixel_t **pixeles;
    size_t ancho, alto;
} imagen_t;

int main(void) {
    imagen_t *imagen = imagen_generar(640, 480, 255);
    assert(imagen != NULL);

    imagen_t *squirtle = imagen_leer_pgm();
    assert(squirtle != NULL);

    imagen_t *squirtle_chico = imagen_escalar(squirtle, 208, 215);
    assert(squirtle_chico != NULL);

    imagen_t *squirtle_grande = imagen_escalar(squirtle, 834, 862);
    assert(squirtle_grande != NULL);

    imagen_pegar(imagen, squirtle, 10, 10);
    imagen_pegar(imagen, squirtle_chico, 380, 20);
    imagen_pegar(imagen, squirtle_grande, 280, 230);

    assert(imagen_generar(1UL << 62, 10000, 0) == NULL);

    imagen_imprimir_pgm(imagen);

    imagen_destruir(imagen);
    imagen_destruir(squirtle);
    imagen_destruir(squirtle_chico);
    imagen_destruir(squirtle_grande);

    return 0;
}

Además se provee la siguiente imagen PGM entrada_20222_ej3.pgm

El programa al ser invocado como:

./20222_ej3 < entrada_20222_ej3.pgm > salida_20222_ej3.pgm

deberá generar una imagen como la siguiente:

../_images/20222_ej3_salida.png

Entrega

Deberá entregarse el código fuente del programa desarrollado.

El programa debe:

  1. Compilar correctamente con los flags:

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

  3. validar la salida dada.

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

El ejercicio es de entrega individual.