David 11 роки тому
батько
коміт
a7187acd3d
23 змінених файлів з 1603 додано та 0 видалено
  1. 2 0
      .gitignore
  2. 42 0
      Makefile
  3. 205 0
      cli.c
  4. BIN
      documentos/tp2-enunciado.pdf
  5. BIN
      enunciado.pdf
  6. 39 0
      filtros/Makefile
  7. 48 0
      filtros/blur.c
  8. 23 0
      filtros/blur_asm.asm
  9. 18 0
      filtros/blur_c.c
  10. 50 0
      filtros/diff.c
  11. 22 0
      filtros/diff_asm.asm
  12. 20 0
      filtros/diff_c.c
  13. 32 0
      helper/Makefile
  14. 298 0
      helper/bmpdiff.c
  15. 70 0
      helper/imagenes.c
  16. 9 0
      helper/imagenes.h
  17. 276 0
      helper/libbmp.c
  18. 188 0
      helper/libbmp.h
  19. 41 0
      helper/tiempo.h
  20. 28 0
      helper/utils.h
  21. BIN
      img.tar.gz
  22. 95 0
      tp2.c
  23. 97 0
      tp2.h

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+img/
+*.o

+ 42 - 0
Makefile

@@ -0,0 +1,42 @@
+
+CFLAGS64 = -ggdb -Wall -Wextra -std=c99 -pedantic -m64
+#CFLAGS64 = -O3 -Wall -std=c99 -pedantic -m64
+
+
+CFLAGS   = $(CFLAGS64)
+
+BUILD_DIR = build
+BIN = tp2
+
+
+
+FILTROS = diff blur
+
+FILTROS_OBJ = $(addsuffix .o, $(FILTROS)) $(addsuffix _asm.o, $(FILTROS)) $(addsuffix _c.o, $(FILTROS))
+LIBS_OBJS   = libbmp.o imagenes.o
+MAIN_OBJS   = tp2.o cli.o
+MAIN_OBJS_CON_PATH = $(addprefix $(BUILD_DIR)/, $(MAIN_OBJS))
+
+OBJS = $(MAIN_OBJS) $(LIBS_OBJS) $(FILTROS_OBJ)
+OBJS_CON_PATH = $(addprefix $(BUILD_DIR)/, $(OBJS))
+
+.PHONY: all clean FORCE
+
+all: $(BUILD_DIR)/$(BIN)
+
+
+$(BUILD_DIR)/$(BIN): FORCE $(MAIN_OBJS_CON_PATH)
+	$(CC) $(CFLAGS) $(OBJS_CON_PATH) -o $@ -lm
+
+export CFLAGS64
+FORCE:
+	make -C helper
+	make -C filtros
+
+$(BUILD_DIR)/%.o: %.c
+	$(CC) $(CFLAGS) -c -o $@ $< -lm
+
+clean:
+	rm -fr $(BUILD_DIR)/*
+
+

+ 205 - 0
cli.c

@@ -0,0 +1,205 @@
+
+/** ~~~~~~~~~~ COMMAND LINE INTERFACE ~~~~~~~~~~ **/
+
+
+/** ---------------------------------------------- *
+ *                                                 *
+ *  Este archivo contiene la implementacion de la  *
+ *  lectura de argumentos genericos por linea de   *
+ *  comandos (los argumentos particulares de cada  *
+ *  filtro se leen en su respectivo .c)            *
+ *                                                 *
+ *  Autor: orga2                                   *
+ *                                                 *
+ * ----------------------------------------------- *
+**/
+
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "tp2.h"
+
+void procesar_opciones(int argc, char **argv, configuracion_t *config)
+{
+	// Si se ejecuta sin parametros ni opciones
+	if (argc == 1) {
+		imprimir_ayuda (argv[0]);
+		exit ( EXIT_SUCCESS );
+	}
+
+	char *tipo_filtro;
+	int tiempo = 0;
+	int siguiente_opcion;
+
+	// opciones por defecto
+	config->es_video = false;
+	config->verbose = false;
+	config->frames = false;
+	config->nombre = false;
+	config->cant_iteraciones = 1;
+	config->archivo_entrada = NULL;
+	config->archivo_entrada_2 = NULL;
+	config->carpeta_salida = ".";
+	config->extra_archivo_salida = "";
+
+	// extraemos opciones de la linea de comandos
+	const char* const op_cortas = "hi:vt:fo:wn";
+
+	const struct option op_largas[] = {
+		{ "help", 0, NULL, 'h' },
+		{ "implementacion", 1, NULL, 'i' },
+		{ "verbose", 0, NULL, 'v' },
+		{ "video", 0, NULL, 'w' },
+		{ "tiempo", 1, NULL, 't' },
+		{ "frames", 0, NULL, 'f' },
+		{ "nombre", 0, NULL, 'n' },
+		{ "output", 1, NULL, 'o' },
+		{ NULL, 0, NULL, 0 }
+	};
+
+
+	while (1) {
+		siguiente_opcion = getopt_long ( argc, argv, op_cortas, op_largas, NULL);
+
+		// No hay mas opciones
+		if ( siguiente_opcion == -1 )
+			break;
+
+		// Procesar opcion
+		switch ( siguiente_opcion ) {
+			case 'h' : /* -h o --help */
+				imprimir_ayuda (argv[0]);
+				exit ( EXIT_SUCCESS );
+				break;
+			case 'i' : /* -i o --implementacion */
+				tipo_filtro = optarg;
+				break;
+			case 't' : /* -t o --tiempo */
+				tiempo = 1;
+				config->cant_iteraciones = atoi ( optarg );
+				break;
+			case 'v' : /* -v o --verbose */
+				config->verbose = true;
+				break;
+			case 'f' : /* -f o --frames */
+			    config->frames = true;
+			    break;
+			case 'n' : /* -n o --nombre */
+			    config->nombre = true;
+			    break;
+			case 'o' : /* -o o --output */
+			    config->carpeta_salida = optarg;
+			    break;
+			case 'w' : /* -w o --video */
+			    config->es_video = true;
+			    break;
+			case '?' : /* opcion no valida */
+				imprimir_ayuda (argv[0]);
+				exit ( EXIT_SUCCESS );
+			default : /* opcion no valida */
+				abort ( );
+		}
+	}
+
+	// Verifico nombre del proceso
+	config->nombre_filtro = argv[optind++];
+
+	if (config->nombre_filtro == NULL) {
+		imprimir_ayuda (argv[0]);
+
+		exit ( EXIT_SUCCESS );
+	}
+
+	// Verifico nombre de la implementacion
+	if (tipo_filtro == NULL ||
+		(strcmp(tipo_filtro, "c") != 0 &&
+		strcmp(tipo_filtro, "asm") != 0)) {
+		imprimir_ayuda (argv[0]);
+
+		exit ( EXIT_SUCCESS );
+	}
+
+	if (strcmp(tipo_filtro, "c") == 0) {
+		config->tipo_filtro = FILTRO_C;
+	} else {
+		config->tipo_filtro = FILTRO_ASM;
+	}
+
+
+	// Verifico nombre de archivo
+	config->archivo_entrada = argv[optind++];
+
+	if (config->archivo_entrada == NULL) {
+		imprimir_ayuda (argv[0]);
+		exit ( EXIT_SUCCESS );
+	}
+
+	if (access( config->archivo_entrada, F_OK ) == -1) {
+		printf("Error al intentar abrir el archivo: %s.\n", config->archivo_entrada);
+
+		exit ( EXIT_SUCCESS );
+	}
+	filtro_t * filtro = detectar_filtro(config);
+    if (filtro != NULL && optind < argc && filtro->n_entradas > 1) {
+        config->archivo_entrada_2 = argv[optind++];
+    	if (config->archivo_entrada_2 == NULL) {
+    		imprimir_ayuda (argv[0]);
+    		exit ( EXIT_SUCCESS );
+    	}
+
+    	if (access( config->archivo_entrada_2, F_OK ) == -1) {
+    		printf("Error al intentar abrir el archivo: %s.\n", config->archivo_entrada_2);
+
+    		exit ( EXIT_SUCCESS );
+    	}
+
+    }
+
+}
+
+
+void imprimir_ayuda ( char *nombre_programa) {
+	printf ( "Uso: %s opciones filtro nombre_archivo_entrada parametros_filtro\n",
+	         nombre_programa );
+	printf ( "    Los filtros que se pueden aplicar son \n");
+
+	for (int i = 0; filtros[i].nombre != 0; i++)
+		filtros[i].ayuda();
+
+
+	printf ( "\n" );
+	printf ( "    -h, --help: \n");
+	printf ( "                Imprime esta ayuda\n" );
+    printf ( "\n" );
+	printf ( "    -i, --implementacion NOMBRE_MODO\n");
+	printf ( "                                     "
+	         "Implementación sobre la que se ejecutará el filtro\n"
+	         "                                     "
+	         "seleccionado. Los implementaciones disponibles\n"
+	         "                                     "
+	         "son: c, asm\n");
+	printf ( "\n" );
+	printf ( "    -t, --tiempo CANT_ITERACIONES\n");
+	printf ( "                                   "
+	         "Mide el tiempo que tarda en ejecutar el filtro sobre la\n"
+	         "                                   "
+	         "imagen de entrada una cantidad de veces igual a\n"
+	         "                                   "
+	         "CANT_ITERACIONES\n");
+	printf ( "\n" );
+	printf ( "    -o, --output CARPETA\n");
+	printf ( "                          "
+	         "Carpeta de salida. Por defecto es la misma que la de entrada\n");
+	printf ( "    -n, --nombre\n");
+	printf ( "                          "
+	         "No aplica el filtro, solo muestra el nombre del archivo de salida\n");
+	printf ( "    -v, --verbose\n");
+	printf ( "                   "
+	         "Imprime información adicional\n" );
+	printf ( "\n" );
+
+}

