/* * (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 "MetaFile.h" #include "Common/MetaFileTypes.h" #include "Common/MetaFileRenderer.h" #include "../../raster/BgraFrame.h" #include "../../graphics/pro/Graphics.h" #ifdef METAFILE_SUPPORT_WMF_EMF #include "Wmf/WmfInterpretator/CWmfInterpretatorSvg.h" #include "Emf/EmfInterpretator/CEmfInterpretatorSvg.h" #endif namespace MetaFile { IMetaFile* Create(NSFonts::IApplicationFonts *pAppFonts) { return new CMetaFile(pAppFonts); } CMetaFile::CMetaFile(NSFonts::IApplicationFonts *pAppFonts) : MetaFile::IMetaFile(pAppFonts) { m_pFontManager = NULL; m_pAppFonts = pAppFonts; // Создаем менеджер шрифтов с собственным кэшем if (pAppFonts) { m_pFontManager = pAppFonts->GenerateFontManager(); NSFonts::IFontsCache* pMeasurerCache = NSFonts::NSFontCache::Create(); pMeasurerCache->SetStreams(pAppFonts->GetStreams()); m_pFontManager->SetOwnerCache(pMeasurerCache); } #ifdef METAFILE_SUPPORT_WMF_EMF m_oWmfFile.SetFontManager(m_pFontManager); m_oEmfFile.SetFontManager(m_pFontManager); #endif #ifdef METAFILE_SUPPORT_SVM m_oSvmFile.SetFontManager(m_pFontManager); #endif #ifdef METAFILE_SUPPORT_SVG m_oSvgFile.SetFontManager(m_pFontManager); #endif m_lType = 0; } NSFonts::IFontManager* CMetaFile::get_FontManager() { return m_pFontManager; } CMetaFile::~CMetaFile() { Close(); RELEASEINTERFACE(m_pFontManager); } std::wstring CMetaFile::ConvertToSvg(unsigned int unWidth, unsigned int unHeight) { #ifdef METAFILE_SUPPORT_WMF_EMF if (c_lMetaWmf == m_lType) { m_oWmfFile.SetOutputDevice(InterpretatorType::Svg, unWidth, unHeight); m_oWmfFile.PlayMetaFile(); return ((CWmfInterpretatorSvg*)m_oWmfFile.GetWmfParser()->GetInterpretator())->GetFile(); } else if (c_lMetaEmf == m_lType) { m_oEmfFile.SetOutputDevice(InterpretatorType::Svg, unWidth, unHeight); m_oEmfFile.PlayMetaFile(); return ((CEmfInterpretatorSvg*)m_oEmfFile.GetEmfParser()->GetInterpretator())->GetFile(); } #endif return L""; } #ifdef METAFILE_SUPPORT_WMF_EMF void CMetaFile::ConvertToXml(const wchar_t *wsFilePath) { if (NULL == wsFilePath) return; m_oEmfFile.SetOutputDevice(wsFilePath, InterpretatorType::XML); m_oEmfFile.PlayMetaFile(); } void CMetaFile::ConvertToXmlAndRaster(const wchar_t *wsXmlFilePath, const wchar_t *wsOutFilePath, unsigned int unFileType, int nWidth, int nHeight) { if (NULL == wsXmlFilePath || NULL == wsOutFilePath) return; m_oEmfFile.SetOutputDevice(NULL, wsXmlFilePath); NSGraphics::IGraphicsRenderer* pGrRenderer = NSGraphics::Create(); NSFonts::IFontManager* pFontManager = m_pAppFonts->GenerateFontManager(); NSFonts::IFontsCache* pFontCache = NSFonts::NSFontCache::Create(); pFontCache->SetStreams(m_pAppFonts->GetStreams()); pFontManager->SetOwnerCache(pFontCache); pGrRenderer->SetFontManager(pFontManager); if (-1 == nHeight) { double dX, dY, dW, dH; GetBounds(&dX, &dY, &dW, &dH); if (dW < 0) dW = -dW; if (dH < 0) dH = -dH; if (nWidth < 0) nWidth = (int)(dW * 96 / 25.4); nHeight = (int)((double)nWidth * dH / dW); } double dWidth = 25.4 * nWidth / 96; double dHeight = 25.4 * nHeight / 96; BYTE* pBgraData = new(std::nothrow) BYTE[nWidth * nHeight * 4]; if (!pBgraData) return; unsigned int alfa = 0xffffff; //дефолтный тон должен быть прозрачным, а не белым //memset(pBgraData, 0xff, nWidth * nHeight * 4); for (int i = 0; i < nWidth * nHeight; i++) { ((unsigned int*)pBgraData)[i] = alfa; } CBgraFrame oFrame; oFrame.put_Data(pBgraData); oFrame.put_Width(nWidth); oFrame.put_Height(nHeight); oFrame.put_Stride(-4 * nWidth); pGrRenderer->CreateFromBgraFrame(&oFrame); pGrRenderer->SetSwapRGB(false); pGrRenderer->put_Width(dWidth); pGrRenderer->put_Height(dHeight); DrawOnRenderer(wsXmlFilePath, pGrRenderer, 0, 0, dWidth, dHeight); oFrame.SaveFile(wsOutFilePath, unFileType); RELEASEINTERFACE(pFontManager); RELEASEINTERFACE(pGrRenderer); } bool CMetaFile::DrawOnRenderer(const wchar_t *wsXmlFilePath, IRenderer *pRenderer, double dX, double dY, double dWidth, double dHeight) { if (NULL == wsXmlFilePath || NULL == pRenderer) return false; pRenderer->BeginCommand(c_nImageType); switch (m_lType) { #ifdef METAFILE_SUPPORT_WMF_EMF case c_lMetaWmf: { CMetaFileRenderer oWmfOut(m_oWmfFile.GetWmfParser(), pRenderer, dX, dY, dWidth, dHeight); m_oWmfFile.SetOutputDevice((IOutputDevice*)&oWmfOut); m_oWmfFile.PlayMetaFile(); break; } case c_lMetaEmf: { CMetaFileRenderer oEmfOut(m_oEmfFile.GetEmfParser(), pRenderer, dX, dY, dWidth, dHeight); m_oEmfFile.SetOutputDevice((IOutputDevice*)&oEmfOut, wsXmlFilePath); m_oEmfFile.PlayMetaFile(); break; } #endif #ifdef METAFILE_SUPPORT_SVM case c_lMetaSvm: { CMetaFileRenderer oSvmOut(&m_oSvmFile, pRenderer, dX, dY, dWidth, dHeight); m_oSvmFile.SetOutputDevice((IOutputDevice*)&oSvmOut); m_oSvmFile.PlayMetaFile(); break; } #endif #ifdef METAFILE_SUPPORT_SVG case c_lMetaSvg: { m_oSvgFile.Draw(pRenderer, dX, dY, dWidth, dHeight); break; } #endif default: break; } pRenderer->EndCommand(c_nImageType); return true; } bool CMetaFile::LoadFromXmlFile(const wchar_t *wsFilePath) { RELEASEINTERFACE(m_pFontManager); if (m_pAppFonts) { m_pFontManager = m_pAppFonts->GenerateFontManager(); NSFonts::IFontsCache* pMeasurerCache = NSFonts::NSFontCache::Create(); pMeasurerCache->SetStreams(m_pAppFonts->GetStreams()); m_pFontManager->SetOwnerCache(pMeasurerCache); } m_oWmfFile.SetFontManager(m_pFontManager); m_oEmfFile.SetFontManager(m_pFontManager); #ifdef METAFILE_SUPPORT_SVM m_oSvmFile.SetFontManager(m_pFontManager); #endif #ifdef METAFILE_SUPPORT_SVG m_oSvgFile.SetFontManager(m_pFontManager); #endif #ifdef METAFILE_SUPPORT_WMF_EMF_XML if (m_oEmfFile.OpenFromXmlFile(wsFilePath) == true) { m_oEmfFile.Scan(); if (!m_oEmfFile.CheckError()) { m_lType = c_lMetaEmf; return true; } m_oEmfFile.Close(); } #endif return false; } void CMetaFile::ConvertToEmf(const wchar_t *wsFilePath) { if (m_lType != c_lMetaEmf || m_oEmfFile.GetEmfParser()->GetType() != EmfParserType::EmfxParser) return; m_oEmfFile.SetOutputDevice(wsFilePath, InterpretatorType::Emf); m_oEmfFile.PlayMetaFile(); //TODO:: сохранение в *.emf файл } #endif bool CMetaFile::LoadFromFile(const wchar_t *wsFilePath) { // TODO: Сейчас при загрузке каждой новой картинки мы пересоздаем // FontManager, потому что сейчас в нем кэш без ограничения. //------------------------------------------------------ RELEASEINTERFACE(m_pFontManager); if (m_pAppFonts) { m_pFontManager = m_pAppFonts->GenerateFontManager(); NSFonts::IFontsCache* pMeasurerCache = NSFonts::NSFontCache::Create(); pMeasurerCache->SetStreams(m_pAppFonts->GetStreams()); m_pFontManager->SetOwnerCache(pMeasurerCache); } #ifdef METAFILE_SUPPORT_WMF_EMF m_oWmfFile.SetFontManager(m_pFontManager); m_oEmfFile.SetFontManager(m_pFontManager); #endif #ifdef METAFILE_SUPPORT_SVM m_oSvmFile.SetFontManager(m_pFontManager); #endif #ifdef METAFILE_SUPPORT_SVG m_oSvgFile.SetFontManager(m_pFontManager); #endif //------------------------------------------------------ #ifdef METAFILE_SUPPORT_WMF_EMF // Сначала пытаемся открыть файл как Wmf if (m_oWmfFile.OpenFromWmfFile(wsFilePath) == true) { m_oWmfFile.Scan(); if (!m_oWmfFile.CheckError()) { m_lType = c_lMetaWmf; return true; } m_oWmfFile.Close(); } // Это не Wmf if (m_oEmfFile.OpenFromEmfFile(wsFilePath) == true) { m_oEmfFile.Scan(); if (!m_oEmfFile.CheckError()) { m_lType = c_lMetaEmf; return true; } m_oEmfFile.Close(); } #endif // Это не Emf #ifdef METAFILE_SUPPORT_SVM if (m_oSvmFile.OpenFromFile(wsFilePath) == true) { m_oSvmFile.Scan(); if (!m_oSvmFile.CheckError()) { m_lType = c_lMetaSvm; return true; } m_oSvmFile.Close(); } #endif // Это не svm #ifdef METAFILE_SUPPORT_SVG if (m_oSvgFile.OpenFromFile(wsFilePath) == true) { m_lType = c_lMetaSvg; return true; } #endif return false; } bool CMetaFile::LoadFromBuffer(BYTE *pBuffer, unsigned int unSize) { if (NULL == pBuffer || 0 == unSize) return false; // TODO: Сейчас при загрузке каждой новой картинки мы пересоздаем // FontManager, потому что сейчас в нем кэш без ограничения. //------------------------------------------------------ RELEASEINTERFACE(m_pFontManager); if (m_pAppFonts) { m_pFontManager = m_pAppFonts->GenerateFontManager(); NSFonts::IFontsCache* pMeasurerCache = NSFonts::NSFontCache::Create(); pMeasurerCache->SetStreams(m_pAppFonts->GetStreams()); m_pFontManager->SetOwnerCache(pMeasurerCache); } #ifdef METAFILE_SUPPORT_WMF_EMF m_oWmfFile.SetFontManager(m_pFontManager); m_oEmfFile.SetFontManager(m_pFontManager); #endif #ifdef METAFILE_SUPPORT_SVM m_oSvmFile.SetFontManager(m_pFontManager); #endif #ifdef METAFILE_SUPPORT_SVG m_oSvgFile.SetFontManager(m_pFontManager); #endif //------------------------------------------------------ #ifdef METAFILE_SUPPORT_WMF_EMF // Сначала пытаемся открыть файл как Wmf if (m_oWmfFile.ReadFromBuffer(pBuffer, unSize) == true) { m_oWmfFile.Scan(); if (!m_oWmfFile.CheckError()) { m_lType = c_lMetaWmf; return true; } m_oWmfFile.Close(); } // Это не Wmf if (m_oEmfFile.ReadFromBuffer(pBuffer, unSize) == true) { m_oEmfFile.Scan(); if (!m_oEmfFile.CheckError()) { m_lType = c_lMetaEmf; return true; } m_oEmfFile.Close(); } #endif // Это не Emf #ifdef METAFILE_SUPPORT_SVM if (m_oSvmFile.ReadFromBuffer(pBuffer, unSize) == true) { m_oSvmFile.Scan(); if (!m_oSvmFile.CheckError()) { m_lType = c_lMetaSvm; return true; } m_oSvmFile.Close(); } #endif // Это не svm #ifdef METAFILE_SUPPORT_SVG if (m_oSvgFile.ReadFromBuffer(pBuffer, unSize) == true) { m_lType = c_lMetaSvg; return true; } #endif return false; } bool CMetaFile::LoadFromString(const std::wstring& data) { #ifdef METAFILE_SUPPORT_SVG RELEASEINTERFACE(m_pFontManager); if (m_pAppFonts) { m_pFontManager = m_pAppFonts->GenerateFontManager(); NSFonts::IFontsCache* pMeasurerCache = NSFonts::NSFontCache::Create(); pMeasurerCache->SetStreams(m_pAppFonts->GetStreams()); m_pFontManager->SetOwnerCache(pMeasurerCache); } m_oSvgFile.SetFontManager(m_pFontManager); if (m_oSvgFile.ReadFromWString(data) == true) { m_lType = c_lMetaSvg; return true; } #endif return false; } void CMetaFile::SetTempDirectory(const std::wstring& dir) { #ifdef METAFILE_SUPPORT_SVG m_oSvgFile.SetWorkingDirectory(dir); #endif } bool CMetaFile::DrawOnRenderer(IRenderer* pRenderer, double dX, double dY, double dWidth, double dHeight) { if (NULL == pRenderer) return false; pRenderer->BeginCommand(c_nImageType); switch (m_lType) { #ifdef METAFILE_SUPPORT_WMF_EMF case c_lMetaWmf: { CMetaFileRenderer oWmfOut(m_oWmfFile.GetWmfParser(), pRenderer, dX, dY, dWidth, dHeight); m_oWmfFile.SetOutputDevice((IOutputDevice*)&oWmfOut); m_oWmfFile.PlayMetaFile(); break; } case c_lMetaEmf: { CMetaFileRenderer oEmfOut(m_oEmfFile.GetEmfParser(), pRenderer, dX, dY, dWidth, dHeight); m_oEmfFile.SetOutputDevice((IOutputDevice*)&oEmfOut); m_oEmfFile.PlayMetaFile(); break; } #endif #ifdef METAFILE_SUPPORT_SVM case c_lMetaSvm: { CMetaFileRenderer oSvmOut(&m_oSvmFile, pRenderer, dX, dY, dWidth, dHeight); m_oSvmFile.SetOutputDevice((IOutputDevice*)&oSvmOut); m_oSvmFile.PlayMetaFile(); break; } #endif #ifdef METAFILE_SUPPORT_SVG case c_lMetaSvg: { m_oSvgFile.Draw(pRenderer, dX, dY, dWidth, dHeight); break; } #endif default: break; } pRenderer->EndCommand(c_nImageType); return true; } void CMetaFile::Close() { #ifdef METAFILE_SUPPORT_WMF_EMF m_oWmfFile.Close(); m_oEmfFile.Close(); #endif #ifdef METAFILE_SUPPORT_SVM m_oSvmFile.Close(); #endif m_lType = 0; } int CMetaFile::GetType() { return m_lType; } void CMetaFile::GetBounds(double* pdX, double* pdY, double* pdW, double* pdH) { switch (m_lType) { #ifdef METAFILE_SUPPORT_WMF_EMF case c_lMetaWmf: { const TRectL& oRect{m_oWmfFile.GetBounds()}; *pdX = oRect.Left; *pdY = oRect.Top; *pdW = oRect.Right - oRect.Left; *pdH = oRect.Bottom - oRect.Top; break; } case c_lMetaEmf: { const TRectL& oRect{m_oEmfFile.GetBounds()}; *pdX = oRect.Left; *pdY = oRect.Top; *pdW = oRect.Right - oRect.Left; *pdH = oRect.Bottom - oRect.Top; break; } #endif #ifdef METAFILE_SUPPORT_SVM case c_lMetaSvm: { const TRectL& oRect{m_oSvmFile.GetBounds()}; *pdX = oRect.Left; *pdY = oRect.Top; *pdW = oRect.Right - oRect.Left; *pdH = oRect.Bottom - oRect.Top; if (*pdW > 10000 || *pdH > 10000) { *pdW /= 10; *pdH /= 10; } break; } #endif #ifdef METAFILE_SUPPORT_SVG case c_lMetaSvg: { m_oSvgFile.GetBounds(*pdX, *pdY, *pdW, *pdH); break; } #endif default: { *pdX = 0; *pdY = 0; *pdW = 0; *pdH = 0; break; } } if (*pdW < 0) *pdW = -*pdW; if (*pdH < 0) *pdH = -*pdH; } void CMetaFile::ConvertToRaster(const wchar_t* wsOutFilePath, unsigned int unFileType, int nWidth, int nHeight) { if (nWidth == 0 || nHeight == 0) return; NSGraphics::IGraphicsRenderer* pGrRenderer = NSGraphics::Create(); NSFonts::IFontManager* pFontManager = m_pAppFonts->GenerateFontManager(); NSFonts::IFontsCache* pFontCache = NSFonts::NSFontCache::Create(); pFontCache->SetStreams(m_pAppFonts->GetStreams()); pFontManager->SetOwnerCache(pFontCache); pGrRenderer->SetFontManager(pFontManager); if (-1 == nHeight) { double dX, dY, dW, dH; GetBounds(&dX, &dY, &dW, &dH); if (dW < 0) dW = -dW; if (dH < 0) dH = -dH; if (nWidth < 0) nWidth = (int)(dW * 96 / 25.4); nHeight = (int)((double)nWidth * dH / dW); } double dWidth = 25.4 * nWidth / 96; double dHeight = 25.4 * nHeight / 96; BYTE* pBgraData = (BYTE*)malloc(nWidth * nHeight * 4); if (!pBgraData) { double dKoef = 2000.0 / (nWidth > nHeight ? nWidth : nHeight); nWidth = (int)(dKoef * nWidth); nHeight = (int)(dKoef * nHeight); dWidth = 25.4 * nWidth / 96; dHeight = 25.4 * nHeight / 96; pBgraData = (BYTE*)malloc(nWidth * nHeight * 4); } if (!pBgraData) return; unsigned int alfa = 0xffffff; //дефолтный тон должен быть прозрачным, а не белым //memset(pBgraData, 0xff, nWidth * nHeight * 4); for (int i = 0; i < nWidth * nHeight; i++) { ((unsigned int*)pBgraData)[i] = alfa; } CBgraFrame oFrame; oFrame.put_Data(pBgraData); oFrame.put_Width(nWidth); oFrame.put_Height(nHeight); oFrame.put_Stride(-4 * nWidth); pGrRenderer->CreateFromBgraFrame(&oFrame); pGrRenderer->SetSwapRGB(false); pGrRenderer->put_Width(dWidth); pGrRenderer->put_Height(dHeight); DrawOnRenderer(pGrRenderer, 0, 0, dWidth, dHeight); oFrame.SaveFile(wsOutFilePath, unFileType); oFrame.put_Data(NULL); RELEASEINTERFACE(pFontManager); RELEASEINTERFACE(pGrRenderer); if (pBgraData) free(pBgraData); } }