Click here to Skip to main content
15,881,568 members
Articles / Desktop Programming / WTL
Article

A CWtlPicture Control Based on GDI+

Rate me:
Please Sign up or sign in to vote.
4.91/5 (16 votes)
11 Jul 2011CPOL4 min read 36.2K   2.6K   27   8
CWtlPicture attaches to an owner-drawn picture control and reads, displays, and saves disk or database images

Introduction

This is a graphics class written for Windows Template Library (WTL) that uses GDI+ to draw images on an owner-drawn picture (static) control. It supports bitmap, gif, jpeg, png and tif image formats and allows reading images from disk files, saving images to disk files in the same or different format, reading image or varbinary database columns, and writing database images in the same or different format.

WtlPictureSample.gif

Development Environment

This class is compatible with WTL 8.0 and the sample was created in Visual Studio 2008.

Background

CWtlPicture is designed to interface with a common Picture control with Type set to Owner Draw on an ordinary Windows dialog. A GDI+ Bitmap object is loaded with image data from disk or database and the GDI+ graphics object then draws upon the Picture control surface. Disk images are opened using CFileDialog with Bitmap::FromFile and saved using Bitmap::Save supplemented with Encoder selection logic capable of converting image type. In addition, there is an image scaling function as well as a helper class that implements an ISequentialStream for reading and writing OLE DB blob database columns.

The class can also be used in a standard view or other window by assigning the window handle to CWtlPicture and calling the Render() function from the window's OnPaint event handler.

Using GDI+

GDI+ is a Microsoft imaging library. The library and its header are added to the CWtlPicture source file and the library is started in the class constructor and stopped in the destructor.

CWtlPicture functionality

The code can open bitmap, gif, jpeg, png and tif images either from disk file or OLE DB compatible database. After loading, an image can be saved to disk or database in any of the 5 supported formats. However, image processing rules apply. Bitmaps and Jpegs do not support transparency, so they cannot be saved as gif, png or tif transparent image and transparency is lost when images are saved as Bitmaps or Jpegs. Also, GDI+ does not enable transparency even for image types that support it. For example, a gif image that is not transparent cannot be made transparent with a GDI+ function.

Using the Code without Database Support

If you don't need database support and only wish to work with disk files, comment out the #define __DATABASE_SUPPORT__ line in WtlPicture.h and the database-specific code sections will be ignored.

MainDlg additions

You need to add a picture control to your dialog using the resource editor. For simplicity, name the control IDC_PICTURE and set the Type to Owner Draw, then size the control to your desired dimensions. Using the scaling property (discussed later), you can control how the image is sized when displayed.

Next, add a member variable to MainDlg. For example, CWtlPicture m_odPicture;, and attach the picture control window handle in InitDialog like this: m_odPicture = GetDlgItem(IDC_PICTURE);.

After that, set up any desired command handlers such as file open and file save in your dialog's message map, and add a message handler for draw notifications: MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem). Finally, add event handlers for menu command and for drawing. The code for drawing is straightforward, as shown below.

// Message handler for drawing the image on the picture control
LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    if (IDC_PICTURE == wParam)
    {
        // Paint the background
        LPDRAWITEMSTRUCT lpDis = (LPDRAWITEMSTRUCT)lParam;
        ::GetClientRect(lpDis->hwndItem, &lpDis->rcItem);
        ::FillRect(lpDis->hDC, &lpDis->rcItem,
                        (HBRUSH)(COLOR_BTNFACE + 1));

        // Draw the image
        if (!m_odPicture.IsNull()) m_odPicture.Render();
    }
    else bHandled = FALSE;

    return 0;
}

Adding database support

To add database support to your project, you need to create an OLE DB consumer class for your data. There is a wizard available in Visual Studio Professional or higher that (mostly) automates this task. For Express versions of VS, you can download the Windows Driver Kit 7.1 to obtain ATL features. Once you've created your consumer class, you'll need to make a few changes to support image/varbinary operations. I've detailed the procedure in previous OLE DB articles.