BIN
documentos/tp2-enunciado.pdf



+ 39 - 0
filtros/Makefile

@@ -0,0 +1,39 @@
+# ************************************************************************* #
+# Organizacion del Computador II                                            #
+#                                                                           #
+#   Trabajo Practico 2                                                      #
+#                                                                           #
+# ************************************************************************* #
+ASM = nasm
+UNAME_S := $(shell uname -s)
+ifeq ($(UNAME_S),Linux)
+	ASMFLAGS64 = -felf64 -g -F dwarf
+endif
+ifeq ($(UNAME_S),Darwin)
+	ASMFLAGS64 = -fmacho64 -g -DDARWIN
+endif
+
+ASMFLAGS = $(ASMFLAGS64)
+
+CFLAGS64 ?=-Wall -Wextra -pedantic -O0 -ggdb
+CFLAGS=$(CFLAGS64)
+
+BUILD_DIR = ../build
+
+FILTROS = diff blur
+
+FILTROS_OBJ = $(addsuffix .o, $(FILTROS)) $(addsuffix _asm.o, $(FILTROS)) $(addsuffix _c.o, $(FILTROS))
+FILTROS_OBJ_CON_PATH = $(addprefix  $(BUILD_DIR)/, $(FILTROS_OBJ))
+
+.PHONY: filtros clean
+
+filtros: $(FILTROS_OBJ_CON_PATH)
+
+$(BUILD_DIR)/%.o: %.c
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+$(BUILD_DIR)/%.o: %.asm
+	$(ASM) $(ASMFLAGS) -o $@ $<
+
+clean:
+	rm -f $(FILTROS_OBJ_CON_PATH)

+ 48 - 0
filtros/blur.c

@@ -0,0 +1,48 @@
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "../tp2.h"
+
+void blur_asm    (unsigned char *src, unsigned char *dst, int cols, int filas,
+                      float sigma, int radius);
+
+void blur_c    (unsigned char *src, unsigned char *dst, int cols, int filas,
+                      float sigma, int radius);
+
+typedef void (blur_fn_t) (unsigned char*, unsigned char*, int, int, float, int);
+
+typedef struct blur_params_t {
+	float sigma;
+    int radius;
+} blur_params_t;
+
+blur_params_t extra;
+void leer_params_blur(configuracion_t *config, int argc, char *argv[]) {
+    config->extra_config = &extra;
+    extra.sigma    = atof(argv[argc - 2]);
+    extra.radius    = atoi(argv[argc - 1]);
+}
+
+
+
+void aplicar_blur(configuracion_t *config)
+{
+	blur_fn_t *blur = SWITCH_C_ASM ( config, blur_c, blur_asm ) ;
+	buffer_info_t info = config->src;
+    blur_params_t * extra_params = (blur_params_t *) config->extra_config;
+	blur(info.bytes, config->dst.bytes, info.width, info.height,
+				extra_params->sigma, extra_params->radius);
+
+}
+
+void ayuda_blur()
+{
+	printf ( "       * blur\n" );
+	printf ( "           Parámetros     : \n"
+	         "                         sigma\n"
+	         "                         radio\n");
+	printf ( "           Ejemplo de uso : \n"
+	         "                         blur -i c facil.bmp 0.7 1\n");
+}

+ 23 - 0
filtros/blur_asm.asm

@@ -0,0 +1,23 @@
+default rel
+global _blur_asm
+global blur_asm
+
+
+section .data
+
+
+
+section .text
+;void blur_asm    (
+	;unsigned char *src,
+	;unsigned char *dst,
+	;int filas,
+	;int cols,
+    ;float sigma,
+    ;int radius)
+
+_blur_asm:
+blur_asm:
+
+
+    ret

+ 18 - 0
filtros/blur_c.c

@@ -0,0 +1,18 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include "../tp2.h"
+
+
+void blur_c    (
+    unsigned char *src,
+    unsigned char *dst,
+    int cols,
+    int filas,
+    float sigma,
+    int radius)
+{
+    unsigned char (*src_matrix)[cols*4] = (unsigned char (*)[cols*4]) src;
+    unsigned char (*dst_matrix)[cols*4] = (unsigned char (*)[cols*4]) dst;
+
+}

+ 50 - 0
filtros/diff.c

@@ -0,0 +1,50 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../tp2.h"
+
+void diff_asm  (unsigned char *src, unsigned char *src_2, unsigned char *dst,
+                int cols, int filas, int src_row_size,
+                int src_row_size_2 ,int dst_row_size);
+
+void diff_c (unsigned char *src, unsigned char *src_2, unsigned char *dst,
+            int cols, int filas, int src_row_size,
+            int src_row_size_2 ,int dst_row_size);
+
+typedef void (diff_fn_t) (unsigned char*, unsigned char*, unsigned char*,
+                          int, int, int, int, int);
+
+void ayuda_diff()
+{
+	printf ( "       * diff\n" );
+	printf ( "           Parámetros     : \n"
+	         "                         no tiene\n");
+	printf ( "           Ejemplo de uso : \n"
+	         "                         diff -i c facil.bmp facil2.bmp\n" );
+}
+
+void leer_params_diff(configuracion_t *config, int argc, char *argv[]) {
+    if (config->archivo_entrada_2 == NULL) {
+        printf("El filtro diff requiere de dos archivos de entrada\n\n");
+        ayuda_diff();
+        exit(EXIT_FAILURE);
+    } else {
+        printf ( "  Archivo de entrada : %s\n", config->archivo_entrada_2);
+    }
+}
+
+void aplicar_diff(configuracion_t *config)
+{
+	diff_fn_t *diff = SWITCH_C_ASM ( config, diff_c, diff_asm ) ;
+	buffer_info_t info = config->src;
+	buffer_info_t info2 = config->src_2;
+    if (info.width != info2.width || info.height != info2.height) {
+        perror("Las imagenes deben tener el mismo tamaño en pixeles");
+    }
+	diff(info.bytes, info2.bytes, config->dst.bytes, info.width, info.height,
+         info.width_with_padding, info2.width_with_padding,
+         config->dst.width_with_padding);
+
+}

