Make order of chunks deterministic by sorting chunks

Closes #174
This commit is contained in:
Josh Holmer 2019-06-18 13:28:59 -04:00
parent 5dcfe44ccd
commit 5b1121c9dd
2 changed files with 18 additions and 11 deletions

View file

@ -14,7 +14,7 @@ use crate::reduction::*;
use crc::crc32; use crc::crc32;
use image::{DynamicImage, GenericImageView, ImageFormat, Pixel}; use image::{DynamicImage, GenericImageView, ImageFormat, Pixel};
use rayon::prelude::*; use rayon::prelude::*;
use std::collections::{HashMap, HashSet}; use std::collections::{BTreeMap, HashMap, HashSet};
use std::fmt; use std::fmt;
use std::fs::{copy, File}; use std::fs::{copy, File};
use std::io::{stdin, stdout, BufWriter, Read, Write}; use std::io::{stdin, stdout, BufWriter, Read, Write};
@ -843,11 +843,15 @@ fn perform_strip(png: &mut PngData, opts: &Options) {
// Strip headers // Strip headers
Headers::None => (), Headers::None => (),
Headers::Keep(ref hdrs) => { Headers::Keep(ref hdrs) => {
raw.aux_headers.retain(|chunk, _| { let keys: Vec<[u8; 4]> = raw.aux_headers.keys().cloned().collect();
std::str::from_utf8(chunk) for hdr in &keys {
let preserve = std::str::from_utf8(hdr)
.ok() .ok()
.map_or(false, |name| hdrs.contains(name)) .map_or(false, |name| hdrs.contains(name));
}); if !preserve {
raw.aux_headers.remove(hdr);
}
}
} }
Headers::Strip(ref hdrs) => { Headers::Strip(ref hdrs) => {
for hdr in hdrs { for hdr in hdrs {
@ -859,11 +863,14 @@ fn perform_strip(png: &mut PngData, opts: &Options) {
*b"cHRM", *b"gAMA", *b"iCCP", *b"sBIT", *b"sRGB", *b"bKGD", *b"hIST", *b"pHYs", *b"cHRM", *b"gAMA", *b"iCCP", *b"sBIT", *b"sRGB", *b"bKGD", *b"hIST", *b"pHYs",
*b"sPLT", *b"sPLT",
]; ];
raw.aux_headers for hdr in &PRESERVED_HEADERS {
.retain(|hdr, _| PRESERVED_HEADERS.contains(hdr)); if !PRESERVED_HEADERS.contains(hdr) {
raw.aux_headers.remove(hdr);
}
}
} }
Headers::All => { Headers::All => {
raw.aux_headers = HashMap::new(); raw.aux_headers = BTreeMap::new();
} }
} }

View file

@ -8,7 +8,7 @@ use byteorder::{BigEndian, WriteBytesExt};
use crc::crc32; use crc::crc32;
use rgb::ComponentSlice; use rgb::ComponentSlice;
use rgb::RGBA8; use rgb::RGBA8;
use std::collections::HashMap; use std::collections::BTreeMap;
use std::fs::File; use std::fs::File;
use std::io::{Read, Seek, SeekFrom}; use std::io::{Read, Seek, SeekFrom};
use std::iter::Iterator; use std::iter::Iterator;
@ -38,7 +38,7 @@ pub struct PngImage {
/// The pixel value that should be rendered as transparent /// The pixel value that should be rendered as transparent
pub transparency_pixel: Option<Vec<u8>>, pub transparency_pixel: Option<Vec<u8>>,
/// All non-critical headers from the PNG are stored here /// All non-critical headers from the PNG are stored here
pub aux_headers: HashMap<[u8; 4], Vec<u8>>, pub aux_headers: BTreeMap<[u8; 4], Vec<u8>>,
} }
/// Contains all data relevant to a PNG image /// Contains all data relevant to a PNG image
@ -97,7 +97,7 @@ impl PngData {
} }
byte_offset += 8; byte_offset += 8;
// Read the data headers // Read the data headers
let mut aux_headers: HashMap<[u8; 4], Vec<u8>> = HashMap::new(); let mut aux_headers: BTreeMap<[u8; 4], Vec<u8>> = BTreeMap::new();
let mut idat_headers: Vec<u8> = Vec::new(); let mut idat_headers: Vec<u8> = Vec::new();
while let Some(header) = parse_next_header(byte_data, &mut byte_offset, fix_errors)? { while let Some(header) = parse_next_header(byte_data, &mut byte_offset, fix_errors)? {
match &header.name { match &header.name {