Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zero copy rendering #83

Closed
DorianRudolph opened this issue Apr 16, 2023 · 7 comments
Closed

Zero copy rendering #83

DorianRudolph opened this issue Apr 16, 2023 · 7 comments
Assignees

Comments

@DorianRudolph
Copy link
Contributor

I would like to render a PdfPage into an external buffer via a raw pointer. My use case is to render directly into a skia bitmap. This way I don't have to copy the data from the PdfBitmap to the skia bitmap, saving one copy.

Right now there does not appear to be a way to give pdfium-render a pointer or slice to render into.

@ajrcarey
Copy link
Owner

Hi @DorianRudolph , yes, Pdfium does support rendering into an external buffer. We would need to add a new constructor to PdfBitmap. Are you wanting to provide a buffer in the form of a &mut [u8] slice?

(This approach is fundamentally incompatible with WASM because Pdfium and pdfium-render inhabit separate memory address spaces when running in the browser.)

ajrcarey pushed a commit that referenced this issue Apr 18, 2023
@ajrcarey
Copy link
Owner

Under the assumption that you will be providing a &mut [u8], added a new PdfBitmap::external() function that lets you pass in a buffer. You can test the function by using pdfium-render as a git dependency in your project's Cargo.toml.

@DorianRudolph
Copy link
Contributor Author

Thanks, this is what I had in mind. I should be able to test it sometime this week.

Eventually I would like to get my project running in the web. Why would this not work in WASM? I guess your concern is that pdfium and pdfium-render are compiled to two different .wasm modules? I'm just learning about WASM, but could something like this work to establish a shared memory between WASM modules?

@ajrcarey
Copy link
Owner

ajrcarey commented Apr 18, 2023

Because Pdfium and pdfium-render are compiled separately, they inhabit independent WASM modules with independent linear address spaces. In theory it might be possible to combine these; in practice I highly doubt it could ever work safely, because the two modules have two different memory allocators that would have no knowledge of one-another and would therefore be endlessly clobbering one another's memory allocations.

So long as the WASM memory address spaces are separate, it will never be possible to share a buffer between Pdfium and pdfium-render without a copy.

Because Javascript does have access to all memory irrespective of WASM modules, it is possible to work around this to a certain degree. The WASM-specific PdfBitmap::as_array() function lets you pass through the array data of a Pdfium FPDF_BITMAP buffer directly to Javascript without copying it into pdfium-render's address space first.

My suggestion is that you have two code paths: one using PdfBitmap::external() for your non-WASM builds, and one using PdfBitmap::as_array() for your WASM build.

You are welcome to try getting Pdfium and pdfium-render to share a single linear address space, but I would not be able to help you with this.

I will rename the PdfBitmap::external() function in the next commit, and restrict it to non-WASM builds only.

ajrcarey pushed a commit that referenced this issue Apr 18, 2023
@ajrcarey
Copy link
Owner

Renamed PdfBitmap::external() as PdfBitmap::from_bytes(). Restricted compilation to non-WASM targets.

@ajrcarey ajrcarey self-assigned this Apr 18, 2023
@ajrcarey
Copy link
Owner

Added unit test for PdfBitmap::from_bytes(). As there have been no further comments, and I believe PdfBitmap::from_bytes() provides the functionality you require, I am closing the issue. Feel free to reopen if you feel the issue has not been resolved.

@DorianRudolph
Copy link
Contributor Author

DorianRudolph commented May 30, 2023

Yes thank you it works for me.

Btw, this is how I render into a skia image:

let w: f32 = page.width().value;
let h = page.height().value;
let scale = (2_000_000.0 / (w * h)).sqrt();
let width = (w * scale) as i32;
let height = (h * scale) as i32;
let data = unsafe { Data::new_uninitialized((width * height * 4) as usize) };
assert!(data.inner()._base.fRefCnt == 1);

let mut bitmap = unsafe {
  let mut_data = std::slice::from_raw_parts_mut(data.inner().fPtr as _, data.size());
  PdfBitmap::from_bytes(width, height, PdfBitmapFormat::BGRA, mut_data, pdfium.bindings())
    .expect("Could not create bitmap")
};
page
  .render_into_bitmap(&mut bitmap, width, height, None)
  .expect("Could not render page");

let size = ISize::new(width, height);
let info = ImageInfo::new(size, ColorType::RGBA8888, AlphaType::Premul, None);  // need RGB and not BGR, not sure why
let image = Image::from_raster_data(&info, data, (width * 4) as usize).unwrap();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants