Update rust and fix issues
This commit is contained in:
parent
13d9eceb4b
commit
b453b7c3f8
19 changed files with 39 additions and 48 deletions
2
.github/workflows/oxipng.yml
vendored
2
.github/workflows/oxipng.yml
vendored
|
|
@ -161,7 +161,7 @@ jobs:
|
||||||
- name: Install MSRV Rust toolchain
|
- name: Install MSRV Rust toolchain
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
with:
|
with:
|
||||||
toolchain: 1.74.0
|
toolchain: 1.85.1
|
||||||
cache-bin: false
|
cache-bin: false
|
||||||
cache-shared-key: cache
|
cache-shared-key: cache
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ categories = ["command-line-utilities", "compression"]
|
||||||
description = "A lossless PNG compression optimizer"
|
description = "A lossless PNG compression optimizer"
|
||||||
keywords = ["png", "image-compression", "optimization", "multi-threading", "lossless"]
|
keywords = ["png", "image-compression", "optimization", "multi-threading", "lossless"]
|
||||||
documentation = "https://docs.rs/oxipng"
|
documentation = "https://docs.rs/oxipng"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
exclude = [
|
exclude = [
|
||||||
".editorconfig",
|
".editorconfig",
|
||||||
".gitattributes",
|
".gitattributes",
|
||||||
|
|
@ -21,7 +21,7 @@ license = "MIT"
|
||||||
name = "oxipng"
|
name = "oxipng"
|
||||||
repository = "https://github.com/oxipng/oxipng"
|
repository = "https://github.com/oxipng/oxipng"
|
||||||
version = "9.1.5"
|
version = "9.1.5"
|
||||||
rust-version = "1.74.0"
|
rust-version = "1.85.1"
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
travis-ci = { repository = "oxipng/oxipng", branch = "master" }
|
travis-ci = { repository = "oxipng/oxipng", branch = "master" }
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
# check=error=true
|
# check=error=true
|
||||||
FROM --platform=$BUILDPLATFORM tonistiigi/xx AS xx
|
FROM --platform=$BUILDPLATFORM tonistiigi/xx AS xx
|
||||||
|
|
||||||
FROM --platform=$BUILDPLATFORM rust:1.74-alpine AS base
|
FROM --platform=$BUILDPLATFORM rust:1.85.1-alpine AS base
|
||||||
|
|
||||||
RUN apk update && \
|
RUN apk update && \
|
||||||
apk add \
|
apk add \
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ cargo build --release
|
||||||
cp target/release/oxipng /usr/local/bin
|
cp target/release/oxipng /usr/local/bin
|
||||||
```
|
```
|
||||||
|
|
||||||
The current minimum supported Rust version is **1.74.0**.
|
The current minimum supported Rust version is **1.85.1**.
|
||||||
|
|
||||||
Oxipng follows Semantic Versioning.
|
Oxipng follows Semantic Versioning.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,7 @@ use std::{num::NonZeroU8, path::PathBuf};
|
||||||
use oxipng::{internal_tests::*, *};
|
use oxipng::{internal_tests::*, *};
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
// SAFETY: trivially safe. Stopgap solution until const unwrap is stabilized.
|
const DEFAULT_ZOPFLI_ITERATIONS: NonZeroU8 = NonZeroU8::new(15).unwrap();
|
||||||
const DEFAULT_ZOPFLI_ITERATIONS: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(15) };
|
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn zopfli_16_bits_strategy_0(b: &mut Bencher) {
|
fn zopfli_16_bits_strategy_0(b: &mut Bencher) {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
PngResult,
|
||||||
error::PngError,
|
error::PngError,
|
||||||
headers::{read_be_u16, read_be_u32},
|
headers::{read_be_u16, read_be_u32},
|
||||||
PngResult,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,7 @@ impl AtomicMin {
|
||||||
|
|
||||||
pub fn get(&self) -> Option<usize> {
|
pub fn get(&self) -> Option<usize> {
|
||||||
let val = self.val.load(SeqCst);
|
let val = self.val.load(SeqCst);
|
||||||
if val == usize::MAX {
|
if val == usize::MAX { None } else { Some(val) }
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(val)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try a new value, returning true if it is the new minimum
|
/// Try a new value, returning true if it is the new minimum
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use clap::{value_parser, Arg, ArgAction, Command};
|
use clap::{Arg, ArgAction, Command, value_parser};
|
||||||
|
|
||||||
include!("display_chunks.rs");
|
include!("display_chunks.rs");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,12 @@
|
||||||
#[cfg(not(feature = "parallel"))]
|
#[cfg(not(feature = "parallel"))]
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::sync::{
|
use std::sync::{
|
||||||
atomic::{AtomicUsize, Ordering::*},
|
|
||||||
Arc,
|
Arc,
|
||||||
|
atomic::{AtomicUsize, Ordering::*},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "parallel")]
|
#[cfg(feature = "parallel")]
|
||||||
use crossbeam_channel::{unbounded, Receiver, Sender};
|
use crossbeam_channel::{Receiver, Sender, unbounded};
|
||||||
use deflate::Deflaters;
|
use deflate::Deflaters;
|
||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
|
@ -17,7 +17,7 @@ use rayon::prelude::*;
|
||||||
|
|
||||||
#[cfg(not(feature = "parallel"))]
|
#[cfg(not(feature = "parallel"))]
|
||||||
use crate::rayon;
|
use crate::rayon;
|
||||||
use crate::{atomicmin::AtomicMin, deflate, filters::RowFilter, png::PngImage, Deadline, PngError};
|
use crate::{Deadline, PngError, atomicmin::AtomicMin, deflate, filters::RowFilter, png::PngImage};
|
||||||
|
|
||||||
pub(crate) struct Candidate {
|
pub(crate) struct Candidate {
|
||||||
pub image: Arc<PngImage>,
|
pub image: Arc<PngImage>,
|
||||||
|
|
@ -30,7 +30,7 @@ pub(crate) struct Candidate {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Candidate {
|
impl Candidate {
|
||||||
fn cmp_key(&self) -> impl Ord {
|
fn cmp_key(&self) -> impl Ord + use<> {
|
||||||
(
|
(
|
||||||
self.estimated_output_size,
|
self.estimated_output_size,
|
||||||
self.image.data.len(),
|
self.image.data.len(),
|
||||||
|
|
@ -161,10 +161,7 @@ impl Evaluator {
|
||||||
best_candidate_size.set_min(estimated_output_size);
|
best_candidate_size.set_min(estimated_output_size);
|
||||||
trace!(
|
trace!(
|
||||||
"Eval: {}-bit {:23} {:8} {} bytes",
|
"Eval: {}-bit {:23} {:8} {} bytes",
|
||||||
image.ihdr.bit_depth,
|
image.ihdr.bit_depth, description, filter, estimated_output_size
|
||||||
description,
|
|
||||||
filter,
|
|
||||||
estimated_output_size
|
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(feature = "parallel")]
|
#[cfg(feature = "parallel")]
|
||||||
|
|
@ -182,10 +179,7 @@ impl Evaluator {
|
||||||
} else if let Err(PngError::DeflatedDataTooLong(size)) = idat_data {
|
} else if let Err(PngError::DeflatedDataTooLong(size)) = idat_data {
|
||||||
trace!(
|
trace!(
|
||||||
"Eval: {}-bit {:23} {:8} >{} bytes",
|
"Eval: {}-bit {:23} {:8} >{} bytes",
|
||||||
image.ihdr.bit_depth,
|
image.ihdr.bit_depth, description, filter, size
|
||||||
description,
|
|
||||||
filter,
|
|
||||||
size
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@ use log::{debug, trace, warn};
|
||||||
use rgb::{RGB16, RGBA8};
|
use rgb::{RGB16, RGBA8};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
Deflaters, Options, PngResult,
|
||||||
colors::{BitDepth, ColorType},
|
colors::{BitDepth, ColorType},
|
||||||
deflate::{crc32, inflate},
|
deflate::{crc32, inflate},
|
||||||
display_chunks::DISPLAY_CHUNKS,
|
display_chunks::DISPLAY_CHUNKS,
|
||||||
error::PngError,
|
error::PngError,
|
||||||
interlace::Interlacing,
|
interlace::Interlacing,
|
||||||
Deflaters, Options, PngResult,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::{fmt, fmt::Display};
|
||||||
|
|
||||||
use bitvec::prelude::*;
|
use bitvec::prelude::*;
|
||||||
|
|
||||||
use crate::{headers::IhdrData, png::PngImage, PngError};
|
use crate::{PngError, headers::IhdrData, png::PngImage};
|
||||||
|
|
||||||
/// Whether to enable progressive rendering. See [`Options`][crate::Options])
|
/// Whether to enable progressive rendering. See [`Options`][crate::Options])
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
|
|
|
||||||
18
src/lib.rs
18
src/lib.rs
|
|
@ -27,16 +27,16 @@ mod rayon;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
fs::{File, Metadata},
|
fs::{File, Metadata},
|
||||||
io::{stdin, stdout, BufWriter, Read, Write},
|
io::{BufWriter, Read, Write, stdin, stdout},
|
||||||
path::Path,
|
path::Path,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicBool, Ordering},
|
|
||||||
Arc,
|
Arc,
|
||||||
|
atomic::{AtomicBool, Ordering},
|
||||||
},
|
},
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use indexmap::{indexset, IndexSet};
|
pub use indexmap::{IndexSet, indexset};
|
||||||
use log::{debug, info, trace, warn};
|
use log::{debug, info, trace, warn};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
pub use rgb::{RGB16, RGBA8};
|
pub use rgb::{RGB16, RGBA8};
|
||||||
|
|
@ -232,9 +232,9 @@ pub fn optimize(input: &InFile, output: &OutFile, opts: &Options) -> PngResult<(
|
||||||
|
|
||||||
if is_fully_optimized(in_data.len(), optimized_output.len(), opts) {
|
if is_fully_optimized(in_data.len(), optimized_output.len(), opts) {
|
||||||
match (output, input) {
|
match (output, input) {
|
||||||
// if p is None, it also means same as the input path
|
// If output path is None, it also means same as the input path
|
||||||
(OutFile::Path { path, .. }, InFile::Path(ref input_path))
|
(OutFile::Path { path, .. }, InFile::Path(input_path))
|
||||||
if path.as_ref().map_or(true, |p| p == input_path) =>
|
if path.as_ref().is_none_or(|p| p == input_path) =>
|
||||||
{
|
{
|
||||||
info!("{input}: Could not optimize further, no change written");
|
info!("{input}: Could not optimize further, no change written");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
@ -396,7 +396,9 @@ fn optimize_png(
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.interlace == Some(Interlacing::Adam7) && png.raw.ihdr.interlaced != Interlacing::Adam7 {
|
if opts.interlace == Some(Interlacing::Adam7) && png.raw.ihdr.interlaced != Interlacing::Adam7 {
|
||||||
warn!("Interlacing was not enabled as it would result in a larger file. To override this, use `--force`.");
|
warn!(
|
||||||
|
"Interlacing was not enabled as it would result in a larger file. To override this, use `--force`."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "sanity-checks")]
|
#[cfg(feature = "sanity-checks")]
|
||||||
|
|
@ -471,7 +473,7 @@ fn optimize_raw(
|
||||||
};
|
};
|
||||||
|
|
||||||
if result.data_is_compressed
|
if result.data_is_compressed
|
||||||
&& max_size.map_or(true, |max_size| result.estimated_output_size < max_size)
|
&& max_size.is_none_or(|max_size| result.estimated_output_size < max_size)
|
||||||
{
|
{
|
||||||
debug!("Found better result:");
|
debug!("Found better result:");
|
||||||
debug!(" {}, f = {}", deflater, result.filter);
|
debug!(" {}, f = {}", deflater, result.filter);
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ use std::{
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
mod cli;
|
mod cli;
|
||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
use log::{error, warn, Level, LevelFilter};
|
use log::{Level, LevelFilter, error, warn};
|
||||||
use oxipng::{Deflaters, InFile, Options, OutFile, PngError, RowFilter, StripChunks};
|
use oxipng::{Deflaters, InFile, Options, OutFile, PngError, RowFilter, StripChunks};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use std::{
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use indexmap::{indexset, IndexSet};
|
use indexmap::{IndexSet, indexset};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
|
||||||
use crate::{deflate::Deflaters, filters::RowFilter, headers::StripChunks, interlace::Interlacing};
|
use crate::{deflate::Deflaters, filters::RowFilter, headers::StripChunks, interlace::Interlacing};
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,14 @@ use rgb::ComponentSlice;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
Options,
|
||||||
apng::*,
|
apng::*,
|
||||||
colors::{BitDepth, ColorType},
|
colors::{BitDepth, ColorType},
|
||||||
deflate,
|
deflate,
|
||||||
error::PngError,
|
error::PngError,
|
||||||
filters::*,
|
filters::*,
|
||||||
headers::*,
|
headers::*,
|
||||||
interlace::{deinterlace_image, interlace_image, Interlacing},
|
interlace::{Interlacing, deinterlace_image, interlace_image},
|
||||||
Options,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) mod scan_lines;
|
pub(crate) mod scan_lines;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::hash::{BuildHasherDefault, Hash};
|
use std::hash::{BuildHasherDefault, Hash};
|
||||||
|
|
||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
use rgb::{alt::Gray, ComponentMap, ComponentSlice, FromSlice, RGB, RGBA};
|
use rgb::{ComponentMap, ComponentSlice, FromSlice, RGB, RGBA, alt::Gray};
|
||||||
use rustc_hash::FxHasher;
|
use rustc_hash::FxHasher;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{evaluate::Evaluator, png::PngImage, ColorType, Deadline, Deflaters, Options};
|
use crate::{ColorType, Deadline, Deflaters, Options, evaluate::Evaluator, png::PngImage};
|
||||||
|
|
||||||
pub mod alpha;
|
pub mod alpha;
|
||||||
use crate::alpha::*;
|
use crate::alpha::*;
|
||||||
|
|
@ -183,7 +183,7 @@ pub(crate) fn perform_reductions(
|
||||||
if (!cheap || reduced.is_none()) && !deadline.passed() {
|
if (!cheap || reduced.is_none()) && !deadline.passed() {
|
||||||
if let Some(indexed) = indexed.and_then(|png| reduced_bit_depth_8_or_less(&png)) {
|
if let Some(indexed) = indexed.and_then(|png| reduced_bit_depth_8_or_less(&png)) {
|
||||||
// Only evaluate this if it's different from the first result (which must be grayscale if it exists)
|
// Only evaluate this if it's different from the first result (which must be grayscale if it exists)
|
||||||
if reduced.as_ref().map_or(true, |r| r.data != indexed.data) {
|
if reduced.as_ref().is_none_or(|r| r.data != indexed.data) {
|
||||||
eval.try_image(Arc::new(indexed));
|
eval.try_image(Arc::new(indexed));
|
||||||
evaluation_added = true;
|
evaluation_added = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@ use indexmap::IndexSet;
|
||||||
use rgb::RGBA8;
|
use rgb::RGBA8;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
Interlacing,
|
||||||
colors::{BitDepth, ColorType},
|
colors::{BitDepth, ColorType},
|
||||||
headers::IhdrData,
|
headers::IhdrData,
|
||||||
png::{scan_lines::ScanLine, PngImage},
|
png::{PngImage, scan_lines::ScanLine},
|
||||||
Interlacing,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Attempt to reduce the number of colors in the palette, returning the reduced image if successful
|
/// Attempt to reduce the number of colors in the palette, returning the reduced image if successful
|
||||||
|
|
|
||||||
|
|
@ -99,11 +99,11 @@ fn test_it_converts(
|
||||||
fn verbose_mode() {
|
fn verbose_mode() {
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
#[cfg(not(feature = "parallel"))]
|
#[cfg(not(feature = "parallel"))]
|
||||||
use std::sync::mpsc::{channel as unbounded, Sender};
|
use std::sync::mpsc::{Sender, channel as unbounded};
|
||||||
|
|
||||||
#[cfg(feature = "parallel")]
|
#[cfg(feature = "parallel")]
|
||||||
use crossbeam_channel::{unbounded, Sender};
|
use crossbeam_channel::{Sender, unbounded};
|
||||||
use log::{set_logger, set_max_level, Level, LevelFilter, Log, Metadata, Record};
|
use log::{Level, LevelFilter, Log, Metadata, Record, set_logger, set_max_level};
|
||||||
|
|
||||||
// Rust runs tests in parallel by default.
|
// Rust runs tests in parallel by default.
|
||||||
// We want to make sure that we verify only logs from our test.
|
// We want to make sure that we verify only logs from our test.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue