AnteriorPosterior

6.10 Ejemplo: leer información de un fichero BMP

  Curso: Fundamentos de programación en C, por Nacho Cabanes

6.10 Ejemplo: leer información de un fichero BMP

Ahora vamos a ver un ejemplo un poco más sofisticado: vamos a abrir un fichero que sea una imagen en formato BMP y a mostrar en pantalla si está comprimido o no.

Para eso necesitamos antes saber cómo se guarda la información en un fichero BMP, pero esto es algo fácil de localizar:

FICHEROS .BMP
Un fichero BMP está compuesto por las siguientes partes: una cabecera de fichero, una cabecera del bitmap, una tabla de colores y los bytes que definirán la imagen.

En concreto, los datos que forman la cabecera de fiochero y la cabecera de bitmap son los siguientes:

TIPO DE INFORMACIÓN

POSICIÓN EN EL ARCHIVO

Tipo de fichero (letras BM)

0-1

Tamaño del archivo

2-5

Reservado

6-7

Reservado

8-9

Inicio de los datos de la imagen

10-13

Tamaño de la cabecera de bitmap

14-17

Anchura (píxeles)

18-21

Altura (píxeles)

22-25

Número de planos

26-27

Tamaño de cada punto

28-29

Compresión (0=no comprimido)

30-33

Tamaño de la imagen

34-37

Resolución horizontal

38-41

Resolución vertical

42-45

Tamaño de la tabla de color

46-49

Contador de colores importantes

50-53


Con esta información nos basta para nuestro propósito: la compresión se indica en la posición 30 del fichero, ocupa 4 bytes (lo mismo que un “int” en los sistemas operativos de 32 bits), y si es un 0 querrá decir que la imagen no está comprimida.

Entonces lo podríamos comprobar así:

/*---------------------------*/
/*  Ejemplo en C nº 59:      */
/*  C059.C                   */
/*                           */
/*  Información sobre un     */ 
/*  fichero BMP (1)          */
/*                           */
/*  Curso de C,              */
/*    Nacho Cabanes          */
/*---------------------------*/
 
#include <stdio.h>
 
int main(){
 
  char nombre[60];
  FILE* fichero;
  int compresion;
 
  puts("Comprobador de imágenes BMP\n");
  printf("Dime el nombre del fichero: ");
  gets(nombre);
  fichero = fopen(nombre, "rb");
  if (fichero==NULL)
    puts("No encontrado\n");
  else {
    fseek(fichero, 30, SEEK_SET);   
    fread(&compresion, 1, 4, fichero);
    fclose(fichero);
    if (compression == 0) 
      puts("Sin compresión");
   else
      puts ("BMP Comprimido ");
  }
 
  return 0;
}
 

Ya que estamos, podemos mejorarlo un poco para que además nos muestre el ancho y el alto de la imagen, y que compruebe antes si realmente se trata de un fichero BMP:

/*---------------------------*/
/*  Ejemplo en C nº 60:      */
/*  C060.C                   */
/*                           */
/*  Información sobre un     */ 
/*  fichero BMP (2)          */
/*                           */
/*  Curso de C,              */
/*    Nacho Cabanes          */
/*---------------------------*/
 
#include <stdio.h>
 
int main(){
  char nombre[60];
  FILE* fichero;
  int compresion, ancho, alto;
  char marca1, marca2;
 
  puts("Comprobador de imágenes BMP\n");
  printf("Dime el nombre del fichero: ");
  gets(nombre);
  fichero = fopen(nombre, "rb");
  if (fichero==NULL)
    puts("No encontrado\n");
  else {
    marca1 = fgetc(fichero);  /* Leo los dos primeros bytes */
    marca2 = fgetc(fichero);
    if ((marca1 =='B') && (marca2 =='M')) { /* Si son BM */
        printf#40;"Marca del fichero: %c%c\n", 
          marca1, marca2);
        fseek(fichero, 18, SEEK_SET);    /* Posición 18: ancho */
        fread(&ancho, 1, 4, fichero);
        printf("Ancho: %d\n", ancho);    
        fread(&alto, 1, 4, fichero);     /* Siguiente dato: alto */
        printf("Alto: %d\n", alto);    
        fseek(fichero, 4, SEEK_CUR);     /* 4 bytes después: compresión */
        fread(&compresion, 1, 4, fichero);
        fclose(fichero);
        switch (compresion) {
          case 0: puts("Sin compresión"); break;
          case 1: puts("Compresión RLE 8 bits"); break;
          case 2: puts("Compresión RLE 4 bits"); break;
          }
    } else
      printf("No parece un fichero BMP\n");  /* Si la marca no es BM */
  }
 
  return 0;
}
 

Ejercicios propuestos:

  • Mejorar la última versión de la agenda anterior (la que usa fwrite, fread y sizeof) para que no lea todas las fichas a la vez, sino que lea una única ficha del disco cada vez que lo necesite, saltando a la posición en que se encuentra dicha ficha con “fseek”.
  • Hacer un programa que muestre información sobre una imagen en formato GIF (se deberá localizar en Internet los detalles sobre dicho formato): versión, ancho de la imagen (en píxeles), alto de la imagen y cantidad de colores.
  • Hacer un programa que muestre información sobre una imagen en formato PCX: ancho de la imagen (en píxeles), alto de la imagen y cantidad de colores.
  • Mejorar la base de datos de ficheros (ejemplo 53) para que los datos se guarden en disco al terminar la sesión de uso, y se lean de disco cuando comienza una nueva sesión.
  • Mejorar la base de datos de ficheros (ejemplo 53) para que cada dato introducido se guarde inmediatamente en disco, sin esperar a que termine la sesión de uso. En vez de emplear un ?array de structs?, debe existir un solo ?struct? en memoria cada vez, y para las búsquedas se recorra todo el contenido del fichero.
  • Mejorar el ejercicio anterior (ejemplo 53 ampliado con ficheros, que se manejan ficha a ficha) para que se pueda modificar un cierto dato a partir de su número (por ejemplo, el dato número 3). En esa modificación, se deberá permitir al usuario pulsar Intro sin teclear nada, para indicar que no desea modificar un cierto dato, en vez de reemplazarlo por una cadena vacía.

 

Actualizado el: 25-07-2014 16:55

AnteriorPosterior