From 8a69fc72eb98431b6f14f2ec72779d029cbf8de7 Mon Sep 17 00:00:00 2001 From: Alastair Carey Date: Sat, 9 Mar 2024 15:57:08 +0000 Subject: [PATCH] Resolves #140 --- Cargo.toml | 2 +- README.md | 16 ++++++++++++---- src/page.rs | 50 ++++++++++++++++++++++++++++++++------------------ 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5031f2b..e662c42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pdfium-render" -version = "0.8.18" +version = "0.8.19" edition = "2018" publish = true description = "A high-level idiomatic Rust wrapper around Pdfium, the C++ PDF library used by the Google Chromium project." diff --git a/README.md b/README.md index 15e9067..7a1731e 100644 --- a/README.md +++ b/README.md @@ -83,10 +83,14 @@ available at . T _Note: upcoming release 0.9.0 will remove all deprecated items. For a complete list of deprecated items, see ._ -Release 0.8.19 adds support for creating new annotations, positioning those annotations, +Release 0.8.20 adds support for creating new annotations, positioning those annotations, associating them with page objects, and retrieving and setting more annotation properties for each annotation type. A new `examples/create_annotations.rs` example demonstrates the extended functionality. +Release 0.8.19 fixes a bug in `PdfPage::flatten()` that prevented the effect of the flatten operation +from taking effect until the page was dropped and reloaded. The effect of the flatten operation +is now immediately available. + Releases 0.8.17 and 0.8.18 adjust the WASM implementation of `pdfium-render` to account for some small packaging changes in the upstream releases of Pdfium published at ; release 0.8.17 also fixes a potential segmentation fault that could occur when dropping a `PdfDocument` @@ -345,7 +349,7 @@ functions specific to interactive scripting, user interaction, and printing. * Releases numbered 0.8.x aim to progressively add support for all remaining Pdfium editing functions to `pdfium-render`. * Releases numbered 0.9.x aim to fill any remaining gaps in the high-level interface prior to 1.0. -There are 368 `FPDF_*` functions in the Pdfium API. As of version 0.8.18, 325 (88%) have +There are 368 `FPDF_*` functions in the Pdfium API. As of version 0.8.19, 325 (88%) have bindings available in `PdfiumLibraryBindings`, with the functionality of the majority of these available via the `pdfium-render` high-level interface. @@ -358,7 +362,7 @@ at . ## Version history -* 0.8.19: adds `PdfPageAnnotationAttachmentPoints` struct and matching iterator; adds new annotation functions +* 0.8.20: adds `PdfPageAnnotationAttachmentPoints` struct and matching iterator; adds new annotation functions to `PdfPageAnnotationCommon` along with their matching implementations in `PdfPageAnnotationPrivate`, including `PdfPageAnnotationCommon::set_bounds()`, `PdfPageAnnotationCommon::set_position()`, `PdfPageAnnotationCommon::set_width()`, `PdfPageAnnotationCommon::set_height()`, @@ -369,7 +373,11 @@ at . `chrono::DateTime` types to PDF date strings in `utils::dates`; adds mutability and annotation creation functions to `PdfPageAnnotations` collection; adds new `create_annotations.rs` example; adds `PdfPageTextSegment::chars()` convenience function. -* 0.8.18: Adjusts `PdfiumRenderWasmState::bind_to_pdfium()` to fall back to +* 0.8.19: adjusts the behaviour of `PdfPage::flatten()` so that the page is reloaded after the + call to `FPDFPage_Flatten()`. This ensures that the effect of the flatten operation is immediately + visible to the caller; previously, it was necessary for the caller to drop and reload the page + themselves. For more details, see . +* 0.8.18: adjusts `PdfiumRenderWasmState::bind_to_pdfium()` to fall back to `Module["wasmExports"]["__indirect_function_table"]` if `Window.wasmTable` global variable is not available, in response to upstream packaging changes at . For more details, see diff --git a/src/page.rs b/src/page.rs index 46302ad..7497a73 100644 --- a/src/page.rs +++ b/src/page.rs @@ -849,22 +849,7 @@ impl<'a> PdfPage<'a> { // transformation to take effect. For more information, see: // https://github.com/ajrcarey/pdfium-render/issues/93 - if let Some(page_index) = - PdfPageIndexCache::get_index_for_page(self.document_handle, self.page_handle) - { - self.drop_impl(); - - self.page_handle = self - .bindings - .FPDF_LoadPage(self.document_handle, page_index as c_int); - - PdfPageIndexCache::set_index_for_page( - self.document_handle, - self.page_handle, - page_index, - ); - } - + self.reload_in_place(); Ok(()) } else { Err(PdfiumError::PdfiumLibraryInternalError( @@ -915,9 +900,16 @@ impl<'a> PdfPage<'a> { .FPDFPage_Flatten(self.page_handle, flag as c_int) as u32 { FLATTEN_SUCCESS => { - self.is_content_regeneration_required = true; + self.regenerate_content()?; - self.regenerate_content() + // As noted at https://bugs.chromium.org/p/pdfium/issues/detail?id=2055, + // FPDFPage_Flatten() updates the underlying dictionaries and content streams for + // the page, but does not update the FPDF_Page structure. We must reload the + // page for the effects of the flatten operation to be visible. For more information, see: + // https://github.com/ajrcarey/pdfium-render/issues/140 + + self.reload_in_place(); + Ok(()) } FLATTEN_NOTHINGTODO => Ok(()), FLATTEN_FAIL => Err(PdfiumError::PageFlattenFailure), @@ -1025,6 +1017,28 @@ impl<'a> PdfPage<'a> { } } + /// Reloads the page transparently to any caller, forcing a refresh of all page data structures. + /// This will replace this page's `FPDF_PAGE` handle. The page index cache will be updated. + fn reload_in_place(&mut self) { + if let Some(page_index) = + PdfPageIndexCache::get_index_for_page(self.document_handle, self.page_handle) + { + self.drop_impl(); + + self.page_handle = self + .bindings + .FPDF_LoadPage(self.document_handle, page_index as c_int); + + PdfPageIndexCache::set_index_for_page( + self.document_handle, + self.page_handle, + page_index, + ); + } + } + + /// Drops the page by calling `FPDF_ClosePage()`, freeing held memory. This will invalidate + /// this page's `FPDF_PAGE` handle. The page index cache will be updated. fn drop_impl(&mut self) { if self.regeneration_strategy != PdfPageContentRegenerationStrategy::Manual && self.is_content_regeneration_required