Obtenir les valeurs RVB pour chaque pixel d'une Bitmap 24bpp pour la conversion au format GBA en C
Question
Je veux lire les valeurs RVB pour chaque pixel à partir d'un fichier .bmp
, donc je peux convertir le bmp
en un format adapté à l'ACS (GameBoy Advance).
Je dois obtenir juste le RVB pour chaque pixel, puis écrire ces informations dans un fichier.
Je suis en train d'utiliser les structures de <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;
mais je ne ai besoin struct RVB. Alors disons que je lis « 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);
Est-ce exact? Comment puis-je écrire que les informations RVB dans un fichier?
La solution
Vous devez d'abord obtenir le nombre de couleurs disponibles dans la palette intégrée. Il est disponible dans l'en-tête DIB.
Ensuite, vous pouvez lire tous les composants de couleur qui contiennent la palette.
Vous pouvez voir toutes les informations d'en-tête offset savoir vers quoi chercher: http: //en.wikipedia. org / wiki / BMP_file_format .
Cela devrait fonctionner: (Edit: Ajouter du code à écrire dans le fichier)
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);
Autres conseils
Si vous êtes sur Windows, vous pouvez utiliser le la fonction de LoadBitmap de Win32
alors donné la poignée le convertir en un bitmap DIB et obtenir les pixels de cette façon
Je l'ai fait un peu d'essais et a étendu le programme de Patrice un peu. Je ne suis pas un bon programmeur C, donc tout le crédit va à lui et mes pièces ne sont pas aussi élégant que son -. Désolé
Attention:. Énorme code source avant
#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;
}
Ce programme lit les informations de pixel stockées dans le fichier. Il faut le rembourrage en compte, mais ne fonctionne qu'avec bmps avec 24 bits par la profondeur de couleur de pixel (Si vous avez besoin d'autres profondeurs, vous devrez personnaliser le struct Rgb). Espérons que cela vous aide, mais comme je l'ai dit, il est juste une extension du code de Patrice.
Voici un exemple de sortie de mon 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: Oui, mon image affiche une croix rouge. Notez que l'image est stockée à l'envers si la ligne 1 du fichier est rangée en fait 5 de l'image. D'oh a oublié d'écrire quelque chose pour déposer le code ouvre, mais cela reste comme excercise à vous;)
.Si vous êtes assuré que c'est un bitmap non compressé 24bpp et sa largeur est divisible par 4, il est relativement simple:
- Lire un
BmpHeader
au début du fichier. - Sans chercher, lire un
BmpImageInfo
. - Recherche aux octets
BmpHeader
duoffset
de au début du fichier . Notez qu'il n'y a pas de palette (au moins, pas un nous nous soucions) en bitmaps 24 bits! - Lire triplets BGR (dans cet ordre, et il n'y a aucun membre inutilisé
reserved
ici). Il y aura des (membres deBmpImageInfo
) les triplés dewidth * abs(height)
. Si je me souviens, siheight
est positif (le cas standard), la première ligne de la couleur que vous lisez sera le bas ligne de l'image, va à partir de là. Siheight
est négatif, cependant, la première ligne de la couleur dans le fichier est le top de l'image, en descendant à partir de là.
Si vous ne pouvez pas faire ces garanties, alors les choses deviennent beaucoup plus compliquées.
Disclaimer:. Je Tooting mon propre titre gratuit corne ici Il y a quelques années, j'ai écrit un petit (un fichier source) utilitaire pour faire exactement ce que vous parlez, dans un portable (100% ANSI C) ainsi: glbmp libbmpread . Sa source pourrait faire la lumière sur votre problème -. Il gère bitmaps uncompresed (pas RLE) de toute profondeur de bits, et devrait fonctionner sur une GBA
Voir la page wikipedia de .bmp format de fichier qui fournit beaucoup d'informations sur la structure du fichier et devrait vous aider à analyser.
http://en.wikipedia.org/wiki/BMP_file_format
Dans votre code, vous devez d'abord lire l'adresse de départ des données (spécifié dans la tête de fichier) et la hauteur de l'image. Ensuite, chercher à ce poste. Après que vous avez lu dans un pixel de ligne par pixel (l'en-tête indique le nombre de bits par pixel) et doivent prendre soin du rembourrage 32 bits à la fin de celui-ci. On notera que dans une image de 24 bits (RGB) les informations sont stockées dans l'ordre BGR. Aussi, si la valeur de hauteur ne soit pas négatif, l'image est stockée à l'envers.
Je ne suis pas familier avec le format de fichier BMP, mais ne vous devez lire les informations d'en-tête en premier? Quelque chose comme:
BmpHeader header;
fread(&header,sizeof(BmpHeader),1,inFile);
et lire des informations détaillées sur l'image, que vous aurez besoin:
BmpImageInfo info;
fread(&info,sizeof(BmpImageInfo),1,inFile);
et lire les informations de la palette ainsi.
une fois que vous avez que vous connaîtrez la taille du fichier et des données de décalage. Vous pouvez pré-allouer suffisamment d'espace et lire tout à la fois, ce qui peut être plus simple. Sinon, vous pouvez lire en morceaux et analyser comme vous allez (réduit la chance de ne pas avoir assez de mémoire, mais l'analyse est plus complexe).
Vous saurez également de la section d'information si la compression est activée, les dimensions des images etc.
Si vous lisez tout à la fois, sauter au décalage des données, et faire quelque chose comme:
Rgb* rgb = offset;
blueVal = rgb->blue;
greenVal = rgb->green;
redVal = rgb->red;
rgb += sizeof( Rgb );
et ainsi de suite. Il est évident que le code ne vérifie pas pour les erreurs, à la fin de tampon, et ainsi de suite, vous aurez donc besoin de le faire. Vous aurez probablement aussi de lire des informations de la palette pour donner un sens des données d'image.
Ou, comme quelqu'un l'a dit, regardez la spécification de format sur Wikipédia
Si le fichier BMP a une palette puis le code ci-dessous devrait travail:
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);
}
Vous trouverez peut-être utile de regarder un peu de code C je l'ai écrit il y a plusieurs années pour la lecture et l'écriture de fichiers BMP, situés à:
http://david.tribble.com/src/bmp/bmp.html
Je crois qu'il gère les différentes tailles de bits de pixels (1/2/4/8/24) ainsi que la compression RLE.