This PR adds the modified zeng ("mzeng") palette sorting method, in
addition to the existing luma and battiato methods. Speed is very
similar to the battiato method with slightly better results on average.
Resulting sizes from two different image sets (all indexed or able to be
indexed):
| | master | PR |
|-|-|-|
| Set 1 | 29,647,156 | 29,555,697 |
| Set 2 | 23,732,133 | 23,570,862 |
Additionally, I've added a new "first colour" heuristic for both the
mzeng and battiato methods: We use the most popular colour overall, but
only if it covers at least 15% of the image. This provided 13k savings
on Set 2 vs the edge colour heuristic (which is still used in the luma
sort).
Repology is a free service that monitors the packaging status of
projects in lots of package repositories, and offers a nice API to
generate badges with a summary of what OxiPNG versions are available in
what repositories. Let's introduce that to our README to make it easier
for users to decide whether to use a package manager of their
convenience, and visibilize the work package maintainers do with OxiPNG.
GitHub introduced free macOS ARM runners on January, and my experience
using them in other projects to improve CI times and be able to actually
run tests on Apple Silicon Macs has been positive. Let's use them in
OxiPNG to hopefully speed up CI a bit, and finally be able to run the
test suite on AArch64 macOS.
This PR adds a build script to generate a man page using clap_mangen, as
per this example:
https://github.com/sondr3/clap-man-example/blob/main/build.rs
I'm not sure what to actually do with the man file from here, I guess
it's up to the packaging process to do something with it?
See
https://github.com/shssoichiro/oxipng/issues/69#issuecomment-1963352536
Note I couldn't see a way to include the `DISPLAY` chunk names from the
constant as we did before. They're now just hardcoded into the help and
will require manually updating if the list changes.
Closes#526
---------
Co-authored-by: Alejandro González <me@alegon.dev>
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.
There was an incorrect glob `bench/*` that was doing nothing, since the
benchmarks are in `benches/`; when I corrected it to `benches/*`, `cargo
publish --dry-run` failed:
```
error: failed to verify package tarball
Caused by:
failed to parse manifest at `/home/ben/src/forks/oxipng/target/package/oxipng-9.0.0/Cargo.toml`
Caused by:
can't find `zopfli` bench at `benches/zopfli.rs` or `benches/zopfli/main.rs`. Please specify bench.path if you want to use a non-default path.
```
…so I stopped trying to exclude the benchmarks from published crates at
all.
-----
Then, I added `Dockerfile`, `index.html`, and `scripts/` to the list of
paths to exclude from published crates.
Finally, I added some unnecessary “dotfiles” to the list of paths to
exclude from published crates.
-----
Some of this was suggested in a [package review for Fedora
Linux](https://bugzilla.redhat.com/show_bug.cgi?id=2259760).
After the PR:
```
$ cargo package --list
.cargo/config.toml
.cargo_vcs_info.json
CHANGELOG.md
Cargo.lock
Cargo.toml
Cargo.toml.orig
LICENSE
MANUAL.txt
README.md
benches/deflate.rs
[…]
benches/zopfli.rs
src/atomicmin.rs
[…]
src/sanity_checks.rs
$ cargo publish --dry-run
[…]
Compiling oxipng v9.0.0 (/home/ben/src/forks/oxipng/target/package/oxipng-9.0.0)
Finished dev [optimized + debuginfo] target(s) in 15.76s
Packaged 37 files, 255.4KiB (61.6KiB compressed)
Uploading oxipng v9.0.0 (/home/ben/src/forks/oxipng)
warning: aborting upload due to dry run
```
Hey !
Following the addition of [pre-commit
support](https://github.com/shssoichiro/oxipng/issues/429), I've updated
the docs with a small section to reflect that.
I've added this just above the [trunk
integration](https://github.com/shssoichiro/oxipng/pull/486) section.
Because pre-commit is open source while trunk is proprietary, it felt
more appropriate to promote this option.
Let me know if you want me to make any changes.
Cheers
Bumps
[dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact)
from 2 to 3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/dawidd6/action-download-artifact/releases">dawidd6/action-download-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v3.0.0</h2>
<p>Node was updated from 16 to 20.
Node 20 requires <code>glibc>=2.28</code>.</p>
<h2>v2.28.0</h2>
<p>No release notes provided.</p>
<h2>v2.27.0</h2>
<p>No release notes provided.</p>
<h2>v2.26.1</h2>
<p>No release notes provided.</p>
<h2>v2.26.0</h2>
<p>No release notes provided.</p>
<h2>v2.25.0</h2>
<p>No release notes provided.</p>
<h2>v2.24.4</h2>
<p>No release notes provided.</p>
<h2>v2.24.3</h2>
<p>No release notes provided.</p>
<h2>v2.24.2</h2>
<p>No release notes provided.</p>
<h2>v2.24.0</h2>
<p>No release notes provided.</p>
<h2>v2.23.0</h2>
<p>No release notes provided.</p>
<h2>v2.22.0</h2>
<p>No release notes provided.</p>
<h2>v2.21.1</h2>
<p>No release notes provided.</p>
<h2>v2.21.0</h2>
<p>No release notes provided.</p>
<h2>v2.20.0</h2>
<p>No release notes provided.</p>
<h2>v2.19.0</h2>
<p>No release notes provided.</p>
<h2>v2.18.0</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="e7466d1a75"><code>e7466d1</code></a>
build(deps): bump <code>@actions/artifact</code> from 1.1.2 to 2.0.0
(<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/260">#260</a>)</li>
<li><a
href="f29d1b6a89"><code>f29d1b6</code></a>
node_modules: upgrade</li>
<li><a
href="587cee61f5"><code>587cee6</code></a>
action: node16 -> node20 (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/259">#259</a>)</li>
<li><a
href="1cf761fba6"><code>1cf761f</code></a>
build(deps): bump undici from 5.25.4 to 5.28.2 (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/258">#258</a>)</li>
<li><a
href="d44631c448"><code>d44631c</code></a>
build(deps): bump <code>@actions/github</code> from 5.1.1 to 6.0.0 (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/252">#252</a>)</li>
<li>See full diff in <a
href="https://github.com/dawidd6/action-download-artifact/compare/v2...v3">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
The filters used during reduction evaluations are normally set to None &
Bigrams, regardless of any options. This PR makes a slight change so
that if only one filter is specified in the options, this filter will be
used for reduction evaluations too.
This resolves an odd situation affecting lower levels (when --fast is
enabled) where you may try to force the filter to a specific value but
it actually ends up different because a reduction evaluation was
smaller. It's particularly helpful if you're wanting it to be as fast as
possible by using `-o0 -f0` which will now exclusively use None instead
of trying the slower Bigrams as well.
As another use, you could try to brute force oxipng by iterating each
filter separately, though this may not actually achieve anything 😂
[edit] I also pulled the options out into a separate file, though this
wasn't relevant to the filter change.
This is a minor change that allows using both `--strip` and `--keep` at
the same time.
E.g. `--strip safe --keep eXIf` will strip chunks while preserving both
the ones that aren't "safe" to remove *and* eXIf. Essentially it's a
convenience to allow extending the default list used by `--strip safe`.
Specifying chunk names for both options is not permitted, e.g. `--strip
eXIf --keep eXIf` will error.
Use of `--strip all` with `--keep` is redundant, but is permitted.
These changes resolve#575 by setting the OxiPNG binary that's about to
be put in a release tarball to be world-executable during the release
workflow, as such permissions are lost when fetching them from
artifacts.
A detailed read to the [Rust documentation for the `fs::Permissions`
struct](https://doc.rust-lang.org/stable/std/fs/struct.Permissions.html)
and a little digging into its implementation in the standard library
have shown that this code didn't work as expected in any platform, and
was a bit weird to begin with:
- It first read the permissions from the input file metadata.
- Then it fetched the output file metadata.
- After that, it changed the permissions for that output file metadata.
- It then performed a sanity check that the output file had the expected
permissions.
Barring the fact that the sanity check in step 4 is not needed, the
overall approach is wrong because setting the permissions in a file
metadata struct does not actually persist those changes anywere; it's
just an in-memory change only, so these operations were useless. The
Rust documentation explicitly mentions that the `set_readonly` method
"does not modify the files attributes" [sic], but it's easy to miss that
warning and not realize that it also applies to the methods offered by
the `PermissionsExt` trait. The code only appeared to work because in
most cases the default permissions for new files happen to match the
input file permissions, so the sanity check passed.
To fix this, use the `set_permissions` method on `File` to actually set
the output file permissions to be the same as the input file
permissions, which is both much simpler and robust.
These changes were tested in the context of issue #576, and fix#576.
This PR brings a big overhaul to oxipng's help, with new long form
descriptions of many options.
The full output (--help) is added as a text file MANUAL.txt. Critiques
welcome.
The short output (-h) is simplified and appears as follows:
```
Losslessly improve compression of PNG files
Usage: oxipng [OPTIONS] <files>...
Arguments:
<files>... File(s) to compress (use '-' for stdin)
Options:
-o, --opt <level> Optimization level (0-6, or max) [default: 2]
-r, --recursive Recurse input directories, optimizing all PNG files
--dir <directory> Write output file(s) to <directory>
--out <file> Write output file to <file>
--stdout Write output to stdout
-p, --preserve Preserve file permissions and timestamps if possible
-P, --pretend Do not write any files, only show compression results
-s Strip safely-removable chunks, same as '--strip safe'
--strip <mode> Strip metadata (safe, all, or comma-separated list)
CAUTION: 'all' will convert APNGs to standard PNGs
--keep <list> Strip all metadata except in the comma-separated list
-a, --alpha Perform additional alpha channel optimization
-i, --interlace <type> Set PNG interlacing type (0, 1, keep) [default: 0]
--scale16 Forcibly reduce 16-bit images to 8-bit (lossy)
-v, --verbose... Run in verbose mode (use twice to increase verbosity)
-q, --quiet Run in quiet mode
-f, --filters <list> Filters to try (0-9; see '--help' for details)
--fast Use fast filter evaluation
--zc <level> Deflate compression level (1-12)
--nb Do not change bit depth
--nc Do not change color type
--np Do not change color palette
--ng Do not change to or from grayscale
--nx Do not perform any transformations
--nz Do not recompress unless transformations occur
--fix Disable checksum validation
--force Write the output even if it is larger than the input
-Z, --zopfli Use the much slower but stronger Zopfli compressor
--timeout <secs> Maximum amount of time to spend on optimizations
-t, --threads <num> Set number of threads to use [default: num CPU cores]
-h, --help Print help (see more with '--help')
-V, --version Print version
Run `oxipng --help` to see full details of all options
```
---------
Co-authored-by: Alejandro González <me@alegon.dev>
This update brings several parameterization and usage flexibility
improvements on Zopfli, allowing users to choose to limit execution time
by a number of iterations without improvement, and exposing a more
advanced `ZlibEncoder` struct to tune compression block sizes and
DEFLATE block types. Some minor microoptimizations were also made.
For now, I don't expect this PR to substantially affect how OxiPNG
compresses images using its Zopfli mode, but the additional parameter
customization may come in handy for future work improving how Zopfli is
used in OxiPNG.