Merge Outlines two files

This commit is contained in:
Svetlana Kulikova
2025-04-09 15:38:21 +03:00
parent 21ec043636
commit 7b264e940d
10 changed files with 192 additions and 34 deletions

View File

@ -40,12 +40,16 @@
#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 "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"
#define AddToObject(oVal)\
{\
@ -929,7 +933,7 @@ CPdfEditor::CPdfEditor(const std::wstring& _wsSrcFile, const std::wstring& _wsPa
}
bool CPdfEditor::IncrementalUpdates()
{
if (m_nMode == Mode::Unknown)
if (m_nMode != Mode::Unknown)
return true;
m_nMode = Mode::WriteAppend;
@ -1157,7 +1161,7 @@ void CPdfEditor::Close()
if (m_wsDstFile.empty())
return;
if (m_nMode == Mode::WriteAppend)
if (m_nMode != Mode::WriteAppend)
{
m_pWriter->SaveToFile(m_wsDstFile);
return;
@ -1894,7 +1898,106 @@ BYTE* CPdfEditor::SplitPages(const int* arrPageIndex, unsigned int unLength)
RELEASEARRAYOBJECTS(pRes);
return NULL;
}
bool CPdfEditor::MergePages(const int* arrPageIndex, unsigned int unLength)
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::MergePages(const std::wstring& wsPath, const int* arrPageIndex, unsigned int unLength)
{
if (m_nMode != Mode::WriteAppend && !IncrementalUpdates())
return false;
@ -1904,6 +2007,39 @@ bool CPdfEditor::MergePages(const int* arrPageIndex, unsigned int unLength)
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)

View File

@ -94,7 +94,7 @@ public:
bool IsBase14(const std::wstring& wsFontName, bool& bBold, bool& bItalic, std::wstring& wsFontPath);
BYTE* SplitPages(const int* arrPageIndex, unsigned int unLength);
bool MergePages(const int* arrPageIndex, unsigned int unLength);
bool MergePages(const std::wstring& wsPath, const int* arrPageIndex, unsigned int unLength);
private:
void GetPageTree(XRef* xref, Object* pPagesRefObj, PdfWriter::CPageTree* pPageParent = NULL);

View File

@ -32,13 +32,12 @@
#include "PdfFile.h"
#include "PdfWriter.h"
#include "PdfReader.h"
#include "PdfEditor.h"
#include "../DesktopEditor/common/File.h"
#include "../DesktopEditor/graphics/commands/DocInfo.h"
#include "lib/xpdf/PDFDoc.h"
#include "Resources/BaseFonts.h"
#include "PdfEditor.h"
#include "OnlineOfficeBinToPdf.h"
#include "SrcWriter/Document.h"
@ -141,7 +140,7 @@ bool CPdfFile::MergePages(const std::wstring& wsPath, const std::wstring& wsPass
if (!m_pInternal->pEditor)
return false;
if (m_pInternal->pReader->MergePages(wsPath, wsPassword))
return m_pInternal->pEditor->MergePages(arrPageIndex, unLength);
return m_pInternal->pEditor->MergePages(wsPath, arrPageIndex, unLength);
return false;
}
bool CPdfFile::MovePage(int nPageIndex, int nPos)

View File

@ -126,8 +126,8 @@ public:
virtual BYTE* GetStructure();
virtual BYTE* GetLinks(int nPageIndex);
bool MergePages(BYTE* data, DWORD length);
bool ValidMetaData();
bool MergePages(BYTE* data, DWORD length);
int GetRotate(int nPageIndex);
int GetMaxRefID();
BYTE* GetWidgets();

View File

@ -961,13 +961,13 @@ BYTE* CPdfReader::GetStructure()
for (int iPDF = 0; iPDF < m_vPDFContext.size(); ++iPDF)
{
PDFDoc* pDoc = m_vPDFContext[iPDF]->m_pDocument;
if (!pDoc->getOutline())
Outline* pOutline = pDoc->getOutline();
if (!pOutline)
{
nStartPage += pDoc->getNumPages();
continue;
}
Outline* pOutline = pDoc->getOutline();
GList* pList = pOutline->getItems();
if (!pList)
{

View File

@ -30,20 +30,19 @@
*
*/
#include "Destination.h"
#include "Pages.h"
namespace PdfWriter
{
//----------------------------------------------------------------------------------------
// CDestination
//----------------------------------------------------------------------------------------
CDestination::CDestination(CPage* pPage, CXref* pXref, bool bInline)
CDestination::CDestination(CObjectBase* pPage, CXref* pXref, bool bInline)
{
if (!bInline)
pXref->Add(this);
// Первый элемент массива должен быть страницей, которой принадлежит объект
Add((CObjectBase*)pPage);
Add(pPage);
Add("Fit"); // Значение по умолчанию Fit
}
bool CDestination::IsValid() const
@ -51,21 +50,28 @@ namespace PdfWriter
if (m_arrList.size() < 2)
return false;
CObjectBase* pObject = Get(0, false);
if ((object_type_DICT != pObject->GetType() || dict_type_PAGE != ((CDictObject*)pObject)->GetDictType()) &&
(object_type_PROXY != pObject->GetType() || object_type_DICT != ((CProxyObject*)pObject)->Get()->GetType() || dict_type_PAGE != ((CDictObject*)((CProxyObject*)pObject)->Get())->GetDictType()))
return false;
// Проверка, что объект является страницей. Но это может быть ссылка на нередактируемую страницу
// CObjectBase* pObject = Get(0, false);
// if ((object_type_DICT != pObject->GetType() || dict_type_PAGE != ((CDictObject*)pObject)->GetDictType()) &&
// (object_type_PROXY != pObject->GetType() || object_type_DICT != ((CProxyObject*)pObject)->Get()->GetType() || dict_type_PAGE != ((CDictObject*)((CProxyObject*)pObject)->Get())->GetDictType()))
// return false;
return true;
}
void CDestination::PrepareArray()
{
CPage* pPage = (CPage*)Get(0);
if (m_arrList.size() > 1)
{
CObjectBase* pPage = Get(0);
if (pPage->GetType() != object_type_DICT)
{
CObjectBase* pCopy = pPage->Copy();
pCopy->SetRef(pPage->GetObjId(), pPage->GetGenNo());
pPage = new CProxyObject(pCopy, true);
}
Clear();
Add((CObjectBase*)pPage);
Add(pPage);
}
}
void CDestination::SetXYZ(float fLeft, float fTop, float fZoom)

View File

@ -36,12 +36,10 @@
namespace PdfWriter
{
class CPage;
class CDestination : public CArrayObject
{
public:
CDestination(CPage* pPage, CXref* pXref, bool bInline = false);
CDestination(CObjectBase* pPage, CXref* pXref, bool bInline = false);
bool IsValid() const;
void SetXYZ (float fLeft, float fTop, float fZoom);
void SetFit ();

View File

@ -527,7 +527,7 @@ namespace PdfWriter
return new COutline(pParent, sTitle, m_pXref);
}
CDestination* CDocument::CreateDestination(CPage* pPage, bool bInline)
CDestination* CDocument::CreateDestination(CObjectBase* pPage, bool bInline)
{
if (pPage)
return new CDestination(pPage, m_pXref, bInline);

View File

@ -130,7 +130,8 @@ namespace PdfWriter
void AddPageLabel(EPageNumStyle eStyle, unsigned int unFirstPage, const char* sPrefix);
void AddPageLabel(unsigned int unPageIndex, EPageNumStyle eStyle, unsigned int unFirstPage, const char* sPrefix);
COutline* CreateOutline(COutline* pParent, const char* sTitle);
CDestination* CreateDestination(CPage* pPage, bool bInline = false);
COutline* GetOutlines() { return m_pOutlines; }
CDestination* CreateDestination(CObjectBase* pPage, bool bInline = false);
bool AddMetaData(const std::wstring& sMetaName, BYTE* pMetaData, DWORD nMetaLength);
CExtGrState* GetExtGState(double dAlphaStroke = -1, double dAlphaFill = -1, EBlendMode eMode = blendmode_Unknown, int nStrokeAdjustment = -1);

View File

@ -90,13 +90,13 @@ public:
RELEASEOBJECT(oWorker);
}
void LoadFromFile()
void LoadFromFile(const std::wstring& _wsSrcFile = L"")
{
bool bResult = pdfFile->LoadFromFile(wsSrcFile);
bool bResult = pdfFile->LoadFromFile(_wsSrcFile.empty() ? wsSrcFile : _wsSrcFile);
if (!bResult)
{
std::wstring wsPassword = L"123456";
bResult = pdfFile->LoadFromFile(wsSrcFile, L"", wsPassword, wsPassword);
bResult = pdfFile->LoadFromFile(_wsSrcFile.empty() ? wsSrcFile : _wsSrcFile, L"", wsPassword, wsPassword);
}
ASSERT_TRUE(bResult);
@ -350,21 +350,39 @@ TEST_F(CPdfFileTest, VerifySign)
RELEASEOBJECT(pCertificate);
}
TEST_F(CPdfFileTest, MergePdf)
TEST_F(CPdfFileTest, SplitPdf)
{
GTEST_SKIP();
LoadFromFile();
std::vector<int> arrPages = { 0, 1 };
std::vector<int> arrPages = { 0 };
BYTE* pFile = pdfFile->SplitPages(arrPages.data(), arrPages.size());
ASSERT_TRUE(pFile != NULL);
NSFile::CFileBinary oFile;
std::wstring wsSplitFile = NSFile::GetProcessDirectory() + L"/test_split.pdf";
if (oFile.CreateFileW(wsSplitFile))
{
int nLength = pFile[0] | pFile[1] << 8 | pFile[2] << 16 | pFile[3] << 24;
oFile.WriteFile(pFile + 4, nLength);
}
oFile.CloseFile();
RELEASEARRAYOBJECTS(pFile);
}
TEST_F(CPdfFileTest, MergePdf)
{
// GTEST_SKIP();
LoadFromFile();
ASSERT_TRUE(pdfFile->EditPdf(wsDstFile));
pdfFile->MergePages(wsDstFile);
std::wstring wsSplitFile = NSFile::GetProcessDirectory() + L"/test_split.pdf";
pdfFile->MergePages(wsSplitFile);
pdfFile->Close();
RELEASEARRAYOBJECTS(pFile);
}
TEST_F(CPdfFileTest, EditPdf)
@ -389,7 +407,7 @@ TEST_F(CPdfFileTest, EditPdf)
TEST_F(CPdfFileTest, EditPdfFromBase64)
{
// GTEST_SKIP();
GTEST_SKIP();
NSFonts::NSApplicationFontStream::SetGlobalMemoryStorage(NSFonts::NSApplicationFontStream::CreateDefaultGlobalMemoryStorage());