Sign in to follow this  

Problem with creating bitmaps..?

This topic is 2632 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

This code creates an bitmap image, except it doesn't work.. The output image cannot be opened so i'm guessing i'm messing up the formatting.. But i can't figure out where..

Oh and, in the CreateBitmap function, i try to use a void pointer, except i get this error: error C2036: 'const void *' : unknown size
Why am i getting this error? It shows up at line 48:
bmpfile.write((char*)(&Data[i * Width - Width]), Width);

So i'm using a char pointer instead..


#include <iostream>
#include <windows.h>
#include <fstream>
using namespace std;

#include <iostream>
#include <windows.h>
#include <fstream>
using namespace std;

bool CreateBitmap(LPCSTR Name, int Width, int Height, UINT BitCount, const char* Data)
{
const short padding = 0x0000;

// Figure out how much padding is need per row
int padding_per_row = (4 - ((Width * BitCount / 8) % 4)) % 4;

// Create the Info Header data
BITMAPINFOHEADER info;

info.biSize = 40;
info.biWidth = Width;
info.biHeight = Height;
info.biPlanes = 1;
info.biBitCount = BitCount;
info.biCompression = 0;
info.biSizeImage = sizeof(Data) + sizeof(padding) * padding_per_row * Height;
info.biXPelsPerMeter = 0;
info.biYPelsPerMeter = 0;
info.biClrUsed = 0;
info.biClrImportant = 0;

// Create the File Header data
BITMAPFILEHEADER file;

file.bfType = 0x4D42;
file.bfSize = info.biSizeImage + sizeof(file) + sizeof(info);
file.bfReserved1 = 0;
file.bfReserved2 = 0;
file.bfOffBits = 54;

// Create and fill the .bmp file
ofstream bmpfile(Name, ios::out | ios::binary | ios::trunc);

if (bmpfile.is_open())
{
bmpfile.write((char*)&file, sizeof(file));
bmpfile.write((char*)&info, sizeof(info));

// First send in the pixel data, then the padding
for(int i = Height; i > 0; i--)
{
bmpfile.write((char*)(&Data[i * Width - Width]), Width);

for (int j = 0; j < padding_per_row; j++)
bmpfile.write((char*) &padding, 2);
}

return true;
}

return false;
}

int main()
{
char data [12] =
{
0xFF,0x00,0x00, 0x00,0xFF,0x00,
0x00,0x00,0xFF, 0xFF,0xFF,0xFF
};

if (!CreateBitmap("Image.bmp", 2, 2, 24, data))
cout << "Error" << endl;
}



Share this post


Link to post
Share on other sites
sizeof used on a pointer gives you the size of the pointer, not the size of the data the pointer points to. You can't do pointer arithmetic on a void pointer because void has no size.

Share this post


Link to post
Share on other sites
Why would you need or want or think of using sizeof() here?

The size of the bitmap is the padded width times the height. The padded width is the width plus the amount of padding. The width and height are passed as parameters and you have already calculated the padding at this point.

Share this post


Link to post
Share on other sites
Quote:
You can't do pointer arithmetic on a void pointer because void has no size.

Right. So what can i do? I notice that windows' version of CreateBitmap uses a void pointer...



Sorry, stupid mistake, but in my defence i haven't slept properly in ages ;)
Here's the updated code, reflecting what you all said.. (still not working)


#include <iostream>
#include <windows.h>
#include <fstream>
using namespace std;

bool CreateBitmap(LPCSTR Name, int Width, int Height, UINT BitCount, const char* Data)
{
const short padding = 0x0000;

// Figure out how much padding is need per row
int padding_per_row = (4 - ((Width * BitCount / 8) % 4)) % 4;

// Create the Info Header data
BITMAPINFOHEADER info;

info.biSize = 40;
info.biWidth = Width;
info.biHeight = Height;
info.biPlanes = 1;
info.biBitCount = BitCount;
info.biCompression = 0;
info.biSizeImage = (Width + padding_per_row) * Height;
info.biXPelsPerMeter = 0;
info.biYPelsPerMeter = 0;
info.biClrUsed = 0;
info.biClrImportant = 0;

// Create the File Header data
BITMAPFILEHEADER file;

file.bfType = 0x4D42;
file.bfSize = info.biSizeImage + sizeof(file) + sizeof(info);
file.bfReserved1 = 0;
file.bfReserved2 = 0;
file.bfOffBits = 54;

// Create and fill the .bmp file
ofstream bmpfile(Name, ios::out | ios::binary | ios::trunc);

if (bmpfile.is_open())
{
bmpfile.write((char*)&file, sizeof(file));
bmpfile.write((char*)&info, sizeof(info));

// First send in the pixel data, then the padding
for(int i = Height; i > 0; i--)
{
bmpfile.write((char*)(&Data[i * Width - Width]), Width);

for (int j = 0; j < padding_per_row; j++)
bmpfile.write((char*) &padding, 2);
}

return true;
}

return false;
}

int main()
{
char data [12] =
{
0xFF,0x00,0x00, 0x00,0xFF,0x00,
0x00,0x00,0xFF, 0xFF,0xFF,0xFF
};

if (!CreateBitmap("Image.bmp", 2, 2, 24, data))
cout << "Error" << endl;
}



Share this post


Link to post
Share on other sites
Your padding calculation is wrong; the amount of padding you calculate per row is a count of bytes, but your unit of padding is a short. Your unit of padding should be a byte, because it is quite possible to require 1 byte or 3 bytes of padding.

Share this post


Link to post
Share on other sites
Thanks for your help by the way

So i just replace
const short padding = 0x0000;
bmpfile.write((char*) &padding, 2);

