Commit graph

78 commits

Author SHA1 Message Date
Jakub Onderka
015d31e6a1
Remove crossbeam-channel dependency (#777) 2026-02-22 13:37:38 +00:00
andrews05
ff168f5d2d
Add json output option (#761) 2026-01-24 11:35:55 +00:00
andrews05
e5e1568196
Rework preserving attributes (#759) 2026-01-12 19:11:45 +01:00
Luracasmus
33cea5603e
Apply some Clippy lints (#744)
Let me know if I should add these to the `Cargo.toml`.

All `cargo test` tests pass on the latest x86_64-unknown-linux-gnu
nightly.

---------

Co-authored-by: Alejandro González <me@alegon.dev>
2025-12-06 16:06:35 +01:00
andrews05
7cc91b1308
Add max_uncompressed_size (#732)
Adds an option to skip files when the uncompressed IDAT (or the file
size itself) exceeds a certain size. This provides an effective way to
limit resource usage in constrained environments.

Closes #411.
2025-09-25 22:46:35 +02:00
andrews05
14532e8bf5
BC breaks for v10 (#715)
This is a collection of all the BC breaks mentioned in #714, except for
11 which I'm not including for now.

Fixes #658.
Fixes #660.

It might be best to review each commit individually, referencing the
notes in #714 and #660 (I just didn't want to create a dozen separate
PRs).
2025-09-20 17:16:22 +02:00
andrews05
71290acc62
Reduce memory usage of fast evaluation (#713)
This is an experiment I started a while ago before life happened. It
reduces memory usage of fast evaluation (-o2 and lower), bringing it
inline with normal (slow) evaluation. It does this by not retaining the
filtered image data of the evaluations, but instead retaining the row
filters that were used in each line so it can be quickly re-filtered
when required. This does incur a tiny performance penalty, but it's
negligible even at `-o0`.
Although this is fully functional, there are a few rough spots in the
code so I'm just opening it as a draft for now.

```
PR -sao6
       70.08 real       614.36 user         2.66 sys
          2024243200  maximum resident set size
          1839339520  peak memory footprint

PR -sao2
       11.16 real        60.85 user         1.33 sys
          1982562304  maximum resident set size
          1842173824  peak memory footprint

PR -sao2 -t1
       55.11 real        53.85 user         0.76 sys
           429457408  maximum resident set size
           245008064  peak memory footprint

master -sao6
       67.70 real       616.07 user         2.72 sys
          2043379712  maximum resident set size
          1838340416  peak memory footprint

master -sao2
       11.53 real        60.63 user         1.25 sys
          2753396736  maximum resident set size
          2283741440  peak memory footprint

master -sao2 -t1
       54.29 real        53.55 user         0.72 sys
           626311168  maximum resident set size
           305252544  peak memory footprint
```

Note that this involves some refactoring of `RowFilter` and the new
`FilterStrategy`. These are breaking changes so it will ultimately be
destined for v10. One advantage to this new structure is it opens the
door for future changes such as allowing the Brute strategy to take a
parameter for the number of lines.
2025-09-19 20:36:17 +02:00
andrews05
c60dbd12a5
Update runners, rust, and dependencies (#724)
#719 is failing tests due to requiring a newer version of rust than we
currently specify. This PR updates to 1.85.1 and sets the edition to
2024.
I've also updated dependencies and runner images, using the ubuntu arm
runner which removes the need for qemu and other hacks.

Closes #719.
2025-08-25 14:49:59 +02:00
andrews05
1e3f4520ef
Disallow grayscale transformation if non-sRGB profile (#682)
Fixes #677
2025-02-26 22:39:20 +01:00
andrews05
bbde68ddce
Refactor optimize_raw (#670)
Code always tends to get messy over time. I've found the `optimize_raw`
function increasingly harder to read, particularly after the addition of
fast mode, so I've taken some time to refactor and simplify it.

One change of note here is the main compression trials now use the
Evaluator. This means verbose output is a little different which is
shown below.

There is no change to performance or output size.

`-vvo2`: master
```
Processing: tests/files/rgba_8_should_be_palette_4.png
    500x400 pixels, PNG format
    8-bit RGB + Alpha, non-interlaced
    IDAT size = 2757 bytes
    File size = 18109 bytes
Eval: 4-bit Indexed (5 colors)      None       1837 bytes
Eval: 8-bit Indexed (5 colors)      None       1988 bytes
Eval: 4-bit Indexed (5 colors)      Bigrams   >1837 bytes
Eval: 8-bit Indexed (5 colors)      Bigrams   >1837 bytes
Transformed image to 4-bit Indexed (5 colors), non-interlaced
Evaluating: 2 filters
Eval: 4-bit Indexed (5 colors)      Sub       >1810 bytes
Eval: 4-bit Indexed (5 colors)      Entropy   >1810 bytes
Trying: None
    zc = 11  f = None      1583 bytes
Found better combination:
    zc = 11  f = None      1583 bytes
    IDAT size = 1583 bytes (1174 bytes decrease)
    file size = 16962 bytes (1147 bytes = 6.33% decrease)
16962 bytes (6.33% smaller): Running in pretend mode, no output
```

`-vvo2`: PR
```
Processing: tests/files/rgba_8_should_be_palette_4.png
    500x400 pixels, PNG format
    8-bit RGB + Alpha, non-interlaced
    IDAT size = 2757 bytes
    File size = 18109 bytes
Eval: 4-bit Indexed (5 colors)      None       1837 bytes
Eval: 8-bit Indexed (5 colors)      None       1988 bytes
Eval: 4-bit Indexed (5 colors)      Bigrams   >1837 bytes
Eval: 8-bit Indexed (5 colors)      Bigrams   >1837 bytes
Transformed image to 4-bit Indexed (5 colors), non-interlaced
Evaluating 2 filters
Eval: 4-bit Indexed (5 colors)      Sub       >1810 bytes
Eval: 4-bit Indexed (5 colors)      Entropy   >1810 bytes
Trying filter None with zc = 11
1610 bytes
Found better result:
    zc = 11, f = None
    IDAT size = 1583 bytes (1174 bytes decrease)
    file size = 16962 bytes (1147 bytes = 6.33% decrease)
16962 bytes (6.33% smaller): Running in pretend mode, no output
```

`-vvZo5`: master
```
Processing: tests/files/rgba_8_should_be_palette_4.png
    500x400 pixels, PNG format
    8-bit RGB + Alpha, non-interlaced
    IDAT size = 2757 bytes
    File size = 18109 bytes
Eval: 8-bit Indexed (battiato sort) None       1821 bytes
Eval: 4-bit Indexed (5 colors)      None       1657 bytes
Eval: 8-bit Indexed (mzeng sort)    None       1821 bytes
Eval: 8-bit Indexed (5 colors)      None       1821 bytes
Eval: 8-bit Indexed (battiato sort) Bigrams   >1821 bytes
Eval: 4-bit Indexed (5 colors)      Bigrams   >1657 bytes
Eval: 8-bit Indexed (mzeng sort)    Bigrams   >1657 bytes
Eval: 8-bit Indexed (5 colors)      Bigrams   >1657 bytes
Transformed image to 4-bit Indexed (5 colors), non-interlaced
Trying: 8 filters
    zc = zopfli  f = Brute     1562 bytes
    zc = zopfli  f = Sub      >1562 bytes
    zc = zopfli  f = Bigrams  >1562 bytes
    zc = zopfli  f = None      1407 bytes
    zc = zopfli  f = Up       >1407 bytes
    zc = zopfli  f = MinSum   >1407 bytes
    zc = zopfli  f = BigEnt   >1407 bytes
    zc = zopfli  f = Entropy  >1407 bytes
Found better combination:
    zc = zopfli  f = None      1407 bytes
    IDAT size = 1407 bytes (1350 bytes decrease)
    file size = 16786 bytes (1323 bytes = 7.31% decrease)
16786 bytes (7.31% smaller): Running in pretend mode, no output
```

`-vvZo5`: PR
```
Processing: tests/files/rgba_8_should_be_palette_4.png
    500x400 pixels, PNG format
    8-bit RGB + Alpha, non-interlaced
    IDAT size = 2757 bytes
    File size = 18109 bytes
Eval: 8-bit Indexed (battiato sort) None       1821 bytes
Eval: 4-bit Indexed (5 colors)      None       1657 bytes
Eval: 8-bit Indexed (mzeng sort)    None       1821 bytes
Eval: 8-bit Indexed (5 colors)      None       1821 bytes
Eval: 8-bit Indexed (battiato sort) Bigrams   >1657 bytes
Eval: 4-bit Indexed (5 colors)      Bigrams   >1657 bytes
Eval: 8-bit Indexed (mzeng sort)    Bigrams   >1657 bytes
Eval: 8-bit Indexed (5 colors)      Bigrams   >1657 bytes
Transformed image to 4-bit Indexed (5 colors), non-interlaced
Trying 8 filters with zopfli, zi = 15
Eval: 4-bit Indexed (5 colors)      Brute      1589 bytes
Eval: 4-bit Indexed (5 colors)      Bigrams    1641 bytes
Eval: 4-bit Indexed (5 colors)      Sub        1711 bytes
Eval: 4-bit Indexed (5 colors)      None       1434 bytes
Eval: 4-bit Indexed (5 colors)      Up         1764 bytes
Eval: 4-bit Indexed (5 colors)      MinSum     1760 bytes
Eval: 4-bit Indexed (5 colors)      BigEnt     1742 bytes
Eval: 4-bit Indexed (5 colors)      Entropy    1748 bytes
Found better result:
    zopfli, zi = 15, f = None
    IDAT size = 1407 bytes (1350 bytes decrease)
    file size = 16786 bytes (1323 bytes = 7.31% decrease)
16786 bytes (7.31% smaller): Running in pretend mode, no output
```
2025-01-29 20:53:11 +01:00
Kornel
a72bc945fc Clippy 2025-01-02 09:15:24 +13:00
andrews05
8ebb5e6dfd
Cleanup tests (#656)
I've replaced a few tests with synthetic images and removed a number
that I don't believe are relevant anymore.

I've also removed the #553 test without replacement as I don't know how
to synthesise a replacement and the issue is still open anyway.

Going forward I think we should avoid adding any new "issue" tests and
instead synthesise something suitable in one of the other collections.

Closes #655.
2024-12-02 20:58:01 +01:00
Kornel
f6e3614fe9 Use Rust 1.60 feature syntax 2024-07-10 12:47:26 +12:00
Alejandro González
0608ab9cab
Fix some new nightly Clippy lints and run rustfmt with prettier config 2024-02-20 19:12:35 +01:00
andrews05
98fd4de30a
Reduce size of release binary (#592)
This PR makes 3 changes that together reduce binary size by around 25%:
- Sets lto="fat" in cargo.toml
- Sets panic="abort" in cargo.toml
- Sets location-detail=none in RUSTFLAGS

Closes #571

An unrelated change: I've replaced the zopfli test file with a smaller
one that runs much faster, as well as removing the slow test for
issue-133 which was related to an older alpha optimisation that is no
longer relevant.
2024-02-20 19:02:12 +01:00
Alejandro González
1b500da585
Fix new Clippy lint 2024-01-22 13:40:53 +01:00
andrews05
462e982784
Move file-specific options under OutFile (#529)
This PR is addressing #220. It's not super important but it's a breaking
change, so if it's something we want to do then I thought I should get
it in now before the next release.

- [x] pretend can become another variant of OutFile, probably
OutFile::None, as that's what it essentially is - just another output
destination and not a separate option
- [x] ~~backup and~~ preserve_attrs should become properties of
OutFile::Path variant (so that it would contain Path { path, ~~backup,~~
preserve_attrs }) as they don't have any effect on any other output and
so semantically belong there best

Closes #220
2023-09-25 11:15:13 +02:00
Alejandro González
1f2e0f336a
Revamp CI workflow to upload artifacts, cross-compile ARM64 binaries, and more (#534)
As commented in issues https://github.com/shssoichiro/oxipng/issues/444
and https://github.com/shssoichiro/oxipng/issues/518, there is some user
interest for distributing binaries for each unstable commit, and target
ARM64 platforms. Personally, I think both suggestions are useful for the
project, as uploading binary artifacts for each commit might help
interested users to catch regressions and give feedback earlier, and
powerful ARM64 platforms are becoming increasingly popular due to some
cloud services (e.g., Amazon EC2, Azure VMs, Oracle Cloud) offering
cheaper plans for this hardware, in addition to the well-known push for
ARM by Apple with their custom M1 chips.

These changes make the CI target ARM64 as a first-class citizen. Because
the public GitHub actions runners can only be hosted on x64 for now, I
resorted to cross-compilation, [Debian's
multiarch](https://elinux.org/images/d/d8/Multiarch_and_Why_You_Should_Care-_Running%2C_Installing_and_Crossbuilding_With_Multiple_Architectures.pdf),
and QEMU to build, get ARM64 C library dependencies, and run tests,
respectively.

When the CI workflow finishes, a release CLI binary artifact is now
uploaded, which can be downloaded from the workflow run page on the
GitHub web interface.

In addition, these changes also introduce some cleanup and miscellaneous
improvements and changes to the CI workflow:

- Tests are run using [`nextest`](https://nexte.st/) instead of `cargo
test`, which substantially speeds up their execution. (On my development
workstation, `cargo test --release` takes around 10.67 s, while `cargo
nextest run --release` takes around 6.02 s.)
- The dependencies on unmaintained `actions-rs` actions were dropped in
favor of running Cargo commands directly, or using
`giraffate/clippy-action` for pretty inline annotations for Clippy. This
gets rid of the deprecation warnings for each workflow run.
- Most CI steps are run with a nightly Rust toolchain now, which allows
to take advantage of the latest Clippy lints and codegen improvements.
In my experience, when not relying on specific nightly features or
compiler internals, Rust does a pretty good job at making it possible to
rely on a rolling-release compiler for CI, as breakage is extremely rare
and thus offset by the improved features.
- The MSRV check was moved to a separate job with less steps, so that it
takes less of a toll on total workflow run minutes.

## Pending tasks

- [x] Generate universal macOS binaries with `lipo` (i.e., containing
both `aarch64` and `x64` code)
- [x] Tirelessly fix the stupid errors that tend to happen when
deploying a new CI workflow for the first time
- [x] Think what to do with the `deploy.yml` workflow. Should it fetch
artifacts from the CI job instead of building them again?
- [x] Maybe bring back 32-bit Windows binaries. Are they actually useful
for somebody, or just a way to remember the good old days?

---------

Co-authored-by: Josh Holmer <jholmer.in@gmail.com>
2023-09-02 11:09:20 -04:00
andrews05
b883c660fc
Additional palette sorting algorithm (#514)
This adds a new palette sorting algorithm that attempts to minimise
entropy by an approximate solution to the Traveling Salesman Problem.
The algorithm comes from "An efficient Re-indexing algorithm for
color-mapped images" by Battiato et al
(https://ieeexplore.ieee.org/document/1344033).
It's fast and effective and works in addition to the luma sort (which
remains the single most effective sort). In order to keep lower presets
fast though, I've only enabled this for o3 and higher.

Results on a set of 190 indexed images at `-o5`:
18,932,727 bytes - master
18,578,306 bytes - PR
18,559,863 bytes - PR + #509
(These images may be particularly suited to alternative sorting methods
- the gains here are not necessarily what should be expected on average)

Note I looked into the 120 different palette sorting methods from
TruePNG, as mentioned in #74 (and seen in action in the Zopfli KrzYmod
fork). They're... largely ineffective. The combination of all 120
methods are outperformed by just the existing luma sort plus this new
one. That's not to say there's nothing further to be gained from them,
but trying to brute force all the combinations definitely seems like a
bad idea. There are other algorithms I hope to explore in future...

@ace-dent Thought this might interest you


UPDATE: I realised a quick tweak to alpha values in the luma sort can
provide a great improvement on images with transparency. The following
numbers were taken with PR #509 as base.
`-o2`:
19,065,549 bytes - base (luma sort)
18,949,747 bytes - modified luma sort

`-o5`:
18,922,165 bytes - base (luma sort)
18,559,863 bytes - new sorting algorithm + luma sort
18,544,813 bytes - new sorting algorithm + modified luma sort
2023-07-11 12:33:57 -04:00
andrews05
4ae64c568b
Process files in parallel (#531)
This PR makes the oxipng binary process multiple files in parallel,
finally fulfilling #275. There seemed to be some debate about whether
oxipng _should_ do this or not but there's a couple of reasons I think
it makes sense:
1. The concern seemed mostly around the complexity of such a feature.
Not to worry, it was trivial* 🙂
2. Since then, oxipng has dropped from a max of something like 180
simultaneous compression trials down to 10, which is very much a good
thing but it does mean it's not utilising any more cores than that.

Some benchmarks on around 100 files on a machine with 8 cores:
Level | Master time | PR time
-|-|-
2 | 28.303 | 19.005
3 | 36.507 | 23.089
5 | 1:10.86 | 1:16.01

*Some additional changes were required in order to make sure sensible
output is printed to the terminal, since things won't be in order
anymore. Here's some example output from before:
```
Processing: tests/files/fully_optimized.png
    file size = 67 bytes (0 bytes = 0.00% decrease)
File already optimized
Processing: tests/files/corrupted_header.png
Invalid PNG header detected
Processing: tests/files/verbose_mode.png
    file size = 102480 bytes (12228 bytes = 10.66% decrease)
Output: tests/files/verbose_mode.png
```
And after:
```
Processing: tests/files/verbose_mode.png
Processing: tests/files/fully_optimized.png
Processing: tests/files/corrupted_header.png
tests/files/corrupted_header.png: Invalid PNG header detected
tests/files/fully_optimized.png: Could not optimize further, no change written
102480 bytes (10.66% smaller): tests/files/verbose_mode.png
```

Closes #275, #84, #169, #196 and #419.

[edit] This is the last thing I wanted to land before the next release 🥳
2023-07-11 03:45:10 -04:00
Josh Holmer
31e796c4e8 Revert "Provide BufferedZopfliDeflater and allow user to pass in a custom Deflater (#530)"
This reverts commit 2a59419bdf.
2023-07-09 13:40:20 -04:00
andrews05
39b00910ae
Use stronger compression in eval (#509) 2023-07-08 18:54:58 -04:00
Josh Holmer
2a59419bdf
Provide BufferedZopfliDeflater and allow user to pass in a custom Deflater (#530)
* Add .whitesource configuration file

* Experimental: allow Zopfli to use any size BufWriter

* Allow user to specify the output buffer size as well

* Allow user to specify maximum block splits

* Reformat and fix warnings

* Use deflater on iCCP chunk as well

* Bug fix: need to implement Zlib format

* Make functions const when possible

* Switch to using zopfli::Options in prep for https://github.com/zopfli-rs/zopfli/pull/21

* Switch to using zopfli::Options in prep for https://github.com/zopfli-rs/zopfli/pull/21

* Cargo fmt

* Fix compilation

* Fix tests

* Fix more lints

* Fix more lints

* Fix compilation more

---------

Co-authored-by: mend-bolt-for-github[bot] <42819689+mend-bolt-for-github[bot]@users.noreply.github.com>
Co-authored-by: Chris Hennick <hennickc@amazon.com>
Co-authored-by: Chris Hennick <4961925+Pr0methean@users.noreply.github.com>
2023-07-07 22:35:01 -04:00
andrews05
96122fa45a
Expand low depths to 8-bit (#516)
* Keep track of number of pixels in each scanline

* Expand depth to 8-bit

* Attempt expand bit depth

* Simplify tracking of reduction_occurred

* Fix test

* Simplify depth handling in reductions

* Add tests for disabled reductions
2023-06-18 01:32:47 -04:00
Andrew
88b930b5b1 Add scale16 option to force 16-bit reduction 2023-05-24 10:21:42 -04:00
andrews05
ea5f1884be
Refactor aux chunk handling (#505) 2023-05-21 15:34:23 -04:00
andrews05
d8b7ebaf47
Further small reduction improvements (#504) 2023-05-16 20:53:05 -04:00
andrews05
a26d225d81
More flexible verbosity, improve verbose test (#501)
* More flexible verbosity, improve verbose test

* Tweak reporting format

* Add evaluation reporting at trace level
2023-05-06 10:45:31 -04:00
andrews05
c97572be3e
ColorType Refactor (#500)
* Refactor ColorType
Move transparency and palette data into the ColorType

* Fixup tests

* Make more use of helper functions

* Change BitDepth to u8 representation with TryFrom

* Fix clippy lints

* Don't use unstable language features

* Restore documentation on transparency/palette
2023-04-27 19:49:54 -04:00
Alejandro González
be19ed592d
Make dependency on image optional (#498)
* Make dependency on `image` optional

After PR https://github.com/shssoichiro/oxipng/pull/481 was merged, the
`image` dependency became unused when building with debug assertions
disabled, as it is only used to implement output sanity checks when such
assertions are enabled.

The `image` crate transitively pulls a significant amount of
dependencies, so it's useful for OxiPNG users to get rid of them when
not needed.

[Cargo does not allow specifying dependencies that are only pulled when
debug assertions are
enabled](https://github.com/rust-lang/cargo/issues/7634), so the next
best way to give users some flexibility is to gate those debug
assertions behind a feature flag.

These changes add a `sanity-checks` feature flag that controls whether
the `image` crate and the related sanity checks are compiled in. This
feature is enabled by default to keep debug builds useful to catch
problems during development.

* Fix Clippy lints

* Run tests with new sanity-checks feature enabled
2023-04-24 13:24:23 -04:00
Alejandro González
0ff1049eb7 Gate dependency on crossbeam-channel behind the parallel feature
`crossbeam-channel` is only used if the `parallel` flag is enabled, so
it can be gated behind that feature flag to potentially reduce the size
of the build dependency tree for dependent projects.

While at it, I've fixed several warnings emmitted in tests/flags.rs.
2023-04-16 20:05:38 -04:00
Douman
cc37f645ba
Refactoring to use appropriate log level for debug logs (#489) 2023-04-04 00:48:01 -04:00
andrews05
2599b9fe82
Tweaks to interlacing and format display (#476) 2022-12-12 09:54:35 -05:00
andrews05
a41d7de348
New filter strategies (#461)
* Refactor filters as enum

* Include filter byte in filter output

* Add entropy filter

* Add bigrams filter

* Add bigram entropy filter

* Add brute filter

* Replace bit-vec

* Add tests and benches

* Show filters in help

* Use FxHasher in color to palette

* Use windows function for minor improvement
2022-11-19 08:49:25 -05:00
andrews05
446c788eb3
Full switch to Libdeflater (#457)
* Switch main compressor to libdeflate

* Use libdeflater in evaluate

* Use libdeflater to inflate

* Use libdeflater crc

* Tidy up

* Fix benches

* Allow libdeflater/freestanding feature

* Fix building without zopfli
2022-11-01 09:02:08 -04:00
andrews05
f688d20fe6
Allow setting libdeflate compression level (#455)
* Allow --zc with libdeflater

* Update libdeflater

* Allocate sufficient space for libdefate
2022-10-28 21:54:04 -04:00
Alejandro González
84bbec0666
Add initial support for changing Zopfli iterations (#446)
* Update and optimize dependencies

These changes update the dependencies to their latest versions, fixing
some known issues that prevented doing so in the first place.

In addition, the direct dependency on byteorder was dropped in favor
of stdlib functions that have been stabilized for some time in Rust, and
the transitive dependency on chrono, pulled by stderrlog, was also
dropped, which had been affected by security issues and improperly
maintained in the past:

- https://github.com/cardoe/stderrlog-rs/issues/31
- https://www.reddit.com/r/rust/comments/ts84n4/chrono_or_time_03/

* Run rustfmt

* Bump MSRV to 1.56.1

Updating to this patch version should not be cumbersome for end-users,
and it is required by a transitive dependency.

* Bump MSRV to 1.57.0

os_str_bytes requires it.

* Add initial support for changing Zopfli iterations

PR https://github.com/shssoichiro/oxipng/pull/445 did some dependency
updates, which included using the latest zopfli version. The latest
version of this crate exposes new options in its API that allow users to
choose the desired number of Zopfli compression iterations, which
may greatly affect execution time. In fact, other optimizers such as
zopflipng dynamically select this number depending on the input file
size (see: https://github.com/shssoichiro/oxipng/issues/414).

As a first step towards making OxiPNG deal with Zopfli better, let's add
the necessary options for libraries to be able to choose the number of
iterations. This number is still fixed to 15 as before when using the
CLI.

* Fix Clippy lint

Co-authored-by: Josh Holmer <jholmer.in@gmail.com>
2022-09-05 12:50:13 -04:00
Moe
40a88f57f7
initial implementation of timestamp preservation #166 (#360)
Closes #166
2021-07-11 23:34:10 -04:00
Rémi Lauzier
91a18ebe97 Fix some clippy warnings 2021-06-24 15:57:41 -04:00
Kornel
f8bb4fa637 Fix tests without default features 2021-06-16 17:37:33 -04:00
Ingvar Stepanyan
e38c759563
Switch to crossbeam-channel + rayon::spawn (#327)
* Switch to crossbeam-channel + rayon::spawn

* Remove thread_spawn for evaluation altogether

This allows to avoid a deadlock when there is only one Rayon thread, and doesn't sacrifice performance, since the caller of .get_result() had to always block on the iterator to be finished anyway, and all the messages are already sent from separate threads.

* Fix `verbose_mode` test

This one is easier to "fix", since we're in control of the rayon pool - just adding one extra thread to the default number to make sure we always can one root "spawn" call without stealing from the actual pool.
2020-11-11 12:01:13 -05:00
Ingvar Stepanyan
23ae9c302f
Switch to standard logging library (#218)
This allows to configure or compile away logging in the library from a single place in Rust apps.

For the CLI side, the usage and output remained the same, except it's now colour-coded.

Fixes #217.
2020-04-18 18:33:48 -04:00
Josh Holmer
43735086d1 Migrate to Github Actions
Closes #206
2020-04-15 13:26:28 -04:00
Ingvar Stepanyan
878bbedb37
Improve performance consistency (#202)
* Improve performance consistency

Switch from HashMap / HashSet to IndexMap / IndexSet for consistent iteration order of various options and, as a result, more predictable performance.
2020-03-31 21:54:05 -04:00
Ingvar Stepanyan
121558bf5c
Add libdeflater as an option (#203)
libdeflater is a Rust wrapper around
[libdeflate](https://github.com/ebiggers/libdeflate) - an alternative
heavily optimised library for deflate/zlib/gzip compression and
decompression that is intended for situations where upper bounds of the
output are well-known.

In my benchmarks on test files in the repo it has shown to be usually
both slightly faster and providing better compressed output than
cloudflare-zlib, but in some cases showing the opposite, so rather
than swapping defaults, it's currently provided as another option,
similarly to zopfli.

Since it's not strictly better in all cases, I'm not providing median
numbers, but you can check distribution histograms for time and size
differences here (all using `oxipng -o 6 -t 6 -P`):
https://docs.google.com/spreadsheets/d/1WOKgeYZBhLkQvMGAC36snN4azilElzOFhx63RJu0EZY/edit?usp=sharing
2020-03-31 20:24:57 -04:00
Felix Hanau
5dcfe44ccd Fix info message and typos (#172) 2019-06-18 13:06:37 -04:00
Kornel
9af874d21b Make reductions return a new uncompressed image (#158)
* Fix verbose message

* No cloning when restoring original data

* Make reductions return a new uncompressed image

Partially fixes #145

* Async reduction evaluator

* Assert

* Faster bit depth check

* Also try 4-bit depth for small-depth images

* Skip test when using miniz

* Ensure palette is trimmed after depth reduction

Fixes #159

* Fudge factor for reductions to prefer better reductions even if gzip estimation says otherwise
2019-01-27 03:22:49 -05:00
Kornel
96eda85806 Identify and drop useless sRGB profiles (#143) 2018-11-13 14:37:02 -05:00
Kornel
3c466df80e Chunk name as 4 bytes (#135) 2018-09-16 16:09:55 -04:00
Matthias Krüger
947ccaad04 fix more clippy warnings found by "cargo clippy --all-targets --all-features" (#130) 2018-08-02 23:19:42 -04:00