- Creating a Bitmap-file in code
- Posted by R.Wieser on June 1st, 2008
Hello All,
I would like to be able to generate BMP-images containing simple graphics
and/or text.
I allso would like to be able to create those images with any color quantity
(from black-and-white upto 24 bits-per-color)
I've looked thru my information and googled the web, but I can't sem to be
able to find a good, simple example showing me how to do that *independant*
of the computers current settings. Most examples talk about DIBs, DDBs
selecting them in-and-outof DCs and whatnot. Due to a lack of explanation
to the different GDI functions I have little idea to what is done or why ...
Although I do have got several examples, they do seem to be quite
complicated for a simple task. Allmost more complicated than creating the
BMP-file myself ... :-\
The question therefore is :
1) How can I use the result of a CreateBitmap to draw upon (using
GDI-functions).
2) how can I save the result of the CreateBitmap function to a file (the
returned value is not a memory-pointer)
Regards,
Rudy Wieser
- Posted by David Jones on June 1st, 2008
R.Wieser <address@not.available> wrote...
You probably want to use a DIB Section for this since you can specify
the BITMAPINFO structure for it, which includes color, and it also lets
you easily get at the image bits in memory. You've probably also run
across GetDIBits, but you need a DDB for that, which means the original
image will be constrained by that machine's display device.
A device context is used to draw on something. In most cases, it draws
on the screen (display device) or to a printer, which is where the name
comes from. But, it can also be made to draw on a bitmap by using a
memory DC and selecting the bitmap into the DC.
There are two kinds of bitmaps: device-dependent (DDB) and device-
independent (DIB). The difference should be fairly self-explanatory:
DDBs are tied to the capabilities of the current display, whereas DIBs
aren't.
So, the standard code for this is:
/* Device contexts are either tied directly to a display device
(CreateDC) or are not tied to a display but merely "compatible" with
one. All that "compatible" means is that it's not incompatible. 
This will create a so-called "memory DC" that is compatible with the
current display, but it definitely does not have the same
characteristics of the display with respect to colors and dimensions. */
dc = CreateCompatibleDC(NULL);
/* Since the DC is not actually tied to the screen display, it has to
draw on *something*, so the system selects a 1x1 monochrome bitmap into
it to draw on. Needless to say, this is probably not what you want, so
you have to create a bitmap and select it into the device. Make sure
you do this first, since if you create any pens, brushes, etc., before
the bitmap is selected, those objects will be created as monochrome
since the DC is monochrome. */
bm = CreateDIBSection(dc, ..., pBits, ...);
oldbm = SelectObject(dc, bm);
/* Now, the DC is backed by the bitmap, so any drawing done with the DC
is applied to the bitmap. The DC has picked up the dimensions and color
depth of the bitmap that backs it. This is why, if you want the drawing
to be independent of the display, you should use a DIB and not a DDB. */
DrawSomethingOnMyDC(dc);
/* Make sure that GDI is finished writing to the DC before reading the
bits. */
GdiFlush();
/* Now, anything you've done to the DC will be reflected in the bitmap.
If you used a DIB Section, you get a pointer to the bits when you create
it, so all you have to do is write those bits out to a file (with the
appropriate header information). */
WriteToMyFile(headerInfo, pBits);
/* And, of course, when you're done, clean up. You probably don't want
to delete the bitmap while it's still selected in the device context
(what will the DC draw on?), so remove it by selecting the original
bitmap first. */
SelectObject(dc, oldbm);
DeleteObject(bm);
DeleteDC(dc);
Select it into a DC, then draw on the DC.
For DDBs, use GetDIBits. For DIB Sections, you get a pointer when you
create it.
HTH,
David
- Posted by R.Wieser on June 2nd, 2008
Hello David,
May I thank you for your thorough explanation to what needs to be done.
I have one question though : The CreateCompatibleDC function. I would never
have thought to use that for a DIB.
Could you tell me what it means that its able to create an independant
<something> to attatch the DIB to, but at the same time be "compatible" ?
It sounds to be contradictory.
Regards,
Rudy Wieser
David Jones <ncic@tadmas.com> schreef in berichtnieuws
MPG.22ac7e1494e7a82b9896eb@news.suddenlink.net...
- Posted by R.Wieser on June 2nd, 2008
Hello David,
David Jones <ncic@tadmas.com> schreef in berichtnieuws
MPG.22ac7e1494e7a82b9896eb@news.suddenlink.net...
<snip>
Another question if you don't mind : I've just looked at the
CreateDIBSection function, and more specific at the BITMAPINFOHEADER it
needs. In there I specify the width, height, number of planes(?) and
bits-per-color and color-table type. So far, so good.
But than something I do not understand : it allso asks for the *size* of the
image. From my POV that size could be calculated from the width, height,
etc.
Two questions:
1) Can I somehow tell the function to do the calculation for me (from the
allready available data), or if not what is the generic formule to do it
(funny: although it needs this value there is no description of how it
should be generated) ?
I'm sure I can come up with a way to do it too, but probably much more
complex than need be ...
2) Do you know any reason/usage to why I can specify too little or too much
space for the bitmap-bits ?
Regards,
Rudy Wieser
- Posted by Jerry Coffin on June 2nd, 2008
In article <4843cd62$0$3246$e4fe514c@dreader30.news.xs4all.nl >,
address@not.available says...
[ ... ]
Unless somebody has messed them up recently, the docs should point out
that the size member can be set to zero if you're dealing with a BI_RGB
bitmap. The size is needed only when you're dealing with a compressed
bitmap (in which case it cannot just compute the overall size from the
height and width).
--
Later,
Jerry.
The universe is a figment of its own imagination.
- Posted by David Jones on June 2nd, 2008
R.Wieser <address@not.available> wrote...
This is all a guess since I didn't come up with the term, but it seems
to me that you can tell what it means by comparing CreateDC and
CreateCompatibleDC. The first creates a DC for an actual device, and
the other creates a DC "compatible" with a device.
It's possible to take, say, a 256-color bitmap and blit it onto a 24-bit
color display -- it's just a simple color conversion. The same is true
for a 24-bit bitmap onto a 256-color display. It's a bit harder to blit
it onto a DC for, say, a plotter, since that's vector-based instead of
raster-based. (The docs for CreateCompatibleDC specify that it must be
a raster-based DC for that very reason.)
So, to me, it sounds like a compatible DC is merely one for which
calling BitBlt will work. That's the most common use for compatible
DCs: buffering a drawing to blit it all at once to the screen.
And the name also implies that it's not an exact copy either --
otherwise it might be named DuplicateDC. So some properties could be
different, such as dimensions and color.
David
- Posted by R.Wieser on June 2nd, 2008
Hello Jerry,
Thanks for the response.
Nope, not in in the "Win32 Programmer's Reference" I have (but its rather
old).
As so many times, I only after I posted my question and continued trying to
get it to work/figure it out I bumped into the different kinds of
compression.
And only much later I bumped into the DIBSECTION structure (which seems to
hold the size needed for the bitmap-bits, but which is not described, so I
have to make a guess :-\ ).
And as so often, it allso generated other questions : how do I know if the
bitmap-handle is coming off of a CreateDIBSection or from somewhere else.
And where is the color-table I created the bitmap with (Or: why do I have to
put it into a DC to be able to get them). And how do I retrieve the size
of the bitmap-bits if the bitmap-handle does *not* return a DIBSECTION (but
instead only BITMAP structure).
In short : just to many un-described/documented things :-(
Regards,
Rudy Wieser
Jerry Coffin <jcoffin@taeus.com> schreef in berichtnieuws
MPG.22ad9c719d5dfe3f989d04@news.sunsite.dk...
- Posted by R.Wieser on June 2nd, 2008
Hell David,
Thanks for your explanation. It looks as if I have to make do with it, as
I have no other explanation. :-)
Regards,
Rudy Wieser
David Jones <ncic@tadmas.com> schreef in berichtnieuws
MPG.22adb95a6257b92e9896ec@news.suddenlink.net...
- Posted by Scott McPhillips [MVP] on June 2nd, 2008
"R.Wieser" <address@not.available> wrote in message
news:4844100c$0$3296$e4fe514c@dreader28.news.xs4al l.nl...
It's not so much a matter of being undocumented as being highly flexible.
There are numerous bitmap formats and the DIB section and file format can
handle all of them. With different data members, and/or variable length
data members, being used for different formats.
When I first got into this stuff I found this CreateDIBSection sample
program highly useful. It does display and file read & write:
http://www.codeguru.com/cpp/g-m/bitm...cle.php/c1737/
--
Scott McPhillips [VC++ MVP]
- Posted by R.Wieser on June 2nd, 2008
Hello Scott,
Thanks for your reply.
:-) The second does not exclude the first. And that currently seems to be
my problem.
I've taken a look at the code there and at least something became clear to
me : a Create*DIB*Section does *not* return, nonwithstanding its name, a
handle to DIB at all, but instead a handle to a bitmap.
Another thing became clear to me : nonwithstanding the confusing naming a
DIB is nothing like a Bitmap, and neither looks a bitmap anything like a
BMP.
I think I'm going to look if I can create a true DIB, as that one seems to
be the easiest to save to a BMP. Though a quick look in my documents does
not show a CreateDIB command (returning a hDIB) though.
Regards,
Rudy Wieser
Scott McPhillips [MVP] <org-dot-mvps-at-scottmcp> schreef in berichtnieuws
GZKdnbXNNugOi9nVnZ2dnUVZ_jydnZ2d@comcast.com...
- Posted by David Jones on June 3rd, 2008
R.Wieser <address@not.available> wrote...
I don't understand what you mean here: a DIB *IS* a bitmap: Device-
Independent *Bitmap*. That's a bit like saying: "When I create a
multiline edit control, it actually gives me back a handle to an edit
control."
If you mean that a DIB is nothing like a DDB, I could understand what
you mean, but otherwise I'm lost.
Easier than a couple of writes? In the sample code that Scott pointed
out, it basically does:
BITMAPFILEHEADER hdr;
// m_DIBinfo is passed as an argument to CreateDIBSection
LPBITMAPINFOHEADER lpbi = (BITMAPINFOHEADER*) m_DIBinfo;
// color table size deduced from the BITMAPINFOHEADER
DWORD dwBitmapInfoSize = sizeof(BITMAPINFO) + m_iColorTableSize*sizeof
(RGBQUAD);
DWORD dwFileHeaderSize = dwBitmapInfoSize + sizeof(hdr);
hdr.bfType = DS_BITMAP_FILEMARKER;
hdr.bfSize = dwFileHeaderSize + lpbi->biSizeImage;
hdr.bfReserved1 = 0;
hdr.bfReserved2 = 0;
hdr.bfOffBits = dwFileHeaderSize;
file.Write(&hdr, sizeof(hdr));
file.Write(lpbi, dwBitmapInfoSize);
file.Write(m_ppvBits, lpbi->biSizeImage);
You fill out one structure, and then bulk write the two headers and the
buffer initialized by CreateDIBSection. I don't think there's any API
that will write a BMP all in one shot, so that's about as easy as it can
get.
David
- Posted by R.Wieser on June 3rd, 2008
Hello David,
Just like a square is a special kind of rectangle. :-)
Question : if a DIB is independant and a DBB dependant, what is a hBitmap
than ?
You see, I just used a CreateDIBSection, and it returned a hBitmap. Apart
from the functions name being *very* confusing to what its outputting, I had
to supply it with all kinds of data which leads me to believe that a bitmap
is independant too.
So, now I'm stuck. If a DIB is independant and a bitmap too, what is the
*difference* between them ?
Apart ofcourse from the question why MS found it prudent to give a
bitmap-returning function the name as if its returning a DIB ofcourse.
Nope. I do understand the difference between those two. :-)
FYI: I'm currently trying to find out how I can retrieve the color-table
from a hBitmap. I supplied them at creation (CreateDIBSection), so they
most be there. But where ?
Yes, that code works. But imagine that code being divided into a create
image, fill with info, write to file and destroy image functions. How many
pieces of duplicate information (in the structure you provided to the
CreateDIBSection, as well as in the returned bitmap) would you than be
carrying around ?
For the moment I'm going to assume that the info I can get from a hBitmap
using the GetObject call (returning a BITMAP (or DIBSECTION) structure )
will be enough to construct (default) BITMAPINFOHEADER and BITMAPFILEHEADER
structures. I'll have to think about the colors though ...
As I mentioned in my first post, I missing important information, which, at
times, gets at me. I feel like someone stumbling thru a forest at night : I
*think* I recognise things, but when I walk towards it I don't ...
Regards,
Rudy Wieser
David Jones <ncic@tadmas.com> schreef in berichtnieuws
MPG.22ae4d636020315e9896ed@news.suddenlink.net...
- Posted by Scott McPhillips [MVP] on June 3rd, 2008
"R.Wieser" <address@not.available> wrote in message
news:48450b57$0$3256$e4fe514c@dreader27.news.xs4al l.nl...
An opaque reference to either one. It simply tells any API which bitmap you
are referring to. You know what kind it is because you created it. The
system knows what kind it is because it knows how you created it.
If you pass a DIB section handle to an API that takes HBITMAP, that API
will, behind the scenes, convert the DIB as necessary for rendering on the
hardware. It's the essence of device-independence.
--
Scott McPhillips [VC++ MVP]
- Posted by R.Wieser on June 3rd, 2008
Hello Scott,
Thanks for your reply.
Alas, although you *seem* to be saying something, nothing of it is touching
my question. :-(
Actually, all I read is a vague "you know what they need because you created
it yourself" blurb, wich contradicts my question. I do *NOT* know.
Only my trying, trying-and-trying-again together with some lucky guesses
currently gets me get any kind of result. And thats not the way I want it
to go, because its *very* tyring and takes heaps of time.
So, if you know the difference between the two than please be so kind as to
tell me.
And, if you know, than please tell me why a GetDIBColorTable cannot use,
nonwithstanding their similarity in naming, simething a CreateDIBSection
outputs.
You see, I would currently like to be able to retrieve the color-table used
in creating a hBitmap -bitmap, but can't seem to find any such function,
although it *is* availabe for a DIB (how's that for at least *one*
difference ?) ...
Regards,
Rudy Wieser
Scott McPhillips [MVP] <org-dot-mvps-at-scottmcp> schreef in berichtnieuws
L6mdnYtEW98J19jVnZ2dnUVZ_sudnZ2d@comcast.com...
- Posted by Scott McPhillips [MVP] on June 3rd, 2008
"R.Wieser" <address@not.available> wrote in message
news:484585f5$0$3500$e4fe514c@dreader20.news.xs4al l.nl...
Conceptually, it does. One just has to select the DIB into a DC to access
the color table. Of course, if the DIB has a color table you created it, so
accessing it should be a non-problem.
Your question assumes that such a color table exists. It does only rarely
on obsolete hardware. When this was common it involved "palettes" and APIs
such as GetPaletteEntries. Nobody said this stuff is simple: It is complex
not only because of the many different ways to represent and render bitmaps,
but also because it is compatible all the way back to DOS-machines that
could only render 16 colors. Considering all that, it cannot be simple and
consistent. If you don't have a book, it would be a good idea to get one.
The MSDN documentation is not intended to be tutorial in nature.
--
Scott McPhillips [VC++ MVP]
- Posted by Jerry Coffin on June 4th, 2008
In article <484438ea$0$3502$e4fe514c@dreader25.news.xs4all.nl >,
address@not.available says...
[ ... ]
It returns a bitmap handle AND a pointer to memory that's device
independent (e.g. RGB triplets, even on something like a planar graphics
card).
--
Later,
Jerry.
The universe is a figment of its own imagination.
- Posted by R.Wieser on June 4th, 2008
Hello Scott,
You sound like you should be doing politics :-(
As far as I know a CreateDIBSection does not return a DIB, which means that
your above "explanation" again does not touch my question.
As long as I used a CreateDIBSection (defining less-or-equal to 256 colors)
and I provide such a color-table I must assume that it exists.
I have no idea what the users choice to use that little colors has to do
with hardware, new or old.
That "nobody" includes me, as I mentioned in my first post. Its allso why I
ask questions like "whats the difference between a DIB and Bitmap".
Hmmm ... I would have thought that the information (read:
function-specifications) available on the 'Net (Websites as well as
newsgroups like this one) would be all I would need
Worse : The definition of some of the commands is at best incomplete. Like,
to name one, for the above CreateDIBSection -functions BIMAPINFO structure
what the required fields are. :-(
Do you think that I would be able to find such information (authorative, no
mere guessing/experience) in a book ?
Regards,
Rudy Wieser
Scott McPhillips [MVP] <org-dot-mvps-at-scottmcp> schreef in berichtnieuws
Md6dnQrejL1pF9jVnZ2dnUVZ_ovinZ2d@comcast.com...
- Posted by R.Wieser on June 4th, 2008
Hello Jerry,
I know. MSDN told me.
So, why is it called "Create*DIB*section" when it doesn't return a DIB at
all (and neither can other DIB related commands be used on any of its
returned items) ?
Regards,
Rudy Wieser
Jerry Coffin <jcoffin@taeus.com> schreef in berichtnieuws
MPG.22afc80cd9e101cd989d08@news.sunsite.dk...
- Posted by Scott McPhillips [MVP] on June 4th, 2008
"R.Wieser" <address@not.available> wrote in message
news:48464bbf$0$3442$e4fe514c@dreader15.news.xs4al l.nl...
Highly authoritative:
"Windows Graphics Programming" by Feng Yuan
--
Scott McPhillips [VC++ MVP]