with
const char padding = 0x0000;
bmpfile.write(&padding, 1); ?

Still not working.. Ugh!!

Share this post


Link to post
Share on other sites
You could skip the j loop and just have:

char Padding[3]={0,0,0};

bmpfile.write(padding, padding_per_row);

------------

However, there are a number of issues with your code. For a start you tell the bitmap size it is (Width + padding_per_row) * Height;

From MSDN, this member is measured as:

biSizeImage:
The size, in bytes, of the image.

You are passing it the number of pixels, not the number of bytes. (Hint: How many bytes per pixel do you have?)

This issue is repeated:

bmpfile.write((char*)(&Data[i * Width - Width]), Width);

All these 'widths' are assuming one byte per pixel

-----
info.biSize = 40;

Do not use 40. use sizeof(BITMAPINFOHEADER)

------

bfOffBits *may* be from the END of the BITMAPFILEHEADER not the start (I'm not sure)

-----

Regarding the use of void.
If you wish to accept a void * parameter you can then cast into a char *.

bool CreateBitmap(LPCSTR Name, int Width, int Height, UINT BitCount, const void * vpData)
{
cost char * Data=(char *)vpData;
//Now ready for use

However, this may be against convention.

Share this post


Link to post
Share on other sites
I fixed my code. It works for 24-bit formats only..

I can't get it to work with 8 bit!!! The code below is for 24-bit. To use 8-bit bitmaps, i change the width to 6 instead of 2, change the BitCount to 8 instead of 24 and i replace this line:

bmpfile.write((char*)(&Data[i * (Width * 3) - (Width * 3)]), Width * 3);

With:

bmpfile.write((char*)(&Data[i * Width - Width]), Width);

Won't work!! :(


#include <iostream>
#include <windows.h>
#include <fstream>
using namespace std;

bool CreateBitmap(LPCSTR Name, int Width, int Height, UINT BitCount, const char* Data, int DataSize)
{
const char padding = 0x0000;

// Figure out how much padding is need per row
int padding_per_row = (4 - ((Width * BitCount / 8) % 4)) % 4;

// Create the Info Header data
BITMAPINFOHEADER info;

info.biSize = sizeof(BITMAPINFOHEADER);
info.biWidth = Width;
info.biHeight = Height;
info.biPlanes = 1;
info.biBitCount = BitCount;
info.biCompression = 0;
info.biSizeImage = DataSize + (padding_per_row * Height * sizeof(padding));
info.biXPelsPerMeter = 0;
info.biYPelsPerMeter = 0;
info.biClrUsed = 0;
info.biClrImportant = 0;

// Create the File Header data
BITMAPFILEHEADER file;

file.bfType = 0x4d42;
file.bfSize = info.biSizeImage + sizeof(file) + sizeof(info);
file.bfReserved1 = 0;
file.bfReserved2 = 0;
file.bfOffBits = 54;

// Create and fill the .bmp file
ofstream bmpfile(Name, ios::out | ios::binary | ios::trunc);

if (bmpfile.is_open())
{
bmpfile.write((char*)&file, sizeof(file));
bmpfile.write((char*)&info, sizeof(info));

// First send in the pixel data, then the padding
for(int i = Height; i > 0; i--)
{
bmpfile.write((char*)(&Data[i * (Width * 3) - (Width * 3)]), Width * 3);

for (int j = 0; j < padding_per_row; j++)
{
bmpfile.write(&padding, 1);
}
}

return true;
}

return false;
}

int main()
{
char data [6] =
{
0,255,0, 255, 0, 0
};

if (!CreateBitmap("Image.bmp", 2, 1, 24, data, sizeof(data)))
cout << "Error" << endl;
}

Share this post


Link to post
Share on other sites
Why do you think it's not working?
How is a color represented in a 8 bit BMP format?
How is a color represented in your data? Are they the same? Nope. So can you just copy the whole stuff like that?

Nope.

Share this post


Link to post
Share on other sites
Quote:
I don't see you writing the palette information.

Palette information...?

Quote:

Why do you think it's not working?

I don't know, and that's not from lack of trying.

Quote:

How is a color represented in a 8 bit BMP format?

In one byte? having a value from 0 - 256

Quote:

How is a color represented in your data? Are they the same? Nope. So can you just copy the whole stuff like that?


eh, i use a char array, currently an array of 6 pixels.. And yes i can copy the whole stuff like that.. I really don't understand this question..

Share this post


Link to post
Share on other sites
EDIT: Aww.. too slow :(

A little googling gave me:

"In 8-bit mode every byte represents a pixel. The value points to an entry in the color table which contains 256 entries"

So, i'm supposed to create a color table? I'm assuming that's the palette you're talking about?

eh, is the color table supposed to be an array of 256 colours?

Share this post


Link to post
Share on other sites
Alright then. Just one last question ;)

To create this colour palette, do i just start outputting colour values after the headers?

for example,

// header
0x000000
0x000001
0x000002
.
.
. etc..?

// pixel info

The links don't say how to create the palette.. It does however say that i need to send in three colour values, RGB. So does that mean instead of Hexs i need to output 3 numbers per colour?

I realize you guys want to kill me, but i'd appreciate it if you could answer me :)

Share this post


Link to post
Share on other sites
I (for one at least) don't want to kill you. I just want to suggest (in my harsh way) that people should solve their problems for themselves. There are may specifications on the net and stuff. Or you could just try things out. I think it's faster than waiting for responses and far more useful/helpful in the long run. I learned that way. And now I can solve almost anything quickly, even if I'm thrown out in a cave with no net, just a notebook.

Share this post


Link to post
Share on other sites

This topic is 2632 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this