From 026717cb667cf0c7215cf55daf794d69752fc900 Mon Sep 17 00:00:00 2001 From: Lei Zhang Date: Thu, 8 Feb 2018 23:31:00 +0000 Subject: Split CPDF_PageOrganizer into multiple classes. Retain CPDF_PageOrganizer as a base class. Add CPDF_PageExporter and CPDF_NPageToOneExporter sub-classes. The sub-classes only do one type of exporting. Therefore it is much easier to understand what part of the original combined CPDF_PageOrganizer is used where. Change-Id: I424ef9c32b101d23e8397fc9a656d9b0b5da6a27 Reviewed-on: https://pdfium-review.googlesource.com/26011 Commit-Queue: Lei Zhang Reviewed-by: Henrique Nakashima Reviewed-by: Shirleen Lou --- fpdfsdk/fpdf_ppo.cpp | 529 ++++++++++++++++++++++++++++----------------------- 1 file changed, 292 insertions(+), 237 deletions(-) (limited to 'fpdfsdk') diff --git a/fpdfsdk/fpdf_ppo.cpp b/fpdfsdk/fpdf_ppo.cpp index f51bb22f98..efec4b222b 100644 --- a/fpdfsdk/fpdf_ppo.cpp +++ b/fpdfsdk/fpdf_ppo.cpp @@ -283,50 +283,18 @@ std::vector GetPageNumbers(const CPDF_Document& doc, return page_numbers; } -} // namespace - class CPDF_PageOrganizer { - public: + protected: + // Map source page object number to XObject object number. + using ObjectNumberMap = std::map; + CPDF_PageOrganizer(CPDF_Document* pDestPDFDoc, CPDF_Document* pSrcPDFDoc); ~CPDF_PageOrganizer(); + // Must be called after construction before doing anything else. bool PDFDocInit(); - bool ExportPage(const std::vector& pageNums, int nIndex); - bool ExportNPagesToOne(const std::vector& pageNums, - float destPageWidth, - float destPageHeight, - unsigned int numPagesOnXAxis, - unsigned int numPagesOnYAxis); - - private: - // Map source page object number to XObject object number. - using ObjectNumberMap = std::map; - // Map page object number to XObject object name. - using PageXObjectMap = std::map; - // Map XObject's object name to it's object number. - using XObjectNameNumberMap = std::map; - - static void SetMediaBox(CPDF_Dictionary* pDestPageDict, - const CFX_SizeF& pagesize); bool UpdateReference(CPDF_Object* pObj, ObjectNumberMap* pObjNumberMap); - uint32_t GetNewObjId(ObjectNumberMap* pObjNumberMap, CPDF_Reference* pRef); - // Creates a xobject from the source page dictionary, and appends the - // bsContent string with the xobject reference surrounded by the - // transformation matrix. - void AddSubPage(CPDF_Dictionary* pPageDict, - const CFX_PointF& position, - float scale, - ObjectNumberMap* pObjNumberMap, - PageXObjectMap* pPageXObjectMap, - XObjectNameNumberMap* pXObjNameNumberMap, - ByteString* bsContent); - uint32_t MakeXObject(CPDF_Dictionary* pSrcPageDict, - ObjectNumberMap* pObjNumberMap, - CPDF_Document* pDestDoc); - void FinishPage(CPDF_Dictionary* pCurPageDict, - const ByteString& bsContent, - XObjectNameNumberMap* pXObjNameNumberMap); CPDF_Document* dest() { return m_pDestPDFDoc.Get(); } const CPDF_Document* dest() const { return m_pDestPDFDoc.Get(); } @@ -334,13 +302,11 @@ class CPDF_PageOrganizer { CPDF_Document* src() { return m_pSrcPDFDoc.Get(); } const CPDF_Document* src() const { return m_pSrcPDFDoc.Get(); } + private: + uint32_t GetNewObjId(ObjectNumberMap* pObjNumberMap, CPDF_Reference* pRef); + UnownedPtr const m_pDestPDFDoc; UnownedPtr const m_pSrcPDFDoc; - uint32_t m_xobjectNum = 0; - CFX_SizeF m_pageSize; - // Mapping of XObject name and XObject object number of the entire document. - // Key is XObject name. - XObjectNameNumberMap m_xobjs; }; CPDF_PageOrganizer::CPDF_PageOrganizer(CPDF_Document* pDestPDFDoc, @@ -389,101 +355,121 @@ bool CPDF_PageOrganizer::PDFDocInit() { return true; } -void CPDF_PageOrganizer::AddSubPage(CPDF_Dictionary* pPageDict, - const CFX_PointF& position, - float scale, - ObjectNumberMap* pObjNumberMap, - PageXObjectMap* pPageXObjectMap, - XObjectNameNumberMap* pXObjNameNumberMap, - ByteString* bsContent) { - uint32_t dwPageObjnum = pPageDict->GetObjNum(); - ByteString bsXObjectName; - const auto it = pPageXObjectMap->find(dwPageObjnum); - if (it != pPageXObjectMap->end()) { - bsXObjectName = it->second; - } else { - ++m_xobjectNum; - // TODO(Xlou): A better name schema to avoid possible object name collision. - bsXObjectName = ByteString::Format("X%d", m_xobjectNum); - m_xobjs[bsXObjectName] = MakeXObject(pPageDict, pObjNumberMap, dest()); - (*pPageXObjectMap)[dwPageObjnum] = bsXObjectName; +bool CPDF_PageOrganizer::UpdateReference(CPDF_Object* pObj, + ObjectNumberMap* pObjNumberMap) { + switch (pObj->GetType()) { + case CPDF_Object::REFERENCE: { + CPDF_Reference* pReference = pObj->AsReference(); + uint32_t newobjnum = GetNewObjId(pObjNumberMap, pReference); + if (newobjnum == 0) + return false; + pReference->SetRef(dest(), newobjnum); + break; + } + case CPDF_Object::DICTIONARY: { + CPDF_Dictionary* pDict = pObj->AsDictionary(); + auto it = pDict->begin(); + while (it != pDict->end()) { + const ByteString& key = it->first; + CPDF_Object* pNextObj = it->second.get(); + ++it; + if (key == "Parent" || key == "Prev" || key == "First") + continue; + if (!pNextObj) + return false; + if (!UpdateReference(pNextObj, pObjNumberMap)) + pDict->RemoveFor(key); + } + break; + } + case CPDF_Object::ARRAY: { + CPDF_Array* pArray = pObj->AsArray(); + for (size_t i = 0; i < pArray->GetCount(); ++i) { + CPDF_Object* pNextObj = pArray->GetObjectAt(i); + if (!pNextObj) + return false; + if (!UpdateReference(pNextObj, pObjNumberMap)) + return false; + } + break; + } + case CPDF_Object::STREAM: { + CPDF_Stream* pStream = pObj->AsStream(); + CPDF_Dictionary* pDict = pStream->GetDict(); + if (!pDict) + return false; + if (!UpdateReference(pDict, pObjNumberMap)) + return false; + break; + } + default: + break; } - (*pXObjNameNumberMap)[bsXObjectName] = m_xobjs[bsXObjectName]; - CFX_Matrix matrix; - matrix.Scale(scale, scale); - matrix.Translate(position.x, position.y); - - std::ostringstream contentStream; - contentStream << "q\n" - << matrix.a << " " << matrix.b << " " << matrix.c << " " - << matrix.d << " " << matrix.e << " " << matrix.f << " cm\n" - << "/" << bsXObjectName << " Do Q\n"; - *bsContent += ByteString(contentStream); + return true; } -uint32_t CPDF_PageOrganizer::MakeXObject(CPDF_Dictionary* pSrcPageDict, - ObjectNumberMap* pObjNumberMap, - CPDF_Document* pDestDoc) { - ASSERT(pSrcPageDict); +uint32_t CPDF_PageOrganizer::GetNewObjId(ObjectNumberMap* pObjNumberMap, + CPDF_Reference* pRef) { + if (!pRef) + return 0; - CPDF_Object* pSrcContentObj = GetPageOrganizerPageContent(pSrcPageDict); - CPDF_Stream* pNewXObject = pDestDoc->NewIndirect( - nullptr, 0, - pdfium::MakeUnique(pDestDoc->GetByteStringPool())); - CPDF_Dictionary* pNewXObjectDict = pNewXObject->GetDict(); - const ByteString bsResourceString = "Resources"; - if (!CopyInheritable(pNewXObjectDict, pSrcPageDict, bsResourceString)) { - // Use a default empty resources if it does not exist. - pNewXObjectDict->SetNewFor(bsResourceString); - } - uint32_t dwSrcPageObj = pSrcPageDict->GetObjNum(); - uint32_t dwNewXobjectObj = pNewXObjectDict->GetObjNum(); - (*pObjNumberMap)[dwSrcPageObj] = dwNewXobjectObj; - UpdateReference(pNewXObjectDict, pObjNumberMap); + uint32_t dwObjnum = pRef->GetRefObjNum(); + uint32_t dwNewObjNum = 0; + const auto it = pObjNumberMap->find(dwObjnum); + if (it != pObjNumberMap->end()) + dwNewObjNum = it->second; + if (dwNewObjNum) + return dwNewObjNum; - pNewXObjectDict->SetNewFor("Type", "XObject"); - pNewXObjectDict->SetNewFor("Subtype", "Form"); - pNewXObjectDict->SetNewFor("FormType", 1); - pNewXObjectDict->SetRectFor("BBox", GetTrimBox(pSrcPageDict)); - // TODO(xlou): add matrix field to pNewXObjectDict. + CPDF_Object* pDirect = pRef->GetDirect(); + if (!pDirect) + return 0; - if (CPDF_Array* pSrcContentArray = ToArray(pSrcContentObj)) { - ByteString bsSrcContentStream; - for (size_t i = 0; i < pSrcContentArray->GetCount(); ++i) { - CPDF_Stream* pStream = pSrcContentArray->GetStreamAt(i); - auto pAcc = pdfium::MakeRetain(pStream); - pAcc->LoadAllDataFiltered(); - ByteString bsStream(pAcc->GetData(), pAcc->GetSize()); - bsSrcContentStream += bsStream; - bsSrcContentStream += "\n"; + std::unique_ptr pClone = pDirect->Clone(); + if (CPDF_Dictionary* pDictClone = pClone->AsDictionary()) { + if (pDictClone->KeyExist("Type")) { + ByteString strType = pDictClone->GetStringFor("Type"); + if (!FXSYS_stricmp(strType.c_str(), "Pages")) + return 4; + if (!FXSYS_stricmp(strType.c_str(), "Page")) + return 0; } - pNewXObject->SetDataAndRemoveFilter(bsSrcContentStream.raw_str(), - bsSrcContentStream.GetLength()); - } else { - CPDF_Stream* pStream = pSrcContentObj->AsStream(); - auto pAcc = pdfium::MakeRetain(pStream); - pAcc->LoadAllDataFiltered(); - ByteString bsStream(pAcc->GetData(), pAcc->GetSize()); - pNewXObject->SetDataAndRemoveFilter(bsStream.raw_str(), - bsStream.GetLength()); } + CPDF_Object* pUnownedClone = dest()->AddIndirectObject(std::move(pClone)); + dwNewObjNum = pUnownedClone->GetObjNum(); + (*pObjNumberMap)[dwObjnum] = dwNewObjNum; + if (!UpdateReference(pUnownedClone, pObjNumberMap)) + return 0; - return pNewXObject->GetObjNum(); + return dwNewObjNum; } -// static -void CPDF_PageOrganizer::SetMediaBox(CPDF_Dictionary* pDestPageDict, - const CFX_SizeF& pagesize) { - CPDF_Array* pArray = pDestPageDict->SetNewFor("MediaBox"); - pArray->AddNew(0); - pArray->AddNew(0); - pArray->AddNew(pagesize.width); - pArray->AddNew(pagesize.height); -} +// Copies pages from a source document into a destination document. +// This class is intended to be used once via ExportPage() and then destroyed. +class CPDF_PageExporter : public CPDF_PageOrganizer { + public: + CPDF_PageExporter(CPDF_Document* pDestPDFDoc, CPDF_Document* pSrcPDFDoc); + ~CPDF_PageExporter(); + + // For the pages from the source document with |pageNums| as their page + // numbers, insert them into the destination document at page |nIndex|. + // |pageNums| is 1-based. + // |nIndex| is 0-based. + bool ExportPage(const std::vector& pageNums, int nIndex); +}; + +CPDF_PageExporter::CPDF_PageExporter(CPDF_Document* pDestPDFDoc, + CPDF_Document* pSrcPDFDoc) + : CPDF_PageOrganizer(pDestPDFDoc, pSrcPDFDoc) {} + +CPDF_PageExporter::~CPDF_PageExporter() = default; + +bool CPDF_PageExporter::ExportPage(const std::vector& pageNums, + int nIndex) { + if (!PDFDocInit()) + return false; -bool CPDF_PageOrganizer::ExportPage(const std::vector& pageNums, - int nIndex) { int curpage = nIndex; auto pObjNumberMap = pdfium::MakeUnique(); for (size_t i = 0; i < pageNums.size(); ++i) { @@ -545,46 +531,82 @@ bool CPDF_PageOrganizer::ExportPage(const std::vector& pageNums, return true; } -void CPDF_PageOrganizer::FinishPage(CPDF_Dictionary* pCurPageDict, - const ByteString& bsContent, - XObjectNameNumberMap* pXObjNameNumberMap) { - ASSERT(pCurPageDict); +// Copies pages from a source document into a destination document. Creates 1 +// page in the destination document for every N source pages. This class is +// intended to be used once via ExportNPagesToOne() and then destroyed. +class CPDF_NPageToOneExporter : public CPDF_PageOrganizer { + public: + CPDF_NPageToOneExporter(CPDF_Document* pDestPDFDoc, + CPDF_Document* pSrcPDFDoc); + ~CPDF_NPageToOneExporter(); + + // For the pages from the source document with |pageNums| as their page + // numbers, insert them into the destination document, starting at page 0. + // |pageNums| is 1-based. + // |destPageWidth| and |destPageHeight| are the destination document page + // dimensions, measured in pixels. + // |numPagesOnXAxis| and |numPagesOnXAxis| together defines how many source + // pages fit on one destination page. + bool ExportNPagesToOne(const std::vector& pageNums, + float destPageWidth, + float destPageHeight, + unsigned int numPagesOnXAxis, + unsigned int numPagesOnYAxis); - CPDF_Dictionary* pRes = pCurPageDict->GetDictFor("Resources"); - if (!pRes) - pRes = pCurPageDict->SetNewFor("Resources"); + private: + // Map page object number to XObject object name. + using PageXObjectMap = std::map; + // Map XObject's object name to it's object number. + using XObjectNameNumberMap = std::map; - CPDF_Dictionary* pPageXObject = pRes->GetDictFor("XObject"); - if (!pPageXObject) - pPageXObject = pRes->SetNewFor("XObject"); + static void SetMediaBox(CPDF_Dictionary* pDestPageDict, + const CFX_SizeF& pagesize); - for (auto& it : *pXObjNameNumberMap) { - pPageXObject->SetNewFor(it.first, dest(), it.second); - } + // Creates a xobject from the source page dictionary, and appends the + // bsContent string with the xobject reference surrounded by the + // transformation matrix. + void AddSubPage(CPDF_Dictionary* pPageDict, + const CFX_PointF& position, + float scale, + ObjectNumberMap* pObjNumberMap, + PageXObjectMap* pPageXObjectMap, + XObjectNameNumberMap* pXObjNameNumberMap, + ByteString* bsContent); + uint32_t MakeXObject(CPDF_Dictionary* pSrcPageDict, + ObjectNumberMap* pObjNumberMap, + CPDF_Document* pDestDoc); - auto pDict = pdfium::MakeUnique(dest()->GetByteStringPool()); - CPDF_Stream* pStream = - dest()->NewIndirect(nullptr, 0, std::move(pDict)); - pStream->SetData(bsContent.raw_str(), bsContent.GetLength()); - pCurPageDict->SetNewFor("Contents", dest(), - pStream->GetObjNum()); -} + void FinishPage(CPDF_Dictionary* pCurPageDict, + const ByteString& bsContent, + XObjectNameNumberMap* pXObjNameNumberMap); + + uint32_t m_xobjectNum = 0; + CFX_SizeF m_pageSize; + XObjectNameNumberMap m_xobjs; +}; + +CPDF_NPageToOneExporter::CPDF_NPageToOneExporter(CPDF_Document* pDestPDFDoc, + CPDF_Document* pSrcPDFDoc) + : CPDF_PageOrganizer(pDestPDFDoc, pSrcPDFDoc) {} -bool CPDF_PageOrganizer::ExportNPagesToOne( +CPDF_NPageToOneExporter::~CPDF_NPageToOneExporter() = default; + +bool CPDF_NPageToOneExporter::ExportNPagesToOne( const std::vector& pageNums, float destPageWidth, float destPageHeight, unsigned int numPagesOnXAxis, unsigned int numPagesOnYAxis) { + if (!PDFDocInit()) + return false; + FX_SAFE_SIZE_T safe_numPagesPerSheet = numPagesOnXAxis; safe_numPagesPerSheet *= numPagesOnYAxis; - if (!safe_numPagesPerSheet.IsValid()) return false; size_t numPagesPerSheet = safe_numPagesPerSheet.ValueOrDie(); - if (numPagesPerSheet == 1) - return ExportPage(pageNums, 0); + // Mapping of source page object number and XObject object number. // Used to update refernece. ObjectNumberMap objectNumberMap; @@ -632,96 +654,128 @@ bool CPDF_PageOrganizer::ExportNPagesToOne( return true; } -bool CPDF_PageOrganizer::UpdateReference(CPDF_Object* pObj, - ObjectNumberMap* pObjNumberMap) { - switch (pObj->GetType()) { - case CPDF_Object::REFERENCE: { - CPDF_Reference* pReference = pObj->AsReference(); - uint32_t newobjnum = GetNewObjId(pObjNumberMap, pReference); - if (newobjnum == 0) - return false; - pReference->SetRef(dest(), newobjnum); - break; - } - case CPDF_Object::DICTIONARY: { - CPDF_Dictionary* pDict = pObj->AsDictionary(); - auto it = pDict->begin(); - while (it != pDict->end()) { - const ByteString& key = it->first; - CPDF_Object* pNextObj = it->second.get(); - ++it; - if (key == "Parent" || key == "Prev" || key == "First") - continue; - if (!pNextObj) - return false; - if (!UpdateReference(pNextObj, pObjNumberMap)) - pDict->RemoveFor(key); - } - break; - } - case CPDF_Object::ARRAY: { - CPDF_Array* pArray = pObj->AsArray(); - for (size_t i = 0; i < pArray->GetCount(); ++i) { - CPDF_Object* pNextObj = pArray->GetObjectAt(i); - if (!pNextObj) - return false; - if (!UpdateReference(pNextObj, pObjNumberMap)) - return false; - } - break; - } - case CPDF_Object::STREAM: { - CPDF_Stream* pStream = pObj->AsStream(); - CPDF_Dictionary* pDict = pStream->GetDict(); - if (!pDict) - return false; - if (!UpdateReference(pDict, pObjNumberMap)) - return false; - break; - } - default: - break; +// static +void CPDF_NPageToOneExporter::SetMediaBox(CPDF_Dictionary* pDestPageDict, + const CFX_SizeF& pagesize) { + CPDF_Array* pArray = pDestPageDict->SetNewFor("MediaBox"); + pArray->AddNew(0); + pArray->AddNew(0); + pArray->AddNew(pagesize.width); + pArray->AddNew(pagesize.height); +} + +void CPDF_NPageToOneExporter::AddSubPage( + CPDF_Dictionary* pPageDict, + const CFX_PointF& position, + float scale, + ObjectNumberMap* pObjNumberMap, + PageXObjectMap* pPageXObjectMap, + XObjectNameNumberMap* pXObjNameNumberMap, + ByteString* bsContent) { + uint32_t dwPageObjnum = pPageDict->GetObjNum(); + ByteString bsXObjectName; + const auto it = pPageXObjectMap->find(dwPageObjnum); + if (it != pPageXObjectMap->end()) { + bsXObjectName = it->second; + } else { + ++m_xobjectNum; + // TODO(Xlou): A better name schema to avoid possible object name collision. + bsXObjectName = ByteString::Format("X%d", m_xobjectNum); + m_xobjs[bsXObjectName] = MakeXObject(pPageDict, pObjNumberMap, dest()); + (*pPageXObjectMap)[dwPageObjnum] = bsXObjectName; } + (*pXObjNameNumberMap)[bsXObjectName] = m_xobjs[bsXObjectName]; - return true; + CFX_Matrix matrix; + matrix.Scale(scale, scale); + matrix.Translate(position.x, position.y); + + std::ostringstream contentStream; + contentStream << "q\n" + << matrix.a << " " << matrix.b << " " << matrix.c << " " + << matrix.d << " " << matrix.e << " " << matrix.f << " cm\n" + << "/" << bsXObjectName << " Do Q\n"; + *bsContent += ByteString(contentStream); } -uint32_t CPDF_PageOrganizer::GetNewObjId(ObjectNumberMap* pObjNumberMap, - CPDF_Reference* pRef) { - if (!pRef) - return 0; +uint32_t CPDF_NPageToOneExporter::MakeXObject(CPDF_Dictionary* pSrcPageDict, + ObjectNumberMap* pObjNumberMap, + CPDF_Document* pDestDoc) { + ASSERT(pSrcPageDict); - uint32_t dwObjnum = pRef->GetRefObjNum(); - uint32_t dwNewObjNum = 0; - const auto it = pObjNumberMap->find(dwObjnum); - if (it != pObjNumberMap->end()) - dwNewObjNum = it->second; - if (dwNewObjNum) - return dwNewObjNum; + CPDF_Object* pSrcContentObj = GetPageOrganizerPageContent(pSrcPageDict); + CPDF_Stream* pNewXObject = pDestDoc->NewIndirect( + nullptr, 0, + pdfium::MakeUnique(pDestDoc->GetByteStringPool())); + CPDF_Dictionary* pNewXObjectDict = pNewXObject->GetDict(); + const ByteString bsResourceString = "Resources"; + if (!CopyInheritable(pNewXObjectDict, pSrcPageDict, bsResourceString)) { + // Use a default empty resources if it does not exist. + pNewXObjectDict->SetNewFor(bsResourceString); + } + uint32_t dwSrcPageObj = pSrcPageDict->GetObjNum(); + uint32_t dwNewXobjectObj = pNewXObjectDict->GetObjNum(); + (*pObjNumberMap)[dwSrcPageObj] = dwNewXobjectObj; + UpdateReference(pNewXObjectDict, pObjNumberMap); - CPDF_Object* pDirect = pRef->GetDirect(); - if (!pDirect) - return 0; + pNewXObjectDict->SetNewFor("Type", "XObject"); + pNewXObjectDict->SetNewFor("Subtype", "Form"); + pNewXObjectDict->SetNewFor("FormType", 1); + pNewXObjectDict->SetRectFor("BBox", GetTrimBox(pSrcPageDict)); + // TODO(xlou): add matrix field to pNewXObjectDict. - std::unique_ptr pClone = pDirect->Clone(); - if (CPDF_Dictionary* pDictClone = pClone->AsDictionary()) { - if (pDictClone->KeyExist("Type")) { - ByteString strType = pDictClone->GetStringFor("Type"); - if (!FXSYS_stricmp(strType.c_str(), "Pages")) - return 4; - if (!FXSYS_stricmp(strType.c_str(), "Page")) - return 0; + if (CPDF_Array* pSrcContentArray = ToArray(pSrcContentObj)) { + ByteString bsSrcContentStream; + for (size_t i = 0; i < pSrcContentArray->GetCount(); ++i) { + CPDF_Stream* pStream = pSrcContentArray->GetStreamAt(i); + auto pAcc = pdfium::MakeRetain(pStream); + pAcc->LoadAllDataFiltered(); + ByteString bsStream(pAcc->GetData(), pAcc->GetSize()); + bsSrcContentStream += bsStream; + bsSrcContentStream += "\n"; } + pNewXObject->SetDataAndRemoveFilter(bsSrcContentStream.raw_str(), + bsSrcContentStream.GetLength()); + } else { + CPDF_Stream* pStream = pSrcContentObj->AsStream(); + auto pAcc = pdfium::MakeRetain(pStream); + pAcc->LoadAllDataFiltered(); + ByteString bsStream(pAcc->GetData(), pAcc->GetSize()); + pNewXObject->SetDataAndRemoveFilter(bsStream.raw_str(), + bsStream.GetLength()); } - CPDF_Object* pUnownedClone = dest()->AddIndirectObject(std::move(pClone)); - dwNewObjNum = pUnownedClone->GetObjNum(); - (*pObjNumberMap)[dwObjnum] = dwNewObjNum; - if (!UpdateReference(pUnownedClone, pObjNumberMap)) - return 0; - return dwNewObjNum; + return pNewXObject->GetObjNum(); +} + +void CPDF_NPageToOneExporter::FinishPage( + CPDF_Dictionary* pCurPageDict, + const ByteString& bsContent, + XObjectNameNumberMap* pXObjNameNumberMap) { + ASSERT(pCurPageDict); + + CPDF_Dictionary* pRes = pCurPageDict->GetDictFor("Resources"); + if (!pRes) + pRes = pCurPageDict->SetNewFor("Resources"); + + CPDF_Dictionary* pPageXObject = pRes->GetDictFor("XObject"); + if (!pPageXObject) + pPageXObject = pRes->SetNewFor("XObject"); + + for (auto& it : *pXObjNameNumberMap) { + pPageXObject->SetNewFor(it.first, dest(), it.second); + } + + auto pDict = pdfium::MakeUnique(dest()->GetByteStringPool()); + CPDF_Stream* pStream = + dest()->NewIndirect(nullptr, 0, std::move(pDict)); + pStream->SetData(bsContent.raw_str(), bsContent.GetLength()); + pCurPageDict->SetNewFor("Contents", dest(), + pStream->GetObjNum()); } +} // namespace + FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_ImportPages(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc, FPDF_BYTESTRING pagerange, @@ -738,12 +792,8 @@ FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_ImportPages(FPDF_DOCUMENT dest_doc, if (page_numbers.empty()) return false; - CPDF_PageOrganizer pageOrg(pDestDoc, pSrcDoc); - - if (!pageOrg.PDFDocInit()) - return false; - - return pageOrg.ExportPage(page_numbers, index); + CPDF_PageExporter exporter(pDestDoc, pSrcDoc); + return exporter.ExportPage(page_numbers, index); } FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV @@ -773,13 +823,18 @@ FPDF_ImportNPagesToOne(FPDF_DOCUMENT src_doc, if (page_numbers.empty()) return nullptr; - CPDF_PageOrganizer pageOrg(pDestDoc, pSrcDoc); - if (!pageOrg.PDFDocInit() || - !pageOrg.ExportNPagesToOne(page_numbers, output_width, output_height, - num_pages_on_x_axis, num_pages_on_y_axis)) { - return nullptr; + if (num_pages_on_x_axis == 1 && num_pages_on_y_axis == 1) { + CPDF_PageExporter exporter(pDestDoc, pSrcDoc); + if (!exporter.ExportPage(page_numbers, 0)) + return nullptr; + return output_doc.release(); } + CPDF_NPageToOneExporter exporter(pDestDoc, pSrcDoc); + if (!exporter.ExportNPagesToOne(page_numbers, output_width, output_height, + num_pages_on_x_axis, num_pages_on_y_axis)) { + return nullptr; + } return output_doc.release(); } -- cgit v1.2.3