diff --git a/Cargo.lock b/Cargo.lock index 56158ad0..002f8862 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,3 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. [[package]] name = "adler32" version = "1.0.3" @@ -149,8 +151,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "image" -version = "0.21.0" -source = "git+https://github.com/PistonDevelopers/image?rev=41dfbae#41dfbaecfa0e702eaef61e4dba156e9be5b2f70d" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -257,7 +259,7 @@ dependencies = [ "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "cloudflare-zlib 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "image 0.21.0 (git+https://github.com/PistonDevelopers/image?rev=41dfbae)", + "image 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -419,7 +421,7 @@ dependencies = [ "checksum deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6abb26e16e8d419b5c78662aa9f82857c2386a073da266840e474d5055ec86" "checksum either 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c67353c641dc847124ea1902d69bd753dee9bb3beff9aa3662ecf86c971d1fac" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum image 0.21.0 (git+https://github.com/PistonDevelopers/image?rev=41dfbae)" = "" +"checksum image 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)" = "99198e595d012efccf12abf4abc08da2d97be0b0355a2b08d101347527476ba4" "checksum inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" diff --git a/Cargo.toml b/Cargo.toml index 0095665e..5c24e963 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,11 +55,7 @@ cloudflare-zlib = "^0.2.2" [dependencies.image] default-features = false features = ["png_codec"] -#FIXME: Use upstream version when 0.22 is released -#Contains bugfix for issues 167 and 168 -#version = "^0.21.0" -git = "https://github.com/PistonDevelopers/image" -rev = "41dfbae" +version = "^0.21.2" [features] binary = [ diff --git a/README.md b/README.md index d4131d89..79937789 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ to give any extra compression gains and is not recommended. PNG interlacing on any images that are processed. `-i 0` will remove interlacing from all processed images. Not specifying either will keep the same interlacing state as the input image. Note: Interlacing can add 25-50% to the size of an optimized image. Only use -it if you believe the benefits outweight the costs for your use case. +it if you believe the benefits outweigh the costs for your use case. * Strip: Used to remove metadata info from processed images. Used via `--strip [safe,all]`. Can save a few kilobytes if you don't need the metadata. "Safe" removes only metadata that will never affect rendering of the image. "All" removes all metadata that is not critical diff --git a/README.template.md b/README.template.md index da8e0934..91343543 100644 --- a/README.template.md +++ b/README.template.md @@ -49,7 +49,7 @@ to give any extra compression gains and is not recommended. PNG interlacing on any images that are processed. `-i 0` will remove interlacing from all processed images. Not specifying either will keep the same interlacing state as the input image. Note: Interlacing can add 25-50% to the size of an optimized image. Only use -it if you believe the benefits outweight the costs for your use case. +it if you believe the benefits outweigh the costs for your use case. * Strip: Used to remove metadata info from processed images. Used via `--strip [safe,all]`. Can save a few kilobytes if you don't need the metadata. "Safe" removes only metadata that will never affect rendering of the image. "All" removes all metadata that is not critical diff --git a/src/lib.rs b/src/lib.rs index 49a0b06f..70ff06ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,7 @@ use crate::reduction::*; use crc::crc32; use image::{DynamicImage, GenericImageView, ImageFormat, Pixel}; use rayon::prelude::*; -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeMap, HashMap, HashSet}; use std::fmt; use std::fs::{copy, File}; use std::io::{stdin, stdout, BufWriter, Read, Write}; @@ -477,7 +477,7 @@ fn optimize_png( eprintln!( " {} bits/pixel, {} colors in palette", png.raw.ihdr.bit_depth, - palette.len() / 3 + palette.len() ); } else { eprintln!( @@ -824,7 +824,7 @@ fn report_reduction(png: &PngImage) { eprintln!( "Reducing image to {} bits/pixel, {} colors in palette", png.ihdr.bit_depth, - palette.len() / 3 + palette.len() ); } else { eprintln!( @@ -843,11 +843,15 @@ fn perform_strip(png: &mut PngData, opts: &Options) { // Strip headers Headers::None => (), Headers::Keep(ref hdrs) => { - raw.aux_headers.retain(|chunk, _| { - std::str::from_utf8(chunk) + let keys: Vec<[u8; 4]> = raw.aux_headers.keys().cloned().collect(); + for hdr in &keys { + let preserve = std::str::from_utf8(hdr) .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) => { for hdr in hdrs { @@ -859,11 +863,15 @@ 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"sPLT", ]; - raw.aux_headers - .retain(|hdr, _| PRESERVED_HEADERS.contains(hdr)); + let keys: Vec<[u8; 4]> = raw.aux_headers.keys().cloned().collect(); + for hdr in &keys { + if !PRESERVED_HEADERS.contains(hdr) { + raw.aux_headers.remove(hdr); + } + } } Headers::All => { - raw.aux_headers = HashMap::new(); + raw.aux_headers = BTreeMap::new(); } } diff --git a/src/png/mod.rs b/src/png/mod.rs index 6d46670e..2fd5184f 100644 --- a/src/png/mod.rs +++ b/src/png/mod.rs @@ -8,7 +8,7 @@ use byteorder::{BigEndian, WriteBytesExt}; use crc::crc32; use rgb::ComponentSlice; use rgb::RGBA8; -use std::collections::HashMap; +use std::collections::BTreeMap; use std::fs::File; use std::io::{Read, Seek, SeekFrom}; use std::iter::Iterator; @@ -38,7 +38,7 @@ pub struct PngImage { /// The pixel value that should be rendered as transparent pub transparency_pixel: Option>, /// All non-critical headers from the PNG are stored here - pub aux_headers: HashMap<[u8; 4], Vec>, + pub aux_headers: BTreeMap<[u8; 4], Vec>, } /// Contains all data relevant to a PNG image @@ -97,7 +97,7 @@ impl PngData { } byte_offset += 8; // Read the data headers - let mut aux_headers: HashMap<[u8; 4], Vec> = HashMap::new(); + let mut aux_headers: BTreeMap<[u8; 4], Vec> = BTreeMap::new(); let mut idat_headers: Vec = Vec::new(); while let Some(header) = parse_next_header(byte_data, &mut byte_offset, fix_errors)? { match &header.name { diff --git a/src/reduction/bit_depth.rs b/src/reduction/bit_depth.rs index 262357b0..6f04ec86 100644 --- a/src/reduction/bit_depth.rs +++ b/src/reduction/bit_depth.rs @@ -4,24 +4,28 @@ use crate::png::PngImage; use bit_vec::BitVec; const ONE_BIT_PERMUTATIONS: [u8; 2] = [0b0000_0000, 0b1111_1111]; -const TWO_BIT_PERMUTATIONS: [u8; 5] = [ +const TWO_BIT_PERMUTATIONS: [u8; 4] = [ 0b0000_0000, - 0b0000_1111, - 0b0011_1100, - 0b1111_0000, + 0b0101_0101, + 0b1010_1010, 0b1111_1111, ]; -const FOUR_BIT_PERMUTATIONS: [u8; 11] = [ +const FOUR_BIT_PERMUTATIONS: [u8; 16] = [ 0b0000_0000, - 0b0000_0011, - 0b0000_1100, - 0b0011_0000, - 0b1100_0000, - 0b0000_1111, - 0b0011_1100, - 0b1111_0000, - 0b0011_1111, - 0b1111_1100, + 0b0001_0001, + 0b0010_0010, + 0b0011_0011, + 0b0100_0100, + 0b0101_0101, + 0b0110_0110, + 0b0111_0111, + 0b1000_1000, + 0b1001_1001, + 0b1010_1010, + 0b1011_1011, + 0b1100_1100, + 0b1101_1101, + 0b1110_1110, 0b1111_1111, ]; diff --git a/tests/files/issue-171.png b/tests/files/issue-171.png new file mode 100644 index 00000000..bf83f52b Binary files /dev/null and b/tests/files/issue-171.png differ diff --git a/tests/flags.rs b/tests/flags.rs index 9f308854..1e9a43f7 100644 --- a/tests/flags.rs +++ b/tests/flags.rs @@ -332,7 +332,7 @@ fn interlacing_1_to_0_small_files() { assert_eq!(png.raw.ihdr.interlaced, 0); assert_eq!(png.raw.ihdr.color_type, ColorType::Indexed); - // the depth can't be asserted reliably, because on such small file different zlib implementaitons pick diferent depth as the best + // the depth can't be asserted reliably, because on such small file different zlib implementations pick different depth as the best remove_file(output).ok(); } diff --git a/tests/regression.rs b/tests/regression.rs index 91c73cc7..a5d8bd39 100644 --- a/tests/regression.rs +++ b/tests/regression.rs @@ -600,6 +600,7 @@ fn issue_159() { } #[test] +#[cfg(target_pointer_width = "64")] fn issue_167() { test_it_converts( "tests/files/issue-167.png", @@ -611,6 +612,18 @@ fn issue_167() { ); } +#[test] +fn issue_171() { + test_it_converts( + "tests/files/issue-171.png", + None, + ColorType::Grayscale, + BitDepth::Eight, + ColorType::Grayscale, + BitDepth::Eight, + ); +} + #[test] fn issue_175() { test_it_converts( @@ -621,4 +634,4 @@ fn issue_175() { ColorType::Grayscale, BitDepth::One, ); -} +} \ No newline at end of file