📄 scemfimage.cpp
字号:
/*
* This file is part of the EMFexplorer projet.
* Copyright (C) 2004 Smith Charles.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* Extension: for commercial use, apply the Equity Public License, which
* adds to the normal terms of the GLPL a condition of donation to the author.
* If you are interested in support for this source code,
* contact Smith Charles <smith.charles@free.fr> for more information.
*/
#include "stdafx.h"
#include "SCEMFImage.h"
#include "SCEMF.h"
#include "SCEMFRasterizer.h"
#include "kSCEMFLibMsgs.h"
#include "SCGenInclude.h"
#include SC_INC_WINLIB(SCPreviewView.h) // for CPrintInfo
#include SC_INC_WINLIB(SCWinFile.h)
#include SC_INC_WINLIB(SCBitmap.h)
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
extern CLIPFORMAT s_cfRTF;
/////////////////////////////////////////////////////////////////////////////
// CSCEMFImage
IMPLEMENT_DYNCREATE(CSCEMFImage, CWnd)
BEGIN_MESSAGE_MAP(CSCEMFImage, CWnd)
//{{AFX_MSG_MAP(CSCEMFImage)
ON_WM_PAINT()
ON_WM_SIZE()
ON_WM_HSCROLL()
ON_WM_VSCROLL()
ON_WM_CREATE()
ON_WM_ERASEBKGND()
ON_WM_RBUTTONDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSCEMFImage construction/destruction
CSCEMFImage::CSCEMFImage():
m_iCurPage(0),
m_iWorldCx(0),
m_iWorldCy(0),
m_iAngle(0),
m_hEmf(NULL),
//
m_iFitMode(SC_FIT_NONE),
m_iCurZoom(SC_ZOOM100),
m_rectMargins(0, 0, 0, 0),
m_uiRasEngine(SC_ENGINE_GDI),
m_bReverseVideo(FALSE),
m_crPaperColor(RGB(255, 255, 255)),
m_pEMFDoc(NULL),
m_hCtxMenu(NULL),
m_pICtlOwner(NULL),
m_dwColorScheme(SC_CSM_CTLCOLOR_SYSINDEX),
m_crCtlColor(SC_MAKE_SYSCOLOR(COLOR_APPWORKSPACE))
{
SetRectEmpty(&m_rectPaper);
m_DrawingAttributes.dwInkingMode = SC_DFLT_INKINGMODE;
#if 0
// test
m_DrawingAttributes.bBkSolid = TRUE;
#endif
}
void CSCEMFImage::SCReset()
{
// App settings
m_iCurPage = 0;
m_iWorldCx = 0;
m_iWorldCy = 0;
m_iAngle = 0;
m_hEmf = NULL;
SetRectEmpty(&m_rectPaper);
InitializeScrollBars(m_iWorldCx, m_iWorldCy);
}
CSCEMFImage::~CSCEMFImage()
{
}
BOOL CSCEMFImage::PreCreateWindow(CREATESTRUCT& cs)
{
// Modify the Window class or styles here by modifying the CREATESTRUCT cs
cs.style |= WS_HSCROLL|WS_VSCROLL|CS_DBLCLKS;
return CWnd::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////////
// CSCEMFImage drawing
void CSCEMFImage::OnPaint()
{
CPaintDC dc(this); // device context for painting
SCPaint(&dc);
}
void CSCEMFImage::SCPaint(CDC* pDC)
{
CRect rectClient;
GetClientRect(&rectClient);
int cx = rectClient.Width();
int cy = rectClient.Height();
// Add draw code for native data here
if (!m_pEMFDoc || !m_pEMFDoc->SCGetNbPages() || !m_iCurPage)
{// when there is no doc, paint all in white
SCEMFExplorerPaint(pDC, &rectClient, SC_EMFLIB_UFMTMSG_EMFEXPLORER, SC_EMFLIB_UFMTMSG_DROPFILEs);
return;
}
int xScroll = GetScrollPos(SB_HORZ);
int yScroll = GetScrollPos(SB_VERT);
#ifdef SC_NO_MEMDC
CDC* pPageDC = pDC;
#else
CDC* pPageDC = &m_WorkMemDC;
if (!m_WorkMemDC.m_hDC)
{
m_WorkMemDC.SCPrepareSurface(cx, cy);
ASSERT(m_WorkMemDC.m_hDC);
}
#endif
int iDCState = pPageDC->SaveDC();
pPageDC->SetWindowOrg(xScroll, yScroll);
CSize PgSize;
SCGetPageSize(PgSize); // Contains rotation and scaling
int iImgCx = PgSize.cx;
int iImgCy = PgSize.cy;
int xDest = m_iPgPosX;
int yDest = m_iPgPosY;
// paint non-covered region
{
int iXRight = xDest + iImgCx;
int iYBottom = yDest + iImgCy;
if ((xDest>xScroll) || (yDest>yScroll) ||
(iXRight<cx+xScroll) || (iYBottom<cy+yScroll))
{
CBrush* pRGBBrush = NULL;
CBrush* pBrush;
switch (m_dwColorScheme & SC_CSM_CTLCOLOR_MASK)
{
case SC_CSM_CTLCOLOR_SYSINDEX:
pBrush = CBrush::FromHandle(::GetSysColorBrush((DWORD)SC_SYSCOLOR_INDEX(m_crCtlColor)));
break;
case SC_CSM_CTLCOLOR_RGBVALUE:
default:
// treat transparent as RGB in m_crCtlColor
pBrush = pRGBBrush = new CBrush(SC_RGBCOLOR_VALUE(m_crCtlColor));
}
CRect rExclude(xDest, yDest, iXRight, iYBottom);
if (m_dwColorScheme & SC_CSM_BORDER_MASK)
rExclude.InflateRect(1, 1);
// Image body
pPageDC->ExcludeClipRect(&rExclude);
if (m_dwColorScheme & SC_CSM_SHADOW_MASK)
{
// Shadow Right band
rExclude.SetRect(iXRight, yDest + 2, rExclude.right + SC_SHADOW_WDT, rExclude.bottom + SC_SHADOW_WDT);
pPageDC->ExcludeClipRect(&rExclude);
// Shadow Bottom band
rExclude.left = xDest + 2;
rExclude.top = iYBottom;
pPageDC->ExcludeClipRect(&rExclude);
}
OffsetRect(&rectClient, xScroll, yScroll);
pPageDC->FillRect(&rectClient, pBrush);
pPageDC->SelectClipRgn(NULL);
if (pRGBBrush)
delete pRGBBrush;
}
}
// paint page
// background
if (!m_DrawingAttributes.bBkSolid)
{
COLORREF crColor = (SCIsPartialReverseVideo())? SCGetReversedPaperColor() : SCGetTranslatedPaperColor();
CBrush Brush;
CRect rcBkgn(xDest, yDest, xDest + iImgCx, yDest + iImgCy);
Brush.CreateSolidBrush(crColor);
pPageDC->FillRect(&rcBkgn, &Brush);
pPageDC->SetBkColor(crColor);
}
// image
if (m_hEmf)
SCDisplayPage(pPageDC->m_hDC, xDest, yDest, iImgCx, iImgCy);
// shadow
if (m_dwColorScheme & (SC_CSM_BORDER_MASK|SC_CSM_SHADOW_MASK))
{
COLORREF crColor = m_bReverseVideo ? SCGetReversedPaperColor() : SCGetTranslatedPaperColor();
SCDrawFrameAndShadow(pPageDC, xDest, yDest, iImgCx, iImgCy,
((m_dwColorScheme & SC_CSM_SHADOW_MASK)? SC_SHADOW_WDT : 0),
crColor, (m_dwColorScheme & SC_CSM_BORDER_MASK));
}
pPageDC->RestoreDC(iDCState);
#ifndef SC_NO_MEMDC
pDC->StretchBlt(0, 0, cx, cy, pPageDC, 0, 0, cx, cy, SRCCOPY);
#endif
}
BOOL CSCEMFImage::SCRasterizeEMF(HDC hDC, HENHMETAFILE hEMF, CRect& rcPlay, BOOL bPrinting/*=FALSE*/)
{
BOOL bOk = FALSE;
BeginWaitCursor();
if (SCGdipGetEMFType(hEMF)!=EmfTypeEmfOnly)
bOk = SCGdipPlayMetafile(hDC, hEMF, rcPlay);
else
if (SC_ENGINE_GDIP==m_uiRasEngine)
{// Note: rasterizer must be detached from hDC before reusing DC
SCEMFRasterizer Rasterizer;
CSCEMFdcRenderer& rRenderer = Rasterizer.SCGetRenderer();
m_DrawingAttributes.bPrinting = bPrinting;
rRenderer.SCSetDrawingAttributes(m_DrawingAttributes);
Rasterizer.SCBreakMetafile(hDC, hEMF, NULL, (LPRECT)&rcPlay); // equivalent to attach
bOk = TRUE;
// DC detachment point
} else
{
// default to GDI
bOk = PlayEnhMetaFile(hDC, hEMF, (LPRECT)&rcPlay);
}
EndWaitCursor();
return bOk;
}
// Normal display
void CSCEMFImage::SCDisplayPage(HDC hDC, int xDest, int yDest, int iWdt, int iHgt)
{
// We are going to seriously alter the DC (rotation, metafile playing, etc.).
// So save its state
int iState = SaveDC(hDC);
// Ensure that nothing goes outside the page (before rotation)
::IntersectClipRect(hDC, xDest, yDest, xDest + iWdt, yDest + iHgt);
// Current paper size may differ from actual EMF size. So we must
// compute the playing destination by subtrating from the destination (xDest, yDest)
// the uppper left corner PgPaper(left, top) of the page. Note that PgPaper is
// expressed relatively to the uppper left corner of the EMF.
int iPlayX = xDest - m_rectPaper.left;
int iPlayY = yDest - m_rectPaper.top;
// Position of the EMF rectangle in world coordinates for playing
CSize sizeEMF;
SCGetEMFPlaySize(m_hEmf, sizeEMF);
CRect rcPlay(iPlayX, iPlayY,
iPlayX + MulDiv(sizeEMF.cx, m_iCurZoom, SC_ZOOM100),
iPlayY + MulDiv(sizeEMF.cy, m_iCurZoom, SC_ZOOM100));
int iGrOldMode;
if (m_iAngle)
{// Position of the PAGE rectangle for rotation in world coordinates
CRect rcRotate = m_rectPaper;
rcRotate.OffsetRect(iPlayX, iPlayY);
// Give the actual page rectangle for the rotation
// and the actual destination (xDest, yDest) for the translation
SCRotateDC(hDC, m_iAngle, rcRotate, xDest, yDest, iGrOldMode);
}
// Rasterize
BOOL bOK = SCRasterizeEMF(hDC, m_hEmf, rcPlay);
// Comments
PSCEMFDocPage pDocPage = m_pEMFDoc->SCGetDocPage(m_iCurPage-1);
ASSERT(pDocPage);
switch (m_iAngle)
{
case 90:
case 270:
pDocPage->SCDisplayPageComments(hDC, float(m_iCurZoom)/float(SC_ZOOM100),
xDest, yDest, iHgt, iWdt);
break;
default:
pDocPage->SCDisplayPageComments(hDC, float(m_iCurZoom)/float(SC_ZOOM100),
xDest, yDest, iWdt, iHgt);
}
// Restore DC state
RestoreDC(hDC, iState);
// Perform full rvideo
if (SCIsFullReverseVideo())
PatBlt(hDC, xDest-1, yDest-1, iWdt+2, iHgt+2, DSTINVERT);
}
// Save/Copy/Print
void CSCEMFImage::SCDisplayPageEx(HDC hDC, HENHMETAFILE hEmf,
CRect& rcDest, CRect& rcPaper,
SCGDIpDrawingAttributes& rAttributes,
int iAngle/*=0*/, int iZoom/*=SC_ZOOM100*/,
BOOL bInvert/*=FALSE*/)
{
// Paper
CRect PaperRect = rcPaper;
// Position of the EMF rectangle in world coordinates for playing
CSize sizeEMF;
SCGetEMFPlaySize(hEmf, sizeEMF);
int iPlayX = rcDest.left - PaperRect.left;
int iPlayY = rcDest.top - PaperRect.top;
CRect rcPlay(iPlayX, iPlayY,
iPlayX + MulDiv(sizeEMF.cx, iZoom, SC_ZOOM100),
iPlayY + MulDiv(sizeEMF.cy, iZoom, SC_ZOOM100));
int iState = SaveDC(hDC);
::IntersectClipRect(hDC, rcDest.left, rcDest.top, rcDest.right, rcDest.bottom);
int iGrOldMode;
if (iAngle)
{// Position of the PAGE rectangle for rotation in world coordinates
CRect rcRotate = PaperRect;
rcRotate.OffsetRect(iPlayX, iPlayY);
SCRotateDC(hDC, iAngle, rcRotate, rcDest.left, rcDest.top, iGrOldMode);
}
// Rasterize
BOOL bOK = FALSE;
if (SCGdipGetEMFType(hEmf)!=EmfTypeEmfOnly)
bOK = SCGdipPlayMetafile(hDC, hEmf, rcPlay);
else
if (SC_ENGINE_GDIP==m_uiRasEngine)
{// Note: rasterizer must be detached from hDC before reusing DC
SCEMFRasterizer Rasterizer;
CSCEMFdcRenderer& rRenderer = Rasterizer.SCGetRenderer();
rRenderer.SCSetDrawingAttributes(rAttributes);
Rasterizer.SCBreakMetafile(hDC, hEmf, NULL, (LPRECT)&rcPlay);
bOK = TRUE;
// DC detachment point
} else
{
bOK = PlayEnhMetaFile(hDC, hEmf, (LPRECT)&rcPlay);
}
// Restore DC state
RestoreDC(hDC, iState);
// Perform full rvideo
if (bInvert)
PatBlt(hDC, rcDest.left, rcDest.top, rcDest.Width(), rcDest.Height(), DSTINVERT);
}
/////////////////////////////////////////////////////////////////////////////
// CSCEMFImage message handlers
void CSCEMFImage::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
#ifndef SC_NO_MEMDC
m_WorkMemDC.SCPrepareSurface(cx, cy);
#endif
SizeScrollBars(cx, cy);
SCComputeFitZoom();
SCComputeRowsCols();
}
COLORREF CSCEMFImage::SCGetTranslatedPaperColor()
{
switch (m_dwColorScheme & SC_CSM_PAPERCOLOR_MASK)
{
case SC_CSM_PAPERCOLOR_SYSINDEX:
return ::GetSysColor((DWORD)SC_SYSCOLOR_INDEX(m_crPaperColor));
case SC_CSM_PAPERCOLOR_RGBVALUE:
return SC_RGBCOLOR_VALUE(m_crPaperColor);
//default:
}
return SCGetTranslatedCtlColor();
}
COLORREF CSCEMFImage::SCGetTranslatedCtlColor()
{
switch (m_dwColorScheme & SC_CSM_CTLCOLOR_MASK)
{
case SC_CSM_CTLCOLOR_SYSINDEX:
return ::GetSysColor((DWORD)SC_SYSCOLOR_INDEX(m_crCtlColor));
case SC_CSM_CTLCOLOR_RGBVALUE:
return SC_RGBCOLOR_VALUE(m_crCtlColor);
//default:
}
return ::GetSysColor(COLOR_WINDOW);
}
void CSCEMFImage::SCRotateLeft()
{
m_iAngle -= 90;
if (m_iAngle<0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -