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](Image).
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 // NOTICE: If a new value is added, be sure to update the bytemuck CheckedBitPattern impl.
15}
16
17impl ImageFormat {
18 /// Returns the required size in bytes for an image in this format
19 /// of the given dimensions.
20 ///
21 /// A result of `None` indicates an overflow in the size calculation.
22 #[must_use]
23 pub fn size_in_bytes(self, width: u32, height: u32) -> Option<usize> {
24 match self {
25 Self::Rgba8 => 4_usize
26 .checked_mul(width as usize)
27 .and_then(|x| x.checked_mul(height as usize)),
28 }
29 }
30}
31
32/// Defines the desired quality for sampling an [image](Image).
33#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
34#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
35#[repr(u8)]
36pub enum ImageQuality {
37 /// Lowest quality with best performance characteristics.
38 ///
39 /// This is typically nearest neighbor sampling.
40 Low = 0,
41 /// Medium quality with reasonable performance characteristics.
42 ///
43 /// This is typically bilinear sampling.
44 #[default]
45 Medium = 1,
46 /// Highest quality with worst performance characteristics.
47 ///
48 /// This is typically bicubic sampling.
49 High = 2,
50 // NOTICE: If a new value is added, be sure to update the bytemuck CheckedBitPattern impl.
51}
52
53/// Owned shareable image resource.
54#[derive(Clone, PartialEq, Debug)]
55#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
56pub struct Image {
57 /// Blob containing the image data.
58 pub data: Blob<u8>,
59 /// Pixel format of the image.
60 pub format: ImageFormat,
61 /// Width of the image.
62 pub width: u32,
63 /// Height of the image.
64 pub height: u32,
65 /// Extend mode in the horizontal direction.
66 pub x_extend: Extend,
67 /// Extend mode in the vertical direction.
68 pub y_extend: Extend,
69 /// Hint for desired rendering quality.
70 pub quality: ImageQuality,
71 /// An additional alpha multiplier to use with the image.
72 pub alpha: f32,
73}
74
75impl Image {
76 /// Creates a new image with the given data, [format](ImageFormat) and dimensions.
77 #[must_use]
78 pub fn new(data: Blob<u8>, format: ImageFormat, width: u32, height: u32) -> Self {
79 Self {
80 data,
81 format,
82 width,
83 height,
84 x_extend: Extend::Pad,
85 y_extend: Extend::Pad,
86 quality: ImageQuality::Medium,
87 // Opaque
88 alpha: 1.,
89 }
90 }
91
92 /// Builder method for setting the image [extend mode](Extend) in both
93 /// directions.
94 #[must_use]
95 pub fn with_extend(mut self, mode: Extend) -> Self {
96 self.x_extend = mode;
97 self.y_extend = mode;
98 self
99 }
100
101 /// Builder method for setting the image [extend mode](Extend) in the
102 /// horizontal direction.
103 #[must_use]
104 pub fn with_x_extend(mut self, mode: Extend) -> Self {
105 self.x_extend = mode;
106 self
107 }
108
109 /// Builder method for setting the image [extend mode](Extend) in the
110 /// vertical direction.
111 #[must_use]
112 pub fn with_y_extend(mut self, mode: Extend) -> Self {
113 self.y_extend = mode;
114 self
115 }
116
117 /// Builder method for setting a hint for the desired image [quality](ImageQuality)
118 /// when rendering.
119 #[must_use]
120 pub fn with_quality(mut self, quality: ImageQuality) -> Self {
121 self.quality = quality;
122 self
123 }
124
125 /// Returns the image with the alpha multiplier set to `alpha`.
126 #[must_use]
127 #[track_caller]
128 pub fn with_alpha(mut self, alpha: f32) -> Self {
129 debug_assert!(
130 alpha.is_finite() && alpha >= 0.0,
131 "A non-finite or negative alpha ({alpha}) is meaningless."
132 );
133 self.alpha = alpha;
134 self
135 }
136
137 /// Returns the image with the alpha multiplier multiplied again by `alpha`.
138 /// The behaviour of this transformation is undefined if `alpha` is negative.
139 #[must_use]
140 #[track_caller]
141 pub fn multiply_alpha(mut self, alpha: f32) -> Self {
142 debug_assert!(
143 alpha.is_finite() && alpha >= 0.0,
144 "A non-finite or negative alpha ({alpha}) is meaningless."
145 );
146 self.alpha *= alpha;
147 self
148 }
149}