Files
DocumentServer-v-9.2.0/core/PdfFile/PdfEditor.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

3742 lines
104 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 "PdfEditor.h"
#include "../DesktopEditor/common/Path.h"
#include "../DesktopEditor/graphics/commands/AnnotField.h"
#include "SrcReader/Adaptors.h"
#include "SrcReader/PdfAnnot.h"
#include "lib/xpdf/PDFDoc.h"
#include "lib/xpdf/AcroForm.h"
#include "lib/xpdf/TextString.h"
#include "lib/xpdf/Lexer.h"
#include "lib/xpdf/Parser.h"
#include "lib/xpdf/Outline.h"
#include "lib/xpdf/Link.h"
#include "lib/xpdf/Stream.h"
#include "SrcWriter/Catalog.h"
#include "SrcWriter/EncryptDictionary.h"
#include "SrcWriter/Info.h"
#include "SrcWriter/ResourcesDictionary.h"
#include "SrcWriter/Streams.h"
#include "SrcWriter/Destination.h"
#include "SrcWriter/Outline.h"
#include "SrcWriter/GState.h"
#include "SrcWriter/RedactOutputDev.h"
#define AddToObject(oVal)\
{\
if (pObj->GetType() == PdfWriter::object_type_DICT)\
((PdfWriter::CDictObject*)pObj)->Add(sKey, oVal);\
else if (pObj->GetType() == PdfWriter::object_type_ARRAY)\
((PdfWriter::CArrayObject*)pObj)->Add(oVal);\
}
void DictToCDictObject(Object* obj, PdfWriter::CObjectBase* pObj, const std::string& sKey, bool bMakeBinary = false)
{
Object oTemp;
switch (obj->getType())
{
case objBool:
{
bool b = obj->getBool() == gTrue;
AddToObject(b)
break;
}
case objInt:
{
AddToObject(obj->getInt())
break;
}
case objReal:
{
AddToObject(obj->getReal())
break;
}
case objString:
{
GString* str = obj->getString();
if (str->isBinary() || bMakeBinary)
{
int nLength = str->getLength();
BYTE* arrId = new BYTE[nLength];
for (int nIndex = 0; nIndex < nLength; ++nIndex)
arrId[nIndex] = str->getChar(nIndex);
AddToObject(new PdfWriter::CBinaryObject(arrId, nLength, false));
}
else
{
TextString* s = new TextString(str);
std::string sValue = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
AddToObject(new PdfWriter::CStringObject(sValue.c_str(), !s->isPDFDocEncoding()))
delete s;
}
break;
}
case objName:
{
AddToObject(obj->getName())
break;
}
case objNull:
{
AddToObject(new PdfWriter::CNullObject())
break;
}
case objArray:
{
PdfWriter::CArrayObject* pArray = new PdfWriter::CArrayObject();
AddToObject(pArray)
for (int nIndex = 0; nIndex < obj->arrayGetLength(); ++nIndex)
{
obj->arrayGetNF(nIndex, &oTemp);
DictToCDictObject(&oTemp, pArray, "");
oTemp.free();
}
break;
}
case objDict:
{
PdfWriter::CDictObject* pDict = new PdfWriter::CDictObject();
AddToObject(pDict);
for (int nIndex = 0; nIndex < obj->dictGetLength(); ++nIndex)
{
char* chKey = obj->dictGetKey(nIndex);
obj->dictGetValNF(nIndex, &oTemp);
DictToCDictObject(&oTemp, pDict, chKey);
oTemp.free();
}
break;
}
case objRef:
{
PdfWriter::CObjectBase* pBase = new PdfWriter::CObjectBase();
pBase->SetRef(obj->getRefNum(), obj->getRefGen());
AddToObject(new PdfWriter::CProxyObject(pBase, true))
break;
}
case objNone:
{
AddToObject("None")
break;
}
case objStream:
case objCmd:
case objError:
case objEOF:
break;
}
}
bool SplitSkipDict(Object* obj, CObjectsManager* pManager, int nStartRefID)
{
Object oTemp, oTemp2;
if (obj->dictLookup("Type", &oTemp)->isName("Page"))
{
oTemp.free();
return true;
}
else if (oTemp.isName("Annot") && obj->dictLookupNF("P", &oTemp2)->isRef())
{
PdfWriter::CObjectBase* pObj = pManager->GetObj(oTemp2.getRefNum() + nStartRefID);
if (!pObj)
{
oTemp.free(); oTemp2.free();
return true;
}
}
oTemp.free(); oTemp2.free();
if (obj->dictLookup("S", &oTemp)->isName("GoTo"))
{
oTemp.free();
if (obj->dictLookup("D", &oTemp)->isArray() && oTemp.arrayGetLength() > 1 && oTemp.arrayGetNF(0, &oTemp2)->isRef())
{
PdfWriter::CObjectBase* pObj = pManager->GetObj(oTemp2.getRefNum() + nStartRefID);
if (!pObj)
{
oTemp.free(); oTemp2.free();
return true;
}
}
oTemp2.free();
}
oTemp.free();
return false;
}
PdfWriter::CAnnotation* CreateAnnot(Object* oAnnot, Object* oType, PdfWriter::CXref* pXref)
{
PdfWriter::CAnnotation* pAnnot = NULL;
if (oType->isName("Text"))
pAnnot = new PdfWriter::CTextAnnotation(pXref);
else if (oType->isName("Ink"))
pAnnot = new PdfWriter::CInkAnnotation(pXref);
else if (oType->isName("Line"))
pAnnot = new PdfWriter::CLineAnnotation(pXref);
else if (oType->isName("Highlight") || oType->isName("Underline") || oType->isName("Squiggly") || oType->isName("StrikeOut"))
pAnnot = new PdfWriter::CTextMarkupAnnotation(pXref);
else if (oType->isName("Square") || oType->isName("Circle"))
pAnnot = new PdfWriter::CSquareCircleAnnotation(pXref);
else if (oType->isName("Polygon") || oType->isName("PolyLine"))
pAnnot = new PdfWriter::CPolygonLineAnnotation(pXref);
else if (oType->isName("FreeText"))
pAnnot = new PdfWriter::CFreeTextAnnotation(pXref);
else if (oType->isName("Caret"))
pAnnot = new PdfWriter::CCaretAnnotation(pXref);
else if (oType->isName("Stamp"))
pAnnot = new PdfWriter::CStampAnnotation(pXref);
else if (oType->isName("Redact"))
pAnnot = new PdfWriter::CRedactAnnotation(pXref);
else if (oType->isName("Popup"))
pAnnot = new PdfWriter::CPopupAnnotation(pXref);
else if (oType->isName("Widget"))
{
char* sName = NULL;
Object oFT;
if (oAnnot->dictLookup("FT", &oFT)->isName())
sName = oFT.getName();
if (!sName)
{
Object oParent, oParent2;
oAnnot->dictLookup("Parent", &oParent);
while (oParent.isDict())
{
if (oParent.dictLookup("FT", &oFT)->isName())
{
sName = oFT.getName();
break;
}
oFT.free();
oParent.dictLookup("Parent", &oParent2);
oParent.free();
oParent = oParent2;
}
oParent.free();
}
if (!sName)
{
oFT.free();
return new PdfWriter::CWidgetAnnotation(pXref, PdfWriter::EAnnotType::AnnotWidget);
}
if (strcmp("Btn", sName) == 0)
{
bool bPushButton = false;
oFT.free();
int nFf = 0;
if (oAnnot->dictLookup("Ff", &oFT)->isInt())
nFf = oFT.getInt();
if (!nFf)
{
Object oParent, oParent2;
oAnnot->dictLookup("Parent", &oParent);
while (oParent.isDict())
{
if (oParent.dictLookup("Ff", &oFT)->isInt())
{
nFf = oFT.getInt();
break;
}
oFT.free();
oParent.dictLookup("Parent", &oParent2);
oParent.free();
oParent = oParent2;
}
oParent.free();
}
bPushButton = (bool)((nFf >> 16) & 1);
if (bPushButton)
pAnnot = new PdfWriter::CPushButtonWidget(pXref);
else
pAnnot = new PdfWriter::CCheckBoxWidget(pXref);
}
else if (strcmp("Tx", sName) == 0)
pAnnot = new PdfWriter::CTextWidget(pXref);
else if (strcmp("Ch", sName) == 0)
pAnnot = new PdfWriter::CChoiceWidget(pXref);
else if (strcmp("Sig", sName) == 0)
pAnnot = new PdfWriter::CSignatureWidget(pXref);
else
pAnnot = new PdfWriter::CWidgetAnnotation(pXref, PdfWriter::EAnnotType::AnnotWidget);
oFT.free();
}
return pAnnot;
}
PdfWriter::CExtGrState* CreateExtGState(Object* oState)
{
PdfWriter::CExtGrState* pState = new PdfWriter::CExtGrState(NULL);
return pState;
}
PdfWriter::CObjectBase* DictToCDictObject2(Object* obj, PdfWriter::CDocument* pDoc, XRef* xref, CObjectsManager* pManager, int nStartRefID, int nAddObjToXRef = 0, bool bUndecodedStream = true)
{
PdfWriter::CObjectBase* pBase = NULL;
Object oTemp;
switch (obj->getType())
{
case objBool:
{
pBase = new PdfWriter::CBoolObject(obj->getBool() == gTrue);
break;
}
case objInt:
{
pBase = new PdfWriter::CNumberObject(obj->getInt());
break;
}
case objReal:
{
pBase = new PdfWriter::CRealObject(obj->getReal());
break;
}
case objString:
{
GString* str = obj->getString();
if (str->isBinary())
{
int nLength = str->getLength();
BYTE* arrId = new BYTE[nLength];
for (int nIndex = 0; nIndex < nLength; ++nIndex)
arrId[nIndex] = str->getChar(nIndex);
pBase = new PdfWriter::CBinaryObject(arrId, nLength, false);
}
else
{
TextString* s = new TextString(str);
std::string sValue = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
pBase = new PdfWriter::CStringObject(sValue.c_str(), !s->isPDFDocEncoding());
delete s;
}
break;
}
case objName:
{
pBase = new PdfWriter::CNameObject(obj->getName());
break;
}
case objNull:
{
pBase = new PdfWriter::CNullObject();
break;
}
case objArray:
{
PdfWriter::CArrayObject* pArray = new PdfWriter::CArrayObject();
if (nAddObjToXRef > 0)
{
pDoc->AddObject(pArray);
pManager->AddObj(nAddObjToXRef + nStartRefID, pArray);
nAddObjToXRef = 0;
}
for (int nIndex = 0; nIndex < obj->arrayGetLength(); ++nIndex)
{
obj->arrayGetNF(nIndex, &oTemp);
pBase = DictToCDictObject2(&oTemp, pDoc, xref, pManager, nStartRefID, 0, bUndecodedStream);
pArray->Add(pBase);
oTemp.free();
}
pBase = pArray;
break;
}
case objDict:
{
if (SplitSkipDict(obj, pManager, nStartRefID))
return NULL;
Object oType, oSubtype;
PdfWriter::CDictObject* pDict = NULL;
if (obj->dictLookup("Subtype", &oSubtype)->isName())
{
PdfWriter::CAnnotation* pAnnot = CreateAnnot(obj, &oSubtype, NULL);
if (pAnnot)
{
pDoc->AddAnnotation(nAddObjToXRef + nStartRefID, pAnnot);
pDict = pAnnot;
}
}
oSubtype.free();
if (obj->dictLookup("Type", &oType)->isName("ExtGState"))
{
PdfWriter::CExtGrState* pState = CreateExtGState(obj);
if (pState)
{
pDoc->AddExtGState(pState);
pDict = pState;
}
}
oType.free();
if (!pDict)
pDict = new PdfWriter::CDictObject();
if (nAddObjToXRef > 0)
{
pDoc->AddObject(pDict);
pManager->AddObj(nAddObjToXRef + nStartRefID, pDict);
nAddObjToXRef = 0;
}
for (int nIndex = 0; nIndex < obj->dictGetLength(); ++nIndex)
{
char* chKey = obj->dictGetKey(nIndex);
obj->dictGetValNF(nIndex, &oTemp);
pBase = DictToCDictObject2(&oTemp, pDoc, xref, pManager, nStartRefID, 0, bUndecodedStream);
pDict->Add(chKey, pBase);
oTemp.free();
}
pBase = pDict;
break;
}
case objRef:
{
int nObjNum = obj->getRefNum();
PdfWriter::CObjectBase* pObj = pManager->GetObj(nObjNum + nStartRefID);
if (pObj)
{
pManager->IncRefCount(nObjNum + nStartRefID);
return pObj;
}
obj->fetch(xref, &oTemp);
pBase = DictToCDictObject2(&oTemp, pDoc, xref, pManager, nStartRefID, nObjNum, bUndecodedStream);
oTemp.free();
break;
}
case objNone:
{
pBase = new PdfWriter::CNameObject("None");
break;
}
case objStream:
{
PdfWriter::CDictObject* pDict = new PdfWriter::CDictObject();
if (nAddObjToXRef > 0)
{
pDoc->AddObject(pDict);
pManager->AddObj(nAddObjToXRef + nStartRefID, pDict);
nAddObjToXRef = 0;
}
Dict* pODict = obj->streamGetDict();
int nLength = 0;
for (int nIndex = 0; nIndex < pODict->getLength(); ++nIndex)
{
char* chKey = pODict->getKey(nIndex);
if (strcmp("Length", chKey) == 0)
{
pODict->getVal(nIndex, &oTemp);
nLength = oTemp.getNum();
pBase = new PdfWriter::CNumberObject(nLength);
pDoc->AddObject(pBase);
pDict->Add(chKey, pBase);
oTemp.free();
continue;
}
pODict->getValNF(nIndex, &oTemp);
pBase = DictToCDictObject2(&oTemp, pDoc, xref, pManager, nStartRefID);
pDict->Add(chKey, pBase);
oTemp.free();
}
pBase = pDict;
PdfWriter::CStream* pStream = new PdfWriter::CMemoryStream(nLength);
pDict->SetStream(pStream);
Stream* pOStream = bUndecodedStream ? obj->getStream()->getUndecodedStream() : obj->getStream();
pOStream->reset();
int nChar = pOStream->getChar();
while (nChar != EOF)
{
pStream->WriteChar(nChar);
nChar = pOStream->getChar();
}
break;
}
case objCmd:
case objError:
case objEOF:
break;
}
if (nAddObjToXRef > 0)
{
pDoc->AddObject(pBase);
pManager->AddObj(nAddObjToXRef + nStartRefID, pBase);
}
return pBase;
}
void AddWidgetParent(PdfWriter::CDocument* pDoc, CObjectsManager* pManager, PdfWriter::CObjectBase* pObj)
{
if (pObj->GetType() != PdfWriter::object_type_DICT)
return;
PdfWriter::CDictObject* pDict = dynamic_cast<PdfWriter::CDictObject*>(pObj);
if (!pDict)
return;
int nID = pManager->FindObj(pObj);
if (nID < 0)
return;
if (pDict->GetDictType() == PdfWriter::dict_type_UNKNOWN)
{
if (pDoc->GetParent(nID))
return;
pDoc->AddParent(nID, pDict);
}
PdfWriter::CObjectBase* pObjParent = pDict->Get("Parent");
if (pObjParent && pObjParent->GetType() == PdfWriter::object_type_DICT)
AddWidgetParent(pDoc, pManager, pObjParent);
if (pDict->GetDictType() != PdfWriter::dict_type_UNKNOWN)
return;
PdfWriter::CObjectBase* pObjKids = pDict->Get("Kids");
if (!pObjKids || pObjKids->GetType() != PdfWriter::object_type_ARRAY)
return;
PdfWriter::CArrayObject* pKids = (PdfWriter::CArrayObject*)pObjKids;
for (int i = 0; i < pKids->GetCount(); ++i)
AddWidgetParent(pDoc, pManager, pKids->Get(i));
}
PdfWriter::CDictObject* GetWidgetParent(PDFDoc* pdfDoc, PdfWriter::CDocument* pDoc, Object* pParentRef, int nStartRefID)
{
if (!pParentRef || !pParentRef->isRef() || !pdfDoc)
return NULL;
PdfWriter::CDictObject* pParent = pDoc->GetParent(pParentRef->getRefNum() + nStartRefID);
if (pParent)
return pParent;
Object oParent;
if (!pParentRef->fetch(pdfDoc->getXRef(), &oParent)->isDict())
{
oParent.free();
return pParent;
}
PdfWriter::CXref* pXref = NULL;
pParent = new PdfWriter::CDictObject();
if (nStartRefID == 0)
{
pXref = new PdfWriter::CXref(pDoc, pParentRef->getRefNum());
pXref->Add(pParent, pParentRef->getRefGen());
}
if (!pDoc->EditParent(pXref, pParent, pParentRef->getRefNum() + nStartRefID))
{
RELEASEOBJECT(pXref);
oParent.free();
return NULL;
}
for (int i = 0; i < oParent.dictGetLength(); ++i)
{
char* chKey = oParent.dictGetKey(i);
if (strcmp("Parent", chKey) == 0)
{
Object oParentRef;
oParent.dictGetValNF(i, &oParentRef);
PdfWriter::CDictObject* pParent2 = GetWidgetParent(pdfDoc, pDoc, &oParentRef, nStartRefID);
if (pParent2)
{
pParent->Add("Parent", pParent2);
oParentRef.free();
continue;
}
oParentRef.free();
}
Object oTemp;
oParent.dictGetValNF(i, &oTemp);
DictToCDictObject(&oTemp, pParent, chKey);
oTemp.free();
}
oParent.free();
return pParent;
}
HRESULT _ChangePassword(const std::wstring& wsPath, const std::wstring& wsPassword, CPdfReader* _pReader, CPdfWriter* _pWriter)
{
if (!_pReader || !_pWriter)
return S_FALSE;
PDFDoc* pPDFDocument = _pReader->GetPDFDocument(0);
if (!pPDFDocument)
return S_FALSE;
XRef* xref = pPDFDocument->getXRef();
if (!xref)
return S_FALSE;
Object* trailerDict = xref->getTrailerDict();
if (!trailerDict)
return S_FALSE;
PdfWriter::CDocument* pDoc = _pWriter->GetDocument();
PdfWriter::CXref* pXref = new PdfWriter::CXref(pDoc, 0);
PdfWriter::CXref* m_pXref = new PdfWriter::CXref(pDoc, xref->getNumObjects()); // Для новых объектов
if (!xref || !pDoc || !pXref || !m_pXref)
{
RELEASEOBJECT(pXref);
RELEASEOBJECT(m_pXref);
return S_FALSE;
}
pXref->SetPrev(m_pXref);
for (int i = 0; i < xref->getSize(); ++i)
{
XRefEntry* pEntry = xref->getEntry(i);
if (pEntry->type == xrefEntryFree)
continue;
if (i != pXref->GetSizeXRef())
{
PdfWriter::CXref* pXref2 = new PdfWriter::CXref(pDoc, i);
pXref2->SetPrev(pXref);
pXref = pXref2;
}
Object oTemp;
xref->fetch(i, pEntry->type == xrefEntryCompressed ? 0 : pEntry->gen, &oTemp);
PdfWriter::CObjectBase* pObj = NULL;
switch (oTemp.getType())
{
case objBool:
{
pObj = new PdfWriter::CBoolObject(oTemp.getBool());
break;
}
case objInt:
{
pObj = new PdfWriter::CNumberObject(oTemp.getInt());
break;
}
case objReal:
{
pObj = new PdfWriter::CRealObject(oTemp.getReal());
break;
}
case objString:
{
GString* str = oTemp.getString();
if (str->isBinary())
{
int nLength = str->getLength();
BYTE* arrId = new BYTE[nLength];
for (int nIndex = 0; nIndex < nLength; ++nIndex)
arrId[nIndex] = str->getChar(nIndex);
pObj = new PdfWriter::CBinaryObject(arrId, nLength, false);
}
else
{
TextString* s = new TextString(str);
std::string sValue = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
pObj = new PdfWriter::CStringObject(sValue.c_str(), !s->isPDFDocEncoding());
delete s;
}
break;
}
case objName:
{
pObj = new PdfWriter::CNameObject(oTemp.getName());
break;
}
case objNull:
{
pObj = new PdfWriter::CNullObject();
break;
}
case objArray:
{
pObj = new PdfWriter::CArrayObject();
for (int nIndex = 0; nIndex < oTemp.arrayGetLength(); ++nIndex)
{
Object oT;
oTemp.arrayGetNF(nIndex, &oT);
DictToCDictObject(&oT, pObj, "");
oT.free();
}
break;
}
case objDict:
{
pObj = new PdfWriter::CDictObject();
for (int nIndex = 0; nIndex < oTemp.dictGetLength(); ++nIndex)
{
Object oT;
char* chKey = oTemp.dictGetKey(nIndex);
oTemp.dictGetValNF(nIndex, &oT);
DictToCDictObject(&oT, pObj, chKey);
oT.free();
}
break;
}
case objRef:
{
PdfWriter::CObjectBase* pBase = new PdfWriter::CObjectBase();
pBase->SetRef(oTemp.getRefNum(), oTemp.getRefGen());
pObj = new PdfWriter::CProxyObject(pBase, true);
break;
}
case objStream:
{
Dict* pDict = oTemp.streamGetDict();
Object oObjStm;
if (pDict->lookup("Type", &oObjStm)->isName("ObjStm"))
{
oObjStm.free();
break;
}
oObjStm.free();
PdfWriter::CDictObject* pDObj = new PdfWriter::CDictObject();
pObj = pDObj;
int nLength = 0;
for (int nIndex = 0; nIndex < pDict->getLength(); ++nIndex)
{
Object oT;
char* chKey = pDict->getKey(nIndex);
if (strcmp("Length", chKey) == 0)
{
Object oLength;
nLength = pDict->getVal(nIndex, &oLength)->isInt() ? oLength.getInt() : 0;
oLength.free();
continue;
}
pDict->getValNF(nIndex, &oT);
DictToCDictObject(&oT, pObj, chKey);
oT.free();
}
PdfWriter::CStream* pStream = new PdfWriter::CMemoryStream();
pDObj->SetStream(m_pXref, pStream, false);
Stream* pImage = oTemp.getStream()->getUndecodedStream();
pImage->reset();
for (int nI = 0; nI < nLength; ++nI)
pStream->WriteChar(pImage->getChar());
break;
}
case objNone:
case objCmd:
case objError:
case objEOF:
default:
break;
}
oTemp.free();
if (pObj)
pXref->Add(pObj);
}
PdfWriter::CDictObject* pTrailer = pXref->GetTrailer();
for (int nIndex = 0; nIndex < trailerDict->dictGetLength(); ++nIndex)
{
Object oTemp;
char* chKey = trailerDict->dictGetKey(nIndex);
if (strcmp("Root", chKey) == 0 || strcmp("Info", chKey) == 0)
{
trailerDict->dictGetValNF(nIndex, &oTemp);
DictToCDictObject(&oTemp, pTrailer, chKey);
}
oTemp.free();
}
bool bRes = pDoc->SaveNewWithPassword(pXref, m_pXref, wsPath, wsPassword, wsPassword, pTrailer);
RELEASEOBJECT(pXref);
return bRes ? S_OK : S_FALSE;
}
void GetCTM(XRef* pXref, Object* oPage, double* dCTM)
{
if (!oPage || !oPage->isDict())
return;
Object oContents;
if (!oPage->dictLookup("Contents", &oContents) || (!oContents.isArray() && !oContents.isStream()))
{
oContents.free();
return;
}
Parser* parser = new Parser(pXref, new Lexer(pXref, &oContents), gFalse);
int nNumArgs = 0;
Object oObj;
Object pArgs[maxArgs];
parser->getObj(&oObj);
while (!oObj.isEOF())
{
if (oObj.isCmd())
{
if (oObj.isCmd("q"))
{
Object obj;
parser->getObj(&obj);
while (!obj.isEOF() && !obj.isCmd("Q"))
{
obj.free();
parser->getObj(&obj);
}
obj.free();
}
else if (oObj.isCmd("cm") && nNumArgs > 5)
{
double a1 = dCTM[0];
double b1 = dCTM[1];
double c1 = dCTM[2];
double d1 = dCTM[3];
dCTM[0] = pArgs[0].getNum() * a1 + pArgs[1].getNum() * c1;
dCTM[1] = pArgs[0].getNum() * b1 + pArgs[1].getNum() * d1;
dCTM[2] = pArgs[2].getNum() * a1 + pArgs[3].getNum() * c1;
dCTM[3] = pArgs[2].getNum() * b1 + pArgs[3].getNum() * d1;
dCTM[4] = pArgs[4].getNum() * a1 + pArgs[5].getNum() * c1 + dCTM[4];
dCTM[5] = pArgs[4].getNum() * b1 + pArgs[5].getNum() * d1 + dCTM[5];
}
oObj.free();
for (int i = 0; i < nNumArgs; ++i)
pArgs[i].free();
nNumArgs = 0;
}
else if (nNumArgs < maxArgs)
pArgs[nNumArgs++] = oObj;
parser->getObj(&oObj);
}
oObj.free();
for (int i = 0; i < nNumArgs; ++i)
pArgs[i].free();
RELEASEOBJECT(parser);
oContents.free();
}
void CObjectsManager::AddObj(int nID, PdfWriter::CObjectBase* pObj)
{
if (m_mUniqueRef.find(nID) == m_mUniqueRef.end())
m_mUniqueRef[nID] = { pObj, 1 };
}
void CObjectsManager::RemoveObj(int nID)
{
m_mUniqueRef.erase(nID);
}
PdfWriter::CObjectBase* CObjectsManager::GetObj(int nID)
{
if (m_mUniqueRef.find(nID) != m_mUniqueRef.end())
return m_mUniqueRef[nID].pObj;
return NULL;
}
bool CObjectsManager::IncRefCount(int nID)
{
if (m_mUniqueRef.find(nID) != m_mUniqueRef.end())
{
m_mUniqueRef[nID].nRefCount++;
return true;
}
return false;
}
bool CObjectsManager::DecRefCount(int nID)
{
if (m_mUniqueRef.find(nID) != m_mUniqueRef.end())
{
if (m_pDoc)
m_pDoc->RemoveObj(m_mUniqueRef[nID].pObj);
else
m_mUniqueRef[nID].pObj->SetHidden();
return true;
}
return false;
}
int CObjectsManager::FindObj(PdfWriter::CObjectBase* pObj)
{
std::map<int, CObjectInfo>::iterator it = std::find_if(m_mUniqueRef.begin(), m_mUniqueRef.end(), [pObj](const std::pair<int, CObjectInfo>& t){ return t.second.pObj == pObj; });
if (it != m_mUniqueRef.end())
return it->first;
return -1;
}
void CObjectsManager::DeleteObjTree(Object* obj, XRef* xref, int nStartRefID)
{
Object oTemp;
switch (obj->getType())
{
case objBool:
case objInt:
case objReal:
case objString:
case objName:
case objNull:
case objNone:
case objCmd:
case objError:
case objEOF:
break;
case objArray:
{
for (int nIndex = 0; nIndex < obj->arrayGetLength(); ++nIndex)
{
obj->arrayGetNF(nIndex, &oTemp);
DeleteObjTree(&oTemp, xref, nStartRefID);
oTemp.free();
}
break;
}
case objDict:
{
if (SplitSkipDict(obj, this, nStartRefID))
return;
for (int nIndex = 0; nIndex < obj->dictGetLength(); ++nIndex)
{
obj->dictGetValNF(nIndex, &oTemp);
DeleteObjTree(&oTemp, xref, nStartRefID);
oTemp.free();
}
break;
}
case objRef:
{
int nObjNum = obj->getRefNum();
PdfWriter::CObjectBase* pObj = GetObj(nObjNum + nStartRefID);
if (pObj && DecRefCount(nObjNum + nStartRefID))
return;
obj->fetch(xref, &oTemp);
DeleteObjTree(&oTemp, xref, nStartRefID);
oTemp.free();
break;
}
case objStream:
{
Dict* pODict = obj->streamGetDict();
for (int nIndex = 0; nIndex < pODict->getLength(); ++nIndex)
{
pODict->getValNF(nIndex, &oTemp);
DeleteObjTree(&oTemp, xref, nStartRefID);
oTemp.free();
}
break;
}
}
}
void CObjectsManager::SetDoc(PdfWriter::CDocument* pDoc) { m_pDoc = pDoc; }
CPdfEditor::CPdfEditor(const std::wstring& _wsSrcFile, const std::wstring& _wsPassword, const std::wstring& _wsDstFile, CPdfReader* _pReader, CPdfWriter* _pWriter, Mode nMode)
{
m_wsSrcFile = _wsSrcFile;
m_wsDstFile = _wsDstFile;
m_wsPassword = _wsPassword;
m_pReader = _pReader;
m_pWriter = _pWriter;
m_nEditPage = -1;
m_nError = 0;
m_nMode = Mode::Unknown;
PDFDoc* pPDFDocument = m_pReader->GetPDFDocument(0);
if (!pPDFDocument)
{
m_nError = 1;
return;
}
XRef* xref = pPDFDocument->getXRef();
PdfWriter::CDocument* pDoc = m_pWriter->GetDocument();
if (!xref || !pDoc)
{
m_nError = 1;
return;
}
m_nOriginIndex = m_pReader->GetNumPages();
SetMode(nMode);
}
void CPdfEditor::SetMode(Mode nMode)
{
if (m_nMode != Mode::Unknown)
return;
m_nMode = nMode;
if (m_nMode == Mode::WriteAppend)
IncrementalUpdates();
else if (m_nMode == Mode::WriteNew)
{
PdfWriter::CDocument* pDoc = m_pWriter->GetDocument();
PdfWriter::CPageTree* pPageTree = pDoc->GetPageTree();
m_mObjManager.SetDoc(pDoc);
int nPages = m_pReader->GetNumPages();
pPageTree->CreateFakePages(nPages);
}
}
bool CPdfEditor::IncrementalUpdates()
{
if (m_nMode != Mode::Unknown)
return true;
m_nMode = Mode::WriteAppend;
PDFDoc* pPDFDocument = m_pReader->GetPDFDocument(0);
XRef* xref = pPDFDocument->getXRef();
PdfWriter::CDocument* pDoc = m_pWriter->GetDocument();
std::string sPathUtf8New = U_TO_UTF8(m_wsDstFile);
std::string sPathUtf8Old = U_TO_UTF8(m_wsSrcFile);
if (sPathUtf8Old == sPathUtf8New || NSSystemPath::NormalizePath(sPathUtf8Old) == NSSystemPath::NormalizePath(sPathUtf8New))
{
GString* owner_pswd = NSStrings::CreateString(m_wsPassword);
GString* user_pswd = NSStrings::CreateString(m_wsPassword);
GBool bRes = pPDFDocument->makeWritable(true, owner_pswd, user_pswd);
delete owner_pswd;
delete user_pswd;
if (!bRes)
return false;
}
else
{
if (!NSFile::CFileBinary::Copy(m_wsSrcFile, m_wsDstFile))
return false;
NSFile::CFileBinary oFile;
if (!oFile.OpenFile(m_wsDstFile, true))
return false;
oFile.CloseFile();
}
// Получение каталога и дерева страниц из reader
Object catDict, catRefObj, pagesRefObj;
if (!xref->getCatalog(&catDict)->isDict() || !catDict.dictLookupNF("Pages", &pagesRefObj))
{
pagesRefObj.free(); catDict.free();
return false;
}
Object* trailer = xref->getTrailerDict();
if (!trailer || !trailer->isDict() || !trailer->dictLookupNF("Root", &catRefObj)->isRef())
{
pagesRefObj.free(); catDict.free(); catRefObj.free();
return false;
}
Ref catRef = catRefObj.getRef();
catRefObj.free();
// Создание каталога для writer
PdfWriter::CXref* pXref = new PdfWriter::CXref(pDoc, catRef.num);
if (!pXref)
{
pagesRefObj.free(); catDict.free();
return false;
}
PdfWriter::CCatalog* pCatalog = new PdfWriter::CCatalog();
if (!pCatalog)
{
pagesRefObj.free(); catDict.free(); RELEASEOBJECT(pXref);
return false;
}
pXref->Add(pCatalog, catRef.gen);
PdfWriter::CResourcesDict* pDR = NULL;
PdfWriter::CXref* pDRXref = NULL;
for (int nIndex = 0; nIndex < catDict.dictGetLength(); ++nIndex)
{
Object oAcroForm;
char* chKey = catDict.dictGetKey(nIndex);
if (strcmp("AcroForm", chKey) == 0)
{
catDict.dictGetVal(nIndex, &oAcroForm);
PdfWriter::CDictObject* pAcroForm = new PdfWriter::CDictObject();
for (int nIndex = 0; nIndex < oAcroForm.dictGetLength(); ++nIndex)
{
Object oTemp2;
char* chKey = oAcroForm.dictGetKey(nIndex);
if (strcmp("DR", chKey) == 0)
{
if (!oAcroForm.dictGetVal(nIndex, &oTemp2)->isDict())
{
oTemp2.free();
continue;
}
Object oDR;
oAcroForm.dictGetValNF(nIndex, &oDR);
int nDRxrefNum = oDR.isRef() ? oDR.getRefNum() : xref->getNumObjects();
int nDRxrefGen = oDR.isRef() ? oDR.getRefGen() : 0;
oDR.free();
pDRXref = new PdfWriter::CXref(pDoc, nDRxrefNum);
pDR = new PdfWriter::CResourcesDict(NULL, true, false);
pDRXref->Add(pDR, nDRxrefGen);
pAcroForm->Add(chKey, pDR);
for (int nIndex2 = 0; nIndex2 < oTemp2.dictGetLength(); ++nIndex2)
{
Object oTemp;
char* chKey2 = oTemp2.dictGetKey(nIndex2);
oTemp2.dictGetVal(nIndex2, &oTemp);
DictToCDictObject(&oTemp, pDR, chKey2);
oTemp.free();
}
oTemp2.free();
pDR->Fix();
continue;
}
else if (strcmp("Fields", chKey) == 0)
oAcroForm.dictGetVal(nIndex, &oTemp2);
else if (strcmp("NeedAppearances", chKey) == 0)
{
oTemp2.free();
continue;
}
else
oAcroForm.dictGetValNF(nIndex, &oTemp2);
DictToCDictObject(&oTemp2, pAcroForm, chKey);
oTemp2.free();
}
if (!pAcroForm->Get("Fields"))
pAcroForm->Add("Fields", new PdfWriter::CArrayObject());
oAcroForm.free();
pCatalog->Add(chKey, pAcroForm);
continue;
}
else
catDict.dictGetValNF(nIndex, &oAcroForm);
DictToCDictObject(&oAcroForm, pCatalog, chKey);
oAcroForm.free();
}
catDict.free();
// Проверка уникальности имён текущих цифровых подписей pdf
unsigned int nFormField = 0;
AcroForm* form = pPDFDocument->getCatalog()->getForm();
if (form)
{
nFormField = form->getNumFields() + 1;
std::wstring sSig = L"Sig" + std::to_wstring(nFormField);
int i = 0, nFormFields = form->getNumFields();
while (i < nFormFields)
{
int nLength;
Unicode* uName = form->getField(i)->getName(&nLength);
std::wstring sName = NSStringExt::CConverter::GetUnicodeFromUTF32(uName, nLength);
RELEASEMEM(uName);
if (sName == sSig)
{
i = 0;
nFormField++;
sSig = L"Sig" + std::to_wstring(nFormField);
}
else
i++;
}
nFormField--;
}
// Получение шифрования из reader и применения для writer
int nCryptAlgorithm = -1;
PdfWriter::CEncryptDict* pEncryptDict = NULL;
if (xref->isEncrypted())
{
CryptAlgorithm encAlgorithm;
GBool ownerPasswordOk;
int permFlags, keyLength, encVersion;
xref->getEncryption(&permFlags, &ownerPasswordOk, &keyLength, &encVersion, &encAlgorithm);
nCryptAlgorithm = encAlgorithm;
Object* pTrailerDict = xref->getTrailerDict();
if (pTrailerDict)
{
pEncryptDict = new PdfWriter::CEncryptDict();
// Нужно получить словарь Encrypt БЕЗ дешифровки, поэтому времено отключаем encrypted в xref
xref->offEncrypted();
Object encrypt, ID, ID1;
if (pTrailerDict->dictLookup("Encrypt", &encrypt) && encrypt.isDict())
{
for (int nIndex = 0; nIndex < encrypt.dictGetLength(); ++nIndex)
{
Object oTemp;
char* chKey = encrypt.dictGetKey(nIndex);
encrypt.dictGetValNF(nIndex, &oTemp);
DictToCDictObject(&oTemp, pEncryptDict, chKey, true);
oTemp.free();
}
}
if (!pEncryptDict->Get("Length"))
pEncryptDict->Add("Length", 40);
encrypt.free();
if (pTrailerDict->dictLookup("ID", &ID) && ID.isArray() && ID.arrayGet(0, &ID1) && ID1.isString())
DictToCDictObject(&ID1, pEncryptDict, "ID", true);
ID.free(); ID1.free();
xref->onEncrypted();
pEncryptDict->SetRef(0, 0);
pEncryptDict->Fix();
pEncryptDict->SetPasswords(m_wsPassword, m_wsPassword);
if (!pEncryptDict->UpdateKey(nCryptAlgorithm))
{
pagesRefObj.free();
RELEASEOBJECT(pXref);
RELEASEOBJECT(pDRXref);
return false;
}
}
}
// Применение редактирования для writer
bool bRes = pDoc->EditPdf(xref->getLastXRefPos(), xref->getNumObjects() + 1, pXref, pCatalog, pEncryptDict, nFormField);
if (bRes)
{
// Воспроизведение дерева страниц во writer
GetPageTree(xref, &pagesRefObj);
if (pDR && pDRXref)
bRes = pDoc->EditResources(pDRXref, pDR);
}
pagesRefObj.free();
return bRes;
}
void CPdfEditor::Close()
{
if (m_wsDstFile.empty())
return;
if (m_nMode == Mode::Unknown)
{
if (m_wsDstFile != m_wsSrcFile && NSSystemPath::NormalizePath(m_wsDstFile) != NSSystemPath::NormalizePath(m_wsSrcFile))
NSFile::CFileBinary::Copy(m_wsSrcFile, m_wsDstFile);
return;
}
if (m_nMode == Mode::Split)
{
m_pWriter->SaveToFile(m_wsDstFile);
return;
}
if (m_nMode == Mode::WriteNew)
{
PdfWriter::CDocument* pDoc = m_pWriter->GetDocument();
PdfWriter::CPageTree* pPageTree = pDoc->GetPageTree();
int nPages = pPageTree->GetCount();
for (int i = 0; i < nPages; ++i)
{
PdfWriter::CObjectBase* pObj = pPageTree->GetObj(i);
if (pObj && pObj->GetType() != PdfWriter::object_type_DICT)
EditPage(i, false, true);
}
Object oCatalog;
PDFDoc* pPDFDocument = m_pReader->GetPDFDocument(0);
int nStartRefID = 0;
XRef* xref = pPDFDocument->getXRef();
if (!xref->getCatalog(&oCatalog)->isDict())
{
oCatalog.free();
return;
}
Object oAcroForm;
if (oCatalog.dictLookupNF("AcroForm", &oAcroForm)->isRef() || oAcroForm.isDict())
{
PdfWriter::CDictObject* pAcroForm = pDoc->GetAcroForm();
if (!pAcroForm)
{
pAcroForm = new PdfWriter::CDictObject();
if (oAcroForm.isRef())
pDoc->AddObject(pAcroForm);
pDoc->SetAcroForm(pAcroForm);
}
else
pAcroForm->Remove("NeedAppearances");
if (oAcroForm.isRef())
{
oAcroForm.free();
if (!oCatalog.dictLookup("AcroForm", &oAcroForm)->isDict())
{
oAcroForm.free(); oCatalog.free();
return;
}
}
for (int nIndex = 0; nIndex < oAcroForm.dictGetLength(); ++nIndex)
{
Object oTemp;
char* chKey = oAcroForm.dictGetKey(nIndex);
if (strcmp("Fields", chKey) == 0)
{
Ref oFieldsRef = { -1, -1 };
if (oAcroForm.dictGetValNF(nIndex, &oTemp)->isRef())
oFieldsRef = oTemp.getRef();
oTemp.free();
PdfWriter::CArrayObject* pFields = dynamic_cast<PdfWriter::CArrayObject*>(pAcroForm->Get("Fields"));
if (!pFields)
{
PdfWriter::CObjectBase* pObj = oFieldsRef.num > 0 ? m_mObjManager.GetObj(oFieldsRef.num + nStartRefID) : NULL;
if (pObj)
{
pAcroForm->Add(chKey, pObj);
m_mObjManager.IncRefCount(oFieldsRef.num + nStartRefID);
continue;
}
}
if (oAcroForm.dictGetVal(nIndex, &oTemp)->isArray())
{
if (!pFields)
{
pFields = new PdfWriter::CArrayObject();
if (oFieldsRef.num > 0)
{
pDoc->AddObject(pFields);
m_mObjManager.AddObj(oFieldsRef.num + nStartRefID, pFields);
}
pAcroForm->Add(chKey, pFields);
}
for (int nIndex = 0; nIndex < oTemp.arrayGetLength(); ++nIndex)
{
Object oRes;
PdfWriter::CObjectBase* pObj = NULL;
if (oTemp.arrayGetNF(nIndex, &oRes)->isRef())
pObj = m_mObjManager.GetObj(oRes.getRefNum() + nStartRefID);
if (pObj)
{
pFields->Add(pObj);
m_mObjManager.IncRefCount(oRes.getRefNum() + nStartRefID);
AddWidgetParent(pDoc, &m_mObjManager, pObj);
oRes.free();
continue;
}
oRes.free();
}
oTemp.free();
continue;
}
else if (!pFields)
{
oTemp.free();
oAcroForm.dictGetValNF(nIndex, &oTemp);
}
else
{
oTemp.free();
continue;
}
}
else if (strcmp("SigFlags", chKey) == 0 || strcmp("XFA", chKey) == 0 || (strcmp("DA", chKey) == 0 && pAcroForm->Get("DA")) || strcmp("NeedAppearances", chKey) == 0)
{ // Нельзя гарантировать их выполнение
oTemp.free();
continue;
}
else if (strcmp("DR", chKey) == 0)
{ // Добавляем только уникальные ключи
PdfWriter::CDictObject* pDR = dynamic_cast<PdfWriter::CDictObject*>(pAcroForm->Get("DR"));
if (!pDR)
{
pDR = new PdfWriter::CDictObject();
pDoc->AddObject(pDR);
pAcroForm->Add(chKey, pDR);
}
PdfWriter::CArrayObject* pProcset = new PdfWriter::CArrayObject();
pDR->Add("ProcSet", pProcset);
pProcset->Add(new PdfWriter::CNameObject("PDF"));
pProcset->Add(new PdfWriter::CNameObject("Text"));
pProcset->Add(new PdfWriter::CNameObject("ImageB"));
pProcset->Add(new PdfWriter::CNameObject("ImageC"));
pProcset->Add(new PdfWriter::CNameObject("ImageI"));
if (oAcroForm.dictGetVal(nIndex, &oTemp)->isDict())
{
Object oTemp2;
for (int nIndex2 = 0; nIndex2 < oTemp.dictGetLength(); ++nIndex2)
{
char* chKey2 = oTemp.dictGetKey(nIndex2);
if (strcmp("ProcSet", chKey2) == 0 || !oTemp.dictGetVal(nIndex2, &oTemp2)->isDict())
{
oTemp2.free();
continue;
}
PdfWriter::CDictObject* pDict = dynamic_cast<PdfWriter::CDictObject*>(pDR->Get(chKey2));
if (!pDict)
{
Object oTempRef;
if (oTemp.dictGetValNF(nIndex2, &oTempRef)->isRef())
{
PdfWriter::CObjectBase* pObj = m_mObjManager.GetObj(oTempRef.getRefNum() + nStartRefID);
if (pObj)
{
pDR->Add(chKey2, pObj);
m_mObjManager.IncRefCount(oTempRef.getRefNum() + nStartRefID);
oTemp2.free(); oTempRef.free();
continue;
}
}
PdfWriter::CObjectBase* pBase = DictToCDictObject2(&oTemp2, pDoc, xref, &m_mObjManager, nStartRefID);
if (oTempRef.isRef())
pDoc->AddObject(pBase);
pDR->Add(chKey2, pBase);
oTemp2.free(); oTempRef.free();
continue;
}
else
{
for (int nIndex3 = 0; nIndex3 < oTemp2.dictGetLength(); ++nIndex3)
{
char* chKey3 = oTemp2.dictGetKey(nIndex3);
if (pDict->Get(chKey3))
continue;
Object oTempRef;
if (oTemp2.dictGetValNF(nIndex3, &oTempRef)->isRef())
{
PdfWriter::CObjectBase* pObj = m_mObjManager.GetObj(oTempRef.getRefNum() + nStartRefID);
if (pObj)
{
pDict->Add(chKey3, pObj);
m_mObjManager.IncRefCount(oTempRef.getRefNum() + nStartRefID);
oTemp2.free(); oTempRef.free();
continue;
}
}
PdfWriter::CObjectBase* pBase = DictToCDictObject2(&oTemp2, pDoc, xref, &m_mObjManager, nStartRefID);
if (oTempRef.isRef())
pDoc->AddObject(pBase);
pDict->Add(chKey3, pBase);
oTemp2.free(); oTempRef.free();
continue;
}
}
}
oTemp2.free(); oTemp.free();
continue;
}
else
{
oTemp.free();
oAcroForm.dictGetValNF(nIndex, &oTemp);
}
}
else
oAcroForm.dictGetValNF(nIndex, &oTemp);
PdfWriter::CObjectBase* pBase = DictToCDictObject2(&oTemp, pDoc, xref, &m_mObjManager, nStartRefID);
pAcroForm->Add(chKey, pBase);
oTemp.free();
}
}
oAcroForm.free(); oCatalog.free();
m_pWriter->SaveToFile(m_wsDstFile);
return;
}
// m_nMode == Mode::WriteAppend
PDFDoc* pPDFDocument = m_pReader->GetPDFDocument(0);
PdfWriter::CDocument* pDoc = m_pWriter->GetDocument();
XRef* xref = pPDFDocument->getXRef();
// Добавляем первый элемент в таблицу xref
// он должен иметь вид 0000000000 65535 f
PdfWriter::CXref* pXref = new PdfWriter::CXref(pDoc, 0, 65535);
if (!pXref)
return;
PdfWriter::CDictObject* pTrailer = NULL;
Object* trailerDict = xref->getTrailerDict();
if (trailerDict)
{
pTrailer = pXref->GetTrailer();
for (int nIndex = 0; nIndex < trailerDict->dictGetLength(); ++nIndex)
{
Object oTemp;
char* chKey = trailerDict->dictGetKey(nIndex);
trailerDict->dictGetValNF(nIndex, &oTemp);
DictToCDictObject(&oTemp, pTrailer, chKey);
oTemp.free();
}
}
Object info;
pPDFDocument->getDocInfo(&info);
PdfWriter::CXref* pInfoXref = NULL;
PdfWriter::CInfoDict* pInfoDict = NULL;
if (info.isDict())
{
// Обновление Info
PdfWriter::CObjectBase* pInfo = pTrailer->Get("Info");
pInfoXref = new PdfWriter::CXref(pDoc, pInfo ? pInfo->GetObjId() : 0);
if (!pInfoXref)
{
RELEASEOBJECT(pXref);
return;
}
pInfoDict = new PdfWriter::CInfoDict();
if (!pInfoDict)
{
RELEASEOBJECT(pXref);
RELEASEOBJECT(pInfoXref);
return;
}
pInfoXref->Add(pInfoDict, pInfo ? pInfo->GetGenNo() : 0);
for (int nIndex = 0; nIndex < info.dictGetLength(); ++nIndex)
{
Object oTemp;
char* chKey = info.dictGetKey(nIndex);
info.dictGetValNF(nIndex, &oTemp);
DictToCDictObject(&oTemp, pInfoDict, chKey);
oTemp.free();
}
pInfoDict->SetTime(PdfWriter::InfoModaDate);
}
info.free();
if (!m_pWriter->EditClose() || !pDoc->AddToFile(m_wsDstFile, pXref, pTrailer, pInfoXref, pInfoDict))
{
RELEASEOBJECT(pXref);
return;
}
std::string sPathUtf8New = U_TO_UTF8(m_wsDstFile);
std::string sPathUtf8Old = U_TO_UTF8(m_wsSrcFile);
if (sPathUtf8Old == sPathUtf8New || NSSystemPath::NormalizePath(sPathUtf8Old) == NSSystemPath::NormalizePath(sPathUtf8New))
{
GString* owner_pswd = NSStrings::CreateString(m_wsPassword);
GString* user_pswd = NSStrings::CreateString(m_wsPassword);
pPDFDocument->makeWritable(false, owner_pswd, user_pswd);
delete owner_pswd;
delete user_pswd;
NSFile::CFileBinary oFile;
if (oFile.OpenFile(m_wsSrcFile))
{
m_pReader->ChangeLength(oFile.GetFileSize());
oFile.CloseFile();
}
}
m_pReader = NULL;
m_pWriter = NULL;
m_nEditPage = -1;
}
int CPdfEditor::GetError()
{
return m_nError;
}
void CPdfEditor::GetPageTree(XRef* xref, Object* pPagesRefObj, PdfWriter::CPageTree* pPageParent)
{
PdfWriter::CDocument* pDoc = m_pWriter->GetDocument();
if (!pPagesRefObj || !xref || !pDoc)
return;
Object pagesObj;
if (!pPagesRefObj->isRef() || !pPagesRefObj->fetch(xref, &pagesObj)->isDict("Pages"))
{
pagesObj.free();
return;
}
Ref topPagesRef = pPagesRefObj->getRef();
PdfWriter::CXref* pXref = new PdfWriter::CXref(pDoc, topPagesRef.num);
if (!pXref)
{
pagesObj.free();
return;
}
PdfWriter::CPageTree* pPageT = new PdfWriter::CPageTree();
if (!pPageT)
{
pagesObj.free();
RELEASEOBJECT(pXref);
return;
}
pXref->Add(pPageT, topPagesRef.gen);
for (int nIndex = 0; nIndex < pagesObj.dictGetLength(); ++nIndex)
{
Object oTemp;
char* chKey = pagesObj.dictGetKey(nIndex);
if (strcmp("Resources", chKey) == 0)
{
if (pagesObj.dictGetVal(nIndex, &oTemp)->isDict())
{
PdfWriter::CResourcesDict* pDict = new PdfWriter::CResourcesDict(NULL, true, false);
pPageT->Add("Resources", pDict);
for (int nIndex = 0; nIndex < oTemp.dictGetLength(); ++nIndex)
{
Object oRes;
char* chKey2 = oTemp.dictGetKey(nIndex);
if (strcmp("Font", chKey2) == 0 || strcmp("ExtGState", chKey2) == 0 || strcmp("XObject", chKey2) == 0 || strcmp("Shading", chKey2) == 0 || strcmp("Pattern", chKey2) == 0)
oTemp.dictGetVal(nIndex, &oRes);
else
oTemp.dictGetValNF(nIndex, &oRes);
DictToCDictObject(&oRes, pDict, chKey2);
oRes.free();
}
oTemp.free();
continue;
}
else
{
oTemp.free();
pagesObj.dictGetValNF(nIndex, &oTemp);
}
}
else if (strcmp("Parent", chKey) == 0 && pPageParent)
{
pPageT->Add("Parent", pPageParent);
continue;
}
else
pagesObj.dictGetValNF(nIndex, &oTemp);
DictToCDictObject(&oTemp, pPageT, chKey);
oTemp.free();
}
pDoc->CreatePageTree(pXref, pPageT);
pPageT->Fix();
Object kidsArrObj;
if (!pagesObj.dictLookup("Kids", &kidsArrObj)->isArray())
{
pagesObj.free();
kidsArrObj.free();
return;
}
pagesObj.free();
for (int i = 0, count = kidsArrObj.arrayGetLength(); i < count; ++i)
{
Object kidRefObj;
if (kidsArrObj.arrayGetNF(i, &kidRefObj))
GetPageTree(xref, &kidRefObj, pPageT);
kidRefObj.free();
}
kidsArrObj.free();
}
bool CPdfEditor::EditPage(int _nPageIndex, bool bSet, bool bActualPos)
{
if (m_nMode == Mode::Unknown && !IncrementalUpdates())
return false;
WriteRedact({});
m_arrRedact.clear();
PDFDoc* pPDFDocument = NULL;
PdfReader::CPdfFontList* pFontList = NULL;
int nStartRefID = 0;
PdfWriter::CDocument* pDoc = m_pWriter->GetDocument();
if (!pDoc)
return false;
PdfWriter::CPageTree* pPageTree = pDoc->GetPageTree();
PdfWriter::CPage* pEditPage = NULL;
pEditPage = bActualPos ? pDoc->GetPage(_nPageIndex) : pDoc->GetEditPage(_nPageIndex);
if (m_nMode == Mode::Split && !pEditPage)
return false;
if (pEditPage)
{
if (bSet)
{
pDoc->SetCurPage(pEditPage);
m_pWriter->EditPage(pEditPage);
m_nEditPage = _nPageIndex;
}
return true;
}
int nOriginIndex = _nPageIndex;
if (m_nMode == Mode::WriteNew)
{
PdfWriter::CObjectBase* pObj = pPageTree->GetObj(_nPageIndex);
PdfWriter::CFakePage* pFakePage = NULL;
if (pObj)
pFakePage = dynamic_cast<PdfWriter::CFakePage*>(pObj);
if (pFakePage)
nOriginIndex = pFakePage->GetOriginIndex();
}
int nPageIndex = m_pReader->GetPageIndex(nOriginIndex, &pPDFDocument, &pFontList, &nStartRefID);
if (nPageIndex < 0 || !pPDFDocument)
return NULL;
if (m_nMode == Mode::WriteNew)
{
PdfWriter::CPage* pPage = new PdfWriter::CPage(pDoc);
pDoc->AddObject(pPage);
pPageTree->ReplacePage(_nPageIndex, pPage);
pDoc->AddEditPage(pPage, _nPageIndex);
// Получение объекта страницы
Catalog* pCatalog = pPDFDocument->getCatalog();
XRef* xref = pPDFDocument->getXRef();
Ref* pPageRef = pCatalog->getPageRef(nPageIndex);
Object pageRefObj, pageObj;
pageRefObj.initRef(pPageRef->num, pPageRef->gen);
if (!pageRefObj.fetch(xref, &pageObj)->isDict())
{
pageObj.free(); pageRefObj.free();
return false;
}
m_mObjManager.AddObj(pPageRef->num + nStartRefID, pPage);
pageRefObj.free();
bool bResources = false, bMediaBox = false, bCropBox = false, bRotate = false;
for (int nIndex = 0; nIndex < pageObj.dictGetLength(); ++nIndex)
{
Object oTemp;
char* chKey = pageObj.dictGetKey(nIndex);
if (strcmp("Resources", chKey) == 0)
{
bResources = true;
Ref oResourcesRef = { -1, -1 };
if (pageObj.dictGetValNF(nIndex, &oTemp)->isRef())
oResourcesRef = oTemp.getRef();
oTemp.free();
PdfWriter::CObjectBase* pObj = oResourcesRef.num > 0 ? m_mObjManager.GetObj(oResourcesRef.num + nStartRefID) : NULL;
if (pObj)
{
pPage->Add(chKey, pObj);
m_mObjManager.IncRefCount(oResourcesRef.num + nStartRefID);
continue;
}
if (pageObj.dictGetVal(nIndex, &oTemp)->isDict())
{
PdfWriter::CResourcesDict* pDict = pDoc->CreateResourcesDict(oResourcesRef.num < 0, false);
if (oResourcesRef.num > 0)
m_mObjManager.AddObj(oResourcesRef.num + nStartRefID, pDict);
pPage->Add(chKey, pDict);
for (int nIndex = 0; nIndex < oTemp.dictGetLength(); ++nIndex)
{
Object oRes;
char* chKey2 = oTemp.dictGetKey(nIndex);
oTemp.dictGetValNF(nIndex, &oRes);
PdfWriter::CObjectBase* pBase = DictToCDictObject2(&oRes, pDoc, xref, &m_mObjManager, nStartRefID);
pDict->Add(chKey2, pBase);
oRes.free();
}
oTemp.free();
continue;
}
else
{
oTemp.free();
pageObj.dictGetValNF(nIndex, &oTemp);
}
}
else if (strcmp("Parent", chKey) == 0)
{
// Поля родителей страниц переносятся к самим страницам
oTemp.free();
continue;
}
else if (strcmp("MediaBox", chKey) == 0)
{
bMediaBox = true;
pageObj.dictGetValNF(nIndex, &oTemp);
}
else if (strcmp("CropBox", chKey) == 0)
{
bCropBox = true;
pageObj.dictGetValNF(nIndex, &oTemp);
}
else if (strcmp("Rotate", chKey) == 0)
{
bRotate = true;
pageObj.dictGetValNF(nIndex, &oTemp);
}
else if (strcmp("Contents", chKey) == 0)
{
pageObj.dictGetValNF(nIndex, &oTemp);
PdfWriter::CObjectBase* pBase = DictToCDictObject2(&oTemp, pDoc, xref, &m_mObjManager, nStartRefID, 0, false);
pPage->Add(chKey, pBase);
continue;
}
else
pageObj.dictGetValNF(nIndex, &oTemp);
PdfWriter::CObjectBase* pBase = DictToCDictObject2(&oTemp, pDoc, xref, &m_mObjManager, nStartRefID);
pPage->Add(chKey, pBase);
oTemp.free();
}
if (!bResources || !bMediaBox || !bCropBox || !bRotate)
{
Page* pOPage = pCatalog->getPage(nPageIndex);
if (!bMediaBox)
{
PDFRectangle* pRect = pOPage->getMediaBox();
pPage->Add("MediaBox", PdfWriter::CArrayObject::CreateBox(pRect->x1, pRect->y1, pRect->x2, pRect->y2));
}
if (!bCropBox && pOPage->isCropped())
{
PDFRectangle* pRect = pOPage->getCropBox();
pPage->Add("CropBox", PdfWriter::CArrayObject::CreateBox(pRect->x1, pRect->y1, pRect->x2, pRect->y2));
}
if (!bRotate)
pPage->Add("Rotate", pOPage->getRotate());
if (!bResources)
{
Dict* pResources = pOPage->getResourceDict();
PdfWriter::CResourcesDict* pDict = pDoc->CreateResourcesDict(true, false);
pPage->Add("Resources", pDict);
for (int nIndex = 0; nIndex < pResources->getLength(); ++nIndex)
{
Object oRes;
char* chKey2 = pResources->getKey(nIndex);
pResources->getValNF(nIndex, &oRes);
PdfWriter::CObjectBase* pBase = DictToCDictObject2(&oRes, pDoc, xref, &m_mObjManager, nStartRefID);
pDict->Add(chKey2, pBase);
oRes.free();
}
}
}
pPage->Fix();
pDoc->FixEditPage(pPage);
double dCTM[6] = { 1, 0, 0, 1, 0, 0 };
GetCTM(xref, &pageObj, dCTM);
pageObj.free();
if (bSet)
{
pDoc->SetCurPage(pPage);
m_pWriter->EditPage(pPage);
m_nEditPage = _nPageIndex;
if (bCropBox)
{
Page* pOPage = pCatalog->getPage(nPageIndex);
if (pOPage->isCropped())
{
PDFRectangle* pCropBox = pOPage->getCropBox();
PdfWriter::CStream* pStream = pPage->GetStream();
pStream->WriteStr("1 0 0 1 ");
pStream->WriteReal(pCropBox->x1);
pStream->WriteChar(' ');
pStream->WriteReal(pCropBox->y2 - pOPage->getMediaBox()->y2);
pStream->WriteStr(" cm\012");
}
}
pPage->StartTransform(dCTM[0], dCTM[1], dCTM[2], dCTM[3], dCTM[4], dCTM[5]);
pPage->SetStrokeColor(0, 0, 0);
pPage->SetFillColor(0, 0, 0);
pPage->SetExtGrState(pDoc->GetExtGState(255, 255));
pPage->BeginText();
pPage->SetCharSpace(0);
pPage->SetTextRenderingMode(PdfWriter::textrenderingmode_Fill);
pPage->SetHorizontalScaling(100);
pPage->EndText();
}
return true;
}
XRef* xref = pPDFDocument->getXRef();
Catalog* pCatalog = pPDFDocument->getCatalog();
if (!xref || !pCatalog)
return false;
std::pair<int, int> pPageRef = std::make_pair(0, 0);
if (bActualPos)
pPageRef = pDoc->GetPageRef(_nPageIndex);
else
{
Ref* pRef = pPDFDocument->getCatalog()->getPageRef(nPageIndex);
if (pRef && pRef->num != 0)
pPageRef = std::make_pair(pRef->num, pRef->gen);
}
if (pPageRef.first == 0)
return false;
// Получение объекта страницы
Object pageRefObj, pageObj;
pageRefObj.initRef(pPageRef.first, pPageRef.second);
if (!pageRefObj.fetch(xref, &pageObj) || !pageObj.isDict())
{
pageObj.free();
pageRefObj.free();
return false;
}
pageRefObj.free();
// Воспроизведение словаря страницы из reader для writer
PdfWriter::CXref* pXref = new PdfWriter::CXref(pDoc, pPageRef.first);
if (!pXref)
{
pageObj.free();
return false;
}
PdfWriter::CPage* pPage = new PdfWriter::CPage(pDoc);
if (!pPage)
{
pageObj.free();
RELEASEOBJECT(pXref);
return false;
}
pXref->Add(pPage, pPageRef.second);
bool bResources = false, bMediaBox = false, bCropBox = false, bRotate = false;
for (int nIndex = 0; nIndex < pageObj.dictGetLength(); ++nIndex)
{
Object oTemp;
char* chKey = pageObj.dictGetKey(nIndex);
if (strcmp("Resources", chKey) == 0)
{
bResources = true;
if (pageObj.dictGetVal(nIndex, &oTemp)->isDict())
{
PdfWriter::CResourcesDict* pDict = new PdfWriter::CResourcesDict(NULL, true, false);
pPage->Add("Resources", pDict);
for (int nIndex = 0; nIndex < oTemp.dictGetLength(); ++nIndex)
{
Object oRes;
char* chKey2 = oTemp.dictGetKey(nIndex);
if (strcmp("Font", chKey2) == 0 || strcmp("ExtGState", chKey2) == 0 || strcmp("XObject", chKey2) == 0 || strcmp("Shading", chKey2) == 0 || strcmp("Pattern", chKey2) == 0)
oTemp.dictGetVal(nIndex, &oRes);
else
oTemp.dictGetValNF(nIndex, &oRes);
DictToCDictObject(&oRes, pDict, chKey2);
oRes.free();
}
oTemp.free();
continue;
}
else
{
oTemp.free();
pageObj.dictGetValNF(nIndex, &oTemp);
}
}
else if (strcmp("Annots", chKey) == 0)
{
if (pageObj.dictGetVal(nIndex, &oTemp)->isArray())
{
PdfWriter::CArrayObject* pArray = new PdfWriter::CArrayObject();
pPage->Add("Annots", pArray);
for (int nIndex = 0; nIndex < oTemp.arrayGetLength(); ++nIndex)
{
Object oAnnot;
oTemp.arrayGetNF(nIndex, &oAnnot);
DictToCDictObject(&oAnnot, pArray, "");
oAnnot.free();
}
oTemp.free();
continue;
}
else
{
oTemp.free();
pageObj.dictGetValNF(nIndex, &oTemp);
}
}
else if (strcmp("Contents", chKey) == 0)
{
if (pageObj.dictGetVal(nIndex, &oTemp)->isArray())
{
DictToCDictObject(&oTemp, pPage, chKey);
oTemp.free();
continue;
}
else
{
oTemp.free();
pageObj.dictGetValNF(nIndex, &oTemp);
}
}
else if (strcmp("Parent", chKey) == 0)
{
pageObj.dictGetValNF(nIndex, &oTemp);
}
else if (strcmp("MediaBox", chKey) == 0)
{
bMediaBox = true;
pageObj.dictGetValNF(nIndex, &oTemp);
}
else if (strcmp("CropBox", chKey) == 0)
{
bCropBox = true;
pageObj.dictGetValNF(nIndex, &oTemp);
}
else if (strcmp("Rotate", chKey) == 0)
{
bRotate = true;
pageObj.dictGetValNF(nIndex, &oTemp);
}
else
pageObj.dictGetValNF(nIndex, &oTemp);
DictToCDictObject(&oTemp, pPage, chKey);
oTemp.free();
}
if (!bResources || !bMediaBox || !bCropBox || !bRotate)
{
Page* pOPage = pCatalog->getPage(nPageIndex);
if (!bMediaBox)
{
PDFRectangle* pRect = pOPage->getMediaBox();
pPage->Add("MediaBox", PdfWriter::CArrayObject::CreateBox(pRect->x1, pRect->y1, pRect->x2, pRect->y2));
}
if (!bCropBox && pOPage->isCropped())
{
PDFRectangle* pRect = pOPage->getCropBox();
pPage->Add("CropBox", PdfWriter::CArrayObject::CreateBox(pRect->x1, pRect->y1, pRect->x2, pRect->y2));
}
if (!bRotate)
pPage->Add("Rotate", pOPage->getRotate());
if (!bResources)
{
Dict* pResources = pOPage->getResourceDict();
PdfWriter::CResourcesDict* pDict = pDoc->CreateResourcesDict(true, false);
pPage->Add("Resources", pDict);
for (int nIndex = 0; nIndex < pResources->getLength(); ++nIndex)
{
Object oRes;
char* chKey2 = pResources->getKey(nIndex);
if (strcmp("Font", chKey2) == 0 || strcmp("ExtGState", chKey2) == 0 || strcmp("XObject", chKey2) == 0 || strcmp("Shading", chKey2) == 0 || strcmp("Pattern", chKey2) == 0)
pResources->getVal(nIndex, &oRes);
else
pResources->getValNF(nIndex, &oRes);
DictToCDictObject(&oRes, pDict, chKey2);
}
}
}
pPage->Fix();
double dCTM[6] = { 1, 0, 0, 1, 0, 0 };
GetCTM(xref, &pageObj, dCTM);
pageObj.free();
// Применение редактирования страницы для writer
if (pDoc->EditPage(pXref, pPage, _nPageIndex))
{
if (bSet)
{
m_pWriter->EditPage(pPage);
m_nEditPage = _nPageIndex;
}
if (bCropBox)
{
Page* pOPage = pCatalog->getPage(nPageIndex);
if (pOPage->isCropped())
{
PDFRectangle* pCropBox = pOPage->getCropBox();
PdfWriter::CStream* pStream = pPage->GetStream();
pStream->WriteStr("1 0 0 1 ");
pStream->WriteReal(pCropBox->x1);
pStream->WriteChar(' ');
pStream->WriteReal(pCropBox->y2 - pOPage->getMediaBox()->y2);
pStream->WriteStr(" cm\012");
}
}
pPage->StartTransform(dCTM[0], dCTM[1], dCTM[2], dCTM[3], dCTM[4], dCTM[5]);
pPage->SetStrokeColor(0, 0, 0);
pPage->SetFillColor(0, 0, 0);
pPage->SetExtGrState(pDoc->GetExtGState(255, 255));
pPage->BeginText();
pPage->SetCharSpace(0);
pPage->SetTextRenderingMode(PdfWriter::textrenderingmode_Fill);
pPage->SetHorizontalScaling(100);
pPage->EndText();
return true;
}
RELEASEOBJECT(pXref);
return false;
}
bool CPdfEditor::SplitPages(const int* arrPageIndex, unsigned int unLength, PDFDoc* _pDoc, int nStartRefID)
{
if (m_nMode == Mode::Unknown)
return false;
PDFDoc* pPDFDocument = _pDoc;
XRef* xref = pPDFDocument->getXRef();
PdfWriter::CDocument* pDoc = m_pWriter->GetDocument();
PdfWriter::CPageTree* pPageTree = pDoc->GetPageTree();
int nPagesBefore = m_pReader->GetNumPagesBefore(pPDFDocument);
if (unLength == 0)
unLength = pPDFDocument->getNumPages();
// Страницы должны быть созданы заранее для ссылки на них
Catalog* pCatalog = pPDFDocument->getCatalog();
for (unsigned int i = 0; i < unLength; ++i)
{
Ref* pPageRef = pCatalog->getPageRef((arrPageIndex ? arrPageIndex[i] : i) + 1);
if (pPageRef->num == 0)
return false;
PdfWriter::CPage* pPage = new PdfWriter::CPage(pDoc);
pDoc->AddObject(pPage);
if (m_nMode == Mode::WriteAppend || m_nMode == Mode::WriteNew)
pDoc->AddPage(pDoc->GetPagesCount(), pPage);
else
pPageTree->ReplacePage(nPagesBefore + (arrPageIndex ? arrPageIndex[i] : i), pPage);
pDoc->AddEditPage(pPage, nPagesBefore + (arrPageIndex ? arrPageIndex[i] : i));
// Получение объекта страницы
Object pageRefObj, pageObj;
pageRefObj.initRef(pPageRef->num, pPageRef->gen);
if (!pageRefObj.fetch(xref, &pageObj)->isDict())
{
pageObj.free(); pageRefObj.free();
return false;
}
m_mObjManager.AddObj(pPageRef->num + nStartRefID, pPage);
pageObj.free(); pageRefObj.free();
}
for (unsigned int i = 0; i < unLength; ++i)
{
Ref* pPageRef = pCatalog->getPageRef((arrPageIndex ? arrPageIndex[i] : i) + 1);
if (pPageRef->num == 0)
return false;
// Получение объекта страницы
PdfWriter::CPage* pPage = (PdfWriter::CPage*)m_mObjManager.GetObj(pPageRef->num + nStartRefID);
Object pageRefObj, pageObj;
pageRefObj.initRef(pPageRef->num, pPageRef->gen);
if (!pageRefObj.fetch(xref, &pageObj)->isDict())
{
pageObj.free();
pageRefObj.free();
return false;
}
pageRefObj.free();
bool bResources = false, bMediaBox = false, bCropBox = false, bRotate = false;
// Копирование страницы со всеми ресурсами из reader для writer
for (int nIndex = 0; nIndex < pageObj.dictGetLength(); ++nIndex)
{
Object oTemp;
char* chKey = pageObj.dictGetKey(nIndex);
if (strcmp("Resources", chKey) == 0)
{
bResources = true;
Ref oResourcesRef = { -1, -1 };
if (pageObj.dictGetValNF(nIndex, &oTemp)->isRef())
oResourcesRef = oTemp.getRef();
oTemp.free();
PdfWriter::CObjectBase* pObj = oResourcesRef.num > 0 ? m_mObjManager.GetObj(oResourcesRef.num + nStartRefID) : NULL;
if (pObj)
{
pPage->Add(chKey, pObj);
m_mObjManager.IncRefCount(oResourcesRef.num + nStartRefID);
continue;
}
if (pageObj.dictGetVal(nIndex, &oTemp)->isDict())
{
PdfWriter::CResourcesDict* pDict = pDoc->CreateResourcesDict(oResourcesRef.num < 0, false);
if (oResourcesRef.num > 0)
m_mObjManager.AddObj(oResourcesRef.num + nStartRefID, pDict);
pPage->Add(chKey, pDict);
for (int nIndex = 0; nIndex < oTemp.dictGetLength(); ++nIndex)
{
Object oRes;
char* chKey2 = oTemp.dictGetKey(nIndex);
oTemp.dictGetValNF(nIndex, &oRes);
PdfWriter::CObjectBase* pBase = DictToCDictObject2(&oRes, pDoc, xref, &m_mObjManager, nStartRefID);
pDict->Add(chKey2, pBase);
oRes.free();
}
oTemp.free();
continue;
}
else
{
oTemp.free();
pageObj.dictGetValNF(nIndex, &oTemp);
}
}
else if (strcmp("Parent", chKey) == 0)
{
oTemp.free();
continue;
}
else if (strcmp("MediaBox", chKey) == 0)
{
bMediaBox = true;
pageObj.dictGetValNF(nIndex, &oTemp);
}
else if (strcmp("CropBox", chKey) == 0)
{
bCropBox = true;
pageObj.dictGetValNF(nIndex, &oTemp);
}
else if (strcmp("Rotate", chKey) == 0)
{
bRotate = true;
pageObj.dictGetValNF(nIndex, &oTemp);
}
else
pageObj.dictGetValNF(nIndex, &oTemp);
PdfWriter::CObjectBase* pBase = DictToCDictObject2(&oTemp, pDoc, xref, &m_mObjManager, nStartRefID);
pPage->Add(chKey, pBase);
if (strcmp("Contents", chKey) == 0)
{
if (pBase->GetType() == PdfWriter::object_type_ARRAY)
{
PdfWriter::CArrayObject* pArr = (PdfWriter::CArrayObject*)pBase;
for (int j = 0; j < pArr->GetCount(); ++j)
{
pBase = pArr->Get(j);
if (pBase->GetType() == PdfWriter::object_type_DICT)
{
PdfWriter::CDictObject* pDict = (PdfWriter::CDictObject*)pBase;
if (pDict->Get("Filter"))
pDict->SetFilter(STREAM_FILTER_ALREADY_DECODE);
}
}
}
else if (pBase->GetType() == PdfWriter::object_type_DICT)
{
PdfWriter::CDictObject* pDict = (PdfWriter::CDictObject*)pBase;
if (pDict->Get("Filter"))
pDict->SetFilter(STREAM_FILTER_ALREADY_DECODE);
}
}
oTemp.free();
}
if (!bResources || !bMediaBox || !bCropBox || !bRotate)
{
Page* pOPage = pCatalog->getPage((arrPageIndex ? arrPageIndex[i] : i) + 1);
if (!bMediaBox)
{
PDFRectangle* pRect = pOPage->getMediaBox();
pPage->Add("MediaBox", PdfWriter::CArrayObject::CreateBox(pRect->x1, pRect->y1, pRect->x2, pRect->y2));
}
if (!bCropBox && pOPage->isCropped())
{
PDFRectangle* pRect = pOPage->getCropBox();
pPage->Add("CropBox", PdfWriter::CArrayObject::CreateBox(pRect->x1, pRect->y1, pRect->x2, pRect->y2));
}
if (!bRotate)
pPage->Add("Rotate", pOPage->getRotate());
if (!bResources)
{
Dict* pResources = pOPage->getResourceDict();
PdfWriter::CResourcesDict* pDict = pDoc->CreateResourcesDict(true, false);
pPage->Add("Resources", pDict);
for (int nIndex = 0; nIndex < pResources->getLength(); ++nIndex)
{
Object oRes;
char* chKey2 = pResources->getKey(nIndex);
pResources->getValNF(nIndex, &oRes);
PdfWriter::CObjectBase* pBase = DictToCDictObject2(&oRes, pDoc, xref, &m_mObjManager, nStartRefID);
pDict->Add(chKey2, pBase);
oRes.free();
}
}
}
pPage->Fix();
if (m_nMode == Mode::WriteAppend || m_nMode == Mode::WriteNew)
{
pDoc->FixEditPage(pPage);
double dCTM[6] = { 1, 0, 0, 1, 0, 0 };
GetCTM(xref, &pageObj, dCTM);
pPage->StartTransform(dCTM[0], dCTM[1], dCTM[2], dCTM[3], dCTM[4], dCTM[5]);
pPage->SetStrokeColor(0, 0, 0);
pPage->SetFillColor(0, 0, 0);
pPage->SetExtGrState(pDoc->GetExtGState(255, 255));
pPage->BeginText();
pPage->SetCharSpace(0);
pPage->SetTextRenderingMode(PdfWriter::textrenderingmode_Fill);
pPage->SetHorizontalScaling(100);
pPage->EndText();
}
else
m_pWriter->SetNeedAddHelvetica(false); // TODO дописывает шрифт для адекватного редактирования Adobe pdf без текст. Убрать при реализации map шрифтов
pageObj.free();
}
Object oCatalog;
if (!xref->getCatalog(&oCatalog)->isDict())
{
oCatalog.free();
return false;
}
Object oAcroForm;
if (oCatalog.dictLookupNF("AcroForm", &oAcroForm)->isRef() || oAcroForm.isDict())
{
PdfWriter::CDictObject* pAcroForm = pDoc->GetAcroForm();
if (!pAcroForm)
{
pAcroForm = new PdfWriter::CDictObject();
if (oAcroForm.isRef())
pDoc->AddObject(pAcroForm);
pDoc->SetAcroForm(pAcroForm);
}
else
pAcroForm->Remove("NeedAppearances");
if (oAcroForm.isRef())
{
oAcroForm.free();
if (!oCatalog.dictLookup("AcroForm", &oAcroForm)->isDict())
{
oAcroForm.free(); oCatalog.free();
return false;
}
}
for (int nIndex = 0; nIndex < oAcroForm.dictGetLength(); ++nIndex)
{
Object oTemp;
char* chKey = oAcroForm.dictGetKey(nIndex);
if (strcmp("Fields", chKey) == 0)
{
Ref oFieldsRef = { -1, -1 };
if (oAcroForm.dictGetValNF(nIndex, &oTemp)->isRef())
oFieldsRef = oTemp.getRef();
oTemp.free();
PdfWriter::CArrayObject* pFields = dynamic_cast<PdfWriter::CArrayObject*>(pAcroForm->Get("Fields"));
if (!pFields)
{
PdfWriter::CObjectBase* pObj = oFieldsRef.num > 0 ? m_mObjManager.GetObj(oFieldsRef.num + nStartRefID) : NULL;
if (pObj)
{
pAcroForm->Add(chKey, pObj);
m_mObjManager.IncRefCount(oFieldsRef.num + nStartRefID);
continue;
}
}
if (oAcroForm.dictGetVal(nIndex, &oTemp)->isArray())
{
if (!pFields)
{
pFields = new PdfWriter::CArrayObject();
if (oFieldsRef.num > 0)
{
pDoc->AddObject(pFields);
m_mObjManager.AddObj(oFieldsRef.num + nStartRefID, pFields);
}
pAcroForm->Add(chKey, pFields);
}
for (int nIndex = 0; nIndex < oTemp.arrayGetLength(); ++nIndex)
{
Object oRes;
PdfWriter::CObjectBase* pObj = NULL;
if (oTemp.arrayGetNF(nIndex, &oRes)->isRef())
pObj = m_mObjManager.GetObj(oRes.getRefNum() + nStartRefID);
if (pObj)
{
pFields->Add(pObj);
m_mObjManager.IncRefCount(oRes.getRefNum() + nStartRefID);
AddWidgetParent(pDoc, &m_mObjManager, pObj);
oRes.free();
continue;
}
oRes.free();
}
oTemp.free();
continue;
}
else if (!pFields)
{
oTemp.free();
oAcroForm.dictGetValNF(nIndex, &oTemp);
}
else
{
oTemp.free();
continue;
}
}
else if (strcmp("SigFlags", chKey) == 0 || strcmp("XFA", chKey) == 0 || (strcmp("DA", chKey) == 0 && pAcroForm->Get("DA")) || strcmp("NeedAppearances", chKey) == 0)
{ // Нельзя гарантировать их выполнение
oTemp.free();
continue;
}
else if (strcmp("DR", chKey) == 0)
{ // Добавляем только уникальные ключи
PdfWriter::CDictObject* pDR = dynamic_cast<PdfWriter::CDictObject*>(pAcroForm->Get("DR"));
if (!pDR)
{
pDR = new PdfWriter::CDictObject();
pDoc->AddObject(pDR);
pAcroForm->Add(chKey, pDR);
}
PdfWriter::CArrayObject* pProcset = new PdfWriter::CArrayObject();
pDR->Add("ProcSet", pProcset);
pProcset->Add(new PdfWriter::CNameObject("PDF"));
pProcset->Add(new PdfWriter::CNameObject("Text"));
pProcset->Add(new PdfWriter::CNameObject("ImageB"));
pProcset->Add(new PdfWriter::CNameObject("ImageC"));
pProcset->Add(new PdfWriter::CNameObject("ImageI"));
if (oAcroForm.dictGetVal(nIndex, &oTemp)->isDict())
{
Object oTemp2;
for (int nIndex2 = 0; nIndex2 < oTemp.dictGetLength(); ++nIndex2)
{
char* chKey2 = oTemp.dictGetKey(nIndex2);
if (strcmp("ProcSet", chKey2) == 0 || !oTemp.dictGetVal(nIndex2, &oTemp2)->isDict())
{
oTemp2.free();
continue;
}
PdfWriter::CDictObject* pDict = dynamic_cast<PdfWriter::CDictObject*>(pDR->Get(chKey2));
if (!pDict)
{
Object oTempRef;
if (oTemp.dictGetValNF(nIndex2, &oTempRef)->isRef())
{
PdfWriter::CObjectBase* pObj = m_mObjManager.GetObj(oTempRef.getRefNum() + nStartRefID);
if (pObj)
{
pDR->Add(chKey2, pObj);
m_mObjManager.IncRefCount(oTempRef.getRefNum() + nStartRefID);
oTemp2.free(); oTempRef.free();
continue;
}
}
PdfWriter::CObjectBase* pBase = DictToCDictObject2(&oTemp2, pDoc, xref, &m_mObjManager, nStartRefID);
if (oTempRef.isRef())
pDoc->AddObject(pBase);
pDR->Add(chKey2, pBase);
oTemp2.free(); oTempRef.free();
continue;
}
else
{
for (int nIndex3 = 0; nIndex3 < oTemp2.dictGetLength(); ++nIndex3)
{
char* chKey3 = oTemp2.dictGetKey(nIndex3);
if (pDict->Get(chKey3))
continue;
Object oTempRef;
if (oTemp2.dictGetValNF(nIndex3, &oTempRef)->isRef())
{
PdfWriter::CObjectBase* pObj = m_mObjManager.GetObj(oTempRef.getRefNum() + nStartRefID);
if (pObj)
{
pDict->Add(chKey3, pObj);
m_mObjManager.IncRefCount(oTempRef.getRefNum() + nStartRefID);
oTemp2.free(); oTempRef.free();
continue;
}
}
PdfWriter::CObjectBase* pBase = DictToCDictObject2(&oTemp2, pDoc, xref, &m_mObjManager, nStartRefID);
if (oTempRef.isRef())
pDoc->AddObject(pBase);
pDict->Add(chKey3, pBase);
oTemp2.free(); oTempRef.free();
continue;
}
}
}
oTemp2.free(); oTemp.free();
continue;
}
else
{
oTemp.free();
oAcroForm.dictGetValNF(nIndex, &oTemp);
}
}
else
oAcroForm.dictGetValNF(nIndex, &oTemp);
PdfWriter::CObjectBase* pBase = DictToCDictObject2(&oTemp, pDoc, xref, &m_mObjManager, nStartRefID);
pAcroForm->Add(chKey, pBase);
oTemp.free();
}
}
oAcroForm.free(); oCatalog.free();
// Переименование полей
std::string sPrefix = m_pReader->GetPrefixForm(pPDFDocument);
if (!sPrefix.empty())
{
sPrefix = "_" + sPrefix;
std::vector<int> arrRename; // Вектор переименованных полей
std::map<int, PdfWriter::CAnnotation*> mAnnots = m_pWriter->GetDocument()->GetAnnots();
for (auto it = mAnnots.begin(); it != mAnnots.end(); it++)
{
PdfWriter::CAnnotation* pAnnot = it->second;
if (pAnnot->GetAnnotationType() != PdfWriter::AnnotWidget || it->first < nStartRefID)
continue;
std::vector<int>::iterator it2 = std::find(arrRename.begin(), arrRename.end(), it->first);
if (it2 != arrRename.end())
continue;
PdfWriter::CObjectBase* pObjBase = pAnnot->Get("Parent");
if (!pObjBase || !ChangeFullNameParent(m_mObjManager.FindObj(pObjBase), sPrefix, arrRename))
{
pObjBase = pAnnot->Get("T");
if (pObjBase && pObjBase->GetType() == PdfWriter::object_type_STRING)
{
PdfWriter::CStringObject* pStr = (PdfWriter::CStringObject*)pObjBase;
pStr->Add(sPrefix.c_str());
}
else if (pObjBase && pObjBase->GetType() == PdfWriter::object_type_BINARY)
{
PdfWriter::CBinaryObject* pBin = (PdfWriter::CBinaryObject*)pObjBase;
pBin->Add((BYTE*)sPrefix.c_str(), sPrefix.length());
}
}
arrRename.push_back(it->first);
}
}
return true;
}
bool CPdfEditor::SplitPages(const int* arrPageIndex, unsigned int unLength)
{
if (m_nMode != Mode::Split)
return false;
PdfWriter::CDocument* pDoc = m_pWriter->GetDocument();
if (!pDoc)
return false;
PdfWriter::CPageTree* pPageTree = pDoc->GetPageTree();
if (!pPageTree)
return false;
m_mObjManager.SetDoc(pDoc);
int nPages = m_pReader->GetNumPages();
pPageTree->CreateFakePages(nPages);
int nTotalPages = 0;
int nPDFIndex = 0;
std::map<int, std::vector<int>> mFileToPages;
PDFDoc* pPDFDocument = m_pReader->GetPDFDocument(nPDFIndex);
nPages = pPDFDocument->getNumPages();
for (unsigned int i = 0; i < unLength; ++i)
{
if (arrPageIndex[i] < nTotalPages + nPages)
mFileToPages[nPDFIndex].push_back(arrPageIndex[i] - nTotalPages);
else
{
pPDFDocument = m_pReader->GetPDFDocument(++nPDFIndex);
if (!pPDFDocument)
{
m_mObjManager.m_arrSplitAddPages.push_back(arrPageIndex[i]);
--nPDFIndex;
continue;
}
nTotalPages += nPages;
nPages = pPDFDocument->getNumPages();
--i;
}
}
for (const std::pair<const int, std::vector<int>>& it : mFileToPages)
{
pPDFDocument = m_pReader->GetPDFDocument(it.first);
if (!SplitPages(it.second.data(), it.second.size(), pPDFDocument, m_pReader->GetStartRefID(pPDFDocument)))
return false;
}
return true;
}
void CPdfEditor::AfterSplitPages()
{
PdfWriter::CDocument* pDoc = m_pWriter->GetDocument();
if (!pDoc)
return;
PdfWriter::CPageTree* pPageTree = pDoc->GetPageTree();
if (!pPageTree)
return;
pPageTree->ClearFakePages();
}
void CreateOutlines(PDFDoc* pdfDoc, PdfWriter::CDocument* pDoc, OutlineItem* pOutlineItem, PdfWriter::COutline* pParent)
{
std::string sTitle = NSStringExt::CConverter::GetUtf8FromUTF32(pOutlineItem->getTitle(), pOutlineItem->getTitleLength());
PdfWriter::COutline* pOutline = pDoc->CreateOutline(pParent, sTitle.c_str());
PdfWriter::CDestination* pDest = NULL;
LinkAction* pLinkAction = pOutlineItem->getAction();
if (pLinkAction && pLinkAction->getKind() == actionGoTo)
{
GString* str = ((LinkGoTo*)pLinkAction)->getNamedDest();
LinkDest* pLinkDest = str ? pdfDoc->findDest(str) : ((LinkGoTo*)pLinkAction)->getDest();
if (pLinkDest)
{
int pg;
if (pLinkDest->isPageRef())
{
Ref pageRef = pLinkDest->getPageRef();
pg = pdfDoc->findPage(pageRef.num, pageRef.gen);
}
else
pg = pLinkDest->getPageNum();
if (pg == 0)
pg = 1;
Ref* pPageRef = pdfDoc->getCatalog()->getPageRef(pg);
PdfWriter::CObjectBase* pPageD = pDoc->GetEditPage(--pg);
if (!pPageD && pPageRef->num > 0)
{
PdfWriter::CObjectBase* pBase = new PdfWriter::CObjectBase();
pBase->SetRef(pPageRef->num, pPageRef->gen);
pPageD = new PdfWriter::CProxyObject(pBase, true);
}
pDest = pDoc->CreateDestination(pPageD, true);
switch (pLinkDest->getKind())
{
case destXYZ:
{
pDest->SetXYZ(pLinkDest->getLeft(), pLinkDest->getTop(), pLinkDest->getZoom());
break;
}
case destFit:
{
pDest->SetFit();
break;
}
case destFitH:
{
pDest->SetFitH(pLinkDest->getTop());
break;
}
case destFitV:
{
pDest->SetFitV(pLinkDest->getLeft());
break;
}
case destFitR:
{
pDest->SetFitR(pLinkDest->getLeft(), pLinkDest->getBottom(), pLinkDest->getRight(), pLinkDest->getTop());
break;
}
case destFitB:
{
pDest->SetFitB();
break;
}
case destFitBH:
{
pDest->SetFitBH(pLinkDest->getTop());
break;
}
case destFitBV:
{
pDest->SetFitBV(pLinkDest->getLeft());
break;
}
}
}
if (str)
RELEASEOBJECT(pLinkDest);
}
if (pDest)
pOutline->SetDestination(pDest);
pOutlineItem->open();
GList* pList = pOutlineItem->getKids();
if (!pList)
{
pOutlineItem->close();
return;
}
for (int i = 0, num = pList->getLength(); i < num; i++)
{
OutlineItem* pOutlineItemKid = (OutlineItem*)pList->get(i);
if (pOutlineItemKid)
CreateOutlines(pdfDoc, pDoc, pOutlineItemKid, pOutline);
}
pOutlineItem->close();
}
bool CPdfEditor::ChangeFullNameParent(int nParent, const std::string& sPrefix, std::vector<int>& arrRename)
{
std::vector<int>::const_iterator it2 = std::find(arrRename.begin(), arrRename.end(), nParent);
if (it2 != arrRename.end())
return true;
PdfWriter::CObjectBase* pObjBase = m_mObjManager.GetObj(nParent);
if (!pObjBase || pObjBase->GetType() != PdfWriter::object_type_DICT)
return false;
PdfWriter::CDictObject* pDict = (PdfWriter::CDictObject*)pObjBase;
pObjBase = pDict->Get("Parent");
if (!pObjBase || !ChangeFullNameParent(m_mObjManager.FindObj(pObjBase), sPrefix, arrRename))
{
pObjBase = pDict->Get("T");
if (pObjBase && pObjBase->GetType() == PdfWriter::object_type_STRING)
{
PdfWriter::CStringObject* pStr = (PdfWriter::CStringObject*)pObjBase;
pStr->Add(sPrefix.c_str());
}
else if (pObjBase && pObjBase->GetType() == PdfWriter::object_type_BINARY)
{
PdfWriter::CBinaryObject* pBin = (PdfWriter::CBinaryObject*)pObjBase;
pBin->Add((BYTE*)sPrefix.c_str(), sPrefix.length());
}
}
arrRename.push_back(nParent);
return true;
}
bool CPdfEditor::MergePages(const std::wstring& wsPath)
{
if (m_nMode == Mode::Unknown && !IncrementalUpdates())
return false;
m_nOriginIndex = m_pReader->GetNumPages();
PDFDoc* pDocument = m_pReader->GetLastPDFDocument();
int nStartRefID = m_pReader->GetStartRefID(pDocument);
m_mObjManager.SetDoc(m_pWriter->GetDocument());
bool bRes = SplitPages(NULL, 0, pDocument, nStartRefID);
if (!bRes)
return false;
Outline* pOutlineAdd = pDocument->getOutline();
GList* pListAdd = NULL;
if (pOutlineAdd)
pListAdd = pOutlineAdd->getItems();
if (!pListAdd)
return bRes;
PdfWriter::CDocument* pDoc = m_pWriter->GetDocument();
PDFDoc* pDocumentFirst = m_pReader->GetPDFDocument(0);
Outline* pOutlineOld = pDocumentFirst->getOutline();
GList* pListOld = NULL;
if (pOutlineOld)
pListOld = pOutlineOld->getItems();
if (!pDoc->GetOutlines() && pListOld)
{
for (int i = 0, num = pListOld->getLength(); i < num; i++)
{
OutlineItem* pOutlineItem = (OutlineItem*)pListOld->get(i);
if (pOutlineItem)
CreateOutlines(pDocumentFirst, pDoc, pOutlineItem, NULL);
}
}
std::wstring wsFileName = NSFile::GetFileName(wsPath);
std::string sFileName = U_TO_UTF8(wsFileName);
PdfWriter::COutline* pOutline = pDoc->CreateOutline(NULL, sFileName.c_str());
for (int i = 0, num = pListAdd->getLength(); i < num; i++)
{
OutlineItem* pOutlineItem = (OutlineItem*)pListAdd->get(i);
if (pOutlineItem)
CreateOutlines(pDocumentFirst, pDoc, pOutlineItem, pOutline);
}
return bRes;
}
bool CPdfEditor::DeletePage(int nPageIndex)
{
if (m_nMode == Mode::Unknown && !IncrementalUpdates())
return false;
WriteRedact({});
m_arrRedact.clear();
PdfWriter::CDocument* pDoc = m_pWriter->GetDocument();
PdfWriter::CPage* pPage = pDoc->GetPage(nPageIndex);
int nObjID = m_mObjManager.FindObj(pPage);
bool bRes = pDoc->DeletePage(nPageIndex);
if (bRes && nObjID > 0)
{
m_mObjManager.RemoveObj(nObjID);
pDoc->RemoveObj(pPage);
}
return bRes;
}
bool CPdfEditor::AddPage(int nPageIndex)
{
if (m_nMode == Mode::Unknown && !IncrementalUpdates())
return false;
WriteRedact({});
m_arrRedact.clear();
if (m_nMode == Mode::Split)
{
std::vector<int>::iterator it = std::find(m_mObjManager.m_arrSplitAddPages.begin(), m_mObjManager.m_arrSplitAddPages.end(), m_nOriginIndex++);
if (it == m_mObjManager.m_arrSplitAddPages.end())
{
PdfWriter::CPageTree* pPageTree = m_pWriter->GetDocument()->GetPageTree();
pPageTree->CreateFakePages(1, nPageIndex);
return false;
}
m_mObjManager.m_arrSplitAddPages.erase(it);
}
// Mode WriteNew & WriteAppend
m_nEditPage = -1;
// Применение добавления страницы для writer
if (!m_pWriter->AddPage(nPageIndex))
return false;
// По умолчанию выставляются размеры первой страницы, в дальнейшем размеры можно изменить
double dPageDpiX, dPageDpiY;
double dWidth, dHeight;
m_pReader->GetPageInfo(0, &dWidth, &dHeight, &dPageDpiX, &dPageDpiY);
dWidth *= 25.4 / dPageDpiX;
dHeight *= 25.4 / dPageDpiY;
m_pWriter->put_Width(dWidth);
m_pWriter->put_Height(dHeight);
return true;
}
bool CPdfEditor::MovePage(int nPageIndex, int nPos)
{
WriteRedact({});
m_arrRedact.clear();
if (m_nMode == Mode::Split || m_nMode == Mode::WriteNew || EditPage(nPageIndex, true, true))
return m_pWriter->GetDocument()->MovePage(nPageIndex, nPos);
return false;
}
bool CPdfEditor::EditAnnot(int _nPageIndex, int nID)
{
PdfWriter::CObjectBase* pObj = m_mObjManager.GetObj(nID);
if (pObj)
return true;
PDFDoc* pPDFDocument = NULL;
PdfReader::CPdfFontList* pFontList = NULL;
int nStartRefID = 0;
int nPageIndex = m_pReader->GetPageIndex(_nPageIndex, &pPDFDocument, &pFontList, &nStartRefID);
PdfWriter::CDocument* pDoc = m_pWriter->GetDocument();
if (nPageIndex < 0 || !pPDFDocument || !pDoc)
return false;
if (pDoc->GetAnnot(nID))
return true;
if (m_nMode == Mode::Split || m_nMode == Mode::WriteNew)
return false;
XRef* xref = pPDFDocument->getXRef();
Ref* pPageRef = pPDFDocument->getCatalog()->getPageRef(nPageIndex);
if (!xref || !pPageRef || pPageRef->num == 0)
return false;
// Получение объекта аннотации
Object pageRefObj, pageObj, oAnnots;
pageRefObj.initRef(pPageRef->num, pPageRef->gen);
if (!pageRefObj.fetch(xref, &pageObj)->isDict() || !pageObj.dictLookup("Annots", &oAnnots)->isArray())
{
pageRefObj.free(); pageObj.free(); oAnnots.free();
return false;
}
pageRefObj.free(); pageObj.free();
Object oAnnotRef, oAnnot, oType;
for (int i = 0; i < oAnnots.arrayGetLength(); ++i)
{
if (oAnnots.arrayGetNF(i, &oAnnotRef)->isRef() && oAnnotRef.getRefNum() + nStartRefID == nID)
break;
oAnnotRef.free();
}
oAnnots.free();
if (!oAnnotRef.isRef() || !oAnnotRef.fetch(xref, &oAnnot)->isDict() || !oAnnot.dictLookup("Subtype", &oType)->isName())
{
oAnnotRef.free(); oAnnot.free(); oType.free();
return false;
}
if (!pDoc->GetEditPage(_nPageIndex))
EditPage(_nPageIndex, false);
// Воспроизведение словаря аннотации из reader для writer
PdfWriter::CXref* pXref = new PdfWriter::CXref(pDoc, oAnnotRef.getRefNum());
if (!pXref)
{
oAnnotRef.free(); oAnnot.free(); oType.free();
return false;
}
bool bIsWidget = false;
PdfWriter::CAnnotation* pAnnot = NULL;
if (oType.isName("Text"))
pAnnot = new PdfWriter::CTextAnnotation(pXref);
else if (oType.isName("Ink"))
pAnnot = new PdfWriter::CInkAnnotation(pXref);
else if (oType.isName("Line"))
pAnnot = new PdfWriter::CLineAnnotation(pXref);
else if (oType.isName("Highlight") || oType.isName("Underline") || oType.isName("Squiggly") || oType.isName("StrikeOut"))
pAnnot = new PdfWriter::CTextMarkupAnnotation(pXref);
else if (oType.isName("Square") || oType.isName("Circle"))
pAnnot = new PdfWriter::CSquareCircleAnnotation(pXref);
else if (oType.isName("Polygon") || oType.isName("PolyLine"))
pAnnot = new PdfWriter::CPolygonLineAnnotation(pXref);
else if (oType.isName("FreeText"))
{
std::map<std::wstring, std::wstring> mapFont = PdfReader::CAnnotFonts::GetAnnotFont(pPDFDocument, m_pReader->GetFontManager(), pFontList, &oAnnotRef);
m_mFonts.insert(mapFont.begin(), mapFont.end());
pAnnot = new PdfWriter::CFreeTextAnnotation(pXref);
}
else if (oType.isName("Caret"))
pAnnot = new PdfWriter::CCaretAnnotation(pXref);
else if (oType.isName("Stamp"))
pAnnot = new PdfWriter::CStampAnnotation(pXref);
else if (oType.isName("Redact"))
pAnnot = new PdfWriter::CRedactAnnotation(pXref);
else if (oType.isName("Popup"))
pAnnot = new PdfWriter::CPopupAnnotation(pXref);
else if (oType.isName("Widget"))
{
bIsWidget = true;
char* sName = NULL;
Object oFT;
if (oAnnot.dictLookup("FT", &oFT)->isName())
sName = oFT.getName();
if (!sName)
{
Object oParent, oParent2;
oAnnot.dictLookup("Parent", &oParent);
while (oParent.isDict())
{
if (oParent.dictLookup("FT", &oFT)->isName())
{
sName = oFT.getName();
break;
}
oFT.free();
oParent.dictLookup("Parent", &oParent2);
oParent.free();
oParent = oParent2;
}
oParent.free();
}
if (sName)
{
if (strcmp("Btn", sName) == 0)
{
bool bPushButton = false;
oFT.free();
int nFf = 0;
if (oAnnot.dictLookup("Ff", &oFT)->isInt())
nFf = oFT.getInt();
if (!nFf)
{
Object oParent, oParent2;
oAnnot.dictLookup("Parent", &oParent);
while (oParent.isDict())
{
if (oParent.dictLookup("Ff", &oFT)->isInt())
{
nFf = oFT.getInt();
break;
}
oFT.free();
oParent.dictLookup("Parent", &oParent2);
oParent.free();
oParent = oParent2;
}
oParent.free();
}
bPushButton = (bool)((nFf >> 16) & 1);
bool bRadiobutton = (bool)((nFf >> 15) & 1);
if (bPushButton)
pAnnot = new PdfWriter::CPushButtonWidget(pXref);
else
pAnnot = new PdfWriter::CCheckBoxWidget(pXref, bRadiobutton ? PdfWriter::WidgetRadiobutton : PdfWriter::WidgetCheckbox);
}
else if (strcmp("Tx", sName) == 0)
pAnnot = new PdfWriter::CTextWidget(pXref);
else if (strcmp("Ch", sName) == 0)
pAnnot = new PdfWriter::CChoiceWidget(pXref);
else if (strcmp("Sig", sName) == 0)
pAnnot = new PdfWriter::CSignatureWidget(pXref);
else
pAnnot = new PdfWriter::CWidgetAnnotation(pXref, PdfWriter::EAnnotType::AnnotWidget);
}
oFT.free();
}
if (!pAnnot)
{
oAnnotRef.free(); oAnnot.free(); oType.free();
RELEASEOBJECT(pXref);
return false;
}
pXref->Add(pAnnot, oAnnotRef.getRefGen());
for (int nIndex = 0; nIndex < oAnnot.dictGetLength(); ++nIndex)
{
char* chKey = oAnnot.dictGetKey(nIndex);
if (!strcmp("Popup", chKey))
{
Object oPopupRef;
if (oAnnot.dictGetValNF(nIndex, &oPopupRef)->isRef() && EditAnnot(nPageIndex, oPopupRef.getRefNum() + nStartRefID))
{
PdfWriter::CAnnotation* pPopup = pDoc->GetAnnot(oPopupRef.getRefNum() + nStartRefID);
if (pPopup)
{
pAnnot->Add("Popup", pPopup);
pPopup->Add("Parent", pAnnot);
}
}
continue;
}
else if (!strcmp("Parent", chKey) && bIsWidget)
{
Object oParentRef;
oAnnot.dictGetValNF(nIndex, &oParentRef);
PdfWriter::CDictObject* pParent = GetWidgetParent(pPDFDocument, pDoc, &oParentRef, nStartRefID);
if (!pParent)
{
oParentRef.free();
continue;
}
((PdfWriter::CWidgetAnnotation*)pAnnot)->SetParent(pParent);
PdfWriter::CArrayObject* pKids = dynamic_cast<PdfWriter::CArrayObject*>(pParent->Get("Kids"));
if (!pKids)
{
oParentRef.free();
continue;
}
for (int i = 0; i < pKids->GetCount(); ++i)
{
PdfWriter::CObjectBase* pKid = pKids->Get(i);
if (pKid->GetObjId() == oAnnotRef.getRefNum())
{
pKids->Insert(pKid, pAnnot, true);
break;
}
}
oParentRef.free();
continue;
}
else if (!strcmp("AP", chKey) && pAnnot->GetAnnotationType() == PdfWriter::AnnotWidget)
{
PdfWriter::EWidgetType nType = ((PdfWriter::CWidgetAnnotation*)pAnnot)->GetWidgetType();
if (nType == PdfWriter::WidgetRadiobutton || nType == PdfWriter::WidgetCheckbox)
{
PdfWriter::CCheckBoxWidget* pCAnnot = dynamic_cast<PdfWriter::CCheckBoxWidget*>(pAnnot);
Object oAP, oN;
if (oAnnot.dictGetVal(nIndex, &oAP)->isDict() && oAP.dictLookup("N", &oN)->isDict())
{
for (int j = 0, nNormLength = oN.dictGetLength(); j < nNormLength; ++j)
{
std::string sNormName(oN.dictGetKey(j));
if (sNormName != "Off")
{
pCAnnot->SetAP_N_Yes(UTF8_TO_U(sNormName));
break;
}
}
}
}
}
Object oTemp;
oAnnot.dictGetValNF(nIndex, &oTemp);
DictToCDictObject(&oTemp, pAnnot, chKey);
oTemp.free();
}
if (oType.isName("Stamp"))
{
Object oAP, oAPN;
if (oAnnot.dictLookup("AP", &oAP)->isDict() && oAP.dictLookup("N", &oAPN)->isStream())
{
Object oAPNRef;
oAP.dictLookupNF("N", &oAPNRef);
PdfWriter::CXref* pXRef = new PdfWriter::CXref(pDoc, oAPNRef.getRefNum());
pDoc->EditXref(pXRef);
PdfWriter::CDictObject* pAPN = new PdfWriter::CDictObject();
pXRef->Add(pAPN, oAPNRef.getRefGen());
((PdfWriter::CStampAnnotation*)pAnnot)->SetAPStream(pAPN);
oAPNRef.free();
Object oTemp;
Dict* pODict = oAPN.streamGetDict();
for (int nIndex = 0; nIndex < pODict->getLength(); ++nIndex)
{
char* chKey = pODict->getKey(nIndex);
pODict->getValNF(nIndex, &oTemp);
DictToCDictObject(&oTemp, pAPN, chKey);
oTemp.free();
}
int nLength = 0;
if (pODict->lookup("Length", &oTemp)->isInt())
nLength = oTemp.getInt();
PdfWriter::CStream* pStream = new PdfWriter::CMemoryStream(nLength);
pAPN->SetStream(pStream);
pAPN->Add("Length", nLength);
Stream* pOStream = oAPN.getStream()->getUndecodedStream();
pOStream->reset();
for (int nI = 0; nI < nLength; ++nI)
pStream->WriteChar(pOStream->getChar());
}
oAP.free(); oAPN.free();
}
oAnnotRef.free(); oAnnot.free(); oType.free();
if (pDoc->EditAnnot(pXref, pAnnot, nID))
return true;
RELEASEOBJECT(pXref);
return false;
}
bool CPdfEditor::DeleteAnnot(int nID, Object* oAnnots)
{
PdfWriter::CDocument* pDoc = m_pWriter->GetDocument();
if (!pDoc)
return false;
PdfWriter::CObjectBase* pObj = m_mObjManager.GetObj(nID);
if (pObj)
{
m_mObjManager.RemoveObj(nID);
pDoc->RemoveObj(pObj);
return true;
}
if (m_nMode == Mode::Split || m_nMode == Mode::WriteNew)
return true;
PDFDoc* pPDFDocument = NULL;
int nPageIndex = m_pReader->GetPageIndex(m_nEditPage, &pPDFDocument);
if (nPageIndex < 0 || !pPDFDocument)
return false;
XRef* xref = pPDFDocument->getXRef();
bool bClear = false;
if (!oAnnots)
{
PdfWriter::CPage* pPage = pDoc->GetCurPage();
std::pair<int, int> pPageRef = { pPage->GetObjId(), pPage->GetGenNo() };
if (pPageRef.first == 0)
return false;
oAnnots = new Object();
bClear = true;
// Получение объекта аннотации
Object pageRefObj, pageObj;
pageRefObj.initRef(pPageRef.first, pPageRef.second);
if (!pageRefObj.fetch(xref, &pageObj)->isDict() || !pageObj.dictLookup("Annots", oAnnots)->isArray())
{
pageRefObj.free(); pageObj.free(); oAnnots->free();
RELEASEOBJECT(oAnnots);
return false;
}
pageRefObj.free(); pageObj.free();
}
bool bRes = false;
for (int i = 0; i < oAnnots->arrayGetLength(); ++i)
{
Object oAnnotRef, oAnnot;
if (oAnnots->arrayGetNF(i, &oAnnotRef)->isRef() && oAnnotRef.getRefNum() == nID)
{
bool bNeed = false;
if (oAnnotRef.fetch(xref, &oAnnot)->isDict())
{
Object oType;
if (oAnnot.dictLookup("Subtype", &oType)->isName("Widget"))
{
char* sName = NULL;
Object oFT;
if (oAnnot.dictLookup("FT", &oFT)->isName())
sName = oFT.getName();
if (!sName)
{
Object oParent, oParent2;
oAnnot.dictLookup("Parent", &oParent);
while (oParent.isDict())
{
if (oParent.dictLookup("FT", &oFT)->isName())
{
sName = oFT.getName();
break;
}
oFT.free();
oParent.dictLookup("Parent", &oParent2);
oParent.free();
oParent = oParent2;
}
oParent.free();
}
if (sName && strcmp("Btn", sName) == 0)
{
bool bPushButton = false;
oFT.free();
int nFf = 0;
if (oAnnot.dictLookup("Ff", &oFT)->isInt())
nFf = oFT.getInt();
if (!nFf)
{
Object oParent, oParent2;
oAnnot.dictLookup("Parent", &oParent);
while (oParent.isDict())
{
if (oParent.dictLookup("Ff", &oFT)->isInt())
{
nFf = oFT.getInt();
break;
}
oFT.free();
oParent.dictLookup("Parent", &oParent2);
oParent.free();
oParent = oParent2;
}
oParent.free();
}
bPushButton = (bool)((nFf >> 16) & 1);
bool bRadiosInUnison = (bool)(nFf & (1 << 25));
if (!bPushButton)
{
oFT.free();
bNeed = oAnnot.dictLookup("Opt", &oFT)->isArray() == gTrue;
if (!bNeed)
{
Object oParent, oParent2;
oAnnot.dictLookup("Parent", &oParent);
while (oParent.isDict())
{
if (oParent.dictLookup("Opt", &oFT)->isArray())
{
bNeed = true;
break;
}
oFT.free();
oParent.dictLookup("Parent", &oParent2);
oParent.free();
oParent = oParent2;
}
oParent.free();
}
if (bNeed && EditAnnot(m_nEditPage, nID))
{
PdfWriter::CAnnotation* pAnnot = pDoc->GetAnnot(nID);
if (pAnnot)
{
pAnnot->SetHidden();
PdfWriter::CObjectBase* pObj = pAnnot->Get("Parent");
PdfWriter::CDictObject* pParent = NULL;
if (pObj && pObj->GetType() == PdfWriter::object_type_DICT)
pParent = (PdfWriter::CDictObject*)pObj;
PdfWriter::CArrayObject* pOpt = NULL, *pKids = NULL;
if (pParent)
{
pObj = pParent->Get("Kids");
if (pObj && pObj->GetType() == PdfWriter::object_type_ARRAY)
pKids = (PdfWriter::CArrayObject*)pObj;
pObj = pParent->Get("Opt");
if (pObj && pObj->GetType() == PdfWriter::object_type_ARRAY)
pOpt = (PdfWriter::CArrayObject*)pObj;
}
std::map<std::wstring, std::wstring> mNameAP_N_Yes;
if (pKids && pOpt && pKids->GetCount() == pOpt->GetCount())
{
for (int i = 0; i < pKids->GetCount(); ++i)
{
pObj = pKids->Get(i);
if (pObj == pAnnot)
{
pObj = pKids->Remove(i);
delete pObj;
pObj = pOpt->Remove(i);
delete pObj;
--i;
}
else
{
pObj = pOpt->Get(i);
if (pObj->GetType() == PdfWriter::object_type_ARRAY && ((PdfWriter::CArrayObject*)pObj)->GetCount() > 0)
pObj = ((PdfWriter::CArrayObject*)pObj)->Get(0);
std::wstring sNameOpt;
if (pObj->GetType() == PdfWriter::object_type_STRING)
{
PdfWriter::CStringObject* pStr = (PdfWriter::CStringObject*)pObj;
sNameOpt = NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)pStr->GetString(), pStr->GetLength());
if (mNameAP_N_Yes.find(sNameOpt) == mNameAP_N_Yes.end())
mNameAP_N_Yes[sNameOpt] = std::to_wstring(i);
}
pObj = pKids->Get(i);
Object oAnnot, oSubtype, oPageRef;
if (xref->fetch(pObj->GetObjId(), pObj->GetGenNo(), &oAnnot)->isDict("Annot") && oAnnot.dictLookup("Subtype", &oSubtype)->isName("Widget") &&
oAnnot.dictLookupNF("P", &oPageRef)->isRef())
{
int nPage = pPDFDocument->findPage(oPageRef.getRefNum(), oPageRef.getRefGen()) - 1;
PdfWriter::CCheckBoxWidget* pKidAnnot = NULL;
int nObjId = pObj->GetObjId();
if (nPage >= 0 && EditAnnot(nPage, nObjId))
pKidAnnot = dynamic_cast<PdfWriter::CCheckBoxWidget*>(pDoc->GetAnnot(nObjId));
if (pKidAnnot && !sNameOpt.empty())
pKidAnnot->RenameAP_N_Yes((bRadiosInUnison || pKidAnnot->GetWidgetType() == PdfWriter::WidgetCheckbox) ? mNameAP_N_Yes[sNameOpt] : std::to_wstring(i));
}
oAnnot.free(); oSubtype.free(); oPageRef.free();
}
}
}
Object oPopupRef;
if (oAnnot.dictLookupNF("Popup", &oPopupRef)->isRef())
{
pAnnot = pDoc->GetAnnot(oPopupRef.getRefNum());
if (pAnnot)
pAnnot->SetHidden();
}
oPopupRef.free();
}
}
}
}
oFT.free();
}
oType.free();
if (!bNeed)
{
Object oPopupRef;
if (oAnnot.dictLookupNF("Popup", &oPopupRef)->isRef())
pDoc->DeleteAnnot(oPopupRef.getRefNum(), oPopupRef.getRefGen());
oPopupRef.free();
}
}
if (!bNeed)
bRes = pDoc->DeleteAnnot(oAnnotRef.getRefNum(), oAnnotRef.getRefGen());
}
else if (oAnnots->arrayGet(i, &oAnnot)->isDict())
{
Object oIRTRef;
if (oAnnot.dictLookupNF("IRT", &oIRTRef)->isRef() && oIRTRef.getRefNum() == nID)
DeleteAnnot(oAnnotRef.getRefNum(), oAnnots);
oIRTRef.free();
}
oAnnotRef.free(); oAnnot.free();
}
if (bClear)
{
oAnnots->free();
RELEASEOBJECT(oAnnots);
}
return bRes;
}
bool CPdfEditor::EditWidgets(IAdvancedCommand* pCommand)
{
if (m_nMode == Mode::Unknown && !IncrementalUpdates())
return false;
WriteRedact({});
m_arrRedact.clear();
CWidgetsInfo* pFieldInfo = (CWidgetsInfo*)pCommand;
PdfWriter::CDocument* pDoc = m_pWriter->GetDocument();
const std::vector< std::pair<int, int> >& arrCO = pFieldInfo->GetCO();
for (int i = 0; i < arrCO.size(); ++i)
{
int nObjNum = arrCO[i].first;
if (pDoc->GetParent(nObjNum))
continue;
if (pDoc->GetAnnot(nObjNum))
continue;
PDFDoc* pPDFDocument = NULL;
int nStartRefID = 0;
int nRefID = m_pReader->FindRefNum(nObjNum, &pPDFDocument, &nStartRefID);
if (nRefID < 0)
continue;
XRefEntry* pEntry = pPDFDocument->getXRef()->getEntry(nRefID);
pFieldInfo->ChangeCO(i, nRefID, pEntry->type == xrefEntryCompressed ? 0 : pEntry->gen);
}
const std::vector<CWidgetsInfo::CParent*>& arrParents = pFieldInfo->GetParents();
for (CWidgetsInfo::CParent* pParent : arrParents)
{
PdfWriter::CDictObject* pDParent = pDoc->GetParent(pParent->nID);
if (pDParent)
continue;
PDFDoc* pPDFDocument = NULL;
int nStartRefID = 0;
int nRefID = m_pReader->FindRefNum(pParent->nID, &pPDFDocument, &nStartRefID);
if (nRefID < 0)
continue;
XRefEntry* pEntry = pPDFDocument->getXRef()->getEntry(nRefID);
Object oParentRef;
oParentRef.initRef(nRefID, pEntry->type == xrefEntryCompressed ? 0 : pEntry->gen);
GetWidgetParent(pPDFDocument, pDoc, &oParentRef, nStartRefID);
// TODO перевыставить детей
oParentRef.free();
}
return true;
}
int CPdfEditor::GetPagesCount()
{
return m_pWriter->GetDocument()->GetPagesCount();
}
void CPdfEditor::GetPageInfo(int nPageIndex, double* pdWidth, double* pdHeight, double* pdDpiX, double* pdDpiY)
{
PdfWriter::CPage* pPage = m_pWriter->GetDocument()->GetPage(nPageIndex);
if (!pPage)
return;
int nRotate = pPage->GetRotate();
if (nRotate % 180 == 0)
{
*pdWidth = pPage->GetWidth();
*pdHeight = pPage->GetHeight();
}
else
{
*pdWidth = pPage->GetHeight();
*pdHeight = pPage->GetWidth();
}
*pdDpiX = 72.0;
*pdDpiY = 72.0;
}
int CPdfEditor::GetRotate(int nPageIndex)
{
PdfWriter::CPage* pPage = m_pWriter->GetDocument()->GetPage(nPageIndex);
if (!pPage)
return 0;
return pPage->GetRotate();
}
bool CPdfEditor::IsEditPage()
{
return m_nEditPage >= 0;
}
void CPdfEditor::ClearPage()
{
PDFDoc* pPDFDocument = NULL;
int nPageIndex = m_pReader->GetPageIndex(m_nEditPage, &pPDFDocument);
PdfWriter::CDocument* pDoc = m_pWriter->GetDocument();
if (nPageIndex < 0 || !pPDFDocument || !pDoc)
return;
XRef* xref = pPDFDocument->getXRef();
Ref* pPageRef = pPDFDocument->getCatalog()->getPageRef(nPageIndex);
// Получение объекта страницы
Object pageRefObj, pageObj;
pageRefObj.initRef(pPageRef->num, pPageRef->gen);
if (!pageRefObj.fetch(xref, &pageObj)->isDict())
{
pageObj.free(); pageRefObj.free();
return;
}
pageRefObj.free();
Object oAnnots;
// ВРЕМЕННО удаление Link аннотаций при редактировании
if (pageObj.dictLookup("Annots", &oAnnots)->isArray())
{
for (int nIndex = 0; nIndex < oAnnots.arrayGetLength(); ++nIndex)
{
Object oAnnot, oSubtype, oAnnotRef;
if (oAnnots.arrayGet(nIndex, &oAnnot)->isDict("Annot") && oAnnot.dictLookup("Subtype", &oSubtype)->isName("Link"))
{
oAnnots.arrayGetNF(nIndex, &oAnnotRef);
DeleteAnnot(oAnnotRef.getRefNum(), &oAnnots);
}
oAnnot.free(); oSubtype.free(); oAnnotRef.free();
}
}
pageObj.free();
if (m_nMode == Mode::Split || m_nMode == Mode::WriteNew)
pDoc->ClearPageFull();
else
pDoc->ClearPage();
Page* pOPage = pPDFDocument->getCatalog()->getPage(nPageIndex);
if (pOPage->isCropped())
{
PDFRectangle* pCropBox = pOPage->getCropBox();
PdfWriter::CStream* pStream = pDoc->GetCurPage()->GetStream();
pStream->WriteStr("1 0 0 1 ");
pStream->WriteReal(pCropBox->x1);
pStream->WriteChar(' ');
pStream->WriteReal(pCropBox->y2 - pOPage->getMediaBox()->y2);
pStream->WriteStr(" cm\012");
}
}
void CPdfEditor::AddShapeXML(const std::string& sXML)
{
return m_pWriter->GetDocument()->AddShapeXML(sXML);
}
void CPdfEditor::EndMarkedContent()
{
m_pWriter->GetDocument()->EndShapeXML();
}
bool CPdfEditor::IsBase14(const std::wstring& wsFontName, bool& bBold, bool& bItalic, std::wstring& wsFontPath)
{
std::map<std::wstring, std::wstring>::const_iterator it = m_mFonts.find(wsFontName);
if (it != m_mFonts.end())
wsFontPath = it->second;
if (wsFontPath.empty())
{
const std::map<std::wstring, std::wstring>& mFonts = m_pReader->GetFonts();
std::map<std::wstring, std::wstring>::const_iterator it2 = mFonts.find(wsFontName);
if (it2 != mFonts.end())
wsFontPath = it2->second;
}
if (wsFontPath.empty())
return false;
if (wsFontName == L"Helvetica")
return true;
if (wsFontName == L"Helvetica-Bold")
{
bBold = true;
return true;
}
if (wsFontName == L"Helvetica-Oblique")
{
bItalic = true;
return true;
}
if (wsFontName == L"Helvetice-BoldOblique")
{
bBold = true;
bItalic = true;
return true;
}
if (wsFontName == L"Courier")
return true;
if (wsFontName == L"Courier-Bold")
{
bBold = true;
return true;
}
if (wsFontName == L"Courier-Oblique")
{
bItalic = true;
return true;
}
if (wsFontName == L"Courier-BoldOblique")
{
bBold = true;
bItalic = true;
return true;
}
if (wsFontName == L"Times" || wsFontName == L"Times-Roman")
return true;
if (wsFontName == L"Times-Bold")
{
bBold = true;
return true;
}
if (wsFontName == L"Times-Oblique")
{
bItalic = true;
return true;
}
if (wsFontName == L"Times-BoldOblique")
{
bBold = true;
bItalic = true;
return true;
}
if (wsFontName == L"Symbol")
return true;
if (wsFontName == L"ZapfDingbats")
return true;
return false;
}
void CPdfEditor::Redact(IAdvancedCommand* _pCommand)
{
PDFDoc* pPDFDocument = NULL;
PDFRectangle* cropBox = NULL;
int nPageIndex = -1;
Page* pPage = NULL;
bool bEditPage = IsEditPage();
PdfWriter::CDocument* pDoc = m_pWriter->GetDocument();
if (bEditPage)
{
nPageIndex = m_pReader->GetPageIndex(m_nEditPage, &pPDFDocument);
if (nPageIndex < 0 || !pPDFDocument)
return;
pPage = pPDFDocument->getCatalog()->getPage(nPageIndex);
cropBox = pPage->getCropBox();
}
else
{
cropBox = new PDFRectangle();
PdfWriter::CPage* pWPage = pDoc->GetCurPage();
cropBox->x2 = pWPage->GetWidth();
cropBox->y2 = pWPage->GetHeight();
}
std::vector<double> arrAllQuads;
CRedact* pCommand = (CRedact*)_pCommand;
std::vector<CRedact::SRedact*> arrRedacts = pCommand->GetRedact();
for (CRedact::SRedact* pRedact : arrRedacts)
{
m_arrRedact.push_back(CRedactData());
m_arrRedact.back().sID = pRedact->sID;
m_arrRedact.back().arrQuads = pRedact->arrQuadPoints;
for (int i = 0; i < pRedact->arrQuadPoints.size(); i += 2)
{
arrAllQuads.push_back(pRedact->arrQuadPoints[i + 0] + cropBox->x1);
arrAllQuads.push_back(cropBox->y2 - pRedact->arrQuadPoints[i + 1]);
}
int nFlags = pRedact->nFlag;
if (nFlags & (1 << 0))
{
m_arrRedact.back().pRender = pRedact->pRender;
m_arrRedact.back().nLenRender = pRedact->nRenderLen;
}
}
if (bEditPage)
{
PdfWriter::RedactOutputDev oRedactOut(m_pWriter);
oRedactOut.NewPDF(pPDFDocument->getXRef());
oRedactOut.SetRedact(arrAllQuads);
Object oContents;
pPage->getContents(&oContents);
PDFRectangle* box = pPage->getMediaBox();
Gfx* gfx = new Gfx(pPDFDocument, &oRedactOut, m_nEditPage, pPage->getResourceDict(), 72.0, 72.0, box, NULL, 0);
gfx->saveState();
gfx->display(&oContents);
gfx->endOfPage();
oContents.free();
RELEASEOBJECT(gfx);
PdfWriter::CPage* pWPage = pDoc->GetCurPage();
pWPage->SetFontType(PdfWriter::EFontType::fontUnknownType);
}
else
{
RELEASEOBJECT(cropBox);
}
}
std::vector<double> CPdfEditor::WriteRedact(const std::vector<std::wstring>& arrID)
{
std::wstring sID;
if (!arrID.empty())
sID = arrID[0];
std::vector<double> arrRes;
for (int i = 0; i < m_arrRedact.size(); ++i)
{
if (m_arrRedact[i].sID == sID)
{
for (int j = i; j < m_arrRedact.size(); ++j)
arrRes.insert(arrRes.end(), m_arrRedact[j].arrQuads.begin(), m_arrRedact[j].arrQuads.end());
return arrRes;
}
CRedactData oRedact = m_arrRedact[i];
if (oRedact.bDraw || !oRedact.pRender || oRedact.nLenRender != oRedact.arrQuads.size() / 8 * 12)
continue;
BYTE* pMemory = oRedact.pRender;
m_pWriter->AddRedact({});
double dM1, dM2, dM3, dM4, dM5, dM6;
m_pWriter->GetTransform(&dM1, &dM2, &dM3, &dM4, &dM5, &dM6);
LONG lType, lColorB, lAlpha1, lAlpha2;
m_pWriter->get_BrushType(&lType);
m_pWriter->get_BrushColor1(&lColorB);
m_pWriter->get_BrushAlpha1(&lAlpha1);
m_pWriter->get_BrushAlpha2(&lAlpha2);
m_pWriter->SetTransform(1, 0, 0, 1, 0, 0);
m_pWriter->PathCommandEnd();
m_pWriter->put_BrushType(c_BrushTypeSolid);
m_pWriter->put_BrushAlpha1(255);
m_pWriter->put_BrushAlpha2(255);
for (int i = 0; i < oRedact.arrQuads.size(); i += 8)
{
int ret = *((int*)pMemory);
pMemory += 4;
LONG R = ret;
ret = *((int*)pMemory);
pMemory += 4;
LONG G = ret;
ret = *((int*)pMemory);
pMemory += 4;
LONG B = ret;
LONG lColor = (LONG)(R | (G << 8) | (B << 16) | ((LONG)255 << 24));
m_pWriter->put_BrushColor1(lColor);
m_pWriter->PathCommandMoveTo(PdfReader::PDFCoordsToMM(oRedact.arrQuads[i + 0]), PdfReader::PDFCoordsToMM(oRedact.arrQuads[i + 1]));
m_pWriter->PathCommandLineTo(PdfReader::PDFCoordsToMM(oRedact.arrQuads[i + 2]), PdfReader::PDFCoordsToMM(oRedact.arrQuads[i + 3]));
m_pWriter->PathCommandLineTo(PdfReader::PDFCoordsToMM(oRedact.arrQuads[i + 4]), PdfReader::PDFCoordsToMM(oRedact.arrQuads[i + 5]));
m_pWriter->PathCommandLineTo(PdfReader::PDFCoordsToMM(oRedact.arrQuads[i + 6]), PdfReader::PDFCoordsToMM(oRedact.arrQuads[i + 7]));
m_pWriter->PathCommandClose();
m_pWriter->DrawPath(NULL, L"", c_nWindingFillMode);
m_pWriter->PathCommandEnd();
}
m_pWriter->SetTransform(dM1, dM2, dM3, dM4, dM5, dM6);
m_pWriter->put_BrushType(lType);
m_pWriter->put_BrushColor1(lColorB);
m_pWriter->put_BrushAlpha1(lAlpha1);
m_pWriter->put_BrushAlpha2(lAlpha2);
// TODO рендер редакта должен быть пересечён со всеми последующими редактами
// TODO на самом деле должен быть рендер команд редакта
/*
PdfWriter::CPage* pCurPage = m_pWriter->GetPage();
pDoc->FixEditPage(pCurPage);
PdfWriter::CPage* pFakePage = new PdfWriter::CPage(pDoc);
m_pWriter->SetPage(pFakePage);
pDoc->SetCurPage(pFakePage);
// TODO Нужно нивелировать текущую матрицу до единичной, а потом сместить ещё на CropBox
pFakePage->SetStream(pCurPage->GetStream());
pFakePage->Add("Resources", pCurPage->Get("Resources"));
IMetafileToRenderter* pCorrector = new IMetafileToRenderter(m_pWriter->GetRenderer());
NSOnlineOfficeBinToPdf::ConvertBufferToRenderer(pRender, nLenRender, pCorrector);
RELEASEOBJECT(pCorrector);
m_pWriter->SetPage(pCurPage);
pDoc->SetCurPage(pCurPage);
RELEASEOBJECT(pFakePage);
*/
m_arrRedact[i].bDraw = true;
}
return arrRes;
}