tags:

views:

2292

answers:

9

Hello,

i want to read the RGB values for each pixel from a .bmp file , so i can convert the bmp into a format suitable for gba .

so i need to get just the RGB for each pixel and then write this information to a file.

i am trying to use the windows.h structures :

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;

but i only need RGB struct. So lets say i read "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);

is this correct ? how do i write only the RGB information to a file ?

can anyone please give me some information please .

Thank you.

+4  A: 

If you are on windows you can use the LoadBitmap function from win32

then given the handle convert it to a DIB bitmap and get to the pixels that way

Toad
+1  A: 

See wikipedia page of .bmp file format which provides lots of information about the structure of the file and should help you to parse it.

http://en.wikipedia.org/wiki/BMP%5Ffile%5Fformat

In your code you first have to read the starting address of the data (specified in file header) and the height of the image. Then seek to this position. After that you read in one row pixel by pixel (the header specifies how many bits per pixel) and have to take care of the 32-bit padding at the end of it. Note that in a 24-bit image (RGB) the information is stored in BGR order. Also if the height value is not negative, the image is stored upside down.

svens
+2  A: 

You need first to get the number of colors available in the embedded palette. This is available in the DIB Header.

Then you can read all color components that contain the palette.

You can see all header information like offset to know whereto seek : http://en.wikipedia.org/wiki/BMP_file_format.

This should work: (Edit: Add code to write in file)

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);
Patrice Bernassola
and then when i write this info to a file i just :fwrite(palette,sizeof(RGB),1,inFile); ?
seven
does the palette contain every pixel's rgb information ?
seven
The palette contains all composant values of each color it contains. If you just want to copy the palette in a file you can do `fwrite(palette, sizeof(RGB), info.numColors, outFile);` with out file open like that: `fopen("path", "wb");` Then it depends on what you want to exactly do.
Patrice Bernassola
thanks for reply, but look, what i want to write to that file and what i need to use from a bmp file is the RGB for each pixel, so i need to read the information past the image header (if what i say makes sense)
seven
If I understand you want to write all component values in a text file?
Patrice Bernassola
not necessarily a txt file, it may have any extension .. but yes , thats what i want to do .. so i can then use those files and display them on the gba - there i can only read the information and write it to memory to display it
seven
I add two ways of writing the palette in a file. First allow you to quickly read and keep in memory the palette when reading the second File. Second way is be read by human. I think you need the first way but I wrote the two's to be sure to answer your question.
Patrice Bernassola
Note that the color palette is only used for 1, 4 and 8 bit color depths. Have you tried your bmp reading code? I can't get it to work with a 5x5 bmp from photoshop. (For example printf("Width x Height: %i x %i\n", info.width, info.height); prints out some crazy numbers)
svens
@svens: Here depth is 8bit as said in the question. If header and info structures are correct then it should work.
Patrice Bernassola
No, the depth is 24bit as it's a RGB image. 8 bit would be monochromatic. I hope my bmp has correct header, using a hex editor it looks like this. Could provide a bmp which you know it works?
svens
Ok, you have to take care of memory alignment when using this structs. #pragma pack(2) does the trick when using gcc.
svens
@svens: Sorry I was thinking 8bit depth per component instead of color
Patrice Bernassola
A: 

I'm not familiar with the BMP file format, but wouldn't you need to read in the header information first? Something like:

BmpHeader header;
fread(&header,sizeof(BmpHeader),1,inFile);

and read in detailed image information, which you'll need:

BmpImageInfo info;
fread(&info,sizeof(BmpImageInfo),1,inFile);

and read in palette information as well.

once you have that you will know the file size and data offset. You could pre-allocate sufficient space and read in all at once, which may be simplest. Alternatively you could read in in chunks and parse as you're going (reduces chance of not having enough memory, but parsing is more complicated).

You'll also know from the info section if compression is enabled, image dimensions etc.

If you're reading in all at once, jump to the offset of the data, and do something like:

