Skip to content

Commit

Permalink
Progressing #152
Browse files Browse the repository at this point in the history
  • Loading branch information
Alastair Carey committed Aug 4, 2024
1 parent d98ef05 commit c5e5eef
Show file tree
Hide file tree
Showing 8 changed files with 422 additions and 64 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:

env:
CARGO_TERM_COLOR: always
PDFIUM_RELEASE_TAG: 6281
PDFIUM_RELEASE_TAG: 6611 # July 2024, https://github.com/bblanchon/pdfium-binaries/releases/tag/chromium%2F6611

jobs:
build:
Expand All @@ -28,7 +28,7 @@ jobs:
- name: Unpack Pdfium
run: mkdir pdfium && tar -xvzf pdfium.tgz -C pdfium
- name: Install Pdfium
run: cp pdfium/lib/libpdfium.so .
run: cp pdfium/lib/libpdfium.so . && export LD_LIBRARY_PATH="./"
- name: Run tests
run: cargo test --verbose
- name: Verify static linking compatibility
Expand Down
37 changes: 23 additions & 14 deletions examples/fonts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,37 +41,46 @@ fn main() -> Result<(), PdfiumError> {
// italic angles, and certain other properties correctly for built-in fonts.

println!(
"Built-in PDF font {} is built-in {:?}: name = {}, is symbolic? {}, is non-symbolic? {}, ascent {:?}, descent {:?}, number of glyphs: {}",
"Built-in PDF font {} is built-in {:?}: family = {}, is symbolic? {}, is non-symbolic? {}, ascent {:?}, descent {:?}, number of glyphs: {}, is embedded in document?: {}",
index,
built_in,
font.name(),
font.family(),
font.is_symbolic(),
font.is_non_symbolic(),
font.ascent(font_size),
font.descent(font_size),
font.glyphs().len()
font.glyphs().len(),
font.is_embedded()?,
);
}

// At the time of writing, Pdfium does not reliably return font weights,
// italic angles, and certain other properties correctly for built-in fonts.
// So let's also output these properties for some fonts embedded into a file.

let document = pdfium.load_pdf_from_file("test/form-test.pdf", None)?;
let document = pdfium.load_pdf_from_file("test/text-test.pdf", None)?;

for (page_index, page) in document.pages().iter().enumerate() {
for (font_index, font) in page.fonts().iter().enumerate() {
println!(
"Font {} on page {} is embedded: name = {}, is symbolic? {}, is non-symbolic? {}, ascent {:?}, descent {:?}, number of glyphs: {}",
font_index,
page_index,
font.name(),
font.is_symbolic(),
font.is_non_symbolic(),
font.ascent(font_size),
font.descent(font_size),
font.glyphs().len()
);
"Font {} on page {} is embedded: family = {}, is symbolic? {}, is non-symbolic? {}, ascent {:?}, descent {:?}, number of glyphs: {}, is embedded in document?: {}",
font_index,
page_index,
font.family(),
font.is_symbolic(),
font.is_non_symbolic(),
font.ascent(font_size),
font.descent(font_size),
font.glyphs().len(),
font.is_embedded()?,
);

if font.is_embedded()? {
println!("{} bytes in embedded font data", font.data()?.len());

// If we wished, we could write the embedded font data out to a file like so:
// std::fs::write(format!("./{}.ttf", font_index), font.data()?).expect("failed writing font data");
}
}
}

