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}