1
0
mirror of https://github.com/ONLYOFFICE/core.git synced 2025-09-17 22:42:14 +03:00
Files
core/PdfFile/PdfWriter.cpp
Svetlana Kulikova 13e30bf918 Fix bug 75871
2025-07-14 12:54:33 +03:00

4427 lines
135 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* (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);
}