Fix some warnings

This commit is contained in:
Rémi Lauzier 2021-07-25 20:38:26 -04:00
parent 8053211bf4
commit e896960b42
No known key found for this signature in database
GPG key ID: D4B9ECD143336C1D
18 changed files with 193 additions and 110 deletions

8
Cargo.lock generated
View file

@ -60,9 +60,9 @@ checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7"
[[package]]
name = "bytemuck"
version = "1.7.0"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9966d2ab714d0f785dbac0a0396251a35280aeb42413281617d0209ab4898435"
checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b"
[[package]]
name = "byteorder"
@ -72,9 +72,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.68"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"
[[package]]
name = "cfg-if"

View file

@ -1,4 +1,5 @@
#![feature(test)]
#![allow(unused_must_use)]
extern crate oxipng;
extern crate test;

View file

@ -2,7 +2,7 @@ use rustc_version::{version, Version};
use std::process::exit;
fn main() {
// This should match the version in Github Actions scripts and the Readme
// This should match the version in GitHub Actions scripts and the Readme
const REQUIRED_VERSION: &str = "1.46.0";
if version().unwrap() < Version::parse(REQUIRED_VERSION).unwrap() {
eprintln!("oxipng requires rustc >= {}.", REQUIRED_VERSION);

4
clippy.toml Normal file
View file

@ -0,0 +1,4 @@
msrv = "1.46"
too-many-arguments-threshold = 9
max-struct-bools = 11
too-many-lines-threshold = 249

View file

@ -7,6 +7,7 @@ pub struct AtomicMin {
}
impl AtomicMin {
#[must_use]
pub fn new(init: Option<usize>) -> Self {
Self {
val: AtomicUsize::new(init.unwrap_or(usize::MAX)),
@ -22,7 +23,7 @@ impl AtomicMin {
}
}
/// Unset value is usize_max
/// Unset value is `usize_max`
pub fn as_atomic_usize(&self) -> &AtomicUsize {
&self.val
}

View file

@ -35,6 +35,7 @@ impl fmt::Display for ColorType {
impl ColorType {
/// Get the code used by the PNG specification to denote this color type
#[inline]
#[must_use]
pub fn png_header_code(self) -> u8 {
match self {
ColorType::Grayscale => 0,
@ -46,6 +47,7 @@ impl ColorType {
}
#[inline]
#[must_use]
pub fn channels_per_pixel(self) -> u8 {
match self {
ColorType::Grayscale | ColorType::Indexed => 1,
@ -91,6 +93,7 @@ impl fmt::Display for BitDepth {
impl BitDepth {
/// Retrieve the number of bits per channel per pixel as a `u8`
#[inline]
#[must_use]
pub fn as_u8(self) -> u8 {
match self {
BitDepth::One => 1,
@ -106,6 +109,7 @@ impl BitDepth {
///
/// If depth is unsupported
#[inline]
#[must_use]
pub fn from_u8(depth: u8) -> BitDepth {
match depth {
1 => BitDepth::One,

View file

@ -3,7 +3,7 @@ use crate::Deadline;
use crate::PngError;
use crate::PngResult;
pub use cloudflare_zlib::is_supported;
use cloudflare_zlib::*;
use cloudflare_zlib::{Deflate, ZError};
impl From<ZError> for PngError {
fn from(err: ZError) -> Self {
@ -40,6 +40,7 @@ pub(crate) fn cfzlib_deflate(
#[test]
fn compress_test() {
use cloudflare_zlib::{Z_BEST_COMPRESSION, Z_DEFAULT_STRATEGY};
let vec = cfzlib_deflate(
b"azxcvbnm",
Z_BEST_COMPRESSION as u8,

View file

@ -1,7 +1,9 @@
use crate::atomicmin::AtomicMin;
use crate::error::PngError;
use crate::PngResult;
use miniz_oxide::deflate::core::*;
use miniz_oxide::deflate::core::{
compress, create_comp_flags_from_zip_params, CompressorOxide, TDEFLFlush, TDEFLStatus,
};
pub(crate) fn compress_to_vec_oxipng(
input: &[u8],

View file

@ -37,6 +37,7 @@ impl fmt::Display for PngError {
impl PngError {
#[cold]
#[must_use]
pub fn new(description: &str) -> PngError {
PngError::Other(description.into())
}

View file

@ -88,12 +88,12 @@ impl Evaluator {
/// Set baseline image. It will be used only to measure minimum compression level required
pub fn set_baseline(&self, image: Arc<PngImage>) {
self.try_image_inner(image, false)
self.try_image_inner(image, false);
}
/// Check if the image is smaller than others
pub fn try_image(&self, image: Arc<PngImage>) {
self.try_image_inner(image, true)
self.try_image_inner(image, true);
}
fn try_image_inner(&self, image: Arc<PngImage>, is_reduction: bool) {

View file

@ -80,6 +80,7 @@ pub enum Headers {
}
#[inline]
#[must_use]
pub fn file_header_is_valid(bytes: &[u8]) -> bool {
let expected_header: [u8; 8] = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];

View file

@ -1,18 +1,41 @@
#![warn(trivial_casts, trivial_numeric_casts, unused_import_braces)]
#![deny(missing_debug_implementations, missing_copy_implementations)]
#![warn(clippy::expl_impl_clone_on_copy)]
#![warn(clippy::float_cmp_const)]
#![warn(clippy::linkedlist)]
#![warn(clippy::map_flatten)]
#![warn(clippy::match_same_arms)]
#![warn(clippy::mem_forget)]
#![warn(clippy::mut_mut)]
#![warn(clippy::mutex_integer)]
#![warn(clippy::needless_continue)]
#![warn(clippy::path_buf_push_overwrite)]
#![warn(clippy::range_plus_one)]
#![allow(clippy::cognitive_complexity)]
#![allow(clippy::upper_case_acronyms)]
#![deny(
trivial_casts,
trivial_numeric_casts,
unused_import_braces,
missing_debug_implementations,
missing_copy_implementations,
rust_2018_idioms,
rust_2018_compatibility,
future_incompatible,
unused,
nonstandard_style
)]
#![warn(
clippy::all,
clippy::doc_markdown,
clippy::wildcard_imports,
clippy::unreadable_literal,
clippy::unnested_or_patterns,
clippy::must_use_candidate,
clippy::map_unwrap_or,
clippy::large_types_passed_by_value,
clippy::float_cmp_const,
clippy::lossy_float_literal,
clippy::float_equality_without_abs,
clippy::suboptimal_flops,
clippy::imprecise_flops,
clippy::mem_forget,
clippy::mutex_integer,
clippy::path_buf_push_overwrite,
clippy::expl_impl_clone_on_copy,
clippy::linkedlist,
clippy::map_flatten,
clippy::match_same_arms,
clippy::mut_mut,
clippy::needless_continue,
clippy::range_plus_one,
clippy::range_minus_one
)]
#![cfg_attr(
not(any(feature = "libdeflater", feature = "zopfli")),
allow(irrefutable_let_patterns),
@ -30,7 +53,10 @@ use crate::deflate::inflate;
use crate::evaluate::Evaluator;
use crate::png::PngData;
use crate::png::PngImage;
use crate::reduction::*;
use crate::reduction::{
alpha, bit_depth, color, reduce_bit_depth, reduce_color_type, reduced_palette,
try_alpha_reductions,
};
use crc::{Crc, CRC_32_ISO_HDLC};
use image::{DynamicImage, GenericImageView, ImageFormat, Pixel};
use log::{debug, error, info, warn};
@ -79,6 +105,7 @@ pub enum OutFile {
}
impl OutFile {
#[must_use]
pub fn path(&self) -> Option<&Path> {
match *self {
OutFile::Path(Some(ref p)) => Some(p.as_path()),
@ -95,6 +122,7 @@ pub enum InFile {
}
impl InFile {
#[must_use]
pub fn path(&self) -> Option<&Path> {
match *self {
InFile::Path(ref p) => Some(p.as_path()),
@ -201,6 +229,7 @@ pub struct Options {
}
impl Options {
#[must_use]
pub fn from_preset(level: u8) -> Options {
let opts = Options::default();
match level {
@ -221,6 +250,7 @@ impl Options {
}
}
#[must_use]
pub fn max_compression() -> Options {
Options::from_preset(6)
}
@ -364,7 +394,7 @@ pub fn optimize(input: &InFile, output: &OutFile, opts: &Options) -> PngResult<(
let mut png = PngData::from_slice(&in_data, opts.fix_errors)?;
// Run the optimizer on the decoded PNG.
let mut optimized_output = optimize_png(&mut png, &in_data, opts, deadline)?;
let mut optimized_output = optimize_png(&mut png, &in_data, opts, &deadline)?;
if is_fully_optimized(in_data.len(), optimized_output.len(), opts) {
info!("File already optimized");
@ -396,8 +426,7 @@ pub fn optimize(input: &InFile, output: &OutFile, opts: &Options) -> PngResult<(
(&OutFile::Path(ref output_path), _) => {
let output_path = output_path
.as_ref()
.map(|p| p.as_path())
.unwrap_or_else(|| input.path().unwrap());
.map_or_else(|| input.path().unwrap(), PathBuf::as_path);
if opts.backup {
perform_backup(output_path)?;
}
@ -447,7 +476,7 @@ pub fn optimize_from_memory(data: &[u8], opts: &Options) -> PngResult<Vec<u8>> {
let mut png = PngData::from_slice(data, opts.fix_errors)?;
// Run the optimizer on the decoded PNG.
let optimized_output = optimize_png(&mut png, data, opts, deadline)?;
let optimized_output = optimize_png(&mut png, data, opts, &deadline)?;
if is_fully_optimized(original_size, optimized_output.len(), opts) {
info!("Image already optimized");
@ -470,7 +499,7 @@ fn optimize_png(
png: &mut PngData,
original_data: &[u8],
opts: &Options,
deadline: Arc<Deadline>,
deadline: &Arc<Deadline>,
) -> PngResult<Vec<u8>> {
type TrialWithData = (TrialOptions, Vec<u8>);
@ -532,13 +561,11 @@ fn optimize_png(
if opts.interlace.is_none() {
eval.set_baseline(png.raw.clone());
}
perform_reductions(png.raw.clone(), opts, &deadline, &eval);
let reduction_occurred = if let Some(result) = eval.get_result() {
perform_reductions(png.raw.clone(), opts, deadline, &eval);
let reduction_occurred = eval.get_result().map_or(false, |result| {
*png = result;
true
} else {
false
};
});
if opts.idat_recoding || reduction_occurred {
// Go through selected permutations and determine the best
@ -605,7 +632,7 @@ fn optimize_png(
trial.strategy,
window,
&best_size,
&deadline,
deadline,
),
#[cfg(feature = "zopfli")]
Deflaters::Zopfli => deflate::zopfli_deflate(filtered),
@ -783,7 +810,7 @@ fn perform_reductions(
}
}
try_alpha_reductions(png, &opts.alphas, eval);
try_alpha_reductions(&png, &opts.alphas, eval);
}
#[derive(Debug)]
@ -801,6 +828,7 @@ pub struct Deadline {
}
impl Deadline {
#[must_use]
pub fn new(timeout: Option<Duration>) -> Self {
Self {
imp: timeout.map(|timeout| DeadlineImp {
@ -872,7 +900,7 @@ 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",
];
let keys: Vec<[u8; 4]> = raw.aux_headers.keys().cloned().collect();
let keys: Vec<[u8; 4]> = raw.aux_headers.keys().copied().collect();
for hdr in &keys {
if !PRESERVED_HEADERS.contains(hdr) {
raw.aux_headers.remove(hdr);
@ -908,7 +936,7 @@ fn perform_strip(png: &mut PngData, opts: &Options) {
}
}
/// If the profile is sRGB, extracts the rendering intent value from it
/// If the profile is `sRGB`, extracts the rendering intent value from it
fn srgb_rendering_intent(mut iccp: &[u8]) -> Option<u8> {
// Skip (useless) profile name
loop {
@ -1032,14 +1060,14 @@ fn copy_permissions(metadata_input: &Metadata, out_file: &File) -> PngResult<()>
))
})
.and_then(|out_meta_reread| {
if out_meta_reread.permissions().mode() != permissions {
if out_meta_reread.permissions().mode() == permissions {
Ok(())
} else {
Err(PngError::new(&format!(
"failed to set permissions, expected: {:04o}, found: {:04o}",
permissions,
out_meta_reread.permissions().mode()
)))
} else {
Ok(())
}
})
})

View file

@ -1,17 +1,41 @@
#![warn(trivial_casts, trivial_numeric_casts, unused_import_braces)]
#![deny(missing_debug_implementations, missing_copy_implementations)]
#![warn(clippy::expl_impl_clone_on_copy)]
#![warn(clippy::float_cmp_const)]
#![warn(clippy::linkedlist)]
#![warn(clippy::map_flatten)]
#![warn(clippy::match_same_arms)]
#![warn(clippy::mem_forget)]
#![warn(clippy::mut_mut)]
#![warn(clippy::mutex_integer)]
#![warn(clippy::needless_continue)]
#![warn(clippy::path_buf_push_overwrite)]
#![warn(clippy::range_plus_one)]
#![allow(clippy::cognitive_complexity)]
#![deny(
trivial_casts,
trivial_numeric_casts,
unused_import_braces,
missing_debug_implementations,
missing_copy_implementations,
rust_2018_idioms,
rust_2018_compatibility,
future_incompatible,
unused,
nonstandard_style
)]
#![warn(
clippy::all,
clippy::doc_markdown,
clippy::wildcard_imports,
clippy::unreadable_literal,
clippy::unnested_or_patterns,
clippy::must_use_candidate,
clippy::map_unwrap_or,
clippy::large_types_passed_by_value,
clippy::float_cmp_const,
clippy::lossy_float_literal,
clippy::float_equality_without_abs,
clippy::suboptimal_flops,
clippy::imprecise_flops,
clippy::mem_forget,
clippy::mutex_integer,
clippy::path_buf_push_overwrite,
clippy::expl_impl_clone_on_copy,
clippy::linkedlist,
clippy::map_flatten,
clippy::match_same_arms,
clippy::mut_mut,
clippy::needless_continue,
clippy::range_plus_one,
clippy::range_minus_one
)]
use clap::{App, AppSettings, Arg, ArgMatches};
use indexmap::IndexSet;
@ -318,12 +342,13 @@ fn collect_files(
}
continue;
};
let out_file = if let Some(ref out_dir) = *out_dir {
let out_path = Some(out_dir.join(input.file_name().unwrap()));
OutFile::Path(out_path)
} else {
(*out_file).clone()
};
let out_file = out_dir.as_ref().map_or_else(
|| (*out_file).clone(),
|out_dir| {
let out_path = Some(out_dir.join(input.file_name().unwrap()));
OutFile::Path(out_path)
},
);
let in_file = if using_stdin {
InFile::StdIn
} else {
@ -335,7 +360,7 @@ fn collect_files(
}
fn parse_opts_into_struct(
matches: &ArgMatches,
matches: &ArgMatches<'_>,
) -> Result<(OutFile, Option<PathBuf>, Options), String> {
stderrlog::new()
.module(module_path!())
@ -389,10 +414,12 @@ fn parse_opts_into_struct(
let out_file = if matches.is_present("stdout") {
OutFile::StdOut
} else if let Some(x) = matches.value_of("output_file") {
OutFile::Path(Some(PathBuf::from(x)))
} else {
OutFile::Path(None)
matches
.value_of("output_file")
.map_or(OutFile::Path(None), |x| {
OutFile::Path(Some(PathBuf::from(x)))
})
};
if matches.is_present("alpha") {
@ -452,7 +479,7 @@ fn parse_opts_into_struct(
}
if let Some(hdrs) = matches.value_of("keep") {
opts.strip = Headers::Keep(hdrs.split(',').map(|x| x.trim().to_owned()).collect())
opts.strip = Headers::Keep(hdrs.split(',').map(|x| x.trim().to_owned()).collect());
}
if let Some(hdrs) = matches.value_of("strip") {

View file

@ -1,8 +1,8 @@
use crate::colors::ColorType;
use crate::deflate;
use crate::error::PngError;
use crate::filters::*;
use crate::headers::*;
use crate::filters::{filter_line, unfilter_line};
use crate::headers::{file_header_is_valid, parse_ihdr_header, parse_next_header, IhdrData};
use crate::interlace::{deinterlace_image, interlace_image};
use byteorder::{BigEndian, WriteBytesExt};
use crc::{Crc, CRC_32_ISO_HDLC};
@ -170,6 +170,7 @@ impl PngData {
}
/// Format the `PngData` struct into a valid PNG bytestream
#[must_use]
pub fn output(&self) -> Vec<u8> {
// PNG header
let mut output = vec![0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
@ -264,12 +265,14 @@ impl PngImage {
/// Return the number of channels in the image, based on color type
#[inline]
#[must_use]
pub fn channels_per_pixel(&self) -> u8 {
self.ihdr.color_type.channels_per_pixel()
}
/// Return an iterator over the scanlines of the image
#[inline]
#[must_use]
pub fn scan_lines(&self) -> ScanLines<'_> {
ScanLines::new(self)
}
@ -309,6 +312,7 @@ impl PngImage {
/// 3: Average
/// 4: Paeth
/// 5: All (heuristically pick the best filter for each line)
#[must_use]
pub fn filter_image(&self, filter: u8) -> Vec<u8> {
let mut filtered = Vec::with_capacity(self.data.len());
let bpp = ((self.ihdr.bit_depth.as_u8() * self.channels_per_pixel() + 7) / 8) as usize;
@ -351,7 +355,7 @@ impl PngImage {
best_filter = filter;
std::mem::swap(&mut best_line, &mut f_buf);
}
f_buf.clear() //discard buffer, and start again
f_buf.clear(); //discard buffer, and start again
}
filtered.push(best_filter);
filtered.extend_from_slice(&best_line);

View file

@ -12,7 +12,7 @@ use rayon::prelude::*;
use std::sync::Arc;
pub(crate) fn try_alpha_reductions(
png: Arc<PngImage>,
png: &Arc<PngImage>,
alphas: &IndexSet<AlphaOptim>,
eval: &Evaluator,
) {
@ -23,10 +23,11 @@ pub(crate) fn try_alpha_reductions(
alphas
.par_iter()
.with_max_len(1)
.filter_map(|&alpha| filtered_alpha_channel(&png, alpha))
.filter_map(|&alpha| filtered_alpha_channel(png, alpha))
.for_each(|image| eval.try_image(Arc::new(image)));
}
#[must_use]
pub fn filtered_alpha_channel(png: &PngImage, optim: AlphaOptim) -> Option<PngImage> {
let (bpc, bpp) = match png.ihdr.color_type {
ColorType::RGBA | ColorType::GrayscaleAlpha => {
@ -214,7 +215,7 @@ pub fn reduced_alpha_channel(png: &PngImage) -> Option<PngImage> {
// and alpha has just been removed
if let Some(sbit_header) = png.aux_headers.get(b"sBIT") {
// Some programs save the sBIT header as RGB even if the image is RGBA.
aux_headers.insert(*b"sBIT", sbit_header.iter().cloned().take(3).collect());
aux_headers.insert(*b"sBIT", sbit_header.iter().copied().take(3).collect());
}
Some(PngImage {

View file

@ -117,11 +117,11 @@ pub fn reduced_color_to_palette(png: &PngImage) -> Option<PngImage> {
raw_data.push(line.filter);
let ok = if png.ihdr.color_type == ColorType::RGB {
reduce_scanline_to_palette(
line.data.as_rgb().iter().cloned().map(|px| {
px.alpha(if Some(px) != transparency_pixel {
255
} else {
line.data.as_rgb().iter().copied().map(|px| {
px.alpha(if Some(px) == transparency_pixel {
0
} else {
255
})
}),
&mut palette,
@ -130,7 +130,7 @@ pub fn reduced_color_to_palette(png: &PngImage) -> Option<PngImage> {
} else {
debug_assert_eq!(png.ihdr.color_type, ColorType::RGBA);
reduce_scanline_to_palette(
line.data.as_rgba().iter().cloned(),
line.data.as_rgba().iter().copied(),
&mut palette,
&mut raw_data,
)
@ -143,10 +143,10 @@ pub fn reduced_color_to_palette(png: &PngImage) -> Option<PngImage> {
let num_transparent = palette
.iter()
.filter_map(|(px, &idx)| {
if px.a != 255 {
Some(idx as usize + 1)
} else {
if px.a == 255 {
None
} else {
Some(idx as usize + 1)
}
})
.max();
@ -180,7 +180,7 @@ pub fn reduced_color_to_palette(png: &PngImage) -> Option<PngImage> {
if let Some(sbit_header) = png.aux_headers.get(b"sBIT") {
// Some programs save the sBIT header as RGB even if the image is RGBA.
aux_headers.insert(*b"sBIT", sbit_header.iter().cloned().take(3).collect());
aux_headers.insert(*b"sBIT", sbit_header.iter().copied().take(3).collect());
}
let mut palette_vec = vec![RGBA8::new(0, 0, 0, 0); palette.len()];
@ -220,8 +220,8 @@ pub fn reduce_rgb_to_grayscale(png: &PngImage) -> Option<PngImage> {
let pixel_bytes = cur_pixel
.iter()
.step_by(2)
.cloned()
.zip(cur_pixel.iter().skip(1).step_by(2).cloned())
.copied()
.zip(cur_pixel.iter().skip(1).step_by(2).copied())
.unique()
.collect::<Vec<(u8, u8)>>();
if pixel_bytes.len() > 1 {
@ -235,15 +235,16 @@ pub fn reduce_rgb_to_grayscale(png: &PngImage) -> Option<PngImage> {
}
}
let transparency_pixel = if let Some(ref trns) = png.transparency_pixel {
if trns.len() != 6 || trns[0..2] != trns[2..4] || trns[2..4] != trns[4..6] {
None
} else {
Some(trns[0..2].to_owned())
}
} else {
png.transparency_pixel.clone()
};
let transparency_pixel = png.transparency_pixel.as_ref().map_or_else(
|| png.transparency_pixel.clone(),
|trns| {
if trns.len() != 6 || trns[0..2] != trns[2..4] || trns[2..4] != trns[4..6] {
None
} else {
Some(trns[0..2].to_owned())
}
},
);
let mut aux_headers = png.aux_headers.clone();
if let Some(sbit_header) = png.aux_headers.get(b"sBIT") {

View file

@ -1,7 +1,10 @@
use crate::colors::{BitDepth, ColorType};
use crate::headers::IhdrData;
use crate::png::PngImage;
use indexmap::map::{Entry::*, IndexMap};
use indexmap::map::{
Entry::{Occupied, Vacant},
IndexMap,
};
use rgb::RGBA8;
use std::borrow::Cow;
@ -10,13 +13,16 @@ use crate::alpha::reduced_alpha_channel;
pub mod bit_depth;
use crate::bit_depth::reduce_bit_depth_8_or_less;
pub mod color;
use crate::color::*;
use crate::color::{
reduce_rgb_to_grayscale, reduce_rgba_to_grayscale_alpha, reduced_color_to_palette,
};
pub(crate) use crate::alpha::try_alpha_reductions;
pub(crate) use crate::bit_depth::reduce_bit_depth;
/// Attempt to reduce the number of colors in the palette
/// Returns `None` if palette hasn't changed
#[must_use]
pub fn reduced_palette(png: &PngImage) -> Option<PngImage> {
if png.ihdr.color_type != ColorType::Indexed {
// Can't reduce if there is no palette
@ -67,7 +73,7 @@ pub fn reduced_palette(png: &PngImage) -> Option<PngImage> {
.get(i)
.copied()
.unwrap_or_else(|| RGBA8::new(0, 0, 0, 255));
((color.a as i32) << 18)
((i32::from(color.a)) << 18)
// These are coefficients for standard sRGB to luma conversion
- i32::from(color.r) * 299
- i32::from(color.g) * 587
@ -78,14 +84,14 @@ pub fn reduced_palette(png: &PngImage) -> Option<PngImage> {
let mut next_index = 0_u16;
let mut seen = IndexMap::with_capacity(palette.len());
for (i, used) in used_enumerated.iter().cloned() {
for (i, used) in used_enumerated.iter().copied() {
if !used {
continue;
}
// There are invalid files that use pixel indices beyond palette size
let color = palette
.get(i)
.cloned()
.copied()
.unwrap_or_else(|| RGBA8::new(0, 0, 0, 255));
match seen.entry(color) {
Vacant(new) => {
@ -137,7 +143,7 @@ fn do_palette_reduction(png: &PngImage, palette_map: &[Option<u8>; 256]) -> Opti
}
fn palette_map_to_byte_map(png: &PngImage, palette_map: &[Option<u8>; 256]) -> Option<[u8; 256]> {
let len = png.palette.as_ref().map_or(0, |p| p.len());
let len = png.palette.as_ref().map_or(0, Vec::len);
if (0..len).all(|i| palette_map[i].map_or(true, |to| to == i as u8)) {
// No reduction necessary
return None;
@ -148,18 +154,18 @@ fn palette_map_to_byte_map(png: &PngImage, palette_map: &[Option<u8>; 256]) -> O
// low bit-depths can be pre-computed for every byte value
match png.ihdr.bit_depth {
BitDepth::Eight => {
for byte in 0..=255usize {
byte_map[byte] = palette_map[byte].unwrap_or(0)
for byte in 0..=255_usize {
byte_map[byte] = palette_map[byte].unwrap_or(0);
}
}
BitDepth::Four => {
for byte in 0..=255usize {
for byte in 0..=255_usize {
byte_map[byte] = palette_map[(byte & 0x0F)].unwrap_or(0)
| (palette_map[(byte >> 4)].unwrap_or(0) << 4);
}
}
BitDepth::Two => {
for byte in 0..=255usize {
for byte in 0..=255_usize {
byte_map[byte] = palette_map[(byte & 0x03)].unwrap_or(0)
| (palette_map[((byte >> 2) & 0x03)].unwrap_or(0) << 2)
| (palette_map[((byte >> 4) & 0x03)].unwrap_or(0) << 4)
@ -173,7 +179,7 @@ fn palette_map_to_byte_map(png: &PngImage, palette_map: &[Option<u8>; 256]) -> O
}
fn reordered_palette(palette: &[RGBA8], palette_map: &[Option<u8>; 256]) -> Vec<RGBA8> {
let max_index = palette_map.iter().cloned().flatten().max().unwrap_or(0) as usize;
let max_index = palette_map.iter().copied().flatten().max().unwrap_or(0) as usize;
let mut new_palette = vec![RGBA8::new(0, 0, 0, 255); max_index + 1];
for (&color, &map_to) in palette.iter().zip(palette_map.iter()) {
if let Some(map_to) = map_to {
@ -185,6 +191,7 @@ fn reordered_palette(palette: &[RGBA8], palette_map: &[Option<u8>; 256]) -> Vec<
/// Attempt to reduce the color type of the image
/// Returns true if the color type was reduced, false otherwise
#[must_use]
pub fn reduce_color_type(png: &PngImage, grayscale_reduction: bool) -> Option<PngImage> {
let mut should_reduce_bit_depth = false;
let mut reduced = Cow::Borrowed(png);
@ -244,6 +251,6 @@ pub fn reduce_color_type(png: &PngImage, grayscale_reduction: bool) -> Option<Pn
match reduced {
Cow::Owned(r) => Some(r),
_ => None,
Cow::Borrowed(_) => None,
}
}

View file

@ -36,8 +36,8 @@ fn test_it_converts_callbacks<CBPRE, CBPOST>(
mut callback_pre: CBPRE,
mut callback_post: CBPOST,
) where
CBPOST: FnMut(&Path) -> (),
CBPRE: FnMut(&Path) -> (),
CBPOST: FnMut(&Path),
CBPRE: FnMut(&Path),
{
let png = PngData::new(&input, opts.fix_errors).unwrap();
@ -46,14 +46,14 @@ fn test_it_converts_callbacks<CBPRE, CBPOST>(
callback_pre(&input);
match oxipng::optimize(&InFile::Path(input), &output, &opts) {
match oxipng::optimize(&InFile::Path(input), output, opts) {
Ok(_) => (),
Err(x) => panic!("{}", x),
};
let output = output.path().unwrap();
assert!(output.exists());
callback_post(&output);
callback_post(output);
let png = match PngData::new(output, opts.fix_errors) {
Ok(x) => x,