Problem with creating bitmaps..?

Started by
16 comments, last by SiCrane 13 years, 6 months ago
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), Width);</pre><br>So i'm using a char pointer instead..<br><br><!–STARTSCRIPT–><!–source lang="cpp"–><div class="source"><pre><br><span class="cpp-directive">#include</span> &lt;iostream&gt;<br><span class="cpp-directive">#include</span> &lt;windows.h&gt;<br><span class="cpp-directive">#include</span> &lt;fstream&gt;<br><span class="cpp-keyword">using</span> <span class="cpp-keyword">namespace</span> std;<br><br><span class="cpp-directive">#include</span> &lt;iostream&gt;<br><span class="cpp-directive">#include</span> &lt;windows.h&gt;<br><span class="cpp-directive">#include</span> &lt;fstream&gt;<br><span class="cpp-keyword">using</span> <span class="cpp-keyword">namespace</span> std;<br><br><span class="cpp-keyword">bool</span> CreateBitmap(LPCSTR Name, <span class="cpp-keyword">int</span> Width, <span class="cpp-keyword">int</span> Height, UINT BitCount, <span class="cpp-keyword">const</span> <span class="cpp-keyword">char</span>* Data)<br>{<br>	<span class="cpp-keyword">const</span> <span class="cpp-keyword">short</span> padding = 0x0000;<br><br>	<span class="cpp-comment">// Figure out how much padding is need per row</span><br>	<span class="cpp-keyword">int</span> padding_per_row = (<span class="cpp-number">4</span> - ((Width * BitCount / <span class="cpp-number">8</span>) % <span class="cpp-number">4</span>)) % <span class="cpp-number">4</span>;<br><br>	<span class="cpp-comment">// Create the Info Header data</span><br>	BITMAPINFOHEADER info;<br><br>	info.biSize = <span class="cpp-number">40</span>;<br>	info.biWidth = Width;<br>	info.biHeight = Height;<br>	info.biPlanes = <span class="cpp-number">1</span>;<br>	info.biBitCount = BitCount;<br>	info.biCompression = <span class="cpp-number">0</span>;<br>	info.biSizeImage = <span class="cpp-keyword">sizeof</span>(Data) + <span class="cpp-keyword">sizeof</span>(padding) * padding_per_row * Height;<br>	info.biXPelsPerMeter = <span class="cpp-number">0</span>;<br>	info.biYPelsPerMeter = <span class="cpp-number">0</span>;<br>	info.biClrUsed = <span class="cpp-number">0</span>;<br>	info.biClrImportant = <span class="cpp-number">0</span>;<br><br>	<span class="cpp-comment">// Create the File Header data</span><br>	BITMAPFILEHEADER file;<br><br>	file.bfType = 0x4D42;<br>	file.bfSize = info.biSizeImage + <span class="cpp-keyword">sizeof</span>(file) + <span class="cpp-keyword">sizeof</span>(info);<br>	file.bfReserved1 = <span class="cpp-number">0</span>;<br>	file.bfReserved2 = <span class="cpp-number">0</span>;<br>	file.bfOffBits = <span class="cpp-number">54</span>;<br><br>	<span class="cpp-comment">// Create and fill the .bmp file</span><br>	ofstream bmpfile(Name, ios::out | ios::binary | ios::trunc);<br>	<br>	<span class="cpp-keyword">if</span> (bmpfile.is_open())<br>	{<br>		bmpfile.write((<span class="cpp-keyword">char</span>*)&amp;file, <span class="cpp-keyword">sizeof</span>(file));<br>		bmpfile.write((<span class="cpp-keyword">char</span>*)&amp;info, <span class="cpp-keyword">sizeof</span>(info));<br><br>		<span class="cpp-comment">// First send in the pixel data, then the padding</span><br>		<span class="cpp-keyword">for</span>(<span class="cpp-keyword">int</span> i = Height; i &gt; <span class="cpp-number">0</span>; i–)<br>		{<br>			bmpfile.write((<span class="cpp-keyword">char</span>*)(&amp;Data), Width);<br><br>			<span class="cpp-keyword">for</span> (<span class="cpp-keyword">int</span> j = <span class="cpp-number">0</span>; j &lt; padding_per_row; j++)<br>				bmpfile.write((<span class="cpp-keyword">char</span>*) &amp;padding, <span class="cpp-number">2</span>);<br>		}<br><br>		<span class="cpp-keyword">return</span> <span class="cpp-keyword">true</span>;<br>	}<br><br>	<span class="cpp-keyword">return</span> <span class="cpp-keyword">false</span>;<br>}<br><br><span class="cpp-keyword">int</span> main()<br>{<br>	<span class="cpp-keyword">char</span> data [<span class="cpp-number">12</span>] = <br>	{<br>		0xFF,0x00,0x00,   0x00,0xFF,0x00,<br>		0x00,0x00,0xFF,   0xFF,0xFF,0xFF <br>	};	<br>	<br>	<span class="cpp-keyword">if</span> (!CreateBitmap(<span class="cpp-literal">"Image.bmp"</span>, <span class="cpp-number">2</span>, <span class="cpp-number">2</span>, <span class="cpp-number">24</span>, data))<br>		cout &lt;&lt; <span class="cpp-literal">"Error"</span> &lt;&lt; endl;<br>}<br><br><br><br></pre></div><!–ENDSCRIPT–> 
"Spending your life waiting for the messiah to come save the world is like waiting around for the straight piece to come in Tetris...even if it comes, by that time you've accumulated a mountain of shit so high that you're fucked no matter what you do. "
Advertisement
info->biSizeImage = sizeof(Data) + sizeof(padding) * padding_per_row * Height;

