I am developing my own OS, with GNU-EFI, I am written a small BMP Image loader program.
I can Successfully read its headers and data ( not sure ) when I plot that on my Screen that is only showing blue color on pixels.
// Blue Pixels are Plotted BMP Image
How can I load this with Colours?
PlotPixel(x,y,color) Color takes Value as 0xFFFFFFFF;
Following is my bmp loader:
BMP.h
// bmp.h
#define WIN_BITMAP_SIGNATURE 0x4D42 // BM [ASCII]
#define BMP_HEADER_SIZE 54
#define DIB_HEADER_SIZE 40
#pragma pack(push, 1)
typedef struct
{
uint16_t bfType; // The characters "BM" - 2 Bytes
uint32_t bfSize; // The size of the file in bytes - 4 Bytes
uint16_t bfReserved1; // Unused - must be zero - 2 Bytes
uint16_t bfReserved2; // Unused - must be zero - 2 Bytes
uint32_t bfOffBits; // Offset to start of Pixel Data - 4 Bytes
uint32_t biSize; // DIB Header Size - 4 Bytes
int32_t biWidth; // Width - 4 Bytes
int32_t biHeight;
uint16_t biPlanes;
uint16_t biBitCount;
uint32_t biCompression;
uint32_t biSizeImage;
int32_t biXPexelsPerMeter;
int32_t biYPexelsPerMeter;
uint32_t biClrUsed;
uint32_t biClrImportant;
} BITMAP_HEADER;
typedef struct
{
BITMAP_HEADER* header;
uint8_t* data;
} BITMAP_IMG;
typedef struct
{
uint32_t red_mask;
uint32_t green_mask;
uint32_t blue_mask;
uint32_t alpha_mask;
uint32_t color_space_type;
uint32_t unused[16];
} BMPColorHeader;
#pragma pack(pop)
unsigned long createRGBA(int r, int g, int b, int a);
unsigned long createRGB(int r, int g, int b);
BITMAP_IMG* LoadBMPImage(EFI_FILE* Directory, CHAR16* Path, EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable);
BMP.c
// bmp.c
#include "bmp.h"
unsigned long createRGB(int r, int g, int b)
{
return ((r & 0xff) << 16) + ((g & 0xff) << 8) + (b & 0xff);
}
unsigned long createRGBA(int r, int g, int b, int a)
{
return ((r & 0xff) << 24) + ((g & 0xff) << 16) + ((b & 0xff) << 8)
+ (a & 0xff);
}
BITMAP_IMG* LoadBMPImage(EFI_FILE* Directory, CHAR16* Path, EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable)
{
EFI_FILE* BMPImage = LoadFile(Directory, Path, ImageHandle, SystemTable);
if(BMPImage == NULL) return NULL;
BITMAP_HEADER* BMPImageHeader;
SystemTable->BootServices->AllocatePool(EfiLoaderData, sizeof(BITMAP_HEADER), (void**)&BMPImageHeader);
UINTN size = sizeof(BITMAP_HEADER);
BMPImage->Read(BMPImage, &size, BMPImageHeader);
// Verify Signature
if(BMPImageHeader->bfType != WIN_BITMAP_SIGNATURE)
{
// Signature not Matched
Print(L"Signature Not Matched!");
Print(L"BMP Type [ Signature ] : ", BMPImageHeader->bfType);
return NULL;
}
else
{
Print(L"Signature Found");
}
if(BMPImageHeader->biBitCount == 32)
{
Print(L"BMP 32 Bit");
BMPColorHeader* BmpColor;
SystemTable->BootServices->AllocatePool(EfiLoaderData, sizeof(BMPColorHeader), (void**)&BmpColor);
UINTN size = sizeof(BITMAP_HEADER);
BMPImage->Read(BMPImage, &size, BmpColor);
// Check Color Header
if(0x00ff0000 != BmpColor->red_mask || 0x000000ff != BmpColor->blue_mask || 0x0000ff00 != BmpColor->green_mask)
{
Print(L"Unexpected Color Format");
}
if(0x73524742 != BmpColor->color_space_type)
{
Print(L"Unexcepted Color Space Type : %d", BmpColor->color_space_type);
}
}
else
{
Print(L"BMP Not 32 Bit : %d", BMPImageHeader->biBitCount);
}
uint8_t* BMPData;
{
BMPImage->SetPosition(BMPImage, sizeof(BITMAP_HEADER));
SystemTable->BootServices->AllocatePool(EfiLoaderData, size, (void**)&BMPData);
BMPImage->Read(BMPImage, &size, BMPData);
}
BITMAP_IMG* finishedImage;
SystemTable->BootServices->AllocatePool(EfiLoaderData, sizeof(BITMAP_IMG), (void**)&finishedImage);
finishedImage->header = BMPImageHeader;
finishedImage->data = BMPData;
int offset = 0;
int channels = finishedImage->header->biBitCount / 8;
for (int i = 0; i < finishedImage->header->biHeight; i++)
{
for (int j = 0; j < finishedImage->header->biWidth; j++)
{
//// I thinks following are wrong
// Red
int red = finishedImage->data[offset] & 0xFF;
int green = finishedImage->data[offset+1] & 0xFF;
int blue = finishedImage->data[offset+2] & 0xFF;
int alpha = 0x00;
// I thinks CreateRGBA can be also wrong
int hex_calculated = createRGBA(red, green, blue, alpha);
// This function is surely right ; It takes color value as 0xFFFFFFFF
PlotPixel(120+i, 120+j, hex_calculated);
offset += 3;
}
}
return finishedImage;
}
can someone help me with my code? I was looking at it for like half a day and still cant find any seg fault... I think problem is somewhere where i allocate memory bcs i really dont understand what am i doing :D.
struct bmp_image* flip_horizontally(const struct bmp_image* image){
if(image == NULL || image->data == NULL || image->header == NULL){
return NULL;
}
struct bmp_image* new_image= calloc(1,sizeof(struct bmp_image));
new_image->header = calloc(1,sizeof(struct bmp_header));
new_image->header =image->header;
uint32_t height=image->header->height, width=image->header->width;
struct pixel* pixels = calloc(height*width,sizeof(struct pixel));
for (uint32_t y = 0; y<height; y++){
for(uint32_t z = 0, zz = width-1; z<width; z++, zz--){
pixels[(y*width)+zz]=image->data[(y*width)+z];
}
}
new_image->data=pixels;
return new_image;}
struct bmp_header{
uint16_t type; // "BM" (0x42, 0x4D)
uint32_t size; // file size
uint16_t reserved1; // not used (0)
uint16_t reserved2; // not used (0)
uint32_t offset; // offset to image data (54B)
uint32_t dib_size; // DIB header size (40B)
uint32_t width; // width in pixels
uint32_t height; // height in pixels
uint16_t planes; // 1
uint16_t bpp; // bits per pixel (1/4/8/24)
uint32_t compression; // compression type (0/1/2) 0
uint32_t image_size; // size of picture in bytes, 0
uint32_t x_ppm; // X Pixels per meter (0)
uint32_t y_ppm; // X Pixels per meter (0)
uint32_t num_colors; // number of colors (0)
uint32_t important_colors; // important colors (0)
} __attribute__((__packed__));
struct pixel {
uint8_t blue;
uint8_t green;
uint8_t red;
//uint8_t alpha;
} __attribute__((__packed__));
struct bmp_image {
struct bmp_header* header;
struct pixel* data; // nr. of pixels is `width` * `height`
};
I am writing code to generate monochrome bmp image out of array. there are plenty of tools to generate bmp to array but i want it in reverse way. i found lots of code but it was color image.
here is code i am trying...
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <malloc.h>
#define _height 64
#define _width 128
#define _bitsperpixel 1
#define _planes 1
#define _compression 0
#define _pixelbytesize _height*_width*_bitsperpixel/8
#define _filesize _pixelbytesize+sizeof(bitmap)
#define _xpixelpermeter 0x130B //2835 , 72 DPI
#define _ypixelpermeter 0x130B //2835 , 72 DPI
#define pixel 0x55
#pragma pack(push,1)
unsigned char arr[8192]={0};
typedef struct{
uint8_t signature[2];
uint32_t filesize;
uint32_t reserved;
uint32_t fileoffset_to_pixelarray;
} fileheader;
typedef struct{
uint32_t dibheadersize;
uint32_t width;
uint32_t height;
uint16_t planes;
uint16_t bitsperpixel;
uint32_t compression;
uint32_t imagesize;
uint32_t ypixelpermeter;
uint32_t xpixelpermeter;
uint32_t numcolorspallette;
uint32_t mostimpcolor;
} bitmapinfoheader;
typedef struct {
fileheader fileheader;
bitmapinfoheader bitmapinfoheader;
} bitmap;
#pragma pack(pop)
int main (int argc , char *argv[]) {
int i;
FILE *fp = fopen("test.bmp","wb");
bitmap *pbitmap = (bitmap*)calloc(1,sizeof(bitmap));
uint8_t *pixelbuffer = (uint8_t*)malloc(_pixelbytesize);
strcpy(pbitmap->fileheader.signature,"BM");
pbitmap->fileheader.filesize = _filesize;
pbitmap->fileheader.fileoffset_to_pixelarray = sizeof(bitmap);
pbitmap->bitmapinfoheader.dibheadersize =sizeof(bitmapinfoheader);
pbitmap->bitmapinfoheader.width = _width;
pbitmap->bitmapinfoheader.height = _height;
pbitmap->bitmapinfoheader.planes = _planes;
pbitmap->bitmapinfoheader.bitsperpixel = _bitsperpixel;
pbitmap->bitmapinfoheader.compression = _compression;
pbitmap->bitmapinfoheader.imagesize = _pixelbytesize;
pbitmap->bitmapinfoheader.ypixelpermeter = _ypixelpermeter ;
pbitmap->bitmapinfoheader.xpixelpermeter = _xpixelpermeter ;
pbitmap->bitmapinfoheader.numcolorspallette = 0;
fwrite (pbitmap, 1, sizeof(bitmap),fp);
for(i=0;i<8192;i++)
{
pixelbuffer[i] = arr[i];
}
// memset(pixelbuffer,pixel,_pixelbytesize);
fwrite(pixelbuffer,1,_pixelbytesize,fp);
fclose(fp);
free(pbitmap);
free(pixelbuffer);
}
i am giving bits per pixel is 1 bit (i want either black or white), and not sure about other parameters which has to be change.
if i use _bitsperpixel as 24 then it is working properly but if i assign as 1 then getting it is getting crashed..
When _bitsperpixel == 1, then _pixelbytesize == 1024. Your loop runs till 8192, thus writing beyond the allocated memory.
Depending on what you store in your arr, you should either reduce the number of iterations of the loop to _pixelbytesize, or convert your bytes in arr into bits:
for(int i = 0; i < _pixelbytesize; ++i)
{
uint8_t b = 0;
for(int j = 0; j < 8; ++j)
b |= arr[8*i + j] >> 7 << j;
pixelbuffer[i] = b;
}
Note that this is a simple code that works only for image widths that are divisible by eight.
I came across this, the C version of Bilinear interpolation. I can't figure out how to run it. I have an image called image_1.jpeg that I want to use...
It looks you just need to call scale(), but how exactly do you write the main() method to do that?
The Code ->
#include <stdint.h>
typedef struct {
uint32_t *pixels;
unsigned int w;
unsigned int h;
} image_t;
#define getByte(value, n) (value >> (n*8) & 0xFF)
uint32_t getpixel(image_t *image, unsigned int x, unsigned int y){
return image->pixels[(y*image->w)+x];
}
float lerp(float s, float e, float t){return s+(e-s)*t;}
float blerp(float c00, float c10, float c01, float c11, float tx, float ty){
return lerp(lerp(c00, c10, tx), lerp(c01, c11, tx), ty);
}
void putpixel(image_t *image, unsigned int x, unsigned int y, uint32_t color){
image->pixels[(y*image->w) + x] = color;
}
void scale(image_t *src, image_t *dst, float scalex, float scaley){
int newWidth = (int)src->w*scalex;
int newHeight= (int)src->h*scaley;
int x, y;
for(x= 0, y=0; y < newHeight; x++){
if(x > newWidth){
x = 0; y++;
}
float gx = x / (float)(newWidth) * (src->w-1);
float gy = y / (float)(newHeight) * (src->h-1);
int gxi = (int)gx;
int gyi = (int)gy;
uint32_t result=0;
uint32_t c00 = getpixel(src, gxi, gyi);
uint32_t c10 = getpixel(src, gxi+1, gyi);
uint32_t c01 = getpixel(src, gxi, gyi+1);
uint32_t c11 = getpixel(src, gxi+1, gyi+1);
uint8_t i;
for(i = 0; i < 3; i++){
//((uint8_t*)&result)[i] = blerp( ((uint8_t*)&c00)[i], ((uint8_t*)&c10)[i], ((uint8_t*)&c01)[i], ((uint8_t*)&c11)[i], gxi - gx, gyi - gy); // this is shady
result |= (uint8_t)blerp(getByte(c00, i), getByte(c10, i), getByte(c01, i), getByte(c11, i), gx - gxi, gy -gyi) << (8*i);
}
putpixel(dst,x, y, result);
}
}
source: https://rosettacode.org/wiki/Bilinear_interpolation#C
Your problem here is probably less so figuring out how to call scale, and more so figuring out how to load your images. I recommend the SOIL library, it handles most common formats and gets you the raw pixel data.
You'll also most likely need some function to create the actual image_t instances from the raw image. SOIL and other image libraries should be able to provide you the width and height, as well as some kind of byte or int array for the image itself. image_t appears to be row-major in your example, so something like this could work:
image_t to_image_t(int width, int height, unsigned char* data) {
image_t img = { malloc(sizeof(int) * width * height), width, height };
for (int i = 0; i < width * height; i ++) {
// You may need to fiddle with this based on your image's format
// and how you load it.
img->pixels[i] = (data[0] << 24)
| (data[1] << 16)
| (data[2] << 8)
| (data[3]);
}
return img;
}
Just remember to free your image's pixel data after you're done using it.
I'm trying to change a pixel from a picture (format bmp, 24 bits).
I have this 3 structures:
for file header:
#pragma pack(2)
typedef struct {
unsigned short int typeID;
unsigned int size;
unsigned short int reserved1, reserved2;
unsigned int offset;
}BITMAPFILEHEADER;
#pragma pack(0)
for information header:
typedef struct {
unsigned int headerSize;
signed int widthPixel, heightPixel;
unsigned short int colorPlanes;
unsigned short int bitsPerPixel;
unsigned int compressionMethod;
unsigned int imagesize;
signed int xResolution, yResolution; // pixel per meter
unsigned int nbColor;
unsigned int importantColor;
}BITMAPINFOHEADER;
for RGB color:
typedef struct {
unsigned char blue;
unsigned char green;
unsigned char red;
unsigned char reserved;
} RGBCOLOR;
Then the main code:
int main(void) {
BITMAPFILEHEADER fileHeader;
BITMAPINFOHEADER infoHeader;
FILE *inFileImage = NULL;
unsigned char *pBitsData = NULL;
int rowSize = 0;
int nImageSize = 0;
inFileImage = fopen("panda.bmp", "r+");
if (inFileImage == NULL)
{
fprintf(stderr, "Unable to open image");
return 0;
}
fread(&fileHeader, sizeof(BITMAPFILEHEADER), 1, inFileImage);
rewind(inFileImage);
pBitsData = (unsigned char *)calloc( fileHeader.size, sizeof(unsigned char) );
if( NULL == pBitsData )
{
printf("NO memory!!!!!\n");
}
else
{
fread(pBitsData, fileHeader.size * sizeof(unsigned char), 1, inFileImage);
memcpy(&fileHeader,pBitsData,sizeof(BITMAPFILEHEADER));
printf("Type ID: %x\n", fileHeader.typeID);
printf("File size: %d\n", fileHeader.size);
printf("Offset: %d\n", fileHeader.offset);
printf("**********************\n");
memcpy(&infoHeader, (pBitsData + sizeof(BITMAPFILEHEADER)), sizeof(BITMAPINFOHEADER));
printf("Header size: %u\n", infoHeader.headerSize);
printf("Width: %d\n", infoHeader.widthPixel);
printf("Height: %d\n", infoHeader.heightPixel);
printf("Nb planes: %d\n", infoHeader.colorPlanes);
printf("Bits per pixel: %d\n", infoHeader.bitsPerPixel);
printf("Compression method: %u\n", infoHeader.compressionMethod);
printf("Image size: %u\n", infoHeader.imagesize);
printf("Horizontal pixel per metre: %d\n", infoHeader.xResolution);
printf("Vertical pixel per metre: %d\n", infoHeader.yResolution);
printf("Number color in color table: %u\n", infoHeader.nbColor);
printf("Color important count: %u\n", infoHeader.importantColor);
printf("**********************\n");
rowSize = ((infoHeader.bitsPerPixel * infoHeader.widthPixel + 31) / 32) * 4;
printf("Row Size: %d\n", rowSize);
nImageSize = rowSize * abs(infoHeader.heightPixel);
printf("Pixel Array Size: %d\n", nImageSize);
printf("**********************\n");
RGBCOLOR* pixelData = (RGBCOLOR*)(pBitsData + fileHeader.offset);
// M is define with the value 5 - the 5 pixel from image
printf("Pixel %x, %x, %x\n", pixelData[M].blue, pixelData[M].green, pixelData[M].red);
//fseek(inFileImage, fileHeader.offset, SEEK_CUR);
//fread(pixelData, sizeof(RGBCOLOR), 1, inFileImage);
pixelData[M].red = 0x00;
pixelData[M].blue = 0xef;
pixelData[M].green = 0x00;
//memcpy((pBitsData + fileHeader.offset), &pixelData, sizeof(RGBCOLOR)); // <= here seems to be my problem
//fwrite(pixelData, sizeof(RGBCOLOR), 1, inFileImage); // how can i copy to image from a memory
printf("Pixel %x, %x, %x\n", pixelData[M].blue, pixelData[M].green, pixelData[M].red);
}
fclose(inFileImage);
if(NULL != pBitsData)
{
free(pBitsData);
}
return 0;
}
I want to change the 5th pixel from image (one of this: blue->red, green->blue, etc).
Can you show me where do i have mistakes in my code? And how can i change to work correctly my code? Thx
Edit:
instead of
RGBCOLOR* pixelData = (RGBCOLOR*)(pBitsData + fileHeader.offset);
// M is define with the value 5 - the 5 pixel from image
printf("Pixel %x, %x, %x\n", pixelData[M].blue, pixelData[M].green, pixelData[M].red);
//fseek(inFileImage, fileHeader.offset, SEEK_CUR);
//fread(pixelData, sizeof(RGBCOLOR), 1, inFileImage);
pixelData[M].red = 0x00;
pixelData[M].blue = 0xef;
pixelData[M].green = 0x00;
//memcpy((pBitsData + fileHeader.offset), &pixelData, sizeof(RGBCOLOR)); // <= here seems to be my problem
//fwrite(pixelData, sizeof(RGBCOLOR), 1, inFileImage); // how can i copy to image from a memory
printf("Pixel %x, %x, %x\n", pixelData[M].blue, pixelData[M].green, pixelData[M].red);
if i write
RGBCOLOR img;
fseek(inFileImage, fileHeader.offset, SEEK_SET);
img.blue = 0x00;
img.green = 0x00;
img.red = 0xff;
fwrite(&img, sizeof(RGBCOLOR), 1, inFileImage);
This will change the first pixel. But i want to copy in memory, and from there to change the pixel.
I use MinGW, so you'll need to change the #pragmas used for structure alignment.
Here's an all-in-one source that will
read an image
change a specified pixel
output the modified image to a new file
I haven't bothered with any error checking in the interests of brevity. I've tested it with a 24/32 bit images. It doesn't output a valid image when used with 32 bit images.
First, here's the before and after images. The image itself is 2x2 pixels, I've just shown it larger here for the sake of visibility.
Before:
After:
If you have a close look, you can see that the only byte different between the 2 images is the one at 0x3E in the file. We've changed a red pixel (00 00 FF) to a purple one (FF 00 FF). Since the image is a bottom-up one, the first 3 bytes of the pixel data are for the yellow pixel, the next 3 are for the blue one, 2 bytes of padding follows, then we have 3 for red, 3 for green and another 2 padding bytes.
Here's the code that made the change:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef WORD
#define WORD unsigned short
#endif
#ifndef DWORD
#define DWORD unsigned long
#endif
#ifndef BYTE
#define BYTE unsigned char
#endif
#ifndef LONG
#define LONG long
#endif
#define minGW 1
#ifdef minGW
#pragma pack(push,2)
#endif
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER,*LPBITMAPFILEHEADER,*PBITMAPFILEHEADER;
#ifdef minGW
#pragma pack(pop)
#endif
typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER,*LPBITMAPINFOHEADER,*PBITMAPINFOHEADER;
typedef struct tagRGBQUAD
{
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
} RGBQUAD,*LPRGBQUAD;
typedef struct tagBITMAPINFO
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO,*LPBITMAPINFO,*PBITMAPINFO;
typedef struct tagBITMAP
{
BITMAPINFOHEADER bmInfo;
unsigned char *pBits;
} BITMAP, *PBITMAP;
PBITMAP readBitmapFile(const char *filename)
{
FILE *fp;
PBITMAP result;
BITMAPFILEHEADER fileHeader;
BITMAPINFO bmpInfo;
fp = fopen(filename, "rb");
fread(&fileHeader, sizeof(BITMAPFILEHEADER), 1, fp);
fread(&bmpInfo, sizeof(BITMAPINFO), 1, fp);
fseek(fp, fileHeader.bfOffBits, SEEK_SET);
unsigned char *pBits = (unsigned char *)calloc(bmpInfo.bmiHeader.biSizeImage, sizeof(unsigned char) );
fread(pBits, sizeof(char), bmpInfo.bmiHeader.biSizeImage, fp);
fclose(fp);
result = (PBITMAP) calloc(1, sizeof(*result) );
memcpy(&result->bmInfo, &bmpInfo, sizeof(bmpInfo) );
result->pBits = pBits;
return result;
}
void saveBitmapFile(const char *filename, PBITMAP img)
{
FILE *fp;
BITMAPFILEHEADER fileHeader;
memset(&fileHeader, 0, sizeof(fileHeader));
fileHeader.bfType = 0x4d42; //'BM'
fileHeader.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);
fileHeader.bfSize = fileHeader.bfOffBits + (img->bmInfo.biSizeImage);
fp = fopen(filename, "wb");
fwrite(&fileHeader, sizeof(fileHeader), 1, fp);
fwrite(&img->bmInfo, sizeof(img->bmInfo), 1, fp);
fwrite(img->pBits, 1, img->bmInfo.biSizeImage, fp);
fclose(fp);
}
void myPixel(int x, int y, char r, char g, char b, PBITMAP image)
{
unsigned char *ptrToPixel;
int rowSize = ((image->bmInfo.biBitCount * image->bmInfo.biWidth + 31) / 32) * 4;
int curRow, bytesPerPixel;
if (image->bmInfo.biHeight < 0)
{
curRow = y;
}
else if (image->bmInfo.biHeight > 0)
{
curRow = (image->bmInfo.biHeight-1) - y;
}
bytesPerPixel = image->bmInfo.biBitCount / 8;
ptrToPixel = (curRow * rowSize) + (x*bytesPerPixel) + image->pBits;
ptrToPixel[0] = b;
ptrToPixel[1] = g;
ptrToPixel[2] = r;
}
int main()
{
PBITMAP inImage = readBitmapFile("colorTile.bmp");
myPixel(0,0, 255,0,255, inImage);
saveBitmapFile("colorTileOut.bmp", inImage);
}
EDIT:
After reading Can someone provide me a specification of 32 bit BMP image format? and https://forums.adobe.com/message/3272950#3272950 it seemed apparent that 32 bit bitmaps were using a V3 header - a header that includes 4 longs to specify the bitmask of each of the 4 channels. I've subsequently modified both the saveBitmapFile and myPixel routines and can confirm that the code now appears to function correctly with 32 bit bitmaps too.
void saveBitmapFile(const char *filename, PBITMAP img)
{
FILE *fp;
BITMAPFILEHEADER fileHeader;
unsigned long maskArray[] = {0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF};
memset(&fileHeader, 0, sizeof(fileHeader));
fileHeader.bfType = 0x4d42; //'BM'
fileHeader.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);
if (img->bmInfo.biBitCount == 32)
fileHeader.bfOffBits += sizeof(maskArray);
fileHeader.bfSize = fileHeader.bfOffBits + (img->bmInfo.biSizeImage);
fp = fopen(filename, "wb");
fwrite(&fileHeader, sizeof(fileHeader), 1, fp);
fwrite(&img->bmInfo, sizeof(img->bmInfo), 1, fp);
if (img->bmInfo.biBitCount == 32)
fwrite(&maskArray, sizeof(long), 4, fp);
fwrite(img->pBits, 1, img->bmInfo.biSizeImage, fp);
fclose(fp);
}
void myPixel(int x, int y, char r, char g, char b, PBITMAP image)
{
unsigned char *ptrToPixel;
int rowSize = ((image->bmInfo.biBitCount * image->bmInfo.biWidth + 31) / 32) * 4;
int curRow, bytesPerPixel;
if (image->bmInfo.biHeight < 0)
{
curRow = y;
}
else if (image->bmInfo.biHeight > 0)
{
curRow = (image->bmInfo.biHeight-1) - y;
}
bytesPerPixel = image->bmInfo.biBitCount / 8;
ptrToPixel = (curRow * rowSize) + (x*bytesPerPixel) + image->pBits;
if (image->bmInfo.biBitCount == 24)
{
ptrToPixel[0] = b;
ptrToPixel[1] = g;
ptrToPixel[2] = r;
}
else if (image->bmInfo.biBitCount == 32)
{
// ptrToPixel[0] = a;
ptrToPixel[1] = b;
ptrToPixel[2] = g;
ptrToPixel[3] = r;
}
}