/* * (c) Copyright Ascensio System SIA 2010-2023 * * This program is a free software product. You can redistribute it and/or * modify it under the terms of the GNU Affero General Public License (AGPL) * version 3 as published by the Free Software Foundation. In accordance with * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect * that Ascensio System SIA expressly excludes the warranty of non-infringement * of any third-party rights. * * This program is distributed WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html * * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish * street, Riga, Latvia, EU, LV-1050. * * The interactive user interfaces in modified source and object code versions * of the Program must display Appropriate Legal Notices, as required under * Section 5 of the GNU AGPL version 3. * * Pursuant to Section 7(b) of the License you must retain the original Product * logo when distributing the program. Pursuant to Section 7(e) we decline to * grant you any rights under trademark law for use of our trademarks. * * All the Product's GUI elements, including illustrations and icon sets, as * well as technical writing content are licensed under the terms of the * Creative Commons Attribution-ShareAlike 4.0 International. See the License * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode * */ #include "../DesktopEditor/common/File.h" #include "../DesktopEditor/common/Directory.h" #include "PdfWriter.h" #include "SrcWriter/Document.h" #include "SrcWriter/Pages.h" #include "SrcWriter/Image.h" #include "SrcWriter/Font.h" #include "SrcWriter/FontCidTT.h" #include "SrcWriter/FontTT.h" #include "SrcWriter/Font14.h" #include "SrcWriter/Destination.h" #include "SrcWriter/Field.h" #include "SrcWriter/Outline.h" #include "SrcWriter/Utils.h" #include "Resources/BaseFonts.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 "../DesktopEditor/common/StringExt.h" #include "../DesktopEditor/graphics/GraphicsPath.h" #include "../DesktopEditor/graphics/MetafileToRenderer.h" #include "../DesktopEditor/raster/Metafile/MetaFileCommon.h" #include "../UnicodeConverter/UnicodeConverter.h" #ifndef BUILDING_WASM_MODULE #include "../Common/Network/FileTransporter/include/FileTransporter.h" #endif #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 MM_TO_PT(value) (value * 300.0 / 25.4) #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 // Этих типов браша нет в рендерере, мы их используем, когда конвертим из веба static const long c_BrushTypeLinearGradient = 8001; static const long c_BrushTypeRadialGradient = 8002; Aggplus::CImage* ConvertMetafile(NSFonts::IApplicationFonts* pAppFonts, const std::wstring& wsPath, const std::wstring& wsTempDirectory, double dWidth = -1, double dHeight = -1) { if (wsPath.find(L"data:") == 0) { std::wstring::size_type posZ = wsPath.find(L','); int nBase64Size = (int)(wsPath.length() - posZ - 1); const wchar_t* pBase64Data = wsPath.c_str() + posZ + 1; char* pBase64Buffer = new char[nBase64Size]; for (int i = 0; i < nBase64Size; ++i) pBase64Buffer[i] = (char)pBase64Data[i]; int nBufferLen = NSBase64::Base64DecodeGetRequiredLength(nBase64Size); BYTE* pImageBuffer = new BYTE[nBufferLen + 64]; Aggplus::CImage* pImage = new Aggplus::CImage(); if (NSBase64::Base64Decode(pBase64Buffer, nBase64Size, pImageBuffer, &nBufferLen)) pImage->Decode(pImageBuffer, nBufferLen); RELEASEARRAYOBJECTS(pImageBuffer); RELEASEARRAYOBJECTS(pBase64Buffer); return pImage; } CImageFileFormatChecker oImageFormat(wsPath); if (_CXIMAGE_FORMAT_WMF == oImageFormat.eFileType || _CXIMAGE_FORMAT_EMF == oImageFormat.eFileType || _CXIMAGE_FORMAT_SVM == oImageFormat.eFileType || _CXIMAGE_FORMAT_SVG == oImageFormat.eFileType) { MetaFile::IMetaFile* pMeta = MetaFile::Create(pAppFonts); if (NULL == pMeta || !pMeta->LoadFromFile(wsPath.c_str())) return new Aggplus::CImage(wsPath); bool bUseMax = false; if (dWidth > 5000 || dHeight > 5000) bUseMax = true; else if (dWidth <= 0 && dHeight <= 0) bUseMax = true; if (!bUseMax) pMeta->ConvertToRaster(wsTempDirectory.c_str(), _CXIMAGE_FORMAT_PNG, MM_2_PT(dWidth), MM_2_PT(dHeight)); else MetaFile::ConvertToRasterMaxSize(pMeta, wsTempDirectory.c_str(), _CXIMAGE_FORMAT_PNG, 2000); RELEASEOBJECT(pMeta); return new Aggplus::CImage(wsTempDirectory); } return new Aggplus::CImage(wsPath); } //---------------------------------------------------------------------------------------- // // CPdfRenderer // //---------------------------------------------------------------------------------------- CPdfWriter::CPdfWriter(NSFonts::IApplicationFonts* pAppFonts, bool isPDFA, IRenderer* pRenderer, bool bCreate, const std::wstring& wsTempDirectory) : m_oCommandManager(this) { // Создаем менеджер шрифтов с собственным кэшем m_pFontManager = pAppFonts->GenerateFontManager(); NSFonts::IFontsCache* pMeasurerCache = NSFonts::NSFontCache::Create(); pMeasurerCache->SetStreams(pAppFonts->GetStreams()); m_pFontManager->SetOwnerCache(pMeasurerCache); m_pRenderer = pRenderer; m_bNeedAddHelvetica = true; m_wsTempDirectory = wsTempDirectory; m_pShading = NULL; m_pShadingExtGrState = NULL; m_pDocument = new PdfWriter::CDocument(); if (isPDFA) m_pDocument->SetPDFAConformanceMode(true); if (!m_pDocument || (bCreate && !m_pDocument->CreateNew())) { SetError(); return; } m_pDocument->SetCompressionMode(COMP_ALL); m_bValid = true; m_bSplit = false; m_dPageHeight = 297; m_dPageWidth = 210; m_pPage = NULL; m_pFont = NULL; m_pFont14 = NULL; m_lClipMode = 0; m_unFieldsCounter = 0; m_bNeedUpdateTextFont = true; } CPdfWriter::~CPdfWriter() { RELEASEOBJECT(m_pDocument); RELEASEINTERFACE(m_pFontManager); } 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; if (!m_pFont && !m_pFont14 && !m_pDocument->IsPDFA() && m_bNeedAddHelvetica) { m_bNeedUpdateTextFont = false; m_pFont14 = m_pDocument->CreateFont14(L"Helvetica", 0, PdfWriter::EStandard14Fonts::standard14fonts_Helvetica); CommandDrawTextCHAR(32, 0, 0, 0, 0); } m_oCommandManager.Flush(); if (!m_pDocument->SaveToFile(wsPath)) return 1; return 0; } int CPdfWriter::SaveToMemory(BYTE** pData, int* pLength) { // TODO: Переделать на код ошибки if (!IsValid()) return 1; m_oCommandManager.Flush(); if (!m_pDocument->SaveToMemory(pData, pLength)) return 1; return 0; } void CPdfWriter::SetDocumentInfo(const std::wstring& wsTitle, const std::wstring& wsCreator, const std::wstring& wsSubject, const std::wstring& wsKeywords) { if (!IsValid()) return; if (!wsTitle.empty()) m_pDocument->SetTitle(U_TO_UTF8(wsTitle)); if (!wsCreator.empty()) { std::string sAuthor = U_TO_UTF8(wsCreator); NSStringUtils::string_replaceA(sAuthor, ";", ", "); m_pDocument->SetAuthor(sAuthor); } if (!wsSubject.empty()) m_pDocument->SetSubject(U_TO_UTF8(wsSubject)); if (!wsKeywords.empty()) m_pDocument->SetKeywords(U_TO_UTF8(wsKeywords)); } std::wstring CPdfWriter::GetTempFile(const std::wstring& wsDirectory) { return NSFile::CFileBinary::CreateTempFileWithUniqueName(wsDirectory, L"PDF"); } void CPdfWriter::SetTempDirectory(const std::wstring& wsTempDirectory) { m_wsTempDirectory = wsTempDirectory; } //---------------------------------------------------------------------------------------- // Функции для работы со страницей //---------------------------------------------------------------------------------------- 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, bool bMM2PT) { if (!IsValid() || !m_pPage) return S_FALSE; m_dPageHeight = bMM2PT ? dHeight : PT_2_MM(dHeight); m_pPage->SetHeight(bMM2PT ? MM_2_PT(dHeight) : dHeight); return S_OK; } HRESULT CPdfWriter::get_Width(double* dWidth) { *dWidth = m_dPageWidth; return S_OK; } HRESULT CPdfWriter::put_Width(const double& dWidth, bool bMM2PT) { if (!IsValid() || !m_pPage) return S_FALSE; m_dPageWidth = bMM2PT ? dWidth : PT_2_MM(dWidth); m_pPage->SetWidth(bMM2PT ? MM_2_PT(dWidth) : dWidth); 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); } 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); } 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::put_BrushGradientColors(LONG* lColors, double* pPositions, LONG lCount) { m_oBrush.SetGradientColors(lColors, pPositions, lCount); return S_OK; } HRESULT CPdfWriter::get_BrushTextureImage(Aggplus::CImage** pImage) { // TODO: return S_OK; } HRESULT CPdfWriter::put_BrushTextureImage(Aggplus::CImage* pImage) { // TODO: return S_OK; } HRESULT CPdfWriter::get_BrushTransform(Aggplus::CMatrix& oMatrix) { // TODO: return S_OK; } HRESULT CPdfWriter::put_BrushTransform(const Aggplus::CMatrix& oMatrix) { // TODO: 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); } 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); } 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; } //---------------------------------------------------------------------------------------- // Функции для вывода текста //---------------------------------------------------------------------------------------- bool UnicodePUA(unsigned int unUnicode) { return (unUnicode >= 0xE000 && unUnicode <= 0xF8FF) || (unUnicode >= 0xF0000 && unUnicode <= 0xFFFFD) || (unUnicode >= 0x100000 && unUnicode <= 0x10FFFD); } bool UnicodesPUA(unsigned int* pUnicodes, unsigned int unLen) { for (int i = 0; i < unLen; ++i) { if (UnicodePUA(pUnicodes[i])) return true; } return false; } 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); if (!pCodes) return DrawTextToRenderer(NULL, 0, dX, dY, NSStringExt::CConverter::GetUnicodeFromUTF32(&unUnicode, 1)) ? S_OK : S_FALSE; return DrawText(pCodes, 2, dX, dY, UnicodePUA(unUnicode) ? NSStringExt::CConverter::GetUtf8FromUTF32(&unUnicode, 1) : "") ? 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 = NSStringExt::CConverter::GetUtf32FromUnicode(wsUnicodeText, unLen); if (!pUnicodes) return S_FALSE; unsigned char* pCodes = EncodeString(pUnicodes, unLen); std::string sPUA; if (UnicodesPUA(pUnicodes, unLen)) sPUA = NSStringExt::CConverter::GetUtf8FromUTF32(pUnicodes, unLen); delete[] pUnicodes; if (!pCodes) return DrawTextToRenderer(NULL, 0, dX, dY, wsUnicodeText) ? S_OK : 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(PdfWriter::textrenderingmode_Invisible); if (fabs(dStringWidth) > 0.001) pText->SetHorScaling(dResultWidth / dStringWidth * 100); pText->SetPUA(sPUA); return S_OK; } return DrawText(pCodes, unLen * 2, dX, dY, sPUA) ? 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); if (!pCodes) return DrawTextToRenderer(&unGID, 1, dX, dY) ? S_OK : S_FALSE; return DrawText(pCodes, 2, dX, dY, UnicodePUA(unUnicode) ? NSStringExt::CConverter::GetUtf8FromUTF32(&unUnicode, 1) : "") ? 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 = NSStringExt::CConverter::GetUtf32FromUnicode(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 = NSStringExt::CConverter::GetUtf32FromUnicode(wsUnicodeText, unLen); if (!pUnicodes) return S_FALSE; } unsigned char* pCodes = EncodeString(pUnicodes, unLen, pGids); std::string sPUA; if (UnicodesPUA(pUnicodes, unLen)) sPUA = NSStringExt::CConverter::GetUtf8FromUTF32(pUnicodes, unLen); RELEASEARRAYOBJECTS(pUnicodes); if (!pCodes) return DrawTextToRenderer(pGids, unGidsCount, dX, dY) ? S_OK : S_FALSE; return DrawText(pCodes, unLen * 2, dX, dY, sPUA) ? 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); if (!pCodes) return DrawTextToRenderer(&unGid, 1, dX, dY) ? S_OK : S_FALSE; return DrawText(pCodes, 2, dX, dY, UnicodesPUA(pUnicodes, unUnicodeCount) ? NSStringExt::CConverter::GetUtf8FromUTF32(pUnicodes, unUnicodeCount) : "") ? S_OK : S_FALSE; } //---------------------------------------------------------------------------------------- // Маркеры команд //---------------------------------------------------------------------------------------- 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(); m_oPath.Clip(m_pPage, c_nClipRegionTypeEvenOdd & m_lClipMode); } 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(NSFonts::IApplicationFonts* pAppFonts, const std::wstring& wsTempDirectory, const LONG& lType, bool bIgnoreRedact) { 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, wsTempDirectory); if (!sTextureTmpPath.empty()) m_oBrush.SetTexturePath(sTextureTmpPath); } UpdateBrush(pAppFonts, wsTempDirectory); } if (!bIgnoreRedact && !m_arrRedact.empty()) { PdfWriter::CMatrix* pMatrix = m_pPage->GetTransform(); m_oPath.Redact(pMatrix, m_arrRedact, m_pPage, bStroke, bFill, bEoFill, m_pShading, m_pShadingExtGrState); m_pPage->GrRestore(); if (!sTextureTmpPath.empty()) m_oBrush.SetTexturePath(sTextureOldPath); return S_OK; } 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); // We do not delete the temporary file - it will still be used. // It must be deleted along with the temporary directory //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 = NSStringExt::CConverter::GetUtf32FromUnicode(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 = NSStringExt::CConverter::GetUtf32FromUnicode(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 = NSStringExt::CConverter::GetUtf32FromUnicode(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 || SkipRedact(dX, dY, dW, dH)) return S_OK; if (!DrawImage((Aggplus::CImage*)pImage, dX, dY, dW, dH, 255)) return S_FALSE; return S_OK; } HRESULT CPdfWriter::DrawImageFromFile(NSFonts::IApplicationFonts* pAppFonts, const std::wstring& wsTempDirectory, const std::wstring& wsImagePathSrc, const double& dX, const double& dY, const double& dW, const double& dH, const BYTE& nAlpha) { m_oCommandManager.Flush(); if (!IsPageValid() || SkipRedact(dX, dY, dW, dH)) return S_OK; if (m_pDocument->HasImage(wsImagePathSrc, nAlpha)) { PdfWriter::CImageDict* pPdfImage = m_pDocument->GetImage(wsImagePathSrc, nAlpha); 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 S_OK; } std::wstring sTempImagePath = GetDownloadFile(wsImagePathSrc, wsTempDirectory); std::wstring wsImagePath = sTempImagePath.empty() ? wsImagePathSrc : sTempImagePath; Aggplus::CImage* pAggImage = ConvertMetafile(pAppFonts, wsImagePath, GetTempFile(wsTempDirectory), MM_TO_PT(dW), MM_TO_PT(dH)); HRESULT hRes = S_OK; PdfWriter::CImageDict* pPdfImage = NULL; if (!pAggImage || !(pPdfImage = DrawImage(pAggImage, dX, dY, dW, dH, nAlpha))) hRes = S_FALSE; m_pDocument->AddImage(wsImagePathSrc, nAlpha, pPdfImage); 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::AddHyperlink(const double& dX, const double& dY, const double& dW, const double& dH, const std::wstring& wsUrl, const std::wstring& wsTooltip) { NSUnicodeConverter::CUnicodeConverter conv; PdfWriter::CAnnotation* pAnnot = m_pDocument->CreateUriLinkAnnot(PdfWriter::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()); m_pPage->AddAnnotation(pAnnot); pAnnot->SetBorder(0, 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; PdfWriter::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(NSFonts::IApplicationFonts* pAppFonts, CFormFieldInfo* pFieldInfo, const std::wstring& wsTempDirectory) { if (!m_pDocument || 0 == m_pDocument->GetPagesCount() || !pFieldInfo) return S_OK; CFormFieldInfo& oInfo = *pFieldInfo; PdfWriter::CFontCidTrueType* pCheckedFont = NULL; PdfWriter::CFontCidTrueType* pUncheckedFont = NULL; if (oInfo.IsCheckBox()) { const CFormFieldInfo::CCheckBoxFormPr* pPr = oInfo.GetCheckBoxPr(); pCheckedFont = GetFont(pPr->GetCheckedFontName(), false, false); pUncheckedFont = GetFont(pPr->GetUncheckedFontName(), false, false); } if ((oInfo.IsCheckBox() && (!pCheckedFont || !pUncheckedFont)) || oInfo.IsTextField() || oInfo.IsDropDownList() || oInfo.IsDateTime()) { if (m_bNeedUpdateTextFont) UpdateFont(); if (!m_pFont) return S_OK; if (oInfo.IsCheckBox()) { if (!pCheckedFont) pCheckedFont = m_pFont; if (!pUncheckedFont) pUncheckedFont = m_pFont; } } double dX, dY, dW, dH; oInfo.GetBounds(dX, dY, dW, dH); PdfWriter::CFieldBase* pFieldBase = NULL; bool bRadioButton = false; if (oInfo.IsTextField()) { PdfWriter::CTextField* pField = m_pDocument->CreateTextField(); pFieldBase = static_cast(pField); } else if (oInfo.IsDropDownList()) { PdfWriter::CChoiceField* pField = m_pDocument->CreateChoiceField(); pFieldBase = static_cast(pField); } else if (oInfo.IsCheckBox()) { const CFormFieldInfo::CCheckBoxFormPr* pPr = oInfo.GetCheckBoxPr(); PdfWriter::CCheckBoxField* pField = NULL; std::wstring wsGroupName = pPr->GetGroupKey(); if (L"" != wsGroupName) { bRadioButton = true; PdfWriter::CRadioGroupField* pRadioGroup = m_pDocument->GetRadioGroupField(wsGroupName); if (pRadioGroup) pField = pRadioGroup->CreateKid(); } else { pField = m_pDocument->CreateCheckBoxField(); } pFieldBase = static_cast(pField); } else if (oInfo.IsPicture()) { PdfWriter::CPictureField* pField = m_pDocument->CreatePictureField(); pFieldBase = static_cast(pField); } else if (oInfo.IsDateTime()) { PdfWriter::CDateTimeField* pField = m_pDocument->CreateDateTimeField(); 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(PdfWriter::CFieldBase::EFieldAlignType::Right); else if (2 == unAlign) pFieldBase->SetAlign(PdfWriter::CFieldBase::EFieldAlignType::Center); if (oInfo.HaveBorder()) { unsigned char unR, unG, unB, unA; oInfo.GetBorderColor(unR, unG, unB, unA); pFieldBase->SetFieldBorder(PdfWriter::EBorderSubtype::border_subtype_Solid, PdfWriter::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(PdfWriter::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.GetTextFormPr(); std::wstring wsValue = pPr->GetTextValue(); wsValue = PdfWriter::NormalizeWhitespace(wsValue); unsigned int unLen = 0; unsigned int* pUnicodes = NULL; unsigned short* pCodes = NULL; PdfWriter::CFontCidTrueType** ppFonts = NULL; bool bFont = GetFontData(pAppFonts, wsValue, m_pFont, isBold, isItalic, pUnicodes, unLen, pCodes, ppFonts); if (!bFont) { RELEASEARRAYOBJECTS(pUnicodes); RELEASEARRAYOBJECTS(pCodes); RELEASEARRAYOBJECTS(ppFonts); return S_FALSE; } PdfWriter::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, PdfWriter::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(); PdfWriter::TRgb oNormalColor(oColor.r, oColor.g, oColor.b); PdfWriter::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); PdfWriter::CFontTrueType* pFontTT = NULL; if (!isComb && pPr->IsMultiLine()) { unsigned short* pCodes2 = new unsigned short[unLen]; unsigned int* pWidths = new unsigned int[unLen]; unsigned short ushSpaceCode = 0xFFFF; unsigned short ushNewLineCode = 0xFFFE; for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex) { unsigned short ushCode = 0; if (0x0020 == pUnicodes[unIndex]) ushCode = ushSpaceCode; else if (0x000D == pUnicodes[unIndex] || 0x000A == pUnicodes[unIndex]) ushCode = ushNewLineCode; pCodes2[unIndex] = ushCode; pWidths[unIndex] = ppFonts[unIndex]->GetWidth(pCodes[unIndex]); } pFontTT = m_pDocument->CreateTrueTypeFont(m_pFont); m_oLinesManager.Init(pCodes2, pWidths, unLen, ushSpaceCode, ushNewLineCode, 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); if (pField->GetFont() && pField->GetFont() != m_pFont && pField->GetFont()->GetFontType() == PdfWriter::fontCIDType2) pFontTT = m_pDocument->CreateTrueTypeFont((PdfWriter::CFontCidTrueType*)pField->GetFont()); else pFontTT = m_pDocument->CreateTrueTypeFont(m_pFont); pField->SetDefaultAppearance(pFontTT, m_oFont.GetSize(), PdfWriter::TRgb(oColor.r, oColor.g, oColor.b)); std::wstring wsPlaceHolder = pPr->GetPlaceHolder(); wsPlaceHolder = PdfWriter::NormalizeWhitespace(wsPlaceHolder); 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 = 0; unsigned int* pUnicodes = NULL; unsigned short* pCodes = NULL; PdfWriter::CFontCidTrueType** ppFonts = NULL; bool bFont = GetFontData(pAppFonts, wsValue, m_pFont, isBold, isItalic, pUnicodes, unLen, pCodes, ppFonts); if (!bFont) { RELEASEARRAYOBJECTS(pUnicodes); RELEASEARRAYOBJECTS(pCodes); RELEASEARRAYOBJECTS(ppFonts); return S_FALSE; } PdfWriter::CChoiceField* pField = dynamic_cast(pFieldBase); if (!pField) { RELEASEARRAYOBJECTS(pUnicodes); RELEASEARRAYOBJECTS(pCodes); RELEASEARRAYOBJECTS(ppFonts); return S_FALSE; } pFieldBase->AddPageRect(m_pPage, PdfWriter::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(); PdfWriter::TRgb oNormalColor(oColor.r, oColor.g, oColor.b); PdfWriter::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()); PdfWriter::CFontTrueType* pFontTT = NULL; if (pField->GetFont() && pField->GetFont() != m_pFont && pField->GetFont()->GetFontType() == PdfWriter::fontCIDType2) pFontTT = m_pDocument->CreateTrueTypeFont((PdfWriter::CFontCidTrueType*)pField->GetFont()); else pFontTT = m_pDocument->CreateTrueTypeFont(m_pFont); pField->SetDefaultAppearance(pFontTT, m_oFont.GetSize(), oInfo.IsPlaceHolder() ? oPlaceHolderColor : oNormalColor); std::wstring wsPlaceHolder = pPr->GetPlaceHolder(); wsPlaceHolder = PdfWriter::NormalizeWhitespace(wsPlaceHolder); if (!wsPlaceHolder.empty()) { pField->SetPlaceHolderText(wsPlaceHolder, 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(); PdfWriter::CCheckBoxField* pField = dynamic_cast(pFieldBase); if (!pField) return S_FALSE; pFieldBase->AddPageRect(m_pPage, PdfWriter::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()); 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, PdfWriter::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(); PdfWriter::CPictureField* pField = dynamic_cast(pFieldBase); pFieldBase->AddPageRect(m_pPage, PdfWriter::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(); PdfWriter::CImageDict* pImage = NULL; if (wsPath.length()) { Aggplus::CImage* pCImage = ConvertMetafile(pAppFonts, wsPath, GetTempFile(wsTempDirectory), MM_TO_PT(dW), MM_TO_PT(dH)); pImage = LoadImage(pCImage, 255); RELEASEOBJECT(pCImage); } pField->SetAppearance(pImage); } else if (oInfo.IsDateTime()) { const CFormFieldInfo::CDateTimeFormPr* pPr = oInfo.GetDateTimePr(); std::wstring wsValue = pPr->GetValue(); unsigned int unLen = 0; unsigned int* pUnicodes = NULL; unsigned short* pCodes = NULL; PdfWriter::CFontCidTrueType** ppFonts = NULL; bool bFont = GetFontData(pAppFonts, wsValue, m_pFont, isBold, isItalic, pUnicodes, unLen, pCodes, ppFonts); if (!bFont) { RELEASEARRAYOBJECTS(pUnicodes); RELEASEARRAYOBJECTS(pCodes); RELEASEARRAYOBJECTS(ppFonts); return S_FALSE; } PdfWriter::CDateTimeField* pField = dynamic_cast(pFieldBase); if (!pField) { RELEASEARRAYOBJECTS(pUnicodes); RELEASEARRAYOBJECTS(pCodes); RELEASEARRAYOBJECTS(ppFonts); return S_FALSE; } pFieldBase->AddPageRect(m_pPage, PdfWriter::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(); PdfWriter::TRgb oNormalColor(oColor.r, oColor.g, oColor.b); PdfWriter::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); pField->SetFormat(pPr->GetFormat()); } // Выставляем имя в конце, потому что там возможно копирование настроек поля в новое родительское поле, поэтому к текущему моменту // все настройки должны быть выставлены if (!bRadioButton) { std::wstring wsKey = oInfo.GetKey(); if (L"" != wsKey) pFieldBase->SetFieldName(wsKey); else pFieldBase->SetFieldName("F" + std::to_string(++m_unFieldsCounter)); } return S_OK; } void GetRCSpanStyle(CAnnotFieldInfo::CMarkupAnnotPr::CFontData* pFontData, NSStringUtils::CStringBuilder& oRC) { oRC += L"font-size:"; oRC.AddDouble(pFontData->dFontSise, 2); oRC += L"pt;text-align:"; switch (pFontData->nAlignment) { case 1: { oRC += L"center"; break; } case 2: { oRC += L"right"; break; } case 3: { oRC += L"justify"; break; } case 0: default:{ oRC += L"left"; break; } } oRC += L";text-decoration:"; if ((pFontData->nFontFlag >> 4) & 1) oRC += L"word"; if ((pFontData->nFontFlag >> 3) & 1) { if ((pFontData->nFontFlag >> 4) & 1) oRC += L" "; oRC += L"line-through"; } oRC += L";color:"; oRC.WriteHexColor3((unsigned char)(pFontData->dColor[0] * 255.0), (unsigned char)(pFontData->dColor[1] * 255.0), (unsigned char)(pFontData->dColor[2] * 255.0)); oRC += L";font-weight:"; oRC += (pFontData->nFontFlag >> 0) & 1 ? L"bold" : L"normal"; oRC += L";font-style:"; oRC += (pFontData->nFontFlag >> 1) & 1 ? L"italic" : L"normal"; oRC += L";font-family:"; oRC += pFontData->sActualFont.empty() ? pFontData->sFontFamily : pFontData->sActualFont; if (pFontData->dVAlign != 0) { oRC += L";vertical-align:"; if (pFontData->dVAlign > 0) oRC += L"+"; oRC.AddDouble(pFontData->dVAlign, 2); } } PdfWriter::CAction* GetAction(PdfWriter::CDocument* m_pDocument, CAnnotFieldInfo::CWidgetAnnotPr::CActionWidget* pAction) { PdfWriter::CAction* pA = m_pDocument->CreateAction(pAction->nActionType); if (!pA) return NULL; pA->SetType(pAction->wsType); switch (pAction->nActionType) { case 1: { PdfWriter::CActionGoTo* ppA = (PdfWriter::CActionGoTo*)pA; PdfWriter::CPage* pPageD = m_pDocument->GetPage(pAction->nInt1); PdfWriter::CDestination* pDest = m_pDocument->CreateDestination(pPageD); if (!pDest) break; ppA->SetDestination(pDest); PdfWriter::CArrayObject* pPageBoxD = (PdfWriter::CArrayObject*)pPageD->Get("CropBox"); if (!pPageBoxD) pPageBoxD = (PdfWriter::CArrayObject*)pPageD->Get("MediaBox"); if (!pPageBoxD) return NULL; PdfWriter::CObjectBase* pD = pPageBoxD->Get(3); double dPageDH = pD->GetType() == PdfWriter::object_type_NUMBER ? ((PdfWriter::CNumberObject*)pD)->Get() : ((PdfWriter::CRealObject*)pD)->Get(); pD = pPageBoxD->Get(0); double dPageDX = pD->GetType() == PdfWriter::object_type_NUMBER ? ((PdfWriter::CNumberObject*)pD)->Get() : ((PdfWriter::CRealObject*)pD)->Get(); switch (pAction->nKind) { case 0: { pDest->SetXYZ(pAction->dD[0] + dPageDX, dPageDH - pAction->dD[1], pAction->dD[2]); break; } case 1: { pDest->SetFit(); break; } case 2: { pDest->SetFitH(dPageDH - pAction->dD[1]); break; } case 3: { pDest->SetFitV(pAction->dD[0] + dPageDX); break; } case 4: { pDest->SetFitR(pAction->dD[0] + dPageDX, dPageDH - pAction->dD[1], pAction->dD[2] + dPageDX, dPageDH - pAction->dD[3]); break; } case 5: { pDest->SetFitB(); break; } case 6: { pDest->SetFitBH(dPageDH - pAction->dD[1]); break; } case 7: { pDest->SetFitBV(pAction->dD[0] + dPageDX); break; } } break; } case 6: { PdfWriter::CActionURI* ppA = (PdfWriter::CActionURI*)pA; ppA->SetURI(pAction->wsStr1); break; } case 9: { PdfWriter::CActionHide* ppA = (PdfWriter::CActionHide*)pA; ppA->SetH(pAction->nKind); ppA->SetT(pAction->arrStr); break; } case 10: { PdfWriter::CActionNamed* ppA = (PdfWriter::CActionNamed*)pA; ppA->SetN(pAction->wsStr1); break; } case 12: { PdfWriter::CActionResetForm* ppA = (PdfWriter::CActionResetForm*)pA; ppA->SetFlags(pAction->nInt1); ppA->SetFields(pAction->arrStr); break; } case 14: { PdfWriter::CActionJavaScript* ppA = (PdfWriter::CActionJavaScript*)pA; ppA->SetJS(pAction->wsStr1); break; } } if (pAction->pNext) { PdfWriter::CAction* pANext = GetAction(m_pDocument, pAction->pNext); pA->SetNext(pANext); } return pA; } HRESULT CPdfWriter::AddAnnotField(NSFonts::IApplicationFonts* pAppFonts, CAnnotFieldInfo* pFieldInfo) { if (!m_pDocument || 0 == m_pDocument->GetPagesCount() || !pFieldInfo) return S_OK; CAnnotFieldInfo& oInfo = *pFieldInfo; PdfWriter::CAnnotation* pAnnot = NULL; PdfWriter::CPage* pOrigPage = m_pDocument->GetEditPage(oInfo.GetPage()); if (!pOrigPage) pOrigPage = m_pDocument->GetPage(oInfo.GetPage()); PdfWriter::CPage* pPage = m_pPage; int nID = oInfo.GetID(); if (nID > 0) pAnnot = m_pDocument->GetAnnot(nID); if (pAnnot && pOrigPage && pPage != pOrigPage) { pOrigPage->DeleteAnnotation(nID); pPage->AddAnnotation(pAnnot); } BYTE nWidgetType = 0; if (oInfo.IsWidget()) { CAnnotFieldInfo::CWidgetAnnotPr* pPr = oInfo.GetWidgetAnnotPr(); nWidgetType = pPr->GetType(); } if (!pAnnot) { CAnnotFieldInfo::EAnnotType oType = oInfo.GetType(); BYTE nType = (BYTE) oType; pAnnot = m_pDocument->CreateAnnot(nType); if (pAnnot) { m_pDocument->AddObject(pAnnot); m_pDocument->AddAnnotation(nID, pAnnot); pPage->AddAnnotation(pAnnot); } } if (!pAnnot) return S_FALSE; double dX1, dY1, dX2, dY2; PdfWriter::CArrayObject* pPageBox = (PdfWriter::CArrayObject*)pPage->Get("CropBox"); if (!pPageBox) pPageBox = (PdfWriter::CArrayObject*)pPage->Get("MediaBox"); PdfWriter::CObjectBase* pD = pPageBox->Get(3); double dPageH = pD->GetType() == PdfWriter::object_type_NUMBER ? ((PdfWriter::CNumberObject*)pD)->Get() : ((PdfWriter::CRealObject*)pD)->Get(); pD = pPageBox->Get(0); double dPageX = pD->GetType() == PdfWriter::object_type_NUMBER ? ((PdfWriter::CNumberObject*)pD)->Get() : ((PdfWriter::CRealObject*)pD)->Get(); pPageBox = (PdfWriter::CArrayObject*)pPage->Get("MediaBox"); pD = pPageBox->Get(3); double dPageY = pD->GetType() == PdfWriter::object_type_NUMBER ? ((PdfWriter::CNumberObject*)pD)->Get() : ((PdfWriter::CRealObject*)pD)->Get(); dPageY -= dPageH; oInfo.GetBounds(dX1, dY1, dX2, dY2); pAnnot->SetRect({dPageX + dX1, dPageH - dY1, dPageX + dX2, dPageH - dY2}); pAnnot->SetPage(pPage, pPage->GetWidth(), dPageH, dPageX, dPageY); pAnnot->SetAnnotFlag(oInfo.GetAnnotFlag()); pAnnot->SetDocument(m_pDocument); int nFlags = oInfo.GetFlag(); if (nFlags & (1 << 0)) pAnnot->SetNM(oInfo.GetNM()); if (nFlags & (1 << 1)) pAnnot->SetContents(oInfo.GetContents()); if (nFlags & (1 << 2)) { BYTE nS; double dI; oInfo.GetBE(nS, dI); pAnnot->SetBE(nS, dI); } if ((nFlags & (1 << 3)) && !oInfo.IsFreeText()) pAnnot->SetC(oInfo.GetC()); if (nFlags & (1 << 4)) { BYTE nType; double dWidth; std::vector arrDash; oInfo.GetBorder(nType, dWidth, arrDash); pAnnot->SetBorder(nType, dWidth, arrDash); } if (nFlags & (1 << 5)) pAnnot->SetLM(oInfo.GetLM()); bool bRender = (nFlags >> 6) & 1; if (nFlags & (1 << 7)) pAnnot->SetOUserID(oInfo.GetOUserID()); if (nFlags & (1 << 9)) pAnnot->SetOMetadata(oInfo.GetOMetadata()); if (oInfo.IsMarkup()) { CAnnotFieldInfo::CMarkupAnnotPr* pPr = oInfo.GetMarkupAnnotPr(); PdfWriter::CMarkupAnnotation* pMarkupAnnot = (PdfWriter::CMarkupAnnotation*)pAnnot; nFlags = pPr->GetFlag(); PdfWriter::CAnnotation* pPopupAnnot = NULL; if (nFlags & (1 << 0)) { int nPopupID = pPr->GetPopupID(); if (nPopupID) pPopupAnnot = m_pDocument->GetAnnot(nPopupID); if (pOrigPage && pPage != pOrigPage) { pOrigPage->DeleteAnnotation(nPopupID); if (pPopupAnnot) { pPage->AddAnnotation(pPopupAnnot); pPopupAnnot->SetPage(pPage); } } } if (!pPopupAnnot && !oInfo.IsFreeText()) { pPopupAnnot = pMarkupAnnot->CreatePopup(); pPage->AddAnnotation(pPopupAnnot); pPopupAnnot->SetPage(pPage); } if (nFlags & (1 << 1)) pMarkupAnnot->SetT(pPr->GetT()); if (nFlags & (1 << 2)) pMarkupAnnot->SetCA(pPr->GetCA()); std::wstring sDefaultStyle; if (nFlags & (1 << 3)) { NSStringUtils::CStringBuilder oRC; oRC += L""; std::vector arrRC = pPr->GetRC(); bool bCurRTL = false; if (!arrRC.empty()) { NSStringUtils::CStringBuilder oDS; oDS += L"font: Helvetica,sans-serif "; oDS.AddDouble(arrRC[0]->dFontSise, 2); oDS += L"pt; text-align:"; switch (arrRC[0]->nAlignment) { case 1: { oDS += L"center"; break; } case 2: { oDS += L"right"; break; } case 3: { oDS += L"justify"; break; } case 0: default:{ oDS += L"left"; break; } } oDS += L"; color:"; oDS.WriteHexColor3((unsigned char)(arrRC[0]->dColor[0] * 255.0), (unsigned char)(arrRC[0]->dColor[1] * 255.0), (unsigned char)(arrRC[0]->dColor[2] * 255.0)); sDefaultStyle = oDS.GetData(); bCurRTL = (arrRC[0]->nFontFlag >> 7) & 1; } oRC += (bCurRTL ? L"

