hayro_interpret/types.rs
1use crate::CacheKey;
2use crate::color::Color;
3use crate::pattern::Pattern;
4use crate::util::hash128;
5use crate::x_object::ImageXObject;
6use kurbo::{BezPath, Cap, Join};
7use smallvec::{SmallVec, smallvec};
8
9/// A clip path.
10#[derive(Debug, Clone)]
11pub struct ClipPath {
12 /// The clipping path.
13 pub path: BezPath,
14 /// The fill rule.
15 pub fill: FillRule,
16}
17
18impl CacheKey for ClipPath {
19 fn cache_key(&self) -> u128 {
20 hash128(&(&self.path.to_svg(), &self.fill))
21 }
22}
23
24/// A stencil image.
25pub struct StencilImage<'a, 'b> {
26 pub(crate) paint: Paint<'a>,
27 pub(crate) image_xobject: ImageXObject<'b>,
28}
29
30impl<'a, 'b> StencilImage<'a, 'b> {
31 /// Perform some operation with the stencil data of the image.
32 ///
33 /// The second argument allows you to give the image decoder a hint for
34 /// what resolution of the image you want to have. Note that this does not
35 /// mean that the resulting image will have that dimension. Instead, it allows
36 /// the image decoder to extract a lower-resolution version of the image in
37 /// certain cases.
38 pub fn with_stencil(
39 &self,
40 func: impl FnOnce(LumaData, &Paint<'a>),
41 target_dimension: Option<(u32, u32)>,
42 ) {
43 if let Some(luma) = self
44 .image_xobject
45 .decoded_object(target_dimension)
46 .and_then(|d| d.luma_data)
47 {
48 func(luma, &self.paint);
49 }
50 }
51
52 // These are hidden since clients are supposed to call get the
53 // width/height from `LumaData` instead.
54 #[doc(hidden)]
55 pub fn width(&self) -> u32 {
56 self.image_xobject.width()
57 }
58
59 #[doc(hidden)]
60 pub fn height(&self) -> u32 {
61 self.image_xobject.height()
62 }
63}
64
65impl CacheKey for StencilImage<'_, '_> {
66 fn cache_key(&self) -> u128 {
67 self.image_xobject.cache_key()
68 }
69}
70
71/// A raster image.
72pub struct RasterImage<'a>(pub(crate) ImageXObject<'a>);
73
74impl RasterImage<'_> {
75 /// Perform some operation with the RGB and alpha channel of the image.
76 ///
77 /// The second argument allows you to give the image decoder a hint for
78 /// what resolution of the image you want to have. Note that this does not
79 /// mean that the resulting image will have that dimension. Instead, it allows
80 /// the image decoder to extract a lower-resolution version of the image in
81 /// certain cases.
82 pub fn with_rgba(
83 &self,
84 func: impl FnOnce(RgbData, Option<LumaData>),
85 target_dimension: Option<(u32, u32)>,
86 ) {
87 let decoded = self.0.decoded_object(target_dimension);
88
89 if let Some(decoded) = decoded
90 && let Some(rgb) = decoded.rgb_data
91 {
92 func(rgb, decoded.luma_data);
93 }
94 }
95
96 // These are hidden since clients are supposed to call get the
97 // width/height from `LumaData` instead.
98 #[doc(hidden)]
99 pub fn width(&self) -> u32 {
100 self.0.width()
101 }
102
103 #[doc(hidden)]
104 pub fn height(&self) -> u32 {
105 self.0.height()
106 }
107}
108
109impl CacheKey for RasterImage<'_> {
110 fn cache_key(&self) -> u128 {
111 self.0.cache_key()
112 }
113}
114
115/// A type of image.
116pub enum Image<'a, 'b> {
117 /// A stencil image.
118 Stencil(StencilImage<'a, 'b>),
119 /// A normal raster image.
120 Raster(RasterImage<'b>),
121}
122
123impl Image<'_, '_> {
124 // These are hidden since clients are supposed to call get the
125 // width/height from `LumaData/RgbData` instead.
126 #[doc(hidden)]
127 pub fn width(&self) -> u32 {
128 match self {
129 Image::Stencil(s) => s.width(),
130 Image::Raster(r) => r.width(),
131 }
132 }
133
134 // These are hidden since clients are supposed to call get the
135 // width/height from `LumaData/RgbData` instead.
136 #[doc(hidden)]
137 pub fn height(&self) -> u32 {
138 match self {
139 Image::Stencil(s) => s.height(),
140 Image::Raster(r) => r.height(),
141 }
142 }
143}
144
145impl CacheKey for Image<'_, '_> {
146 fn cache_key(&self) -> u128 {
147 match self {
148 Image::Stencil(i) => i.cache_key(),
149 Image::Raster(i) => i.cache_key(),
150 }
151 }
152}
153
154/// A structure holding 3-channel RGB data.
155#[derive(Clone)]
156pub struct RgbData {
157 /// The actual data. It is guaranteed to have the length width * height * 3.
158 pub data: Vec<u8>,
159 /// The width.
160 pub width: u32,
161 /// The height.
162 pub height: u32,
163 /// Whether the image should be interpolated.
164 pub interpolate: bool,
165 /// Additional scaling factors to apply to the image.
166 ///
167 /// In most cases, those factors will just be 1.0, and you can
168 /// ignore them. There are two situations in which they will not be equal
169 /// to 1:
170 /// 1) The PDF provided wrong metadata about the width/height of the image,
171 /// which needs to be corrected
172 /// 2) A lower resolution of the image was requested, in which case it needs
173 /// to be scaled up so that it still covers the same area.
174 ///
175 /// The first number indicates the x scaling factor, the second number the
176 /// y scaling factor.
177 pub scale_factors: (f32, f32),
178}
179
180/// A structure holding 1-channel luma data.
181#[derive(Clone)]
182pub struct LumaData {
183 /// The actual data. It is guaranteed to have the length width * height.
184 pub data: Vec<u8>,
185 /// The width.
186 pub width: u32,
187 /// The height.
188 pub height: u32,
189 /// Whether the image should be interpolated.
190 pub interpolate: bool,
191 /// Additional scaling factors to apply to the image.
192 ///
193 /// In most cases, those factors will just be 1.0, and you can
194 /// ignore them. There are two situations in which they will not be equal
195 /// to 1:
196 /// 1) The PDF provided wrong metadata about the width/height of the image,
197 /// which needs to be corrected
198 /// 2) A lower resolution of the image was requested, in which case it needs
199 /// to be scaled up so that it still covers the same area.
200 ///
201 /// The first number indicates the x scaling factor, the second number the
202 /// y scaling factor.
203 pub scale_factors: (f32, f32),
204}
205
206/// A type of paint.
207#[derive(Clone, Debug)]
208pub enum Paint<'a> {
209 /// A solid RGBA color.
210 Color(Color),
211 /// A PDF pattern.
212 Pattern(Box<Pattern<'a>>),
213}
214
215impl CacheKey for Paint<'_> {
216 fn cache_key(&self) -> u128 {
217 match self {
218 Paint::Color(c) => {
219 // TODO: We should actually cache the color with color space etc., not just the
220 // RGBA8 version.
221 hash128(&c.to_rgba().to_rgba8())
222 }
223 Paint::Pattern(p) => p.cache_key(),
224 }
225 }
226}
227
228/// The draw mode that should be used for a path.
229#[derive(Clone, Debug)]
230pub enum PathDrawMode {
231 /// Draw using a fill.
232 Fill(FillRule),
233 /// Draw using a stroke.
234 Stroke(StrokeProps),
235}
236
237/// The draw mode that should be used for a glyph.
238#[derive(Clone, Debug)]
239pub enum GlyphDrawMode {
240 /// Draw using a fill.
241 Fill,
242 /// Draw using a stroke.
243 Stroke(StrokeProps),
244 /// Invisible text (for text extraction but not visual rendering).
245 Invisible,
246}
247
248/// Stroke properties.
249#[derive(Clone, Debug)]
250pub struct StrokeProps {
251 /// The line width.
252 pub line_width: f32,
253 /// The line cap.
254 pub line_cap: Cap,
255 /// The line join.
256 pub line_join: Join,
257 /// The miter limit.
258 pub miter_limit: f32,
259 /// The dash array.
260 pub dash_array: SmallVec<[f32; 4]>,
261 /// The dash offset.
262 pub dash_offset: f32,
263}
264
265impl Default for StrokeProps {
266 fn default() -> Self {
267 Self {
268 line_width: 1.0,
269 line_cap: Cap::Butt,
270 line_join: Join::Miter,
271 miter_limit: 10.0,
272 dash_array: smallvec![],
273 dash_offset: 0.0,
274 }
275 }
276}
277
278/// A fill rule.
279#[derive(Clone, Debug, Copy, Hash, PartialEq, Eq)]
280pub enum FillRule {
281 /// Non-zero filling.
282 NonZero,
283 /// Even-odd filling.
284 EvenOdd,
285}
286
287/// A blend mode.
288#[derive(Clone, Debug, Copy, Hash, PartialEq, Eq, Default)]
289pub enum BlendMode {
290 /// Normal blend mode (default).
291 #[default]
292 Normal,
293 /// Multiply blend mode.
294 Multiply,
295 /// Screen blend mode.
296 Screen,
297 /// Overlay blend mode.
298 Overlay,
299 /// Darken blend mode.
300 Darken,
301 /// Lighten blend mode.
302 Lighten,
303 /// `ColorDodge` blend mode.
304 ColorDodge,
305 /// `ColorBurn` blend mode.
306 ColorBurn,
307 /// `HardLight` blend mode.
308 HardLight,
309 /// `SoftLight` blend mode.
310 SoftLight,
311 /// Difference blend mode.
312 Difference,
313 /// Exclusion blend mode.
314 Exclusion,
315 /// Hue blend mode.
316 Hue,
317 /// Saturation blend mode.
318 Saturation,
319 /// Color blend mode.
320 Color,
321 /// Luminosity blend mode.
322 Luminosity,
323}