You've already forked core
mirror of
https://github.com/ONLYOFFICE/core.git
synced 2025-09-17 22:42:14 +03:00
4427 lines
135 KiB
C++
4427 lines
135 KiB
C++
/*
|
||
* (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)
|
||
{
|
||
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_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_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)
|
||
{
|
||
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 (!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)
|
||
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())
|
||
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<PdfWriter::CFieldBase*>(pField);
|
||
}
|
||
else if (oInfo.IsDropDownList())
|
||
{
|
||
PdfWriter::CChoiceField* pField = m_pDocument->CreateChoiceField();
|
||
pFieldBase = static_cast<PdfWriter::CFieldBase*>(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<PdfWriter::CFieldBase*>(pField);
|
||
}
|
||
else if (oInfo.IsPicture())
|
||
{
|
||
PdfWriter::CPictureField* pField = m_pDocument->CreatePictureField();
|
||
pFieldBase = static_cast<PdfWriter::CFieldBase*>(pField);
|
||
}
|
||
else if (oInfo.IsDateTime())
|
||
{
|
||
PdfWriter::CDateTimeField* pField = m_pDocument->CreateDateTimeField();
|
||
pFieldBase = static_cast<PdfWriter::CFieldBase*>(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<PdfWriter::CTextField*>(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<PdfWriter::CChoiceField*>(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<PdfWriter::CCheckBoxField*>(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<PdfWriter::CPictureField*>(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<PdfWriter::CPictureField::EScaleType>(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<PdfWriter::CDateTimeField*>(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))
|
||
pAnnot->SetC(oInfo.GetC());
|
||
if (nFlags & (1 << 4))
|
||
{
|
||
BYTE nType;
|
||
double dWidth;
|
||
std::vector<double> 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());
|
||
bool bRenderCopy = (nFlags >> 8) & 1;
|
||
|
||
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"<?xml version=\"1.0\"?><body xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:xfa=\"http://www.xfa.org/schema/xfa-data/1.0/\" xfa:APIVersion=\"Acrobat:23.8.0\" xfa:spec=\"2.0.2\"><p dir=\"ltr\">";
|
||
std::vector<CAnnotFieldInfo::CMarkupAnnotPr::CFontData*> arrRC = pPr->GetRC();
|
||
|
||
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();
|
||
}
|
||
|
||
for (int i = 0; i < arrRC.size(); ++i)
|
||
{
|
||
oRC += L"<span style=\"";
|
||
GetRCSpanStyle(arrRC[i], oRC);
|
||
oRC += L"\">";
|
||
oRC.WriteEncodeXmlString(arrRC[i]->sText);
|
||
oRC += L"</span>";
|
||
}
|
||
oRC += L"</p></body>";
|
||
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());
|
||
|
||
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);
|
||
}
|
||
|
||
//pLineAnnot->SetAP();
|
||
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());
|
||
|
||
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());
|
||
|
||
// pMarkupAnnot->RemoveAP();
|
||
}
|
||
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);
|
||
}
|
||
else if (bRenderCopy)
|
||
{
|
||
int nID = oInfo.GetCopyAP();
|
||
PdfWriter::CAnnotation* pAnnot2 = m_pDocument->GetAnnot(nID);
|
||
if (pAnnot2->GetAnnotationType() == PdfWriter::EAnnotType::AnnotStamp)
|
||
{
|
||
PdfWriter::CStampAnnotation* pStampAnnot2 = (PdfWriter::CStampAnnotation*)pAnnot2;
|
||
PdfWriter::CDictObject* pAPN = (PdfWriter::CDictObject*)pStampAnnot2->GetAPStream();
|
||
pStampAnnot->SetAPStream(pAPN, true);
|
||
}
|
||
}
|
||
|
||
pStampAnnot->SetRotate(nRotate);
|
||
}
|
||
}
|
||
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 << 20))
|
||
pWidgetAnnot->SetOMetadata(pPr->GetOMetadata());
|
||
|
||
const std::vector<CAnnotFieldInfo::CWidgetAnnotPr::CActionWidget*> 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)
|
||
DrawButtonWidget(pAppFonts, pButtonWidget, 0, NULL);
|
||
}
|
||
if (nFlags & (1 << 11))
|
||
{
|
||
pButtonWidget->SetRC(pPr->GetRC());
|
||
if (nTP == 0)
|
||
DrawButtonWidget(pAppFonts, pButtonWidget, 1, NULL);
|
||
}
|
||
if (nFlags & (1 << 12))
|
||
{
|
||
pButtonWidget->SetAC(pPr->GetAC());
|
||
if (nTP == 0)
|
||
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();
|
||
|
||
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_pFont)
|
||
pFont = m_pDocument->CreateTrueTypeFont(m_pFont);
|
||
}
|
||
if (pFont)
|
||
pWidgetAnnot->SetDA(pFont, oInfo.GetWidgetAnnotPr()->GetFontSize(), dFontSize, oInfo.GetWidgetAnnotPr()->GetTC());
|
||
}
|
||
else if ((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<std::wstring> 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();
|
||
|
||
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_pFont)
|
||
pFont = m_pDocument->CreateTrueTypeFont(m_pFont);
|
||
}
|
||
if (pFont)
|
||
pWidgetAnnot->SetDA(pFont, oInfo.GetWidgetAnnotPr()->GetFontSize(), dFontSize, oInfo.GetWidgetAnnotPr()->GetTC());
|
||
}
|
||
else if (!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;
|
||
}
|
||
void CreateOutlines(PdfWriter::CDocument* m_pDocument, const std::vector<CHeadings::CHeading*>& 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)
|
||
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)
|
||
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<CWidgetsInfo::CParent*> 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<std::wstring> 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<PdfWriter::CArrayObject*>(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<PdfWriter::CChoiceWidget*>(pObj);
|
||
if (!pKid->HaveAPV())
|
||
DrawChoiceWidget(pAppFonts, pKid, pParent->arrV);
|
||
}
|
||
}
|
||
}
|
||
std::map<std::wstring, std::wstring> 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<std::wstring, std::wstring> 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<std::wstring, std::wstring> 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<PdfWriter::CCheckBoxWidget*>(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));
|
||
|
||
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<PdfWriter::CCheckBoxWidget*>(pObj);
|
||
if (!pKid)
|
||
continue;
|
||
if (pKid->NeedAP_N_Yes())
|
||
{
|
||
std::pair<std::wstring, std::wstring> PV = pParent->arrOpt[i];
|
||
std::wstring sOpt = PV.first.empty() ? PV.second : PV.first;
|
||
pKid->SetAP_N_Yes(mNameAP_N_Yes[sOpt]);
|
||
}
|
||
|
||
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<PdfWriter::CChoiceWidget*>(pObj);
|
||
if (!pKid->HaveAPV())
|
||
DrawChoiceWidget(pAppFonts, pKid, {pParent->sV});
|
||
}
|
||
else if (nType == PdfWriter::WidgetText)
|
||
{
|
||
PdfWriter::CTextWidget* pKid = dynamic_cast<PdfWriter::CTextWidget*>(pObj);
|
||
if (!pKid->HaveAPV())
|
||
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<CAnnotFieldInfo::CWidgetAnnotPr::CActionWidget*> 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);
|
||
}
|
||
|
||
std::vector<std::wstring> arrBI = pFieldInfo->GetButtonImg();
|
||
std::vector<PdfWriter::CXObject*> 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, GetTempFile(wsTempDirectory));
|
||
PdfWriter::CImageDict* pImage = LoadImage(pCImage, 255);
|
||
RELEASEOBJECT(pCImage);
|
||
|
||
arrForm.push_back(m_pDocument->CreateForm(pImage, std::to_string(i)));
|
||
}
|
||
|
||
std::map<int, PdfWriter::CAnnotation*> 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<PdfWriter::CDictObject*>(pPBWidget->Get("AP"));
|
||
if (pObj && pObj->Get("R"))
|
||
{
|
||
pObj = dynamic_cast<PdfWriter::CDictObject*>(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<PdfWriter::CDictObject*>(pPBWidget->Get("AP"));
|
||
if (pObj && pObj->Get("D"))
|
||
{
|
||
pObj = dynamic_cast<PdfWriter::CDictObject*>(pPBWidget->Get("MK"));
|
||
if (pObj && !pObj->Get("IX"))
|
||
DrawButtonWidget(pAppFonts, pPBWidget, 2, arrForm[pPBWidget->m_nI]);
|
||
}
|
||
}
|
||
|
||
if (!pPBWidget->Get("AP"))
|
||
DrawButtonWidget(pAppFonts, pPBWidget, 0, NULL);
|
||
}
|
||
|
||
std::map<int, PdfWriter::CDictObject*> 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<PdfWriter::CArrayObject*>(pParent->Get("Kids"));
|
||
if (!pKids)
|
||
{
|
||
pKids = new PdfWriter::CArrayObject();
|
||
pParent->Add("Kids", pKids);
|
||
}
|
||
|
||
bool bReplase = false;
|
||
int nID = pP->GetObjId();
|
||
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; }
|
||
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);
|
||
}
|
||
//----------------------------------------------------------------------------------------
|
||
// Внутренние функции
|
||
//----------------------------------------------------------------------------------------
|
||
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;
|
||
|
||
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)
|
||
{
|
||
// 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);
|
||
PathCommandEnd();
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
bool CPdfWriter::PathCommandDrawText(unsigned int* pUnicodes, unsigned int unLen, const double& dX, const double& dY, const unsigned int* pGids)
|
||
{
|
||
unsigned char* pCodes = EncodeString(pUnicodes, unLen, pGids);
|
||
if (!pCodes)
|
||
return false;
|
||
|
||
m_oPath.AddText(m_pFont, pCodes, unLen * 2, MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY), m_oFont.GetSize(), MM_2_PT(m_oFont.GetCharSpace()));
|
||
return true;
|
||
}
|
||
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_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)
|
||
{
|
||
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;
|
||
|
||
// 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<std::wstring>& 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)
|
||
{
|
||
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);
|
||
|
||
RELEASEARRAYOBJECTS(pUnicodes);
|
||
RELEASEARRAYOBJECTS(pCodes);
|
||
RELEASEARRAYOBJECTS(ppFonts);
|
||
}
|