Click here to Skip to main content
15,885,366 members
Articles / Desktop Programming / MFC
Article

Thumbnails viewer and image processing using GDI+ and MFC

Rate me:
Please Sign up or sign in to vote.
4.93/5 (78 votes)
24 Sep 20034 min read 371.9K   24.8K   232   47
Using GDI+ and MFC to create a thumbnail image viewer and some processing functions

Image 1

Introduction

I want to propose an easy way to implement an image thumbnail viewer with some image processing functions incorporated using GDI+ in a regular MFC VC++ 6.0 application.

Background

The idea is to use only what is available in a standard Microsoft Windows environment and not using one of the many custom image libraries available.

Using the code

"ImageTool" application has an image viewer that displays thumbnail images available in a folder. This view window CImageToolView uses a CImageList object and is inherited from CListView class and contains the thread that loads the thumbnails. Also has a CFoldersDlg object used for browsing computer specific folders and another object CPreviewDlg used for previewing the selected image including the result on various image operations. Both objects are inherited from CDialog class.

After starting the application we have to select a folder and in the main view we will see thumbnail images if there are images available in that folder. Selecting an image from the thumbnail images list we can see the original into the preview dialog. By applying one of the image processing operations we can see the result also into the preview dialog. The basic image processing operations are: - Mirror, - Flip, - Rotate Right 90, - Rotate Left 90, - Grayscale, - Negative, - Pseudo Colors... (gamma value), - Pseudo Threshold... (transparency range), - Lighten, - Darken, - Contrast, - Sharpen. These operations are implemented into a separate thread found into the CImageToolDoc class. We have also "Undo/Redo" capabilities with the help of Bitmap::Clone( . ) function.

The images possible to be displayed are given by the graphics file formats supported by GDI+: - BMP (Windows bitmap), - EMF (Enhanced Metafile), - Exif (Exchangeable Image File), - GIF (Graphics Interchange Format), - Icon, - Indicates the JPEG (Joint Photographic Experts Group), - PNG (Portable Network Graphics), - TIFF (Tag Image File Format), - WMF (Windows Metafile), basically everything that can be loaded into a GDI+ Bitmap object.

Anyway we have to check always if we are dealing with a GDI+ valid image. This is very easy using Bitmap::GetFlags() function like:

////
BOOL CImageToolDoc::IsImageGDIPLUSValid( CString filePath )
{
  Bitmap image( filePath.AllocSysString() );
  if( image.GetFlags() == ImageFlagsNone ) return FALSE;
  else return TRUE;
}
/////

where ImageFlagsNone, part of the ImageFlags enumeration, means that no format information is available.

The point is that after selecting a folder (CImageToolDoc::SelectDirectory( . ) ) to load into the files' list (m_vFileName) to be displayed only the supported images including the image files having an altered extension. The RunLoadThumbnailThread thread loads the image files from this list using GDI+ Bitmap object.

The code here is not complicated but I just want to note that I don't use Image::GetThumbnailImage( . ) function to obtain the thumbnail image, instead I prefer to scale the bitmap myself. I am doing this not because I cannot use:

Bitmap *pThumbnail = (Bitmap*)image.GetThumbnailImage( nDestWidth, 
    nDestHeight, NULL, NULL );

but because I cannot deal directly with the background color how I want so anyway I have to use a GDI+ Graphics object created from the image like this:

Graphics *grPhoto = Graphics::FromImage( bmPhoto );
Color colorW(255, 255, 255, 255);
Clear( colorW );

And also I don’t want to deal with the embedded thumbnail image - if the file has one - because in this case GetThumbnailImage( . ) retrieves the embedded thumbnail image and doesn't create a thumbnail image by scaling the main image to the specified size.

On the end of the thread I have to fill the image list with MFC CBitmap objects obtained from the already scaled GDI+ Bitmap objects.

The second thread - the image processing thread - uses either direct GDI+ Bitmap image processing function (e.g. RotateFlip( . ) ) or a GDI+ Graphics object created from the image, associated with a GDI+ ColorMatrix structure and a GDI+ ImageAttributes object.

There are operations that are using hard-coded parameters and others - like gamma value and transparency range - that have an associated dialog to specify the parameters. This is just for demonstration purpose and can be improved further.

I have also a "Print Preview" capability provided by the CImageToolView::OnDraw( . ) but the "Print" function needs to be improved.

The CFoldersDlg object uses a CTreeCtrl derived control (CFoldersTreeCtrl) to facilitate the folder selection and CPreviewDlg object uses a CStatic object to display the image. In CPreviewDlg I use a memory device context object to eliminate flickering.

Conclusion