should be sizeof(Data) * .... Maybe??

Um, sizeof(Data) is suspicious too.
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.
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.
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), Width);<br><br>			<span class="cpp-keyword">for</span> (<span class="cpp-keyword">int</span> j = <span class="cpp-number">0</span>; j &lt; padding_per_row; j++)<br>				bmpfile.write((<span class="cpp-keyword">char</span>*) &amp;padding, <span class="cpp-number">2</span>);<br>		}<br><br>		<span class="cpp-keyword">return</span> <span class="cpp-keyword">true</span>;<br>	}<br><br>	<span class="cpp-keyword">return</span> <span class="cpp-keyword">false</span>;<br>}<br><br><span class="cpp-keyword">int</span> main()<br>{<br>	<span class="cpp-keyword">char</span> data [<span class="cpp-number">12</span>] = <br>	{<br>		0xFF,0x00,0x00,   0x00,0xFF,0x00,<br>		0x00,0x00,0xFF,   0xFF,0xFF,0xFF <br>	};	<br>	<br>	<span class="cpp-keyword">if</span> (!CreateBitmap(<span class="cpp-literal">"Image.bmp"</span>, <span class="cpp-number">2</span>, <span class="cpp-number">2</span>, <span class="cpp-number">24</span>, data))<br>		cout &lt;&lt; <span class="cpp-literal">"Error"</span> &lt;&lt; endl;<br>}<br><br><br><br></pre></div><!–ENDSCRIPT–> 
"Spending your life waiting for the messiah to come save the world is like waiting around for the straight piece to come in Tetris...even if it comes, by that time you've accumulated a mountain of shit so high that you're fucked no matter what you do. "
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.
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!!
"Spending your life waiting for the messiah to come save the world is like waiting around for the straight piece to come in Tetris...even if it comes, by that time you've accumulated a mountain of shit so high that you're fucked no matter what you do. "
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), Width);<br><br>All these 'widths' are assuming &#111;ne byte per pixel<br><br>—–<br>info.biSize = 40; <br><br>Do not use 40. use sizeof(BITMAPINFOHEADER)<br><br>——<br><br>bfOffBits *may* be from the END of the BITMAPFILEHEADER not the start (I'm not sure)<br><br>—–<br><br>Regarding the use of void.<br>If you wish to accept a void * parameter you can then cast into a char *.<br><br>bool CreateBitmap(LPCSTR Name, int Width, int Height, UINT BitCount, const void * vpData)<br>{<br>cost char * Data=(char *)vpData;<br>//Now ready for use<br><br>However, this may be against convention. <br>
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), Width * 3);<br><br>With:<br><br>bmpfile.write((char*)(&Data), Width);<br><br>Won't work!! :(<br><br><!–STARTSCRIPT–><!–source lang="cpp"–><div class="source"><pre><br><span class="cpp-directive">#include</span> &lt;iostream&gt;<br><span class="cpp-directive">#include</span> &lt;windows.h&gt;<br><span class="cpp-directive">#include</span> &lt;fstream&gt;<br><span class="cpp-keyword">using</span> <span class="cpp-keyword">namespace</span> std;<br><br><span class="cpp-keyword">bool</span> CreateBitmap(LPCSTR Name, <span class="cpp-keyword">int</span> Width, <span class="cpp-keyword">int</span> Height, UINT BitCount, <span class="cpp-keyword">const</span> <span class="cpp-keyword">char</span>* Data, <span class="cpp-keyword">int</span> DataSize)<br>{<br> <span class="cpp-keyword">const</span> <span class="cpp-keyword">char</span> padding = 0x0000;<br><br> <span class="cpp-comment">// Figure out how much padding is need per row</span><br> <span class="cpp-keyword">int</span> padding_per_row = (<span class="cpp-number">4</span> - ((Width * BitCount / <span class="cpp-number">8</span>) % <span class="cpp-number">4</span>)) % <span class="cpp-number">4</span>;<br><br> <span class="cpp-comment">// Create the Info Header data</span><br> BITMAPINFOHEADER info;<br><br> info.biSize = <span class="cpp-keyword">sizeof</span>(BITMAPINFOHEADER);<br> info.biWidth = Width;<br> info.biHeight = Height;<br> info.biPlanes = <span class="cpp-number">1</span>;<br> info.biBitCount = BitCount;<br> info.biCompression = <span class="cpp-number">0</span>;<br> info.biSizeImage = DataSize + (padding_per_row * Height * <span class="cpp-keyword">sizeof</span>(padding));<br> info.biXPelsPerMeter = <span class="cpp-number">0</span>;<br> info.biYPelsPerMeter = <span class="cpp-number">0</span>;<br> info.biClrUsed = <span class="cpp-number">0</span>;<br> info.biClrImportant = <span class="cpp-number">0</span>;<br><br> <span class="cpp-comment">// Create the File Header data</span><br> BITMAPFILEHEADER file;<br><br> file.bfType = 0x4d42;<br> file.bfSize = info.biSizeImage + <span class="cpp-keyword">sizeof</span>(file) + <span class="cpp-keyword">sizeof</span>(info);<br> file.bfReserved1 = <span class="cpp-number">0</span>;<br> file.bfReserved2 = <span class="cpp-number">0</span>;<br> file.bfOffBits = <span class="cpp-number">54</span>;<br><br> <span class="cpp-comment">// Create and fill the .bmp file</span><br> ofstream bmpfile(Name, ios::out | ios::binary | ios::trunc);<br> <br> <span class="cpp-keyword">if</span> (bmpfile.is_open())<br> {<br> bmpfile.write((<span class="cpp-keyword">char</span>*)&amp;file, <span class="cpp-keyword">sizeof</span>(file));<br> bmpfile.write((<span class="cpp-keyword">char</span>*)&amp;info, <span class="cpp-keyword">sizeof</span>(info));<br><br> <span class="cpp-comment">// First send in the pixel data, then the padding</span><br> <span class="cpp-keyword">for</span>(<span class="cpp-keyword">int</span> i = Height; i &gt; <span class="cpp-number">0</span>; i–)<br> {<br> bmpfile.write((<span class="cpp-keyword">char</span>*)(&amp;Data), Width * <span class="cpp-number">3</span>);<br><br> <span class="cpp-keyword">for</span> (<span class="cpp-keyword">int</span> j = <span class="cpp-number">0</span>; j &lt; padding_per_row; j++)<br> {<br> bmpfile.write(&amp;padding, <span class="cpp-number">1</span>);<br> }<br> }<br><br> <span class="cpp-keyword">return</span> <span class="cpp-keyword">true</span>;<br> }<br><br> <span class="cpp-keyword">return</span> <span class="cpp-keyword">false</span>;<br>}<br><br><span class="cpp-keyword">int</span> main()<br>{<br> <span class="cpp-keyword">char</span> data [<span class="cpp-number">6</span>] = <br> {<br> <span class="cpp-number">0</span>,<span class="cpp-number">255</span>,<span class="cpp-number">0</span>, <span class="cpp-number">255</span>, <span class="cpp-number">0</span>, <span class="cpp-number">0</span><br> }; <br> <br> <span class="cpp-keyword">if</span> (!CreateBitmap(<span class="cpp-literal">"Image.bmp"</span>, <span class="cpp-number">2</span>, <span class="cpp-number">1</span>, <span class="cpp-number">24</span>, data, <span class="cpp-keyword">sizeof</span>(data)))<br> cout &lt;&lt; <span class="cpp-literal">"Error"</span> &lt;&lt; endl;<br>}<br><br></pre></div><!–ENDSCRIPT–>
"Spending your life waiting for the messiah to come save the world is like waiting around for the straight piece to come in Tetris...even if it comes, by that time you've accumulated a mountain of shit so high that you're fucked no matter what you do. "
I don't see you writing the palette information.

This topic is closed to new replies.

Advertisement