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
.