2025-11-27 16:46:48 +09:00

563 lines
12 KiB
C++

// ==========================================================================
// Class Implementation : COXImageViewer
// ==========================================================================
// Version: 9.3
// This software along with its related components, documentation and files ("The Libraries")
// is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office. For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
// //////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "OXImageViewer.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNAMIC(COXImageViewer, COXScrollWnd)
int COXImageViewer::m_nDisplayColors=-1;
/////////////////////////////////////////////////////////////////////////////
// COXImageViewer
COXImageViewer::COXImageViewer() : m_clrBackground(::GetSysColor(COLOR_WINDOW))
{
m_bUseTrackZoom=TRUE;
SetSmoothScrolling(TRUE);
}
COXImageViewer::~COXImageViewer()
{
}
BEGIN_MESSAGE_MAP(COXImageViewer, COXScrollWnd)
//{{AFX_MSG_MAP(COXImageViewer)
ON_WM_PAINT()
ON_WM_SETFOCUS()
ON_WM_SETTINGCHANGE()
ON_WM_PALETTECHANGED()
ON_WM_QUERYNEWPALETTE()
ON_WM_ERASEBKGND()
//}}AFX_MSG_MAP
ON_COMMAND_RANGE(IDM_OX_IMGVIEVER_ROTATE90,IDM_OX_IMGVIEVER_ROTATE270,OnRotate)
ON_COMMAND_RANGE(IDM_OX_IMGVIEVER_FLIPVERT,IDM_OX_IMGVIEVER_FLIPHORZ,OnFlip)
ON_COMMAND_RANGE(IDM_OX_IMGVIEVER_ALIGNTOPLEFT,IDM_OX_IMGVIEVER_ALIGNBOTTOMRIGHT,OnAlign)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// COXImageViewer message handlers
void COXImageViewer::OnPaint()
{
CPaintDC dc(this); // device context for painting
if(m_dib.IsEmpty())
return;
// TODO: Add your message handler code here
OnPrepareDC(&dc);
// get the size of image
CSize sizeDIB=GetDIBSize();
CRect rect(0,0,sizeDIB.cx,sizeDIB.cy);
CRect rectPaint=rect;
// transform coordinates of boundary rectangle
// taking into account current zoom level
NormalToScaled(&rectPaint);
///
// we have to revert Y-coordinates
// to get right print output
UINT diff=rect.bottom-rect.top;
rect.bottom=sizeDIB.cy-rect.top;
rect.top=rect.bottom-diff;
///
DrawDIB(&dc,rectPaint,rect);
// Do not call COXScrollWnd::OnPaint() for painting messages
}
BOOL COXImageViewer::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
ASSERT_VALID(pDC);
CBrush brush(m_clrBackground);
//Bug-fix - by Nish - Mar 9th, 2005
if(IsEmpty())
{
CRect rect;
GetClientRect(&rect);
pDC->FillRect(&rect,&brush);
}
else
FillOutsideRect(pDC,&brush);
return TRUE;
}
void COXImageViewer::OnSetFocus(CWnd* pOldWnd)
{
COXScrollWnd::OnSetFocus(pOldWnd);
// TODO: Add your message handler code here
DoRealizePalette(TRUE,TRUE);
}
void COXImageViewer::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
{
COXScrollWnd::OnSettingChange(uFlags, lpszSection);
// TODO: Add your message handler code here
m_nDisplayColors=-1;
}
void COXImageViewer::OnPaletteChanged(CWnd* pFocusWnd)
{
// TODO: Add your message handler code here
if(pFocusWnd!=this)
{
DoRealizePalette(TRUE,FALSE);
}
}
BOOL COXImageViewer::OnQueryNewPalette()
{
// TODO: Add your message handler code here and/or call default
return (DoRealizePalette(TRUE,FALSE)>0 ? TRUE : FALSE);
}
//////////////////////////////////////////////////////
BOOL COXImageViewer::LoadFile(LPCTSTR lpszPathName)
{
// try to open file on read
CFile file;
BOOL bSuccess=FALSE;
TRY
{
bSuccess=file.Open(lpszPathName,CFile::modeRead);
}
CATCH(CFileException, e)
{
TCHAR szCause[255];
e->GetErrorMessage(szCause, 255);
TRACE(_T("COXImageViewer::LoadFile:exception: %s"),szCause);
bSuccess=FALSE;
}
END_CATCH
if(!bSuccess)
return FALSE;
return LoadFile(&file);
}
BOOL COXImageViewer::LoadFile(CFile* pFile)
{
pFile->SeekToBegin();
// just try to read DIB file
if(!m_dib.Read(pFile))
{
TRACE(_T("COXImageViewer::LoadFile: Unknown file format!"));
return FALSE;
}
return InitializeImage();
}
#ifdef OXDIB_SUPPORTJPEG
BOOL COXImageViewer::LoadJPEGFile(LPCTSTR lpszPathName)
{
// just try to read JPEG file
if(!m_dib.ReadJPEG(lpszPathName))
{
TRACE(_T("COXImageViewer::LoadJPEGFile: Unknown file format!\n"));
return FALSE;
}
return InitializeImage();
}
BOOL COXImageViewer::LoadJPEGFile(CFile* pFile)
{
// just try to read JPEG file
if(!m_dib.ReadJPEG(pFile))
{
TRACE(_T("COXImageViewer::LoadJPEGFile: Unknown file format!\n"));
return FALSE;
}
return InitializeImage();
}
#endif
BOOL COXImageViewer::LoadResource(LPCTSTR lpszResource)
{
// just try to load DIB resource
if(!m_dib.LoadResource(lpszResource))
{
TRACE(_T("COXImageViewer::LoadResource: Unknown file format!\n"));
return FALSE;
}
return InitializeImage();
}
BOOL COXImageViewer::Empty(BOOL bRedraw/*=TRUE*/)
{
if(m_dib.IsEmpty())
{
return TRUE;
}
m_dib.Empty();
m_dibDither.Empty();
if(bRedraw)
{
RedrawWindow();
}
return TRUE;
}
void COXImageViewer::SetBackgroundColor(COLORREF clrBackground, BOOL bRedraw/*=TRUE*/)
{
if(m_clrBackground!=clrBackground)
{
m_clrBackground=clrBackground;
if(bRedraw)
{
if(!IsEmpty() && CheckUsePalette())
{
DoRealizePalette(TRUE,TRUE);
}
else
{
RedrawWindow();
}
}
}
}
BOOL COXImageViewer::UpdateImage(BOOL bRedraw/*=TRUE*/)
{
ASSERT(::IsWindow(GetSafeHwnd()));
if(InitializeImage(m_pageDev,m_lineDev))
{
if(bRedraw)
{
if(CheckUsePalette())
{
DoRealizePalette(TRUE,TRUE);
}
else
{
RedrawWindow();
}
}
return TRUE;
}
else
return FALSE;
}
BOOL COXImageViewer::InitializeImage(const CSize& sizePage/*=CSize(10,10)*/,
const CSize& sizeLine/*=CSize(1,1)*/)
{
ASSERT(!m_dib.IsEmpty());
m_dibDither=NULL;
// if current video color palette is no more than 256 colors and
// DIB file uses no less than 256 color then create dithered copy
// of the file to render it on the display (this way we will get
// better output quality)
if(CheckUseDithered())
{
m_dibDither=m_dib;
m_dibDither.HalfToneDitherDIB();
}
CSize sizeDIB=GetDIBSize();
SetScrollSizes(MM_TEXT,sizeDIB,sizePage,sizeLine);
SetZoomAlign(ZA_CENTER);
if(IsAlwaysFitWindow())
ZoomToWindow();
else
RedrawWindow();
return TRUE;
}
BOOL COXImageViewer::CheckUseDithered()
{
// if current video color palette is no more than 256 colors and
// DIB file uses more than 256 color then create dithered copy
// of the file to render it on the display (this way we will get
// better output quality)
if(m_nDisplayColors==-1)
{
CWindowDC dc(this);
m_nDisplayColors=dc.GetDeviceCaps(BITSPIXEL);
}
return (m_nDisplayColors==8 && m_dib.GetNumColors()==0);
}
BOOL COXImageViewer::CheckUsePalette()
{
// if current video color mode is able to display no more than 256 colors and
// DIB file uses no less than 256 color then palette must be used
return (CheckUseDithered() || (m_nDisplayColors==8 && m_dib.GetNumColors()==256));
}
BOOL COXImageViewer::DrawDIB(CDC* pDC, const CRect& rectDest,
const CRect& rectSrc)
{
// set neccessary map mode
int oldMapMode;
oldMapMode=pDC->SetMapMode(MM_TEXT);
// depending on current palette use original or dithered image
// to render image on display
int bSuccess;
if(!CheckUseDithered())
bSuccess=m_dib.Paint(pDC,rectDest,rectSrc);
else
bSuccess=m_dibDither.Paint(pDC,rectDest,rectSrc);
pDC->SetMapMode(oldMapMode);
return bSuccess;
}
UINT COXImageViewer::DoRealizePalette(BOOL bRedraw/*=TRUE*/,
BOOL bForeground/*=TRUE*/)
{
UINT nCount=0;
// applicable only when palette is used
if(CheckUsePalette())
{
// retrieve image palette
CPalette* pPalette=GetDIBPalette();
if(pPalette!=NULL)
{
CClientDC dc(this);
CPalette* pOldPalette=dc.SelectPalette(pPalette,!bForeground);
nCount=dc.RealizePalette();
if(nCount>0)
{
// if image pallete is selected then
// redraw image if needed
if(bRedraw)
{
RedrawWindow(NULL,NULL,
RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_FRAME|
RDW_ERASENOW|RDW_INTERNALPAINT|RDW_ALLCHILDREN);
}
dc.SelectPalette(pOldPalette,!bForeground);
}
}
}
return nCount;
}
CPalette* COXImageViewer::GetDIBPalette()
{
// depending on the current color palette
// return original palette or palette of dithered file
if(!CheckUseDithered())
return m_dib.GetPalette();
else
return m_dibDither.GetPalette();
}
CSize COXImageViewer::GetDIBSize()
{
// depending on the current color palette
// return original size or size of dithered file
if(!CheckUseDithered())
return m_dib.GetSize();
else
return m_dibDither.GetSize();
}
BOOL COXImageViewer::OnPopulateContextMenu(CMenu* pMenu, CPoint& point)
{
UNREFERENCED_PARAMETER(point);
if(pMenu==NULL)
return TRUE;
// create "Align" popup menu
//
CMenu menuAlign;
if(menuAlign.CreatePopupMenu())
{
CString sItem;
VERIFY(sItem.LoadString(IDS_OX_IMGVIEVER_ALIGNTOPLEFT));
menuAlign.AppendMenu(MF_STRING|MF_CHECKED,IDM_OX_IMGVIEVER_ALIGNTOPLEFT,sItem);
VERIFY(sItem.LoadString(IDS_OX_IMGVIEVER_ALIGNCENTER));
menuAlign.AppendMenu(MF_STRING|MF_CHECKED,IDM_OX_IMGVIEVER_ALIGNCENTER,sItem);
VERIFY(sItem.LoadString(IDS_OX_IMGVIEVER_ALIGNBOTTOMRIGHT));
menuAlign.AppendMenu(MF_STRING|MF_CHECKED,IDM_OX_IMGVIEVER_ALIGNBOTTOMRIGHT,
sItem);
menuAlign.CheckMenuItem(IDM_OX_IMGVIEVER_ALIGNTOPLEFT,MF_BYCOMMAND|
((GetContentsAlign()==CA_TOPLEFT) ? MF_CHECKED : MF_UNCHECKED));
menuAlign.CheckMenuItem(IDM_OX_IMGVIEVER_ALIGNCENTER,MF_BYCOMMAND|
((GetContentsAlign()==CA_CENTER) ? MF_CHECKED : MF_UNCHECKED));
menuAlign.CheckMenuItem(IDM_OX_IMGVIEVER_ALIGNBOTTOMRIGHT,MF_BYCOMMAND|
((GetContentsAlign()==CA_BOTTOMRIGHT) ? MF_CHECKED : MF_UNCHECKED));
VERIFY(sItem.LoadString(IDS_OX_IMGVIEVER_ALIGNPOPUPMENU));
pMenu->InsertMenu(0,MF_BYPOSITION|MF_STRING|MF_POPUP,
(UINT_PTR)menuAlign.Detach(),sItem);
pMenu->InsertMenu(1,MF_BYPOSITION|MF_SEPARATOR);
}
// create "Rotate" popup menu
//
CMenu menuRotate;
if(menuRotate.CreatePopupMenu())
{
CString sItem;
VERIFY(sItem.LoadString(IDS_OX_IMGVIEVER_ROTATE90));
menuRotate.AppendMenu(MF_STRING,IDM_OX_IMGVIEVER_ROTATE90,sItem);
VERIFY(sItem.LoadString(IDS_OX_IMGVIEVER_ROTATE180));
menuRotate.AppendMenu(MF_STRING,IDM_OX_IMGVIEVER_ROTATE180,sItem);
VERIFY(sItem.LoadString(IDS_OX_IMGVIEVER_ROTATE270));
menuRotate.AppendMenu(MF_STRING,IDM_OX_IMGVIEVER_ROTATE270,sItem);
if(pMenu->GetMenuItemCount()>0)
pMenu->AppendMenu(MF_SEPARATOR);
VERIFY(sItem.LoadString(IDS_OX_IMGVIEVER_ROTATEPOPUPMENU));
pMenu->AppendMenu(MF_STRING|MF_POPUP,
(UINT_PTR)menuRotate.Detach(),sItem);
// create "Flip" popup menu
//
CMenu menuFlip;
if(menuFlip.CreatePopupMenu())
{
VERIFY(sItem.LoadString(IDS_OX_IMGVIEVER_FLIPVERT));
menuFlip.AppendMenu(MF_STRING,IDM_OX_IMGVIEVER_FLIPVERT,sItem);
VERIFY(sItem.LoadString(IDS_OX_IMGVIEVER_FLIPHORZ));
menuFlip.AppendMenu(MF_STRING,IDM_OX_IMGVIEVER_FLIPHORZ,sItem);
VERIFY(sItem.LoadString(IDS_OX_IMGVIEVER_FLIPPOPUPMENU));
pMenu->AppendMenu(MF_STRING|MF_POPUP,
(UINT_PTR)menuFlip.Detach(),sItem);
}
}
return TRUE;
}
void COXImageViewer::OnRotate(UINT nID)
{
int nRotateAngle=0;
switch(nID)
{
case IDM_OX_IMGVIEVER_ROTATE90:
nRotateAngle=90;
break;
case IDM_OX_IMGVIEVER_ROTATE180:
nRotateAngle=180;
break;
case IDM_OX_IMGVIEVER_ROTATE270:
nRotateAngle=270;
break;
default:
ASSERT(FALSE);
}
CWaitCursor wait;
m_dib.Rotate(nRotateAngle);
UpdateImage();
}
void COXImageViewer::OnFlip(UINT nID)
{
BOOL bFlipVert=FALSE;
BOOL bFlipHorz=FALSE;
switch(nID)
{
case IDM_OX_IMGVIEVER_FLIPVERT:
bFlipVert=TRUE;
break;
case IDM_OX_IMGVIEVER_FLIPHORZ:
bFlipHorz=TRUE;
break;
default:
ASSERT(FALSE);
}
CWaitCursor wait;
m_dib.Rotate(0,bFlipHorz,bFlipVert);
UpdateImage();
}
void COXImageViewer::OnAlign(UINT nID)
{
ContentsAlignment align=CA_TOPLEFT;
switch(nID)
{
case IDM_OX_IMGVIEVER_ALIGNTOPLEFT:
align=CA_TOPLEFT;
break;
case IDM_OX_IMGVIEVER_ALIGNCENTER:
align=CA_CENTER;
break;
case IDM_OX_IMGVIEVER_ALIGNBOTTOMRIGHT:
align=CA_BOTTOMRIGHT;
break;
default:
ASSERT(FALSE);
}
SetContentsAlign(align);
}