Files
DocumentServer-v-9.2.0/core/PdfFile/SrcWriter/States.h
Yajbir Singh f1b860b25c
Some checks failed
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++
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-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