1use super::lossless::subsample_size;
2use super::lossless::DecoderError;
3
4#[derive(Debug, Clone)]
5pub(crate) enum TransformType {
6 PredictorTransform {
7 size_bits: u8,
8 predictor_data: Vec<u32>,
9 },
10 ColorTransform {
11 size_bits: u8,
12 transform_data: Vec<u32>,
13 },
14 SubtractGreen,
15 ColorIndexingTransform {
16 table_size: u16,
17 table_data: Vec<u32>,
18 },
19}
20
21impl TransformType {
22 /// Applies a transform to the image data
23 pub(crate) fn apply_transform(
24 &self,
25 image_data: &mut Vec<u32>,
26 width: u16,
27 height: u16,
28 ) -> Result<(), DecoderError> {
29 match self {
30 TransformType::PredictorTransform {
31 size_bits,
32 predictor_data,
33 } => {
34 let block_xsize = usize::from(subsample_size(width, *size_bits));
35 let width = usize::from(width);
36 let height = usize::from(height);
37
38 if image_data.len() < width * height {
39 return Err(DecoderError::TransformError);
40 }
41
42 //handle top and left borders specially
43 //this involves ignoring mode and just setting prediction values like this
44 image_data[0] = add_pixels(image_data[0], 0xff000000);
45
46 for x in 1..width {
47 image_data[x] = add_pixels(image_data[x], get_left(image_data, x, 0, width));
48 }
49
50 for y in 1..height {
51 image_data[y * width] =
52 add_pixels(image_data[y * width], get_top(image_data, 0, y, width));
53 }
54
55 for y in 1..height {
56 for x in 1..width {
57 let block_index = (y >> size_bits) * block_xsize + (x >> size_bits);
58
59 let index = y * width + x;
60
61 let green = (predictor_data[block_index] >> 8) & 0xff;
62
63 match green {
64 0 => image_data[index] = add_pixels(image_data[index], 0xff000000),
65 1 => {
66 image_data[index] =
67 add_pixels(image_data[index], get_left(image_data, x, y, width))
68 }
69 2 => {
70 image_data[index] =
71 add_pixels(image_data[index], get_top(image_data, x, y, width))
72 }
73 3 => {
74 image_data[index] = add_pixels(
75 image_data[index],
76 get_top_right(image_data, x, y, width),
77 )
78 }
79 4 => {
80 image_data[index] = add_pixels(
81 image_data[index],
82 get_top_left(image_data, x, y, width),
83 )
84 }
85 5 => {
86 image_data[index] = add_pixels(image_data[index], {
87 let first = average2(
88 get_left(image_data, x, y, width),
89 get_top_right(image_data, x, y, width),
90 );
91 average2(first, get_top(image_data, x, y, width))
92 })
93 }
94 6 => {
95 image_data[index] = add_pixels(
96 image_data[index],
97 average2(
98 get_left(image_data, x, y, width),
99 get_top_left(image_data, x, y, width),
100 ),
101 )
102 }
103 7 => {
104 image_data[index] = add_pixels(
105 image_data[index],
106 average2(
107 get_left(image_data, x, y, width),
108 get_top(image_data, x, y, width),
109 ),
110 )
111 }
112 8 => {
113 image_data[index] = add_pixels(
114 image_data[index],
115 average2(
116 get_top_left(image_data, x, y, width),
117 get_top(image_data, x, y, width),
118 ),
119 )
120 }
121 9 => {
122 image_data[index] = add_pixels(
123 image_data[index],
124 average2(
125 get_top(image_data, x, y, width),
126 get_top_right(image_data, x, y, width),
127 ),
128 )
129 }
130 10 => {
131 image_data[index] = add_pixels(image_data[index], {
132 let first = average2(
133 get_left(image_data, x, y, width),
134 get_top_left(image_data, x, y, width),
135 );
136 let second = average2(
137 get_top(image_data, x, y, width),
138 get_top_right(image_data, x, y, width),
139 );
140 average2(first, second)
141 })
142 }
143 11 => {
144 image_data[index] = add_pixels(
145 image_data[index],
146 select(
147 get_left(image_data, x, y, width),
148 get_top(image_data, x, y, width),
149 get_top_left(image_data, x, y, width),
150 ),
151 )
152 }
153 12 => {
154 image_data[index] = add_pixels(
155 image_data[index],
156 clamp_add_subtract_full(
157 get_left(image_data, x, y, width),
158 get_top(image_data, x, y, width),
159 get_top_left(image_data, x, y, width),
160 ),
161 )
162 }
163 13 => {
164 image_data[index] = add_pixels(image_data[index], {
165 let first = average2(
166 get_left(image_data, x, y, width),
167 get_top(image_data, x, y, width),
168 );
169 clamp_add_subtract_half(
170 first,
171 get_top_left(image_data, x, y, width),
172 )
173 })
174 }
175 _ => {}
176 }
177 }
178 }
179 }
180 TransformType::ColorTransform {
181 size_bits,
182 transform_data,
183 } => {
184 let block_xsize = usize::from(subsample_size(width, *size_bits));
185 let width = usize::from(width);
186 let height = usize::from(height);
187
188 for y in 0..height {
189 for x in 0..width {
190 let block_index = (y >> size_bits) * block_xsize + (x >> size_bits);
191
192 let index = y * width + x;
193
194 let multiplier =
195 ColorTransformElement::from_color_code(transform_data[block_index]);
196
197 image_data[index] = transform_color(&multiplier, image_data[index]);
198 }
199 }
200 }
201 TransformType::SubtractGreen => {
202 let width = usize::from(width);
203 for y in 0..usize::from(height) {
204 for x in 0..width {
205 image_data[y * width + x] = add_green(image_data[y * width + x]);
206 }
207 }
208 }
209 TransformType::ColorIndexingTransform {
210 table_size,
211 table_data,
212 } => {
213 let mut new_image_data =
214 Vec::with_capacity(usize::from(width) * usize::from(height));
215
216 let table_size = *table_size;
217 let width_bits: u8 = if table_size <= 2 {
218 3
219 } else if table_size <= 4 {
220 2
221 } else if table_size <= 16 {
222 1
223 } else {
224 0
225 };
226
227 let bits_per_pixel = 8 >> width_bits;
228 let mask = (1 << bits_per_pixel) - 1;
229
230 let mut src = 0;
231 let width = usize::from(width);
232
233 let pixels_per_byte = 1 << width_bits;
234 let count_mask = pixels_per_byte - 1;
235 let mut packed_pixels = 0;
236
237 for _y in 0..usize::from(height) {
238 for x in 0..width {
239 if (x & count_mask) == 0 {
240 packed_pixels = (image_data[src] >> 8) & 0xff;
241 src += 1;
242 }
243
244 let pixels: usize = (packed_pixels & mask).try_into().unwrap();
245 let new_val = if pixels >= table_size.into() {
246 0x00000000
247 } else {
248 table_data[pixels]
249 };
250
251 new_image_data.push(new_val);
252
253 packed_pixels >>= bits_per_pixel;
254 }
255 }
256
257 *image_data = new_image_data;
258 }
259 }
260
261 Ok(())
262 }
263}
264
265//predictor functions
266
267/// Adds 2 pixels mod 256 for each pixel
268pub(crate) fn add_pixels(a: u32, b: u32) -> u32 {
269 let new_alpha: u32 = ((a >> 24) + (b >> 24)) & 0xff;
270 let new_red: u32 = (((a >> 16) & 0xff) + ((b >> 16) & 0xff)) & 0xff;
271 let new_green: u32 = (((a >> 8) & 0xff) + ((b >> 8) & 0xff)) & 0xff;
272 let new_blue: u32 = ((a & 0xff) + (b & 0xff)) & 0xff;
273
274 (new_alpha << 24) + (new_red << 16) + (new_green << 8) + new_blue
275}
276
277/// Get left pixel
278fn get_left(data: &[u32], x: usize, y: usize, width: usize) -> u32 {
279 data[y * width + x - 1]
280}
281
282/// Get top pixel
283fn get_top(data: &[u32], x: usize, y: usize, width: usize) -> u32 {
284 data[(y - 1) * width + x]
285}
286
287/// Get pixel to top right
288fn get_top_right(data: &[u32], x: usize, y: usize, width: usize) -> u32 {
289 // if x == width - 1 this gets the left most pixel of the current row
290 // as described in the specification
291 data[(y - 1) * width + x + 1]
292}
293
294/// Get pixel to top left
295fn get_top_left(data: &[u32], x: usize, y: usize, width: usize) -> u32 {
296 data[(y - 1) * width + x - 1]
297}
298
299/// Get average of 2 pixels
300fn average2(a: u32, b: u32) -> u32 {
301 let mut avg: u32 = 0u32;
302 for i: i32 in 0..4 {
303 let sub_a: u8 = ((a >> (i * 8)) & 0xff).try_into().unwrap();
304 let sub_b: u8 = ((b >> (i * 8)) & 0xff).try_into().unwrap();
305 avg |= u32::from(sub_average2(sub_a, sub_b)) << (i * 8);
306 }
307 avg
308}
309
310/// Get average of 2 bytes
311fn sub_average2(a: u8, b: u8) -> u8 {
312 ((u16::from(a) + u16::from(b)) / 2).try_into().unwrap()
313}
314
315/// Get a specific byte from argb pixel
316fn get_byte(val: u32, byte: u8) -> u8 {
317 ((val >> (byte * 8)) & 0xff).try_into().unwrap()
318}
319
320/// Get byte as i32 for convenience
321fn get_byte_i32(val: u32, byte: u8) -> i32 {
322 i32::from(get_byte(val, byte))
323}
324
325/// Select left or top byte
326fn select(left: u32, top: u32, top_left: u32) -> u32 {
327 let predict_alpha: i32 = get_byte_i32(val:left, byte:3) + get_byte_i32(val:top, byte:3) - get_byte_i32(val:top_left, byte:3);
328 let predict_red: i32 = get_byte_i32(val:left, byte:2) + get_byte_i32(val:top, byte:2) - get_byte_i32(val:top_left, byte:2);
329 let predict_green: i32 = get_byte_i32(val:left, byte:1) + get_byte_i32(val:top, byte:1) - get_byte_i32(val:top_left, byte:1);
330 let predict_blue: i32 = get_byte_i32(val:left, byte:0) + get_byte_i32(val:top, byte:0) - get_byte_i32(val:top_left, byte:0);
331
332 let predict_left: i32 = i32::abs(self:predict_alpha - get_byte_i32(val:left, byte:3))
333 + i32::abs(self:predict_red - get_byte_i32(val:left, byte:2))
334 + i32::abs(self:predict_green - get_byte_i32(val:left, byte:1))
335 + i32::abs(self:predict_blue - get_byte_i32(val:left, byte:0));
336 let predict_top: i32 = i32::abs(self:predict_alpha - get_byte_i32(val:top, byte:3))
337 + i32::abs(self:predict_red - get_byte_i32(val:top, byte:2))
338 + i32::abs(self:predict_green - get_byte_i32(val:top, byte:1))
339 + i32::abs(self:predict_blue - get_byte_i32(val:top, byte:0));
340
341 if predict_left < predict_top {
342 left
343 } else {
344 top
345 }
346}
347
348/// Clamp a to [0, 255]
349fn clamp(a: i32) -> i32 {
350 if a < 0 {
351 0
352 } else if a > 255 {
353 255
354 } else {
355 a
356 }
357}
358
359/// Clamp add subtract full on one part
360fn clamp_add_subtract_full_sub(a: i32, b: i32, c: i32) -> i32 {
361 clamp(a + b - c)
362}
363
364/// Clamp add subtract half on one part
365fn clamp_add_subtract_half_sub(a: i32, b: i32) -> i32 {
366 clamp(a + (a - b) / 2)
367}
368
369/// Clamp add subtract full on 3 pixels
370fn clamp_add_subtract_full(a: u32, b: u32, c: u32) -> u32 {
371 let mut value: u32 = 0;
372 for i: u8 in 0..4u8 {
373 let sub_a: i32 = ((a >> (i * 8)) & 0xff).try_into().unwrap();
374 let sub_b: i32 = ((b >> (i * 8)) & 0xff).try_into().unwrap();
375 let sub_c: i32 = ((c >> (i * 8)) & 0xff).try_into().unwrap();
376 value |=
377 u32::try_from(clamp_add_subtract_full_sub(sub_a, sub_b, sub_c)).unwrap() << (i * 8);
378 }
379 value
380}
381
382/// Clamp add subtract half on 2 pixels
383fn clamp_add_subtract_half(a: u32, b: u32) -> u32 {
384 let mut value: u32 = 0;
385 for i: u8 in 0..4u8 {
386 let sub_a: i32 = ((a >> (i * 8)) & 0xff).try_into().unwrap();
387 let sub_b: i32 = ((b >> (i * 8)) & 0xff).try_into().unwrap();
388 value |= u32::try_from(clamp_add_subtract_half_sub(sub_a, sub_b)).unwrap() << (i * 8);
389 }
390
391 value
392}
393
394//color transform
395
396#[derive(Debug, Clone, Copy)]
397struct ColorTransformElement {
398 green_to_red: u8,
399 green_to_blue: u8,
400 red_to_blue: u8,
401}
402
403impl ColorTransformElement {
404 fn from_color_code(color_code: u32) -> ColorTransformElement {
405 ColorTransformElement {
406 green_to_red: (color_code & 0xff).try_into().unwrap(),
407 green_to_blue: ((color_code >> 8) & 0xff).try_into().unwrap(),
408 red_to_blue: ((color_code >> 16) & 0xff).try_into().unwrap(),
409 }
410 }
411}
412
413/// Does color transform on red and blue transformed by green
414fn color_transform(red: u8, blue: u8, green: u8, trans: &ColorTransformElement) -> (u8, u8) {
415 let mut temp_red: u32 = u32::from(red);
416 let mut temp_blue: u32 = u32::from(blue);
417
418 //as does the conversion from u8 to signed two's complement i8 required
419 temp_red += color_transform_delta(t:trans.green_to_red as i8, c:green as i8);
420 temp_blue += color_transform_delta(t:trans.green_to_blue as i8, c:green as i8);
421 temp_blue += color_transform_delta(t:trans.red_to_blue as i8, c:temp_red as i8);
422
423 (
424 (temp_red & 0xff).try_into().unwrap(),
425 (temp_blue & 0xff).try_into().unwrap(),
426 )
427}
428
429/// Does color transform on 2 numbers
430fn color_transform_delta(t: i8, c: i8) -> u32 {
431 ((i16::from(t) * i16::from(c)) as u32) >> 5
432}
433
434// Does color transform on a pixel with a color transform element
435fn transform_color(multiplier: &ColorTransformElement, color_value: u32) -> u32 {
436 let alpha: u8 = get_byte(val:color_value, byte:3);
437 let red: u8 = get_byte(val:color_value, byte:2);
438 let green: u8 = get_byte(val:color_value, byte:1);
439 let blue: u8 = get_byte(val:color_value, byte:0);
440
441 let (new_red: u8, new_blue: u8) = color_transform(red, blue, green, trans:multiplier);
442
443 (u32::from(alpha) << 24)
444 + (u32::from(new_red) << 16)
445 + (u32::from(green) << 8)
446 + u32::from(new_blue)
447}
448
449//subtract green function
450
451/// Adds green to red and blue of a pixel
452fn add_green(argb: u32) -> u32 {
453 let red: u32 = (argb >> 16) & 0xff;
454 let green: u32 = (argb >> 8) & 0xff;
455 let blue: u32 = argb & 0xff;
456
457 let new_red: u32 = (red + green) & 0xff;
458 let new_blue: u32 = (blue + green) & 0xff;
459
460 (argb & 0xff00ff00) | (new_red << 16) | (new_blue)
461}
462