+ 22 - 0
filtros/diff_asm.asm

@@ -0,0 +1,22 @@
+default rel
+global _diff_asm
+global diff_asm
+
+
+section .data
+
+
+
+section .text
+;void diff_asm    (
+	;unsigned char *src,
+    ;unsigned char *src2,
+	;unsigned char *dst,
+	;int filas,
+	;int cols)
+
+_diff_asm:
+diff_asm:
+
+
+    ret

+ 20 - 0
filtros/diff_c.c

@@ -0,0 +1,20 @@
+
+#include <stdlib.h>
+#include <math.h>
+#include "../tp2.h"
+
+void diff_c (
+	unsigned char *src,
+	unsigned char *src_2,
+	unsigned char *dst,
+	int m,
+	int n,
+	int src_row_size,
+	int src_2_row_size,
+	int dst_row_size
+) {
+	unsigned char (*src_matrix)[src_row_size] = (unsigned char (*)[src_row_size]) src;
+	unsigned char (*src_2_matrix)[src_2_row_size] = (unsigned char (*)[src_2_row_size]) src_2;
+	unsigned char (*dst_matrix)[dst_row_size] = (unsigned char (*)[dst_row_size]) dst;
+
+}

+ 32 - 0
helper/Makefile

@@ -0,0 +1,32 @@
+# ************************************************************************* #
+# Organizacion del Computador II                                            #
+#                                                                           #
+#   Trabajo Practico 2                                                      #
+#                                                                           #
+# ************************************************************************* #
+
+CFLAGS=-Wall -Wextra -pedantic -O0 -ggdb -std=c99
+
+BUILD_DIR = ../build
+BIN = tp2
+
+OBJS          = libbmp.o imagenes.o
+OBJS_CON_PATH = $(addprefix $(BUILD_DIR)/, $(OBJS))
+BMPDIFF       = $(BUILD_DIR)/bmpdiff
+
+
+# .PHONY: all clean libbmp bmpdiff
+
+all: $(OBJS_CON_PATH) bmpdiff
+
+lib: all
+
+$(BUILD_DIR)/%.o: %.c
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+bmpdiff: bmpdiff.c $(OBJS_CON_PATH)
+	$(CC) $(CFLAGS) bmpdiff.c $(OBJS_CON_PATH) -o $(BMPDIFF)
+
+
+clean:
+	rm -f $(OBJS_CON_PATH) $(BMPDIFF)

+ 298 - 0
helper/bmpdiff.c