Please remember that this is only for demonstration purpose and to be used like a professional application has to be improved especially on the design level regarding validating and loading image files in a multithreading operation. Also "Save" and other functions should be added. Regards to Moah whose article "Thumbnails Viewer using ListCtrl" reminded me to write this paper. Good luck!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior) IBI Group
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
AnswerRe: How to convert CBitmap to GDI+ Bitmap Pin
21-Sep-04 10:45
suss21-Sep-04 10:45 
QuestionHow to save GDI+ bmp file as PDF File Format. Pin
pubududilena13-Jul-04 19:58
pubududilena13-Jul-04 19:58 
Generali need some help plz Pin
Member 41696021-Apr-04 22:06
Member 41696021-Apr-04 22:06 
Generalwork with paletised images in GDI+ Pin
ming6915-Apr-04 17:49
ming6915-Apr-04 17:49 
GeneralNice viewer too bad it crashes after 1 sec Pin
BRIAN BIRD24-Nov-03 14:36
BRIAN BIRD24-Nov-03 14:36 
GeneralRe: Nice viewer too bad it crashes after 1 sec Pin
Liviu Birjega25-Nov-03 4:26
Liviu Birjega25-Nov-03 4:26 
GeneralNice sample(wiith Thumbnail Viewer) Pin
sealchan4-Nov-03 20:39
sealchan4-Nov-03 20:39 
GeneralRe: Await your "Save" function! Pin
Liviu Birjega29-Sep-03 7:01
Liviu Birjega29-Sep-03 7:01 
1 – About Save As…
Sorry to say but it’s a fact:

From - Platform SDK: GDI+
“Using Image Encoders and Decoders
GDI+ provides the Image class and the Bitmap class for storing images in memory and manipulating images in memory. GDI+ writes images to disk files with the help of image encoders and loads images from disk files with the help of image decoders. An encoder translates the data in an Image or Bitmap object into a designated disk file format. A decoder translates the data in a disk file to the format required by the Image and Bitmap objects. GDI+ has built-in encoders and decoders that support the following file types:
· BMP
· GIF
· JPEG
· PNG
· TIFF
GDI+ also has built-in decoders that support the following file types:
· WMF
· EMF
· ICON “
So there are no encoders for wmf, exif or emf.

The ImageConverter C# sample paper says that
“You can OPEN any image file format from the ones specified by a group of properties of ImageFormat class:
Bmp - Bitmap image format (extension .bmp)
Emf - Enhanced Windows metafile image format
Exif - Exchangable Image Format
Gif - Graphics Interchange Format image format (extension .gif)
Icon - Windows icon image format (extension .ico)
Jpeg - Joint Photographic Experts Group image format (extensions .jpg, .jpeg)
MemoryBmp - Specifies a memory bitmap image format
Png - Specifies the W3C Portable Network Graphics image format (extension .png)
Tiff - Tag Image File Format (extension .tif)
Wmf - Windows metafile image format (extension .wmf)”

And nothing about saving operation

In the code for “Save As…” we have:
////
m_btnSaveAs.Text = "SaveAs...";
...........
m_cmbSaveAs.Items.Add("*.bmp");
m_cmbSaveAs.Items.Add("*.jpg");
m_cmbSaveAs.Items.Add("*.gif");
m_cmbSaveAs.Items.Add("*.tif");
..........
///////

and for “Open” we have:
//////
m_btnOpen.Text = "Open...";
.......
m_cmbOpen.Items.Add("*.bmp");
m_cmbOpen.Items.Add("*.jpg");
m_cmbOpen.Items.Add("*.gif");
m_cmbOpen.Items.Add("*.tif");
........
///////////
Again I don’t see any other file types.


2 - About GetEncoderClsid( . ):

I use like this:

HRESULT CMyClass::SomeFunc()
{
Status st;
CLSID jpgClsid;
Bitmap img( L"pic.jpg" );
GetEncoderClsid( L"image/jpeg", &jpgClsid );
st = img.Save(L"..\\\tmp.jpg", &jpgClsid, NULL);

if(st == Ok)
{
}
else
{
TRY
{
CFile::Remove(L"..\\tmp.jpg");
}
CATCH_ALL(e)
{
TRACE0("Warning: failed to delete file after failed SaveAs\n");
}
END_CATCH_ALL
}

return S_OK;
}

int CMyClass::GetEncoderClsid( const WCHAR* format, CLSID* pClsid )
{
UINT num = 0;
UINT size = 0;
ImageCodecInfo* pImageCodecInfo = NULL;
GetImageEncodersSize(&num, &size);
if(size == 0)
{
return -1;
}
pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if(pImageCodecInfo == NULL)
{
return -1;
}
GetImageEncoders(num, size, pImageCodecInfo);
for(UINT j = 0; j < num; ++j)
{
if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
{
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j; // Success
}
}
free(pImageCodecInfo);
return -1;
}
and is OK!


Regards,
Liviu;)
GeneralNice to see... Pin
Member 34642225-Sep-03 15:12
Member 34642225-Sep-03 15:12 
GeneralRe: Nice to see... Pin
Liviu Birjega25-Sep-03 18:10
Liviu Birjega25-Sep-03 18:10 

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.