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 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 let i0 = x_ + y * frame.stride as usize;
68
69 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 let i0 = x_ + y * frame.stride as usize;
102
103 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 let i0 = x_ + y * frame.stride as usize;
123 let i1 = i0 + src_pixel_n_bytes;
124
125 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}