From 87c26930d60a19b7f2cdb29fffdde6de65396fb7 Mon Sep 17 00:00:00 2001 From: Josh Stoik Date: Sat, 14 Sep 2024 21:53:54 -0700 Subject: [PATCH 1/8] bump: utc2k 0.10 --- flaca/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flaca/Cargo.toml b/flaca/Cargo.toml index 150be9c..095c178 100644 --- a/flaca/Cargo.toml +++ b/flaca/Cargo.toml @@ -118,7 +118,7 @@ ctrlc = "=3.4.5" dactyl = "0.7.*" dowser = "0.9.*" libc = "0.2.*" -utc2k = "0.9.*" +utc2k = "0.10.*" write_atomic = "0.5.*" [dependencies.flapfli] From 4bd4ba4ef4269e737a7dfcb51cef369a073c15ab Mon Sep 17 00:00:00 2001 From: Josh Stoik Date: Thu, 10 Oct 2024 15:14:46 -0700 Subject: [PATCH 2/8] bump: fyi 1.1 --- flaca/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flaca/Cargo.toml b/flaca/Cargo.toml index 095c178..61b4f20 100644 --- a/flaca/Cargo.toml +++ b/flaca/Cargo.toml @@ -126,7 +126,7 @@ version = "*" path = "../flapfli" [dependencies.fyi_msg] -version = "0.14.*" +version = "1.1.*" features = [ "progress" ] [dependencies.mozjpeg-sys] From 6155930cdf84b393fd8dce51a9704763800dc740 Mon Sep 17 00:00:00 2001 From: Josh Stoik Date: Tue, 15 Oct 2024 08:49:23 -0700 Subject: [PATCH 3/8] bump: lodepng 20241014 --- skel/vendor/lodepng/lodepng.c | 43 +++++++++++++++++++++++++---------- skel/vendor/lodepng/lodepng.h | 9 +++++--- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/skel/vendor/lodepng/lodepng.c b/skel/vendor/lodepng/lodepng.c index 4afbb54..ca576d8 100644 --- a/skel/vendor/lodepng/lodepng.c +++ b/skel/vendor/lodepng/lodepng.c @@ -1,7 +1,7 @@ /* -LodePNG version 20230410 +LodePNG version 20241014 -Copyright (c) 2005-2023 Lode Vandevenne +Copyright (c) 2005-2024 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -44,7 +44,7 @@ Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for #pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/ #endif /*_MSC_VER */ -const char* LODEPNG_VERSION_STRING = "20230410"; +const char* LODEPNG_VERSION_STRING = "20241014"; /* This source file is divided into the following large parts. The code sections @@ -1740,7 +1740,7 @@ static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, s 2 bytes LEN, 2 bytes NLEN, LEN bytes literal DATA*/ size_t i, numdeflateblocks = (datasize + 65534u) / 65535u; - unsigned datapos = 0; + size_t datapos = 0; for(i = 0; i != numdeflateblocks; ++i) { unsigned BFINAL, BTYPE, LEN, NLEN; unsigned char firstbyte; @@ -4062,9 +4062,18 @@ unsigned lodepng_compute_color_stats(LodePNGColorStats* stats, } } else /* < 16-bit */ { unsigned char r = 0, g = 0, b = 0, a = 0; + unsigned char pr = 0, pg = 0, pb = 0, pa = 0; for(i = 0; i != numpixels; ++i) { getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in); + /*skip if color same as before, this speeds up large non-photographic + images with many same colors by avoiding 'color_tree_has' below */ + if(i != 0 && r == pr && g == pg && b == pb && a == pa) continue; + pr = r; + pg = g; + pb = b; + pa = a; + if(!bits_done && stats->bits < 8) { /*only r is checked, < 8 bits is only relevant for grayscale*/ unsigned bits = getValueRequiredBits(r); @@ -5588,11 +5597,20 @@ static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t d LodePNGCompressSettings* zlibsettings) { unsigned error = 0; unsigned char* zlib = 0; + size_t pos = 0; size_t zlibsize = 0; + /* max chunk length allowed by the specification is 2147483647 bytes */ + const size_t max_chunk_length = 2147483647u; error = zlib_compress(&zlib, &zlibsize, data, datasize, zlibsettings); - if(!error) { - error = lodepng_chunk_createv(out, zlibsize, "IDAT", zlib); + while(!error) { + if(zlibsize - pos > max_chunk_length) { + error = lodepng_chunk_createv(out, max_chunk_length, "IDAT", zlib + pos); + pos += max_chunk_length; + } else { + error = lodepng_chunk_createv(out, zlibsize - pos, "IDAT", zlib + pos); + break; + } } lodepng_free(zlib); return error; @@ -6158,18 +6176,19 @@ static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigne /*out must be buffer big enough to contain uncompressed IDAT chunk data, and in must contain the full image. return value is error**/ static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned char* in, - unsigned w, unsigned h, + size_t w, size_t h, const LodePNGInfo* info_png, const LodePNGEncoderSettings* settings) { /* This function converts the pure 2D image with the PNG's colortype, into filtered-padded-interlaced data. Steps: *) if no Adam7: 1) add padding bits (= possible extra bits per scanline if bpp < 8) 2) filter *) if adam7: 1) Adam7_interlace 2) 7x add padding bits 3) 7x filter */ - unsigned bpp = lodepng_get_bpp(&info_png->color); + size_t bpp = lodepng_get_bpp(&info_png->color); unsigned error = 0; - if(info_png->interlace_method == 0) { - *outsize = h + (h * ((w * bpp + 7u) / 8u)); /*image size plus an extra byte per scanline + possible padding bits*/ + /*image size plus an extra byte per scanline + possible padding bits*/ + /*this requires the w and h inputs to be size_t, not unsigned int, to compute it correctly if larger than 2^32*/ + *outsize = h + (h * ((w * bpp + 7u) / 8u)); *out = (unsigned char*)lodepng_malloc(*outsize); if(!(*out) && (*outsize)) error = 83; /*alloc fail*/ @@ -6436,12 +6455,12 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h); } if(!state->error) { - state->error = preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder); + state->error = preProcessScanlines(&data, &datasize, converted, (size_t)w, (size_t)h, &info, &state->encoder); } lodepng_free(converted); if(state->error) goto cleanup; } else { - state->error = preProcessScanlines(&data, &datasize, image, w, h, &info, &state->encoder); + state->error = preProcessScanlines(&data, &datasize, image, (size_t)w, (size_t)h, &info, &state->encoder); if(state->error) goto cleanup; } diff --git a/skel/vendor/lodepng/lodepng.h b/skel/vendor/lodepng/lodepng.h index 3f3649d..2538302 100644 --- a/skel/vendor/lodepng/lodepng.h +++ b/skel/vendor/lodepng/lodepng.h @@ -1,7 +1,7 @@ /* -LodePNG version 20230410 +LodePNG version 20241014 -Copyright (c) 2005-2023 Lode Vandevenne +Copyright (c) 2005-2024 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -818,7 +818,10 @@ unsigned lodepng_compute_color_stats(LodePNGColorStats* stats, typedef struct LodePNGEncoderSettings { LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/ - unsigned auto_convert; /*automatically choose output PNG color type. Default: true*/ + /*automatically choose output PNG color type. If false, must explicitely choose the output color + type in state.info_png.color.colortype, info_png.color.bitdepth and optionally its palette. + Default: true*/ + unsigned auto_convert; /*If true, follows the official PNG heuristic: if the PNG uses a palette or lower than 8 bit depth, set all filters to zero. Otherwise use the filter_strategy. Note that to From 0f2043f43f0cd1e448e8ac1d32a7a8d7a5975a3b Mon Sep 17 00:00:00 2001 From: Josh Stoik Date: Tue, 15 Oct 2024 13:48:16 -0700 Subject: [PATCH 4/8] bump: argyle 0.9 refactor: cli parsing --- flaca/Cargo.toml | 2 +- flaca/src/error.rs | 89 ++++++++++++++++- flaca/src/image/kind.rs | 13 +++ flaca/src/main.rs | 209 +++++++++++++++++----------------------- 4 files changed, 192 insertions(+), 121 deletions(-) diff --git a/flaca/Cargo.toml b/flaca/Cargo.toml index 61b4f20..f274229 100644 --- a/flaca/Cargo.toml +++ b/flaca/Cargo.toml @@ -112,7 +112,7 @@ items = [ ] [dependencies] -argyle = "0.8.*" +argyle = "0.9.*" crossbeam-channel = "=0.5.*" ctrlc = "=3.4.5" dactyl = "0.7.*" diff --git a/flaca/src/error.rs b/flaca/src/error.rs index 1bb22aa..132aeef 100644 --- a/flaca/src/error.rs +++ b/flaca/src/error.rs @@ -2,7 +2,7 @@ # Flaca: Errors */ -use argyle::ArgyleError; +use argyle::stream::ArgyleError; use fyi_msg::ProglessError; use std::{ error::Error, @@ -11,21 +11,95 @@ use std::{ +/// # Help Text. +const HELP: &str = concat!(r" + ,--._,--. + ,' ,' ,-`. +(`-.__ / ,' / + `. `--' \__,--'-. + `--/ ,-. ______/ + (o-. ,o- / + `. ; \ ", "\x1b[38;5;199mFlaca\x1b[0;38;5;69m v", env!("CARGO_PKG_VERSION"), "\x1b[0m", r#" + |: \ Brute-force, lossless + ,'` , \ JPEG and PNG compression. + (o o , --' : + \--','. ; + `;; : / + ;' ; ,' ,' + ,',' : ' + \ \ : + ` + +USAGE: + flaca [FLAGS] [OPTIONS] ... + +FLAGS: + -h, --help Print help information and exit. + --no-jpeg Skip JPEG images. + --no-png Skip PNG images. + -p, --progress Show pretty progress while minifying. + -V, --version Print version information and exit. + +OPTIONS: + -j Limit parallelization to this many threads (instead of + giving each logical core its own image to work on). If + negative, the value will be subtracted from the total + number of logical cores. + -l, --list Read (absolute) image and/or directory paths from this + text file — or STDIN if "-" — one entry per line, instead + of or in addition to (actually trailing) . + --max-resolution + Skip images containing more than total pixels to + avoid potential OOM errors during decompression. + [default: ~4.29 billion] + -z Run NUM lz77 backward/forward iterations during zopfli + PNG encoding passes. More iterations yield better + compression (up to a point), but require *significantly* + longer processing times. In practice, values beyond 500 + are unlikely to save more than a few bytes, and could + take *days* to complete! Haha. [default: 20 or 60, + depending on the file size] +ARGS: + ... One or more image and/or directory paths to losslessly + compress. + +EARLY EXIT: + Press "#, "\x1b[38;5;208mCTRL\x1b[0m+\x1b[38;5;208mC\x1b[0m once to quit as soon as the already-in-progress operations + have finished (ignoring any pending images still in the queue). + + Press \x1b[38;5;208mCTRL\x1b[0m+\x1b[38;5;208mC\x1b[0m a second time if you need to exit IMMEDIATELY, but note that + doing so may leave artifacts (temporary files) behind, and in rare cases, + lead to image corruption. + +OPTIMIZERS USED: + MozJPEG + Oxipng + Zopflipng +"); + + + #[derive(Debug, Copy, Clone)] /// # Encoding Errors. pub(super) enum EncodingError { /// # Empty File. Empty, + /// # Wrong/Unknown Format. Format, + /// # Read Error. Read, + /// # Resolution. Resolution, + /// # Intentionally Skipped. Skipped, + /// # Vanished. Vanished, + /// # Write Error. Write, } @@ -53,16 +127,27 @@ impl EncodingError { pub(super) enum FlacaError { /// # Argyle Passthrough. Argue(ArgyleError), + /// # Killed Early. Killed, + /// # No Images. NoImages, + /// # Max Resolution. MaxResolution, + /// # Progress Passthrough. Progress(ProglessError), + /// # Invalid Zopfli Iterations. ZopfliIterations, + + /// # Print Help (Not an Error). + PrintHelp, + + /// # Print Version (Not an Error). + PrintVersion, } impl AsRef for FlacaError { @@ -100,6 +185,8 @@ impl FlacaError { Self::MaxResolution => "Pixel limits must be between 1..=4_294_967_295.", Self::Progress(e) => e.as_str(), Self::ZopfliIterations => "The number of (zopfli) lz77 iterations must be between 1..=2_147_483_647.", + Self::PrintHelp => HELP, + Self::PrintVersion => concat!("Flaca v", env!("CARGO_PKG_VERSION")), } } } diff --git a/flaca/src/image/kind.rs b/flaca/src/image/kind.rs index ee1cd5b..3fe2b4c 100644 --- a/flaca/src/image/kind.rs +++ b/flaca/src/image/kind.rs @@ -2,6 +2,7 @@ # Flaca: Image Kind */ +use crate::FlacaError; use std::num::NonZeroU32; @@ -25,6 +26,18 @@ pub(crate) enum ImageKind { } impl ImageKind { + /// # Return the Difference. + /// + /// Subtract `other` from `self`, returning an error if that leaves + /// nothing. + pub(crate) const fn diff(self, other: Self) -> Result { + match other { + Self::Jpeg if matches!(self, Self::All | Self::Png) => Ok(Self::Png), + Self::Png if matches!(self, Self::All | Self::Jpeg) => Ok(Self::Jpeg), + _ => Err(FlacaError::NoImages), + } + } + #[expect(clippy::inline_always, reason = "For performance.")] #[inline(always)] /// # Supports JPEG? diff --git a/flaca/src/main.rs b/flaca/src/main.rs index dd7a02f..72ed53c 100644 --- a/flaca/src/main.rs +++ b/flaca/src/main.rs @@ -63,13 +63,7 @@ pub(crate) use error::{ }; pub(crate) use image::kind::ImageKind; -use argyle::{ - Argue, - ArgyleError, - FLAG_HELP, - FLAG_REQUIRED, - FLAG_VERSION, -}; +use argyle::stream::Argument; use crossbeam_channel::Receiver; use dactyl::{ NiceElapsed, @@ -137,10 +131,9 @@ static AFTER: AtomicU64 = AtomicU64::new(0); fn main() { match _main() { Ok(()) => {}, - Err(FlacaError::Argue(ArgyleError::WantsVersion)) => { - println!(concat!("Flaca v", env!("CARGO_PKG_VERSION"))); + Err(e @ (FlacaError::PrintHelp | FlacaError::PrintVersion)) => { + println!("{e}"); }, - Err(FlacaError::Argue(ArgyleError::WantsHelp)) => { helper(); }, Err(e) => { Msg::error(e).die(1); }, } } @@ -151,58 +144,76 @@ fn main() { /// This is the actual main, allowing us to easily bubble errors. fn _main() -> Result<(), FlacaError> { // Parse CLI arguments. - let args = Argue::new(FLAG_HELP | FLAG_REQUIRED | FLAG_VERSION)? - .with_list(); - - // Figure out which kinds we're doing. - let kinds = match (args.switch2(b"--no-jpeg", b"--no-jpg"), args.switch(b"--no-png")) { - (false, false) => ImageKind::All, - (true, false) => ImageKind::Png, - (false, true) => ImageKind::Jpeg, - (true, true) => return Err(FlacaError::NoImages), - }; - - // Zopfli iterations. - if let Some(n) = args.option(b"-z") { - let n = NonZeroU32::btou(n).ok_or(FlacaError::ZopfliIterations)?; - flapfli::set_zopfli_iterations(n); - } + let args = argyle::stream::args() + .with_switches([ + "-h", "--help", + "--no-jpg", "--no-jpeg", + "--no-png", + "-p", "--progress", + "-V", "--version", + ])? + .with_options([ + "-j", + "-l", "--list", + "--max-resolution", + "-z", + ])?; + + let mut kinds = ImageKind::All; + let mut threads = None; + let mut paths = Dowser::default(); + let mut progress = false; + for arg in args { + match arg { + Argument::Key("-h" | "--help") => return Err(FlacaError::PrintHelp), + Argument::Key("--no-jpg" | "--no-jpeg") => { kinds = kinds.diff(ImageKind::Jpeg)?; }, + Argument::Key("--no-png") => { kinds = kinds.diff(ImageKind::Png)?; }, + Argument::Key("-p" | "--progress") => { progress = true; }, + Argument::Key("-V" | "--version") => return Err(FlacaError::PrintVersion), + + Argument::KeyWithValue("-j", s) => { threads.replace(s); }, + + Argument::KeyWithValue("-l" | "--list", s) => if let Ok(s) = std::fs::read_to_string(s) { + paths = paths.with_paths(s.lines().filter_map(|line| { + let line = line.trim(); + if line.is_empty() { None } + else { Some(line) } + })); + }, - // Pixel limits. - if let Some(n) = args.option(b"--max-resolution") { set_pixel_limit(n)?; } + Argument::KeyWithValue("--max-resolution", s) => { + set_pixel_limit(s.trim().as_bytes())?; + }, - // Figure out the maximum number of threads to use… - let mut threads = std::thread::available_parallelism().unwrap_or(NonZeroUsize::MIN); - if let Some(t) = args.option(b"-j") { - if let Some(t) = t.strip_prefix(b"-").and_then(NonZeroUsize::btou) { - threads = threads.get().checked_sub(t.get()) - .and_then(NonZeroUsize::new) - .unwrap_or(NonZeroUsize::MIN); - } - else if let Some(t) = NonZeroUsize::btou(t) { - if t < threads { threads = t; } + Argument::KeyWithValue("-z", s) => { + let s = NonZeroU32::btou(s.trim().as_bytes()) + .ok_or(FlacaError::ZopfliIterations)?; + flapfli::set_zopfli_iterations(s); + }, + + // Assume these are paths. + Argument::Other(s) => { paths = paths.with_path(s); }, + Argument::InvalidUtf8(s) => { paths = paths.with_path(s); }, + + // Nothing else is relevant. + _ => {}, } } // Find and sort the images! - let mut paths = Dowser::default() - .with_paths(args.args_os()) - .into_vec_filtered(|p| Extension::try_from3(p).map_or_else( - || Some(E_JPEG) == Extension::try_from4(p), - |e| e == E_JPG || e == E_PNG - )); + let mut paths = paths.into_vec_filtered(dowser_filter); // Make sure we have paths, and if we only have a few, reduce the // number of threads accordingly. let total = NonZeroUsize::new(paths.len()).ok_or(FlacaError::NoImages)?; - if total < threads { threads = total; } + let threads = max_threads(threads, total); // Sort the paths for reproduceability. paths.sort(); // Boot up a progress bar, if desired. let progress = - if args.switch2(b"-p", b"--progress") { + if progress { Progless::try_from(total).ok().map(|p| p.with_reticulating_splines("Flaca")) } else { None }; @@ -266,9 +277,7 @@ fn _main() -> Result<(), FlacaError> { }); // Summarize! - if let Some(progress) = progress { - summarize(&progress, total.get() as u64); - } + if let Some(progress) = progress { summarize(&progress, total.get() as u64); } // Did anything get missed? if ! undone.is_empty() { dump_undone(&undone); } @@ -330,6 +339,15 @@ fn crunch_quiet(rx: &Receiver::<&Path>, kinds: ImageKind) { while let Ok(p) = rx.recv() { let _res = crate::image::encode(p, kinds); } } +#[inline] +/// # Dowser Filter. +fn dowser_filter(p: &Path) -> bool { + Extension::try_from3(p).map_or_else( + || Some(E_JPEG) == Extension::try_from4(p), + |e| e == E_JPG || e == E_PNG + ) +} + #[cold] /// # Dump Undone. /// @@ -356,76 +374,29 @@ fn dump_undone(undone: &[&Path]) { } } -#[cold] -#[inline(never)] -/// # Print Help. -fn helper() { - println!(concat!( - r" - ,--._,--. - ,' ,' ,-`. -(`-.__ / ,' / - `. `--' \__,--'-. - `--/ ,-. ______/ - (o-. ,o- / - `. ; \ ", "\x1b[38;5;199mFlaca\x1b[0;38;5;69m v", env!("CARGO_PKG_VERSION"), "\x1b[0m", r#" - |: \ Brute-force, lossless - ,'` , \ JPEG and PNG compression. - (o o , --' : - \--','. ; - `;; : / - ;' ; ,' ,' - ,',' : ' - \ \ : - ` - -USAGE: - flaca [FLAGS] [OPTIONS] ... - -FLAGS: - -h, --help Print help information and exit. - --no-jpeg Skip JPEG images. - --no-png Skip PNG images. - -p, --progress Show pretty progress while minifying. - -V, --version Print version information and exit. - -OPTIONS: - -j Limit parallelization to this many threads (instead of - giving each logical core its own image to work on). If - negative, the value will be subtracted from the total - number of logical cores. - -l, --list Read (absolute) image and/or directory paths from this - text file — or STDIN if "-" — one entry per line, instead - of or in addition to (actually trailing) . - --max-resolution - Skip images containing more than total pixels to - avoid potential OOM errors during decompression. - [default: ~4.29 billion] - -z Run NUM lz77 backward/forward iterations during zopfli - PNG encoding passes. More iterations yield better - compression (up to a point), but require *significantly* - longer processing times. In practice, values beyond 500 - are unlikely to save more than a few bytes, and could - take *days* to complete! Haha. [default: 20 or 60, - depending on the file size] -ARGS: - ... One or more image and/or directory paths to losslessly - compress. - -EARLY EXIT: - Press "#, "\x1b[38;5;208mCTRL\x1b[0m+\x1b[38;5;208mC\x1b[0m once to quit as soon as the already-in-progress operations - have finished (ignoring any pending images still in the queue). - - Press \x1b[38;5;208mCTRL\x1b[0m+\x1b[38;5;208mC\x1b[0m a second time if you need to exit IMMEDIATELY, but note that - doing so may leave artifacts (temporary files) behind, and in rare cases, - lead to image corruption. - -OPTIMIZERS USED: - MozJPEG - Oxipng - Zopflipng -" - )); +/// # Max Threads. +/// +/// Given the hardware, user preference, and total number of jobs, calculate +/// and return the maximum number of threads to spawn. +fn max_threads(user: Option, jobs: NonZeroUsize) -> NonZeroUsize { + // The default number. + let mut threads = std::thread::available_parallelism().unwrap_or(NonZeroUsize::MIN); + + // Lower it if the user wants differently. + if let Some(t) = user { + let t = t.trim().as_bytes(); + if let Some(t) = t.strip_prefix(b"-").and_then(NonZeroUsize::btou) { + threads = threads.get().checked_sub(t.get()) + .and_then(NonZeroUsize::new) + .unwrap_or(NonZeroUsize::MIN); + } + else if let Some(t) = NonZeroUsize::btou(t) { + if t < threads { threads = t; } + } + } + + // Return the smaller of the user/machine and job counts. + NonZeroUsize::min(threads, jobs) } /// # Set Pixel Limit. From 9aec22e96b694e140ececaf42d58b43d0ed9432d Mon Sep 17 00:00:00 2001 From: Josh Stoik Date: Wed, 16 Oct 2024 00:22:41 -0700 Subject: [PATCH 5/8] bump: lodepng 20241015 --- skel/vendor/lodepng/lodepng.c | 25 ++++++++++++------------- skel/vendor/lodepng/lodepng.h | 2 +- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/skel/vendor/lodepng/lodepng.c b/skel/vendor/lodepng/lodepng.c index ca576d8..7e788ae 100644 --- a/skel/vendor/lodepng/lodepng.c +++ b/skel/vendor/lodepng/lodepng.c @@ -1,5 +1,5 @@ /* -LodePNG version 20241014 +LodePNG version 20241015 Copyright (c) 2005-2024 Lode Vandevenne @@ -44,7 +44,7 @@ Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for #pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/ #endif /*_MSC_VER */ -const char* LODEPNG_VERSION_STRING = "20241014"; +const char* LODEPNG_VERSION_STRING = "20241015"; /* This source file is divided into the following large parts. The code sections @@ -1750,7 +1750,7 @@ static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, s BTYPE = 0; LEN = 65535; - if(datasize - datapos < 65535u) LEN = (unsigned)datasize - datapos; + if(datasize - datapos < 65535u) LEN = (unsigned)datasize - (unsigned)datapos; NLEN = 65535 - LEN; if(!ucvector_resize(out, out->size + LEN + 5)) return 83; /*alloc fail*/ @@ -6176,7 +6176,7 @@ static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigne /*out must be buffer big enough to contain uncompressed IDAT chunk data, and in must contain the full image. return value is error**/ static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned char* in, - size_t w, size_t h, + unsigned w, unsigned h, const LodePNGInfo* info_png, const LodePNGEncoderSettings* settings) { /* This function converts the pure 2D image with the PNG's colortype, into filtered-padded-interlaced data. Steps: @@ -6187,18 +6187,17 @@ static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned error = 0; if(info_png->interlace_method == 0) { /*image size plus an extra byte per scanline + possible padding bits*/ - /*this requires the w and h inputs to be size_t, not unsigned int, to compute it correctly if larger than 2^32*/ - *outsize = h + (h * ((w * bpp + 7u) / 8u)); + *outsize = (size_t)h + ((size_t)h * (((size_t)w * bpp + 7u) / 8u)); *out = (unsigned char*)lodepng_malloc(*outsize); if(!(*out) && (*outsize)) error = 83; /*alloc fail*/ if(!error) { /*non multiple of 8 bits per scanline, padding bits needed per scanline*/ - if(bpp < 8 && w * bpp != ((w * bpp + 7u) / 8u) * 8u) { + if(bpp < 8 && (size_t)w * bpp != (((size_t)w * bpp + 7u) / 8u) * 8u) { unsigned char* padded = (unsigned char*)lodepng_malloc(h * ((w * bpp + 7u) / 8u)); if(!padded) error = 83; /*alloc fail*/ if(!error) { - addPaddingBits(padded, in, ((w * bpp + 7u) / 8u) * 8u, w * bpp, h); + addPaddingBits(padded, in, (((size_t)w * bpp + 7u) / 8u) * 8u, (size_t)w * bpp, h); error = filter(*out, padded, w, h, &info_png->color, settings); } lodepng_free(padded); @@ -6212,7 +6211,7 @@ static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const size_t filter_passstart[8], padded_passstart[8], passstart[8]; unsigned char* adam7; - Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, (unsigned)bpp); *outsize = filter_passstart[7]; /*image size plus an extra byte per scanline + possible padding bits*/ *out = (unsigned char*)lodepng_malloc(*outsize); @@ -6224,13 +6223,13 @@ static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const if(!error) { unsigned i; - Adam7_interlace(adam7, in, w, h, bpp); + Adam7_interlace(adam7, in, w, h, (unsigned)bpp); for(i = 0; i != 7; ++i) { if(bpp < 8) { unsigned char* padded = (unsigned char*)lodepng_malloc(padded_passstart[i + 1] - padded_passstart[i]); if(!padded) ERROR_BREAK(83); /*alloc fail*/ addPaddingBits(padded, &adam7[passstart[i]], - ((passw[i] * bpp + 7u) / 8u) * 8u, passw[i] * bpp, passh[i]); + (((size_t)passw[i] * bpp + 7u) / 8u) * 8u, (size_t)passw[i] * bpp, passh[i]); error = filter(&(*out)[filter_passstart[i]], padded, passw[i], passh[i], &info_png->color, settings); lodepng_free(padded); @@ -6455,12 +6454,12 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h); } if(!state->error) { - state->error = preProcessScanlines(&data, &datasize, converted, (size_t)w, (size_t)h, &info, &state->encoder); + state->error = preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder); } lodepng_free(converted); if(state->error) goto cleanup; } else { - state->error = preProcessScanlines(&data, &datasize, image, (size_t)w, (size_t)h, &info, &state->encoder); + state->error = preProcessScanlines(&data, &datasize, image, w, h, &info, &state->encoder); if(state->error) goto cleanup; } diff --git a/skel/vendor/lodepng/lodepng.h b/skel/vendor/lodepng/lodepng.h index 2538302..ae2cc3d 100644 --- a/skel/vendor/lodepng/lodepng.h +++ b/skel/vendor/lodepng/lodepng.h @@ -1,5 +1,5 @@ /* -LodePNG version 20241014 +LodePNG version 20241015 Copyright (c) 2005-2024 Lode Vandevenne From 8067e227007424c05b20963658591e9badbadb37 Mon Sep 17 00:00:00 2001 From: Josh Stoik Date: Thu, 17 Oct 2024 13:52:47 -0700 Subject: [PATCH 6/8] bump: argyle 0.10 re-refactor: cli parsing --- flaca/Cargo.toml | 9 +++++---- flaca/build.rs | 21 +++++++++++++++++++++ flaca/src/error.rs | 10 ---------- flaca/src/main.rs | 18 +++--------------- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/flaca/Cargo.toml b/flaca/Cargo.toml index f274229..93c4e28 100644 --- a/flaca/Cargo.toml +++ b/flaca/Cargo.toml @@ -111,8 +111,12 @@ items = [ [ "Zopflipng", "" ] ] +[build-dependencies] +argyle = "0.10.*" +dowser = "0.9.*" + [dependencies] -argyle = "0.9.*" +argyle = "0.10.*" crossbeam-channel = "=0.5.*" ctrlc = "=3.4.5" dactyl = "0.7.*" @@ -138,6 +142,3 @@ features = [ "jpegtran", "nasm_simd", "unwinding" ] version = "=9.1.2" default-features = false features = [ "freestanding" ] - -[build-dependencies] -dowser = "0.9.*" diff --git a/flaca/build.rs b/flaca/build.rs index fa059ae..61f0239 100644 --- a/flaca/build.rs +++ b/flaca/build.rs @@ -2,6 +2,7 @@ # Flaca - Build */ +use argyle::KeyWordsBuilder; use dowser::Extension; use std::{ fs::File, @@ -23,9 +24,29 @@ pub fn main() { #[cfg(not(target_pointer_width = "64"))] panic!("Flaca requires a 64-bit CPU architecture."); + build_cli(); build_exts(); } +/// # Build CLI Arguments. +fn build_cli() { + let mut builder = KeyWordsBuilder::default(); + builder.push_keys([ + "-h", "--help", + "--no-jpg", "--no-jpeg", + "--no-png", + "-p", "--progress", + "-V", "--version", + ]); + builder.push_keys_with_values([ + "-j", + "-l", "--list", + "--max-resolution", + "-z", + ]); + builder.save(out_path("argyle.rs")); +} + /// # Pre-Compute Extensions. /// /// We might as well generate the path-matching constants while we're here. diff --git a/flaca/src/error.rs b/flaca/src/error.rs index 132aeef..0c98cc2 100644 --- a/flaca/src/error.rs +++ b/flaca/src/error.rs @@ -2,7 +2,6 @@ # Flaca: Errors */ -use argyle::stream::ArgyleError; use fyi_msg::ProglessError; use std::{ error::Error, @@ -125,9 +124,6 @@ impl EncodingError { #[derive(Debug, Copy, Clone)] /// # General/Deal-Breaking Errors. pub(super) enum FlacaError { - /// # Argyle Passthrough. - Argue(ArgyleError), - /// # Killed Early. Killed, @@ -164,11 +160,6 @@ impl fmt::Display for FlacaError { } } -impl From for FlacaError { - #[inline] - fn from(err: ArgyleError) -> Self { Self::Argue(err) } -} - impl From for FlacaError { #[inline] fn from(err: ProglessError) -> Self { Self::Progress(err) } @@ -179,7 +170,6 @@ impl FlacaError { /// # As Str. pub(super) const fn as_str(self) -> &'static str { match self { - Self::Argue(e) => e.as_str(), Self::Killed => "The process was aborted early.", Self::NoImages => "No images were found.", Self::MaxResolution => "Pixel limits must be between 1..=4_294_967_295.", diff --git a/flaca/src/main.rs b/flaca/src/main.rs index 72ed53c..0309e64 100644 --- a/flaca/src/main.rs +++ b/flaca/src/main.rs @@ -63,7 +63,7 @@ pub(crate) use error::{ }; pub(crate) use image::kind::ImageKind; -use argyle::stream::Argument; +use argyle::Argument; use crossbeam_channel::Receiver; use dactyl::{ NiceElapsed, @@ -144,20 +144,8 @@ fn main() { /// This is the actual main, allowing us to easily bubble errors. fn _main() -> Result<(), FlacaError> { // Parse CLI arguments. - let args = argyle::stream::args() - .with_switches([ - "-h", "--help", - "--no-jpg", "--no-jpeg", - "--no-png", - "-p", "--progress", - "-V", "--version", - ])? - .with_options([ - "-j", - "-l", "--list", - "--max-resolution", - "-z", - ])?; + let args = argyle::args() + .with_keywords(include!(concat!(env!("OUT_DIR"), "/argyle.rs"))); let mut kinds = ImageKind::All; let mut threads = None; From dd7b6c5938e2bd69c2387d35b1f0c7cdd32deeaa Mon Sep 17 00:00:00 2001 From: Josh Stoik Date: Thu, 17 Oct 2024 13:53:15 -0700 Subject: [PATCH 7/8] bump: 3.1.9 --- flaca/Cargo.toml | 2 +- flapfli/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/flaca/Cargo.toml b/flaca/Cargo.toml index 93c4e28..16cb982 100644 --- a/flaca/Cargo.toml +++ b/flaca/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "flaca" -version = "3.1.8" +version = "3.1.9" license = "WTFPL" authors = ["Josh Stoik "] edition = "2021" diff --git a/flapfli/Cargo.toml b/flapfli/Cargo.toml index 1da2156..d5bf6d3 100644 --- a/flapfli/Cargo.toml +++ b/flapfli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "flapfli" -version = "3.1.8" +version = "3.1.9" license = "WTFPL" authors = ["Josh Stoik "] edition = "2021" From d2e768455ebb260d19f862bcea1ca0317b5027b3 Mon Sep 17 00:00:00 2001 From: Josh Stoik Date: Thu, 17 Oct 2024 13:54:50 -0700 Subject: [PATCH 8/8] build: 3.1.9 --- CREDITS.md | 34 +++++++++++++++++----------------- release/completions/flaca.bash | 2 +- release/man/flaca.1 | 4 ++-- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/CREDITS.md b/CREDITS.md index 518bb00..3d019fc 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -1,44 +1,44 @@ # Project Dependencies Package: flaca - Version: 3.1.8 - Generated: 2024-09-12 18:28:44 UTC + Version: 3.1.9 + Generated: 2024-10-17 20:53:40 UTC | Package | Version | Author(s) | License | | ---- | ---- | ---- | ---- | | [ahash](https://github.com/tkaitchuck/ahash) | 0.8.11 | [Tom Kaitchuck](mailto:tom.kaitchuck@gmail.com) | Apache-2.0 or MIT | -| [argyle](https://github.com/Blobfolio/argyle) | 0.8.1 | [Blobfolio, LLC.](mailto:hello@blobfolio.com) | WTFPL | +| [argyle](https://github.com/Blobfolio/argyle) | 0.10.0 | [Blobfolio, LLC.](mailto:hello@blobfolio.com) | WTFPL | | [bitvec](https://github.com/bitvecto-rs/bitvec) | 1.0.1 | | MIT | | [bytecount](https://github.com/llogiq/bytecount) | 0.6.8 | [Andre Bogus](mailto:bogusandre@gmail.de) and [Joshua Landau](mailto:joshua@landau.ws) | Apache-2.0 or MIT | -| [bytemuck](https://github.com/Lokathor/bytemuck) | 1.18.0 | [Lokathor](mailto:zefria@gmail.com) | Apache-2.0, MIT, or Zlib | +| [bytemuck](https://github.com/Lokathor/bytemuck) | 1.19.0 | [Lokathor](mailto:zefria@gmail.com) | Apache-2.0, MIT, or Zlib | | [cfg-if](https://github.com/alexcrichton/cfg-if) | 1.0.0 | [Alex Crichton](mailto:alex@alexcrichton.com) | Apache-2.0 or MIT | | [crc32fast](https://github.com/srijs/rust-crc32fast) | 1.4.2 | [Sam Rijs](mailto:srijs@airpost.net) and [Alex Crichton](mailto:alex@alexcrichton.com) | Apache-2.0 or MIT | | [crossbeam-channel](https://github.com/crossbeam-rs/crossbeam) | 0.5.13 | | Apache-2.0 or MIT | | [crossbeam-utils](https://github.com/crossbeam-rs/crossbeam) | 0.8.20 | | Apache-2.0 or MIT | | [ctrlc](https://github.com/Detegr/rust-ctrlc.git) | 3.4.5 | [Antti Keränen](mailto:detegr@gmail.com) | Apache-2.0 or MIT | -| [dactyl](https://github.com/Blobfolio/dactyl) | 0.7.3 | [Blobfolio, LLC.](mailto:hello@blobfolio.com) | WTFPL | +| [dactyl](https://github.com/Blobfolio/dactyl) | 0.7.4 | [Blobfolio, LLC.](mailto:hello@blobfolio.com) | WTFPL | | [dowser](https://github.com/Blobfolio/dowser) | 0.9.3 | [Blobfolio, LLC.](mailto:hello@blobfolio.com) | WTFPL | | [equivalent](https://github.com/cuviper/equivalent) | 1.0.1 | | Apache-2.0 or MIT | | [fastrand](https://github.com/smol-rs/fastrand) | 2.1.1 | [Stjepan Glavina](mailto:stjepang@gmail.com) | Apache-2.0 or MIT | -| flapfli | 3.1.8 | [Josh Stoik](mailto:josh@blobfolio.com) | WTFPL | +| flapfli | 3.1.9 | [Josh Stoik](mailto:josh@blobfolio.com) | WTFPL | | [funty](https://github.com/myrrlyn/funty) | 2.0.0 | [myrrlyn](mailto:self@myrrlyn.dev) | MIT | -| [fyi_msg](https://github.com/Blobfolio/fyi) | 0.14.0 | [Blobfolio, LLC.](mailto:hello@blobfolio.com) | WTFPL | -| [hashbrown](https://github.com/rust-lang/hashbrown) | 0.14.5 | [Amanieu d'Antras](mailto:amanieu@gmail.com) | Apache-2.0 or MIT | -| [indexmap](https://github.com/indexmap-rs/indexmap) | 2.5.0 | | Apache-2.0 or MIT | -| [libc](https://github.com/rust-lang/libc) | 0.2.158 | The Rust Project Developers | Apache-2.0 or MIT | -| [libdeflate-sys](https://github.com/adamkewley/libdeflater) | 1.21.0 | [Adam Kewley](mailto:contact@adamkewley.com) | Apache-2.0 | -| [libdeflater](https://github.com/adamkewley/libdeflater) | 1.21.0 | [Adam Kewley](mailto:contact@adamkewley.com) | Apache-2.0 | +| [fyi_msg](https://github.com/Blobfolio/fyi) | 1.1.1 | [Blobfolio, LLC.](mailto:hello@blobfolio.com) | WTFPL | +| [hashbrown](https://github.com/rust-lang/hashbrown) | 0.15.0 | [Amanieu d'Antras](mailto:amanieu@gmail.com) | Apache-2.0 or MIT | +| [indexmap](https://github.com/indexmap-rs/indexmap) | 2.6.0 | | Apache-2.0 or MIT | +| [libc](https://github.com/rust-lang/libc) | 0.2.161 | The Rust Project Developers | Apache-2.0 or MIT | +| [libdeflate-sys](https://github.com/adamkewley/libdeflater) | 1.22.0 | [Adam Kewley](mailto:contact@adamkewley.com) | Apache-2.0 | +| [libdeflater](https://github.com/adamkewley/libdeflater) | 1.22.0 | [Adam Kewley](mailto:contact@adamkewley.com) | Apache-2.0 | | [log](https://github.com/rust-lang/log) | 0.4.22 | The Rust Project Developers | Apache-2.0 or MIT | | [mozjpeg-sys](https://github.com/kornelski/mozjpeg-sys.git) | 2.2.1 | [Kornel](mailto:kornel@geekhood.net) | IJG AND Zlib AND BSD-3-Clause | -| [once_cell](https://github.com/matklad/once_cell) | 1.19.0 | [Aleksey Kladov](mailto:aleksey.kladov@gmail.com) | Apache-2.0 or MIT | +| [once_cell](https://github.com/matklad/once_cell) | 1.20.2 | [Aleksey Kladov](mailto:aleksey.kladov@gmail.com) | Apache-2.0 or MIT | | [oxipng](https://github.com/shssoichiro/oxipng) | 9.1.2 | [Joshua Holmer](mailto:jholmer.in@gmail.com) | MIT | | [radium](https://github.com/bitvecto-rs/radium) | 0.7.0 | [Nika Layzell](mailto:nika@thelayzells.com) and [myrrlyn](mailto:self@myrrlyn.dev) | MIT | | [rgb](https://github.com/kornelski/rust-rgb) | 0.8.50 | [Kornel Lesiński](mailto:kornel@geekhood.net) and [James Forster](mailto:james.forsterer@gmail.com) | MIT | | [rustc-hash](https://github.com/rust-lang-nursery/rustc-hash) | 1.1.0 | The Rust Project Developers | Apache-2.0 or MIT | | [tap](https://github.com/myrrlyn/tap) | 1.0.1 | [Elliott Linder](mailto:elliott.darfink@gmail.com) and [myrrlyn](mailto:self@myrrlyn.dev) | MIT | -| [tempfile](https://github.com/Stebalien/tempfile) | 3.12.0 | [Steven Allen](mailto:steven@stebalien.com), The Rust Project Developers, [Ashley Mannix](mailto:ashleymannix@live.com.au), and [Jason White](mailto:me@jasonwhite.io) | Apache-2.0 or MIT | -| [terminal_size](https://github.com/eminence/terminal-size) | 0.3.0 | [Andrew Chin](mailto:achin@eminence32.net) | Apache-2.0 or MIT | -| [unicode-width](https://github.com/unicode-rs/unicode-width) | 0.1.13 | [kwantam](mailto:kwantam@gmail.com) and [Manish Goregaokar](mailto:manishsmail@gmail.com) | Apache-2.0 or MIT | -| [utc2k](https://github.com/Blobfolio/utc2k) | 0.9.1 | [Blobfolio, LLC.](mailto:hello@blobfolio.com) | WTFPL | +| [tempfile](https://github.com/Stebalien/tempfile) | 3.13.0 | [Steven Allen](mailto:steven@stebalien.com), The Rust Project Developers, [Ashley Mannix](mailto:ashleymannix@live.com.au), and [Jason White](mailto:me@jasonwhite.io) | Apache-2.0 or MIT | +| [terminal_size](https://github.com/eminence/terminal-size) | 0.4.0 | [Andrew Chin](mailto:achin@eminence32.net) | Apache-2.0 or MIT | +| [unicode-width](https://github.com/unicode-rs/unicode-width) | 0.2.0 | [kwantam](mailto:kwantam@gmail.com) and [Manish Goregaokar](mailto:manishsmail@gmail.com) | Apache-2.0 or MIT | +| [utc2k](https://github.com/Blobfolio/utc2k) | 0.10.0 | [Blobfolio, LLC.](mailto:hello@blobfolio.com) | WTFPL | | [write_atomic](https://github.com/Blobfolio/write_atomic) | 0.5.1 | [Blobfolio, LLC.](mailto:hello@blobfolio.com) | WTFPL | | [wyz](https://github.com/myrrlyn/wyz) | 0.5.1 | [myrrlyn](mailto:self@myrrlyn.dev) | MIT | | [zerocopy](https://github.com/google/zerocopy) | 0.7.35 | [Joshua Liebow-Feeser](mailto:joshlf@google.com) | Apache-2.0, BSD-2-Clause, or MIT | diff --git a/release/completions/flaca.bash b/release/completions/flaca.bash index 0d8fac6..ebd36f0 100644 --- a/release/completions/flaca.bash +++ b/release/completions/flaca.bash @@ -31,7 +31,7 @@ _basher___flaca() { return 0 fi case "${prev}" in - -l|--list) + --list|-l) if [ -z "$( declare -f _filedir )" ]; then COMPREPLY=( $( compgen -f "${cur}" ) ) else diff --git a/release/man/flaca.1 b/release/man/flaca.1 index d30314d..572935c 100644 --- a/release/man/flaca.1 +++ b/release/man/flaca.1 @@ -1,6 +1,6 @@ -.TH "FLACA" "1" "September 2024" "Flaca v3.1.8" "User Commands" +.TH "FLACA" "1" "October 2024" "flaca v3.1.9" "User Commands" .SH NAME -Flaca \- Manual page for flaca v3.1.8. +FLACA \- Manual page for flaca v3.1.9. .SH DESCRIPTION Brute\-force, lossless JPEG and PNG compression. .SS USAGE: