7.13. Ejemplo: leer información de un fichero BMP
Ahora vamos a ver un ejemplo un poco más sofisticado y un poco más real: 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 en Internet:
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 fichero 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, es un entero de 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.
Como el bit menos significativo se almacena en primer lugar, nos podría bastar con leer sólo el byte de la posición 30, para ver si vale 0, y despreciar los 3 bytes siguientes. Entonces, lo podríamos comprobar así:
/*---------------------------*/ /* Ejemplo en C# nº 82: */ /* ejemplo82.cs */ /* */ /* Ficheros binarios (6): */ /* Ver si un BMP está */ /* comprimido */ /* */ /* Introduccion a C#, */ /* Nacho Cabanes */ /*---------------------------*/ using System; using System.IO; public class Ejemplo82 { public static void Main() { FileStream fichero; string nombre; int compresion; Console.WriteLine("Comprobador de imágenes BMP\n"); Console.WriteLine("Dime el nombre del fichero: "); nombre = Console.ReadLine(); if (! File.Exists( nombre) ) { Console.WriteLine("No encontrado!"); } else { fichero = File.OpenRead(nombre); fichero.Seek(30, SeekOrigin.Begin); compresion = fichero.ReadByte(); fichero.Close(); if (compresion == 0) Console.WriteLine("Sin compresión"); else Console.WriteLine("BMP Comprimido "); } } }
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º 83: */ /* ejemplo83.cs */ /* */ /* Ficheros binarios (7): */ /* Información de un */ /* fichero BMP */ /* */ /* Introduccion a C#, */ /* Nacho Cabanes */ /*---------------------------*/ using System; using System.IO; public class Ejemplo83 { public static void Main() { FileStream fichero; string nombre; int compresion, ancho, alto; char marca1, marca2; byte[] datosTemp = new byte[4]; Console.WriteLine("Comprobador de imágenes BMP\n"); Console.WriteLine("Dime el nombre del fichero: "); nombre = Console.ReadLine(); if (! File.Exists( nombre) ) { Console.WriteLine("No encontrado!"); } else { fichero = File.OpenRead(nombre); // Leo los dos primeros bytes marca1 = Convert.ToChar( fichero.ReadByte() ); marca2 = Convert.ToChar( fichero.ReadByte() ); if ((marca1 =='B') && (marca2 =='M')) { // Si son BM Console.WriteLine("Marca del fichero: {0}{1}", marca1, marca2); fichero.Seek(18, SeekOrigin.Begin); // Posición 18: ancho fichero.Read(datosTemp, 0, 4); ancho = datosTemp[0] + // Convierto 4 bytes a Int32 datosTemp[1] * 256 + datosTemp[2] * 256 * 256 + datosTemp[3] * 256 * 256 * 256; Console.WriteLine("Ancho: {0}", ancho); fichero.Read(datosTemp, 0, 4); alto = datosTemp[0] + // Convierto 4 bytes a Int32 datosTemp[1] * 256 + datosTemp[2] * 256 * 256 + datosTemp[3] * 256 * 256 * 256; Console.WriteLine("Alto: {0}", alto); fichero.Seek(4, SeekOrigin.Current); // 4 bytes después: compresión compresion = fichero.ReadByte(); fichero.Close(); switch (compresion) { case 0: Console.WriteLine("Sin compresión"); break; case 1: Console.WriteLine("Compresión RLE 8 bits"); break; case 2: Console.WriteLine("Compresión RLE 4 bits"); break; } } else Console.WriteLine("No parece un fichero BMP\n"); // Si la marca no es BM } } }
También podemos hacer lo mismo empleando un "BinaryReader", en lugar de un "FileStream". En ese caso, se simplifica la lectura de datos de 32 bits, a cambio de complicarse ligeramente la apertura y los "Seek", como se ve en este ejemplo:
/*---------------------------*/ /* Ejemplo en C# nº 84: */ /* ejemplo84.cs */ /* */ /* Ficheros binarios (8): */ /* Información de un BMP */ /* con BinaryReader */ /* */ /* Introduccion a C#, */ /* Nacho Cabanes */ /*---------------------------*/ using System; using System.IO; public class Ejemplo84 { public static void Main() { BinaryReader fichero; string nombre; int compresion, ancho, alto; char marca1, marca2; Console.WriteLine("Comprobador de imágenes BMP\n"); Console.WriteLine("Dime el nombre del fichero: "); nombre = Console.ReadLine(); if (! File.Exists( nombre) ) { Console.WriteLine("No encontrado!"); } else { fichero = new BinaryReader( File.Open(nombre, FileMode.Open)); // Leo los dos primeros bytes marca1 = Convert.ToChar( fichero.ReadByte() ); marca2 = Convert.ToChar( fichero.ReadByte() ); if ((marca1 =='B') && (marca2 =='M')) { // Si son BM Console.WriteLine("Marca del fichero: {0}{1}", marca1, marca2); fichero.BaseStream.Seek(18, SeekOrigin.Begin); // Posición 18: ancho ancho = fichero.ReadInt32(); Console.WriteLine("Ancho: {0}", ancho); alto = fichero.ReadInt32(); Console.WriteLine("Alto: {0}", alto); fichero.BaseStream.Seek(4, SeekOrigin.Current); // 4 bytes después: compresión compresion = fichero.ReadInt32(); fichero.Close(); switch (compresion) { case 0: Console.WriteLine("Sin compresión"); break; case 1: Console.WriteLine("Compresión RLE 8 bits"); break; case 2: Console.WriteLine("Compresión RLE 4 bits"); break; } } else Console.WriteLine("No parece un fichero BMP\n"); // Si la marca no es BM } } }
Ejercicios propuestos:
- Localiza en Internet información sobre el formato de imágenes PCX. Crea un programa que diga el ancho, alto y número de colores de una imagen PCX.
- Localiza en Internet información sobre el formato de imágenes GIF. Crea un programa que diga el subformato, ancho, alto y número de colores de una imagen GIF.