Skip to content

Commit

Permalink
release: 3.0.2
Browse files Browse the repository at this point in the history
  • Loading branch information
joshstoik1 committed Apr 25, 2024
2 parents 46c2d70 + b01d0ce commit a4bce67
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 60 deletions.
4 changes: 2 additions & 2 deletions CREDITS.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Project Dependencies
Package: flaca
Version: 3.0.1
Generated: 2024-04-24 05:50:28 UTC
Version: 3.0.2
Generated: 2024-04-25 03:55:30 UTC

| Package | Version | Author(s) | License |
| ---- | ---- | ---- | ---- |
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "flaca"
version = "3.0.1"
version = "3.0.2"
license = "WTFPL"
authors = ["Josh Stoik <josh@blobfolio.com>"]
edition = "2021"
Expand Down
4 changes: 2 additions & 2 deletions release/man/flaca.1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.TH "FLACA" "1" "April 2024" "Flaca v3.0.1" "User Commands"
.TH "FLACA" "1" "April 2024" "Flaca v3.0.2" "User Commands"
.SH NAME
Flaca \- Manual page for flaca v3.0.1.
Flaca \- Manual page for flaca v3.0.2.
.SH DESCRIPTION
Brute\-force, lossless JPEG and PNG compression.
.SS USAGE:
Expand Down
15 changes: 9 additions & 6 deletions src/image/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,15 @@ impl ImageKind {
pub(crate) fn is_jpeg(src: &[u8]) -> bool {
12 < src.len() &&
src[..3] == [0xFF, 0xD8, 0xFF] &&
(
src[3] == 0xDB ||
src[3] == 0xEE ||
src[3..12] == [0xE0, 0x00, 0x10, b'J', b'F', b'I', b'F', 0x00, 0x01] ||
(src[3] == 0xE1 && src[6..12] == [b'E', b'x', b'i', b'f', 0x00, 0x00])
)
match src[3] {
0xE0 =>
src[6..11] == [b'J', b'F', b'I', b'F', 0x00] ||
src[src.len() - 2..] == [0xFF, 0xD9],
0xE1 => src[6..11] == [b'E', b'x', b'i', b'f', 0x00],
0xE8 => src[6..12] == [b'S', b'P', b'I', b'F', b'F', 0x00],
0xDB | 0xED | 0xEE => src[src.len() - 2..] == [0xFF, 0xD9],
_ => false,
}
}

/// # Is PNG?
Expand Down
4 changes: 1 addition & 3 deletions src/image/zopflipng/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@ impl SplitPoints {
Ok(len)
}

#[allow(unsafe_code)]
/// # Split Best.
///
/// Compare the optimal raw split points with a dedicated lz77 pass and
Expand Down Expand Up @@ -189,8 +188,7 @@ impl SplitPoints {
// Make another store.
store2.clear();
lz77_optimal(
// Safety: the split points are checked at creation.
unsafe { arr.get_unchecked(..end) },
arr.get(..end).ok_or(zopfli_error!())?,
start,
numiterations,
store2,
Expand Down
89 changes: 43 additions & 46 deletions src/image/zopflipng/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,59 +298,43 @@ impl ZopfliHash {
#[allow(unsafe_code)]
/// # New (Boxed) Instance.
///
/// Fixed arrays really do seem to be the most efficient structure for
/// this data — even though `HashMap` seems ready-made for the job! — but
/// they're way too big to throw on the stack willynilly.
/// The fixed arrays holding this structure's data are monstrous — 458,756
/// bytes per instance! — but absolutely critical for performance.
///
/// Taking a page from the [`zopfli-rs`](https://github.com/zopfli-rs/zopfli)
/// port, new instances are initialized from raw pointers and `Box`ed to
/// keep them on the heap.
///
/// ## Safety.
///
/// The return value is allocated but **uninitialized**. Re/initialization
/// occurs subsequently when `ZopfliHash::reset` is called.
///
/// The only (crate)-facing entrypoints into this data are
/// `ZopfliState::greedy` and `ZopfliState::optimal_run`, both of which
/// call reset as their first order business, so in practice everything is
/// A-OK!
/// To keep Rust from placing all that shit on the stack — as it would
/// normally try to do — this method manually initializes everything from
/// raw pointers, then boxes it up for delivery à la [`zopfli-rs`](https://github.com/zopfli-rs/zopfli).
fn new() -> Box<Self> {
// Reserve the space.
const LAYOUT: Layout = Layout::new::<ZopfliHash>();
let out = NonNull::new(unsafe { alloc(LAYOUT).cast() })
.unwrap_or_else(|| handle_alloc_error(LAYOUT));
let ptr: *mut Self = out.as_ptr();

// Safety: all this pointer business is necessary to keep the content
// off the stack. Once it's boxed we can breathe easier. ;)
unsafe {
NonNull::new(alloc(LAYOUT).cast())
.map_or_else(
|| handle_alloc_error(LAYOUT),
|ptr| Box::from_raw(ptr.as_ptr())
)
}
}
// All the hash/index arrays default to `-1_i16` for `None`, which
// we can do efficiently by setting all bits to one.
addr_of_mut!((*ptr).chain1.hash_idx).write_bytes(u8::MAX, 1);
addr_of_mut!((*ptr).chain1.idx_hash).write_bytes(u8::MAX, 1);
addr_of_mut!((*ptr).chain1.idx_prev).write_bytes(u8::MAX, 1);

#[allow(unsafe_code)]
/// # Initialize Values.
///
/// Initialize/reset hash values to their defaults so we can reuse the
/// structure for a new dataset.
unsafe fn init(&mut self) {
// All the hash/index arrays default to `-1_i16` for `None`, which we
// can do efficiently by setting all bits to one.
addr_of_mut!(self.chain1.hash_idx).write_bytes(u8::MAX, 1);
addr_of_mut!(self.chain1.idx_hash).write_bytes(u8::MAX, 1);
addr_of_mut!(self.chain1.idx_prev).write_bytes(u8::MAX, 1);

// The initial hash value is just plain zero.
addr_of_mut!(self.chain1.val).write(0);

// The second chain is the same as the first, so we can simply copy it
// wholesale.
addr_of_mut!(self.chain2).copy_from_nonoverlapping(addr_of!(self.chain1), 1);

// Repetitions default to zero.
addr_of_mut!(self.same).write_bytes(0, 1);
// The initial hash value is just plain zero.
addr_of_mut!((*ptr).chain1.val).write(0);

// The second chain is the same as the first, so we can simply copy
// it wholesale.
addr_of_mut!((*ptr).chain2).copy_from_nonoverlapping(addr_of!((*ptr).chain1), 1);

// The repetition counts default to zero.
addr_of_mut!((*ptr).same).write_bytes(0, 1);

// All set!
Box::from_raw(ptr)
}
}

#[allow(unsafe_code)]
/// # Reset/Warm Up.
///
/// This sets all values to their defaults, then cycles the first chain's
Expand All @@ -361,7 +345,10 @@ impl ZopfliHash {
arr: &[u8],
instart: usize,
) {
unsafe { self.init(); }
// Reset the data.
self.chain1.reset();
self.chain2.reset();
self.same.fill(0);

// Cycle the hash once or twice.
if instart >= arr.len() { return; }
Expand Down Expand Up @@ -955,6 +942,16 @@ struct ZopfliHashChain {
}

impl ZopfliHashChain {
/// # Reset.
///
/// Set everything to its default values so we can begin again.
fn reset(&mut self) {
self.hash_idx.fill(-1);
self.idx_hash.fill(-1);
self.idx_prev.fill(-1);
self.val = 0;
}

#[allow(
clippy::cast_possible_truncation,
clippy::cast_possible_wrap,
Expand Down

0 comments on commit a4bce67

Please sign in to comment.