Skip to main content

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