
Introduction
There are several image libraries and sources currently available. So I made my mind up to make a free Image Viewer using a free image library, and I got many free demo programs. I think a good image viewer must be able to show thumbnail images in a selected directory. I found some sources showing thumbnails, but they didn't support several formats, only BMP files. This thumbnail viewer is based on CxImage, so if there is an image format supported by CxImage, this viewer also supports that format.
Implementation
I want to show you the core part in this article. How to make a CListCtrl, CImageList, and then how to load images and attach that image to an ImageList.
1. Creating CListCtrl and CImageList
I used a CListView instead of CListCtrl, but you know that CListView uses CListCtrl internally. So overriding Create(...) will make your icon view CListCtrl initially. And then on OnInitialUpdate(), make ImageList which can support 24 bit color images and attach to CListCtrl.
return CListView::Create(lpszClassName, _T("ListView"),
dwStyle|LVS_SHOWSELALWAYS|LVS_ALIGNTOP|LVS_ICON|LVS_SINGLESEL|
LVS_AUTOARRANGE, rect, pParentWnd, nID, pContext);
....
m_ImageListThumb.Create(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, ILC_COLOR24, 0, 1);
ListCtrl.SetImageList(&m_ImageListThumb, LVSIL_NORMAL);
2. Load Images and Insert Items
Create a Compatible DC and a Bitmap Handle. Stretch a loaded image to the Bitmap Handle and then attach it to CBitmap. Finally, replace CBitmap with an image in the ImageList.
unsigned __stdcall CThumbViewerView::LoadThumbNail(LPVOID lpParam)
{
CThumbViewerView* pView=(CThumbViewerView*)lpParam;
CThumbViewerDoc* pDoc=pView->GetDocument();
CListCtrl& ListCtrl=pView->GetListCtrl();
CImageList* pImgList=&pView->m_ImageListThumb;
for(int i=0; i<pImgList->GetImageCount(); i++)
pImgList->Remove(i);
ListCtrl.DeleteAllItems();
pImgList->SetImageCount(pDoc->m_vFileName.size());
char path[MAX_PATH];
vector<CString>::iterator iter;
ListCtrl.SetRedraw(FALSE);
int nIndex=0;
for(iter=pDoc->m_vFileName.begin();
iter!=pDoc->m_vFileName.end() && pView->m_bTerminate!=true;
iter++, nIndex++)
{
ListCtrl.InsertItem(nIndex, *iter, nIndex);
}
ListCtrl.SetRedraw(TRUE);
ListCtrl.Invalidate();
HBRUSH hBrushBorder=::CreateSolidBrush(RGB(192, 192, 192));
HBRUSH hBrushBk=::CreateSolidBrush(RGB(255, 255, 255));
RECT rcBorder;
rcBorder.left=rcBorder.top=0;
rcBorder.right=THUMBNAIL_WIDTH;
rcBorder.bottom=THUMBNAIL_HEIGHT;
const float fRatio=(float)THUMBNAIL_HEIGHT/THUMBNAIL_WIDTH;
int XDest, YDest, nDestWidth, nDestHeight;
nIndex=0;
for(iter=pDoc->m_vFileName.begin();
iter!=pDoc->m_vFileName.end() && pView->m_bTerminate!=true;
iter++, nIndex++)
{
sprintf(path, "%s\\%s", pDoc->m_strCurrentDirectory, *iter);
int nImageType=pDoc->GetTypeFromFileName(path);
if(nImageType==CXIMAGE_FORMAT_UNKNOWN)
continue;
CxImage image(path, nImageType);
if(image.IsValid()==false)
continue;
const float fImgRatio=(float)image.GetHeight()/image.GetWidth();
if(fImgRatio > fRatio)
{
nDestWidth=THUMBNAIL_HEIGHT/fImgRatio;
XDest=(THUMBNAIL_WIDTH-nDestWidth)/2;
YDest=0;
nDestHeight=THUMBNAIL_HEIGHT;
}
else
{
XDest=0;
nDestWidth=THUMBNAIL_WIDTH;
nDestHeight=THUMBNAIL_WIDTH*fImgRatio;
YDest=(THUMBNAIL_HEIGHT-nDestHeight)/2;
}
CClientDC cdc(pView);
HDC hDC=::CreateCompatibleDC(cdc.m_hDC);
HBITMAP bm = CreateCompatibleBitmap(cdc.m_hDC, THUMBNAIL_WIDTH,
THUMBNAIL_HEIGHT);
HBITMAP pOldBitmapImage = (HBITMAP)SelectObject(hDC,bm);
::FillRect(hDC, &rcBorder, hBrushBk);
image.Stretch(hDC, XDest, YDest, nDestWidth, nDestHeight);
::FrameRect(hDC, &rcBorder, hBrushBorder);
SelectObject(hDC, pOldBitmapImage);
CBitmap bitmap;
bitmap.Attach(bm);
pImgList->Replace(nIndex, &bitmap, NULL);
ListCtrl.RedrawItems(nIndex, nIndex);
DeleteDC(hDC);
DeleteObject(bm);
}
DeleteObject(hBrushBorder);
DeleteObject(hBrushBk);
ListCtrl.Invalidate();
pView->m_bRunning=false;
pView->m_bTerminate=false;
_endthreadex( 0 );
return 0;
}
Acknowledgment
You can download CxImage freely from here.
History
- Ver. 1.0 15, Sep. 2003
- Ver. 1.1 24, Mar. 2005
- Fixed crashing when changing a directory fast.
- Supports Unicode option using preprocessor
_UNICODE.
Youngjin Kim lives in South Korea. I'm interested in every part of Computer Science, cause it has not been long time since graduate a University.
But now I'm working and researching on Pattern Recognition. Using that trying to recognize a Handwriting Prints. Korean and Chinese are my interesting Research Part.