" : L"

"); for (int i = 0; i < arrRC.size(); ++i) { bool bRTL = (arrRC[i]->nFontFlag >> 7) & 1; if (bRTL != bCurRTL) { oRC += (bRTL ? L"

" : L"

"); bCurRTL = bRTL; } oRC += L""; oRC.WriteEncodeXmlString(arrRC[i]->sText); oRC += L""; } oRC += L"

"; pMarkupAnnot->SetRC(oRC.GetData()); // std::wcout << oRC.GetData() << std::endl; } if (nFlags & (1 << 4)) pMarkupAnnot->SetCD(pPr->GetCD()); if (nFlags & (1 << 5)) { int nIRTID = pPr->GetIRTID(); PdfWriter::CAnnotation* pIRTAnnot = m_pDocument->GetAnnot(nIRTID); if (pIRTAnnot) pMarkupAnnot->SetIRTID(pIRTAnnot); else { PdfWriter::CObjectBase* pBase = new PdfWriter::CObjectBase(); pBase->SetRef(nIRTID, 0); pMarkupAnnot->Add("IRT", new PdfWriter::CProxyObject(pBase, true)); } } if (nFlags & (1 << 6)) pMarkupAnnot->SetRT(pPr->GetRT()); if (nFlags & (1 << 7)) pMarkupAnnot->SetSubj(pPr->GetSubj()); if (oInfo.IsText()) { CAnnotFieldInfo::CTextAnnotPr* pPr = oInfo.GetTextAnnotPr(); PdfWriter::CTextAnnotation* pTextAnnot = (PdfWriter::CTextAnnotation*)pAnnot; pTextAnnot->SetOpen(pPr->IsOpen()); if (nFlags & (1 << 16)) pTextAnnot->SetName(pPr->GetName()); if (nFlags & (1 << 17)) pTextAnnot->SetStateModel(pPr->GetStateModel()); if (nFlags & (1 << 18)) pTextAnnot->SetState(pPr->GetState()); if (!m_bSplit) { pMarkupAnnot->RemoveAP(); pTextAnnot->SetAP(); } } else if (oInfo.IsInk()) { CAnnotFieldInfo::CInkAnnotPr* pPr = oInfo.GetInkAnnotPr(); PdfWriter::CInkAnnotation* pInkAnnot = (PdfWriter::CInkAnnotation*)pAnnot; pInkAnnot->SetInkList(pPr->GetInkList()); if (bRender) { pMarkupAnnot->RemoveAP(); LONG nLen = 0; BYTE* pRender = oInfo.GetRender(nLen); DrawAP(pAnnot, pRender, nLen); } } else if (oInfo.IsLine()) { CAnnotFieldInfo::CLineAnnotPr* pPr = oInfo.GetLineAnnotPr(); PdfWriter::CLineAnnotation* pLineAnnot = (PdfWriter::CLineAnnotation*)pAnnot; double dLX1, dLY1, dLX2, dLY2; pPr->GetL(dLX1, dLY1, dLX2, dLY2); pLineAnnot->SetL(dLX1, dLY1, dLX2, dLY2); if (nFlags & (1 << 15)) { BYTE nLE1, nLE2; pPr->GetLE(nLE1, nLE2); pLineAnnot->SetLE(nLE1, nLE2); } if (nFlags & (1 << 16)) pLineAnnot->SetIC(pPr->GetIC()); if (nFlags & (1 << 17)) pLineAnnot->SetLL(pPr->GetLL()); if (nFlags & (1 << 18)) pLineAnnot->SetLLE(pPr->GetLLE()); pLineAnnot->SetCap(pPr->IsCap()); if (nFlags & (1 << 20)) pLineAnnot->SetIT(pPr->GetIT()); if (nFlags & (1 << 21)) pLineAnnot->SetLLO(pPr->GetLLO()); if (nFlags & (1 << 22)) pLineAnnot->SetCP(pPr->GetCP()); if (nFlags & (1 << 23)) { double dCO1, dCO2; pPr->GetCO(dCO1, dCO2); pLineAnnot->SetCO(dCO1, dCO2); } if (bRender) { pMarkupAnnot->RemoveAP(); LONG nLen = 0; BYTE* pRender = oInfo.GetRender(nLen); DrawAP(pAnnot, pRender, nLen); } } else if (oInfo.IsTextMarkup()) { CAnnotFieldInfo::CTextMarkupAnnotPr* pTMPr = oInfo.GetTextMarkupAnnotPr(); PdfWriter::CTextMarkupAnnotation* pTextMarkupAnnot = (PdfWriter::CTextMarkupAnnotation*)pAnnot; pTextMarkupAnnot->SetSubtype(pTMPr->GetSubtype()); pTextMarkupAnnot->SetQuadPoints(pTMPr->GetQuadPoints()); if (!m_bSplit) { pMarkupAnnot->RemoveAP(); pTextMarkupAnnot->SetAP(pTMPr->GetQuadPoints(), pPr->GetCA()); } } else if (oInfo.IsSquareCircle()) { CAnnotFieldInfo::CSquareCircleAnnotPr* pPr = oInfo.GetSquareCircleAnnotPr(); PdfWriter::CSquareCircleAnnotation* pSquareCircleAnnot = (PdfWriter::CSquareCircleAnnotation*)pAnnot; pSquareCircleAnnot->SetSubtype(pPr->GetSubtype()); if (nFlags & (1 << 15)) { double dRD1, dRD2, dRD3, dRD4; pPr->GetRD(dRD1, dRD2, dRD3, dRD4); pSquareCircleAnnot->SetRD(dRD1, dRD2, dRD3, dRD4); } if (nFlags & (1 << 16)) pSquareCircleAnnot->SetIC(pPr->GetIC()); if (bRender) { pMarkupAnnot->RemoveAP(); LONG nLen = 0; BYTE* pRender = oInfo.GetRender(nLen); DrawAP(pAnnot, pRender, nLen); } } else if (oInfo.IsPolygonLine()) { CAnnotFieldInfo::CPolygonLineAnnotPr* pPr = oInfo.GetPolygonLineAnnotPr(); PdfWriter::CPolygonLineAnnotation* pPolygonLineAnnot = (PdfWriter::CPolygonLineAnnotation*)pAnnot; pPolygonLineAnnot->SetVertices(pPr->GetVertices()); pPolygonLineAnnot->SetSubtype(pPr->GetSubtype()); if (nFlags & (1 << 15)) { BYTE nLE1, nLE2; pPr->GetLE(nLE1, nLE2); pPolygonLineAnnot->SetLE(nLE1, nLE2); } if (nFlags & (1 << 16)) pPolygonLineAnnot->SetIC(pPr->GetIC()); if (nFlags & (1 << 20)) pPolygonLineAnnot->SetIT(pPr->GetIT()); if (bRender) { pMarkupAnnot->RemoveAP(); LONG nLen = 0; BYTE* pRender = oInfo.GetRender(nLen); DrawAP(pAnnot, pRender, nLen); } } else if (oInfo.IsFreeText()) { CAnnotFieldInfo::CFreeTextAnnotPr* pFTPr = oInfo.GetFreeTextAnnotPr(); PdfWriter::CFreeTextAnnotation* pFreeTextAnnot = (PdfWriter::CFreeTextAnnotation*)pAnnot; pFreeTextAnnot->SetQ(pFTPr->GetQ()); pFreeTextAnnot->SetRotate(pFTPr->GetRotate()); if (nFlags & (1 << 15)) { double dRD1, dRD2, dRD3, dRD4; pFTPr->GetRD(dRD1, dRD2, dRD3, dRD4); pFreeTextAnnot->SetRD(dRD1, dRD2, dRD3, dRD4); } if (nFlags & (1 << 16)) pFreeTextAnnot->SetCL(pFTPr->GetCL()); std::wstring sDS = pFTPr->GetDS(); if (sDS.empty()) sDS = sDefaultStyle; pFreeTextAnnot->SetDS(sDS); if (nFlags & (1 << 18)) pFreeTextAnnot->SetLE(pFTPr->GetLE()); if (nFlags & (1 << 20)) pFreeTextAnnot->SetIT(pFTPr->GetIT()); if (nFlags & (1 << 21)) pFreeTextAnnot->SetIC(pFTPr->GetIC()); if (bRender) { pMarkupAnnot->RemoveAP(); LONG nLen = 0; BYTE* pRender = oInfo.GetRender(nLen); DrawAP(pAnnot, pRender, nLen); } PdfWriter::CFontDict* pFont = m_pFont; if (m_pFont14) pFont = m_pFont14; pFreeTextAnnot->SetDA(pFont, m_oFont.GetSize(), oInfo.GetC()); } else if (oInfo.IsCaret()) { CAnnotFieldInfo::CCaretAnnotPr* pPr = oInfo.GetCaretAnnotPr(); PdfWriter::CCaretAnnotation* pCaretAnnot = (PdfWriter::CCaretAnnotation*)pAnnot; if (nFlags & (1 << 15)) { double dRD1, dRD2, dRD3, dRD4; pPr->GetRD(dRD1, dRD2, dRD3, dRD4); pCaretAnnot->SetRD(dRD1, dRD2, dRD3, dRD4); } if (nFlags & (1 << 16)) pCaretAnnot->SetSy(pPr->GetSy()); } else if (oInfo.IsStamp()) { CAnnotFieldInfo::CStampAnnotPr* pPr = oInfo.GetStampAnnotPr(); PdfWriter::CStampAnnotation* pStampAnnot = (PdfWriter::CStampAnnotation*)pAnnot; pStampAnnot->SetName(L"#" + pPr->GetName()); double nRotate = pPr->GetRotate(); if (bRender) { LONG nLen = 0; BYTE* pRender = oInfo.GetRender(nLen); PdfWriter::CAnnotAppearanceObject* pAP = DrawAP(pAnnot, pRender, nLen); double dRD1, dRD2, dRD3, dRD4; pPr->GetInRect(dRD1, dRD2, dRD3, dRD4); PdfWriter::CArrayObject* pArray = new PdfWriter::CArrayObject(); pAP->Add("BBox", pArray); pArray->Add(dRD1 + dPageX); pArray->Add(dPageH - dRD4); pArray->Add(dRD3 + dPageX); pArray->Add(dPageH - dRD2); pStampAnnot->SetAPStream(pAP); } pStampAnnot->SetRotate(nRotate); } else if (oInfo.IsRedact()) { CAnnotFieldInfo::CRedactAnnotPr* pPr = oInfo.GetRedactAnnotPr(); PdfWriter::CRedactAnnotation* pRedactAnnot = (PdfWriter::CRedactAnnotation*)pAnnot; if (nFlags & (1 << 15)) pRedactAnnot->SetQuadPoints(pPr->GetQuadPoints()); if (nFlags & (1 << 16)) pRedactAnnot->SetIC(pPr->GetIC()); if (nFlags & (1 << 17)) pRedactAnnot->SetOverlayText(pPr->GetOverlayText()); if (nFlags & (1 << 18)) pRedactAnnot->SetRepeat(true); if (nFlags & (1 << 19)) pRedactAnnot->SetQ(pPr->GetQ()); pRedactAnnot->SetOC(oInfo.GetC()); if (nFlags & (1 << 20)) { std::wstring wsFontName = pPr->GetFontName(); int nStyle = pPr->GetFontStyle(); double dFontSize = pPr->GetFontSize(); PdfWriter::CFontTrueType* pFontTT = NULL; put_FontName(wsFontName); put_FontStyle(nStyle); put_FontSize(dFontSize); if (m_bNeedUpdateTextFont) UpdateFont(); if (m_pFont) pFontTT = m_pDocument->CreateTrueTypeFont(m_pFont); pRedactAnnot->SetDA(pFontTT, dFontSize, pPr->GetFontColor()); } } } else if (oInfo.IsPopup()) { CAnnotFieldInfo::CPopupAnnotPr* pPr = oInfo.GetPopupAnnotPr(); PdfWriter::CPopupAnnotation* pPopupAnnot = (PdfWriter::CPopupAnnotation*)pAnnot; nFlags = pPr->GetFlag(); pPopupAnnot->SetOpen(pPr->IsOpen()); if (nFlags & (1 << 1)) { int nParentID = pPr->GetParentID(); PdfWriter::CAnnotation* pParentAnnot = m_pDocument->GetAnnot(nParentID); if (pParentAnnot) pPopupAnnot->SetParentID(pParentAnnot); } } else if (oInfo.IsWidget()) { CAnnotFieldInfo::CWidgetAnnotPr* pPr = oInfo.GetWidgetAnnotPr(); PdfWriter::CWidgetAnnotation* pWidgetAnnot = (PdfWriter::CWidgetAnnotation*)pAnnot; std::wstring wsFontKey; if (nFlags & (1 << 2)) wsFontKey = pPr->GetFontKey(); std::wstring wsFontName = pPr->GetFontName(); int nStyle = pPr->GetFontStyle(); double dFontSize = pPr->GetFontSizeAP(); PdfWriter::CFontTrueType* pFontTT = NULL; BYTE nAlign = pPr->GetQ(); if (nWidgetType != 27 && nWidgetType != 28 && nWidgetType != 29) pWidgetAnnot->SetQ(nAlign); pWidgetAnnot->SetSubtype(nWidgetType); pWidgetAnnot->SetFlag(pPr->GetFlag()); int nFlags = pPr->GetFlags(); int nR = 0; if (nFlags & (1 << 0)) pWidgetAnnot->SetTU(pPr->GetTU()); if (nFlags & (1 << 1)) pWidgetAnnot->SetDS(pPr->GetDS()); if (nFlags & (1 << 3)) pWidgetAnnot->SetH(pPr->GetH()); if (nFlags & (1 << 5)) pWidgetAnnot->SetBC(pPr->GetBC()); if (nFlags & (1 << 6)) { nR = pPr->GetR(); pWidgetAnnot->SetR(nR); } if (nFlags & (1 << 7)) pWidgetAnnot->SetBG(pPr->GetBG()); if (nFlags & (1 << 8)) pWidgetAnnot->SetDV(pPr->GetDV()); if (nFlags & (1 << 17)) pWidgetAnnot->SetParentID(pPr->GetParentID()); if (nFlags & (1 << 18)) pWidgetAnnot->SetT(pPr->GetT()); else pWidgetAnnot->Remove("T"); if (nFlags & (1 << 21)) pWidgetAnnot->SetMEOptions(pPr->GetMEOptions()); else pWidgetAnnot->Remove("MEOptions"); const std::vector arrActions = pPr->GetActions(); for (CAnnotFieldInfo::CWidgetAnnotPr::CActionWidget* pAction : arrActions) { PdfWriter::CAction* pA = GetAction(m_pDocument, pAction); pWidgetAnnot->AddAction(pA); } bool isBold = (nStyle & 1 ? true : false); bool isItalic = (nStyle & 2 ? true : false); if (oInfo.IsButtonWidget()) { if (nWidgetType == 27) { CAnnotFieldInfo::CWidgetAnnotPr::CButtonWidgetPr* pPr = oInfo.GetWidgetAnnotPr()->GetButtonWidgetPr(); PdfWriter::CPushButtonWidget* pButtonWidget = (PdfWriter::CPushButtonWidget*)pAnnot; BYTE nTP = 0; if (nFlags & (1 << 13)) { nTP = pPr->GetTP(); pButtonWidget->SetTP(nTP); } int nIFFlags = pPr->GetIFFlag(); pButtonWidget->SetIFFlag(nIFFlags); if (nIFFlags & (1 << 0)) { if (nIFFlags & (1 << 1)) pButtonWidget->SetSW(pPr->GetSW()); if (nIFFlags & (1 << 2)) pButtonWidget->SetS(pPr->GetS()); if (nIFFlags & (1 << 3)) { double d1, d2; pPr->GetA(d1, d2); pButtonWidget->SetA(d1, d2); } } if (nIFFlags & (1 << 5)) pButtonWidget->SetI(pPr->GetI()); if (nIFFlags & (1 << 6)) pButtonWidget->SetRI(pPr->GetRI()); if (nIFFlags & (1 << 7)) pButtonWidget->SetIX(pPr->GetIX()); put_FontName(wsFontName); put_FontStyle(nStyle); put_FontSize(dFontSize); if (m_bNeedUpdateTextFont) UpdateFont(); if (m_pFont) pFontTT = m_pDocument->CreateTrueTypeFont(m_pFont); pWidgetAnnot->SetDA(pFontTT, oInfo.GetWidgetAnnotPr()->GetFontSize(), dFontSize, oInfo.GetWidgetAnnotPr()->GetTC()); // ВНЕШНИЙ ВИД pButtonWidget->SetFont(m_pFont, dFontSize, isBold, isItalic); if (nFlags & (1 << 10)) { pButtonWidget->SetCA(pPr->GetCA()); if (nTP == 0 && !m_bSplit) DrawButtonWidget(pAppFonts, pButtonWidget, 0, NULL); } if (nFlags & (1 << 11)) { pButtonWidget->SetRC(pPr->GetRC()); if (nTP == 0 && !m_bSplit) DrawButtonWidget(pAppFonts, pButtonWidget, 1, NULL); } if (nFlags & (1 << 12)) { pButtonWidget->SetAC(pPr->GetAC()); if (nTP == 0 && !m_bSplit) DrawButtonWidget(pAppFonts, pButtonWidget, 2, NULL); } } else { CAnnotFieldInfo::CWidgetAnnotPr::CButtonWidgetPr* pPrB = oInfo.GetWidgetAnnotPr()->GetButtonWidgetPr(); PdfWriter::CCheckBoxWidget* pButtonWidget = (PdfWriter::CCheckBoxWidget*)pAnnot; if (nFlags & (1 << 14)) pButtonWidget->SetAP_N_Yes(pPrB->GetAP_N_Yes()); pButtonWidget->SetStyle(pPrB->GetStyle()); if (!pButtonWidget->Get("DA")) { PdfWriter::CFontDict* pFont = pFontTT; dFontSize = oInfo.GetWidgetAnnotPr()->GetFontSize(); if (!wsFontName.empty()) { put_FontName(wsFontName); put_FontStyle(nStyle); put_FontSize(dFontSize); if (m_bNeedUpdateTextFont) UpdateFont(); if (m_pFont) pFont = m_pDocument->CreateTrueTypeFont(m_pFont); } else { put_FontName(L"Embedded: ZapfDingbats"); put_FontStyle(0); put_FontSize(dFontSize); if (m_bNeedUpdateTextFont) UpdateFont(); if (m_pFont14) pFont = m_pFont14; } pButtonWidget->SetDA(pFont, oInfo.GetWidgetAnnotPr()->GetFontSize(), dFontSize, oInfo.GetWidgetAnnotPr()->GetTC()); } // ВНЕШНИЙ ВИД if (!pButtonWidget->Get("AP")) pButtonWidget->SetAP(nR); if (nFlags & (1 << 9)) { std::wstring sValue = pPrB->GetV(); if (sValue != L"Off") pButtonWidget->Yes(); else pButtonWidget->Off(); } } } else if (oInfo.IsTextWidget()) { CAnnotFieldInfo::CWidgetAnnotPr::CTextWidgetPr* pPr = oInfo.GetWidgetAnnotPr()->GetTextWidgetPr(); PdfWriter::CTextWidget* pTextWidget = (PdfWriter::CTextWidget*)pAnnot; std::wstring wsValue; bool bValue = false; if (nFlags & (1 << 9)) { bValue = true; wsValue = pPr->GetV(); pTextWidget->SetV(wsValue); } if (nFlags & (1 << 10)) pTextWidget->SetMaxLen(pPr->GetMaxLen()); if (nFlags & (1 << 11)) pTextWidget->SetRV(pPr->GetRV()); bool bAPValue = false; if (nFlags & (1 << 12)) { bAPValue = true; wsValue = pPr->GetAPV(); pTextWidget->SetAPV(); } if (nFlags & (1 << 13)) { pTextWidget->SetAPV(); m_pFont14 = NULL; m_pFont = NULL; m_bNeedUpdateTextFont = true; LONG nLen = 0; BYTE* pRender = pPr->GetRender(nLen); DrawWidgetAP(pAnnot, pRender, nLen, nR); PdfWriter::CFontDict* pFont = NULL; if (m_pFont14) pFont = m_pFont14; else if (m_pFont) pFont = m_pDocument->CreateTrueTypeFont(m_pFont); else { dFontSize = oInfo.GetWidgetAnnotPr()->GetFontSize(); put_FontName(wsFontName); put_FontStyle(nStyle); put_FontSize(dFontSize); if (m_bNeedUpdateTextFont) UpdateFont(); if (m_pFont14) pFont = m_pFont14; else if (m_pFont) pFont = m_pDocument->CreateTrueTypeFont(m_pFont); } if (pFont) pWidgetAnnot->SetDA(pFont, oInfo.GetWidgetAnnotPr()->GetFontSize(), dFontSize, oInfo.GetWidgetAnnotPr()->GetTC()); } else if (!m_bSplit && ((bValue && pTextWidget->Get("T")) || bAPValue)) { put_FontName(wsFontName); put_FontStyle(nStyle); put_FontSize(dFontSize); if (m_bNeedUpdateTextFont) UpdateFont(); if (m_pFont) pFontTT = m_pDocument->CreateTrueTypeFont(m_pFont); pWidgetAnnot->SetDA(pFontTT, oInfo.GetWidgetAnnotPr()->GetFontSize(), dFontSize, oInfo.GetWidgetAnnotPr()->GetTC()); pTextWidget->SetFont(m_pFont, dFontSize, isBold, isItalic); DrawTextWidget(pAppFonts, pTextWidget, wsValue); } } else if (oInfo.IsChoiceWidget()) { CAnnotFieldInfo::CWidgetAnnotPr::CChoiceWidgetPr* pPr = oInfo.GetWidgetAnnotPr()->GetChoiceWidgetPr(); PdfWriter::CChoiceWidget* pChoiceWidget = (PdfWriter::CChoiceWidget*)pAnnot; std::vector arrValue; if (nFlags & (1 << 9)) { arrValue.push_back(pPr->GetV()); pChoiceWidget->SetV(arrValue.back()); } if (nFlags & (1 << 10)) pChoiceWidget->SetOpt(pPr->GetOpt()); if (nFlags & (1 << 11)) pChoiceWidget->SetTI(pPr->GetTI()); if (nFlags & (1 << 12)) arrValue[arrValue.size()] = pPr->GetAPV(); if (nFlags & (1 << 13)) pChoiceWidget->SetV(pPr->GetArrV()); if (nFlags & (1 << 14)) pChoiceWidget->SetI(pPr->GetI()); else pChoiceWidget->Remove("I"); if (nFlags & (1 << 15)) { pChoiceWidget->SetAPV(); m_pFont14 = NULL; m_pFont = NULL; m_bNeedUpdateTextFont = true; LONG nLen = 0; BYTE* pRender = pPr->GetRender(nLen); DrawWidgetAP(pAnnot, pRender, nLen, nR, pChoiceWidget->GetWidgetType() == PdfWriter::WidgetCombobox); PdfWriter::CFontDict* pFont = NULL; if (m_pFont14) pFont = m_pFont14; else if (m_pFont) pFont = m_pDocument->CreateTrueTypeFont(m_pFont); else { dFontSize = oInfo.GetWidgetAnnotPr()->GetFontSize(); put_FontName(wsFontName); put_FontStyle(nStyle); put_FontSize(dFontSize); if (m_bNeedUpdateTextFont) UpdateFont(); if (m_pFont14) pFont = m_pFont14; else if (m_pFont) pFont = m_pDocument->CreateTrueTypeFont(m_pFont); } if (pFont) pWidgetAnnot->SetDA(pFont, oInfo.GetWidgetAnnotPr()->GetFontSize(), dFontSize, oInfo.GetWidgetAnnotPr()->GetTC()); } else if (!m_bSplit && !arrValue.empty()) { put_FontName(wsFontName); put_FontStyle(nStyle); put_FontSize(dFontSize); if (m_bNeedUpdateTextFont) UpdateFont(); if (m_pFont) pFontTT = m_pDocument->CreateTrueTypeFont(m_pFont); pWidgetAnnot->SetDA(pFontTT, oInfo.GetWidgetAnnotPr()->GetFontSize(), dFontSize, oInfo.GetWidgetAnnotPr()->GetTC()); pChoiceWidget->SetFont(m_pFont, dFontSize, isBold, isItalic); DrawChoiceWidget(pAppFonts, pChoiceWidget, arrValue); } } else if (oInfo.IsSignatureWidget()) { CAnnotFieldInfo::CWidgetAnnotPr::CSignatureWidgetPr* pPr = oInfo.GetWidgetAnnotPr()->GetSignatureWidgetPr(); PdfWriter::CSignatureWidget* pSignatureWidget = (PdfWriter::CSignatureWidget*)pAnnot; } } return S_OK; } HRESULT CPdfWriter::AddMetaData(const std::wstring& sMetaName, BYTE* pMetaData, DWORD nMetaLength) { return m_pDocument->AddMetaData(sMetaName, pMetaData, nMetaLength) ? S_OK : S_FALSE; } HRESULT CPdfWriter::AddRedact(const std::vector& arrRedact) { m_arrRedact.clear(); if (arrRedact.empty()) return S_OK; m_arrRedact = arrRedact; PdfWriter::CArrayObject* pPageBox = (PdfWriter::CArrayObject*)m_pPage->Get("CropBox"); if (!pPageBox) pPageBox = (PdfWriter::CArrayObject*)m_pPage->Get("MediaBox"); PdfWriter::CObjectBase* pD = pPageBox->Get(3); double dPageH = pD->GetType() == PdfWriter::object_type_NUMBER ? ((PdfWriter::CNumberObject*)pD)->Get() : ((PdfWriter::CRealObject*)pD)->Get(); pD = pPageBox->Get(0); double dPageX = pD->GetType() == PdfWriter::object_type_NUMBER ? ((PdfWriter::CNumberObject*)pD)->Get() : ((PdfWriter::CRealObject*)pD)->Get(); for (int i = 0; i < m_arrRedact.size(); i += 2) { m_arrRedact[i + 0] += dPageX; m_arrRedact[i + 1] = dPageH - m_arrRedact[i + 1]; } return S_OK; } void CreateOutlines(PdfWriter::CDocument* m_pDocument, const std::vector& arrHeadings, PdfWriter::COutline* pParent) { for (int i = 0; i < arrHeadings.size(); ++i) { std::string sTitle = U_TO_UTF8(arrHeadings[i]->wsTitle); PdfWriter::COutline* pOutline = m_pDocument->CreateOutline(pParent, sTitle.c_str()); PdfWriter::CPage* pPageD = m_pDocument->GetPage(arrHeadings[i]->nPage); PdfWriter::CDestination* pDest = m_pDocument->CreateDestination(pPageD, true); if (pDest) { pOutline->SetDestination(pDest); pDest->SetXYZ(MM_2_PT(arrHeadings[i]->dX), pPageD->GetHeight() - MM_2_PT(arrHeadings[i]->dY), 0); } CreateOutlines(m_pDocument, arrHeadings[i]->arrHeading, pOutline); } } void CPdfWriter::SetHeadings(CHeadings* pCommand) { if (!m_pDocument || !pCommand) return; CreateOutlines(m_pDocument, pCommand->GetHeading(), NULL); } void CPdfWriter::SetNeedAddHelvetica(bool bNeedAddHelvetica) { m_bNeedAddHelvetica = bNeedAddHelvetica; } //---------------------------------------------------------------------------------------- // Дополнительные функции Pdf рендерера //---------------------------------------------------------------------------------------- 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 || SkipRedact(dX, dY, dW, dH)) return S_OK; m_pPage->GrSave(); UpdateTransform(); PdfWriter::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 || SkipRedact(dX, dY, dW, dH)) return S_OK; PdfWriter::CImageDict* pPdfImage = LoadImage((Aggplus::CImage*)pImage, 255); if (!pPdfImage) return S_OK; m_pPage->GrSave(); UpdateTransform(); 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; } HRESULT CPdfWriter::EditWidgetParents(NSFonts::IApplicationFonts* pAppFonts, CWidgetsInfo* pFieldInfo, const std::wstring& wsTempDirectory) { if (!m_pDocument || 0 == m_pDocument->GetPagesCount() || !pFieldInfo) return S_OK; if (!m_pDocument->EditCO(pFieldInfo->GetCO())) return S_FALSE; std::vector arrParents = pFieldInfo->GetParents(); for (int j = 0; j < arrParents.size(); ++j) { CWidgetsInfo::CParent* pParent = arrParents[j]; PdfWriter::CDictObject* pParentObj = m_pDocument->GetParent(pParent->nID); if (!pParentObj) pParentObj = m_pDocument->CreateParent(pParent->nID); std::vector arrValue; int nFlags = pParent->nFlags; // Adobe не может смешивать юникод и utf имена полей if (nFlags & (1 << 0)) pParentObj->Add("T", new PdfWriter::CStringObject((U_TO_UTF8(pParent->sName)).c_str(), true)); std::string sFT = m_pDocument->SetParentKids(pParent->nID); PdfWriter::CArrayObject* pKids = dynamic_cast(pParentObj->Get("Kids")); if (!pKids) { pKids = new PdfWriter::CArrayObject(); pParentObj->Add("Kids", pKids); } if (nFlags & (1 << 2)) { std::string sDV = U_TO_UTF8(pParent->sDV); if (sFT == "Btn") pParentObj->Add("DV", sDV.c_str()); else pParentObj->Add("DV", new PdfWriter::CStringObject(sDV.c_str(), true)); } if (nFlags & (1 << 3)) { PdfWriter::CArrayObject* pArray = new PdfWriter::CArrayObject(); pParentObj->Add("I", pArray); for (int i = 0; i < pParent->arrI.size(); ++i) pArray->Add(pParent->arrI[i]); } else pParentObj->Remove("I"); if (nFlags & (1 << 4)) { PdfWriter::CDictObject* pParentObj2 = m_pDocument->GetParent(pParent->nParentID); if (!pParentObj2) pParentObj2 = m_pDocument->CreateParent(pParent->nParentID); if (pParentObj2) pParentObj->Add("Parent", pParentObj2); } if (nFlags & (1 << 5)) { PdfWriter::CArrayObject* pArray = new PdfWriter::CArrayObject(); pParentObj->Add("V", pArray); for (int i = 0; i < pParent->arrV.size(); ++i) pArray->Add(new PdfWriter::CStringObject(U_TO_UTF8(pParent->arrV[i]).c_str(), true)); for (int i = 0; i < pKids->GetCount(); ++i) { PdfWriter::CObjectBase* pObj = pKids->Get(i); if (pObj->GetType() != PdfWriter::object_type_DICT || ((PdfWriter::CDictObject*)pObj)->GetDictType() != PdfWriter::dict_type_ANNOTATION || ((PdfWriter::CAnnotation*)pObj)->GetAnnotationType() != PdfWriter::AnnotWidget) continue; PdfWriter::EWidgetType nType = ((PdfWriter::CWidgetAnnotation*)pObj)->GetWidgetType(); if (nType == PdfWriter::WidgetCombobox || nType == PdfWriter::WidgetListbox) { PdfWriter::CChoiceWidget* pKid = dynamic_cast(pObj); if (!pKid->HaveAPV() && !m_bSplit) DrawChoiceWidget(pAppFonts, pKid, pParent->arrV); } } } std::map mNameAP_N_Yes; if (nFlags & (1 << 6)) { PdfWriter::CArrayObject* pArray = new PdfWriter::CArrayObject(); pParentObj->Add("Opt", pArray); for (int i = 0; i < pParent->arrOpt.size(); ++i) { std::pair PV = pParent->arrOpt[i]; std::string sValue; if (PV.first.empty()) { sValue = U_TO_UTF8(PV.second); pArray->Add(new PdfWriter::CStringObject(sValue.c_str(), true)); if (mNameAP_N_Yes.find(PV.second) == mNameAP_N_Yes.end()) mNameAP_N_Yes[PV.second] = std::to_wstring(i); } else { PdfWriter::CArrayObject* pArray2 = new PdfWriter::CArrayObject(); pArray->Add(pArray2); sValue = U_TO_UTF8(PV.first); pArray2->Add(new PdfWriter::CStringObject(sValue.c_str(), true)); if (mNameAP_N_Yes.find(PV.first) == mNameAP_N_Yes.end()) mNameAP_N_Yes[PV.first] = std::to_wstring(i); sValue = U_TO_UTF8(PV.second); pArray2->Add(new PdfWriter::CStringObject(sValue.c_str(), true)); } } } if (nFlags & (1 << 1)) { std::string sV = U_TO_UTF8(pParent->sV); if (sFT == "Btn") { int nFf = 0; if (nFlags & (1 << 7)) nFf = pParent->nFieldFlag; bool bRadiosInUnison = (bool)(nFf & (1 << 25)); int nOptIndex = -1; if (isdigit(sV[0])) nOptIndex = std::stoi(sV); if (!pParent->arrOpt.empty() && nOptIndex >= 0 && nOptIndex < pParent->arrOpt.size()) { std::pair PV = pParent->arrOpt[nOptIndex]; std::wstring sOpt = PV.first.empty() ? PV.second : PV.first; for (int i = 0; i < pParent->arrOpt.size(); ++i) { if (i >= pKids->GetCount()) break; PdfWriter::CObjectBase* pObj = pKids->Get(i); if (pObj->GetType() != PdfWriter::object_type_DICT || ((PdfWriter::CDictObject*)pObj)->GetDictType() != PdfWriter::dict_type_ANNOTATION || ((PdfWriter::CAnnotation*)pObj)->GetAnnotationType() != PdfWriter::AnnotWidget) continue; PdfWriter::EWidgetType nType = ((PdfWriter::CWidgetAnnotation*)pObj)->GetWidgetType(); if (nType != PdfWriter::WidgetCheckbox && nType != PdfWriter::WidgetRadiobutton) continue; PdfWriter::CCheckBoxWidget* pKid = dynamic_cast(pObj); if (!pKid) continue; PV = pParent->arrOpt[i]; std::wstring sOptI = PV.first.empty() ? PV.second : PV.first; if (pKid->NeedAP_N_Yes()) pKid->SetAP_N_Yes((bRadiosInUnison || nType == PdfWriter::WidgetCheckbox) ? mNameAP_N_Yes[sOptI] : std::to_wstring(i)); pKid->Remove("V"); if (((bRadiosInUnison || nType == PdfWriter::WidgetCheckbox) && sOptI == sOpt) || (!bRadiosInUnison && i == nOptIndex)) { if (i == nOptIndex) pKid->RenameAP_N_Yes(pParent->sV); sV = pKid->Yes(); } else pKid->Off(); } } else { for (int i = 0; i < pKids->GetCount(); ++i) { PdfWriter::CObjectBase* pObj = pKids->Get(i); if (pObj->GetType() != PdfWriter::object_type_DICT || ((PdfWriter::CDictObject*)pObj)->GetDictType() != PdfWriter::dict_type_ANNOTATION || ((PdfWriter::CAnnotation*)pObj)->GetAnnotationType() != PdfWriter::AnnotWidget) continue; PdfWriter::EWidgetType nType = ((PdfWriter::CWidgetAnnotation*)pObj)->GetWidgetType(); if (nType != PdfWriter::WidgetCheckbox && nType != PdfWriter::WidgetRadiobutton) continue; PdfWriter::CCheckBoxWidget* pKid = dynamic_cast(pObj); if (!pKid) continue; if (pKid->NeedAP_N_Yes()) { std::pair PV = pParent->arrOpt[i]; std::wstring sOpt = PV.first.empty() ? PV.second : PV.first; pKid->SetAP_N_Yes(mNameAP_N_Yes[sOpt]); } pKid->Remove("V"); if (pKid->GetAP_N_Yes() == sV) sV = pKid->Yes(); else pKid->Off(); } } pParentObj->Add("V", sV.c_str()); } else { for (int i = 0; i < pKids->GetCount(); ++i) { PdfWriter::CObjectBase* pObj = pKids->Get(i); if (pObj->GetType() != PdfWriter::object_type_DICT || ((PdfWriter::CDictObject*)pObj)->GetDictType() != PdfWriter::dict_type_ANNOTATION || ((PdfWriter::CAnnotation*)pObj)->GetAnnotationType() != PdfWriter::AnnotWidget) continue; PdfWriter::EWidgetType nType = ((PdfWriter::CWidgetAnnotation*)pObj)->GetWidgetType(); if (nType == PdfWriter::WidgetCombobox || nType == PdfWriter::WidgetListbox) { PdfWriter::CChoiceWidget* pKid = dynamic_cast(pObj); if (!pKid->HaveAPV() && !m_bSplit) DrawChoiceWidget(pAppFonts, pKid, {pParent->sV}); } else if (nType == PdfWriter::WidgetText) { PdfWriter::CTextWidget* pKid = dynamic_cast(pObj); if (!pKid->HaveAPV() && !m_bSplit) DrawTextWidget(pAppFonts, pKid, pParent->sV); } } pParentObj->Add("V", new PdfWriter::CStringObject(sV.c_str(), true)); } } if (nFlags & (1 << 7)) pParentObj->Add("Ff", pParent->nFieldFlag); if (nFlags & (1 << 8)) { const std::vector arrActions = pParent->arrAction; for (CAnnotFieldInfo::CWidgetAnnotPr::CActionWidget* pAction : arrActions) { PdfWriter::CAction* pA = GetAction(m_pDocument, pAction); if (!pA) continue; if (pA->m_sType == "A") pParentObj->Add(pA->m_sType.c_str(), pA); else { PdfWriter::CDictObject* pAA = (PdfWriter::CDictObject*)pParentObj->Get("AA"); if (!pAA) { pAA = new PdfWriter::CDictObject(); pParentObj->Add("AA", pAA); } pAA->Add(pA->m_sType.c_str(), pA); } } } if (nFlags & (1 << 9)) pParentObj->Add("MaxLen", pParent->nMaxLen); if (nFlags & (1 << 10)) pParentObj->Add("TU", new PdfWriter::CStringObject((U_TO_UTF8(pParent->sTU)).c_str(), true)); if (nFlags & (1 << 11)) pParentObj->Add("MEOptions", pParent->nMEOptions); else pParentObj->Remove("MEOptions"); } std::vector arrBI = pFieldInfo->GetButtonImg(); std::vector arrForm; for (int i = 0; i < arrBI.size(); ++i) { std::wstring wsPath = arrBI[i]; if (wsPath.empty()) { arrForm.push_back(NULL); continue; } std::wstring sTempImagePath = GetDownloadFile(wsPath, wsTempDirectory); std::wstring wsImagePath = sTempImagePath.empty() ? wsPath : sTempImagePath; Aggplus::CImage* pCImage = ConvertMetafile(pAppFonts, wsImagePath, m_bSplit ? L"" : GetTempFile(wsTempDirectory)); PdfWriter::CImageDict* pImage = LoadImage(pCImage, 255); RELEASEOBJECT(pCImage); arrForm.push_back(m_pDocument->CreateForm(pImage, std::to_string(i))); } std::map mAnnots = m_pDocument->GetAnnots(); for (auto it = mAnnots.begin(); it != mAnnots.end(); it++) { PdfWriter::CAnnotation* pAnnot = it->second; if (pAnnot->GetAnnotationType() != PdfWriter::AnnotWidget) continue; PdfWriter::CWidgetAnnotation* pWidget = (PdfWriter::CWidgetAnnotation*)pAnnot; if (pWidget->GetWidgetType() != PdfWriter::WidgetPushbutton) continue; PdfWriter::CPushButtonWidget* pPBWidget = (PdfWriter::CPushButtonWidget*)pAnnot; if (pPBWidget->m_nI >= 0) DrawButtonWidget(pAppFonts, pPBWidget, 0, arrForm[pPBWidget->m_nI]); if (pPBWidget->m_nRI >= 0) DrawButtonWidget(pAppFonts, pPBWidget, 1, arrForm[pPBWidget->m_nRI]); else if (pPBWidget->m_nI >= 0) { PdfWriter::CDictObject* pObj = dynamic_cast(pPBWidget->Get("AP")); if (pObj && pObj->Get("R")) { pObj = dynamic_cast(pPBWidget->Get("MK")); if (pObj && !pObj->Get("RI")) DrawButtonWidget(pAppFonts, pPBWidget, 1, arrForm[pPBWidget->m_nI]); } } if (pPBWidget->m_nIX >= 0) DrawButtonWidget(pAppFonts, pPBWidget, 2, arrForm[pPBWidget->m_nIX]); else if (pPBWidget->m_nI >= 0) { PdfWriter::CDictObject* pObj = dynamic_cast(pPBWidget->Get("AP")); if (pObj && pObj->Get("D")) { pObj = dynamic_cast(pPBWidget->Get("MK")); if (pObj && !pObj->Get("IX")) DrawButtonWidget(pAppFonts, pPBWidget, 2, arrForm[pPBWidget->m_nI]); } } if (!pPBWidget->Get("AP") && !m_bSplit) DrawButtonWidget(pAppFonts, pPBWidget, 0, NULL); } std::map mParents = m_pDocument->GetParents(); for (auto it = mParents.begin(); it != mParents.end(); it++) { PdfWriter::CDictObject* pP = it->second; PdfWriter::CObjectBase* pParentOfParent = pP->Get("Parent"); if (!pParentOfParent || pParentOfParent->GetType() != PdfWriter::object_type_DICT) continue; PdfWriter::CDictObject* pParent = (PdfWriter::CDictObject*)pParentOfParent; PdfWriter::CArrayObject* pKids = dynamic_cast(pParent->Get("Kids")); if (!pKids) { pKids = new PdfWriter::CArrayObject(); pParent->Add("Kids", pKids); } bool bReplase = false; int nID = pP->GetObjId(); if (nID > 0) { for (int i = 0; i < pKids->GetCount(); ++i) { PdfWriter::CObjectBase* pKid = pKids->Get(i); if (pKid->GetObjId() == nID) { pKids->Insert(pKid, pP, true); bReplase = true; break; } } } if (!bReplase) pKids->Add(pP); } return S_OK; } PdfWriter::CDocument* CPdfWriter::GetDocument() { return m_pDocument; } PdfWriter::CPage* CPdfWriter::GetPage() { return m_pPage; } IRenderer* CPdfWriter::GetRenderer() { return m_pRenderer; } void CPdfWriter::SetPage(PdfWriter::CPage* pPage) { if (!IsValid()) return; m_oCommandManager.Flush(); m_pPage = pPage; } 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::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) { PdfWriter::CImageDict* pImage = NULL; if (!wsPicturePath.empty()) { Aggplus::CImage oImage(wsPicturePath); pImage = LoadImage(&oImage, 255); } m_pDocument->Sign(PdfWriter::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); } //---------------------------------------------------------------------------------------- // Внутренние функции //---------------------------------------------------------------------------------------- bool CPdfWriter::SkipRedact(const double& dX, const double& dY, const double& dW, const double& dH) { if (m_arrRedact.empty()) return false; double dXmin = MM_2_PT(dX), dYmin = MM_2_PT(m_dPageHeight - dY - dH), dXmax = MM_2_PT(dX + dW), dYmax = MM_2_PT(m_dPageHeight - dY); CTransform& t = m_oTransform; CTransform oT; oT.Set(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)); double dX1, dY1, dX2, dY2, dX3, dY3, dX4, dY4; dX1 = dXmin, dY1 = dYmin; dX2 = dXmin, dY2 = dYmax; dX3 = dXmax, dY3 = dYmax; dX4 = dXmax, dY4 = dYmin; oT.Transform(dX1, dY1, &dX1, &dY1); oT.Transform(dX2, dY2, &dX2, &dY2); oT.Transform(dX3, dY3, &dX3, &dY3); oT.Transform(dX4, dY4, &dX4, &dY4); std::vector poly2 = { PdfWriter::CPoint(dX1, dY1), PdfWriter::CPoint(dX2, dY2), PdfWriter::CPoint(dX3, dY3), PdfWriter::CPoint(dX4, dY4) }; for (int i = 0; i < m_arrRedact.size(); i += 8) { std::vector poly1 = { PdfWriter::CPoint(m_arrRedact[i + 0], m_arrRedact[i + 1]), PdfWriter::CPoint(m_arrRedact[i + 2], m_arrRedact[i + 3]), PdfWriter::CPoint(m_arrRedact[i + 4], m_arrRedact[i + 5]), PdfWriter::CPoint(m_arrRedact[i + 6], m_arrRedact[i + 7]) }; if (PdfWriter::SAT(poly1, poly2)) return true; } return false; } bool CPdfWriter::SkipRedact(const double& dX, const double& dY) { if (m_arrRedact.empty()) return false; double dXc = MM_2_PT(dX), dYc = MM_2_PT(m_dPageHeight - dY); CTransform& t = m_oTransform; CTransform oT; oT.Set(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)); oT.Transform(dXc, dYc, &dXc, &dYc); for (int i = 0; i < m_arrRedact.size(); i += 8) { double x1 = m_arrRedact[i + 0]; double y1 = m_arrRedact[i + 1]; double x2 = m_arrRedact[i + 2]; double y2 = m_arrRedact[i + 3]; double x3 = m_arrRedact[i + 4]; double y3 = m_arrRedact[i + 5]; double x4 = m_arrRedact[i + 6]; double y4 = m_arrRedact[i + 7]; if (PdfWriter::isPointInQuad(dXc, dYc, x1, y1, x2, y2, x3, y3, x4, y4)) return true; } return false; } PdfWriter::CImageDict* CPdfWriter::LoadImage(Aggplus::CImage* pImage, BYTE nAlpha) { TColor oColor; 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; PdfWriter::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; } PdfWriter::CImageDict* CPdfWriter::DrawImage(Aggplus::CImage* pImage, const double& dX, const double& dY, const double& dW, const double& dH, const BYTE& nAlpha) { PdfWriter::CImageDict* pPdfImage = LoadImage(pImage, nAlpha); if (!pPdfImage) return NULL; 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 pPdfImage; } bool CPdfWriter::DrawText(unsigned char* pCodes, const unsigned int& unLen, const double& dX, const double& dY, const std::string& sPUA) { if (!pCodes || !unLen) return false; // TODO должна быть проверка центрального положения, а не точки начала // TODO Сюда приходит много символов за раз, и нужно отрисовать только те, что вне областей редакта if (SkipRedact(dX, dY)) return true; 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)); PdfWriter::CFontDict* pFont = m_pFont; if (m_pFont14) pFont = m_pFont14; pText->SetFont(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()); pText->SetPUA(sPUA); return true; } bool CPdfWriter::DrawTextToRenderer(const unsigned int* unGid, const unsigned int& unLen, const double& dX, const double& dY, const std::wstring& wsUnicodeText) { if (m_bSplit) return false; // TODO должна быть проверка центрального положения, а не точки начала // TODO Сюда приходит много символов за раз, и нужно отрисовать только те, что вне областей редакта if (SkipRedact(dX, dY)) return true; // TODO pdf позволяет создание своего шрифта, но не следует это использовать для воссоздания шрифта запрещенного для редактирования или встраивания Aggplus::CGraphicsPathSimpleConverter simplifier; simplifier.SetRenderer(m_pRenderer); m_pFontManager->LoadFontByName(m_oFont.GetName(), m_oFont.GetSize(), (int)m_oFont.GetStyle(), 72.0, 72.0); PathCommandEnd(); if (simplifier.PathCommandText2(wsUnicodeText, (const int*)unGid, unLen, m_pFontManager, dX, dY, 0, 0)) { DrawPath(NULL, L"", c_nWindingFillMode, true); PathCommandEnd(); return true; } return false; } bool CPdfWriter::PathCommandDrawText(unsigned int* pUnicodes, unsigned int unLen, const double& dX, const double& dY, const unsigned int* pGids) { // TODO должна быть проверка центрального положения, а не точки начала // TODO Сюда приходит много символов за раз, и нужно отрисовать только те, что вне областей редакта if (SkipRedact(dX, dY)) return true; 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; } int CPdfWriter::IsEmbeddedBase14(const std::wstring& wsName) { if (wsName.find(L"Embedded: ") != 0) return -1; std::wstring sSub = wsName.substr(10); if (sSub == L"Helvetica") return 0; if (sSub == L"Helvetica-Bold") return 1; if (sSub == L"Helvetica-Oblique") return 2; if (sSub == L"Helvetice-BoldOblique") return 3; if (sSub == L"Courier") return 4; if (sSub == L"Courier-Bold") return 5; if (sSub == L"Courier-Oblique") return 6; if (sSub == L"Courier-BoldOblique") return 7; if (sSub == L"Times" || sSub == L"Times-Roman") return 8; if (sSub == L"Times-Bold") return 9; if (sSub == L"Times-Oblique") return 10; if (sSub == L"Times-BoldOblique") return 11; if (sSub == L"Symbol") return 12; if (sSub == L"ZapfDingbats") return 13; return -1; } bool CPdfWriter::GetBaseFont14(const std::wstring& wsFontName, int nBase14) { std::wstring wsFontPath = m_oFont.GetPath(); LONG lFaceIndex = m_oFont.GetFaceIndex(); if (!FindFontPath(wsFontName, m_oFont.IsBold(), m_oFont.IsItalic(), wsFontPath, lFaceIndex)) { std::wstring sSub = wsFontName.substr(10); const BYTE* pData14 = NULL; unsigned int nSize14 = 0; PdfReader::GetBaseFont(sSub, pData14, nSize14); NSFonts::IFontsMemoryStorage* pMemoryStorage = NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage(); if (pMemoryStorage) { if (!pMemoryStorage->Get(sSub)) pMemoryStorage->Add(sSub, (BYTE*)pData14, nSize14); AddFont(wsFontName, false, false, sSub, 0); } else { std::wstring wsTempFileName = m_wsTempDirectory + L"/" + sSub + L".base"; if (NSFile::CFileBinary::Exists(wsTempFileName)) wsFontPath = wsTempFileName; else { NSFile::CFileBinary oFile; if (oFile.CreateFileW(wsTempFileName)) { oFile.WriteFile((BYTE*)pData14, nSize14); wsFontPath = wsTempFileName; } oFile.CloseFile(); } AddFont(wsFontName, false, false, wsFontPath, 0); } if (!FindFontPath(wsFontName, m_oFont.IsBold(), m_oFont.IsItalic(), wsFontPath, lFaceIndex)) return false; } if (m_bSplit) return false; if (!m_pFontManager->LoadFontFromFile(wsFontPath, lFaceIndex, m_oFont.GetSize(), 72, 72)) return false; PdfWriter::EStandard14Fonts nType = (PdfWriter::EStandard14Fonts)nBase14; m_pFont14 = m_pDocument->CreateFont14(wsFontPath, lFaceIndex, nType); return !!m_pFont14; } bool CPdfWriter::UpdateFont() { m_bNeedUpdateTextFont = false; m_pFont14 = NULL; std::wstring wsFontPath = m_oFont.GetPath(); LONG lFaceIndex = m_oFont.GetFaceIndex(); if (L"" == wsFontPath) { std::wstring wsFontName = m_oFont.GetName(); int nBase14 = IsEmbeddedBase14(wsFontName); if (nBase14 >= 0 && GetBaseFont14(wsFontName, nBase14)) { m_pFont = NULL; return true; } if (!GetFontPath(wsFontName, m_oFont.IsBold(), m_oFont.IsItalic(), wsFontPath, lFaceIndex)) { m_pFont = NULL; return false; } } m_pFont = NULL; m_oFont.SetNeedDoBold(false); m_oFont.SetNeedDoItalic(false); 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); } else return false; } return true; } void CPdfWriter::AddFont(const std::wstring& wsFontName, const bool& bBold, const bool& bItalic, const std::wstring& wsFontPath, const LONG& lFaceIndex) { std::wstring _wsFontPath; LONG _lFaceIndex; if (FindFontPath(wsFontName, bBold, bItalic, _wsFontPath, _lFaceIndex)) return; m_vFonts.push_back(TFontInfo(wsFontName, bBold, bItalic, wsFontPath, lFaceIndex)); } bool CPdfWriter::FindFontPath(const std::wstring& wsFontName, const bool& bBold, const bool& bItalic, std::wstring& wsFontPath, LONG& lFaceIndex) { 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; return true; } } return false; } bool CPdfWriter::GetFontPath(const std::wstring &wsFontName, const bool &bBold, const bool &bItalic, std::wstring& wsFontPath, LONG& lFaceIndex) { bool bFind = FindFontPath(wsFontName, bBold, bItalic, wsFontPath, lFaceIndex); if (!bFind) { if (m_bSplit) return false; 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)) { return false; 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)); } return true; } 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; if (m_bSplit) 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); } bool CPdfWriter::GetFontData(NSFonts::IApplicationFonts* pAppFonts, const std::wstring& wsValue, PdfWriter::CFontCidTrueType* pFont, bool bBold, bool bItalic, unsigned int*& pUnicodes, unsigned int& unLen, unsigned short*& pCodes, PdfWriter::CFontCidTrueType**& ppFonts) { pUnicodes = NSStringExt::CConverter::GetUtf32FromUnicode(wsValue, unLen); if (!pUnicodes) return false; pCodes = new unsigned short[unLen]; if (!pCodes) { RELEASEARRAYOBJECTS(pUnicodes); return false; } ppFonts = new PdfWriter::CFontCidTrueType*[unLen]; if (!ppFonts) { RELEASEARRAYOBJECTS(pUnicodes); RELEASEARRAYOBJECTS(pCodes); return false; } for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex) { unsigned int unUnicode = pUnicodes[unIndex]; if (!pFont->HaveChar(unUnicode)) { std::wstring wsFontFamily = pAppFonts->GetFontBySymbol(unUnicode); PdfWriter::CFontCidTrueType* pTempFont = GetFont(wsFontFamily, bBold, bItalic); if (pTempFont) { pCodes[unIndex] = pTempFont->EncodeUnicode(unUnicode); ppFonts[unIndex] = pTempFont; continue; } } pCodes[unIndex] = pFont->EncodeUnicode(unUnicode); ppFonts[unIndex] = pFont; } return true; } 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(PdfWriter::linecap_Round); else if (Aggplus::LineCapSquare == lCapStyle) m_pPage->SetLineCap(PdfWriter::linecap_ProjectingSquare); else m_pPage->SetLineCap(PdfWriter::linecap_Butt); LONG lJoinStyle = m_oPen.GetJoinStyle(); if (Aggplus::LineJoinBevel == lJoinStyle) m_pPage->SetLineJoin(PdfWriter::linejoin_Bevel); else if (Aggplus::LineJoinMiter == lJoinStyle) { m_pPage->SetLineJoin(PdfWriter::linejoin_Miter); m_pPage->SetMiterLimit(MM_2_PT(m_oPen.GetMiter())); } else m_pPage->SetLineJoin(PdfWriter::linejoin_Round); } void CPdfWriter::UpdateBrush(NSFonts::IApplicationFonts* pAppFonts, const std::wstring& wsTempDirectory) { m_pShading = NULL; m_pShadingExtGrState = NULL; LONG lBrushType = m_oBrush.GetType(); if (c_BrushTypeTexture == lBrushType) { std::wstring wsTexturePath = m_oBrush.GetTexturePath(); BYTE nAlpha = m_oBrush.GetTextureAlpha(); CImageFileFormatChecker oImageFormat(wsTexturePath); PdfWriter::CImageDict* pImage = NULL; int nImageW = 0; int nImageH = 0; bool bHasImage = false; if (m_pDocument->HasImage(wsTexturePath, nAlpha)) { pImage = m_pDocument->GetImage(wsTexturePath, nAlpha); nImageH = pImage->GetHeight(); nImageW = pImage->GetWidth(); bHasImage = true; } else 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); m_pDocument->AddImage(wsTexturePath, nAlpha, pImage); } } 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(pAppFonts); pMeta->LoadFromFile(wsTexturePath.c_str()); double dL, dR, dT, dB; m_oPath.GetBounds(dL, dT, dR, dB); double dW = 300.0 * (dR - dL) / 72; if (dW < 0) dW = -dW; double dH = 300.0 * (dB - dT) / 72; if (dH < 0) dH = -dH; if (dW < 1) dW = 1; if (dH < 1) dH = 1; double dMax = 2000; double dMin = 10; if (dW > dMax || dH > dMax) { double dMaxSrc = (dW > dH) ? dW : dH; dW *= (dMax / dMaxSrc); dH *= (dMax / dMaxSrc); } if (dW < dMin) dW = dMin; if (dH < dMin) dH = dMin; std::wstring wsTempFile = GetTempFile(wsTempDirectory); pMeta->ConvertToRaster(wsTempFile.c_str(), _CXIMAGE_FORMAT_PNG, (int)dW, (int)dH); RELEASEOBJECT(pMeta); Aggplus::CImage oImage(wsTempFile); nImageW = abs((int)oImage.GetWidth()); nImageH = abs((int)oImage.GetHeight()); pImage = LoadImage(&oImage, 255); m_pDocument->AddImage(wsTexturePath, nAlpha, pImage); } else { Aggplus::CImage oImage(wsTexturePath); nImageW = abs((int)oImage.GetWidth()); nImageH = abs((int)oImage.GetHeight()); pImage = LoadImage(&oImage, 255); m_pDocument->AddImage(wsTexturePath, nAlpha, pImage); } if (pImage) { if (0xFF != nAlpha && !bHasImage) 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 = (double)nImageW * 72.0 / 96.0; dH = (double)nImageH * 72.0 / 96.0; dT = dB; } // Нам нужно, чтобы левый нижний угол границ нашего пата являлся точкой переноса для матрицы преобразования. PdfWriter::CMatrix* pMatrix = m_pPage->GetTransform(); pMatrix->Apply(dL, dT); PdfWriter::CMatrix oPatternMatrix = *pMatrix; oPatternMatrix.x = dL; oPatternMatrix.y = dT; m_pPage->SetPatternColorSpace(m_pDocument->CreateImageTilePattern(dW, dH, pImage, &oPatternMatrix, PdfWriter::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; } 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) { PdfWriter::CPage* pDestPage = m_pDocument->GetPage(unDestPage); if (!pPage || !pDestPage) return; PdfWriter::CDestination* pDestination = m_pDocument->CreateDestination(pDestPage); if (!pDestination) return; pDestination->SetXYZ(MM_2_PT(dDestX), pDestPage->GetHeight() - MM_2_PT(dDestY), 0); PdfWriter::CAnnotation* pAnnot = m_pDocument->CreateLinkAnnot(PdfWriter::TRect(MM_2_PT(dX), pPage->GetHeight() - MM_2_PT(dY), MM_2_PT(dX + dW), pPage->GetHeight() - MM_2_PT(dY + dH)), pDestination); if (pAnnot && pPage) pPage->AddAnnotation(pAnnot); pAnnot->SetBorder(0, 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) { if (!UpdateFont()) return NULL; } if (m_pFont14) { unsigned char* pCodes = new unsigned char[unCount * 2]; if (!pCodes) return NULL; for (unsigned int unIndex = 0; unIndex < unCount; unIndex++) { bool bNew = false; if (pGIDs) m_pFont14->EncodeUnicode(pGIDs[unIndex], pUnicodes[unIndex], bNew); if (bNew) { TBBoxAdvance oBox = m_pFontManager->MeasureChar2(*pUnicodes); double dWidth = oBox.fAdvanceX / m_oFont.GetSize() * 1000.0; m_pFont14->AddWidth(dWidth); } pCodes[2 * unIndex + 0] = (pUnicodes[unIndex] >> 8) & 0xFF; pCodes[2 * unIndex + 1] = pUnicodes[unIndex] & 0xFF; } return pCodes; } 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]); if (ushCode == 0) { RELEASEARRAYOBJECTS(pCodes); return NULL; } 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) { if (!UpdateFont()) return NULL; } if (m_pFont14) { bool bNew = false; m_pFont14->EncodeUnicode(unGID, *pUnicodes, bNew); if (bNew) { TBBoxAdvance oBox = m_pFontManager->MeasureChar2(*pUnicodes); double dWidth = oBox.fAdvanceX / m_oFont.GetSize() * 1000.0; m_pFont14->AddWidth(dWidth); } unsigned char* pCodes = new unsigned char[2]; pCodes[0] = (*pUnicodes >> 8) & 0xFF; pCodes[1] = *pUnicodes & 0xFF; return pCodes; } 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); if (ushCode == 0) { RELEASEARRAYOBJECTS(pCodes); return NULL; } pCodes[0] = (ushCode >> 8) & 0xFF; pCodes[1] = ushCode & 0xFF; return pCodes; } std::wstring CPdfWriter::GetDownloadFile(const std::wstring& sUrl, const std::wstring& wsTempDirectory) { 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 n5 = sUrl.find(L"file://"); 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; else if (n5 != std::wstring::npos && n5 < nMax) bIsNeedDownload = true; if (!bIsNeedDownload) return L""; #ifndef BUILDING_WASM_MODULE std::wstring sTempFile = GetTempFile(wsTempDirectory); NSNetwork::NSFileTransport::CFileDownloader oDownloader(sUrl, false); oDownloader.SetFilePath(sTempFile); if (oDownloader.DownloadSync()) return sTempFile; if (NSFile::CFileBinary::Exists(sTempFile)) NSFile::CFileBinary::Remove(sTempFile); #endif return L""; } PdfWriter::CAnnotAppearanceObject* CPdfWriter::DrawAP(PdfWriter::CAnnotation* pAnnot, BYTE* pRender, LONG nLenRender) { if (!pAnnot || !pRender) return NULL; PdfWriter::CPage* pCurPage = m_pPage; PdfWriter::CPage* pFakePage = new PdfWriter::CPage(m_pDocument); m_pPage = pFakePage; m_pDocument->SetCurPage(pFakePage); m_pPage->StartTransform(1, 0, 0, 1, -pAnnot->GetPageX(), pAnnot->GetPageY()); PdfWriter::CAnnotAppearanceObject* pAP = pAnnot->StartAP(0); pFakePage->SetStream(pAP->GetStream()); pFakePage->Add("Resources", pAP->Get("Resources")); IMetafileToRenderter* pCorrector = new IMetafileToRenderter(m_pRenderer); NSOnlineOfficeBinToPdf::ConvertBufferToRenderer(pRender, nLenRender, pCorrector); RELEASEOBJECT(pCorrector); pAnnot->APFromFakePage(); m_pPage = pCurPage; m_pDocument->SetCurPage(pCurPage); RELEASEOBJECT(pFakePage); return pAP; } void CPdfWriter::DrawWidgetAP(PdfWriter::CAnnotation* pA, BYTE* pRender, LONG nLenRender, int nRotate, bool bDiff) { if (!pA || !pRender) return; PdfWriter::CWidgetAnnotation* pAnnot = (PdfWriter::CWidgetAnnotation*)pA; PdfWriter::CPage* pCurPage = m_pPage; PdfWriter::CPage* pFakePage = new PdfWriter::CPage(m_pDocument); m_pPage = pFakePage; m_pDocument->SetCurPage(pFakePage); double dY = pAnnot->GetRect().fBottom; if (nRotate == 90 || nRotate == 270) { double dW = pAnnot->GetWidth(); double dH = pAnnot->GetHeight(); double dDiff = dW / 2.0 - dH / 2.0; if (!bDiff) dDiff *= 2.0; dY -= dDiff; } m_oTransform.Set(1, 0, 0, 1, PT_2_MM(-pAnnot->GetPageX() - pAnnot->GetRect().fLeft), PT_2_MM(dY)); PdfWriter::CAnnotAppearanceObject* pAP = pAnnot->StartAP(nRotate); pFakePage->SetStream(pAP->GetStream()); pFakePage->Add("Resources", pAP->Get("Resources")); pFakePage->SetStrokeColor(0, 0, 0); pFakePage->SetFillColor(0, 0, 0); IMetafileToRenderter* pCorrector = new IMetafileToRenderter(m_pRenderer); NSOnlineOfficeBinToPdf::ConvertBufferToRenderer(pRender, nLenRender, pCorrector); RELEASEOBJECT(pCorrector); m_oCommandManager.Flush(); pAP->EndDraw(); pFakePage->EndMarkedContent(); m_pPage = pCurPage; m_pDocument->SetCurPage(pCurPage); RELEASEOBJECT(pFakePage); } void CPdfWriter::DrawTextWidget(NSFonts::IApplicationFonts* pAppFonts, PdfWriter::CTextWidget* pTextWidget, const std::wstring& wsValue) { if (!pAppFonts || !pTextWidget) return; PdfWriter::CFontCidTrueType* pFont = pTextWidget->GetFont(); if (!pFont) return; PdfWriter::CFontTrueType* pFontTT = m_pDocument->CreateTrueTypeFont(pFont); double dFontSize = pTextWidget->GetFontSize(); bool isBold = pTextWidget->GetFontIsBold(); bool isItalic = pTextWidget->GetFontIsItalic(); bool isComb = pTextWidget->IsCombFlag(); double dWidth = pTextWidget->GetWidth(); double dHeight = pTextWidget->GetHeight(); BYTE nAlign = pTextWidget->GetQ(); if (!pTextWidget->HaveBorder() && pTextWidget->HaveBC()) pTextWidget->SetBorder(0, 1, {}); double dShiftBorder = pTextWidget->GetBorderWidth(); PdfWriter::EBorderType nType = pTextWidget->GetBorderType(); if (nType == PdfWriter::EBorderType::Beveled || nType == PdfWriter::EBorderType::Inset) dShiftBorder *= 2; // Коды, шрифты, количество unsigned int unLen = 0; unsigned int* pUnicodes = NULL; unsigned short* pCodes = NULL; PdfWriter::CFontCidTrueType** ppFonts = NULL; bool bFont = GetFontData(pAppFonts, wsValue, pFont, isBold, isItalic, pUnicodes, unLen, pCodes, ppFonts); if (!bFont) { pTextWidget->SetEmptyAP(); RELEASEARRAYOBJECTS(pUnicodes); RELEASEARRAYOBJECTS(pCodes); RELEASEARRAYOBJECTS(ppFonts); return; } if (!isComb && pTextWidget->IsMultiLine() && pFontTT) { unsigned short* pCodes2 = new unsigned short[unLen]; unsigned int* pWidths = new unsigned int[unLen]; unsigned short ushSpaceCode = 0xFFFF; unsigned short ushNewLineCode = 0xFFFE; for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex) { unsigned short ushCode = 0; if (0x0020 == pUnicodes[unIndex]) ushCode = ushSpaceCode; else if (0x000D == pUnicodes[unIndex] || 0x000A == pUnicodes[unIndex]) ushCode = ushNewLineCode; pCodes2[unIndex] = ushCode; pWidths[unIndex] = ppFonts[unIndex]->GetWidth(pCodes[unIndex]); } m_oLinesManager.Init(pCodes2, pWidths, unLen, ushSpaceCode, ushNewLineCode, pFontTT->GetLineHeight(), pFontTT->GetAscent()); double dKoef = dFontSize / pFontTT->m_dUnitsPerEm; double dLineHeight = (pFontTT->m_dAscent + std::abs(pFontTT->m_dDescent)) * dKoef; m_oLinesManager.CalculateLines(dFontSize, dWidth - dShiftBorder * 4); pTextWidget->StartAP(0); unsigned int unLinesCount = m_oLinesManager.GetLinesCount(); double dLineShiftY = dHeight - dShiftBorder * 2 - dLineHeight; for (unsigned int unIndex = 0; unIndex < unLinesCount; ++unIndex) { unsigned int unLineStart = m_oLinesManager.GetLineStartPos(unIndex); double dLineShiftX = dShiftBorder * 2; double dLineWidth = m_oLinesManager.GetLineWidth(unIndex, dFontSize); if (2 == nAlign) dLineShiftX = dWidth - dLineWidth - dShiftBorder * 2; else if (1 == nAlign) dLineShiftX = (dWidth - dLineWidth) / 2; int nInLineCount = m_oLinesManager.GetLineEndPos(unIndex) - m_oLinesManager.GetLineStartPos(unIndex); if (nInLineCount > 0) pTextWidget->AddLineToAP(dLineShiftX, dLineShiftY, pCodes + unLineStart, nInLineCount, ppFonts + unLineStart, NULL); dLineShiftY -= dLineHeight; } pTextWidget->EndAP(); m_oLinesManager.Clear(); RELEASEARRAYOBJECTS(pCodes2); RELEASEARRAYOBJECTS(pWidths); } else { double* pShifts = NULL; unsigned int unShiftsCount = 0; double dShiftX = dShiftBorder * 2; if (dShiftX == 0) dShiftX = 2; if (isComb) { unShiftsCount = unLen; pShifts = new double[unShiftsCount]; if (pShifts && unShiftsCount) { dShiftX = 0; unsigned int unCellsCount = std::max(unShiftsCount, pTextWidget->GetMaxLen()); double dPrevW = 0; double dCellW = dWidth / unCellsCount; if (1 == nAlign) { unsigned int unCells = (unCellsCount - unShiftsCount) / 2; dPrevW = unCells * dCellW; } if (2 == nAlign) 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 if (1 == nAlign || 2 == nAlign) { double dLineWidth = 0; for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex) { unsigned short ushCode = pCodes[unIndex]; double dLetterWidth = ppFonts[unIndex]->GetWidth(ushCode) / 1000.0 * dFontSize; dLineWidth += dLetterWidth; } if (2 == nAlign) dShiftX = dWidth - dLineWidth - dShiftBorder * 2; else if (1 == nAlign) dShiftX = (dWidth - dLineWidth) / 2; } double dBaseLine = (dHeight - dFontSize) / 2.0 - dShiftBorder; if (pFontTT) { double dKoef = dFontSize / pFontTT->m_dUnitsPerEm; double dLineHeight = (pFontTT->m_dAscent + std::abs(pFontTT->m_dDescent)) * dKoef;; dBaseLine = (dHeight - dLineHeight) / 2.0 + std::abs(pFontTT->m_dDescent * dKoef); } pTextWidget->SetAP(wsValue, pCodes, unLen, dShiftX, dBaseLine, ppFonts, pShifts); RELEASEARRAYOBJECTS(pShifts); } RELEASEARRAYOBJECTS(pUnicodes); RELEASEARRAYOBJECTS(pCodes); RELEASEARRAYOBJECTS(ppFonts); } void CPdfWriter::DrawChoiceWidget(NSFonts::IApplicationFonts* pAppFonts, PdfWriter::CChoiceWidget* pChoiceWidget, const std::vector& arrValue) { if (!pAppFonts || !pChoiceWidget) return; PdfWriter::CFontCidTrueType* pFont = pChoiceWidget->GetFont(); if (!pFont) return; PdfWriter::CFontTrueType* pFontTT = m_pDocument->CreateTrueTypeFont(pFont); if (!pFontTT) return; double dFontSize = pChoiceWidget->GetFontSize(); bool isBold = pChoiceWidget->GetFontIsBold(); bool isItalic = pChoiceWidget->GetFontIsItalic(); double dWidth = pChoiceWidget->GetWidth(); double dHeight = pChoiceWidget->GetHeight(); BYTE nAlign = pChoiceWidget->GetQ(); if (!pChoiceWidget->HaveBorder() && pChoiceWidget->HaveBC()) pChoiceWidget->SetBorder(0, 1, {}); double dShiftBorder = pChoiceWidget->GetBorderWidth(); PdfWriter::EBorderType nType = pChoiceWidget->GetBorderType(); if (nType == PdfWriter::EBorderType::Beveled || nType == PdfWriter::EBorderType::Inset) dShiftBorder *= 2; if (arrValue.empty()) { pChoiceWidget->SetEmptyAP(); return; } if (pChoiceWidget->GetWidgetType() == PdfWriter::WidgetCombobox) { std::wstring wsValue = pChoiceWidget->GetValue(arrValue.back()); unsigned int unLen = 0; unsigned int* pUnicodes = NULL; unsigned short* pCodes = NULL; PdfWriter::CFontCidTrueType** ppFonts = NULL; bool bFont = GetFontData(pAppFonts, wsValue, pFont, isBold, isItalic, pUnicodes, unLen, pCodes, ppFonts); if (!bFont) { RELEASEARRAYOBJECTS(pUnicodes); RELEASEARRAYOBJECTS(pCodes); RELEASEARRAYOBJECTS(ppFonts); return; } double dShiftX = dShiftBorder * 2; if (dShiftX == 0) dShiftX = 2; if (1 == nAlign || 2 == nAlign) { 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 (2 == nAlign) dShiftX = dWidth - dSumWidth - dShiftBorder * 2; else if (1 == nAlign) dShiftX = (dWidth - dSumWidth) / 2; } double dBaseLine = (dHeight - dFontSize) / 2.0 - dShiftBorder; if (pFontTT) dBaseLine = (dHeight - pFontTT->m_dHeight * dFontSize / pFontTT->m_dUnitsPerEm) / 2.0 + std::abs(pFontTT->m_dDescent * dFontSize / pFontTT->m_dUnitsPerEm); pChoiceWidget->SetAP(wsValue, pCodes, unLen, dShiftX, dBaseLine, ppFonts, NULL); RELEASEARRAYOBJECTS(pUnicodes); RELEASEARRAYOBJECTS(pCodes); RELEASEARRAYOBJECTS(ppFonts); } else // ListBox { std::wstring wsValue = pChoiceWidget->SetListBoxIndex(arrValue); unsigned int unLen = 0; unsigned int* pUnicodes = NULL; unsigned short* pCodes = NULL; PdfWriter::CFontCidTrueType** ppFonts = NULL; bool bFont = GetFontData(pAppFonts, wsValue, pFont, isBold, isItalic, pUnicodes, unLen, pCodes, ppFonts); if (!bFont) { RELEASEARRAYOBJECTS(pUnicodes); RELEASEARRAYOBJECTS(pCodes); RELEASEARRAYOBJECTS(ppFonts); return; } unsigned short* pCodes2 = new unsigned short[unLen]; unsigned int* pWidths = new unsigned int[unLen]; unsigned short ushSpaceCode = 0xFFFF; unsigned short ushNewLineCode = 0xFFFE; for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex) { unsigned short ushCode = 0; if (0x0020 == pUnicodes[unIndex]) ushCode = ushSpaceCode; else if (0x000D == pUnicodes[unIndex] || 0x000A == pUnicodes[unIndex]) ushCode = ushNewLineCode; pCodes2[unIndex] = ushCode; pWidths[unIndex] = ppFonts[unIndex]->GetWidth(pCodes[unIndex]); } m_oLinesManager.Init(pCodes2, pWidths, unLen, ushSpaceCode, ushNewLineCode, pFontTT->GetLineHeight(), pFontTT->GetAscent()); m_oLinesManager.CalculateLines(dFontSize, dWidth - dShiftBorder * 4); double dKoef = dFontSize / pFontTT->m_dUnitsPerEm; double dLineHeight = pFontTT->m_dHeight * dKoef; pChoiceWidget->SetListBoxHeight(dLineHeight); pChoiceWidget->StartAP(0); // double dKoef = dFontSize / pFontTT->m_dUnitsPerEm; // double dDescent = std::abs(pFontTT->m_dDescent * dFontSize / pFontTT->m_dUnitsPerEm); // double dAscent = dLineHeight - dDescent; // double dMidPoint = dAscent - pFontTT->m_dMinY * dKoef + dAscent - pFontTT->m_dMaxY * dKoef; // double dDiff = dLineHeight - dMidPoint; double dLineShiftY = dHeight - dShiftBorder - dLineHeight + std::abs(pFontTT->m_dDescent * dKoef); unsigned int unLinesCount = m_oLinesManager.GetLinesCount(); for (unsigned int unIndex = 0; unIndex < unLinesCount; ++unIndex) { unsigned int unLineStart = m_oLinesManager.GetLineStartPos(unIndex); double dLineShiftX = dShiftBorder * 2; if (dLineShiftX == 0) dLineShiftX = 2; double dLineWidth = m_oLinesManager.GetLineWidth(unIndex, dFontSize); if (2 == nAlign) dLineShiftX = dWidth - dLineWidth - dShiftBorder * 2; else if (1 == nAlign) dLineShiftX = (dWidth - dLineWidth) / 2; int nInLineCount = m_oLinesManager.GetLineEndPos(unIndex) - m_oLinesManager.GetLineStartPos(unIndex); if (nInLineCount > 0) pChoiceWidget->AddLineToAP(dLineShiftX, dLineShiftY, pCodes + unLineStart, nInLineCount, ppFonts + unLineStart, NULL); dLineShiftY -= dLineHeight; if (dLineShiftY < 0) break; } pChoiceWidget->EndAP(); m_oLinesManager.Clear(); RELEASEARRAYOBJECTS(pCodes2); RELEASEARRAYOBJECTS(pWidths); RELEASEARRAYOBJECTS(pUnicodes); RELEASEARRAYOBJECTS(pCodes); RELEASEARRAYOBJECTS(ppFonts); } } void CPdfWriter::DrawButtonWidget(NSFonts::IApplicationFonts* pAppFonts, PdfWriter::CPushButtonWidget* pButtonWidget, BYTE nAP, PdfWriter::CXObject* pForm) { if (!pAppFonts || !pButtonWidget) return; double dShiftX = 0; double dShiftY = 0; double dLineW = 0; double dLineH = 0; unsigned int unLen = 0; unsigned int* pUnicodes = NULL; unsigned short* pCodes = NULL; PdfWriter::CFontCidTrueType** ppFonts = NULL; BYTE nTP = pButtonWidget->GetTP(); std::wstring wsValue; if (nAP == 0) wsValue = pButtonWidget->GetCA(); else if (nAP == 1) wsValue = pButtonWidget->GetRC(); else wsValue = pButtonWidget->GetAC(); if (!pButtonWidget->HaveBorder() && pButtonWidget->HaveBC()) pButtonWidget->SetBorder(0, 1, {}); if (nTP != 1 && !pForm) nTP = 0; if (nTP != 1 && !m_bSplit) { PdfWriter::CFontCidTrueType* pFont = pButtonWidget->GetFont(); if (!pFont) return; PdfWriter::CFontTrueType* pFontTT = m_pDocument->CreateTrueTypeFont(pFont); double dFontSize = pButtonWidget->GetFontSize(); bool isBold = pButtonWidget->GetFontIsBold(); bool isItalic = pButtonWidget->GetFontIsItalic(); double dWidth = pButtonWidget->GetWidth(); double dHeight = pButtonWidget->GetHeight(); int nRotate = pButtonWidget->GetR(); if (nRotate == 90 || nRotate == 270) std::swap(dWidth, dHeight); double dShiftBorder = pButtonWidget->GetBorderWidth(); PdfWriter::EBorderType nType = pButtonWidget->GetBorderType(); if (nType == PdfWriter::EBorderType::Beveled || nType == PdfWriter::EBorderType::Inset) dShiftBorder *= 2; if (dShiftBorder == 0) dShiftBorder = 1; double dShiftRespectBorder = dShiftBorder / 2; bool bRespectBorder = pButtonWidget->GetRespectBorder(); if (!bRespectBorder) dShiftBorder = 0; bool bFont = GetFontData(pAppFonts, wsValue, pFont, isBold, isItalic, pUnicodes, unLen, pCodes, ppFonts); if (!wsValue.empty() && !bFont) { RELEASEARRAYOBJECTS(pUnicodes); RELEASEARRAYOBJECTS(pCodes); RELEASEARRAYOBJECTS(ppFonts); return; } for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex) { unsigned short ushCode = pCodes[unIndex]; double dLetterWidth = ppFonts[unIndex]->GetWidth(ushCode) / 1000.0 * dFontSize; dLineW += dLetterWidth; } if (pFontTT) { double dKoef = dFontSize / pFontTT->m_dUnitsPerEm; // TODO что-то между m_dMaxY-m_dMinY и m_dHeight, но не просто среднее dLineH = (pFontTT->m_dMaxY + std::abs(pFontTT->m_dMinY) + pFontTT->m_dHeight) / 2.0 * dKoef; // dLineH = (pFontTT->m_dMaxY + std::abs(pFontTT->m_dMinY)) * dKoef; // dLineH = pFontTT->m_dHeight * dKoef; // double dLineHeight = pFontTT->m_dHeight * dKoef; // double dDescent = std::abs(pFontTT->m_dDescent * dKoef); // double dAscent1 = pFontTT->m_dAscent * dKoef; // double dAscent = dLineHeight - dDescent; // double dMidPoint = dAscent - pFontTT->m_dMinY * dKoef + dAscent - pFontTT->m_dMaxY * dKoef; // double dDiff = dLineHeight - dMidPoint; if (nTP == 0 || nTP == 2 || nTP == 3 || nTP == 6) dShiftX = (dWidth - dLineW) / 2; else if (nTP == 4) dShiftX = dWidth - dLineW - dShiftBorder * 2 + dShiftRespectBorder; else if (nTP == 5) dShiftX = dShiftBorder * 2 + dShiftRespectBorder; if (nTP == 0 || nTP == 6 || nTP == 4 || nTP == 5) dShiftY = (dHeight - dLineH) / 2 + std::abs(pFontTT->m_dMinY * dKoef); else if (nTP == 3) dShiftY = dHeight - dShiftBorder * 2 - dShiftRespectBorder - dLineH + std::abs(pFontTT->m_dMinY * dKoef); else if (nTP == 2) dShiftY = dShiftBorder * 2 + std::abs(pFontTT->m_dMinY * dKoef); } } pButtonWidget->SetAP(pForm, nAP, pCodes, unLen, dShiftX, dShiftY, dLineW, dLineH, ppFonts, m_bSplit); RELEASEARRAYOBJECTS(pUnicodes); RELEASEARRAYOBJECTS(pCodes); RELEASEARRAYOBJECTS(ppFonts); }