Expand Down
28 changes: 25 additions & 3 deletions src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3190,13 +3190,35 @@ pub trait PdfiumLibraryBindings {
#[allow(non_snake_case)]
fn FPDFPathSegment_GetClose(&self, segment: FPDF_PATHSEGMENT) -> FPDF_BOOL;

// TODO: AJRC - 4-Aug-2024 - FPDFFont_GetBaseFontName() is in Pdfium export headers
// but changes not yet released. Tracking issue: https://github.com/ajrcarey/pdfium-render/issues/152
// #[allow(non_snake_case)]
// fn FPDFFont_GetBaseFontName(
// &self,
// font: FPDF_FONT,
// buffer: *mut c_char,
// length: usize, // size_t is used in Pdfium API header, so usize is appropriate here
// ) -> usize; // size_t is used in Pdfium API header, so usize is appropriate here

#[allow(non_snake_case)]
fn FPDFFont_GetFontName(
fn FPDFFont_GetFamilyName(
&self,
font: FPDF_FONT,
buffer: *mut c_char,
length: c_ulong,
) -> c_ulong;
length: usize, // size_t is used in Pdfium API header, so usize is appropriate here
) -> usize; // size_t is used in Pdfium API header, so usize is appropriate here

#[allow(non_snake_case)]
fn FPDFFont_GetFontData(
&self,
font: FPDF_FONT,
buffer: *mut u8,
buflen: usize,
out_buflen: *mut usize,
) -> FPDF_BOOL;

#[allow(non_snake_case)]
fn FPDFFont_GetIsEmbedded(&self, font: FPDF_FONT) -> c_int;

#[allow(non_snake_case)]
fn FPDFFont_GetFlags(&self, font: FPDF_FONT) -> c_int;
Expand Down
120 changes: 116 additions & 4 deletions src/font.rs
Original file line number Diff line number Diff line change
Expand Up @@ -755,10 +755,60 @@ impl<'a> PdfFont<'a> {
self.bindings
}

#[inline]
#[deprecated(
since = "0.8.22",
note = "This function has been renamed in line with upstream Pdfium. Use the PdfFont::family() function instead."
)]
/// Returns the name of this [PdfFont].
pub fn name(&self) -> String {
// Retrieving the font name from Pdfium is a two-step operation. First, we call
// FPDFFont_GetFontName() with a null buffer; this will retrieve the length of
self.family()
}

// TODO: AJRC - 4-Aug-2024 - FPDFFont_GetBaseFontName() is in Pdfium export headers
// but changes not yet released. Tracking issue: https://github.com/ajrcarey/pdfium-render/issues/152
/// Returns the name of this [PdfFont].
// pub fn name(&self) -> String {
// // Retrieving the font name from Pdfium is a two-step operation. First, we call
// // FPDFFont_GetBaseFontName() with a null buffer; this will retrieve the length of
// // the font name in bytes. If the length is zero, then there is no font name.

// // If the length is non-zero, then we reserve a byte buffer of the given
// // length and call FPDFFont_GetBaseFontName() again with a pointer to the buffer;
// // this will write the font name into the buffer. Unlike most text handling in
// // Pdfium, font names are returned in UTF-8 format.

// let buffer_length =
// self.bindings
// .FPDFFont_GetBaseFontName(self.handle, std::ptr::null_mut(), 0);

// if buffer_length == 0 {
// // The font name is not present.

// return String::new();
// }

// let mut buffer = create_byte_buffer(buffer_length as usize);

// let result = self.bindings.FPDFFont_GetBaseFontName(
// self.handle,
// buffer.as_mut_ptr() as *mut c_char,
// buffer_length,
// );

// assert_eq!(result, buffer_length);

// String::from_utf8(buffer)
// // Trim any trailing nulls. All strings returned from Pdfium are generally terminated
// // by one null byte.
// .map(|str| str.trim_end_matches(char::from(0)).to_owned())
// .unwrap_or_else(|_| String::new())
// }

