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

2061 lines
55 KiB
C++

/*
* (c) Copyright Ascensio System SIA 2010-2023
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#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 "FontTT.h"
#include "FontTTWriter.h"
#include "Shading.h"
#include "Pattern.h"
#include "AcroForm.h"
#include "Field.h"
#include "ResourcesDictionary.h"
#include "Metadata.h"
#include "../../DesktopEditor/agg-2.4/include/agg_span_hatch.h"
#include "../../DesktopEditor/common/SystemUtils.h"
#ifdef CreateFont
#undef CreateFont
#endif
#ifndef VALUE2STR
#define VALUE_TO_STRING(x) #x
#define VALUE2STR(x) VALUE_TO_STRING(x)
#endif
namespace PdfWriter
{
const char* c_sPdfHeader = "%PDF-1.7\015%\315\312\322\251\015";
const char* c_sPdfAHeader = "%PDF-1.4\015%\315\312\322\251\015";
//----------------------------------------------------------------------------------------
// CDocument
//----------------------------------------------------------------------------------------
CDocument::CDocument()
{
m_pCatalog = NULL;
m_pOutlines = NULL;
m_pXref = NULL;
m_pLastXref = NULL;
m_pPageTree = NULL;
m_pCurPage = NULL;
m_nCurPageNum = -1;
m_pCurImage = NULL;
m_pInfo = NULL;
m_pTrailer = NULL;
m_pResources = NULL;
m_pMetaData = NULL;
m_bEncrypt = false;
m_pEncryptDict = NULL;
m_unFormFields = 0;
m_unCompressMode = COMP_NONE;
memset((void*)m_sTTFontTag, 0x00, 8);
m_pJbig2 = NULL;
m_pDefaultCheckBoxFont = NULL;
m_pTransparencyGroup = NULL;
m_pFreeTypeLibrary = NULL;
m_bPDFAConformance = false;
m_pAcroForm = NULL;
m_pFieldsResources = NULL;
}
CDocument::~CDocument()
{
Close();
}
bool CDocument::CreateNew()
{
Close();
m_pXref = new CXref(this, 0);
if (!m_pXref)
return false;
m_pTrailer = m_pXref->GetTrailer();
if (!m_pTrailer)
return false;
m_pMetaData = new CStreamData(m_pXref);
if (!m_pMetaData)
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->SetTime(InfoCreationDate);
m_pInfo->SetTime(InfoModaDate);
std::wstring sCreator = NSSystemUtils::GetEnvVariable(NSSystemUtils::gc_EnvApplicationName);
if (sCreator.empty())
sCreator = NSSystemUtils::gc_EnvApplicationNameDefault;
std::string sCreatorA = NSFile::CUtf8Converter::GetUtf8StringFromUnicode(sCreator);
#if defined(INTVER)
std::string sVersion = VALUE2STR(INTVER);
sCreatorA += ("/" + sVersion);
#endif
m_pInfo->SetInfo(InfoProducer, sCreatorA.c_str());
m_pInfo->SetInfo(InfoCreator, sCreatorA.c_str());
if (IsPDFA())
{
CArrayObject* pID = (CArrayObject*)m_pTrailer->Get("ID");
if (!pID)
{
BYTE arrId[16];
CEncryptDict::CreateId(m_pInfo, m_pXref, (BYTE*)arrId);
pID = new CArrayObject();
m_pTrailer->Add("ID", pID);
pID->Add(new CBinaryObject(arrId, 16));
pID->Add(new CBinaryObject(arrId, 16));
}
}
m_nCurPageNum = -1;
m_vExtGrStates.clear();
m_vFillAlpha.clear();
m_vStrokeAlpha.clear();
m_vRadioGroups.clear();
m_vMetaOForms.clear();
m_vImages.clear();
m_pTransparencyGroup = NULL;
return true;
}
void CDocument::Close()
{
// Все объекты удаляются внутри CXref
RELEASEOBJECT(m_pXref);
m_pLastXref = NULL;
m_pTrailer = NULL;
m_pResources = NULL;
m_pCatalog = NULL;
m_pOutlines = NULL;
m_pPageTree = NULL;
m_pCurPage = NULL;
m_nCurPageNum = 0;
m_pCurImage = NULL;
m_unFormFields = 0;
m_bEncrypt = false;
m_pEncryptDict = NULL;
m_pInfo = NULL;
m_unCompressMode = COMP_NONE;
m_pJbig2 = NULL;
m_pTransparencyGroup= NULL;
m_pAcroForm = NULL;
m_pFieldsResources = NULL;
memset((void*)m_sTTFontTag, 0x00, 8);
m_pDefaultCheckBoxFont = NULL;
m_vExtGrStates.clear();
m_vStrokeAlpha.clear();
m_vFillAlpha.clear();
m_vShadings.clear();
m_vCidTTFonts.clear();
m_vTTFonts.clear();
m_vFreeTypeFonts.clear();
m_vSignatures.clear();
m_vMetaOForms.clear();
m_vImages.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;
Sign(wsPath, m_pXref->GetSizeXRef());
return true;
}
bool CDocument::SaveToMemory(BYTE** pData, int* pLength)
{
CMemoryStream* pStream = new CMemoryStream();
if (!pStream)
return false;
if (m_pJbig2)
m_pJbig2->FlushStreams();
SaveToStream(pStream);
*pData = pStream->GetBuffer();
*pLength = pStream->Size();
pStream->ClearWithoutAttack();
return true;
}
void CDocument::SaveToStream(CStream* pStream)
{
m_pCatalog->AddMetadata(m_pXref, m_pInfo);
// Пишем заголовок
if (IsPDFA())
pStream->WriteStr(c_sPdfAHeader);
else
pStream->WriteStr(c_sPdfHeader);
if (false == m_wsDocumentID.empty())
{
std::string sDocumentID = "%DocumentID " + NSFile::CUtf8Converter::GetUtf8StringFromUnicode(m_wsDocumentID);
pStream->WriteStr(sDocumentID.c_str());
}
// Добавляем в 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, true);
}
bool CDocument::SaveNewWithPassword(CXref* pXref, CXref* _pXref, const std::wstring& wsPath, const std::wstring& wsOwnerPassword, const std::wstring& wsUserPassword, CDictObject* pTrailer)
{
if (!pXref || !pTrailer || !_pXref)
return false;
m_pTrailer = pTrailer;
CEncrypt* pEncrypt = NULL;
if (!wsOwnerPassword.empty())
{
m_pEncryptDict = new CEncryptDict(_pXref);
m_pEncryptDict->SetPasswords(wsOwnerPassword, wsUserPassword);
m_pTrailer->Add("Encrypt", m_pEncryptDict);
pEncrypt = m_pEncryptDict->GetEncrypt();
PrepareEncryption();
}
CFileStream* pStream = new CFileStream();
if (!pStream || !pStream->OpenFile(wsPath, true))
return false;
pStream->WriteStr(c_sPdfHeader);
pXref->WriteToStream(pStream, pEncrypt);
delete pStream;
return true;
}
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, 16));
pID->Add(new CBinaryObject(pEncrypt->m_anEncryptID, 16));
if (m_pMetaData)
m_pMetaData->SetID(new CBinaryObject(pEncrypt->m_anEncryptID, 16));
for (int i = 0; i < m_vMetaOForms.size(); ++i)
m_vMetaOForms[i]->Add("ID", new CBinaryObject(pEncrypt->m_anEncryptID, 16));
}
void CDocument::SetPasswords(const std::wstring & wsOwnerPassword, const std::wstring & wsUserPassword)
{
if (IsPDFA())
return;
if (!m_pEncryptDict)
m_pEncryptDict = new CEncryptDict(m_pXref);
if (!m_pEncryptDict)
return;
m_pEncryptDict->SetPasswords(wsOwnerPassword, wsUserPassword);
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;
#ifndef FILTER_FLATE_DECODE_DISABLED
if (m_unCompressMode & COMP_TEXT)
pPage->SetFilter(STREAM_FILTER_FLATE_DECODE);
#endif
m_nCurPageNum++;
return pPage;
}
CPage* CDocument::GetPage(const unsigned int &unPage)
{
if (unPage >= m_pPageTree->GetCount())
return NULL;
return m_pPageTree->GetPage(unPage);
}
CPage* CDocument::GetEditPage(const unsigned int& unPage)
{
CPage* pRes = NULL;
std::map<int, CPage*>::iterator p = m_mEditPages.find(unPage);
if (p != m_mEditPages.end())
pRes = p->second;
return pRes;
}
int CDocument::FindPage(CPage* pPage)
{
int nI = 0;
return m_pPageTree->Find(pPage, nI) ? nI : -1;
}
unsigned int CDocument::GetPagesCount() const
{
return m_pPageTree->GetCount();
}
void CDocument::SetDocumentID(const std::wstring& documentID)
{
m_wsDocumentID = documentID;
}
void CDocument::SetTitle(const std::string& sTitle)
{
if (!m_pInfo)
return;
m_pInfo->SetInfo(InfoTitle, sTitle.c_str());
}
void CDocument::SetAuthor(const std::string& sAuthor)
{
if (!m_pInfo)
return;
m_pInfo->SetInfo(InfoAuthor, sAuthor.c_str());
}
void CDocument::SetSubject(const std::string& sSubject)
{
if (!m_pInfo)
return;
m_pInfo->SetInfo(InfoSubject, sSubject.c_str());
}
void CDocument::SetKeywords(const std::string& sKeywords)
{
if (!m_pInfo)
return;
m_pInfo->SetInfo(InfoKeyWords, sKeywords.c_str());
}
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;
}
unsigned int CDocument::GetCompressionMode() const
{
return m_unCompressMode;
}
void CDocument::SetPDFAConformanceMode(bool isPDFA)
{
m_bPDFAConformance = isPDFA;
}
bool CDocument::IsPDFA() const
{
return m_bPDFAConformance;
}
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);
}
bool CDocument::AddMetaData(const std::wstring& sMetaName, BYTE* pMetaData, DWORD nMetaLength)
{
if (!m_pMetaData)
return false;
CBinaryObject* sID = NULL;
CArrayObject* pID = (CArrayObject*)m_pTrailer->Get("ID");
if (!pID)
{
BYTE arrId[16];
CEncryptDict::CreateId(m_pInfo, m_pXref, (BYTE*)arrId);
pID = new CArrayObject();
m_pTrailer->Add("ID", pID);
pID->Add(new CBinaryObject(arrId, 16));
pID->Add(new CBinaryObject(arrId, 16));
sID = new CBinaryObject(arrId, 16);
}
else
sID = (CBinaryObject*)pID->Get(1)->Copy();
m_pMetaData->SetID(sID);
return m_pMetaData->AddMetaData(sMetaName, pMetaData, nMetaLength);
}
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(CObjectBase* pPage, bool bInline)
{
if (pPage)
return new CDestination(pPage, m_pXref, bInline);
return NULL;
}
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;
}
void CDocument::AddExtGState(CExtGrState* pState)
{
m_vExtGrStates.push_back(pState);
}
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::CreateAnnot(BYTE m_nType)
{
CAnnotation* pAnnot = NULL;
if (m_nType == 0)
{
pAnnot = new CTextAnnotation(m_pXref);
pAnnot->SetC({ 1.0, 0.8, 0.0 });
}
else if (m_nType == 14)
pAnnot = new CInkAnnotation(m_pXref);
else if (m_nType == 3)
pAnnot = new CLineAnnotation(m_pXref);
else if (m_nType >= 8 && m_nType <= 11)
pAnnot = new CTextMarkupAnnotation(m_pXref);
else if (m_nType == 4 || m_nType == 5)
pAnnot = new CSquareCircleAnnotation(m_pXref);
else if (m_nType == 6 || m_nType == 7)
pAnnot = new CPolygonLineAnnotation(m_pXref);
else if (m_nType == 15)
pAnnot = new CPopupAnnotation(m_pXref);
else if (m_nType == 2)
pAnnot = new CFreeTextAnnotation(m_pXref);
else if (m_nType == 13)
pAnnot = new CCaretAnnotation(m_pXref);
else if (m_nType == 12)
pAnnot = new CStampAnnotation(m_pXref);
else if (m_nType == 25)
pAnnot = new CRedactAnnotation(m_pXref);
if (pAnnot)
m_pXref->Add(pAnnot);
if (m_nType >= 26)
{
if (!CheckAcroForm())
return NULL;
switch (m_nType)
{
case 26:
{
pAnnot = new CWidgetAnnotation(m_pXref, EAnnotType::AnnotWidget);
break;
}
case 27:
{
pAnnot = new CPushButtonWidget(m_pXref);
pAnnot->Add("FT", "Btn");
break;
}
case 28:
case 29:
{
pAnnot = new CCheckBoxWidget(m_pXref);
pAnnot->Add("FT", "Btn");
break;
}
case 30:
{
pAnnot = new CTextWidget(m_pXref);
pAnnot->Add("FT", "Tx");
break;
}
case 31:
case 32:
{
pAnnot = new CChoiceWidget(m_pXref);
pAnnot->Add("FT", "Ch");
break;
}
case 33:
{
pAnnot = new CSignatureWidget(m_pXref);
pAnnot->Add("FT", "Sig");
break;
}
default: break;
}
if (pAnnot)
{
m_pXref->Add(pAnnot);
CArrayObject* ppFields = (CArrayObject*)m_pAcroForm->Get("Fields");
ppFields->Add(pAnnot);
}
}
return pAnnot;
}
CAnnotation* CDocument::CreateLinkAnnot(const TRect& oRect, CDestination* pDest)
{
CAnnotation* pAnnot = new CLinkAnnotation(m_pXref, pDest);
pAnnot->SetRect(oRect);
m_pXref->Add(pAnnot);
return pAnnot;
}
CAnnotation* CDocument::CreateUriLinkAnnot(const TRect& oRect, const char* sUrl)
{
CAnnotation* pAnnot = new CUriLinkAnnotation(m_pXref, sUrl);
pAnnot->SetRect(oRect);
m_pXref->Add(pAnnot);
return pAnnot;
}
CAction* CDocument::CreateAction(BYTE nType)
{
switch (nType)
{
case 1: return new CActionGoTo(m_pXref);
case 6: return new CActionURI(m_pXref);
case 9: return new CActionHide(m_pXref);
case 10: return new CActionNamed(m_pXref);
case 12: return new CActionResetForm(m_pXref);
case 14: return new CActionJavaScript(m_pXref);
}
return NULL;
}
void CDocument::AddAnnotation(const int& nID, CAnnotation* pAnnot)
{
pAnnot->SetXref(m_pXref);
m_mAnnotations[nID] = pAnnot;
}
CImageDict* CDocument::CreateImage()
{
return new CImageDict(m_pXref, this);
}
CXObject* CDocument::CreateForm(CImageDict* pImage, const std::string& sName)
{
if (!pImage)
return NULL;
std::string sFrmName = "FRM" + sName;
std::string sImgName = "Img" + sName;
CXObject* pForm = new CXObject();
CStream* pStream = new CMemoryStream();
pForm->SetStream(m_pXref, pStream);
#ifndef FILTER_FLATE_DECODE_DISABLED
if (m_unCompressMode & COMP_TEXT)
pForm->SetFilter(STREAM_FILTER_FLATE_DECODE);
#endif
double dOriginW = pImage->GetWidth();
double dOriginH = pImage->GetHeight();
pForm->SetWidth(dOriginW);
pForm->SetHeight(dOriginH);
CArrayObject* pBBox = new CArrayObject();
pForm->Add("BBox", pBBox);
pBBox->Add(0);
pBBox->Add(0);
pBBox->Add(dOriginW);
pBBox->Add(dOriginH);
pForm->Add("FormType", 1);
CArrayObject* pFormMatrix = new CArrayObject();
pForm->Add("Matrix", pFormMatrix);
pFormMatrix->Add(1);
pFormMatrix->Add(0);
pFormMatrix->Add(0);
pFormMatrix->Add(1);
pFormMatrix->Add(0);
pFormMatrix->Add(0);
pForm->Add("Name", sFrmName.c_str());
pForm->SetName(sFrmName);
CDictObject* pFormRes = new CDictObject();
CArrayObject* pFormResProcset = new CArrayObject();
pFormRes->Add("ProcSet", pFormResProcset);
pFormResProcset->Add(new CNameObject("PDF"));
pFormResProcset->Add(new CNameObject("ImageC"));
CDictObject* pFormResXObject = new CDictObject();
pFormRes->Add("XObject", pFormResXObject);
pFormResXObject->Add(sImgName, pImage);
pForm->Add("Resources", pFormRes);
pForm->Add("Subtype", "Form");
pForm->Add("Type", "XObject");
pStream->WriteStr("q\012");
pStream->WriteReal(dOriginW);
pStream->WriteStr(" 0 0 ");
pStream->WriteReal(dOriginH);
pStream->WriteStr(" 0 0 cm\012/");
pStream->WriteStr(sImgName.c_str());
pStream->WriteStr(" Do\012Q");
return pForm;
}
CFont14* CDocument::CreateFont14(const std::wstring& wsFontPath, unsigned int unIndex, EStandard14Fonts eType)
{
CFont14* pFont = FindFont14(wsFontPath, unIndex);
if (pFont)
return pFont;
pFont = new CFont14(m_pXref, this, eType);
m_vFonts14.push_back(TFontInfo(wsFontPath, unIndex, pFont));
return pFont;
}
CFont14* CDocument::FindFont14(const std::wstring& wsFontPath, unsigned int unIndex)
{
for (int nIndex = 0, nCount = m_vFonts14.size(); nIndex < nCount; nIndex++)
{
TFontInfo& oInfo = m_vFonts14.at(nIndex);
if (wsFontPath == oInfo.wsPath && unIndex == oInfo.unIndex)
return (CFont14*)oInfo.pFont;
}
return NULL;
}
CFontCidTrueType* CDocument::CreateCidTrueTypeFont(const std::wstring& wsFontPath, unsigned int unIndex)
{
CFontCidTrueType* pFont = FindCidTrueTypeFont(wsFontPath, unIndex);
if (pFont)
return pFont;
CFontFileTrueType* pFontTT = CFontFileTrueType::LoadFromFile(wsFontPath, unIndex);
if (!pFontTT)
return NULL;
pFont = new CFontCidTrueType(m_pXref, this, wsFontPath, unIndex, pFontTT);
if (!pFont)
return NULL;
// 0 GID всегда используется для .notdef символа, не используем данный код для настоящих символов
unsigned int unUnicode = 0;
pFont->EncodeGID(0, &unUnicode, 1);
m_vCidTTFonts.push_back(TFontInfo(wsFontPath, unIndex, pFont));
return pFont;
}
CFontCidTrueType* CDocument::FindCidTrueTypeFont(const std::wstring &wsFontPath, unsigned int unIndex)
{
for (int nIndex = 0, nCount = m_vCidTTFonts.size(); nIndex < nCount; nIndex++)
{
TFontInfo& oInfo = m_vCidTTFonts.at(nIndex);
if (wsFontPath == oInfo.wsPath && unIndex == oInfo.unIndex)
return (CFontCidTrueType*)oInfo.pFont;
}
return NULL;
}
CFontTrueType* 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 (CFontTrueType*)oInfo.pFont;
}
CFontTrueType* pFont = new CFontTrueType(m_pXref, this, wsFontPath, unIndex);
if (!pFont)
return NULL;
m_vTTFonts.push_back(TFontInfo(wsFontPath, unIndex, pFont));
return pFont;
}
CFontTrueType* CDocument::CreateTrueTypeFont(CFontCidTrueType* pCidFont)
{
for (int nIndex = 0, nCount = m_vCidTTFonts.size(); nIndex < nCount; nIndex++)
{
TFontInfo& oInfo = m_vCidTTFonts.at(nIndex);
if (pCidFont == (CFontCidTrueType*)oInfo.pFont)
{
return CreateTrueTypeFont(oInfo.wsPath, oInfo.unIndex);
}
}
return NULL;
}
CFont14* CDocument::GetDefaultCheckboxFont()
{
if (!m_pDefaultCheckBoxFont)
m_pDefaultCheckBoxFont = new CFont14(m_pXref, this, EStandard14Fonts::standard14fonts_ZapfDingbats);
return m_pDefaultCheckBoxFont;
}
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 (!IsPDFA())
{
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));
if (m_pTransparencyGroup)
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);
if (!IsPDFA())
{
// Создаем 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, double dXStepSpacing, double dYStepSpacing)
{
return new CImageTilePattern(m_pXref, dW, dH, pImageDict, pMatrix, eType, dXStepSpacing, dYStepSpacing);
}
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);
}
CResourcesDict* CDocument::GetFieldsResources()
{
if (!m_pFieldsResources)
{
if (!CheckAcroForm())
return NULL;
m_pFieldsResources = new CResourcesDict(m_pXref, false, true);
m_pAcroForm->Add("DR", m_pFieldsResources);
}
return m_pFieldsResources;
}
CTextField* CDocument::CreateTextField()
{
if (!CheckAcroForm())
return NULL;
CTextField* pField = new CTextField(m_pXref, this);
if (!pField)
return NULL;
CArrayObject* ppFields = (CArrayObject*)m_pAcroForm->Get("Fields");
ppFields->Add(pField);
return pField;
}
CChoiceField* CDocument::CreateChoiceField()
{
if (!CheckAcroForm())
return NULL;
CChoiceField* pField = new CChoiceField(m_pXref, this);
if (!pField)
return NULL;
CArrayObject* ppFields = (CArrayObject*)m_pAcroForm->Get("Fields");
ppFields->Add(pField);
return pField;
}
CSignatureField* CDocument::CreateSignatureField()
{
if (!CheckAcroForm())
return NULL;
CSignatureField* pField = new CSignatureField(m_pXref, this);
if (!pField)
return NULL;
CArrayObject* ppFields = (CArrayObject*)m_pAcroForm->Get("Fields");
ppFields->Add(pField);
return pField;
}
CDateTimeField* CDocument::CreateDateTimeField()
{
if (!CheckAcroForm())
return NULL;
CDateTimeField* pField = new CDateTimeField(m_pXref, this);
if (!pField)
return NULL;
CArrayObject* ppFields = (CArrayObject*)m_pAcroForm->Get("Fields");
ppFields->Add(pField);
return pField;
}
CCheckBoxField* CDocument::CreateCheckBoxField()
{
if (!CheckAcroForm())
return NULL;
CCheckBoxField* pField = new CCheckBoxField(m_pXref, this);
if (!pField)
return NULL;
CArrayObject* ppFields = (CArrayObject*)m_pAcroForm->Get("Fields");
ppFields->Add(pField);
return pField;
}
CRadioGroupField* CDocument::GetRadioGroupField(const std::wstring& wsGroupName)
{
CRadioGroupField* pField = FindRadioGroupField(wsGroupName);
if (!pField)
{
if (!CheckAcroForm())
return NULL;
pField = new CRadioGroupField(m_pXref, this);
if (!pField)
return NULL;
m_vRadioGroups.push_back(pField);
pField->SetFieldName(wsGroupName);
CArrayObject* ppFields = (CArrayObject*)m_pAcroForm->Get("Fields");
ppFields->Add(pField);
}
return pField;
}
CRadioGroupField* CDocument::FindRadioGroupField(const std::wstring& wsGroupName)
{
CRadioGroupField* pField = NULL;
for (unsigned int unIndex = 0, unCount = m_vRadioGroups.size(); unIndex < unCount; ++unIndex)
{
pField = m_vRadioGroups.at(unIndex);
if (pField->GetFieldName() == wsGroupName)
return pField;
}
return NULL;
}
CPictureField* CDocument::CreatePictureField()
{
if (!CheckAcroForm())
return NULL;
CPictureField* pField = new CPictureField(m_pXref, this);
if (!pField)
return NULL;
CArrayObject* ppFields = (CArrayObject*)m_pAcroForm->Get("Fields");
ppFields->Add(pField);
return pField;
}
bool CDocument::HasImage(const std::wstring& wsImagePath, BYTE nAlpha)
{
for (size_t i = 0, nSize = m_vImages.size(); i < nSize; ++i)
{
if (m_vImages[i].wsImagePath == wsImagePath && m_vImages[i].nAlpha == nAlpha)
return true;
}
return false;
}
CImageDict* CDocument::GetImage(const std::wstring& wsImagePath, BYTE nAlpha)
{
for (size_t i = 0, nSize = m_vImages.size(); i < nSize; ++i)
{
if (m_vImages[i].wsImagePath == wsImagePath && m_vImages[i].nAlpha == nAlpha)
{
m_pCurImage = m_vImages[i].pImage;
return m_vImages[i].pImage;
}
}
return NULL;
}
void CDocument::AddImage(const std::wstring& wsImagePath, BYTE nAlpha, CImageDict* pImage)
{
if (!pImage)
return;
m_pCurImage = pImage;
m_vImages.push_back({wsImagePath, nAlpha, pImage});
}
void CDocument::AddObject(CObjectBase* pObj)
{
m_pXref->Add(pObj);
}
void CDocument::RemoveObj(CObjectBase* pObj)
{
std::map<int, CAnnotation*>::iterator it1 = std::find_if(m_mAnnotations.begin(), m_mAnnotations.end(), [pObj](const std::pair<int, CAnnotation*>& t){ return t.second == pObj; });
if (it1 != m_mAnnotations.end())
m_mAnnotations.erase(it1);
std::map<int, CPage*>::iterator it2 = std::find_if(m_mEditPages.begin(), m_mEditPages.end(), [pObj](const std::pair<int, CPage*>& t){ return t.second == pObj; });
if (it2 != m_mEditPages.end())
m_mEditPages.erase(it2);
if (m_pCurPage == pObj)
m_pCurPage = NULL;
m_pXref->Remove(pObj);
}
bool CDocument::CheckFieldName(CFieldBase* pField, const std::string& sName)
{
CFieldBase* pBase = m_mFields[sName];
if (pBase)
{
if (!pBase->GetKidsCount())
{
CFieldBase* pParent = new CFieldBase(m_pXref, this);
pParent->SetFieldName(sName, true);
pParent->Add("Ff", pBase->GetFieldFlag());
pParent->Add("FT", pBase->GetFieldType());
CObjectBase* pT = pBase->Get("T");
if (pT && pT->GetType() == object_type_STRING)
pParent->Add("T", pT->Copy());
CObjectBase* pV = pBase->Get("V");
if (pV && pV->GetType() == object_type_STRING)
pParent->Add("V", pV->Copy());
CObjectBase* pAA = pBase->Get("AA");
if (pAA)
pParent->Add("AA", pAA->Copy());
CTextField* pTextField = dynamic_cast<CTextField*>(pBase);
int nMaxLen = 0;
if (pTextField && 0 != (nMaxLen = pTextField->GetMaxLen()))
{
pBase->Remove("MaxLen");
pParent->Add("MaxLen", nMaxLen);
}
pBase->SetParent(pParent);
pBase->ClearKidRecords();
pParent->AddKid(pBase);
m_mFields[sName] = pParent;
pField->ClearKidRecords();
pField->SetParent(pParent);
pParent->AddKid(pField);
CChoiceField* pChoice = dynamic_cast<CChoiceField*>(pBase);
if (pChoice)
pChoice->UpdateSelectedIndexToParent();
pParent->UpdateKidsPlaceHolder();
}
else
{
pField->ClearKidRecords();
pField->SetParent(pBase);
pBase->AddKid(pField);
CChoiceField* pChoice = dynamic_cast<CChoiceField*>(pBase);
if (pChoice)
pChoice->UpdateSelectedIndexToParent();
pBase->UpdateKidsPlaceHolder();
}
return true;
}
else
{
m_mFields[sName] = pField;
return false;
}
}
bool CDocument::CheckAcroForm()
{
if (!m_pXref || !m_pCatalog)
return false;
if (!m_pAcroForm)
{
m_pAcroForm = new CDictObject();
if (!m_pAcroForm)
return false;
m_pCatalog->Add("AcroForm", m_pAcroForm);
m_pAcroForm->Add("Fields", new CArrayObject());
}
return (!!m_pAcroForm);
}
void CDocument::SetAcroForm(CDictObject* pObj)
{
if (!m_pXref || !m_pCatalog)
return;
m_pCatalog->Add("AcroForm", pObj);
m_pAcroForm = pObj;
}
CResourcesDict* CDocument::CreateResourcesDict(bool bInline, bool bProcSet)
{
return new CResourcesDict(m_pXref, bInline, bProcSet);
}
bool CDocument::CreatePageTree(CXref* pXref, CPageTree* pPageTree)
{
if (!pPageTree || !EditXref(pXref))
return false;
if (!m_pPageTree)
m_pPageTree = pPageTree;
else
m_pPageTree->Join(pPageTree);
return true;
}
bool CDocument::EditPdf(int nPosLastXRef, int nSizeXRef, CXref* pXref, CCatalog* pCatalog, CEncryptDict* pEncrypt, int nFormField)
{
if (!pXref || !pCatalog)
return false;
Close();
m_pXref = new CXref(this, nSizeXRef);
if (!m_pXref)
return false;
m_pXref->SetPrevAddr(nPosLastXRef);
m_pLastXref = m_pXref;
m_pTrailer = m_pXref->GetTrailer();
if (!m_pTrailer)
return false;
SetCompressionMode(COMP_ALL);
m_pCatalog = pCatalog;
pXref->SetPrev(m_pLastXref);
m_pLastXref = pXref;
CObjectBase* pAcroForm = m_pCatalog->Get("AcroForm");
if (pAcroForm && pAcroForm->GetType() == object_type_DICT)
m_pAcroForm = (CDictObject*)pAcroForm;
if (pEncrypt)
{
m_pEncryptDict = pEncrypt;
m_bEncrypt = true;
}
m_unFormFields = nFormField;
return true;
}
bool CDocument::EditResources(CXref* pXref, CResourcesDict* pResources)
{
if (!pResources || !EditXref(pXref))
return false;
CheckAcroForm();
m_pAcroForm->Add("DR", pResources);
m_pFieldsResources = pResources;
return true;
}
std::pair<int, int> CDocument::GetPageRef(int nPageIndex)
{
std::pair<int, int> pRes = std::make_pair(0, 0);
if (!m_pPageTree)
return pRes;
CObjectBase* pObj = m_pPageTree->GetObj(nPageIndex);
if (pObj)
{
pRes.first = pObj->GetObjId();
pRes.second = pObj->GetGenNo();
}
return pRes;
}
bool CDocument::EditPage(CXref* pXref, CPage* pPage, int nPageIndex)
{
if (!pPage || !EditXref(pXref))
return false;
pPage->AddContents(m_pXref);
#ifndef FILTER_FLATE_DECODE_DISABLED
if (m_unCompressMode & COMP_TEXT)
pPage->SetFilter(STREAM_FILTER_FLATE_DECODE);
#endif
m_pCurPage = pPage;
m_mEditPages[nPageIndex] = pPage;
if (m_pPageTree)
m_pPageTree->ReplacePage(nPageIndex, pPage);
return true;
}
void CDocument::FixEditPage(CPage* _pPage, int nPageIndex)
{
CPage* pPage = _pPage ? _pPage : m_mEditPages[nPageIndex];
if (!pPage)
return;
pPage->AddContents(m_pXref);
#ifndef FILTER_FLATE_DECODE_DISABLED
if (m_unCompressMode & COMP_TEXT)
pPage->SetFilter(STREAM_FILTER_FLATE_DECODE);
#endif
}
void CDocument::AddEditPage(CPage* pPage, int nPageIndex)
{
m_mEditPages[nPageIndex] = pPage;
}
bool CDocument::EditAnnot(CXref* pXref, CAnnotation* pAnnot, int nID)
{
if (!pAnnot || !EditXref(pXref))
return false;
pAnnot->SetXref(m_pXref);
m_mAnnotations[nID] = pAnnot;
return true;
}
void CDocument::AddParent(int nID, CDictObject* pParent)
{
m_mParents[nID] = pParent;
}
CDictObject* CDocument::CreateParent(int nID)
{
CDictObject* pParent = new CDictObject();
m_pXref->Add(pParent);
m_mParents[nID] = pParent;
return pParent;
}
bool CDocument::EditParent(CXref* pXref, CDictObject* pParent, int nID)
{
if (!pParent || !EditXref(pXref))
return false;
m_mParents[nID] = pParent;
return true;
}
bool CDocument::EditXref(CXref* pXref)
{
if (!pXref)
return true;
pXref->SetPrev(m_pLastXref);
m_pLastXref = pXref;
return true;
}
bool CDocument::DeleteAnnot(int nObjNum, int nObjGen)
{
if (m_pCurPage && m_pCurPage->DeleteAnnotation(nObjNum))
{
if (m_pAcroForm)
{
CArrayObject* ppFields = (CArrayObject*)m_pAcroForm->Get("Fields");
for (int i = 0; i < ppFields->GetCount(); ++i)
{
CObjectBase* pObj = ppFields->Get(i);
if (pObj->GetObjId() == nObjNum)
{
CObjectBase* pDelete = ppFields->Remove(i);
RELEASEOBJECT(pDelete);
break;
}
}
}
CXref* pXref = new CXref(this, nObjNum, nObjGen);
if (!pXref)
return false;
pXref->SetPrev(m_pLastXref);
m_pLastXref = pXref;
return true;
}
return false;
}
CAnnotation* CDocument::GetAnnot(int nID)
{
std::map<int, CAnnotation*>::iterator p = m_mAnnotations.find(nID);
if (p != m_mAnnotations.end())
return p->second;
return NULL;
}
CDictObject* CDocument::GetParent(int nID)
{
std::map<int, CDictObject*>::iterator p = m_mParents.find(nID);
if (p != m_mParents.end())
return p->second;
return NULL;
}
std::string CDocument::SetParentKids(int nParentID)
{
CDictObject* pParent = GetParent(nParentID);
if (!pParent)
return "";
for (auto it = m_mAnnotations.begin(); it != m_mAnnotations.end(); it++)
{
CAnnotation* pAnnot = it->second;
if (pAnnot->GetAnnotationType() != AnnotWidget)
continue;
CWidgetAnnotation* pWidget = (CWidgetAnnotation*)pAnnot;
int nWidgetParentID = pWidget->GetParentID();
if (nWidgetParentID != nParentID)
continue;
pWidget->SetParent(pParent);
CObjectBase* pFT = pParent->Get("FT");
CObjectBase* pWidgetFT = pWidget->Get("FT");
if (!pFT && pParent->Get("T") && pWidgetFT)
pParent->Add("FT", pWidgetFT->Copy());
CArrayObject* pKids = dynamic_cast<CArrayObject*>(pParent->Get("Kids"));
if (!pKids)
{
pKids = new CArrayObject();
pParent->Add("Kids", pKids);
}
bool bReplase = false;
int nID = pWidget->GetObjId();
if (nID > 0)
{
for (int i = 0; i < pKids->GetCount(); ++i)
{
CObjectBase* pKid = pKids->Get(i);
if (pKid->GetObjId() == nID)
{
pKids->Insert(pKid, pWidget, true);
bReplase = true;
break;
}
}
}
if (!bReplase)
pKids->Add(pWidget);
}
CObjectBase* pFT = pParent->Get("FT");
if (pFT && pFT->GetType() == object_type_NAME)
return ((CNameObject*)pFT)->Get();
return "";
}
bool CDocument::EditCO(const std::vector< std::pair<int, int> >& arrCO)
{
if (arrCO.empty())
return true;
if (!CheckAcroForm())
return false;
CArrayObject* pArray = new CArrayObject();
if (!pArray)
return false;
m_pAcroForm->Add("CO", pArray);
for (std::pair<int, int> CO : arrCO)
{
CDictObject* pObj = GetParent(CO.first);
if (pObj)
pArray->Add(pObj);
else
{
CAnnotation* pAnnot = GetAnnot(CO.first);
if (pAnnot)
pArray->Add(pAnnot);
else if (CO.second >= 0)
{
PdfWriter::CObjectBase* pBase = new PdfWriter::CObjectBase();
pBase->SetRef(CO.first, CO.second);
pArray->Add(new PdfWriter::CProxyObject(pBase, true));
}
}
}
return true;
}
CPage* CDocument::AddPage(int nPageIndex, CPage* _pNewPage)
{
if (!m_pPageTree)
return NULL;
CPage* pNewPage = _pNewPage ? _pNewPage : new CPage(m_pXref, NULL, this);
if (!pNewPage)
return NULL;
bool bRes = m_pPageTree->InsertPage(nPageIndex, pNewPage);
if (!bRes)
return NULL;
if (!_pNewPage)
pNewPage->SetFilter(STREAM_FILTER_FLATE_DECODE);
m_pCurPage = pNewPage;
return pNewPage;
}
bool CDocument::DeletePage(int nPageIndex)
{
if (!m_pPageTree)
return false;
CObjectBase* pObj = m_pPageTree->RemovePage(nPageIndex);
if (pObj)
{
if (pObj->IsIndirect())
return true;
if (!pObj->GetObjId())
{
delete pObj;
return true;
}
CXref* pXref = new CXref(this, pObj->GetObjId(), pObj->GetGenNo());
delete pObj;
if (!pXref)
return false;
pXref->SetPrev(m_pLastXref);
m_pLastXref = pXref;
return true;
}
return false;
}
bool CDocument::MovePage(int nPageIndex, int nPos)
{
if (m_pPageTree)
{
CObjectBase* pObj = m_pPageTree->RemovePage(nPageIndex);
if (pObj)
{
if (pObj->GetType() == object_type_UNKNOWN)
{
CObjectBase* pObjTemp = pObj->Copy();
delete pObj;
pObj = pObjTemp;
}
return m_pPageTree->InsertPage(nPos, pObj);
}
}
return false;
}
bool CDocument::AddToFile(const std::wstring& wsPath, CXref* pXref, CDictObject* pTrailer, CXref* pInfoXref, CInfoDict* pInfo)
{
if (!pTrailer || wsPath.empty())
return false;
CFileStream* pStream = new CFileStream();
if (!pStream)
return false;
if (!pStream->OpenFile(wsPath, false))
{
RELEASEOBJECT(pStream);
return false;
}
m_pTrailer = pTrailer;
m_pInfo = pInfo;
if (!m_pInfo)
m_pInfo = new PdfWriter::CInfoDict(m_pXref);
std::wstring sCreator = NSSystemUtils::GetEnvVariable(NSSystemUtils::gc_EnvApplicationName);
if (sCreator.empty())
sCreator = NSSystemUtils::gc_EnvApplicationNameDefault;
std::string sCreatorA = U_TO_UTF8(sCreator);
#if defined(INTVER)
sCreatorA += "/";
sCreatorA += VALUE2STR(INTVER);
#endif
const char* cCreator = m_pInfo->GetInfo(InfoProducer);
m_pInfo->SetInfo(InfoCreator, cCreator ? cCreator : sCreatorA.c_str());
m_pInfo->SetInfo(InfoProducer, sCreatorA.c_str());
if (pInfoXref)
{
pInfoXref->SetPrev(m_pLastXref);
m_pLastXref = pInfoXref;
}
pXref->SetPrev(m_pLastXref);
m_pLastXref = pXref;
// Вторая часть идентификатора должна обновляться
CObjectBase* pID = m_pTrailer->Get("ID");
if ((pID && pID->GetType() == object_type_ARRAY) || !m_vMetaOForms.empty())
{
BYTE arrId[16];
CEncryptDict::CreateId(m_pInfo, m_pXref, (BYTE*)arrId);
CArrayObject* pArrID = (CArrayObject*)pID;
if (pArrID)
{
CObjectBase* pObject = pArrID->Get(1, false);
pArrID->Insert(pObject, new CBinaryObject(arrId, 16), true);
}
else
{
pArrID = new CArrayObject();
m_pTrailer->Add("ID", pArrID);
pArrID->Add(new CBinaryObject(arrId, 16));
pArrID->Add(new CBinaryObject(arrId, 16));
}
for (int i = 0; i < m_vMetaOForms.size(); ++i)
m_vMetaOForms[i]->Add("ID", new CBinaryObject(arrId, 16));
}
CEncrypt* pEncrypt = NULL;
if (m_bEncrypt)
pEncrypt = m_pEncryptDict->GetEncrypt();
// Если m_pTrailer поток перекрестных ссылок, то при дозаписи тоже должен быть поток
m_pTrailer->Remove("XRefStm");
bool bNeedStreamXRef = false;
pStream->WriteChar('\n');
if (m_pTrailer->Get("Type"))
{
m_pTrailer->Remove("Length");
m_pTrailer->Remove("Filter");
m_pTrailer->Remove("DecodeParms");
m_pTrailer->Remove("F");
m_pTrailer->Remove("FFilter");
m_pTrailer->Remove("FDecodeParms");
m_pTrailer->Remove("DL");
m_pTrailer->Remove("Type");
m_pTrailer->Remove("Index");
m_pTrailer->Remove("W");
bNeedStreamXRef = true;
m_pLastXref->WriteToStream(pStream, pEncrypt, bNeedStreamXRef);
}
else
m_pLastXref->WriteToStream(pStream, pEncrypt);
RELEASEOBJECT(pStream);
unsigned int nSizeXRef = m_pXref->GetSizeXRef();
m_pXref = m_pLastXref;
Sign(wsPath, nSizeXRef, bNeedStreamXRef);
RELEASEOBJECT(m_pEncryptDict);
return true;
}
void CDocument::Sign(const TRect& oRect, CImageDict* pImage, ICertificate* pCertificate)
{
m_vSignatures.push_back({ oRect, m_pCurPage ? m_pCurPage : m_pPageTree->GetPage(0), pImage, pCertificate });
}
void CDocument::Sign(const std::wstring& wsPath, unsigned int nSizeXRef, bool bNeedStreamXRef)
{
unsigned int nPrevAddr = m_pXref->GetPrevAddr();
std::vector<CXref*> vXRefForWrite;
for (unsigned int i = 0; i < m_vSignatures.size(); i++)
{
CXref* pXrefBefore = m_pXref;
m_pXref = new CXref(this, nSizeXRef);
if (!m_pXref)
{
m_pXref = pXrefBefore;
continue;
}
m_pXref->SetPrevAddr(nPrevAddr);
CSignatureField* pField = CreateSignatureField();
if (!pField)
{
RELEASEOBJECT(m_pXref);
m_pXref = pXrefBefore;
continue;
}
m_pAcroForm->Add("SigFlags", 3);
pField->GetSignatureDict()->SetCert(m_vSignatures[i].pCertificate);
pField->GetSignatureDict()->SetDate();
pField->AddPageRect(m_vSignatures[i].pPage, m_vSignatures[i].oRect);
pField->Add("F", 132);
pField->SetFieldName("Sig" + std::to_string(i + m_unFormFields + 1));
if (m_vSignatures[i].pImage)
pField->SetAppearance(m_vSignatures[i].pImage);
CFileStream* pStream = new CFileStream();
if (!pStream || !pStream->OpenFile(wsPath, false))
{
RELEASEOBJECT(m_pXref);
m_pXref = pXrefBefore;
continue;
}
CXref* pXrefCatalog = new CXref(this, m_pCatalog->GetObjId());
if (pXrefCatalog)
{
pXrefCatalog->Add(m_pCatalog->Copy(), m_pCatalog->GetGenNo());
pXrefCatalog->SetPrev(m_pXref);
}
CXref* pXrefPage = new CXref(this, m_vSignatures[i].pPage->GetObjId());
if (pXrefPage)
{
pXrefPage->Add(m_vSignatures[i].pPage->Copy(), m_vSignatures[i].pPage->GetGenNo());
pXrefPage->SetPrev(pXrefCatalog);
}
CXref* pXref = new CXref(this, 0, 65535);
if (pXref)
{
pXref->SetPrev(pXrefPage);
CDictObject* pTrailer = pXref->GetTrailer();
m_pTrailer->Copy(pTrailer);
CEncrypt* pEncrypt = NULL;
if (m_bEncrypt && m_pEncryptDict)
pEncrypt = m_pEncryptDict->GetEncrypt();
pXref->WriteToStream(pStream, pEncrypt, bNeedStreamXRef);
nPrevAddr = pXref->GetPrevAddr();
nSizeXRef = m_pXref->GetSizeXRef();
vXRefForWrite.push_back(pXref);
}
RELEASEOBJECT(pStream);
pStream = new CFileStream();
if (pStream && pStream->OpenFile(wsPath, false))
pField->GetSignatureDict()->WriteToStream(pStream, pStream->Size());
m_pXref = pXrefBefore;
RELEASEOBJECT(pStream);
}
for (CXref* XRef : vXRefForWrite)
RELEASEOBJECT(XRef);
vXRefForWrite.clear();
}
void CDocument::AddShapeXML(const std::string& sXML)
{
CDictObject* pResources = (CDictObject*)m_pCurPage->GetResourcesItem();
if (!pResources)
{
pResources = new CResourcesDict(NULL, true, false);
m_pCurPage->Add("Resources", pResources);
}
CDictObject* pProperties = (CDictObject*)pResources->Get("Properties");
if (!pProperties)
{
pProperties = new CDictObject();
pResources->Add("Properties", pProperties);
}
CObjectBase* pObj = pProperties->Get("OShapes");
if (pObj && pObj->GetType() != object_type_DICT)
{
pProperties->Remove("OShapes");
pObj = NULL;
}
CBinaryObject* sID = NULL;
CArrayObject* pID = (CArrayObject*)m_pTrailer->Get("ID");
if (!pID)
{
BYTE arrId[16];
CEncryptDict::CreateId(m_pInfo, m_pXref, (BYTE*)arrId);
pID = new CArrayObject();
m_pTrailer->Add("ID", pID);
pID->Add(new CBinaryObject(arrId, 16));
pID->Add(new CBinaryObject(arrId, 16));
sID = new CBinaryObject(arrId, 16);
}
else
sID = (CBinaryObject*)pID->Get(1)->Copy();
CDictObject* pMetaOForm = (CDictObject*)pObj;
if (!pMetaOForm)
{
pMetaOForm = new CDictObject();
m_pXref->Add(pMetaOForm);
pMetaOForm->Add("Type", "OShapes");
pProperties->Add("OShapes", pMetaOForm);
m_vMetaOForms.push_back(pMetaOForm);
pMetaOForm->Add("IDF", sID->Copy());
pMetaOForm->Add("ID", sID->Copy());
}
CArrayObject* pArrayMeta = (CArrayObject*)pMetaOForm->Get("Metadata");
if (!pArrayMeta)
{
pArrayMeta = new CArrayObject();
pMetaOForm->Add("Metadata", pArrayMeta);
CArrayObject* pArrayImage = new CArrayObject();
pMetaOForm->Add("Image", pArrayImage);
}
CStringObject* pXML = new CStringObject();
pXML->Set(sXML.c_str(), false, false, -1);
pArrayMeta->Add(pXML);
CDictObject* pBDC = new CDictObject();
pBDC->Add("MCID", pArrayMeta->GetCount() - 1);
pBDC->Add("IDF", sID);
m_pCurPage->BeginMarkedContentDict("OShapes", pBDC);
RELEASEOBJECT(pBDC);
}
void CDocument::EndShapeXML()
{
CDictObject* pResources = (CDictObject*)m_pCurPage->GetResourcesItem();
if (!pResources)
return;
CDictObject* pProperties = (CDictObject*)pResources->Get("Properties");
if (!pProperties)
return;
CObjectBase* pObj = pProperties->Get("OShapes");
if (!pObj || pObj->GetType() != object_type_DICT)
return;
CDictObject* pMetaOForm = (CDictObject*)pObj;
CArrayObject* pArrayImage = (CArrayObject*)pMetaOForm->Get("Image");
if (!pArrayImage)
return;
pObj = m_pCurImage;
if (!pObj)
pObj = new PdfWriter::CNullObject();
pArrayImage->Add(pObj);
m_pCurPage->EndMarkedContent();
}
void CDocument::ClearPage()
{
m_pCurPage->ClearContent(m_pXref);
m_pCurPage->StartTransform(1, 0, 0, 1, 0, 0);
}
void CDocument::ClearPageFull()
{
m_pCurPage->ClearContentFull(m_pXref);
}
}