8.14. Ejemplo completo: leer información de un fichero BMP
Curso: Programación en C# (2015), por Nacho Cabanes
8.14. Ejemplo completo: leer información de un fichero BMP
Hemos estado extrayendo algo de información de ficheros BMP. Ahora vamos a ir un poco más allá y a tratar de obtener muchos de los detalles que hay en su cabecera. El formato de dicha cabecera es el siguiente:
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
Por tanto, será fácil hacer que se nos muestren algunos detales, como su ancho, su alto, la resolución y si la imagen está comprimida o no:
?// Ejemplo_08_14a.cs // Información de un fichero BMP, con BinaryReader // Introducción a C#, por Nacho Cabanes using System; using System.IO; public class Ejemplo_08_14a { public static void Main() { Console.WriteLine("Información de imágenes BMP"); Console.WriteLine("Dime el nombre del fichero: "); string nombre = Console.ReadLine(); if (! File.Exists( nombre) ) { Console.WriteLine("No encontrado!"); } else { BinaryReader fichero = new BinaryReader( File.Open(nombre, FileMode.Open)); // Leo los dos primeros bytes char marca1 = Convert.ToChar( fichero.ReadByte() ); char marca2 = Convert.ToChar( fichero.ReadByte() ); if ((marca1 !='B') || (marca2 !='M')) Console.WriteLine("No parece un fichero BMP"); else { Console.WriteLine("Marca del fichero: {0}{1}", marca1, marca2); // Posición 18: ancho fichero.BaseStream.Seek(18, SeekOrigin.Begin); int ancho = fichero.ReadInt32(); Console.WriteLine("Ancho: {0}", ancho); // A continuación: alto int alto = fichero.ReadInt32(); Console.WriteLine("Alto: {0}", alto); // Posición 30: compresión fichero.BaseStream.Seek(30, SeekOrigin.Begin); int compresion = fichero.ReadInt32(); 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; } // 4 bytes después: resolución horizontal fichero.BaseStream.Seek(4, SeekOrigin.Current); int resolH = fichero.ReadInt32(); Console.WriteLine("Resolución Horiz.: {0}", resolH); // A continuación: resolución vertical int resolV = fichero.ReadInt32(); Console.WriteLine("Resolución Vertical: {0}", resolV); fichero.Close(); } } } }
Podemos hacerlo también con un FileStream, que simplificará ciertas operaciones, como la lectura, que se puede hacer toda en un bloque, pero a cambio complicará otras operaciones, como el cálculo de los valores enteros, que habrá que componer a partir de los 4 bytes que los forman:
?// Ejemplo_08_14b.cs // Información de un fichero BMP, con FileStream // Introducción a C#, por Nacho Cabanes using System; using System.IO; public class Ejemplo_08_14b { public static void Main() { Console.WriteLine("Información de imágenes BMP"); Console.WriteLine("Dime el nombre del fichero: "); string nombre = Console.ReadLine(); if (! File.Exists( nombre) ) { Console.WriteLine("No encontrado!"); } else { FileStream fichero = File.OpenRead(nombre); int tamanyoCabecera = 54; byte[] cabecera = new byte[tamanyoCabecera]; int cantidadLeida = fichero.Read(cabecera, 0, tamanyoCabecera); fichero.Close(); if (cantidadLeida != tamanyoCabecera) { Console.WriteLine("No se ha podido leer la cabecera"); } else { // Analizo los dos primeros bytes char marca1 = Convert.ToChar( cabecera[0] ); char marca2 = Convert.ToChar( cabecera[1] ); if ((marca1 !='B') || (marca2 !='M')) Console.WriteLine("No parece un fichero BMP"); else { Console.WriteLine("Marca del fichero: {0}{1}", marca1, marca2); int ancho = cabecera[18] + // Convierto 4 bytes a Int32 cabecera[19] * 256 + cabecera[20] * 256 * 256 + cabecera[21] * 256 * 256 * 256; Console.WriteLine("Ancho: {0}", ancho); int alto = cabecera[22] + cabecera[23] * 256 + cabecera[24] * 256 * 256 + cabecera[25] * 256 * 256 * 256; Console.WriteLine("Alto: {0}", alto); int compresion = cabecera[30]; 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; } int resolH = cabecera[38] + cabecera[39] * 256 + cabecera[40] * 256 * 256 + cabecera[41] * 256 * 256 * 256; Console.WriteLine("Resolución Horiz.: {0}", resolH); int resolV = cabecera[42] + cabecera[43] * 256 + cabecera[44] * 256 * 256 + cabecera[45] * 256 * 256 * 256; Console.WriteLine("Resolución Vertical: {0}", resolV); } } } } }
Ejercicios propuestos:
Ejercicio propuesto 8.14.1: 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.
Ejercicio propuesto 8.14.2: 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.
Actualizado el: 22-03-2015 17:07