Skip to content

Commit

Permalink
Resolves #154
Browse files Browse the repository at this point in the history
  • Loading branch information
Alastair Carey committed Aug 11, 2024
1 parent 876842d commit 6d76ba6
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 80 deletions.
146 changes: 74 additions & 72 deletions examples/index.html
Original file line number Diff line number Diff line change
@@ -1,101 +1,103 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="pdfium.js"></script>
<script src="pdfium_render_wasm_example.js"></script>
</head>

<body>
<canvas id="canvas" style="max-width: 100%; height: auto; border: 1px solid black;"></canvas>
<head>
<meta charset="utf-8" />
<script src="pdfium.js"></script>
<script src="pdfium_render_wasm_example.js"></script>
</head>

<script>
// The Rust sample code that accompanies this file can be found in wasm.rs.
<body>
<canvas id="canvas" style="max-width: 100%; height: auto; border: 1px solid black;"></canvas>

// We export two functions from our Rust code via #[wasm_bindgen] declarations.
// We'll call these two functions below from Javascript - but first, we need to get
// the WASM modules for Pdfium and pdfium-render talking to each other.
<script>
// The Rust sample code that accompanies this file can be found in wasm.rs.

// First, we initialize Pdfium's Emscripten-wrapped WASM module. The exact way in which
// we do this depends on the way in which the Pdfium WASM module was built.
// For Pdfium WASM modules downloaded from https://github.com/paulocoutinhox/pdfium-lib/releases
// _before_ version V5407, the Pdfium WASM module can be initialized like this:
// We export two functions from our Rust code via #[wasm_bindgen] declarations.
// We'll call these two functions below from Javascript - but first, we need to get
// the WASM modules for Pdfium and pdfium-render talking to each other.

// Module.onRuntimeInitialized = (async _ => {
// pdfiumModule = Module;
// First, we initialize Pdfium's Emscripten-wrapped WASM module. The exact way in which
// we do this depends on the way in which the Pdfium WASM module was built.
// For Pdfium WASM modules downloaded from https://github.com/paulocoutinhox/pdfium-lib/releases
// _before_ version V5407, the Pdfium WASM module can be initialized like this:

// For Pdfium WASM modules downloaded from https://github.com/paulocoutinhox/pdfium-lib/releases
// _after or including_ version V5407, the Pdfium WASM module can be initialized like this:
// Module.onRuntimeInitialized = (async _ => {
// pdfiumModule = Module;

// PDFiumModule().then(async pdfiumModule => {
// For Pdfium WASM modules downloaded from https://github.com/paulocoutinhox/pdfium-lib/releases
// _after or including_ version V5407, the Pdfium WASM module can be initialized like this:

// No other changes are required. The remainder of this example assumes we are using
// V5407 or later.
// PDFiumModule().then(async pdfiumModule => {

