/* * (c) Copyright Ascensio System SIA 2010-2023 * * This program is a free software product. You can redistribute it and/or * modify it under the terms of the GNU Affero General Public License (AGPL) * version 3 as published by the Free Software Foundation. In accordance with * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect * that Ascensio System SIA expressly excludes the warranty of non-infringement * of any third-party rights. * * This program is distributed WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html * * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish * street, Riga, Latvia, EU, LV-1050. * * The interactive user interfaces in modified source and object code versions * of the Program must display Appropriate Legal Notices, as required under * Section 5 of the GNU AGPL version 3. * * Pursuant to Section 7(b) of the License you must retain the original Product * logo when distributing the program. Pursuant to Section 7(e) we decline to * grant you any rights under trademark law for use of our trademarks. * * All the Product's GUI elements, including illustrations and icon sets, as * well as technical writing content are licensed under the terms of the * Creative Commons Attribution-ShareAlike 4.0 International. See the License * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode * */ #include "GraphicsRenderer.h" #include #ifndef GRAPHICS_DISABLE_METAFILE #include "../raster/Metafile/MetaFile.h" #endif #if 0 static void LOGGING(char* buffer, ...) { FILE* f = fopen("path_to_log.txt", "a+"); va_list args; va_start(args, buffer); vfprintf(f, buffer, args); fprintf(f, "\n"); fclose(f); va_end(args); } #endif //////////////////////////////////////////////////////////////////////////////// Aggplus::CBrush* CGraphicsRenderer::CreateBrush(NSStructures::CBrush* pBrush) { if (NULL == pBrush) return NULL; bool bIsSwappedRGB = false; if (m_pRenderer && m_pRenderer->m_bSwapRGB) bIsSwappedRGB = true; LONG Type = pBrush->Type; if ((0 == Type) || (c_BrushTypeSolid == Type)) { Aggplus::CColor oColor((BYTE)(pBrush->Alpha1 * m_dGlobalAlpha), pBrush->Color1, bIsSwappedRGB); if (m_pRenderer && m_pRenderer->m_bIsDarkMode) oColor.ConvertToDarkMode(bIsSwappedRGB); Aggplus::CBrushSolid* pNew = new Aggplus::CBrushSolid(oColor); return pNew; } else if ((c_BrushTypeHorizontal == Type) || (c_BrushTypeVertical == Type) || (c_BrushTypeDiagonal1 == Type) || (c_BrushTypeDiagonal2 == Type) || (c_BrushTypeCenter == Type) || (c_BrushTypePathGradient1 == Type) || (c_BrushTypePathGradient2 == Type) || (c_BrushTypeCylinderHor == Type) || (c_BrushTypeCylinderVer == Type) || (c_BrushTypePathRadialGradient == Type) || (c_BrushTypePathNewLinearGradient == Type) || (c_BrushTypePathConicalGradient == Type) || (c_BrushTypePathDiamondGradient == Type) || (c_BrushTypeMyTestGradient == Type) || (c_BrushTypeTriagnleMeshGradient == Type) || (c_BrushTypeCurveGradient == Type) || (c_BrushTypeTensorCurveGradient == Type)) { Aggplus::CColor o1((BYTE)(pBrush->Alpha1 * m_dGlobalAlpha), pBrush->Color1, bIsSwappedRGB); Aggplus::CColor o2((BYTE)(pBrush->Alpha2 * m_dGlobalAlpha), pBrush->Color2, bIsSwappedRGB); Aggplus::CBrushLinearGradient* pNew = new Aggplus::CBrushLinearGradient( Aggplus::RectF(0.0f, 0.0f, 1.0f, 1.0f), o1, o2, (float)pBrush->LinearAngle, TRUE ); if( pNew ) { pNew->SetRelativeCoords( TRUE ); pNew->m_oGradientInfo = pBrush->m_oGradientInfo; int nCountSubColors = pBrush->m_arrSubColors.size(); if( nCountSubColors > 0 ) { Aggplus::CColor* pColors = new Aggplus::CColor[nCountSubColors]; float* pBlends = new float[nCountSubColors]; if( pColors && pBlends ) { for( int i = 0; i < nCountSubColors; i++ ) { DWORD dwColor = (DWORD)pBrush->m_arrSubColors[i].color; BYTE a = (dwColor >> 24) & 0xFF; BYTE b = (dwColor >> 16) & 0xFF; BYTE g = (dwColor >> 8) & 0xFF; BYTE r = (dwColor) & 0xFF; if (bIsSwappedRGB) { BYTE tmp = r; r = b; b = tmp; } pColors[i] = Aggplus::CColor((BYTE)(a * m_dGlobalAlpha), b, g, r); pBlends[i] = (float)(pBrush->m_arrSubColors[i].position / 65536.0); } pNew->SetInterpolationColors( pColors, pBlends, nCountSubColors ); } delete [] pColors; delete [] pBlends; } pNew->SetBounds(pBrush->Bounds); } if(!pNew) return NULL; switch (Type) { case c_BrushTypePathGradient2: pNew->m_bType = Aggplus::BrushTypePathGradient; break; case c_BrushTypeMyTestGradient: pNew->m_bType = Aggplus::BrushTypeMyTestGradient; break; case c_BrushTypePathRadialGradient: pNew->m_bType = Aggplus::BrushTypeRadialGradient; break; case c_BrushTypePathNewLinearGradient: pNew->m_bType = Aggplus::BrushTypeNewLinearGradient; break; case c_BrushTypePathConicalGradient: pNew->m_bType = Aggplus::BrushTypeConicalGradient; break; case c_BrushTypePathDiamondGradient: pNew->m_bType = Aggplus::BrushTypeDiamondGradient; break; case c_BrushTypeTensorCurveGradient: pNew->m_bType = Aggplus::BrushTypeTensorCurveGradient; break; case c_BrushTypeCurveGradient: pNew->m_bType = Aggplus::BrushTypeCurveGradient; break; case c_BrushTypeTriagnleMeshGradient: pNew->m_bType = Aggplus::BrushTypeTriagnleMeshGradient; break; default: break; } return pNew; } else if (c_BrushTypeHatch1 == Type) { Aggplus::CColor o1((BYTE)(pBrush->Alpha1 * m_dGlobalAlpha), pBrush->Color1, bIsSwappedRGB); Aggplus::CColor o2((BYTE)(pBrush->Alpha2 * m_dGlobalAlpha), pBrush->Color2, bIsSwappedRGB); Aggplus::CBrushHatch* pNew = new Aggplus::CBrushHatch(); pNew->m_dwColor1 = o1; pNew->m_dwColor2 = o2; pNew->m_name = pBrush->TexturePath; pNew->Bounds = pBrush->Bounds; return pNew; } else { Aggplus::CBrushTexture* pNew; if (NULL != pBrush->Image) pNew = new Aggplus::CBrushTexture(pBrush->Image, Aggplus::WrapModeClamp); else pNew = new Aggplus::CBrushTexture(pBrush->TexturePath, Aggplus::WrapModeClamp); pNew->SetTransform(&m_oBrush.Transform); return pNew; } } CGraphicsRenderer::CGraphicsRenderer() : NSGraphics::IGraphicsRenderer() { m_pRenderer = NULL; m_pPath = NULL; m_dWidth = 210; m_dHeight = 190; m_dPixelsWidth = 720; m_dPixelsHeight = 576; m_lCurrentCommandType = 0; m_lCurrentClipMode = 0; m_bIsSetupClip = FALSE; m_pFontManager = NULL; m_oInstalledFont.Name = L""; m_pPixels = NULL; m_pDIB = NULL; m_pCache = NULL; m_dGlobalAlpha = 1.0; m_bGlobalAlphaEnabled = false; m_dGammaStroke = -1; } CGraphicsRenderer::~CGraphicsRenderer() { Clear(); RELEASEOBJECT(m_pDIB); RELEASEINTERFACE(m_pFontManager); RELEASEINTERFACE(m_pCache); } void CGraphicsRenderer::SetImageCache(NSImages::IImageFilesCache* pCache) { RELEASEINTERFACE(m_pCache); m_pCache = (CImageFilesCache*)pCache; ADDREFINTERFACE(m_pCache); } void CGraphicsRenderer::SetFontManager(NSFonts::IFontManager* pManager) { RELEASEINTERFACE(m_pFontManager); if (NULL == pManager) { m_pFontManager = new CFontManager(); m_pFontManager->Initialize(); } else { m_pFontManager = (CFontManager*)pManager; ADDREFINTERFACE(m_pFontManager); } } void CGraphicsRenderer::CheckFontManager() { if (NULL == m_pFontManager) SetFontManager(NULL); } NSFonts::IFontManager* CGraphicsRenderer::GetFontManager() { return m_pFontManager; } BYTE* CGraphicsRenderer::GetPixels(LONG& lWidth, LONG& lHeight) { lWidth = (LONG)m_dPixelsWidth; lHeight = (LONG)m_dPixelsHeight; return m_pPixels; } void CGraphicsRenderer::ClearInstallFont() { m_oInstalledFont.Name = L""; m_oInstalledFont.Path = L""; } void CGraphicsRenderer::SetClipRect(double x, double y, double w, double h) { m_pRenderer->SetClipRect3(x, y, w, h); } INT CGraphicsRenderer::CheckValidate(INT bOnlyGraphics) { if (NULL == m_pRenderer) return FALSE; if (!bOnlyGraphics) return (NULL != m_pPath); return TRUE; } void CGraphicsRenderer::Clear() { RELEASEOBJECT(m_pPath); RELEASEOBJECT(m_pRenderer); } void CGraphicsRenderer::UpdateSize() { if (NULL == m_pRenderer) return; m_pRenderer->SetPageWidth(m_dWidth, Aggplus::UnitMillimeter); m_pRenderer->SetPageHeight(m_dHeight, Aggplus::UnitMillimeter); m_pRenderer->SetPageUnit(Aggplus::UnitMillimeter); } // тип рендерера----------------------------------------------------------------------------- HRESULT CGraphicsRenderer::get_Type(LONG* lType) { if (NULL == lType) return S_FALSE; *lType = c_nGrRenderer; return S_OK; } //-------- Функции для работы со страницей -------------------------------------------------- HRESULT CGraphicsRenderer::NewPage() { // ну не влезло так не влезло return S_OK; } HRESULT CGraphicsRenderer::put_Height(const double& dHeight) { m_dHeight = dHeight; if (NULL != m_pRenderer) { m_pRenderer->SetPageHeight(m_dHeight, Aggplus::UnitMillimeter); m_pRenderer->SetPageUnit(Aggplus::UnitMillimeter); } return S_OK; } HRESULT CGraphicsRenderer::get_Height(double* dHeight) { if (NULL == dHeight) return S_FALSE; *dHeight = m_dHeight; return S_OK; } HRESULT CGraphicsRenderer::put_Width(const double& dWidth) { m_dWidth = dWidth; if (NULL != m_pRenderer) { m_pRenderer->SetPageWidth(m_dWidth, Aggplus::UnitMillimeter); m_pRenderer->SetPageUnit(Aggplus::UnitMillimeter); } return S_OK; } HRESULT CGraphicsRenderer::get_Width(double* dWidth) { if (NULL == dWidth) return S_FALSE; *dWidth = m_dWidth; return S_OK; } HRESULT CGraphicsRenderer::get_DpiX(double* dDpiX) { if (NULL == dDpiX) return S_FALSE; *dDpiX = 25.4 * m_dPixelsWidth / m_dWidth; return S_OK; } HRESULT CGraphicsRenderer::get_DpiY(double* dDpiY) { if (NULL == dDpiY) return S_FALSE; *dDpiY = 25.4 * m_dPixelsHeight / m_dHeight; return S_OK; } // pen -------------------------------------------------------------------------------------- HRESULT CGraphicsRenderer::get_PenColor(LONG* lColor) { *lColor = m_oPen.Color; return S_OK; } HRESULT CGraphicsRenderer::put_PenColor(const LONG& lColor) { m_oPen.Color = lColor; return S_OK; } HRESULT CGraphicsRenderer::get_PenAlpha(LONG* lAlpha) { *lAlpha = m_oPen.Alpha; return S_OK; } HRESULT CGraphicsRenderer::put_PenAlpha(const LONG& lAlpha) { m_oPen.Alpha = lAlpha; return S_OK; } HRESULT CGraphicsRenderer::get_PenSize(double* dSize) { *dSize = m_oPen.Size; return S_OK; } HRESULT CGraphicsRenderer::put_PenSize(const double& dSize) { m_oPen.Size = dSize; return S_OK; } HRESULT CGraphicsRenderer::get_PenDashStyle(BYTE* val) { *val = m_oPen.DashStyle; return S_OK; } HRESULT CGraphicsRenderer::put_PenDashStyle(const BYTE& val) { m_oPen.DashStyle = val; return S_OK; } HRESULT CGraphicsRenderer::get_PenLineStartCap(BYTE* val) { *val = m_oPen.LineStartCap; return S_OK; } HRESULT CGraphicsRenderer::put_PenLineStartCap(const BYTE& val) { m_oPen.LineStartCap = val; return S_OK; } HRESULT CGraphicsRenderer::get_PenLineEndCap(BYTE* val) { *val = m_oPen.LineEndCap; return S_OK; } HRESULT CGraphicsRenderer::put_PenLineEndCap(const BYTE& val) { m_oPen.LineEndCap = val; return S_OK; } HRESULT CGraphicsRenderer::get_PenLineJoin(BYTE* val) { *val = m_oPen.LineJoin; return S_OK; } HRESULT CGraphicsRenderer::put_PenLineJoin(const BYTE& val) { m_oPen.LineJoin = val; return S_OK; } HRESULT CGraphicsRenderer::get_PenDashOffset(double* dOffset) { *dOffset = m_oPen.DashOffset; return S_OK; } HRESULT CGraphicsRenderer::put_PenDashOffset(const double& dOffset) { m_oPen.DashOffset = dOffset; return S_OK; } HRESULT CGraphicsRenderer::get_PenAlign(LONG* lAlign) { *lAlign = m_oPen.Align; return S_OK; } HRESULT CGraphicsRenderer::put_PenAlign(const LONG& lAlign) { m_oPen.Align = lAlign; return S_OK; } HRESULT CGraphicsRenderer::get_PenMiterLimit(double* dOffset) { *dOffset = m_oPen.MiterLimit; return S_OK; } HRESULT CGraphicsRenderer::put_PenMiterLimit(const double& dOffset) { m_oPen.MiterLimit = dOffset; return S_OK; } HRESULT CGraphicsRenderer::PenDashPattern(double* pPattern, LONG lCount) { RELEASEARRAYOBJECTS((m_oPen.DashPattern)); m_oPen.DashPattern = new double[lCount]; memcpy(m_oPen.DashPattern, pPattern, lCount * sizeof(double)); m_oPen.Count = lCount; return S_OK; } // brush ------------------------------------------------------------------------------------ HRESULT CGraphicsRenderer::get_BrushType(LONG* lType) { *lType = m_oBrush.Type; return S_OK; } HRESULT CGraphicsRenderer::put_BrushType(const LONG& lType) { m_oBrush.Type = lType; return S_OK; } HRESULT CGraphicsRenderer::get_BrushColor1(LONG* lColor) { *lColor = m_oBrush.Color1; return S_OK; } HRESULT CGraphicsRenderer::put_BrushColor1(const LONG& lColor) { m_oBrush.Color1 = lColor; return S_OK; } HRESULT CGraphicsRenderer::get_BrushAlpha1(LONG* lAlpha) { *lAlpha = m_oBrush.Alpha1; return S_OK; } HRESULT CGraphicsRenderer::put_BrushAlpha1(const LONG& lAlpha) { m_oBrush.Alpha1 = lAlpha; return S_OK; } HRESULT CGraphicsRenderer::get_BrushColor2(LONG* lColor) { *lColor = m_oBrush.Color2; return S_OK; } HRESULT CGraphicsRenderer::put_BrushColor2(const LONG& lColor) { m_oBrush.Color2 = lColor; return S_OK; } HRESULT CGraphicsRenderer::get_BrushAlpha2(LONG* lAlpha) { *lAlpha = m_oBrush.Alpha2; return S_OK; } HRESULT CGraphicsRenderer::put_BrushAlpha2(const LONG& lAlpha) { m_oBrush.Alpha2 = lAlpha; return S_OK; } HRESULT CGraphicsRenderer::get_BrushTexturePath(std::wstring* bsPath) { *bsPath = m_oBrush.TexturePath; return S_OK; } HRESULT CGraphicsRenderer::put_BrushTexturePath(const std::wstring& bsPath) { m_oBrush.TexturePath = bsPath; return S_OK; } HRESULT CGraphicsRenderer::get_BrushTextureImage(Aggplus::CImage** pImage) { *pImage = m_oBrush.Image; return S_OK; } HRESULT CGraphicsRenderer::put_BrushTextureImage(Aggplus::CImage *pImage) { RELEASEINTERFACE(m_oBrush.Image); if (NULL == pImage) return S_OK; m_oBrush.Image = pImage; m_oBrush.Image->AddRef(); return S_OK; } HRESULT CGraphicsRenderer::get_BrushTextureMode(LONG* lMode) { *lMode = m_oBrush.TextureMode; return S_OK; } HRESULT CGraphicsRenderer::put_BrushTextureMode(const LONG& lMode) { m_oBrush.TextureMode = lMode; return S_OK; } HRESULT CGraphicsRenderer::get_BrushTextureAlpha(LONG* lTxAlpha) { *lTxAlpha = m_oBrush.TextureAlpha; return S_OK; } HRESULT CGraphicsRenderer::put_BrushTextureAlpha(const LONG& lTxAlpha) { m_oBrush.TextureAlpha = lTxAlpha; return S_OK; } HRESULT CGraphicsRenderer::get_BrushLinearAngle(double* dAngle) { *dAngle = m_oBrush.LinearAngle; return S_OK; } HRESULT CGraphicsRenderer::put_BrushLinearAngle(const double& dAngle) { m_oBrush.LinearAngle = dAngle; return S_OK; } HRESULT CGraphicsRenderer::get_BrushTransform(Aggplus::CMatrix &oMatrix) { oMatrix = m_oBrush.Transform; return S_OK; } HRESULT CGraphicsRenderer::put_BrushTransform(const Aggplus::CMatrix& oMatrix) { m_oBrush.Transform = oMatrix; return S_OK; } HRESULT CGraphicsRenderer::BrushRect(const INT& val, const double& left, const double& top, const double& width, const double& height) { m_oBrush.Rectable = val; m_oBrush.Rect.X = (float)left; m_oBrush.Rect.Y = (float)top; m_oBrush.Rect.Width = (float)width; m_oBrush.Rect.Height = (float)height; return S_OK; } HRESULT CGraphicsRenderer::BrushBounds(const double& left, const double& top, const double& width, const double& height) { m_oBrush.Bounds.left = left; m_oBrush.Bounds.top = top; m_oBrush.Bounds.right = left + width; m_oBrush.Bounds.bottom = top + height; return S_OK; } HRESULT CGraphicsRenderer::put_BrushGradientColors(LONG* lColors, double* pPositions, LONG nCount) { m_oBrush.m_arrSubColors.clear(); for (LONG i = 0; i < nCount; ++i) { NSStructures::CBrush::TSubColor color; color.color = lColors[i]; color.position = (long)(pPositions[i] * 65536); m_oBrush.m_arrSubColors.push_back(color); } return S_OK; } // font ------------------------------------------------------------------------------------- HRESULT CGraphicsRenderer::get_FontName(std::wstring* bsName) { *bsName = m_oFont.Name; return S_OK; } HRESULT CGraphicsRenderer::put_FontName(const std::wstring& bsName) { m_oFont.Name = bsName; return S_OK; } HRESULT CGraphicsRenderer::get_FontPath(std::wstring* bsName) { *bsName = m_oFont.Path; return S_OK; } HRESULT CGraphicsRenderer::put_FontPath(const std::wstring& bsName) { m_oFont.Path = bsName; return S_OK; } HRESULT CGraphicsRenderer::get_FontSize(double* dSize) { *dSize = m_oFont.Size; return S_OK; } HRESULT CGraphicsRenderer::put_FontSize(const double& dSize) { m_oFont.Size = dSize; return S_OK; } HRESULT CGraphicsRenderer::get_FontStyle(LONG* lStyle) { *lStyle = m_oFont.GetStyle(); return S_OK; } HRESULT CGraphicsRenderer::put_FontStyle(const LONG& lStyle) { m_oFont.SetStyle(lStyle); return S_OK; } HRESULT CGraphicsRenderer::get_FontStringGID(INT* bGID) { *bGID = m_oFont.StringGID; return S_OK; } HRESULT CGraphicsRenderer::put_FontStringGID(const INT& bGID) { m_oFont.StringGID = bGID; return S_OK; } HRESULT CGraphicsRenderer::get_FontCharSpace(double* dSpace) { *dSpace = m_oFont.CharSpace; return S_OK; } HRESULT CGraphicsRenderer::put_FontCharSpace(const double& dSpace) { m_oFont.CharSpace = dSpace; return S_OK; } HRESULT CGraphicsRenderer::get_FontFaceIndex(int* lFaceIndex) { *lFaceIndex = m_oFont.FaceIndex; return S_OK; } HRESULT CGraphicsRenderer::put_FontFaceIndex(const int& lFaceIndex) { m_oFont.FaceIndex = lFaceIndex; return S_OK; } //-------- Функции для вывода текста -------------------------------------------------------- HRESULT CGraphicsRenderer::CommandDrawTextCHAR(const LONG& c, const double& x, const double& y, const double& w, const double& h) { if (c_nHyperlinkType == m_lCurrentCommandType) return S_OK; put_BrushType(c_BrushTypeSolid); _SetFont(); Aggplus::CBrush* pBrush = CreateBrush(&m_oBrush); m_pRenderer->DrawStringC(c, m_pFontManager, pBrush, x, y); RELEASEOBJECT(pBrush); return S_OK; } HRESULT CGraphicsRenderer::CommandDrawText(const std::wstring& bsText, const double& x, const double& y, const double& w, const double& h) { if (c_nHyperlinkType == m_lCurrentCommandType) return S_OK; put_BrushType(c_BrushTypeSolid); m_oFont.StringGID = FALSE; _SetFont(); Aggplus::CBrush* pBrush = CreateBrush(&m_oBrush); m_pRenderer->DrawString(bsText, m_pFontManager, pBrush, x, y); RELEASEOBJECT(pBrush); return S_OK; } HRESULT CGraphicsRenderer::CommandDrawTextExCHAR(const LONG& c, const LONG& gid, const double& x, const double& y, const double& w, const double& h) { if (gid >= 0) { m_oFont.StringGID = TRUE; return CommandDrawTextCHAR(gid, x, y, w, h); } m_oFont.StringGID = FALSE; return CommandDrawTextCHAR(c, x, y, w, h); } HRESULT CGraphicsRenderer::CommandDrawTextEx(const std::wstring& bsUnicodeText, const unsigned int* pGids, const unsigned int nGidsCount, const double& x, const double& y, const double& w, const double& h) { if (NULL != pGids && 0 != nGidsCount && !(1 == nGidsCount && 0 == *pGids)) { m_oFont.StringGID = TRUE; if (c_nHyperlinkType == m_lCurrentCommandType) return S_OK; put_BrushType(c_BrushTypeSolid); _SetFont(); Aggplus::CBrush* pBrush = CreateBrush(&m_oBrush); m_pRenderer->DrawString(pGids, nGidsCount, m_pFontManager, pBrush, x, y); RELEASEOBJECT(pBrush); return S_OK; } m_oFont.StringGID = FALSE; return CommandDrawText(bsUnicodeText, x, y, w, h); } //-------- Маркеры для команд --------------------------------------------------------------- HRESULT CGraphicsRenderer::BeginCommand(const DWORD& lType) { m_lCurrentCommandType = lType; switch (lType) { case c_nPageType: { return NewPage(); } case c_nMaskType: { m_pRenderer->StartCreatingAlphaMask(); break; } case c_nLayerType: { m_pRenderer->CreateLayer(); break; } default: break; }; return S_OK; } HRESULT CGraphicsRenderer::EndCommand(const DWORD& lType) { switch (lType) { case c_nClipType: { INT bIsIn = (c_nClipRegionTypeWinding == (0x0001 & m_lCurrentClipMode)); m_pPath->SetRuler(bIsIn ? false : true); INT bIsIntersect = (c_nClipRegionIntersect == (0x0100 & m_lCurrentClipMode)); INT bIsStrokePath = (c_nClipToStrokePath == (0x0010 & m_lCurrentClipMode)); m_pRenderer->CombineClip(m_pPath, bIsIntersect ? agg::sbool_and : agg::sbool_or, bIsStrokePath ? &m_oPen : NULL); //m_pRenderer->SetClip(m_pPath); break; } case c_nResetClipType: { m_pRenderer->ResetClip(); m_bIsSetupClip = FALSE; break; } case c_nMaskType: { m_pRenderer->EndCreatingAlphaMask(); break; } case c_nResetMaskType: { m_pRenderer->ResetAlphaMask(); break; } case c_nLayerType: { m_pRenderer->BlendLayer(); break; } default: break; }; m_lCurrentCommandType = 0; return S_OK; } //-------- Функции для работы с Graphics Path ----------------------------------------------- HRESULT CGraphicsRenderer::PathCommandMoveTo(const double& x, const double& y) { if (!CheckValidate()) return S_FALSE; m_pPath->MoveTo(x, y); return S_OK; } HRESULT CGraphicsRenderer::PathCommandLineTo(const double& x, const double& y) { if (!CheckValidate()) return S_FALSE; m_pPath->LineTo(x, y); return S_OK; } HRESULT CGraphicsRenderer::PathCommandLinesTo(double* points, const int& count) { if (!CheckValidate()) return S_FALSE; m_pPath->AddLines(points, count); return S_OK; } HRESULT CGraphicsRenderer::PathCommandCurveTo(const double& x1, const double& y1, const double& x2, const double& y2, const double& x3, const double& y3) { if (!CheckValidate()) return S_FALSE; m_pPath->CurveTo(x1, y1, x2, y2, x3, y3); return S_OK; } HRESULT CGraphicsRenderer::PathCommandCurvesTo(double* points, const int& count) { if (!CheckValidate()) return S_FALSE; m_pPath->AddBeziers(points, count); return S_OK; } HRESULT CGraphicsRenderer::PathCommandArcTo(const double& x, const double& y, const double& w, const double& h, const double& startAngle, const double& sweepAngle) { if (!CheckValidate()) return S_FALSE; m_pPath->AddArc2(x, y, w, h, -startAngle, -sweepAngle); return S_OK; } HRESULT CGraphicsRenderer::PathCommandClose() { if (!CheckValidate()) return S_FALSE; m_pPath->CloseFigure(); return S_OK; } HRESULT CGraphicsRenderer::PathCommandEnd() { if (!CheckValidate()) return S_FALSE; m_pPath->Reset(); return S_OK; } HRESULT CGraphicsRenderer::DrawPath(const LONG& nType) { if (!CheckValidate(TRUE)) return S_FALSE; LONG lFillType = (nType & 0xFF00); INT bIsStroke = (0x01 == (nType & 0x01)); switch (lFillType) { case c_nWindingFillMode: case c_nEvenOddFillMode: { m_pPath->SetRuler((lFillType == c_nWindingFillMode) ? false : true); CCacheImage* pCacheImage = NULL; Aggplus::CBrush* pBrush = NULL; if (m_oBrush.Type == c_BrushTypeTexture) { Aggplus::WrapMode oMode = Aggplus::WrapModeClamp; switch (m_oBrush.TextureMode) { case c_BrushTextureModeTile: oMode = Aggplus::WrapModeTile; break; case c_BrushTextureModeTileCenter: oMode = Aggplus::WrapModeTile; break; default: break; } Aggplus::CBrushTexture* pTextureBrush = NULL; if (NULL != m_oBrush.Image) { pTextureBrush = new Aggplus::CBrushTexture(m_oBrush.Image, oMode); } else if (m_oBrush.TexturePath.find(L"data:") == 0) { bool bIsOnlyOfficeHatch = false; if (m_oBrush.TexturePath.find(L"onlyoffice_hatch") != std::wstring::npos) bIsOnlyOfficeHatch = true; int countErase = (int)(m_oBrush.TexturePath.find(',') + 1); int nInputSize = (int)(m_oBrush.TexturePath.length() - countErase); const wchar_t* pInputSrc = m_oBrush.TexturePath.c_str() + countErase; int nDecodeLen = NSBase64::Base64DecodeGetRequiredLength(nInputSize); BYTE* pImageData = new BYTE[nDecodeLen]; if (TRUE == NSBase64::Base64Decode(pInputSrc, nInputSize, pImageData, &nDecodeLen)) { CBgraFrame oFrame; if (bIsOnlyOfficeHatch) { int nSize = (int)sqrt(nDecodeLen >> 2); oFrame.put_IsRGBA(true); oFrame.put_Data(pImageData); oFrame.put_Width(nSize); oFrame.put_Height(nSize); oFrame.put_Stride(4 * nSize); } else { oFrame.put_IsRGBA(false); oFrame.Decode(pImageData, nDecodeLen); RELEASEARRAYOBJECTS(pImageData); } // pImage отдается pTextureBrush и освобождается вместе с pBrush Aggplus::CImage* pImage = new Aggplus::CImage(); pImage->Create(oFrame.get_Data(), oFrame.get_Width(), oFrame.get_Height(), oFrame.get_Stride()); oFrame.ClearNoAttack(); pTextureBrush = new Aggplus::CBrushTexture(pImage, oMode); pTextureBrush->m_bReleaseImage = TRUE; } else RELEASEARRAYOBJECTS(pImageData); } else { if (NULL != m_pCache) { pCacheImage = (CCacheImage*)m_pCache->Lock(m_oBrush.TexturePath); pTextureBrush = new Aggplus::CBrushTexture(pCacheImage->GetImage(), oMode); } else { pTextureBrush = new Aggplus::CBrushTexture(m_oBrush.TexturePath, oMode); } } if( pTextureBrush ) { pTextureBrush->SetTransform(&m_oBrush.Transform); pTextureBrush->Alpha = (BYTE)m_oBrush.TextureAlpha; if (m_oBrush.Rectable == 1) { pTextureBrush->m_bUseBounds = true; pTextureBrush->m_oBounds.left = m_oBrush.Rect.X; pTextureBrush->m_oBounds.top = m_oBrush.Rect.Y; pTextureBrush->m_oBounds.right = pTextureBrush->m_oBounds.left + m_oBrush.Rect.Width; pTextureBrush->m_oBounds.bottom = pTextureBrush->m_oBounds.top + m_oBrush.Rect.Height; } } pBrush = pTextureBrush; } else { pBrush = CreateBrush(&m_oBrush); } m_pRenderer->FillPath(pBrush, m_pPath); RELEASEOBJECT(pBrush); RELEASEINTERFACE(pCacheImage); break; } default: break; }; if (bIsStroke) { m_pRenderer->DrawPath(&m_oPen, m_pPath, m_dGammaStroke); } return S_OK; } HRESULT CGraphicsRenderer::PathCommandStart() { if (!CheckValidate()) return S_FALSE; m_pPath->StartFigure(); return S_OK; } HRESULT CGraphicsRenderer::PathCommandGetCurrentPoint(double* x, double* y) { if (!CheckValidate()) return S_FALSE; m_pPath->GetLastPoint(*x, *y); return S_OK; } // textpath HRESULT CGraphicsRenderer::PathCommandTextCHAR(const LONG& c, const double& x, const double& y, const double& w, const double& h) { if (!CheckValidate()) return S_FALSE; _SetFont(); // так как пат рисуется в миллиметрах - надо перевести пункты в миллиметры float fSize = (float)(0.3528 * m_oFont.Size); m_pPath->AddStringC(c, m_pFontManager, x, y); return S_OK; } HRESULT CGraphicsRenderer::PathCommandText(const std::wstring& bsText, const double& x, const double& y, const double& w, const double& h) { if (!CheckValidate()) return S_FALSE; _SetFont(); // так как пат рисуется в миллиметрах - надо перевести пункты в миллиметры float fSize = (float)(0.3528 * m_oFont.Size); m_pPath->AddString(bsText, m_pFontManager, x, y); return S_OK; } HRESULT CGraphicsRenderer::PathCommandTextExCHAR(const LONG& c, const LONG& gid, const double& x, const double& y, const double& w, const double& h) { if (gid >= 0) { m_oFont.StringGID = TRUE; return PathCommandTextCHAR(gid, x, y, w, h); } m_oFont.StringGID = FALSE; return PathCommandTextCHAR(c, x, y, w, h); } HRESULT CGraphicsRenderer::PathCommandTextEx(const std::wstring& bsUnicodeText, const unsigned int* pGids, const unsigned int nGidsCount, const double& x, const double& y, const double& w, const double& h) { if (NULL != pGids) { m_oFont.StringGID = TRUE; if (!CheckValidate()) return S_FALSE; _SetFont(); // так как пат рисуется в миллиметрах - надо перевести пункты в миллиметры float fSize = (float)(0.3528 * m_oFont.Size); m_pPath->AddString(pGids, nGidsCount, m_pFontManager, x, y); return S_OK; } m_oFont.StringGID = FALSE; return PathCommandText(bsUnicodeText, x, y, w, h); } //-------- Функции для вывода изображений --------------------------------------------------- HRESULT CGraphicsRenderer::DrawImage(IGrObject* pImage, const double& x, const double& y, const double& w, const double& h) { if (!CheckValidate(TRUE) || NULL == pImage) return S_FALSE; m_pRenderer->DrawImage((Aggplus::CImage*)pImage, x, y, w, h); return S_OK; } HRESULT CGraphicsRenderer::DrawImageFromFile(const std::wstring& bstrVal, const double& x, const double& y, const double& w, const double& h, const BYTE& lAlpha) { #if 0 MetaFile::CMetaFile oMetafile(m_pFontManager ? m_pFontManager->m_pApplication : NULL); if (oMetafile.LoadFromFile(bstrVal.c_str())) { this->Save(); bool bRet = oMetafile.DrawOnRenderer(this, x, y, w, h); this->Restore(); return bRet ? S_OK : S_FALSE; } #endif CCacheImage* pCacheImage = NULL; if (NULL != m_pCache) { pCacheImage = (CCacheImage*)m_pCache->Lock(bstrVal); } else { pCacheImage = new CCacheImage(NULL, bstrVal); } if (NULL != pCacheImage) { Aggplus::CImage* pImage = pCacheImage->GetImage(); m_pRenderer->DrawImage(pImage, x, y, w, h); RELEASEINTERFACE(pCacheImage); } return S_OK; } // transform -------------------------------------------------------------------------------- HRESULT CGraphicsRenderer::SetTransform(const double& m1, const double& m2, const double& m3, const double& m4, const double& m5, const double& m6) { if (!CheckValidate()) return S_FALSE; ApplyTransform(m1, m2, m3, m4, m5, m6); return S_OK; } HRESULT CGraphicsRenderer::GetTransform(double *pdA, double *pdB, double *pdC, double *pdD, double *pdE, double *pdF) { if (!CheckValidate()) return S_FALSE; double buffer[6]; Aggplus::CMatrix oMatrix; m_pRenderer->GetTransform()->GetElements(buffer); *pdA = (double)buffer[0]; *pdB = (double)buffer[1]; *pdC = (double)buffer[2]; *pdD = (double)buffer[3]; *pdE = (double)buffer[4]; *pdF = (double)buffer[5]; return S_OK; } HRESULT CGraphicsRenderer::ResetTransform() { _ResetTransform(); return S_OK; } // ----------------------------------------------------------------------------------------- HRESULT CGraphicsRenderer::get_ClipMode(LONG* plMode) { *plMode = m_lCurrentClipMode; return S_OK; } HRESULT CGraphicsRenderer::put_ClipMode(const LONG& lMode) { if (!CheckValidate()) return S_FALSE; m_lCurrentClipMode = lMode; return S_OK; } // additiaonal params ---------------------------------------------------------------------- HRESULT CGraphicsRenderer::CommandLong(const LONG& lType, const LONG& lCommand) { if (c_nDarkMode == lType && m_pRenderer) m_pRenderer->m_bIsDarkMode = (1 == lCommand); if (c_nUseDictionaryFonts == lType && m_pFontManager) m_pFontManager->SetUseCorrentFontByName((1 == lCommand) ? true : false); if (c_nPenWidth0As1px == lType && m_pRenderer) m_pRenderer->m_bIs0PenWidthAs1px = (1 == lCommand) ? true : false; return S_OK; } HRESULT CGraphicsRenderer::CommandDouble(const LONG& lType, const double& dCommand) { return S_OK; } HRESULT CGraphicsRenderer::CommandString(const LONG& lType, const std::wstring& sCommand) { return S_OK; } HRESULT CGraphicsRenderer::StartConvertCoordsToIdentity() { m_bUseTransformCoordsToIdentity = true; m_pPath->m_internal->m_pTransform = m_pRenderer->GetFullTransform(); return S_OK; } HRESULT CGraphicsRenderer::EndConvertCoordsToIdentity() { m_bUseTransformCoordsToIdentity = false; m_pPath->m_internal->m_pTransform = NULL; return S_OK; } // common void CGraphicsRenderer::_SetFont() { if (m_oInstalledFont.IsEqual(&m_oFont)) { if (1 < m_dWidth) { double dPix = m_oFont.CharSpace * m_dPixelsWidth / m_dWidth; m_pFontManager->SetCharSpacing(dPix); } return; } if (1 < m_dWidth) { double dPix = m_oFont.CharSpace * m_dPixelsWidth / m_dWidth; m_pFontManager->m_fCharSpacing = dPix; } if (m_oFont.Path.empty()) { m_pFontManager->LoadFontByName(m_oFont.Name, m_oFont.Size, m_oFont.GetStyle(), m_pRenderer->GetDpiX(), m_pRenderer->GetDpiY()); } else { m_pFontManager->LoadFontFromFile(m_oFont.Path, m_oFont.FaceIndex, m_oFont.Size, m_pRenderer->GetDpiX(), m_pRenderer->GetDpiY()); } m_pFontManager->m_oString.ResetCTM(); m_pFontManager->SetStringGID(m_oFont.StringGID); m_pFontManager->SetCharSpacing(m_pFontManager->m_fCharSpacing); m_oInstalledFont = m_oFont; } void CGraphicsRenderer::ApplyTransform(const double& d1, const double& d2, const double& d3, const double& d4, const double& d5, const double& d6) { Aggplus::CMatrix oMatrix(d1, d2, d3, d4, d5, d6); ApplyTransform(&oMatrix); } void CGraphicsRenderer::ApplyTransform(Aggplus::CMatrix* pMatrix) { if (!CheckValidate()) return; m_pRenderer->SetTransform(pMatrix); m_pRenderer->CalculateFullTransform(); } void CGraphicsRenderer::_ResetTransform() { if (!CheckValidate()) return; ApplyTransform(1, 0, 0, 1, 0, 0); } void CGraphicsRenderer::CreateFromBgraFrame(CBgraFrame* pFrame) { Aggplus::CDoubleRect oRect; oRect.left = 0; oRect.top = 0; oRect.right = pFrame->get_Width(); oRect.bottom = pFrame->get_Height(); if (pFrame->get_Stride() > 0) { CreateFlip(pFrame->get_Data(), oRect, pFrame->get_Width(), pFrame->get_Height()); } else { Create(pFrame->get_Data(), oRect, pFrame->get_Width(), pFrame->get_Height()); } } void CGraphicsRenderer::Create(BYTE* pPixels, const Aggplus::CDoubleRect& oRect, LONG lWidthControl, LONG lHeightControl, Aggplus::CDIB* pDib) { LONG lRectLeft = (LONG)oRect.left; LONG lRectTop = (LONG)oRect.top; LONG lWidth = (LONG)oRect.GetWidth(); LONG lHeight = (LONG)oRect.GetHeight(); m_dPixelsWidth = lWidth; m_dPixelsHeight = lHeight; LONG lStride = 4 * lWidthControl; m_pPixels = pPixels + (4 * lRectLeft); m_pPixels += lStride * lRectTop; RELEASEOBJECT(m_pRenderer); RELEASEOBJECT(m_pPath); m_pRenderer = new Aggplus::CGraphics(); m_pPath = new Aggplus::CGraphicsPath(); m_lClipLeft = (std::max)(0, (int) lRectLeft); m_lClipTop = (std::max)(0, (int) lRectTop); //LONG lClipRight = min(lWidth, -lRectLeft + lWidthControl); //LONG lClipBottom = min(lHeight, -lRectTop + lHeightControl); LONG lClipRight = (std::min)((LONG)oRect.right, lWidthControl); LONG lClipBottom = (std::min)((LONG)oRect.bottom, lHeightControl); m_lClipWidth = lClipRight - m_lClipLeft; m_lClipHeight = lClipBottom - m_lClipTop; m_pRenderer->Create2(pPixels, lWidthControl, lHeightControl, -4 * lWidthControl, 0, m_lClipLeft, m_lClipTop, m_lClipWidth, m_lClipHeight, oRect.GetWidth(), oRect.GetHeight(), pDib); Aggplus::CMatrix oBase(1, 0, 0, 1, oRect.left, oRect.top); m_pRenderer->SetBaseTransform(&oBase); m_pRenderer->SetPageWidth(m_dWidth, Aggplus::UnitMillimeter); m_pRenderer->SetPageHeight(m_dHeight, Aggplus::UnitMillimeter); m_pRenderer->SetPageUnit(Aggplus::UnitMillimeter); } void CGraphicsRenderer::CreateFlip(BYTE* pPixels, const Aggplus::CDoubleRect& oRect, LONG lWidthControl, LONG lHeightControl, Aggplus::CDIB* pDib) { LONG lRectLeft = (LONG)oRect.left; LONG lRectTop = (LONG)oRect.top; LONG lWidth = (LONG)oRect.GetWidth(); LONG lHeight = (LONG)oRect.GetHeight(); m_dPixelsWidth = lWidth; m_dPixelsHeight = lHeight; LONG lStride = 4 * lWidthControl; RELEASEOBJECT(m_pRenderer); RELEASEOBJECT(m_pPath); m_pRenderer = new Aggplus::CGraphics(); m_pPath = new Aggplus::CGraphicsPath(); m_lClipLeft = (std::max) (0, (int) lRectLeft); m_lClipTop = (std::max) (0, (int) lRectTop); //LONG lClipRight = min(lWidth, -lRectLeft + lWidthControl); //LONG lClipBottom = min(lHeight, -lRectTop + lHeightControl); LONG lClipRight = (std::min) ((LONG)oRect.right, lWidthControl); LONG lClipBottom = (std::min) ((LONG)oRect.bottom, lHeightControl); m_lClipWidth = lClipRight - m_lClipLeft; m_lClipHeight = lClipBottom - m_lClipTop; //m_pRenderer->Create(m_pPixels, lWidth, lHeight, -4 * lWidthControl, 0, colorModeRGBA8); m_pRenderer->Create2(pPixels, lWidthControl, lHeightControl, 4 * lWidthControl, 0, m_lClipLeft, m_lClipTop, m_lClipWidth, m_lClipHeight, oRect.GetWidth(), oRect.GetHeight(), pDib); Aggplus::CMatrix oBase(1, 0, 0, 1, oRect.left, oRect.top); m_pRenderer->SetBaseTransform(&oBase); m_pRenderer->SetPageWidth(m_dWidth, Aggplus::UnitMillimeter); m_pRenderer->SetPageHeight(m_dHeight, Aggplus::UnitMillimeter); m_pRenderer->SetPageUnit(Aggplus::UnitMillimeter); } void CGraphicsRenderer::SetAlphaMask(Aggplus::CAlphaMask *pAlphaMask) { m_pRenderer->SetAlphaMask(pAlphaMask); } Aggplus::CSoftMask* CGraphicsRenderer::CreateSoftMask(bool bAlpha) { return m_pRenderer->CreateSoftMask(bAlpha); } void CGraphicsRenderer::SetSoftMask(Aggplus::CSoftMask* pSoftMask) { m_pRenderer->SetSoftMask(pSoftMask); } HRESULT CGraphicsRenderer::put_LayerOpacity(double dValue) { return m_pRenderer->SetLayerOpacity(dValue); } void CGraphicsRenderer::put_GlobalAlphaEnabled(const bool& bEnabled, const double& dVal) { m_bGlobalAlphaEnabled = bEnabled; if (m_bGlobalAlphaEnabled) m_dGlobalAlpha = dVal; else m_dGlobalAlpha = 1.0; m_pRenderer->m_dGlobalAlpha = m_dGlobalAlpha; } void CGraphicsRenderer::AddRect(const double& x, const double& y, const double& w, const double& h) { if (!CheckValidate()) return; m_pPath->MoveTo(x, y); m_pPath->LineTo(x + w, y); m_pPath->LineTo(x + w, y + h); m_pPath->LineTo(x, y + h); m_pPath->CloseFigure(); } void CGraphicsRenderer::SetGammaStroke(double value) { m_dGammaStroke = value; } // SAVE/RESTORE section class CGraphicsRenderer_State : public IGraphicsRenderer_State { public: CGraphicsRenderer_State() : IGraphicsRenderer_State() { } CGraphicsRenderer_State(const Aggplus::CGraphics_ClipState& oState) : IGraphicsRenderer_State(), m_oClipState(oState) { } virtual ~CGraphicsRenderer_State() { } public: NSStructures::CPen m_oPen; NSStructures::CBrush m_oBrush; NSStructures::CFont m_oFont; Aggplus::CMatrix m_oTransform; double m_dGlobalAlpha; bool m_bGlobalAlphaEnabled; bool m_bIntegerGrid; unsigned int m_nBlendMode; Aggplus::CGraphics_ClipState m_oClipState; }; void CGraphicsRenderer::Save() { if (!m_pRenderer) return; CGraphicsRenderer_State* pState = new CGraphicsRenderer_State(m_pRenderer->m_oClipState); pState->m_oPen = m_oPen; pState->m_oBrush = m_oBrush; pState->m_oFont = m_oFont; pState->m_oTransform = *m_pRenderer->GetTransform(); pState->m_dGlobalAlpha = m_dGlobalAlpha; pState->m_bGlobalAlphaEnabled = m_bGlobalAlphaEnabled; pState->m_bIntegerGrid = m_pRenderer->m_bIntegerGrid; pState->m_nBlendMode = m_pRenderer->m_nBlendMode; m_arStates.push_back(pState); } void CGraphicsRenderer::Restore() { if (!m_pRenderer) return; if (0 == m_arStates.size()) return; CGraphicsRenderer_State* pState = (CGraphicsRenderer_State*)m_arStates.at(m_arStates.size() - 1); m_arStates.pop_back(); m_oPen = pState->m_oPen; m_oBrush = pState->m_oBrush; m_oFont = pState->m_oFont; ApplyTransform(&pState->m_oTransform); this->put_IntegerGrid(pState->m_bIntegerGrid); this->put_GlobalAlphaEnabled(pState->m_bGlobalAlphaEnabled, pState->m_dGlobalAlpha); this->put_BlendMode(pState->m_nBlendMode); m_pRenderer->ResetClip(); for (std::vector::iterator i = pState->m_oClipState.Records.begin(); i != pState->m_oClipState.Records.end(); i++) { Aggplus::CGraphics_ClipStateRecord* pRecord = *i; m_pRenderer->InternalClip(pRecord->Path, pRecord->Transform, pRecord->Operation); } RELEASEOBJECT(pState); } void CGraphicsRenderer::put_BlendMode(const unsigned int& nBlendMode) { if (NULL != m_pRenderer) { m_pRenderer->m_nBlendMode = nBlendMode; } }