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.