PDFiumModule().then(async pdfiumModule => {
// Pdfium's WASM module has now been loaded and initialized. We need to tell
// pdfium-render about Pdfium's WASM module, so it can bind to the Pdfium API
// functions exported by the module.
// No other changes are required. The remainder of this example assumes we are using
// V5407 or later.

// In addition to any functions exported by our Rust application, pdfium-render will
// always export an initialization function, initialize_pdfium_render(),
// which _must_ be called from Javascript prior to the use of any Pdfium functionality.
PDFiumModule().then(async pdfiumModule => {
// Pdfium's WASM module has now been loaded and initialized. We need to tell
// pdfium-render about Pdfium's WASM module, so it can bind to the Pdfium API
// functions exported by the module.

const {
initialize_pdfium_render, // Always provided by pdfium-render
log_page_metrics_to_console, // Defined by us ...
get_image_data_for_page // ... in examples/wasm.rs
} = wasm_bindgen;
// In addition to any functions exported by our Rust application, pdfium-render will
// always export an initialization function, initialize_pdfium_render(),
// which _must_ be called from Javascript prior to the use of any Pdfium functionality.

// Next, we load the WASM module generated by wasm-pack that contains our Rust
// application and pdfium-render.
const {
initialize_pdfium_render, // Always provided by pdfium-render
log_page_metrics_to_console, // Defined by us ...
get_image_data_for_page // ... in examples/wasm.rs
} = wasm_bindgen;

wasm_bindgen('pdfium_render_wasm_example_bg.wasm').then(async rustModule => {
// The functions exported by our Rust application are now loaded and available.
// Next, we load the WASM module generated by wasm-pack that contains our Rust
// application and pdfium-render.

// First, we call pdfium-render's exported initialize_pdfium_render() function,
// passing in the WASM modules for both Pdfium and our Rust application, along
// with a debug flag. pdfium-render will bind to the functions it needs from the
// Pdfium WASM module and return a boolean value indicating success or failure.
wasm_bindgen('pdfium_render_wasm_example_bg.wasm').then(async rustModule => {
// The functions exported by our Rust application are now loaded and available.

console.assert(
initialize_pdfium_render(
pdfiumModule, // Emscripten-wrapped Pdfium WASM module
rustModule, // wasm_bindgen-wrapped WASM module built from our Rust application
false, // Debugging flag; set this to true to get tracing information logged to the Javascript console
),
"Initialization of pdfium-render failed!"
);
// First, we call pdfium-render's exported initialize_pdfium_render() function,
// passing in the WASM modules for both Pdfium and our Rust application, along
// with a debug flag. pdfium-render will bind to the functions it needs from the
// Pdfium WASM module and return a boolean value indicating success or failure.

// Now we can call the Rust functions we exported in example/wasm.rs.
console.assert(
initialize_pdfium_render(
pdfiumModule, // Emscripten-wrapped Pdfium WASM module
rustModule, // wasm_bindgen-wrapped WASM module built from our Rust application
false, // Debugging flag; set this to true to get tracing information logged to the Javascript console
),
"Initialization of pdfium-render failed!"
);

// The first function dumps sizing metrics for each page in our target PDF file
// to the console. The file will be retrieved over the network using the browser's
// built-in fetch() function.
// Now we can call the Rust functions we exported in example/wasm.rs.

const targetDocument = "./test.pdf";
// The first function dumps sizing metrics for each page in our target PDF file
// to the console. The file will be retrieved over the network using the browser's
// built-in fetch() function.

await log_page_metrics_to_console(targetDocument);
const targetDocument = "./test.pdf";

// The second function generates the ImageData object for a single page in
// our target PDF file. We can render this ImageData directly to an HTML canvas.
await log_page_metrics_to_console(targetDocument);

const pageIndex = 0; // Zero-based index of the page we wish to render.
const width = 1414;
const height = 1999;
// The second function generates the ImageData object for a single page in
// our target PDF file. We can render this ImageData directly to an HTML canvas.

const canvas = document.getElementById("canvas");
const pageIndex = 0; // Zero-based index of the page we wish to render.
const width = 1414;
const height = 1999;

canvas.width = width;
canvas.height = height;
const canvas = document.getElementById("canvas");

const context = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;

const imageData = await get_image_data_for_page(targetDocument, pageIndex, width, height);
const context = canvas.getContext("2d");

context.putImageData(imageData, 0, 0);
});
const imageData = await get_image_data_for_page(targetDocument, pageIndex, width, height);

context.putImageData(imageData, 0, 0);
});
</script>
</body>
</html>
});
</script>
</body>

</html>
66 changes: 58 additions & 8 deletions src/bindings/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,56 @@ impl PdfiumRenderWasmState {
self.copy_struct_to_pdfium(ptr as *const T)
}

/// Copies the raw bytes of the given `FPDF_WIDESTRING` into Pdfium's WASM memory heap,
/// returning a pointer to the copied string at the destination location.
///
/// The source `FPDF_WIDESTRING` must be terminated by two null bytes.
///
/// WASM modules are isolated from one another and cannot directly share memory. We must
/// therefore copy buffers from our own memory heap across into Pdfium's memory heap, and vice versa.
#[inline]
fn copy_string_to_pdfium(&self, str: FPDF_WIDESTRING) -> usize {
log::debug!("pdfium-render::PdfiumRenderWasmState::copy_string_to_pdfium(): entering");

// Copying the FPDF_WIDESTRING using copy_struct_to_pdfium() will only copy the
// two-byte pointer, not the string data itself. We must scan the source memory
// location for two null bytes to find the correct data length.

let mut len = 0;
let mut last_byte = None;

log::debug!(
"pdfium-render::PdfiumRenderWasmState::copy_string_to_pdfium(): FPDF_WIDESTRING is at heap offset {}",
str as usize as u32,
);

loop {
let this_byte =
unsafe { Uint8Array::view_mut_raw((str as *mut u8).add(len), 1) }.get_index(0);

len += 1;

if this_byte == 0 && last_byte == Some(0) {
// We have found two sequential null bytes. This is the end of the string.

break;
}

last_byte = Some(this_byte);
}

log::debug!(
"pdfium-render::PdfiumRenderWasmState::copy_string_to_pdfium(): FPDF_WIDESTRING has data length {} bytes",
len,
);

let result = self.copy_ptr_with_len_to_pdfium(str, len);

log::debug!("pdfium-render::PdfiumRenderWasmState::copy_string_to_pdfium(): leaving");

result
}

/// Copies bytes from the given pointer address in Pdfium's memory heap into our memory
/// heap, returning an address to the location in our memory heap where the first copied
/// byte was placed.
Expand Down Expand Up @@ -5047,7 +5097,7 @@ impl PdfiumLibraryBindings for WasmPdfiumBindings {

let key_ptr = state.copy_bytes_to_pdfium(&c_key.into_bytes_with_nul());

let value_ptr = state.copy_struct_to_pdfium(value);
let value_ptr = state.copy_string_to_pdfium(value);

let result = state
.call(
Expand Down Expand Up @@ -5199,7 +5249,7 @@ impl PdfiumLibraryBindings for WasmPdfiumBindings {

let state = PdfiumRenderWasmState::lock();

let value_ptr = state.copy_struct_to_pdfium(value);
let value_ptr = state.copy_string_to_pdfium(value);

let result = state
.call(
Expand Down Expand Up @@ -6338,7 +6388,7 @@ impl PdfiumLibraryBindings for WasmPdfiumBindings {

let state = PdfiumRenderWasmState::lock();

let title_ptr = state.copy_struct_to_pdfium(title);
let title_ptr = state.copy_string_to_pdfium(title);

let result = state
.call(
Expand Down Expand Up @@ -7952,12 +8002,12 @@ impl PdfiumLibraryBindings for WasmPdfiumBindings {

let state = PdfiumRenderWasmState::lock();

let findwhat_ptr = state.copy_struct_to_pdfium(findwhat);
let findwhat_ptr = state.copy_string_to_pdfium(findwhat);

let result = state
.call(
"FPDFText_FindStart",
JsFunctionArgumentType::Number,
JsFunctionArgumentType::Pointer,
Some(vec![
JsFunctionArgumentType::Pointer,
JsFunctionArgumentType::Pointer,
Expand Down Expand Up @@ -8932,7 +8982,7 @@ impl PdfiumLibraryBindings for WasmPdfiumBindings {

let state = PdfiumRenderWasmState::lock();

let text_ptr = state.copy_struct_to_pdfium(text);
let text_ptr = state.copy_string_to_pdfium(text);

let result = state
.call(
Expand Down Expand Up @@ -11988,7 +12038,7 @@ impl PdfiumLibraryBindings for WasmPdfiumBindings {

let state = PdfiumRenderWasmState::lock();

let name_ptr = state.copy_struct_to_pdfium(name);
let name_ptr = state.copy_string_to_pdfium(name);

let result = state
.call(
Expand Down Expand Up @@ -12188,7 +12238,7 @@ impl PdfiumLibraryBindings for WasmPdfiumBindings {

let key_ptr = state.copy_bytes_to_pdfium(&c_key.into_bytes_with_nul());

let value_ptr = state.copy_struct_to_pdfium(value);
let value_ptr = state.copy_string_to_pdfium(value);

let result = state
.call(
Expand Down

0 comments on commit 6d76ba6

Please sign in to comment.