1use std::ops::Range;
2
3use crate::decoder::DecodingError;
4
5use super::lossless::subsample_size;
6
7#[derive(Debug, Clone)]
8pub(crate) enum TransformType {
9 PredictorTransform {
10 size_bits: u8,
11 predictor_data: Vec<u8>,
12 },
13 ColorTransform {
14 size_bits: u8,
15 transform_data: Vec<u8>,
16 },
17 SubtractGreen,
18 ColorIndexingTransform {
19 table_size: u16,
20 table_data: Vec<u8>,
21 },
22}
23
24pub(crate) fn apply_predictor_transform(
25 image_data: &mut [u8],
26 width: u16,
27 height: u16,
28 size_bits: u8,
29 predictor_data: &[u8],
30) -> Result<(), DecodingError> {
31 let block_xsize = usize::from(subsample_size(width, size_bits));
32 let width = usize::from(width);
33 let height = usize::from(height);
34
35 // Handle top and left borders specially. This involves ignoring mode and using specific
36 // predictors for each.
37 image_data[3] = image_data[3].wrapping_add(255);
38 apply_predictor_transform_1(image_data, 4..width * 4, width);
39 for y in 1..height {
40 for i in 0..4 {
41 image_data[y * width * 4 + i] =
42 image_data[y * width * 4 + i].wrapping_add(image_data[(y - 1) * width * 4 + i]);
43 }
44 }
45
46 for y in 1..height {
47 for block_x in 0..block_xsize {
48 let block_index = (y >> size_bits) * block_xsize + block_x;
49 let predictor = predictor_data[block_index * 4 + 1];
50 let start_index = (y * width + (block_x << size_bits).max(1)) * 4;
51 let end_index = (y * width + ((block_x + 1) << size_bits).min(width)) * 4;
52
53 match predictor {
54 0 => apply_predictor_transform_0(image_data, start_index..end_index, width),
55 1 => apply_predictor_transform_1(image_data, start_index..end_index, width),
56 2 => apply_predictor_transform_2(image_data, start_index..end_index, width),
57 3 => apply_predictor_transform_3(image_data, start_index..end_index, width),
58 4 => apply_predictor_transform_4(image_data, start_index..end_index, width),
59 5 => apply_predictor_transform_5(image_data, start_index..end_index, width),
60 6 => apply_predictor_transform_6(image_data, start_index..end_index, width),
61 7 => apply_predictor_transform_7(image_data, start_index..end_index, width),
62 8 => apply_predictor_transform_8(image_data, start_index..end_index, width),
63 9 => apply_predictor_transform_9(image_data, start_index..end_index, width),
64 10 => apply_predictor_transform_10(image_data, start_index..end_index, width),
65 11 => apply_predictor_transform_11(image_data, start_index..end_index, width),
66 12 => apply_predictor_transform_12(image_data, start_index..end_index, width),
67 13 => apply_predictor_transform_13(image_data, start_index..end_index, width),
68 _ => {}
69 }
70 }
71 }
72
73 Ok(())
74}
75pub fn apply_predictor_transform_0(image_data: &mut [u8], range: Range<usize>, _width: usize) {
76 for i: usize in ((range.start + 3)..range.end).step_by(step:4) {
77 image_data[i] = image_data[i].wrapping_add(0xff);
78 }
79}
80pub fn apply_predictor_transform_1(image_data: &mut [u8], range: Range<usize>, _width: usize) {
81 let mut prev: [u8; 4] = image_data[range.start - 4..][..4].try_into().unwrap();
82 for chunk: &mut [u8] in image_data[range].chunks_exact_mut(chunk_size:4) {
83 prev = [
84 chunk[0].wrapping_add(prev[0]),
85 chunk[1].wrapping_add(prev[1]),
86 chunk[2].wrapping_add(prev[2]),
87 chunk[3].wrapping_add(prev[3]),
88 ];
89 chunk.copy_from_slice(&prev);
90 }
91}
92pub fn apply_predictor_transform_2(image_data: &mut [u8], range: Range<usize>, width: usize) {
93 for i: usize in range {
94 image_data[i] = image_data[i].wrapping_add(image_data[i - width * 4]);
95 }
96}
97pub fn apply_predictor_transform_3(image_data: &mut [u8], range: Range<usize>, width: usize) {
98 for i: usize in range {
99 image_data[i] = image_data[i].wrapping_add(image_data[i - width * 4 + 4]);
100 }
101}
102pub fn apply_predictor_transform_4(image_data: &mut [u8], range: Range<usize>, width: usize) {
103 for i: usize in range {
104 image_data[i] = image_data[i].wrapping_add(image_data[i - width * 4 - 4]);
105 }
106}
107pub fn apply_predictor_transform_5(image_data: &mut [u8], range: Range<usize>, width: usize) {
108 let (old: &mut [u8], current: &mut [u8]) = image_data[..range.end].split_at_mut(mid:range.start);
109
110 let mut prev: [u8; 4] = old[range.start - 4..][..4].try_into().unwrap();
111 let top_right: &[u8] = &old[range.start - width * 4 + 4..];
112 let top: &[u8] = &old[range.start - width * 4..];
113
114 for ((chunk: &mut [u8], tr: &[u8]), t: &[u8]) in currentimpl Iterator
115 .chunks_exact_mut(chunk_size:4)
116 .zip(top_right.chunks_exact(chunk_size:4))
117 .zip(top.chunks_exact(chunk_size:4))
118 {
119 prev = [
120 chunk[0].wrapping_add(average2(a:average2(prev[0], tr[0]), b:t[0])),
121 chunk[1].wrapping_add(average2(a:average2(prev[1], tr[1]), b:t[1])),
122 chunk[2].wrapping_add(average2(a:average2(prev[2], tr[2]), b:t[2])),
123 chunk[3].wrapping_add(average2(a:average2(prev[3], tr[3]), b:t[3])),
124 ];
125 chunk.copy_from_slice(&prev);
126 }
127}
128pub fn apply_predictor_transform_6(image_data: &mut [u8], range: Range<usize>, width: usize) {
129 let (old: &mut [u8], current: &mut [u8]) = image_data[..range.end].split_at_mut(mid:range.start);
130
131 let mut prev: [u8; 4] = old[range.start - 4..][..4].try_into().unwrap();
132 let top_left: &[u8] = &old[range.start - width * 4 - 4..];
133
134 for (chunk: &mut [u8], tl: &[u8]) in current.chunks_exact_mut(chunk_size:4).zip(top_left.chunks_exact(chunk_size:4)) {
135 for i: usize in 0..4 {
136 chunk[i] = chunk[i].wrapping_add(average2(a:prev[i], b:tl[i]));
137 }
138 prev.copy_from_slice(src:chunk);
139 }
140}
141pub fn apply_predictor_transform_7(image_data: &mut [u8], range: Range<usize>, width: usize) {
142 let (old, current) = image_data[..range.end].split_at_mut(range.start);
143
144 let mut prev: [u8; 4] = old[range.start - 4..][..4].try_into().unwrap();
145 let top = &old[range.start - width * 4..][..(range.end - range.start)];
146
147 let mut current_chunks = current.chunks_exact_mut(64);
148 let mut top_chunks = top.chunks_exact(64);
149
150 for (current, top) in (&mut current_chunks).zip(&mut top_chunks) {
151 for (chunk, t) in current.chunks_exact_mut(4).zip(top.chunks_exact(4)) {
152 prev = [
153 chunk[0].wrapping_add(average2(prev[0], t[0])),
154 chunk[1].wrapping_add(average2(prev[1], t[1])),
155 chunk[2].wrapping_add(average2(prev[2], t[2])),
156 chunk[3].wrapping_add(average2(prev[3], t[3])),
157 ];
158 chunk.copy_from_slice(&prev);
159 }
160 }
161 for (chunk, t) in current_chunks
162 .into_remainder()
163 .chunks_exact_mut(4)
164 .zip(top_chunks.remainder().chunks_exact(4))
165 {
166 prev = [
167 chunk[0].wrapping_add(average2(prev[0], t[0])),
168 chunk[1].wrapping_add(average2(prev[1], t[1])),
169 chunk[2].wrapping_add(average2(prev[2], t[2])),
170 chunk[3].wrapping_add(average2(prev[3], t[3])),
171 ];
172 chunk.copy_from_slice(&prev);
173 }
174}
175pub fn apply_predictor_transform_8(image_data: &mut [u8], range: Range<usize>, width: usize) {
176 for i: usize in range {
177 image_data[i] = image_data[i].wrapping_add(average2(
178 a:image_data[i - width * 4 - 4],
179 b:image_data[i - width * 4],
180 ));
181 }
182}
183pub fn apply_predictor_transform_9(image_data: &mut [u8], range: Range<usize>, width: usize) {
184 for i: usize in range {
185 image_data[i] = image_data[i].wrapping_add(average2(
186 a:image_data[i - width * 4],
187 b:image_data[i - width * 4 + 4],
188 ));
189 }
190}
191pub fn apply_predictor_transform_10(image_data: &mut [u8], range: Range<usize>, width: usize) {
192 let (old: &mut [u8], current: &mut [u8]) = image_data[..range.end].split_at_mut(mid:range.start);
193 let mut prev: [u8; 4] = old[range.start - 4..][..4].try_into().unwrap();
194
195 let top_left: &[u8] = &old[range.start - width * 4 - 4..];
196 let top: &[u8] = &old[range.start - width * 4..];
197 let top_right: &[u8] = &old[range.start - width * 4 + 4..];
198
199 for (((chunk: &mut [u8], tl: &[u8]), t: &[u8]), tr: &[u8]) in currentimpl Iterator
200 .chunks_exact_mut(chunk_size:4)
201 .zip(top_left.chunks_exact(chunk_size:4))
202 .zip(top.chunks_exact(chunk_size:4))
203 .zip(top_right.chunks_exact(chunk_size:4))
204 {
205 prev = [
206 chunk[0].wrapping_add(average2(a:average2(prev[0], tl[0]), b:average2(a:t[0], b:tr[0]))),
207 chunk[1].wrapping_add(average2(a:average2(prev[1], tl[1]), b:average2(a:t[1], b:tr[1]))),
208 chunk[2].wrapping_add(average2(a:average2(prev[2], tl[2]), b:average2(a:t[2], b:tr[2]))),
209 chunk[3].wrapping_add(average2(a:average2(prev[3], tl[3]), b:average2(a:t[3], b:tr[3]))),
210 ];
211 chunk.copy_from_slice(&prev);
212 }
213}
214pub fn apply_predictor_transform_11(image_data: &mut [u8], range: Range<usize>, width: usize) {
215 let (old, current) = image_data[..range.end].split_at_mut(range.start);
216 let top = &old[range.start - width * 4..];
217
218 let mut l = [
219 i16::from(old[range.start - 4]),
220 i16::from(old[range.start - 3]),
221 i16::from(old[range.start - 2]),
222 i16::from(old[range.start - 1]),
223 ];
224 let mut tl = [
225 i16::from(old[range.start - width * 4 - 4]),
226 i16::from(old[range.start - width * 4 - 3]),
227 i16::from(old[range.start - width * 4 - 2]),
228 i16::from(old[range.start - width * 4 - 1]),
229 ];
230
231 for (chunk, top) in current.chunks_exact_mut(4).zip(top.chunks_exact(4)) {
232 let t = [
233 i16::from(top[0]),
234 i16::from(top[1]),
235 i16::from(top[2]),
236 i16::from(top[3]),
237 ];
238
239 let mut predict_left = 0;
240 let mut predict_top = 0;
241 for i in 0..4 {
242 let predict = l[i] + t[i] - tl[i];
243 predict_left += i16::abs(predict - l[i]);
244 predict_top += i16::abs(predict - t[i]);
245 }
246
247 if predict_left < predict_top {
248 chunk.copy_from_slice(&[
249 chunk[0].wrapping_add(l[0] as u8),
250 chunk[1].wrapping_add(l[1] as u8),
251 chunk[2].wrapping_add(l[2] as u8),
252 chunk[3].wrapping_add(l[3] as u8),
253 ]);
254 } else {
255 chunk.copy_from_slice(&[
256 chunk[0].wrapping_add(t[0] as u8),
257 chunk[1].wrapping_add(t[1] as u8),
258 chunk[2].wrapping_add(t[2] as u8),
259 chunk[3].wrapping_add(t[3] as u8),
260 ]);
261 }
262
263 tl = t;
264 l = [
265 i16::from(chunk[0]),
266 i16::from(chunk[1]),
267 i16::from(chunk[2]),
268 i16::from(chunk[3]),
269 ];
270 }
271}
272pub fn apply_predictor_transform_12(image_data: &mut [u8], range: Range<usize>, width: usize) {
273 let (old, current) = image_data[..range.end].split_at_mut(range.start);
274 let mut prev: [u8; 4] = old[range.start - 4..][..4].try_into().unwrap();
275
276 let top_left = &old[range.start - width * 4 - 4..];
277 let top = &old[range.start - width * 4..];
278
279 for ((chunk, tl), t) in current
280 .chunks_exact_mut(4)
281 .zip(top_left.chunks_exact(4))
282 .zip(top.chunks_exact(4))
283 {
284 prev = [
285 chunk[0].wrapping_add(clamp_add_subtract_full(
286 i16::from(prev[0]),
287 i16::from(t[0]),
288 i16::from(tl[0]),
289 )),
290 chunk[1].wrapping_add(clamp_add_subtract_full(
291 i16::from(prev[1]),
292 i16::from(t[1]),
293 i16::from(tl[1]),
294 )),
295 chunk[2].wrapping_add(clamp_add_subtract_full(
296 i16::from(prev[2]),
297 i16::from(t[2]),
298 i16::from(tl[2]),
299 )),
300 chunk[3].wrapping_add(clamp_add_subtract_full(
301 i16::from(prev[3]),
302 i16::from(t[3]),
303 i16::from(tl[3]),
304 )),
305 ];
306 chunk.copy_from_slice(&prev);
307 }
308}
309pub fn apply_predictor_transform_13(image_data: &mut [u8], range: Range<usize>, width: usize) {
310 let (old, current) = image_data[..range.end].split_at_mut(range.start);
311 let mut prev: [u8; 4] = old[range.start - 4..][..4].try_into().unwrap();
312
313 let top_left = &old[range.start - width * 4 - 4..][..(range.end - range.start)];
314 let top = &old[range.start - width * 4..][..(range.end - range.start)];
315
316 for ((chunk, tl), t) in current
317 .chunks_exact_mut(4)
318 .zip(top_left.chunks_exact(4))
319 .zip(top.chunks_exact(4))
320 {
321 prev = [
322 chunk[0].wrapping_add(clamp_add_subtract_half(
323 (i16::from(prev[0]) + i16::from(t[0])) / 2,
324 i16::from(tl[0]),
325 )),
326 chunk[1].wrapping_add(clamp_add_subtract_half(
327 (i16::from(prev[1]) + i16::from(t[1])) / 2,
328 i16::from(tl[1]),
329 )),
330 chunk[2].wrapping_add(clamp_add_subtract_half(
331 (i16::from(prev[2]) + i16::from(t[2])) / 2,
332 i16::from(tl[2]),
333 )),
334 chunk[3].wrapping_add(clamp_add_subtract_half(
335 (i16::from(prev[3]) + i16::from(t[3])) / 2,
336 i16::from(tl[3]),
337 )),
338 ];
339 chunk.copy_from_slice(&prev);
340 }
341}
342
343pub(crate) fn apply_color_transform(
344 image_data: &mut [u8],
345 width: u16,
346 size_bits: u8,
347 transform_data: &[u8],
348) {
349 let block_xsize = usize::from(subsample_size(width, size_bits));
350 let width = usize::from(width);
351
352 for (y, row) in image_data.chunks_exact_mut(width * 4).enumerate() {
353 for (block_x, block) in row.chunks_mut(4 << size_bits).enumerate() {
354 let block_index = (y >> size_bits) * block_xsize + block_x;
355 let red_to_blue = transform_data[block_index * 4];
356 let green_to_blue = transform_data[block_index * 4 + 1];
357 let green_to_red = transform_data[block_index * 4 + 2];
358
359 for pixel in block.chunks_exact_mut(4) {
360 let green = u32::from(pixel[1]);
361 let mut temp_red = u32::from(pixel[0]);
362 let mut temp_blue = u32::from(pixel[2]);
363
364 temp_red += color_transform_delta(green_to_red as i8, green as i8);
365 temp_blue += color_transform_delta(green_to_blue as i8, green as i8);
366 temp_blue += color_transform_delta(red_to_blue as i8, temp_red as i8);
367
368 pixel[0] = (temp_red & 0xff) as u8;
369 pixel[2] = (temp_blue & 0xff) as u8;
370 }
371 }
372 }
373}
374
375pub(crate) fn apply_subtract_green_transform(image_data: &mut [u8]) {
376 for pixel: &mut [u8] in image_data.chunks_exact_mut(chunk_size:4) {
377 pixel[0] = pixel[0].wrapping_add(pixel[1]);
378 pixel[2] = pixel[2].wrapping_add(pixel[1]);
379 }
380}
381
382pub(crate) fn apply_color_indexing_transform(
383 image_data: &mut [u8],
384 width: u16,
385 height: u16,
386 table_size: u16,
387 table_data: &[u8],
388) {
389 if table_size > 16 {
390 let mut table = table_data.chunks_exact(4).collect::<Vec<_>>();
391 table.resize(256, &[0; 4]);
392
393 for pixel in image_data.chunks_exact_mut(4) {
394 pixel.copy_from_slice(table[pixel[1] as usize]);
395 }
396 } else {
397 let width_bits: u8 = if table_size <= 2 {
398 3
399 } else if table_size <= 4 {
400 2
401 } else if table_size <= 16 {
402 1
403 } else {
404 unreachable!()
405 };
406
407 let bits_per_entry = 8 / (1 << width_bits);
408 let mask = (1 << bits_per_entry) - 1;
409 let table = (0..256)
410 .flat_map(|i| {
411 let mut entry = Vec::new();
412 for j in 0..(1 << width_bits) {
413 let k = (i >> (j * bits_per_entry)) & mask;
414 if k < table_size {
415 entry.extend_from_slice(&table_data[usize::from(k) * 4..][..4]);
416 } else {
417 entry.extend_from_slice(&[0; 4]);
418 }
419 }
420 entry
421 })
422 .collect::<Vec<_>>();
423 let table = table.chunks_exact(4 << width_bits).collect::<Vec<_>>();
424
425 let entry_size = 4 << width_bits;
426 let index_image_width = width.div_ceil(1 << width_bits) as usize;
427 let final_entry_size = width as usize * 4 - entry_size * (index_image_width - 1);
428
429 for y in (0..height as usize).rev() {
430 for x in (0..index_image_width).rev() {
431 let input_index = y * index_image_width * 4 + x * 4 + 1;
432 let output_index = y * width as usize * 4 + x * entry_size;
433 let table_index = image_data[input_index] as usize;
434
435 if x == index_image_width - 1 {
436 image_data[output_index..][..final_entry_size]
437 .copy_from_slice(&table[table_index][..final_entry_size]);
438 } else {
439 image_data[output_index..][..entry_size].copy_from_slice(table[table_index]);
440 }
441 }
442 }
443 }
444}
445
446//predictor functions
447
448/// Get average of 2 bytes
449fn average2(a: u8, b: u8) -> u8 {
450 ((u16::from(a) + u16::from(b)) / 2) as u8
451}
452
453/// Clamp add subtract full on one part
454fn clamp_add_subtract_full(a: i16, b: i16, c: i16) -> u8 {
455 // Clippy suggests the clamp method, but it seems to optimize worse as of rustc 1.82.0 nightly.
456 #![allow(clippy::manual_clamp)]
457 (a + b - c).max(0).min(255) as u8
458}
459
460/// Clamp add subtract half on one part
461fn clamp_add_subtract_half(a: i16, b: i16) -> u8 {
462 // Clippy suggests the clamp method, but it seems to optimize worse as of rustc 1.82.0 nightly.
463 #![allow(clippy::manual_clamp)]
464 (a + (a - b) / 2).max(0).min(255) as u8
465}
466
467/// Does color transform on 2 numbers
468fn color_transform_delta(t: i8, c: i8) -> u32 {
469 (i32::from(t) * i32::from(c)) as u32 >> 5
470}
471
472#[cfg(all(test, feature = "_benchmarks"))]
473mod benches {
474 use rand::Rng;
475 use test::{black_box, Bencher};
476
477 fn measure_predictor(b: &mut Bencher, predictor: fn(&mut [u8], std::ops::Range<usize>, usize)) {
478 let width = 256;
479 let mut data = vec![0u8; width * 8];
480 rand::thread_rng().fill(&mut data[..]);
481 b.bytes = 4 * width as u64 - 4;
482 b.iter(|| {
483 predictor(
484 black_box(&mut data),
485 black_box(width * 4 + 4..width * 8),
486 black_box(width),
487 )
488 });
489 }
490
491 #[bench]
492 fn predictor00(b: &mut Bencher) {
493 measure_predictor(b, super::apply_predictor_transform_0);
494 }
495 #[bench]
496 fn predictor01(b: &mut Bencher) {
497 measure_predictor(b, super::apply_predictor_transform_1);
498 }
499 #[bench]
500 fn predictor02(b: &mut Bencher) {
501 measure_predictor(b, super::apply_predictor_transform_2);
502 }
503 #[bench]
504 fn predictor03(b: &mut Bencher) {
505 measure_predictor(b, super::apply_predictor_transform_3);
506 }
507 #[bench]
508 fn predictor04(b: &mut Bencher) {
509 measure_predictor(b, super::apply_predictor_transform_4);
510 }
511 #[bench]
512 fn predictor05(b: &mut Bencher) {
513 measure_predictor(b, super::apply_predictor_transform_5);
514 }
515 #[bench]
516 fn predictor06(b: &mut Bencher) {
517 measure_predictor(b, super::apply_predictor_transform_6);
518 }
519 #[bench]
520 fn predictor07(b: &mut Bencher) {
521 measure_predictor(b, super::apply_predictor_transform_7);
522 }
523 #[bench]
524 fn predictor08(b: &mut Bencher) {
525 measure_predictor(b, super::apply_predictor_transform_8);
526 }
527 #[bench]
528 fn predictor09(b: &mut Bencher) {
529 measure_predictor(b, super::apply_predictor_transform_9);
530 }
531 #[bench]
532 fn predictor10(b: &mut Bencher) {
533 measure_predictor(b, super::apply_predictor_transform_10);
534 }
535 #[bench]
536 fn predictor11(b: &mut Bencher) {
537 measure_predictor(b, super::apply_predictor_transform_11);
538 }
539 #[bench]
540 fn predictor12(b: &mut Bencher) {
541 measure_predictor(b, super::apply_predictor_transform_12);
542 }
543 #[bench]
544 fn predictor13(b: &mut Bencher) {
545 measure_predictor(b, super::apply_predictor_transform_13);
546 }
547
548 #[bench]
549 fn color_transform(b: &mut Bencher) {
550 let width = 256;
551 let height = 256;
552 let size_bits = 3;
553 let mut data = vec![0u8; width * height * 4];
554 let mut transform_data = vec![0u8; (width * height * 4) >> (size_bits * 2)];
555 rand::thread_rng().fill(&mut data[..]);
556 rand::thread_rng().fill(&mut transform_data[..]);
557 b.bytes = 4 * width as u64 * height as u64;
558 b.iter(|| {
559 super::apply_color_transform(
560 black_box(&mut data),
561 black_box(width as u16),
562 black_box(size_bits),
563 black_box(&transform_data),
564 );
565 });
566 }
567
568 #[bench]
569 fn subtract_green(b: &mut Bencher) {
570 let mut data = vec![0u8; 1024 * 4];
571 rand::thread_rng().fill(&mut data[..]);
572 b.bytes = data.len() as u64;
573 b.iter(|| {
574 super::apply_subtract_green_transform(black_box(&mut data));
575 });
576 }
577}
578