Skip to main content

glycin_utils/editing/
change_memory_format.rs

1use std::sync::Arc;
2
3use glycin_common::{ChannelType, MemoryFormatInfo, Source, Target};
4use gufo_common::math::Checked;
5use rayon::iter::IntoParallelIterator;
6use rayon::prelude::*;
7
8use crate::{Frame, ImgBuf, MemoryFormat, editing};
9pub fn change_memory_format(
10    mut img_buf: ImgBuf,
11    mut frame: Frame,
12    target_format: MemoryFormat,
13) -> Result<(Frame, ImgBuf), editing::Error> {
14    let src_format = frame.memory_format;
15
16    if src_format == target_format {
17        log::debug!("Same image format {src_format:?}, no need for transformation");
18        return Ok((frame, img_buf));
19    }
20
21    log::debug!("Starting to transform image format from {src_format:?} to {target_format:?}");
22    let start_instant = std::time::Instant::now();
23
24    let src_format = frame.memory_format;
25    let src_data = img_buf.as_mut_slice();
26    let src_pixel_n_bytes = src_format.n_bytes().usize();
27
28    let target_pixel_n_bytes = target_format.n_bytes().usize();
29    let new_stride = (Checked::new(frame.width) * target_format.n_bytes().u32()).check()?;
30    let new_total_size: usize =
31        (Checked::new(frame.height as usize) * new_stride as usize).check()?;
32
33    let mut new_data = vec![0; new_total_size];
34
35    // Target rows for parallel processing
36    let mut target_rows = Vec::new();
37    (0..frame.height as usize).fold(new_data.as_mut_slice(), |x, y| {
38        let (row, rest) = x.split_at_mut(new_stride as usize);
39        target_rows.push((y, row));
40        rest
41    });
42
43    rayon::ThreadPoolBuilder::new()
44        .thread_name(|i| format!("gly-rayon-{i}"))
45        .build()
46        .map_err(Arc::new)?
47        .install(|| {
48            if src_format.channel_type() == target_format.channel_type()
49                && src_format.is_premultiplied() == target_format.is_premultiplied()
50                && (!src_format.source_definition().contains(&Source::Opaque)
51                    || !target_format.target_definition().contains(&Target::A))
52                && !target_format.target_definition().contains(&Target::RgbAvg)
53            {
54                let mut source_target_index_map = [0; 4];
55                for (n, target) in target_format.target_definition().iter().enumerate() {
56                    source_target_index_map[n] =
57                        src_format.source_definition()[*target as usize] as usize;
58                }
59
60                let target_n_channels = target_format.n_channels();
61
62                target_rows.into_par_iter().for_each(|(y, new_row)| {
63                    for x in 0..frame.width as usize {
64                        let x_ = x * src_pixel_n_bytes;
65
66                        // src bytes for pixel
67                        let i0 = x_ + y * frame.stride as usize;
68
69                        // target bytes for pixel
70                        let k0 = x * target_pixel_n_bytes;
71
72                        for channel_byte in 0..target_format.channel_type().size() {
73                            for i in 0..target_n_channels as usize {
74                                new_row[k0 + i + channel_byte] =
75                                    src_data[i0 + source_target_index_map[i] + channel_byte];
76                            }
77                        }
78                    }
79                });
80            } else if src_format.channel_type() == ChannelType::U16
81                && target_format.channel_type() == ChannelType::U8
82                && src_format.is_premultiplied() == target_format.is_premultiplied()
83                && (!src_format.source_definition().contains(&Source::Opaque)
84                    || !target_format.target_definition().contains(&Target::A))
85                && !target_format.target_definition().contains(&Target::RgbAvg)
86            {
87                let mut source_target_index_map = [0; 4];
88                for (n, target) in target_format.target_definition().iter().enumerate() {
89                    source_target_index_map[n] =
90                        src_format.source_definition()[*target as usize] as usize;
91                }
92
93                let target_n_channels = target_format.n_channels();
94                let source_channel_size = src_format.channel_type().size();
95
96                target_rows.into_par_iter().for_each(|(y, new_row)| {
97                    for x in 0..frame.width as usize {
98                        let x_ = x * src_pixel_n_bytes;
99
100                        // src bytes for pixel
101                        let i0 = x_ + y * frame.stride as usize;
102
103                        // target bytes for pixel
104                        let k0 = x * target_pixel_n_bytes;
105
106                        for i in 0..target_n_channels as usize {
107                            new_row[k0 + i] = (u16::from_ne_bytes([
108                                src_data[i0 + source_target_index_map[i] * source_channel_size],
109                                src_data[i0 + source_target_index_map[i] * source_channel_size + 1],
110                            ])
111                            .saturating_add(128)
112                                >> 8) as u8;
113                        }
114                    }
115                });
116            } else {
117                target_rows.into_par_iter().for_each(|(y, new_row)| {
118                    for x in 0..frame.width as usize {
119                        let x_ = x * src_pixel_n_bytes;
120
121                        // src bytes for pixel
122                        let i0 = x_ + y * frame.stride as usize;
123                        let i1 = i0 + src_pixel_n_bytes;
124
125                        // target bytes for pixel
126                        let k0 = x * target_pixel_n_bytes;
127                        let k1 = k0 + target_pixel_n_bytes;
128
129                        MemoryFormat::transform(
130                            src_format,
131                            &src_data[i0..i1],
132                            target_format,
133                            &mut new_row[k0..k1],
134                        );
135                    }
136                });
137            }
138        });
139
140    frame.stride = new_stride;
141    frame.memory_format = target_format;
142
143    log::debug!(
144        "Transformation completed after {:?}",
145        start_instant.elapsed()
146    );
147
148    Ok((frame, ImgBuf::Vec(new_data)))
149}
150
151#[cfg(test)]
152mod test {
153    use std::os::fd::{FromRawFd, IntoRawFd, OwnedFd};
154
155    use glycin_common::BinaryData;
156
157    use super::*;
158
159    #[test]
160    fn u16_to_u8() {
161        let (a, _) = std::os::unix::net::UnixStream::pair().unwrap();
162        let texture = BinaryData::from(unsafe { OwnedFd::from_raw_fd(a.into_raw_fd()) });
163        let img_buf = ImgBuf::Vec(if cfg!(target_endian = "little") {
164            vec![
165                127, 0, 128, 0, 127, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 127, 253, 128, 253,
166                255, 255,
167            ]
168        } else {
169            vec![
170                0, 127, 0, 128, 2, 127, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 253, 127, 253, 128,
171                255, 255,
172            ]
173        });
174        let frame = Frame::new(2, 2, crate::MemoryFormat::R16g16b16, texture).unwrap();
175        let x = change_memory_format(img_buf, frame, MemoryFormat::R8g8b8)
176            .unwrap()
177            .1;
178        assert_eq!(x.as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 253, 254, 255]);
179    }
180
181    #[test]
182    fn u8alpha_to_u8reversed() {
183        let (a, _) = std::os::unix::net::UnixStream::pair().unwrap();
184        let texture = BinaryData::from(unsafe { OwnedFd::from_raw_fd(a.into_raw_fd()) });
185        let img_buf = ImgBuf::Vec(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
186        let frame = Frame::new(2, 2, crate::MemoryFormat::R8g8b8a8, texture).unwrap();
187        let x = change_memory_format(img_buf, frame, MemoryFormat::B8g8r8)
188            .unwrap()
189            .1;
190        assert_eq!(x.as_slice(), &[3, 2, 1, 7, 6, 5, 11, 10, 9, 15, 14, 13]);
191    }
192
193    #[test]
194    fn u8premultiplied_to_u8() {
195        let (a, _) = std::os::unix::net::UnixStream::pair().unwrap();
196        let texture = BinaryData::from(unsafe { OwnedFd::from_raw_fd(a.into_raw_fd()) });
197        let img_buf = ImgBuf::Vec(vec![127, 63, 0, 127, 127, 63, 0, 255]);
198        let frame = Frame::new(1, 2, crate::MemoryFormat::R8g8b8a8Premultiplied, texture).unwrap();
199        let x = change_memory_format(img_buf, frame, MemoryFormat::R8g8b8a8)
200            .unwrap()
201            .1;
202        assert_eq!(x.as_slice(), &[255, 126, 0, 127, 127, 63, 0, 255]);
203    }
204}