After your consumer class is prepared, add a member variable for your table (for example, CProductionProductPhoto m_dbTable;) and command handlers for database operations. The sample project includes handlers for move next and previous and database read/write.

Note: MS Access stores images as embedded OLE objects. The Northwind database for SQL Server has similar OLE photo objects. The code in CWtlPicture DOES NOT read or write OLE objects. If you need to read OLE objects, you can use code something like this to skip over the 78 byte OLE header:

void SkipOleHeader(IStream* pstm, ULONG& ulStatus)
{
    LARGE_INTEGER liOffset = { 0, 0 };
    struct OLEOBJHDR { WORD Sig; WORD Size; } Hdr;

    // Set stream to 0 and load header structure
    pstm->Seek(liOffset, STREAM_SEEK_SET, NULL);
    pstm->Read(&Hdr, sizeof(Hdr), NULL);

    // Set stream past OLE bitmap header
    if (Hdr.Sig == 0x1C15 && Hdr.Size == 0x2F)
    {
        liOffset.QuadPart = Hdr.Size + 1 + 30;
        ulStatus = DBSTATUS_S_OLE;
    }
    pstm->Seek(liOffset, STREAM_SEEK_SET, NULL);
}

Properties

Get/SetScaleType - controls how the image is displayed in the picture control. Choices are Normal, AutoFit, Stretch and Zoom. AutoFit sizes the image to fit entirely within the picture control. Zoom allows a scaling factor to be set through the render function. Zoom factors less than 1.0 shrink the image (for example, 0.25 displays the image at 1/4 size) and greater than 1.0 expand the image.

About the Sample Application

The sample dialog application uses the Production.ProductPhoto table from the AdventureWorks database. You will need access to a database server with this databases to use the sample database functions or you can generate your own consumer class for your database table and add it to the project. You may also need to modify the connection string in the consumer classes to point to your database. It is currently set to localhost with integrated security.

License

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


Written By
Founder Choycer
United States United States
Ed has over 40 years experience in computer technology and a bachelor's degree in Business Administration. He's currently a marketing technology consultant. During his career, he's led software development departments and created software still in use in the communications and healthcare industries. Ed is a veteran of the United States Army. He lives in Arizona in the United States.

Find Ed on Linkedin.

This material is copyright 2019 by Ed Gadziemski. Unauthorized use is strictly prohibited. All rights reserved.

Comments and Discussions

 
Questioncan we use in MFC dialog-based app? Pin
Jason.LYJ22-Mar-16 4:27
professionalJason.LYJ22-Mar-16 4:27 
GeneralMessage Closed Pin
23-Oct-14 20:14
professionalmajid torfi23-Oct-14 20:14 
GeneralRe: My vote of 1 Pin
Ed Gadziemski24-Oct-14 6:57
professionalEd Gadziemski24-Oct-14 6:57 
Links are offered to source code and a Visual Studio project. The article does not offer a link to an EXE file. Perhaps you are unaware that computer viruses can be transmitted via EXE files. Because of that, I no longer include them in my Code Project articles. If you have a properly configured Visual Studio with WTL, you can safely compile the source code into an EXE.
GeneralRe: My vote of 1 Pin
Pete O'Hanlon25-Oct-14 9:15
mvePete O'Hanlon25-Oct-14 9:15 
GeneralRe: My vote of 1 Pin
majid torfi26-Oct-14 0:14
professionalmajid torfi26-Oct-14 0:14 
QuestionTiny Code Pin
Anima_in_Bofekor21-Mar-14 0:25
Anima_in_Bofekor21-Mar-14 0:25 
QuestionZoom Pin
Love In Snowing11-Jul-11 19:56
Love In Snowing11-Jul-11 19:56 
AnswerRe: Zoom [modified] Pin
Ed Gadziemski11-Jul-11 20:12
professionalEd Gadziemski11-Jul-11 20:12 

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

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