Commit graph

66 commits

Author SHA1 Message Date
Andrew
268499b0db Allow passing a format description to the evaluator 2024-04-13 08:12:16 +12:00
andrews05
2d3555fe0f
Add modified zeng palette sorting method (#602)
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).
2024-04-06 01:16:29 +02:00
Andrew
fca76a7afb Always run palette reduction even if there's only one entry 2024-03-29 09:15:27 +13:00
Andrew
1ddab42edb Always fix palette even if it would be larger 2024-03-29 09:15:27 +13:00
Kornel
a3590df20c Optimize co-occurence matrix 2024-03-29 09:07:24 +13:00
Kornel
36de54318d Faster, garbage-resilient most_popular_edge_color 2024-03-29 09:07:24 +13:00
Andrew
3e3c027cd0 Skip extra evaluation when identical 2024-03-11 17:38:48 +13:00
Andrew
703ebb4813 Try both gray and indexed low depths 2024-03-11 17:38:48 +13:00
Andrew
a426fabe13 Fix secondary palette sort
This was only working if the input image was already indexed
2024-02-21 08:13:03 +13: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
Andrew
6763eea1e3 Combine palette reduction and sorting 2023-10-10 11:03:08 +13: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
b846a2e909
Try to pick tRNS value that's valid at low depth (#520) 2023-07-07 20:56:15 -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
c71fd44454 Prevent conversion from grayscale when disabled 2023-06-18 01:02:11 -04:00
Andrew
86fccf082a Fix grayscale_reduction option 2023-05-28 16:11:41 -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
2f622fc7bd
Minor reduction improvements (#502)
* Fix bKGD conversion from gray to palette

* Allow grayscale reduction from 16 to 4 or less

* Refactor reduction evaluation sequence

* Separate palette into new file
2023-05-07 17:46:58 -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
Josh Holmer
a234c39e41 Fix new annoyingly pedantic clippy warnings 2023-04-22 22:25:59 -04:00
Andrew
a874fe9cb7 Remove incorrect comment 2023-01-06 15:35:05 -05:00
andrews05
a3b104a2ed
Faster reductions (#479)
* Add grayscale depth tests and benches

* Don't include filter byte in PngImage.data

* Simplify reductions by not using scan lines

* Faster grayscale reduction

* Simplify reduce_color_type

* Faster depth reduction
2022-12-22 16:56:36 -05:00
andrews05
2008d09915
Reduce alpha to tRNS (#477) 2022-12-13 15:18:19 -05:00
andrews05
131a3c6af7
🚀 Revamp alpha optimisation (#475) 2022-12-10 21:14:50 -05:00
andrews05
54ee621e41
Fix Grayscale depth reduction with tRNS (#470) 2022-12-08 06:11:26 -05:00
andrews05
bd5a0b526b
More Reductions (#468)
* Add test for issue 195

* Reduce grayscale alpha to palette

* Black alpha before color type reductions
2022-12-07 13:22:13 -05:00
andrews05
3365aca12f
Palette reduction fixes (#466)
* Verify bKGD in tests

* Don't truncate bKGD on output

* Make sure correct bKGD is retained

* Update safe chunk list

* Perform strip first

* Check entire palette map
2022-12-07 07:49:52 -05:00
andrews05
6022fc2aa1
Refactor use_heuristics for fast filter evaluation (#463) 2022-12-02 05:34:38 -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
420d904ba9
Strengthen alpha reductions (#460)
* Improve up and left alpha reductions

* Disable alpha down and right by default

* Improve performance of up
2022-11-01 19:13:24 -04:00
andrews05
a02d4ff0dd
Fix directional alpha reductions (#458)
* Fix alpha up and down

* Fix alpha left and right
2022-10-28 19:41:44 -04:00
Josh Holmer
17f5cc36ca Fix clippy lints 2022-07-05 10:05:06 -04:00
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
Rémi Lauzier
91a18ebe97 Fix some clippy warnings 2021-06-24 15:57:41 -04:00
Kornel
d2cebc3c2d Don't allocate reduced buffer until needed 2021-06-16 17:37:33 -04:00
Kornel
14867c7abc
Clippy lints (#401) 2021-05-19 10:04:31 -04:00
Kornel
3163a92594 Ignore broken tRNS 2021-01-20 14:33:27 -05:00
Kornel
17212477c5 Avoid asserts panicking on broken files 2021-01-20 14:33:27 -05:00
Josh Holmer
9b5cd9a1a4 Fix a new clippy lint 2021-01-04 16:12:46 -05:00
Josh Holmer
0d9c23f4ce Fix new clippy lints from Rust 1.47 2020-10-09 20:20:52 -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
Kornel
681089f8c7
Remove the concept of size bias (#199)
Closes #198
2020-03-31 19:28:22 -04:00
Josh Holmer
0e3c0b922d Enable more clippy lints and fix some clippy issues 2020-01-19 05:22:14 -05:00
Josh Holmer
139d29cc9b Version 2.3.0 2019-10-07 23:34:23 -04:00
Kornel
e473958377 Palette sorting (#193)
* Implement alpha and luminosity palette sorting

* Also sort when reducing to palette

* Bump Rust version

* Color comparison
2019-09-10 18:13:05 -04:00
Daniel Wong
4cb26d462e Allow disabling all alpha optimizations (#181)
Fixes a bug where oxipng would crash if alpha optimizations were all disabled.
2019-07-23 14:21:46 -04:00
Kamal Ahmad
34ee78dbbc Preallocate memory in reduced_alpha_to_up (#180) 2019-06-27 13:44:49 -04:00