about summary refs log tree commit diff
path: root/gifcheck/src/fix.rs
blob: 95f7ef210f052d01995d16e5807e42d353b3fe26 (plain)
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
use gifed::{
	block::{Block, Palette},
	Color, Gif,
};

use crate::PaletteReport;

pub fn palette_errors(gif: &Gif, report: PaletteReport) -> Option<Gif> {
	if report.local_matching_indicies {
		let mut new = gif.clone();

		for block in new.blocks.iter_mut() {
			if let Block::CompressedImage(comp) = block {
				comp.image_descriptor.packed.set_color_table(false);
				comp.image_descriptor.packed.set_color_table_size(0);

				if let Some(plt) = comp.local_color_table.take() {
					new.global_color_table.get_or_insert(plt);
				}
			}
		}

		Some(new)
	} else {
		None
	}
}

pub fn images_match_exactly(gifa: &Gif, gifb: &Gif) -> bool {
	let mut a_buf = vec![0; gifa.width() * gifa.height() * 4];
	let mut b_buf = vec![0; gifb.width() * gifb.height() * 4];

	for (a, b) in gifa.images().zip(gifb.images()) {
		if a.width() != b.width() || a.height() != b.height() {
			return false;
		}

		if a.left() != b.left() || a.top() != b.top() {
			return false;
		}

		let a_decomp = a.decompess();
		let b_decomp = b.decompess();

		let a_size = deindex(
			&a_decomp.indicies,
			a.palette(),
			a.transparent_index(),
			&mut a_buf,
		);

		let b_size = deindex(
			&b_decomp.indicies,
			b.palette(),
			b.transparent_index(),
			&mut b_buf,
		);

		match (a_size, b_size) {
			(None, _) | (_, None) => return false,
			(Some(asize), Some(bsize)) => {
				if asize != bsize {
					return false;
				}

				if a_buf[..asize] != b_buf[..bsize] {
					return false;
				}
			}
		}
	}

	true
}

fn deindex(indicies: &[u8], plt: &Palette, trns: Option<u8>, buffer: &mut [u8]) -> Option<usize> {
	let mut rgba = |idx: usize, clr: Option<Color>| match clr {
		None => {
			buffer[idx] = 0;
			buffer[idx + 1] = 0;
			buffer[idx + 2] = 0;
			buffer[idx + 3] = 0;
		}
		Some(clr) => {
			buffer[idx] = clr.r;
			buffer[idx + 1] = clr.g;
			buffer[idx + 2] = clr.b;
			buffer[idx + 3] = 255;
		}
	};

	for (idx, color_idx) in indicies.iter().enumerate() {
		match (trns, plt.get(*color_idx)) {
			(Some(trns_idx), _) if trns_idx == *color_idx => rgba(idx * 4, None),
			(_, Some(color)) => rgba(idx * 4, Some(color)),
			(Some(_) | None, None) => {
				return None;
			}
		}
	}

	Some(indicies.len() * 4)
}