pdfium_render/pdf/font.rs
1//! Defines the [PdfFont] struct, exposing functionality related to a single font used to
2//! render text in a `PdfDocument`.
3
4pub mod glyph;
5pub mod glyphs;
6
7use crate::bindgen::{FPDF_FONT, FPDF_FONT_TRUETYPE, FPDF_FONT_TYPE1};
8use crate::bindings::PdfiumLibraryBindings;
9use crate::error::{PdfiumError, PdfiumInternalError};
10use crate::pdf::document::PdfDocument;
11use crate::pdf::document::fonts::PdfFontBuiltin;
12use crate::pdf::font::glyphs::PdfFontGlyphs;
13use crate::pdf::points::PdfPoints;
14use crate::utils::mem::create_byte_buffer;
15use bitflags::bitflags;
16use std::io::Read;
17use std::os::raw::{c_char, c_int, c_uint};
18
19#[cfg(not(target_arch = "wasm32"))]
20use std::fs::File;
21
22#[cfg(not(target_arch = "wasm32"))]
23use std::path::Path;
24
25#[cfg(target_arch = "wasm32")]
26use wasm_bindgen::JsCast;
27
28#[cfg(target_arch = "wasm32")]
29use wasm_bindgen_futures::JsFuture;
30
31#[cfg(target_arch = "wasm32")]
32use js_sys::{ArrayBuffer, Uint8Array};
33
34#[cfg(target_arch = "wasm32")]
35use web_sys::{Blob, Response, window};
36
37#[cfg(doc)]
38struct Blob;
39
40bitflags! {
41 pub(crate) struct FpdfFontDescriptorFlags: u32 {
42 const FIXED_PITCH_BIT_1 = 0b00000000000000000000000000000001;
43 const SERIF_BIT_2 = 0b00000000000000000000000000000010;
44 const SYMBOLIC_BIT_3 = 0b00000000000000000000000000000100;
45 const SCRIPT_BIT_4 = 0b00000000000000000000000000001000;
46 const NON_SYMBOLIC_BIT_6 = 0b00000000000000000000000000100000;
47 const ITALIC_BIT_7 = 0b00000000000000000000000001000000;
48 const ALL_CAP_BIT_17 = 0b00000000000000010000000000000000;
49 const SMALL_CAP_BIT_18 = 0b00000000000000100000000000000000;
50 const FORCE_BOLD_BIT_19 = 0b00000000000001000000000000000000;
51 }
52}
53
54/// The weight of a [PdfFont]. Typical values are 400 (normal) and 700 (bold).
55#[derive(Copy, Clone, Debug, PartialEq)]
56pub enum PdfFontWeight {
57 Weight100,
58 Weight200,
59 Weight300,
60 Weight400Normal,
61 Weight500,
62 Weight600,
63 Weight700Bold,
64 Weight800,
65 Weight900,
66
67 /// Any font weight value that falls outside the typical 100 - 900 value range.
68 Custom(u32),
69}
70
71impl PdfFontWeight {
72 pub(crate) fn from_pdfium(value: c_int) -> Option<PdfFontWeight> {
73 match value {
74 -1 => None,
75 100 => Some(PdfFontWeight::Weight100),
76 200 => Some(PdfFontWeight::Weight200),
77 300 => Some(PdfFontWeight::Weight300),
78 400 => Some(PdfFontWeight::Weight400Normal),
79 500 => Some(PdfFontWeight::Weight500),
80 600 => Some(PdfFontWeight::Weight600),
81 700 => Some(PdfFontWeight::Weight700Bold),
82 800 => Some(PdfFontWeight::Weight800),
83 900 => Some(PdfFontWeight::Weight900),
84 other => Some(PdfFontWeight::Custom(other as u32)),
85 }
86 }
87}
88
89/// A single font used to render text in a [PdfDocument].
90///
91/// The PDF specification defines 14 built-in fonts that can be used in any PDF file without
92/// font embedding. Additionally, custom fonts can be directly embedded into any PDF file as
93/// a data stream.
94pub struct PdfFont<'a> {
95 built_in: Option<PdfFontBuiltin>,
96 handle: FPDF_FONT,
97 bindings: &'a dyn PdfiumLibraryBindings,
98 glyphs: PdfFontGlyphs<'a>,
99 is_font_memory_loaded: bool,
100}
101
102impl<'a> PdfFont<'a> {
103 #[inline]
104 pub(crate) fn from_pdfium(
105 handle: FPDF_FONT,
106 bindings: &'a dyn PdfiumLibraryBindings,
107 built_in: Option<PdfFontBuiltin>,
108 is_font_memory_loaded: bool,
109 ) -> Self {
110 PdfFont {
111 built_in,
112 handle,
113 bindings,
114 glyphs: PdfFontGlyphs::from_pdfium(handle, bindings),
115 is_font_memory_loaded,
116 }
117 }
118
119 /// Creates a new [PdfFont] from the given given built-in font argument.
120 ///
121 /// This function is now deprecated and will be removed in release 0.9.0.
122 /// Use the `PdfFonts::new_built_in()` function instead.
123 #[deprecated(
124 since = "0.8.1",
125 note = "This function has been moved. Use the PdfFonts::new_built_in() function instead."
126 )]
127 #[doc(hidden)]
128 #[inline]
129 pub fn new_built_in(document: &'a PdfDocument<'a>, font: PdfFontBuiltin) -> PdfFont<'a> {
130 Self::from_pdfium(
131 document
132 .bindings()
133 .FPDFText_LoadStandardFont(document.handle(), font.to_pdf_font_name()),
134 document.bindings(),
135 Some(font),
136 true,
137 )
138 }
139
140 /// Creates a new [PdfFont] for the built-in "Times-Roman" font.
141 ///
142 /// This function is now deprecated and will be removed in release 0.9.0.
143 /// Use the `PdfFonts::times_roman()` function instead.
144 #[deprecated(
145 since = "0.8.1",
146 note = "This function has been moved. Use the PdfFonts::times_roman() function instead."
147 )]
148 #[doc(hidden)]
149 #[inline]
150 pub fn times_roman(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
151 #[allow(deprecated)]
152 Self::new_built_in(document, PdfFontBuiltin::TimesRoman)
153 }
154
155 /// Creates a new [PdfFont] for the built-in "Times-Bold" font.
156 ///
157 /// This function is now deprecated and will be removed in release 0.9.0.
158 /// Use the `PdfFonts::times_bold()` function instead.
159 #[deprecated(
160 since = "0.8.1",
161 note = "This function has been moved. Use the PdfFonts::times_bold() function instead."
162 )]
163 #[doc(hidden)]
164 #[inline]
165 pub fn times_bold(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
166 #[allow(deprecated)]
167 Self::new_built_in(document, PdfFontBuiltin::TimesBold)
168 }
169
170 /// Creates a new [PdfFont] for the built-in "Times-Italic" font.
171 ///
172 /// This function is now deprecated and will be removed in release 0.9.0.
173 /// Use the `PdfFonts::times_italic()` function instead.
174 #[deprecated(
175 since = "0.8.1",
176 note = "This function has been moved. Use the PdfFonts::times_italic() function instead."
177 )]
178 #[doc(hidden)]
179 #[inline]
180 pub fn times_italic(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
181 #[allow(deprecated)]
182 Self::new_built_in(document, PdfFontBuiltin::TimesItalic)
183 }
184
185 /// Creates a new [PdfFont] for the built-in "Times-BoldItalic" font.
186 ///
187 /// This function is now deprecated and will be removed in release 0.9.0.
188 /// Use the `PdfFonts::times_bold_italic()` function instead.
189 #[deprecated(
190 since = "0.8.1",
191 note = "This function has been moved. Use the PdfFonts::times_bold_italic() function instead."
192 )]
193 #[doc(hidden)]
194 #[inline]
195 pub fn times_bold_italic(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
196 #[allow(deprecated)]
197 Self::new_built_in(document, PdfFontBuiltin::TimesBoldItalic)
198 }
199
200 /// Creates a new [PdfFont] for the built-in "Helvetica" font.
201 ///
202 /// This function is now deprecated and will be removed in release 0.9.0.
203 /// Use the `PdfFonts::helvetica()` function instead.
204 #[deprecated(
205 since = "0.8.1",
206 note = "This function has been moved. Use the PdfFonts::helvetica() function instead."
207 )]
208 #[doc(hidden)]
209 #[inline]
210 pub fn helvetica(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
211 #[allow(deprecated)]
212 Self::new_built_in(document, PdfFontBuiltin::Helvetica)
213 }
214
215 /// Creates a new [PdfFont] for the built-in "Helvetica-Bold" font.
216 ///
217 /// This function is now deprecated and will be removed in release 0.9.0.
218 /// Use the `PdfFonts::helvetica_bold()` function instead.
219 #[deprecated(
220 since = "0.8.1",
221 note = "This function has been moved. Use the PdfFonts::helvetica_bold() function instead."
222 )]
223 #[doc(hidden)]
224 #[inline]
225 pub fn helvetica_bold(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
226 #[allow(deprecated)]
227 Self::new_built_in(document, PdfFontBuiltin::HelveticaBold)
228 }
229
230 /// Creates a new [PdfFont] for the built-in "Helvetica-Oblique" font.
231 ///
232 /// This function is now deprecated and will be removed in release 0.9.0.
233 /// Use the `PdfFonts::helvetica_oblique()` function instead.
234 #[deprecated(
235 since = "0.8.1",
236 note = "This function has been moved. Use the PdfFonts::helvetica_oblique() function instead."
237 )]
238 #[doc(hidden)]
239 #[inline]
240 pub fn helvetica_oblique(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
241 #[allow(deprecated)]
242 Self::new_built_in(document, PdfFontBuiltin::HelveticaOblique)
243 }
244
245 /// Creates a new [PdfFont] for the built-in "Helvetica-BoldOblique" font.
246 ///
247 /// This function is now deprecated and will be removed in release 0.9.0.
248 /// Use the `PdfFonts::helvetica_bold_oblique()` function instead.
249 #[deprecated(
250 since = "0.8.1",
251 note = "This function has been moved. Use the PdfFonts::helvetica_bold_oblique() function instead."
252 )]
253 #[doc(hidden)]
254 #[inline]
255 pub fn helvetica_bold_oblique(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
256 #[allow(deprecated)]
257 Self::new_built_in(document, PdfFontBuiltin::HelveticaBoldOblique)
258 }
259
260 /// Creates a new [PdfFont] for the built-in "Courier" font.
261 ///
262 /// This function is now deprecated and will be removed in release 0.9.0.
263 /// Use the `PdfFonts::courier()` function instead.
264 #[deprecated(
265 since = "0.8.1",
266 note = "This function has been moved. Use the PdfFonts::courier() function instead."
267 )]
268 #[doc(hidden)]
269 #[inline]
270 pub fn courier(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
271 #[allow(deprecated)]
272 Self::new_built_in(document, PdfFontBuiltin::Courier)
273 }
274
275 /// Creates a new [PdfFont] for the built-in "Courier-Bold" font.
276 ///
277 /// This function is now deprecated and will be removed in release 0.9.0.
278 /// Use the `PdfFonts::courier_bold()` function instead.
279 #[deprecated(
280 since = "0.8.1",
281 note = "This function has been moved. Use the PdfFonts::courier_bold() function instead."
282 )]
283 #[doc(hidden)]
284 #[inline]
285 pub fn courier_bold(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
286 #[allow(deprecated)]
287 Self::new_built_in(document, PdfFontBuiltin::CourierBold)
288 }
289
290 /// Creates a new [PdfFont] for the built-in "Courier-Oblique" font.
291 ///
292 /// This function is now deprecated and will be removed in release 0.9.0.
293 /// Use the `PdfFonts::courier_oblique()` function instead.
294 #[deprecated(
295 since = "0.8.1",
296 note = "This function has been moved. Use the PdfFonts::courier_oblique() function instead."
297 )]
298 #[doc(hidden)]
299 #[inline]
300 pub fn courier_oblique(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
301 #[allow(deprecated)]
302 Self::new_built_in(document, PdfFontBuiltin::CourierOblique)
303 }
304
305 /// Creates a new [PdfFont] for the built-in "Courier-BoldOblique" font.
306 ///
307 /// This function is now deprecated and will be removed in release 0.9.0.
308 /// Use the `PdfFonts::courier_bold_oblique()` function instead.
309 #[deprecated(
310 since = "0.8.1",
311 note = "This function has been moved. Use the PdfFonts::courier_bold_oblique() function instead."
312 )]
313 #[doc(hidden)]
314 #[inline]
315 pub fn courier_bold_oblique(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
316 #[allow(deprecated)]
317 Self::new_built_in(document, PdfFontBuiltin::CourierBoldOblique)
318 }
319
320 /// Creates a new [PdfFont] for the built-in "Symbol" font.
321 ///
322 /// This function is now deprecated and will be removed in release 0.9.0.
323 /// Use the `PdfFonts::symbol()` function instead.
324 #[deprecated(
325 since = "0.8.1",
326 note = "This function has been moved. Use the PdfFonts::symbol() function instead."
327 )]
328 #[doc(hidden)]
329 #[inline]
330 pub fn symbol(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
331 #[allow(deprecated)]
332 Self::new_built_in(document, PdfFontBuiltin::Symbol)
333 }
334
335 /// Creates a new [PdfFont] for the built-in "ZapfDingbats" font.
336 ///
337 /// This function is now deprecated and will be removed in release 0.9.0.
338 /// Use the `PdfFonts::zapf_dingbats()` function instead.
339 #[deprecated(
340 since = "0.8.1",
341 note = "This function has been moved. Use the PdfFonts::zapf_dingbats() function instead."
342 )]
343 #[doc(hidden)]
344 #[inline]
345 pub fn zapf_dingbats(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
346 #[allow(deprecated)]
347 Self::new_built_in(document, PdfFontBuiltin::ZapfDingbats)
348 }
349
350 /// Attempts to load a Type 1 font file from the given file path.
351 ///
352 /// Set the `is_cid_font` parameter to `true` if the given font is keyed by
353 /// 16-bit character ID (CID), indicating that it supports an extended glyphset of
354 /// 65,535 glyphs. This is typically the case with fonts that support Asian character sets
355 /// or right-to-left languages.
356 ///
357 /// This function is not available when compiling to WASM. You have several options for
358 /// loading font data in WASM:
359 /// * Use the [PdfFonts::load_type1_from_fetch()] function to download font data from a
360 /// URL using the browser's built-in `fetch()` API. This function is only available when
361 /// compiling to WASM.
362 /// * Use the [PdfFonts::load_type1_from_blob()] function to load font data from a
363 /// Javascript File or Blob object (such as a File object returned from an HTML
364 /// `<input type="file">` element). This function is only available when compiling to WASM.
365 /// * Use the [PdfFonts::load_type1_from_reader()] function to load font data from any
366 /// valid Rust reader.
367 /// * Use another method to retrieve the bytes of the target font over the network,
368 /// then load those bytes into Pdfium using the [PdfFonts::new_type1_from_bytes()] function.
369 /// * Embed the bytes of the desired font directly into the compiled WASM module
370 /// using the `include_bytes!()` macro.
371 ///
372 /// This function is now deprecated and will be removed in release 0.9.0.
373 /// Use the `PdfFonts::load_type1_from_file()` function instead.
374 #[deprecated(
375 since = "0.8.1",
376 note = "This function has been moved. Use the PdfFonts::load_type1_from_file() function instead."
377 )]
378 #[doc(hidden)]
379 #[cfg(not(target_arch = "wasm32"))]
380 pub fn load_type1_from_file(
381 document: &'a PdfDocument<'a>,
382 path: &(impl AsRef<Path> + ?Sized),
383 is_cid_font: bool,
384 ) -> Result<PdfFont<'a>, PdfiumError> {
385 #[allow(deprecated)]
386 Self::load_type1_from_reader(document, File::open(path).map_err(PdfiumError::IoError)?, is_cid_font)
387 }
388
389 /// Attempts to load a Type 1 font file from the given reader.
390 ///
391 /// Set the `is_cid_font` parameter to `true` if the given font is keyed by
392 /// 16-bit character ID (CID), indicating that it supports an extended glyphset of
393 /// 65,535 glyphs. This is typically the case with fonts that support Asian character sets
394 /// or right-to-left languages.
395 ///
396 /// This function is now deprecated and will be removed in release 0.9.0.
397 /// Use the `PdfFonts::load_type1_from_reader()` function instead.
398 #[deprecated(
399 since = "0.8.1",
400 note = "This function has been moved. Use the PdfFonts::load_type1_from_reader() function instead."
401 )]
402 #[doc(hidden)]
403 pub fn load_type1_from_reader(
404 document: &'a PdfDocument<'a>,
405 mut reader: impl Read,
406 is_cid_font: bool,
407 ) -> Result<PdfFont<'a>, PdfiumError> {
408 let mut bytes = Vec::new();
409
410 reader.read_to_end(&mut bytes).map_err(PdfiumError::IoError)?;
411
412 #[allow(deprecated)]
413 Self::new_type1_from_bytes(document, bytes.as_slice(), is_cid_font)
414 }
415
416 /// Attempts to load a Type 1 font file from the given URL.
417 /// The Javascript `fetch()` API is used to download data over the network.
418 ///
419 /// Set the `is_cid_font` parameter to `true` if the given font is keyed by
420 /// 16-bit character ID (CID), indicating that it supports an extended glyphset of
421 /// 65,535 glyphs. This is typically the case with fonts that support Asian character sets
422 /// or right-to-left languages.
423 ///
424 /// This function is only available when compiling to WASM.
425 ///
426 /// This function is now deprecated and will be removed in release 0.9.0.
427 /// Use the `PdfFonts::load_type1_from_fetch()` function instead.
428 #[deprecated(
429 since = "0.8.1",
430 note = "This function has been moved. Use the PdfFonts::load_type1_from_fetch() function instead."
431 )]
432 #[doc(hidden)]
433 #[cfg(any(doc, target_arch = "wasm32"))]
434 pub async fn load_type1_from_fetch(
435 document: &'a PdfDocument<'a>,
436 url: impl ToString,
437 is_cid_font: bool,
438 ) -> Result<PdfFont<'a>, PdfiumError> {
439 if let Some(window) = window() {
440 let fetch_result = JsFuture::from(window.fetch_with_str(url.to_string().as_str()))
441 .await
442 .map_err(PdfiumError::WebSysFetchError)?;
443
444 debug_assert!(fetch_result.is_instance_of::<Response>());
445
446 let response: Response = fetch_result
447 .dyn_into()
448 .map_err(|_| PdfiumError::WebSysInvalidResponseError)?;
449
450 let blob: Blob = JsFuture::from(response.blob().map_err(PdfiumError::WebSysFetchError)?)
451 .await
452 .map_err(PdfiumError::WebSysFetchError)?
453 .into();
454
455 #[allow(deprecated)]
456 Self::load_type1_from_blob(document, blob, is_cid_font).await
457 } else {
458 Err(PdfiumError::WebSysWindowObjectNotAvailable)
459 }
460 }
461
462 /// Attempts to load a Type 1 font from the given Blob.
463 /// A File object returned from a FileList is a suitable Blob:
464 ///
465 /// ```text
466 /// <input id="filePicker" type="file">
467 ///
468 /// const file = document.getElementById('filePicker').files[0];
469 /// ```
470 ///
471 /// Set the `is_cid_font` parameter to `true` if the given font is keyed by
472 /// 16-bit character ID (CID), indicating that it supports an extended glyphset of
473 /// 65,535 glyphs. This is typically the case with fonts that support Asian character sets
474 /// or right-to-left languages.
475 ///
476 /// This function is only available when compiling to WASM.
477 ///
478 /// This function is now deprecated and will be removed in release 0.9.0.
479 /// Use the `PdfFonts::load_type1_from_blob()` function instead.
480 #[deprecated(
481 since = "0.8.1",
482 note = "This function has been moved. Use the PdfFonts::load_type1_from_blob() function instead."
483 )]
484 #[doc(hidden)]
485 #[cfg(any(doc, target_arch = "wasm32"))]
486 pub async fn load_type1_from_blob(
487 document: &'a PdfDocument<'a>,
488 blob: Blob,
489 is_cid_font: bool,
490 ) -> Result<PdfFont<'a>, PdfiumError> {
491 let array_buffer: ArrayBuffer = JsFuture::from(blob.array_buffer())
492 .await
493 .map_err(PdfiumError::WebSysFetchError)?
494 .into();
495
496 let u8_array: Uint8Array = Uint8Array::new(&array_buffer);
497
498 let bytes: Vec<u8> = u8_array.to_vec();
499
500 #[allow(deprecated)]
501 Self::new_type1_from_bytes(document, bytes.as_slice(), is_cid_font)
502 }
503
504 /// Attempts to load the given byte data as a Type 1 font file.
505 ///
506 /// Set the `is_cid_font` parameter to `true` if the given font is keyed by
507 /// 16-bit character ID (CID), indicating that it supports an extended glyphset of
508 /// 65,535 glyphs. This is typically the case with fonts that support Asian character sets
509 /// or right-to-left languages.
510 ///
511 /// This function is now deprecated and will be removed in release 0.9.0.
512 /// Use the `PdfFonts::load_type1_from_bytes()` function instead.
513 #[deprecated(
514 since = "0.8.1",
515 note = "This function has been moved. Use the PdfFonts::load_type1_from_bytes() function instead."
516 )]
517 #[doc(hidden)]
518 pub fn new_type1_from_bytes(
519 document: &'a PdfDocument<'a>,
520 font_data: &[u8],
521 is_cid_font: bool,
522 ) -> Result<PdfFont<'a>, PdfiumError> {
523 Self::new_font_from_bytes(document, font_data, FPDF_FONT_TYPE1, is_cid_font)
524 }
525
526 /// Attempts to load a TrueType font file from the given file path.
527 ///
528 /// Set the `is_cid_font` parameter to `true` if the given font is keyed by
529 /// 16-bit character ID (CID), indicating that it supports an extended glyphset of
530 /// 65,535 glyphs. This is typically the case with fonts that support Asian character sets
531 /// or right-to-left languages.
532 ///
533 /// This function is not available when compiling to WASM. You have several options for
534 /// loading font data in WASM:
535 /// * Use the [PdfFonts::load_true_type_from_fetch()] function to download font data from a
536 /// URL using the browser's built-in `fetch()` API. This function is only available when
537 /// compiling to WASM.
538 /// * Use the [PdfFonts::load_true_type_from_blob()] function to load font data from a
539 /// Javascript `File` or `Blob` object (such as a `File` object returned from an HTML
540 /// `<input type="file">` element). This function is only available when compiling to WASM.
541 /// * Use the [PdfFonts::load_true_type_from_reader()] function to load font data from any
542 /// valid Rust reader.
543 /// * Use another method to retrieve the bytes of the target font over the network,
544 /// then load those bytes into Pdfium using the [PdfFonts::new_true_type_from_bytes()] function.
545 /// * Embed the bytes of the desired font directly into the compiled WASM module
546 /// using the `include_bytes!()` macro.
547 ///
548 /// This function is now deprecated and will be removed in release 0.9.0.
549 /// Use the `PdfFonts::load_true_type_from_file()` function instead.
550 #[deprecated(
551 since = "0.8.1",
552 note = "This function has been moved. Use the PdfFonts::load_true_type_from_file() function instead."
553 )]
554 #[doc(hidden)]
555 #[cfg(not(target_arch = "wasm32"))]
556 pub fn load_true_type_from_file(
557 document: &'a PdfDocument<'a>,
558 path: &(impl AsRef<Path> + ?Sized),
559 is_cid_font: bool,
560 ) -> Result<PdfFont<'a>, PdfiumError> {
561 #[allow(deprecated)]
562 Self::load_true_type_from_reader(document, File::open(path).map_err(PdfiumError::IoError)?, is_cid_font)
563 }
564
565 /// Attempts to load a TrueType font file from the given reader.
566 ///
567 /// Set the `is_cid_font` parameter to `true` if the given font is keyed by
568 /// 16-bit character ID (CID), indicating that it supports an extended glyphset of
569 /// 65,535 glyphs. This is typically the case with fonts that support Asian character sets
570 /// or right-to-left languages.
571 ///
572 /// This function is now deprecated and will be removed in release 0.9.0.
573 /// Use the `PdfFonts::load_true_type_from_reader()` function instead.
574 #[deprecated(
575 since = "0.8.1",
576 note = "This function has been moved. Use the PdfFonts::load_true_type_from_reader() function instead."
577 )]
578 #[doc(hidden)]
579 pub fn load_true_type_from_reader(
580 document: &'a PdfDocument<'a>,
581 mut reader: impl Read,
582 is_cid_font: bool,
583 ) -> Result<PdfFont<'a>, PdfiumError> {
584 let mut bytes = Vec::new();
585
586 reader.read_to_end(&mut bytes).map_err(PdfiumError::IoError)?;
587
588 #[allow(deprecated)]
589 Self::new_true_type_from_bytes(document, bytes.as_slice(), is_cid_font)
590 }
591
592 /// Attempts to load a TrueType font file from the given URL.
593 /// The Javascript `fetch()` API is used to download data over the network.
594 ///
595 /// Set the `is_cid_font` parameter to `true` if the given font is keyed by
596 /// 16-bit character ID (CID), indicating that it supports an extended glyphset of
597 /// 65,535 glyphs. This is typically the case with fonts that support Asian character sets
598 /// or right-to-left languages.
599 ///
600 /// This function is only available when compiling to WASM.
601 ///
602 /// This function is now deprecated and will be removed in release 0.9.0.
603 /// Use the `PdfFonts::load_true_type_from_fetch()` function instead.
604 #[deprecated(
605 since = "0.8.1",
606 note = "This function has been moved. Use the PdfFonts::load_true_type_from_fetch() function instead."
607 )]
608 #[doc(hidden)]
609 #[cfg(any(doc, target_arch = "wasm32"))]
610 pub async fn load_true_type_from_fetch(
611 document: &'a PdfDocument<'a>,
612 url: impl ToString,
613 is_cid_font: bool,
614 ) -> Result<PdfFont<'a>, PdfiumError> {
615 if let Some(window) = window() {
616 let fetch_result = JsFuture::from(window.fetch_with_str(url.to_string().as_str()))
617 .await
618 .map_err(PdfiumError::WebSysFetchError)?;
619
620 debug_assert!(fetch_result.is_instance_of::<Response>());
621
622 let response: Response = fetch_result
623 .dyn_into()
624 .map_err(|_| PdfiumError::WebSysInvalidResponseError)?;
625
626 let blob: Blob = JsFuture::from(response.blob().map_err(PdfiumError::WebSysFetchError)?)
627 .await
628 .map_err(PdfiumError::WebSysFetchError)?
629 .into();
630
631 #[allow(deprecated)]
632 Self::load_true_type_from_blob(document, blob, is_cid_font).await
633 } else {
634 Err(PdfiumError::WebSysWindowObjectNotAvailable)
635 }
636 }
637
638 /// Attempts to load a TrueType font from the given `Blob`.
639 /// A `File` object returned from a `FileList` is a suitable `Blob`:
640 ///
641 /// ```text
642 /// <input id="filePicker" type="file">
643 ///
644 /// const file = document.getElementById('filePicker').files[0];
645 /// ```
646 ///
647 /// Set the `is_cid_font` parameter to `true` if the given font is keyed by
648 /// 16-bit character ID (CID), indicating that it supports an extended glyphset of
649 /// 65,535 glyphs. This is typically the case with fonts that support Asian character sets
650 /// or right-to-left languages.
651 ///
652 /// This function is only available when compiling to WASM.
653 ///
654 /// This function is now deprecated and will be removed in release 0.9.0.
655 /// Use the `PdfFonts::load_true_type_from_blob()` function instead.
656 #[deprecated(
657 since = "0.8.1",
658 note = "This function has been moved. Use the PdfFonts::load_true_type_from_blob() function instead."
659 )]
660 #[doc(hidden)]
661 #[cfg(any(doc, target_arch = "wasm32"))]
662 pub async fn load_true_type_from_blob(
663 document: &'a PdfDocument<'a>,
664 blob: Blob,
665 is_cid_font: bool,
666 ) -> Result<PdfFont<'a>, PdfiumError> {
667 let array_buffer: ArrayBuffer = JsFuture::from(blob.array_buffer())
668 .await
669 .map_err(PdfiumError::WebSysFetchError)?
670 .into();
671
672 let u8_array: Uint8Array = Uint8Array::new(&array_buffer);
673
674 let bytes: Vec<u8> = u8_array.to_vec();
675
676 #[allow(deprecated)]
677 Self::new_true_type_from_bytes(document, bytes.as_slice(), is_cid_font)
678 }
679
680 /// Attempts to load the given byte data as a TrueType font file.
681 ///
682 /// Set the `is_cid_font` parameter to `true` if the given font is keyed by
683 /// 16-bit character ID (CID), indicating that it supports an extended glyphset of
684 /// 65,535 glyphs. This is typically the case with fonts that support Asian character sets
685 /// or right-to-left languages.
686 ///
687 /// This function is now deprecated and will be removed in release 0.9.0.
688 /// Use the `PdfFonts::load_true_type_from_bytes()` function instead.
689 #[deprecated(
690 since = "0.8.1",
691 note = "This function has been moved. Use the PdfFonts::load_true_type_from_bytes() function instead."
692 )]
693 #[doc(hidden)]
694 pub fn new_true_type_from_bytes(
695 document: &'a PdfDocument<'a>,
696 font_data: &[u8],
697 is_cid_font: bool,
698 ) -> Result<PdfFont<'a>, PdfiumError> {
699 Self::new_font_from_bytes(document, font_data, FPDF_FONT_TRUETYPE, is_cid_font)
700 }
701
702 #[inline]
703 pub(crate) fn new_font_from_bytes(
704 document: &'a PdfDocument<'a>,
705 font_data: &[u8],
706 font_type: c_uint,
707 is_cid_font: bool,
708 ) -> Result<PdfFont<'a>, PdfiumError> {
709 let handle = document.bindings().FPDFText_LoadFont(
710 document.handle(),
711 font_data.as_ptr(),
712 font_data.len() as c_uint,
713 font_type as c_int,
714 document.bindings().bool_to_pdfium(is_cid_font),
715 );
716
717 if handle.is_null() {
718 Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
719 } else {
720 Ok(PdfFont::from_pdfium(handle, document.bindings(), None, true))
721 }
722 }
723
724 /// Returns the internal `FPDF_FONT` handle for this [PdfFont].
725 #[inline]
726 pub(crate) fn handle(&self) -> FPDF_FONT {
727 self.handle
728 }
729
730 /// Returns the [PdfiumLibraryBindings] used by this [PdfFont].
731 #[inline]
732 pub fn bindings(&self) -> &'a dyn PdfiumLibraryBindings {
733 self.bindings
734 }
735
736 /// Returns the name of this [PdfFont].
737 pub fn name(&self) -> String {
738 let buffer_length = self
739 .bindings
740 .FPDFFont_GetBaseFontName(self.handle, std::ptr::null_mut(), 0);
741
742 if buffer_length == 0 {
743 return String::new();
744 }
745
746 let mut buffer = create_byte_buffer(buffer_length);
747
748 let result =
749 self.bindings
750 .FPDFFont_GetBaseFontName(self.handle, buffer.as_mut_ptr() as *mut c_char, buffer_length);
751
752 assert_eq!(result, buffer_length);
753
754 String::from_utf8(buffer)
755 .map(|str| str.trim_end_matches(char::from(0)).to_owned())
756 .unwrap_or_else(|_| String::new())
757 }
758
759 /// Returns the family of this [PdfFont].
760 pub fn family(&self) -> String {
761 let buffer_length = self
762 .bindings
763 .FPDFFont_GetFamilyName(self.handle, std::ptr::null_mut(), 0);
764
765 if buffer_length == 0 {
766 return String::new();
767 }
768
769 let mut buffer = create_byte_buffer(buffer_length);
770
771 let result =
772 self.bindings
773 .FPDFFont_GetFamilyName(self.handle, buffer.as_mut_ptr() as *mut c_char, buffer_length);
774
775 assert_eq!(result, buffer_length);
776
777 String::from_utf8(buffer)
778 .map(|str| str.trim_end_matches(char::from(0)).to_owned())
779 .unwrap_or_else(|_| String::new())
780 }
781
782 /// Returns the weight of this [PdfFont].
783 ///
784 /// Pdfium may not reliably return the correct value of this property for built-in fonts.
785 pub fn weight(&self) -> Result<PdfFontWeight, PdfiumError> {
786 PdfFontWeight::from_pdfium(self.bindings.FPDFFont_GetWeight(self.handle))
787 .ok_or(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
788 }
789
790 /// Returns the italic angle of this [PdfFont]. The italic angle is the angle,
791 /// expressed in degrees counter-clockwise from the vertical, of the dominant vertical
792 /// strokes of the font. The value is zero for non-italic fonts, and negative for fonts
793 /// that slope to the right (as almost all italic fonts do).
794 ///
795 /// Pdfium may not reliably return the correct value of this property for built-in fonts.
796 pub fn italic_angle(&self) -> Result<i32, PdfiumError> {
797 let mut angle = 0;
798
799 if self
800 .bindings
801 .is_true(self.bindings.FPDFFont_GetItalicAngle(self.handle, &mut angle))
802 {
803 Ok(angle)
804 } else {
805 Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
806 }
807 }
808
809 /// Returns the ascent of this [PdfFont] for the given font size. The ascent is the maximum
810 /// height above the baseline reached by glyphs in this font, excluding the height of glyphs
811 /// for accented characters.
812 pub fn ascent(&self, font_size: PdfPoints) -> Result<PdfPoints, PdfiumError> {
813 let mut ascent = 0.0;
814
815 if self.bindings.is_true(
816 self.bindings
817 .FPDFFont_GetAscent(self.handle, font_size.value, &mut ascent),
818 ) {
819 Ok(PdfPoints::new(ascent))
820 } else {
821 Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
822 }
823 }
824
825 /// Returns the descent of this [PdfFont] for the given font size. The descent is the
826 /// maximum distance below the baseline reached by glyphs in this font, expressed as a
827 /// negative points value.
828 pub fn descent(&self, font_size: PdfPoints) -> Result<PdfPoints, PdfiumError> {
829 let mut descent = 0.0;
830
831 if self.bindings.is_true(
832 self.bindings
833 .FPDFFont_GetDescent(self.handle, font_size.value, &mut descent),
834 ) {
835 Ok(PdfPoints::new(descent))
836 } else {
837 Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
838 }
839 }
840
841 /// Returns the raw font descriptor bitflags for the containing [PdfFont].
842 #[inline]
843 fn get_flags_bits(&self) -> FpdfFontDescriptorFlags {
844 FpdfFontDescriptorFlags::from_bits_truncate(self.bindings.FPDFFont_GetFlags(self.handle) as u32)
845 }
846
847 /// Returns `true` if all the glyphs in this [PdfFont] have the same width.
848 ///
849 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
850 pub fn is_fixed_pitch(&self) -> bool {
851 self.get_flags_bits()
852 .contains(FpdfFontDescriptorFlags::FIXED_PITCH_BIT_1)
853 }
854
855 /// Returns `true` if the glyphs in this [PdfFont] have variable widths.
856 ///
857 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
858 #[inline]
859 pub fn is_proportional_pitch(&self) -> bool {
860 !self.is_fixed_pitch()
861 }
862
863 /// Returns `true` if one or more glyphs in this [PdfFont] have serifs - short strokes
864 /// drawn at an angle on the top or bottom of glyph stems to decorate the glyphs.
865 /// For example, Times New Roman is a serif font.
866 ///
867 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
868 pub fn is_serif(&self) -> bool {
869 self.get_flags_bits().contains(FpdfFontDescriptorFlags::SERIF_BIT_2)
870 }
871
872 /// Returns `true` if no glyphs in this [PdfFont] have serifs - short strokes
873 /// drawn at an angle on the top or bottom of glyph stems to decorate the glyphs.
874 /// For example, Helvetica is a sans-serif font.
875 ///
876 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
877 #[inline]
878 pub fn is_sans_serif(&self) -> bool {
879 !self.is_serif()
880 }
881
882 /// Returns `true` if this [PdfFont] contains glyphs outside the Adobe standard Latin
883 /// character set.
884 ///
885 /// This classification of non-symbolic and symbolic fonts is peculiar to PDF. A font may
886 /// contain additional characters that are used in Latin writing systems but are outside the
887 /// Adobe standard Latin character set; PDF considers such a font to be symbolic.
888 ///
889 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
890 pub fn is_symbolic(&self) -> bool {
891 self.get_flags_bits().contains(FpdfFontDescriptorFlags::SYMBOLIC_BIT_3)
892 }
893
894 /// Returns `true` if this [PdfFont] does not contain glyphs outside the Adobe standard
895 /// Latin character set.
896 ///
897 /// This classification of non-symbolic and symbolic fonts is peculiar to PDF. A font may
898 /// contain additional characters that are used in Latin writing systems but are outside the
899 /// Adobe standard Latin character set; PDF considers such a font to be symbolic.
900 ///
901 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
902 pub fn is_non_symbolic(&self) -> bool {
903 self.get_flags_bits()
904 .contains(FpdfFontDescriptorFlags::NON_SYMBOLIC_BIT_6)
905 }
906
907 /// Returns `true` if the glyphs in this [PdfFont] are designed to resemble cursive handwriting.
908 ///
909 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
910 pub fn is_cursive(&self) -> bool {
911 self.get_flags_bits().contains(FpdfFontDescriptorFlags::SCRIPT_BIT_4)
912 }
913
914 /// Returns `true` if the glyphs in this [PdfFont] include dominant vertical strokes
915 /// that are slanted.
916 ///
917 /// The designed vertical stroke angle can be retrieved using the [PdfFont::italic_angle()] function.
918 ///
919 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
920 pub fn is_italic(&self) -> bool {
921 self.get_flags_bits().contains(FpdfFontDescriptorFlags::ITALIC_BIT_7)
922 }
923
924 /// Returns `true` if this [PdfFont] contains no lowercase letters by design.
925 ///
926 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
927 pub fn is_all_caps(&self) -> bool {
928 self.get_flags_bits().contains(FpdfFontDescriptorFlags::ALL_CAP_BIT_17)
929 }
930
931 /// Returns `true` if the lowercase letters in this [PdfFont] have the same shapes as the
932 /// corresponding uppercase letters but are sized proportionally so they have the same size
933 /// and stroke weight as lowercase glyphs in the same typeface family.
934 ///
935 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
936 pub fn is_small_caps(&self) -> bool {
937 self.get_flags_bits()
938 .contains(FpdfFontDescriptorFlags::SMALL_CAP_BIT_18)
939 }
940
941 /// Returns `true` if bold glyphs in this [PdfFont] are painted with extra pixels
942 /// at very small font sizes.
943 ///
944 /// Typically when glyphs are painted at small sizes on low-resolution devices, individual strokes
945 /// of bold glyphs may appear only one pixel wide. Because this is the minimum width of a pixel
946 /// based device, individual strokes of non-bold glyphs may also appear as one pixel wide
947 /// and therefore cannot be distinguished from bold glyphs. If this flag is set, individual
948 /// strokes of bold glyphs may be thickened at small font sizes.
949 ///
950 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
951 pub fn is_bold_reenforced(&self) -> bool {
952 self.get_flags_bits()
953 .contains(FpdfFontDescriptorFlags::FORCE_BOLD_BIT_19)
954 }
955
956 /// Returns `true` if this [PdfFont] is an instance of one of the 14 built-in fonts
957 /// provided as part of the PDF specification.
958 #[inline]
959 pub fn is_built_in(&self) -> bool {
960 self.built_in.is_some()
961 }
962
963 /// Returns the [PdfFontBuiltin] type of this built-in font, or `None` if this font is
964 /// not one of the 14 built-in fonts provided as part of the PDF specification.
965 #[inline]
966 pub fn built_in(&self) -> Option<PdfFontBuiltin> {
967 self.built_in
968 }
969
970 /// Returns `true` if the data for this [PdfFont] is embedded in the containing [PdfDocument].
971 pub fn is_embedded(&self) -> Result<bool, PdfiumError> {
972 let result = self.bindings.FPDFFont_GetIsEmbedded(self.handle);
973
974 match result {
975 1 => Ok(true),
976 0 => Ok(false),
977 _ => Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown)),
978 }
979 }
980
981 /// Writes this [PdfFont] to a new byte buffer, returning the byte buffer.
982 ///
983 /// If this [PdfFont] is not embedded in the containing [PdfDocument], then the data
984 /// returned will be for the substitution font instead.
985 pub fn data(&self) -> Result<Vec<u8>, PdfiumError> {
986 let mut out_buflen: usize = 0;
987
988 if self.bindings().is_true(self.bindings().FPDFFont_GetFontData(
989 self.handle,
990 std::ptr::null_mut(),
991 0,
992 &mut out_buflen,
993 )) {
994 let buffer_length = out_buflen;
995
996 let mut buffer = create_byte_buffer(buffer_length);
997
998 let result =
999 self.bindings()
1000 .FPDFFont_GetFontData(self.handle, buffer.as_mut_ptr(), buffer_length, &mut out_buflen);
1001
1002 assert!(self.bindings.is_true(result));
1003 assert_eq!(buffer_length, out_buflen);
1004
1005 Ok(buffer)
1006 } else {
1007 Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
1008 }
1009 }
1010
1011 /// Returns a collection of all the [PdfFontGlyphs] defined for this [PdfFont] in the containing
1012 /// `PdfDocument`.
1013 ///
1014 /// Note that documents typically include only the specific glyphs they need from any given font,
1015 /// not the entire font glyphset. This is a PDF feature known as font subsetting. The collection
1016 /// of glyphs returned by this function may therefore not cover the entire font glyphset.
1017 #[inline]
1018 pub fn glyphs(&self) -> &PdfFontGlyphs<'_> {
1019 self.glyphs.initialize_len();
1020 &self.glyphs
1021 }
1022}
1023
1024impl<'a> Drop for PdfFont<'a> {
1025 /// Closes this [PdfFont], releasing held memory.
1026 #[inline]
1027 fn drop(&mut self) {
1028 if self.is_font_memory_loaded {
1029 self.bindings.FPDFFont_Close(self.handle);
1030 }
1031 }
1032}