From e27a20f9aea4f20e036e62793e932f1acec7c37a Mon Sep 17 00:00:00 2001 From: Kulikova Svetlana Date: Wed, 2 Nov 2022 17:50:50 +0300 Subject: [PATCH] new PdfReader and PdfWriter for PdfFile --- PdfFile/PdfFile.cpp | 88 +- PdfFile/PdfFile.h | 37 +- PdfFile/PdfFile.pro | 23 +- PdfFile/Src/OnlineOfficeBinToPdf.cpp | 148 ++ PdfFile/Src/OnlineOfficeBinToPdf.h | 44 + PdfFile/Src/PdfReader.cpp | 787 +++++++ PdfFile/Src/PdfReader.h | 109 + PdfFile/Src/PdfWriter.cpp | 2933 ++++++++++++++++++++++++++ PdfFile/Src/PdfWriter.h | 1864 ++++++++++++++++ PdfFile/test/test.cpp | 2 +- PdfWriter/PdfRenderer.cpp | 2 + PdfWriter/PdfRenderer.h | 21 +- 12 files changed, 6026 insertions(+), 32 deletions(-) create mode 100644 PdfFile/Src/OnlineOfficeBinToPdf.cpp create mode 100644 PdfFile/Src/OnlineOfficeBinToPdf.h create mode 100644 PdfFile/Src/PdfReader.cpp create mode 100644 PdfFile/Src/PdfReader.h create mode 100644 PdfFile/Src/PdfWriter.cpp create mode 100644 PdfFile/Src/PdfWriter.h diff --git a/PdfFile/PdfFile.cpp b/PdfFile/PdfFile.cpp index 5a57324670..e076f13f76 100644 --- a/PdfFile/PdfFile.cpp +++ b/PdfFile/PdfFile.cpp @@ -1,6 +1,38 @@ +/* + * (c) Copyright Ascensio System SIA 2010-2019 + * + * 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-12 Ernesta Birznieka-Upisha + * 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 "PdfFile.h" -#include "../PdfWriter/PdfRenderer.h" -#include "../PdfReader/PdfReader.h" +#include "Src/PdfWriter.h" +#include "Src/OnlineOfficeBinToPdf.h" +#include "Src/PdfReader.h" #include "../PdfReader/Src/Adaptors.h" #include "../DesktopEditor/common/File.h" @@ -127,11 +159,12 @@ void DictToCDictObject(Object* obj, PdfWriter::CObjectBase* pObj, bool bBinary, class CPdfFile_Private { public: - CPdfRenderer* pWriter; + CPdfWriter* pWriter; PdfReader::CPdfReader* pReader; std::wstring wsSrcFile; std::wstring wsPassword; bool bEdit; + bool bEditPage; void GetPageTree(XRef* xref, Object* pPagesRefObj) { @@ -206,9 +239,11 @@ CPdfFile::CPdfFile(NSFonts::IApplicationFonts* pAppFonts, bool isPDFA) { m_pInternal = new CPdfFile_Private(); - m_pInternal->pWriter = new CPdfRenderer (pAppFonts, isPDFA); + m_pInternal->pWriter = new CPdfWriter(pAppFonts, isPDFA); m_pInternal->pReader = new PdfReader::CPdfReader(pAppFonts); m_pInternal->wsPassword = L""; + m_pInternal->bEdit = false; + m_pInternal->bEditPage = false; } // nMode = 1/2/3, 01 - reader, 10 - writer, 11 - editer CPdfFile::CPdfFile(NSFonts::IApplicationFonts* pAppFonts, int nMode, bool isPDFA) @@ -218,8 +253,10 @@ CPdfFile::CPdfFile(NSFonts::IApplicationFonts* pAppFonts, int nMode, bool isPDFA if (nMode & 1) m_pInternal->pReader = new PdfReader::CPdfReader(pAppFonts); if (nMode & 2) - m_pInternal->pWriter = new CPdfRenderer (pAppFonts, isPDFA); + m_pInternal->pWriter = new CPdfWriter(pAppFonts, isPDFA); m_pInternal->wsPassword = L""; + m_pInternal->bEdit = false; + m_pInternal->bEditPage = false; } CPdfFile::~CPdfFile() { @@ -401,7 +438,7 @@ bool CPdfFile::EditPdf(const std::wstring& wsDstFile) if (bRes) { m_pInternal->GetPageTree(xref, &pagesRefObj); - m_pInternal->pWriter->EditPdf(); + m_pInternal->bEdit = true; } pagesRefObj.free(); return bRes; @@ -410,7 +447,7 @@ bool CPdfFile::EditClose() { PDFDoc* pPDFDocument = m_pInternal->pReader->GetPDFDocument(); PdfWriter::CDocument* pDoc = m_pInternal->pWriter->GetPDFDocument(); - if (!pPDFDocument || !pDoc) + if (!pPDFDocument || !pDoc || !m_pInternal->bEdit) return false; XRef* xref = pPDFDocument->getXRef(); @@ -499,13 +536,15 @@ bool CPdfFile::EditClose() } } + m_pInternal->bEdit = false; + m_pInternal->bEditPage = false; return bRes; } bool CPdfFile::EditPage(int nPageIndex) { PDFDoc* pPDFDocument = m_pInternal->pReader->GetPDFDocument(); PdfWriter::CDocument* pDoc = m_pInternal->pWriter->GetPDFDocument(); - if (!pPDFDocument || !pDoc) + if (!pPDFDocument || !pDoc || !m_pInternal->bEdit) return false; XRef* xref = pPDFDocument->getXRef(); @@ -557,6 +596,7 @@ bool CPdfFile::EditPage(int nPageIndex) pNewPage->Fix(); pageObj.free(); + m_pInternal->bEditPage = true; if (m_pInternal->pWriter->EditPage(pNewPage) && pDoc->EditPage(pXref, pNewPage)) return true; @@ -565,10 +605,14 @@ bool CPdfFile::EditPage(int nPageIndex) } bool CPdfFile::DeletePage(int nPageIndex) { + if (!m_pInternal->bEdit) + return false; return m_pInternal->pWriter->DeletePage(nPageIndex); } bool CPdfFile::AddPage(int nPageIndex) { + if (!m_pInternal->bEdit) + return false; bool bRes = m_pInternal->pWriter->AddPage(nPageIndex); if (bRes) { @@ -581,15 +625,20 @@ bool CPdfFile::AddPage(int nPageIndex) m_pInternal->pWriter->put_Width(dWidth); m_pInternal->pWriter->put_Height(dHeight); + m_pInternal->bEditPage = true; } return bRes; } void CPdfFile::Sign(const double& dX, const double& dY, const double& dW, const double& dH, const std::wstring& wsPicturePath, ICertificate* pCertificate) { + if (!m_pInternal->bEdit) + return; m_pInternal->pWriter->Sign(dX, dY, dW, dH, wsPicturePath, pCertificate); } void CPdfFile::PageRotate(int nRotate) { + if (!m_pInternal->bEdit) + return; m_pInternal->pWriter->PageRotate(nRotate); } @@ -642,7 +691,7 @@ void CPdfFile::GetPageInfo(int nPageIndex, double* pdWidth, double* pdHeight, do } void CPdfFile::DrawPageOnRenderer(IRenderer* pRenderer, int nPageIndex, bool* pBreak) { - m_pInternal->pReader->DrawPageOnRenderer((pRenderer == this ? m_pInternal->pWriter : pRenderer), nPageIndex, pBreak); + m_pInternal->pReader->DrawPageOnRenderer(this, nPageIndex, pBreak); } std::wstring CPdfFile::GetInfo() { @@ -679,11 +728,17 @@ void CPdfFile::SetTempFolder(const std::wstring& wsPath) } HRESULT CPdfFile::OnlineWordToPdf(const std::wstring& wsSrcFile, const std::wstring& wsDstFile, CConvertFromBinParams* pParams) { - return m_pInternal->pWriter->OnlineWordToPdf(wsSrcFile, wsDstFile, pParams); + if (!NSOnlineOfficeBinToPdf::ConvertBinToPdf(this, wsSrcFile, wsDstFile, false, pParams)) + return S_FALSE; + + return S_OK; } HRESULT CPdfFile::OnlineWordToPdfFromBinary(const std::wstring& wsSrcFile, const std::wstring& wsDstFile, CConvertFromBinParams* pParams) { - return m_pInternal->pWriter->OnlineWordToPdfFromBinary(wsSrcFile, wsDstFile, pParams); + if (!NSOnlineOfficeBinToPdf::ConvertBinToPdf(this, wsSrcFile, wsDstFile, true, pParams)) + return S_FALSE; + + return S_OK; } HRESULT CPdfFile::DrawImageWith1bppMask(IGrObject* pImage, NSImages::CPixJbig2* pMaskBuffer, const unsigned int& unMaskWidth, const unsigned int& unMaskHeight, const double& dX, const double& dY, const double& dW, const double& dH) { @@ -701,7 +756,10 @@ HRESULT CPdfFile::SetRadialGradient(const double& dX1, const double& dY1, const { return m_pInternal->pWriter->SetRadialGradient(dX1, dY1, dR1, dX2, dY2, dR2); } - +NSFonts::IApplicationFonts* CPdfFile::GetApplicationFonts() +{ + return m_pInternal->pWriter->GetApplicationFonts(); +} HRESULT CPdfFile::get_Type(LONG* lType) { @@ -709,6 +767,8 @@ HRESULT CPdfFile::get_Type(LONG* lType) } HRESULT CPdfFile::NewPage() { + if (m_pInternal->bEdit) + return S_FALSE; return m_pInternal->pWriter->NewPage(); } HRESULT CPdfFile::get_Height(double* dHeight) @@ -717,6 +777,8 @@ HRESULT CPdfFile::get_Height(double* dHeight) } HRESULT CPdfFile::put_Height(const double& dHeight) { + if (m_pInternal->bEdit && m_pInternal->bEditPage) + return S_OK; return m_pInternal->pWriter->put_Height(dHeight); } HRESULT CPdfFile::get_Width(double* dWidth) @@ -725,6 +787,8 @@ HRESULT CPdfFile::get_Width(double* dWidth) } HRESULT CPdfFile::put_Width(const double& dWidth) { + if (m_pInternal->bEdit && m_pInternal->bEditPage) + return S_OK; return m_pInternal->pWriter->put_Width(dWidth); } HRESULT CPdfFile::get_DpiX(double* dDpiX) diff --git a/PdfFile/PdfFile.h b/PdfFile/PdfFile.h index 882a296666..9d4f236be2 100644 --- a/PdfFile/PdfFile.h +++ b/PdfFile/PdfFile.h @@ -1,3 +1,34 @@ +/* + * (c) Copyright Ascensio System SIA 2010-2019 + * + * 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-12 Ernesta Birznieka-Upisha + * 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 + * + */ #ifndef _PDF_FILE_H #define _PDF_FILE_H @@ -8,11 +39,9 @@ #define PDFFILE_DECL_EXPORT Q_DECL_EXPORT #endif -#include "../DesktopEditor/graphics/pro/officedrawingfile.h" #include "../DesktopEditor/graphics/IRenderer.h" - -#include "../DesktopEditor/graphics/pro/Fonts.h" #include "../DesktopEditor/graphics/pro/Image.h" +#include "../DesktopEditor/graphics/pro/officedrawingfile.h" #include "../DesktopEditor/xmlsec/src/include/Certificate.h" class CPdfFile_Private; @@ -108,7 +137,7 @@ public: HRESULT DrawImage1bpp(NSImages::CPixJbig2* pImageBuffer, const unsigned int& unWidth, const unsigned int& unHeight, const double& dX, const double& dY, const double& dW, const double& dH); HRESULT SetLinearGradient(const double& dX1, const double& dY1, const double& dX2, const double& dY2); HRESULT SetRadialGradient(const double& dX1, const double& dY1, const double& dR1, const double& dX2, const double& dY2, const double& dR2); - + NSFonts::IApplicationFonts* GetApplicationFonts(); //---------------------------------------------------------------------------------------- // Тип рендерера diff --git a/PdfFile/PdfFile.pro b/PdfFile/PdfFile.pro index d070987a29..81adb504f6 100644 --- a/PdfFile/PdfFile.pro +++ b/PdfFile/PdfFile.pro @@ -56,15 +56,13 @@ SOURCES -= \ SOURCES += \ $$PDFREADER_ROOT_DIR/Src/RendererOutputDev.cpp \ $$PDFREADER_ROOT_DIR/Src/Adaptors.cpp \ - $$PDFREADER_ROOT_DIR/Src/GfxClip.cpp \ - $$PDFREADER_ROOT_DIR/PdfReader.cpp + $$PDFREADER_ROOT_DIR/Src/GfxClip.cpp HEADERS += \ $$PDFREADER_ROOT_DIR/Src/RendererOutputDev.h \ $$PDFREADER_ROOT_DIR/Src/Adaptors.h \ $$PDFREADER_ROOT_DIR/Src/MemoryUtils.h \ - $$PDFREADER_ROOT_DIR/Src/GfxClip.h \ - $$PDFREADER_ROOT_DIR/PdfReader.h + $$PDFREADER_ROOT_DIR/Src/GfxClip.h # Base fonts HEADERS += \ @@ -165,8 +163,6 @@ HEADERS += \ $$PDFWRITER_ROOT_DIR/Src/Streams.h \ $$PDFWRITER_ROOT_DIR/Src/Types.h \ $$PDFWRITER_ROOT_DIR/Src/Utils.h \ - $$PDFWRITER_ROOT_DIR/OnlineOfficeBinToPdf.h \ - $$PDFWRITER_ROOT_DIR/PdfRenderer.h \ $$PDFWRITER_ROOT_DIR/Src/Metadata.h \ $$PDFWRITER_ROOT_DIR/Src/ICCProfile.h @@ -195,11 +191,16 @@ SOURCES += \ $$PDFWRITER_ROOT_DIR/Src/Shading.cpp \ $$PDFWRITER_ROOT_DIR/Src/Streams.cpp \ $$PDFWRITER_ROOT_DIR/Src/Utils.cpp \ - $$PDFWRITER_ROOT_DIR/Src/Metadata.cpp \ - $$PDFWRITER_ROOT_DIR/OnlineOfficeBinToPdf.cpp \ - $$PDFWRITER_ROOT_DIR/PdfRenderer.cpp + $$PDFWRITER_ROOT_DIR/Src/Metadata.cpp # PdfFile -HEADERS += PdfFile.h -SOURCES += PdfFile.cpp +HEADERS += PdfFile.h \ + Src/PdfWriter.h \ + Src/PdfReader.h \ + Src/OnlineOfficeBinToPdf.h + +SOURCES += PdfFile.cpp \ + Src/PdfWriter.cpp \ + Src/PdfReader.cpp \ + Src/OnlineOfficeBinToPdf.cpp diff --git a/PdfFile/Src/OnlineOfficeBinToPdf.cpp b/PdfFile/Src/OnlineOfficeBinToPdf.cpp new file mode 100644 index 0000000000..dc990ff97a --- /dev/null +++ b/PdfFile/Src/OnlineOfficeBinToPdf.cpp @@ -0,0 +1,148 @@ +/* + * (c) Copyright Ascensio System SIA 2010-2019 + * + * 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-12 Ernesta Birznieka-Upisha + * 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 "OnlineOfficeBinToPdf.h" + +#include "../../DesktopEditor/common/File.h" +#include "../../DesktopEditor/common/Directory.h" +#include "../../DesktopEditor/common/Base64.h" +#include "../../DesktopEditor/graphics/MetafileToRenderer.h" + +namespace NSOnlineOfficeBinToPdf +{ + class CMetafileToRenderterPDF : public IMetafileToRenderter + { + public: + CMetafileToRenderterPDF(IRenderer* pRenderer) : IMetafileToRenderter(pRenderer) + { + } + + public: + virtual void SetLinearGradiant(const double& x0, const double& y0, const double& x1, const double& y1) + { + ((CPdfFile*)m_pRenderer)->SetLinearGradient(x0, y0, x1, y1); + } + + virtual void SetRadialGradiant(const double& dX0, const double& dY0, const double& dR0, const double& dX1, const double& dY1, const double& dR1) + { + ((CPdfFile*)m_pRenderer)->SetRadialGradient(dX0, dY0, dR0, dX1, dY1, dR1); + } + }; + + static bool ConvertBufferToPdf(CPdfFile* pPdf, BYTE* pBuffer, LONG lBufferLen, CConvertFromBinParams* pParams) + { + CMetafileToRenderterPDF oCorrector(pPdf); + oCorrector.SetTempDirectory(pPdf->GetTempDirectory()); + if (pParams) + { + oCorrector.SetMediaDirectory(pParams->m_sMediaDirectory); + oCorrector.SetInternalMediaDirectory(pParams->m_sInternalMediaDirectory); + oCorrector.SetThemesDirectory(pParams->m_sThemesDirectory); + + if (pParams->m_bIsUsePicker) + oCorrector.InitPicker(pPdf->GetApplicationFonts()); + } + NSOnlineOfficeBinToPdf::ConvertBufferToRenderer(pBuffer, lBufferLen, &oCorrector); + + return true; + } + bool ConvertBinToPdf(CPdfFile* pPdf, const std::wstring& wsSrcFile, const std::wstring& wsDstFile, bool bBinary, CConvertFromBinParams* pParams) + { + NSFile::CFileBinary oFile; + if (!oFile.OpenFile(wsSrcFile)) + return false; + + DWORD dwFileSize = oFile.GetFileSize(); + BYTE* pFileContent = new BYTE[dwFileSize]; + if (!pFileContent) + { + oFile.CloseFile(); + return false; + } + + DWORD dwReaded; + oFile.ReadFile(pFileContent, dwFileSize, dwReaded); + oFile.CloseFile(); + + bool bIsNeedDestroy = (NULL == pParams) ? true : false; + if (bIsNeedDestroy) + pParams = new CConvertFromBinParams(); + + if (pParams->m_sMediaDirectory.empty()) + pParams->m_sMediaDirectory = NSFile::GetDirectoryName(wsSrcFile); + + if (bBinary) + { + ConvertBufferToPdf(pPdf, pFileContent, dwFileSize, pParams); + } + else + { + int nBufferLen = NSBase64::Base64DecodeGetRequiredLength(dwFileSize); + BYTE* pBuffer = new BYTE[nBufferLen]; + if (!pBuffer) + { + RELEASEARRAYOBJECTS(pFileContent); + + if (bIsNeedDestroy) + RELEASEOBJECT(pParams); + return false; + } + + if (NSBase64::Base64Decode((const char*)pFileContent, dwFileSize, pBuffer, &nBufferLen)) + { + ConvertBufferToPdf(pPdf, pBuffer, nBufferLen, pParams); + } + else + { + RELEASEARRAYOBJECTS(pBuffer); + RELEASEARRAYOBJECTS(pFileContent); + + if (bIsNeedDestroy) + RELEASEOBJECT(pParams); + return false; + } + + RELEASEARRAYOBJECTS(pBuffer); + } + RELEASEARRAYOBJECTS(pFileContent); + + if (bIsNeedDestroy) + RELEASEOBJECT(pParams); + + if (!wsDstFile.empty()) + { + if (0 != pPdf->SaveToFile(wsDstFile)) + return false; + } + + return true; + } +} diff --git a/PdfFile/Src/OnlineOfficeBinToPdf.h b/PdfFile/Src/OnlineOfficeBinToPdf.h new file mode 100644 index 0000000000..f0acd449d2 --- /dev/null +++ b/PdfFile/Src/OnlineOfficeBinToPdf.h @@ -0,0 +1,44 @@ +/* + * (c) Copyright Ascensio System SIA 2010-2019 + * + * 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-12 Ernesta Birznieka-Upisha + * 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 + * + */ +#ifndef _PDF_WRITER_ONLINEOFFICEBINTOPDF_H +#define _PDF_WRITER_ONLINEOFFICEBINTOPDF_H + +#include +#include "../PdfFile.h" + +namespace NSOnlineOfficeBinToPdf +{ + bool ConvertBinToPdf(CPdfFile* pPdf, const std::wstring& wsSrcFile, const std::wstring& wsDstFile, bool bBinary, CConvertFromBinParams* pParams); +} + +#endif // _PDF_WRITER_ONLINEOFFICEBINTOPDF_H + diff --git a/PdfFile/Src/PdfReader.cpp b/PdfFile/Src/PdfReader.cpp new file mode 100644 index 0000000000..fa721e224a --- /dev/null +++ b/PdfFile/Src/PdfReader.cpp @@ -0,0 +1,787 @@ +/* + * (c) Copyright Ascensio System SIA 2010-2019 + * + * 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-12 Ernesta Birznieka-Upisha + * 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 + * + */ + +#define errMemory 12 + +#include "../../DesktopEditor/graphics/pro/Graphics.h" +#include "PdfReader.h" + +#include "../../PdfReader/Src/Adaptors.h" +#include "../../PdfReader/lib/xpdf/ErrorCodes.h" + +#include "../../Common/OfficeDefines.h" +#include "../../DesktopEditor/raster/BgraFrame.h" +#include "../../DesktopEditor/graphics/IRenderer.h" +#include "../../DesktopEditor/common/Directory.h" +#include "../../DesktopEditor/common/StringExt.h" +#include "../../DesktopEditor/common/Path.h" +#include "../../PdfWriter/PdfRenderer.h" + +#include "../../PdfReader/lib/xpdf/PDFDoc.h" +#include "../../PdfReader/lib/xpdf/GlobalParams.h" +#include "../../PdfReader/lib/xpdf/ErrorCodes.h" +#include "../../PdfReader/lib/xpdf/ImageOutputDev.h" +#include "../../PdfReader/lib/xpdf/TextString.h" +#include "../../PdfReader/lib/xpdf/SecurityHandler.h" +#include "../../PdfReader/lib/xpdf/Lexer.h" +#include "../../PdfReader/lib/xpdf/Parser.h" +#include "../../PdfReader/lib/xpdf/AcroForm.h" +#include "../../PdfReader/Src/RendererOutputDev.h" +#include "../../PdfReader/Src/Adaptors.h" + +#ifdef BUILDING_WASM_MODULE +#include "../../DesktopEditor/graphics/pro/js/wasm/src/serialize.h" +#include "../../PdfReader/lib/xpdf/Outline.h" +#include "../../PdfReader/lib/xpdf/Link.h" +#include "../../PdfReader/lib/xpdf/TextOutputDev.h" +#include "../../PdfReader/lib/goo/GList.h" +#include +#endif + +namespace PdfReader +{ + class CPdfReader_Private + { + public: + PDFDoc* m_pPDFDocument; + std::wstring m_wsTempFolder; + std::wstring m_wsCMapFolder; + std::wstring m_wsSrcPath; + NSFonts::IApplicationFonts* m_pAppFonts; + NSFonts::IFontManager* m_pFontManager; + CFontList* m_pFontList; + DWORD m_nFileLength; + }; + + CPdfReader::CPdfReader(NSFonts::IApplicationFonts* pAppFonts) + { + m_pInternal = new CPdfReader_Private(); + + m_pInternal->m_wsTempFolder = L""; + m_pInternal->m_wsCMapFolder = L""; + m_pInternal->m_wsSrcPath = L""; + + m_pInternal->m_pPDFDocument = NULL; + m_pInternal->m_pFontManager = NULL; + m_pInternal->m_nFileLength = 0; + + globalParams = new GlobalParamsAdaptor(NULL); +#ifndef _DEBUG + globalParams->setErrQuiet(gTrue); +#endif + + m_pInternal->m_pFontList = new CFontList(); + + m_pInternal->m_pAppFonts = pAppFonts; + + // Создаем менеджер шрифтов с собственным кэшем + m_pInternal->m_pFontManager = pAppFonts->GenerateFontManager(); + NSFonts::IFontsCache* pMeasurerCache = NSFonts::NSFontCache::Create(); + pMeasurerCache->SetStreams(pAppFonts->GetStreams()); + m_pInternal->m_pFontManager->SetOwnerCache(pMeasurerCache); + pMeasurerCache->SetCacheSize(1); + ((GlobalParamsAdaptor*)globalParams)->SetFontManager(m_pInternal->m_pFontManager); + #ifndef BUILDING_WASM_MODULE + globalParams->setupBaseFonts(NULL); + #endif + +#ifdef CMAP_USE_MEMORY + SetCMapMemory(); +#endif + + m_eError = errNone; + } + CPdfReader::~CPdfReader() + { + if (m_pInternal->m_pFontList) + { + m_pInternal->m_pFontList->Clear(); + delete m_pInternal->m_pFontList; + } + + m_pInternal->m_wsCMapFolder = L""; + + if (!m_pInternal->m_wsTempFolder.empty()) + { + NSDirectory::DeleteDirectory(m_pInternal->m_wsTempFolder); + m_pInternal->m_wsTempFolder = L""; + } + + RELEASEOBJECT((m_pInternal->m_pPDFDocument)); + RELEASEOBJECT((globalParams)); + RELEASEINTERFACE((m_pInternal->m_pFontManager)); + } + bool CPdfReader::LoadFromFile(const std::wstring& wsSrcPath, const std::wstring& wsOptions, + const std::wstring& wsOwnerPassword, const std::wstring& wsUserPassword) + { +// TODO: Сейчас при загрузке каждой новой картинки мы пересоздаем +// FontManager, потому что сейчас в нем кэш без ограничения. +//------------------------------------------------------ + RELEASEINTERFACE((m_pInternal->m_pFontManager)); + m_pInternal->m_pFontManager = m_pInternal->m_pAppFonts->GenerateFontManager(); + NSFonts::IFontsCache* pMeasurerCache = NSFonts::NSFontCache::Create(); + pMeasurerCache->SetStreams(m_pInternal->m_pAppFonts->GetStreams()); + m_pInternal->m_pFontManager->SetOwnerCache(pMeasurerCache); + pMeasurerCache->SetCacheSize(1); + ((GlobalParamsAdaptor*)globalParams)->SetFontManager(m_pInternal->m_pFontManager); +//------------------------------------------------------ + + if (m_pInternal->m_pPDFDocument) + delete m_pInternal->m_pPDFDocument; + + if (GetTempDirectory() == L"") + { + SetTempDirectory(NSDirectory::GetTempPath()); + } + + m_eError = errNone; + GString* owner_pswd = NSStrings::CreateString(wsOwnerPassword); + GString* user_pswd = NSStrings::CreateString(wsUserPassword); + + // конвертим путь в utf8 - под виндой они сконвертят в юникод, а на остальных - так и надо + m_pInternal->m_wsSrcPath = wsSrcPath; + std::string sPathUtf8 = U_TO_UTF8(wsSrcPath); + m_pInternal->m_pPDFDocument = new PDFDoc((char*)sPathUtf8.c_str(), owner_pswd, user_pswd); + + delete owner_pswd; + delete user_pswd; + + NSFile::CFileBinary oFile; + if (oFile.OpenFile(wsSrcPath)) + { + m_pInternal->m_nFileLength = oFile.GetFileSize(); + oFile.CloseFile(); + } + + if (m_pInternal->m_pPDFDocument) + m_eError = m_pInternal->m_pPDFDocument->getErrorCode(); + else + m_eError = errMemory; + + if (!m_pInternal->m_pPDFDocument || !m_pInternal->m_pPDFDocument->isOk()) + { + RELEASEOBJECT(m_pInternal->m_pPDFDocument); + return false; + } + + m_pInternal->m_pFontList->Clear(); + + return true; + } + bool CPdfReader::LoadFromMemory(BYTE* data, DWORD length, const std::wstring& options, + const std::wstring& owner_password, const std::wstring& user_password) + { +// TODO: Сейчас при загрузке каждой новой картинки мы пересоздаем +// FontManager, потому что сейчас в нем кэш без ограничения. +//------------------------------------------------------ + RELEASEINTERFACE((m_pInternal->m_pFontManager)); + m_pInternal->m_pFontManager = m_pInternal->m_pAppFonts->GenerateFontManager(); + NSFonts::IFontsCache* pMeasurerCache = NSFonts::NSFontCache::Create(); + pMeasurerCache->SetStreams(m_pInternal->m_pAppFonts->GetStreams()); + m_pInternal->m_pFontManager->SetOwnerCache(pMeasurerCache); + pMeasurerCache->SetCacheSize(1); + ((GlobalParamsAdaptor*)globalParams)->SetFontManager(m_pInternal->m_pFontManager); +//------------------------------------------------------ + + RELEASEOBJECT(m_pInternal->m_pPDFDocument); + m_eError = errNone; + GString* owner_pswd = NSStrings::CreateString(owner_password); + GString* user_pswd = NSStrings::CreateString(user_password); + + Object obj; + obj.initNull(); + // будет освобожден в деструкторе PDFDoc + BaseStream *str = new MemStream((char*)data, 0, length, &obj); + m_pInternal->m_pPDFDocument = new PDFDoc(str, owner_pswd, user_pswd); + m_pInternal->m_nFileLength = length; + + delete owner_pswd; + delete user_pswd; + + m_eError = m_pInternal->m_pPDFDocument ? m_pInternal->m_pPDFDocument->getErrorCode() : errMemory; + + if (!m_pInternal->m_pPDFDocument || !m_pInternal->m_pPDFDocument->isOk()) + { + RELEASEOBJECT(m_pInternal->m_pPDFDocument); + return false; + } + + m_pInternal->m_pFontList->Clear(); + + return true; + } + void CPdfReader::Close() + { + RELEASEOBJECT((m_pInternal->m_pPDFDocument)); + } + NSFonts::IApplicationFonts* CPdfReader::GetFonts() + { + return m_pInternal->m_pAppFonts; + } + + int CPdfReader::GetError() + { + if (!m_pInternal->m_pPDFDocument) + return m_eError; + + if (m_pInternal->m_pPDFDocument->isOk()) + return 0; + + return m_pInternal->m_pPDFDocument->getErrorCode(); + } + int CPdfReader::GetPagesCount() + { + if (!m_pInternal->m_pPDFDocument) + return 0; + + return m_pInternal->m_pPDFDocument->getNumPages(); + } + double CPdfReader::GetVersion() + { + if (!m_pInternal->m_pPDFDocument) + return 0; + + return m_pInternal->m_pPDFDocument->getPDFVersion(); + } + int CPdfReader::GetPermissions() + { + if (!m_pInternal->m_pPDFDocument) + return 0; + + int nPermissions = 0; + + if (m_pInternal->m_pPDFDocument->okToPrint()) + nPermissions += PERMISSION_PRINT; + if (m_pInternal->m_pPDFDocument->okToCopy()) + nPermissions += PERMISSION_COPY; + if (m_pInternal->m_pPDFDocument->okToChange()) + nPermissions += PERMISSION_CHANGE; + + return nPermissions; + } + std::wstring CPdfReader::GetPageLabel(int nPageIndex) + { + if (!m_pInternal->m_pPDFDocument) + return std::wstring(); +// todo label +// StringExt* seLabel = m_pInternal->m_pPDFDocument->GetPageLabels()->GetLabel(nPageIndex); +// if (seLabel) +// { +// std::wstring wsResult(seLabel->GetWString()); +// delete seLabel; +// return wsResult; +// } + + return std::wstring(); + } + bool CPdfReader::ExtractAllImages(const wchar_t* wsDstPath, const wchar_t* wsPrefix) + { + std::wstring sDstPath(wsDstPath); + if (sDstPath.empty()) + return false; + + // check last symbol (directory) + wchar_t nLastSymbol = sDstPath[sDstPath.length() - 1]; + if ('\\' != nLastSymbol && '/' != nLastSymbol) + sDstPath += '/'; + // prefix for each file + if (NULL != wsPrefix) + sDstPath += std::wstring(wsPrefix); + + std::string sDstPathA = U_TO_UTF8(sDstPath); + ImageOutputDev *pOutputDev = new ImageOutputDev((char*)sDstPathA.c_str(), true, false, false); + if (!pOutputDev) + return false; + + int nPagesCount = GetPagesCount(); + for (int nIndex = 1; nIndex <= nPagesCount; nIndex++) + { + m_pInternal->m_pPDFDocument->displayPage(pOutputDev, nIndex, 72, 72, 0, false, false, false); + } + + delete pOutputDev; + + return true; + } + void CPdfReader::GetPageInfo(int _nPageIndex, double* pdWidth, double* pdHeight, double* pdDpiX, double* pdDpiY) + { + int nPageIndex = _nPageIndex + 1; + + if (!m_pInternal->m_pPDFDocument) + return; + + const double c_dInch = 25.399; // Миллиметров в дюйме + const double c_dXResolution = 154.0; + const double c_dYResolution = 154.0; + + double dKoefX = c_dInch / c_dXResolution; + double dKoefY = c_dInch / c_dYResolution; + + int nRotate = m_pInternal->m_pPDFDocument->getPageRotate(nPageIndex); + + while (nRotate >= 360) + nRotate -= 360; + + while (nRotate < 0) + nRotate += 360; + + if (0 != nRotate && 180 != nRotate) + { + *pdHeight = m_pInternal->m_pPDFDocument->getPageCropWidth(nPageIndex); + *pdWidth = m_pInternal->m_pPDFDocument->getPageCropHeight(nPageIndex); + } + else + { + *pdWidth = m_pInternal->m_pPDFDocument->getPageCropWidth(nPageIndex); + *pdHeight = m_pInternal->m_pPDFDocument->getPageCropHeight(nPageIndex); + } + + *pdDpiX = 72; + *pdDpiY = 72; + } + void CPdfReader::DrawPageOnRenderer(IRenderer* pRenderer, int _nPageIndex, bool* pbBreak) + { + int nPageIndex = _nPageIndex + 1; + + if (m_pInternal->m_pPDFDocument && pRenderer) + { + RendererOutputDev oRendererOut(pRenderer, m_pInternal->m_pFontManager, m_pInternal->m_pFontList); + oRendererOut.NewPDF(m_pInternal->m_pPDFDocument->getXRef()); + oRendererOut.SetBreak(pbBreak); + m_pInternal->m_pPDFDocument->displayPage(&oRendererOut, nPageIndex, 72.0, 72.0, 0, false, true, false); + } + } + int CPdfReader::GetImagesCount() + { +// ImageOutputDev *pOutputDev = new ImageOutputDev(NULL, true, true, false); +// if (!pOutputDev) +// return 0; +// +// for (int nIndex = 1; nIndex <= m_pInternal->m_pPDFDocument->GetPagesCount(); nIndex++) +// { +// m_pInternal->m_pPDFDocument->displayPage(pOutputDev, nIndex, 72, 72, 0, false, false, false); +// } +// +// return pOutputDev-> +return 0; + } + void CPdfReader::SetTempDirectory(const std::wstring& wsTempFolder) + { + if (!m_pInternal->m_wsTempFolder.empty()) + { + NSDirectory::DeleteDirectory(m_pInternal->m_wsTempFolder); + m_pInternal->m_wsTempFolder = wsTempFolder; + } + + if (!wsTempFolder.empty()) + { + std::wstring wsFolderName = std::wstring(wsTempFolder) + L"//pdftemp"; + std::wstring wsFolder = wsFolderName; + int nCounter = 0; + while (NSDirectory::Exists(wsFolder)) + { + nCounter++; + wsFolder = wsFolderName + L"_" + std::to_wstring(nCounter); + } + NSDirectory::CreateDirectory(wsFolder); + m_pInternal->m_wsTempFolder = wsFolder; + } + else + m_pInternal->m_wsTempFolder = L""; + + if (globalParams) + ((GlobalParamsAdaptor*)globalParams)->SetTempFolder(m_pInternal->m_wsTempFolder.c_str()); + } + std::wstring CPdfReader::GetTempDirectory() + { + return m_pInternal->m_wsTempFolder; + } + + void CPdfReader::SetCMapFolder(const wchar_t* wsCMapFolder) + { + m_pInternal->m_wsCMapFolder = std::wstring(wsCMapFolder); + + if (globalParams) + ((GlobalParamsAdaptor*)globalParams)->SetCMapFolder(m_pInternal->m_wsCMapFolder.c_str()); + } + void CPdfReader::SetCMapMemory() + { + if (globalParams) + ((GlobalParamsAdaptor*)globalParams)->SetCMapMemory(); + } + NSFonts::IFontManager* CPdfReader::GetFontManager() + { + return m_pInternal->m_pFontManager; + } + std::wstring CPdfReader::ToXml(const std::wstring& wsFilePath, bool isPrintStream) + { + XMLConverter oConverter(m_pInternal->m_pPDFDocument->getXRef(), isPrintStream); + std::wstring wsXml = oConverter.GetXml(); + + if (wsFilePath != L"") + { + NSFile::CFileBinary oFile; + if (!oFile.CreateFileW(wsFilePath)) + return wsXml; + + oFile.WriteStringUTF8(wsXml); + oFile.CloseFile(); + } + + return wsXml; + } + PDFDoc* CPdfReader::GetPDFDocument() + { + return m_pInternal->m_pPDFDocument; + } + void CPdfReader::ChangeLength(DWORD nLength) + { + m_pInternal->m_nFileLength = nLength; + } + +#define DICT_LOOKUP(sName, wsName) \ + if (info.dictLookup(sName, &obj1)->isString())\ + {\ + TextString* s = new TextString(obj1.getString());\ + sRes += L"\"";\ + sRes += wsName;\ + sRes += L"\":\"";\ + std::wstring sValue = NSStringExt::CConverter::GetUnicodeFromUTF32(s->getUnicode(), s->getLength());\ + NSStringExt::Replace(sValue, L"\"", L"\\\"");\ + sRes += sValue;\ + sRes += L"\",";\ + delete s;\ + }\ + +#define DICT_LOOKUP_DATE(sName, wsName) \ + if (info.dictLookup(sName, &obj1)->isString())\ + {\ + char* str = obj1.getString()->getCString();\ + if (str)\ + {\ + TextString* s = new TextString(obj1.getString());\ + std::wstring sNoDate = NSStringExt::CConverter::GetUnicodeFromUTF32(s->getUnicode(), s->getLength());\ + if (sNoDate.length() > 16)\ + {\ + std::wstring sDate = sNoDate.substr(2, 4) + L'-' + sNoDate.substr(6, 2) + L'-' + sNoDate.substr(8, 2) + L'T' +\ + sNoDate.substr(10, 2) + L':' + sNoDate.substr(12, 2) + L':' + sNoDate.substr(14, 2);\ + if (sNoDate.length() > 21)\ + sDate += (L".000" + sNoDate.substr(16, 3) + L':' + sNoDate.substr(20, 2));\ + else\ + sDate += L"Z";\ + NSStringExt::Replace(sDate, L"\"", L"\\\"");\ + sRes += L"\"";\ + sRes += wsName;\ + sRes += L"\":\"";\ + sRes += sDate;\ + sRes += L"\",";\ + }\ + delete s;\ + }\ + }\ + + std::wstring CPdfReader::GetInfo() + { + if (!m_pInternal->m_pPDFDocument) + return NULL; + XRef* xref = m_pInternal->m_pPDFDocument->getXRef(); + BaseStream* str = m_pInternal->m_pPDFDocument->getBaseStream(); + if (!xref || !str) + return NULL; + + std::wstring sRes = L"{"; + + Object info, obj1; + m_pInternal->m_pPDFDocument->getDocInfo(&info); + if (info.isDict()) + { + DICT_LOOKUP("Title", L"Title"); + DICT_LOOKUP("Author", L"Author"); + DICT_LOOKUP("Subject", L"Subject"); + DICT_LOOKUP("Keywords", L"Keywords"); + DICT_LOOKUP("Creator", L"Creator"); + DICT_LOOKUP("Producer", L"Producer"); + + DICT_LOOKUP_DATE("CreationDate", L"CreationDate"); + DICT_LOOKUP_DATE("ModDate", L"ModDate"); + } + + info.free(); + obj1.free(); + + std::wstring version = std::to_wstring(GetVersion()); + std::wstring::size_type posDot = version.find('.'); + if (posDot != std::wstring::npos) + version = version.substr(0, posDot + 2); + + sRes += L"\"Version\":"; + sRes += version; + double nW = 0; + double nH = 0; + double nDpi = 0; + GetPageInfo(0, &nW, &nH, &nDpi, &nDpi); + sRes += L",\"PageWidth\":"; + sRes += std::to_wstring((int)(nW * 100)); + sRes += L",\"PageHeight\":"; + sRes += std::to_wstring((int)(nH * 100)); + sRes += L",\"NumberOfPages\":"; + sRes += std::to_wstring(GetPagesCount()); + sRes += L",\"FastWebView\":"; + + Object obj2, obj3, obj4, obj5, obj6; + bool bLinearized = false; + obj1.initNull(); + Parser* parser = new Parser(xref, new Lexer(xref, str->makeSubStream(str->getStart(), gFalse, 0, &obj1)), gTrue); + parser->getObj(&obj1); + parser->getObj(&obj2); + parser->getObj(&obj3); + parser->getObj(&obj4); + if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") && obj4.isDict()) + { + obj4.dictLookup("Linearized", &obj5); + obj4.dictLookup("L", &obj6); + if (obj5.isNum() && obj5.getNum() > 0 && obj6.isNum()) + { + unsigned long size = obj6.getNum(); + bLinearized = size == m_pInternal->m_nFileLength; + } + obj6.free(); + obj5.free(); + } + obj4.free(); + obj3.free(); + obj2.free(); + obj1.free(); + delete parser; + + sRes += bLinearized ? L"true" : L"false"; + sRes += L",\"Tagged\":"; + + bool bTagged = false; + Object catDict, markInfoObj; + if (xref->getCatalog(&catDict) && catDict.isDict() && catDict.dictLookup("MarkInfo", &markInfoObj) && markInfoObj.isDict()) + { + Object marked, suspects; + if (markInfoObj.dictLookup("Marked", &marked) && marked.isBool() && marked.getBool()) + { + bTagged = true; + // If Suspects is true, the document may not completely conform to Tagged PDF conventions. + if (markInfoObj.dictLookup("Suspects", &suspects) && suspects.isBool() && suspects.getBool()) + bTagged = false; + } + marked.free(); + suspects.free(); + } + markInfoObj.free(); + catDict.free(); + + sRes += bTagged ? L"true" : L"false"; + sRes += L"}"; + + return sRes; + } +#ifdef BUILDING_WASM_MODULE + void getBookmars(PDFDoc* pdfDoc, OutlineItem* pOutlineItem, NSWasm::CData& out, int level) + { + int nLengthTitle = pOutlineItem->getTitleLength(); + Unicode* pTitle = pOutlineItem->getTitle(); + std::string sTitle = NSStringExt::CConverter::GetUtf8FromUTF32(pTitle, nLengthTitle); + + LinkAction* pLinkAction = pOutlineItem->getAction(); + if (!pLinkAction) + return; + LinkActionKind kind = pLinkAction->getKind(); + if (kind != actionGoTo) + return; + + GString* str = ((LinkGoTo*)pLinkAction)->getNamedDest(); + LinkDest* pLinkDest = str ? pdfDoc->findDest(str) : ((LinkGoTo*)pLinkAction)->getDest(); + if (!pLinkDest) + return; + int pg; + if (pLinkDest->isPageRef()) + { + Ref pageRef = pLinkDest->getPageRef(); + pg = pdfDoc->findPage(pageRef.num, pageRef.gen); + } + else + pg = pLinkDest->getPageNum(); + if (pg == 0) + pg = 1; + double dy = 0; + double dTop = pLinkDest->getTop(); + double dHeight = pdfDoc->getPageCropHeight(pg); + if (dTop > 0 && dTop < dHeight) + dy = dHeight - dTop; + if (str) + RELEASEOBJECT(pLinkDest); + + out.AddInt(pg - 1); + out.AddInt(level); + out.AddDouble(dy); + out.WriteString((BYTE*)sTitle.c_str(), sTitle.length()); + + pOutlineItem->open(); + GList* pList = pOutlineItem->getKids(); + if (!pList) + return; + int num = pList->getLength(); + for (int i = 0; i < num; i++) + { + OutlineItem* pOutlineItemKid = (OutlineItem*)pList->get(i); + if (!pOutlineItemKid) + continue; + getBookmars(pdfDoc, pOutlineItemKid, out, level + 1); + } + pOutlineItem->close(); + } + BYTE* CPdfReader::GetStructure() + { + if (!m_pInternal->m_pPDFDocument) + return NULL; + Outline* pOutline = m_pInternal->m_pPDFDocument->getOutline(); + if (!pOutline) + return NULL; + GList* pList = pOutline->getItems(); + if (!pList) + return NULL; + + NSWasm::CData oRes; + oRes.SkipLen(); + int num = pList->getLength(); + for (int i = 0; i < num; i++) + { + OutlineItem* pOutlineItem = (OutlineItem*)pList->get(i); + if (pOutlineItem) + getBookmars(m_pInternal->m_pPDFDocument, pOutlineItem, oRes, 1); + } + oRes.WriteLen(); + + BYTE* bRes = oRes.GetBuffer(); + oRes.ClearWithoutAttack(); + return bRes; + } + BYTE* CPdfReader::GetLinks(int nPageIndex) + { + if (!m_pInternal->m_pPDFDocument) + return NULL; + + nPageIndex++; + + NSWasm::CPageLink oLinks; + double height = m_pInternal->m_pPDFDocument->getPageCropHeight(nPageIndex); + + // Гиперссылка + Links* pLinks = m_pInternal->m_pPDFDocument->getLinks(nPageIndex); + if (!pLinks) + return NULL; + + int num = pLinks->getNumLinks(); + for (int i = 0; i < num; i++) + { + Link* pLink = pLinks->getLink(i); + if (!pLink) + continue; + + GString* str = NULL; + double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0, dy = 0.0; + pLink->getRect(&x1, &y1, &x2, &y2); + y1 = height - y1; + y2 = height - y2; + + LinkAction* pLinkAction = pLink->getAction(); + if (!pLinkAction) + continue; + LinkActionKind kind = pLinkAction->getKind(); + if (kind == actionGoTo) + { + str = ((LinkGoTo*)pLinkAction)->getNamedDest(); + LinkDest* pLinkDest = str ? m_pInternal->m_pPDFDocument->findDest(str) : ((LinkGoTo*)pLinkAction)->getDest()->copy(); + if (pLinkDest) + { + int pg; + if (pLinkDest->isPageRef()) + { + Ref pageRef = pLinkDest->getPageRef(); + pg = m_pInternal->m_pPDFDocument->findPage(pageRef.num, pageRef.gen); + } + else + pg = pLinkDest->getPageNum(); + std::string sLink = "#" + std::to_string(pg - 1); + str = new GString(sLink.c_str()); + dy = m_pInternal->m_pPDFDocument->getPageCropHeight(pg) - pLinkDest->getTop(); + } + RELEASEOBJECT(pLinkDest); + } + else if (kind == actionURI) + str = ((LinkURI*)pLinkAction)->getURI()->copy(); + + oLinks.m_arLinks.push_back({str ? std::string(str->getCString(), str->getLength()) : "", dy, x1, y2, x2 - x1, y1 - y2}); + RELEASEOBJECT(str); + } + RELEASEOBJECT(pLinks); + + // Текст-ссылка + TextOutputControl textOutControl; + textOutControl.mode = textOutReadingOrder; + TextOutputDev* pTextOut = new TextOutputDev(NULL, &textOutControl, gFalse); + m_pInternal->m_pPDFDocument->displayPage(pTextOut, nPageIndex, 72, 72, 0, gFalse, gTrue, gFalse); + m_pInternal->m_pPDFDocument->processLinks(pTextOut, nPageIndex); + TextWordList* pWordList = pTextOut->makeWordList(); + for (int i = 0; i < pWordList->getLength(); i++) + { + TextWord* pWord = pWordList->get(i); + if (!pWord) + continue; + GString* sLink = pWord->getText(); + if (!sLink) + continue; + std::string link(sLink->getCString(), sLink->getLength()); + size_t find = link.find("http://"); + if (find == std::string::npos) + find = link.find("https://"); + if (find == std::string::npos) + find = link.find("www."); + if (find != std::string::npos) + { + link.erase(0, find); + double x1, y1, x2, y2; + pWord->getBBox(&x1, &y1, &x2, &y2); + oLinks.m_arLinks.push_back({link, 0, x1, y1, x2 - x1, y2 - y1}); + } + } + RELEASEOBJECT(pTextOut); + + return oLinks.Serialize(); + } +#endif +} diff --git a/PdfFile/Src/PdfReader.h b/PdfFile/Src/PdfReader.h new file mode 100644 index 0000000000..50835d9956 --- /dev/null +++ b/PdfFile/Src/PdfReader.h @@ -0,0 +1,109 @@ +/* + * (c) Copyright Ascensio System SIA 2010-2019 + * + * 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-12 Ernesta Birznieka-Upisha + * 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 + * + */ +#ifndef _PDF_READER_H +#define _PDF_READER_H + +#include "../../DesktopEditor/graphics/pro/Fonts.h" +#include "../../DesktopEditor/graphics/IRenderer.h" + +class PDFDoc; +namespace PdfReader +{ + typedef enum + { + errorNone = 0, // Нет ошибок + errorOpenFile = 1, // Ошибка при открытии PDF файла + errorBadCatalog = 2, // couldn't read the page catalog + errorDamaged = 3, // PDF файл был поврежден и его невозможно восстановить + errorEncrypted = 4, // Файл зашифрован, авторизация не пройдена + errorHighlightFile = 5, // nonexistent or invalid highlight file + errorBadPrinter = 6, // плохой принтер + errorPrinting = 7, // ошибка во время печати + errorPermission = 8, // Ошибка связанная с ограничениями наложенными на файл + errorBadPageNum = 9, // Неверное количество страниц + errorFileIO = 10, // Ошибка при чтении/записи + errorMemory = 11 // Memory exceed + } EError; + + class CPdfReader_Private; + class CPdfReader + { + public: + + CPdfReader(NSFonts::IApplicationFonts* fonts); + ~CPdfReader(); + + bool LoadFromFile(const std::wstring& file, const std::wstring& options = L"", + const std::wstring& owner_password = L"", const std::wstring& user_password = L""); + bool LoadFromMemory(BYTE* data, DWORD length, const std::wstring& options = L"", + const std::wstring& owner_password = L"", const std::wstring& user_password = L""); + + void Close(); + + NSFonts::IApplicationFonts* GetFonts(); + + std::wstring GetTempDirectory(); + void SetTempDirectory(const std::wstring& directory); + + int GetPagesCount(); + void GetPageInfo(int nPageIndex, double* pdWidth, double* pdHeight, double* pdDpiX, double* pdDpiY); + void DrawPageOnRenderer(IRenderer* pRenderer, int nPageIndex, bool* pBreak); + std::wstring GetInfo(); + + int GetError(); + double GetVersion(); + int GetPermissions(); + std::wstring GetPageLabel(int nPageIndex); + + bool ExtractAllImages(const wchar_t* wsDstPath, const wchar_t* wsPrefix = 0); + int GetImagesCount(); + + void SetCMapFolder(const wchar_t* wsCMapFolder); + void SetCMapMemory(); + NSFonts::IFontManager* GetFontManager(); + + std::wstring ToXml(const std::wstring& wsXmlPath, bool isPrintStreams = false); + PDFDoc* GetPDFDocument(); + void ChangeLength(DWORD nLength); + + #ifdef BUILDING_WASM_MODULE + BYTE* GetStructure(); + BYTE* GetLinks(int nPageIndex); + #endif + + private: + CPdfReader_Private* m_pInternal; + int m_eError; + }; +} + +#endif // _PDF_READER_H diff --git a/PdfFile/Src/PdfWriter.cpp b/PdfFile/Src/PdfWriter.cpp new file mode 100644 index 0000000000..2f8cd0d327 --- /dev/null +++ b/PdfFile/Src/PdfWriter.cpp @@ -0,0 +1,2933 @@ +/* + * (c) Copyright Ascensio System SIA 2010-2019 + * + * 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-12 Ernesta Birznieka-Upisha + * 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 "../../DesktopEditor/common/File.h" +#include "../../DesktopEditor/common/Directory.h" + +#include "PdfWriter.h" + +#include "../../PdfWriter/Src/Document.h" +#include "../../PdfWriter/Src/Pages.h" +#include "../../PdfWriter/Src/Image.h" +#include "../../PdfWriter/Src/Font.h" +#include "../../PdfWriter/Src/FontCidTT.h" +#include "../../PdfWriter/Src/FontTT.h" +#include "../../PdfWriter/Src/Annotation.h" +#include "../../PdfWriter/Src/Destination.h" +#include "../../PdfWriter/Src/Field.h" + +#include "../../DesktopEditor/graphics/Image.h" +#include "../../DesktopEditor/graphics/structures.h" +#include "../../DesktopEditor/raster/BgraFrame.h" +#include "../../DesktopEditor/raster/ImageFileFormatChecker.h" +#include "../../DesktopEditor/graphics/pro/Fonts.h" +#include "../../DesktopEditor/graphics/pro/Image.h" + +#include "../../UnicodeConverter/UnicodeConverter.h" +#include "../../Common/Network/FileTransporter/include/FileTransporter.h" + +#if defined(GetTempPath) +#undef GetTempPath +#endif + +#if defined(CreateFile) +#undef CreateFile +#endif + +#if defined(CreateDirectory) +#undef CreateDirectory +#endif + +#define MM_2_PT(X) ((X) * 72.0 / 25.4) +#define PT_2_MM(X) ((X) * 25.4 / 72.0) + +#define LONG_2_BOOL(X) ((X) ? true : false) + +#ifdef DrawText +#undef DrawText +#endif + +#ifdef LoadImage +#undef LoadImage +#endif + +#define HI_SURROGATE_START 0xD800 +#define HI_SURROGATE_END 0xDBFF +#define LO_SURROGATE_START 0xDC00 +#define LO_SURROGATE_END 0xDFFF + +using namespace PdfWriter; + +static unsigned int* WStringToUtf32(const std::wstring& wsUnicodeText, unsigned int& unLen) +{ + if (wsUnicodeText.size() <= 0) + return NULL; + + unsigned int* pUnicodes = new unsigned int[wsUnicodeText.size()]; + if (!pUnicodes) + return NULL; + + unLen = 0; + if (2 == sizeof(wchar_t)) + { + const wchar_t* wsEnd = wsUnicodeText.c_str() + wsUnicodeText.size(); + wchar_t* wsInput = (wchar_t*)wsUnicodeText.c_str(); + + wchar_t wLeading, wTrailing; + unsigned int unCode; + while (wsInput < wsEnd) + { + wLeading = *wsInput++; + if (wLeading < 0xD800 || wLeading > 0xDFFF) + { + pUnicodes[unLen++] = (unsigned int)wLeading; + } + else if (wLeading >= 0xDC00) + { + // Такого не должно быть + continue; + } + else + { + unCode = (wLeading & 0x3FF) << 10; + wTrailing = *wsInput++; + if (wTrailing < 0xDC00 || wTrailing > 0xDFFF) + { + // Такого не должно быть + continue; + } + else + { + pUnicodes[unLen++] = ((unCode | (wTrailing & 0x3FF)) + 0x10000); + } + } + } + } + else + { + unLen = wsUnicodeText.size(); + for (unsigned int unIndex = 0; unIndex < unLen; unIndex++) + { + pUnicodes[unIndex] = (unsigned int)wsUnicodeText.at(unIndex); + } + } + + return pUnicodes; +} + +// Этих типов браша нет в рендерере, мы их используем, когда конвертим из веба +static const long c_BrushTypeLinearGradient = 8001; +static const long c_BrushTypeRadialGradient = 8002; + +enum ERendererCommandType +{ + renderercommandtype_Text = 0x01, + renderercommandtype_Image = 0x02, + renderercommandtype_Path = 0x03, + renderercommandtype_Clip = 0x04 +}; +//---------------------------------------------------------------------------------------- +// +// CRendererCommandBase +// +//---------------------------------------------------------------------------------------- +class CRendererCommandBase +{ +public: + virtual ~CRendererCommandBase(){}; + virtual ERendererCommandType GetType() = 0; +}; +//---------------------------------------------------------------------------------------- +// +// CRendererTextCommand +// +//---------------------------------------------------------------------------------------- +class CRendererTextCommand : public CRendererCommandBase +{ +public: + CRendererTextCommand(unsigned char* pCodes, unsigned int nLen, const double& dX, const double& dY) + { + m_pCodes = pCodes; + m_nLen = nLen; + m_dX = dX; + m_dY = dY; + m_pFont = NULL; + m_dSize = -1; + m_lColor = 0; + m_nAlpha = 255; + m_dCharSpace = 0; + m_dHorScaling = 100; + m_nMode = (int)textrenderingmode_Fill; + + m_bNeedDoItalic = false; + m_bNeedDoBold = false; + } + ~CRendererTextCommand() + { + if (m_pCodes) + delete[] m_pCodes; + } + ERendererCommandType GetType() + { + return renderercommandtype_Text; + } + + inline double GetX() const + { + return m_dX; + } + inline double GetY() const + { + return m_dY; + } + inline unsigned char* GetCodes() const + { + return m_pCodes; + } + inline unsigned int GetCodesLen() const + { + return m_nLen; + } + inline void SetFont(CFontDict* pFont) + { + m_pFont = pFont; + } + inline void SetSize(const double& dSize) + { + m_dSize = dSize; + } + inline void SetColor(const LONG& lColor) + { + m_lColor = lColor; + } + inline void SetAlpha(const BYTE& nAlpha) + { + m_nAlpha = nAlpha; + } + inline void SetCharSpace(const double& dCharSpace) + { + m_dCharSpace = dCharSpace; + } + inline void SetHorScaling(const double& dKoef) + { + m_dHorScaling = dKoef; + } + inline void SetMode(const int& nMode) + { + m_nMode = nMode; + } + inline void SetNeedDoItalic(const bool& bItalic) + { + m_bNeedDoItalic = bItalic; + } + inline void SetNeedDoBold(const bool& bBold) + { + m_bNeedDoBold = bBold; + } + inline CFontDict* GetFont() const + { + return m_pFont; + } + inline double GetSize() const + { + return m_dSize; + } + inline LONG GetColor() const + { + return m_lColor; + } + inline BYTE GetAlpha() const + { + return m_nAlpha; + } + inline double GetSpace() const + { + return m_dCharSpace; + } + inline double GetHorScaling() const + { + return m_dHorScaling; + } + inline int GetMode() const + { + return m_nMode; + } + inline bool IsNeedDoItalic() const + { + return m_bNeedDoItalic; + } + inline bool IsNeedDoBold() const + { + return m_bNeedDoBold; + } + +private: + + unsigned char* m_pCodes; + unsigned int m_nLen; + double m_dX; + double m_dY; + + CFontDict* m_pFont; + bool m_bNeedDoItalic; + bool m_bNeedDoBold; + double m_dSize; + LONG m_lColor; + BYTE m_nAlpha; + double m_dCharSpace; + int m_nMode; + double m_dHorScaling; +}; +//---------------------------------------------------------------------------------------- +// +// CCommandManager +// +//---------------------------------------------------------------------------------------- +CPdfWriter::CCommandManager::CCommandManager(CPdfWriter* pRenderer) : m_pRenderer(pRenderer) +{ +} +CPdfWriter::CCommandManager::~CCommandManager() +{ + Clear(); +} +CRendererTextCommand* CPdfWriter::CCommandManager::AddText(unsigned char* pCodes, unsigned int nLen, const double& dX, const double& dY) +{ + CRendererCommandBase* pCommand = new CRendererTextCommand(pCodes, nLen, dX, dY); + Add(pCommand); + return (CRendererTextCommand*)pCommand; +} +void CPdfWriter::CCommandManager::Add(CRendererCommandBase* pCommand) +{ + if (pCommand) + { + if (m_vCommands.size() > 0 && pCommand->GetType() != m_vCommands.at(0)->GetType()) + Flush(); + + m_vCommands.push_back(pCommand); + } +} +void CPdfWriter::CCommandManager::Flush() +{ + size_t nCommandsCount = m_vCommands.size(); + if (nCommandsCount > 0) + { + CPage* pPage = m_pRenderer->m_pPage; + pPage->GrSave(); + + pPage->SetTransform(m_oTransform.m11, m_oTransform.m12, m_oTransform.m21, m_oTransform.m22, m_oTransform.dx, m_oTransform.dy); + + ERendererCommandType eType = m_vCommands.at(0)->GetType(); + if (renderercommandtype_Text == eType) + { + pPage->BeginText(); + CRendererTextCommand* pText = NULL; + + CFontDict* pTextFont = NULL; + double dTextSize = -1; + LONG lTextColor = 0; + BYTE nTextAlpha = 255; + double dTextSpace = 0; + double dHorScaling = 100; + ETextRenderingMode eMode = textrenderingmode_Fill; + bool isNeedDoBold = false; + bool isNeedDoItalic = false; + double dLineWidth = -1; + + CTextLine oTextLine; + for (size_t nIndex = 0; nIndex < nCommandsCount; nIndex++) + { + pText = (CRendererTextCommand*)m_vCommands.at(nIndex); + if (!pText) + continue; + + if (pTextFont != pText->GetFont() || fabs(dTextSize - pText->GetSize()) > 0.001) + { + oTextLine.Flush(pPage); + pTextFont = pText->GetFont(); + dTextSize = pText->GetSize(); + pPage->SetFontAndSize(pTextFont, dTextSize); + } + + if (lTextColor != pText->GetColor()) + { + oTextLine.Flush(pPage); + lTextColor = pText->GetColor(); + TColor oColor = lTextColor; + pPage->SetFillColor(oColor.r, oColor.g, oColor.b); + pPage->SetStrokeColor(oColor.r, oColor.g, oColor.b); + } + + if (nTextAlpha != pText->GetAlpha()) + { + oTextLine.Flush(pPage); + nTextAlpha = pText->GetAlpha(); + pPage->SetFillAlpha(nTextAlpha); + pPage->SetStrokeAlpha(nTextAlpha); + } + + if (fabs(dTextSpace - pText->GetSpace()) > 0.001) + { + oTextLine.Flush(pPage); + dTextSpace = pText->GetSpace(); + pPage->SetCharSpace(dTextSpace); + } + + if ((int)eMode != pText->GetMode() || isNeedDoBold != pText->IsNeedDoBold()) + { + oTextLine.Flush(pPage); + eMode = (ETextRenderingMode)pText->GetMode(); + isNeedDoBold = pText->IsNeedDoBold(); + + if (isNeedDoBold && eMode == textrenderingmode_Fill) + { + double dNewLineWidth = dTextSize / 12 * 0.343; + if (fabs(dLineWidth - dNewLineWidth) > 0.001) + { + dLineWidth = dNewLineWidth; + pPage->SetLineWidth(dLineWidth); + } + + pPage->SetTextRenderingMode(textrenderingmode_FillThenStroke); + } + else + { + pPage->SetTextRenderingMode(eMode); + } + } + + if (fabs(dHorScaling - pText->GetHorScaling()) > 0.001) + { + oTextLine.Flush(pPage); + dHorScaling = pText->GetHorScaling(); + pPage->SetHorizontalScalling(dHorScaling); + } + + if (isNeedDoItalic != pText->IsNeedDoItalic()) + { + oTextLine.Flush(pPage); + + if (pText->IsNeedDoItalic()) + pPage->SetTextMatrix(1, 0, 0.26, 1, 0, 0); + else + pPage->SetTextMatrix(1, 0, 0, 1, 0, 0); + + isNeedDoItalic = pText->IsNeedDoItalic(); + } + + unsigned char* pCodes = pText->GetCodes(); + unsigned short ushCode = (pCodes[0] << 8) + pCodes[1]; + unsigned int unLen = pText->GetCodesLen(); + double dX = pText->GetX(); + double dY = pText->GetY(); + double dTextSize = pText->GetSize(); + double dWidth = ((CFontCidTrueType*)pText->GetFont())->GetWidth(ushCode) / 1000.0 * dTextSize; + + if (!oTextLine.Add(pCodes, unLen, dX, dY, dWidth, dTextSize)) + { + oTextLine.Flush(pPage); + if (!oTextLine.Add(pCodes, unLen, dX, dY, dWidth, dTextSize)) + { + pPage->DrawText(dX, dY, pCodes, unLen); + } + } + } + + oTextLine.Flush(pPage); + pPage->EndText(); + } + + pPage->GrRestore(); + } + + Clear(); +} +void CPdfWriter::CCommandManager::Clear() +{ + for (size_t nIndex = 0, nCount = m_vCommands.size(); nIndex < nCount; nIndex++) + { + CRendererCommandBase* pCommand = m_vCommands.at(nIndex); + delete pCommand; + } + m_vCommands.clear(); +} +void CPdfWriter::CCommandManager::SetTransform(const CTransform& oTransform) +{ + m_oTransform = oTransform; +} +void CPdfWriter::CCommandManager::SetTransform(const double& m11, const double& m12, const double& m21, const double& m22, const double& dx, const double& dy) +{ + m_oTransform.Set(m11, m12, m21, m22, dx, dy); +} +//---------------------------------------------------------------------------------------- +// +// CPdfRenderer +// +//---------------------------------------------------------------------------------------- +CPdfWriter::CPdfWriter(NSFonts::IApplicationFonts* pAppFonts, bool isPDFA) : m_oCommandManager(this) +{ + m_pAppFonts = pAppFonts; + + // Создаем менеджер шрифтов с собственным кэшем + m_pFontManager = pAppFonts->GenerateFontManager(); + NSFonts::IFontsCache* pMeasurerCache = NSFonts::NSFontCache::Create(); + pMeasurerCache->SetStreams(pAppFonts->GetStreams()); + m_pFontManager->SetOwnerCache(pMeasurerCache); + + m_pDocument = new CDocument(); + + if (isPDFA) + m_pDocument->SetPDFAConformanceMode(true); + + if (!m_pDocument || !m_pDocument->CreateNew()) + { + SetError(); + return; + } + + m_pDocument->SetCompressionMode(COMP_ALL); + + m_bValid = true; + m_dPageHeight = 297; + m_dPageWidth = 210; + m_pPage = NULL; + m_pFont = NULL; + + m_bNeedUpdateTextFont = true; + m_bNeedUpdateTextColor = true; + m_bNeedUpdateTextAlpha = true; + m_bNeedUpdateTextCharSpace = true; + m_bNeedUpdateTextSize = true; + + m_wsTempFolder = L""; + SetTempFolder(NSFile::CFileBinary::GetTempPath()); +} +CPdfWriter::~CPdfWriter() +{ + RELEASEOBJECT(m_pDocument); + RELEASEINTERFACE(m_pFontManager); + + if (L"" != m_wsTempFolder) + NSDirectory::DeleteDirectory(m_wsTempFolder); +} +void CPdfWriter::SetPassword(const std::wstring& wsPassword) +{ + if (!IsValid()) + return; + + m_pDocument->SetPasswords(wsPassword, wsPassword); +} + +void CPdfWriter::SetDocumentID(const std::wstring& wsDocumentID) +{ + if (!IsValid()) + return; + + m_pDocument->SetDocumentID(wsDocumentID); +} +int CPdfWriter::SaveToFile(const std::wstring& wsPath) +{ + // TODO: Переделать на код ошибки + if (!IsValid()) + return 1; + + m_oCommandManager.Flush(); + + if (!m_pDocument->SaveToFile(wsPath)) + return 1; + + return 0; +} +void CPdfWriter::SetTempFolder(const std::wstring& wsPath) +{ + if (L"" != m_wsTempFolder) + NSDirectory::DeleteDirectory(m_wsTempFolder); + + int nCounter = 0; + m_wsTempFolder = wsPath; + int nPathLen = (int)m_wsTempFolder.length(); + if (nPathLen > 0) + { + const wchar_t* pData = m_wsTempFolder.c_str(); + if ((pData[nPathLen - 1] != '/') && (pData[nPathLen - 1] != '\\')) + m_wsTempFolder += L"/"; + + m_wsTempFolder += L"PDF"; + } + + std::wstring sTest = m_wsTempFolder; + while (NSDirectory::Exists(m_wsTempFolder)) + { + m_wsTempFolder = sTest + L"/PDF_" + std::to_wstring(nCounter); + nCounter++; + } + NSDirectory::CreateDirectory(m_wsTempFolder); +} +std::wstring CPdfWriter::GetTempFile() +{ + return NSFile::CFileBinary::CreateTempFileWithUniqueName(m_wsTempFolder, L"PDF"); +} +std::wstring CPdfWriter::GetTempDirectory() +{ + return m_wsTempFolder; +} +//---------------------------------------------------------------------------------------- +// Тип рендерера +//---------------------------------------------------------------------------------------- +HRESULT CPdfWriter::get_Type(LONG* lType) +{ + *lType = c_nPDFWriter; + return S_OK; +} +//---------------------------------------------------------------------------------------- +// Функции для работы со страницей +//---------------------------------------------------------------------------------------- +HRESULT CPdfWriter::NewPage() +{ + m_oCommandManager.Flush(); + + if (!IsValid()) + return S_FALSE; + + m_pPage = m_pDocument->AddPage(); + + if (!m_pPage) + { + SetError(); + return S_FALSE; + } + + m_pPage->SetWidth(MM_2_PT(m_dPageWidth)); + m_pPage->SetHeight(MM_2_PT(m_dPageHeight)); + + Reset(); + + return S_OK; +} +HRESULT CPdfWriter::get_Height(double* dHeight) +{ + *dHeight = m_dPageHeight; + return S_OK; +} +HRESULT CPdfWriter::put_Height(const double& dHeight) +{ + if (!IsValid() || !m_pPage) + return S_FALSE; + + m_dPageHeight = dHeight; + m_pPage->SetHeight(MM_2_PT(dHeight)); + return S_OK; +} +HRESULT CPdfWriter::get_Width(double* dWidth) +{ + *dWidth = m_dPageWidth; + return S_OK; +} +HRESULT CPdfWriter::put_Width(const double& dWidth) +{ + if (!IsValid() || !m_pPage) + return S_FALSE; + + m_dPageWidth = dWidth; + m_pPage->SetWidth(MM_2_PT(dWidth)); + return S_OK; +} +HRESULT CPdfWriter::get_DpiX(double* dDpiX) +{ + *dDpiX = 72; + return S_OK; +} +HRESULT CPdfWriter::get_DpiY(double* dDpiY) +{ + *dDpiY = 72; + return S_OK; +} +//---------------------------------------------------------------------------------------- +// Функции для работы с Pen +//---------------------------------------------------------------------------------------- +HRESULT CPdfWriter::get_PenColor(LONG* lColor) +{ + *lColor = m_oPen.GetColor(); + return S_OK; +} +HRESULT CPdfWriter::put_PenColor(const LONG& lColor) +{ + m_oPen.SetColor(lColor); + return S_OK; +} +HRESULT CPdfWriter::get_PenAlpha(LONG* lAlpha) +{ + *lAlpha = m_oPen.GetAlpha(); + return S_OK; +} +HRESULT CPdfWriter::put_PenAlpha(const LONG& lAlpha) +{ + m_oPen.SetAlpha(lAlpha); + return S_OK; +} +HRESULT CPdfWriter::get_PenSize(double* dSize) +{ + *dSize = m_oPen.GetSize(); + return S_OK; +} +HRESULT CPdfWriter::put_PenSize(const double& dSize) +{ + m_oPen.SetSize(dSize); + return S_OK; +} +HRESULT CPdfWriter::get_PenDashStyle(BYTE* nDashStyle) +{ + *nDashStyle = m_oPen.GetDashStyle(); + return S_OK; +} +HRESULT CPdfWriter::put_PenDashStyle(const BYTE& nDashStyle) +{ + m_oPen.SetDashStyle(nDashStyle); + return S_OK; +} +HRESULT CPdfWriter::get_PenLineStartCap(BYTE* nCapStyle) +{ + *nCapStyle = m_oPen.GetStartCapStyle(); + return S_OK; +} +HRESULT CPdfWriter::put_PenLineStartCap(const BYTE& nCapStyle) +{ + m_oPen.SetStartCapStyle(nCapStyle); + return S_OK; +} +HRESULT CPdfWriter::get_PenLineEndCap(BYTE* nCapStyle) +{ + *nCapStyle = m_oPen.GetEndCapStyle(); + return S_OK; +} +HRESULT CPdfWriter::put_PenLineEndCap(const BYTE& nCapStyle) +{ + m_oPen.SetEndCapStyle(nCapStyle); + return S_OK; +} +HRESULT CPdfWriter::get_PenLineJoin(BYTE* nJoinStyle) +{ + *nJoinStyle = m_oPen.GetJoinStyle(); + return S_OK; +} +HRESULT CPdfWriter::put_PenLineJoin(const BYTE& nJoinStyle) +{ + m_oPen.SetJoinStyle(nJoinStyle); + return S_OK; +} +HRESULT CPdfWriter::get_PenDashOffset(double* dOffset) +{ + *dOffset = m_oPen.GetDashOffset(); + return S_OK; +} +HRESULT CPdfWriter::put_PenDashOffset(const double& dOffset) +{ + m_oPen.SetDashOffset(dOffset); + return S_OK; +} +HRESULT CPdfWriter::get_PenAlign(LONG* lAlign) +{ + *lAlign = m_oPen.GetAlign(); + return S_OK; +} +HRESULT CPdfWriter::put_PenAlign(const LONG& lAlign) +{ + m_oPen.SetAlign(lAlign); + return S_OK; +} +HRESULT CPdfWriter::get_PenMiterLimit(double* dMiter) +{ + *dMiter = m_oPen.GetMiter(); + return S_OK; +} +HRESULT CPdfWriter::put_PenMiterLimit(const double& dMiter) +{ + m_oPen.SetMiter(dMiter); + return S_OK; +} +HRESULT CPdfWriter::PenDashPattern(double* pPattern, LONG lCount) +{ + m_oPen.SetDashPattern(pPattern, lCount); + return S_OK; +} +//---------------------------------------------------------------------------------------- +// Функции для работы с Brush +//---------------------------------------------------------------------------------------- +HRESULT CPdfWriter::get_BrushType(LONG* lType) +{ + *lType = m_oBrush.GetType(); + return S_OK; +} +HRESULT CPdfWriter::put_BrushType(const LONG& lType) +{ + m_oBrush.SetType(lType); + return S_OK; +} +HRESULT CPdfWriter::get_BrushColor1(LONG* lColor) +{ + *lColor = m_oBrush.GetColor1(); + return S_OK; +} +HRESULT CPdfWriter::put_BrushColor1(const LONG& lColor) +{ + if (lColor != m_oBrush.GetColor1()) + { + m_oBrush.SetColor1(lColor); + m_bNeedUpdateTextColor = true; + } + return S_OK; +} +HRESULT CPdfWriter::get_BrushAlpha1(LONG* lAlpha) +{ + *lAlpha = m_oBrush.GetAlpha1(); + return S_OK; +} +HRESULT CPdfWriter::put_BrushAlpha1(const LONG& lAlpha) +{ + if (lAlpha != m_oBrush.GetAlpha1()) + { + m_oBrush.SetAlpha1(lAlpha); + m_bNeedUpdateTextAlpha = true; + } + return S_OK; +} +HRESULT CPdfWriter::get_BrushColor2(LONG* lColor) +{ + *lColor = m_oBrush.GetColor2(); + return S_OK; +} +HRESULT CPdfWriter::put_BrushColor2(const LONG& lColor) +{ + m_oBrush.SetColor2(lColor); + return S_OK; +} +HRESULT CPdfWriter::get_BrushAlpha2(LONG* lAlpha) +{ + *lAlpha = m_oBrush.GetAlpha2(); + return S_OK; +} +HRESULT CPdfWriter::put_BrushAlpha2(const LONG& lAlpha) +{ + m_oBrush.SetAlpha2(lAlpha); + return S_OK; +} +HRESULT CPdfWriter::get_BrushTexturePath(std::wstring* wsPath) +{ + *wsPath = m_oBrush.GetTexturePath(); + return S_OK; +} +HRESULT CPdfWriter::put_BrushTexturePath(const std::wstring& wsPath) +{ + m_oBrush.SetTexturePath(wsPath); + return S_OK; +} +HRESULT CPdfWriter::get_BrushTextureMode(LONG* lMode) +{ + *lMode = m_oBrush.GetTextureMode(); + return S_OK; +} +HRESULT CPdfWriter::put_BrushTextureMode(const LONG& lMode) +{ + m_oBrush.SetTextureMode(lMode); + return S_OK; +} +HRESULT CPdfWriter::get_BrushTextureAlpha(LONG* lAlpha) +{ + *lAlpha = m_oBrush.GetTextureAlpha(); + return S_OK; +} +HRESULT CPdfWriter::put_BrushTextureAlpha(const LONG& lAlpha) +{ + m_oBrush.SetTextureAlpha(lAlpha); + return S_OK; +} +HRESULT CPdfWriter::get_BrushLinearAngle(double* dAngle) +{ + *dAngle = m_oBrush.GetLinearAngle(); + return S_OK; +} +HRESULT CPdfWriter::put_BrushLinearAngle(const double& dAngle) +{ + m_oBrush.SetLinearAngle(dAngle); + return S_OK; +} +HRESULT CPdfWriter::BrushRect(const INT& nVal, const double& dLeft, const double& dTop, const double& dWidth, const double& dHeight) +{ + // Данными параметрами пользуемся, только если пришла команда EnableBrushRect, если команда не пришла, тогда + // ориентируемся на границы пата. + m_oBrush.SetBrushRect(nVal, dLeft, dTop, dWidth, dHeight); + m_oBrush.EnableBrushRect(1 == nVal ? true : false); + return S_OK; +} +HRESULT CPdfWriter::BrushBounds(const double& dLeft, const double& dTop, const double& dWidth, const double& dHeight) +{ + // TODO: Пока определяется все по границам пата + return S_OK; +} +HRESULT CPdfWriter::put_BrushGradientColors(LONG* lColors, double* pPositions, LONG lCount) +{ + m_oBrush.SetGradientColors(lColors, pPositions, lCount); + return S_OK; +} +//---------------------------------------------------------------------------------------- +// Функции для работы со шрифтами +//---------------------------------------------------------------------------------------- +HRESULT CPdfWriter::get_FontName(std::wstring* wsName) +{ + *wsName = m_oFont.GetName(); + return S_OK; +} +HRESULT CPdfWriter::put_FontName(const std::wstring& wsName) +{ + if (wsName != m_oFont.GetName()) + { + m_oFont.SetName(wsName); + m_bNeedUpdateTextFont = true; + } + + return S_OK; +} +HRESULT CPdfWriter::get_FontPath(std::wstring* wsPath) +{ + *wsPath = m_oFont.GetPath(); + return S_OK; +} +HRESULT CPdfWriter::put_FontPath(const std::wstring& wsPath) +{ + if (wsPath != m_oFont.GetPath()) + { + m_oFont.SetPath(wsPath); + m_bNeedUpdateTextFont = true; + } + return S_OK; +} +HRESULT CPdfWriter::get_FontSize(double* dSize) +{ + *dSize = m_oFont.GetSize(); + return S_OK; +} +HRESULT CPdfWriter::put_FontSize(const double& dSize) +{ + if (fabs(dSize - m_oFont.GetSize()) > 0.001) + { + m_oFont.SetSize(dSize); + m_bNeedUpdateTextSize = true; + } + return S_OK; +} +HRESULT CPdfWriter::get_FontStyle(LONG* lStyle) +{ + *lStyle = m_oFont.GetStyle(); + return S_OK; +} +HRESULT CPdfWriter::put_FontStyle(const LONG& lStyle) +{ + if (lStyle != m_oFont.GetStyle()) + { + m_oFont.SetStyle(lStyle); + m_bNeedUpdateTextFont = true; + } + return S_OK; +} +HRESULT CPdfWriter::get_FontStringGID(INT* bGid) +{ + *bGid = m_oFont.GetGid() ? 1 : 0; + return S_OK; +} +HRESULT CPdfWriter::put_FontStringGID(const INT& bGid) +{ + m_oFont.SetGid(bGid ? true : false); + return S_OK; +} +HRESULT CPdfWriter::get_FontCharSpace(double* dSpace) +{ + *dSpace = m_oFont.GetCharSpace(); + return S_OK; +} +HRESULT CPdfWriter::put_FontCharSpace(const double& dSpace) +{ + if (fabs(dSpace - m_oFont.GetCharSpace()) > 0.001) + { + m_oFont.SetCharSpace(dSpace); + m_bNeedUpdateTextCharSpace = true; + } + return S_OK; +} +HRESULT CPdfWriter::get_FontFaceIndex(int* nFaceIndex) +{ + *nFaceIndex = (int)m_oFont.GetFaceIndex(); + return S_OK; +} +HRESULT CPdfWriter::put_FontFaceIndex(const int& nFaceIndex) +{ + if (nFaceIndex != m_oFont.GetFaceIndex()) + { + m_oFont.SetFaceIndex(nFaceIndex); + m_bNeedUpdateTextFont = true; + } + + return S_OK; +} +//---------------------------------------------------------------------------------------- +// Функции для вывода текста +//---------------------------------------------------------------------------------------- +HRESULT CPdfWriter::CommandDrawTextCHAR(const LONG& lUnicode, const double& dX, const double& dY, const double& dW, const double& dH) +{ + if (!IsPageValid()) + return S_FALSE; + + unsigned int unUnicode = lUnicode; + unsigned char* pCodes = EncodeString(&unUnicode, 1); + return DrawText(pCodes, 2, dX, dY) ? S_OK : S_FALSE; +} +HRESULT CPdfWriter::CommandDrawText(const std::wstring& wsUnicodeText, const double& dX, const double& dY, const double& dW, const double& dH) +{ + if (!IsPageValid() || !wsUnicodeText.size()) + return S_FALSE; + + unsigned int unLen; + unsigned int* pUnicodes = WStringToUtf32(wsUnicodeText, unLen); + if (!pUnicodes) + return S_FALSE; + + unsigned char* pCodes = EncodeString(pUnicodes, unLen); + delete[] pUnicodes; + + if (!pCodes) + return S_FALSE; + + // Специальный случай для текста из Djvu, нам не нужно, чтобы он рисовался + if (L"" == m_oFont.GetPath() && L"DjvuEmptyFont" == m_oFont.GetName()) + { + if (m_bNeedUpdateTextFont) + { + m_oFont.SetName(L"Arial"); + UpdateFont(); + m_oFont.SetName(L"DjvuEmptyFont"); + if (!m_pFont) + return S_FALSE; + } + + double dFontSize = MM_2_PT(dH); + double dStringWidth = 0; + for (unsigned int unIndex = 0; unIndex < unLen; unIndex++) + { + unsigned short ushCode = (pCodes[2 * unIndex] << 8) + pCodes[2 * unIndex + 1]; + dStringWidth += m_pFont->GetWidth(ushCode) * dFontSize / 1000.0; + } + + double dResultWidth = MM_2_PT(dW); + + CTransform& t = m_oTransform; + m_oCommandManager.SetTransform(t.m11, -t.m12, -t.m21, t.m22, MM_2_PT(t.dx + t.m21 * m_dPageHeight), MM_2_PT(m_dPageHeight - m_dPageHeight * t.m22 - t.dy)); + + CRendererTextCommand* pText = m_oCommandManager.AddText(pCodes, unLen * 2, MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY - dH)); + pText->SetFont(m_pFont); + pText->SetSize(dFontSize); + pText->SetMode(textrenderingmode_Invisible); + if (fabs(dStringWidth) > 0.001) + pText->SetHorScaling(dResultWidth / dStringWidth * 100); + + return S_OK; + } + + return DrawText(pCodes, unLen * 2, dX, dY) ? S_OK : S_FALSE; +} +HRESULT CPdfWriter::CommandDrawTextExCHAR(const LONG& lUnicode, const LONG& lGid, const double& dX, const double& dY, const double& dW, const double& dH) +{ + if (!IsPageValid()) + return S_FALSE; + + unsigned int unUnicode = lUnicode; + unsigned int unGID = lGid; + unsigned char* pCodes = EncodeGID(unGID, &unUnicode, 1); + return DrawText(pCodes, 2, dX, dY) ? S_OK : S_FALSE; +} +HRESULT CPdfWriter::CommandDrawTextEx(const std::wstring& wsUnicodeText, const unsigned int* pGids, const unsigned int unGidsCount, const double& dX, const double& dY, const double& dW, const double& dH) +{ + if (!IsPageValid() || (!wsUnicodeText.size() && (!pGids || !unGidsCount))) + return S_FALSE; + + unsigned int unLen = 0; + unsigned int* pUnicodes = NULL; + if (pGids && unGidsCount) + { + unLen = unGidsCount; + if (wsUnicodeText.size()) + { + unsigned int unUnicodeLen; + pUnicodes = WStringToUtf32(wsUnicodeText, unUnicodeLen); + if (!pUnicodes || unUnicodeLen != unLen) + RELEASEARRAYOBJECTS(pUnicodes); + } + + if (!pUnicodes) + { + pUnicodes = new unsigned int[unLen]; + if (!pUnicodes) + return S_FALSE; + + for (unsigned int unIndex = 0; unIndex < unLen; unIndex++) + pUnicodes[unIndex] = pGids[unIndex]; + } + } + else + { + pUnicodes = WStringToUtf32(wsUnicodeText, unLen); + if (!pUnicodes) + return S_FALSE; + } + + unsigned char* pCodes = EncodeString(pUnicodes, unLen, pGids); + RELEASEARRAYOBJECTS(pUnicodes); + return DrawText(pCodes, unLen * 2, dX, dY) ? S_OK : S_FALSE; +} +HRESULT CPdfWriter::CommandDrawTextCHAR2(unsigned int* pUnicodes, const unsigned int& unUnicodeCount, const unsigned int& unGid, const double& dX, const double& dY, const double& dW, const double& dH) +{ + if (!IsPageValid()) + return S_FALSE; + + unsigned char* pCodes = EncodeGID(unGid, pUnicodes, unUnicodeCount); + return DrawText(pCodes, 2, dX, dY) ? S_OK : S_FALSE; +} +//---------------------------------------------------------------------------------------- +// Маркеры команд +//---------------------------------------------------------------------------------------- +HRESULT CPdfWriter::BeginCommand(const DWORD& dwType) +{ + // Здесь мы ничего не делаем + return S_OK; +} +HRESULT CPdfWriter::EndCommand(const DWORD& dwType) +{ + if (!IsPageValid()) + return S_FALSE; + + // Здесь мы различаем лишь 2 команды: присоединить текущий пат к клипу и отменить клип + if (c_nClipType == dwType) + { + m_oCommandManager.Flush(); + m_pPage->GrSave(); + m_lClipDepth++; + UpdateTransform(); + + if (c_nClipRegionTypeEvenOdd & m_lClipMode) + m_oPath.Clip(m_pPage, true); + else + m_oPath.Clip(m_pPage, false); + } + else if (c_nResetClipType == dwType) + { + m_oCommandManager.Flush(); + while (m_lClipDepth) + { + m_pPage->GrRestore(); + m_lClipDepth--; + } + } + else if (c_nPageType == dwType) + { + for (int nIndex = 0, nCount = m_vDestinations.size(); nIndex < nCount; ++nIndex) + { + TDestinationInfo& oInfo = m_vDestinations.at(nIndex); + if (m_pDocument->GetPagesCount() > oInfo.unDestPage) + { + AddLink(oInfo.pPage, oInfo.dX, oInfo.dY, oInfo.dW, oInfo.dH, oInfo.dDestX, oInfo.dDestY, oInfo.unDestPage); + m_vDestinations.erase(m_vDestinations.begin() + nIndex); + nIndex--; + nCount--; + } + } + } + + return S_OK; +} +//---------------------------------------------------------------------------------------- +// Функции для работы с патом +//---------------------------------------------------------------------------------------- +HRESULT CPdfWriter::PathCommandStart() +{ + m_oPath.Clear(); + return S_OK; +} +HRESULT CPdfWriter::PathCommandEnd() +{ + m_oPath.Clear(); + return S_OK; +} +HRESULT CPdfWriter::DrawPath(const LONG& lType) +{ + m_oCommandManager.Flush(); + + if (!IsPageValid()) + return S_FALSE; + + bool bStroke = LONG_2_BOOL(lType & c_nStroke); + bool bFill = LONG_2_BOOL(lType & c_nWindingFillMode); + bool bEoFill = LONG_2_BOOL(lType & c_nEvenOddFillMode); + + m_pPage->GrSave(); + UpdateTransform(); + + if (bStroke) + UpdatePen(); + + std::wstring sTextureOldPath = L""; + std::wstring sTextureTmpPath = L""; + + if (bFill || bEoFill) + { + if (c_BrushTypeTexture == m_oBrush.GetType()) + { + sTextureOldPath = m_oBrush.GetTexturePath(); + sTextureTmpPath = GetDownloadFile(sTextureOldPath); + + if (!sTextureTmpPath.empty()) + m_oBrush.SetTexturePath(sTextureTmpPath); + } + + UpdateBrush(); + } + + if (!m_pShading) + { + m_oPath.Draw(m_pPage, bStroke, bFill, bEoFill); + } + else + { + if (bFill || bEoFill) + { + m_pPage->GrSave(); + m_oPath.Clip(m_pPage, bEoFill); + + if (NULL != m_pShadingExtGrState) + m_pPage->SetExtGrState(m_pShadingExtGrState); + + m_pPage->DrawShading(m_pShading); + m_pPage->GrRestore(); + } + + if (bStroke) + m_oPath.Draw(m_pPage, bStroke, false, false); + } + + m_pPage->GrRestore(); + + if (!sTextureTmpPath.empty()) + { + m_oBrush.SetTexturePath(sTextureOldPath); + + if (NSFile::CFileBinary::Exists(sTextureTmpPath)) + NSFile::CFileBinary::Remove(sTextureTmpPath); + } + + return S_OK; +} +HRESULT CPdfWriter::PathCommandMoveTo(const double& dX, const double& dY) +{ + m_oPath.MoveTo(MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY)); + return S_OK; +} +HRESULT CPdfWriter::PathCommandLineTo(const double& dX, const double& dY) +{ + m_oPath.LineTo(MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY)); + return S_OK; +} +HRESULT CPdfWriter::PathCommandLinesTo(double* pPoints, const int& nCount) +{ + if (nCount < 4 || !pPoints) + return S_OK; + + if (!m_oPath.IsMoveTo()) + m_oPath.MoveTo(MM_2_PT(pPoints[0]), MM_2_PT(m_dPageHeight - pPoints[1])); + + int nPointsCount = (nCount / 2) - 1; + for (int nIndex = 1; nIndex <= nPointsCount; ++nIndex) + { + m_oPath.LineTo(MM_2_PT(pPoints[nIndex * 2]), MM_2_PT(m_dPageHeight - pPoints[nIndex * 2 + 1])); + } + + return S_OK; +} +HRESULT CPdfWriter::PathCommandCurveTo(const double& dX1, const double& dY1, const double& dX2, const double& dY2, const double& dXe, const double& dYe) +{ + m_oPath.CurveTo(MM_2_PT(dX1), MM_2_PT(m_dPageHeight - dY1), MM_2_PT(dX2), MM_2_PT(m_dPageHeight - dY2), MM_2_PT(dXe), MM_2_PT(m_dPageHeight - dYe)); + return S_OK; +} +HRESULT CPdfWriter::PathCommandCurvesTo(double* pPoints, const int& nCount) +{ + if (nCount < 8 || !pPoints) + return S_OK; + + if (!m_oPath.IsMoveTo()) + m_oPath.MoveTo(MM_2_PT(pPoints[0]), MM_2_PT(m_dPageHeight - pPoints[1])); + + int nPointsCount = (nCount - 2) / 6; + double* pCur = pPoints + 2; + for (int nIndex = 0; nIndex <= nPointsCount; ++nIndex, pCur += 6) + { + m_oPath.CurveTo(MM_2_PT(pCur[0]), MM_2_PT(m_dPageHeight - pCur[1]), MM_2_PT(pCur[2]), MM_2_PT(m_dPageHeight - pCur[3]), MM_2_PT(pCur[4]), MM_2_PT(m_dPageHeight - pCur[5])); + } + + return S_OK; +} +HRESULT CPdfWriter::PathCommandArcTo(const double& dX, const double& dY, const double& dW, const double& dH, const double& dStartAngle, const double& dSweepAngle) +{ + m_oPath.ArcTo(MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY - dH), MM_2_PT(dW), MM_2_PT(dH), dStartAngle, dSweepAngle); + return S_OK; +} +HRESULT CPdfWriter::PathCommandClose() +{ + m_oPath.Close(); + return S_OK; +} +HRESULT CPdfWriter::PathCommandGetCurrentPoint(double* dX, double* dY) +{ + m_oPath.GetLastPoint(*dX, *dY); + *dX = PT_2_MM(*dX); + *dY = PT_2_MM(*dY); + return S_OK; +} +HRESULT CPdfWriter::PathCommandTextCHAR(const LONG& lUnicode, const double& dX, const double& dY, const double& dW, const double& dH) +{ + unsigned int unUnicode = lUnicode; + bool bRes = PathCommandDrawText(&unUnicode, 1, dX, dY, NULL); + return bRes ? S_OK : S_FALSE; +} +HRESULT CPdfWriter::PathCommandText(const std::wstring& wsUnicodeText, const double& dX, const double& dY, const double& dW, const double& dH) +{ + unsigned int unLen; + unsigned int* pUnicodes = WStringToUtf32(wsUnicodeText, unLen); + if (!pUnicodes) + return S_FALSE; + + PathCommandDrawText(pUnicodes, unLen, dX, dY, NULL); + delete[] pUnicodes; + + return S_OK; +} +HRESULT CPdfWriter::PathCommandTextExCHAR(const LONG& lUnicode, const LONG& lGid, const double& dX, const double& dY, const double& dW, const double& dH) +{ + unsigned int unUnicode = lUnicode; + unsigned int unGid = lGid; + bool bRes = PathCommandDrawText(&unUnicode, 1, dX, dY, &unGid); + return bRes ? S_OK : S_FALSE; +} +HRESULT CPdfWriter::PathCommandTextEx(const std::wstring& wsUnicodeText, const unsigned int* pGids, const unsigned int unGidsCount, const double& dX, const double& dY, const double& dW, const double& dH) +{ + if (!IsPageValid() || (!wsUnicodeText.size() && (!pGids || !unGidsCount))) + return S_FALSE; + + unsigned int unLen = 0; + unsigned int* pUnicodes = NULL; + if (pGids && unGidsCount) + { + unLen = unGidsCount; + if (wsUnicodeText.size()) + { + unsigned int unUnicodeLen; + pUnicodes = WStringToUtf32(wsUnicodeText, unUnicodeLen); + if (!pUnicodes || unUnicodeLen != unLen) + RELEASEARRAYOBJECTS(pUnicodes); + } + + if (!pUnicodes) + { + pUnicodes = new unsigned int[unLen]; + if (!pUnicodes) + return S_FALSE; + + for (unsigned int unIndex = 0; unIndex < unLen; unIndex++) + pUnicodes[unIndex] = pGids[unIndex]; + } + } + else + { + pUnicodes = WStringToUtf32(wsUnicodeText, unLen); + if (!pUnicodes) + return S_FALSE; + } + + bool bRes = PathCommandDrawText(pUnicodes, unLen, dX, dY, pGids); + RELEASEARRAYOBJECTS(pUnicodes); + + return bRes ? S_OK : S_FALSE; +} +//---------------------------------------------------------------------------------------- +// Функции для вывода изображений +//---------------------------------------------------------------------------------------- +HRESULT CPdfWriter::DrawImage(IGrObject* pImage, const double& dX, const double& dY, const double& dW, const double& dH) +{ + m_oCommandManager.Flush(); + + if (!IsPageValid() || !pImage) + return S_OK; + + if (!DrawImage((Aggplus::CImage*)pImage, dX, dY, dW, dH, 255)) + return S_FALSE; + + return S_OK; +} +HRESULT CPdfWriter::DrawImageFromFile(const std::wstring& wsImagePathSrc, const double& dX, const double& dY, const double& dW, const double& dH, const BYTE& nAlpha) +{ + m_oCommandManager.Flush(); + + if (!IsPageValid()) + return S_OK; + + std::wstring sTempImagePath = GetDownloadFile(wsImagePathSrc); + std::wstring wsImagePath = sTempImagePath.empty() ? wsImagePathSrc : sTempImagePath; + + Aggplus::CImage* pAggImage = NULL; + + CImageFileFormatChecker oImageFormat(wsImagePath); + if (_CXIMAGE_FORMAT_WMF == oImageFormat.eFileType || + _CXIMAGE_FORMAT_EMF == oImageFormat.eFileType || + _CXIMAGE_FORMAT_SVM == oImageFormat.eFileType || + _CXIMAGE_FORMAT_SVG == oImageFormat.eFileType) + { + // TODO: Реализовать отрисовку метафайлов по-нормальному + MetaFile::IMetaFile* pMeta = MetaFile::Create(m_pAppFonts); + pMeta->LoadFromFile(wsImagePath.c_str()); + + double dNewW = std::max(10.0, dW) / 25.4 * 300; + std::wstring wsTempFile = GetTempFile(); + pMeta->ConvertToRaster(wsTempFile.c_str(), _CXIMAGE_FORMAT_PNG, dNewW); + + RELEASEOBJECT(pMeta); + + pAggImage = new Aggplus::CImage(wsTempFile); + } + else + { + pAggImage = new Aggplus::CImage(wsImagePath); + } + + HRESULT hRes = S_OK; + if (!pAggImage || !DrawImage(pAggImage, dX, dY, dW, dH, nAlpha)) + hRes = S_FALSE; + + if (NSFile::CFileBinary::Exists(sTempImagePath)) + NSFile::CFileBinary::Remove(sTempImagePath); + + if (pAggImage) + delete pAggImage; + + return hRes; +} +//---------------------------------------------------------------------------------------- +// Функции для выставления преобразования +//---------------------------------------------------------------------------------------- +HRESULT CPdfWriter::SetTransform(const double& dM11, const double& dM12, const double& dM21, const double& dM22, const double& dX, const double& dY) +{ + m_oCommandManager.Flush(); + m_oTransform.Set(dM11, dM12, dM21, dM22, dX, dY); + return S_OK; +} +HRESULT CPdfWriter::GetTransform(double* dM11, double* dM12, double* dM21, double* dM22, double* dX, double* dY) +{ + *dM11 = m_oTransform.m11; + *dM12 = m_oTransform.m12; + *dM21 = m_oTransform.m21; + *dM22 = m_oTransform.m22; + *dX = m_oTransform.dx; + *dY = m_oTransform.dy; + return S_OK; +} +HRESULT CPdfWriter::ResetTransform() +{ + m_oCommandManager.Flush(); + m_oTransform.Reset(); + return S_OK; +} +//---------------------------------------------------------------------------------------- +// Тип клипа +//---------------------------------------------------------------------------------------- +HRESULT CPdfWriter::get_ClipMode(LONG* lMode) +{ + *lMode = m_lClipMode; + return S_OK; +} +HRESULT CPdfWriter::put_ClipMode(const LONG& lMode) +{ + m_lClipMode = lMode; + return S_OK; +} +//---------------------------------------------------------------------------------------- +// Дополнительные функции +//---------------------------------------------------------------------------------------- +HRESULT CPdfWriter::CommandLong(const LONG& lType, const LONG& lCommand) +{ + return S_OK; +} +HRESULT CPdfWriter::CommandDouble(const LONG& lType, const double& dCommand) +{ + return S_OK; +} +HRESULT CPdfWriter::CommandString(const LONG& lType, const std::wstring& sCommand) +{ + return S_OK; +} +HRESULT CPdfWriter::AddHyperlink(const double& dX, const double& dY, const double& dW, const double& dH, const std::wstring& wsUrl, const std::wstring& wsTooltip) +{ + NSUnicodeConverter::CUnicodeConverter conv; + CAnnotation* pAnnot = m_pDocument->CreateUriLinkAnnot(m_pPage, TRect(MM_2_PT(dX), m_pPage->GetHeight() - MM_2_PT(dY), MM_2_PT(dX + dW), m_pPage->GetHeight() - MM_2_PT(dY + dH)), conv.SASLprepToUtf8(wsUrl).c_str()); + pAnnot->SetBorderStyle(EBorderSubtype::border_subtype_Solid, 0); + return S_OK; +} +HRESULT CPdfWriter::AddLink(const double& dX, const double& dY, const double& dW, const double& dH, const double& dDestX, const double& dDestY, const int& nPage) +{ + unsigned int unPagesCount = m_pDocument->GetPagesCount(); + if (unPagesCount == 0) + return S_OK; + + CPage* pPage = m_pDocument->GetPage(nPage); + if (!pPage) + { + m_vDestinations.push_back(TDestinationInfo(m_pPage, dX, dY, dW, dH, dDestX, dDestY, nPage)); + } + else + { + AddLink(m_pPage, dX, dY, dW, dH, dDestX, dDestY, nPage); + } + + return S_OK; +} +HRESULT CPdfWriter::AddFormField(const CFormFieldInfo &oInfo) +{ + unsigned int unPagesCount = m_pDocument->GetPagesCount(); + if (!m_pDocument || 0 == unPagesCount) + return S_OK; + + if (m_bNeedUpdateTextFont) + UpdateFont(); + + if (!m_pFont) + return S_OK; + + PdfWriter::CFontTrueType* pFontTT = m_pDocument->CreateTrueTypeFont(m_pFont); + if (!pFontTT) + return S_OK; + + double dX, dY, dW, dH; + oInfo.GetBounds(dX, dY, dW, dH); + + CFieldBase* pFieldBase = NULL; + + bool bRadioButton = false; + + if (oInfo.IsTextField()) + { + CTextField* pField = m_pDocument->CreateTextField(); + pFieldBase = static_cast(pField); + } + else if (oInfo.IsDropDownList()) + { + CChoiceField* pField = m_pDocument->CreateChoiceField(); + pFieldBase = static_cast(pField); + } + else if (oInfo.IsCheckBox()) + { + const CFormFieldInfo::CCheckBoxFormPr* pPr = oInfo.GetCheckBoxPr(); + + CCheckBoxField* pField = NULL; + std::wstring wsGroupName = pPr->GetGroupKey(); + if (L"" != wsGroupName) + { + bRadioButton = true; + CRadioGroupField* pRadioGroup = m_pDocument->GetRadioGroupField(wsGroupName); + if (pRadioGroup) + pField = pRadioGroup->CreateKid(); + } + else + { + pField = m_pDocument->CreateCheckBoxField(); + } + + pFieldBase = static_cast(pField); + } + else if (oInfo.IsPicture()) + { + CPictureField* pField = m_pDocument->CreatePictureField(); + pFieldBase = static_cast(pField); + } + else if (oInfo.IsSignature()) + { + CSignatureField* pField = m_pDocument->CreateSignatureField(); + pFieldBase = static_cast(pField); + } + + if (!pFieldBase) + return S_FALSE; + + // 0 - Right + // 1 - Left + // 2 - Center + // 3 - Justify + // 4 - Distributed + unsigned int unAlign = oInfo.GetJc(); + if (0 == unAlign) + pFieldBase->SetAlign(CFieldBase::EFieldAlignType::Right); + else if (2 == unAlign) + pFieldBase->SetAlign(CFieldBase::EFieldAlignType::Center); + + if (oInfo.HaveBorder()) + { + unsigned char unR, unG, unB, unA; + oInfo.GetBorderColor(unR, unG, unB, unA); + + pFieldBase->SetFieldBorder(EBorderSubtype::border_subtype_Solid, TRgb(unR, unG, unB), MM_2_PT(oInfo.GetBorderSize()), 0, 0, 0); + } + + if (oInfo.HaveShd()) + { + unsigned char unR, unG, unB, unA; + oInfo.GetShdColor(unR, unG, unB, unA); + pFieldBase->SetShd(TRgb(unR, unG, unB)); + } + + pFieldBase->SetRequiredFlag(oInfo.IsRequired()); + pFieldBase->SetFieldHint(oInfo.GetHelpText()); + + bool isBold = m_oFont.IsBold(); + bool isItalic = m_oFont.IsItalic(); + + + if (oInfo.IsTextField()) + { + const CFormFieldInfo::CTextFormPr* pPr = oInfo.GetTextPr(); + std::wstring wsValue = pPr->GetTextValue(); + + unsigned int unLen; + unsigned int* pUnicodes = WStringToUtf32(wsValue, unLen); + if (!pUnicodes) + return S_FALSE; + + unsigned short* pCodes = new unsigned short[unLen]; + if (!pCodes) + { + RELEASEARRAYOBJECTS(pUnicodes); + return S_FALSE; + } + + CFontCidTrueType** ppFonts = new CFontCidTrueType*[unLen]; + if (!ppFonts) + { + RELEASEARRAYOBJECTS(pUnicodes); + RELEASEARRAYOBJECTS(pCodes); + return S_FALSE; + } + + for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex) + { + unsigned int unUnicode = pUnicodes[unIndex]; + + if (!m_pFont->HaveChar(unUnicode)) + { + std::wstring wsFontFamily = m_pAppFonts->GetFontBySymbol(unUnicode); + CFontCidTrueType* pTempFont = GetFont(wsFontFamily, isBold, isItalic); + if (pTempFont) + { + pCodes[unIndex] = pTempFont->EncodeUnicode(unUnicode); + ppFonts[unIndex] = pTempFont; + continue; + } + } + + pCodes[unIndex] = m_pFont->EncodeUnicode(unUnicode); + ppFonts[unIndex] = m_pFont; + } + + CTextField* pField = dynamic_cast(pFieldBase); + if (!pField) + { + RELEASEARRAYOBJECTS(pUnicodes); + RELEASEARRAYOBJECTS(pCodes); + RELEASEARRAYOBJECTS(ppFonts); + return S_FALSE; + } + + double _dY = m_pPage->GetHeight() - MM_2_PT(dY); + double _dB = m_pPage->GetHeight() - MM_2_PT(dY + dH); + + double dMargin = 2; // такой отступ используется в AdobeReader + double dBaseLine = MM_2_PT(dH - oInfo.GetBaseLineOffset()); + double dShiftX = dMargin; + + pFieldBase->AddPageRect(m_pPage, TRect(MM_2_PT(dX) - dMargin, _dY, MM_2_PT(dX + dW) + dMargin, _dB)); + + pField->SetMaxLen(pPr->GetMaxCharacters()); + pField->SetCombFlag(pPr->IsComb()); + pField->SetAutoFit(pPr->IsAutoFit()); + pField->SetMultilineFlag(pPr->IsMultiLine()); + + bool isComb = pPr->IsComb(); + unsigned int unAlign = oInfo.GetJc(); + double dFontSize = m_oFont.GetSize(); + + TColor oColor = m_oBrush.GetTColor1(); + bool isPlaceHolder = oInfo.IsPlaceHolder(); + + TRgb oNormalColor(oColor.r, oColor.g, oColor.b); + TRgb oPlaceHolderColor; + oPlaceHolderColor.r = oNormalColor.r + (1.0 - oNormalColor.r) / 2.0; + oPlaceHolderColor.g = oNormalColor.g + (1.0 - oNormalColor.g) / 2.0; + oPlaceHolderColor.b = oNormalColor.b + (1.0 - oNormalColor.b) / 2.0; + + if (!isPlaceHolder) + pField->SetTextValue(wsValue); + + if (!isComb && pPr->IsMultiLine()) + { + unsigned short* pCodes2 = new unsigned short[unLen]; + unsigned int* pWidths = new unsigned int[unLen]; + + unsigned short ushSpaceCode = 0xFFFF; + for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex) + { + pCodes2[unIndex] = (0x0020 == pUnicodes[unIndex] ? ushSpaceCode : 0); + pWidths[unIndex] = ppFonts[unIndex]->GetWidth(pCodes[unIndex]); + } + + m_oLinesManager.Init(pCodes2, pWidths, unLen, ushSpaceCode, pFontTT->GetLineHeight(), pFontTT->GetAscent()); + + // TODO: Разобраться более детально по какой именно высоте идет в Adobe расчет + // пока временно оставим (H - 3 * margin) + if (pPr->IsAutoFit()) + dFontSize = m_oLinesManager.ProcessAutoFit(MM_2_PT(dW), (MM_2_PT(dH) - 3 * dMargin)); + + double dLineHeight = pFontTT->GetLineHeight() * dFontSize / 1000.0; + + m_oLinesManager.CalculateLines(dFontSize, MM_2_PT(dW)); + + pField->StartTextAppearance(m_pFont, dFontSize, isPlaceHolder ? oPlaceHolderColor : oNormalColor, 1.0); + + unsigned int unLinesCount = m_oLinesManager.GetLinesCount(); + double dLineShiftY = MM_2_PT(dH) - pFontTT->GetLineHeight() * dFontSize / 1000.0 - dMargin; + for (unsigned int unIndex = 0; unIndex < unLinesCount; ++unIndex) + { + unsigned int unLineStart = m_oLinesManager.GetLineStartPos(unIndex); + double dLineShiftX = dShiftX; + double dLineWidth = m_oLinesManager.GetLineWidth(unIndex, dFontSize); + if (0 == unAlign) + dLineShiftX += MM_2_PT(dW) - dLineWidth; + else if (2 == unAlign) + dLineShiftX += (MM_2_PT(dW) - dLineWidth) / 2; + + int nInLineCount = m_oLinesManager.GetLineEndPos(unIndex) - m_oLinesManager.GetLineStartPos(unIndex); + if (nInLineCount > 0) + pField->AddLineToTextAppearance(dLineShiftX, dLineShiftY, pCodes + unLineStart, nInLineCount, ppFonts + unLineStart, NULL); + + dLineShiftY -= dLineHeight; + } + + pField->EndTextAppearance(); + + m_oLinesManager.Clear(); + + delete[] pCodes2; + delete[] pWidths; + } + else + { + double* pShifts = NULL; + unsigned int unShiftsCount = 0; + + if (isComb) + { + pField->SetDoNotScrollFlag(true); + pField->SetDoNotSpellCheckFlag(true); + pField->SetMultilineFlag(false); + + unShiftsCount = unLen; + pShifts = new double[unShiftsCount]; + if (pShifts && unShiftsCount) + { + // Сдвиг нулевой для comb форм и не забываем, что мы к ширине добавили 2 * dMargin + dShiftX = 0; + unsigned int unCellsCount = std::max(unShiftsCount, pPr->GetMaxCharacters()); + double dPrevW = 0; + double dCellW = (MM_2_PT(dW) + 2 * dMargin) / unCellsCount; + + if (0 == unAlign && unShiftsCount) + dPrevW = (unCellsCount - unShiftsCount) * dCellW; + + for (unsigned int unIndex = 0; unIndex < unShiftsCount; ++unIndex) + { + unsigned short ushCode = pCodes[unIndex]; + double dGlyphWidth = ppFonts[unIndex]->GetGlyphWidth(ushCode) / 1000.0 * dFontSize; + double dTempShift = (dCellW - dGlyphWidth) / 2; + pShifts[unIndex] = dPrevW + dTempShift; + dPrevW = dCellW - dTempShift; + + } + } + else + { + unShiftsCount = 0; + } + } + else if (0 == unAlign || 2 == unAlign) + { + double dSumWidth = 0; + for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex) + { + unsigned short ushCode = pCodes[unIndex]; + double dLetterWidth = ppFonts[unIndex]->GetWidth(ushCode) / 1000.0 * dFontSize; + dSumWidth += dLetterWidth; + } + + if (0 == unAlign && MM_2_PT(dW) - dSumWidth > 0) + dShiftX += MM_2_PT(dW) - dSumWidth; + else if (2 == unAlign && (MM_2_PT(dW) - dSumWidth) / 2 > 0) + dShiftX += (MM_2_PT(dW) - dSumWidth) / 2; + } + + pField->SetTextAppearance(wsValue, pCodes, unLen, m_pFont, isPlaceHolder ? oPlaceHolderColor : oNormalColor, 1.0, m_oFont.GetSize(), dShiftX, dBaseLine, ppFonts, pShifts); + RELEASEARRAYOBJECTS(pShifts); + } + + RELEASEARRAYOBJECTS(pUnicodes); + RELEASEARRAYOBJECTS(pCodes); + RELEASEARRAYOBJECTS(ppFonts); + + pField->SetDefaultAppearance(pFontTT, m_oFont.GetSize(), TRgb(oColor.r, oColor.g, oColor.b)); + + std::wstring wsPlaceHolder = pPr->GetPlaceHolder(); + if (!wsPlaceHolder.empty()) + { + unsigned int unMaxLen = pPr->GetMaxCharacters(); + if (unMaxLen && wsPlaceHolder.length() > unMaxLen) + wsPlaceHolder = wsPlaceHolder.substr(0, unMaxLen); + + pField->SetPlaceHolderText(wsPlaceHolder, oNormalColor, oPlaceHolderColor); + } + + pField->SetFormat(pPr->GetFormatPr()); + } + else if (oInfo.IsDropDownList()) + { + const CFormFieldInfo::CDropDownFormPr* pPr = oInfo.GetDropDownPr(); + std::wstring wsValue = pPr->GetTextValue(); + + unsigned int unLen; + unsigned int* pUnicodes = WStringToUtf32(wsValue, unLen); + if (!pUnicodes) + return S_FALSE; + + unsigned short* pCodes = new unsigned short[unLen]; + if (!pCodes) + { + RELEASEARRAYOBJECTS(pUnicodes); + return S_FALSE; + } + + CFontCidTrueType** ppFonts = new CFontCidTrueType*[unLen]; + if (!ppFonts) + { + RELEASEARRAYOBJECTS(pUnicodes); + RELEASEARRAYOBJECTS(pCodes); + return S_FALSE; + } + + for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex) + { + unsigned int unUnicode = pUnicodes[unIndex]; + + if (!m_pFont->HaveChar(unUnicode)) + { + std::wstring wsFontFamily = m_pAppFonts->GetFontBySymbol(unUnicode); + CFontCidTrueType* pTempFont = GetFont(wsFontFamily, isBold, isItalic); + if (pTempFont) + { + pCodes[unIndex] = pTempFont->EncodeUnicode(unUnicode); + ppFonts[unIndex] = pTempFont; + continue; + } + } + pCodes[unIndex] = m_pFont->EncodeUnicode(unUnicode); + ppFonts[unIndex] = m_pFont; + } + + CChoiceField* pField = dynamic_cast(pFieldBase); + if (!pField) + { + RELEASEARRAYOBJECTS(pUnicodes); + RELEASEARRAYOBJECTS(pCodes); + RELEASEARRAYOBJECTS(ppFonts); + return S_FALSE; + } + + pFieldBase->AddPageRect(m_pPage, TRect(MM_2_PT(dX), m_pPage->GetHeight() - MM_2_PT(dY), MM_2_PT(dX + dW), m_pPage->GetHeight() - MM_2_PT(dY + dH))); + + TColor oColor = m_oBrush.GetTColor1(); + + TRgb oNormalColor(oColor.r, oColor.g, oColor.b); + TRgb oPlaceHolderColor; + oPlaceHolderColor.r = oNormalColor.r + (1.0 - oNormalColor.r) / 2.0; + oPlaceHolderColor.g = oNormalColor.g + (1.0 - oNormalColor.g) / 2.0; + oPlaceHolderColor.b = oNormalColor.b + (1.0 - oNormalColor.b) / 2.0; + + pField->SetTextValue(wsValue); + pField->SetTextAppearance(wsValue, pCodes, unLen, m_pFont, oInfo.IsPlaceHolder() ? oPlaceHolderColor : oNormalColor, 1, m_oFont.GetSize(), 0, MM_2_PT(dH - oInfo.GetBaseLineOffset()), ppFonts); + + RELEASEARRAYOBJECTS(pUnicodes); + RELEASEARRAYOBJECTS(pCodes); + RELEASEARRAYOBJECTS(ppFonts); + + unsigned int unSelectedIndex = 0xFFFF; + for (unsigned int unIndex = 0, unItemsCount = pPr->GetComboBoxItemsCount(); unIndex < unItemsCount; ++unIndex) + { + std::wstring wsItem = pPr->GetComboBoxItem(unIndex); + pField->AddOption(wsItem); + if (wsItem == wsValue) + unSelectedIndex = unIndex; + } + + pField->SetComboFlag(true); + pField->SetEditFlag(pPr->IsEditComboBox()); + + pField->SetDefaultAppearance(pFontTT, m_oFont.GetSize(), oInfo.IsPlaceHolder() ? oPlaceHolderColor : oNormalColor); + + if (!pPr->GetPlaceHolder().empty()) + { + pField->SetPlaceHolderText(pPr->GetPlaceHolder(), oNormalColor, oPlaceHolderColor); + + if (!pPr->IsEditComboBox()) + { + // Для drop-down list в 0 позиции мы добавили плейсхолдер + if (oInfo.IsPlaceHolder()) + unSelectedIndex = 0; + else if (0xFFFF != unSelectedIndex) + unSelectedIndex++; + } + } + + if (!pPr->IsEditComboBox() && 0xFFFF != unSelectedIndex) + pField->SetSelectedIndex(unSelectedIndex); + } + else if (oInfo.IsCheckBox()) + { + const CFormFieldInfo::CCheckBoxFormPr* pPr = oInfo.GetCheckBoxPr(); + + CCheckBoxField* pField = dynamic_cast(pFieldBase); + if (!pField) + return S_FALSE; + + pFieldBase->AddPageRect(m_pPage, TRect(MM_2_PT(dX), m_pPage->GetHeight() - MM_2_PT(dY), MM_2_PT(dX + dW), m_pPage->GetHeight() - MM_2_PT(dY + dH))); + pField->SetValue(pPr->IsChecked()); + + CFontCidTrueType* pCheckedFont = GetFont(pPr->GetCheckedFontName(), false, false); + CFontCidTrueType* pUncheckedFont = GetFont(pPr->GetUncheckedFontName(), false, false); + if (!pCheckedFont) + pCheckedFont = m_pFont; + + if (!pUncheckedFont) + pUncheckedFont = m_pFont; + + unsigned int unCheckedSymbol = pPr->GetCheckedSymbol(); + unsigned int unUncheckedSymbol = pPr->GetUncheckedSymbol(); + + unsigned short ushCheckedCode = pCheckedFont->EncodeUnicode(unCheckedSymbol); + unsigned short ushUncheckedCode = pUncheckedFont->EncodeUnicode(unUncheckedSymbol); + + TColor oColor = m_oBrush.GetTColor1(); + pField->SetAppearance(L"", &ushCheckedCode, 1, pCheckedFont, L"", &ushUncheckedCode, 1, pUncheckedFont, TRgb(oColor.r, oColor.g, oColor.b), 1, m_oFont.GetSize(), 0, MM_2_PT(dH - oInfo.GetBaseLineOffset())); + } + else if (oInfo.IsPicture()) + { + const CFormFieldInfo::CPictureFormPr* pPr = oInfo.GetPicturePr(); + + CPictureField* pField = dynamic_cast(pFieldBase); + pFieldBase->AddPageRect(m_pPage, TRect(MM_2_PT(dX), m_pPage->GetHeight() - MM_2_PT(dY), MM_2_PT(dX + dW), m_pPage->GetHeight() - MM_2_PT(dY + dH))); + pField->SetConstantProportions(pPr->IsConstantProportions()); + pField->SetRespectBorders(pPr->IsRespectBorders()); + pField->SetScaleType(static_cast(pPr->GetScaleType())); + pField->SetShift(pPr->GetShiftX() / 1000.0, (1000 - pPr->GetShiftY()) / 1000.0); + + std::wstring wsPath = pPr->GetPicturePath(); + CImageDict* pImage = NULL; + if (wsPath.length()) + { + Aggplus::CImage oImage(wsPath); + pImage = LoadImage(&oImage, 255); + } + + pField->SetAppearance(pImage); + } + else if (oInfo.IsSignature()) + { + const CFormFieldInfo::CSignatureFormPr* pPr = oInfo.GetSignaturePr(); + + CSignatureField* pField = dynamic_cast(pFieldBase); + if (!pField) + return S_FALSE; + + pFieldBase->AddPageRect(m_pPage, TRect(MM_2_PT(dX), m_pPage->GetHeight() - MM_2_PT(dY), MM_2_PT(dX + dW), m_pPage->GetHeight() - MM_2_PT(dY + dH))); + pField->SetName(pPr->GetName()); + pField->SetReason(pPr->GetReason()); + pField->SetContact(pPr->GetContact()); + pField->SetDate(pPr->GetDate()); + + std::wstring wsPath = pPr->GetPicturePath(); + CImageDict* pImage = NULL; + if (!wsPath.empty()) + { + Aggplus::CImage oImage(wsPath); + pImage = LoadImage(&oImage, 255); + } + + pField->SetAppearance(pImage); + + // TODO Реализовать, когда появится поддержка CSignatureField + pField->SetCert(); + } + + + // Выставляем имя в конце, потому что там возможно копирование настроек поля в новое родительское поле, поэтому к текущему моменту + // все настройки должны быть выставлены + if (!bRadioButton) + { + std::wstring wsKey = oInfo.GetKey(); + if (L"" != wsKey) + pFieldBase->SetFieldName(wsKey); + else + pFieldBase->SetFieldName(m_oFieldsManager.GetNewFieldName()); + } + + return S_OK; +} +//---------------------------------------------------------------------------------------- +// Дополнительные функции Pdf рендерера +//---------------------------------------------------------------------------------------- +HRESULT CPdfWriter::CommandDrawTextPdf(const std::wstring& bsUnicodeText, const unsigned int* pGids, const unsigned int unGidsCount, const std::wstring& bsSrcCodeText, const double& dX, const double& dY, const double& dW, const double& dH) +{ + return S_OK; +} +HRESULT CPdfWriter::PathCommandTextPdf(const std::wstring& bsUnicodeText, const unsigned int* pGids, const unsigned int unGidsCount, const std::wstring& bsSrcCodeText, const double& dX, const double& dY, const double& dW, const double& dH) +{ + return S_OK; +} +HRESULT CPdfWriter::DrawImage1bpp(NSImages::CPixJbig2* pImageBuffer, const unsigned int& unWidth, const unsigned int& unHeight, const double& dX, const double& dY, const double& dW, const double& dH) +{ + m_oCommandManager.Flush(); + + if (!IsPageValid() || !pImageBuffer) + return S_OK; + + m_pPage->GrSave(); + UpdateTransform(); + + CImageDict* pPdfImage = m_pDocument->CreateImage(); + pPdfImage->LoadBW(pImageBuffer, unWidth, unHeight); + m_pPage->DrawImage(pPdfImage, MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY - dH), MM_2_PT(dW), MM_2_PT(dH)); + + m_pPage->GrRestore(); + return S_OK; +} +HRESULT CPdfWriter::EnableBrushRect(const LONG& lEnable) +{ + m_oBrush.EnableBrushRect(LONG_2_BOOL(lEnable)); + return S_OK; +} +HRESULT CPdfWriter::SetLinearGradient(const double& dX0, const double& dY0, const double& dX1, const double& dY1) +{ + m_oBrush.SetType(c_BrushTypeLinearGradient); + m_oBrush.SetLinearGradientPattern(dX0, dY0, dX1, dY1); + return S_OK; +} +HRESULT CPdfWriter::SetRadialGradient(const double& dX0, const double& dY0, const double& dR0, const double& dX1, const double& dY1, const double& dR1) +{ + m_oBrush.SetType(c_BrushTypeRadialGradient); + m_oBrush.SetRadialGradientPattern(dX0, dY0, dR0, dX1, dY1, dR1); + return S_OK; +} +HRESULT CPdfWriter::DrawImageWith1bppMask(IGrObject* pImage, NSImages::CPixJbig2* pMaskBuffer, const unsigned int& unMaskWidth, const unsigned int& unMaskHeight, const double& dX, const double& dY, const double& dW, const double& dH) +{ + m_oCommandManager.Flush(); + + if (!IsPageValid() || !pMaskBuffer || !pImage) + return S_OK; + + m_pPage->GrSave(); + UpdateTransform(); + CImageDict* pPdfImage = LoadImage((Aggplus::CImage*)pImage, 255); + pPdfImage->LoadMask(pMaskBuffer, unMaskWidth, unMaskHeight); + m_pPage->DrawImage(pPdfImage, MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY - dH), MM_2_PT(dW), MM_2_PT(dH)); + m_pPage->GrRestore(); + return S_OK; +} +std::pair CPdfWriter::GetPageRef(int nPageIndex) +{ + return m_pDocument->GetPageRef(nPageIndex); +} +bool CPdfWriter::EditPage(PdfWriter::CPage* pNewPage) +{ + if (!IsValid()) + return false; + m_oCommandManager.Flush(); + + m_pPage = pNewPage; + if (m_pPage) + { + m_dPageWidth = PT_2_MM(m_pPage->GetWidth()); + m_dPageHeight = PT_2_MM(m_pPage->GetHeight()); + Reset(); + return true; + } + return false; +} +bool CPdfWriter::AddPage(int nPageIndex) +{ + if (!IsValid()) + return false; + m_oCommandManager.Flush(); + + m_pPage = m_pDocument->AddPage(nPageIndex); + if (m_pPage) + { + m_pPage->SetWidth(MM_2_PT(m_dPageWidth)); + m_pPage->SetHeight(MM_2_PT(m_dPageHeight)); + Reset(); + return true; + } + return false; +} +bool CPdfWriter::DeletePage(int nPageIndex) +{ + return m_pDocument->DeletePage(nPageIndex); +} +bool CPdfWriter::EditClose() +{ + if (!IsValid()) + return false; + m_oCommandManager.Flush(); + + unsigned int nPagesCount = m_pDocument->GetPagesCount(); + for (int nIndex = 0, nCount = m_vDestinations.size(); nIndex < nCount; ++nIndex) + { + TDestinationInfo& oInfo = m_vDestinations.at(nIndex); + if (nPagesCount > oInfo.unDestPage) + { + AddLink(oInfo.pPage, oInfo.dX, oInfo.dY, oInfo.dW, oInfo.dH, oInfo.dDestX, oInfo.dDestY, oInfo.unDestPage); + m_vDestinations.erase(m_vDestinations.begin() + nIndex); + nIndex--; + nCount--; + } + } + + return true; +} +void CPdfWriter::PageRotate(int nRotate) +{ + if (m_pPage) + m_pPage->SetRotate(nRotate); +} +void CPdfWriter::Sign(const double& dX, const double& dY, const double& dW, const double& dH, const std::wstring& wsPicturePath, ICertificate* pCertificate) +{ + CImageDict* pImage = NULL; + if (!wsPicturePath.empty()) + { + Aggplus::CImage oImage(wsPicturePath); + pImage = LoadImage(&oImage, 255); + } + + m_pDocument->Sign(TRect(MM_2_PT(dX), m_pPage->GetHeight() - MM_2_PT(dY), MM_2_PT(dX + dW), m_pPage->GetHeight() - MM_2_PT(dY + dH)), + pImage, pCertificate); +} +std::wstring CPdfWriter::GetEditPdfPath() +{ + return m_pDocument->GetEditPdfPath(); +} + +NSFonts::IApplicationFonts* CPdfWriter::GetApplicationFonts() +{ + return m_pAppFonts; +} +//---------------------------------------------------------------------------------------- +// Внутренние функции +//---------------------------------------------------------------------------------------- +PdfWriter::CImageDict* CPdfWriter::LoadImage(Aggplus::CImage* pImage, const BYTE& nAlpha) +{ + int nImageW = abs((int)pImage->GetWidth()); + int nImageH = abs((int)pImage->GetHeight()); + BYTE* pData = pImage->GetData(); + int nStride = 4 * nImageW; + + // Картинки совсем маленьких размеров нельзя делать Jpeg2000 + bool bJpeg = false; + if (nImageH < 100 || nImageW < 100 || m_pDocument->IsPDFA()) + bJpeg = true; + + if (nImageH <= 0 || nImageW <= 0) + return NULL; + + // TODO: Пока не разберемся как в CxImage управлять параметрами кодирования нельзя писать в Jpeg2000, + // т.к. файлы получаются гораздо больше и конвертация идет намного дольше. + bJpeg = true; + + // Пробегаемся по картинке и определяем есть ли у нас альфа-канал + bool bAlpha = false; + + CBgraFrame oFrame; + if (m_pDocument->IsPDFA()) + { + BYTE* pCopyImage = new BYTE[4 * nImageW * nImageH]; + if (!pCopyImage) + return NULL; + + ::memcpy(pCopyImage, pData, 4 * nImageW * nImageH); + + BYTE* pDataMem = pCopyImage; + for (int nIndex = 0, nSize = nImageW * nImageH; nIndex < nSize; nIndex++) + { + if (pDataMem[3] < 32) + { + pDataMem[0] = 255; + pDataMem[1] = 255; + pDataMem[2] = 255; + } + pDataMem += 4; + } + + oFrame.put_Width(nImageW); + oFrame.put_Height(nImageH); + oFrame.put_Data(pCopyImage);// +4 * (nImageH - 1) * nImageW); + oFrame.put_Stride(-4* nImageW); + } + else + { + BYTE* pDataMem = pData; + for (int nIndex = 0, nSize = nImageW * nImageH; nIndex < nSize; nIndex++) + { + // making full-transparent pixels white + if (pDataMem[3] == 0) + { + pDataMem[0] = 255; + pDataMem[1] = 255; + pDataMem[2] = 255; + } + + if (!bAlpha && (pDataMem[3] < 255)) + { + bAlpha = true; + } + + pDataMem += 4; + } + oFrame.FromImage(pImage); + } + + oFrame.SetJpegQuality(85.0); + + BYTE* pBuffer = NULL; + int nBufferSize = 0; + if (!oFrame.Encode(pBuffer, nBufferSize, bJpeg ? _CXIMAGE_FORMAT_JPG : _CXIMAGE_FORMAT_JP2)) + return NULL; + + if (!pBuffer || !nBufferSize) + return NULL; + + CImageDict* pPdfImage = m_pDocument->CreateImage(); + if (bAlpha || nAlpha < 255) + pPdfImage->LoadSMask(pData, nImageW, nImageH, nAlpha, (pImage->GetStride() >= 0) ? false : true); + + if (bJpeg) + pPdfImage->LoadJpeg(pBuffer, nBufferSize, nImageW, nImageH); + else + pPdfImage->LoadJpx(pBuffer, nBufferSize, nImageW, nImageH); + + free(pBuffer); + + return pPdfImage; +} +bool CPdfWriter::DrawImage(Aggplus::CImage* pImage, const double& dX, const double& dY, const double& dW, const double& dH, const BYTE& nAlpha) +{ + CImageDict* pPdfImage = LoadImage(pImage, nAlpha); + if (!pPdfImage) + return false; + + m_pPage->GrSave(); + UpdateTransform(); + m_pPage->DrawImage(pPdfImage, MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY - dH), MM_2_PT(dW), MM_2_PT(dH)); + m_pPage->GrRestore(); + + return true; +} +bool CPdfWriter::DrawText(unsigned char* pCodes, const unsigned int& unLen, const double& dX, const double& dY) +{ + if (!pCodes || !unLen) + return false; + + CTransform& t = m_oTransform; + m_oCommandManager.SetTransform(t.m11, -t.m12, -t.m21, t.m22, MM_2_PT(t.dx + t.m21 * m_dPageHeight), MM_2_PT(m_dPageHeight - m_dPageHeight * t.m22 - t.dy)); + + CRendererTextCommand* pText = m_oCommandManager.AddText(pCodes, unLen, MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY)); + pText->SetFont(m_pFont); + pText->SetSize(m_oFont.GetSize()); + pText->SetColor(m_oBrush.GetColor1()); + pText->SetAlpha((BYTE)m_oBrush.GetAlpha1()); + pText->SetCharSpace(MM_2_PT(m_oFont.GetCharSpace())); + pText->SetNeedDoBold(m_oFont.IsNeedDoBold()); + pText->SetNeedDoItalic(m_oFont.IsNeedDoItalic()); + + return true; +} +bool CPdfWriter::PathCommandDrawText(unsigned int* pUnicodes, unsigned int unLen, const double& dX, const double& dY, const unsigned int* pGids) +{ + unsigned char* pCodes = EncodeString(pUnicodes, unLen, pGids); + if (!pCodes) + return false; + + m_oPath.AddText(m_pFont, pCodes, unLen * 2, MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY), m_oFont.GetSize(), MM_2_PT(m_oFont.GetCharSpace())); + return true; +} +void CPdfWriter::UpdateFont() +{ + m_bNeedUpdateTextFont = false; + std::wstring wsFontPath = m_oFont.GetPath(); + LONG lFaceIndex = m_oFont.GetFaceIndex(); + if (L"" == wsFontPath) + GetFontPath(m_oFont.GetName(), m_oFont.IsBold(), m_oFont.IsItalic(), wsFontPath, lFaceIndex); + + m_oFont.SetNeedDoBold(false); + m_oFont.SetNeedDoItalic(false); + + m_pFont = NULL; + if (L"" != wsFontPath) + { + m_pFont = GetFont(wsFontPath, lFaceIndex); + if (m_pFont) + { + if (m_oFont.IsItalic() && !m_pFont->IsItalic()) + m_oFont.SetNeedDoItalic(true); + + if (m_oFont.IsBold() && !m_pFont->IsBold()) + m_oFont.SetNeedDoBold(true); + } + } +} +void CPdfWriter::GetFontPath(const std::wstring &wsFontName, const bool &bBold, const bool &bItalic, std::wstring& wsFontPath, LONG& lFaceIndex) +{ + bool bFind = false; + for (int nIndex = 0, nCount = m_vFonts.size(); nIndex < nCount; nIndex++) + { + TFontInfo& oInfo = m_vFonts.at(nIndex); + if (oInfo.wsFontName == wsFontName && oInfo.bBold == bBold && oInfo.bItalic == bItalic) + { + wsFontPath = oInfo.wsFontPath; + lFaceIndex = oInfo.lFaceIndex; + bFind = true; + break; + } + } + + if (!bFind) + { + NSFonts::CFontSelectFormat oFontSelect; + oFontSelect.wsName = new std::wstring(wsFontName); + oFontSelect.bItalic = new INT(bItalic ? 1 : 0); + oFontSelect.bBold = new INT(bBold ? 1 : 0); + NSFonts::CFontInfo* pFontInfo = m_pFontManager->GetFontInfoByParams(oFontSelect, false); + if (!NSFonts::CFontInfo::CanEmbedForPreviewAndPrint(pFontInfo->m_usType)) + { + oFontSelect.Fill(pFontInfo); + if (NULL != oFontSelect.usType) + *oFontSelect.usType = NSFONTS_EMBEDDING_RIGHTS_PRINT_AND_PREVIEW; + else + oFontSelect.usType = new USHORT(NSFONTS_EMBEDDING_RIGHTS_PRINT_AND_PREVIEW); + + pFontInfo = m_pFontManager->GetFontInfoByParams(oFontSelect, false); + } + + wsFontPath = pFontInfo->m_wsFontPath; + lFaceIndex = pFontInfo->m_lIndex; + + m_vFonts.push_back(TFontInfo(wsFontName, bBold, bItalic, wsFontPath, lFaceIndex)); + } +} +PdfWriter::CFontCidTrueType* CPdfWriter::GetFont(const std::wstring& wsFontPath, const LONG& lFaceIndex) +{ + PdfWriter::CFontCidTrueType* pFont = NULL; + if (L"" != wsFontPath) + { + pFont = m_pDocument->FindCidTrueTypeFont(wsFontPath, lFaceIndex); + if (pFont) + return pFont; + + // TODO: Пока мы здесь предполагаем, что шрифты только либо TrueType, либо OpenType + if (!m_pFontManager->LoadFontFromFile(wsFontPath, lFaceIndex, 10, 72, 72)) + { + std::wcout << L"PDF Writer: Can't load fontfile " << wsFontPath.c_str() << "\n"; + return NULL; + } + + std::wstring wsFontType = m_pFontManager->GetFontType(); + if (L"TrueType" == wsFontType || L"OpenType" == wsFontType || L"CFF" == wsFontType) + pFont = m_pDocument->CreateCidTrueTypeFont(wsFontPath, lFaceIndex); + } + + return pFont; +} +PdfWriter::CFontCidTrueType* CPdfWriter::GetFont(const std::wstring& wsFontName, const bool& bBold, const bool& bItalic) +{ + std::wstring wsFontPath; + LONG lFaceIndex; + + GetFontPath(wsFontName, bBold, bItalic, wsFontPath, lFaceIndex); + return GetFont(wsFontPath, lFaceIndex); +} +void CPdfWriter::UpdateTransform() +{ + CTransform& t = m_oTransform; + m_pPage->SetTransform(t.m11, -t.m12, -t.m21, t.m22, MM_2_PT(t.dx + t.m21 * m_dPageHeight), MM_2_PT(m_dPageHeight - m_dPageHeight * t.m22 - t.dy)); +} +void CPdfWriter::UpdatePen() +{ + TColor oColor = m_oPen.GetTColor(); + m_pPage->SetStrokeColor(oColor.r, oColor.g, oColor.b); + m_pPage->SetStrokeAlpha((unsigned char)m_oPen.GetAlpha()); + m_pPage->SetLineWidth(MM_2_PT(m_oPen.GetSize())); + + LONG lDashCount = 0; + double* pDashPattern = NULL; + + LONG lDashStyle = m_oPen.GetDashStyle(); + if (Aggplus::DashStyleSolid == lDashStyle) + { + // Ничего не делаем + } + else if (Aggplus::DashStyleCustom == lDashStyle) + { + double *pDashPatternMM = m_oPen.GetDashPattern(lDashCount); + if (pDashPatternMM && lDashCount) + { + pDashPattern = new double[lDashCount]; + if (pDashPattern) + { + for (LONG lIndex = 0; lIndex < lDashCount; lIndex++) + { + pDashPattern[lIndex] = MM_2_PT(pDashPatternMM[lIndex]); + } + } + } + } + else + { + // TODO: Реализовать другие типы пунктирных линий + } + + if (pDashPattern && lDashCount) + { + m_pPage->SetDash(pDashPattern, lDashCount, MM_2_PT(m_oPen.GetDashOffset())); + delete[] pDashPattern; + } + + LONG lCapStyle = m_oPen.GetStartCapStyle(); + if (Aggplus::LineCapRound == lCapStyle) + m_pPage->SetLineCap(linecap_Round); + else if (Aggplus::LineCapSquare == lCapStyle) + m_pPage->SetLineCap(linecap_ProjectingSquare); + else + m_pPage->SetLineCap(linecap_Butt); + + LONG lJoinStyle = m_oPen.GetJoinStyle(); + if (Aggplus::LineJoinBevel == lJoinStyle) + m_pPage->SetLineJoin(linejoin_Bevel); + else if (Aggplus::LineJoinMiter == lJoinStyle) + { + m_pPage->SetLineJoin(linejoin_Miter); + m_pPage->SetMiterLimit(MM_2_PT(m_oPen.GetMiter())); + } + else + m_pPage->SetLineJoin(linejoin_Round); +} +void CPdfWriter::UpdateBrush() +{ + m_pShading = NULL; + m_pShadingExtGrState = NULL; + + LONG lBrushType = m_oBrush.GetType(); + if (c_BrushTypeTexture == lBrushType) + { + std::wstring wsTexturePath = m_oBrush.GetTexturePath(); + CImageFileFormatChecker oImageFormat(wsTexturePath); + + CImageDict* pImage = NULL; + int nImageW = 0; + int nImageH = 0; + if (_CXIMAGE_FORMAT_JPG == oImageFormat.eFileType || _CXIMAGE_FORMAT_JP2 == oImageFormat.eFileType) + { + pImage = m_pDocument->CreateImage(); + CBgraFrame oFrame; + oFrame.OpenFile(wsTexturePath); + nImageH = oFrame.get_Height(); + nImageW = oFrame.get_Width(); + + if (pImage) + { + if (_CXIMAGE_FORMAT_JPG == oImageFormat.eFileType) + pImage->LoadJpeg(wsTexturePath.c_str(), nImageW, nImageH, oFrame.IsGrayScale()); + else + pImage->LoadJpx(wsTexturePath.c_str(), nImageW, nImageH); + } + } + else if (_CXIMAGE_FORMAT_WMF == oImageFormat.eFileType || + _CXIMAGE_FORMAT_EMF == oImageFormat.eFileType || + _CXIMAGE_FORMAT_SVM == oImageFormat.eFileType || + _CXIMAGE_FORMAT_SVG == oImageFormat.eFileType) + { + // TODO: Реализовать отрисовку метафайлов по-нормальному + MetaFile::IMetaFile* pMeta = MetaFile::Create(m_pAppFonts); + pMeta->LoadFromFile(wsTexturePath.c_str()); + + double dL, dR, dT, dB; + m_oPath.GetBounds(dL, dT, dR, dB); + + double dNewW = std::max(10.0, dR - dL) / 72 * 300; + + std::wstring wsTempFile = GetTempFile(); + pMeta->ConvertToRaster(wsTempFile.c_str(), _CXIMAGE_FORMAT_PNG, dNewW); + + RELEASEOBJECT(pMeta); + + Aggplus::CImage oImage(wsTempFile); + nImageW = abs((int)oImage.GetWidth()); + nImageH = abs((int)oImage.GetHeight()); + pImage = LoadImage(&oImage, 255); + } + else + { + Aggplus::CImage oImage(wsTexturePath); + nImageW = abs((int)oImage.GetWidth()); + nImageH = abs((int)oImage.GetHeight()); + pImage = LoadImage(&oImage, 255); + } + + if (pImage) + { + BYTE nAlpha = m_oBrush.GetTextureAlpha(); + if (0xFF != nAlpha) + pImage->AddTransparency(nAlpha); + + LONG lTextureMode = m_oBrush.GetTextureMode(); + + double dW = 10; + double dH = 10; + + double dL, dR, dT, dB; + CBrushState::TBrushRect& oRect = m_oBrush.GetBrushRect(); + if (!oRect.bUse) + { + m_oPath.GetBounds(dL, dT, dR, dB); + } + else + { + dL = MM_2_PT(oRect.dLeft); + dB = MM_2_PT(m_dPageHeight - oRect.dTop); + dR = MM_2_PT(oRect.dLeft + oRect.dWidth); + dT = MM_2_PT(m_dPageHeight - oRect.dTop - oRect.dHeight); + } + + double dXStepSpacing = 0, dYStepSpacing = 0; + if (c_BrushTextureModeStretch == lTextureMode) + { + // Растягиваем картинку по размерам пата + dW = std::max(10.0, dR - dL); + dH = std::max(10.0, dB - dT); + + // Чтобы избавиться от погрешностей из-за которых могут возникать полоски или обрезание картинки, + // удвоим расстрояние между соседними тайлами. Плохого тут нет, т.к. нам нужен всего 1 тайл + dXStepSpacing = dW; + dYStepSpacing = dH; + } + else + { + // Размеры картинки заданы в пикселях. Размеры тайла - это размеры картинки в пунктах. + dW = nImageW * 72 / 96; + dH = nImageH * 72 / 96; + } + + // Нам нужно, чтобы левый нижний угол границ нашего пата являлся точкой переноса для матрицы преобразования. + CMatrix* pMatrix = m_pPage->GetTransform(); + pMatrix->Apply(dL, dT); + CMatrix oPatternMatrix = *pMatrix; + oPatternMatrix.x = dL; + oPatternMatrix.y = dT; + m_pPage->SetPatternColorSpace(m_pDocument->CreateImageTilePattern(dW, dH, pImage, &oPatternMatrix, imagetilepatterntype_Default, dXStepSpacing, dYStepSpacing)); + } + } + else if (c_BrushTypeHatch1 == lBrushType) + { + std::wstring wsHatchType = m_oBrush.GetTexturePath(); + + double dW = 8 * 72 / 96; + double dH = 8 * 72 / 96; + + TColor oColor1 = m_oBrush.GetTColor1(); + TColor oColor2 = m_oBrush.GetTColor2(); + BYTE nAlpha1 = (BYTE)m_oBrush.GetAlpha1(); + BYTE nAlpha2 = (BYTE)m_oBrush.GetAlpha2(); + + m_pPage->SetPatternColorSpace(m_pDocument->CreateHatchPattern(dW, dH, oColor1.r, oColor1.g, oColor1.b, nAlpha1, oColor2.r, oColor2.g, oColor2.b, nAlpha2, wsHatchType)); + } + else if (c_BrushTypeRadialGradient == lBrushType || c_BrushTypeLinearGradient == lBrushType) + { + TColor* pGradientColors; + double* pPoints; + LONG lCount; + + m_oBrush.GetGradientColors(pGradientColors, pPoints, lCount); + + if (lCount > 0) + { + unsigned char* pColors = new unsigned char[3 * lCount]; + unsigned char* pAlphas = new unsigned char[lCount]; + if (pColors) + { + for (LONG lIndex = 0; lIndex < lCount; lIndex++) + { + pColors[3 * lIndex + 0] = pGradientColors[lIndex].r; + pColors[3 * lIndex + 1] = pGradientColors[lIndex].g; + pColors[3 * lIndex + 2] = pGradientColors[lIndex].b; + pAlphas[lIndex] = pGradientColors[lIndex].a; + } + + if (c_BrushTypeLinearGradient == lBrushType) + { + double dX0, dY0, dX1, dY1; + m_oBrush.GetLinearGradientPattern(dX0, dY0, dX1, dY1); + m_pShading = m_pDocument->CreateAxialShading(m_pPage, MM_2_PT(dX0), MM_2_PT(m_dPageHeight - dY0), MM_2_PT(dX1), MM_2_PT(m_dPageHeight - dY1), pColors, pAlphas, pPoints, lCount, m_pShadingExtGrState); + } + else //if (c_BrushTypeRadialGradient == lBrushType) + { + double dX0, dY0, dR0, dX1, dY1, dR1; + m_oBrush.GetRadialGradientPattern(dX0, dY0, dR0, dX1, dY1, dR1); + m_pShading = m_pDocument->CreateRadialShading(m_pPage, MM_2_PT(dX0), MM_2_PT(m_dPageHeight - dY0), MM_2_PT(dR0), MM_2_PT(dX1), MM_2_PT(m_dPageHeight - dY1), MM_2_PT(dR1), pColors, pAlphas, pPoints, lCount, m_pShadingExtGrState); + } + delete[] pColors; + delete[] pAlphas; + } + } + } + else// if (c_BrushTypeSolid == lBrushType) + { + TColor oColor1 = m_oBrush.GetTColor1(); + m_pPage->SetFillColor(oColor1.r, oColor1.g, oColor1.b); + m_pPage->SetFillAlpha((unsigned char)m_oBrush.GetAlpha1()); + } +} +void CPdfWriter::Reset() +{ + m_oPen.Reset(); + m_oBrush.Reset(); + m_oFont.Reset(); + m_oPath.Clear(); + + // clear font!!! + m_oFont.SetName(L""); + m_oFont.SetSize(-1); + m_oFont.SetStyle(1 << 5); + + m_lClipDepth = 0; +} + +static inline void UpdateMaxMinPoints(double& dMinX, double& dMinY, double& dMaxX, double& dMaxY, const double& dX, const double& dY) +{ + if (dX < dMinX) + dMinX = dX; + + if (dX > dMaxX) + dMaxX = dX; + + if (dY < dMinY) + dMinY = dY; + + if (dY > dMaxY) + dMaxY = dY; +} +void CPdfWriter::CPath::Draw(PdfWriter::CPage* pPage, bool bStroke, bool bFill, bool bEoFill) +{ + for (int nIndex = 0, nCount = m_vCommands.size(); nIndex < nCount; nIndex++) + { + CPathCommandBase* pCommand = m_vCommands.at(nIndex); + pCommand->Draw(pPage); + } + + if (bStroke && !bFill && !bEoFill) + pPage->Stroke(); + else if (bStroke && bFill) + pPage->FillStroke(); + else if (bStroke && bEoFill) + pPage->EoFillStroke(); + else if (bFill) + pPage->Fill(); + else if (bEoFill) + pPage->EoFill(); + else + pPage->EndPath(); +} +void CPdfWriter::CPath::Clip(PdfWriter::CPage* pPage, bool bEvenOdd) +{ + for (int nIndex = 0, nCount = m_vCommands.size(); nIndex < nCount; nIndex++) + { + CPathCommandBase* pCommand = m_vCommands.at(nIndex); + pCommand->Draw(pPage); + } + + if (bEvenOdd) + pPage->Eoclip(); + else + pPage->Clip(); + + pPage->EndPath(); +} +void CPdfWriter::CPath::GetLastPoint(double& dX, double& dY) +{ + dX = 0; + dY = 0; + + bool bFindMoveTo = false; + for (int nIndex = m_vCommands.size() - 1; nIndex >= 0; nIndex--) + { + CPathCommandBase* pCommand = m_vCommands.at(nIndex); + if (rendererpathcommand_Close == pCommand->GetType()) + { + bFindMoveTo = true; + continue; + } + else + { + pCommand->GetLastPoint(dX, dY); + if (!bFindMoveTo || rendererpathcommand_MoveTo == pCommand->GetType()) + break; + } + } +} +void CPdfWriter::CPath::GetBounds(double& dL, double& dT, double& dR, double& dB) +{ + GetLastPoint(dL, dT); + dR = dL; + dB = dT; + + for (int nIndex = 0, nCount = m_vCommands.size(); nIndex < nCount; nIndex++) + { + CPathCommandBase* pCommand = m_vCommands.at(nIndex); + pCommand->UpdateBounds(dL, dT, dR, dB); + } +} +void CPdfWriter::CPath::CPathMoveTo::Draw(PdfWriter::CPage* pPage) +{ + pPage->MoveTo(x, y); +} +void CPdfWriter::CPath::CPathMoveTo::UpdateBounds(double& dL, double& dT, double& dR, double& dB) +{ + UpdateMaxMinPoints(dL, dT, dR, dB, x, y); +} +void CPdfWriter::CPath::CPathLineTo::Draw(PdfWriter::CPage* pPage) +{ + pPage->LineTo(x, y); +} +void CPdfWriter::CPath::CPathLineTo::UpdateBounds(double& dL, double& dT, double& dR, double& dB) +{ + UpdateMaxMinPoints(dL, dT, dR, dB, x, y); +} +void CPdfWriter::CPath::CPathCurveTo::Draw(PdfWriter::CPage* pPage) +{ + pPage->CurveTo(x1, y1, x2, y2, xe, ye); +} +void CPdfWriter::CPath::CPathCurveTo::UpdateBounds(double& dL, double& dT, double& dR, double& dB) +{ + UpdateMaxMinPoints(dL, dT, dR, dB, x1, y1); + UpdateMaxMinPoints(dL, dT, dR, dB, x2, y2); + UpdateMaxMinPoints(dL, dT, dR, dB, xe, ye); +} +void CPdfWriter::CPath::CPathArcTo::Draw(PdfWriter::CPage* pPage) +{ + if (sweepAngle >= 360 - 0.001) + pPage->Ellipse(x + w / 2, y + h / 2, w / 2, h / 2); + else + pPage->EllipseArcTo(x + w / 2, y + h / 2, w / 2, h / 2, 360 - startAngle, 360 - (startAngle + sweepAngle), sweepAngle > 0 ? true : false); +} +void CPdfWriter::CPath::CPathArcTo::UpdateBounds(double& dL, double& dT, double& dR, double& dB) +{ + UpdateMaxMinPoints(dL, dT, dR, dB, x, y); + UpdateMaxMinPoints(dL, dT, dR, dB, x + w, y + h); +} +void CPdfWriter::CPath::CPathClose::Draw(PdfWriter::CPage* pPage) +{ + pPage->ClosePath(); +} +void CPdfWriter::CPath::CPathClose::UpdateBounds(double& dL, double& dT, double& dR, double& dB) +{ +} +void CPdfWriter::CPath::CPathText::Draw(PdfWriter::CPage* pPage) +{ + // TODO: Если данная команда будет часто вызываться, тогда ее нужно будет оптимизировать, точно также как это делается в обычном тексте + pPage->BeginText(); + pPage->SetFontAndSize(font, fontSize); + pPage->SetCharSpace(charSpace); + pPage->SetTextRenderingMode(textrenderingmode_Stroke); + pPage->DrawText(x, y, codes, codesCount); + pPage->EndText(); +} +void CPdfWriter::CPath::CPathText::UpdateBounds(double& dL, double& dT, double& dR, double& dB) +{ + UpdateMaxMinPoints(dL, dT, dR, dB, x, y); +} +void CPdfWriter::CBrushState::Reset() +{ + m_lType = c_BrushTypeSolid; + m_oColor1.Set(0); + m_oColor2.Set(0); + m_nAlpha1 = 255; + m_nAlpha2 = 255; + m_wsTexturePath = L""; + m_lTextureMode = c_BrushTextureModeStretch; + m_nTextureAlpha = 255; + m_dLinearAngle = 0; + m_oRect.Reset(); + + if (m_pShadingColors) + delete[] m_pShadingColors; + + if (m_pShadingPoints) + delete[] m_pShadingPoints; + + m_pShadingColors = NULL; + m_pShadingPoints = NULL; + m_lShadingPointsCount = 0; +} +void CPdfWriter::AddLink(PdfWriter::CPage* pPage, const double& dX, const double& dY, const double& dW, const double& dH, const double& dDestX, const double& dDestY, const unsigned int& unDestPage) +{ + CPage* pCurPage = pPage; + CPage* pDestPage = m_pDocument->GetPage(unDestPage); + if (!pCurPage || !pDestPage) + return; + + CDestination* pDestination = m_pDocument->CreateDestination(unDestPage); + if (!pDestination) + return; + + pDestination->SetXYZ(MM_2_PT(dDestX), pDestPage->GetHeight() - MM_2_PT(dDestY), 0); + CAnnotation* pAnnot = m_pDocument->CreateLinkAnnot(pCurPage, TRect(MM_2_PT(dX), pCurPage->GetHeight() - MM_2_PT(dY), MM_2_PT(dX + dW), m_pPage->GetHeight() - MM_2_PT(dY + dH)), pDestination); + pAnnot->SetBorderStyle(EBorderSubtype::border_subtype_Solid, 0); +} +bool CPdfWriter::IsValid() +{ + return m_bValid; +} +bool CPdfWriter::IsPageValid() +{ + if (!IsValid() || !m_pPage) + return false; + + return true; +} +void CPdfWriter::SetError() +{ + m_bValid = false; +} +unsigned char* CPdfWriter::EncodeString(const unsigned int *pUnicodes, const unsigned int& unCount, const unsigned int *pGIDs) +{ + if (m_bNeedUpdateTextFont) + UpdateFont(); + + if (!m_pFont) + return NULL; + + unsigned char* pCodes = new unsigned char[unCount * 2]; + if (!pCodes) + return NULL; + + for (unsigned int unIndex = 0; unIndex < unCount; unIndex++) + { + unsigned short ushCode; + if (pGIDs) + ushCode = m_pFont->EncodeGID(pGIDs[unIndex], &pUnicodes[unIndex], 1); + else + ushCode = m_pFont->EncodeUnicode(pUnicodes[unIndex]); + + pCodes[2 * unIndex + 0] = (ushCode >> 8) & 0xFF; + pCodes[2 * unIndex + 1] = ushCode & 0xFF; + } + + return pCodes; +} +unsigned char* CPdfWriter::EncodeGID(const unsigned int& unGID, const unsigned int* pUnicodes, const unsigned int& unUnicodesCount) +{ + if (m_bNeedUpdateTextFont) + UpdateFont(); + + if (!m_pFont) + return NULL; + + unsigned char* pCodes = new unsigned char[2]; + if (!pCodes) + return NULL; + + unsigned short ushCode = m_pFont->EncodeGID(unGID, pUnicodes, unUnicodesCount); + pCodes[0] = (ushCode >> 8) & 0xFF; + pCodes[1] = ushCode & 0xFF; + return pCodes; +} +std::wstring CPdfWriter::GetDownloadFile(const std::wstring& sUrl) +{ + std::wstring::size_type n1 = sUrl.find(L"www."); + std::wstring::size_type n2 = sUrl.find(L"http://"); + std::wstring::size_type n3 = sUrl.find(L"ftp://"); + std::wstring::size_type n4 = sUrl.find(L"https://"); + std::wstring::size_type nMax = 3; + + bool bIsNeedDownload = false; + if (n1 != std::wstring::npos && n1 < nMax) + bIsNeedDownload = true; + else if (n2 != std::wstring::npos && n2 < nMax) + bIsNeedDownload = true; + else if (n3 != std::wstring::npos && n3 < nMax) + bIsNeedDownload = true; + else if (n4 != std::wstring::npos && n4 < nMax) + bIsNeedDownload = true; + + if (!bIsNeedDownload) + return L""; + + std::wstring sTempFile = GetTempFile(); + NSNetwork::NSFileTransport::CFileDownloader oDownloader(sUrl, false); + oDownloader.SetFilePath(sTempFile); + + if (oDownloader.DownloadSync()) + return sTempFile; + + if (NSFile::CFileBinary::Exists(sTempFile)) + NSFile::CFileBinary::Remove(sTempFile); + + return L""; +} diff --git a/PdfFile/Src/PdfWriter.h b/PdfFile/Src/PdfWriter.h new file mode 100644 index 0000000000..6c3a85c617 --- /dev/null +++ b/PdfFile/Src/PdfWriter.h @@ -0,0 +1,1864 @@ +/* + * (c) Copyright Ascensio System SIA 2010-2019 + * + * 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-12 Ernesta Birznieka-Upisha + * 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 + * + */ +#ifndef _PDF_WRITER_H +#define _PDF_WRITER_H + +#include "../../DesktopEditor/graphics/IRenderer.h" +#include "../../DesktopEditor/graphics/pro/Fonts.h" +#include "../../DesktopEditor/graphics/pro/Image.h" +#include "../../DesktopEditor/xmlsec/src/include/Certificate.h" + +#include +#include +#include +#include + +namespace PdfWriter +{ + class CDocument; + class CPage; + class CFontCidTrueType; + class CFontTrueType; + class CImageDict; + class CShading; + class CExtGrState; + class CFontDict; +} + +namespace Aggplus +{ + class CImage; +} + +class CRendererCommandBase; +class CRendererTextCommand; +class CConvertFromBinParams; + +class CPdfWriter +{ +public: + CPdfWriter(NSFonts::IApplicationFonts* pAppFonts, bool isPDFA = false); + ~CPdfWriter(); + int SaveToFile(const std::wstring& wsPath); + void SetPassword(const std::wstring& wsPassword); + void SetDocumentID(const std::wstring& wsDocumentID); + void SetTempFolder(const std::wstring& wsPath); + std::wstring GetTempDirectory(); + std::wstring GetTempFile(); + //---------------------------------------------------------------------------------------- + // Тип рендерера + //---------------------------------------------------------------------------------------- + virtual HRESULT get_Type(LONG* lType); + //---------------------------------------------------------------------------------------- + // Функции для работы со страницей + //---------------------------------------------------------------------------------------- + virtual HRESULT NewPage(); + virtual HRESULT get_Height(double* dHeight); + virtual HRESULT put_Height(const double& dHeight); + virtual HRESULT get_Width(double* dWidth); + virtual HRESULT put_Width(const double& dWidth); + virtual HRESULT get_DpiX(double* dDpiX); + virtual HRESULT get_DpiY(double* dDpiY); + //---------------------------------------------------------------------------------------- + // Функции для работы с Pen + //---------------------------------------------------------------------------------------- + virtual HRESULT get_PenColor(LONG* lColor); + virtual HRESULT put_PenColor(const LONG& lColor); + virtual HRESULT get_PenAlpha(LONG* lAlpha); + virtual HRESULT put_PenAlpha(const LONG& lAlpha); + virtual HRESULT get_PenSize(double* dSize); + virtual HRESULT put_PenSize(const double& dSize); + virtual HRESULT get_PenDashStyle(BYTE* nDashStyle); + virtual HRESULT put_PenDashStyle(const BYTE& nDashStyle); + virtual HRESULT get_PenLineStartCap(BYTE* nCapStyle); + virtual HRESULT put_PenLineStartCap(const BYTE& nCapStyle); + virtual HRESULT get_PenLineEndCap(BYTE* nCapStyle); + virtual HRESULT put_PenLineEndCap(const BYTE& nCapStyle); + virtual HRESULT get_PenLineJoin(BYTE* nJoinStyle); + virtual HRESULT put_PenLineJoin(const BYTE& nJoinStyle); + virtual HRESULT get_PenDashOffset(double* dOffset); + virtual HRESULT put_PenDashOffset(const double& dOffset); + virtual HRESULT get_PenAlign(LONG* lAlign); + virtual HRESULT put_PenAlign(const LONG& lAlign); + virtual HRESULT get_PenMiterLimit(double* dMiter); + virtual HRESULT put_PenMiterLimit(const double& dMiter); + virtual HRESULT PenDashPattern(double* pPattern, LONG lCount); + //---------------------------------------------------------------------------------------- + // Функции для работы с Brush + //---------------------------------------------------------------------------------------- + virtual HRESULT get_BrushType(LONG* lType); + virtual HRESULT put_BrushType(const LONG& lType); + virtual HRESULT get_BrushColor1(LONG* lColor); + virtual HRESULT put_BrushColor1(const LONG& lColor); + virtual HRESULT get_BrushAlpha1(LONG* lAlpha); + virtual HRESULT put_BrushAlpha1(const LONG& lAlpha); + virtual HRESULT get_BrushColor2(LONG* lColor); + virtual HRESULT put_BrushColor2(const LONG& lColor); + virtual HRESULT get_BrushAlpha2(LONG* lAlpha); + virtual HRESULT put_BrushAlpha2(const LONG& lAlpha); + virtual HRESULT get_BrushTexturePath(std::wstring* wsPath); + virtual HRESULT put_BrushTexturePath(const std::wstring& wsPath); + virtual HRESULT get_BrushTextureMode(LONG* lMode); + virtual HRESULT put_BrushTextureMode(const LONG& lMode); + virtual HRESULT get_BrushTextureAlpha(LONG* lAlpha); + virtual HRESULT put_BrushTextureAlpha(const LONG& lAlpha); + virtual HRESULT get_BrushLinearAngle(double* dAngle); + virtual HRESULT put_BrushLinearAngle(const double& dAngle); + virtual HRESULT BrushRect(const INT& nVal, const double& dLeft, const double& dTop, const double& dWidth, const double& dHeight); + virtual HRESULT BrushBounds(const double& dLeft, const double& dTop, const double& dWidth, const double& dHeight); + virtual HRESULT put_BrushGradientColors(LONG* pColors, double* pPositions, LONG lCount); + //---------------------------------------------------------------------------------------- + // Функции для работы со шрифтами + //---------------------------------------------------------------------------------------- + virtual HRESULT get_FontName(std::wstring* wsName); + virtual HRESULT put_FontName(const std::wstring& wsName); + virtual HRESULT get_FontPath(std::wstring* wsPath); + virtual HRESULT put_FontPath(const std::wstring& wsPath); + virtual HRESULT get_FontSize(double* dSize); + virtual HRESULT put_FontSize(const double& dSize); + virtual HRESULT get_FontStyle(LONG* lStyle); + virtual HRESULT put_FontStyle(const LONG& lStyle); + virtual HRESULT get_FontStringGID(INT* bGid); + virtual HRESULT put_FontStringGID(const INT& bGid); + virtual HRESULT get_FontCharSpace(double* dSpace); + virtual HRESULT put_FontCharSpace(const double& dSpace); + virtual HRESULT get_FontFaceIndex(int* lFaceIndex); + virtual HRESULT put_FontFaceIndex(const int& lFaceIndex); + //---------------------------------------------------------------------------------------- + // Функции для вывода текста + //---------------------------------------------------------------------------------------- + virtual HRESULT CommandDrawTextCHAR (const LONG& lUnicode, const double& dX, const double& dY, const double& dW, const double& dH); + virtual HRESULT CommandDrawTextExCHAR(const LONG& lUnicode, const LONG& lGid, const double& dX, const double& dY, const double& dW, const double& dH); + virtual HRESULT CommandDrawText (const std::wstring& wsUnicodeText, const double& dX, const double& dY, const double& dW, const double& dH); + virtual HRESULT CommandDrawTextEx (const std::wstring& wsUnicodeText, const unsigned int* pGids, const unsigned int nGidsCount, const double& dX, const double& dY, const double& dW, const double& dH); + virtual HRESULT CommandDrawTextCHAR2 (unsigned int* unUnicode, const unsigned int& unUnicodeCount, const unsigned int& unGid, const double& dX, const double& dY, const double& dW, const double& dH); + //---------------------------------------------------------------------------------------- + // Маркеры команд + //---------------------------------------------------------------------------------------- + virtual HRESULT BeginCommand(const DWORD& lType); + virtual HRESULT EndCommand(const DWORD& lType); + //---------------------------------------------------------------------------------------- + // Функции для работы с патом + //---------------------------------------------------------------------------------------- + virtual HRESULT PathCommandMoveTo(const double& dX, const double& dY); + virtual HRESULT PathCommandLineTo(const double& dX, const double& dY); + virtual HRESULT PathCommandLinesTo(double* pPoints, const int& nCount); + virtual HRESULT PathCommandCurveTo(const double& dX1, const double& dY1, const double& dX2, const double& dY2, const double& dXe, const double& dYe); + virtual HRESULT PathCommandCurvesTo(double* pPoints, const int& nCount); + virtual HRESULT PathCommandArcTo(const double& dX, const double& dY, const double& dW, const double& dH, const double& dStartAngle, const double& dSweepAngle); + virtual HRESULT PathCommandClose(); + virtual HRESULT PathCommandEnd(); + virtual HRESULT DrawPath(const LONG& lType); + virtual HRESULT PathCommandStart(); + virtual HRESULT PathCommandGetCurrentPoint(double* dX, double* dY); + virtual HRESULT PathCommandTextCHAR (const LONG& lUnicode, const double& dX, const double& dY, const double& dW, const double& dH); + virtual HRESULT PathCommandTextExCHAR(const LONG& lUnicode, const LONG& lGid, const double& dX, const double& dY, const double& dW, const double& dH); + virtual HRESULT PathCommandText (const std::wstring& wsUnicodeText, const double& dX, const double& dY, const double& dW, const double& dH); + virtual HRESULT PathCommandTextEx (const std::wstring& wsUnicodeText, const unsigned int* pGids, const unsigned int nGidsCount, const double& dX, const double& dY, const double& dW, const double& dH); + //---------------------------------------------------------------------------------------- + // Функции для вывода изображений + //---------------------------------------------------------------------------------------- + virtual HRESULT DrawImage(IGrObject* pImage, const double& dX, const double& dY, const double& dW, const double& dH); + virtual HRESULT DrawImageFromFile(const std::wstring& wsImagePath, const double& dX, const double& dY, const double& dW, const double& dH, const BYTE& nAlpha = 255); + //---------------------------------------------------------------------------------------- + // Функции для выставления преобразования + //---------------------------------------------------------------------------------------- + virtual HRESULT SetTransform(const double& dM11, const double& dM12, const double& dM21, const double& dM22, const double& dX, const double& dY); + virtual HRESULT GetTransform(double* dM11, double* dM12, double* dM21, double* dM22, double* dX, double* dY); + virtual HRESULT ResetTransform(); + //---------------------------------------------------------------------------------------- + // Тип клипа + //---------------------------------------------------------------------------------------- + virtual HRESULT get_ClipMode(LONG* lMode); + virtual HRESULT put_ClipMode(const LONG& lMode); + //---------------------------------------------------------------------------------------- + // Дополнительные функции + //---------------------------------------------------------------------------------------- + virtual HRESULT CommandLong(const LONG& lType, const LONG& lCommand); + virtual HRESULT CommandDouble(const LONG& lType, const double& dCommand); + virtual HRESULT CommandString(const LONG& lType, const std::wstring& sCommand); + virtual HRESULT AddHyperlink(const double& dX, const double& dY, const double& dW, const double& dH, const std::wstring& wsUrl, const std::wstring& wsTooltip); + virtual HRESULT AddLink(const double& dX, const double& dY, const double& dW, const double& dH, const double& dDestX, const double& dDestY, const int& nPage); + virtual HRESULT AddFormField(const CFormFieldInfo& oInfo); + //---------------------------------------------------------------------------------------- + // Дополнительные функции Pdf рендерера + //---------------------------------------------------------------------------------------- + HRESULT CommandDrawTextPdf(const std::wstring& bsUnicodeText, const unsigned int* pGids, const unsigned int nGidsCount, const std::wstring& wsSrcCodeText, const double& dX, const double& dY, const double& dW, const double& dH); + HRESULT PathCommandTextPdf(const std::wstring& bsUnicodeText, const unsigned int* pGids, const unsigned int nGidsCount, const std::wstring& bsSrcCodeText, const double& dX, const double& dY, const double& dW, const double& dH); + HRESULT DrawImage1bpp(NSImages::CPixJbig2* pImageBuffer, const unsigned int& unWidth, const unsigned int& unHeight, const double& dX, const double& dY, const double& dW, const double& dH); + HRESULT EnableBrushRect(const LONG& lEnable); + HRESULT SetLinearGradient(const double& dX1, const double& dY1, const double& dX2, const double& dY2); + HRESULT SetRadialGradient(const double& dX1, const double& dY1, const double& dR1, const double& dX2, const double& dY2, const double& dR2); + HRESULT DrawImageWith1bppMask(IGrObject* pImage, NSImages::CPixJbig2* pMaskBuffer, const unsigned int& unMaskWidth, const unsigned int& unMaskHeight, const double& dX, const double& dY, const double& dW, const double& dH); + + //---------------------------------------------------------------------------------------- + // Дополнительные функции для дозаписи Pdf + //---------------------------------------------------------------------------------------- + std::pair GetPageRef(int nPageIndex); + bool EditPage(PdfWriter::CPage* pNewPage); + bool AddPage(int nPageIndex); + bool DeletePage(int nPageIndex); + bool EditClose(); + void PageRotate(int nRotate); + void Sign(const double& dX, const double& dY, const double& dW, const double& dH, const std::wstring& wsPicturePath, ICertificate* pCertificate); + std::wstring GetEditPdfPath(); + PdfWriter::CDocument* GetPDFDocument() { return m_pDocument; } + + NSFonts::IApplicationFonts* GetApplicationFonts(); + +private: + PdfWriter::CImageDict* LoadImage(Aggplus::CImage* pImage, const BYTE& nAlpha); + bool DrawImage(Aggplus::CImage* pImage, const double& dX, const double& dY, const double& dW, const double& dH, const BYTE& nAlpha); + bool DrawText(unsigned char* pCodes, const unsigned int& unLen, const double& dX, const double& dY); + bool PathCommandDrawText(unsigned int* pUnicodes, unsigned int unLen, const double& dX, const double& dY, const unsigned int* pGids = NULL); + void UpdateFont(); + void GetFontPath(const std::wstring& wsFontName, const bool& bBold, const bool& bItalic, std::wstring& wsFontPath, LONG& lFaceIndex); + PdfWriter::CFontCidTrueType* GetFont(const std::wstring& wsFontPath, const LONG& lFontIndex); + PdfWriter::CFontCidTrueType* GetFont(const std::wstring& wsFontName, const bool& bBold, const bool& bItalic); + void UpdateTransform(); + void UpdatePen(); + void UpdateBrush(); + void Reset(); + bool IsValid(); + bool IsPageValid(); + void SetError(); + void AddLink(PdfWriter::CPage* pPage, const double& dX, const double& dY, const double& dW, const double& dH, const double& dDestX, const double& dDestY, const unsigned int& unDestPage); + unsigned char* EncodeString(const unsigned int* pUnicodes, const unsigned int& unUnicodesCount, const unsigned int* pGIDs = NULL); + unsigned char* EncodeGID(const unsigned int& unGID, const unsigned int* pUnicodes, const unsigned int& unUnicodesCount); + std::wstring GetDownloadFile(const std::wstring& sUrl); + +private: + + struct TFontInfo + { + TFontInfo(const std::wstring& fontName, const bool& bold, const bool& italic, const std::wstring& fontPath, const LONG& faceIndex) + { + wsFontName = fontName; + bBold = bold; + bItalic = italic; + wsFontPath = fontPath; + lFaceIndex = faceIndex; + } + + std::wstring wsFontName; + bool bBold; + bool bItalic; + std::wstring wsFontPath; + LONG lFaceIndex; + }; + struct TColor + { + TColor() + { + lColor = 0; + r = 0; + g = 0; + b = 0; + a = 255; + } + TColor(const LONG& _lColor) + { + Set(_lColor); + } + + void Set(const LONG& _lColor) + { + lColor = _lColor; + + r = (unsigned char)(lColor & 0xFF); + g = (unsigned char)((lColor >> 8) & 0xFF); + b = (unsigned char)((lColor >> 16) & 0xFF); + a = (unsigned char)((lColor >> 24) & 0xFF); + } + void operator=(const LONG& _lColor) + { + Set(_lColor); + } + void Set(BYTE _r, BYTE _g, BYTE _b, BYTE _a = 255) + { + r = _r; + g = _g; + b = _b; + a = _a; + + lColor = (LONG)(((LONG)r) | ((LONG)g << 8) | ((LONG)b << 16) | ((LONG)a << 24)); + } + + LONG lColor; + BYTE r; + BYTE g; + BYTE b; + BYTE a; + }; + class CPenState + { + public: + + CPenState() + { + m_pDashPattern = NULL; + Reset(); + } + ~CPenState() + { + if (m_pDashPattern) + delete[] m_pDashPattern; + } + inline LONG GetColor() + { + return m_oColor.lColor; + } + inline void SetColor(const LONG& lColor) + { + m_oColor.Set(lColor); + } + inline TColor GetTColor() + { + return m_oColor; + } + inline LONG GetAlpha() + { + return m_nAlpha; + } + inline void SetAlpha(const LONG& lAlpha) + { + m_nAlpha = (BYTE)(std::max)(0, (std::min)(255, (int)lAlpha)); + } + inline double GetSize() + { + return m_dSize; + } + inline void SetSize(const double& dSize) + { + m_dSize = dSize; + } + inline BYTE GetDashStyle() + { + return m_nDashStyle; + } + inline void SetDashStyle(const BYTE& nDashStyle) + { + m_nDashStyle = nDashStyle; + } + inline BYTE GetStartCapStyle() + { + return m_nStartCapStyle; + } + inline void SetStartCapStyle(const BYTE& nCapStyle) + { + m_nStartCapStyle = nCapStyle; + } + inline BYTE GetEndCapStyle() + { + return m_nEndCapStyle; + } + inline void SetEndCapStyle(const BYTE& nCapStyle) + { + m_nEndCapStyle = nCapStyle; + } + inline BYTE GetJoinStyle() + { + return m_nJoinStyle; + } + inline void SetJoinStyle(const BYTE& nJoinStyle) + { + m_nJoinStyle = nJoinStyle; + } + inline double GetDashOffset() + { + return m_dDashOffset; + } + inline void SetDashOffset(const double& dOffset) + { + m_dDashOffset = dOffset; + } + inline LONG GetAlign() + { + return m_lAlign; + } + inline void SetAlign(const LONG& lAlign) + { + m_lAlign = lAlign; + } + inline double GetMiter() + { + return m_dMiter; + } + inline void SetMiter(const double& dMiter) + { + m_dMiter = dMiter; + } + inline void SetDashPattern(const double* pPattern, const LONG& lSize) + { + if (m_pDashPattern) + { + delete[] m_pDashPattern; + m_pDashPattern = NULL; + } + + m_lDashPatternSize = 0; + + if (!pPattern || !lSize) + { + m_lDashPatternSize = 0; + m_pDashPattern = NULL; + } + else + { + // Избавляемся от нулей, потому что все pdf-ридеры плохо их воспринимают + std::vector vPattern; + for (LONG lIndex = 0; lIndex < lSize; lIndex++) + { + if (lIndex > 1 && fabs(pPattern[lIndex]) < 0.001) + { + if (0 == lIndex % 2) + { + if (fabs(pPattern[lIndex + 1]) < 0.001) + { + lIndex++; + } + else if (lIndex + 1 < lSize) + { + size_t nPatternSize = vPattern.size(); + vPattern.at(nPatternSize - 1) = vPattern.at(nPatternSize - 1) + pPattern[lIndex + 1]; + lIndex++; + } + } + else + { + size_t nPatternSize = vPattern.size(); + vPattern.at(nPatternSize - 2) = vPattern.at(nPatternSize - 2) + vPattern.at(nPatternSize - 1); + vPattern.pop_back(); + } + } + else + { + vPattern.push_back(pPattern[lIndex]); + } + } + + size_t nPatternSize = vPattern.size(); + if (nPatternSize > 0) + { + m_pDashPattern = new double[nPatternSize]; + if (m_pDashPattern) + { + for (int nIndex = 0; nIndex < nPatternSize; nIndex++) + { + m_pDashPattern[nIndex] = vPattern.at(nIndex); + } + m_lDashPatternSize = nPatternSize; + } + } + } + } + inline double*GetDashPattern(LONG& lSize) + { + lSize = m_lDashPatternSize; + return m_pDashPattern; + } + + void Reset() + { + if (m_pDashPattern) + delete[] m_pDashPattern; + + m_oColor.Set(0); + m_dSize = 0; + m_nAlpha = 255; + m_nStartCapStyle = Aggplus::LineCapRound; + m_nEndCapStyle = Aggplus::LineCapRound; + m_nJoinStyle = Aggplus::LineJoinRound; + + m_lAlign = 0; + m_dMiter = 0; + + m_nDashStyle = Aggplus::DashStyleSolid; + m_lDashPatternSize = 0; + m_pDashPattern = NULL; + + m_dDashOffset = 0; + } + + private: + + double m_dSize; + TColor m_oColor; + BYTE m_nAlpha; + BYTE m_nStartCapStyle; + BYTE m_nEndCapStyle; + BYTE m_nJoinStyle; + + LONG m_lAlign; + double m_dMiter; + + BYTE m_nDashStyle; + double m_dDashOffset; + double*m_pDashPattern; + LONG m_lDashPatternSize; + + }; + class CBrushState + { + public: + struct TColorAndPoint + { + TColorAndPoint() + { + lColor = 0; + dPoint = 0; + bUse = false; + } + TColorAndPoint(const LONG& color, const double& point) + { + lColor = color; + dPoint = point; + bUse = true; + } + + static bool Compare(const TColorAndPoint& oFirst, const TColorAndPoint& oSecond) + { + return (oFirst.dPoint < oSecond.dPoint); + } + static LONG GetLinearApprox(const TColorAndPoint& oPoint1, const TColorAndPoint& oPoint2, const double& dDstPoint) + { + double dPoint1 = oPoint1.dPoint; + double dPoint2 = oPoint2.dPoint; + LONG lColor1 = oPoint1.lColor; + LONG lColor2 = oPoint2.lColor; + + double dDiff = dPoint2 - dPoint1; + if (fabs(dDiff) < 0) + return lColor1; + + TColor oColor1 = lColor1; + TColor oColor2 = lColor2; + + BYTE r = (BYTE)(std::max)(0, (std::min)(255, (int)(oColor1.r + (oColor2.r - oColor1.r) / dDiff * (dDstPoint - dPoint1)))); + BYTE g = (BYTE)(std::max)(0, (std::min)(255, (int)(oColor1.g + (oColor2.g - oColor1.g) / dDiff * (dDstPoint - dPoint1)))); + BYTE b = (BYTE)(std::max)(0, (std::min)(255, (int)(oColor1.b + (oColor2.b - oColor1.b) / dDiff * (dDstPoint - dPoint1)))); + BYTE a = (BYTE)(std::max)(0, (std::min)(255, (int)(oColor1.a + (oColor2.a - oColor1.a) / dDiff * (dDstPoint - dPoint1)))); + + TColor oResColor; + oResColor.Set(r, g, b, a); + return oResColor.lColor; + } + + LONG lColor; + double dPoint; + bool bUse; + }; + struct TBrushRect + { + TBrushRect() + { + Reset(); + } + + void Reset() + { + bUse = false; + nVal = 0; + dLeft = 0; + dTop = 0; + dWidth = 0; + dHeight = 0; + } + + bool bUse; + int nVal; + double dLeft; + double dTop; + double dWidth; + double dHeight; + }; + + public: + CBrushState() + { + m_pShadingColors = NULL; + m_pShadingPoints = NULL; + m_lShadingPointsCount = 0; + Reset(); + } + ~CBrushState() + { + if (m_pShadingColors) + delete[] m_pShadingColors; + if (m_pShadingPoints) + delete[] m_pShadingPoints; + } + void Reset(); + inline LONG GetType() + { + return m_lType; + } + inline void SetType(const LONG& lType) + { + m_lType = lType; + } + inline LONG GetColor1() + { + return m_oColor1.lColor; + } + inline TColor GetTColor1() + { + return m_oColor1; + } + inline void SetColor1(const LONG& lColor) + { + m_oColor1.Set(lColor); + } + inline LONG GetColor2() + { + return m_oColor2.lColor; + } + inline TColor GetTColor2() + { + return m_oColor2; + } + inline void SetColor2(const LONG& lColor) + { + m_oColor2.Set(lColor); + } + inline LONG GetAlpha1() + { + return m_nAlpha1; + } + inline void SetAlpha1(const LONG& lAlpha) + { + m_nAlpha1 = (BYTE)(std::max)(0, (std::min)(255, (int)lAlpha)); + } + inline LONG GetAlpha2() + { + return m_nAlpha2; + } + inline void SetAlpha2(const LONG& lAlpha) + { + m_nAlpha2 = (BYTE)(std::max)(0, (std::min)(255, (int)lAlpha)); + } + inline std::wstring GetTexturePath() + { + return m_wsTexturePath; + } + inline void SetTexturePath(const std::wstring& wsPath) + { + m_wsTexturePath = wsPath; + } + inline LONG GetTextureMode() + { + return m_lTextureMode; + } + inline void SetTextureMode(const LONG& lMode) + { + m_lTextureMode = lMode; + } + inline BYTE GetTextureAlpha() + { + return m_nTextureAlpha; + } + inline void SetTextureAlpha(const LONG& lAlpha) + { + m_nTextureAlpha = (BYTE)(std::max)(0, (std::min)(255, (int)lAlpha)); + } + inline double GetLinearAngle() + { + return m_dLinearAngle; + } + inline void SetLinearAngle(const double& dAngle) + { + m_dLinearAngle = dAngle; + } + inline void SetGradientColors(LONG* pColors, double* pPoints, const LONG& lCount) + { + // Мы создаем упорядоченный по возрастанию массив, причем первая и последняя точки должны быть 0 и 1 соответственно. + if (m_pShadingColors) + { + delete[] m_pShadingColors; + m_pShadingColors = NULL; + } + + if (m_pShadingPoints) + { + delete[] m_pShadingPoints; + m_pShadingPoints = NULL; + } + + if (!pColors || !pPoints || !lCount) + return; + + // Проверим вырожденный случай, когда задана либо 1 точка, либо несколько точек с одинковым значением + bool bIrregular = false; + if (1 == lCount) + { + bIrregular = true; + } + else + { + bIrregular = true; + for (LONG lIndex = 0; lIndex < lCount; lIndex++) + { + double dPoint1 = pPoints[lIndex]; + for (LONG lIndex2 = lIndex + 1; lIndex2 < lCount; lIndex2++) + { + double dPoint2 = pPoints[lIndex2]; + if (fabs(dPoint2 - dPoint1) > 0.00001) + { + bIrregular = false; + break; + } + } + + if (!bIrregular) + break; + } + } + + if (bIrregular) + { + if (1 == lCount) + { + m_pShadingPoints = new double[2]; + m_pShadingColors = new TColor[2]; + + if (!m_pShadingColors || !m_pShadingColors) + return; + + m_pShadingPoints[0] = 0.0; + m_pShadingColors[0] = pColors[0]; + m_pShadingPoints[1] = 1.0; + m_pShadingColors[1] = pColors[0]; + m_lShadingPointsCount = 2; + } + else + { + if (pPoints[0] < 0) + { + m_pShadingPoints = new double[2]; + m_pShadingColors = new TColor[2]; + + if (!m_pShadingColors || !m_pShadingColors) + return; + + m_pShadingPoints[0] = 0.0; + m_pShadingColors[0] = pColors[lCount - 1]; + m_pShadingPoints[1] = 1.0; + m_pShadingColors[1] = pColors[lCount - 1]; + m_lShadingPointsCount = 2; + } + else if (pPoints[0] > 1) + { + m_pShadingPoints = new double[2]; + m_pShadingColors = new TColor[2]; + + if (!m_pShadingColors || !m_pShadingColors) + return; + + m_pShadingPoints[0] = 0.0; + m_pShadingColors[0] = pColors[0]; + m_pShadingPoints[1] = 1.0; + m_pShadingColors[1] = pColors[0]; + m_lShadingPointsCount = 2; + } + else + { + m_pShadingPoints = new double[4]; + m_pShadingColors = new TColor[4]; + + if (!m_pShadingColors || !m_pShadingColors) + return; + + m_pShadingPoints[0] = 0.0; + m_pShadingColors[0] = pColors[0]; + m_pShadingPoints[1] = pPoints[0]; + m_pShadingColors[1] = pColors[0]; + m_pShadingPoints[2] = pPoints[lCount - 1]; + m_pShadingColors[2] = pColors[lCount - 1]; + m_pShadingPoints[3] = 1.0; + m_pShadingColors[3] = pColors[lCount - 1]; + m_lShadingPointsCount = 4; + } + } + } + else + { + std::vector vPoints; + for (LONG lIndex = 0; lIndex < lCount; lIndex++) + { + vPoints.push_back(TColorAndPoint(pColors[lIndex], pPoints[lIndex])); + } + std::sort(vPoints.begin(), vPoints.end(), TColorAndPoint::Compare); + + LONG lMinIn = -1, lMaxIn = -1, lMinOut = -1, lMaxOut = -1; + for (LONG lIndex = 0; lIndex < lCount; lIndex++) + { + double dPoint = vPoints.at(lIndex).dPoint; + if (0 <= dPoint && dPoint <= 1) + { + if (-1 == lMinIn || dPoint < vPoints.at(lMinIn).dPoint) + lMinIn = lIndex; + + if (-1 == lMaxIn || dPoint > vPoints.at(lMaxIn).dPoint) + lMaxIn = lIndex; + } + else if (dPoint < 0) + { + if (-1 == lMinOut || dPoint > vPoints.at(lMinOut).dPoint) + lMinOut = lIndex; + } + else// if (dPoint > 1) + { + if (-1 == lMaxOut || dPoint < vPoints.at(lMaxOut).dPoint) + lMaxOut = lIndex; + } + } + + LONG lBeginIndex = lMinIn; + LONG lEndIndex = lMaxIn; + + bool bNeed0 = true, bNeed1 = true; + if (-1 != lMinIn && vPoints.at(lMinIn).dPoint < 0.001) + { + bNeed0 = false; + lBeginIndex = lMinIn; + vPoints.at(lMinIn).dPoint = 0; + } + else if (-1 != lMinOut && vPoints.at(lMinOut).dPoint > -0.001) + { + bNeed0 = false; + lBeginIndex = lMinOut; + vPoints.at(lMinOut).dPoint = 0; + } + + if (-1 != lMaxIn && vPoints.at(lMaxIn).dPoint > 0.999) + { + bNeed1 = false; + lEndIndex = lMaxIn; + vPoints.at(lEndIndex).dPoint = 1; + } + else if (-1 != lMaxOut && vPoints.at(lMaxOut).dPoint < 1.001) + { + bNeed1 = false; + lEndIndex = lMaxOut; + vPoints.at(lEndIndex).dPoint = 1; + } + + std::vector vResPoints; + if (bNeed0) + { + LONG lIndex0, lIndex1; + if (-1 != lMinOut) + { + if (-1 != lMinIn) + { + lIndex0 = lMinOut; + lIndex1 = lMinIn; + } + else if (-1 != lMaxOut) + { + lIndex0 = lMinOut; + lIndex1 = lMaxOut; + } + else + { + lIndex0 = lMinIn - 1; + lIndex1 = lMinIn; + } + } + else + { + if (-1 != lMinIn) + { + lIndex0 = lMinIn; + lIndex1 = lMinIn + 1; + } + else + { + lIndex0 = lMaxOut; + lIndex1 = lMaxOut + 1; + } + } + + LONG lColor0 = TColorAndPoint::GetLinearApprox(vPoints.at(lIndex0), vPoints.at(lIndex1), 0); + vResPoints.push_back(TColorAndPoint(lColor0, 0)); + } + + if (-1 != lBeginIndex && -1 != lEndIndex) + { + for (LONG lIndex = lBeginIndex; lIndex <= lEndIndex; lIndex++) + { + vResPoints.push_back(vPoints.at(lIndex)); + } + } + + if (bNeed1) + { + LONG lIndex0, lIndex1; + if (-1 != lMaxOut) + { + if (-1 != lMaxIn) + { + lIndex0 = lMaxIn; + lIndex1 = lMaxOut; + } + else if (-1 != lMinOut) + { + lIndex0 = lMinOut; + lIndex1 = lMaxOut; + } + else + { + lIndex0 = lMaxOut; + lIndex1 = lMaxOut + 1; + } + } + else + { + if (-1 != lMaxIn) + { + lIndex0 = lMaxIn - 1; + lIndex1 = lMaxIn; + } + else + { + lIndex0 = lMinOut - 1; + lIndex1 = lMinOut; + } + } + + LONG lColor1 = TColorAndPoint::GetLinearApprox(vPoints.at(lIndex0), vPoints.at(lIndex1), 1); + vResPoints.push_back(TColorAndPoint(lColor1, 1)); + } + + size_t lResCount = vResPoints.size(); + if (lResCount == 0) + return; + + m_pShadingColors = new TColor[lResCount]; + m_pShadingPoints = new double[lResCount]; + m_lShadingPointsCount = lResCount; + + if (!m_pShadingColors || !m_pShadingPoints) + return; + + for (LONG lIndex = 0; lIndex < lResCount; lIndex++) + { + m_pShadingColors[lIndex] = vResPoints.at(lIndex).lColor; + m_pShadingPoints[lIndex] = vResPoints.at(lIndex).dPoint; + } + } + } + inline void SetBrushRect(const int& nVal, const double& dLeft, const double& dTop, const double& dWidth, const double& dHeight) + { + m_oRect.nVal = nVal; + m_oRect.dLeft = dLeft; + m_oRect.dTop = dTop; + m_oRect.dWidth = dWidth; + m_oRect.dHeight = dHeight; + } + inline void EnableBrushRect(bool bEnable) + { + m_oRect.bUse = bEnable; + } + TBrushRect& GetBrushRect() + { + return m_oRect; + } + + inline void SetLinearGradientPattern(const double& dX0, const double& dY0, const double& dX1, const double& dY1) + { + m_pShadingPattern[0] = dX0; + m_pShadingPattern[1] = dY0; + m_pShadingPattern[2] = dX1; + m_pShadingPattern[3] = dY1; + } + inline void SetRadialGradientPattern(const double& dX0, const double& dY0, const double& dR0, const double& dX1, const double& dY1, const double& dR1) + { + m_pShadingPattern[0] = dX0; + m_pShadingPattern[1] = dY0; + m_pShadingPattern[2] = dR0; + m_pShadingPattern[3] = dX1; + m_pShadingPattern[4] = dY1; + m_pShadingPattern[5] = dR1; + } + inline void GetLinearGradientPattern(double& dX0, double& dY0, double& dX1, double& dY1) + { + dX0 = m_pShadingPattern[0]; + dY0 = m_pShadingPattern[1]; + dX1 = m_pShadingPattern[2]; + dY1 = m_pShadingPattern[3]; + } + inline void GetRadialGradientPattern(double& dX0, double& dY0, double& dR0, double& dX1, double& dY1, double& dR1) + { + dX0 = m_pShadingPattern[0]; + dY0 = m_pShadingPattern[1]; + dR0 = m_pShadingPattern[2]; + dX1 = m_pShadingPattern[3]; + dY1 = m_pShadingPattern[4]; + dR1 = m_pShadingPattern[5]; + } + inline void GetGradientColors(TColor*& pColors, double*& pPoints, LONG& lCount) + { + pColors = m_pShadingColors; + pPoints = m_pShadingPoints; + lCount = m_lShadingPointsCount; + } + + private: + + LONG m_lType; + TColor m_oColor1; + TColor m_oColor2; + BYTE m_nAlpha1; + BYTE m_nAlpha2; + std::wstring m_wsTexturePath; + LONG m_lTextureMode; + BYTE m_nTextureAlpha; + double m_dLinearAngle; + TBrushRect m_oRect; + + TColor* m_pShadingColors; + double* m_pShadingPoints; + LONG m_lShadingPointsCount; + double m_pShadingPattern[6]; // У линейного градиента x0, y0, x1, y1 (2 не используются), у радиального x0, y0, r0, x1, y1, r1 + }; + class CFontState + { + public: + + CFontState() : m_wsPath(L""), m_wsName(L"Arial"), m_lStyle(0), m_bBold(false), m_bItalic(false), m_dCharSpace(0), + m_lFaceIndex(0), m_dSize(10), m_bGid(false), m_bNeedDoBold(false), m_bNeedDoItalic(false) + { + } + + void Reset() + { + m_wsPath = L""; + m_wsName = L"Arial"; + m_lStyle = 0; + m_bBold = false; + m_bItalic = false; + m_dCharSpace = 0; + m_lFaceIndex = 0; + m_dSize = 10; + m_bGid = false; + + m_bNeedDoBold = false; + m_bNeedDoItalic = false; + } + + inline std::wstring GetName() + { + return m_wsName; + } + inline void SetName(const std::wstring& wsName) + { + m_wsName = wsName; + } + inline std::wstring GetPath() + { + return m_wsPath; + } + inline void SetPath(const std::wstring& wsPath) + { + m_wsPath = wsPath; + } + inline double GetSize() + { + return m_dSize; + } + inline void SetSize(const double& dSize) + { + m_dSize = dSize; + } + inline LONG GetFaceIndex() + { + return m_lFaceIndex; + } + inline void SetFaceIndex(const LONG& lFaceIndex) + { + m_lFaceIndex = lFaceIndex; + } + inline LONG GetStyle() + { + return m_lStyle; + } + inline void SetStyle(const LONG& lStyle) + { + m_lStyle = lStyle; + m_bBold = (lStyle & 1 ? true : false); + m_bItalic = (lStyle & 2 ? true : false); + } + inline bool GetGid() + { + return m_bGid; + } + inline void SetGid(const bool& bGid) + { + m_bGid = bGid; + } + inline double GetCharSpace() + { + return m_dCharSpace; + } + inline void SetCharSpace(const double& dCharSpace) + { + m_dCharSpace = dCharSpace; + } + inline bool IsBold() + { + return m_bBold; + } + inline bool IsItalic() + { + return m_bItalic; + } + inline void SetNeedDoItalic(const bool& bNeedDoItalic) + { + m_bNeedDoItalic = bNeedDoItalic; + } + inline void SetNeedDoBold(const bool& bNeedDoBold) + { + m_bNeedDoBold = bNeedDoBold; + } + inline bool IsNeedDoItalic() + { + return m_bNeedDoItalic; + } + inline bool IsNeedDoBold() + { + return m_bNeedDoBold; + } + + private: + + std::wstring m_wsName; + std::wstring m_wsPath; + double m_dSize; + bool m_bGid; + LONG m_lFaceIndex; + LONG m_lStyle; + bool m_bBold; + bool m_bItalic; + double m_dCharSpace; + bool m_bNeedDoItalic; + bool m_bNeedDoBold; + }; + class CPath + { + private: + + enum EPathCommandType + { + rendererpathcommand_Unknown = 0x00, + rendererpathcommand_MoveTo = 0x01, + rendererpathcommand_LineTo = 0x02, + rendererpathcommand_CurveTo = 0x03, + rendererpathcommand_ArcTo = 0x04, + rendererpathcommand_Close = 0x05, + rendererpathcommand_TextChar = 0x06, + rendererpathcommand_Text = 0x07, + rendererpathcommand_TextExChar = 0x08, + rendererpathcommand_TextEx = 0x09 + }; + class CPathCommandBase + { + public: + CPathCommandBase() + { + } + virtual ~CPathCommandBase() + { + } + virtual void Draw(PdfWriter::CPage* pPage) = 0; + virtual void UpdateBounds(double& dL, double& dT, double& dR, double& dB) = 0; + virtual void GetLastPoint(double& dX, double& dY) = 0; + virtual EPathCommandType GetType() = 0; + }; + class CPathMoveTo : public CPathCommandBase + { + public: + CPathMoveTo(const double& dX, const double& dY) + { + x = dX; + y = dY; + } + void GetLastPoint(double& dX, double& dY) + { + dX = x; + dY = y; + } + void Draw(PdfWriter::CPage* pPage); + void UpdateBounds(double& dL, double& dT, double& dR, double& dB); + EPathCommandType GetType() + { + return rendererpathcommand_MoveTo; + } + + public: + + double x; + double y; + }; + class CPathLineTo : public CPathCommandBase + { + public: + CPathLineTo(const double& dX, const double& dY) + { + x = dX; + y = dY; + } + void GetLastPoint(double& dX, double& dY) + { + dX = x; + dY = y; + } + void Draw(PdfWriter::CPage* pPage); + void UpdateBounds(double& dL, double& dT, double& dR, double& dB); + EPathCommandType GetType() + { + return rendererpathcommand_LineTo; + } + + public: + + double x; + double y; + }; + class CPathCurveTo : public CPathCommandBase + { + public: + CPathCurveTo(const double& dX1, const double& dY1, const double& dX2, const double& dY2, const double& dXe, const double& dYe) + { + x1 = dX1; + y1 = dY1; + x2 = dX2; + y2 = dY2; + xe = dXe; + ye = dYe; + } + void GetLastPoint(double& dX, double& dY) + { + dX = xe; + dY = ye; + } + void Draw(PdfWriter::CPage* pPage); + void UpdateBounds(double& dL, double& dT, double& dR, double& dB); + EPathCommandType GetType() + { + return rendererpathcommand_CurveTo; + } + + public: + + double x1; + double y1; + double x2; + double y2; + double xe; + double ye; + }; + class CPathArcTo : public CPathCommandBase + { + public: + CPathArcTo(const double& dX, const double& dY, const double& dW, const double& dH, const double& dStartAngle, const double& dSweepAngle) + { + x = dX; + y = dY; + w = dW; + h = dH; + startAngle = dStartAngle; + sweepAngle = dSweepAngle; + } + void GetLastPoint(double& dX, double& dY) + { + // TODO: Надо грамотно пересчитать + dX = x; + dY = y; + } + void Draw(PdfWriter::CPage* pPage); + void UpdateBounds(double& dL, double& dT, double& dR, double& dB); + EPathCommandType GetType() + { + return rendererpathcommand_ArcTo; + } + + public: + + double x; + double y; + double w; + double h; + double startAngle; + double sweepAngle; + }; + class CPathClose : public CPathCommandBase + { + public: + CPathClose() + { + } + void GetLastPoint(double& dX, double& dY) + { + // TODO: Надо грамотно пересчитать + dX = 0; + dY = 0; + } + void Draw(PdfWriter::CPage* pPage); + void UpdateBounds(double& dL, double& dT, double& dR, double& dB); + EPathCommandType GetType() + { + return rendererpathcommand_Close; + } + }; + class CPathText : public CPathCommandBase + { + public: + CPathText(PdfWriter::CFontDict* pFont, unsigned char* pCodes, const unsigned int& unCodesCount, const double& dX, const double& dY, const double& dSize, const double& dCharSpace) + { + font = pFont; + codes = pCodes; + codesCount = unCodesCount; + x = dX; + y = dY; + fontSize = dSize; + charSpace = dCharSpace; + } + ~CPathText() + { + RELEASEARRAYOBJECTS(codes); + } + void GetLastPoint(double& dX, double& dY) + { + dX = x; + dY = y; + } + void Draw(PdfWriter::CPage* pPage); + void UpdateBounds(double& dL, double& dT, double& dR, double& dB); + EPathCommandType GetType() + { + return rendererpathcommand_Text; + } + + public: + + PdfWriter::CFontDict* font; + unsigned char* codes; + unsigned int codesCount; + double x; + double y; + double fontSize; + double charSpace; + }; + + public: + + CPath() + { + m_bIsMoveTo = false; + } + ~CPath() + { + Clear(); + } + + bool MoveTo(const double& dX, const double& dY) + { + m_bIsMoveTo = true; + return Add(new CPathMoveTo(dX, dY)); + } + bool LineTo(const double& dX, const double& dY) + { + if (!m_bIsMoveTo) + MoveTo(dX, dY); + + return Add(new CPathLineTo(dX, dY)); + } + bool CurveTo(double dX1, double dY1, double dX2, double dY2, double dXE, double dYE) + { + if (!m_bIsMoveTo) + MoveTo(dX1, dY1); + + return Add(new CPathCurveTo(dX1, dY1, dX2, dY2, dXE, dYE)); + } + bool ArcTo(double dX, double dY, double dW, double dH, double dStart, double dSweep) + { + if (!m_bIsMoveTo) + MoveTo(dX, dY); + + return Add(new CPathArcTo(dX, dY, dW, dH, dStart, dSweep)); + } + bool AddText(PdfWriter::CFontDict* pFont, unsigned char* pCodes, const unsigned int& unLen, const double& dX, const double& dY, const double& dSize, const double& dCharSpace) + { + return Add(new CPathText(pFont, pCodes, unLen, dX, dY, dSize, dCharSpace)); + } + bool Close() + { + return Add(new CPathClose()); + } + void Clear() + { + for (size_t nIndex = 0, nCount = m_vCommands.size(); nIndex < nCount; nIndex++) + { + CPathCommandBase* pCommand = m_vCommands.at(nIndex); + delete pCommand; + } + m_vCommands.clear(); + m_bIsMoveTo = false; + } + bool IsMoveTo() + { + return m_bIsMoveTo; + } + void GetLastPoint(double& dX, double& dY); + void Draw(PdfWriter::CPage* pPage, bool bStroke, bool bFill, bool bEoFill); + void Clip(PdfWriter::CPage* pPage, bool bEvenOdd = false); + void GetBounds(double& dL, double& dT, double& dR, double& dB); + + private: + + bool Add(CPathCommandBase* pCommand) + { + if (pCommand) + { + m_vCommands.push_back(pCommand); + return true; + } + + return false; + } + + + public: + + std::vector m_vCommands; + bool m_bIsMoveTo; + }; + class CTransform + { + public: + + CTransform() + { + Reset(); + } + void operator=(const CTransform& oT) + { + m11 = oT.m11; + m12 = oT.m12; + m21 = oT.m21; + m22 = oT.m22; + dx = oT.dx; + dy = oT.dy; + } + void Reset() + { + m11 = 1.0; + m12 = 0.0; + m21 = 0.0; + m22 = 1.0; + dx = 0; + dy = 0; + } + bool IsIdentity() const + { + if (fabs(m11 - 1) < 0.001 + && fabs(m12) < 0.001 + && fabs(m21) < 0.001 + && fabs(m22 - 1) < 0.001 + && fabs(dx) < 0.001 + && fabs(dy) < 0.001) + return true; + + return false; + } + void Set(const double& dM11, const double& dM12, const double& dM21, const double& dM22, const double& dX, const double& dY) + { + m11 = dM11; + m12 = dM12; + m21 = dM21; + m22 = dM22; + dx = dX; + dy = dY; + } + + public: + + double m11; + double m12; + double m21; + double m22; + double dx; + double dy; + }; + class CCommandManager + { + public: + CCommandManager(CPdfWriter* pRenderer); + ~CCommandManager(); + CRendererTextCommand* AddText(unsigned char* pCodes, unsigned int nLen, const double& dX, const double& dY); + void Flush(); + void SetTransform(const CTransform& oTransform); + void SetTransform(const double& m11, const double& m12, const double& m21, const double& m22, const double& dx, const double& dy); + private: + void Add(CRendererCommandBase* pCommand); + void Clear(); + private: + CPdfWriter* m_pRenderer; + std::vector m_vCommands; + CTransform m_oTransform; + }; + struct TImageInfo + { + std::wstring wsPath; + BYTE nAlpha; + int nWidth; + int nHeight; + PdfWriter::CImageDict* pImage; + }; + struct TDestinationInfo + { + TDestinationInfo(PdfWriter::CPage* page, const double& x, const double& y, const double& w, const double& h, const double& dx, const double& dy, const unsigned int& undpage) + { + pPage = page; + dX = x; + dY = y; + dW = w; + dH = h; + dDestX = dx; + dDestY = dy; + unDestPage = undpage; + } + + PdfWriter::CPage* pPage; + double dX; + double dY; + double dW; + double dH; + double dDestX; + double dDestY; + unsigned int unDestPage; + }; + class CFieldsManager + { + public: + + CFieldsManager() + { + m_unCounter = 0; + } + + std::string GetNewFieldName() + { + std::string sName("F"); + sName.append(std::to_string(++m_unCounter)); + return sName; + } + + private: + + unsigned int m_unCounter; + }; + //---------------------------------------------------------------------------------------- + // + // CMultiLineTextManager + // + //---------------------------------------------------------------------------------------- + class CMultiLineTextManager + { + public: + CMultiLineTextManager() + { + m_pCodes = NULL; + m_pWidths = NULL; + m_unLen = 0; + m_ushSpaceCode = 0; + m_unLineHeight = 0; + m_nAscent = 0; + m_nDescent = 0; + } + void Init(unsigned short* pCodes, unsigned int* pWidths, const unsigned int& unLen, const unsigned short& ushSpaceCode, const unsigned int& unLineHeight, const int& nAscent) + { + m_pCodes = pCodes; + m_pWidths = pWidths; + m_unLen = unLen; + m_ushSpaceCode = ushSpaceCode; + m_unLineHeight = unLineHeight; + m_nAscent = nAscent; + m_nDescent = unLineHeight - nAscent; + } + void Clear() + { + m_pCodes = NULL; + m_pWidths = NULL; + m_unLen = 0; + m_ushSpaceCode = 0; + m_unLineHeight = 0; + m_nAscent = 0; + m_nDescent = 0; + } + void CalculateLines(const double& dFontSize, const double& dW) + { + m_vBreaks.clear(); + + bool bLineStart = true, bWord = false, bFirstItemOnLine = true; + + unsigned int unPos = 0, unWordStartPos = 0; + double dWordWidth = 0; + double dX = 0, dKoef = dFontSize / 1000.0; + + while (unPos < m_unLen) + { + if (IsSpace(unPos)) + { + dX += dWordWidth + m_pWidths[unPos] * dKoef; + bWord = false; + dWordWidth = 0; + bLineStart = false; + bFirstItemOnLine = false; + } + else + { + double dLetterWidth = m_pWidths[unPos] * dKoef; + if (dX + dWordWidth + dLetterWidth > dW) + { + if (bLineStart) + { + if (bFirstItemOnLine) + { + if (unPos != m_unLen - 1) + m_vBreaks.push_back(unPos + 1); + + unPos++; + } + else + { + m_vBreaks.push_back(unPos); + } + } + else + { + if (bWord) + { + m_vBreaks.push_back(unWordStartPos); + unPos = unWordStartPos; + } + else + { + m_vBreaks.push_back(unPos); + } + } + + dX = 0; + bWord = false; + dWordWidth = 0; + bLineStart = true; + bFirstItemOnLine = true; + continue; + } + + if (bWord) + { + dWordWidth += m_pWidths[unPos] * dKoef; + } + else + { + unWordStartPos = unPos; + bWord = true; + dWordWidth = m_pWidths[unPos] * dKoef; + } + + bFirstItemOnLine = false; + } + + unPos++; + } + } + double ProcessAutoFit(const double& dW, const double& dH) + { + double dGoodFontSize = 0; + + // Параметры подобраны для совместимости с AdobeReader + double dFontSize = 4; + double dFontSizeStep = 0.797 / 3.0; + + while (true) + { + CalculateLines(dFontSize, dW); + if (CheckHeight(dH, dFontSize)) + { + dGoodFontSize = dFontSize; + dFontSize += dFontSizeStep; + + if (dFontSize > 12) + { + dFontSize = 12; + break; + } + } + else + { + if (dGoodFontSize > 0.001) + { + dFontSize = dGoodFontSize; + break; + } + + dFontSize -= dFontSizeStep; + if (dFontSize < 4) + { + dFontSize = 4; + break; + } + } + } + + return (floor(dFontSize * 1000.0 + 0.5) / 1000.0); + } + unsigned int GetLinesCount() const + { + return m_vBreaks.size() + 1; + } + unsigned int GetLineStartPos(const int& nLineIndex) const + { + if (!nLineIndex || nLineIndex > m_vBreaks.size()) + return 0; + + return m_vBreaks[nLineIndex - 1]; + } + unsigned int GetLineEndPos(const int& nLineIndex) const + { + if (nLineIndex >= m_vBreaks.size()) + return m_unLen; + + return m_vBreaks[nLineIndex]; + } + double GetLineWidth(const int& nLineIndex, const double& dFontSize = 10.0) + { + if (nLineIndex < 0 || nLineIndex > m_vBreaks.size()) + return 0; + + unsigned int unStart = GetLineStartPos(nLineIndex); + unsigned int unEnd = GetLineEndPos(nLineIndex); + + double dWidth = 0; + double dKoef = dFontSize / 1000.0; + + while (unStart < unEnd) + { + if (IsSpace(unStart)) + unStart++; + else + break; + } + + while (unEnd > unStart && unEnd > 0) + { + if (IsSpace(unEnd - 1)) + unEnd--; + else + break; + } + + for (unsigned int unPos = unStart; unPos < unEnd; ++unPos) + { + dWidth += m_pWidths[unPos] * dKoef; + } + + return dWidth; + } + + + private: + + inline bool IsSpace(const unsigned int& unPos) const + { + return (m_pCodes[unPos] == m_ushSpaceCode); + } + inline bool CheckHeight(const double& dH, const double& dFontSize) const + { + double dKoef = dFontSize / 1000.0; + return (GetLinesCount() * (m_unLineHeight * dKoef) < (dH - (m_nDescent * dKoef))); + } + + + private: + + unsigned short* m_pCodes; + unsigned int* m_pWidths; + unsigned int m_unLen; + unsigned short m_ushSpaceCode; + unsigned int m_unLineHeight; + int m_nAscent; + int m_nDescent; + + std::vector m_vBreaks; + }; + +private: + + NSFonts::IApplicationFonts* m_pAppFonts; + NSFonts::IFontManager* m_pFontManager; + std::wstring m_wsTempFolder; + + PdfWriter::CDocument* m_pDocument; + PdfWriter::CPage* m_pPage; + PdfWriter::CFontCidTrueType* m_pFont; + PdfWriter::CShading* m_pShading; + PdfWriter::CExtGrState* m_pShadingExtGrState; + + bool m_bNeedUpdateTextFont; + bool m_bNeedUpdateTextColor; + bool m_bNeedUpdateTextAlpha; + bool m_bNeedUpdateTextCharSpace; + bool m_bNeedUpdateTextSize; + + CCommandManager m_oCommandManager; + + CPenState m_oPen; + CBrushState m_oBrush; + CFontState m_oFont; + CPath m_oPath; + CTransform m_oTransform; + LONG m_lClipMode; + double m_dPageHeight; + double m_dPageWidth; + LONG m_lClipDepth; + std::vector m_vFonts; + std::vectorm_vDestinations; + CFieldsManager m_oFieldsManager; + CMultiLineTextManager m_oLinesManager; + + bool m_bValid; +}; + +#endif // _PDF_WRITER_H diff --git a/PdfFile/test/test.cpp b/PdfFile/test/test.cpp index 146b1c8700..1cc923dd1a 100644 --- a/PdfFile/test/test.cpp +++ b/PdfFile/test/test.cpp @@ -80,7 +80,7 @@ int main() return 0; } - if (true) + if (false) { double dPageDpiX, dPageDpiY, dWidth, dHeight; pdfFile.GetPageInfo(0, &dWidth, &dHeight, &dPageDpiX, &dPageDpiY); diff --git a/PdfWriter/PdfRenderer.cpp b/PdfWriter/PdfRenderer.cpp index bb82a9efde..2970d453f6 100644 --- a/PdfWriter/PdfRenderer.cpp +++ b/PdfWriter/PdfRenderer.cpp @@ -2704,6 +2704,7 @@ void CPdfRenderer::Reset() m_lClipDepth = 0; } +/* HRESULT CPdfRenderer::OnlineWordToPdf (const std::wstring& wsSrcFile, const std::wstring& wsDstFile, CConvertFromBinParams* pParams) { if (!NSOnlineOfficeBinToPdf::ConvertBinToPdf(this, wsSrcFile, wsDstFile, false, pParams)) @@ -2718,6 +2719,7 @@ HRESULT CPdfRenderer::OnlineWordToPdfFromBinary(const std::wstring& wsSrcFile, c return S_OK; } +*/ static inline void UpdateMaxMinPoints(double& dMinX, double& dMinY, double& dMaxX, double& dMaxY, const double& dX, const double& dY) { diff --git a/PdfWriter/PdfRenderer.h b/PdfWriter/PdfRenderer.h index 0b5eb14d58..d2351d6214 100644 --- a/PdfWriter/PdfRenderer.h +++ b/PdfWriter/PdfRenderer.h @@ -32,8 +32,6 @@ #ifndef _PDF_WRITER_PDFRENDERER_H #define _PDF_WRITER_PDFRENDERER_H -#include "../PdfFile/PdfFile.h" - #include "../DesktopEditor/graphics/IRenderer.h" #include "../DesktopEditor/graphics/pro/Fonts.h" #include "../DesktopEditor/graphics/pro/Image.h" @@ -71,6 +69,21 @@ namespace Aggplus class CRendererCommandBase; class CRendererTextCommand; +class CConvertFromBinParams +{ +public: + std::wstring m_sMediaDirectory; + std::wstring m_sInternalMediaDirectory; + std::wstring m_sThemesDirectory; + bool m_bIsUsePicker; + +public: + CConvertFromBinParams() + { + m_bIsUsePicker = false; + } +}; + class PDFWRITER_DECL_EXPORT CPdfRenderer : public IRenderer { public: @@ -226,8 +239,8 @@ public: HRESULT EnableBrushRect(const LONG& lEnable); HRESULT SetLinearGradient(const double& dX1, const double& dY1, const double& dX2, const double& dY2); HRESULT SetRadialGradient(const double& dX1, const double& dY1, const double& dR1, const double& dX2, const double& dY2, const double& dR2); - HRESULT OnlineWordToPdf (const std::wstring& wsSrcFile, const std::wstring& wsDstFile, CConvertFromBinParams* pParams = NULL); - HRESULT OnlineWordToPdfFromBinary(const std::wstring& wsSrcFile, const std::wstring& wsDstFile, CConvertFromBinParams* pParams = NULL); + //HRESULT OnlineWordToPdf (const std::wstring& wsSrcFile, const std::wstring& wsDstFile, CConvertFromBinParams* pParams = NULL); + //HRESULT OnlineWordToPdfFromBinary(const std::wstring& wsSrcFile, const std::wstring& wsDstFile, CConvertFromBinParams* pParams = NULL); HRESULT DrawImageWith1bppMask(IGrObject* pImage, NSImages::CPixJbig2* pMaskBuffer, const unsigned int& unMaskWidth, const unsigned int& unMaskHeight, const double& dX, const double& dY, const double& dW, const double& dH); //----------------------------------------------------------------------------------------