@@ -0,0 +1,298 @@
+/* ************************************************************************* */
+/* Organizacion del Computador II                                            */
+/*                                                                           */
+/*                   Buscador de diferencias en archivos BMP                 */
+/*                                                                           */
+/*  Ejmplo para obtener la cantidad de pixeles distintos por diferencia      */
+/*     bin/diff -v img1.bmp img2.bmp 0 | awk '{print $5}' | sort | uniq -c   */
+/*                                                                           */
+/* ************************************************************************* */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "libbmp.h"
+
+typedef struct s_options {
+    char* program_name;
+    int value;
+    int verbose;
+    int image;
+    int help;
+    int summaryop;
+    int* summary;
+    char* file1;
+    char* file2;
+    uint8_t epsilon;
+} options;
+
+void print_help(char* name);
+
+int read_options(int argc, char* argv[], options* opt);
+
+uint8_t cmp(uint8_t a, uint8_t b, int c, int r, char* channel, options* opt);
+
+int main(int argc, char* argv[]){
+    int i, j;
+
+    // (0) leer parametros
+    options opt;
+    if (argc == 1) {
+        print_help(argv[0]);
+        return 0;
+    }
+    if (read_options(argc, argv, &opt)) {
+        printf("ERROR reading parameters\n");
+        return 1;
+    }
+    int len1 = strlen(opt.file1);
+    int len2 = strlen(opt.file2);
+    if (strcmp(&(opt.file1[len1-4]),".bmp") || strcmp(&(opt.file2[len2-4]),".bmp")) {
+        printf("ERROR: nombre del archivo\n");
+        return -1;
+    }
+
+    // (0.1) siempre armo el summary
+    opt.summary = (int*)malloc(sizeof(int)*256);
+    for (i=0; i<256; i++) {
+        opt.summary[i]=0;
+    }
+
+    // (1) leer imagenes
+    BMP* bmp1 = bmp_read(opt.file1);
+    BMP* bmp2 = bmp_read(opt.file2);
+    if (bmp1 == 0 || bmp1 == 0) {
+        printf("ERROR: no se puede abrir el archivo\n");
+        return -1;
+    }
+
+    // (2) check tipo de archivo
+    if (((BMPIH*)(bmp1->ih))->biSize != ((BMPIH*)(bmp1->ih))->biSize) {
+        printf("ERROR: tipo de archivo diferente\n");
+        return -1;
+    }
+
+    // (3) check tamaño del archivo
+    int w1 = ((BMPIH*)(bmp1->ih))->biWidth;
+    int h1 = ((BMPIH*)(bmp1->ih))->biHeight;
+    int c1 = ((BMPIH*)(bmp1->ih))->biBitCount;
+    int w2 = ((BMPIH*)(bmp2->ih))->biWidth;
+    int h2 = ((BMPIH*)(bmp2->ih))->biHeight;
+    int c2 = ((BMPIH*)(bmp2->ih))->biBitCount;
+    if (w1!=w2 || h1!=h2 || c1!=c2) {
+        printf("ERROR: tamaño de archivo diferente\n");
+        return -1;
+    }
+    //printf("%i=%i %i=%i %i=%i\n",w1,w2,h1,h2,c1,c2);
+    if (w1 % 4 != 0) {
+        // TODO: soportar padding!
+        printf("ERROR: padding no soportado\n");
+        return -1;
+    }
+
+    // (3) check el bit count TODO: only 24 o 32
+    if (c1 != 24 && c1 != 32) {
+        printf("ERROR: (%i) bitcount distinto de 24 o 32\n", c1);
+        return -1;
+    }
+
+    // (4) crear imagenes de diferencias
+    BMP *bmpDiffR, *bmpDiffG, *bmpDiffB, *bmpDiffA;
+    bmpDiffR = bmp_copy(bmp1, 0);
+    bmpDiffG = bmp_copy(bmp1, 0);
+    bmpDiffB = bmp_copy(bmp1, 0);
+    if (c1 == 32) {
+        bmpDiffA = bmp_copy(bmp1,0);
+    }
+
+    // (5) extraer data
+    uint8_t *data1, *data2, *dataR, *dataG, *dataB, *dataA;
+    data1 = bmp_data(bmp1);
+    data2 = bmp_data(bmp2);
+    dataR = bmp_data(bmpDiffR);
+    dataG = bmp_data(bmpDiffG);
+    dataB = bmp_data(bmpDiffB);
+    if (c1 == 32) {
+        dataA = bmp_data(bmpDiffA);
+    }
+
+    // (6) calcular diferencias
+    if (c1 == 32) {
+        for(j=0;j<h1;j++) {
+            for(i=0;i<w1;i++) {
+              int pos = (j*w1+i)*4;
+              uint8_t R1 = data1[pos+3];
+              uint8_t G1 = data1[pos+2];
+              uint8_t B1 = data1[pos+1];
+              uint8_t A1 = data1[pos+0];
+              uint8_t R2 = data2[pos+3];
+              uint8_t G2 = data2[pos+2];
+              uint8_t B2 = data2[pos+1];
+              uint8_t A2 = data2[pos+0];
+
+              dataR[pos+0] = cmp(R1,R2,i,j,"R",&opt);
+              dataR[pos+1] = dataR[pos+0];
+              dataR[pos+2] = dataR[pos+30];
+              dataR[pos+3] = 255;
+
+              dataG[pos+0] = cmp(G1,G2,i,j,"G",&opt);
+              dataG[pos+1] = dataG[pos+0];
+              dataG[pos+2] = dataG[pos+0];
+              dataG[pos+3] = 255;
+
+              dataB[pos+0] = cmp(B1,B2,i,j,"B",&opt);
+              dataB[pos+1] = dataB[pos+0];
+              dataB[pos+2] = dataB[pos+0];
+              dataB[pos+3] = 255;
+
+              dataA[pos+0] = cmp(A1,A2,i,j,"A",&opt);
+              dataA[pos+1] = dataA[pos+0];
+              dataA[pos+2] = dataA[pos+0];
+              dataA[pos+3] = 255;
+            }
+        }
+    } else if(c1 == 24) {
+        for(j=0;j<h1;j++) {
+            for(i=0;i<w1;i++) {
+                int pos = (j*w1+i)*3;
+                uint8_t R1 = data1[pos+2];
+                uint8_t G1 = data1[pos+1];
+                uint8_t B1 = data1[pos+0];
+                uint8_t R2 = data2[pos+2];
+                uint8_t G2 = data2[pos+1];
+                uint8_t B2 = data2[pos+0];
+
+                dataR[pos+2] = cmp(R1,R2,i,j,"R",&opt);
+                dataR[pos+1] = dataR[pos+2];
+                dataR[pos+0] = dataR[pos+2];
+
+                dataG[pos+2] = cmp(G1,G2,i,j,"G",&opt);
+                dataG[pos+1] = dataG[pos+2];
+                dataG[pos+0] = dataG[pos+2];
+
+                dataB[pos+2] = cmp(B1,B2,i,j,"B",&opt);
+                dataB[pos+1] = dataB[pos+2];
+                dataB[pos+0] = dataB[pos+2];
+            }
+        }
+    }
+
+    // (7) mostrar summary
+    if(opt.summaryop) {
+        for(i=1;i<256;i++) {
+            if(opt.summary[i]!=0) {
+                printf("%i\t%i\n", i, opt.summary[i]);
+            }
+        }
+    }
+
+    // (8) guardar resultados
+    if(opt.image) {
+        char* strX = "diffX.bmp";
+        char* fileSto = malloc(strlen(opt.file1) + 5 + 1);
+        strcpy(fileSto, opt.file1);
+        strcpy(fileSto + len1 - 4, strX);
+        fileSto[len1]='R';
+        bmp_save(fileSto, bmpDiffR);
+        fileSto[len1]='G';
+        bmp_save(fileSto, bmpDiffG);
+        fileSto[len1]='B';
+        bmp_save(fileSto, bmpDiffB);
+        fileSto[len1]='A';
+        if (c1 == 32) {
+            bmp_save(fileSto,bmpDiffA);
+        }
+
+        // (8.1) borrar las imagenes
+        bmp_delete(bmp1);
+        bmp_delete(bmp2);
+        bmp_delete(bmpDiffR);
+        bmp_delete(bmpDiffG);
+        bmp_delete(bmpDiffB);
+        if (c1 == 32) {
+            bmp_delete(bmpDiffA);
+        }
+    }
+
+    // (9) retorno error si encontre una diferencia
+    for (i = opt.epsilon; i < 256; i++) {
+        if (opt.summary[i] > 0) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+uint8_t cmp(uint8_t a, uint8_t b, int c, int r, char* channel, options* opt) {
+    int diff = (int)abs(((int)a)-((int)b));
+    opt->summary[diff]++;
+    if (opt->verbose && diff > opt->epsilon) {
+        printf("%i\t%i\t%s\t=\t%i\n", r, c, channel, diff);
+    }
+    if (opt->value) {
+        return (uint8_t)((256-diff) & 0xff);
+    }
+    if (diff > opt->epsilon) {
+        return 255;
+    }
+    return 0;
+}
+
+void print_help(char* name) {
+    printf ( "Uso: %s <opciones> <archivo_1> <archivo_2> <epsilon>\n", name );
+    printf ( "Ejemplo de uso:\n" );
+    printf ( "    %s lena_a.bmp lena_b.bmp 5\n", name );
+    printf ( "\n" );
+    printf ( "    Verifica pixel a pixel que la diferencia entre lena_a.bmp y  \n" );
+    printf ( "    lena_b.bmp no supere el valor 5. Genera una imágen por canal \n" );
+    printf ( "    a partir de las diferencias. Coloca un pixel blanco donde    \n" );
+    printf ( "    haya diferencias y uno negro donde no. Si se usa -a entonces \n" );
+    printf ( "    indica en gris el valor de la diferencia, donde negro es sin \n" );
+    printf ( "    diferencias y blanco es diferencia en 1.\n" );
+    printf ( "\n" );
+    printf ( "    -h, --help       Imprime esta ayuda\n" );
+    printf ( "    -a, --value      Valor de la diferencia en la imagen\n" );
+    printf ( "    -v, --verbose    Ejecuta en verbose mostrando las diferencias\n" );
+    printf ( "    -s, --summary    Muestra un resumen de diferencias\n" );
+    printf ( "    -i, --image      Genera Imagenes de diferencias\n" );
+}
+
+int read_options(int argc, char* argv[], options* opt) {
+    opt->program_name = argv[0];
+    opt->verbose = 0;
+    opt->value = 0;
+    opt->help = 0;
+    opt->file1 = 0;
+    opt->file2 = 0;
+    opt->image = 0;
+    opt->summaryop = 0;
+    int i, optionals = 0;
+    for (i=1; i < argc; i++) {
+        if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
+            opt->help = 1;
+            optionals++;
+        }
+        if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")) {
+            opt->verbose = 1;
+            optionals++;
+        }
+        if (!strcmp(argv[i], "-a") || !strcmp(argv[i], "--value")) {
+            opt->value = 1;
+            optionals++;
+        }
+        if (!strcmp(argv[i], "-i") || !strcmp(argv[i], "--image")) {
+            opt->image = 1;
+            optionals++;
+        }
+        if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--summary")) {
+            opt->summaryop = 1;
+            optionals++;
+        }
+    }
+    if (argc - 1 - optionals != 3) {
+        return 1;
+    }
+    opt->epsilon = atoi(argv[argc-1]);
+    opt->file1 = argv[argc-2];
+    opt->file2 = argv[argc-3];
+    return 0;
+}

+ 70 - 0
helper/imagenes.c