/// Returns the family of this [PdfFont].
pub fn family(&self) -> String {
// Retrieving the family name from Pdfium is a two-step operation. First, we call
// FPDFFont_GetFamilyName() with a null buffer; this will retrieve the length of
// the font name in bytes. If the length is zero, then there is no font name.

// If the length is non-zero, then we reserve a byte buffer of the given
Expand All @@ -768,7 +818,7 @@ impl<'a> PdfFont<'a> {

let buffer_length =
self.bindings
.FPDFFont_GetFontName(self.handle, std::ptr::null_mut(), 0);
.FPDFFont_GetFamilyName(self.handle, std::ptr::null_mut(), 0);

if buffer_length == 0 {
// The font name is not present.
Expand All @@ -778,7 +828,7 @@ impl<'a> PdfFont<'a> {

let mut buffer = create_byte_buffer(buffer_length as usize);

let result = self.bindings.FPDFFont_GetFontName(
let result = self.bindings.FPDFFont_GetFamilyName(
self.handle,
buffer.as_mut_ptr() as *mut c_char,
buffer_length,
Expand Down Expand Up @@ -1001,6 +1051,68 @@ impl<'a> PdfFont<'a> {
self.built_in
}

/// Returns `true` if the data for this [PdfFont] is embedded in the containing [PdfDocument].
pub fn is_embedded(&self) -> Result<bool, PdfiumError> {
let result = self.bindings.FPDFFont_GetIsEmbedded(self.handle);

match result {
1 => Ok(true),
0 => Ok(false),
_ => Err(PdfiumError::PdfiumLibraryInternalError(
PdfiumInternalError::Unknown,
)),
}
}

/// Writes this [PdfFont] to a new byte buffer, returning the byte buffer.
///
/// If this [PdfFont] is not embedded in the containing [PdfDocument], then the data
/// returned will be for the substitution font instead.
pub fn data(&self) -> Result<Vec<u8>, PdfiumError> {
// Retrieving the font data from Pdfium is a two-step operation. First, we call
// FPDFFont_GetFontData() with a null buffer; this will retrieve the length of
// the data in bytes. If the length is zero, then there is no data associated
// with this font.

// If the length is non-zero, then we reserve a byte buffer of the given
// length and call FPDFFont_GetFontData() again with a pointer to the buffer;
// this will write the font data to the buffer.

let mut out_buflen: usize = 0;

if self
.bindings()
.is_true(self.bindings().FPDFFont_GetFontData(
self.handle,
std::ptr::null_mut(),
0,
&mut out_buflen,
))
{
// out_buflen now contains the length of the font data.

let buffer_length = out_buflen;

let mut buffer = create_byte_buffer(buffer_length as usize);

let result = self.bindings().FPDFFont_GetFontData(
self.handle,
buffer.as_mut_ptr(),
buffer_length,
&mut out_buflen,
);

assert!(self.bindings.is_true(result));
assert_eq!(buffer_length, out_buflen);

Ok(buffer)
} else {
Err(PdfiumError::PdfiumLibraryInternalError(
PdfiumInternalError::Unknown,
))
}
}

/// Returns a collection of all the [PdfFontGlyphs] defined for this [PdfFont] in the containing
/// `PdfDocument`.
///
Expand Down
36 changes: 31 additions & 5 deletions src/linked.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2904,15 +2904,41 @@ impl PdfiumLibraryBindings for StaticPdfiumBindings {
unsafe { crate::bindgen::FPDFPathSegment_GetClose(segment) }
}

// TODO: AJRC - 4-Aug-2024 - FPDFFont_GetBaseFontName() is in Pdfium export headers
// but changes not yet released. Tracking issue: https://github.com/ajrcarey/pdfium-render/issues/152
// #[inline]
// #[allow(non_snake_case)]
// fn FPDFFont_GetBaseFontName(
// &self,
// font: FPDF_FONT,
// buffer: *mut c_char,
// length: usize,
// ) -> usize {
// unsafe { crate::bindgen::FPDFFont_GetBaseFontName(font, buffer, length) }
// }

#[inline]
#[allow(non_snake_case)]
fn FPDFFont_GetFontName(
fn FPDFFont_GetFamilyName(&self, font: FPDF_FONT, buffer: *mut c_char, length: usize) -> usize {
unsafe { crate::bindgen::FPDFFont_GetFamilyName(font, buffer, length) }
}

#[inline]
#[allow(non_snake_case)]
fn FPDFFont_GetFontData(
&self,
font: FPDF_FONT,
buffer: *mut c_char,
length: c_ulong,
) -> c_ulong {
unsafe { crate::bindgen::FPDFFont_GetFontName(font, buffer, length) }
buffer: *mut u8,
buflen: usize,
out_buflen: *mut usize,
) -> FPDF_BOOL {
unsafe { crate::bindgen::FPDFFont_GetFontData(font, buffer, buflen, out_buflen) }
}

#[inline]
#[allow(non_snake_case)]
fn FPDFFont_GetIsEmbedded(&self, font: FPDF_FONT) -> c_int {
unsafe { crate::bindgen::FPDFFont_GetIsEmbedded(font) }
}

#[inline]
Expand Down
58 changes: 50 additions & 8 deletions src/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1082,8 +1082,19 @@ pub(crate) struct DynamicPdfiumBindings {
unsafe extern "C" fn(segment: FPDF_PATHSEGMENT, x: *mut f32, y: *mut f32) -> FPDF_BOOL,
extern_FPDFPathSegment_GetType: unsafe extern "C" fn(segment: FPDF_PATHSEGMENT) -> c_int,
extern_FPDFPathSegment_GetClose: unsafe extern "C" fn(segment: FPDF_PATHSEGMENT) -> FPDF_BOOL,
extern_FPDFFont_GetFontName:
unsafe extern "C" fn(font: FPDF_FONT, buffer: *mut c_char, length: c_ulong) -> c_ulong,
// TODO: AJRC - 4-Aug-2024 - FPDFFont_GetBaseFontName() is in Pdfium export headers
// but changes not yet released. Tracking issue: https://github.com/ajrcarey/pdfium-render/issues/152
// extern_FPDFFont_GetBaseFontName:
// unsafe extern "C" fn(font: FPDF_FONT, buffer: *mut c_char, length: usize) -> usize,
extern_FPDFFont_GetFamilyName:
unsafe extern "C" fn(font: FPDF_FONT, buffer: *mut c_char, length: usize) -> usize,
extern_FPDFFont_GetFontData: unsafe extern "C" fn(
font: FPDF_FONT,
buffer: *mut u8,
buflen: usize,
out_buflen: *mut usize,
) -> FPDF_BOOL,
extern_FPDFFont_GetIsEmbedded: unsafe extern "C" fn(font: FPDF_FONT) -> c_int,
extern_FPDFFont_GetFlags: unsafe extern "C" fn(font: FPDF_FONT) -> c_int,
extern_FPDFFont_GetWeight: unsafe extern "C" fn(font: FPDF_FONT) -> c_int,
extern_FPDFFont_GetItalicAngle:
Expand Down Expand Up @@ -1550,7 +1561,12 @@ impl DynamicPdfiumBindings {
extern_FPDFPathSegment_GetPoint: *(library.get(b"FPDFPathSegment_GetPoint\0")?),
extern_FPDFPathSegment_GetType: *(library.get(b"FPDFPathSegment_GetType\0")?),
extern_FPDFPathSegment_GetClose: *(library.get(b"FPDFPathSegment_GetClose\0")?),
extern_FPDFFont_GetFontName: *(library.get(b"FPDFFont_GetFontName\0")?),
// TODO: AJRC - 4-Aug-2024 - FPDFFont_GetBaseFontName() is in Pdfium export headers
// but changes not yet released. Tracking issue: https://github.com/ajrcarey/pdfium-render/issues/152
// extern_FPDFFont_GetBaseFontName: *(library.get(b"FPDFFont_GetBaseFontName\0")?),
extern_FPDFFont_GetFamilyName: *(library.get(b"FPDFFont_GetFamilyName\0")?),
extern_FPDFFont_GetFontData: *(library.get(b"FPDFFont_GetFontData\0")?),
extern_FPDFFont_GetIsEmbedded: *(library.get(b"FPDFFont_GetIsEmbedded\0")?),
extern_FPDFFont_GetFlags: *(library.get(b"FPDFFont_GetFlags\0")?),
extern_FPDFFont_GetWeight: *(library.get(b"FPDFFont_GetWeight\0")?),
extern_FPDFFont_GetItalicAngle: *(library.get(b"FPDFFont_GetItalicAngle\0")?),
Expand Down Expand Up @@ -4468,15 +4484,41 @@ impl PdfiumLibraryBindings for DynamicPdfiumBindings {
unsafe { (self.extern_FPDFPathSegment_GetClose)(segment) }
}

// TODO: AJRC - 4-Aug-2024 - FPDFFont_GetBaseFontName() is in Pdfium export headers
// but changes not yet released. Tracking issue: https://github.com/ajrcarey/pdfium-render/issues/152
// #[inline]
// #[allow(non_snake_case)]
// fn FPDFFont_GetBaseFontName(
// &self,
// font: FPDF_FONT,
// buffer: *mut c_char,
// length: usize,
// ) -> usize {
// unsafe { (self.extern_FPDFFont_GetBaseFontName)(font, buffer, length) }
// }

#[inline]
#[allow(non_snake_case)]
fn FPDFFont_GetFamilyName(&self, font: FPDF_FONT, buffer: *mut c_char, length: usize) -> usize {
unsafe { (self.extern_FPDFFont_GetFamilyName)(font, buffer, length) }
}

#[inline]
#[allow(non_snake_case)]
fn FPDFFont_GetFontName(
fn FPDFFont_GetFontData(
&self,
font: FPDF_FONT,
buffer: *mut c_char,
length: c_ulong,
) -> c_ulong {
unsafe { (self.extern_FPDFFont_GetFontName)(font, buffer, length) }
buffer: *mut u8,
buflen: usize,
out_buflen: *mut usize,
) -> FPDF_BOOL {
unsafe { (self.extern_FPDFFont_GetFontData)(font, buffer, buflen, out_buflen) }
}

#[inline]
#[allow(non_snake_case)]
fn FPDFFont_GetIsEmbedded(&self, font: FPDF_FONT) -> c_int {
unsafe { (self.extern_FPDFFont_GetIsEmbedded)(font) }
}

#[inline]
Expand Down
Loading

0 comments on commit c5e5eef

Please sign in to comment.