What I wanted to do was display a 256 color bitmap, which I have done.
But what I want to know about is the BITS of the bitmap. After I loaded
my bitmap, and pointed to the BITMAPINFO, I wasn't sure where
the BITS to the bitmap were. Based on a sample program,
I just assumed the bits were immediately AFTER the BITMAPINFO
strucutre and the RGBQUAD array. What I did was this.
lpBits = (LPSTR)BitmapInfo +
(WORD)BitmapInfo->bmiHeader.biSize +
sizeof(RGBQUAD) * 256; // 8-bit bitmap
using all 256 colors.
This works. But I had to take a leap of faith that the bits would be there.
Is
this how it is done for DIBS? Can I always assume the bits will
immeidately follow the BITMAPINFO data? Looking at documentation for DIBS,
it says that after
the BITMAPINFO there is an area of undefined data, THEN the BITS.
I'd appreciate any info in helping me understand this detail.
A DIB on disk is exactly the same as the CF_DIB clipboard format (with,
of course a "file header" at the start). You have three items stored
immediately following on from one another:
1. The BITMAPINFO structure.
2. (Perhaps) an RGBQUAD colour palette table.
3. The bitmap "bits" data.
Chris
----------------------------------------------------------------
Chris Marriott, Microsoft Certified Solution Developer.
SkyMap Software, U.K. e-mail: ch...@skymap.com
Visit our web site at http://www.skymap.com
I agree that the files & resources are structured as above. The
question concerns the 'hole' which may or may not appear
before the bits.
Various bits of documentation I've read indicate that the bits may
NOT be contiguous with the BITMAPINFO struct (which may
or may not include the RGBQUAD table).
Example 1:
The following appears in the FILE.C module of the DIBAPI.DLL that is
included with the WINCAP example:
"...
//If the bfOffBits field is non-zero, then the bits might *not* be
//directly following the color table in the file. Use the value in
//bfOffBits to seek the bits.
if (bmfHeader.bfOffBits != 0L)
_llseek(hFile, bmfHeader.bfOffBits, SEEK_SET)
..."
Example 2:
The following is a quote from ARTICLE.HLP from the SPRITES example:
"...
DIBs in memory
If you examine the file format structures carefully, you will see
that
the file header contains a pointer to the position of the image bits
within the file, implying that the block containing the bits need
not
be contiguous with the header. This is a convenience for the file
format but a nuisance for a memory image format ..."
Furthermore most of the other DIB reading code I've seen goes out
of its way to seek() directly to the bits, never assuming that they
immediately follow the BITMAPINFOHEADER struct.But of course,
when dealing with resource DIBs, you assume that LoadResource
gives you a handle to a contiguous block of bits. So if there is a
possibility that the bits are NOT contiguous in a *file*, why is this
not an issue for a *resource*?
The Resource Compiler strips off the BITMAPFILEHEADER,
so .bfOffBits is lost and you have no choice but to assume
that the bits are contiguous for a resource. Does RC or
LoadResource() re-align the bits (if necessary) so that they
*are* contiguous? I can't imagine either doing that. As one
other person points out, if you happen to have a DIB with
a 'hole' before the bits and you use it as a resource, you
are out of luck and it won't work.
I scanned a few hundred DIB/BMP on my disk and I couldn't
find a single file in which the bits were NOT contiguous with
the BITMAPINFOHEADER, i.e. in all cases the
BITMAPFILEHEADER.bfOffBits value was identical to:
sizeof(BITMAPINFO)+ncolour*sizeof(RGBQUAD)
where ncolour is either the default 2^n or as is contained
in BITMAPINFOHEADER.biClrUsed (or 0 for 24-bit).
I would like to see an example of a DIB that actually has
a 'hole' before the bits. I've never seen one and I don't
think they exist. Perhaps this is only for OS/2 DIBs
with BITMAPCORE<INFO HEADER>?
--
John A. Grant * I speak only for myself * (remove 'z' to reply)
Airborne Geophysics, Geological Survey of Canada, Ottawa
If you followup, please do NOT e-mail me a copy: I will read it here.
I strongly suspect that this is there from "prehistoric" times. A
*resource* DIB is documented to be in CF_DIB format, where the three
items are contiguous in memory; it's difficult to imagine any situation
in which a *file* DIB would have the "hole".
Pretty interesting. Jeez, John (Grant), you are diligent!
What Chris said reminds me of a quick question I had. In the
BITMAPFILEHEADER, there is the bfType field.
It says that this field must have the value BM. I presumed this was a
constant, but it is not defined in the header files.
As a quick fix, I just looked up the value from some bitmap files. They
were consistent, so I just used it.
What the documentation means is "BM" (2-byte string), not
a predefined constant BM.
BITMAPFILEHEADER bf;
bf.bfType=*(WORD *)"BM"; //copies first 2 bytes
Perhaps I better clarify that. "BM" is a 'char *' pointer, so you
cast it to 'WORD *', i.e. a pointer to a WORD. Then you just
dereference the WORD * pointer to retrieve the WORD to
which it points.
You might also be able to use:
bf.bfType='BM'; //2-character constant
but I don't know how portable that syntax is.
It doesn't need to be "defined". It's literally what it says - the ASCII
value 'BM'!
I'm writing a very simple Bitmap file loader. Since I have no formal
programming experience, I'm still
learning and thinking of ways to organize my code.
With reading in a .bmp file... I figured there had to be a simple way to
read the file, so
what I did was this.
// Open the file for reading.
fpBmp = fopen(szFileName,"rb");
// Determine the size of the file.
fileSize = _GetFileSize(fpBmp);
// Alloc. mem for the entire .bmp.
Dib.ptrRawData = (char *) malloc(fileSize);
// Read the entire .bmp file into memory.
bytesRead = fread(Dib.ptrRawData,
sizeof(char),
fileSize,fpBmp);
// Point to the file header.
Dib.ptrHeader = (BITMAPFILEHEADER*) Dib.ptrRawData;
// Point to the Bitmap Info.
Dib.ptrInfo = (BITMAPINFO*) (Dib.ptrRawData +
sizeof(BITMAPFILEHEADER));
// Point to the bits.
Dib.ptrBits = (char*) ( Dib.ptrRawData +
Dib.ptrHeader->bfOffBits );
fclose(fpBmp);
I took out any error checking code and stuff. This is the basic way I
loaded the .bmp.
Kinda curious if this is an acceptable way to do it?
Use GlobalAllocPtr() instead of malloc(). Eventually, you
will want to copy a DIB to the clipboard and the CF_DIB
clipboard format requires a handle to the packed DIB. Also,
if you're not aware of how the clipboard works, you should
know that once you pass the handle of your data (any type)
to the clipboard, you no longer own that handle and you're
not supposed to free it.
What does _GetFileSize() do? The size of the block that you
need to allocate is:
sizeof(BITMAPINFOHEADER) +
bih.biClrUsed*sizeof(RGBQUAD) +
bih.biSizeImage
where bih is BITMAPINFO * and bih.biClrUsed has already
been fixed up by you in case it was 0 (set it to 2^n).
You seem to be allocating enough memory to hold the
BITMAPFILEHEADER, but since that isn't part of the packed
DIB (CF_DIB) format, it's 'extra'. Just read it into a local
variable and discard it. You only need to check for 'BM'
and deal with bfOffBits for prehistoric files (as discussed
already).