VC++
Example: Quick
Draw Image Stretching Technique, StretchBlt
Dib
|
|
Andy McGovern
November 26, 2002
Overview
The ability to draw
an image on the screen
that is a different size than the original source image
is incredibly easy with Win32's GDI
StretchBlt function
and its variants. However, using StretchBlt
with large images,
especially with a large amount of stretch, is very slow.
Also, shrinking images with StretchBlt
often produces poor image
quality. This article provides some simple
techniques to get around the performance and image
quality limitations of StretchBlt.
The most aggravating
effect caused by the poor performance of StretchBlt
is to make scrolling very slow. If you call StretchBlt
to draw an image
each time the scroll bars are moved, you may be in for a
long wait. A simple solution is to only call StretchBlt
when the size of the image
actually needs to change. Instead of stretching each time
the image is drawn
to the screen, only stretch it when necessary and rely on BitBlt
(which is much faster) for the majority of your drawing.
The downside of this approach means storing a copy of the
stretched image in
memory as well as the original source image. Considering
the ever-present need for speed and these times of cheap
memory modules, making a copy seems very reasonable.
Image
quality (for shrinking) can be improved over using StretchBlt
by a simple image
sampling function. The DIBSection::Resize method samples
the source image to produce an image
of a different size. Unset the ALTERNATE_RESIZE_METHOD
define to see the difference between the sampling method
and StretchBlt.
An Outline of the
Approach
- Load an image from a
disk file and store the contents in a DIBSection
object.
- When the image size
changes, stretch the source image into another
DIBSection object.
- As the image is
scrolled or re-painted, simply BitBlt
the second DIBSection object.
A Code Sample that
Implements the Approach
void QSView::StretchImage(double scale_factor)
{
QSDoc * doc = GetDocument();
if (doc)
{
DIBSection * dib = doc->GetDIB();
if (dib && dib->IsCreated())
{
if (m_view_dib.IsCreated())
{
m_scale_factor = scale_factor;
if (m_scale_factor < 0.1) m_scale_factor = 0.1;
if (m_scale_factor > 2.0) m_scale_factor = 2.0;
unsigned long w = (int)(dib->Width()
* scale_factor + 0.50);
unsigned long h = (int)(dib->Height()
* scale_factor + 0.50);
m_size.cx = w;
m_size.cy = h;
#ifdef PRE_STRETCH_METHOD
if ((w != m_view_dib.Width()) ||
(h != m_view_dib.Height()))
{
m_view_dib.Close();
m_view_dib.Create(w,h,dib->GetBitCount());
if (m_view_dib.IsCreated())
{
StretchBlt((HDC)*m_view_dib.GetDC(),0,0,w,h,(HDC)
*dib->GetDC(),0,0,dib->Width(),
dib->Height(),SRCCOPY);
}
}
#endif
SetScrollSizes(MM_TEXT,m_size);
CClientDC dc(this);
CRect r;
GetClientRect(&r);
dc.PatBlt(0,0,r.Width()-1,r.Height()-1,WHITENESS);
ShowImage();
}
}
}
}
void QSView::ShowImage(void)
{
if (m_view_dib.IsCreated())
{
CClientDC dc(this);
CPoint sp = GetScrollPosition();
#ifdef PRE_STRETCH_METHOD
m_view_dib.Draw(&dc,sp.x,sp.y);
#else
StretchBlt((HDC)dc,0,0,m_size.cx,m_size.cy,
(HDC)*m_view_dib.GetDC(),
(int)(0.50 + sp.x/m_scale_factor),(int)
(0.5 + sp.y/m_scale_factor),
m_view_dib.Width(),m_view_dib.Height(),SRCCOPY);
#endif
}
}
Some Information About
the Sample Project
This article is NOT
intended to be the final word on image stretching for
Windows; it is merely one technique to make your apps
respond a little better.
The sample project has
several DEFINEs.
The PRE_STRETCH_METHOD
define can be turned off if you want to see the difference
between stretching each time and storing the stretched image.
The
ALTERNATE_RESIZE_METHOD define enables a sampling routine
for re-sizing the image, instead of StretchBlt.
The NO_FLICKER define
uses a client-window-sized DIB
to draw the image
to the screen. This reduces the flicker associated with
making the non-image areas white.
All three settings are
defined by default within the sample project.
A test image file was
included with the project; however, because of the small
size of the image it is difficult to see the speed
difference between the two methods. The project only
supports reading 24-bit BMP files.
Please do NOT post
comments about the project's inability to read other file
formats; this article is not about image file formats.
The sample project was
built using VC++6 on
NT4 SP6 using a 32-bit color setting.
Enjoy.
Downloads
Download
demo project - 212 Kb
|