Click here to Skip to main content
Click here to Skip to main content

Plain C Resampling DLL

, 19 Dec 2007 CPOL
Rate this:
Please Sign up or sign in to vote.
A small DLL providing two functions to resample GDI-based bitmap
Screenshot -

Introduction

When I first saw Libor Tinka's great article on resampling Image Resizing - Outperform GDI+, I said to myself: "very good stuff indeed, I really need a similar tool for GDI based bitmaps."

The Library

Resample.dll is a small dynamic library that exports two resampling functions. The design aims to resemble the Win32 GDI API interface and behaviour.

The function scenario is simple: Suppose we have a GDI HBITMAP (for instance loaded from a file via LoadImage), say hBmp, whose size is w x h and we need to resize it to wNew x hNew without a big loss in image quality. We can accomplish the above task with just a call to the library provided function CreateResampledBitmap in the following way:

hBmpNew = CreateResampledBitmap(hdc, hBmp, wNew, hNew, STOCK_FILTER_LANCZOS8);

Note that (as with, for instance, GDI CreateCompatibleBitmap), the obtained handle must be deleted (via GDI DeleteObject) when it is no longer needed. The other exported function is CreateUserFilterResampledBitmap that allows the caller to provide a custom filter function pointer.

Acknowledgements

This article is based on Libor Tinka's one: Image Resizing - Outperform GDI+. I just ported his C# code to a pure C one (changing the algorithm a bit) and packaged it all inside a DLL. All stock filters are the ones used in the original article by Libor, that ultimately can be used as reference.

Background

A general understanding of Win32 GDI API is required to use the code. A slightly deeper understanding of GDI bitmaps and C language is needed in order to hack the library internals. To use custom filters, a familiarity with callback functions may help.

Sample resampling image, CP
Image downsampling example.


Sample resampling image, CP
The same image upsampled.

Library Reference

Since the library contains only two functions, I can give reference information in the classical GDI documentation style.

Resampling With Stock Filters

CreateResampledBitmap

The CreateResampledBitmap function creates a resampled bitmap compatible with the device that is associated with the specified device context. The resampling filter is chosen between available stock filters.

HBITMAP CreateResampledBitmap(
   HDC hdc,             // handle to DC
   HBITMAP hBmpSource,  // handle to original bitmap
   DWORD dwWidth,       // width of the resampled bitmap, in pixels
   DWORD dwHeight,      // height of the resampled bitmap, in pixels
   DWORD dwFilter       // index of the stock resampling filter used
);

Parameters

    hdc
        [in] Handle to a device context
    hBmpSource
        [in] Handle to the original bitmap
    dwWidth
        [in] Specifies the resampled bitmap width, in pixels
    dwHeight
        [in] Specifies the resampled bitmap height, in pixels
    dwFilter
        [in] Specifies the index of the stock resampling filter
        Can be one of the following values
        STOCK_FILTER_BELL
        STOCK_FILTER_BOX
        STOCK_FILTER_CATMULLROM
        STOCK_FILTER_COSINE
        STOCK_FILTER_CUBICCONVOLUTION
        STOCK_FILTER_CUBICSPLINE
        STOCK_FILTER_HERMITE
        STOCK_FILTER_LANCZOS3
        STOCK_FILTER_LANCZOS8
        STOCK_FILTER_MITCHELL
        STOCK_FILTER_QUADRATIC
        STOCK_FILTER_QUADRATICBSPLINE
        STOCK_FILTER_TRIANGLE

Return Values

If the function succeeds, the return value is the handle of the resampled bitmap. If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

  • dwWidth and dwHeight are clipped to the range 1-4096
  • dwFilter is wrapped around the available stock filter range (i.e. dwFilter=STOCK_FILTER_TRIANGLE+1 becomes dwFilter=STOCK_FILTER_BELL).

Resampling With Custom Filters

CreateUserFilterResampledBitmap

The CreateUserFilterResampledBitmap function creates a resampled bitmap compatible with the device that is associated with the specified device context. The resampling filter is provided by the caller.

HBITMAP CreateUserFilterResampledBitmap(
   HDC hdc,                     // handle to DC
   HBITMAP hBmpSource,          // handle to original bitmap
   DWORD dwWidth,               // width of the resampled bitmap, in pixels
   DWORD dwHeight,              // height of the resampled bitmap, in pixels
   double (*pCustomFilter)(double),    // custom filter function pointer
   double dRadius             // custom filter radius
);

Parameters

    hdc
        [in] Handle to a device context
    hBmpSource
        [in] Handle to the original bitmap
    dwWidth
        [in] Specifies the resampled bitmap width, in pixels
    dwHeight
        [in] Specifies the resampled bitmap height, in pixels
    pCustomFilter
        [in] Specifies the pointer to the custom filter function.
    dRadius
        [in] Radius of the custom filter.

Return Values

