use crate::bindgen::{
FPDFBitmap_BGR, FPDFBitmap_BGRA, FPDFBitmap_BGRx, FPDFBitmap_Gray, FPDFBitmap_Unknown,
FPDF_BITMAP,
};
use crate::bindings::PdfiumLibraryBindings;
use crate::error::{PdfiumError, PdfiumInternalError};
use image::{DynamicImage, ImageBuffer};
use std::f32::consts::{FRAC_PI_2, PI};
use std::os::raw::c_int;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::{Clamped, JsValue};
#[cfg(target_arch = "wasm32")]
use web_sys::ImageData;
#[cfg(target_arch = "wasm32")]
use js_sys::Uint8Array;
#[cfg(doc)]
struct Uint8Array;
#[cfg(doc)]
struct ImageData;
#[cfg(doc)]
struct JsValue;
pub type Pixels = u16;
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum PdfBitmapFormat {
Gray = FPDFBitmap_Gray as isize,
BGR = FPDFBitmap_BGR as isize,
BRGx = FPDFBitmap_BGRx as isize,
BGRA = FPDFBitmap_BGRA as isize,
}
impl PdfBitmapFormat {
#[inline]
#[allow(non_upper_case_globals)]
pub(crate) fn from_pdfium(format: u32) -> Result<Self, PdfiumError> {
match format {
FPDFBitmap_Unknown => Err(PdfiumError::UnknownBitmapFormat),
FPDFBitmap_Gray => Ok(PdfBitmapFormat::Gray),
FPDFBitmap_BGR => Ok(PdfBitmapFormat::BGR),
FPDFBitmap_BGRx => Ok(PdfBitmapFormat::BRGx),
FPDFBitmap_BGRA => Ok(PdfBitmapFormat::BGRA),
_ => Err(PdfiumError::UnknownBitmapFormat),
}
}
#[inline]
pub(crate) fn as_pdfium(&self) -> u32 {
match self {
PdfBitmapFormat::Gray => FPDFBitmap_Gray,
PdfBitmapFormat::BGR => FPDFBitmap_BGR,
PdfBitmapFormat::BRGx => FPDFBitmap_BGRx,
PdfBitmapFormat::BGRA => FPDFBitmap_BGRA,
}
}
}
impl Default for PdfBitmapFormat {
#[inline]
fn default() -> Self {
PdfBitmapFormat::BGRA
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum PdfBitmapRotation {
None,
Degrees90,
Degrees180,
Degrees270,
}
impl PdfBitmapRotation {
#[inline]
pub(crate) fn from_pdfium(rotate: i32) -> Result<Self, PdfiumError> {
match rotate {
0 => Ok(PdfBitmapRotation::None),
1 => Ok(PdfBitmapRotation::Degrees90),
2 => Ok(PdfBitmapRotation::Degrees180),
3 => Ok(PdfBitmapRotation::Degrees270),
_ => Err(PdfiumError::UnknownBitmapRotation),
}
}
#[inline]
pub(crate) fn as_pdfium(&self) -> i32 {
match self {
PdfBitmapRotation::None => 0,
PdfBitmapRotation::Degrees90 => 1,
PdfBitmapRotation::Degrees180 => 2,
PdfBitmapRotation::Degrees270 => 3,
}
}
#[inline]
pub const fn as_degrees(&self) -> f32 {
match self {
PdfBitmapRotation::None => 0.0,
PdfBitmapRotation::Degrees90 => 90.0,
PdfBitmapRotation::Degrees180 => 180.0,
PdfBitmapRotation::Degrees270 => 270.0,
}
}
pub const DEGREES_90_AS_RADIANS: f32 = FRAC_PI_2;
pub const DEGREES_180_AS_RADIANS: f32 = PI;
pub const DEGREES_270_AS_RADIANS: f32 = FRAC_PI_2 + PI;
#[inline]
pub const fn as_radians(&self) -> f32 {
match self {
PdfBitmapRotation::None => 0.0,
PdfBitmapRotation::Degrees90 => Self::DEGREES_90_AS_RADIANS,
PdfBitmapRotation::Degrees180 => Self::DEGREES_180_AS_RADIANS,
PdfBitmapRotation::Degrees270 => Self::DEGREES_270_AS_RADIANS,
}
}
#[inline]
pub const fn as_radians_cos(&self) -> f32 {
match self {
PdfBitmapRotation::None => 1.0,
PdfBitmapRotation::Degrees90 => 0.0,
PdfBitmapRotation::Degrees180 => -1.0,
PdfBitmapRotation::Degrees270 => 0.0,
}
}
#[inline]
pub const fn as_radians_sin(&self) -> f32 {
match self {
PdfBitmapRotation::None => 0.0,
PdfBitmapRotation::Degrees90 => 1.0,
PdfBitmapRotation::Degrees180 => 0.0,
PdfBitmapRotation::Degrees270 => -1.0,
}
}
}
pub struct PdfBitmap<'a> {
handle: FPDF_BITMAP,
bindings: &'a dyn PdfiumLibraryBindings,
}
impl<'a> PdfBitmap<'a> {
pub(crate) fn from_pdfium(
handle: FPDF_BITMAP,
bindings: &'a dyn PdfiumLibraryBindings,
) -> Self {
PdfBitmap { handle, bindings }
}
pub fn empty(
width: Pixels,
height: Pixels,
format: PdfBitmapFormat,
bindings: &'a dyn PdfiumLibraryBindings,
) -> Result<PdfBitmap, PdfiumError> {
let handle = bindings.FPDFBitmap_CreateEx(
width as c_int,
height as c_int,
format.as_pdfium() as c_int,
std::ptr::null_mut(),
0, );
if handle.is_null() {
if let Some(error) = bindings.get_pdfium_last_error() {
Err(PdfiumError::PdfiumLibraryInternalError(error))
} else {
Err(PdfiumError::PdfiumLibraryInternalError(
PdfiumInternalError::Unknown,
))
}
} else {
Ok(Self::from_pdfium(handle, bindings))
}
}
#[inline]
pub(crate) fn handle(&self) -> &FPDF_BITMAP {
&self.handle
}
#[inline]
pub fn bindings(&self) -> &dyn PdfiumLibraryBindings {
self.bindings
}
#[inline]
pub fn width(&self) -> Pixels {
self.bindings.FPDFBitmap_GetWidth(self.handle) as Pixels
}
#[inline]
pub fn height(&self) -> Pixels {
self.bindings.FPDFBitmap_GetHeight(self.handle) as Pixels
}
#[inline]
pub fn format(&self) -> Result<PdfBitmapFormat, PdfiumError> {
PdfBitmapFormat::from_pdfium(self.bindings.FPDFBitmap_GetFormat(self.handle) as u32)
}
pub fn as_bytes(&self) -> &'a [u8] {
let buffer_length = self.bindings.FPDFBitmap_GetStride(self.handle)
* self.bindings.FPDFBitmap_GetHeight(self.handle);
let buffer_start = self.bindings.FPDFBitmap_GetBuffer(self.handle);
unsafe { std::slice::from_raw_parts(buffer_start as *const u8, buffer_length as usize) }
}
pub fn as_image(&self) -> DynamicImage {
ImageBuffer::from_raw(
self.width() as u32,
self.height() as u32,
self.as_bytes().to_owned(),
)
.map(DynamicImage::ImageRgba8)
.unwrap()
}
#[deprecated(
since = "0.7.12",
note = "This function is no longer necessary since all page rendering operations are now processed eagerly rather than lazily. Calls to this function can be removed."
)]
#[doc(hidden)]
#[inline]
pub fn render(&self) {}
#[cfg(any(doc, target_arch = "wasm32"))]
pub fn as_array(&self) -> Uint8Array {
self.bindings.FPDFBitmap_GetArray(self.handle)
}
#[cfg(any(doc, target_arch = "wasm32"))]
pub fn as_image_data(&self) -> Result<ImageData, JsValue> {
ImageData::new_with_u8_clamped_array_and_sh(
Clamped(self.as_bytes()),
self.width() as u32,
self.height() as u32,
)
}
}
impl<'a> Drop for PdfBitmap<'a> {
#[inline]
fn drop(&mut self) {
self.bindings.FPDFBitmap_Destroy(self.handle);
}
}