Add experimental FPDF_ImportPagesByIndex() API
Introduce an FPDF_ImportPages() alternative that takes an array of
indices for the pages to import, instead of a string of page ranges.
Bug: chromium:1200000
Change-Id: I2e7b39e464ca46e113b7223c4c11458de243762e
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/81810
Commit-Queue: Daniel Hosseinian <dhoss@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/fpdfsdk/fpdf_ppo.cpp b/fpdfsdk/fpdf_ppo.cpp
index 3e46ed8..614e5ab 100644
--- a/fpdfsdk/fpdf_ppo.cpp
+++ b/fpdfsdk/fpdf_ppo.cpp
@@ -680,6 +680,37 @@
} // namespace
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDF_ImportPagesByIndex(FPDF_DOCUMENT dest_doc,
+ FPDF_DOCUMENT src_doc,
+ const int* page_indices,
+ unsigned long length,
+ int index) {
+ CPDF_Document* pDestDoc = CPDFDocumentFromFPDFDocument(dest_doc);
+ if (!dest_doc)
+ return false;
+
+ CPDF_Document* pSrcDoc = CPDFDocumentFromFPDFDocument(src_doc);
+ if (!pSrcDoc)
+ return false;
+
+ CPDF_PageExporter exporter(pDestDoc, pSrcDoc);
+
+ if (!page_indices) {
+ std::vector<uint32_t> page_indices_vec(pSrcDoc->GetPageCount());
+ std::iota(page_indices_vec.begin(), page_indices_vec.end(), 0);
+ return exporter.ExportPage(page_indices_vec, index);
+ }
+
+ if (length == 0)
+ return false;
+
+ return exporter.ExportPage(
+ pdfium::make_span(reinterpret_cast<const uint32_t*>(page_indices),
+ length),
+ index);
+}
+
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_ImportPages(FPDF_DOCUMENT dest_doc,
FPDF_DOCUMENT src_doc,
FPDF_BYTESTRING pagerange,
diff --git a/fpdfsdk/fpdf_ppo_embeddertest.cpp b/fpdfsdk/fpdf_ppo_embeddertest.cpp
index e063737..84d52e9 100644
--- a/fpdfsdk/fpdf_ppo_embeddertest.cpp
+++ b/fpdfsdk/fpdf_ppo_embeddertest.cpp
@@ -12,6 +12,7 @@
#include "public/fpdfview.h"
#include "testing/embedder_test.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/base/stl_util.h"
namespace {
@@ -43,6 +44,25 @@
FPDF_CloseDocument(output_doc);
}
+TEST_F(FPDFPPOEmbedderTest, ImportPagesByIndex) {
+ ASSERT_TRUE(OpenDocument("viewer_ref.pdf"));
+
+ FPDF_PAGE page = LoadPage(0);
+ EXPECT_TRUE(page);
+
+ ScopedFPDFDocument output_doc(FPDF_CreateNewDocument());
+ ASSERT_TRUE(output_doc);
+ EXPECT_TRUE(FPDF_CopyViewerPreferences(output_doc.get(), document()));
+
+ static constexpr int kPageIndices[] = {1};
+ EXPECT_TRUE(FPDF_ImportPagesByIndex(output_doc.get(), document(),
+ kPageIndices, pdfium::size(kPageIndices),
+ 0));
+ EXPECT_EQ(1, FPDF_GetPageCount(output_doc.get()));
+
+ UnloadPage(page);
+}
+
TEST_F(FPDFPPOEmbedderTest, ImportPages) {
ASSERT_TRUE(OpenDocument("viewer_ref.pdf"));
@@ -160,6 +180,79 @@
FPDF_CloseDocument(output_doc);
}
+TEST_F(FPDFPPOEmbedderTest, BadIndices) {
+ ASSERT_TRUE(OpenDocument("hello_world.pdf"));
+
+ FPDF_PAGE page = LoadPage(0);
+ EXPECT_TRUE(page);
+
+ ScopedFPDFDocument output_doc(FPDF_CreateNewDocument());
+ EXPECT_TRUE(output_doc);
+
+ static constexpr int kBadIndices1[] = {-1};
+ EXPECT_FALSE(FPDF_ImportPagesByIndex(output_doc.get(), document(),
+ kBadIndices1, pdfium::size(kBadIndices1),
+ 0));
+
+ static constexpr int kBadIndices2[] = {1};
+ EXPECT_FALSE(FPDF_ImportPagesByIndex(output_doc.get(), document(),
+ kBadIndices2, pdfium::size(kBadIndices2),
+ 0));
+
+ static constexpr int kBadIndices3[] = {-1, 0, 1};
+ EXPECT_FALSE(FPDF_ImportPagesByIndex(output_doc.get(), document(),
+ kBadIndices3, pdfium::size(kBadIndices3),
+ 0));
+
+ static constexpr int kBadIndices4[] = {42};
+ EXPECT_FALSE(FPDF_ImportPagesByIndex(output_doc.get(), document(),
+ kBadIndices4, pdfium::size(kBadIndices4),
+ 0));
+
+ UnloadPage(page);
+}
+
+TEST_F(FPDFPPOEmbedderTest, GoodIndices) {
+ ASSERT_TRUE(OpenDocument("viewer_ref.pdf"));
+
+ FPDF_PAGE page = LoadPage(0);
+ EXPECT_TRUE(page);
+
+ ScopedFPDFDocument output_doc(FPDF_CreateNewDocument());
+ EXPECT_TRUE(output_doc);
+
+ static constexpr int kGoodIndices1[] = {0, 0, 0, 0};
+ EXPECT_TRUE(FPDF_ImportPagesByIndex(output_doc.get(), document(),
+ kGoodIndices1,
+ pdfium::size(kGoodIndices1), 0));
+ EXPECT_EQ(4, FPDF_GetPageCount(output_doc.get()));
+
+ static constexpr int kGoodIndices2[] = {0};
+ EXPECT_TRUE(FPDF_ImportPagesByIndex(output_doc.get(), document(),
+ kGoodIndices2,
+ pdfium::size(kGoodIndices2), 0));
+ EXPECT_EQ(5, FPDF_GetPageCount(output_doc.get()));
+
+ static constexpr int kGoodIndices3[] = {4};
+ EXPECT_TRUE(FPDF_ImportPagesByIndex(output_doc.get(), document(),
+ kGoodIndices3,
+ pdfium::size(kGoodIndices3), 0));
+ EXPECT_EQ(6, FPDF_GetPageCount(output_doc.get()));
+
+ static constexpr int kGoodIndices4[] = {1, 2, 3};
+ EXPECT_TRUE(FPDF_ImportPagesByIndex(output_doc.get(), document(),
+ kGoodIndices4,
+ pdfium::size(kGoodIndices4), 0));
+ EXPECT_EQ(9, FPDF_GetPageCount(output_doc.get()));
+
+ // Passing in a nullptr should import all the pages.
+ EXPECT_TRUE(
+ FPDF_ImportPagesByIndex(output_doc.get(), document(), nullptr, 0, 0));
+ EXPECT_EQ(14, FPDF_GetPageCount(output_doc.get()));
+
+ UnloadPage(page);
+}
+
TEST_F(FPDFPPOEmbedderTest, BadRanges) {
ASSERT_TRUE(OpenDocument("hello_world.pdf"));
@@ -213,7 +306,10 @@
FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument();
EXPECT_TRUE(output_doc);
- EXPECT_TRUE(FPDF_ImportPages(output_doc, document(), "1", 0));
+
+ static constexpr int kIndices[] = {0};
+ EXPECT_TRUE(FPDF_ImportPagesByIndex(output_doc, document(), kIndices,
+ pdfium::size(kIndices), 0));
FPDF_CloseDocument(output_doc);
UnloadPage(page);
@@ -248,7 +344,10 @@
FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument();
ASSERT_TRUE(output_doc);
- EXPECT_TRUE(FPDF_ImportPages(output_doc, document(), "1,2,3,4", 0));
+
+ static constexpr int kIndices[] = {0, 1, 2, 3};
+ EXPECT_TRUE(FPDF_ImportPagesByIndex(output_doc, document(), kIndices,
+ pdfium::size(kIndices), 0));
ASSERT_EQ(4, FPDF_GetPageCount(output_doc));
for (size_t i = 0; i < 4; ++i) {
FPDF_PAGE page = FPDF_LoadPage(output_doc, i);
@@ -280,7 +379,10 @@
FPDF_DOCUMENT new_doc = FPDF_CreateNewDocument();
EXPECT_TRUE(new_doc);
- EXPECT_TRUE(FPDF_ImportPages(new_doc, document(), "1", 0));
+
+ static constexpr int kIndices[] = {0};
+ EXPECT_TRUE(FPDF_ImportPagesByIndex(new_doc, document(), kIndices,
+ pdfium::size(kIndices), 0));
EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c
index 2a68e11..7297b61 100644
--- a/fpdfsdk/fpdf_view_c_api_test.c
+++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -309,6 +309,7 @@
CHK(FPDF_CopyViewerPreferences);
CHK(FPDF_ImportNPagesToOne);
CHK(FPDF_ImportPages);
+ CHK(FPDF_ImportPagesByIndex);
// fpdf_progressive.h
CHK(FPDF_RenderPageBitmapWithColorScheme_Start);
diff --git a/public/fpdf_ppo.h b/public/fpdf_ppo.h
index e9f3f66..d27b788 100644
--- a/public/fpdf_ppo.h
+++ b/public/fpdf_ppo.h
@@ -14,15 +14,38 @@
extern "C" {
#endif
+// Experimental API.
+// Import pages to a FPDF_DOCUMENT.
+//
+// dest_doc - The destination document for the pages.
+// src_doc - The document to be imported.
+// page_indices - An array of page indices to be imported. The first page is
+// zero. If |page_indices| is NULL, all pages from |src_doc|
+// are imported.
+// length - The length of the |page_indices| array.
+// index - The page index at which to insert the first imported page
+// into |dest_doc|. The first page is zero.
+//
+// Returns TRUE on success. Returns FALSE if any pages in |page_indices| is
+// invalid.
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDF_ImportPagesByIndex(FPDF_DOCUMENT dest_doc,
+ FPDF_DOCUMENT src_doc,
+ const int* page_indices,
+ unsigned long length,
+ int index);
+
// Import pages to a FPDF_DOCUMENT.
//
// dest_doc - The destination document for the pages.
// src_doc - The document to be imported.
-// pagerange - A page range string, Such as "1,3,5-7". If |pagerange| is NULL,
-// all pages from |src_doc| are imported.
-// index - The page index to insert at.
+// pagerange - A page range string, Such as "1,3,5-7". The first page is one.
+// If |pagerange| is NULL, all pages from |src_doc| are imported.
+// index - The page index at which to insert the first imported page into
+// |dest_doc|. The first page is zero.
//
-// Returns TRUE on success.
+// Returns TRUE on success. Returns FALSE if any pages in |pagerange| is
+// invalid or if |pagerange| cannot be read.
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_ImportPages(FPDF_DOCUMENT dest_doc,
FPDF_DOCUMENT src_doc,
FPDF_BYTESTRING pagerange,