Rgb* rgb = offset;
blueVal = rgb->blue;
greenVal = rgb->green;
redVal = rgb->red;
rgb += sizeof( Rgb );

and so on. Obviously that code isn't checking for errors, end of buffer, and so on, so you'll need to do that. You'll probably also have to read in palette information to make sense of the image data.

Or, as someone else said, look at the format spec on Wikipedia

pxb
i will always use this for 32x32 bitmaps so i dont need the header information - i just want to know how exactly i can get the information for each pixel .
seven
ok, fair enough. You'll still either read it in so you can skip over it, or seek past it if you know its length without reading it in. Check the format spec in more detail to see if the header info is fixed length, in which case you can try to seek past it. It looked fixed length, but I didn't look that closely.
pxb
A: 

If the BMP file has a palette then the below code should work:

  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);
  }
Nick D
This work only if the Palette exists AND contains 256 colors whereas palette can contains 0 to 2^n colors.
Patrice Bernassola
@Patrice Bernassola, of course. I assume that Seven wants to read a 256 palette.
Nick D
+2  A: 

I did a bit of testing and extended Patrice's program a bit. I'm not a good C programmer, so all credit goes to him and my parts aren't as elegant as his - sorry for that.

Warning: huge source code ahead.

#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;

}

This program reads out the pixel information stored in the file. It takes the padding into account but only works with bmps with a 24 bits per pixel color depth (If you need other depths, you'll have to customize the Rgb struct). Hope this helps you, but as I said, it's just an extension of Patrice's code.

Here's a sample output from my 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: Yes, my image is displaying a red cross. Note that the image is stored upside-down so row 1 of the file is actually row 5 of the image. D'oh forgot to write something to file the code opens, but this is left as an excercise up to you ;).

svens
thanks - this works fine for me too, pretty much exactly what i had in mind, now i have to work the code a bit so it will fit to my needs but i have a great start , thanks ;)
seven
Great effort. I would recommend against reading pixel by pixel though as this tends to be really slow. Much easier is to allocate the (width+padding)*height*sizeof(RGB) in advance and read the whole thing in one go. Afterwards you can look at all the RGB values by just looking in the correct memory location.
Toad
+1  A: 

If you're guaranteed that it's an uncompressed 24bpp bitmap and its width is divisible by 4, it's relatively simple:

  1. Read a BmpHeader at the start of the file.
  2. Without seeking, read a BmpImageInfo.
  3. Seek to the BmpHeader's offset bytes from the beginning of the file. Note that there is no palette (at least, not one we care about) in 24-bit bitmaps!
  4. Read BGR triplets (in that order, and there's no reserved unused member here). There will be (BmpImageInfo's members) width * abs(height) triplets. As I recall, if height is positive (the standard case), the first line of color you read will be the bottom line of the image, going up from there. If height is negative, though, the first line of color in the file is the top of the image, going down from there.

If you can't make those guarantees, then things get a good deal more complicated.

Disclaimer: I'm gratuitously tooting my own horn here. Years ago I wrote a tiny (one source file) utility to do exactly what you're talking about, in a portable (100% ANSI C) way: glbmp. Its source might shed some light on your problem--it handles uncompresed (no RLE) bitmaps of any bit depth, and should run fine on a GBA.

chazomaticus
hey thanks for pointing me in the right direction, i'll have a look and test the tool tomorrow :D . Also i found in handy svens post also, just that indeed on the ds/gba it reads the RGB backwards -> BGR, so i still have a little thing to do but i hope to make it work .thanks again .
seven
A: 

You might find it useful to look at some C code I wrote many years ago for reading and writing BMP files, located at:

http://david.tribble.com/src/bmp/bmp.html

I believe it handles the various pixel bit sizes (1/2/4/8/24) as well as RLE compression.

Loadmaster
A: 

hey i want to obtain the rgb values from 24 bit bitmap and store it in an array for image processing manipulation. i'm not that good at C. Does anyone have a source code for this?

thanks ns