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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use std::{collections::HashMap, convert::TryFrom, mem};
use crate::{
error::{ParseError, PdfResult},
objects::{Dictionary, Object, ObjectType},
pdf_enum, Resolve,
};
#[derive(Debug)]
pub enum FontEncoding {
Base(BaseFontEncoding),
Dictionary(FontEncodingDict),
}
impl FontEncoding {
pub fn from_obj(obj: Object, resolver: &mut dyn Resolve) -> PdfResult<Self> {
Ok(match resolver.resolve(obj)? {
Object::Name(ref name) => Self::Base(BaseFontEncoding::from_str(name)?),
Object::Dictionary(dict) => {
Self::Dictionary(FontEncodingDict::from_dict(dict, resolver)?)
}
found => {
return Err(ParseError::MismatchedObjectTypeAny {
found,
expected: &[ObjectType::Dictionary, ObjectType::Name],
})
}
})
}
}
pdf_enum!(
#[derive(Debug)]
pub enum BaseFontEncoding {
/// Mac OS standard encoding for Latin text in Western writing systems.
///
/// Conforming readers shall have a predefined encoding named MacRomanEncoding that may be used with
/// both Type 1 and TrueType fonts.
MacRomanEncoding = "MacRomanEncoding",
/// An encoding for use with expert fonts-ones containing the expert character set.
///
/// Conforming readers shall have a predefined encoding named MacExpertEncoding. Despite its
/// name, it is not a platform specific encoding; however, only certain fonts have the
/// appropriate character set for use with this encoding. No such fonts are among the
/// standard 14 predefined fonts.
MacExpertEncoding = "MacExpertEncoding",
/// Windows Code Page 1252, often called the "Windows ANSI" encoding.
///
/// This is the standard Windows encoding for Latin text in Western writing systems. Conforming
/// readers shall have a predefined encoding named WinAnsiEncoding that may be used with both
/// Type 1 and TrueType fonts.
WinAnsiEncoding = "WinAnsiEncoding",
}
);
#[derive(Debug)]
pub struct FontEncodingDict {
/// The base encoding—that is, the encoding from which the Differences entry (if present)
/// describes differences— shall be the name of one of the predefined encodings
/// MacRomanEncoding, MacExpertEncoding, or WinAnsiEncoding. If this entry is absent,
/// the Differences entry shall describe differences from an implicit base encoding. For
/// a font program that is embedded in the PDF file, the implicit base encoding shall be
/// the font program’s built-in encoding. Otherwise, for a nonsymbolic font, it shall be
/// StandardEncoding, and for a symbolic font, it shall be the font’s built-in encoding
base_encoding: Option<BaseFontEncoding>,
/// An array describing the differences from the encoding specified by BaseEncoding or,
/// if BaseEncoding is absent, from an implicit base encoding. The Differences array is
/// described in subsequent sub-clauses.
differences: FontDifferences,
}
impl FontEncodingDict {
const TYPE: &'static str = "Encoding";
pub fn from_dict(mut dict: Dictionary, resolver: &mut dyn Resolve) -> PdfResult<Self> {
dict.expect_type(Self::TYPE, resolver, false)?;
let base_encoding = dict
.get_name("BaseEncoding", resolver)?
.as_deref()
.map(BaseFontEncoding::from_str)
.transpose()?;
let differences =
FontDifferences::from_arr(dict.expect_arr("Differences", resolver)?, resolver)?;
Ok(Self {
base_encoding,
differences,
})
}
}
#[derive(Debug)]
struct FontDifferences(HashMap<u32, Vec<String>>);
impl FontDifferences {
pub fn from_arr(mut arr: Vec<Object>, resolver: &mut dyn Resolve) -> PdfResult<Self> {
if arr.is_empty() {
return Ok(FontDifferences(HashMap::new()));
}
let mut map = HashMap::new();
let mut code_point = resolver.assert_unsigned_integer(arr.remove(0))?;
let mut names = Vec::new();
for obj in arr.into_iter().skip(1) {
match resolver.resolve(obj)? {
Object::Integer(i) => {
map.insert(code_point, mem::take(&mut names));
names.clear();
code_point = u32::try_from(i)?;
}
Object::Name(name) => names.push(name),
found => {
return Err(ParseError::MismatchedObjectTypeAny {
found,
expected: &[ObjectType::Name, ObjectType::Integer],
})
}
}
}
Ok(Self(map))
}
}