Commit graph

143 commits

Author SHA1 Message Date
Alejandro González
491d753edc
Add option to skip grayscale reduction of RGB(A) images (#409)
For RGB(A) images that contain gray colors, this reduction can achieve
significant space savings. However, in the absence of gamma correction
data, some PNG decoders assume more exotic color spaces for grayscale
images instead of the ubiquitous sRGB. This results in gamma
miscorrection, and for the end user this means that colors will look
wrong, like "washed-out". Java's ImageIO class, which is popular in the
JVM world to read PNG files, uses rather unconventional defaults, as
explained in this StackOverflow question: https://stackoverflow.com/questions/31312645/java-imageio-grayscale-png-issue

Gamma miscorrection problems aside, OxiPNG currently tries hard to
reduce RGB(A) images to grayscale, because it expects that reduction to
be quite effective. However, in some cases, OxiPNG generates smaller
PNG files when reducing grasycale RGB(A) images to paletted color than
actual grayscale color. For example, let's say that "~/gray.png" is a
256x256 RGBA image entirely filled with (119, 119, 119, 255) pixels.
OxiPNG, by default, reduces this image to grayscale and achieves a
68.23% decrease:

$ cargo build --release && target/release/oxipng -omax --out ~/out.png ~/gray.png
Processing: /home/user/gray.png
    256x256 pixels, PNG format
    4x8 bits/pixel, RGBA
    IDAT size = 604 bytes
    File size = 661 bytes
Reducing image to 1x4 bits/pixel, Grayscale
Trying: 144 combinations
Found better combination:
    zc = 6  zs = 0  f = 0        153 bytes
    IDAT size = 153 bytes (451 bytes decrease)
    file size = 210 bytes (451 bytes = 68.23% decrease)
Output: /home/user/out.png

However, if the --ng option that this commit adds is used to skip the
grayscale reduction step, OxiPNG reduces to a single color palette
instead, which is much more efficient, achieving a 84.42% decrease:

$ cargo build --release && target/release/oxipng -omax --ng --out ~/out.png ~/gray.png
Processing: /home/alejandro/gray.png
    256x256 pixels, PNG format
    4x8 bits/pixel, RGBA
    IDAT size = 604 bytes
    File size = 661 bytes
Reducing image to 1 bits/pixel, 1 colors in palette
Trying: 144 combinations
Found better combination:
    zc = 3  zs = 3  f = 0        31 bytes
    IDAT size = 31 bytes (573 bytes decrease)
    file size = 103 bytes (558 bytes = 84.42% decrease)
Output: /home/alejandro/out.png

While OxiPNG should arguably be made smarter to better handle these
cases, in the meantime, adding an option to manually skip that grayscale
reduction can't hurt. In fact, it may even help users achieving the most
out of current versions of OxiPNG, and developers reasoning about what
makes a grayscale-like RGB(A) image compress better with a color
palette.

Due to the reasons stated above, this adds a simple "grayscale_reduction"
option to the Options struct, and a "no-grayscale-reduction" command
line switch, that makes OxiPNG not try this problematic grayscale
reduction on RGB(A) images.
2021-07-11 23:21:38 -04:00
Josh Holmer
90c99e4509 Do not exit on first non-PNG file found in recursion
Closes #170
2020-08-12 10:59:43 -04:00
Josh Holmer
ea746da96c Readd the --force flag to the CLI
This was still present in the lib and options parsing,
but was not in the Clap args list for some reason.
2020-07-13 04:36:27 -04:00
Ingvar Stepanyan
b06e077f8d
Add "max" level alias; various level-related warnings (#224)
* Update --help to exclude -a

* Add a deprecation warning to level 4 constructor

* Initialise logger earlier

* Add warning for level > 3 for non-zlib

It's not obvious immediately that these levels don't have any effect on libdeflater and Zopfli, since they don't iterate over zlib-specific fine-tuned options.

Hence, show warning so that user knows they're getting "downgraded" to level 3.

* Add "max" level alias; more level warnings

* Update --help trial numbers for non-zlib

* Fix incorrect trial numbers
2020-04-22 13:34:59 -04:00
Ingvar Stepanyan
fee76ca44f
Remove doc-hidden recursive option (#225)
As the comment mentions, this is used only in CLI interface, so there's no reason for it not to live directly in CLI code.

Ref: #220.
2020-04-20 08:51:18 -04: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
Ingvar Stepanyan
3b754bfa09
Use clap conflict argument checks (#219)
Follow-up to #210.

I haven't noticed / forgotten that clap has own mechanism for conflicts between arguments, and it's probably best to use it instead of custom checks.
2020-04-18 12:20:28 -04:00
Ingvar Stepanyan
a497513d89
Move Zlib-specific options under Zlib compressor (#210)
Make it statically obvious that they're not compatible with other compressors.
2020-04-17 10:05:13 -04:00
Ingvar Stepanyan
e8ff6f7526
Remove unused (outdated?) options (#212)
Co-authored-by: Josh Holmer <jholmer.in@gmail.com>
2020-04-17 05:16:18 -04:00
Ingvar Stepanyan
bb332fa6d7
Don't override global rayon pool (#211)
Rayon uses a singleton global pool.

By default it's set to a regular spawn handler with number of logical CPU cores, but it can be overridden by Rust applications to customize number of threads, spawn handlers, exit handlers and other options.

Such customization should be usually done at the app level, because if a single library initialises the global pool, then Rayon will prevent any further overrides and they will error out. This can cause conflicts between libraries or library and user code and make them impossible to use together.

Hence, I've removed the `threads` option from the `Options` struct and instead moved initialisation to the CLI part of the codebase (main.rs).

Users of the library that didn't depend on custom `threads` number can keep using it as before - they'll still get same number of threads as number of logical CPU cores, while users who need fine-tuning, can do that by customizing rayon pool themselves at the top level of the app.

Note: another alternative to keep the option could've been to use `ThreadPoolBuilder::build` + `ThreadPool::install` to use a local pool just within OxiPNG, but that would ignore any customizations made by users in top-level pool and would prevent usage on targets that require custom spawn handlers like WebAssembly. As such, I've decided to avoid it.

Co-authored-by: Josh Holmer <jholmer.in@gmail.com>
2020-04-17 04:49:40 -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
Josh Holmer
bded03908f Silence cognitive complexity warnings 2020-03-02 01:45:04 -05:00
Josh Holmer
0e3c0b922d Enable more clippy lints and fix some clippy issues 2020-01-19 05:22:14 -05:00
Kamal Ahmad
68db304a2a Don't apply alpha optimizations unless --alpha is paseed (#187)
Closes #164
2019-09-24 11:33:50 -04:00
Josh Holmer
d86bc80f43 Prepare for next release 2019-02-01 17:27:03 -05:00
Josh Holmer
a4e0a34357 Bump version to 2.1.3 2018-09-16 23:21:51 -04:00
Kornel
3c466df80e Chunk name as 4 bytes (#135) 2018-09-16 16:09:55 -04:00
Josh Holmer
f862a0df24 Apply clippy fixes 2018-07-28 16:51:54 -04:00
Josh Holmer
d110949d2a Version 2.0.0 2018-07-20 19:19:20 -04:00
Josh Holmer
2702145f3f Make cfzlib the default on platforms that support it
Raises the minimum Rust version to 1.27.0
2018-07-20 19:03:17 -04:00
Josh Holmer
b235e5601f Remove deprecated clippy plugin, use rustup clippy now 2018-07-20 18:50:27 -04:00
Kornel
c530bba261 --keep option (#121) 2018-07-17 23:55:21 -04:00
Kornel
e1cf3bf54b Display options together, in source order (#120) 2018-07-14 15:28:47 -04:00
Kornel
cb52d8466a Reading from stdin (#118) 2018-07-12 07:54:06 -04:00
Kornel
24735b6ab3 Option to limit wall clock time spent on optimization trials (#115) 2018-07-12 07:40:11 -04:00
Kornel
67fd229f20 CLI args value names (#114) 2018-07-10 18:42:55 -04:00
Kornel
55a095d536 Enum for stdout writing flag (#110) 2018-07-10 18:41:06 -04:00
Kornel
2d303f5dc2 Avoid double glob processing on unix (#111) 2018-07-06 08:11:42 -04:00
magicgoose
5570a24781 allow listing more than 2 filters (#105)
Closes #101
2018-06-06 21:10:20 -04:00
Josh Holmer
3d643b16b2 Adjust spacing in help command 2018-01-31 14:10:03 -05:00
Josh Holmer
d614bba3ac Adjust command line presets to take advantage of the 50% speedup gained by removing memory options 2018-01-31 14:07:03 -05:00
Josh Holmer
fe9cd01b82 Replace miniz_sys with miniz_oxide, a Rust implementation of miniz
This also improves decompression performance by 15%, and obsoletes the
`--zm` parameter.

Closes #57
2018-01-30 23:52:37 -05:00
Josh Holmer
e3ba535a79 Add some changes and fixes around how the output file is handled
See changelog for details
2018-01-10 20:54:15 -05:00
Josh Holmer
88f5bb0931 Hide modules from documentation, and only export structs used in options or return types 2018-01-10 10:37:01 -05:00
Josh Holmer
32e3d245f9 Run latest rustfmt 2017-12-27 17:21:21 -05:00
Josh Holmer
bb6a2513eb Return exit code of 1 if error occurs while processing a file using the CLI
Closes #93
2017-12-27 17:20:12 -05:00
Josh Holmer
9c7fdfd9d1 Fix parsing of glob paths on Windows
Closes #90
2017-11-06 19:01:18 -05:00
Josh Holmer
fa334e0750 Update dependencies 2017-11-06 18:50:10 -05:00
Josh Holmer
0db03c6faf Fix new clippy lints 2017-09-03 23:36:38 -04:00
Josh Holmer
f41ef551d3 Enable option for multiple alpha transformations 2017-07-26 00:37:55 -04:00
Josh Holmer
413f1aac7c Automatically change transparent pixels to black 2017-07-24 08:47:27 -04:00
Josh Holmer
19405cabd6 Fix help text
Closes #70
2017-07-01 10:10:26 -04:00
Josh Holmer
5f4ddbb8f4 Upgrade dependencies 2017-06-14 18:28:07 -04:00
Josh Holmer
ed3b843dd2 Update rayon and itertools dependencies 2017-05-02 19:29:20 -04:00
Josh Holmer
84cf6b09c2 Run rustfmt since it updated to v0.8.0.
I don't really like the new changes, but we might as well follow along.
2017-03-08 11:14:33 -05:00
Josh Holmer
6c8e7d253d Verify images are correct before outputting them, and fix a bug in certain images
Closes #60
2017-03-06 20:16:28 -05:00
Josh Holmer
705d280f8b Fix warning when clippy not enabled 2017-02-19 10:43:46 -05:00
Josh Holmer
ce2d166de2 Allow cyclomatic complexity on parse_opts function, there's no reasonable way to split this up
Closes #26
2017-02-15 13:01:17 -05:00
Joshua Holmer
bf341dd20f Fix clippy warnings 2016-12-01 22:33:38 -05:00
Josh Holmer
6d49d7b8f9 Implement zopfli compression, available as a CLI flag (-Z)
Improves compression by about 10% over DEFLATE, but takes a very long
time at the moment, so it is off by default.
2016-12-01 12:51:30 -05:00
Alice Atlas
7460ffac73 Fix for passing in filenames that contain commas
The versions of clap supported by oxipng default to allowing commas to be used as a delimiter for passing a series of values in a single physical command line argument, when parsing for a parameter that accepts multiple values. This prevents oxipng from accepting filenames containing commas (it splits them into segments separated by commas and treats each one as a separate path to a file to process, generally not finding any); this patch fixes this by disabling the delimiter behavior for the 'files' argument.
2016-09-19 18:13:24 -04:00
Josh Holmer
f654cbeac4 Various minor changes 2016-09-09 21:55:47 -04:00
Josh Holmer
e0dfbf3533 Enable clippy with dev feature, and fix several clippy lints 2016-08-20 20:47:26 -04:00
Josh Holmer
dbc3d97513 Eliminate many clones 2016-08-19 23:42:04 -04:00
Josh Holmer
3166285150 Allow using optimization presets from crate
Closes #43
2016-08-14 11:31:46 -04:00
Josh Holmer
99da13bd8e Version 0.10.0 [ci skip] 2016-07-26 12:59:28 -04:00
Josh Holmer
29557a18e8 Version 0.9.0 2016-07-14 20:00:59 -04:00
Josh Holmer
7f9ad263ec Refactor code into modules 2016-07-14 11:10:10 -04:00
Joshua Holmer
2659776bd5 Fix issue for interlacing images smaller than 4px
Fixes #42
2016-05-25 23:10:44 -04:00
Joshua Holmer
223995b551 Version 0.8.1 [ci skip] 2016-05-13 22:12:27 -04:00
Joshua Holmer
8358f4f72d Version 0.8.0 [ci skip] 2016-05-06 10:00:02 -04:00
Joshua Holmer
193e6496bd Version 0.7.0 2016-05-04 10:41:29 -04:00
Joshua Holmer
3a39b13acf Add option for changing number of threads at runtime
Closes #39
2016-05-04 10:37:45 -04:00
Joshua Holmer
e4cd9b85e7 Move default Options into impl Default in library 2016-05-04 10:09:26 -04:00
Joshua Holmer
b8116dd3dd Version 0.6.0 [ci skip] 2016-05-02 09:40:37 -04:00
Joshua Holmer
fac83c023d Fix issue where output directory would not be created if it did not exist 2016-04-22 13:31:33 -04:00
Joshua Holmer
11308959fa Version 0.5.0 [ci skip] 2016-04-20 15:51:14 -04:00
Joshua Holmer
ea484a8978 Version 0.4.0 2016-04-08 13:52:15 -04:00
Joshua Holmer
c78e3213d6 Update crates and fix interlacing issue 2016-04-08 13:37:00 -04:00
Josh Holmer
e9c44cbc0b Add -s as alias for --strip safe
Fixes #31
2016-04-08 11:56:51 -04:00
Joshua Holmer
548c69cad7 Version 0.3.0 [ci skip] 2016-04-04 20:23:24 -04:00
Joshua Holmer
489964add2 Release v0.2.2 [ci skip] 2016-03-21 12:28:20 -04:00
Joshua Holmer
262bbf003a Release version 0.2.1 [ci skip] 2016-03-10 14:50:35 -05:00
Joshua Holmer
911f51faa9 Version 0.2.0 [ci skip] 2016-03-05 22:55:01 -05:00
Joshua Holmer
b889c73a3b Make --strip option more versatile
Closes #22
2016-03-05 22:36:31 -05:00
Joshua Holmer
7d1e3a5bb9 Print console output to stderr instead of stdout
Makes it friendlier with --stdout option
See #20 for discussion
2016-03-04 16:37:40 -05:00
Joshua Holmer
0ae632c7f4 Revert "Enable quiet when stdout is selected"
This reverts commit 849d36ec6c.
2016-03-04 16:03:33 -05:00
Joshua Holmer
c6452beb12 Select compression and filter modes heuristically for -o1
Closes #21
2016-03-04 15:24:58 -05:00
Joshua Holmer
849d36ec6c Enable quiet when stdout is selected 2016-03-04 14:20:47 -05:00
Joshua Holmer
9a6379ac7e Fix version string from -V 2016-03-04 10:07:43 -05:00
Joshua Holmer
abedfc9c70 Each input file should output to its own file correctly
Fixes #15
2016-03-03 16:30:05 -05:00
Joshua Holmer
3963f8da0a Prefer unreachable over panic where appropriate 2016-03-02 14:16:34 -05:00
Joshua Holmer
fe95e9460e Fix output crcs 2016-01-11 21:22:08 -05:00
Joshua Holmer
ee31774078 Add basic integration tests
Also add force option--necessary for testing but may be useful to some people
who like to live dangerously
2016-01-11 14:16:05 -05:00
Joshua Holmer
12b472e572 Rename project 2016-01-11 11:03:52 -05:00
Joshua Holmer
e24fa4ae27 Run clippy and rustfmt 2016-01-10 15:13:12 -05:00
Joshua Holmer
471d5179d5 Write output files 2016-01-10 15:09:05 -05:00
Joshua Holmer
5f866d9844 Completely parse CLI options 2016-01-08 15:09:00 -05:00
Joshua Holmer
273880ea0b Implement option parsing - Part 1
The compression options help text keeps getting split up by rustfmt.
Don't let it.
2016-01-07 16:29:02 -05:00
Joshua Holmer
052b047222 Get zlib compression to work 2016-01-01 01:00:57 -05:00
Joshua Holmer
9e1cf7881d Use our own libpng 2015-12-18 22:19:05 -05:00
Joshua Holmer
7d3a601686 So as to not lose my work 2015-12-16 08:01:05 -05:00