peniko/image.rs
1// Copyright 2022 the Peniko Authors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4use super::{Blob, Extend};
5
6/// Defines the pixel format of an [image](ImageData).
7#[derive(Copy, Clone, PartialEq, Eq, Debug)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9#[non_exhaustive]
10#[repr(u8)]
11pub enum ImageFormat {
12 /// 32-bit RGBA with 8-bit channels.
13 Rgba8 = 0,
14 /// 32-bit BGRA with 8-bit channels.
15 Bgra8 = 1,
16 // NOTICE: If a new value is added, be sure to update the bytemuck CheckedBitPattern impl.
17}
18
19impl ImageFormat {
20 /// Returns the required size in bytes for an image in this format
21 /// of the given dimensions.
22 ///
23 /// A result of `None` indicates an overflow in the size calculation.
24 #[must_use]
25 pub fn size_in_bytes(self, width: u32, height: u32) -> Option<usize> {
26 match self {
27 Self::Rgba8 | Self::Bgra8 => 4_usize
28 .checked_mul(width as usize)
29 .and_then(|x| x.checked_mul(height as usize)),
30 }
31 }
32}
33
34/// Handling of alpha channel.
35#[derive(Copy, Clone, PartialEq, Eq, Debug)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
37#[repr(u8)]
38pub enum ImageAlphaType {
39 /// Image has separate alpha channel (also called straight/unpremultiplied alpha).
40 Alpha = 0,
41 /// Image has colors with premultiplied alpha.
42 AlphaPremultiplied = 1,
43}
44
45/// Defines the desired quality for sampling an image.
46#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
47#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
48#[repr(u8)]
49pub enum ImageQuality {
50 /// Lowest quality with best performance characteristics.
51 ///
52 /// This is typically nearest neighbor sampling.
53 Low = 0,
54 /// Medium quality with reasonable performance characteristics.
55 ///
56 /// This is typically bilinear sampling.
57 #[default]
58 Medium = 1,
59 /// Highest quality with worst performance characteristics.
60 ///
61 /// This is typically bicubic sampling.
62 High = 2,
63 // NOTICE: If a new value is added, be sure to update the bytemuck CheckedBitPattern impl.
64}
65
66/// Owned shareable image resource.
67#[derive(Clone, PartialEq, Debug)]
68#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
69pub struct ImageData {
70 /// Blob containing the image data.
71 pub data: Blob<u8>,
72 /// Pixel format of the image.
73 pub format: ImageFormat,
74 /// Encoding of alpha in the image pixels.
75 pub alpha_type: ImageAlphaType,
76 /// Width of the image.
77 pub width: u32,
78 /// Height of the image.
79 pub height: u32,
80}
81
82/// Parameters which specify how to sample an image during rendering.
83///
84/// When a renderer is drawing an image, they will (in most cases) not directly
85/// copy the bytes from the source image to their render target; instead, they will
86/// sample from the image.
87/// This involves determining from which part of the source image to read, and how to
88/// handle cases where the source image's pixels are not aligned with the render target
89/// exactly, in any combination of scale, position or rotation.
90/// They might also perform an alpha multiplication, as done here.
91/// This struct contains the parameters used by sampling.
92#[derive(Copy, Clone, PartialEq, Debug)]
93#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
94pub struct ImageSampler {
95 /// Extend mode in the horizontal direction.
96 pub x_extend: Extend,
97 /// Extend mode in the vertical direction.
98 pub y_extend: Extend,
99 /// Hint for desired rendering quality.
100 pub quality: ImageQuality,
101 /// An additional alpha multiplier to use with the image.
102 pub alpha: f32,
103}
104
105impl Default for ImageSampler {
106 fn default() -> Self {
107 Self {
108 x_extend: Extend::Pad,
109 y_extend: Extend::Pad,
110 quality: ImageQuality::Medium,
111 alpha: 1., // Opaque
112 }
113 }
114}
115
116impl ImageSampler {
117 /// Creates a new `ImageSampler` with default values
118 #[must_use]
119 pub fn new() -> Self {
120 Self::default()
121 }
122
123 /// Builder method for setting the image [extend mode](Extend) in both
124 /// directions.
125 #[must_use]
126 pub fn with_extend(mut self, mode: Extend) -> Self {
127 self.x_extend = mode;
128 self.y_extend = mode;
129 self
130 }
131
132 /// Builder method for setting the image [extend mode](Extend) in the
133 /// horizontal direction.
134 #[must_use]
135 pub fn with_x_extend(mut self, mode: Extend) -> Self {
136 self.x_extend = mode;
137 self
138 }
139
140 /// Builder method for setting the image [extend mode](Extend) in the
141 /// vertical direction.
142 #[must_use]
143 pub fn with_y_extend(mut self, mode: Extend) -> Self {
144 self.y_extend = mode;
145 self
146 }
147
148 /// Builder method for setting a hint for the desired image [quality](ImageQuality)
149 /// when rendering.
150 #[must_use]
151 pub fn with_quality(mut self, quality: ImageQuality) -> Self {
152 self.quality = quality;
153 self
154 }
155
156 /// Returns the image with the alpha multiplier set to `alpha`.
157 #[must_use]
158 #[track_caller]
159 pub fn with_alpha(mut self, alpha: f32) -> Self {
160 debug_assert!(
161 alpha.is_finite() && alpha >= 0.0,
162 "A non-finite or negative alpha ({alpha}) is meaningless."
163 );
164 self.alpha = alpha;
165 self
166 }
167
168 /// Returns the image with the alpha multiplier multiplied again by `alpha`.
169 /// The behaviour of this transformation is undefined if `alpha` is negative.
170 #[must_use]
171 #[track_caller]
172 pub fn multiply_alpha(mut self, alpha: f32) -> Self {
173 debug_assert!(
174 alpha.is_finite() && alpha >= 0.0,
175 "A non-finite or negative alpha ({alpha}) is meaningless."
176 );
177 self.alpha *= alpha;
178 self
179 }
180}
181
182/// Describes the image content of a filled or stroked shape.
183///
184/// This type is generic over the storage used for the image data.
185/// By default, the generic parameter is [`ImageData`], which is a shared image with dynamic lifetime.
186/// However, different renderers can use different types here, such as a pre-registered id.
187#[derive(Copy, Clone, PartialEq, Debug)]
188#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
189pub struct ImageBrush<D = ImageData> {
190 /// The image to render.
191 pub image: D,
192 /// Parameters which specify how to sample from the image during rendering.
193 pub sampler: ImageSampler,
194}
195
196impl<D> ImageBrush<D> {
197 /// Builder method for setting the image [extend mode](Extend) in both
198 /// directions.
199 #[must_use]
200 pub fn with_extend(mut self, mode: Extend) -> Self {
201 self.sampler.x_extend = mode;
202 self.sampler.y_extend = mode;
203 self
204 }
205
206 /// Builder method for setting the image [extend mode](Extend) in the
207 /// horizontal direction.
208 #[must_use]
209 pub fn with_x_extend(mut self, mode: Extend) -> Self {
210 self.sampler.x_extend = mode;
211 self
212 }
213
214 /// Builder method for setting the image [extend mode](Extend) in the
215 /// vertical direction.
216 #[must_use]
217 pub fn with_y_extend(mut self, mode: Extend) -> Self {
218 self.sampler.y_extend = mode;
219 self
220 }
221
222 /// Builder method for setting a hint for the desired image [quality](ImageQuality)
223 /// when rendering.
224 #[must_use]
225 pub fn with_quality(mut self, quality: ImageQuality) -> Self {
226 self.sampler.quality = quality;
227 self
228 }
229
230 /// Returns the image with the alpha multiplier set to `alpha`.
231 #[must_use]
232 #[track_caller]
233 pub fn with_alpha(mut self, alpha: f32) -> Self {
234 debug_assert!(
235 alpha.is_finite() && alpha >= 0.0,
236 "A non-finite or negative alpha ({alpha}) is meaningless."
237 );
238 self.sampler.alpha = alpha;
239 self
240 }
241
242 /// Returns the image with the alpha multiplier multiplied again by `alpha`.
243 /// The behaviour of this transformation is undefined if `alpha` is negative.
244 #[must_use]
245 #[track_caller]
246 pub fn multiply_alpha(mut self, alpha: f32) -> Self {
247 debug_assert!(
248 alpha.is_finite() && alpha >= 0.0,
249 "A non-finite or negative alpha ({alpha}) is meaningless."
250 );
251 self.sampler.alpha *= alpha;
252 self
253 }
254}
255
256impl ImageBrush {
257 /// Creates a new `ImageBrush` for the specified `ImageData` with default `ImageSampler`.
258 #[must_use]
259 pub fn new(image: ImageData) -> Self {
260 Self {
261 image,
262 sampler: ImageSampler::default(),
263 }
264 }
265
266 /// Converts an owned `ImageBrush` into a borrowed `ImageBrushRef`.
267 #[must_use]
268 pub fn as_ref(&'_ self) -> ImageBrushRef<'_> {
269 ImageBrush {
270 image: &self.image,
271 sampler: self.sampler,
272 }
273 }
274}
275
276impl From<ImageData> for ImageBrush {
277 fn from(image: ImageData) -> Self {
278 Self::new(image)
279 }
280}
281
282/// Borrowed version of [`ImageBrush`] for avoiding reference counting overhead.
283///
284/// This is useful for methods that would like to accept image brushes by reference.
285/// Defining the type as `impl Into<ImageBrushRef>` is the most general useful argument
286/// type, as it also allows `&ImageBrush`.
287pub type ImageBrushRef<'a> = ImageBrush<&'a ImageData>;
288
289impl ImageBrushRef<'_> {
290 /// Converts the `ImageBrushRef` to an owned `ImageBrush`.
291 #[must_use]
292 pub fn to_owned(&self) -> ImageBrush {
293 ImageBrush {
294 image: (*self.image).clone(),
295 sampler: self.sampler,
296 }
297 }
298}
299
300impl<'a> From<&'a ImageBrush> for ImageBrushRef<'a> {
301 fn from(value: &'a ImageBrush) -> Self {
302 value.as_ref()
303 }
304}