fast image operations
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! define From's for images.
//! these conversions are defined by [`PFrom`].
use crate::{pixels::convert::PFrom, Image};

fn map<const A: usize, const B: usize>(image: Image<&[u8], A>) -> Image<Box<[u8]>, B>
where
    [u8; B]: PFrom<A>,
{
    let buffer = image
        .chunked()
        .copied()
        .flat_map(<[u8; B] as PFrom<A>>::pfrom)
        .collect::<Vec<_>>()
        .into();
    // SAFETY: ctor
    unsafe { Image::new(image.width, image.height, buffer) }
}

macro_rules! convert {
    ($a:literal => $b:literal) => {
        impl From<Image<&[u8], $b>> for Image<Box<[u8]>, $a> {
            fn from(value: Image<&[u8], $b>) -> Self {
                map(value)
            }
        }
    };
}

macro_rules! cv {
    [$($n:literal),+] => {
        $(convert!($n => 1);
        convert!($n => 2);
        convert!($n => 3);
        convert!($n => 4);)+
    };
}

cv![1, 2, 3, 4];

macro_rules! boxconv {
    ($a:literal => $b: literal) => {
        impl From<Image<Box<[u8]>, $b>> for Image<Box<[u8]>, $a> {
            fn from(value: Image<Box<[u8]>, $b>) -> Self {
                value.as_ref().into()
            }
        }
    };
}

boxconv!(1 => 2);
boxconv!(1 => 3);
boxconv!(1 => 4);

boxconv!(2 => 1);
boxconv!(2 => 3);
boxconv!(2 => 4);

boxconv!(3 => 1);
boxconv!(3 => 2);
boxconv!(3 => 4);

boxconv!(4 => 1);
boxconv!(4 => 2);
boxconv!(4 => 3);

#[inline]
fn pack([r, g, b, a]: [u8; 4]) -> u32 {
    ((a as u32) << 24) | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32)
}

#[inline]
fn unpack(n: u32) -> [u8; 4] {
    [
        ((n >> 16) & 0xFF) as u8,
        ((n >> 8) & 0xFF) as u8,
        (n & 0xFF) as u8,
        ((n >> 24) & 0xFF) as u8,
    ]
}

impl<const N: usize> From<Image<&[u8], N>> for Image<Box<[u32]>, 1>
where
    [u8; 4]: PFrom<N>,
{
    /// Pack into ARGB.
    fn from(value: Image<&[u8], N>) -> Self {
        let buf = value
            .chunked()
            .copied()
            .map(PFrom::pfrom)
            .map(pack)
            .collect();
        // SAFETY: ctor
        unsafe { Self::new(value.width, value.height, buf) }
    }
}

pub fn unpack_all<const N: usize>(buffer: &[u32]) -> impl Iterator<Item = u8> + '_
where
    [u8; N]: PFrom<4>,
{
    buffer
        .iter()
        .copied()
        .map(unpack)
        .flat_map(<[u8; N] as PFrom<4>>::pfrom)
}

impl<const N: usize> From<Image<&[u32], 1>> for Image<Box<[u8]>, N>
where
    [u8; N]: PFrom<4>,
{
    fn from(value: Image<&[u32], 1>) -> Self {
        let buf = unpack_all(value.buffer).collect();
        // SAFETY: ctor
        unsafe { Self::new(value.width, value.height, buf) }
    }
}