@@ -0,0 +1,70 @@
+
+#include <stdio.h>
+
+#include "../tp2.h"
+#include "imagenes.h"
+#include "libbmp.h"
+
+BMP *src_img, *src_img2, *dst_img;
+
+void setear_buffer(buffer_info_t *buffer, BMP *bmp)
+{
+	buffer->bytes              = bmp_data(bmp);
+	buffer->width              = bmp_width(bmp);
+	buffer->height             = bmp_height(bmp);
+	buffer->width_with_padding = bmp_bytes_per_row(bmp);
+}
+
+void imagenes_abrir(configuracion_t *config)
+{
+	// Cargo la imagen
+	if ( (src_img = bmp_read (config->archivo_entrada)) == 0 ) {
+    	fprintf(stderr, "Error abriendo la imagen fuente\n");
+		exit(EXIT_FAILURE);
+	}
+	if (bmp_compression(src_img) != BI_RGB) {
+		fprintf(stderr, "Error: La imagen fuente esta comprimida\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (bmp_bit_count(src_img) == 24) {
+    	bmp_convert_24_to_32_bpp(src_img);
+	}
+
+	dst_img = bmp_copy( src_img, 1 );
+
+	if (config->archivo_entrada_2 != NULL) {
+		if ( (src_img2 = bmp_read (config->archivo_entrada_2)) == 0 ) {
+	    	fprintf(stderr, "Error abriendo la imagen fuente 2\n");
+			exit(EXIT_FAILURE);
+		}
+		if (bmp_compression(src_img2) != BI_RGB) {
+			fprintf(stderr, "Error: La imagen fuente 2 esta comprimida\n");
+			exit(EXIT_FAILURE);
+		}
+
+		if (bmp_bit_count(src_img2) == 24) {
+	    	bmp_convert_24_to_32_bpp(src_img2);
+		}
+		setear_buffer(&config->src_2, src_img2);
+	} else {
+		src_img2 = NULL;
+	}
+
+	setear_buffer(&config->src, src_img);
+	setear_buffer(&config->dst, dst_img);
+}
+
+void imagenes_guardar(configuracion_t *config)
+{
+	bmp_save(config->archivo_salida, dst_img);
+}
+
+void imagenes_liberar()
+{
+    bmp_delete(src_img);
+	if (src_img2 != NULL) {
+		bmp_delete(src_img2);
+	}
+    bmp_delete(dst_img);
+}

+ 9 - 0
helper/imagenes.h

@@ -0,0 +1,9 @@
+#ifndef __IMAGENES__H__
+#define __IMAGENES__H__
+
+void imagenes_abrir(configuracion_t *config);
+void imagenes_guardar(configuracion_t *config);
+void imagenes_liberar();
+
+
+#endif /* !__IMAGENES__H__ */

+ 276 - 0
helper/libbmp.c

@@ -0,0 +1,276 @@
+/* ************************************************************************* */
+/* Organizacion del Computador II                                            */
+/*                                                                           */
+/*             Biblioteca de funciones para operar imagenes BMP              */
+/*                                                                           */
+/*   Esta biblioteca permite crear, abrir, modificar y guardar archivos en   */
+/*   formato bmp de forma sencilla. Soporta solamente archivos con header de */
+/*   versiones info_header (40 bytes) y info_v5_header (124 bytes). Para la  */
+/*   primera imagenes de 24 bits (BGR) y la segunda imagenes de 32 (ABGR).   */
+/*                                                                           */
+/*   bmp.h : headers de la biblioteca                                        */
+/*   bmp.c : codigo fuente de la biblioteca                                  */
+/*   example.c : ejemplos de uso de la biblioteca                            */
+/*               $ gcc example.c bmp.c -o example                            */
+/* ************************************************************************* */
+
+#include "libbmp.h"
+
+/* ************************************************************************* */
+BMPIH* get_BMPIH(uint32_t width, uint32_t height) {
+  if(width%4!=0) return 0; // TODO: dont support padding
+  BMPIH* new_bmp_info_ih = (BMPIH*)malloc(sizeof(BMPIH));
+  new_bmp_info_ih->biSize   = sizeof(BMPIH);
+  new_bmp_info_ih->biWidth  = width;
+  new_bmp_info_ih->biHeight = height;
+  new_bmp_info_ih->biPlanes = 1;
+  new_bmp_info_ih->biBitCount = 24; //TODO: dont support other bitcount
+  new_bmp_info_ih->biCompression = BI_RGB;
+  new_bmp_info_ih->biSizeImage = width*height*(new_bmp_info_ih->biBitCount/8);
+  new_bmp_info_ih->biXPelsPerMeter = 2952; // 75 dpi
+  new_bmp_info_ih->biYPelsPerMeter = 2952; // 75 dpi
+  new_bmp_info_ih->biClrUsed = 0;
+  new_bmp_info_ih->biClrImportant = 0;
+  return new_bmp_info_ih;
+}
+
+/* ************************************************************************* */
+BMPV5H* get_BMPV5H(uint32_t width, uint32_t height) {
+  if(width%4!=0) return 0; // TODO: dont support padding
+  BMPV5H* new_bmp_info_v5h = (BMPV5H*)malloc(sizeof(BMPV5H));
+  new_bmp_info_v5h->bV5Size   = sizeof(BMPV5H);
+  new_bmp_info_v5h->bV5Width  = width;
+  new_bmp_info_v5h->bV5Height = height;
+  new_bmp_info_v5h->bV5Planes = 1;
+  new_bmp_info_v5h->bV5BitCount = 32; //TODO: dont support other bitcount
+  new_bmp_info_v5h->bV5Compression = BI_BITFIELDS;
+  new_bmp_info_v5h->bV5SizeImage = width*height*(new_bmp_info_v5h->bV5BitCount/8);
+  new_bmp_info_v5h->bV5XPelsPerMeter = 2952; // 75 dpi
+  new_bmp_info_v5h->bV5YPelsPerMeter = 2952; // 75 dpi
+  new_bmp_info_v5h->bV5ClrUsed      = 0;
+  new_bmp_info_v5h->bV5ClrImportant = 0;
+  new_bmp_info_v5h->bV5RedMask   = 0xff000000;
+  new_bmp_info_v5h->bV5GreenMask = 0x00ff0000;
+  new_bmp_info_v5h->bV5BlueMask  = 0x0000ff00;
+  new_bmp_info_v5h->bV5AlphaMask = 0x000000ff;
+  new_bmp_info_v5h->bV5CSType = LCS_sRGB;
+  CIEXYZTRIPLE bV5Endpoints_ = {{0,0,0},{0,0,0},{0,0,0}};
+  new_bmp_info_v5h->bV5Endpoints = bV5Endpoints_;
+  new_bmp_info_v5h->bV5GammaRed   = 0;
+  new_bmp_info_v5h->bV5GammaGreen = 0;
+  new_bmp_info_v5h->bV5GammaBlue  = 0;
+  new_bmp_info_v5h->bV5Intent = LCS_GM_GRAPHICS;
+  new_bmp_info_v5h->bV5ProfileData = 0;
+  new_bmp_info_v5h->bV5ProfileSize = 0;
+  new_bmp_info_v5h->bV5Reserved = 0;
+  return new_bmp_info_v5h;
+}
+
+/* ************************************************************************* */
+BMP* bmp_create(void* info_header, int init_data) {
+  unsigned int i;
+  BMPIH* ih = (BMPIH*)info_header;
+
+  // (1) creo la data area
+  unsigned int data_size = ih->biSizeImage;
+  uint8_t* new_bmp_data = (uint8_t*)malloc(data_size);
+  if(init_data)
+    for(i=0;i<data_size;i++)
+      new_bmp_data[i] = 0;
+
+  // (2) creo un nuevo fh
+  BMPFH* new_bmp_fh = (BMPFH*) malloc(sizeof(BMPFH));
+  new_bmp_fh->bfType[0] = 'B';
+  new_bmp_fh->bfType[1] = 'M';
+  new_bmp_fh->bfOffBits = ih->biSize + sizeof(BMPFH);
+  new_bmp_fh->bfSize = data_size + new_bmp_fh->bfOffBits;
+  new_bmp_fh->bfReserved1 = 0;
+  new_bmp_fh->bfReserved2 = 0;
+
+  // (3) store information on a BMP struct
+  BMP* bmp = (BMP*)malloc(sizeof(BMP));
+  bmp->fh = new_bmp_fh;
+  bmp->ih = info_header;
+  bmp->data = new_bmp_data;
+
+  return bmp;
+}
+
+/* ************************************************************************* */
+BMP* bmp_copy(BMP* img, int copy_data) {
+  unsigned int i;
+
+  // (1) copy the fh
+  BMPFH* new_bmp_fh = (BMPFH*) malloc(sizeof(BMPFH));
+  (*new_bmp_fh) = (*(img->fh));
+
+  // (2) copy the ih/v5h
+  int info_header_size = new_bmp_fh->bfOffBits - sizeof(BMPFH);
+  char* new_bmp_info = 0;
+  if( info_header_size == sizeof(BMPIH) ) {
+    BMPIH* new_bmp_info_ih = (BMPIH*)malloc(sizeof(BMPIH));
+    (*new_bmp_info_ih) = *(BMPIH*)(img->ih);
+    new_bmp_info = (char*)new_bmp_info_ih;
+  } else
+  if( info_header_size == sizeof(BMPV5H) ) {
+    BMPV5H* new_bmp_info_v5h = (BMPV5H*)malloc(sizeof(BMPV5H));
+    (*new_bmp_info_v5h) = *(BMPV5H*)(img->ih);
+    new_bmp_info = (char*)new_bmp_info_v5h;
+  }
+
+  // (3) data area
+  unsigned int data_size = ((BMPIH*)(new_bmp_info))->biSizeImage;
+  uint8_t* new_bmp_data = (uint8_t*)malloc(data_size);
+  if( copy_data )
+    for(i=0;i<data_size;i++)
+      new_bmp_data[i] = img->data[i];
+
+  // (4) store information on a BMP struct
+  BMP* bmp = (BMP*)malloc(sizeof(BMP));
+  bmp->fh = new_bmp_fh;
+  bmp->ih = new_bmp_info;
+  bmp->data = new_bmp_data;
+
+  return bmp;
+}
+
+/* ************************************************************************* */
+BMP* bmp_read(char* src) {
+
+  // (0) open file
+  FILE* fsrc = fopen(src,"r");
+  if (fsrc == 0) {
+      fprintf(stderr, "Error al abrir el archivo.\n");
+      return 0;
+  } // Error al abrir el archivo
+
+  // (1) read bitmap file header
+  BMPFH* bmp_fh = (BMPFH*) malloc(sizeof(BMPFH));
+  if(!fread(bmp_fh, sizeof(BMPFH), 1, fsrc)){
+      fprintf(stderr, "Error al leer el archivo.\n");
+      return 0;
+  } // Error al leer el archivo
+
+  // (2) read bitmap info header (TODO: only support BMPV5H(130B) and BMPIH(40B))
+  int info_header_size = bmp_fh->bfOffBits - sizeof(BMPFH);
+  char* bmp_info = 0;
+  if( info_header_size == sizeof(BMPIH) ) {
+    bmp_info = malloc(sizeof(BMPIH));
+  } else
+  if( info_header_size == sizeof(BMPV5H) ) {
+    bmp_info = malloc(sizeof(BMPV5H));
+  } else
+  if( info_header_size == sizeof(BMPV3IH) ) {
+    bmp_info = malloc(sizeof(BMPV3IH));
+  }
+  if(!bmp_info){
+      fprintf(stderr, "Formato de archivo no soportado.\n");
+      return 0;
+  } // Error formato no soportado
+  if(!fread(bmp_info, info_header_size, 1, fsrc)){ return 0; } // Error al leer el archivo
+
+  // (3) read bitmap data pixels
+  int image_data_size = bmp_fh->bfSize - info_header_size - sizeof(BMPFH);
+  uint8_t* bmp_data = (uint8_t*) malloc(image_data_size);
+  if(!fread(bmp_data, image_data_size, 1, fsrc)){ return 0; } // Error al leer el archivo
+
+  // (4) store information on a BMP struct
+  BMP* bmp = (BMP*)malloc(sizeof(BMP));
+  bmp->fh = bmp_fh;
+  bmp->ih = bmp_info;
+  bmp->data = bmp_data;
+
+  fclose(fsrc);
+
+  return bmp;
+}
+
+/* ************************************************************************* */
+int bmp_save(char* dst, BMP* img) {
+  int r=0,b;
+
+  // (0) open file
+  FILE* fdst = fopen (dst,"w+");
+  if(fdst == 0){ return 0; } // Error al abrir el archivo
+
+  // (1) write bitmap file header
+  b=fwrite(img->fh, sizeof(BMPFH), 1, fdst); r=b;
+  if(!b){ return 0; } // Error al escribir el archivo
+
+  // (2) write bitmap info header
+  b=fwrite(img->ih, img->fh->bfOffBits-sizeof(BMPFH), 1, fdst); r=r+b;
+  if(!b){ return 0; } // Error al escribir el archivo
+
+  // (3) write bitmap data
+  b=fwrite(img->data, img->fh->bfSize-img->fh->bfOffBits, 1, fdst); r=r+b;
+  if(!b){ return 0; } // Error al escribir el archivo
+
+  fclose(fdst);
+
+  return r;
+}
+
+/* ************************************************************************* */
+void bmp_delete(BMP* img) {
+  free(img->fh);
+  free(img->ih);
+  free(img->data);
+  free(img);
+}
+
+/* ************************************************************************* */
+uint32_t bmp_width(BMP* img) {
+  return (((BMPIH*)(img->ih))->biWidth);
+}
+
+/* ************************************************************************* */
+uint32_t bmp_height(BMP* img) {
+  return (((BMPIH*)(img->ih))->biHeight);
+}
+
+/* ************************************************************************* */
+uint8_t* bmp_data(BMP* img) {
+  return img->data;
+}
+/* ************************************************************************* */
+uint16_t bmp_bit_count(BMP* img) {
+  return (((BMPIH*)(img->ih))->biBitCount);
+}
+
+/* ************************************************************************* */
+uint32_t bmp_compression(BMP* img) {
+  return (((BMPIH*)(img->ih))->biCompression);
+}
+
+void bmp_set_bit_count(BMP* img, uint16_t new_bit_count) {
+  (((BMPIH*)(img->ih))->biBitCount = new_bit_count);
+}
+
+/* ************************************************************************* */
+uint32_t bmp_bytes_per_row(BMP* img)
+{
+	return ((bmp_width(img) * bmp_bit_count(img) + 31) >> 5) << 2;
+}
+
+
+/* ************************************************************************* */
+void bmp_convert_24_to_32_bpp (BMP *img)
+{
+	unsigned int * data32 = (unsigned int *)malloc(32 * bmp_height(img) * bmp_width(img));
+    unsigned char * data24 = (unsigned char *)img->data;
+    unsigned int i = 0;
+    unsigned int val;
+    for (i = 0; i < bmp_height(img) * bmp_width(img); i++) {
+        val = 0xFF;
+        val = (val << 8) + data24[3 * i + 2];
+        val = (val << 8) + data24[3 * i + 1];
+        val = (val << 8) + data24[3 * i];
+        data32[i] = val;
+    }
+    free(data24);
+    bmp_set_bit_count(img, 32);
+    img->data = (uint8_t*) data32;
+    ((BMPIH*)(img->ih))->biSizeImage = bmp_height(img) * bmp_width(img) * 4;
+    uint32_t file_size = ((BMPIH*)(img->ih))->biSizeImage + ((BMPIH*)(img->ih))->biSize + sizeof(BMPFH);
+    ((BMPFH*)(img->fh))->bfSize = file_size;
+}

+ 188 - 0
helper/libbmp.h

@@ -0,0 +1,188 @@
+/* ************************************************************************* */
+/* Organizacion del Computador II                                            */
+/*                                                                           */
+/*             Biblioteca de funciones para operar imagenes BMP              */
+/*                                                                           */
+/*   Esta biblioteca permite crear, abrir, modificar y guardar archivos en   */
+/*   formato bmp de forma sencilla. Soporta solamente archivos con header de */
+/*   versiones info_header (40 bytes) y info_v5_header (124 bytes). Para la  */
+/*   primera imagenes de 24 bits (BGR) y la segunda imagenes de 32 (ABGR).   */
+/*                                                                           */
+/*   bmp.h : headers de la biblioteca                                        */
+/*   bmp.c : codigo fuente de la biblioteca                                  */
+/*   example.c : ejemplos de uso de la biblioteca                            */
+/*               $ gcc example.c bmp.c -o example                            */
+/* ************************************************************************* */
+
+#ifndef __BMP__H__
+#define __BMP__H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#define size_BITMAPCOREHEADER   12
+#define size_OS21XBITMAPHEADER  12
+#define size_OS22XBITMAPHEADER  64
+#define size_BITMAPINFOHEADER   40 // supported
+#define size_BITMAPV2INFOHEADER 52
+#define size_BITMAPV3INFOHEADER 56
+#define size_BITMAPV4HEADER     108
+#define size_BITMAPV5HEADER     124 // supported
+
+typedef enum e_BITMAPTYPE {
+BITMAPINFOHEADER,
+BITMAPV3INFOHEADER,
+BITMAPV5HEADER
+} BITMAPTYPE;
+
+typedef enum {
+  LCS_GM_ABS_COLORIMETRIC = 0x00000008,
+  LCS_GM_BUSINESS = 0x00000001,
+  LCS_GM_GRAPHICS = 0x00000002,
+  LCS_GM_IMAGES = 0x00000004
+} BMPGamutMappingIntent;
+
+typedef  enum {
+  LCS_CALIBRATED_RGB = 0x00000000,
+  LCS_sRGB = 0x73524742,
+  LCS_WINDOWS_COLOR_SPACE = 0x57696E20
+} BMPLogicalColorSpace;
+
+typedef  enum {
+  BI_RGB = 0x0000,
+  BI_RLE8 = 0x0001,
+  BI_RLE4 = 0x0002,
+  BI_BITFIELDS = 0x0003,
+  BI_JPEG = 0x0004,
+  BI_PNG = 0x0005,
+  BI_CMYK = 0x000B,
+  BI_CMYKRLE8 = 0x000C,
+  BI_CMYKRLE4 = 0x000D
+} BMPCompression;
+
+typedef struct __attribute__((packed)) s_CIEXYZ {
+  uint32_t ciexyzX; // FXPT2DOT30
+  uint32_t ciexyzY; // FXPT2DOT30
+  uint32_t ciexyzZ; // FXPT2DOT30
+} CIEXYZ,*LPCIEXYZ;
+
+typedef struct __attribute__((packed)) s_CIEXYZTRIPLE {
+  CIEXYZ ciexyzRed;
+  CIEXYZ ciexyzGreen;
+  CIEXYZ ciexyzBlue;
+} CIEXYZTRIPLE,*LPCIEXYZTRIPLE;
+
+typedef struct __attribute__((packed)) s_BITMAPFILEHEADER {
+  char  bfType[2];
+  uint32_t  bfSize;
+  uint16_t  bfReserved1;
+  uint16_t  bfReserved2;
+  uint32_t bfOffBits;
+} BMPFH;
+
+typedef struct __attribute__((packed)) s_BITMAPINFOHEADER {
+  uint32_t biSize;
+  uint32_t biWidth;
+  uint32_t biHeight;
+  uint16_t biPlanes;
+  uint16_t biBitCount;
+  uint32_t biCompression;
+  uint32_t biSizeImage;
+  uint32_t biXPelsPerMeter;
+  uint32_t biYPelsPerMeter;
+  uint32_t biClrUsed;
+  uint32_t biClrImportant;
+} BMPIH;
+
+typedef struct __attribute__((packed)) s_BITMAPV3INFOHEADER {
+  uint32_t bv3iSize;
+  uint32_t bv3iWidth;
+  uint32_t bv3iHeight;
+  uint16_t bv3iPlanes;
+  uint16_t bv3iBitCount;
+  uint32_t bv3iCompression;
+  uint32_t bv3iSizeImage;
+  uint32_t bv3iXPelsPerMeter;
+  uint32_t bv3iYPelsPerMeter;
+  uint32_t bv3iClrUsed;
+  uint32_t bv3iClrImportant;
+  uint32_t bv3iRedMask;
+  uint32_t bv3iGreenMask;
+  uint32_t bv3iBlueMask;
+  uint32_t bv3iAlphaMask;
+} BMPV3IH;
+
+typedef struct __attribute__((packed)) s_BITMAPV5HEADER{
+  uint32_t bV5Size;
+  uint32_t bV5Width;
+  uint32_t bV5Height;
+  uint16_t bV5Planes;
+  uint16_t bV5BitCount;
+  uint32_t bV5Compression;
+  uint32_t bV5SizeImage;
+  uint32_t bV5XPelsPerMeter;
+  uint32_t bV5YPelsPerMeter;
+  uint32_t bV5ClrUsed;
+  uint32_t bV5ClrImportant;
+  uint32_t bV5RedMask;
+  uint32_t bV5GreenMask;
+  uint32_t bV5BlueMask;
+  uint32_t bV5AlphaMask;
+  uint32_t bV5CSType;
+  CIEXYZTRIPLE bV5Endpoints;
+  uint32_t bV5GammaRed;
+  uint32_t bV5GammaGreen;
+  uint32_t bV5GammaBlue;
+  uint32_t bV5Intent;
+  uint32_t bV5ProfileData;
+  uint32_t bV5ProfileSize;
+  uint32_t bV5Reserved;
+} BMPV5H;
+
+typedef struct s_BMP { BMPFH* fh; void* ih; uint8_t* data; } BMP;
+
+/** get_BMPIH: crea un info header con parametros default**/
+BMPIH* get_BMPIH(uint32_t width, uint32_t height);
+
+/** get_BMPV5H: crea un info header v5 con parametros default **/
+BMPV5H* get_BMPV5H(uint32_t width, uint32_t height);
+
+/** bmp_create: Crea un bmp usando un headers info (40B or 124B), init_data en 1 incializa data **/
+BMP* bmp_create(void* info_header, int init_data);
+
+/** bmp_copy: Copia un bmp, copia data si copy_data es 1 **/
+BMP* bmp_copy(BMP* img, int copy_data);
+
+/** bmp_read: Lee un bmp **/
+BMP* bmp_read(char* src);
+
+/** bmp_save: Guarda un bmp **/
+int bmp_save(char* dst, BMP* img);
+
+/** bmp_delete: Borra un bmp **/
+void bmp_delete(BMP* img);
+
+/** bmp_width: obtiene el ancho de un bmp **/
+uint32_t bmp_width(BMP* img);
+
+/** bmp_height: obtiene el alto de un bmp **/
+uint32_t bmp_height(BMP* img);
+
+/** bmp_bytes_per_row: obtiene el ancho en bytes de cada linea del bmp **/
+uint32_t bmp_bytes_per_row(BMP* img);
+
+/** bmp_bitcount: obtiene el bitcount de un bmp **/
+uint16_t bmp_bit_count(BMP* img);
+
+/** bmp_compression: obtiene el codigo de compresion **/
+uint32_t bmp_compression(BMP* img);
+
+/** bmp_data: obtiene la data de un bmp **/
+uint8_t* bmp_data(BMP* img);
+
+/** bmp_convert_24_to_32_bpp: convierte la data del bmp de 24 a 32 bits **/
+void bmp_convert_24_to_32_bpp(BMP *img);
+
+#endif /* __BMP__H__ */

+ 41 - 0
helper/tiempo.h

@@ -0,0 +1,41 @@
+#ifndef __TIEMPO_H__
+#define __TIEMPO_H__
+
+// uso: 
+// unsigned long start, end;
+// MEDIR_TIEMPO_START(start);
+// ... codigo ...
+// MEDIR_TIEMPO_STOP(end);
+// unsigned long delta = end - start;
+
+#define MEDIR_TIEMPO(var)                                   \
+{                                                           \
+    __asm__ __volatile__ (                                  \
+        "xor %%rdx, %%rdx\n\t"                              \
+        "xor %%rax, %%rax\n\t"                              \
+        "lfence\n\t"                                        \
+        "rdtsc\n\t"                                         \
+        "sal $32, %%rdx\n\t"                                \
+        "or %%rdx, %%rax\n\t"                               \
+        "movq %%rax, %0\n\t"                                \
+        : "=r" (var)                                        \
+        : /* no input */                                    \
+        : "%rax", "%rdx"                                    \
+    );                                                      \
+}
+
+
+#define MEDIR_TIEMPO_START(start)                           \
+{                                                           \
+    /* warm up ... */                                       \
+    MEDIR_TIEMPO(start);                                    \
+    MEDIR_TIEMPO(start);                                    \
+    MEDIR_TIEMPO(start);                                    \
+}
+
+#define MEDIR_TIEMPO_STOP(end)                              \
+{                                                           \
+    MEDIR_TIEMPO(end);                                      \
+}
+
+#endif /* !__TIEMPO_H__ */

+ 28 - 0
helper/utils.h

@@ -0,0 +1,28 @@
+#ifndef __UTILS__H__
+#define __UTILS__H__
+
+void copiar_bordes (
+	unsigned char *src,
+	unsigned char *dst,
+	int m,
+	int n,
+	int row_size
+);
+
+void voltear_horizontal (
+	unsigned char *src,
+	unsigned char *dst,
+	int m,
+	int n,
+	int row_size
+);
+
+void pintar_bordes_negro(unsigned char *frame, int m, int n);
+
+void guardar_mensaje_en_archivo(configuracion_t *config, unsigned char *mensaje_salida);
+
+const char *basename(const char *path);
+
+
+#endif /* !__UTILS__H__ */
+


+ 95 - 0
tp2.c

@@ -0,0 +1,95 @@
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "tp2.h"
+#include "helper/tiempo.h"
+#include "helper/libbmp.h"
+#include "helper/utils.h"
+#include "helper/imagenes.h"
+
+#define N_ENTRADAS_diff 2
+#define N_ENTRADAS_blur 1
+
+DECLARAR_FILTRO(diff)
+DECLARAR_FILTRO(blur)
+
+filtro_t filtros[] = {
+	DEFINIR_FILTRO(diff) ,
+	DEFINIR_FILTRO(blur) ,
+	{0,0,0,0,0}
+};
+
+int main( int argc, char** argv ) {
+
+	configuracion_t config;
+
+	procesar_opciones(argc, argv, &config);
+	// Imprimo info
+	if (!config.nombre)
+	{
+		printf ( "Procesando...\n");
+		printf ( "  Filtro             : %s\n", config.nombre_filtro);
+		printf ( "  Implementación     : %s\n", C_ASM( (&config) ) );
+		printf ( "  Archivo de entrada : %s\n", config.archivo_entrada);
+	}
+
+	filtro_t *filtro = detectar_filtro(&config);
+
+	if (filtro != NULL) {
+		filtro->leer_params(&config, argc, argv);
+		correr_filtro_imagen(&config, filtro->aplicador);
+	}
+
+	return 0;
+}
+
+filtro_t* detectar_filtro(configuracion_t *config)
+{
+	for (int i = 0; filtros[i].nombre != 0; i++)
+	{
+		if (strcmp(config->nombre_filtro, filtros[i].nombre) == 0)
+			return &filtros[i];
+	}
+
+	fprintf(stderr, "Filtro desconocido\n");
+	return NULL; // avoid C warning
+}
+
+
+void imprimir_tiempos_ejecucion(unsigned long long int start, unsigned long long int end, int cant_iteraciones) {
+	unsigned long long int cant_ciclos = end-start;
+
+	printf("Tiempo de ejecución:\n");
+	printf("  Comienzo                          : %llu\n", start);
+	printf("  Fin                               : %llu\n", end);
+	printf("  # iteraciones                     : %d\n", cant_iteraciones);
+	printf("  # de ciclos insumidos totales     : %llu\n", cant_ciclos);
+	printf("  # de ciclos insumidos por llamada : %.3f\n", (float)cant_ciclos/(float)cant_iteraciones);
+}
+
+void correr_filtro_imagen(configuracion_t *config, aplicador_fn_t aplicador)
+{
+	snprintf(config->archivo_salida, sizeof  (config->archivo_salida), "%s/%s.%s.%s%s.bmp",
+             config->carpeta_salida, basename(config->archivo_entrada),
+             config->nombre_filtro,  C_ASM(config), config->extra_archivo_salida );
+
+	if (config->nombre)
+	{
+		printf("%s\n", basename(config->archivo_salida));
+	}
+	else
+	{
+		imagenes_abrir(config);
+		unsigned long long start, end;
+		MEDIR_TIEMPO_START(start)
+		for (int i = 0; i < config->cant_iteraciones; i++) {
+				aplicador(config);
+		}
+		MEDIR_TIEMPO_STOP(end)
+		imagenes_guardar(config);
+		imagenes_liberar(config);
+		imprimir_tiempos_ejecucion(start, end, config->cant_iteraciones);
+	}
+}

+ 97 - 0
tp2.h

@@ -0,0 +1,97 @@
+
+#ifndef __TP2__H__
+#define __TP2__H__
+
+#include <stdbool.h>
+
+#define FILTRO_C   0
+#define FILTRO_ASM 1
+
+typedef struct bgra_t {
+	unsigned char b, g, r, a;
+} __attribute__((packed)) bgra_t;
+
+typedef struct bgra16_t {
+	unsigned short b, g, r, a;
+} __attribute__((packed)) bgra16_t;
+
+typedef struct bgra32_t {
+	unsigned int b, g, r, a;
+} __attribute__((packed)) bgra32_t;
+
+
+
+typedef struct bgr_t {
+	unsigned char b, g, r;
+} __attribute__((packed)) bgr_t;
+
+typedef struct bgr16_t {
+	unsigned short b, g, r;
+} __attribute__((packed)) bgr16_t;
+
+typedef struct bgr32_t {
+	unsigned int b, g, r;
+} __attribute__((packed)) bgr32_t;
+
+
+typedef struct buffer_info_t
+{
+	int width, height, width_with_padding;
+	unsigned char *bytes;
+	unsigned int tipo;
+} buffer_info_t;
+
+
+typedef struct configuracion_t
+{
+	char *nombre_filtro;
+	int  tipo_filtro;
+	buffer_info_t src, src_2, dst;
+	void *extra_config;
+
+	char *archivo_entrada;
+	char *archivo_entrada_2;
+	char  archivo_salida[255];
+	char *carpeta_salida;
+	char *extra_archivo_salida;
+	bool es_video;
+	bool verbose;
+	bool frames;
+	bool nombre;
+	int cant_iteraciones;
+} configuracion_t;
+
+#define SWITCH_C_ASM(config,c_ver,asm_ver) ( config->tipo_filtro == FILTRO_C ? c_ver : asm_ver )
+#define C_ASM(config) ( SWITCH_C_ASM(config, "C", "ASM") )
+
+typedef void (lector_params_fn_t) (configuracion_t *config, int, char *[]);
+typedef void (aplicador_fn_t) (configuracion_t*);
+typedef void (mostrador_ayuda_fn_t) (void);
+
+typedef struct filtro_t {
+	char *nombre;
+	lector_params_fn_t   *leer_params;
+	mostrador_ayuda_fn_t *ayuda;
+	aplicador_fn_t       *aplicador;
+	int					 n_entradas;
+} filtro_t;
+
+#define DECLARAR_FILTRO(nombre) lector_params_fn_t leer_params_##nombre; \
+                                mostrador_ayuda_fn_t ayuda_##nombre; \
+                                aplicador_fn_t aplicar_##nombre; \
+								int  n_entradas_##nombre;
+
+#define DEFINIR_FILTRO(nombre) {#nombre, leer_params_##nombre, ayuda_##nombre, aplicar_##nombre, N_ENTRADAS_##nombre}
+
+// ~~~ declaraciones de tp2
+extern filtro_t filtros[];
+filtro_t* detectar_filtro(configuracion_t *config);
+void      correr_filtro_imagen(configuracion_t *config, aplicador_fn_t aplicador);
+void      imprimir_tiempos_ejecucion(unsigned long long int start, unsigned long long int end, int cant_iteraciones);
+
+// ~~~ declaraciones de cli.h ~~~
+void      procesar_opciones(int argc, char **argv, configuracion_t *config);
+void      imprimir_ayuda ( char *nombre_programa);
+
+
+#endif   /* !__TP2__H__ */