Buenas, esta mañana he programado un pequeño programa que sirve para comprovar cuanto tarda la librería jpeg en cargar las imágenes jpeg contenidas en un directorio (analizándolo recursivamente). Hace tiempo que no programaba nada, y la verdad es que me ha sentado bién, lo colgaré por si a alguien le interesa. Se puede aprender algo del código.. aunque poco:

  • Como recorrer una estructura de directorios en entornos UNIX-like (por ejemplo GNU/Linux) y distinguir las entradas de éste (para saber si son ficheros normales, directorios, enlaces...)
  • Como cargar en memoria imágenes jpeg con las librerías libjpeg, que por lo general están muy mal documentadas en internet.

Empezemos: para comenzar, deberemos instalar en nuestro sistema las librerías libjpeg (así como los archivos de cabecera para poder incluírlos en nuestro código fuente, en sistemas debian el paquete es algo así como libjpeg-dev, en Ubuntu Hardy el paquete se llama libjpeg62-dev).

Nota 1: en el código fuente no he incluído comprovación alguna para que se distingan las imágenes jpeg de las imágenes que no lo son, se debería hacer alguna comprovación sobre el nombre, por ejemplo. No lo he hecho porque no me hacía falta (sí, he hecho el programa para algo útil, aunque no lo parezca, era algo así como un benchmark)

Nota 2: no he incluído ninguna comprovación en el código para que trate los archivos que enlazan a otros, no me hacía falta de la misma forma que antes, en todo caso, si buscáis en google el nombre de las funciones que he utilizado para hacer la distinción de ficheros y directorios os aparecerá el nombre de la función que indica si estamos tratando con enlaces. Por otro lado, si imprimimos por pantalla en modo octal el entero que pasamos como argumento a esa función, veremos que corresponde a los permisos del fichero, y nosotros mismos podríamos programar una función que nos indicara que tipo de entrada estamos tratando.

Nota 3: xD, no, no hay nota n . Bueno, ahora en serio, para compilar el código se tiene que pasar el argumento -ljpeg al gcc (bueno, he presupuesto que utilizamos gcc, los que lo quieran hacer con otro compilador se tendrán que espavilar, si es que a alguien le interesa hacer esto, jejeje).

Finalmente os muestro el código :) (puede que en los días siguientes pula un poco el código y los comentarios, que son un poco chapucheros) :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <sys /types.h> //
#include </sys><sys /stat.h>  // estructura stat
#include <unistd .h>    // mkdir, chdir
#include <dirent .h>    // dirent
 
#include <stdio .h>     // para fopen
#include <stdlib .h>    // para malloc
#include <string .h>    // strcmp
#include <time .h>      // clock
 
#include <setjmp .h>    //libjpeg
#include <jpeglib .h>   //libjpeg
 
/* Defineixo una estructura simple per apilar directoris */
typedef struct s_stack {
    struct s_stack *next;
    DIR  *dir;
} stack;
 
int main() {
    struct  dirent  *dir_entry;
    char    names_buffer[1024];
 
    /* Estructures per manejar la imatge en memòria */
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr         jerr;
 
    /* Estructures per manejar directoris */
    struct stat                   estat;
    stack                  *dirs, *t_dirs;
 
    /* Punters per manejar la memòria de les imatges */
    unsigned char *image;
    unsigned char *ptr;
 
    /* Manejador de fitxer */
    FILE *f;
 
    /* Variable per comptar el temps emprat per carregar imatges */
    clock_t t, T;
 
    dirs = (stack *)malloc(sizeof(stack));
    if(dirs==NULL) {
        printf("Memoria insuficient!\n");
        exit(-1);
    }
    dirs->next = NULL;
 
    getcwd(names_buffer, 1024);
    dirs->dir = opendir(names_buffer);
 
    T = clock();
    while((dir_entry = readdir(dirs->dir)) != NULL || dirs->next != NULL) {
        if(dir_entry == NULL) {
 
            printf("En aquest directori no hi ha més entrades...\n");
            if(dirs->next == NULL) {
                printf("Sortint de %s...\n", dir_entry->d_name);
                exit(0);
            }
            t_dirs = dirs;
            dirs = dirs->next;
            free(t_dirs);
            chdir("..");
            continue;
        }
 
        if(strcmp(dir_entry->d_name, ".")==0 || strcmp(dir_entry->d_name, "..")==0)
            continue;
 
        if( lstat(dir_entry->d_name, &estat) < 0 ) {
            printf("Error al fer lstat sobre %s!\n", dir_entry->d_name);
            exit(-1);
        }
 
        if(S_ISDIR(estat.st_mode)) {
            printf("Entrant en %s ...\n", dir_entry->d_name);
            t_dirs = (stack *)malloc(sizeof(stack));
            if(t_dirs==NULL) {
                printf("Memoria insuficient!\n");
 
                do {
                    t_dirs = dirs;
                    dirs = dirs->next;
                    free(t_dirs);
                } while(dirs!=NULL);
 
                exit(-1);
            }
 
            t_dirs->next = dirs;
            t_dirs->dir = opendir(dir_entry->d_name);
            chdir(dir_entry->d_name);
            dirs = t_dirs;
 
            continue;
        }
        else if(S_ISREG(estat.st_mode)) {
            /* Obrim el descriptor de fitxer de la imatge */
            printf("\tObrint la imatge %s ... ", dir_entry->d_name);
 
            t = clock();
 
            f = fopen(dir_entry->d_name, "r");
            if(f==NULL) {
                printf("No s'ha pogut obrir el fitxer!\n");
                exit(1);
            }
 
            /* Carreguem la informació de la imatge */
            cinfo.err = jpeg_std_error(&jerr);
            jpeg_create_decompress(&cinfo);
            jpeg_stdio_src(&cinfo, f);
            jpeg_read_header(&cinfo, 1);
            jpeg_start_decompress(&cinfo);
 
            /* Reservem memòria per carregar la imatge */
            image = malloc(cinfo.output_width * cinfo.output_height * 3);
 
            /* Carreguem la imatge en memòria */
            ptr=image;
            while (cinfo.output_scanline < cinfo.output_height) {
                jpeg_read_scanlines(&cinfo, &ptr, 1);
                ptr += 3 * cinfo.output_width;
            }
 
            /* Deixem de manejar la imatge */
            jpeg_finish_decompress(&cinfo);
            jpeg_destroy_decompress(&cinfo);
 
            /*Alliberem memòria reservada*/
            free(image);
 
            /* Tanquem (per si un cas) el descriptor de fitxers */
            fclose(f);
 
            printf("%.16G segons\n", (clock()-t)/(double)CLOCKS_PER_SEC);
        }
    }
 
    closedir(dirs->dir);
 
    printf("---\nTemps total: %.16G segons\n", (clock()-T)/(double)CLOCKS_PER_SEC);
 
    return 0;
}