Files
DocumentServer-v-9.2.0/core/PdfFile/SrcWriter/States.h
T
Yajbir Singh f1b860b25c
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

1903 lines
51 KiB
C++

/*
* (c) Copyright Ascensio System SIA 2010-2023
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#ifndef _PDF_WRITER_SRC_STATE_H
#define _PDF_WRITER_SRC_STATE_H
#include "../../DesktopEditor/common/Types.h"
#include "../../DesktopEditor/graphics/AggPlusEnums.h"
#include "../../DesktopEditor/graphics/GraphicsPath.h"
#include "Types.h"
#include <string>
#include <vector>
#include <algorithm>
namespace PdfWriter
{
class CPage;
class CFontDict;
class CShading;
class CExtGrState;
}
class CPdfWriter;
enum ERendererCommandType
{
renderercommandtype_Text = 0x01,
renderercommandtype_Image = 0x02,
renderercommandtype_Path = 0x03,
renderercommandtype_Clip = 0x04
};
class CRendererCommandBase
{
public:
virtual ~CRendererCommandBase(){};
virtual ERendererCommandType GetType() = 0;
};
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_nType = PdfWriter::EFontType::fontUnknownType;
m_lColor = 0;
m_nAlpha = 255;
m_dCharSpace = 0;
m_dHorScaling = 100;
m_nMode = (int)PdfWriter::textrenderingmode_Fill;
m_dRise = 0;
m_dWordSpace = 0;
m_dWidth = -1;
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(PdfWriter::CFontDict* pFont)
{
m_pFont = pFont;
}
inline void SetSize(const double& dSize)
{
m_dSize = dSize;
}
inline void SetType(PdfWriter::EFontType oType)
{
m_nType = oType;
}
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 void SetPUA(const std::string& sPUA)
{
m_sPUA = sPUA;
}
inline void SetRise(const double& dRise)
{
m_dRise = dRise;
}
inline void SetWordSpace(const double& dWordSpace)
{
m_dWordSpace = dWordSpace;
}
inline void SetName(const std::wstring& sName)
{
m_sName = sName;
}
inline void SetWidth(const double& dWidth)
{
m_dWidth = dWidth;
}
inline PdfWriter::CFontDict* GetFont() const
{
return m_pFont;
}
inline double GetSize() const
{
return m_dSize;
}
inline PdfWriter::EFontType GetFontType() const
{
return m_nType;
}
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;
}
inline std::string GetPUA() const
{
return m_sPUA;
}
inline double GetRise()
{
return m_dRise;
}
inline double GetWordSpace()
{
return m_dWordSpace;
}
inline std::wstring GetName()
{
return m_sName;
}
inline double GetWidth()
{
return m_dWidth;
}
private:
unsigned char* m_pCodes;
unsigned int m_nLen;
double m_dX;
double m_dY;
PdfWriter::CFontDict* m_pFont;
bool m_bNeedDoItalic;
bool m_bNeedDoBold;
double m_dSize;
PdfWriter::EFontType m_nType;
LONG m_lColor;
BYTE m_nAlpha;
double m_dCharSpace;
int m_nMode;
double m_dHorScaling;
std::string m_sPUA;
double m_dRise;
double m_dWordSpace;
std::wstring m_sName;
double m_dWidth;
};
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;
}
inline double GetFlatness()
{
return m_dFlatness;
}
inline void SetFlatness(const double& dF)
{
m_dFlatness = dF;
}
inline double* GetDColor2(int& nSize)
{
nSize = m_nColor2Size;
return m_dColor2;
}
inline void SetDColor2(int nSize, double d1 = 0, double d2 = 0, double d3 = 0, double d4 = 0)
{
m_nColor2Size = nSize;
m_dColor2[0] = d1;
m_dColor2[1] = d2;
m_dColor2[2] = d3;
m_dColor2[3] = d4;
}
void Reset()
{
if (m_pDashPattern)
delete[] m_pDashPattern;
m_oColor.Set(0);
m_dSize = 0;
m_nAlpha = 255;
m_nStartCapStyle = Aggplus::LineCapFlat;
m_nEndCapStyle = Aggplus::LineCapFlat;
m_nJoinStyle = Aggplus::LineJoinMiter;
m_lAlign = 0;
m_dMiter = 3.527778;
m_dFlatness = 0;
m_nDashStyle = Aggplus::DashStyleSolid;
m_lDashPatternSize = 0;
m_pDashPattern = NULL;
m_dDashOffset = 0;
m_nColor2Size = 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;
double m_dFlatness;
BYTE m_nDashStyle;
double m_dDashOffset;
double*m_pDashPattern;
LONG m_lDashPatternSize;
double m_dColor2[4];
int m_nColor2Size;
};
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;
}
inline double* GetDColor2(int& nSize)
{
nSize = m_nColor2Size;
return m_dColor2;
}
inline void SetDColor2(int nSize, double d1 = 0, double d2 = 0, double d3 = 0, double d4 = 0)
{
m_nColor2Size = nSize;
m_dColor2[0] = d1;
m_dColor2[1] = d2;
m_dColor2[2] = d3;
m_dColor2[3] = d4;
}
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
double m_dColor2[4];
int m_nColor2Size;
};
class CFontState
{
public:
CFontState() : m_wsName(L"Arial"), m_wsPath(L""), m_dSize(10), m_bGid(false), m_lFaceIndex(0), m_lStyle(0), m_bBold(false), m_bItalic(false), m_dCharSpace(0), m_bNeedDoItalic(false),
m_bNeedDoBold(false), m_nRenderMode(0), m_dRise(0), m_dWordSpace(0), m_dHorizontalScaling(100)
{
}
void Reset()
{
m_wsName = L"Arial";
m_wsPath = L"";
m_dSize = 10;
m_bGid = false;
m_lFaceIndex = 0;
m_lStyle = 0;
m_bBold = false;
m_bItalic = false;
m_dCharSpace = 0;
m_nRenderMode = 0;
m_dRise = 0;
m_dWordSpace = 0;
m_dHorizontalScaling = 100;
m_bNeedDoItalic = false;
m_bNeedDoBold = 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;
}
inline void SetRenderMode(BYTE nMode)
{
m_nRenderMode = nMode;
}
inline BYTE GetRenderMode()
{
return m_nRenderMode;
}
inline void SetRise(double dRise)
{
m_dRise = dRise;
}
inline double GetRise()
{
return m_dRise;
}
inline void SetWordSpace(double dWordSpace)
{
m_dWordSpace = dWordSpace;
}
inline double GetWordSpace()
{
return m_dWordSpace;
}
inline void SetHorizontalScaling(double dHS)
{
m_dHorizontalScaling = dHS;
}
inline double GetHorizontalScaling()
{
return m_dHorizontalScaling;
}
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;
BYTE m_nRenderMode;
double m_dRise;
double m_dWordSpace;
double m_dHorizontalScaling;
};
struct CTransform
{
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;
}
void Transform(double dUserX, double dUserY, double* pdDeviceX, double* pdDeviceY) const
{
*pdDeviceX = dUserX * m11 + dUserY * m21 + dx;
*pdDeviceY = dUserX * m12 + dUserY * m22 + dy;
}
double m11;
double m12;
double m21;
double m22;
double dx;
double dy;
};
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;
virtual void ToCGraphicsPath(PdfWriter::CMatrix* pMatrix, Aggplus::CGraphicsPath& oPath) = 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;
}
void ToCGraphicsPath(PdfWriter::CMatrix* pMatrix, Aggplus::CGraphicsPath& oPath);
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;
}
void ToCGraphicsPath(PdfWriter::CMatrix* pMatrix, Aggplus::CGraphicsPath& oPath);
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;
}
void ToCGraphicsPath(PdfWriter::CMatrix* pMatrix, Aggplus::CGraphicsPath& oPath);
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;
}
void ToCGraphicsPath(PdfWriter::CMatrix* pMatrix, Aggplus::CGraphicsPath& oPath);
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;
}
void ToCGraphicsPath(PdfWriter::CMatrix* pMatrix, Aggplus::CGraphicsPath& oPath);
};
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;
}
void ToCGraphicsPath(PdfWriter::CMatrix* pMatrix, Aggplus::CGraphicsPath& oPath);
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);
void Redact(PdfWriter::CMatrix* oMatrix, const std::vector<double>& arrRedact, PdfWriter::CPage* pPage, bool bStroke, bool bFill, bool bEoFill,
PdfWriter::CShading* pShading, PdfWriter::CExtGrState* pShadingExtGrState);
bool DrawPathRedact(PdfWriter::CMatrix* oMatrix, Aggplus::CGraphicsPath* oPath, bool bStroke, const std::vector<PdfWriter::CSegment>& arrForStroke = {});
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 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) { m_oTransform = oTransform; }
void 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); }
private:
void Add(CRendererCommandBase* pCommand);
void Clear();
private:
CPdfWriter* m_pRenderer;
std::vector<CRendererCommandBase*> m_vCommands;
CTransform m_oTransform;
};
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 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 short& ushNewLineCode, const unsigned int& unLineHeight, const int& nAscent)
{
m_pCodes = pCodes;
m_pWidths = pWidths;
m_unLen = unLen;
m_ushSpaceCode = ushSpaceCode;
m_ushNewLineCode = ushNewLineCode;
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_ushNewLineCode = 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 if (IsNewLine(unPos))
{
bLineStart = true;
bFirstItemOnLine = true;
bWord = false;
dX = 0;
dWordWidth = 0;
m_vBreaks.push_back(unPos + 1);
}
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
{
unsigned int unLineStart = GetLineStartPos(nLineIndex);
unsigned int unLineEnd = nLineIndex >= m_vBreaks.size() ? m_unLen : m_vBreaks[nLineIndex];
while (unLineEnd > 0 && unLineEnd > unLineStart && IsNewLine(unLineEnd - 1))
--unLineEnd;
return unLineEnd;
}
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 IsNewLine(const unsigned int& unPos) const
{
return (m_pCodes[unPos] == m_ushNewLineCode);
}
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 short m_ushNewLineCode;
unsigned int m_unLineHeight;
int m_nAscent;
int m_nDescent;
std::vector<unsigned int> m_vBreaks;
};
#endif // _PDF_WRITER_SRC_STATE_H