If the function succeeds, the return value is the handle of the resampled bitmap. If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

  • dwWidth and dwHeight are clipped to the range 1-4096
  • Radius should be the proper filter radius for the pCustomFilter function
  • Legal range for Radius is 0.0-16.0.

Using the Code

Project Setup

In order to use Resample.dll functions, the application must:

  1. Include Resample.h header file
  2. Link with Resample.lib file

This of course implies that Visual Studio Environment must be able to find both header and library file paths.

Using the library is quite straightforward, the following code snippet loads a bitmap from test.bmp file and resamples it using the BOX stock filter:

  ...
  // load the original bitmap
  hBmp = (HBITMAP) LoadImage( hInstance, _T("test.bmp"),
        IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
  if (! hBmp ) return FALSE;
  // create the 1024x768 resampled bitmap with stock filter
  hBmpResampled = CreateResampledBitmap(hdc, hBmp, 1024, 768, STOCK_FILTER_BOX);
  ...

The following one shows instead the use of a custom filter:

  ...
  // user-filter radius
  const double dRad = 3.0;
  ...
  // user-filter function
  double myFilter( double x)
  {
    if ( x < 0.0 ) x = -x;
    if (x < dRad) return (dRad * dRad - 2 * dRad * x + x * x);
    return 0.0;
  }
  ...
  // load the original bitmap
  hBmp = (HBITMAP) LoadImage( hInstance, _T("test.bmp"),
        IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
  if (! hBmp ) return FALSE;
  // create the 1024x768 resampled bitmap with user filter
  hBmpResampled = CreateUserFilterResampledBitmap(hdc, hBmp, 1024, 768, myFilter, dRad);
  ...

The created HBITMAP can be used (as any other valid bitmap handle) later on, inside the application WM_PAINT message handler as follows:

  // WM_PAINT message handler
  ...
  // hdc is the painting device context
  HDC hMemdc = CreateCompatibleDC(hdc);
  if (hMemDC)
  {
    HBITMAP hBmpOld = (HBITMAP) SelectObject(hMemdc, hBmpResampled);
    BitBlt(hdc, 0, 0, 1024, 768, hMemdc, 0, 0, SRCCOPY);
    SelectObject(hMemdc, hBmpOld);
    DeleteDC(hMemDC);
  }
  ...

The Test Application

I have included a test application project, namely ResampleTestApp. It allows the user to load a bitmap, then the loaded image is shown (using its original dimensions) inside the main window while its resampled twin is painted in a child window. The user can select filter type and scale (zoom) of the resampled bitmap. The application (standard C++ Windows app, no MFC), though very basic and rough, allows to try all filters on different images. The child window title bar shows some information about the occurred resampling:

Child window title bar image

Namely:

  • Name of the filter used
  • Effective size of the resampled image
  • Resampling effective scale
  • Elapsed time

The resampling effective scale may differ significantly with the requested one due to the constraints on the dimension range of the resampled bitmap (1-4096).

Be aware that the application naively creates a resampled bitmap with chosen scale, e.g. if you ask it a 4x of the original 1024 x 768 bitmap, it calls the resampling function even if the window itself is far smaller than 4096 x 3072 (on painting the image is centered and clipped) this can be a very time consuming task (especially with high quality filters like the Lanczos ones).

Points of Interest

I have modified the original Libor algorithm to:

  1. Reduce memory allocation/deallocation calls (memory is allocated in a big chunk)
  2. Avoid unnecessary memory transfer

The resulting function is a bit faster (trade-off: code is less clean...) than the original Libor one (BTW there is, of course, the 100% pure unmanaged code impact...). By design, the resampling happens on all of the RGBQUAD components. It is also worth noting that resampling intermediate results are held by unsigned char instead of unsigned short (used by Libor) this may degrade the quality but, as far as I can perceive, there is no significant effect.

History

  • 19th December, 2007: First release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

CPallini
Software Developer (Senior) AEM S.p.A.
Italy Italy




Debugging? Klingons do not debug. Our software does not coddle the weak. Bugs are good for building character in the user.
-- The Klingon programmer


Beelzebub for his friends [^].



Follow on   LinkedIn

Comments and Discussions

 
GeneralMy vote of 5 PinmvpSergey Alexandrovich Kryukov18-Sep-13 12:56 
QuestionImplementation problem PinmemberFlaviu228-Jun-13 2:56 
AnswerRe: Implementation problem PinmvpCPallini28-Jun-13 3:18 
GeneralRe: Implementation problem PinmemberFlaviu228-Jun-13 3:22 
AnswerRe: Implementation problem PinmvpCPallini28-Jun-13 12:21 
GeneralRe: Implementation problem PinmemberFlaviu230-Jun-13 22:43 
QuestionExtra functionality: resample filterout-out pixels Pinmemberradus21516-Feb-12 23:50 
AnswerRe: Extra functionality: resample filterout-out pixels PinmvpCPallini17-Feb-12 0:53 
GeneralRe: Extra functionality: resample filterout-out pixels Pinmemberradus21517-Feb-12 1:01 
GeneralLines in Resampled Images (Fix) Pinmemberjlpilkin3-Jun-11 21:44 
GeneralRe: Lines in Resampled Images (Fix) PinmvpCPallini4-Jun-11 0:24 
GeneralMy vote of 5 PinmemberNagy Vilmos13-May-11 5:30 
GeneralRe: My vote of 5 PinmvpCPallini23-May-11 7:34 
Answer11x speed improvement PinmemberGuilherme C. Hazan12-May-11 4:39 
GeneralRe: 11x speed improvement PinmvpCPallini12-May-11 6:57 
GeneralRe: 11x speed improvement Pinmemberguju17-May-11 4:36 
GeneralRe: 11x speed improvement PinmemberFlaviu210-Jul-13 0:33 
GeneralStride Pinmemberguju12-Apr-11 9:16 
GeneralRe: Stride PinmvpCPallini12-May-11 7:00 
GeneralRe: Stride Pinmemberguju17-May-11 4:35 
Perhaps an annotation to this.
Considerating the padding is not nescessary to the code the way it is now.
This is because of the 4 byte color width = no padding to 32 bit boundaries nescessary.
But if you make it work for other color width (for example 24 bit from DirectShow),
you will have to take padding into account.
But having a look at the code it seems to be A LOT of work to make it work for different
color widths. Much more than just a few change in the COLOR_COMPONENTS loops (as stated
in one of the earlier comments). It will mess up the tidy and clear code.
GeneralDoesn't seem to work with large images Pinmemberjlpilkin10-Mar-11 8:48 
GeneralRe: Doesn't seem to work with large images PinmvpCPallini10-Mar-11 9:06 
GeneralRe: Doesn't seem to work with large images PinmvpCPallini12-Mar-11 10:49 
GeneralRe: Doesn't seem to work with large images Pinmemberjlpilkin12-Mar-11 11:13 
GeneralRe: Doesn't seem to work with large images PinmvpCPallini12-Mar-11 11:58 
Question16bpp question PinmemberLetMeWorkAlone14-Jan-11 12:07 
AnswerRe: 16bpp question PinmvpCPallini14-Jan-11 12:24 
GeneralExcellent library, but blows up when called from my VS 2005 application. PinmemberLeifUK30-Dec-10 3:25 
GeneralRe: Excellent library, but blows up when called from my VS 2005 application. PinmvpCPallini30-Dec-10 4:09 
GeneralRe: Excellent library, but blows up when called from my VS 2005 application. PinmemberLeifUK30-Dec-10 4:38 
GeneralMy vote of 5 PinmemberHard Coder23-Mar-10 5:22 
GeneralRe: My vote of 5 PinmvpCPallini23-Mar-10 6:59 
GeneralResized 16-bit bitmap has horizontal and vertical gray ( or perhaps blue) lines PinmemberMember 33450956-Oct-09 5:09 
GeneralI am getting Unresolved external error! Pinmemberkapardhi11-May-09 3:29 
GeneralRe: I am getting Unresolved external error! PinmvpCPallini11-May-09 3:42 
GeneralNeed to support RGB images Pinmemberharry4fun14-Nov-08 1:59 
QuestionRe: Need to support RGB images PinmvpCPallini14-Nov-08 3:10 
AnswerRe: Need to support RGB images Pinmemberharry4fun16-Nov-08 20:28 
QuestionRe: Need to support RGB images PinmvpCPallini16-Nov-08 22:24 
AnswerRe: Need to support RGB images Pinmemberharry4fun16-Nov-08 23:15 
GeneralRe: Need to support RGB images PinmvpCPallini16-Nov-08 23:33 
GeneralRe: Need to support RGB images Pinmemberharry4fun17-Nov-08 19:54 
GeneralRe: Need to support RGB images PinmvpCPallini18-Nov-08 3:02 
GeneralRe: Need to support RGB images Pinmemberharry4fun19-Nov-08 0:14 
Questioncode not working properly in my vc++ application [modified] Pinmembermadhuri11-Jul-08 22:04 
QuestionRe: code not working properly in my vc++ application PinmvpCPallini1-Jul-08 22:37 
Answer[Message Deleted] Pinmembermadhuri11-Jul-08 23:07 
GeneralRe: code not working properly in my vc++ application PinmvpCPallini1-Jul-08 23:16 
GeneralRe: code not working properly in my vc++ application Pinmembermadhuri11-Jul-08 23:31 
GeneralRe: code not working properly in my vc++ application PinmvpCPallini1-Jul-08 23:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141223.1 | Last Updated 19 Dec 2007
Article Copyright 2007 by CPallini
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid