mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-02-10 18:05:41 +08:00
1861 lines
52 KiB
C++
1861 lines
52 KiB
C++
/*
|
||
* (c) Copyright Ascensio System SIA 2010-2019
|
||
*
|
||
* This program is a free software product. You can redistribute it and/or
|
||
* modify it under the terms of the GNU Affero General Public License (AGPL)
|
||
* version 3 as published by the Free Software Foundation. In accordance with
|
||
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
|
||
* that Ascensio System SIA expressly excludes the warranty of non-infringement
|
||
* of any third-party rights.
|
||
*
|
||
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
|
||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
|
||
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||
*
|
||
* You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
|
||
* street, Riga, Latvia, EU, LV-1050.
|
||
*
|
||
* The interactive user interfaces in modified source and object code versions
|
||
* of the Program must display Appropriate Legal Notices, as required under
|
||
* Section 5 of the GNU AGPL version 3.
|
||
*
|
||
* Pursuant to Section 7(b) of the License you must retain the original Product
|
||
* logo when distributing the program. Pursuant to Section 7(e) we decline to
|
||
* grant you any rights under trademark law for use of our trademarks.
|
||
*
|
||
* All the Product's GUI elements, including illustrations and icon sets, as
|
||
* well as technical writing content are licensed under the terms of the
|
||
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
|
||
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||
*
|
||
*/
|
||
#ifndef _PDF_WRITER_H
|
||
#define _PDF_WRITER_H
|
||
|
||
#include "../../DesktopEditor/graphics/IRenderer.h"
|
||
#include "../../DesktopEditor/graphics/pro/Fonts.h"
|
||
#include "../../DesktopEditor/graphics/pro/Image.h"
|
||
#include "../../DesktopEditor/xmlsec/src/include/Certificate.h"
|
||
|
||
#include <string>
|
||
#include <vector>
|
||
#include <algorithm>
|
||
#include <math.h>
|
||
|
||
namespace PdfWriter
|
||
{
|
||
class CDocument;
|
||
class CPage;
|
||
class CFontCidTrueType;
|
||
class CFontTrueType;
|
||
class CImageDict;
|
||
class CShading;
|
||
class CExtGrState;
|
||
class CFontDict;
|
||
}
|
||
|
||
namespace Aggplus
|
||
{
|
||
class CImage;
|
||
}
|
||
|
||
class CRendererCommandBase;
|
||
class CRendererTextCommand;
|
||
class CConvertFromBinParams;
|
||
|
||
class CPdfWriter
|
||
{
|
||
public:
|
||
CPdfWriter(NSFonts::IApplicationFonts* pAppFonts, bool isPDFA = false);
|
||
~CPdfWriter();
|
||
int SaveToFile(const std::wstring& wsPath);
|
||
void SetPassword(const std::wstring& wsPassword);
|
||
void SetDocumentID(const std::wstring& wsDocumentID);
|
||
void SetTempFolder(const std::wstring& wsPath);
|
||
std::wstring GetTempDirectory();
|
||
std::wstring GetTempFile();
|
||
//----------------------------------------------------------------------------------------
|
||
// Тип рендерера
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT get_Type(LONG* lType);
|
||
//----------------------------------------------------------------------------------------
|
||
// Функции для работы со страницей
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT NewPage();
|
||
HRESULT get_Height(double* dHeight);
|
||
HRESULT put_Height(const double& dHeight);
|
||
HRESULT get_Width(double* dWidth);
|
||
HRESULT put_Width(const double& dWidth);
|
||
HRESULT get_DpiX(double* dDpiX);
|
||
HRESULT get_DpiY(double* dDpiY);
|
||
//----------------------------------------------------------------------------------------
|
||
// Функции для работы с Pen
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT get_PenColor(LONG* lColor);
|
||
HRESULT put_PenColor(const LONG& lColor);
|
||
HRESULT get_PenAlpha(LONG* lAlpha);
|
||
HRESULT put_PenAlpha(const LONG& lAlpha);
|
||
HRESULT get_PenSize(double* dSize);
|
||
HRESULT put_PenSize(const double& dSize);
|
||
HRESULT get_PenDashStyle(BYTE* nDashStyle);
|
||
HRESULT put_PenDashStyle(const BYTE& nDashStyle);
|
||
HRESULT get_PenLineStartCap(BYTE* nCapStyle);
|
||
HRESULT put_PenLineStartCap(const BYTE& nCapStyle);
|
||
HRESULT get_PenLineEndCap(BYTE* nCapStyle);
|
||
HRESULT put_PenLineEndCap(const BYTE& nCapStyle);
|
||
HRESULT get_PenLineJoin(BYTE* nJoinStyle);
|
||
HRESULT put_PenLineJoin(const BYTE& nJoinStyle);
|
||
HRESULT get_PenDashOffset(double* dOffset);
|
||
HRESULT put_PenDashOffset(const double& dOffset);
|
||
HRESULT get_PenAlign(LONG* lAlign);
|
||
HRESULT put_PenAlign(const LONG& lAlign);
|
||
HRESULT get_PenMiterLimit(double* dMiter);
|
||
HRESULT put_PenMiterLimit(const double& dMiter);
|
||
HRESULT PenDashPattern(double* pPattern, LONG lCount);
|
||
//----------------------------------------------------------------------------------------
|
||
// Функции для работы с Brush
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT get_BrushType(LONG* lType);
|
||
HRESULT put_BrushType(const LONG& lType);
|
||
HRESULT get_BrushColor1(LONG* lColor);
|
||
HRESULT put_BrushColor1(const LONG& lColor);
|
||
HRESULT get_BrushAlpha1(LONG* lAlpha);
|
||
HRESULT put_BrushAlpha1(const LONG& lAlpha);
|
||
HRESULT get_BrushColor2(LONG* lColor);
|
||
HRESULT put_BrushColor2(const LONG& lColor);
|
||
HRESULT get_BrushAlpha2(LONG* lAlpha);
|
||
HRESULT put_BrushAlpha2(const LONG& lAlpha);
|
||
HRESULT get_BrushTexturePath(std::wstring* wsPath);
|
||
HRESULT put_BrushTexturePath(const std::wstring& wsPath);
|
||
HRESULT get_BrushTextureMode(LONG* lMode);
|
||
HRESULT put_BrushTextureMode(const LONG& lMode);
|
||
HRESULT get_BrushTextureAlpha(LONG* lAlpha);
|
||
HRESULT put_BrushTextureAlpha(const LONG& lAlpha);
|
||
HRESULT get_BrushLinearAngle(double* dAngle);
|
||
HRESULT put_BrushLinearAngle(const double& dAngle);
|
||
HRESULT BrushRect(const INT& nVal, const double& dLeft, const double& dTop, const double& dWidth, const double& dHeight);
|
||
HRESULT BrushBounds(const double& dLeft, const double& dTop, const double& dWidth, const double& dHeight);
|
||
HRESULT put_BrushGradientColors(LONG* pColors, double* pPositions, LONG lCount);
|
||
//----------------------------------------------------------------------------------------
|
||
// Функции для работы со шрифтами
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT get_FontName(std::wstring* wsName);
|
||
HRESULT put_FontName(const std::wstring& wsName);
|
||
HRESULT get_FontPath(std::wstring* wsPath);
|
||
HRESULT put_FontPath(const std::wstring& wsPath);
|
||
HRESULT get_FontSize(double* dSize);
|
||
HRESULT put_FontSize(const double& dSize);
|
||
HRESULT get_FontStyle(LONG* lStyle);
|
||
HRESULT put_FontStyle(const LONG& lStyle);
|
||
HRESULT get_FontStringGID(INT* bGid);
|
||
HRESULT put_FontStringGID(const INT& bGid);
|
||
HRESULT get_FontCharSpace(double* dSpace);
|
||
HRESULT put_FontCharSpace(const double& dSpace);
|
||
HRESULT get_FontFaceIndex(int* lFaceIndex);
|
||
HRESULT put_FontFaceIndex(const int& lFaceIndex);
|
||
//----------------------------------------------------------------------------------------
|
||
// Функции для вывода текста
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT CommandDrawTextCHAR (const LONG& lUnicode, const double& dX, const double& dY, const double& dW, const double& dH);
|
||
HRESULT CommandDrawTextExCHAR(const LONG& lUnicode, const LONG& lGid, const double& dX, const double& dY, const double& dW, const double& dH);
|
||
HRESULT CommandDrawText (const std::wstring& wsUnicodeText, const double& dX, const double& dY, const double& dW, const double& dH);
|
||
HRESULT CommandDrawTextEx (const std::wstring& wsUnicodeText, const unsigned int* pGids, const unsigned int nGidsCount, const double& dX, const double& dY, const double& dW, const double& dH);
|
||
HRESULT CommandDrawTextCHAR2 (unsigned int* unUnicode, const unsigned int& unUnicodeCount, const unsigned int& unGid, const double& dX, const double& dY, const double& dW, const double& dH);
|
||
//----------------------------------------------------------------------------------------
|
||
// Маркеры команд
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT BeginCommand(const DWORD& lType);
|
||
HRESULT EndCommand(const DWORD& lType);
|
||
//----------------------------------------------------------------------------------------
|
||
// Функции для работы с патом
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT PathCommandMoveTo(const double& dX, const double& dY);
|
||
HRESULT PathCommandLineTo(const double& dX, const double& dY);
|
||
HRESULT PathCommandLinesTo(double* pPoints, const int& nCount);
|
||
HRESULT PathCommandCurveTo(const double& dX1, const double& dY1, const double& dX2, const double& dY2, const double& dXe, const double& dYe);
|
||
HRESULT PathCommandCurvesTo(double* pPoints, const int& nCount);
|
||
HRESULT PathCommandArcTo(const double& dX, const double& dY, const double& dW, const double& dH, const double& dStartAngle, const double& dSweepAngle);
|
||
HRESULT PathCommandClose();
|
||
HRESULT PathCommandEnd();
|
||
HRESULT DrawPath(NSFonts::IApplicationFonts* pAppFonts, const LONG& lType);
|
||
HRESULT PathCommandStart();
|
||
HRESULT PathCommandGetCurrentPoint(double* dX, double* dY);
|
||
HRESULT PathCommandTextCHAR (const LONG& lUnicode, const double& dX, const double& dY, const double& dW, const double& dH);
|
||
HRESULT PathCommandTextExCHAR(const LONG& lUnicode, const LONG& lGid, const double& dX, const double& dY, const double& dW, const double& dH);
|
||
HRESULT PathCommandText (const std::wstring& wsUnicodeText, const double& dX, const double& dY, const double& dW, const double& dH);
|
||
HRESULT PathCommandTextEx (const std::wstring& wsUnicodeText, const unsigned int* pGids, const unsigned int nGidsCount, const double& dX, const double& dY, const double& dW, const double& dH);
|
||
//----------------------------------------------------------------------------------------
|
||
// Функции для вывода изображений
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT DrawImage(IGrObject* pImage, const double& dX, const double& dY, const double& dW, const double& dH);
|
||
HRESULT DrawImageFromFile(NSFonts::IApplicationFonts* pAppFonts, const std::wstring& wsImagePath, const double& dX, const double& dY, const double& dW, const double& dH, const BYTE& nAlpha = 255);
|
||
//----------------------------------------------------------------------------------------
|
||
// Функции для выставления преобразования
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT SetTransform(const double& dM11, const double& dM12, const double& dM21, const double& dM22, const double& dX, const double& dY);
|
||
HRESULT GetTransform(double* dM11, double* dM12, double* dM21, double* dM22, double* dX, double* dY);
|
||
HRESULT ResetTransform();
|
||
//----------------------------------------------------------------------------------------
|
||
// Тип клипа
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT get_ClipMode(LONG* lMode);
|
||
HRESULT put_ClipMode(const LONG& lMode);
|
||
//----------------------------------------------------------------------------------------
|
||
// Дополнительные функции
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT CommandLong(const LONG& lType, const LONG& lCommand);
|
||
HRESULT CommandDouble(const LONG& lType, const double& dCommand);
|
||
HRESULT CommandString(const LONG& lType, const std::wstring& sCommand);
|
||
HRESULT AddHyperlink(const double& dX, const double& dY, const double& dW, const double& dH, const std::wstring& wsUrl, const std::wstring& wsTooltip);
|
||
HRESULT AddLink(const double& dX, const double& dY, const double& dW, const double& dH, const double& dDestX, const double& dDestY, const int& nPage);
|
||
HRESULT AddFormField(NSFonts::IApplicationFonts* pAppFonts, const CFormFieldInfo& oInfo);
|
||
//----------------------------------------------------------------------------------------
|
||
// Дополнительные функции Pdf рендерера
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT CommandDrawTextPdf(const std::wstring& bsUnicodeText, const unsigned int* pGids, const unsigned int nGidsCount, const std::wstring& wsSrcCodeText, const double& dX, const double& dY, const double& dW, const double& dH);
|
||
HRESULT PathCommandTextPdf(const std::wstring& bsUnicodeText, const unsigned int* pGids, const unsigned int nGidsCount, const std::wstring& bsSrcCodeText, const double& dX, const double& dY, const double& dW, const double& dH);
|
||
HRESULT DrawImage1bpp(NSImages::CPixJbig2* pImageBuffer, const unsigned int& unWidth, const unsigned int& unHeight, const double& dX, const double& dY, const double& dW, const double& dH);
|
||
HRESULT EnableBrushRect(const LONG& lEnable);
|
||
HRESULT SetLinearGradient(const double& dX1, const double& dY1, const double& dX2, const double& dY2);
|
||
HRESULT SetRadialGradient(const double& dX1, const double& dY1, const double& dR1, const double& dX2, const double& dY2, const double& dR2);
|
||
HRESULT DrawImageWith1bppMask(IGrObject* pImage, NSImages::CPixJbig2* pMaskBuffer, const unsigned int& unMaskWidth, const unsigned int& unMaskHeight, const double& dX, const double& dY, const double& dW, const double& dH);
|
||
|
||
//----------------------------------------------------------------------------------------
|
||
// Дополнительные функции для дозаписи Pdf
|
||
//----------------------------------------------------------------------------------------
|
||
std::pair<int, int> GetPageRef(int nPageIndex);
|
||
bool EditPage(PdfWriter::CPage* pNewPage);
|
||
bool AddPage(int nPageIndex);
|
||
bool DeletePage(int nPageIndex);
|
||
bool EditClose();
|
||
void PageRotate(int nRotate);
|
||
void Sign(const double& dX, const double& dY, const double& dW, const double& dH, const std::wstring& wsPicturePath, ICertificate* pCertificate);
|
||
std::wstring GetEditPdfPath();
|
||
PdfWriter::CDocument* GetPDFDocument() { return m_pDocument; }
|
||
|
||
private:
|
||
PdfWriter::CImageDict* LoadImage(Aggplus::CImage* pImage, const BYTE& nAlpha);
|
||
bool DrawImage(Aggplus::CImage* pImage, const double& dX, const double& dY, const double& dW, const double& dH, const BYTE& nAlpha);
|
||
bool DrawText(unsigned char* pCodes, const unsigned int& unLen, const double& dX, const double& dY);
|
||
bool PathCommandDrawText(unsigned int* pUnicodes, unsigned int unLen, const double& dX, const double& dY, const unsigned int* pGids = NULL);
|
||
void UpdateFont();
|
||
void GetFontPath(const std::wstring& wsFontName, const bool& bBold, const bool& bItalic, std::wstring& wsFontPath, LONG& lFaceIndex);
|
||
PdfWriter::CFontCidTrueType* GetFont(const std::wstring& wsFontPath, const LONG& lFontIndex);
|
||
PdfWriter::CFontCidTrueType* GetFont(const std::wstring& wsFontName, const bool& bBold, const bool& bItalic);
|
||
void UpdateTransform();
|
||
void UpdatePen();
|
||
void UpdateBrush(NSFonts::IApplicationFonts* pAppFonts);
|
||
void Reset();
|
||
bool IsValid();
|
||
bool IsPageValid();
|
||
void SetError();
|
||
void AddLink(PdfWriter::CPage* pPage, const double& dX, const double& dY, const double& dW, const double& dH, const double& dDestX, const double& dDestY, const unsigned int& unDestPage);
|
||
unsigned char* EncodeString(const unsigned int* pUnicodes, const unsigned int& unUnicodesCount, const unsigned int* pGIDs = NULL);
|
||
unsigned char* EncodeGID(const unsigned int& unGID, const unsigned int* pUnicodes, const unsigned int& unUnicodesCount);
|
||
std::wstring GetDownloadFile(const std::wstring& sUrl);
|
||
|
||
private:
|
||
|
||
struct TFontInfo
|
||
{
|
||
TFontInfo(const std::wstring& fontName, const bool& bold, const bool& italic, const std::wstring& fontPath, const LONG& faceIndex)
|
||
{
|
||
wsFontName = fontName;
|
||
bBold = bold;
|
||
bItalic = italic;
|
||
wsFontPath = fontPath;
|
||
lFaceIndex = faceIndex;
|
||
}
|
||
|
||
std::wstring wsFontName;
|
||
bool bBold;
|
||
bool bItalic;
|
||
std::wstring wsFontPath;
|
||
LONG lFaceIndex;
|
||
};
|
||
struct TColor
|
||
{
|
||
TColor()
|
||
{
|
||
lColor = 0;
|
||
r = 0;
|
||
g = 0;
|
||
b = 0;
|
||
a = 255;
|
||
}
|
||
TColor(const LONG& _lColor)
|
||
{
|
||
Set(_lColor);
|
||
}
|
||
|
||
void Set(const LONG& _lColor)
|
||
{
|
||
lColor = _lColor;
|
||
|
||
r = (unsigned char)(lColor & 0xFF);
|
||
g = (unsigned char)((lColor >> 8) & 0xFF);
|
||
b = (unsigned char)((lColor >> 16) & 0xFF);
|
||
a = (unsigned char)((lColor >> 24) & 0xFF);
|
||
}
|
||
void operator=(const LONG& _lColor)
|
||
{
|
||
Set(_lColor);
|
||
}
|
||
void Set(BYTE _r, BYTE _g, BYTE _b, BYTE _a = 255)
|
||
{
|
||
r = _r;
|
||
g = _g;
|
||
b = _b;
|
||
a = _a;
|
||
|
||
lColor = (LONG)(((LONG)r) | ((LONG)g << 8) | ((LONG)b << 16) | ((LONG)a << 24));
|
||
}
|
||
|
||
LONG lColor;
|
||
BYTE r;
|
||
BYTE g;
|
||
BYTE b;
|
||
BYTE a;
|
||
};
|
||
class CPenState
|
||
{
|
||
public:
|
||
|
||
CPenState()
|
||
{
|
||
m_pDashPattern = NULL;
|
||
Reset();
|
||
}
|
||
~CPenState()
|
||
{
|
||
if (m_pDashPattern)
|
||
delete[] m_pDashPattern;
|
||
}
|
||
inline LONG GetColor()
|
||
{
|
||
return m_oColor.lColor;
|
||
}
|
||
inline void SetColor(const LONG& lColor)
|
||
{
|
||
m_oColor.Set(lColor);
|
||
}
|
||
inline TColor GetTColor()
|
||
{
|
||
return m_oColor;
|
||
}
|
||
inline LONG GetAlpha()
|
||
{
|
||
return m_nAlpha;
|
||
}
|
||
inline void SetAlpha(const LONG& lAlpha)
|
||
{
|
||
m_nAlpha = (BYTE)(std::max)(0, (std::min)(255, (int)lAlpha));
|
||
}
|
||
inline double GetSize()
|
||
{
|
||
return m_dSize;
|
||
}
|
||
inline void SetSize(const double& dSize)
|
||
{
|
||
m_dSize = dSize;
|
||
}
|
||
inline BYTE GetDashStyle()
|
||
{
|
||
return m_nDashStyle;
|
||
}
|
||
inline void SetDashStyle(const BYTE& nDashStyle)
|
||
{
|
||
m_nDashStyle = nDashStyle;
|
||
}
|
||
inline BYTE GetStartCapStyle()
|
||
{
|
||
return m_nStartCapStyle;
|
||
}
|
||
inline void SetStartCapStyle(const BYTE& nCapStyle)
|
||
{
|
||
m_nStartCapStyle = nCapStyle;
|
||
}
|
||
inline BYTE GetEndCapStyle()
|
||
{
|
||
return m_nEndCapStyle;
|
||
}
|
||
inline void SetEndCapStyle(const BYTE& nCapStyle)
|
||
{
|
||
m_nEndCapStyle = nCapStyle;
|
||
}
|
||
inline BYTE GetJoinStyle()
|
||
{
|
||
return m_nJoinStyle;
|
||
}
|
||
inline void SetJoinStyle(const BYTE& nJoinStyle)
|
||
{
|
||
m_nJoinStyle = nJoinStyle;
|
||
}
|
||
inline double GetDashOffset()
|
||
{
|
||
return m_dDashOffset;
|
||
}
|
||
inline void SetDashOffset(const double& dOffset)
|
||
{
|
||
m_dDashOffset = dOffset;
|
||
}
|
||
inline LONG GetAlign()
|
||
{
|
||
return m_lAlign;
|
||
}
|
||
inline void SetAlign(const LONG& lAlign)
|
||
{
|
||
m_lAlign = lAlign;
|
||
}
|
||
inline double GetMiter()
|
||
{
|
||
return m_dMiter;
|
||
}
|
||
inline void SetMiter(const double& dMiter)
|
||
{
|
||
m_dMiter = dMiter;
|
||
}
|
||
inline void SetDashPattern(const double* pPattern, const LONG& lSize)
|
||
{
|
||
if (m_pDashPattern)
|
||
{
|
||
delete[] m_pDashPattern;
|
||
m_pDashPattern = NULL;
|
||
}
|
||
|
||
m_lDashPatternSize = 0;
|
||
|
||
if (!pPattern || !lSize)
|
||
{
|
||
m_lDashPatternSize = 0;
|
||
m_pDashPattern = NULL;
|
||
}
|
||
else
|
||
{
|
||
// Избавляемся от нулей, потому что все pdf-ридеры плохо их воспринимают
|
||
std::vector<double> vPattern;
|
||
for (LONG lIndex = 0; lIndex < lSize; lIndex++)
|
||
{
|
||
if (lIndex > 1 && fabs(pPattern[lIndex]) < 0.001)
|
||
{
|
||
if (0 == lIndex % 2)
|
||
{
|
||
if (fabs(pPattern[lIndex + 1]) < 0.001)
|
||
{
|
||
lIndex++;
|
||
}
|
||
else if (lIndex + 1 < lSize)
|
||
{
|
||
size_t nPatternSize = vPattern.size();
|
||
vPattern.at(nPatternSize - 1) = vPattern.at(nPatternSize - 1) + pPattern[lIndex + 1];
|
||
lIndex++;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
size_t nPatternSize = vPattern.size();
|
||
vPattern.at(nPatternSize - 2) = vPattern.at(nPatternSize - 2) + vPattern.at(nPatternSize - 1);
|
||
vPattern.pop_back();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
vPattern.push_back(pPattern[lIndex]);
|
||
}
|
||
}
|
||
|
||
size_t nPatternSize = vPattern.size();
|
||
if (nPatternSize > 0)
|
||
{
|
||
m_pDashPattern = new double[nPatternSize];
|
||
if (m_pDashPattern)
|
||
{
|
||
for (int nIndex = 0; nIndex < nPatternSize; nIndex++)
|
||
{
|
||
m_pDashPattern[nIndex] = vPattern.at(nIndex);
|
||
}
|
||
m_lDashPatternSize = nPatternSize;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
inline double*GetDashPattern(LONG& lSize)
|
||
{
|
||
lSize = m_lDashPatternSize;
|
||
return m_pDashPattern;
|
||
}
|
||
|
||
void Reset()
|
||
{
|
||
if (m_pDashPattern)
|
||
delete[] m_pDashPattern;
|
||
|
||
m_oColor.Set(0);
|
||
m_dSize = 0;
|
||
m_nAlpha = 255;
|
||
m_nStartCapStyle = Aggplus::LineCapRound;
|
||
m_nEndCapStyle = Aggplus::LineCapRound;
|
||
m_nJoinStyle = Aggplus::LineJoinRound;
|
||
|
||
m_lAlign = 0;
|
||
m_dMiter = 0;
|
||
|
||
m_nDashStyle = Aggplus::DashStyleSolid;
|
||
m_lDashPatternSize = 0;
|
||
m_pDashPattern = NULL;
|
||
|
||
m_dDashOffset = 0;
|
||
}
|
||
|
||
private:
|
||
|
||
double m_dSize;
|
||
TColor m_oColor;
|
||
BYTE m_nAlpha;
|
||
BYTE m_nStartCapStyle;
|
||
BYTE m_nEndCapStyle;
|
||
BYTE m_nJoinStyle;
|
||
|
||
LONG m_lAlign;
|
||
double m_dMiter;
|
||
|
||
BYTE m_nDashStyle;
|
||
double m_dDashOffset;
|
||
double*m_pDashPattern;
|
||
LONG m_lDashPatternSize;
|
||
|
||
};
|
||
class CBrushState
|
||
{
|
||
public:
|
||
struct TColorAndPoint
|
||
{
|
||
TColorAndPoint()
|
||
{
|
||
lColor = 0;
|
||
dPoint = 0;
|
||
bUse = false;
|
||
}
|
||
TColorAndPoint(const LONG& color, const double& point)
|
||
{
|
||
lColor = color;
|
||
dPoint = point;
|
||
bUse = true;
|
||
}
|
||
|
||
static bool Compare(const TColorAndPoint& oFirst, const TColorAndPoint& oSecond)
|
||
{
|
||
return (oFirst.dPoint < oSecond.dPoint);
|
||
}
|
||
static LONG GetLinearApprox(const TColorAndPoint& oPoint1, const TColorAndPoint& oPoint2, const double& dDstPoint)
|
||
{
|
||
double dPoint1 = oPoint1.dPoint;
|
||
double dPoint2 = oPoint2.dPoint;
|
||
LONG lColor1 = oPoint1.lColor;
|
||
LONG lColor2 = oPoint2.lColor;
|
||
|
||
double dDiff = dPoint2 - dPoint1;
|
||
if (fabs(dDiff) < 0)
|
||
return lColor1;
|
||
|
||
TColor oColor1 = lColor1;
|
||
TColor oColor2 = lColor2;
|
||
|
||
BYTE r = (BYTE)(std::max)(0, (std::min)(255, (int)(oColor1.r + (oColor2.r - oColor1.r) / dDiff * (dDstPoint - dPoint1))));
|
||
BYTE g = (BYTE)(std::max)(0, (std::min)(255, (int)(oColor1.g + (oColor2.g - oColor1.g) / dDiff * (dDstPoint - dPoint1))));
|
||
BYTE b = (BYTE)(std::max)(0, (std::min)(255, (int)(oColor1.b + (oColor2.b - oColor1.b) / dDiff * (dDstPoint - dPoint1))));
|
||
BYTE a = (BYTE)(std::max)(0, (std::min)(255, (int)(oColor1.a + (oColor2.a - oColor1.a) / dDiff * (dDstPoint - dPoint1))));
|
||
|
||
TColor oResColor;
|
||
oResColor.Set(r, g, b, a);
|
||
return oResColor.lColor;
|
||
}
|
||
|
||
LONG lColor;
|
||
double dPoint;
|
||
bool bUse;
|
||
};
|
||
struct TBrushRect
|
||
{
|
||
TBrushRect()
|
||
{
|
||
Reset();
|
||
}
|
||
|
||
void Reset()
|
||
{
|
||
bUse = false;
|
||
nVal = 0;
|
||
dLeft = 0;
|
||
dTop = 0;
|
||
dWidth = 0;
|
||
dHeight = 0;
|
||
}
|
||
|
||
bool bUse;
|
||
int nVal;
|
||
double dLeft;
|
||
double dTop;
|
||
double dWidth;
|
||
double dHeight;
|
||
};
|
||
|
||
public:
|
||
CBrushState()
|
||
{
|
||
m_pShadingColors = NULL;
|
||
m_pShadingPoints = NULL;
|
||
m_lShadingPointsCount = 0;
|
||
Reset();
|
||
}
|
||
~CBrushState()
|
||
{
|
||
if (m_pShadingColors)
|
||
delete[] m_pShadingColors;
|
||
if (m_pShadingPoints)
|
||
delete[] m_pShadingPoints;
|
||
}
|
||
void Reset();
|
||
inline LONG GetType()
|
||
{
|
||
return m_lType;
|
||
}
|
||
inline void SetType(const LONG& lType)
|
||
{
|
||
m_lType = lType;
|
||
}
|
||
inline LONG GetColor1()
|
||
{
|
||
return m_oColor1.lColor;
|
||
}
|
||
inline TColor GetTColor1()
|
||
{
|
||
return m_oColor1;
|
||
}
|
||
inline void SetColor1(const LONG& lColor)
|
||
{
|
||
m_oColor1.Set(lColor);
|
||
}
|
||
inline LONG GetColor2()
|
||
{
|
||
return m_oColor2.lColor;
|
||
}
|
||
inline TColor GetTColor2()
|
||
{
|
||
return m_oColor2;
|
||
}
|
||
inline void SetColor2(const LONG& lColor)
|
||
{
|
||
m_oColor2.Set(lColor);
|
||
}
|
||
inline LONG GetAlpha1()
|
||
{
|
||
return m_nAlpha1;
|
||
}
|
||
inline void SetAlpha1(const LONG& lAlpha)
|
||
{
|
||
m_nAlpha1 = (BYTE)(std::max)(0, (std::min)(255, (int)lAlpha));
|
||
}
|
||
inline LONG GetAlpha2()
|
||
{
|
||
return m_nAlpha2;
|
||
}
|
||
inline void SetAlpha2(const LONG& lAlpha)
|
||
{
|
||
m_nAlpha2 = (BYTE)(std::max)(0, (std::min)(255, (int)lAlpha));
|
||
}
|
||
inline std::wstring GetTexturePath()
|
||
{
|
||
return m_wsTexturePath;
|
||
}
|
||
inline void SetTexturePath(const std::wstring& wsPath)
|
||
{
|
||
m_wsTexturePath = wsPath;
|
||
}
|
||
inline LONG GetTextureMode()
|
||
{
|
||
return m_lTextureMode;
|
||
}
|
||
inline void SetTextureMode(const LONG& lMode)
|
||
{
|
||
m_lTextureMode = lMode;
|
||
}
|
||
inline BYTE GetTextureAlpha()
|
||
{
|
||
return m_nTextureAlpha;
|
||
}
|
||
inline void SetTextureAlpha(const LONG& lAlpha)
|
||
{
|
||
m_nTextureAlpha = (BYTE)(std::max)(0, (std::min)(255, (int)lAlpha));
|
||
}
|
||
inline double GetLinearAngle()
|
||
{
|
||
return m_dLinearAngle;
|
||
}
|
||
inline void SetLinearAngle(const double& dAngle)
|
||
{
|
||
m_dLinearAngle = dAngle;
|
||
}
|
||
inline void SetGradientColors(LONG* pColors, double* pPoints, const LONG& lCount)
|
||
{
|
||
// Мы создаем упорядоченный по возрастанию массив, причем первая и последняя точки должны быть 0 и 1 соответственно.
|
||
if (m_pShadingColors)
|
||
{
|
||
delete[] m_pShadingColors;
|
||
m_pShadingColors = NULL;
|
||
}
|
||
|
||
if (m_pShadingPoints)
|
||
{
|
||
delete[] m_pShadingPoints;
|
||
m_pShadingPoints = NULL;
|
||
}
|
||
|
||
if (!pColors || !pPoints || !lCount)
|
||
return;
|
||
|
||
// Проверим вырожденный случай, когда задана либо 1 точка, либо несколько точек с одинковым значением
|
||
bool bIrregular = false;
|
||
if (1 == lCount)
|
||
{
|
||
bIrregular = true;
|
||
}
|
||
else
|
||
{
|
||
bIrregular = true;
|
||
for (LONG lIndex = 0; lIndex < lCount; lIndex++)
|
||
{
|
||
double dPoint1 = pPoints[lIndex];
|
||
for (LONG lIndex2 = lIndex + 1; lIndex2 < lCount; lIndex2++)
|
||
{
|
||
double dPoint2 = pPoints[lIndex2];
|
||
if (fabs(dPoint2 - dPoint1) > 0.00001)
|
||
{
|
||
bIrregular = false;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!bIrregular)
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (bIrregular)
|
||
{
|
||
if (1 == lCount)
|
||
{
|
||
m_pShadingPoints = new double[2];
|
||
m_pShadingColors = new TColor[2];
|
||
|
||
if (!m_pShadingColors || !m_pShadingColors)
|
||
return;
|
||
|
||
m_pShadingPoints[0] = 0.0;
|
||
m_pShadingColors[0] = pColors[0];
|
||
m_pShadingPoints[1] = 1.0;
|
||
m_pShadingColors[1] = pColors[0];
|
||
m_lShadingPointsCount = 2;
|
||
}
|
||
else
|
||
{
|
||
if (pPoints[0] < 0)
|
||
{
|
||
m_pShadingPoints = new double[2];
|
||
m_pShadingColors = new TColor[2];
|
||
|
||
if (!m_pShadingColors || !m_pShadingColors)
|
||
return;
|
||
|
||
m_pShadingPoints[0] = 0.0;
|
||
m_pShadingColors[0] = pColors[lCount - 1];
|
||
m_pShadingPoints[1] = 1.0;
|
||
m_pShadingColors[1] = pColors[lCount - 1];
|
||
m_lShadingPointsCount = 2;
|
||
}
|
||
else if (pPoints[0] > 1)
|
||
{
|
||
m_pShadingPoints = new double[2];
|
||
m_pShadingColors = new TColor[2];
|
||
|
||
if (!m_pShadingColors || !m_pShadingColors)
|
||
return;
|
||
|
||
m_pShadingPoints[0] = 0.0;
|
||
m_pShadingColors[0] = pColors[0];
|
||
m_pShadingPoints[1] = 1.0;
|
||
m_pShadingColors[1] = pColors[0];
|
||
m_lShadingPointsCount = 2;
|
||
}
|
||
else
|
||
{
|
||
m_pShadingPoints = new double[4];
|
||
m_pShadingColors = new TColor[4];
|
||
|
||
if (!m_pShadingColors || !m_pShadingColors)
|
||
return;
|
||
|
||
m_pShadingPoints[0] = 0.0;
|
||
m_pShadingColors[0] = pColors[0];
|
||
m_pShadingPoints[1] = pPoints[0];
|
||
m_pShadingColors[1] = pColors[0];
|
||
m_pShadingPoints[2] = pPoints[lCount - 1];
|
||
m_pShadingColors[2] = pColors[lCount - 1];
|
||
m_pShadingPoints[3] = 1.0;
|
||
m_pShadingColors[3] = pColors[lCount - 1];
|
||
m_lShadingPointsCount = 4;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
std::vector<TColorAndPoint> vPoints;
|
||
for (LONG lIndex = 0; lIndex < lCount; lIndex++)
|
||
{
|
||
vPoints.push_back(TColorAndPoint(pColors[lIndex], pPoints[lIndex]));
|
||
}
|
||
std::sort(vPoints.begin(), vPoints.end(), TColorAndPoint::Compare);
|
||
|
||
LONG lMinIn = -1, lMaxIn = -1, lMinOut = -1, lMaxOut = -1;
|
||
for (LONG lIndex = 0; lIndex < lCount; lIndex++)
|
||
{
|
||
double dPoint = vPoints.at(lIndex).dPoint;
|
||
if (0 <= dPoint && dPoint <= 1)
|
||
{
|
||
if (-1 == lMinIn || dPoint < vPoints.at(lMinIn).dPoint)
|
||
lMinIn = lIndex;
|
||
|
||
if (-1 == lMaxIn || dPoint > vPoints.at(lMaxIn).dPoint)
|
||
lMaxIn = lIndex;
|
||
}
|
||
else if (dPoint < 0)
|
||
{
|
||
if (-1 == lMinOut || dPoint > vPoints.at(lMinOut).dPoint)
|
||
lMinOut = lIndex;
|
||
}
|
||
else// if (dPoint > 1)
|
||
{
|
||
if (-1 == lMaxOut || dPoint < vPoints.at(lMaxOut).dPoint)
|
||
lMaxOut = lIndex;
|
||
}
|
||
}
|
||
|
||
LONG lBeginIndex = lMinIn;
|
||
LONG lEndIndex = lMaxIn;
|
||
|
||
bool bNeed0 = true, bNeed1 = true;
|
||
if (-1 != lMinIn && vPoints.at(lMinIn).dPoint < 0.001)
|
||
{
|
||
bNeed0 = false;
|
||
lBeginIndex = lMinIn;
|
||
vPoints.at(lMinIn).dPoint = 0;
|
||
}
|
||
else if (-1 != lMinOut && vPoints.at(lMinOut).dPoint > -0.001)
|
||
{
|
||
bNeed0 = false;
|
||
lBeginIndex = lMinOut;
|
||
vPoints.at(lMinOut).dPoint = 0;
|
||
}
|
||
|
||
if (-1 != lMaxIn && vPoints.at(lMaxIn).dPoint > 0.999)
|
||
{
|
||
bNeed1 = false;
|
||
lEndIndex = lMaxIn;
|
||
vPoints.at(lEndIndex).dPoint = 1;
|
||
}
|
||
else if (-1 != lMaxOut && vPoints.at(lMaxOut).dPoint < 1.001)
|
||
{
|
||
bNeed1 = false;
|
||
lEndIndex = lMaxOut;
|
||
vPoints.at(lEndIndex).dPoint = 1;
|
||
}
|
||
|
||
std::vector<TColorAndPoint> vResPoints;
|
||
if (bNeed0)
|
||
{
|
||
LONG lIndex0, lIndex1;
|
||
if (-1 != lMinOut)
|
||
{
|
||
if (-1 != lMinIn)
|
||
{
|
||
lIndex0 = lMinOut;
|
||
lIndex1 = lMinIn;
|
||
}
|
||
else if (-1 != lMaxOut)
|
||
{
|
||
lIndex0 = lMinOut;
|
||
lIndex1 = lMaxOut;
|
||
}
|
||
else
|
||
{
|
||
lIndex0 = lMinIn - 1;
|
||
lIndex1 = lMinIn;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (-1 != lMinIn)
|
||
{
|
||
lIndex0 = lMinIn;
|
||
lIndex1 = lMinIn + 1;
|
||
}
|
||
else
|
||
{
|
||
lIndex0 = lMaxOut;
|
||
lIndex1 = lMaxOut + 1;
|
||
}
|
||
}
|
||
|
||
LONG lColor0 = TColorAndPoint::GetLinearApprox(vPoints.at(lIndex0), vPoints.at(lIndex1), 0);
|
||
vResPoints.push_back(TColorAndPoint(lColor0, 0));
|
||
}
|
||
|
||
if (-1 != lBeginIndex && -1 != lEndIndex)
|
||
{
|
||
for (LONG lIndex = lBeginIndex; lIndex <= lEndIndex; lIndex++)
|
||
{
|
||
vResPoints.push_back(vPoints.at(lIndex));
|
||
}
|
||
}
|
||
|
||
if (bNeed1)
|
||
{
|
||
LONG lIndex0, lIndex1;
|
||
if (-1 != lMaxOut)
|
||
{
|
||
if (-1 != lMaxIn)
|
||
{
|
||
lIndex0 = lMaxIn;
|
||
lIndex1 = lMaxOut;
|
||
}
|
||
else if (-1 != lMinOut)
|
||
{
|
||
lIndex0 = lMinOut;
|
||
lIndex1 = lMaxOut;
|
||
}
|
||
else
|
||
{
|
||
lIndex0 = lMaxOut;
|
||
lIndex1 = lMaxOut + 1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (-1 != lMaxIn)
|
||
{
|
||
lIndex0 = lMaxIn - 1;
|
||
lIndex1 = lMaxIn;
|
||
}
|
||
else
|
||
{
|
||
lIndex0 = lMinOut - 1;
|
||
lIndex1 = lMinOut;
|
||
}
|
||
}
|
||
|
||
LONG lColor1 = TColorAndPoint::GetLinearApprox(vPoints.at(lIndex0), vPoints.at(lIndex1), 1);
|
||
vResPoints.push_back(TColorAndPoint(lColor1, 1));
|
||
}
|
||
|
||
size_t lResCount = vResPoints.size();
|
||
if (lResCount == 0)
|
||
return;
|
||
|
||
m_pShadingColors = new TColor[lResCount];
|
||
m_pShadingPoints = new double[lResCount];
|
||
m_lShadingPointsCount = lResCount;
|
||
|
||
if (!m_pShadingColors || !m_pShadingPoints)
|
||
return;
|
||
|
||
for (LONG lIndex = 0; lIndex < lResCount; lIndex++)
|
||
{
|
||
m_pShadingColors[lIndex] = vResPoints.at(lIndex).lColor;
|
||
m_pShadingPoints[lIndex] = vResPoints.at(lIndex).dPoint;
|
||
}
|
||
}
|
||
}
|
||
inline void SetBrushRect(const int& nVal, const double& dLeft, const double& dTop, const double& dWidth, const double& dHeight)
|
||
{
|
||
m_oRect.nVal = nVal;
|
||
m_oRect.dLeft = dLeft;
|
||
m_oRect.dTop = dTop;
|
||
m_oRect.dWidth = dWidth;
|
||
m_oRect.dHeight = dHeight;
|
||
}
|
||
inline void EnableBrushRect(bool bEnable)
|
||
{
|
||
m_oRect.bUse = bEnable;
|
||
}
|
||
TBrushRect& GetBrushRect()
|
||
{
|
||
return m_oRect;
|
||
}
|
||
|
||
inline void SetLinearGradientPattern(const double& dX0, const double& dY0, const double& dX1, const double& dY1)
|
||
{
|
||
m_pShadingPattern[0] = dX0;
|
||
m_pShadingPattern[1] = dY0;
|
||
m_pShadingPattern[2] = dX1;
|
||
m_pShadingPattern[3] = dY1;
|
||
}
|
||
inline void SetRadialGradientPattern(const double& dX0, const double& dY0, const double& dR0, const double& dX1, const double& dY1, const double& dR1)
|
||
{
|
||
m_pShadingPattern[0] = dX0;
|
||
m_pShadingPattern[1] = dY0;
|
||
m_pShadingPattern[2] = dR0;
|
||
m_pShadingPattern[3] = dX1;
|
||
m_pShadingPattern[4] = dY1;
|
||
m_pShadingPattern[5] = dR1;
|
||
}
|
||
inline void GetLinearGradientPattern(double& dX0, double& dY0, double& dX1, double& dY1)
|
||
{
|
||
dX0 = m_pShadingPattern[0];
|
||
dY0 = m_pShadingPattern[1];
|
||
dX1 = m_pShadingPattern[2];
|
||
dY1 = m_pShadingPattern[3];
|
||
}
|
||
inline void GetRadialGradientPattern(double& dX0, double& dY0, double& dR0, double& dX1, double& dY1, double& dR1)
|
||
{
|
||
dX0 = m_pShadingPattern[0];
|
||
dY0 = m_pShadingPattern[1];
|
||
dR0 = m_pShadingPattern[2];
|
||
dX1 = m_pShadingPattern[3];
|
||
dY1 = m_pShadingPattern[4];
|
||
dR1 = m_pShadingPattern[5];
|
||
}
|
||
inline void GetGradientColors(TColor*& pColors, double*& pPoints, LONG& lCount)
|
||
{
|
||
pColors = m_pShadingColors;
|
||
pPoints = m_pShadingPoints;
|
||
lCount = m_lShadingPointsCount;
|
||
}
|
||
|
||
private:
|
||
|
||
LONG m_lType;
|
||
TColor m_oColor1;
|
||
TColor m_oColor2;
|
||
BYTE m_nAlpha1;
|
||
BYTE m_nAlpha2;
|
||
std::wstring m_wsTexturePath;
|
||
LONG m_lTextureMode;
|
||
BYTE m_nTextureAlpha;
|
||
double m_dLinearAngle;
|
||
TBrushRect m_oRect;
|
||
|
||
TColor* m_pShadingColors;
|
||
double* m_pShadingPoints;
|
||
LONG m_lShadingPointsCount;
|
||
double m_pShadingPattern[6]; // У линейного градиента x0, y0, x1, y1 (2 не используются), у радиального x0, y0, r0, x1, y1, r1
|
||
};
|
||
class CFontState
|
||
{
|
||
public:
|
||
|
||
CFontState() : m_wsPath(L""), m_wsName(L"Arial"), m_lStyle(0), m_bBold(false), m_bItalic(false), m_dCharSpace(0),
|
||
m_lFaceIndex(0), m_dSize(10), m_bGid(false), m_bNeedDoBold(false), m_bNeedDoItalic(false)
|
||
{
|
||
}
|
||
|
||
void Reset()
|
||
{
|
||
m_wsPath = L"";
|
||
m_wsName = L"Arial";
|
||
m_lStyle = 0;
|
||
m_bBold = false;
|
||
m_bItalic = false;
|
||
m_dCharSpace = 0;
|
||
m_lFaceIndex = 0;
|
||
m_dSize = 10;
|
||
m_bGid = false;
|
||
|
||
m_bNeedDoBold = false;
|
||
m_bNeedDoItalic = false;
|
||
}
|
||
|
||
inline std::wstring GetName()
|
||
{
|
||
return m_wsName;
|
||
}
|
||
inline void SetName(const std::wstring& wsName)
|
||
{
|
||
m_wsName = wsName;
|
||
}
|
||
inline std::wstring GetPath()
|
||
{
|
||
return m_wsPath;
|
||
}
|
||
inline void SetPath(const std::wstring& wsPath)
|
||
{
|
||
m_wsPath = wsPath;
|
||
}
|
||
inline double GetSize()
|
||
{
|
||
return m_dSize;
|
||
}
|
||
inline void SetSize(const double& dSize)
|
||
{
|
||
m_dSize = dSize;
|
||
}
|
||
inline LONG GetFaceIndex()
|
||
{
|
||
return m_lFaceIndex;
|
||
}
|
||
inline void SetFaceIndex(const LONG& lFaceIndex)
|
||
{
|
||
m_lFaceIndex = lFaceIndex;
|
||
}
|
||
inline LONG GetStyle()
|
||
{
|
||
return m_lStyle;
|
||
}
|
||
inline void SetStyle(const LONG& lStyle)
|
||
{
|
||
m_lStyle = lStyle;
|
||
m_bBold = (lStyle & 1 ? true : false);
|
||
m_bItalic = (lStyle & 2 ? true : false);
|
||
}
|
||
inline bool GetGid()
|
||
{
|
||
return m_bGid;
|
||
}
|
||
inline void SetGid(const bool& bGid)
|
||
{
|
||
m_bGid = bGid;
|
||
}
|
||
inline double GetCharSpace()
|
||
{
|
||
return m_dCharSpace;
|
||
}
|
||
inline void SetCharSpace(const double& dCharSpace)
|
||
{
|
||
m_dCharSpace = dCharSpace;
|
||
}
|
||
inline bool IsBold()
|
||
{
|
||
return m_bBold;
|
||
}
|
||
inline bool IsItalic()
|
||
{
|
||
return m_bItalic;
|
||
}
|
||
inline void SetNeedDoItalic(const bool& bNeedDoItalic)
|
||
{
|
||
m_bNeedDoItalic = bNeedDoItalic;
|
||
}
|
||
inline void SetNeedDoBold(const bool& bNeedDoBold)
|
||
{
|
||
m_bNeedDoBold = bNeedDoBold;
|
||
}
|
||
inline bool IsNeedDoItalic()
|
||
{
|
||
return m_bNeedDoItalic;
|
||
}
|
||
inline bool IsNeedDoBold()
|
||
{
|
||
return m_bNeedDoBold;
|
||
}
|
||
|
||
private:
|
||
|
||
std::wstring m_wsName;
|
||
std::wstring m_wsPath;
|
||
double m_dSize;
|
||
bool m_bGid;
|
||
LONG m_lFaceIndex;
|
||
LONG m_lStyle;
|
||
bool m_bBold;
|
||
bool m_bItalic;
|
||
double m_dCharSpace;
|
||
bool m_bNeedDoItalic;
|
||
bool m_bNeedDoBold;
|
||
};
|
||
class CPath
|
||
{
|
||
private:
|
||
|
||
enum EPathCommandType
|
||
{
|
||
rendererpathcommand_Unknown = 0x00,
|
||
rendererpathcommand_MoveTo = 0x01,
|
||
rendererpathcommand_LineTo = 0x02,
|
||
rendererpathcommand_CurveTo = 0x03,
|
||
rendererpathcommand_ArcTo = 0x04,
|
||
rendererpathcommand_Close = 0x05,
|
||
rendererpathcommand_TextChar = 0x06,
|
||
rendererpathcommand_Text = 0x07,
|
||
rendererpathcommand_TextExChar = 0x08,
|
||
rendererpathcommand_TextEx = 0x09
|
||
};
|
||
class CPathCommandBase
|
||
{
|
||
public:
|
||
CPathCommandBase()
|
||
{
|
||
}
|
||
virtual ~CPathCommandBase()
|
||
{
|
||
}
|
||
virtual void Draw(PdfWriter::CPage* pPage) = 0;
|
||
virtual void UpdateBounds(double& dL, double& dT, double& dR, double& dB) = 0;
|
||
virtual void GetLastPoint(double& dX, double& dY) = 0;
|
||
virtual EPathCommandType GetType() = 0;
|
||
};
|
||
class CPathMoveTo : public CPathCommandBase
|
||
{
|
||
public:
|
||
CPathMoveTo(const double& dX, const double& dY)
|
||
{
|
||
x = dX;
|
||
y = dY;
|
||
}
|
||
void GetLastPoint(double& dX, double& dY)
|
||
{
|
||
dX = x;
|
||
dY = y;
|
||
}
|
||
void Draw(PdfWriter::CPage* pPage);
|
||
void UpdateBounds(double& dL, double& dT, double& dR, double& dB);
|
||
EPathCommandType GetType()
|
||
{
|
||
return rendererpathcommand_MoveTo;
|
||
}
|
||
|
||
public:
|
||
|
||
double x;
|
||
double y;
|
||
};
|
||
class CPathLineTo : public CPathCommandBase
|
||
{
|
||
public:
|
||
CPathLineTo(const double& dX, const double& dY)
|
||
{
|
||
x = dX;
|
||
y = dY;
|
||
}
|
||
void GetLastPoint(double& dX, double& dY)
|
||
{
|
||
dX = x;
|
||
dY = y;
|
||
}
|
||
void Draw(PdfWriter::CPage* pPage);
|
||
void UpdateBounds(double& dL, double& dT, double& dR, double& dB);
|
||
EPathCommandType GetType()
|
||
{
|
||
return rendererpathcommand_LineTo;
|
||
}
|
||
|
||
public:
|
||
|
||
double x;
|
||
double y;
|
||
};
|
||
class CPathCurveTo : public CPathCommandBase
|
||
{
|
||
public:
|
||
CPathCurveTo(const double& dX1, const double& dY1, const double& dX2, const double& dY2, const double& dXe, const double& dYe)
|
||
{
|
||
x1 = dX1;
|
||
y1 = dY1;
|
||
x2 = dX2;
|
||
y2 = dY2;
|
||
xe = dXe;
|
||
ye = dYe;
|
||
}
|
||
void GetLastPoint(double& dX, double& dY)
|
||
{
|
||
dX = xe;
|
||
dY = ye;
|
||
}
|
||
void Draw(PdfWriter::CPage* pPage);
|
||
void UpdateBounds(double& dL, double& dT, double& dR, double& dB);
|
||
EPathCommandType GetType()
|
||
{
|
||
return rendererpathcommand_CurveTo;
|
||
}
|
||
|
||
public:
|
||
|
||
double x1;
|
||
double y1;
|
||
double x2;
|
||
double y2;
|
||
double xe;
|
||
double ye;
|
||
};
|
||
class CPathArcTo : public CPathCommandBase
|
||
{
|
||
public:
|
||
CPathArcTo(const double& dX, const double& dY, const double& dW, const double& dH, const double& dStartAngle, const double& dSweepAngle)
|
||
{
|
||
x = dX;
|
||
y = dY;
|
||
w = dW;
|
||
h = dH;
|
||
startAngle = dStartAngle;
|
||
sweepAngle = dSweepAngle;
|
||
}
|
||
void GetLastPoint(double& dX, double& dY)
|
||
{
|
||
// TODO: Надо грамотно пересчитать
|
||
dX = x;
|
||
dY = y;
|
||
}
|
||
void Draw(PdfWriter::CPage* pPage);
|
||
void UpdateBounds(double& dL, double& dT, double& dR, double& dB);
|
||
EPathCommandType GetType()
|
||
{
|
||
return rendererpathcommand_ArcTo;
|
||
}
|
||
|
||
public:
|
||
|
||
double x;
|
||
double y;
|
||
double w;
|
||
double h;
|
||
double startAngle;
|
||
double sweepAngle;
|
||
};
|
||
class CPathClose : public CPathCommandBase
|
||
{
|
||
public:
|
||
CPathClose()
|
||
{
|
||
}
|
||
void GetLastPoint(double& dX, double& dY)
|
||
{
|
||
// TODO: Надо грамотно пересчитать
|
||
dX = 0;
|
||
dY = 0;
|
||
}
|
||
void Draw(PdfWriter::CPage* pPage);
|
||
void UpdateBounds(double& dL, double& dT, double& dR, double& dB);
|
||
EPathCommandType GetType()
|
||
{
|
||
return rendererpathcommand_Close;
|
||
}
|
||
};
|
||
class CPathText : public CPathCommandBase
|
||
{
|
||
public:
|
||
CPathText(PdfWriter::CFontDict* pFont, unsigned char* pCodes, const unsigned int& unCodesCount, const double& dX, const double& dY, const double& dSize, const double& dCharSpace)
|
||
{
|
||
font = pFont;
|
||
codes = pCodes;
|
||
codesCount = unCodesCount;
|
||
x = dX;
|
||
y = dY;
|
||
fontSize = dSize;
|
||
charSpace = dCharSpace;
|
||
}
|
||
~CPathText()
|
||
{
|
||
RELEASEARRAYOBJECTS(codes);
|
||
}
|
||
void GetLastPoint(double& dX, double& dY)
|
||
{
|
||
dX = x;
|
||
dY = y;
|
||
}
|
||
void Draw(PdfWriter::CPage* pPage);
|
||
void UpdateBounds(double& dL, double& dT, double& dR, double& dB);
|
||
EPathCommandType GetType()
|
||
{
|
||
return rendererpathcommand_Text;
|
||
}
|
||
|
||
public:
|
||
|
||
PdfWriter::CFontDict* font;
|
||
unsigned char* codes;
|
||
unsigned int codesCount;
|
||
double x;
|
||
double y;
|
||
double fontSize;
|
||
double charSpace;
|
||
};
|
||
|
||
public:
|
||
|
||
CPath()
|
||
{
|
||
m_bIsMoveTo = false;
|
||
}
|
||
~CPath()
|
||
{
|
||
Clear();
|
||
}
|
||
|
||
bool MoveTo(const double& dX, const double& dY)
|
||
{
|
||
m_bIsMoveTo = true;
|
||
return Add(new CPathMoveTo(dX, dY));
|
||
}
|
||
bool LineTo(const double& dX, const double& dY)
|
||
{
|
||
if (!m_bIsMoveTo)
|
||
MoveTo(dX, dY);
|
||
|
||
return Add(new CPathLineTo(dX, dY));
|
||
}
|
||
bool CurveTo(double dX1, double dY1, double dX2, double dY2, double dXE, double dYE)
|
||
{
|
||
if (!m_bIsMoveTo)
|
||
MoveTo(dX1, dY1);
|
||
|
||
return Add(new CPathCurveTo(dX1, dY1, dX2, dY2, dXE, dYE));
|
||
}
|
||
bool ArcTo(double dX, double dY, double dW, double dH, double dStart, double dSweep)
|
||
{
|
||
if (!m_bIsMoveTo)
|
||
MoveTo(dX, dY);
|
||
|
||
return Add(new CPathArcTo(dX, dY, dW, dH, dStart, dSweep));
|
||
}
|
||
bool AddText(PdfWriter::CFontDict* pFont, unsigned char* pCodes, const unsigned int& unLen, const double& dX, const double& dY, const double& dSize, const double& dCharSpace)
|
||
{
|
||
return Add(new CPathText(pFont, pCodes, unLen, dX, dY, dSize, dCharSpace));
|
||
}
|
||
bool Close()
|
||
{
|
||
return Add(new CPathClose());
|
||
}
|
||
void Clear()
|
||
{
|
||
for (size_t nIndex = 0, nCount = m_vCommands.size(); nIndex < nCount; nIndex++)
|
||
{
|
||
CPathCommandBase* pCommand = m_vCommands.at(nIndex);
|
||
delete pCommand;
|
||
}
|
||
m_vCommands.clear();
|
||
m_bIsMoveTo = false;
|
||
}
|
||
bool IsMoveTo()
|
||
{
|
||
return m_bIsMoveTo;
|
||
}
|
||
void GetLastPoint(double& dX, double& dY);
|
||
void Draw(PdfWriter::CPage* pPage, bool bStroke, bool bFill, bool bEoFill);
|
||
void Clip(PdfWriter::CPage* pPage, bool bEvenOdd = false);
|
||
void GetBounds(double& dL, double& dT, double& dR, double& dB);
|
||
|
||
private:
|
||
|
||
bool Add(CPathCommandBase* pCommand)
|
||
{
|
||
if (pCommand)
|
||
{
|
||
m_vCommands.push_back(pCommand);
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
|
||
public:
|
||
|
||
std::vector<CPathCommandBase*> m_vCommands;
|
||
bool m_bIsMoveTo;
|
||
};
|
||
class CTransform
|
||
{
|
||
public:
|
||
|
||
CTransform()
|
||
{
|
||
Reset();
|
||
}
|
||
void operator=(const CTransform& oT)
|
||
{
|
||
m11 = oT.m11;
|
||
m12 = oT.m12;
|
||
m21 = oT.m21;
|
||
m22 = oT.m22;
|
||
dx = oT.dx;
|
||
dy = oT.dy;
|
||
}
|
||
void Reset()
|
||
{
|
||
m11 = 1.0;
|
||
m12 = 0.0;
|
||
m21 = 0.0;
|
||
m22 = 1.0;
|
||
dx = 0;
|
||
dy = 0;
|
||
}
|
||
bool IsIdentity() const
|
||
{
|
||
if (fabs(m11 - 1) < 0.001
|
||
&& fabs(m12) < 0.001
|
||
&& fabs(m21) < 0.001
|
||
&& fabs(m22 - 1) < 0.001
|
||
&& fabs(dx) < 0.001
|
||
&& fabs(dy) < 0.001)
|
||
return true;
|
||
|
||
return false;
|
||
}
|
||
void Set(const double& dM11, const double& dM12, const double& dM21, const double& dM22, const double& dX, const double& dY)
|
||
{
|
||
m11 = dM11;
|
||
m12 = dM12;
|
||
m21 = dM21;
|
||
m22 = dM22;
|
||
dx = dX;
|
||
dy = dY;
|
||
}
|
||
|
||
public:
|
||
|
||
double m11;
|
||
double m12;
|
||
double m21;
|
||
double m22;
|
||
double dx;
|
||
double dy;
|
||
};
|
||
class CCommandManager
|
||
{
|
||
public:
|
||
CCommandManager(CPdfWriter* pRenderer);
|
||
~CCommandManager();
|
||
CRendererTextCommand* AddText(unsigned char* pCodes, unsigned int nLen, const double& dX, const double& dY);
|
||
void Flush();
|
||
void SetTransform(const CTransform& oTransform);
|
||
void SetTransform(const double& m11, const double& m12, const double& m21, const double& m22, const double& dx, const double& dy);
|
||
private:
|
||
void Add(CRendererCommandBase* pCommand);
|
||
void Clear();
|
||
private:
|
||
CPdfWriter* m_pRenderer;
|
||
std::vector<CRendererCommandBase*> m_vCommands;
|
||
CTransform m_oTransform;
|
||
};
|
||
struct TImageInfo
|
||
{
|
||
std::wstring wsPath;
|
||
BYTE nAlpha;
|
||
int nWidth;
|
||
int nHeight;
|
||
PdfWriter::CImageDict* pImage;
|
||
};
|
||
struct TDestinationInfo
|
||
{
|
||
TDestinationInfo(PdfWriter::CPage* page, const double& x, const double& y, const double& w, const double& h, const double& dx, const double& dy, const unsigned int& undpage)
|
||
{
|
||
pPage = page;
|
||
dX = x;
|
||
dY = y;
|
||
dW = w;
|
||
dH = h;
|
||
dDestX = dx;
|
||
dDestY = dy;
|
||
unDestPage = undpage;
|
||
}
|
||
|
||
PdfWriter::CPage* pPage;
|
||
double dX;
|
||
double dY;
|
||
double dW;
|
||
double dH;
|
||
double dDestX;
|
||
double dDestY;
|
||
unsigned int unDestPage;
|
||
};
|
||
class CFieldsManager
|
||
{
|
||
public:
|
||
|
||
CFieldsManager()
|
||
{
|
||
m_unCounter = 0;
|
||
}
|
||
|
||
std::string GetNewFieldName()
|
||
{
|
||
std::string sName("F");
|
||
sName.append(std::to_string(++m_unCounter));
|
||
return sName;
|
||
}
|
||
|
||
private:
|
||
|
||
unsigned int m_unCounter;
|
||
};
|
||
//----------------------------------------------------------------------------------------
|
||
//
|
||
// CMultiLineTextManager
|
||
//
|
||
//----------------------------------------------------------------------------------------
|
||
class CMultiLineTextManager
|
||
{
|
||
public:
|
||
CMultiLineTextManager()
|
||
{
|
||
m_pCodes = NULL;
|
||
m_pWidths = NULL;
|
||
m_unLen = 0;
|
||
m_ushSpaceCode = 0;
|
||
m_unLineHeight = 0;
|
||
m_nAscent = 0;
|
||
m_nDescent = 0;
|
||
}
|
||
void Init(unsigned short* pCodes, unsigned int* pWidths, const unsigned int& unLen, const unsigned short& ushSpaceCode, const unsigned int& unLineHeight, const int& nAscent)
|
||
{
|
||
m_pCodes = pCodes;
|
||
m_pWidths = pWidths;
|
||
m_unLen = unLen;
|
||
m_ushSpaceCode = ushSpaceCode;
|
||
m_unLineHeight = unLineHeight;
|
||
m_nAscent = nAscent;
|
||
m_nDescent = unLineHeight - nAscent;
|
||
}
|
||
void Clear()
|
||
{
|
||
m_pCodes = NULL;
|
||
m_pWidths = NULL;
|
||
m_unLen = 0;
|
||
m_ushSpaceCode = 0;
|
||
m_unLineHeight = 0;
|
||
m_nAscent = 0;
|
||
m_nDescent = 0;
|
||
}
|
||
void CalculateLines(const double& dFontSize, const double& dW)
|
||
{
|
||
m_vBreaks.clear();
|
||
|
||
bool bLineStart = true, bWord = false, bFirstItemOnLine = true;
|
||
|
||
unsigned int unPos = 0, unWordStartPos = 0;
|
||
double dWordWidth = 0;
|
||
double dX = 0, dKoef = dFontSize / 1000.0;
|
||
|
||
while (unPos < m_unLen)
|
||
{
|
||
if (IsSpace(unPos))
|
||
{
|
||
dX += dWordWidth + m_pWidths[unPos] * dKoef;
|
||
bWord = false;
|
||
dWordWidth = 0;
|
||
bLineStart = false;
|
||
bFirstItemOnLine = false;
|
||
}
|
||
else
|
||
{
|
||
double dLetterWidth = m_pWidths[unPos] * dKoef;
|
||
if (dX + dWordWidth + dLetterWidth > dW)
|
||
{
|
||
if (bLineStart)
|
||
{
|
||
if (bFirstItemOnLine)
|
||
{
|
||
if (unPos != m_unLen - 1)
|
||
m_vBreaks.push_back(unPos + 1);
|
||
|
||
unPos++;
|
||
}
|
||
else
|
||
{
|
||
m_vBreaks.push_back(unPos);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (bWord)
|
||
{
|
||
m_vBreaks.push_back(unWordStartPos);
|
||
unPos = unWordStartPos;
|
||
}
|
||
else
|
||
{
|
||
m_vBreaks.push_back(unPos);
|
||
}
|
||
}
|
||
|
||
dX = 0;
|
||
bWord = false;
|
||
dWordWidth = 0;
|
||
bLineStart = true;
|
||
bFirstItemOnLine = true;
|
||
continue;
|
||
}
|
||
|
||
if (bWord)
|
||
{
|
||
dWordWidth += m_pWidths[unPos] * dKoef;
|
||
}
|
||
else
|
||
{
|
||
unWordStartPos = unPos;
|
||
bWord = true;
|
||
dWordWidth = m_pWidths[unPos] * dKoef;
|
||
}
|
||
|
||
bFirstItemOnLine = false;
|
||
}
|
||
|
||
unPos++;
|
||
}
|
||
}
|
||
double ProcessAutoFit(const double& dW, const double& dH)
|
||
{
|
||
double dGoodFontSize = 0;
|
||
|
||
// Параметры подобраны для совместимости с AdobeReader
|
||
double dFontSize = 4;
|
||
double dFontSizeStep = 0.797 / 3.0;
|
||
|
||
while (true)
|
||
{
|
||
CalculateLines(dFontSize, dW);
|
||
if (CheckHeight(dH, dFontSize))
|
||
{
|
||
dGoodFontSize = dFontSize;
|
||
dFontSize += dFontSizeStep;
|
||
|
||
if (dFontSize > 12)
|
||
{
|
||
dFontSize = 12;
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (dGoodFontSize > 0.001)
|
||
{
|
||
dFontSize = dGoodFontSize;
|
||
break;
|
||
}
|
||
|
||
dFontSize -= dFontSizeStep;
|
||
if (dFontSize < 4)
|
||
{
|
||
dFontSize = 4;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
return (floor(dFontSize * 1000.0 + 0.5) / 1000.0);
|
||
}
|
||
unsigned int GetLinesCount() const
|
||
{
|
||
return m_vBreaks.size() + 1;
|
||
}
|
||
unsigned int GetLineStartPos(const int& nLineIndex) const
|
||
{
|
||
if (!nLineIndex || nLineIndex > m_vBreaks.size())
|
||
return 0;
|
||
|
||
return m_vBreaks[nLineIndex - 1];
|
||
}
|
||
unsigned int GetLineEndPos(const int& nLineIndex) const
|
||
{
|
||
if (nLineIndex >= m_vBreaks.size())
|
||
return m_unLen;
|
||
|
||
return m_vBreaks[nLineIndex];
|
||
}
|
||
double GetLineWidth(const int& nLineIndex, const double& dFontSize = 10.0)
|
||
{
|
||
if (nLineIndex < 0 || nLineIndex > m_vBreaks.size())
|
||
return 0;
|
||
|
||
unsigned int unStart = GetLineStartPos(nLineIndex);
|
||
unsigned int unEnd = GetLineEndPos(nLineIndex);
|
||
|
||
double dWidth = 0;
|
||
double dKoef = dFontSize / 1000.0;
|
||
|
||
while (unStart < unEnd)
|
||
{
|
||
if (IsSpace(unStart))
|
||
unStart++;
|
||
else
|
||
break;
|
||
}
|
||
|
||
while (unEnd > unStart && unEnd > 0)
|
||
{
|
||
if (IsSpace(unEnd - 1))
|
||
unEnd--;
|
||
else
|
||
break;
|
||
}
|
||
|
||
for (unsigned int unPos = unStart; unPos < unEnd; ++unPos)
|
||
{
|
||
dWidth += m_pWidths[unPos] * dKoef;
|
||
}
|
||
|
||
return dWidth;
|
||
}
|
||
|
||
|
||
private:
|
||
|
||
inline bool IsSpace(const unsigned int& unPos) const
|
||
{
|
||
return (m_pCodes[unPos] == m_ushSpaceCode);
|
||
}
|
||
inline bool CheckHeight(const double& dH, const double& dFontSize) const
|
||
{
|
||
double dKoef = dFontSize / 1000.0;
|
||
return (GetLinesCount() * (m_unLineHeight * dKoef) < (dH - (m_nDescent * dKoef)));
|
||
}
|
||
|
||
|
||
private:
|
||
|
||
unsigned short* m_pCodes;
|
||
unsigned int* m_pWidths;
|
||
unsigned int m_unLen;
|
||
unsigned short m_ushSpaceCode;
|
||
unsigned int m_unLineHeight;
|
||
int m_nAscent;
|
||
int m_nDescent;
|
||
|
||
std::vector<unsigned int> m_vBreaks;
|
||
};
|
||
|
||
private:
|
||
NSFonts::IFontManager* m_pFontManager;
|
||
std::wstring m_wsTempFolder;
|
||
|
||
PdfWriter::CDocument* m_pDocument;
|
||
PdfWriter::CPage* m_pPage;
|
||
PdfWriter::CFontCidTrueType* m_pFont;
|
||
PdfWriter::CShading* m_pShading;
|
||
PdfWriter::CExtGrState* m_pShadingExtGrState;
|
||
|
||
bool m_bNeedUpdateTextFont;
|
||
bool m_bNeedUpdateTextColor;
|
||
bool m_bNeedUpdateTextAlpha;
|
||
bool m_bNeedUpdateTextCharSpace;
|
||
bool m_bNeedUpdateTextSize;
|
||
|
||
CCommandManager m_oCommandManager;
|
||
|
||
CPenState m_oPen;
|
||
CBrushState m_oBrush;
|
||
CFontState m_oFont;
|
||
CPath m_oPath;
|
||
CTransform m_oTransform;
|
||
LONG m_lClipMode;
|
||
double m_dPageHeight;
|
||
double m_dPageWidth;
|
||
LONG m_lClipDepth;
|
||
std::vector<TFontInfo> m_vFonts;
|
||
std::vector<TDestinationInfo>m_vDestinations;
|
||
CFieldsManager m_oFieldsManager;
|
||
CMultiLineTextManager m_oLinesManager;
|
||
|
||
bool m_bValid;
|
||
};
|
||
|
||
#endif // _PDF_WRITER_H
|