Introduction
CDibData
is a class
used to
simplify
loading,
saving,
converting
(color-depth),
and
accessing
bitmap
image
bits. It was
originally
designed as
a utility
class to
allow direct
access to
the image
bits of a
bitmap
object. Upon
realizing
that it
would be a
useful
class, on
its' own, I
decided to
expand its'
abilities to
include:
loading,
saving,
and
conversion
of bitmaps.
The class
does not
require that
the bitmap
be
loaded
as a
DIBSECTION
in order to
be useful,
that was the
original
requirement
when it was
created.
I have also
included a
copy of
Quantize.cpp
by
Jeff Prosise;
Quantize.cpp
can be found
in the MFC
library for
those
interested
in reading
about it.
Ok after
reading this
article and
testing the
code: blast
me, find the
bugs, tell
me how to
improve the
code and/or
Doxygen
generated
documentation.
Do your best
to break the
code, even
you guys in
quality
control (who
specialize
in the
ridiculous).
If there is
some thing
wrong, I
want to
know!
Background
The main
references
used to
develop this
were
"Programming
Windows
Fifth
Edition" by
Charles
Petzold,
and the MFC
library.
Most of the
references
are listed
in
CDibData.cpp.
Using the
code
The
DIB
is stored
internally
in a single
block of
globally
allocated
memory
suitable for
transfer via
the
clipboard
using the
CF_DIB
format.
Since
CDibData
was not
designed as
a
replacement
for
CBitmap
,
it does not
maintain a
copy of the
original
bitmap
handle.
If you have
not
installed
the Windows
SDK from
Microsoft,
you will get
some
compilation
errors when
compiling in
debug mode.
The reason
for this is
that
BITMAPV5HEADER
was not
defined in
the SDK that
came with
Visual
C++
6.0. Since
BITMAPV5HEADER
is only used
for
displaying
debugging
information,
it should be
easy to
comment out
the code.
Note:
When an
CDibData
object
contains a
compressed
DIB, you no
longer have
direct
access to
the image
bits.
Therefore,
you can
save
the
DIB image to
file
but
not convert
it or use
any function
that
requires
direct
access to
the image
bits.
Examples of
how to
load a
bitmap file:
Collapse
Copy
Code
HBITMAP hBitmap = m_DibData.LoadDIB(lpszPathName);
if( !hBitmap )
return FALSE;
m_Bitmap.Attach(hBitmap);
Collapse
Copy
Code
HBITMAP hBitmap = (HBITMAP)::LoadImage(
NULL, lpszPathName, IMAGE_BITMAP,
0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);
if( !hBitmap )
return FALSE;
if( m_Bitmap.Attach(hBitmap) )
m_DibData.CreateDIB(&m_Bitmap);
Collapse
Copy
Code
try
{
CFile cf(lpszPathName, CFile::modeRead);
BITMAPFILEHEADER bmfh;
cf.Read((void*)&bmfh, sizeof(BITMAPFILEHEADER));
if( bmfh.bfType != 0x4D42 )
{
cf.Close();
return NULL;
}
DWORD dwLen = cf.GetLength() - sizeof(BITMAPFILEHEADER);
hDib = DibAlloc(dwLen);
pDib = DibLock(hDib);
if( pDib )
cf.Read((void*)pDib, (UINT)dwLen);
cf.Close();
if( !pDib )
{
if( hDib )
DibFree(hDib);
return NULL;
}
DibUnlock(hDib);
}
catch( CFileException* )
{
if( pDib )
DibUnlock(hDib);
if( hDib )
DibFree(hDib);
return NULL;
}
if( !Attach(hDib) )
{
DibFree(hDib);
return NULL;
}
Examples of
how to
save a
bitmap file:
Collapse
Copy
Code
m_DibData.CreateDIB.SaveDIB(lpszPathName);
Collapse
Copy
Code
m_DibData.CreateDIB.SaveDIB(lpszPathName, NULL, TRUE);
Collapse
Copy
Code
m_DibData.CreateDIB.SaveDIB(lpszPathName, &m_Bitmap);
Collapse
Copy
Code
m_DibData.CreateDIB.SaveDIB(lpszPathName, &m_Bitmap, TRUE);
Examples of
converting
from one
format to
another:
Collapse
Copy
Code
CDibData* pDibClass = m_DibData.GetConvertedDIB(wNewColorDepth);
Collapse
Copy
Code
CDibData* pDibClass = m_DibData.GetConvertedDIB(wNewColorDepth, TRUE);
Collapse
Copy
Code
CDibData ddObj;
ddObj.CreateDIB(&m_Bitmap);
CDibData* pDibClass = ddObj.GetConvertedDIB(wNewColorDepth, TRUE);
Example of
90 degree
rotation:
Collapse
Copy
Code
CDibData dibSrc;
if( !dibSrc.CreateDIB(&bmpSrc) )
return FALSE;
int x, y, t;
int cx = dibSrc.GetWidth();
int cy = dibSrc.GetHeight();
BOOL bResult = FALSE;
CBitmap bmpDest;
{
CDC dcDest;
dcDest.CreateCompatableDC(NULL);
CBitmap* pOldBitmap = dcDest.SelectObject(&bmpSrc);
BOOL bRet = bmpDest.CreateCompatibleBitmap(&dcDest, cy, cx);
dcDest.SelectObject(pOldBitmap);
dcDest.DeleteDC();
if( !bRet )
return bRet;
}
CDibData dibDest;
if( !dibDest.CreateDIB(&bmpDest) )
return FALSE;
if( nRotations == 0 )
{
for( x = 0; x < cx; ++x )
{
t = cy - 1;
for( y = 0; y < cy; ++y, --t )
dibDest.CopyPixelValue( t, x, dibSrc, x, y);
}
}
else
{
for( y = 0; y < cy; ++y )
{
t = cx - 1;
for( x = 0; x < cx; ++x, --t )
dibDest.CopyPixelValue(y, t, dibSrc, x, y);
}
}
if( !dibDest.SetDIBits(&bmpDest) )
return FALSE;
Points of
Interest
Some of you
may be
interested
in the
following:
-
Question:
What is
with the
style
used to
write
the
comments
proceeding
each
function?
-
Answer:
I
decided
to use
Doxygen
to
generate
documentation
for this
object.
I've
used it
before
to help
me
understand
other
peoples
code,
but
never to
create
accurate
documentation
of mine.
You will
find
Doxygen.dat
in the
CDibData
directory
used by
the
Doxygen
wizard
to
generate
documentation
for the
CDibData
class.
-
Question:
Can
GetDIBits()
be used
to
convert
bitmaps
from one
format
to
another?
-
Answer:
Yes, but
when
converting
to a
lower
color
depth
you
loose
important
color
information.
The
reason
for this
is that
GetDIBits()
does no
color
optimization.
-
Question:
Why use
CDibData::LoadDIB()
instead
of
LoadImage()
?
-
Answer:
CDibData::LoadDIB()
can load
top-down
bitmaps
and 2
bits-per-pixel
bitmaps,
LoadImage()
can not.
It is my
understanding
that
WinCE
supports
2
bits-per-pixel
(shades
of gray)
bitmaps
therefore,
I
decided
to
support
loading,
saving,
and
manipulation
of 2
bits-per-pixel
bitmaps.
Although
CDibData
recognizes
and can
manipulate
2
bits-per-pixel
bitmaps
it must
convert
it to 4
bits-per-pixel,
when
loading,
in order
to
create
an
HBITMAP
handle
that can
be used
by GDI
on
non-WinCE
devices
(a.k.a.
your
monitor).
-
Question:
Does
CDibData
support
WinCE?
-
Answer:
No,
although
CDibData
supports
2
bits-per-pixel
manipulation,
it is
designed
to work
on a PC.
The main
reason
for
supporting
2
bits-per-pixels
is that
some one
has to
create
the
bitmaps
used by
WinCE. I
would
also
like to
note
that
CDibData
does not
remember
the
original
format
of the
bitmap
that was
loaded
therefore,
you will
have to
convert
it back
to 2
bits-per-pixels
when
saving.
-
Question:
Does
CDibData
support
the
newest
bitmap
header
types?
-
Answer:
No,
CDibData
only
supports
DIBs
with a
BITMAPINFOHEADER
.
-
Question:
Why not
use
GetBitmapBits()
to get
access
to image
bits?
-
Answer:
See
Q131896
in the
MFC
library.