Reputation: 1422
I am extremely new to manipulating bitmap data in C++, and I have a problem. I'm trying to follow this example from wikipedia. Here is the code I'm using:
#include <iostream>
#include <fstream>
#include <Windows.h>
using namespace std;
int main()
{
//fileheader
BITMAPFILEHEADER* bf = new BITMAPFILEHEADER;
bf->bfType = 66;
bf->bfSize = 70;
bf->bfOffBits = 54;
//infoheader
BITMAPINFOHEADER* bi = new BITMAPINFOHEADER;
bi->biSize = 40;
bi->biWidth = 2;
bi->biHeight = 2;
bi->biPlanes = 1;
bi->biBitCount = 24;
bi->biCompression = 0;
bi->biSizeImage = 16;
bi->biXPelsPerMeter = 2835;
bi->biYPelsPerMeter = 2835;
bi->biClrUsed = 0;
bi->biClrImportant = 0;
//image data
unsigned char* thedata = new unsigned char;
thedata[0] = 0;
thedata[1] = 0;
thedata[2] = 255;
thedata[3] = 255;
thedata[4] = 255;
thedata[5] = 255;
thedata[6] = 0;
thedata[7] = 0;
thedata[8] = 255;
thedata[9] = 0;
thedata[10] = 0;
thedata[11] = 0;
thedata[12] = 255;
thedata[13] = 0;
thedata[14] = 0;
thedata[15] = 0;
//dc
HDC dc = GetDC(NULL);
//bitmap info
BITMAPINFO* bmi = (BITMAPINFO*)bi;
//handle to bitmap
HBITMAP hbmp = CreateDIBitmap(dc, bi, CBM_INIT, thedata, bmi, DIB_RGB_COLORS);
//output to bmp....?
ofstream outFile;
outFile.open("outtestbmp.bmp");
outFile << hbmp;
outFile.close();
}
I've been searching Google for the past couple days trying to figure out how to get this done but I still can't seem to make it work.
This complies without errors, but the outtestbmp.bmp file in the end is unopenable. Are there any huge mistakes I'm making (probably dozens) that are preventing this from working? (I have high suspicions that using ofstream to output my bmp data is wrong).
EDIT: I've been told that setting bftype to 66 is wrong. What is the correct value?
Also, I've created a .bmp file of what the output should be. Here is the hex data for that bmp:
42 4D 46 00 00 00 00 00 00 00 36 00 00 00 28 00 00 00 02 00 00 00 02 00 00 00 01 00 18
00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF
FF FF 00 00 FF 00 00 00 FF 00 00 00
and here is the data for my .bmp I'm outputting:
42 00 46 00 00 00 CD CD CD CD 36 00 00 00 28 00 00 00 02 00 00 00 02 00 00 00 01 00 18
00 00 00 00 00 10 00 00 00 13 0B 00 00 13 0B 00 00 00 00 00 00 00 00 00 00 00 00 FF FF
FF FF 00 00 FF 00 00 00 FF 00 00 00
Upvotes: 0
Views: 4298
Reputation: 16582
bf->bfType == 66;
This is wrong on two counts. Firstly it's the wrong value (the magic value are the bytes 'BM' or 0x4d42 on a little-endian machine), and secondly it's not an assignment.
Then:
unsigned char* thedata = new unsigned char;
Only allocating 1 char?
And this:
outFile << hbmp;
Doesn't do what you think it does. You're just writing out a handle. You didn't need to create a bitmap, you just need to write out the data structures you've initialised (once you've made them correct).
And why are you new'ing everything? There's no need for this stuff to be dynamically allocated (and you're not delete'ing it either).
I would generally do it something like this (some code removed for brevity):
BITMAPFILEHEADER bf;
bf.bfType = 0x4d42;
bf.bfSize = 70;
bf.bfOffBits = 54;
//infoheader
BITMAPINFOHEADER bi;
bi.biSize = 40;
bi.biWidth = 2;
etc...
//image data
unsigned char* thedata = new unsigned char[16]; // Should really calculate this properly
thedata[0] = 0;
....
//output to bmp....?
ofstream outFile;
outFile.open("outtestbmp.bmp");
outFile.write((char *)&bf,sizeof(bf));
outFile.write((char *)&bi,sizeof(bi));
outFile.write((char *)thedata, 16);
outFile.close();
Upvotes: 3
Reputation: 129314
First, you need to allocate enough data for your pixels:
unsigned char* thedata = new unsigned char[2 * 2 * 3];
Then you need to use write
and open the file as binary
.
Instead of:
outFile.open("outtestbmp.bmp");
outFile << hbmp;
Something like:
outFile.open("outtestbmp.bmp", ios::binary||ios::out);
outfile.write(reinterpret_cast<char *>(bf), sizeof(BITMAPFILEHEADER));
outfile.write(reinterpret_cast<char *>(bi), sizeof(BITMAPINFOHEADER));
outfile.write(reinterpret_cast<char *>(thedata), 2 * 2 * 3);
outfile.close();
Upvotes: 0
Reputation: 1689
HBITMAP is a handle to a bitmap not an actual bitmap. The real bitmap is stored in Kernel memory. You don't need to make any calls to the GDI if you are just writing the bitmap to a file. Even if it was an actual bitmap cout would need an operator overload to actually write the memory structure to a file since it isn't stored in memory the same it is on disk.
All you need to do is write the BITMAPFILEHEADER to a file, then write the BITMAPINFOHEADER to the file, and then write the data (if we are talking RGB, non-indexed).
Here is more info on how bitmaps are actually stored on disk.
Reading a bitmap from a file is just same.
Upvotes: 1
Reputation: 7773
First you don't allocate enough memory for all your pixels, it should be something along the lines of
unsigned char* thedata = new unsigned char[numPixels * bytesPerPixel];
In your case, with a 2
by 2
picture and 24 bpp
(bits per pixel), you should allocate 12 bytes.
Each pixel will correspond to three bytes in a row for their red
, green
and blue
channel.
Note: I've never used Window's bitmap creation process but I worked with many libraries to manipulate images, including FreeImage
, SDL
and GD
Upvotes: 1