fast_image_resize/
pixels.rs

1//! Contains types of pixels.
2use core::fmt::{Debug, Formatter};
3use core::marker::PhantomData;
4use core::mem::size_of;
5use core::slice;
6
7#[allow(unused_imports)]
8// It is used to implement floats in no_std
9use crate::compat::*;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12#[non_exhaustive]
13pub enum PixelType {
14    U8,
15    U8x2,
16    U8x3,
17    U8x4,
18    U16,
19    U16x2,
20    U16x3,
21    U16x4,
22    I32,
23    F32,
24    F32x2,
25    F32x3,
26    F32x4,
27}
28
29impl PixelType {
30    /// Returns pixel size in bytes.
31    pub fn size(&self) -> usize {
32        match self {
33            Self::U8 => 1,
34            Self::U8x2 => 2,
35            Self::U8x3 => 3,
36            Self::U16 => 2,
37            Self::U16x2 => 4,
38            Self::U16x3 => 6,
39            Self::U16x4 => 8,
40            Self::F32x2 => 8,
41            Self::F32x3 => 12,
42            Self::F32x4 => 16,
43            _ => 4,
44        }
45    }
46
47    /// Returns `true` if the given buffer has the same alignment as the pixel.
48    pub(crate) fn is_aligned(&self, buffer: &[u8]) -> bool {
49        match self {
50            Self::U8 => true,
51            Self::U8x2 => unsafe { buffer.align_to::<U8x2>().0.is_empty() },
52            Self::U8x3 => unsafe { buffer.align_to::<U8x3>().0.is_empty() },
53            Self::U8x4 => unsafe { buffer.align_to::<U8x4>().0.is_empty() },
54            Self::U16 => unsafe { buffer.align_to::<U16>().0.is_empty() },
55            Self::U16x2 => unsafe { buffer.align_to::<U16x2>().0.is_empty() },
56            Self::U16x3 => unsafe { buffer.align_to::<U16x3>().0.is_empty() },
57            Self::U16x4 => unsafe { buffer.align_to::<U16x4>().0.is_empty() },
58            Self::I32 => unsafe { buffer.align_to::<I32>().0.is_empty() },
59            Self::F32 => unsafe { buffer.align_to::<F32>().0.is_empty() },
60            Self::F32x2 => unsafe { buffer.align_to::<F32x2>().0.is_empty() },
61            Self::F32x3 => unsafe { buffer.align_to::<F32x3>().0.is_empty() },
62            Self::F32x4 => unsafe { buffer.align_to::<F32x4>().0.is_empty() },
63        }
64    }
65}
66
67pub trait GetCount {
68    fn count() -> usize;
69}
70
71/// Generic type to represent the number of components in a single pixel.
72pub struct Count<const N: usize>;
73
74impl<const N: usize> GetCount for Count<N> {
75    #[inline(always)]
76    fn count() -> usize {
77        N
78    }
79}
80
81pub trait GetCountOfValues {
82    fn count_of_values() -> usize;
83}
84
85/// Generic type to represent the number of available values for a single pixel component.
86pub struct Values<const N: usize>;
87
88impl<const N: usize> GetCountOfValues for Values<N> {
89    fn count_of_values() -> usize {
90        N
91    }
92}
93
94/// Information about one component of a pixel.
95pub trait PixelComponent
96where
97    Self: Sized + Copy + Debug + PartialEq + 'static,
98{
99    /// Type that provides information about a count of
100    /// available values of one pixel's component
101    type CountOfComponentValues: GetCountOfValues;
102
103    /// Count of available values of one pixel's component
104    fn count_of_values() -> usize {
105        Self::CountOfComponentValues::count_of_values()
106    }
107}
108
109impl PixelComponent for u8 {
110    type CountOfComponentValues = Values<0x100>;
111}
112
113impl PixelComponent for u16 {
114    type CountOfComponentValues = Values<0x10000>;
115}
116
117impl PixelComponent for i32 {
118    type CountOfComponentValues = Values<0>;
119}
120
121impl PixelComponent for f32 {
122    type CountOfComponentValues = Values<0>;
123}
124
125// Prevent users from implementing the InnerPixel trait.
126mod private {
127    pub trait Sealed {}
128}
129
130/// Inner trait that provides additional information about a pixel type.
131///
132/// Don't use this trait in your code. You must use the "child"
133/// trait [PixelTrait](crate::PixelTrait) instead.
134///
135/// This trait is sealed and cannot be implemented for types outside this crate.
136pub trait InnerPixel:
137    private::Sealed + Copy + Clone + Sized + Debug + PartialEq + Default + Send + Sync + 'static
138{
139    /// Type of pixel components
140    type Component: PixelComponent;
141    /// Type that provides information about a count of pixel's components
142    type CountOfComponents: GetCount;
143
144    fn pixel_type() -> PixelType;
145
146    /// Count of pixel's components
147    fn count_of_components() -> usize {
148        Self::CountOfComponents::count()
149    }
150
151    /// Count of available values of one pixel's component
152    fn count_of_component_values() -> usize {
153        Self::Component::count_of_values()
154    }
155
156    fn components_is_u8() -> bool {
157        Self::count_of_component_values() == 256
158    }
159
160    /// Size of pixel in bytes
161    ///
162    /// Example:
163    /// ```
164    /// # use fast_image_resize::pixels::{U8x2, U8x3, U8, InnerPixel};
165    /// assert_eq!(U8x3::size(), 3);
166    /// assert_eq!(U8x2::size(), 2);
167    /// assert_eq!(U8::size(), 1);
168    /// ```
169    fn size() -> usize {
170        size_of::<Self>()
171    }
172
173    /// Create a slice of pixel's components from a slice of pixels
174    fn components(buf: &[Self]) -> &[Self::Component] {
175        let size = buf.len() * Self::count_of_components();
176        let components_ptr = buf.as_ptr() as *const Self::Component;
177        unsafe { slice::from_raw_parts(components_ptr, size) }
178    }
179
180    /// Create mutable slice of pixel's components from mutable slice of pixels
181    fn components_mut(buf: &mut [Self]) -> &mut [Self::Component] {
182        let size = buf.len() * Self::count_of_components();
183        let components_ptr = buf.as_mut_ptr() as *mut Self::Component;
184        unsafe { slice::from_raw_parts_mut(components_ptr, size) }
185    }
186
187    /// Returns empty pixel value
188    fn empty() -> Self {
189        Self::default()
190    }
191}
192
193/// Generic type of pixel.
194#[derive(Copy, Clone, PartialEq, Default)]
195#[repr(C)]
196pub struct Pixel<T: Default, C, const COUNT_OF_COMPONENTS: usize>(
197    pub T,
198    PhantomData<[C; COUNT_OF_COMPONENTS]>,
199)
200where
201    T: Sized + Copy + Clone + PartialEq + 'static,
202    C: PixelComponent;
203
204impl<T, C, const COUNT_OF_COMPONENTS: usize> Pixel<T, C, COUNT_OF_COMPONENTS>
205where
206    T: Sized + Copy + Clone + PartialEq + Default + 'static,
207    C: PixelComponent,
208{
209    #[inline(always)]
210    pub const fn new(v: T) -> Self {
211        Self(v, PhantomData)
212    }
213}
214
215// SAFETY: bytemuck derives are tripped by the use of generic arguments.
216// However, since Pixel<T, _, _> is repr(C) it introduces no padding after T nor
217// imposes any additional limitations on T. Hence, if T is Zeroable, Pixel is
218// Zeroable.
219#[cfg(feature = "bytemuck")]
220unsafe impl<T: bytemuck::Zeroable, C, const COUNT_OF_COMPONENTS: usize> bytemuck::Zeroable
221    for Pixel<T, C, COUNT_OF_COMPONENTS>
222where
223    T: Sized + Copy + Clone + PartialEq + Default + 'static,
224    C: PixelComponent,
225{
226}
227
228// SAFETY: As above. If T is Pod, then Pixel<T> is Pod.
229#[cfg(feature = "bytemuck")]
230unsafe impl<T: bytemuck::Pod, C, const COUNT_OF_COMPONENTS: usize> bytemuck::Pod
231    for Pixel<T, C, COUNT_OF_COMPONENTS>
232where
233    T: Sized + Copy + Clone + PartialEq + Default + 'static,
234    C: PixelComponent,
235{
236}
237
238macro_rules! pixel_struct {
239    ($name:ident, $type:tt, $comp_type:tt, $comp_count:literal, $pixel_type:expr, $doc:expr) => {
240        #[doc = $doc]
241        pub type $name = Pixel<$type, $comp_type, $comp_count>;
242
243        impl private::Sealed for $name {}
244
245        impl InnerPixel for $name {
246            type Component = $comp_type;
247            type CountOfComponents = Count<$comp_count>;
248
249            fn pixel_type() -> PixelType {
250                $pixel_type
251            }
252        }
253
254        impl Debug for $name {
255            fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
256                let components_ptr = self as *const _ as *const $comp_type;
257                let components: &[$comp_type] =
258                    unsafe { slice::from_raw_parts(components_ptr, $comp_count) };
259                write!(f, "{}{:?}", stringify!($name), components)
260            }
261        }
262    };
263}
264
265pixel_struct!(U8, u8, u8, 1, PixelType::U8, "One byte per pixel (e.g. L8)");
266pixel_struct!(
267    U8x2,
268    [u8; 2],
269    u8,
270    2,
271    PixelType::U8x2,
272    "Two bytes per pixel (e.g. LA8)"
273);
274pixel_struct!(
275    U8x3,
276    [u8; 3],
277    u8,
278    3,
279    PixelType::U8x3,
280    "Three bytes per pixel (e.g. RGB8)"
281);
282pixel_struct!(
283    U8x4,
284    [u8; 4],
285    u8,
286    4,
287    PixelType::U8x4,
288    "Four bytes per pixel (RGBA8, RGBx8, CMYK8 and other)"
289);
290pixel_struct!(
291    U16,
292    u16,
293    u16,
294    1,
295    PixelType::U16,
296    "One `u16` component per pixel (e.g. L16)"
297);
298pixel_struct!(
299    U16x2,
300    [u16; 2],
301    u16,
302    2,
303    PixelType::U16x2,
304    "Two `u16` components per pixel (e.g. LA16)"
305);
306pixel_struct!(
307    U16x3,
308    [u16; 3],
309    u16,
310    3,
311    PixelType::U16x3,
312    "Three `u16` components per pixel (e.g. RGB16)"
313);
314pixel_struct!(
315    U16x4,
316    [u16; 4],
317    u16,
318    4,
319    PixelType::U16x4,
320    "Four `u16` components per pixel (e.g. RGBA16)"
321);
322pixel_struct!(
323    I32,
324    i32,
325    i32,
326    1,
327    PixelType::I32,
328    "One `i32` component per pixel"
329);
330pixel_struct!(
331    F32,
332    f32,
333    f32,
334    1,
335    PixelType::F32,
336    "One `f32` component per pixel"
337);
338pixel_struct!(
339    F32x2,
340    [f32; 2],
341    f32,
342    2,
343    PixelType::F32x2,
344    "Two `f32` component per pixel (e.g. LA32F)"
345);
346pixel_struct!(
347    F32x3,
348    [f32; 3],
349    f32,
350    3,
351    PixelType::F32x3,
352    "Three `f32` components per pixel (e.g. RGB32F)"
353);
354pixel_struct!(
355    F32x4,
356    [f32; 4],
357    f32,
358    4,
359    PixelType::F32x4,
360    "Four `f32` components per pixel (e.g. RGBA32F)"
361);
362
363pub trait IntoPixelComponent<Out: PixelComponent>
364where
365    Self: PixelComponent,
366{
367    fn into_component(self) -> Out;
368}
369
370impl<C: PixelComponent> IntoPixelComponent<C> for C {
371    fn into_component(self) -> C {
372        self
373    }
374}
375
376// u8
377
378impl IntoPixelComponent<u16> for u8 {
379    fn into_component(self) -> u16 {
380        u16::from_le_bytes([self, self])
381    }
382}
383
384impl IntoPixelComponent<i32> for u8 {
385    fn into_component(self) -> i32 {
386        (self as i32) << 23
387    }
388}
389
390impl IntoPixelComponent<f32> for u8 {
391    fn into_component(self) -> f32 {
392        (self as f32) / u8::MAX as f32
393    }
394}
395
396// u16
397
398impl IntoPixelComponent<u8> for u16 {
399    fn into_component(self) -> u8 {
400        self.to_le_bytes()[1]
401    }
402}
403
404impl IntoPixelComponent<i32> for u16 {
405    fn into_component(self) -> i32 {
406        (self as i32) << 15
407    }
408}
409
410impl IntoPixelComponent<f32> for u16 {
411    fn into_component(self) -> f32 {
412        (self as f32) / u16::MAX as f32
413    }
414}
415
416// i32
417
418impl IntoPixelComponent<u8> for i32 {
419    fn into_component(self) -> u8 {
420        (self.max(0).saturating_add(1 << 22) >> 23) as u8
421    }
422}
423
424impl IntoPixelComponent<u16> for i32 {
425    fn into_component(self) -> u16 {
426        (self.max(0).saturating_add(1 << 14) >> 15) as u16
427    }
428}
429
430impl IntoPixelComponent<f32> for i32 {
431    fn into_component(self) -> f32 {
432        if self < 0 {
433            (self as f32) / i32::MIN as f32
434        } else {
435            (self as f32) / i32::MAX as f32
436        }
437    }
438}
439
440// f32
441
442impl IntoPixelComponent<u8> for f32 {
443    fn into_component(self) -> u8 {
444        (self.clamp(0., 1.) * u8::MAX as f32).round() as u8
445    }
446}
447
448impl IntoPixelComponent<u16> for f32 {
449    fn into_component(self) -> u16 {
450        (self.clamp(0., 1.) * u16::MAX as f32).round() as u16
451    }
452}
453
454impl IntoPixelComponent<i32> for f32 {
455    fn into_component(self) -> i32 {
456        let max = if self < 0. {
457            i32::MIN as f32
458        } else {
459            i32::MAX as f32
460        };
461        (self.clamp(-1., 1.) * max).round() as i32
462    }
463}