Quick Image Stretching Technique
Environment: C6, Win32
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);
// white out the screen before drawing image
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); // calls BitBlt
#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.

Comments
Uncover the Very best Low Cost Louis Vuitton Purses - Locate Louis Vuitton Bags Cheap 1206d
Posted by ibfnifiusu on 12/08/2012 01:38pmLouis vuitton for sale http://www.handbags-outlet.biz/#
ReplyI require documentation
Posted by Legacy on 03/13/2003 12:00amOriginally posted by: gaurav gumber
The code lacks proper documentation. If anyone can provide it to me, I'll be grateful. The email id is
Replygaurav_gumber@rediffmail.com
Weird display problem
Posted by Legacy on 12/30/2002 12:00amOriginally posted by: Kyoko
There seems to be some image display problem in the program. If you feed bmp files created through windows paint program or photoshop program, the image will be displayed sheered and black-whited. However, the images converted from jpg to bmp displayed correctly in the program. I don't see any differnce between the formats of the images. Does anybody have similar problems or could anyone explain what is happening here?
ReplyThe program doesn't last long
Posted by Legacy on 12/25/2002 12:00amOriginally posted by: Kyoko
You cannot run the program for a long time. If you open a big bitmap and playing around with it for a while, the following error message will come up:
Unhandled exception at 0x10006eec in QuickStretch.exe: 0xC0000005: Access violation reading location 0x10006eec.
I checked the code, but I could't find out what's wrong. Please help.
ReplyGreat
Posted by Legacy on 12/02/2002 12:00amOriginally posted by: Yves
Great, I like this code.
I'm wondering how hard it would be to implement anti-aliasing though ;) It sure would make the smaller images look nicer.
Reply
I want this in dialog based appliaction and image on static control
Posted by Legacy on 11/28/2002 12:00amOriginally posted by: vibhavari
ReplyWhy other than 24 bits /pixel image is not supported
Posted by Legacy on 11/27/2002 12:00amOriginally posted by: sikander Rafiq
ReplyIt seems u use memcpy to remake the bitmap image data directly
Posted by Legacy on 11/26/2002 12:00amOriginally posted by: ZHEFU ZHANG
But your implementation can not cope with 256 color bitmap for the code suppose each pixel use at least 1 byte.
ReplyBut your demo GUI contains very good dialog bar, thanks