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

  1. Load an image from a disk file and store the contents in a DIBSection object.
  2. When the image size changes, stretch the source image into another DIBSection object.
  3. 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.

Downloads

Download demo project - 212 Kb



About the Author

Andy McGovern

Andy McGovern - Software Developer/Engineer. Special interests: astronomy, image processing, orbital mechanics, mathematics. Currently work at the Johns Hopkins University Applied Physics Laboratory on the science operations team for the CRISM instrument on the Mars Reconnaissance Orbiter.

Comments

  • Uncover the Very best Low Cost Louis Vuitton Purses - Locate Louis Vuitton Bags Cheap 1206d

    Posted by ibfnifiusu on 12/08/2012 01:38pm

    Louis vuitton for sale http://www.handbags-outlet.biz/#

    Reply
  • I require documentation

    Posted by Legacy on 03/13/2003 12:00am

    Originally posted by: gaurav gumber

    The code lacks proper documentation. If anyone can provide it to me, I'll be grateful. The email id is
    gaurav_gumber@rediffmail.com

    Reply
  • Weird display problem

    Posted by Legacy on 12/30/2002 12:00am

    Originally 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?

    Reply
  • The program doesn't last long

    Posted by Legacy on 12/25/2002 12:00am

    Originally 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.

    Reply
  • Great

    Posted by Legacy on 12/02/2002 12:00am

    Originally 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:00am

    Originally posted by: vibhavari

    your project is very good. but i want to open image files on static control in dialog based application. and according to the size of static  control image size changes.
    
    if u have solution please send me on patelvibha@rediffmail.com.
    eagarly waiting for positive reply.

    Reply
  • Why other than 24 bits /pixel image is not supported

    Posted by Legacy on 11/27/2002 12:00am

    Originally posted by: sikander Rafiq

    I have loaded an image which have 8 bits/pixel. So it is not loaded. I debug the appliaction u can't support other than 24 bits/pixel. Why it is.
    

    Reply
  • It seems u use memcpy to remake the bitmap image data directly

    Posted by Legacy on 11/26/2002 12:00am

    Originally 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.
    But your demo GUI contains very good dialog bar, thanks

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: December 18, 2014 The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this webcast and join industry experts as …

  • On-demand Event Event Date: October 29, 2014 It's well understood how critical version control is for code. However, its importance to DevOps isn't always recognized. The 2014 DevOps Survey of Practice shows that one of the key predictors of DevOps success is putting all production environment artifacts into version control. In this webcast, Gene Kim discusses these survey findings and shares woeful tales of artifact management gone wrong! Gene also shares examples of how high-performing DevOps …

Most Popular Programming Stories

More for Developers

RSS Feeds