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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//! Color palette table.
use super::name::NameId;
use super::parse_prelude::*;
/// Tag for the `CPAL` table.
pub const CPAL: Tag = Tag::new(b"CPAL");
/// Color palette table.
///
/// <https://docs.microsoft.com/en-us/typography/opentype/spec/cpal>
#[derive(Copy, Clone)]
pub struct Cpal<'a> {
data: Buffer<'a>,
version: u16,
len: u16,
offset: u32,
}
impl<'a> Cpal<'a> {
/// Creates a new color palette table from a byte slice containing the
/// table data.
pub fn new(data: &'a [u8]) -> Self {
let data = Buffer::new(data);
let version = data.read_or_default(0);
let len = data.read_or_default(4);
let offset = data.read_or_default(8);
Self {
data,
version,
len,
offset,
}
}
/// Returns the version of the table.
pub fn version(&self) -> u16 {
self.version
}
/// Returns the number of palettes in the table.
pub fn len(&self) -> u16 {
self.len
}
/// Returns true if the table is empty.
pub fn is_empty(&self) -> bool {
self.len == 0
}
/// Returns the palette at the specified index.
pub fn get(&self, index: u16) -> Option<Palette<'a>> {
if index >= self.len {
return None;
}
let d = &self.data;
let name_id = (|| {
if self.version == 0 {
return None;
}
let base = 16 + self.len as usize * 2;
let labels_offset = d.read_u32(base)? as usize;
if labels_offset == 0 {
return None;
}
d.read_u16(labels_offset + index as usize * 2)
})();
let flags = (|| {
if self.version == 0 {
return None;
}
let base = 12 + self.len as usize * 2;
let types_offset = d.read_u32(base)? as usize;
if types_offset == 0 {
return None;
}
d.read_u32(types_offset + index as usize * 4)
})()
.unwrap_or(0);
let theme = match flags & 0b11 {
0b01 => Theme::Light,
0b10 => Theme::Dark,
_ => Theme::Any,
};
let len = d.read::<u16>(2)? as usize;
let first = d.read_u32(12 + index as usize * 2)? as usize;
let offset = self.offset as usize + first;
let colors = d.read_slice(offset, len)?;
Some(Palette {
index,
name_id,
theme,
colors,
})
}
/// Returns an iterator over the palettes in the table.
pub fn palettes(&self) -> impl Iterator<Item = Palette<'a>> + 'a + Clone {
let copy = *self;
(0..self.len).filter_map(move |i| copy.get(i))
}
}
/// Collection of colors.
#[derive(Copy, Clone)]
pub struct Palette<'a> {
/// Index of the palette.
pub index: u16,
/// Identifier for the name of the palette.
pub name_id: Option<NameId>,
/// Theme of the palette.
pub theme: Theme,
/// Color values.
pub colors: Slice<'a, Color>,
}
/// Theme of a palette with respect to background color.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Theme {
/// Usable with both light and dark backgrounds.
Any,
/// Usable with light backgrounds.
Light,
/// Usable with dark backgrounds.
Dark,
}
/// RGBA color value.
#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
pub struct Color {
/// Red component.
pub r: u8,
/// Green component.
pub g: u8,
/// Blue component.
pub b: u8,
/// Alpha component.
pub a: u8,
}
impl ReadData for Color {
unsafe fn read_data_unchecked(buf: &[u8], offset: usize) -> Self {
Self {
r: *buf.get_unchecked(offset + 2),
g: *buf.get_unchecked(offset + 1),
b: *buf.get_unchecked(offset),
a: *buf.get_unchecked(offset + 3),
}
}
}