Files
core/PdfFile/Src/PdfWriter.cpp
2022-11-03 17:47:16 +03:00

2927 lines
84 KiB
C++
Raw 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-2019
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#include "../../DesktopEditor/common/File.h"
#include "../../DesktopEditor/common/Directory.h"
#include "PdfWriter.h"
#include "../../PdfWriter/Src/Document.h"
#include "../../PdfWriter/Src/Pages.h"
#include "../../PdfWriter/Src/Image.h"
#include "../../PdfWriter/Src/Font.h"
#include "../../PdfWriter/Src/FontCidTT.h"
#include "../../PdfWriter/Src/FontTT.h"
#include "../../PdfWriter/Src/Annotation.h"
#include "../../PdfWriter/Src/Destination.h"
#include "../../PdfWriter/Src/Field.h"
#include "../../DesktopEditor/graphics/Image.h"
#include "../../DesktopEditor/graphics/structures.h"
#include "../../DesktopEditor/raster/BgraFrame.h"
#include "../../DesktopEditor/raster/ImageFileFormatChecker.h"
#include "../../DesktopEditor/graphics/pro/Fonts.h"
#include "../../DesktopEditor/graphics/pro/Image.h"
#include "../../UnicodeConverter/UnicodeConverter.h"
#include "../../Common/Network/FileTransporter/include/FileTransporter.h"
#if defined(GetTempPath)
#undef GetTempPath
#endif
#if defined(CreateFile)
#undef CreateFile
#endif
#if defined(CreateDirectory)
#undef CreateDirectory
#endif
#define MM_2_PT(X) ((X) * 72.0 / 25.4)
#define PT_2_MM(X) ((X) * 25.4 / 72.0)
#define LONG_2_BOOL(X) ((X) ? true : false)
#ifdef DrawText
#undef DrawText
#endif
#ifdef LoadImage
#undef LoadImage
#endif
#define HI_SURROGATE_START 0xD800
#define HI_SURROGATE_END 0xDBFF
#define LO_SURROGATE_START 0xDC00
#define LO_SURROGATE_END 0xDFFF
using namespace PdfWriter;
static unsigned int* WStringToUtf32(const std::wstring& wsUnicodeText, unsigned int& unLen)
{
if (wsUnicodeText.size() <= 0)
return NULL;
unsigned int* pUnicodes = new unsigned int[wsUnicodeText.size()];
if (!pUnicodes)
return NULL;
unLen = 0;
if (2 == sizeof(wchar_t))
{
const wchar_t* wsEnd = wsUnicodeText.c_str() + wsUnicodeText.size();
wchar_t* wsInput = (wchar_t*)wsUnicodeText.c_str();
wchar_t wLeading, wTrailing;
unsigned int unCode;
while (wsInput < wsEnd)
{
wLeading = *wsInput++;
if (wLeading < 0xD800 || wLeading > 0xDFFF)
{
pUnicodes[unLen++] = (unsigned int)wLeading;
}
else if (wLeading >= 0xDC00)
{
// Такого не должно быть
continue;
}
else
{
unCode = (wLeading & 0x3FF) << 10;
wTrailing = *wsInput++;
if (wTrailing < 0xDC00 || wTrailing > 0xDFFF)
{
// Такого не должно быть
continue;
}
else
{
pUnicodes[unLen++] = ((unCode | (wTrailing & 0x3FF)) + 0x10000);
}
}
}
}
else
{
unLen = wsUnicodeText.size();
for (unsigned int unIndex = 0; unIndex < unLen; unIndex++)
{
pUnicodes[unIndex] = (unsigned int)wsUnicodeText.at(unIndex);
}
}
return pUnicodes;
}
// Этих типов браша нет в рендерере, мы их используем, когда конвертим из веба
static const long c_BrushTypeLinearGradient = 8001;
static const long c_BrushTypeRadialGradient = 8002;
enum ERendererCommandType
{
renderercommandtype_Text = 0x01,
renderercommandtype_Image = 0x02,
renderercommandtype_Path = 0x03,
renderercommandtype_Clip = 0x04
};
//----------------------------------------------------------------------------------------
//
// CRendererCommandBase
//
//----------------------------------------------------------------------------------------
class CRendererCommandBase
{
public:
virtual ~CRendererCommandBase(){};
virtual ERendererCommandType GetType() = 0;
};
//----------------------------------------------------------------------------------------
//
// CRendererTextCommand
//
//----------------------------------------------------------------------------------------
class CRendererTextCommand : public CRendererCommandBase
{
public:
CRendererTextCommand(unsigned char* pCodes, unsigned int nLen, const double& dX, const double& dY)
{
m_pCodes = pCodes;
m_nLen = nLen;
m_dX = dX;
m_dY = dY;
m_pFont = NULL;
m_dSize = -1;
m_lColor = 0;
m_nAlpha = 255;
m_dCharSpace = 0;
m_dHorScaling = 100;
m_nMode = (int)textrenderingmode_Fill;
m_bNeedDoItalic = false;
m_bNeedDoBold = false;
}
~CRendererTextCommand()
{
if (m_pCodes)
delete[] m_pCodes;
}
ERendererCommandType GetType()
{
return renderercommandtype_Text;
}
inline double GetX() const
{
return m_dX;
}
inline double GetY() const
{
return m_dY;
}
inline unsigned char* GetCodes() const
{
return m_pCodes;
}
inline unsigned int GetCodesLen() const
{
return m_nLen;
}
inline void SetFont(CFontDict* pFont)
{
m_pFont = pFont;
}
inline void SetSize(const double& dSize)
{
m_dSize = dSize;
}
inline void SetColor(const LONG& lColor)
{
m_lColor = lColor;
}
inline void SetAlpha(const BYTE& nAlpha)
{
m_nAlpha = nAlpha;
}
inline void SetCharSpace(const double& dCharSpace)
{
m_dCharSpace = dCharSpace;
}
inline void SetHorScaling(const double& dKoef)
{
m_dHorScaling = dKoef;
}
inline void SetMode(const int& nMode)
{
m_nMode = nMode;
}
inline void SetNeedDoItalic(const bool& bItalic)
{
m_bNeedDoItalic = bItalic;
}
inline void SetNeedDoBold(const bool& bBold)
{
m_bNeedDoBold = bBold;
}
inline CFontDict* GetFont() const
{
return m_pFont;
}
inline double GetSize() const
{
return m_dSize;
}
inline LONG GetColor() const
{
return m_lColor;
}
inline BYTE GetAlpha() const
{
return m_nAlpha;
}
inline double GetSpace() const
{
return m_dCharSpace;
}
inline double GetHorScaling() const
{
return m_dHorScaling;
}
inline int GetMode() const
{
return m_nMode;
}
inline bool IsNeedDoItalic() const
{
return m_bNeedDoItalic;
}
inline bool IsNeedDoBold() const
{
return m_bNeedDoBold;
}
private:
unsigned char* m_pCodes;
unsigned int m_nLen;
double m_dX;
double m_dY;
CFontDict* m_pFont;
bool m_bNeedDoItalic;
bool m_bNeedDoBold;
double m_dSize;
LONG m_lColor;
BYTE m_nAlpha;
double m_dCharSpace;
int m_nMode;
double m_dHorScaling;
};
//----------------------------------------------------------------------------------------
//
// CCommandManager
//
//----------------------------------------------------------------------------------------
CPdfWriter::CCommandManager::CCommandManager(CPdfWriter* pRenderer) : m_pRenderer(pRenderer)
{
}
CPdfWriter::CCommandManager::~CCommandManager()
{
Clear();
}
CRendererTextCommand* CPdfWriter::CCommandManager::AddText(unsigned char* pCodes, unsigned int nLen, const double& dX, const double& dY)
{
CRendererCommandBase* pCommand = new CRendererTextCommand(pCodes, nLen, dX, dY);
Add(pCommand);
return (CRendererTextCommand*)pCommand;
}
void CPdfWriter::CCommandManager::Add(CRendererCommandBase* pCommand)
{
if (pCommand)
{
if (m_vCommands.size() > 0 && pCommand->GetType() != m_vCommands.at(0)->GetType())
Flush();
m_vCommands.push_back(pCommand);
}
}
void CPdfWriter::CCommandManager::Flush()
{
size_t nCommandsCount = m_vCommands.size();
if (nCommandsCount > 0)
{
CPage* pPage = m_pRenderer->m_pPage;
pPage->GrSave();
pPage->SetTransform(m_oTransform.m11, m_oTransform.m12, m_oTransform.m21, m_oTransform.m22, m_oTransform.dx, m_oTransform.dy);
ERendererCommandType eType = m_vCommands.at(0)->GetType();
if (renderercommandtype_Text == eType)
{
pPage->BeginText();
CRendererTextCommand* pText = NULL;
CFontDict* pTextFont = NULL;
double dTextSize = -1;
LONG lTextColor = 0;
BYTE nTextAlpha = 255;
double dTextSpace = 0;
double dHorScaling = 100;
ETextRenderingMode eMode = textrenderingmode_Fill;
bool isNeedDoBold = false;
bool isNeedDoItalic = false;
double dLineWidth = -1;
CTextLine oTextLine;
for (size_t nIndex = 0; nIndex < nCommandsCount; nIndex++)
{
pText = (CRendererTextCommand*)m_vCommands.at(nIndex);
if (!pText)
continue;
if (pTextFont != pText->GetFont() || fabs(dTextSize - pText->GetSize()) > 0.001)
{
oTextLine.Flush(pPage);
pTextFont = pText->GetFont();
dTextSize = pText->GetSize();
pPage->SetFontAndSize(pTextFont, dTextSize);
}
if (lTextColor != pText->GetColor())
{
oTextLine.Flush(pPage);
lTextColor = pText->GetColor();
TColor oColor = lTextColor;
pPage->SetFillColor(oColor.r, oColor.g, oColor.b);
pPage->SetStrokeColor(oColor.r, oColor.g, oColor.b);
}
if (nTextAlpha != pText->GetAlpha())
{
oTextLine.Flush(pPage);
nTextAlpha = pText->GetAlpha();
pPage->SetFillAlpha(nTextAlpha);
pPage->SetStrokeAlpha(nTextAlpha);
}
if (fabs(dTextSpace - pText->GetSpace()) > 0.001)
{
oTextLine.Flush(pPage);
dTextSpace = pText->GetSpace();
pPage->SetCharSpace(dTextSpace);
}
if ((int)eMode != pText->GetMode() || isNeedDoBold != pText->IsNeedDoBold())
{
oTextLine.Flush(pPage);
eMode = (ETextRenderingMode)pText->GetMode();
isNeedDoBold = pText->IsNeedDoBold();
if (isNeedDoBold && eMode == textrenderingmode_Fill)
{
double dNewLineWidth = dTextSize / 12 * 0.343;
if (fabs(dLineWidth - dNewLineWidth) > 0.001)
{
dLineWidth = dNewLineWidth;
pPage->SetLineWidth(dLineWidth);
}
pPage->SetTextRenderingMode(textrenderingmode_FillThenStroke);
}
else
{
pPage->SetTextRenderingMode(eMode);
}
}
if (fabs(dHorScaling - pText->GetHorScaling()) > 0.001)
{
oTextLine.Flush(pPage);
dHorScaling = pText->GetHorScaling();
pPage->SetHorizontalScalling(dHorScaling);
}
if (isNeedDoItalic != pText->IsNeedDoItalic())
{
oTextLine.Flush(pPage);
if (pText->IsNeedDoItalic())
pPage->SetTextMatrix(1, 0, 0.26, 1, 0, 0);
else
pPage->SetTextMatrix(1, 0, 0, 1, 0, 0);
isNeedDoItalic = pText->IsNeedDoItalic();
}
unsigned char* pCodes = pText->GetCodes();
unsigned short ushCode = (pCodes[0] << 8) + pCodes[1];
unsigned int unLen = pText->GetCodesLen();
double dX = pText->GetX();
double dY = pText->GetY();
double dTextSize = pText->GetSize();
double dWidth = ((CFontCidTrueType*)pText->GetFont())->GetWidth(ushCode) / 1000.0 * dTextSize;
if (!oTextLine.Add(pCodes, unLen, dX, dY, dWidth, dTextSize))
{
oTextLine.Flush(pPage);
if (!oTextLine.Add(pCodes, unLen, dX, dY, dWidth, dTextSize))
{
pPage->DrawText(dX, dY, pCodes, unLen);
}
}
}
oTextLine.Flush(pPage);
pPage->EndText();
}
pPage->GrRestore();
}
Clear();
}
void CPdfWriter::CCommandManager::Clear()
{
for (size_t nIndex = 0, nCount = m_vCommands.size(); nIndex < nCount; nIndex++)
{
CRendererCommandBase* pCommand = m_vCommands.at(nIndex);
delete pCommand;
}
m_vCommands.clear();
}
void CPdfWriter::CCommandManager::SetTransform(const CTransform& oTransform)
{
m_oTransform = oTransform;
}
void CPdfWriter::CCommandManager::SetTransform(const double& m11, const double& m12, const double& m21, const double& m22, const double& dx, const double& dy)
{
m_oTransform.Set(m11, m12, m21, m22, dx, dy);
}
//----------------------------------------------------------------------------------------
//
// CPdfRenderer
//
//----------------------------------------------------------------------------------------
CPdfWriter::CPdfWriter(NSFonts::IApplicationFonts* pAppFonts, bool isPDFA) : m_oCommandManager(this)
{
// Создаем менеджер шрифтов с собственным кэшем
m_pFontManager = pAppFonts->GenerateFontManager();
NSFonts::IFontsCache* pMeasurerCache = NSFonts::NSFontCache::Create();
pMeasurerCache->SetStreams(pAppFonts->GetStreams());
m_pFontManager->SetOwnerCache(pMeasurerCache);
m_pDocument = new CDocument();
if (isPDFA)
m_pDocument->SetPDFAConformanceMode(true);
if (!m_pDocument || !m_pDocument->CreateNew())
{
SetError();
return;
}
m_pDocument->SetCompressionMode(COMP_ALL);
m_bValid = true;
m_dPageHeight = 297;
m_dPageWidth = 210;
m_pPage = NULL;
m_pFont = NULL;
m_bNeedUpdateTextFont = true;
m_bNeedUpdateTextColor = true;
m_bNeedUpdateTextAlpha = true;
m_bNeedUpdateTextCharSpace = true;
m_bNeedUpdateTextSize = true;
m_wsTempFolder = L"";
SetTempFolder(NSFile::CFileBinary::GetTempPath());
}
CPdfWriter::~CPdfWriter()
{
RELEASEOBJECT(m_pDocument);
RELEASEINTERFACE(m_pFontManager);
if (L"" != m_wsTempFolder)
NSDirectory::DeleteDirectory(m_wsTempFolder);
}
void CPdfWriter::SetPassword(const std::wstring& wsPassword)
{
if (!IsValid())
return;
m_pDocument->SetPasswords(wsPassword, wsPassword);
}
void CPdfWriter::SetDocumentID(const std::wstring& wsDocumentID)
{
if (!IsValid())
return;
m_pDocument->SetDocumentID(wsDocumentID);
}
int CPdfWriter::SaveToFile(const std::wstring& wsPath)
{
// TODO: Переделать на код ошибки
if (!IsValid())
return 1;
m_oCommandManager.Flush();
if (!m_pDocument->SaveToFile(wsPath))
return 1;
return 0;
}
void CPdfWriter::SetTempFolder(const std::wstring& wsPath)
{
if (L"" != m_wsTempFolder)
NSDirectory::DeleteDirectory(m_wsTempFolder);
int nCounter = 0;
m_wsTempFolder = wsPath;
int nPathLen = (int)m_wsTempFolder.length();
if (nPathLen > 0)
{
const wchar_t* pData = m_wsTempFolder.c_str();
if ((pData[nPathLen - 1] != '/') && (pData[nPathLen - 1] != '\\'))
m_wsTempFolder += L"/";
m_wsTempFolder += L"PDF";
}
std::wstring sTest = m_wsTempFolder;
while (NSDirectory::Exists(m_wsTempFolder))
{
m_wsTempFolder = sTest + L"/PDF_" + std::to_wstring(nCounter);
nCounter++;
}
NSDirectory::CreateDirectory(m_wsTempFolder);
}
std::wstring CPdfWriter::GetTempFile()
{
return NSFile::CFileBinary::CreateTempFileWithUniqueName(m_wsTempFolder, L"PDF");
}
std::wstring CPdfWriter::GetTempDirectory()
{
return m_wsTempFolder;
}
//----------------------------------------------------------------------------------------
// Тип рендерера
//----------------------------------------------------------------------------------------
HRESULT CPdfWriter::get_Type(LONG* lType)
{
*lType = c_nPDFWriter;
return S_OK;
}
//----------------------------------------------------------------------------------------
// Функции для работы со страницей
//----------------------------------------------------------------------------------------
HRESULT CPdfWriter::NewPage()
{
m_oCommandManager.Flush();
if (!IsValid())
return S_FALSE;
m_pPage = m_pDocument->AddPage();
if (!m_pPage)
{
SetError();
return S_FALSE;
}
m_pPage->SetWidth(MM_2_PT(m_dPageWidth));
m_pPage->SetHeight(MM_2_PT(m_dPageHeight));
Reset();
return S_OK;
}
HRESULT CPdfWriter::get_Height(double* dHeight)
{
*dHeight = m_dPageHeight;
return S_OK;
}
HRESULT CPdfWriter::put_Height(const double& dHeight)
{
if (!IsValid() || !m_pPage)
return S_FALSE;
m_dPageHeight = dHeight;
m_pPage->SetHeight(MM_2_PT(dHeight));
return S_OK;
}
HRESULT CPdfWriter::get_Width(double* dWidth)
{
*dWidth = m_dPageWidth;
return S_OK;
}
HRESULT CPdfWriter::put_Width(const double& dWidth)
{
if (!IsValid() || !m_pPage)
return S_FALSE;
m_dPageWidth = dWidth;
m_pPage->SetWidth(MM_2_PT(dWidth));
return S_OK;
}
HRESULT CPdfWriter::get_DpiX(double* dDpiX)
{
*dDpiX = 72;
return S_OK;
}
HRESULT CPdfWriter::get_DpiY(double* dDpiY)
{
*dDpiY = 72;
return S_OK;
}
//----------------------------------------------------------------------------------------
// Функции для работы с Pen
//----------------------------------------------------------------------------------------
HRESULT CPdfWriter::get_PenColor(LONG* lColor)
{
*lColor = m_oPen.GetColor();
return S_OK;
}
HRESULT CPdfWriter::put_PenColor(const LONG& lColor)
{
m_oPen.SetColor(lColor);
return S_OK;
}
HRESULT CPdfWriter::get_PenAlpha(LONG* lAlpha)
{
*lAlpha = m_oPen.GetAlpha();
return S_OK;
}
HRESULT CPdfWriter::put_PenAlpha(const LONG& lAlpha)
{
m_oPen.SetAlpha(lAlpha);
return S_OK;
}
HRESULT CPdfWriter::get_PenSize(double* dSize)
{
*dSize = m_oPen.GetSize();
return S_OK;
}
HRESULT CPdfWriter::put_PenSize(const double& dSize)
{
m_oPen.SetSize(dSize);
return S_OK;
}
HRESULT CPdfWriter::get_PenDashStyle(BYTE* nDashStyle)
{
*nDashStyle = m_oPen.GetDashStyle();
return S_OK;
}
HRESULT CPdfWriter::put_PenDashStyle(const BYTE& nDashStyle)
{
m_oPen.SetDashStyle(nDashStyle);
return S_OK;
}
HRESULT CPdfWriter::get_PenLineStartCap(BYTE* nCapStyle)
{
*nCapStyle = m_oPen.GetStartCapStyle();
return S_OK;
}
HRESULT CPdfWriter::put_PenLineStartCap(const BYTE& nCapStyle)
{
m_oPen.SetStartCapStyle(nCapStyle);
return S_OK;
}
HRESULT CPdfWriter::get_PenLineEndCap(BYTE* nCapStyle)
{
*nCapStyle = m_oPen.GetEndCapStyle();
return S_OK;
}
HRESULT CPdfWriter::put_PenLineEndCap(const BYTE& nCapStyle)
{
m_oPen.SetEndCapStyle(nCapStyle);
return S_OK;
}
HRESULT CPdfWriter::get_PenLineJoin(BYTE* nJoinStyle)
{
*nJoinStyle = m_oPen.GetJoinStyle();
return S_OK;
}
HRESULT CPdfWriter::put_PenLineJoin(const BYTE& nJoinStyle)
{
m_oPen.SetJoinStyle(nJoinStyle);
return S_OK;
}
HRESULT CPdfWriter::get_PenDashOffset(double* dOffset)
{
*dOffset = m_oPen.GetDashOffset();
return S_OK;
}
HRESULT CPdfWriter::put_PenDashOffset(const double& dOffset)
{
m_oPen.SetDashOffset(dOffset);
return S_OK;
}
HRESULT CPdfWriter::get_PenAlign(LONG* lAlign)
{
*lAlign = m_oPen.GetAlign();
return S_OK;
}
HRESULT CPdfWriter::put_PenAlign(const LONG& lAlign)
{
m_oPen.SetAlign(lAlign);
return S_OK;
}
HRESULT CPdfWriter::get_PenMiterLimit(double* dMiter)
{
*dMiter = m_oPen.GetMiter();
return S_OK;
}
HRESULT CPdfWriter::put_PenMiterLimit(const double& dMiter)
{
m_oPen.SetMiter(dMiter);
return S_OK;
}
HRESULT CPdfWriter::PenDashPattern(double* pPattern, LONG lCount)
{
m_oPen.SetDashPattern(pPattern, lCount);
return S_OK;
}
//----------------------------------------------------------------------------------------
// Функции для работы с Brush
//----------------------------------------------------------------------------------------
HRESULT CPdfWriter::get_BrushType(LONG* lType)
{
*lType = m_oBrush.GetType();
return S_OK;
}
HRESULT CPdfWriter::put_BrushType(const LONG& lType)
{
m_oBrush.SetType(lType);
return S_OK;
}
HRESULT CPdfWriter::get_BrushColor1(LONG* lColor)
{
*lColor = m_oBrush.GetColor1();
return S_OK;
}
HRESULT CPdfWriter::put_BrushColor1(const LONG& lColor)
{
if (lColor != m_oBrush.GetColor1())
{
m_oBrush.SetColor1(lColor);
m_bNeedUpdateTextColor = true;
}
return S_OK;
}
HRESULT CPdfWriter::get_BrushAlpha1(LONG* lAlpha)
{
*lAlpha = m_oBrush.GetAlpha1();
return S_OK;
}
HRESULT CPdfWriter::put_BrushAlpha1(const LONG& lAlpha)
{
if (lAlpha != m_oBrush.GetAlpha1())
{
m_oBrush.SetAlpha1(lAlpha);
m_bNeedUpdateTextAlpha = true;
}
return S_OK;
}
HRESULT CPdfWriter::get_BrushColor2(LONG* lColor)
{
*lColor = m_oBrush.GetColor2();
return S_OK;
}
HRESULT CPdfWriter::put_BrushColor2(const LONG& lColor)
{
m_oBrush.SetColor2(lColor);
return S_OK;
}
HRESULT CPdfWriter::get_BrushAlpha2(LONG* lAlpha)
{
*lAlpha = m_oBrush.GetAlpha2();
return S_OK;
}
HRESULT CPdfWriter::put_BrushAlpha2(const LONG& lAlpha)
{
m_oBrush.SetAlpha2(lAlpha);
return S_OK;
}
HRESULT CPdfWriter::get_BrushTexturePath(std::wstring* wsPath)
{
*wsPath = m_oBrush.GetTexturePath();
return S_OK;
}
HRESULT CPdfWriter::put_BrushTexturePath(const std::wstring& wsPath)
{
m_oBrush.SetTexturePath(wsPath);
return S_OK;
}
HRESULT CPdfWriter::get_BrushTextureMode(LONG* lMode)
{
*lMode = m_oBrush.GetTextureMode();
return S_OK;
}
HRESULT CPdfWriter::put_BrushTextureMode(const LONG& lMode)
{
m_oBrush.SetTextureMode(lMode);
return S_OK;
}
HRESULT CPdfWriter::get_BrushTextureAlpha(LONG* lAlpha)
{
*lAlpha = m_oBrush.GetTextureAlpha();
return S_OK;
}
HRESULT CPdfWriter::put_BrushTextureAlpha(const LONG& lAlpha)
{
m_oBrush.SetTextureAlpha(lAlpha);
return S_OK;
}
HRESULT CPdfWriter::get_BrushLinearAngle(double* dAngle)
{
*dAngle = m_oBrush.GetLinearAngle();
return S_OK;
}
HRESULT CPdfWriter::put_BrushLinearAngle(const double& dAngle)
{
m_oBrush.SetLinearAngle(dAngle);
return S_OK;
}
HRESULT CPdfWriter::BrushRect(const INT& nVal, const double& dLeft, const double& dTop, const double& dWidth, const double& dHeight)
{
// Данными параметрами пользуемся, только если пришла команда EnableBrushRect, если команда не пришла, тогда
// ориентируемся на границы пата.
m_oBrush.SetBrushRect(nVal, dLeft, dTop, dWidth, dHeight);
m_oBrush.EnableBrushRect(1 == nVal ? true : false);
return S_OK;
}
HRESULT CPdfWriter::BrushBounds(const double& dLeft, const double& dTop, const double& dWidth, const double& dHeight)
{
// TODO: Пока определяется все по границам пата
return S_OK;
}
HRESULT CPdfWriter::put_BrushGradientColors(LONG* lColors, double* pPositions, LONG lCount)
{
m_oBrush.SetGradientColors(lColors, pPositions, lCount);
return S_OK;
}
//----------------------------------------------------------------------------------------
// Функции для работы со шрифтами
//----------------------------------------------------------------------------------------
HRESULT CPdfWriter::get_FontName(std::wstring* wsName)
{
*wsName = m_oFont.GetName();
return S_OK;
}
HRESULT CPdfWriter::put_FontName(const std::wstring& wsName)
{
if (wsName != m_oFont.GetName())
{
m_oFont.SetName(wsName);
m_bNeedUpdateTextFont = true;
}
return S_OK;
}
HRESULT CPdfWriter::get_FontPath(std::wstring* wsPath)
{
*wsPath = m_oFont.GetPath();
return S_OK;
}
HRESULT CPdfWriter::put_FontPath(const std::wstring& wsPath)
{
if (wsPath != m_oFont.GetPath())
{
m_oFont.SetPath(wsPath);
m_bNeedUpdateTextFont = true;
}
return S_OK;
}
HRESULT CPdfWriter::get_FontSize(double* dSize)
{
*dSize = m_oFont.GetSize();
return S_OK;
}
HRESULT CPdfWriter::put_FontSize(const double& dSize)
{
if (fabs(dSize - m_oFont.GetSize()) > 0.001)
{
m_oFont.SetSize(dSize);
m_bNeedUpdateTextSize = true;
}
return S_OK;
}
HRESULT CPdfWriter::get_FontStyle(LONG* lStyle)
{
*lStyle = m_oFont.GetStyle();
return S_OK;
}
HRESULT CPdfWriter::put_FontStyle(const LONG& lStyle)
{
if (lStyle != m_oFont.GetStyle())
{
m_oFont.SetStyle(lStyle);
m_bNeedUpdateTextFont = true;
}
return S_OK;
}
HRESULT CPdfWriter::get_FontStringGID(INT* bGid)
{
*bGid = m_oFont.GetGid() ? 1 : 0;
return S_OK;
}
HRESULT CPdfWriter::put_FontStringGID(const INT& bGid)
{
m_oFont.SetGid(bGid ? true : false);
return S_OK;
}
HRESULT CPdfWriter::get_FontCharSpace(double* dSpace)
{
*dSpace = m_oFont.GetCharSpace();
return S_OK;
}
HRESULT CPdfWriter::put_FontCharSpace(const double& dSpace)
{
if (fabs(dSpace - m_oFont.GetCharSpace()) > 0.001)
{
m_oFont.SetCharSpace(dSpace);
m_bNeedUpdateTextCharSpace = true;
}
return S_OK;
}
HRESULT CPdfWriter::get_FontFaceIndex(int* nFaceIndex)
{
*nFaceIndex = (int)m_oFont.GetFaceIndex();
return S_OK;
}
HRESULT CPdfWriter::put_FontFaceIndex(const int& nFaceIndex)
{
if (nFaceIndex != m_oFont.GetFaceIndex())
{
m_oFont.SetFaceIndex(nFaceIndex);
m_bNeedUpdateTextFont = true;
}
return S_OK;
}
//----------------------------------------------------------------------------------------
// Функции для вывода текста
//----------------------------------------------------------------------------------------
HRESULT CPdfWriter::CommandDrawTextCHAR(const LONG& lUnicode, const double& dX, const double& dY, const double& dW, const double& dH)
{
if (!IsPageValid())
return S_FALSE;
unsigned int unUnicode = lUnicode;
unsigned char* pCodes = EncodeString(&unUnicode, 1);
return DrawText(pCodes, 2, dX, dY) ? S_OK : S_FALSE;
}
HRESULT CPdfWriter::CommandDrawText(const std::wstring& wsUnicodeText, const double& dX, const double& dY, const double& dW, const double& dH)
{
if (!IsPageValid() || !wsUnicodeText.size())
return S_FALSE;
unsigned int unLen;
unsigned int* pUnicodes = WStringToUtf32(wsUnicodeText, unLen);
if (!pUnicodes)
return S_FALSE;
unsigned char* pCodes = EncodeString(pUnicodes, unLen);
delete[] pUnicodes;
if (!pCodes)
return S_FALSE;
// Специальный случай для текста из Djvu, нам не нужно, чтобы он рисовался
if (L"" == m_oFont.GetPath() && L"DjvuEmptyFont" == m_oFont.GetName())
{
if (m_bNeedUpdateTextFont)
{
m_oFont.SetName(L"Arial");
UpdateFont();
m_oFont.SetName(L"DjvuEmptyFont");
if (!m_pFont)
return S_FALSE;
}
double dFontSize = MM_2_PT(dH);
double dStringWidth = 0;
for (unsigned int unIndex = 0; unIndex < unLen; unIndex++)
{
unsigned short ushCode = (pCodes[2 * unIndex] << 8) + pCodes[2 * unIndex + 1];
dStringWidth += m_pFont->GetWidth(ushCode) * dFontSize / 1000.0;
}
double dResultWidth = MM_2_PT(dW);
CTransform& t = m_oTransform;
m_oCommandManager.SetTransform(t.m11, -t.m12, -t.m21, t.m22, MM_2_PT(t.dx + t.m21 * m_dPageHeight), MM_2_PT(m_dPageHeight - m_dPageHeight * t.m22 - t.dy));
CRendererTextCommand* pText = m_oCommandManager.AddText(pCodes, unLen * 2, MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY - dH));
pText->SetFont(m_pFont);
pText->SetSize(dFontSize);
pText->SetMode(textrenderingmode_Invisible);
if (fabs(dStringWidth) > 0.001)
pText->SetHorScaling(dResultWidth / dStringWidth * 100);
return S_OK;
}
return DrawText(pCodes, unLen * 2, dX, dY) ? S_OK : S_FALSE;
}
HRESULT CPdfWriter::CommandDrawTextExCHAR(const LONG& lUnicode, const LONG& lGid, const double& dX, const double& dY, const double& dW, const double& dH)
{
if (!IsPageValid())
return S_FALSE;
unsigned int unUnicode = lUnicode;
unsigned int unGID = lGid;
unsigned char* pCodes = EncodeGID(unGID, &unUnicode, 1);
return DrawText(pCodes, 2, dX, dY) ? S_OK : S_FALSE;
}
HRESULT CPdfWriter::CommandDrawTextEx(const std::wstring& wsUnicodeText, const unsigned int* pGids, const unsigned int unGidsCount, const double& dX, const double& dY, const double& dW, const double& dH)
{
if (!IsPageValid() || (!wsUnicodeText.size() && (!pGids || !unGidsCount)))
return S_FALSE;
unsigned int unLen = 0;
unsigned int* pUnicodes = NULL;
if (pGids && unGidsCount)
{
unLen = unGidsCount;
if (wsUnicodeText.size())
{
unsigned int unUnicodeLen;
pUnicodes = WStringToUtf32(wsUnicodeText, unUnicodeLen);
if (!pUnicodes || unUnicodeLen != unLen)
RELEASEARRAYOBJECTS(pUnicodes);
}
if (!pUnicodes)
{
pUnicodes = new unsigned int[unLen];
if (!pUnicodes)
return S_FALSE;
for (unsigned int unIndex = 0; unIndex < unLen; unIndex++)
pUnicodes[unIndex] = pGids[unIndex];
}
}
else
{
pUnicodes = WStringToUtf32(wsUnicodeText, unLen);
if (!pUnicodes)
return S_FALSE;
}
unsigned char* pCodes = EncodeString(pUnicodes, unLen, pGids);
RELEASEARRAYOBJECTS(pUnicodes);
return DrawText(pCodes, unLen * 2, dX, dY) ? S_OK : S_FALSE;
}
HRESULT CPdfWriter::CommandDrawTextCHAR2(unsigned int* pUnicodes, const unsigned int& unUnicodeCount, const unsigned int& unGid, const double& dX, const double& dY, const double& dW, const double& dH)
{
if (!IsPageValid())
return S_FALSE;
unsigned char* pCodes = EncodeGID(unGid, pUnicodes, unUnicodeCount);
return DrawText(pCodes, 2, dX, dY) ? S_OK : S_FALSE;
}
//----------------------------------------------------------------------------------------
// Маркеры команд
//----------------------------------------------------------------------------------------
HRESULT CPdfWriter::BeginCommand(const DWORD& dwType)
{
// Здесь мы ничего не делаем
return S_OK;
}
HRESULT CPdfWriter::EndCommand(const DWORD& dwType)
{
if (!IsPageValid())
return S_FALSE;
// Здесь мы различаем лишь 2 команды: присоединить текущий пат к клипу и отменить клип
if (c_nClipType == dwType)
{
m_oCommandManager.Flush();
m_pPage->GrSave();
m_lClipDepth++;
UpdateTransform();
if (c_nClipRegionTypeEvenOdd & m_lClipMode)
m_oPath.Clip(m_pPage, true);
else
m_oPath.Clip(m_pPage, false);
}
else if (c_nResetClipType == dwType)
{
m_oCommandManager.Flush();
while (m_lClipDepth)
{
m_pPage->GrRestore();
m_lClipDepth--;
}
}
else if (c_nPageType == dwType)
{
for (int nIndex = 0, nCount = m_vDestinations.size(); nIndex < nCount; ++nIndex)
{
TDestinationInfo& oInfo = m_vDestinations.at(nIndex);
if (m_pDocument->GetPagesCount() > oInfo.unDestPage)
{
AddLink(oInfo.pPage, oInfo.dX, oInfo.dY, oInfo.dW, oInfo.dH, oInfo.dDestX, oInfo.dDestY, oInfo.unDestPage);
m_vDestinations.erase(m_vDestinations.begin() + nIndex);
nIndex--;
nCount--;
}
}
}
return S_OK;
}
//----------------------------------------------------------------------------------------
// Функции для работы с патом
//----------------------------------------------------------------------------------------
HRESULT CPdfWriter::PathCommandStart()
{
m_oPath.Clear();
return S_OK;
}
HRESULT CPdfWriter::PathCommandEnd()
{
m_oPath.Clear();
return S_OK;
}
HRESULT CPdfWriter::DrawPath(NSFonts::IApplicationFonts* pAppFonts, const LONG& lType)
{
m_oCommandManager.Flush();
if (!IsPageValid())
return S_FALSE;
bool bStroke = LONG_2_BOOL(lType & c_nStroke);
bool bFill = LONG_2_BOOL(lType & c_nWindingFillMode);
bool bEoFill = LONG_2_BOOL(lType & c_nEvenOddFillMode);
m_pPage->GrSave();
UpdateTransform();
if (bStroke)
UpdatePen();
std::wstring sTextureOldPath = L"";
std::wstring sTextureTmpPath = L"";
if (bFill || bEoFill)
{
if (c_BrushTypeTexture == m_oBrush.GetType())
{
sTextureOldPath = m_oBrush.GetTexturePath();
sTextureTmpPath = GetDownloadFile(sTextureOldPath);
if (!sTextureTmpPath.empty())
m_oBrush.SetTexturePath(sTextureTmpPath);
}
UpdateBrush(pAppFonts);
}
if (!m_pShading)
{
m_oPath.Draw(m_pPage, bStroke, bFill, bEoFill);
}
else
{
if (bFill || bEoFill)
{
m_pPage->GrSave();
m_oPath.Clip(m_pPage, bEoFill);
if (NULL != m_pShadingExtGrState)
m_pPage->SetExtGrState(m_pShadingExtGrState);
m_pPage->DrawShading(m_pShading);
m_pPage->GrRestore();
}
if (bStroke)
m_oPath.Draw(m_pPage, bStroke, false, false);
}
m_pPage->GrRestore();
if (!sTextureTmpPath.empty())
{
m_oBrush.SetTexturePath(sTextureOldPath);
if (NSFile::CFileBinary::Exists(sTextureTmpPath))
NSFile::CFileBinary::Remove(sTextureTmpPath);
}
return S_OK;
}
HRESULT CPdfWriter::PathCommandMoveTo(const double& dX, const double& dY)
{
m_oPath.MoveTo(MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY));
return S_OK;
}
HRESULT CPdfWriter::PathCommandLineTo(const double& dX, const double& dY)
{
m_oPath.LineTo(MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY));
return S_OK;
}
HRESULT CPdfWriter::PathCommandLinesTo(double* pPoints, const int& nCount)
{
if (nCount < 4 || !pPoints)
return S_OK;
if (!m_oPath.IsMoveTo())
m_oPath.MoveTo(MM_2_PT(pPoints[0]), MM_2_PT(m_dPageHeight - pPoints[1]));
int nPointsCount = (nCount / 2) - 1;
for (int nIndex = 1; nIndex <= nPointsCount; ++nIndex)
{
m_oPath.LineTo(MM_2_PT(pPoints[nIndex * 2]), MM_2_PT(m_dPageHeight - pPoints[nIndex * 2 + 1]));
}
return S_OK;
}
HRESULT CPdfWriter::PathCommandCurveTo(const double& dX1, const double& dY1, const double& dX2, const double& dY2, const double& dXe, const double& dYe)
{
m_oPath.CurveTo(MM_2_PT(dX1), MM_2_PT(m_dPageHeight - dY1), MM_2_PT(dX2), MM_2_PT(m_dPageHeight - dY2), MM_2_PT(dXe), MM_2_PT(m_dPageHeight - dYe));
return S_OK;
}
HRESULT CPdfWriter::PathCommandCurvesTo(double* pPoints, const int& nCount)
{
if (nCount < 8 || !pPoints)
return S_OK;
if (!m_oPath.IsMoveTo())
m_oPath.MoveTo(MM_2_PT(pPoints[0]), MM_2_PT(m_dPageHeight - pPoints[1]));
int nPointsCount = (nCount - 2) / 6;
double* pCur = pPoints + 2;
for (int nIndex = 0; nIndex <= nPointsCount; ++nIndex, pCur += 6)
{
m_oPath.CurveTo(MM_2_PT(pCur[0]), MM_2_PT(m_dPageHeight - pCur[1]), MM_2_PT(pCur[2]), MM_2_PT(m_dPageHeight - pCur[3]), MM_2_PT(pCur[4]), MM_2_PT(m_dPageHeight - pCur[5]));
}
return S_OK;
}
HRESULT CPdfWriter::PathCommandArcTo(const double& dX, const double& dY, const double& dW, const double& dH, const double& dStartAngle, const double& dSweepAngle)
{
m_oPath.ArcTo(MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY - dH), MM_2_PT(dW), MM_2_PT(dH), dStartAngle, dSweepAngle);
return S_OK;
}
HRESULT CPdfWriter::PathCommandClose()
{
m_oPath.Close();
return S_OK;
}
HRESULT CPdfWriter::PathCommandGetCurrentPoint(double* dX, double* dY)
{
m_oPath.GetLastPoint(*dX, *dY);
*dX = PT_2_MM(*dX);
*dY = PT_2_MM(*dY);
return S_OK;
}
HRESULT CPdfWriter::PathCommandTextCHAR(const LONG& lUnicode, const double& dX, const double& dY, const double& dW, const double& dH)
{
unsigned int unUnicode = lUnicode;
bool bRes = PathCommandDrawText(&unUnicode, 1, dX, dY, NULL);
return bRes ? S_OK : S_FALSE;
}
HRESULT CPdfWriter::PathCommandText(const std::wstring& wsUnicodeText, const double& dX, const double& dY, const double& dW, const double& dH)
{
unsigned int unLen;
unsigned int* pUnicodes = WStringToUtf32(wsUnicodeText, unLen);
if (!pUnicodes)
return S_FALSE;
PathCommandDrawText(pUnicodes, unLen, dX, dY, NULL);
delete[] pUnicodes;
return S_OK;
}
HRESULT CPdfWriter::PathCommandTextExCHAR(const LONG& lUnicode, const LONG& lGid, const double& dX, const double& dY, const double& dW, const double& dH)
{
unsigned int unUnicode = lUnicode;
unsigned int unGid = lGid;
bool bRes = PathCommandDrawText(&unUnicode, 1, dX, dY, &unGid);
return bRes ? S_OK : S_FALSE;
}
HRESULT CPdfWriter::PathCommandTextEx(const std::wstring& wsUnicodeText, const unsigned int* pGids, const unsigned int unGidsCount, const double& dX, const double& dY, const double& dW, const double& dH)
{
if (!IsPageValid() || (!wsUnicodeText.size() && (!pGids || !unGidsCount)))
return S_FALSE;
unsigned int unLen = 0;
unsigned int* pUnicodes = NULL;
if (pGids && unGidsCount)
{
unLen = unGidsCount;
if (wsUnicodeText.size())
{
unsigned int unUnicodeLen;
pUnicodes = WStringToUtf32(wsUnicodeText, unUnicodeLen);
if (!pUnicodes || unUnicodeLen != unLen)
RELEASEARRAYOBJECTS(pUnicodes);
}
if (!pUnicodes)
{
pUnicodes = new unsigned int[unLen];
if (!pUnicodes)
return S_FALSE;
for (unsigned int unIndex = 0; unIndex < unLen; unIndex++)
pUnicodes[unIndex] = pGids[unIndex];
}
}
else
{
pUnicodes = WStringToUtf32(wsUnicodeText, unLen);
if (!pUnicodes)
return S_FALSE;
}
bool bRes = PathCommandDrawText(pUnicodes, unLen, dX, dY, pGids);
RELEASEARRAYOBJECTS(pUnicodes);
return bRes ? S_OK : S_FALSE;
}
//----------------------------------------------------------------------------------------
// Функции для вывода изображений
//----------------------------------------------------------------------------------------
HRESULT CPdfWriter::DrawImage(IGrObject* pImage, const double& dX, const double& dY, const double& dW, const double& dH)
{
m_oCommandManager.Flush();
if (!IsPageValid() || !pImage)
return S_OK;
if (!DrawImage((Aggplus::CImage*)pImage, dX, dY, dW, dH, 255))
return S_FALSE;
return S_OK;
}
HRESULT CPdfWriter::DrawImageFromFile(NSFonts::IApplicationFonts* pAppFonts, const std::wstring& wsImagePathSrc, const double& dX, const double& dY, const double& dW, const double& dH, const BYTE& nAlpha)
{
m_oCommandManager.Flush();
if (!IsPageValid())
return S_OK;
std::wstring sTempImagePath = GetDownloadFile(wsImagePathSrc);
std::wstring wsImagePath = sTempImagePath.empty() ? wsImagePathSrc : sTempImagePath;
Aggplus::CImage* pAggImage = NULL;
CImageFileFormatChecker oImageFormat(wsImagePath);
if (_CXIMAGE_FORMAT_WMF == oImageFormat.eFileType ||
_CXIMAGE_FORMAT_EMF == oImageFormat.eFileType ||
_CXIMAGE_FORMAT_SVM == oImageFormat.eFileType ||
_CXIMAGE_FORMAT_SVG == oImageFormat.eFileType)
{
// TODO: Реализовать отрисовку метафайлов по-нормальному
MetaFile::IMetaFile* pMeta = MetaFile::Create(pAppFonts);
pMeta->LoadFromFile(wsImagePath.c_str());
double dNewW = std::max(10.0, dW) / 25.4 * 300;
std::wstring wsTempFile = GetTempFile();
pMeta->ConvertToRaster(wsTempFile.c_str(), _CXIMAGE_FORMAT_PNG, dNewW);
RELEASEOBJECT(pMeta);
pAggImage = new Aggplus::CImage(wsTempFile);
}
else
{
pAggImage = new Aggplus::CImage(wsImagePath);
}
HRESULT hRes = S_OK;
if (!pAggImage || !DrawImage(pAggImage, dX, dY, dW, dH, nAlpha))
hRes = S_FALSE;
if (NSFile::CFileBinary::Exists(sTempImagePath))
NSFile::CFileBinary::Remove(sTempImagePath);
if (pAggImage)
delete pAggImage;
return hRes;
}
//----------------------------------------------------------------------------------------
// Функции для выставления преобразования
//----------------------------------------------------------------------------------------
HRESULT CPdfWriter::SetTransform(const double& dM11, const double& dM12, const double& dM21, const double& dM22, const double& dX, const double& dY)
{
m_oCommandManager.Flush();
m_oTransform.Set(dM11, dM12, dM21, dM22, dX, dY);
return S_OK;
}
HRESULT CPdfWriter::GetTransform(double* dM11, double* dM12, double* dM21, double* dM22, double* dX, double* dY)
{
*dM11 = m_oTransform.m11;
*dM12 = m_oTransform.m12;
*dM21 = m_oTransform.m21;
*dM22 = m_oTransform.m22;
*dX = m_oTransform.dx;
*dY = m_oTransform.dy;
return S_OK;
}
HRESULT CPdfWriter::ResetTransform()
{
m_oCommandManager.Flush();
m_oTransform.Reset();
return S_OK;
}
//----------------------------------------------------------------------------------------
// Тип клипа
//----------------------------------------------------------------------------------------
HRESULT CPdfWriter::get_ClipMode(LONG* lMode)
{
*lMode = m_lClipMode;
return S_OK;
}
HRESULT CPdfWriter::put_ClipMode(const LONG& lMode)
{
m_lClipMode = lMode;
return S_OK;
}
//----------------------------------------------------------------------------------------
// Дополнительные функции
//----------------------------------------------------------------------------------------
HRESULT CPdfWriter::CommandLong(const LONG& lType, const LONG& lCommand)
{
return S_OK;
}
HRESULT CPdfWriter::CommandDouble(const LONG& lType, const double& dCommand)
{
return S_OK;
}
HRESULT CPdfWriter::CommandString(const LONG& lType, const std::wstring& sCommand)
{
return S_OK;
}
HRESULT CPdfWriter::AddHyperlink(const double& dX, const double& dY, const double& dW, const double& dH, const std::wstring& wsUrl, const std::wstring& wsTooltip)
{
NSUnicodeConverter::CUnicodeConverter conv;
CAnnotation* pAnnot = m_pDocument->CreateUriLinkAnnot(m_pPage, TRect(MM_2_PT(dX), m_pPage->GetHeight() - MM_2_PT(dY), MM_2_PT(dX + dW), m_pPage->GetHeight() - MM_2_PT(dY + dH)), conv.SASLprepToUtf8(wsUrl).c_str());
pAnnot->SetBorderStyle(EBorderSubtype::border_subtype_Solid, 0);
return S_OK;
}
HRESULT CPdfWriter::AddLink(const double& dX, const double& dY, const double& dW, const double& dH, const double& dDestX, const double& dDestY, const int& nPage)
{
unsigned int unPagesCount = m_pDocument->GetPagesCount();
if (unPagesCount == 0)
return S_OK;
CPage* pPage = m_pDocument->GetPage(nPage);
if (!pPage)
{
m_vDestinations.push_back(TDestinationInfo(m_pPage, dX, dY, dW, dH, dDestX, dDestY, nPage));
}
else
{
AddLink(m_pPage, dX, dY, dW, dH, dDestX, dDestY, nPage);
}
return S_OK;
}
HRESULT CPdfWriter::AddFormField(NSFonts::IApplicationFonts* pAppFonts, const CFormFieldInfo &oInfo)
{
unsigned int unPagesCount = m_pDocument->GetPagesCount();
if (!m_pDocument || 0 == unPagesCount)
return S_OK;
if (m_bNeedUpdateTextFont)
UpdateFont();
if (!m_pFont)
return S_OK;
PdfWriter::CFontTrueType* pFontTT = m_pDocument->CreateTrueTypeFont(m_pFont);
if (!pFontTT)
return S_OK;
double dX, dY, dW, dH;
oInfo.GetBounds(dX, dY, dW, dH);
CFieldBase* pFieldBase = NULL;
bool bRadioButton = false;
if (oInfo.IsTextField())
{
CTextField* pField = m_pDocument->CreateTextField();
pFieldBase = static_cast<CFieldBase*>(pField);
}
else if (oInfo.IsDropDownList())
{
CChoiceField* pField = m_pDocument->CreateChoiceField();
pFieldBase = static_cast<CFieldBase*>(pField);
}
else if (oInfo.IsCheckBox())
{
const CFormFieldInfo::CCheckBoxFormPr* pPr = oInfo.GetCheckBoxPr();
CCheckBoxField* pField = NULL;
std::wstring wsGroupName = pPr->GetGroupKey();
if (L"" != wsGroupName)
{
bRadioButton = true;
CRadioGroupField* pRadioGroup = m_pDocument->GetRadioGroupField(wsGroupName);
if (pRadioGroup)
pField = pRadioGroup->CreateKid();
}
else
{
pField = m_pDocument->CreateCheckBoxField();
}
pFieldBase = static_cast<CFieldBase*>(pField);
}
else if (oInfo.IsPicture())
{
CPictureField* pField = m_pDocument->CreatePictureField();
pFieldBase = static_cast<CFieldBase*>(pField);
}
else if (oInfo.IsSignature())
{
CSignatureField* pField = m_pDocument->CreateSignatureField();
pFieldBase = static_cast<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(CFieldBase::EFieldAlignType::Right);
else if (2 == unAlign)
pFieldBase->SetAlign(CFieldBase::EFieldAlignType::Center);
if (oInfo.HaveBorder())
{
unsigned char unR, unG, unB, unA;
oInfo.GetBorderColor(unR, unG, unB, unA);
pFieldBase->SetFieldBorder(EBorderSubtype::border_subtype_Solid, TRgb(unR, unG, unB), MM_2_PT(oInfo.GetBorderSize()), 0, 0, 0);
}
if (oInfo.HaveShd())
{
unsigned char unR, unG, unB, unA;
oInfo.GetShdColor(unR, unG, unB, unA);
pFieldBase->SetShd(TRgb(unR, unG, unB));
}
pFieldBase->SetRequiredFlag(oInfo.IsRequired());
pFieldBase->SetFieldHint(oInfo.GetHelpText());
bool isBold = m_oFont.IsBold();
bool isItalic = m_oFont.IsItalic();
if (oInfo.IsTextField())
{
const CFormFieldInfo::CTextFormPr* pPr = oInfo.GetTextPr();
std::wstring wsValue = pPr->GetTextValue();
unsigned int unLen;
unsigned int* pUnicodes = WStringToUtf32(wsValue, unLen);
if (!pUnicodes)
return S_FALSE;
unsigned short* pCodes = new unsigned short[unLen];
if (!pCodes)
{
RELEASEARRAYOBJECTS(pUnicodes);
return S_FALSE;
}
CFontCidTrueType** ppFonts = new CFontCidTrueType*[unLen];
if (!ppFonts)
{
RELEASEARRAYOBJECTS(pUnicodes);
RELEASEARRAYOBJECTS(pCodes);
return S_FALSE;
}
for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex)
{
unsigned int unUnicode = pUnicodes[unIndex];
if (!m_pFont->HaveChar(unUnicode))
{
std::wstring wsFontFamily = pAppFonts->GetFontBySymbol(unUnicode);
CFontCidTrueType* pTempFont = GetFont(wsFontFamily, isBold, isItalic);
if (pTempFont)
{
pCodes[unIndex] = pTempFont->EncodeUnicode(unUnicode);
ppFonts[unIndex] = pTempFont;
continue;
}
}
pCodes[unIndex] = m_pFont->EncodeUnicode(unUnicode);
ppFonts[unIndex] = m_pFont;
}
CTextField* pField = dynamic_cast<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, TRect(MM_2_PT(dX) - dMargin, _dY, MM_2_PT(dX + dW) + dMargin, _dB));
pField->SetMaxLen(pPr->GetMaxCharacters());
pField->SetCombFlag(pPr->IsComb());
pField->SetAutoFit(pPr->IsAutoFit());
pField->SetMultilineFlag(pPr->IsMultiLine());
bool isComb = pPr->IsComb();
unsigned int unAlign = oInfo.GetJc();
double dFontSize = m_oFont.GetSize();
TColor oColor = m_oBrush.GetTColor1();
bool isPlaceHolder = oInfo.IsPlaceHolder();
TRgb oNormalColor(oColor.r, oColor.g, oColor.b);
TRgb oPlaceHolderColor;
oPlaceHolderColor.r = oNormalColor.r + (1.0 - oNormalColor.r) / 2.0;
oPlaceHolderColor.g = oNormalColor.g + (1.0 - oNormalColor.g) / 2.0;
oPlaceHolderColor.b = oNormalColor.b + (1.0 - oNormalColor.b) / 2.0;
if (!isPlaceHolder)
pField->SetTextValue(wsValue);
if (!isComb && pPr->IsMultiLine())
{
unsigned short* pCodes2 = new unsigned short[unLen];
unsigned int* pWidths = new unsigned int[unLen];
unsigned short ushSpaceCode = 0xFFFF;
for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex)
{
pCodes2[unIndex] = (0x0020 == pUnicodes[unIndex] ? ushSpaceCode : 0);
pWidths[unIndex] = ppFonts[unIndex]->GetWidth(pCodes[unIndex]);
}
m_oLinesManager.Init(pCodes2, pWidths, unLen, ushSpaceCode, pFontTT->GetLineHeight(), pFontTT->GetAscent());
// TODO: Разобраться более детально по какой именно высоте идет в Adobe расчет
// пока временно оставим (H - 3 * margin)
if (pPr->IsAutoFit())
dFontSize = m_oLinesManager.ProcessAutoFit(MM_2_PT(dW), (MM_2_PT(dH) - 3 * dMargin));
double dLineHeight = pFontTT->GetLineHeight() * dFontSize / 1000.0;
m_oLinesManager.CalculateLines(dFontSize, MM_2_PT(dW));
pField->StartTextAppearance(m_pFont, dFontSize, isPlaceHolder ? oPlaceHolderColor : oNormalColor, 1.0);
unsigned int unLinesCount = m_oLinesManager.GetLinesCount();
double dLineShiftY = MM_2_PT(dH) - pFontTT->GetLineHeight() * dFontSize / 1000.0 - dMargin;
for (unsigned int unIndex = 0; unIndex < unLinesCount; ++unIndex)
{
unsigned int unLineStart = m_oLinesManager.GetLineStartPos(unIndex);
double dLineShiftX = dShiftX;
double dLineWidth = m_oLinesManager.GetLineWidth(unIndex, dFontSize);
if (0 == unAlign)
dLineShiftX += MM_2_PT(dW) - dLineWidth;
else if (2 == unAlign)
dLineShiftX += (MM_2_PT(dW) - dLineWidth) / 2;
int nInLineCount = m_oLinesManager.GetLineEndPos(unIndex) - m_oLinesManager.GetLineStartPos(unIndex);
if (nInLineCount > 0)
pField->AddLineToTextAppearance(dLineShiftX, dLineShiftY, pCodes + unLineStart, nInLineCount, ppFonts + unLineStart, NULL);
dLineShiftY -= dLineHeight;
}
pField->EndTextAppearance();
m_oLinesManager.Clear();
delete[] pCodes2;
delete[] pWidths;
}
else
{
double* pShifts = NULL;
unsigned int unShiftsCount = 0;
if (isComb)
{
pField->SetDoNotScrollFlag(true);
pField->SetDoNotSpellCheckFlag(true);
pField->SetMultilineFlag(false);
unShiftsCount = unLen;
pShifts = new double[unShiftsCount];
if (pShifts && unShiftsCount)
{
// Сдвиг нулевой для comb форм и не забываем, что мы к ширине добавили 2 * dMargin
dShiftX = 0;
unsigned int unCellsCount = std::max(unShiftsCount, pPr->GetMaxCharacters());
double dPrevW = 0;
double dCellW = (MM_2_PT(dW) + 2 * dMargin) / unCellsCount;
if (0 == unAlign && unShiftsCount)
dPrevW = (unCellsCount - unShiftsCount) * dCellW;
for (unsigned int unIndex = 0; unIndex < unShiftsCount; ++unIndex)
{
unsigned short ushCode = pCodes[unIndex];
double dGlyphWidth = ppFonts[unIndex]->GetGlyphWidth(ushCode) / 1000.0 * dFontSize;
double dTempShift = (dCellW - dGlyphWidth) / 2;
pShifts[unIndex] = dPrevW + dTempShift;
dPrevW = dCellW - dTempShift;
}
}
else
{
unShiftsCount = 0;
}
}
else if (0 == unAlign || 2 == unAlign)
{
double dSumWidth = 0;
for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex)
{
unsigned short ushCode = pCodes[unIndex];
double dLetterWidth = ppFonts[unIndex]->GetWidth(ushCode) / 1000.0 * dFontSize;
dSumWidth += dLetterWidth;
}
if (0 == unAlign && MM_2_PT(dW) - dSumWidth > 0)
dShiftX += MM_2_PT(dW) - dSumWidth;
else if (2 == unAlign && (MM_2_PT(dW) - dSumWidth) / 2 > 0)
dShiftX += (MM_2_PT(dW) - dSumWidth) / 2;
}
pField->SetTextAppearance(wsValue, pCodes, unLen, m_pFont, isPlaceHolder ? oPlaceHolderColor : oNormalColor, 1.0, m_oFont.GetSize(), dShiftX, dBaseLine, ppFonts, pShifts);
RELEASEARRAYOBJECTS(pShifts);
}
RELEASEARRAYOBJECTS(pUnicodes);
RELEASEARRAYOBJECTS(pCodes);
RELEASEARRAYOBJECTS(ppFonts);
pField->SetDefaultAppearance(pFontTT, m_oFont.GetSize(), TRgb(oColor.r, oColor.g, oColor.b));
std::wstring wsPlaceHolder = pPr->GetPlaceHolder();
if (!wsPlaceHolder.empty())
{
unsigned int unMaxLen = pPr->GetMaxCharacters();
if (unMaxLen && wsPlaceHolder.length() > unMaxLen)
wsPlaceHolder = wsPlaceHolder.substr(0, unMaxLen);
pField->SetPlaceHolderText(wsPlaceHolder, oNormalColor, oPlaceHolderColor);
}
pField->SetFormat(pPr->GetFormatPr());
}
else if (oInfo.IsDropDownList())
{
const CFormFieldInfo::CDropDownFormPr* pPr = oInfo.GetDropDownPr();
std::wstring wsValue = pPr->GetTextValue();
unsigned int unLen;
unsigned int* pUnicodes = WStringToUtf32(wsValue, unLen);
if (!pUnicodes)
return S_FALSE;
unsigned short* pCodes = new unsigned short[unLen];
if (!pCodes)
{
RELEASEARRAYOBJECTS(pUnicodes);
return S_FALSE;
}
CFontCidTrueType** ppFonts = new CFontCidTrueType*[unLen];
if (!ppFonts)
{
RELEASEARRAYOBJECTS(pUnicodes);
RELEASEARRAYOBJECTS(pCodes);
return S_FALSE;
}
for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex)
{
unsigned int unUnicode = pUnicodes[unIndex];
if (!m_pFont->HaveChar(unUnicode))
{
std::wstring wsFontFamily = pAppFonts->GetFontBySymbol(unUnicode);
CFontCidTrueType* pTempFont = GetFont(wsFontFamily, isBold, isItalic);
if (pTempFont)
{
pCodes[unIndex] = pTempFont->EncodeUnicode(unUnicode);
ppFonts[unIndex] = pTempFont;
continue;
}
}
pCodes[unIndex] = m_pFont->EncodeUnicode(unUnicode);
ppFonts[unIndex] = m_pFont;
}
CChoiceField* pField = dynamic_cast<CChoiceField*>(pFieldBase);
if (!pField)
{
RELEASEARRAYOBJECTS(pUnicodes);
RELEASEARRAYOBJECTS(pCodes);
RELEASEARRAYOBJECTS(ppFonts);
return S_FALSE;
}
pFieldBase->AddPageRect(m_pPage, TRect(MM_2_PT(dX), m_pPage->GetHeight() - MM_2_PT(dY), MM_2_PT(dX + dW), m_pPage->GetHeight() - MM_2_PT(dY + dH)));
TColor oColor = m_oBrush.GetTColor1();
TRgb oNormalColor(oColor.r, oColor.g, oColor.b);
TRgb oPlaceHolderColor;
oPlaceHolderColor.r = oNormalColor.r + (1.0 - oNormalColor.r) / 2.0;
oPlaceHolderColor.g = oNormalColor.g + (1.0 - oNormalColor.g) / 2.0;
oPlaceHolderColor.b = oNormalColor.b + (1.0 - oNormalColor.b) / 2.0;
pField->SetTextValue(wsValue);
pField->SetTextAppearance(wsValue, pCodes, unLen, m_pFont, oInfo.IsPlaceHolder() ? oPlaceHolderColor : oNormalColor, 1, m_oFont.GetSize(), 0, MM_2_PT(dH - oInfo.GetBaseLineOffset()), ppFonts);
RELEASEARRAYOBJECTS(pUnicodes);
RELEASEARRAYOBJECTS(pCodes);
RELEASEARRAYOBJECTS(ppFonts);
unsigned int unSelectedIndex = 0xFFFF;
for (unsigned int unIndex = 0, unItemsCount = pPr->GetComboBoxItemsCount(); unIndex < unItemsCount; ++unIndex)
{
std::wstring wsItem = pPr->GetComboBoxItem(unIndex);
pField->AddOption(wsItem);
if (wsItem == wsValue)
unSelectedIndex = unIndex;
}
pField->SetComboFlag(true);
pField->SetEditFlag(pPr->IsEditComboBox());
pField->SetDefaultAppearance(pFontTT, m_oFont.GetSize(), oInfo.IsPlaceHolder() ? oPlaceHolderColor : oNormalColor);
if (!pPr->GetPlaceHolder().empty())
{
pField->SetPlaceHolderText(pPr->GetPlaceHolder(), oNormalColor, oPlaceHolderColor);
if (!pPr->IsEditComboBox())
{
// Для drop-down list в 0 позиции мы добавили плейсхолдер
if (oInfo.IsPlaceHolder())
unSelectedIndex = 0;
else if (0xFFFF != unSelectedIndex)
unSelectedIndex++;
}
}
if (!pPr->IsEditComboBox() && 0xFFFF != unSelectedIndex)
pField->SetSelectedIndex(unSelectedIndex);
}
else if (oInfo.IsCheckBox())
{
const CFormFieldInfo::CCheckBoxFormPr* pPr = oInfo.GetCheckBoxPr();
CCheckBoxField* pField = dynamic_cast<CCheckBoxField*>(pFieldBase);
if (!pField)
return S_FALSE;
pFieldBase->AddPageRect(m_pPage, TRect(MM_2_PT(dX), m_pPage->GetHeight() - MM_2_PT(dY), MM_2_PT(dX + dW), m_pPage->GetHeight() - MM_2_PT(dY + dH)));
pField->SetValue(pPr->IsChecked());
CFontCidTrueType* pCheckedFont = GetFont(pPr->GetCheckedFontName(), false, false);
CFontCidTrueType* pUncheckedFont = GetFont(pPr->GetUncheckedFontName(), false, false);
if (!pCheckedFont)
pCheckedFont = m_pFont;
if (!pUncheckedFont)
pUncheckedFont = m_pFont;
unsigned int unCheckedSymbol = pPr->GetCheckedSymbol();
unsigned int unUncheckedSymbol = pPr->GetUncheckedSymbol();
unsigned short ushCheckedCode = pCheckedFont->EncodeUnicode(unCheckedSymbol);
unsigned short ushUncheckedCode = pUncheckedFont->EncodeUnicode(unUncheckedSymbol);
TColor oColor = m_oBrush.GetTColor1();
pField->SetAppearance(L"", &ushCheckedCode, 1, pCheckedFont, L"", &ushUncheckedCode, 1, pUncheckedFont, TRgb(oColor.r, oColor.g, oColor.b), 1, m_oFont.GetSize(), 0, MM_2_PT(dH - oInfo.GetBaseLineOffset()));
}
else if (oInfo.IsPicture())
{
const CFormFieldInfo::CPictureFormPr* pPr = oInfo.GetPicturePr();
CPictureField* pField = dynamic_cast<CPictureField*>(pFieldBase);
pFieldBase->AddPageRect(m_pPage, TRect(MM_2_PT(dX), m_pPage->GetHeight() - MM_2_PT(dY), MM_2_PT(dX + dW), m_pPage->GetHeight() - MM_2_PT(dY + dH)));
pField->SetConstantProportions(pPr->IsConstantProportions());
pField->SetRespectBorders(pPr->IsRespectBorders());
pField->SetScaleType(static_cast<CPictureField::EScaleType>(pPr->GetScaleType()));
pField->SetShift(pPr->GetShiftX() / 1000.0, (1000 - pPr->GetShiftY()) / 1000.0);
std::wstring wsPath = pPr->GetPicturePath();
CImageDict* pImage = NULL;
if (wsPath.length())
{
Aggplus::CImage oImage(wsPath);
pImage = LoadImage(&oImage, 255);
}
pField->SetAppearance(pImage);
}
else if (oInfo.IsSignature())
{
const CFormFieldInfo::CSignatureFormPr* pPr = oInfo.GetSignaturePr();
CSignatureField* pField = dynamic_cast<CSignatureField*>(pFieldBase);
if (!pField)
return S_FALSE;
pFieldBase->AddPageRect(m_pPage, TRect(MM_2_PT(dX), m_pPage->GetHeight() - MM_2_PT(dY), MM_2_PT(dX + dW), m_pPage->GetHeight() - MM_2_PT(dY + dH)));
pField->SetName(pPr->GetName());
pField->SetReason(pPr->GetReason());
pField->SetContact(pPr->GetContact());
pField->SetDate(pPr->GetDate());
std::wstring wsPath = pPr->GetPicturePath();
CImageDict* pImage = NULL;
if (!wsPath.empty())
{
Aggplus::CImage oImage(wsPath);
pImage = LoadImage(&oImage, 255);
}
pField->SetAppearance(pImage);
// TODO Реализовать, когда появится поддержка CSignatureField
pField->SetCert();
}
// Выставляем имя в конце, потому что там возможно копирование настроек поля в новое родительское поле, поэтому к текущему моменту
// все настройки должны быть выставлены
if (!bRadioButton)
{
std::wstring wsKey = oInfo.GetKey();
if (L"" != wsKey)
pFieldBase->SetFieldName(wsKey);
else
pFieldBase->SetFieldName(m_oFieldsManager.GetNewFieldName());
}
return S_OK;
}
//----------------------------------------------------------------------------------------
// Дополнительные функции Pdf рендерера
//----------------------------------------------------------------------------------------
HRESULT CPdfWriter::CommandDrawTextPdf(const std::wstring& bsUnicodeText, const unsigned int* pGids, const unsigned int unGidsCount, const std::wstring& bsSrcCodeText, const double& dX, const double& dY, const double& dW, const double& dH)
{
return S_OK;
}
HRESULT CPdfWriter::PathCommandTextPdf(const std::wstring& bsUnicodeText, const unsigned int* pGids, const unsigned int unGidsCount, const std::wstring& bsSrcCodeText, const double& dX, const double& dY, const double& dW, const double& dH)
{
return S_OK;
}
HRESULT CPdfWriter::DrawImage1bpp(NSImages::CPixJbig2* pImageBuffer, const unsigned int& unWidth, const unsigned int& unHeight, const double& dX, const double& dY, const double& dW, const double& dH)
{
m_oCommandManager.Flush();
if (!IsPageValid() || !pImageBuffer)
return S_OK;
m_pPage->GrSave();
UpdateTransform();
CImageDict* pPdfImage = m_pDocument->CreateImage();
pPdfImage->LoadBW(pImageBuffer, unWidth, unHeight);
m_pPage->DrawImage(pPdfImage, MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY - dH), MM_2_PT(dW), MM_2_PT(dH));
m_pPage->GrRestore();
return S_OK;
}
HRESULT CPdfWriter::EnableBrushRect(const LONG& lEnable)
{
m_oBrush.EnableBrushRect(LONG_2_BOOL(lEnable));
return S_OK;
}
HRESULT CPdfWriter::SetLinearGradient(const double& dX0, const double& dY0, const double& dX1, const double& dY1)
{
m_oBrush.SetType(c_BrushTypeLinearGradient);
m_oBrush.SetLinearGradientPattern(dX0, dY0, dX1, dY1);
return S_OK;
}
HRESULT CPdfWriter::SetRadialGradient(const double& dX0, const double& dY0, const double& dR0, const double& dX1, const double& dY1, const double& dR1)
{
m_oBrush.SetType(c_BrushTypeRadialGradient);
m_oBrush.SetRadialGradientPattern(dX0, dY0, dR0, dX1, dY1, dR1);
return S_OK;
}
HRESULT CPdfWriter::DrawImageWith1bppMask(IGrObject* pImage, NSImages::CPixJbig2* pMaskBuffer, const unsigned int& unMaskWidth, const unsigned int& unMaskHeight, const double& dX, const double& dY, const double& dW, const double& dH)
{
m_oCommandManager.Flush();
if (!IsPageValid() || !pMaskBuffer || !pImage)
return S_OK;
m_pPage->GrSave();
UpdateTransform();
CImageDict* pPdfImage = LoadImage((Aggplus::CImage*)pImage, 255);
pPdfImage->LoadMask(pMaskBuffer, unMaskWidth, unMaskHeight);
m_pPage->DrawImage(pPdfImage, MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY - dH), MM_2_PT(dW), MM_2_PT(dH));
m_pPage->GrRestore();
return S_OK;
}
std::pair<int, int> CPdfWriter::GetPageRef(int nPageIndex)
{
return m_pDocument->GetPageRef(nPageIndex);
}
bool CPdfWriter::EditPage(PdfWriter::CPage* pNewPage)
{
if (!IsValid())
return false;
m_oCommandManager.Flush();
m_pPage = pNewPage;
if (m_pPage)
{
m_dPageWidth = PT_2_MM(m_pPage->GetWidth());
m_dPageHeight = PT_2_MM(m_pPage->GetHeight());
Reset();
return true;
}
return false;
}
bool CPdfWriter::AddPage(int nPageIndex)
{
if (!IsValid())
return false;
m_oCommandManager.Flush();
m_pPage = m_pDocument->AddPage(nPageIndex);
if (m_pPage)
{
m_pPage->SetWidth(MM_2_PT(m_dPageWidth));
m_pPage->SetHeight(MM_2_PT(m_dPageHeight));
Reset();
return true;
}
return false;
}
bool CPdfWriter::DeletePage(int nPageIndex)
{
return m_pDocument->DeletePage(nPageIndex);
}
bool CPdfWriter::EditClose()
{
if (!IsValid())
return false;
m_oCommandManager.Flush();
unsigned int nPagesCount = m_pDocument->GetPagesCount();
for (int nIndex = 0, nCount = m_vDestinations.size(); nIndex < nCount; ++nIndex)
{
TDestinationInfo& oInfo = m_vDestinations.at(nIndex);
if (nPagesCount > oInfo.unDestPage)
{
AddLink(oInfo.pPage, oInfo.dX, oInfo.dY, oInfo.dW, oInfo.dH, oInfo.dDestX, oInfo.dDestY, oInfo.unDestPage);
m_vDestinations.erase(m_vDestinations.begin() + nIndex);
nIndex--;
nCount--;
}
}
return true;
}
void CPdfWriter::PageRotate(int nRotate)
{
if (m_pPage)
m_pPage->SetRotate(nRotate);
}
void CPdfWriter::Sign(const double& dX, const double& dY, const double& dW, const double& dH, const std::wstring& wsPicturePath, ICertificate* pCertificate)
{
CImageDict* pImage = NULL;
if (!wsPicturePath.empty())
{
Aggplus::CImage oImage(wsPicturePath);
pImage = LoadImage(&oImage, 255);
}
m_pDocument->Sign(TRect(MM_2_PT(dX), m_pPage->GetHeight() - MM_2_PT(dY), MM_2_PT(dX + dW), m_pPage->GetHeight() - MM_2_PT(dY + dH)),
pImage, pCertificate);
}
std::wstring CPdfWriter::GetEditPdfPath()
{
return m_pDocument->GetEditPdfPath();
}
//----------------------------------------------------------------------------------------
// Внутренние функции
//----------------------------------------------------------------------------------------
PdfWriter::CImageDict* CPdfWriter::LoadImage(Aggplus::CImage* pImage, const BYTE& nAlpha)
{
int nImageW = abs((int)pImage->GetWidth());
int nImageH = abs((int)pImage->GetHeight());
BYTE* pData = pImage->GetData();
int nStride = 4 * nImageW;
// Картинки совсем маленьких размеров нельзя делать Jpeg2000
bool bJpeg = false;
if (nImageH < 100 || nImageW < 100 || m_pDocument->IsPDFA())
bJpeg = true;
if (nImageH <= 0 || nImageW <= 0)
return NULL;
// TODO: Пока не разберемся как в CxImage управлять параметрами кодирования нельзя писать в Jpeg2000,
// т.к. файлы получаются гораздо больше и конвертация идет намного дольше.
bJpeg = true;
// Пробегаемся по картинке и определяем есть ли у нас альфа-канал
bool bAlpha = false;
CBgraFrame oFrame;
if (m_pDocument->IsPDFA())
{
BYTE* pCopyImage = new BYTE[4 * nImageW * nImageH];
if (!pCopyImage)
return NULL;
::memcpy(pCopyImage, pData, 4 * nImageW * nImageH);
BYTE* pDataMem = pCopyImage;
for (int nIndex = 0, nSize = nImageW * nImageH; nIndex < nSize; nIndex++)
{
if (pDataMem[3] < 32)
{
pDataMem[0] = 255;
pDataMem[1] = 255;
pDataMem[2] = 255;
}
pDataMem += 4;
}
oFrame.put_Width(nImageW);
oFrame.put_Height(nImageH);
oFrame.put_Data(pCopyImage);// +4 * (nImageH - 1) * nImageW);
oFrame.put_Stride(-4* nImageW);
}
else
{
BYTE* pDataMem = pData;
for (int nIndex = 0, nSize = nImageW * nImageH; nIndex < nSize; nIndex++)
{
// making full-transparent pixels white
if (pDataMem[3] == 0)
{
pDataMem[0] = 255;
pDataMem[1] = 255;
pDataMem[2] = 255;
}
if (!bAlpha && (pDataMem[3] < 255))
{
bAlpha = true;
}
pDataMem += 4;
}
oFrame.FromImage(pImage);
}
oFrame.SetJpegQuality(85.0);
BYTE* pBuffer = NULL;
int nBufferSize = 0;
if (!oFrame.Encode(pBuffer, nBufferSize, bJpeg ? _CXIMAGE_FORMAT_JPG : _CXIMAGE_FORMAT_JP2))
return NULL;
if (!pBuffer || !nBufferSize)
return NULL;
CImageDict* pPdfImage = m_pDocument->CreateImage();
if (bAlpha || nAlpha < 255)
pPdfImage->LoadSMask(pData, nImageW, nImageH, nAlpha, (pImage->GetStride() >= 0) ? false : true);
if (bJpeg)
pPdfImage->LoadJpeg(pBuffer, nBufferSize, nImageW, nImageH);
else
pPdfImage->LoadJpx(pBuffer, nBufferSize, nImageW, nImageH);
free(pBuffer);
return pPdfImage;
}
bool CPdfWriter::DrawImage(Aggplus::CImage* pImage, const double& dX, const double& dY, const double& dW, const double& dH, const BYTE& nAlpha)
{
CImageDict* pPdfImage = LoadImage(pImage, nAlpha);
if (!pPdfImage)
return false;
m_pPage->GrSave();
UpdateTransform();
m_pPage->DrawImage(pPdfImage, MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY - dH), MM_2_PT(dW), MM_2_PT(dH));
m_pPage->GrRestore();
return true;
}
bool CPdfWriter::DrawText(unsigned char* pCodes, const unsigned int& unLen, const double& dX, const double& dY)
{
if (!pCodes || !unLen)
return false;
CTransform& t = m_oTransform;
m_oCommandManager.SetTransform(t.m11, -t.m12, -t.m21, t.m22, MM_2_PT(t.dx + t.m21 * m_dPageHeight), MM_2_PT(m_dPageHeight - m_dPageHeight * t.m22 - t.dy));
CRendererTextCommand* pText = m_oCommandManager.AddText(pCodes, unLen, MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY));
pText->SetFont(m_pFont);
pText->SetSize(m_oFont.GetSize());
pText->SetColor(m_oBrush.GetColor1());
pText->SetAlpha((BYTE)m_oBrush.GetAlpha1());
pText->SetCharSpace(MM_2_PT(m_oFont.GetCharSpace()));
pText->SetNeedDoBold(m_oFont.IsNeedDoBold());
pText->SetNeedDoItalic(m_oFont.IsNeedDoItalic());
return true;
}
bool CPdfWriter::PathCommandDrawText(unsigned int* pUnicodes, unsigned int unLen, const double& dX, const double& dY, const unsigned int* pGids)
{
unsigned char* pCodes = EncodeString(pUnicodes, unLen, pGids);
if (!pCodes)
return false;
m_oPath.AddText(m_pFont, pCodes, unLen * 2, MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY), m_oFont.GetSize(), MM_2_PT(m_oFont.GetCharSpace()));
return true;
}
void CPdfWriter::UpdateFont()
{
m_bNeedUpdateTextFont = false;
std::wstring wsFontPath = m_oFont.GetPath();
LONG lFaceIndex = m_oFont.GetFaceIndex();
if (L"" == wsFontPath)
GetFontPath(m_oFont.GetName(), m_oFont.IsBold(), m_oFont.IsItalic(), wsFontPath, lFaceIndex);
m_oFont.SetNeedDoBold(false);
m_oFont.SetNeedDoItalic(false);
m_pFont = NULL;
if (L"" != wsFontPath)
{
m_pFont = GetFont(wsFontPath, lFaceIndex);
if (m_pFont)
{
if (m_oFont.IsItalic() && !m_pFont->IsItalic())
m_oFont.SetNeedDoItalic(true);
if (m_oFont.IsBold() && !m_pFont->IsBold())
m_oFont.SetNeedDoBold(true);
}
}
}
void CPdfWriter::GetFontPath(const std::wstring &wsFontName, const bool &bBold, const bool &bItalic, std::wstring& wsFontPath, LONG& lFaceIndex)
{
bool bFind = false;
for (int nIndex = 0, nCount = m_vFonts.size(); nIndex < nCount; nIndex++)
{
TFontInfo& oInfo = m_vFonts.at(nIndex);
if (oInfo.wsFontName == wsFontName && oInfo.bBold == bBold && oInfo.bItalic == bItalic)
{
wsFontPath = oInfo.wsFontPath;
lFaceIndex = oInfo.lFaceIndex;
bFind = true;
break;
}
}
if (!bFind)
{
NSFonts::CFontSelectFormat oFontSelect;
oFontSelect.wsName = new std::wstring(wsFontName);
oFontSelect.bItalic = new INT(bItalic ? 1 : 0);
oFontSelect.bBold = new INT(bBold ? 1 : 0);
NSFonts::CFontInfo* pFontInfo = m_pFontManager->GetFontInfoByParams(oFontSelect, false);
if (!NSFonts::CFontInfo::CanEmbedForPreviewAndPrint(pFontInfo->m_usType))
{
oFontSelect.Fill(pFontInfo);
if (NULL != oFontSelect.usType)
*oFontSelect.usType = NSFONTS_EMBEDDING_RIGHTS_PRINT_AND_PREVIEW;
else
oFontSelect.usType = new USHORT(NSFONTS_EMBEDDING_RIGHTS_PRINT_AND_PREVIEW);
pFontInfo = m_pFontManager->GetFontInfoByParams(oFontSelect, false);
}
wsFontPath = pFontInfo->m_wsFontPath;
lFaceIndex = pFontInfo->m_lIndex;
m_vFonts.push_back(TFontInfo(wsFontName, bBold, bItalic, wsFontPath, lFaceIndex));
}
}
PdfWriter::CFontCidTrueType* CPdfWriter::GetFont(const std::wstring& wsFontPath, const LONG& lFaceIndex)
{
PdfWriter::CFontCidTrueType* pFont = NULL;
if (L"" != wsFontPath)
{
pFont = m_pDocument->FindCidTrueTypeFont(wsFontPath, lFaceIndex);
if (pFont)
return pFont;
// TODO: Пока мы здесь предполагаем, что шрифты только либо TrueType, либо OpenType
if (!m_pFontManager->LoadFontFromFile(wsFontPath, lFaceIndex, 10, 72, 72))
{
std::wcout << L"PDF Writer: Can't load fontfile " << wsFontPath.c_str() << "\n";
return NULL;
}
std::wstring wsFontType = m_pFontManager->GetFontType();
if (L"TrueType" == wsFontType || L"OpenType" == wsFontType || L"CFF" == wsFontType)
pFont = m_pDocument->CreateCidTrueTypeFont(wsFontPath, lFaceIndex);
}
return pFont;
}
PdfWriter::CFontCidTrueType* CPdfWriter::GetFont(const std::wstring& wsFontName, const bool& bBold, const bool& bItalic)
{
std::wstring wsFontPath;
LONG lFaceIndex;
GetFontPath(wsFontName, bBold, bItalic, wsFontPath, lFaceIndex);
return GetFont(wsFontPath, lFaceIndex);
}
void CPdfWriter::UpdateTransform()
{
CTransform& t = m_oTransform;
m_pPage->SetTransform(t.m11, -t.m12, -t.m21, t.m22, MM_2_PT(t.dx + t.m21 * m_dPageHeight), MM_2_PT(m_dPageHeight - m_dPageHeight * t.m22 - t.dy));
}
void CPdfWriter::UpdatePen()
{
TColor oColor = m_oPen.GetTColor();
m_pPage->SetStrokeColor(oColor.r, oColor.g, oColor.b);
m_pPage->SetStrokeAlpha((unsigned char)m_oPen.GetAlpha());
m_pPage->SetLineWidth(MM_2_PT(m_oPen.GetSize()));
LONG lDashCount = 0;
double* pDashPattern = NULL;
LONG lDashStyle = m_oPen.GetDashStyle();
if (Aggplus::DashStyleSolid == lDashStyle)
{
// Ничего не делаем
}
else if (Aggplus::DashStyleCustom == lDashStyle)
{
double *pDashPatternMM = m_oPen.GetDashPattern(lDashCount);
if (pDashPatternMM && lDashCount)
{
pDashPattern = new double[lDashCount];
if (pDashPattern)
{
for (LONG lIndex = 0; lIndex < lDashCount; lIndex++)
{
pDashPattern[lIndex] = MM_2_PT(pDashPatternMM[lIndex]);
}
}
}
}
else
{
// TODO: Реализовать другие типы пунктирных линий
}
if (pDashPattern && lDashCount)
{
m_pPage->SetDash(pDashPattern, lDashCount, MM_2_PT(m_oPen.GetDashOffset()));
delete[] pDashPattern;
}
LONG lCapStyle = m_oPen.GetStartCapStyle();
if (Aggplus::LineCapRound == lCapStyle)
m_pPage->SetLineCap(linecap_Round);
else if (Aggplus::LineCapSquare == lCapStyle)
m_pPage->SetLineCap(linecap_ProjectingSquare);
else
m_pPage->SetLineCap(linecap_Butt);
LONG lJoinStyle = m_oPen.GetJoinStyle();
if (Aggplus::LineJoinBevel == lJoinStyle)
m_pPage->SetLineJoin(linejoin_Bevel);
else if (Aggplus::LineJoinMiter == lJoinStyle)
{
m_pPage->SetLineJoin(linejoin_Miter);
m_pPage->SetMiterLimit(MM_2_PT(m_oPen.GetMiter()));
}
else
m_pPage->SetLineJoin(linejoin_Round);
}
void CPdfWriter::UpdateBrush(NSFonts::IApplicationFonts* pAppFonts)
{
m_pShading = NULL;
m_pShadingExtGrState = NULL;
LONG lBrushType = m_oBrush.GetType();
if (c_BrushTypeTexture == lBrushType)
{
std::wstring wsTexturePath = m_oBrush.GetTexturePath();
CImageFileFormatChecker oImageFormat(wsTexturePath);
CImageDict* pImage = NULL;
int nImageW = 0;
int nImageH = 0;
if (_CXIMAGE_FORMAT_JPG == oImageFormat.eFileType || _CXIMAGE_FORMAT_JP2 == oImageFormat.eFileType)
{
pImage = m_pDocument->CreateImage();
CBgraFrame oFrame;
oFrame.OpenFile(wsTexturePath);
nImageH = oFrame.get_Height();
nImageW = oFrame.get_Width();
if (pImage)
{
if (_CXIMAGE_FORMAT_JPG == oImageFormat.eFileType)
pImage->LoadJpeg(wsTexturePath.c_str(), nImageW, nImageH, oFrame.IsGrayScale());
else
pImage->LoadJpx(wsTexturePath.c_str(), nImageW, nImageH);
}
}
else if (_CXIMAGE_FORMAT_WMF == oImageFormat.eFileType ||
_CXIMAGE_FORMAT_EMF == oImageFormat.eFileType ||
_CXIMAGE_FORMAT_SVM == oImageFormat.eFileType ||
_CXIMAGE_FORMAT_SVG == oImageFormat.eFileType)
{
// TODO: Реализовать отрисовку метафайлов по-нормальному
MetaFile::IMetaFile* pMeta = MetaFile::Create(pAppFonts);
pMeta->LoadFromFile(wsTexturePath.c_str());
double dL, dR, dT, dB;
m_oPath.GetBounds(dL, dT, dR, dB);
double dNewW = std::max(10.0, dR - dL) / 72 * 300;
std::wstring wsTempFile = GetTempFile();
pMeta->ConvertToRaster(wsTempFile.c_str(), _CXIMAGE_FORMAT_PNG, dNewW);
RELEASEOBJECT(pMeta);
Aggplus::CImage oImage(wsTempFile);
nImageW = abs((int)oImage.GetWidth());
nImageH = abs((int)oImage.GetHeight());
pImage = LoadImage(&oImage, 255);
}
else
{
Aggplus::CImage oImage(wsTexturePath);
nImageW = abs((int)oImage.GetWidth());
nImageH = abs((int)oImage.GetHeight());
pImage = LoadImage(&oImage, 255);
}
if (pImage)
{
BYTE nAlpha = m_oBrush.GetTextureAlpha();
if (0xFF != nAlpha)
pImage->AddTransparency(nAlpha);
LONG lTextureMode = m_oBrush.GetTextureMode();
double dW = 10;
double dH = 10;
double dL, dR, dT, dB;
CBrushState::TBrushRect& oRect = m_oBrush.GetBrushRect();
if (!oRect.bUse)
{
m_oPath.GetBounds(dL, dT, dR, dB);
}
else
{
dL = MM_2_PT(oRect.dLeft);
dB = MM_2_PT(m_dPageHeight - oRect.dTop);
dR = MM_2_PT(oRect.dLeft + oRect.dWidth);
dT = MM_2_PT(m_dPageHeight - oRect.dTop - oRect.dHeight);
}
double dXStepSpacing = 0, dYStepSpacing = 0;
if (c_BrushTextureModeStretch == lTextureMode)
{
// Растягиваем картинку по размерам пата
dW = std::max(10.0, dR - dL);
dH = std::max(10.0, dB - dT);
// Чтобы избавиться от погрешностей из-за которых могут возникать полоски или обрезание картинки,
// удвоим расстрояние между соседними тайлами. Плохого тут нет, т.к. нам нужен всего 1 тайл
dXStepSpacing = dW;
dYStepSpacing = dH;
}
else
{
// Размеры картинки заданы в пикселях. Размеры тайла - это размеры картинки в пунктах.
dW = nImageW * 72 / 96;
dH = nImageH * 72 / 96;
}
// Нам нужно, чтобы левый нижний угол границ нашего пата являлся точкой переноса для матрицы преобразования.
CMatrix* pMatrix = m_pPage->GetTransform();
pMatrix->Apply(dL, dT);
CMatrix oPatternMatrix = *pMatrix;
oPatternMatrix.x = dL;
oPatternMatrix.y = dT;
m_pPage->SetPatternColorSpace(m_pDocument->CreateImageTilePattern(dW, dH, pImage, &oPatternMatrix, imagetilepatterntype_Default, dXStepSpacing, dYStepSpacing));
}
}
else if (c_BrushTypeHatch1 == lBrushType)
{
std::wstring wsHatchType = m_oBrush.GetTexturePath();
double dW = 8 * 72 / 96;
double dH = 8 * 72 / 96;
TColor oColor1 = m_oBrush.GetTColor1();
TColor oColor2 = m_oBrush.GetTColor2();
BYTE nAlpha1 = (BYTE)m_oBrush.GetAlpha1();
BYTE nAlpha2 = (BYTE)m_oBrush.GetAlpha2();
m_pPage->SetPatternColorSpace(m_pDocument->CreateHatchPattern(dW, dH, oColor1.r, oColor1.g, oColor1.b, nAlpha1, oColor2.r, oColor2.g, oColor2.b, nAlpha2, wsHatchType));
}
else if (c_BrushTypeRadialGradient == lBrushType || c_BrushTypeLinearGradient == lBrushType)
{
TColor* pGradientColors;
double* pPoints;
LONG lCount;
m_oBrush.GetGradientColors(pGradientColors, pPoints, lCount);
if (lCount > 0)
{
unsigned char* pColors = new unsigned char[3 * lCount];
unsigned char* pAlphas = new unsigned char[lCount];
if (pColors)
{
for (LONG lIndex = 0; lIndex < lCount; lIndex++)
{
pColors[3 * lIndex + 0] = pGradientColors[lIndex].r;
pColors[3 * lIndex + 1] = pGradientColors[lIndex].g;
pColors[3 * lIndex + 2] = pGradientColors[lIndex].b;
pAlphas[lIndex] = pGradientColors[lIndex].a;
}
if (c_BrushTypeLinearGradient == lBrushType)
{
double dX0, dY0, dX1, dY1;
m_oBrush.GetLinearGradientPattern(dX0, dY0, dX1, dY1);
m_pShading = m_pDocument->CreateAxialShading(m_pPage, MM_2_PT(dX0), MM_2_PT(m_dPageHeight - dY0), MM_2_PT(dX1), MM_2_PT(m_dPageHeight - dY1), pColors, pAlphas, pPoints, lCount, m_pShadingExtGrState);
}
else //if (c_BrushTypeRadialGradient == lBrushType)
{
double dX0, dY0, dR0, dX1, dY1, dR1;
m_oBrush.GetRadialGradientPattern(dX0, dY0, dR0, dX1, dY1, dR1);
m_pShading = m_pDocument->CreateRadialShading(m_pPage, MM_2_PT(dX0), MM_2_PT(m_dPageHeight - dY0), MM_2_PT(dR0), MM_2_PT(dX1), MM_2_PT(m_dPageHeight - dY1), MM_2_PT(dR1), pColors, pAlphas, pPoints, lCount, m_pShadingExtGrState);
}
delete[] pColors;
delete[] pAlphas;
}
}
}
else// if (c_BrushTypeSolid == lBrushType)
{
TColor oColor1 = m_oBrush.GetTColor1();
m_pPage->SetFillColor(oColor1.r, oColor1.g, oColor1.b);
m_pPage->SetFillAlpha((unsigned char)m_oBrush.GetAlpha1());
}
}
void CPdfWriter::Reset()
{
m_oPen.Reset();
m_oBrush.Reset();
m_oFont.Reset();
m_oPath.Clear();
// clear font!!!
m_oFont.SetName(L"");
m_oFont.SetSize(-1);
m_oFont.SetStyle(1 << 5);
m_lClipDepth = 0;
}
static inline void UpdateMaxMinPoints(double& dMinX, double& dMinY, double& dMaxX, double& dMaxY, const double& dX, const double& dY)
{
if (dX < dMinX)
dMinX = dX;
if (dX > dMaxX)
dMaxX = dX;
if (dY < dMinY)
dMinY = dY;
if (dY > dMaxY)
dMaxY = dY;
}
void CPdfWriter::CPath::Draw(PdfWriter::CPage* pPage, bool bStroke, bool bFill, bool bEoFill)
{
for (int nIndex = 0, nCount = m_vCommands.size(); nIndex < nCount; nIndex++)
{
CPathCommandBase* pCommand = m_vCommands.at(nIndex);
pCommand->Draw(pPage);
}
if (bStroke && !bFill && !bEoFill)
pPage->Stroke();
else if (bStroke && bFill)
pPage->FillStroke();
else if (bStroke && bEoFill)
pPage->EoFillStroke();
else if (bFill)
pPage->Fill();
else if (bEoFill)
pPage->EoFill();
else
pPage->EndPath();
}
void CPdfWriter::CPath::Clip(PdfWriter::CPage* pPage, bool bEvenOdd)
{
for (int nIndex = 0, nCount = m_vCommands.size(); nIndex < nCount; nIndex++)
{
CPathCommandBase* pCommand = m_vCommands.at(nIndex);
pCommand->Draw(pPage);
}
if (bEvenOdd)
pPage->Eoclip();
else
pPage->Clip();
pPage->EndPath();
}
void CPdfWriter::CPath::GetLastPoint(double& dX, double& dY)
{
dX = 0;
dY = 0;
bool bFindMoveTo = false;
for (int nIndex = m_vCommands.size() - 1; nIndex >= 0; nIndex--)
{
CPathCommandBase* pCommand = m_vCommands.at(nIndex);
if (rendererpathcommand_Close == pCommand->GetType())
{
bFindMoveTo = true;
continue;
}
else
{
pCommand->GetLastPoint(dX, dY);
if (!bFindMoveTo || rendererpathcommand_MoveTo == pCommand->GetType())
break;
}
}
}
void CPdfWriter::CPath::GetBounds(double& dL, double& dT, double& dR, double& dB)
{
GetLastPoint(dL, dT);
dR = dL;
dB = dT;
for (int nIndex = 0, nCount = m_vCommands.size(); nIndex < nCount; nIndex++)
{
CPathCommandBase* pCommand = m_vCommands.at(nIndex);
pCommand->UpdateBounds(dL, dT, dR, dB);
}
}
void CPdfWriter::CPath::CPathMoveTo::Draw(PdfWriter::CPage* pPage)
{
pPage->MoveTo(x, y);
}
void CPdfWriter::CPath::CPathMoveTo::UpdateBounds(double& dL, double& dT, double& dR, double& dB)
{
UpdateMaxMinPoints(dL, dT, dR, dB, x, y);
}
void CPdfWriter::CPath::CPathLineTo::Draw(PdfWriter::CPage* pPage)
{
pPage->LineTo(x, y);
}
void CPdfWriter::CPath::CPathLineTo::UpdateBounds(double& dL, double& dT, double& dR, double& dB)
{
UpdateMaxMinPoints(dL, dT, dR, dB, x, y);
}
void CPdfWriter::CPath::CPathCurveTo::Draw(PdfWriter::CPage* pPage)
{
pPage->CurveTo(x1, y1, x2, y2, xe, ye);
}
void CPdfWriter::CPath::CPathCurveTo::UpdateBounds(double& dL, double& dT, double& dR, double& dB)
{
UpdateMaxMinPoints(dL, dT, dR, dB, x1, y1);
UpdateMaxMinPoints(dL, dT, dR, dB, x2, y2);
UpdateMaxMinPoints(dL, dT, dR, dB, xe, ye);
}
void CPdfWriter::CPath::CPathArcTo::Draw(PdfWriter::CPage* pPage)
{
if (sweepAngle >= 360 - 0.001)
pPage->Ellipse(x + w / 2, y + h / 2, w / 2, h / 2);
else
pPage->EllipseArcTo(x + w / 2, y + h / 2, w / 2, h / 2, 360 - startAngle, 360 - (startAngle + sweepAngle), sweepAngle > 0 ? true : false);
}
void CPdfWriter::CPath::CPathArcTo::UpdateBounds(double& dL, double& dT, double& dR, double& dB)
{
UpdateMaxMinPoints(dL, dT, dR, dB, x, y);
UpdateMaxMinPoints(dL, dT, dR, dB, x + w, y + h);
}
void CPdfWriter::CPath::CPathClose::Draw(PdfWriter::CPage* pPage)
{
pPage->ClosePath();
}
void CPdfWriter::CPath::CPathClose::UpdateBounds(double& dL, double& dT, double& dR, double& dB)
{
}
void CPdfWriter::CPath::CPathText::Draw(PdfWriter::CPage* pPage)
{
// TODO: Если данная команда будет часто вызываться, тогда ее нужно будет оптимизировать, точно также как это делается в обычном тексте
pPage->BeginText();
pPage->SetFontAndSize(font, fontSize);
pPage->SetCharSpace(charSpace);
pPage->SetTextRenderingMode(textrenderingmode_Stroke);
pPage->DrawText(x, y, codes, codesCount);
pPage->EndText();
}
void CPdfWriter::CPath::CPathText::UpdateBounds(double& dL, double& dT, double& dR, double& dB)
{
UpdateMaxMinPoints(dL, dT, dR, dB, x, y);
}
void CPdfWriter::CBrushState::Reset()
{
m_lType = c_BrushTypeSolid;
m_oColor1.Set(0);
m_oColor2.Set(0);
m_nAlpha1 = 255;
m_nAlpha2 = 255;
m_wsTexturePath = L"";
m_lTextureMode = c_BrushTextureModeStretch;
m_nTextureAlpha = 255;
m_dLinearAngle = 0;
m_oRect.Reset();
if (m_pShadingColors)
delete[] m_pShadingColors;
if (m_pShadingPoints)
delete[] m_pShadingPoints;
m_pShadingColors = NULL;
m_pShadingPoints = NULL;
m_lShadingPointsCount = 0;
}
void CPdfWriter::AddLink(PdfWriter::CPage* pPage, const double& dX, const double& dY, const double& dW, const double& dH, const double& dDestX, const double& dDestY, const unsigned int& unDestPage)
{
CPage* pCurPage = pPage;
CPage* pDestPage = m_pDocument->GetPage(unDestPage);
if (!pCurPage || !pDestPage)
return;
CDestination* pDestination = m_pDocument->CreateDestination(unDestPage);
if (!pDestination)
return;
pDestination->SetXYZ(MM_2_PT(dDestX), pDestPage->GetHeight() - MM_2_PT(dDestY), 0);
CAnnotation* pAnnot = m_pDocument->CreateLinkAnnot(pCurPage, TRect(MM_2_PT(dX), pCurPage->GetHeight() - MM_2_PT(dY), MM_2_PT(dX + dW), m_pPage->GetHeight() - MM_2_PT(dY + dH)), pDestination);
pAnnot->SetBorderStyle(EBorderSubtype::border_subtype_Solid, 0);
}
bool CPdfWriter::IsValid()
{
return m_bValid;
}
bool CPdfWriter::IsPageValid()
{
if (!IsValid() || !m_pPage)
return false;
return true;
}
void CPdfWriter::SetError()
{
m_bValid = false;
}
unsigned char* CPdfWriter::EncodeString(const unsigned int *pUnicodes, const unsigned int& unCount, const unsigned int *pGIDs)
{
if (m_bNeedUpdateTextFont)
UpdateFont();
if (!m_pFont)
return NULL;
unsigned char* pCodes = new unsigned char[unCount * 2];
if (!pCodes)
return NULL;
for (unsigned int unIndex = 0; unIndex < unCount; unIndex++)
{
unsigned short ushCode;
if (pGIDs)
ushCode = m_pFont->EncodeGID(pGIDs[unIndex], &pUnicodes[unIndex], 1);
else
ushCode = m_pFont->EncodeUnicode(pUnicodes[unIndex]);
pCodes[2 * unIndex + 0] = (ushCode >> 8) & 0xFF;
pCodes[2 * unIndex + 1] = ushCode & 0xFF;
}
return pCodes;
}
unsigned char* CPdfWriter::EncodeGID(const unsigned int& unGID, const unsigned int* pUnicodes, const unsigned int& unUnicodesCount)
{
if (m_bNeedUpdateTextFont)
UpdateFont();
if (!m_pFont)
return NULL;
unsigned char* pCodes = new unsigned char[2];
if (!pCodes)
return NULL;
unsigned short ushCode = m_pFont->EncodeGID(unGID, pUnicodes, unUnicodesCount);
pCodes[0] = (ushCode >> 8) & 0xFF;
pCodes[1] = ushCode & 0xFF;
return pCodes;
}
std::wstring CPdfWriter::GetDownloadFile(const std::wstring& sUrl)
{
std::wstring::size_type n1 = sUrl.find(L"www.");
std::wstring::size_type n2 = sUrl.find(L"http://");
std::wstring::size_type n3 = sUrl.find(L"ftp://");
std::wstring::size_type n4 = sUrl.find(L"https://");
std::wstring::size_type nMax = 3;
bool bIsNeedDownload = false;
if (n1 != std::wstring::npos && n1 < nMax)
bIsNeedDownload = true;
else if (n2 != std::wstring::npos && n2 < nMax)
bIsNeedDownload = true;
else if (n3 != std::wstring::npos && n3 < nMax)
bIsNeedDownload = true;
else if (n4 != std::wstring::npos && n4 < nMax)
bIsNeedDownload = true;
if (!bIsNeedDownload)
return L"";
std::wstring sTempFile = GetTempFile();
NSNetwork::NSFileTransport::CFileDownloader oDownloader(sUrl, false);
oDownloader.SetFilePath(sTempFile);
if (oDownloader.DownloadSync())
return sTempFile;
if (NSFile::CFileBinary::Exists(sTempFile))
NSFile::CFileBinary::Remove(sTempFile);
return L"";
}