mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-04-07 13:55:33 +08:00
git-svn-id: svn://fileserver/activex/AVS/Sources/TeamlabOffice/trunk/ServerComponents@65499 954022d7-b5bf-4e40-9824-e11837661b57
1946 lines
56 KiB
C++
1946 lines
56 KiB
C++
#include "PdfRenderer.h"
|
||
|
||
#include "Src/Document.h"
|
||
#include "Src/Pages.h"
|
||
#include "Src/Image.h"
|
||
#include "Src/Font.h"
|
||
#include "Src/FontCidTT.h"
|
||
|
||
#include "../DesktopEditor/graphics/Image.h"
|
||
#include "../DesktopEditor/graphics/structures.h"
|
||
#include "../DesktopEditor/raster/BgraFrame.h"
|
||
#include "../DesktopEditor/raster/ImageFileFormatChecker.h"
|
||
#include "../DesktopEditor/cximage/CxImage/ximage.h"
|
||
#include "../DesktopEditor/fontengine/ApplicationFonts.h"
|
||
#include "../DesktopEditor/fontengine/FontManager.h"
|
||
#include "../DesktopEditor/raster/Metafile/MetaFile.h"
|
||
|
||
#include "../DesktopEditor/common/File.h"
|
||
#include "../DesktopEditor/common/Directory.h"
|
||
|
||
#include "OnlineOfficeBinToPdf.h"
|
||
|
||
|
||
#define MM_2_PT(X) ((X) * 72.0 / 25.4)
|
||
#define PT_2_MM(X) ((X) * 25.4 / 72.0)
|
||
|
||
#define LONG_2_BOOL(X) ((X) ? true : false)
|
||
|
||
#ifdef DrawText
|
||
#undef DrawText
|
||
#endif
|
||
|
||
#ifdef LoadImage
|
||
#undef LoadImage
|
||
#endif
|
||
|
||
using namespace PdfWriter;
|
||
|
||
#define HI_SURROGATE_START 0xD800
|
||
#define HI_SURROGATE_END 0xDBFF
|
||
#define LO_SURROGATE_START 0xDC00
|
||
#define LO_SURROGATE_END 0xDFFF
|
||
|
||
static unsigned int* WStringToUtf32(const std::wstring& wsUnicodeText, unsigned int& unLen)
|
||
{
|
||
if (wsUnicodeText.size() <= 0)
|
||
return NULL;
|
||
|
||
unsigned int* pUnicodes = new unsigned int[wsUnicodeText.size()];
|
||
if (!pUnicodes)
|
||
return NULL;
|
||
|
||
unsigned int* pOutput = pUnicodes;
|
||
unLen = 0;
|
||
if (2 == sizeof(wchar_t))
|
||
{
|
||
const wchar_t* wsEnd = wsUnicodeText.c_str() + wsUnicodeText.size();
|
||
wchar_t* wsInput = (wchar_t*)wsUnicodeText.c_str();
|
||
|
||
wchar_t wLeading, wTrailing;
|
||
unsigned int unCode;
|
||
while (wsInput < wsEnd)
|
||
{
|
||
wLeading = *wsInput++;
|
||
if (wLeading < 0xD800 || wLeading > 0xDFFF)
|
||
{
|
||
pUnicodes[unLen++] = (unsigned int)wLeading;
|
||
}
|
||
else if (wLeading >= 0xDC00)
|
||
{
|
||
// Такого не должно быть
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
unCode = (wLeading & 0x3FF) << 10;
|
||
wTrailing = *wsInput++;
|
||
if (wTrailing < 0xDC00 || wTrailing > 0xDFFF)
|
||
{
|
||
// Такого не должно быть
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
pUnicodes[unLen++] = (unCode | (wTrailing & 0x3FF) + 0x10000);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
unLen = wsUnicodeText.size();
|
||
for (unsigned int unIndex = 0; unIndex < unLen; unIndex++)
|
||
{
|
||
pUnicodes[unIndex] = (unsigned int)wsUnicodeText.at(unIndex);
|
||
}
|
||
}
|
||
|
||
return pUnicodes;
|
||
}
|
||
|
||
// Этих типов браша нет в рендерере, мы их используем, когда конвертим из веба
|
||
static const long c_BrushTypeLinearGradient = 8001;
|
||
static const long c_BrushTypeRadialGradient = 8002;
|
||
|
||
enum ERendererCommandType
|
||
{
|
||
renderercommandtype_Text = 0x01,
|
||
renderercommandtype_Image = 0x02,
|
||
renderercommandtype_Path = 0x03,
|
||
renderercommandtype_Clip = 0x04
|
||
};
|
||
//----------------------------------------------------------------------------------------
|
||
//
|
||
// CRendererCommandBase
|
||
//
|
||
//----------------------------------------------------------------------------------------
|
||
class CRendererCommandBase
|
||
{
|
||
public:
|
||
virtual ~CRendererCommandBase(){};
|
||
virtual ERendererCommandType GetType() = 0;
|
||
};
|
||
//----------------------------------------------------------------------------------------
|
||
//
|
||
// CRendererTextCommand
|
||
//
|
||
//----------------------------------------------------------------------------------------
|
||
class CRendererTextCommand : public CRendererCommandBase
|
||
{
|
||
public:
|
||
CRendererTextCommand(unsigned char* pCodes, unsigned int nLen, const double& dX, const double& dY)
|
||
{
|
||
m_pCodes = pCodes;
|
||
m_nLen = nLen;
|
||
m_dX = dX;
|
||
m_dY = dY;
|
||
m_pFont = NULL;
|
||
m_dSize = -1;
|
||
m_lColor = 0;
|
||
m_nAlpha = 255;
|
||
m_dCharSpace = 0;
|
||
m_dHorScaling = 100;
|
||
m_nMode = (int)textrenderingmode_Fill;
|
||
}
|
||
~CRendererTextCommand()
|
||
{
|
||
if (m_pCodes)
|
||
delete[] m_pCodes;
|
||
}
|
||
ERendererCommandType GetType()
|
||
{
|
||
return renderercommandtype_Text;
|
||
}
|
||
|
||
inline double GetX() const
|
||
{
|
||
return m_dX;
|
||
}
|
||
inline double GetY() const
|
||
{
|
||
return m_dY;
|
||
}
|
||
inline unsigned char* GetCodes() const
|
||
{
|
||
return m_pCodes;
|
||
}
|
||
inline unsigned int GetCodesLen() const
|
||
{
|
||
return m_nLen;
|
||
}
|
||
inline void SetFont(CFontDict* pFont)
|
||
{
|
||
m_pFont = pFont;
|
||
}
|
||
inline void SetSize(const double& dSize)
|
||
{
|
||
m_dSize = dSize;
|
||
}
|
||
inline void SetColor(const LONG& lColor)
|
||
{
|
||
m_lColor = lColor;
|
||
}
|
||
inline void SetAlpha(const BYTE& nAlpha)
|
||
{
|
||
m_nAlpha = nAlpha;
|
||
}
|
||
inline void SetCharSpace(const double& dCharSpace)
|
||
{
|
||
m_dCharSpace = dCharSpace;
|
||
}
|
||
inline void SetHorScaling(const double& dKoef)
|
||
{
|
||
m_dHorScaling = dKoef;
|
||
}
|
||
inline void SetMode(const int& nMode)
|
||
{
|
||
m_nMode = nMode;
|
||
}
|
||
inline CFontDict* GetFont() const
|
||
{
|
||
return m_pFont;
|
||
}
|
||
inline double GetSize() const
|
||
{
|
||
return m_dSize;
|
||
}
|
||
inline LONG GetColor() const
|
||
{
|
||
return m_lColor;
|
||
}
|
||
inline BYTE GetAlpha() const
|
||
{
|
||
return m_nAlpha;
|
||
}
|
||
inline double GetSpace() const
|
||
{
|
||
return m_dCharSpace;
|
||
}
|
||
inline double GetHorScaling() const
|
||
{
|
||
return m_dHorScaling;
|
||
}
|
||
inline int GetMode() const
|
||
{
|
||
return m_nMode;
|
||
}
|
||
|
||
private:
|
||
|
||
unsigned char* m_pCodes;
|
||
unsigned int m_nLen;
|
||
double m_dX;
|
||
double m_dY;
|
||
|
||
CFontDict* m_pFont;
|
||
double m_dSize;
|
||
LONG m_lColor;
|
||
BYTE m_nAlpha;
|
||
double m_dCharSpace;
|
||
int m_nMode;
|
||
double m_dHorScaling;
|
||
};
|
||
//----------------------------------------------------------------------------------------
|
||
//
|
||
// CCommandManager
|
||
//
|
||
//----------------------------------------------------------------------------------------
|
||
CPdfRenderer::CCommandManager::CCommandManager(CPdfRenderer* pRenderer) : m_pRenderer(pRenderer)
|
||
{
|
||
}
|
||
CPdfRenderer::CCommandManager::~CCommandManager()
|
||
{
|
||
Clear();
|
||
}
|
||
CRendererTextCommand* CPdfRenderer::CCommandManager::AddText(unsigned char* pCodes, unsigned int nLen, const double& dX, const double& dY)
|
||
{
|
||
CRendererCommandBase* pCommand = new CRendererTextCommand(pCodes, nLen, dX, dY);
|
||
Add(pCommand);
|
||
return (CRendererTextCommand*)pCommand;
|
||
}
|
||
void CPdfRenderer::CCommandManager::Add(CRendererCommandBase* pCommand)
|
||
{
|
||
if (pCommand)
|
||
{
|
||
if (m_vCommands.size() > 0 && pCommand->GetType() != m_vCommands.at(0)->GetType())
|
||
Flush();
|
||
|
||
m_vCommands.push_back(pCommand);
|
||
}
|
||
}
|
||
void CPdfRenderer::CCommandManager::Flush()
|
||
{
|
||
int nCommandsCount = m_vCommands.size();
|
||
if (nCommandsCount > 0)
|
||
{
|
||
CPage* pPage = m_pRenderer->m_pPage;
|
||
pPage->GrSave();
|
||
|
||
pPage->SetTransform(m_oTransform.m11, m_oTransform.m12, m_oTransform.m21, m_oTransform.m22, m_oTransform.dx, m_oTransform.dy);
|
||
|
||
ERendererCommandType eType = m_vCommands.at(0)->GetType();
|
||
if (renderercommandtype_Text == eType)
|
||
{
|
||
pPage->BeginText();
|
||
CRendererTextCommand* pText = NULL;
|
||
|
||
CFontDict* pTextFont = NULL;
|
||
double dTextSize = -1;
|
||
LONG lTextColor = 0;
|
||
BYTE nTextAlpha = 255;
|
||
double dTextSpace = 0;
|
||
double dHorScaling = 100;
|
||
ETextRenderingMode eMode = textrenderingmode_Fill;
|
||
|
||
double dPrevX = -1000;
|
||
double dPrevY = -1000;
|
||
unsigned short ushPrevCode = 0;
|
||
|
||
CTextLine oTextLine;
|
||
for (int nIndex = 0; nIndex < nCommandsCount; nIndex++)
|
||
{
|
||
pText = (CRendererTextCommand*)m_vCommands.at(nIndex);
|
||
if (!pText)
|
||
continue;
|
||
|
||
if (pTextFont != pText->GetFont() || fabs(dTextSize - pText->GetSize()) > 0.001)
|
||
{
|
||
oTextLine.Flush(pPage);
|
||
pTextFont = pText->GetFont();
|
||
dTextSize = pText->GetSize();
|
||
pPage->SetFontAndSize(pTextFont, dTextSize);
|
||
}
|
||
|
||
if (lTextColor != pText->GetColor())
|
||
{
|
||
oTextLine.Flush(pPage);
|
||
lTextColor = pText->GetColor();
|
||
TColor oColor = lTextColor;
|
||
pPage->SetFillColor(oColor.r, oColor.g, oColor.b);
|
||
}
|
||
|
||
if (nTextAlpha != pText->GetAlpha())
|
||
{
|
||
oTextLine.Flush(pPage);
|
||
nTextAlpha = pText->GetAlpha();
|
||
pPage->SetFillAlpha(nTextAlpha);
|
||
}
|
||
|
||
if (fabs(dTextSpace - pText->GetSpace()) > 0.001)
|
||
{
|
||
oTextLine.Flush(pPage);
|
||
dTextSpace = pText->GetSpace();
|
||
pPage->SetCharSpace(dTextSpace);
|
||
}
|
||
|
||
if ((int)eMode != pText->GetMode())
|
||
{
|
||
oTextLine.Flush(pPage);
|
||
eMode = (ETextRenderingMode)pText->GetMode();
|
||
pPage->SetTextRenderingMode(eMode);
|
||
}
|
||
|
||
if (fabs(dHorScaling - pText->GetHorScaling()) > 0.001)
|
||
{
|
||
oTextLine.Flush(pPage);
|
||
dHorScaling = pText->GetHorScaling();
|
||
pPage->SetHorizontalScalling(dHorScaling);
|
||
}
|
||
|
||
unsigned char* pCodes = pText->GetCodes();
|
||
unsigned short ushCode = (pCodes[0] << 8) + pCodes[1];
|
||
unsigned int unLen = pText->GetCodesLen();
|
||
double dX = pText->GetX();
|
||
double dY = pText->GetY();
|
||
double dTextSize = pText->GetSize();
|
||
double dWidth = ((CFontCidTrueType*)pText->GetFont())->GetWidth(ushCode) / 1000.0 * dTextSize;
|
||
|
||
if (!oTextLine.Add(pCodes, unLen, dX, dY, dWidth, dTextSize))
|
||
{
|
||
oTextLine.Flush(pPage);
|
||
if (!oTextLine.Add(pCodes, unLen, dX, dY, dWidth, dTextSize))
|
||
{
|
||
pPage->DrawText(dX, dY, pCodes, unLen);
|
||
}
|
||
}
|
||
}
|
||
oTextLine.Flush(pPage);
|
||
|
||
pPage->EndText();
|
||
}
|
||
|
||
pPage->GrRestore();
|
||
}
|
||
|
||
Clear();
|
||
}
|
||
void CPdfRenderer::CCommandManager::Clear()
|
||
{
|
||
for (int nIndex = 0, nCount = m_vCommands.size(); nIndex < nCount; nIndex++)
|
||
{
|
||
CRendererCommandBase* pCommand = m_vCommands.at(nIndex);
|
||
delete pCommand;
|
||
}
|
||
m_vCommands.clear();
|
||
}
|
||
void CPdfRenderer::CCommandManager::SetTransform(const CTransform& oTransform)
|
||
{
|
||
m_oTransform = oTransform;
|
||
}
|
||
void CPdfRenderer::CCommandManager::SetTransform(const double& m11, const double& m12, const double& m21, const double& m22, const double& dx, const double& dy)
|
||
{
|
||
m_oTransform.Set(m11, m12, m21, m22, dx, dy);
|
||
}
|
||
//----------------------------------------------------------------------------------------
|
||
//
|
||
// CPdfRenderer
|
||
//
|
||
//----------------------------------------------------------------------------------------
|
||
CPdfRenderer::CPdfRenderer(CApplicationFonts* pAppFonts) : m_oCommandManager(this)
|
||
{
|
||
m_pAppFonts = pAppFonts;
|
||
|
||
// Создаем менеджер шрифтов с собственным кэшем
|
||
m_pFontManager = pAppFonts->GenerateFontManager();
|
||
CFontsCache* pMeasurerCache = new CFontsCache();
|
||
pMeasurerCache->SetStreams(pAppFonts->GetStreams());
|
||
m_pFontManager->SetOwnerCache(pMeasurerCache);
|
||
|
||
m_pDocument = new CDocument();
|
||
if (!m_pDocument || !m_pDocument->CreateNew())
|
||
{
|
||
SetError();
|
||
return;
|
||
}
|
||
|
||
m_pDocument->SetCompressionMode(COMP_ALL);
|
||
|
||
m_bValid = true;
|
||
m_dPageHeight = 297;
|
||
m_dPageWidth = 210;
|
||
m_pPage = NULL;
|
||
m_pFont = NULL;
|
||
|
||
m_nCounter = 0;
|
||
m_nPagesCount = 0;
|
||
|
||
m_bNeedUpdateTextFont = true;
|
||
m_bNeedUpdateTextColor = true;
|
||
m_bNeedUpdateTextAlpha = true;
|
||
m_bNeedUpdateTextCharSpace = true;
|
||
m_bNeedUpdateTextSize = true;
|
||
|
||
m_wsTempFolder = L"";
|
||
SetTempFolder(NSFile::CFileBinary::GetTempPath());
|
||
}
|
||
CPdfRenderer::~CPdfRenderer()
|
||
{
|
||
RELEASEOBJECT(m_pDocument);
|
||
RELEASEINTERFACE(m_pFontManager);
|
||
|
||
if (L"" != m_wsTempFolder)
|
||
NSDirectory::DeleteDirectory(m_wsTempFolder);
|
||
}
|
||
void CPdfRenderer::SaveToFile(const std::wstring& wsPath)
|
||
{
|
||
if (!IsValid())
|
||
return;
|
||
|
||
m_oCommandManager.Flush();
|
||
|
||
m_pDocument->SaveToFile(wsPath);
|
||
}
|
||
void CPdfRenderer::SetTempFolder(const std::wstring& wsPath)
|
||
{
|
||
if (L"" != m_wsTempFolder)
|
||
NSDirectory::DeleteDirectory(m_wsTempFolder);
|
||
|
||
int nCounter = 0;
|
||
m_wsTempFolder = wsPath + L"\\PDF\\";
|
||
while (NSDirectory::Exists(m_wsTempFolder))
|
||
{
|
||
m_wsTempFolder = wsPath + L"\\PDF_" + std::to_wstring(nCounter) + L"\\";
|
||
nCounter++;
|
||
}
|
||
NSDirectory::CreateDirectory(m_wsTempFolder);
|
||
}
|
||
std::wstring CPdfRenderer::GetTempFile()
|
||
{
|
||
return NSFile::CFileBinary::CreateTempFileWithUniqueName(m_wsTempFolder, L"PDF");
|
||
}
|
||
void CPdfRenderer::SetThemesPlace(const std::wstring& wsThemesPlace)
|
||
{
|
||
m_wsThemesPlace = wsThemesPlace;
|
||
}
|
||
std::wstring CPdfRenderer::GetThemesPlace()
|
||
{
|
||
return m_wsThemesPlace;
|
||
}
|
||
//----------------------------------------------------------------------------------------
|
||
// Тип рендерера
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT CPdfRenderer::get_Type(LONG* lType)
|
||
{
|
||
*lType = c_nPDFWriter;
|
||
return S_OK;
|
||
}
|
||
//----------------------------------------------------------------------------------------
|
||
// Функции для работы со страницей
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT CPdfRenderer::NewPage()
|
||
{
|
||
m_oCommandManager.Flush();
|
||
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
m_pPage = m_pDocument->AddPage();
|
||
|
||
if (!m_pPage)
|
||
{
|
||
SetError();
|
||
return S_FALSE;
|
||
}
|
||
|
||
m_pPage->SetWidth(m_dPageWidth);
|
||
m_pPage->SetHeight(m_dPageHeight);
|
||
|
||
m_oPen.Reset();
|
||
m_oBrush.Reset();
|
||
m_oFont.Reset();
|
||
m_oPath.Clear();
|
||
|
||
m_lClipDepth = 0;
|
||
|
||
m_nPagesCount++;//printf("Page %d\n", m_nPagesCount++);
|
||
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_Height(double* dHeight)
|
||
{
|
||
*dHeight = m_dPageHeight;
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_Height(const double& dHeight)
|
||
{
|
||
if (!IsValid() || !m_pPage)
|
||
return S_FALSE;
|
||
|
||
m_dPageHeight = dHeight;
|
||
m_pPage->SetHeight(MM_2_PT(dHeight));
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_Width(double* dWidth)
|
||
{
|
||
*dWidth = m_dPageWidth;
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_Width(const double& dWidth)
|
||
{
|
||
if (!IsValid() || !m_pPage)
|
||
return S_FALSE;
|
||
|
||
m_dPageWidth = dWidth;
|
||
m_pPage->SetWidth(MM_2_PT(dWidth));
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_DpiX(double* dDpiX)
|
||
{
|
||
*dDpiX = 72;
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_DpiY(double* dDpiY)
|
||
{
|
||
*dDpiY = 72;
|
||
return S_OK;
|
||
}
|
||
//----------------------------------------------------------------------------------------
|
||
// Функции для работы с Pen
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT CPdfRenderer::get_PenColor(LONG* lColor)
|
||
{
|
||
*lColor = m_oPen.GetColor();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_PenColor(const LONG& lColor)
|
||
{
|
||
m_oPen.SetColor(lColor);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_PenAlpha(LONG* lAlpha)
|
||
{
|
||
*lAlpha = m_oPen.GetAlpha();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_PenAlpha(const LONG& lAlpha)
|
||
{
|
||
m_oPen.SetAlpha(lAlpha);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_PenSize(double* dSize)
|
||
{
|
||
*dSize = m_oPen.GetSize();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_PenSize(const double& dSize)
|
||
{
|
||
m_oPen.SetSize(dSize);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_PenDashStyle(BYTE* nDashStyle)
|
||
{
|
||
*nDashStyle = m_oPen.GetDashStyle();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_PenDashStyle(const BYTE& nDashStyle)
|
||
{
|
||
m_oPen.SetDashStyle(nDashStyle);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_PenLineStartCap(BYTE* nCapStyle)
|
||
{
|
||
*nCapStyle = m_oPen.GetStartCapStyle();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_PenLineStartCap(const BYTE& nCapStyle)
|
||
{
|
||
m_oPen.SetStartCapStyle(nCapStyle);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_PenLineEndCap(BYTE* nCapStyle)
|
||
{
|
||
*nCapStyle = m_oPen.GetEndCapStyle();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_PenLineEndCap(const BYTE& nCapStyle)
|
||
{
|
||
m_oPen.SetEndCapStyle(nCapStyle);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_PenLineJoin(BYTE* nJoinStyle)
|
||
{
|
||
*nJoinStyle = m_oPen.GetJoinStyle();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_PenLineJoin(const BYTE& nJoinStyle)
|
||
{
|
||
m_oPen.SetJoinStyle(nJoinStyle);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_PenDashOffset(double* dOffset)
|
||
{
|
||
*dOffset = m_oPen.GetDashOffset();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_PenDashOffset(const double& dOffset)
|
||
{
|
||
m_oPen.SetDashOffset(dOffset);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_PenAlign(LONG* lAlign)
|
||
{
|
||
*lAlign = m_oPen.GetAlign();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_PenAlign(const LONG& lAlign)
|
||
{
|
||
m_oPen.SetAlign(lAlign);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_PenMiterLimit(double* dMiter)
|
||
{
|
||
*dMiter = m_oPen.GetMiter();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_PenMiterLimit(const double& dMiter)
|
||
{
|
||
m_oPen.SetMiter(dMiter);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::PenDashPattern(double* pPattern, LONG lCount)
|
||
{
|
||
m_oPen.SetDashPattern(pPattern, lCount);
|
||
return S_OK;
|
||
}
|
||
//----------------------------------------------------------------------------------------
|
||
// Функции для работы с Brush
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT CPdfRenderer::get_BrushType(LONG* lType)
|
||
{
|
||
*lType = m_oBrush.GetType();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_BrushType(const LONG& lType)
|
||
{
|
||
m_oBrush.SetType(lType);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_BrushColor1(LONG* lColor)
|
||
{
|
||
*lColor = m_oBrush.GetColor1();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_BrushColor1(const LONG& lColor)
|
||
{
|
||
if (lColor != m_oBrush.GetColor1())
|
||
{
|
||
m_oBrush.SetColor1(lColor);
|
||
m_bNeedUpdateTextColor = true;
|
||
}
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_BrushAlpha1(LONG* lAlpha)
|
||
{
|
||
*lAlpha = m_oBrush.GetAlpha1();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_BrushAlpha1(const LONG& lAlpha)
|
||
{
|
||
if (lAlpha != m_oBrush.GetAlpha1())
|
||
{
|
||
m_oBrush.SetAlpha1(lAlpha);
|
||
m_bNeedUpdateTextAlpha = true;
|
||
}
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_BrushColor2(LONG* lColor)
|
||
{
|
||
*lColor = m_oBrush.GetColor2();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_BrushColor2(const LONG& lColor)
|
||
{
|
||
m_oBrush.SetColor2(lColor);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_BrushAlpha2(LONG* lAlpha)
|
||
{
|
||
*lAlpha = m_oBrush.GetAlpha2();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_BrushAlpha2(const LONG& lAlpha)
|
||
{
|
||
m_oBrush.SetAlpha2(lAlpha);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_BrushTexturePath(std::wstring* wsPath)
|
||
{
|
||
*wsPath = m_oBrush.GetTexturePath();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_BrushTexturePath(const std::wstring& wsPath)
|
||
{
|
||
m_oBrush.SetTexturePath(wsPath);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_BrushTextureMode(LONG* lMode)
|
||
{
|
||
*lMode = m_oBrush.GetTextureMode();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_BrushTextureMode(const LONG& lMode)
|
||
{
|
||
m_oBrush.SetTextureMode(lMode);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_BrushTextureAlpha(LONG* lAlpha)
|
||
{
|
||
*lAlpha = m_oBrush.GetTextureAlpha();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_BrushTextureAlpha(const LONG& lAlpha)
|
||
{
|
||
m_oBrush.SetTextureAlpha(lAlpha);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_BrushLinearAngle(double* dAngle)
|
||
{
|
||
*dAngle = m_oBrush.GetLinearAngle();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_BrushLinearAngle(const double& dAngle)
|
||
{
|
||
m_oBrush.SetLinearAngle(dAngle);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::BrushRect(const INT& nVal, const double& dLeft, const double& dTop, const double& dWidth, const double& dHeight)
|
||
{
|
||
// Данными параметрами пользуемся, только если пришла команда EnableBrushRect, если команда не пришла, тогда
|
||
// ориентируемся на границы пата.
|
||
m_oBrush.SetBrushRect(nVal, dLeft, dTop, dWidth, dHeight);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::BrushBounds(const double& dLeft, const double& dTop, const double& dWidth, const double& dHeight)
|
||
{
|
||
// TODO: Пока определяется все по границам пата
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_BrushGradientColors(LONG* lColors, double* pPositions, LONG lCount)
|
||
{
|
||
m_oBrush.SetGradientColors(lColors, pPositions, lCount);
|
||
return S_OK;
|
||
}
|
||
//----------------------------------------------------------------------------------------
|
||
// Функции для работы со шрифтами
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT CPdfRenderer::get_FontName(std::wstring* wsName)
|
||
{
|
||
*wsName = m_oFont.GetName();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_FontName(const std::wstring& wsName)
|
||
{
|
||
if (wsName != m_oFont.GetName())
|
||
{
|
||
m_oFont.SetName(wsName);
|
||
m_bNeedUpdateTextFont = true;
|
||
}
|
||
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_FontPath(std::wstring* wsPath)
|
||
{
|
||
*wsPath = m_oFont.GetPath();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_FontPath(const std::wstring& wsPath)
|
||
{
|
||
if (wsPath != m_oFont.GetPath())
|
||
{
|
||
m_oFont.SetPath(wsPath);
|
||
m_bNeedUpdateTextFont = true;
|
||
}
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_FontSize(double* dSize)
|
||
{
|
||
*dSize = m_oFont.GetSize();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_FontSize(const double& dSize)
|
||
{
|
||
if (fabs(dSize - m_oFont.GetSize()) > 0.001)
|
||
{
|
||
m_oFont.SetSize(dSize);
|
||
m_bNeedUpdateTextSize = true;
|
||
}
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_FontStyle(LONG* lStyle)
|
||
{
|
||
*lStyle = m_oFont.GetStyle();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_FontStyle(const LONG& lStyle)
|
||
{
|
||
if (lStyle != m_oFont.GetStyle())
|
||
{
|
||
m_oFont.SetStyle(lStyle);
|
||
m_bNeedUpdateTextFont = true;
|
||
}
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_FontStringGID(INT* bGid)
|
||
{
|
||
*bGid = m_oFont.GetGid() ? 1 : 0;
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_FontStringGID(const INT& bGid)
|
||
{
|
||
m_oFont.SetGid(bGid ? true : false);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_FontCharSpace(double* dSpace)
|
||
{
|
||
*dSpace = m_oFont.GetCharSpace();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_FontCharSpace(const double& dSpace)
|
||
{
|
||
if (fabs(dSpace - m_oFont.GetCharSpace()) > 0.001)
|
||
{
|
||
m_oFont.SetCharSpace(dSpace);
|
||
m_bNeedUpdateTextCharSpace = true;
|
||
}
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::get_FontFaceIndex(int* nFaceIndex)
|
||
{
|
||
*nFaceIndex = (int)m_oFont.GetFaceIndex();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_FontFaceIndex(const int& nFaceIndex)
|
||
{
|
||
if (nFaceIndex != m_oFont.GetFaceIndex())
|
||
{
|
||
m_oFont.SetFaceIndex(nFaceIndex);
|
||
m_bNeedUpdateTextFont = true;
|
||
}
|
||
|
||
return S_OK;
|
||
}
|
||
//----------------------------------------------------------------------------------------
|
||
// Функции для вывода текста
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT CPdfRenderer::CommandDrawTextCHAR(const LONG& lUnicode, const double& dX, const double& dY, const double& dW, const double& dH)
|
||
{
|
||
if (!IsPageValid())
|
||
return S_FALSE;
|
||
|
||
unsigned int unUnicode = lUnicode;
|
||
bool bRes = DrawText(&unUnicode, 1, dX, dY, NULL);
|
||
return bRes ? S_OK : S_FALSE;
|
||
}
|
||
HRESULT CPdfRenderer::CommandDrawText(const std::wstring& wsUnicodeText, const double& dX, const double& dY, const double& dW, const double& dH)
|
||
{
|
||
if (!IsPageValid() || !wsUnicodeText.size())
|
||
return S_FALSE;
|
||
|
||
unsigned int unLen;
|
||
unsigned int* pUnicodes = WStringToUtf32(wsUnicodeText, unLen);
|
||
if (!pUnicodes)
|
||
return S_FALSE;
|
||
|
||
// Специальный случай для текста из Djvu, нам не нужно, чтобы он рисовался
|
||
if (L"" == m_oFont.GetPath() && L"DjvuEmptyFont" == m_oFont.GetName())
|
||
{
|
||
if (m_bNeedUpdateTextFont)
|
||
{
|
||
m_oFont.SetName(L"Arial");
|
||
UpdateFont();
|
||
m_oFont.SetName(L"DjvuEmptyFont");
|
||
if (!m_pFont)
|
||
return S_FALSE;
|
||
}
|
||
|
||
double dFontSize = MM_2_PT(dH);
|
||
unsigned char* pCodes = m_pFont->EncodeString(pUnicodes, unLen);
|
||
delete[] pUnicodes;
|
||
|
||
double dStringWidth = 0;
|
||
for (unsigned int unIndex = 0; unIndex < unLen; unIndex++)
|
||
{
|
||
unsigned short ushCode = (pCodes[2 * unIndex] << 8) + pCodes[2 * unIndex + 1];
|
||
dStringWidth += m_pFont->GetWidth(ushCode) * dFontSize / 1000.0;
|
||
}
|
||
|
||
double dResultWidth = MM_2_PT(dW);
|
||
|
||
CTransform& t = m_oTransform;
|
||
m_oCommandManager.SetTransform(t.m11, -t.m12, -t.m21, t.m22, MM_2_PT(t.dx + t.m21 * m_dPageHeight), MM_2_PT(m_dPageHeight - m_dPageHeight * t.m22 - t.dy));
|
||
|
||
CRendererTextCommand* pText = m_oCommandManager.AddText(pCodes, unLen * 2, MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY - dH));
|
||
pText->SetFont(m_pFont);
|
||
pText->SetSize(dFontSize);
|
||
pText->SetMode(textrenderingmode_Invisible);
|
||
if (fabs(dStringWidth) > 0.001)
|
||
pText->SetHorScaling(dResultWidth / dStringWidth * 100);
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
bool bRes = DrawText(pUnicodes, unLen, dX, dY, NULL);
|
||
delete[] pUnicodes;
|
||
|
||
return bRes ? S_OK : S_FALSE;
|
||
}
|
||
HRESULT CPdfRenderer::CommandDrawTextExCHAR(const LONG& lUnicode, const LONG& lGid, const double& dX, const double& dY, const double& dW, const double& dH)
|
||
{
|
||
if (!IsPageValid())
|
||
return S_FALSE;
|
||
|
||
unsigned int unUnicode = lUnicode;
|
||
unsigned int unGid = lGid;
|
||
bool bRes = DrawText(&unUnicode, 1, dX, dY, &unGid);
|
||
return bRes ? S_OK : S_FALSE;
|
||
}
|
||
HRESULT CPdfRenderer::CommandDrawTextEx(const std::wstring& wsUnicodeText, const unsigned int* pGids, const unsigned int unGidsCount, const double& dX, const double& dY, const double& dW, const double& dH)
|
||
{
|
||
if (!IsPageValid() || (!wsUnicodeText.size() && (!pGids || !unGidsCount)))
|
||
return S_FALSE;
|
||
|
||
unsigned int unLen = 0;
|
||
unsigned int* pUnicodes = NULL;
|
||
if (pGids && unGidsCount)
|
||
{
|
||
unLen = unGidsCount;
|
||
if (wsUnicodeText.size())
|
||
{
|
||
unsigned int unUnicodeLen;
|
||
pUnicodes = WStringToUtf32(wsUnicodeText, unUnicodeLen);
|
||
if (!pUnicodes || unUnicodeLen != unLen)
|
||
RELEASEARRAYOBJECTS(pUnicodes);
|
||
}
|
||
|
||
if (!pUnicodes)
|
||
{
|
||
pUnicodes = new unsigned int[unLen];
|
||
if (!pUnicodes)
|
||
return S_FALSE;
|
||
|
||
for (unsigned int unIndex = 0; unIndex < unLen; unIndex++)
|
||
pUnicodes[unIndex] = pGids[unIndex];
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pUnicodes = WStringToUtf32(wsUnicodeText, unLen);
|
||
if (!pUnicodes)
|
||
return S_FALSE;
|
||
}
|
||
|
||
bool bRes = DrawText(pUnicodes, unLen, dX, dY, pGids);
|
||
RELEASEARRAYOBJECTS(pUnicodes);
|
||
|
||
return bRes ? S_OK : S_FALSE;
|
||
}
|
||
//----------------------------------------------------------------------------------------
|
||
// Маркеры команд
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT CPdfRenderer::BeginCommand(const DWORD& dwType)
|
||
{
|
||
// Здесь мы ничего не делаем
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::EndCommand(const DWORD& dwType)
|
||
{
|
||
if (!IsPageValid())
|
||
return S_FALSE;
|
||
|
||
// Здесь мы различаем лишь 2 команды: присоединить текущий пат к клипу и отменить клип
|
||
if (c_nClipType == dwType)
|
||
{
|
||
m_oCommandManager.Flush();
|
||
m_pPage->GrSave();
|
||
m_lClipDepth++;
|
||
UpdateTransform();
|
||
|
||
if (c_nClipRegionTypeEvenOdd & m_lClipMode)
|
||
m_oPath.Clip(m_pPage, true);
|
||
else
|
||
m_oPath.Clip(m_pPage, false);
|
||
}
|
||
else if (c_nResetClipType == dwType)
|
||
{
|
||
m_oCommandManager.Flush();
|
||
while (m_lClipDepth)
|
||
{
|
||
m_pPage->GrRestore();
|
||
m_lClipDepth--;
|
||
}
|
||
}
|
||
|
||
return S_OK;
|
||
}
|
||
//----------------------------------------------------------------------------------------
|
||
// Функции для работы с патом
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT CPdfRenderer::PathCommandStart()
|
||
{
|
||
m_oPath.Clear();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::PathCommandEnd()
|
||
{
|
||
m_oPath.Clear();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::DrawPath(const LONG& lType)
|
||
{
|
||
m_oCommandManager.Flush();
|
||
|
||
if (!IsPageValid())
|
||
return S_FALSE;
|
||
|
||
bool bStroke = LONG_2_BOOL(lType & c_nStroke);
|
||
bool bFill = LONG_2_BOOL(lType & c_nWindingFillMode);
|
||
bool bEoFill = LONG_2_BOOL(lType & c_nEvenOddFillMode);
|
||
|
||
m_pPage->GrSave();
|
||
UpdateTransform();
|
||
|
||
if (bStroke)
|
||
UpdatePen();
|
||
|
||
if (bFill || bEoFill)
|
||
UpdateBrush();
|
||
|
||
if (!m_pShading)
|
||
{
|
||
m_oPath.Draw(m_pPage, bStroke, bFill, bEoFill);
|
||
}
|
||
else
|
||
{
|
||
if (bFill || bEoFill)
|
||
{
|
||
m_pPage->GrSave();
|
||
m_oPath.Clip(m_pPage, bEoFill);
|
||
|
||
if (NULL != m_pShadingExtGrState)
|
||
m_pPage->SetExtGrState(m_pShadingExtGrState);
|
||
|
||
m_pPage->DrawShading(m_pShading);
|
||
m_pPage->GrRestore();
|
||
}
|
||
|
||
if (bStroke)
|
||
m_oPath.Draw(m_pPage, bStroke, false, false);
|
||
}
|
||
|
||
m_pPage->GrRestore();
|
||
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::PathCommandMoveTo(const double& dX, const double& dY)
|
||
{
|
||
m_oPath.MoveTo(MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY));
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::PathCommandLineTo(const double& dX, const double& dY)
|
||
{
|
||
m_oPath.LineTo(MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY));
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::PathCommandLinesTo(double* pPoints, const int& nCount)
|
||
{
|
||
if (nCount < 4 || !pPoints)
|
||
return S_OK;
|
||
|
||
if (!m_oPath.IsMoveTo())
|
||
m_oPath.MoveTo(MM_2_PT(pPoints[0]), MM_2_PT(m_dPageHeight - pPoints[1]));
|
||
|
||
int nPointsCount = (nCount / 2) - 1;
|
||
for (int nIndex = 1; nIndex <= nPointsCount; ++nIndex)
|
||
{
|
||
m_oPath.LineTo(MM_2_PT(pPoints[nIndex * 2]), MM_2_PT(m_dPageHeight - pPoints[nIndex * 2 + 1]));
|
||
}
|
||
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::PathCommandCurveTo(const double& dX1, const double& dY1, const double& dX2, const double& dY2, const double& dXe, const double& dYe)
|
||
{
|
||
m_oPath.CurveTo(MM_2_PT(dX1), MM_2_PT(m_dPageHeight - dY1), MM_2_PT(dX2), MM_2_PT(m_dPageHeight - dY2), MM_2_PT(dXe), MM_2_PT(m_dPageHeight - dYe));
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::PathCommandCurvesTo(double* pPoints, const int& nCount)
|
||
{
|
||
if (nCount < 8 || !pPoints)
|
||
return S_OK;
|
||
|
||
if (!m_oPath.IsMoveTo())
|
||
m_oPath.MoveTo(MM_2_PT(pPoints[0]), MM_2_PT(m_dPageHeight - pPoints[1]));
|
||
|
||
int nPointsCount = (nCount - 2) / 6;
|
||
double* pCur = pPoints + 2;
|
||
for (int nIndex = 0; nIndex <= nPointsCount; ++nIndex, pCur += 6)
|
||
{
|
||
m_oPath.CurveTo(MM_2_PT(pCur[0]), MM_2_PT(m_dPageHeight - pCur[1]), MM_2_PT(pCur[2]), MM_2_PT(m_dPageHeight - pCur[3]), MM_2_PT(pCur[4]), MM_2_PT(m_dPageHeight - pCur[5]));
|
||
}
|
||
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::PathCommandArcTo(const double& dX, const double& dY, const double& dW, const double& dH, const double& dStartAngle, const double& dSweepAngle)
|
||
{
|
||
m_oPath.ArcTo(MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY - dH), MM_2_PT(dW), MM_2_PT(dH), dStartAngle, dSweepAngle);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::PathCommandClose()
|
||
{
|
||
m_oPath.Close();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::PathCommandGetCurrentPoint(double* dX, double* dY)
|
||
{
|
||
m_oPath.GetLastPoint(*dX, *dY);
|
||
*dX = PT_2_MM(*dX);
|
||
*dY = PT_2_MM(*dY);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::PathCommandTextCHAR(const LONG& lUnicode, const double& dX, const double& dY, const double& dW, const double& dH)
|
||
{
|
||
unsigned int unUnicode = lUnicode;
|
||
bool bRes = PathCommandDrawText(&unUnicode, 1, dX, dY, NULL);
|
||
return bRes ? S_OK : S_FALSE;
|
||
}
|
||
HRESULT CPdfRenderer::PathCommandText(const std::wstring& wsUnicodeText, const double& dX, const double& dY, const double& dW, const double& dH)
|
||
{
|
||
unsigned int unLen;
|
||
unsigned int* pUnicodes = WStringToUtf32(wsUnicodeText, unLen);
|
||
if (!pUnicodes)
|
||
return S_FALSE;
|
||
|
||
PathCommandDrawText(pUnicodes, unLen, dX, dY, NULL);
|
||
delete[] pUnicodes;
|
||
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::PathCommandTextExCHAR(const LONG& lUnicode, const LONG& lGid, const double& dX, const double& dY, const double& dW, const double& dH)
|
||
{
|
||
unsigned int unUnicode = lUnicode;
|
||
unsigned int unGid = lGid;
|
||
bool bRes = PathCommandDrawText(&unUnicode, 1, dX, dY, &unGid);
|
||
return bRes ? S_OK : S_FALSE;
|
||
}
|
||
HRESULT CPdfRenderer::PathCommandTextEx(const std::wstring& wsUnicodeText, const unsigned int* pGids, const unsigned int unGidsCount, const double& dX, const double& dY, const double& dW, const double& dH)
|
||
{
|
||
if (!IsPageValid() || (!wsUnicodeText.size() && (!pGids || !unGidsCount)))
|
||
return S_FALSE;
|
||
|
||
unsigned int unLen = 0;
|
||
unsigned int* pUnicodes = NULL;
|
||
if (pGids && unGidsCount)
|
||
{
|
||
unLen = unGidsCount;
|
||
if (wsUnicodeText.size())
|
||
{
|
||
unsigned int unUnicodeLen;
|
||
pUnicodes = WStringToUtf32(wsUnicodeText, unUnicodeLen);
|
||
if (!pUnicodes || unUnicodeLen != unLen)
|
||
RELEASEARRAYOBJECTS(pUnicodes);
|
||
}
|
||
|
||
if (!pUnicodes)
|
||
{
|
||
pUnicodes = new unsigned int[unLen];
|
||
if (!pUnicodes)
|
||
return S_FALSE;
|
||
|
||
for (unsigned int unIndex = 0; unIndex < unLen; unIndex++)
|
||
pUnicodes[unIndex] = pGids[unIndex];
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pUnicodes = WStringToUtf32(wsUnicodeText, unLen);
|
||
if (!pUnicodes)
|
||
return S_FALSE;
|
||
}
|
||
|
||
bool bRes = PathCommandDrawText(pUnicodes, unLen, dX, dY, pGids);
|
||
RELEASEARRAYOBJECTS(pUnicodes);
|
||
|
||
return bRes ? S_OK : S_FALSE;
|
||
}
|
||
//----------------------------------------------------------------------------------------
|
||
// Функции для вывода изображений
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT CPdfRenderer::DrawImage(IGrObject* pImage, const double& dX, const double& dY, const double& dW, const double& dH)
|
||
{
|
||
m_oCommandManager.Flush();
|
||
|
||
if (!IsPageValid() || !pImage)
|
||
return S_OK;
|
||
|
||
if (!DrawImage((Aggplus::CImage*)pImage, dX, dY, dW, dH, 255))
|
||
return S_FALSE;
|
||
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::DrawImageFromFile(const std::wstring& wsImagePath, const double& dX, const double& dY, const double& dW, const double& dH, const BYTE& nAlpha)
|
||
{
|
||
m_oCommandManager.Flush();
|
||
|
||
if (!IsPageValid())
|
||
return S_OK;
|
||
|
||
Aggplus::CImage* pAggImage = NULL;
|
||
|
||
CImageFileFormatChecker oImageFormat(wsImagePath);
|
||
if (_CXIMAGE_FORMAT_WMF == oImageFormat.eFileType || _CXIMAGE_FORMAT_EMF == oImageFormat.eFileType || _CXIMAGE_FORMAT_SVM == oImageFormat.eFileType)
|
||
{
|
||
// TODO: Реализовать отрисовку метафайлов по-нормальному
|
||
MetaFile::CMetaFile oMeta(m_pAppFonts);
|
||
oMeta.LoadFromFile(wsImagePath.c_str());
|
||
|
||
double dNewW = std::max(10.0, dW) / 25.4 * 300;
|
||
std::wstring wsTempFile = GetTempFile();
|
||
oMeta.ConvertToRaster(wsTempFile.c_str(), _CXIMAGE_FORMAT_PNG, dNewW);
|
||
|
||
pAggImage = new Aggplus::CImage(wsTempFile);
|
||
}
|
||
else
|
||
{
|
||
pAggImage = new Aggplus::CImage(wsImagePath);
|
||
}
|
||
|
||
if (!pAggImage)
|
||
return S_FALSE;
|
||
|
||
if (!DrawImage(pAggImage, dX, dY, dW, dH, nAlpha))
|
||
{
|
||
delete pAggImage;
|
||
return S_FALSE;
|
||
}
|
||
|
||
delete pAggImage;
|
||
|
||
return S_OK;
|
||
}
|
||
//----------------------------------------------------------------------------------------
|
||
// Функции для выставления преобразования
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT CPdfRenderer::SetTransform(const double& dM11, const double& dM12, const double& dM21, const double& dM22, const double& dX, const double& dY)
|
||
{
|
||
m_oCommandManager.Flush();
|
||
m_oTransform.Set(dM11, dM12, dM21, dM22, dX, dY);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::GetTransform(double* dM11, double* dM12, double* dM21, double* dM22, double* dX, double* dY)
|
||
{
|
||
*dM11 = m_oTransform.m11;
|
||
*dM12 = m_oTransform.m12;
|
||
*dM21 = m_oTransform.m21;
|
||
*dM22 = m_oTransform.m22;
|
||
*dX = m_oTransform.dx;
|
||
*dY = m_oTransform.dy;
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::ResetTransform()
|
||
{
|
||
m_oCommandManager.Flush();
|
||
m_oTransform.Reset();
|
||
return S_OK;
|
||
}
|
||
//----------------------------------------------------------------------------------------
|
||
// Тип клипа
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT CPdfRenderer::get_ClipMode(LONG* lMode)
|
||
{
|
||
*lMode = m_lClipMode;
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::put_ClipMode(const LONG& lMode)
|
||
{
|
||
m_lClipMode = lMode;
|
||
return S_OK;
|
||
}
|
||
//----------------------------------------------------------------------------------------
|
||
// Дополнительные функции
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT CPdfRenderer::CommandLong(const LONG& lType, const LONG& lCommand)
|
||
{
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::CommandDouble(const LONG& lType, const double& dCommand)
|
||
{
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::CommandString(const LONG& lType, const std::wstring& sCommand)
|
||
{
|
||
return S_OK;
|
||
}
|
||
//----------------------------------------------------------------------------------------
|
||
// Дополнительные функции Pdf рендерера
|
||
//----------------------------------------------------------------------------------------
|
||
HRESULT CPdfRenderer::CommandDrawTextPdf(const std::wstring& bsUnicodeText, const unsigned int* pGids, const unsigned int unGidsCount, const std::wstring& bsSrcCodeText, const double& dX, const double& dY, const double& dW, const double& dH)
|
||
{
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::PathCommandTextPdf(const std::wstring& bsUnicodeText, const unsigned int* pGids, const unsigned int unGidsCount, const std::wstring& bsSrcCodeText, const double& dX, const double& dY, const double& dW, const double& dH)
|
||
{
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::DrawImage1bpp(Pix* pImageBuffer, const unsigned int& unWidth, const unsigned int& unHeight, const double& dX, const double& dY, const double& dW, const double& dH)
|
||
{
|
||
m_oCommandManager.Flush();
|
||
|
||
if (!IsPageValid() || !pImageBuffer)
|
||
return S_OK;
|
||
|
||
m_pPage->GrSave();
|
||
UpdateTransform();
|
||
|
||
CImageDict* pPdfImage = m_pDocument->CreateImage();
|
||
pPdfImage->LoadBW(pImageBuffer, unWidth, unHeight);
|
||
m_pPage->DrawImage(pPdfImage, MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY - dH), MM_2_PT(dW), MM_2_PT(dH));
|
||
|
||
m_pPage->GrRestore();
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::EnableBrushRect(const LONG& lEnable)
|
||
{
|
||
m_oBrush.EnableBrushRect(LONG_2_BOOL(lEnable));
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::SetLinearGradient(const double& dX0, const double& dY0, const double& dX1, const double& dY1)
|
||
{
|
||
m_oBrush.SetType(c_BrushTypeLinearGradient);
|
||
m_oBrush.SetLinearGradientPattern(dX0, dY0, dX1, dY1);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::SetRadialGradient(const double& dX0, const double& dY0, const double& dR0, const double& dX1, const double& dY1, const double& dR1)
|
||
{
|
||
m_oBrush.SetType(c_BrushTypeRadialGradient);
|
||
m_oBrush.SetRadialGradientPattern(dX0, dY0, dR0, dX1, dY1, dR1);
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::DrawImageWith1bppMask(IGrObject* pImage, Pix* pMaskBuffer, const unsigned int& unMaskWidth, const unsigned int& unMaskHeight, const double& dX, const double& dY, const double& dW, const double& dH)
|
||
{
|
||
m_oCommandManager.Flush();
|
||
|
||
if (!IsPageValid() || !pMaskBuffer || !pImage)
|
||
return S_OK;
|
||
|
||
m_pPage->GrSave();
|
||
UpdateTransform();
|
||
CImageDict* pPdfImage = LoadImage((Aggplus::CImage*)pImage, 255);
|
||
pPdfImage->LoadMask(pMaskBuffer, unMaskWidth, unMaskHeight);
|
||
m_pPage->DrawImage(pPdfImage, MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY - dH), MM_2_PT(dW), MM_2_PT(dH));
|
||
m_pPage->GrRestore();
|
||
return S_OK;
|
||
}
|
||
//----------------------------------------------------------------------------------------
|
||
// Внутренние функции
|
||
//----------------------------------------------------------------------------------------
|
||
PdfWriter::CImageDict* CPdfRenderer::LoadImage(Aggplus::CImage* pImage, const BYTE& nAlpha)
|
||
{
|
||
int nImageW = abs((int)pImage->GetWidth());
|
||
int nImageH = abs((int)pImage->GetHeight());
|
||
BYTE* pData = pImage->GetData();
|
||
int nStride = 4 * nImageW;
|
||
|
||
// Картинки совсем маленьких размеров нельзя делать Jpeg2000
|
||
bool bJpeg = false;
|
||
if (nImageH < 100 || nImageW < 100)
|
||
bJpeg = true;
|
||
|
||
// TODO: Пока не разберемся как в CxImage управлять параметрами кодирования нельзя писать в Jpeg2000,
|
||
// т.к. файлы получаются гораздо больше и конвертация идет намного дольше.
|
||
bJpeg = true;
|
||
|
||
// Пробегаемся по картинке и определяем есть ли у нас альфа-канал
|
||
bool bAlpha = false;
|
||
for (int nIndex = 0, nSize = nImageW * nImageH; nIndex < nSize; nIndex++)
|
||
{
|
||
if (pData[4 * nIndex + 3] < 255)
|
||
{
|
||
bAlpha = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
CxImage oCxImage;
|
||
if (!oCxImage.CreateFromArray(pData, nImageW, nImageH, 32, nStride, (pImage->GetStride() >= 0) ? true : false))
|
||
return NULL;
|
||
|
||
oCxImage.SetJpegQualityF(85.0f);
|
||
|
||
BYTE* pBuffer = NULL;
|
||
int nBufferSize = 0;
|
||
if (!oCxImage.Encode(pBuffer, nBufferSize, bJpeg ? CXIMAGE_FORMAT_JPG : CXIMAGE_FORMAT_JP2))
|
||
return NULL;
|
||
|
||
if (!pBuffer || !nBufferSize)
|
||
return NULL;
|
||
|
||
CImageDict* pPdfImage = m_pDocument->CreateImage();
|
||
if (bAlpha || nAlpha < 255)
|
||
pPdfImage->LoadSMask(pData, nImageW, nImageH, nAlpha, (pImage->GetStride() >= 0) ? false : true);
|
||
|
||
if (bJpeg)
|
||
pPdfImage->LoadJpeg(pBuffer, nBufferSize, nImageW, nImageH);
|
||
else
|
||
pPdfImage->LoadJpx(pBuffer, nBufferSize, nImageW, nImageH);
|
||
|
||
free(pBuffer);
|
||
|
||
return pPdfImage;
|
||
}
|
||
bool CPdfRenderer::DrawImage(Aggplus::CImage* pImage, const double& dX, const double& dY, const double& dW, const double& dH, const BYTE& nAlpha)
|
||
{
|
||
CImageDict* pPdfImage = LoadImage(pImage, nAlpha);
|
||
if (!pPdfImage)
|
||
return false;
|
||
|
||
m_pPage->GrSave();
|
||
UpdateTransform();
|
||
m_pPage->DrawImage(pPdfImage, MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY - dH), MM_2_PT(dW), MM_2_PT(dH));
|
||
m_pPage->GrRestore();
|
||
|
||
return true;
|
||
}
|
||
bool CPdfRenderer::DrawText(unsigned int* pUnicodes, unsigned int unLen, const double& dX, const double& dY, const unsigned int* pGids)
|
||
{
|
||
if (m_bNeedUpdateTextFont)
|
||
UpdateFont();
|
||
|
||
if (!m_pFont)
|
||
return false;
|
||
|
||
unsigned char* pCodes = m_pFont->EncodeString(pUnicodes, unLen, pGids);
|
||
|
||
CTransform& t = m_oTransform;
|
||
m_oCommandManager.SetTransform(t.m11, -t.m12, -t.m21, t.m22, MM_2_PT(t.dx + t.m21 * m_dPageHeight), MM_2_PT(m_dPageHeight - m_dPageHeight * t.m22 - t.dy));
|
||
|
||
CRendererTextCommand* pText = m_oCommandManager.AddText(pCodes, unLen * 2, MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY));
|
||
pText->SetFont(m_pFont);
|
||
pText->SetSize(m_oFont.GetSize());
|
||
pText->SetColor(m_oBrush.GetColor1());
|
||
pText->SetAlpha((BYTE)m_oBrush.GetAlpha1());
|
||
pText->SetCharSpace(MM_2_PT(m_oFont.GetCharSpace()));
|
||
|
||
return true;
|
||
}
|
||
bool CPdfRenderer::PathCommandDrawText(unsigned int* pUnicodes, unsigned int unLen, const double& dX, const double& dY, const unsigned int* pGids)
|
||
{
|
||
if (m_bNeedUpdateTextFont)
|
||
UpdateFont();
|
||
|
||
if (!m_pFont)
|
||
return false;
|
||
|
||
unsigned char* pCodes = m_pFont->EncodeString(pUnicodes, unLen, pGids);
|
||
m_oPath.AddText(m_pFont, pCodes, unLen * 2, MM_2_PT(dX), MM_2_PT(m_dPageHeight - dY), m_oFont.GetSize(), MM_2_PT(m_oFont.GetCharSpace()));
|
||
return true;
|
||
}
|
||
void CPdfRenderer::UpdateFont()
|
||
{
|
||
m_bNeedUpdateTextFont = false;
|
||
std::wstring wsFontPath = m_oFont.GetPath();
|
||
LONG lFaceIndex = m_oFont.GetFaceIndex();
|
||
if (L"" == wsFontPath)
|
||
{
|
||
std::wstring wsFontName = m_oFont.GetName();
|
||
bool bBold = m_oFont.IsBold();
|
||
bool bItalic = m_oFont.IsItalic();
|
||
bool bFind = false;
|
||
for (int nIndex = 0, nCount = m_vFonts.size(); nIndex < nCount; nIndex++)
|
||
{
|
||
TFontInfo& oInfo = m_vFonts.at(nIndex);
|
||
if (oInfo.wsFontName == wsFontName && oInfo.bBold == bBold && oInfo.bItalic == bItalic)
|
||
{
|
||
wsFontPath = oInfo.wsFontPath;
|
||
lFaceIndex = oInfo.lFaceIndex;
|
||
bFind = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!bFind)
|
||
{
|
||
CFontSelectFormat oFontSelect;
|
||
oFontSelect.wsName = new std::wstring(m_oFont.GetName());
|
||
oFontSelect.bItalic = new INT(m_oFont.IsItalic() ? 1 : 0);
|
||
oFontSelect.bBold = new INT(m_oFont.IsBold() ? 1 : 0);
|
||
CFontInfo* pFontInfo = m_pFontManager->GetFontInfoByParams(oFontSelect, false);
|
||
|
||
wsFontPath = pFontInfo->m_wsFontPath;
|
||
lFaceIndex = pFontInfo->m_lIndex;
|
||
|
||
m_vFonts.push_back(TFontInfo(wsFontName, bBold, bItalic, wsFontPath, lFaceIndex));
|
||
}
|
||
}
|
||
|
||
m_pFont = NULL;
|
||
if (L"" != wsFontPath)
|
||
{
|
||
// TODO: Пока мы здесь предполагаем, что шрифты только либо TrueType, либо OpenType
|
||
m_pFontManager->LoadFontFromFile(wsFontPath, lFaceIndex, 10, 72, 72);
|
||
std::wstring wsFontType = m_pFontManager->GetFontType();
|
||
if (L"TrueType" == wsFontType || L"OpenType" == wsFontType || L"CFF" == wsFontType)
|
||
m_pFont = m_pDocument->CreateTrueTypeFont(wsFontPath, lFaceIndex);
|
||
}
|
||
}
|
||
void CPdfRenderer::UpdateTransform()
|
||
{
|
||
CTransform& t = m_oTransform;
|
||
m_pPage->SetTransform(t.m11, -t.m12, -t.m21, t.m22, MM_2_PT(t.dx + t.m21 * m_dPageHeight), MM_2_PT(m_dPageHeight - m_dPageHeight * t.m22 - t.dy));
|
||
}
|
||
void CPdfRenderer::UpdatePen()
|
||
{
|
||
TColor oColor = m_oPen.GetTColor();
|
||
m_pPage->SetStrokeColor(oColor.r, oColor.g, oColor.b);
|
||
m_pPage->SetStrokeAlpha((unsigned char)m_oPen.GetAlpha());
|
||
m_pPage->SetLineWidth(MM_2_PT(m_oPen.GetSize()));
|
||
|
||
LONG lDashCount = 0;
|
||
double* pDashPattern = NULL;
|
||
|
||
LONG lDashStyle = m_oPen.GetDashStyle();
|
||
if (Aggplus::DashStyleSolid == lDashStyle)
|
||
{
|
||
// Ничего не делаем
|
||
}
|
||
else if (Aggplus::DashStyleCustom == lDashStyle)
|
||
{
|
||
double *pDashPatternMM = m_oPen.GetDashPattern(lDashCount);
|
||
if (pDashPatternMM && lDashCount)
|
||
{
|
||
pDashPattern = new double[lDashCount];
|
||
if (pDashPattern)
|
||
{
|
||
for (LONG lIndex = 0; lIndex < lDashCount; lIndex++)
|
||
{
|
||
pDashPattern[lIndex] = MM_2_PT(pDashPatternMM[lIndex]);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// TODO: Реализовать другие типы пунктирных линий
|
||
}
|
||
|
||
if (pDashPattern && lDashCount)
|
||
{
|
||
m_pPage->SetDash(pDashPattern, lDashCount, MM_2_PT(m_oPen.GetDashOffset()));
|
||
delete[] pDashPattern;
|
||
}
|
||
|
||
LONG lCapStyle = m_oPen.GetStartCapStyle();
|
||
if (Aggplus::LineCapRound == lCapStyle)
|
||
m_pPage->SetLineCap(linecap_Round);
|
||
else if (Aggplus::LineCapSquare == lCapStyle)
|
||
m_pPage->SetLineCap(linecap_ProjectingSquare);
|
||
else
|
||
m_pPage->SetLineCap(linecap_Butt);
|
||
|
||
LONG lJoinStyle = m_oPen.GetJoinStyle();
|
||
if (Aggplus::LineJoinBevel == lJoinStyle)
|
||
m_pPage->SetLineJoin(linejoin_Bevel);
|
||
else if (Aggplus::LineJoinMiter == lJoinStyle)
|
||
{
|
||
m_pPage->SetLineJoin(linejoin_Miter);
|
||
m_pPage->SetMiterLimit(MM_2_PT(m_oPen.GetMiter()));
|
||
}
|
||
else
|
||
m_pPage->SetLineJoin(linejoin_Round);
|
||
}
|
||
void CPdfRenderer::UpdateBrush()
|
||
{
|
||
m_pShading = NULL;
|
||
m_pShadingExtGrState = NULL;
|
||
|
||
LONG lBrushType = m_oBrush.GetType();
|
||
if (c_BrushTypeTexture == lBrushType)
|
||
{
|
||
std::wstring wsTexturePath = m_oBrush.GetTexturePath();
|
||
CImageFileFormatChecker oImageFormat(wsTexturePath);
|
||
|
||
CImageDict* pImage = NULL;
|
||
int nImageW = 0;
|
||
int nImageH = 0;
|
||
if (_CXIMAGE_FORMAT_JPG == oImageFormat.eFileType || _CXIMAGE_FORMAT_JP2 == oImageFormat.eFileType)
|
||
{
|
||
pImage = m_pDocument->CreateImage();
|
||
CBgraFrame oFrame;
|
||
oFrame.OpenFile(wsTexturePath);
|
||
nImageH = oFrame.get_Height();
|
||
nImageW = oFrame.get_Width();
|
||
|
||
if (pImage)
|
||
{
|
||
if (_CXIMAGE_FORMAT_JPG == oImageFormat.eFileType)
|
||
pImage->LoadJpeg(wsTexturePath.c_str(), nImageW, nImageH);
|
||
else
|
||
pImage->LoadJpx(wsTexturePath.c_str(), nImageW, nImageH);
|
||
}
|
||
}
|
||
else if (_CXIMAGE_FORMAT_WMF == oImageFormat.eFileType || _CXIMAGE_FORMAT_EMF == oImageFormat.eFileType || _CXIMAGE_FORMAT_SVM == oImageFormat.eFileType)
|
||
{
|
||
// TODO: Реализовать отрисовку метафайлов по-нормальному
|
||
MetaFile::CMetaFile oMeta(m_pAppFonts);
|
||
oMeta.LoadFromFile(wsTexturePath.c_str());
|
||
|
||
double dL, dR, dT, dB;
|
||
m_oPath.GetBounds(dL, dT, dR, dB);
|
||
|
||
double dNewW = std::max(10.0, dR - dL) / 72 * 300;
|
||
|
||
std::wstring wsTempFile = GetTempFile();
|
||
oMeta.ConvertToRaster(wsTempFile.c_str(), _CXIMAGE_FORMAT_PNG, dNewW);
|
||
|
||
Aggplus::CImage oImage(wsTempFile);
|
||
nImageW = abs((int)oImage.GetWidth());
|
||
nImageH = abs((int)oImage.GetHeight());
|
||
pImage = LoadImage(&oImage, 255);
|
||
}
|
||
else
|
||
{
|
||
Aggplus::CImage oImage(wsTexturePath);
|
||
nImageW = abs((int)oImage.GetWidth());
|
||
nImageH = abs((int)oImage.GetHeight());
|
||
pImage = LoadImage(&oImage, 255);
|
||
}
|
||
|
||
if (pImage)
|
||
{
|
||
LONG lTextureMode = m_oBrush.GetTextureMode();
|
||
|
||
double dW = 10;
|
||
double dH = 10;
|
||
|
||
double dL, dR, dT, dB;
|
||
m_oPath.GetBounds(dL, dT, dR, dB);
|
||
|
||
if (c_BrushTextureModeStretch == lTextureMode)
|
||
{
|
||
// Чтобы избавиться от погрешностей из-за которых могут возникать полоски, немного увеличим границы пата.
|
||
dL -= 1;
|
||
dT -= 1;
|
||
dB += 1;
|
||
dR += 1;
|
||
|
||
// Растягиваем картинку по размерам пата
|
||
dW = std::max(10.0, dR - dL);
|
||
dH = std::max(10.0, dB - dT);
|
||
}
|
||
else
|
||
{
|
||
// Размеры картинки заданы в пикселях. Размеры тайла - это размеры картинки в пунктах.
|
||
dW = nImageW * 72 / 96;
|
||
dH = nImageH * 72 / 96;
|
||
}
|
||
|
||
// Нам нужно, чтобы левый нижний угол границ нашего пата являлся точкой переноса для матрицы преобразования.
|
||
CMatrix* pMatrix = m_pPage->GetTransform();
|
||
pMatrix->Apply(dL, dB);
|
||
CMatrix oPatternMatrix = *pMatrix;
|
||
oPatternMatrix.x = dL;
|
||
oPatternMatrix.y = dB;
|
||
m_pPage->SetPatternColorSpace(m_pDocument->CreateImageTilePattern(dW, dH, pImage, &oPatternMatrix));
|
||
}
|
||
}
|
||
else if (c_BrushTypeHatch1 == lBrushType)
|
||
{
|
||
std::wstring wsHatchType = m_oBrush.GetTexturePath();
|
||
|
||
double dW = 8 * 72 / 96;
|
||
double dH = 8 * 72 / 96;
|
||
|
||
TColor oColor1 = m_oBrush.GetTColor1();
|
||
TColor oColor2 = m_oBrush.GetTColor2();
|
||
BYTE nAlpha1 = (BYTE)m_oBrush.GetAlpha1();
|
||
BYTE nAlpha2 = (BYTE)m_oBrush.GetAlpha2();
|
||
|
||
m_pPage->SetPatternColorSpace(m_pDocument->CreateHatchPattern(dW, dH, oColor1.r, oColor1.g, oColor1.b, nAlpha1, oColor2.r, oColor2.g, oColor2.b, nAlpha2, wsHatchType));
|
||
}
|
||
else if (c_BrushTypeRadialGradient == lBrushType || c_BrushTypeLinearGradient == lBrushType)
|
||
{
|
||
TColor* pGradientColors;
|
||
double* pPoints;
|
||
LONG lCount;
|
||
|
||
m_oBrush.GetGradientColors(pGradientColors, pPoints, lCount);
|
||
|
||
if (lCount > 0)
|
||
{
|
||
unsigned char* pColors = new unsigned char[3 * lCount];
|
||
unsigned char* pAlphas = new unsigned char[lCount];
|
||
if (pColors)
|
||
{
|
||
for (LONG lIndex = 0; lIndex < lCount; lIndex++)
|
||
{
|
||
pColors[3 * lIndex + 0] = pGradientColors[lIndex].r;
|
||
pColors[3 * lIndex + 1] = pGradientColors[lIndex].g;
|
||
pColors[3 * lIndex + 2] = pGradientColors[lIndex].b;
|
||
pAlphas[lIndex] = pGradientColors[lIndex].a;
|
||
}
|
||
|
||
if (c_BrushTypeLinearGradient == lBrushType)
|
||
{
|
||
double dX0, dY0, dX1, dY1;
|
||
m_oBrush.GetLinearGradientPattern(dX0, dY0, dX1, dY1);
|
||
m_pShading = m_pDocument->CreateAxialShading(m_pPage, MM_2_PT(dX0), MM_2_PT(m_dPageHeight - dY0), MM_2_PT(dX1), MM_2_PT(m_dPageHeight - dY1), pColors, pAlphas, pPoints, lCount, m_pShadingExtGrState);
|
||
}
|
||
else //if (c_BrushTypeRadialGradient == lBrushType)
|
||
{
|
||
double dX0, dY0, dR0, dX1, dY1, dR1;
|
||
m_oBrush.GetRadialGradientPattern(dX0, dY0, dR0, dX1, dY1, dR1);
|
||
m_pShading = m_pDocument->CreateRadialShading(m_pPage, MM_2_PT(dX0), MM_2_PT(m_dPageHeight - dY0), MM_2_PT(dR0), MM_2_PT(dX1), MM_2_PT(m_dPageHeight - dY1), MM_2_PT(dR1), pColors, pAlphas, pPoints, lCount, m_pShadingExtGrState);
|
||
}
|
||
delete[] pColors;
|
||
delete[] pAlphas;
|
||
}
|
||
}
|
||
}
|
||
else// if (c_BrushTypeSolid == lBrushType)
|
||
{
|
||
TColor oColor1 = m_oBrush.GetTColor1();
|
||
m_pPage->SetFillColor(oColor1.r, oColor1.g, oColor1.b);
|
||
m_pPage->SetFillAlpha((unsigned char)m_oBrush.GetAlpha1());
|
||
}
|
||
}
|
||
HRESULT CPdfRenderer::OnlineWordToPdf (const std::wstring& wsSrcFile, const std::wstring& wsDstFile)
|
||
{
|
||
if (!NSOnlineOfficeBinToPdf::ConvertBinToPdf(this, wsSrcFile, wsDstFile, false))
|
||
return S_FALSE;
|
||
|
||
return S_OK;
|
||
}
|
||
HRESULT CPdfRenderer::OnlineWordToPdfFromBinary(const std::wstring& wsSrcFile, const std::wstring& wsDstFile)
|
||
{
|
||
if (!NSOnlineOfficeBinToPdf::ConvertBinToPdf(this, wsSrcFile, wsDstFile, true))
|
||
return S_FALSE;
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
static inline void UpdateMaxMinPoints(double& dMinX, double& dMinY, double& dMaxX, double& dMaxY, const double& dX, const double& dY)
|
||
{
|
||
if (dX < dMinX)
|
||
dMinX = dX;
|
||
|
||
if (dX > dMaxX)
|
||
dMaxX = dX;
|
||
|
||
if (dY < dMinY)
|
||
dMinY = dY;
|
||
|
||
if (dY > dMaxY)
|
||
dMaxY = dY;
|
||
}
|
||
void CPdfRenderer::CPath::Draw(PdfWriter::CPage* pPage, bool bStroke, bool bFill, bool bEoFill)
|
||
{
|
||
for (int nIndex = 0, nCount = m_vCommands.size(); nIndex < nCount; nIndex++)
|
||
{
|
||
CPathCommandBase* pCommand = m_vCommands.at(nIndex);
|
||
pCommand->Draw(pPage);
|
||
}
|
||
|
||
if (bStroke && !bFill && !bEoFill)
|
||
pPage->Stroke();
|
||
else if (bStroke && bFill)
|
||
pPage->FillStroke();
|
||
else if (bStroke && bEoFill)
|
||
pPage->EoFillStroke();
|
||
else if (bFill)
|
||
pPage->Fill();
|
||
else if (bEoFill)
|
||
pPage->EoFill();
|
||
else
|
||
pPage->EndPath();
|
||
}
|
||
void CPdfRenderer::CPath::Clip(PdfWriter::CPage* pPage, bool bEvenOdd)
|
||
{
|
||
for (int nIndex = 0, nCount = m_vCommands.size(); nIndex < nCount; nIndex++)
|
||
{
|
||
CPathCommandBase* pCommand = m_vCommands.at(nIndex);
|
||
pCommand->Draw(pPage);
|
||
}
|
||
|
||
if (bEvenOdd)
|
||
pPage->Eoclip();
|
||
else
|
||
pPage->Clip();
|
||
|
||
pPage->EndPath();
|
||
}
|
||
void CPdfRenderer::CPath::GetLastPoint(double& dX, double& dY)
|
||
{
|
||
dX = 0;
|
||
dY = 0;
|
||
|
||
bool bFindMoveTo = false;
|
||
for (int nIndex = m_vCommands.size() - 1; nIndex >= 0; nIndex--)
|
||
{
|
||
CPathCommandBase* pCommand = m_vCommands.at(nIndex);
|
||
if (rendererpathcommand_Close == pCommand->GetType())
|
||
{
|
||
bFindMoveTo = true;
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
pCommand->GetLastPoint(dX, dY);
|
||
if (!bFindMoveTo || rendererpathcommand_MoveTo == pCommand->GetType())
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
void CPdfRenderer::CPath::GetBounds(double& dL, double& dT, double& dR, double& dB)
|
||
{
|
||
GetLastPoint(dL, dT);
|
||
dR = dL;
|
||
dB = dT;
|
||
|
||
for (int nIndex = 0, nCount = m_vCommands.size(); nIndex < nCount; nIndex++)
|
||
{
|
||
CPathCommandBase* pCommand = m_vCommands.at(nIndex);
|
||
pCommand->UpdateBounds(dL, dT, dR, dB);
|
||
}
|
||
}
|
||
void CPdfRenderer::CPath::CPathMoveTo::Draw(PdfWriter::CPage* pPage)
|
||
{
|
||
pPage->MoveTo(x, y);
|
||
}
|
||
void CPdfRenderer::CPath::CPathMoveTo::UpdateBounds(double& dL, double& dT, double& dR, double& dB)
|
||
{
|
||
UpdateMaxMinPoints(dL, dT, dR, dB, x, y);
|
||
}
|
||
void CPdfRenderer::CPath::CPathLineTo::Draw(PdfWriter::CPage* pPage)
|
||
{
|
||
pPage->LineTo(x, y);
|
||
}
|
||
void CPdfRenderer::CPath::CPathLineTo::UpdateBounds(double& dL, double& dT, double& dR, double& dB)
|
||
{
|
||
UpdateMaxMinPoints(dL, dT, dR, dB, x, y);
|
||
}
|
||
void CPdfRenderer::CPath::CPathCurveTo::Draw(PdfWriter::CPage* pPage)
|
||
{
|
||
pPage->CurveTo(x1, y1, x2, y2, xe, ye);
|
||
}
|
||
void CPdfRenderer::CPath::CPathCurveTo::UpdateBounds(double& dL, double& dT, double& dR, double& dB)
|
||
{
|
||
UpdateMaxMinPoints(dL, dT, dR, dB, x1, y1);
|
||
UpdateMaxMinPoints(dL, dT, dR, dB, x2, y2);
|
||
UpdateMaxMinPoints(dL, dT, dR, dB, xe, ye);
|
||
}
|
||
void CPdfRenderer::CPath::CPathArcTo::Draw(PdfWriter::CPage* pPage)
|
||
{
|
||
if (sweepAngle >= 360 - 0.001)
|
||
pPage->Ellipse(x + w / 2, y + h / 2, w / 2, h / 2);
|
||
else
|
||
pPage->EllipseArcTo(x + w / 2, y + h / 2, w / 2, h / 2, 360 - startAngle, 360 - (startAngle + sweepAngle), sweepAngle > 0 ? true : false);
|
||
}
|
||
void CPdfRenderer::CPath::CPathArcTo::UpdateBounds(double& dL, double& dT, double& dR, double& dB)
|
||
{
|
||
UpdateMaxMinPoints(dL, dT, dR, dB, x, y);
|
||
UpdateMaxMinPoints(dL, dT, dR, dB, x + w, y + h);
|
||
}
|
||
void CPdfRenderer::CPath::CPathClose::Draw(PdfWriter::CPage* pPage)
|
||
{
|
||
pPage->ClosePath();
|
||
}
|
||
void CPdfRenderer::CPath::CPathClose::UpdateBounds(double& dL, double& dT, double& dR, double& dB)
|
||
{
|
||
}
|
||
void CPdfRenderer::CPath::CPathText::Draw(PdfWriter::CPage* pPage)
|
||
{
|
||
// TODO: Если данная команда будет часто вызываться, тогда ее нужно будет оптимизировать, точно также как это делается в обычном тексте
|
||
pPage->BeginText();
|
||
pPage->SetFontAndSize(font, fontSize);
|
||
pPage->SetCharSpace(charSpace);
|
||
pPage->SetTextRenderingMode(textrenderingmode_Stroke);
|
||
pPage->DrawText(x, y, codes, codesCount);
|
||
pPage->EndText();
|
||
}
|
||
void CPdfRenderer::CPath::CPathText::UpdateBounds(double& dL, double& dT, double& dR, double& dB)
|
||
{
|
||
UpdateMaxMinPoints(dL, dT, dR, dB, x, y);
|
||
}
|
||
void CPdfRenderer::CBrushState::Reset()
|
||
{
|
||
m_lType = c_BrushTypeSolid;
|
||
m_oColor1.Set(0);
|
||
m_oColor2.Set(0);
|
||
m_nAlpha1 = 255;
|
||
m_nAlpha2 = 255;
|
||
m_wsTexturePath = L"";
|
||
m_lTextureMode = c_BrushTextureModeStretch;
|
||
m_nTextureAlpha = 255;
|
||
m_dLinearAngle = 0;
|
||
m_oRect.Reset();
|
||
|
||
if (m_pShadingColors)
|
||
delete[] m_pShadingColors;
|
||
|
||
if (m_pShadingPoints)
|
||
delete[] m_pShadingPoints;
|
||
|
||
m_pShadingColors = NULL;
|
||
m_pShadingPoints = NULL;
|
||
m_lShadingPointsCount = 0;
|
||
}
|