mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-07-11 03:42:47 +08:00
693 lines
20 KiB
C++
693 lines
20 KiB
C++
#include "Document.h"
|
||
#include "Info.h"
|
||
#include "Catalog.h"
|
||
#include "Streams.h"
|
||
#include "EncryptDictionary.h"
|
||
#include "Encrypt.h"
|
||
#include "Pages.h"
|
||
#include "Outline.h"
|
||
#include "Destination.h"
|
||
#include "GState.h"
|
||
#include "Annotation.h"
|
||
#include "Image.h"
|
||
#include "Font14.h"
|
||
#include "FontCidTT.h"
|
||
#include "Shading.h"
|
||
#include "Pattern.h"
|
||
|
||
#include "../../DesktopEditor/agg-2.4/include/agg_span_hatch.h"
|
||
|
||
#ifdef CreateFont
|
||
#undef CreateFont
|
||
#endif
|
||
|
||
namespace PdfWriter
|
||
{
|
||
const char* c_sPdfHeader = "%PDF-1.7\012%ASC\012";
|
||
//----------------------------------------------------------------------------------------
|
||
// CDocument
|
||
//----------------------------------------------------------------------------------------
|
||
CDocument::CDocument()
|
||
{
|
||
m_pCatalog = NULL;
|
||
m_pOutlines = NULL;
|
||
m_pXref = NULL;
|
||
m_pPageTree = NULL;
|
||
m_pCurPage = NULL;
|
||
m_nCurPageNum = -1;
|
||
m_pInfo = NULL;
|
||
m_pTrailer = NULL;
|
||
m_pResources = NULL;
|
||
m_bEncrypt = false;
|
||
m_pEncryptDict = NULL;
|
||
m_unCompressMode = COMP_NONE;
|
||
m_pJbig2 = NULL;
|
||
memset((void*)m_sTTFontTag, 0x00, 8);
|
||
m_pTransparencyGroup = NULL;
|
||
m_pFreeTypeLibrary = NULL;
|
||
}
|
||
CDocument::~CDocument()
|
||
{
|
||
Close();
|
||
}
|
||
bool CDocument::CreateNew()
|
||
{
|
||
Close();
|
||
|
||
m_pXref = new CXref(0);
|
||
if (!m_pXref)
|
||
return false;
|
||
|
||
m_pTrailer = m_pXref->GetTrailer();
|
||
if (!m_pTrailer)
|
||
return false;
|
||
|
||
m_pCatalog = new CCatalog(m_pXref);
|
||
if (!m_pCatalog)
|
||
return false;
|
||
|
||
m_pCatalog->SetPageMode(pagemode_UseNone);
|
||
m_pCatalog->SetPageLayout(pagelayout_OneColumn);
|
||
|
||
m_pPageTree = m_pCatalog->GetRoot();
|
||
if (!m_pPageTree)
|
||
return false;
|
||
|
||
m_pInfo = new CInfoDict(m_pXref);
|
||
if (!m_pInfo)
|
||
return false;
|
||
|
||
m_pInfo->SetCreationTime();
|
||
m_pInfo->SetInfo(InfoProducer, "Ascensio System SIA Copyright (c) 2015");
|
||
|
||
m_nCurPageNum = -1;
|
||
|
||
m_vPages.clear();
|
||
m_vExtGrStates.clear();
|
||
m_vFillAlpha.clear();
|
||
m_vStrokeAlpha.clear();
|
||
|
||
m_pTransparencyGroup = NULL;
|
||
|
||
return true;
|
||
}
|
||
void CDocument::Close()
|
||
{
|
||
// Все объекты удаляются внутри CXref
|
||
RELEASEOBJECT(m_pXref);
|
||
|
||
m_pTrailer = NULL;
|
||
m_pResources = NULL;
|
||
m_pCatalog = NULL;
|
||
m_pOutlines = NULL;
|
||
m_pPageTree = NULL;
|
||
m_pCurPage = NULL;
|
||
m_nCurPageNum = 0;
|
||
m_bEncrypt = false;
|
||
m_pEncryptDict = NULL;
|
||
m_pInfo = NULL;
|
||
m_unCompressMode = COMP_NONE;
|
||
m_pJbig2 = NULL;
|
||
m_pTransparencyGroup= NULL;
|
||
memset((void*)m_sTTFontTag, 0x00, 8);
|
||
|
||
m_vPages.clear();
|
||
m_vExtGrStates.clear();
|
||
m_vStrokeAlpha.clear();
|
||
m_vFillAlpha.clear();
|
||
m_vShadings.clear();
|
||
m_vTTFonts.clear();
|
||
m_vFreeTypeFonts.clear();
|
||
if (m_pFreeTypeLibrary)
|
||
{
|
||
FT_Done_FreeType(m_pFreeTypeLibrary);
|
||
m_pFreeTypeLibrary = NULL;
|
||
}
|
||
}
|
||
bool CDocument::SaveToFile(const std::wstring& wsPath)
|
||
{
|
||
CFileStream* pStream = new CFileStream();
|
||
if (!pStream || !pStream->OpenFile(wsPath, true))
|
||
return false;
|
||
|
||
if (m_pJbig2)
|
||
m_pJbig2->FlushStreams();
|
||
|
||
SaveToStream((CStream*)pStream);
|
||
delete pStream;
|
||
|
||
return true;
|
||
}
|
||
void CDocument::SaveToStream(CStream* pStream)
|
||
{
|
||
unsigned long nRet = OK;
|
||
|
||
// Пишем заголовок
|
||
pStream->WriteStr(c_sPdfHeader);
|
||
|
||
// Добавляем в Trailer необходимые элементы
|
||
m_pTrailer->Add("Root", m_pCatalog);
|
||
m_pTrailer->Add("Info", m_pInfo);
|
||
|
||
// Шифруем документ, если это необходимо
|
||
CEncrypt* pEncrypt = NULL;
|
||
if (m_bEncrypt)
|
||
{
|
||
pEncrypt = m_pEncryptDict->GetEncrypt();
|
||
PrepareEncryption();
|
||
}
|
||
|
||
m_pXref->WriteToStream(pStream, pEncrypt);
|
||
}
|
||
void CDocument::PrepareEncryption()
|
||
{
|
||
CEncrypt* pEncrypt = m_pEncryptDict->GetEncrypt();
|
||
if (!pEncrypt)
|
||
return;
|
||
|
||
m_pEncryptDict->Prepare(m_pInfo, m_pXref);
|
||
|
||
CArrayObject* pID = (CArrayObject*)m_pTrailer->Get("ID");
|
||
if (!pID)
|
||
{
|
||
pID = new CArrayObject();
|
||
m_pTrailer->Add("ID", pID);
|
||
}
|
||
else
|
||
pID->Clear();
|
||
|
||
pID->Add(new CBinaryObject(pEncrypt->m_anEncryptID, ID_LEN));
|
||
pID->Add(new CBinaryObject(pEncrypt->m_anEncryptID, ID_LEN));
|
||
}
|
||
void CDocument::SetEncryptionMode(EEncryptMode eMode, unsigned int unKeyLen)
|
||
{
|
||
if (!m_bEncrypt)
|
||
return;
|
||
|
||
CEncrypt* pEncrypt = m_pEncryptDict->GetEncrypt();
|
||
pEncrypt->SetMode(eMode, unKeyLen);
|
||
}
|
||
void CDocument::SetPassword(const char* sOwnerPassword, const char* sUserPassword)
|
||
{
|
||
if (!m_pEncryptDict)
|
||
m_pEncryptDict = new CEncryptDict(m_pXref);
|
||
|
||
if (!m_pEncryptDict)
|
||
return;
|
||
|
||
m_pEncryptDict->SetPassword(sOwnerPassword, sUserPassword);
|
||
m_pTrailer->Add("Encrypt", m_pEncryptDict);
|
||
m_bEncrypt = true;
|
||
}
|
||
CPage* CDocument::AddPage()
|
||
{
|
||
CPage* pPage = new CPage(m_pXref, m_pPageTree, this);
|
||
m_pPageTree->AddPage(pPage);
|
||
m_pCurPage = pPage;
|
||
m_vPages.push_back(pPage);
|
||
|
||
|
||
#ifndef FILTER_FLATE_DECODE_DISABLED
|
||
if (m_unCompressMode & COMP_TEXT)
|
||
pPage->SetFilter(STREAM_FILTER_FLATE_DECODE);
|
||
#endif
|
||
|
||
m_nCurPageNum++;
|
||
return pPage;
|
||
}
|
||
void CDocument::SetPermission(unsigned int unPermission)
|
||
{
|
||
if (!m_bEncrypt)
|
||
return;
|
||
|
||
CEncrypt* pEncrypt = m_pEncryptDict->GetEncrypt();
|
||
pEncrypt->SetPermission(unPermission);
|
||
}
|
||
void CDocument::SetCompressionMode(unsigned int unMode)
|
||
{
|
||
m_unCompressMode = unMode;
|
||
}
|
||
void CDocument::AddPageLabel(EPageNumStyle eStyle, unsigned int unFirstPage, const char* sPrefix)
|
||
{
|
||
CDictObject* pPageLabel = CreatePageLabel(eStyle, unFirstPage, sPrefix);
|
||
if (!pPageLabel)
|
||
return;
|
||
|
||
m_pCatalog->AddPageLabel(m_nCurPageNum, pPageLabel);
|
||
}
|
||
void CDocument::AddPageLabel(unsigned int unPageNum, EPageNumStyle eStyle, unsigned int unFirstPage, const char* sPrefix)
|
||
{
|
||
CDictObject* pPageLabel = CreatePageLabel(eStyle, unFirstPage, sPrefix);
|
||
if (!pPageLabel)
|
||
return;
|
||
|
||
m_pCatalog->AddPageLabel(unPageNum, pPageLabel);
|
||
}
|
||
CDictObject* CDocument::CreatePageLabel(EPageNumStyle eStyle, unsigned int unFirstPage, const char* sPrefix)
|
||
{
|
||
CDictObject* pLabel = new CDictObject();
|
||
if (!pLabel)
|
||
return NULL;
|
||
|
||
eStyle = std::min(std::max(eStyle, pagenumstyle_Min), pagenumstyle_Max);
|
||
switch (eStyle)
|
||
{
|
||
case pagenumstyle_UpperRoman: pLabel->Add("S", "R"); break;
|
||
case pagenumstyle_LowerRoman: pLabel->Add("S", "r"); break;
|
||
case pagenumstyle_UpperLetters: pLabel->Add("S", "A"); break;
|
||
case pagenumstyle_LowerLetters: pLabel->Add("S", "a"); break;
|
||
case pagenumstyle_Decimal: pLabel->Add("S", "D"); break;
|
||
}
|
||
|
||
if (sPrefix && 0 != sPrefix[0])
|
||
pLabel->Add("P", new CStringObject(sPrefix));
|
||
|
||
if (0 != unFirstPage)
|
||
pLabel->Add("St", unFirstPage);
|
||
|
||
return pLabel;
|
||
}
|
||
COutline* CDocument::CreateOutline(COutline* pParent, const char* sTitle)
|
||
{
|
||
if (!pParent)
|
||
{
|
||
if (!m_pOutlines)
|
||
{
|
||
m_pOutlines = new COutline(m_pXref);
|
||
if (m_pOutlines)
|
||
m_pCatalog->Add("Outlines", m_pOutlines);
|
||
else
|
||
return NULL;
|
||
}
|
||
|
||
pParent = m_pOutlines;
|
||
}
|
||
|
||
return new COutline(pParent, sTitle, m_pXref);
|
||
}
|
||
CDestination* CDocument::CreateDestination(unsigned int unPageIndex)
|
||
{
|
||
if (unPageIndex >= m_vPages.size())
|
||
return NULL;
|
||
|
||
CPage* pPage = m_vPages.at(unPageIndex);
|
||
return new CDestination(pPage, m_pXref);
|
||
}
|
||
CExtGrState* CDocument::FindExtGrState(double dAlphaStroke, double dAlphaFill, EBlendMode eMode, int nStrokeAdjustment)
|
||
{
|
||
CExtGrState* pExtGrState = NULL;
|
||
for (unsigned int unIndex = 0, unCount = m_vExtGrStates.size(); unIndex < unCount; unIndex++)
|
||
{
|
||
pExtGrState = m_vExtGrStates.at(unIndex);
|
||
|
||
if (dAlphaStroke != pExtGrState->GetAlphaStroke())
|
||
continue;
|
||
|
||
if (dAlphaFill != pExtGrState->GetAlphaFill())
|
||
continue;
|
||
|
||
if (eMode != pExtGrState->GetBlendMode())
|
||
continue;
|
||
|
||
if ((0 == nStrokeAdjustment ? false : true) != pExtGrState->GetStrokeAdjustment())
|
||
continue;
|
||
|
||
return pExtGrState;
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
CExtGrState* CDocument::GetExtGState(double dAlphaStroke, double dAlphaFill, EBlendMode eMode, int nStrokeAdjustment)
|
||
{
|
||
CExtGrState* pExtGrState = FindExtGrState(dAlphaStroke, dAlphaFill, eMode, nStrokeAdjustment);
|
||
|
||
if (!pExtGrState)
|
||
{
|
||
pExtGrState = new CExtGrState(m_pXref);
|
||
if (!pExtGrState)
|
||
return NULL;
|
||
|
||
if (-1 != dAlphaStroke)
|
||
pExtGrState->SetAlphaStroke(dAlphaStroke);
|
||
|
||
|
||
if (-1 != dAlphaFill)
|
||
pExtGrState->SetAlphaFill(dAlphaFill);
|
||
|
||
if (blendmode_Unknown != eMode)
|
||
pExtGrState->SetBlendMode(eMode);
|
||
|
||
if (-1 != nStrokeAdjustment)
|
||
pExtGrState->SetStrokeAdjustment(0 == nStrokeAdjustment ? false : true);
|
||
|
||
m_vExtGrStates.push_back(pExtGrState);
|
||
}
|
||
|
||
return pExtGrState;
|
||
}
|
||
CExtGrState* CDocument::GetStrokeAlpha(double dAlpha)
|
||
{
|
||
CExtGrState* pExtGrState = NULL;
|
||
for (unsigned int unIndex = 0, unCount = m_vStrokeAlpha.size(); unIndex < unCount; unIndex++)
|
||
{
|
||
pExtGrState = m_vStrokeAlpha.at(unIndex);
|
||
|
||
if (fabs(dAlpha - pExtGrState->GetAlphaStroke()) < 0.001)
|
||
return pExtGrState;
|
||
}
|
||
|
||
pExtGrState = new CExtGrState(m_pXref);
|
||
if (!pExtGrState)
|
||
return NULL;
|
||
|
||
pExtGrState->SetAlphaStroke(dAlpha);
|
||
m_vStrokeAlpha.push_back(pExtGrState);
|
||
return pExtGrState;
|
||
}
|
||
CExtGrState* CDocument::GetFillAlpha(double dAlpha)
|
||
{
|
||
CExtGrState* pExtGrState = NULL;
|
||
for (unsigned int unIndex = 0, unCount = m_vFillAlpha.size(); unIndex < unCount; unIndex++)
|
||
{
|
||
pExtGrState = m_vFillAlpha.at(unIndex);
|
||
|
||
if (fabs(dAlpha - pExtGrState->GetAlphaFill()) < 0.001)
|
||
return pExtGrState;
|
||
}
|
||
|
||
pExtGrState = new CExtGrState(m_pXref);
|
||
if (!pExtGrState)
|
||
return NULL;
|
||
|
||
pExtGrState->SetAlphaFill(dAlpha);
|
||
m_vFillAlpha.push_back(pExtGrState);
|
||
return pExtGrState;
|
||
}
|
||
CAnnotation* CDocument::CreateTextAnnot(unsigned int unPageNum, TRect oRect, const char* sText)
|
||
{
|
||
CAnnotation* pAnnot = new CTextAnnotation(m_pXref, oRect, sText);
|
||
if (pAnnot)
|
||
{
|
||
CPage* pPage = m_vPages.at(unPageNum);
|
||
pPage->AddAnnotation(pAnnot);
|
||
}
|
||
|
||
return pAnnot;
|
||
}
|
||
CAnnotation* CDocument::CreateLinkAnnot(unsigned int unPageNum, TRect oRect, CDestination* pDest)
|
||
{
|
||
CAnnotation* pAnnot = new CLinkAnnotation(m_pXref, oRect, pDest);
|
||
|
||
if (pAnnot)
|
||
{
|
||
CPage* pPage = m_vPages.at(unPageNum);
|
||
pPage->AddAnnotation(pAnnot);
|
||
}
|
||
|
||
return pAnnot;
|
||
}
|
||
CAnnotation* CDocument::CreateUriLinkAnnot(unsigned int unPageNum, TRect oRect, const char* sUri)
|
||
{
|
||
CAnnotation* pAnnot = new CUriLinkAnnotation(m_pXref, oRect, sUri);
|
||
|
||
if (pAnnot)
|
||
{
|
||
CPage* pPage = m_vPages.at(unPageNum);
|
||
pPage->AddAnnotation(pAnnot);
|
||
}
|
||
|
||
return pAnnot;
|
||
}
|
||
CImageDict* CDocument::CreateImage()
|
||
{
|
||
return new CImageDict(m_pXref, this);
|
||
}
|
||
CFont14* CDocument::CreateFont14(EStandard14Fonts eType)
|
||
{
|
||
return new CFont14(m_pXref, this, eType);
|
||
}
|
||
CFontCidTrueType* CDocument::CreateTrueTypeFont(const std::wstring& wsFontPath, unsigned int unIndex)
|
||
{
|
||
for (int nIndex = 0, nCount = m_vTTFonts.size(); nIndex < nCount; nIndex++)
|
||
{
|
||
TFontInfo& oInfo = m_vTTFonts.at(nIndex);
|
||
if (wsFontPath == oInfo.wsPath && unIndex == oInfo.unIndex)
|
||
return oInfo.pFont;
|
||
}
|
||
|
||
CFontCidTrueType* pFont = new CFontCidTrueType(m_pXref, this, wsFontPath, unIndex);
|
||
if (!pFont)
|
||
return NULL;
|
||
|
||
m_vTTFonts.push_back(TFontInfo(wsFontPath, unIndex, pFont));
|
||
return pFont;
|
||
}
|
||
char* CDocument::GetTTFontTag()
|
||
{
|
||
if (0 == m_sTTFontTag[0])
|
||
{
|
||
MemCpy((BYTE*)m_sTTFontTag, (BYTE*)"BAAAAA+", 7);
|
||
}
|
||
else
|
||
{
|
||
for (unsigned int nIndex = 0; nIndex <= 5; nIndex++)
|
||
{
|
||
m_sTTFontTag[nIndex] += 1;
|
||
if (m_sTTFontTag[nIndex] > 'Z')
|
||
m_sTTFontTag[nIndex] = 'A';
|
||
else
|
||
break;
|
||
}
|
||
}
|
||
|
||
return m_sTTFontTag;
|
||
}
|
||
void CDocument::AddFreeTypeFont(CFontCidTrueType* pFont)
|
||
{
|
||
for (int nIndex = 0, nCount = m_vFreeTypeFonts.size(); nIndex < nCount; nIndex++)
|
||
{
|
||
if (pFont == m_vFreeTypeFonts.at(nIndex))
|
||
{
|
||
if (nIndex >= 10)
|
||
{
|
||
m_vFreeTypeFonts.erase(m_vFreeTypeFonts.begin() + nIndex);
|
||
m_vFreeTypeFonts.insert(m_vFreeTypeFonts.begin(), pFont);
|
||
}
|
||
return;
|
||
}
|
||
}
|
||
|
||
m_vFreeTypeFonts.insert(m_vFreeTypeFonts.begin(), pFont);
|
||
|
||
int nFontsCount = m_vFreeTypeFonts.size();
|
||
if (nFontsCount > MAX_OPENED_FT_FACES)
|
||
{
|
||
for (int nFontIndex = MAX_OPENED_FT_FACES; nFontIndex < nFontsCount; nFontIndex++)
|
||
{
|
||
CFontCidTrueType* pFont = m_vFreeTypeFonts.at(nFontIndex);
|
||
pFont->CloseFontFace();
|
||
}
|
||
m_vFreeTypeFonts.erase(m_vFreeTypeFonts.begin() + MAX_OPENED_FT_FACES, m_vFreeTypeFonts.end());
|
||
}
|
||
}
|
||
FT_Library CDocument::GetFreeTypeLibrary()
|
||
{
|
||
if (!m_pFreeTypeLibrary)
|
||
FT_Init_FreeType(&m_pFreeTypeLibrary);
|
||
|
||
return m_pFreeTypeLibrary;
|
||
}
|
||
CJbig2Global* CDocument::GetJbig2Global()
|
||
{
|
||
if (m_pJbig2 && m_pJbig2->GetImagesCount() > 4)
|
||
{
|
||
// Удалять не надо, т.к. объект удалится в CXref
|
||
m_pJbig2->FlushStreams();
|
||
m_pJbig2 = NULL;
|
||
}
|
||
|
||
if (!m_pJbig2)
|
||
m_pJbig2 = new CJbig2Global(m_pXref);
|
||
|
||
return m_pJbig2;
|
||
}
|
||
CShading* CDocument::CreateShading(CPage* pPage, double *pPattern, bool bAxial, unsigned char* pColors, unsigned char* pAlphas, double* pPoints, int nCount, CExtGrState*& pExtGrState)
|
||
{
|
||
pExtGrState = NULL;
|
||
|
||
bool bNeedAlpha = false;
|
||
unsigned char* pA = new unsigned char[3 * nCount];
|
||
if (!pA)
|
||
return NULL;
|
||
|
||
for (int nIndex = 0; nIndex < nCount; nIndex++)
|
||
{
|
||
pA[3 * nIndex + 0] = pAlphas[nIndex];
|
||
pA[3 * nIndex + 1] = pAlphas[nIndex];
|
||
pA[3 * nIndex + 2] = pAlphas[nIndex];
|
||
|
||
if (255 != pAlphas[nIndex])
|
||
bNeedAlpha = true;
|
||
}
|
||
|
||
if (!bNeedAlpha)
|
||
{
|
||
delete[] pA;
|
||
if (bAxial)
|
||
return CreateAxialShading(pPattern[0], pPattern[1], pPattern[2], pPattern[3], pColors, pPoints, nCount);
|
||
else
|
||
return CreateRadialShading(pPattern[0], pPattern[1], pPattern[2], pPattern[3], pPattern[4], pPattern[5], pColors, pPoints, nCount);
|
||
}
|
||
|
||
// Создаем 2 shading-объекта, один цветной RGB, второй серый со значениями альфа-канала
|
||
CShading* pColorShading = NULL;
|
||
CShading* pAlphaShading = NULL;
|
||
|
||
if (bAxial)
|
||
{
|
||
pColorShading = CreateAxialShading(pPattern[0], pPattern[1], pPattern[2], pPattern[3], pColors, pPoints, nCount);
|
||
pAlphaShading = CreateAxialShading(pPattern[0], pPattern[1], pPattern[2], pPattern[3], pA, pPoints, nCount);
|
||
}
|
||
else
|
||
{
|
||
pColorShading = CreateRadialShading(pPattern[0], pPattern[1], pPattern[2], pPattern[3], pPattern[4], pPattern[5], pColors, pPoints, nCount);
|
||
pAlphaShading = CreateRadialShading(pPattern[0], pPattern[1], pPattern[2], pPattern[3], pPattern[4], pPattern[5], pA, pPoints, nCount);
|
||
}
|
||
delete[] pA;
|
||
|
||
if (!m_pTransparencyGroup)
|
||
{
|
||
m_pTransparencyGroup = new CDictObject();
|
||
m_pTransparencyGroup->Add("Type", "Group");
|
||
m_pTransparencyGroup->Add("S", "Transparency");
|
||
m_pTransparencyGroup->Add("CS", "DeviceRGB");
|
||
}
|
||
|
||
pPage->Add("Group", m_pTransparencyGroup);
|
||
double dWidth = pPage->GetWidth();
|
||
double dHeight = pPage->GetHeight();
|
||
|
||
// Создаем графический объект, который будет альфа-маской
|
||
CDictObject* pXObject = new CDictObject(m_pXref);
|
||
pXObject->Add("Type", "XObject");
|
||
pXObject->Add("Subtype", "Form");
|
||
pXObject->Add("BBox", CArrayObject::CreateBox(0, 0, dWidth, dHeight));
|
||
pXObject->Add("Group", m_pTransparencyGroup);
|
||
CDictObject* pResources = new CDictObject();
|
||
pXObject->Add("Resources", pResources);
|
||
CDictObject* pResShadings = new CDictObject();
|
||
pResources->Add("Shading", pResShadings);
|
||
pResShadings->Add("S1", pAlphaShading);
|
||
CStream* pStream = pXObject->GetStream();
|
||
|
||
pStream->WriteStr("0 0 ");
|
||
pStream->WriteReal(dWidth);
|
||
pStream->WriteChar(' ');
|
||
pStream->WriteReal(dHeight);
|
||
pStream->WriteStr(" re\012W\012\n\012/S1 sh\012");
|
||
|
||
// Создаем обект-маску для графического состояние
|
||
CDictObject* pMask = new CDictObject();
|
||
m_pXref->Add(pMask);
|
||
pMask->Add("Type", "Mask");
|
||
pMask->Add("S", "Luminosity");
|
||
pMask->Add("G", pXObject);
|
||
|
||
// Создаем ExtGState объект, в который мы запишем альфа-маску
|
||
pExtGrState = new CExtGrState(m_pXref);
|
||
pExtGrState->Add("BM", "Normal");
|
||
pExtGrState->Add("ca", 1);
|
||
pExtGrState->Add("SMask", pMask);
|
||
|
||
return pColorShading;
|
||
}
|
||
CShading* CDocument::CreateAxialShading(double dX0, double dY0, double dX1, double dY1, unsigned char* pColors, double* pPoints, int nCount)
|
||
{
|
||
for (int nIndex = 0, nShadingsCount = m_vShadings.size(); nIndex < nShadingsCount; nIndex++)
|
||
{
|
||
CShading* pShading = m_vShadings.at(nIndex);
|
||
if (shadingtype_Axial == pShading->GetShadingType()
|
||
&& ((CAxialShading*)pShading)->Compare(dX0, dY0, dX1, dY1)
|
||
&& pShading->CompareColors(pColors, pPoints, nCount, true)
|
||
&& pShading->CompareExtend(true, true))
|
||
return pShading;
|
||
}
|
||
|
||
CAxialShading* pShading = new CAxialShading(m_pXref, dX0, dY0, dX1, dY1);
|
||
if (!pShading)
|
||
return NULL;
|
||
|
||
pShading->SetRgbColors(pColors, pPoints, nCount);
|
||
pShading->SetExtend(true, true);
|
||
|
||
m_vShadings.push_back(pShading);
|
||
|
||
return pShading;
|
||
}
|
||
CShading* CDocument::CreateRadialShading(double dX0, double dY0, double dR0, double dX1, double dY1, double dR1, unsigned char* pColors, double* pPoints, int nCount)
|
||
{
|
||
for (int nIndex = 0, nShadingsCount = m_vShadings.size(); nIndex < nShadingsCount; nIndex++)
|
||
{
|
||
CShading* pShading = m_vShadings.at(nIndex);
|
||
if (shadingtype_Radial == pShading->GetShadingType()
|
||
&& ((CRadialShading*)pShading)->Compare(dX0, dY0, dR0, dX1, dY1, dR1)
|
||
&& pShading->CompareColors(pColors, pPoints, nCount, true)
|
||
&& pShading->CompareExtend(true, true))
|
||
return pShading;
|
||
}
|
||
|
||
CRadialShading* pShading = new CRadialShading(m_pXref, dX0, dY0, dR0, dX1, dY1, dR1);
|
||
if (!pShading)
|
||
return NULL;
|
||
|
||
pShading->SetRgbColors(pColors, pPoints, nCount);
|
||
pShading->SetExtend(true, true);
|
||
|
||
m_vShadings.push_back(pShading);
|
||
|
||
return pShading;
|
||
}
|
||
CImageTilePattern*CDocument::CreateImageTilePattern(double dW, double dH, CImageDict* pImageDict, CMatrix* pMatrix, EImageTilePatternType eType)
|
||
{
|
||
return new CImageTilePattern(m_pXref, dW, dH, pImageDict, pMatrix, eType);
|
||
}
|
||
CImageTilePattern*CDocument::CreateHatchPattern(double dW, double dH, const BYTE& nR1, const BYTE& nG1, const BYTE& nB1, const BYTE& nAlpha1, const BYTE& nR2, const BYTE& nG2, const BYTE& nB2, const BYTE& nAlpha2, const std::wstring& wsHatch)
|
||
{
|
||
// TODO: Надо бы сделать мап, чтобы не создавать одинаковых паттернов
|
||
|
||
CImageDict* pImage = CreateImage();
|
||
BYTE* pBuffer = new BYTE[3 * HATCH_TX_SIZE * HATCH_TX_SIZE];
|
||
if (!pBuffer)
|
||
return NULL;
|
||
|
||
TColor oColor1(nR1, nG1, nB1);
|
||
TColor oColor2(nR2, nG2, nB2);
|
||
agg::GetHatchPattern<TColor>(wsHatch, (TColor*)pBuffer, oColor1, oColor2);
|
||
pImage->LoadRaw(pBuffer, 3 * HATCH_TX_SIZE * HATCH_TX_SIZE, HATCH_TX_SIZE, HATCH_TX_SIZE);
|
||
delete[] pBuffer;
|
||
|
||
if (255 != nAlpha1 || 255 != nAlpha2)
|
||
{
|
||
BYTE* pSMask = new BYTE[HATCH_TX_SIZE * HATCH_TX_SIZE];
|
||
if (pSMask)
|
||
{
|
||
agg::GetHatchPattern<BYTE>(wsHatch, pSMask, nAlpha1, nAlpha2);
|
||
pImage->LoadSMask(pSMask, (unsigned int)HATCH_TX_SIZE * HATCH_TX_SIZE, (unsigned int)HATCH_TX_SIZE, (unsigned int)HATCH_TX_SIZE);
|
||
delete[] pSMask;
|
||
}
|
||
}
|
||
|
||
return CreateImageTilePattern(dW, dH, pImage, NULL, imagetilepatterntype_Default);
|
||
}
|
||
CShading* CDocument::CreateAxialShading(CPage* pPage, double dX0, double dY0, double dX1, double dY1, unsigned char* pColors, unsigned char* pAlphas, double* pPoints, int nCount, CExtGrState*& pExtGrState)
|
||
{
|
||
double pPattern[] ={ dX0, dY0, dX1, dY1 };
|
||
return CreateShading(pPage, pPattern, true, pColors, pAlphas, pPoints, nCount, pExtGrState);
|
||
}
|
||
CShading* CDocument::CreateRadialShading(CPage* pPage, double dX0, double dY0, double dR0, double dX1, double dY1, double dR1, unsigned char* pColors, unsigned char* pAlphas, double* pPoints, int nCount, CExtGrState*& pExtGrState)
|
||
{
|
||
double pPattern[] ={ dX0, dY0, dR0, dX1, dY1, dR1 };
|
||
return CreateShading(pPage, pPattern, false, pColors, pAlphas, pPoints, nCount, pExtGrState);
|
||
}
|
||
}
|