Get RGB values ​​for each pixel from 24bpp bitmap for conversion to GBA format in C

I want to read RGB values ​​for each pixel from a file .bmp

, so I can convert bmp

to a GBA (GameBoy Advance) suitable format.

I only need to get RGB for each pixel and then write that information to a file.

I am trying to use structures <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;

      

but I only need the RGB structure. So let's 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);

      

It is right? How to write only RGB information to a file?

+2


source to share


8 answers


You need to first get the number of colors available in the built-in palette. This is available in the DIB header.

Then you can read all the color components containing the palette.

You can view all header information such as offset to see where to look: http://en.wikipedia.org/wiki/BMP_file_format .



This should work: (Edit: Add code to write to 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);

      

+3


source


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



after which the descriptor converts it to a DIB bitmap and gets into pixels in this way

+4


source


I tested and extended Patrice a bit. I'm not a very good C programmer, so all his merit and my details are not as elegant as his - sorry about that.

Warning: There is a 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 the pixel information stored in the file. It takes shims into account, but only works with bmps with 24 bits per pixel color depth (if you need other depths, you'll have to tweak the Rgb structure). Hope this helps you, but as I said, this is just an extension of Patrice's code.

Here's an example of the output from my test file:

$ ./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 shows a red cross. Note that the image is stored in reverse order, so line 1 of the file is actually line 5 of the image. D'oh forgot to write something to open the code, but this is left as an exercise for you;).

+4


source


If you are guaranteed that it is a 24bpp uncompressed bitmap and that its width is divisible by 4, this is relatively simple:

  • Read BmpHeader

    at the beginning of the file.
  • Read without searching BmpImageInfo

    .
  • Refer to the bytes BmpHeader

    offset

    from the beginning of the file. Note that there is no palette in 24-bit bitmaps (at least not about that)!
  • Read the BGR triglets (in that order and there's no reserved

    unused member here). There will be ( BmpImageInfo

    members of) width * abs(height)

    triplets. As far as I remember, if height

    positive (standard case), the first line of color you read will be the bottom line of the image coming from there. If height

    negative, then the first line of color in the file is the top of the image, indented from there.

If you cannot make these guarantees, then things get much more complicated.

Disclaimer: I am free to read my own horn here. Several years ago I wrote a small utility (one source file) to do what you are talking about in a portable (100% ANSI C) way: glbmp libbmpread . Its source may shed light on your problem - it handles uncompresed (no RLE) bitmaps of any bit depth and should work fine on GBA.

+2


source


See the .bmp wikipedia page for a lot of information about the structure of the file and should help you parse it.

http://en.wikipedia.org/wiki/BMP_file_format

In your code, you first need to read the starting data address (specified in the file header) and the height of the image. Then look for that position. After that, you read in one line pixel by pixel (the header indicates how many bits per pixel) and it needs 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.

+1


source


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

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

      

and read the detailed image information you'll need:

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

      

and read also the palette information.

after you know about file size and data offset. You can preallocate enough space and read everything at once, which might be easiest. Alternatively, you can read in chunks and parse as you go (reduces the chances of running out of memory, but parsing is more difficult).

You will also find out from the info section if compression is enabled, image sizes, etc.

If you are reading all at once, go to offset data and do something like:

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

      

etc. Obviously, the code doesn't check for errors, end of buffer, etc., so you will need to do this. You may also need to read the palette information to understand the image data.

Or, as someone else said, have a look at the format specification on Wikipedia

0


source


If there is a palette in the BMP file, then the code below 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);
  }

      

0


source


You may find it helpful to take a look at some C code that I wrote many years ago to read and write BMP files located at:

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

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

0


source







All Articles