Obtener valores RGB para cada píxel de un mapa de bits de 24 bpp para la conversión a formato GBA en C
Pregunta
quiero leer los valores RGB para cada píxel de un archivo .bmp
, por lo que puede convertir el bmp
en un formato adecuado para GBA (Game Boy Advance).
Necesito obtener sólo el RGB para cada píxel y luego escribir esta información en un archivo.
Estoy tratando de utilizar las estructuras <windows.h>
:
typedef struct
{
char signature[2];
unsigned int fileSize;
unsigned int reserved;
unsigned int offset;
}BmpHeader;
typedef struct
{
unsigned int headerSize;
unsigned int width;
unsigned int height;
unsigned short planeCount;
unsigned short bitDepth;
unsigned int compression;
unsigned int compressedImageSize;
unsigned int horizontalResolution;
unsigned int verticalResolution;
unsigned int numColors;
unsigned int importantColors;
}BmpImageInfo;
typedef struct
{
unsigned char blue;
unsigned char green;
unsigned char red;
unsigned char reserved;
}Rgb;
typedef struct
{
BmpHeader header;
BmpImageInfo info;
Rgb colors[256];
unsigned short image[1];
}BmpFile;
pero yo sólo necesito RGB estructura. Así que digamos que leí "in.bmp":
FILE *inFile, *outFile;
inFile = fopen("C://in.bmp", "rb");
Rgb Palette[256];
for(i=0;i<256;i++)
{
fread(&Palette[i],sizeof(Rgb),1,inFile);
}
fclose(inFile);
¿Es esto correcto? ¿Cómo se escribe sólo la información RGB en un archivo?
Solución
Es necesario primero para obtener el número de colores disponibles en la paleta incrustado. Este servicio está disponible en la cabecera DIB.
A continuación, puede leer todos los componentes de color que contienen la paleta.
Se puede ver toda la información de cabecera como el desplazamiento saber Whereto buscan: http: //en.wikipedia. org / wiki / BMP_file_format.
Esto debería funcionar: (Edit: Añadir un código para escribir en el archivo)
FILE *inFile, *outFile;
BMPHeader header;
BMPImageInfo info;
RGB *palette, *p;
int i = 0;
inFile = fopen("C://in.bmp", "rb");
if( !inFile )
return;
if( fread(&header, sizeof(BMPHeader), 1, inFile) != 1 )
return; // Manage error and close file
if( fread&info, sizeof(BMPImageInfo), 1, inFile) != 1 )
return; // Manage error and close file
if( info.numColors > 0 )
{
palette = (RGB*)malloc(sizeof(RGB) * info.numColors);
if( fread(palette, sizeof(RGB), info.numColors, inFile) != info.numColors )
return; // manage error and close file
}
fclose(inFile)
// Binary method => if read later by another computer
outFile = fopen("path", "wb");
if( !outFile )
return;
if( fwrite(&info.numColors, sizeof(unsigned int), 1, outFile) != 1 )
return; // Manage Error and close file
if( fwrite(&palette, sizeof(RGB), info.numColors, outFile) != info.numColors )
return; // Manage error and close file
fclose(outFile);
// Text method => if read later by human
outFile = fopen("path", "w");
if( !outFile )
return;
for( i=0; i<info.numColors; ++i )
{
p = &palette[i];
if( fprintf(outFile, "R:%d, G:%d, B:%d\n", p->red, p->green, p->blue) < 0 )
return; // Manage error and close file
}
fclose(outFile);
Otros consejos
Si está en Windows se puede utilizar el LoadBitmap función de Win32
dada entonces la manija convertirlo en un mapa de bits DIB y llegar a los píxeles de esa manera
Hice un poco de prueba y ampliado programa de Patrice un poco. No soy un buen programador C, por lo que todo el crédito va a él y mis partes no son tan elegante como su -. Lo siento por eso
Advertencia:. Enorme por delante código fuente
#include <stdio.h>
#pragma pack(2)
typedef struct
{
char signature[2];
unsigned int fileSize;
unsigned int reserved;
unsigned int offset;
} BmpHeader;
typedef struct
{
unsigned int headerSize;
unsigned int width;
unsigned int height;
unsigned short planeCount;
unsigned short bitDepth;
unsigned int compression;
unsigned int compressedImageSize;
unsigned int horizontalResolution;
unsigned int verticalResolution;
unsigned int numColors;
unsigned int importantColors;
} BmpImageInfo;
typedef struct
{
unsigned char blue;
unsigned char green;
unsigned char red;
//unsigned char reserved; Removed for convenience in fread; info.bitDepth/8 doesn't seem to work for some reason
} Rgb;
int main( int argc, char **argv ) {
FILE *inFile;
BmpHeader header;
BmpImageInfo info;
Rgb *palette;
int i = 0;
printf( "Opening file %s for reading.\n", argv[1] );
inFile = fopen( argv[1], "rb" );
if( !inFile ) {
printf( "Error opening file %s.\n", argv[1] );
return -1;
}
if( fread(&header, 1, sizeof(BmpHeader), inFile) != sizeof(BmpHeader) ) {
printf( "Error reading bmp header.\n" );
return -1;
}
if( fread(&info, 1, sizeof(BmpImageInfo), inFile) != sizeof(BmpImageInfo) ) {
printf( "Error reading image info.\n" );
return -1;
}
if( info.numColors > 0 ) {
printf( "Reading palette.\n" );
palette = (Rgb*)malloc(sizeof(Rgb) * info.numColors);
if( fread(palette, sizeof(Rgb), info.numColors, inFile) != (info.numColors * sizeof(Rgb)) ) {
printf( "Error reading palette.\n" );
return -1; // error
}
}
printf( "Opening file %s for writing.\n", argv[2] );
FILE *outFile = fopen( argv[2], "wb" );
if( !outFile ) {
printf( "Error opening outputfile.\n" );
return -1;
}
Rgb *pixel = (Rgb*) malloc( sizeof(Rgb) );
int read, j;
for( j=0; j<info.height; j++ ) {
printf( "------ Row %d\n", j+1 );
read = 0;
for( i=0; i<info.width; i++ ) {
if( fread(pixel, 1, sizeof(Rgb), inFile) != sizeof(Rgb) ) {
printf( "Error reading pixel!\n" );
return -1;
}
read += sizeof(Rgb);
printf( "Pixel %d: %3d %3d %3d\n", i+1, pixel->red, pixel->green, pixel->blue );
}
if( read % 4 != 0 ) {
read = 4 - (read%4);
printf( "Padding: %d bytes\n", read );
fread( pixel, read, 1, inFile );
}
}
printf( "Done.\n" );
fclose(inFile);
fclose(outFile);
printf( "\nBMP-Info:\n" );
printf( "Width x Height: %i x %i\n", info.width, info.height );
printf( "Depth: %i\n", (int)info.bitDepth );
return 0;
}
Este programa lee la información de los píxeles almacenados en el archivo. Se necesita el relleno en cuenta, pero sólo funciona con las BMP con 24 bits por píxel profundidad de color (Si necesita otras profundidades, usted tiene que personalizar la estructura RGB). Espero que esto le ayuda, pero como ya he dicho, es sólo una extensión de código de Patrice.
Aquí hay un ejemplo de salida de mi testfile:
$ ./a.out test.bmp out.txt
Opening file test.bmp for reading.
Opening file out.txt for writing.
------ Row 1
Pixel 1: 0 0 0
Pixel 2: 0 0 0
Pixel 3: 0 0 0
Pixel 4: 0 0 0
Pixel 5: 0 0 0
Padding: 1 bytes
------ Row 2
Pixel 1: 0 0 0
Pixel 2: 232 33 33
Pixel 3: 0 0 0
Pixel 4: 232 33 33
Pixel 5: 0 0 0
Padding: 1 bytes
------ Row 3
Pixel 1: 0 0 0
Pixel 2: 0 0 0
Pixel 3: 232 33 33
Pixel 4: 0 0 0
Pixel 5: 0 0 0
Padding: 1 bytes
------ Row 4
Pixel 1: 0 0 0
Pixel 2: 232 33 33
Pixel 3: 0 0 0
Pixel 4: 232 33 33
Pixel 5: 0 0 0
Padding: 1 bytes
------ Row 5
Pixel 1: 0 0 0
Pixel 2: 0 0 0
Pixel 3: 0 0 0
Pixel 4: 0 0 0
Pixel 5: 0 0 0
Padding: 1 bytes
Done.
BMP-Info:
Width x Height: 5 x 5
Depth: 24
Edit: Sí, mi imagen está mostrando una cruz roja. Tenga en cuenta que la imagen se almacena en posición invertida para la fila 1 del archivo es en realidad la fila 5 de la imagen. D'oh olvidó de escribir algo para presentar el código se abre, pero esto se deja como un ejercicio de usted;)
.Si tiene la garantía de que se trata de un mapa de bits sin comprimir 24bpp y su anchura es divisible por 4, es relativamente simple:
- Leer un
BmpHeader
al inicio del archivo. - Sin buscar, leer un
BmpImageInfo
. - Tratar de bytes
BmpHeader
deloffset
de al principio del archivo . Tenga en cuenta que no hay una gama de colores (al menos, no uno que se preocupa) en mapas de bits de 24 bits! - Leer trillizos BGR (en ese orden, y no hay ningún miembro sin usar
reserved
aquí). Habrá (miembros deBmpImageInfo
) trillizoswidth * abs(height)
. Por lo que recuerdo, siheight
es positivo (el caso normal), la primera línea de color que lee será el fondo línea de la imagen, subiendo desde allí. Siheight
es negativo, sin embargo, la primera línea de color en el archivo es el top de la imagen, bajando desde allí.
Si no puede hacer esas garantías, entonces las cosas se ponen bastante más complicado.
exención de responsabilidad:. Estoy gratuitamente haciendo sonar mi molino aquí Hace años escribí una pequeña utilidad (un archivo de origen) para hacer exactamente lo que está hablando, en un portátil (100% ANSI C ida): GLBMP libbmpread . Su fuente podría arrojar alguna luz sobre su problema -. Maneja (sin RLE) uncompresed de cualquier profundidad de bits, y debería funcionar bien en un GBA
Ver página de Wikipedia de formato de archivo .bmp que proporciona una gran cantidad de información sobre la estructura del archivo y le ayudará a analizarlo.
http://en.wikipedia.org/wiki/BMP_file_format
En el código primero hay que leer la dirección inicial de los datos (especificada en el encabezado del archivo) y la altura de la imagen. A continuación, tratar de esta posición. Después de leer en un píxel a píxel fila (el encabezado especifica el número de bits por píxel) y tienen que cuidar del acolchado de 32 bits al final de la misma. Tenga en cuenta que una imagen de 24 bits (RGB) en la información se almacena con el fin BGR. Además, si el valor de la altura no es negativo, la imagen se almacena al revés.
No estoy familiarizado con el formato de archivo BMP, pero ¿no es necesario leer en la información del encabezado en primer lugar? Algo así como:
BmpHeader header;
fread(&header,sizeof(BmpHeader),1,inFile);
y leer la información detallada en la imagen, lo que se necesita:
BmpImageInfo info;
fread(&info,sizeof(BmpImageInfo),1,inFile);
y leer la información en la paleta también.
una vez que tenga que usted sabrá el tamaño del archivo y datos de corrección. Se podría pre-asignar espacio suficiente y leído en todos a la vez, lo que puede ser más simple. Como alternativa se puede leer en en trozos y analizar como vas (reduce la posibilidad de no tener suficiente memoria, pero el análisis es más complicado).
También sabrá de la sección de información si se habilita la compresión, las dimensiones de imagen, etc.
Si usted está leyendo en todos a la vez, saltar al desplazamiento de los datos, y hacer algo como:
Rgb* rgb = offset;
blueVal = rgb->blue;
greenVal = rgb->green;
redVal = rgb->red;
rgb += sizeof( Rgb );
y así sucesivamente. Obviamente que el código no es la comprobación de errores, al final del búfer, y así sucesivamente, por lo que tendrá que hacer eso. Es posible que también tiene que leer en la información de paleta para dar sentido a los datos de la imagen.
O, como alguien dijo, mira la especificación de formato de Wikipedia
Si el archivo BMP tiene una paleta entonces el siguiente código debe de trabajo:
FILE *inFile, *outFile;
inFile = fopen("C:/in.bmp", "rb");
Rgb Palette[256];
if ( inFile ) {
// Bypass headers
fseek(inFile, sizeof(BmpHeader) + sizeof(BmpImageInfo), SEEK_SET);
// Load the whole palette
fread(Palette, sizeof(Palette), 1, inFile);
fclose(inFile);
}
Puede que le resulte útil para mirar algo de código C que escribí hace muchos años para la lectura y escritura de archivos BMP, que se encuentra en:
http://david.tribble.com/src/bmp/bmp.html
Creo que maneja los diferentes tamaños de bits de píxeles (1/2/4/8/24), así como la compresión RLE.