1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
//! Defines the [PdfFont] struct, exposing functionality related to a single font used to
//! render text in a `PdfDocument`.
use crate::bindgen::FPDF_FONT;
use crate::bindings::PdfiumLibraryBindings;
use crate::utils::mem::create_byte_buffer;
use std::os::raw::c_char;
/// A single font used to render text in a `PdfDocument`.
///
/// The PDF specification defines 14 built-in fonts that can be used in any PDF file without
/// font embedding. Additionally, custom fonts can be directly embedded into any PDF file as
/// a data stream.
pub struct PdfFont<'a> {
handle: FPDF_FONT,
bindings: &'a dyn PdfiumLibraryBindings,
}
impl<'a> PdfFont<'a> {
#[inline]
pub(crate) fn from_pdfium(handle: FPDF_FONT, bindings: &'a dyn PdfiumLibraryBindings) -> Self {
PdfFont { handle, bindings }
}
/// 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
// 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_GetFontName() 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_GetFontName(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_GetFontName(
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 non-UTF-16LE 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())
}
}