veluca93 / fpnge

Demo of a fast PNG encoder.
Apache License 2.0
81 stars 8 forks source link

Java Wrapper #27

Open manticore-projects opened 10 months ago

manticore-projects commented 10 months ago

Greetings!

Thank you and compliments for this great library. I wrapped it into a Java Library pursuing for the fastest PNG Encoder. Please see https://github.com/manticore-projects/fpng-java

As it looks by now, FPNGE is the winner by size and also performance:

Benchmark                                           (imageName)  Mode  Cnt     Score    Error  Units
FPNGEBenchmark.encode                               example.png  avgt    3     5.895 ±  0.369  ms/op
FPNGEBenchmark.encode                   looklet-look-scale6.png  avgt    3   242.326 ±  3.215  ms/op
FPNGEncoderBenchmark.encode                         example.png  avgt    3     7.267 ±  4.725  ms/op
FPNGEncoderBenchmark.encode             looklet-look-scale6.png  avgt    3   353.969 ± 14.833  ms/op
ImageIOEncoderBenchmark.encode                      example.png  avgt    3    54.096 ±  0.742  ms/op
ImageIOEncoderBenchmark.encode          looklet-look-scale6.png  avgt    3  1285.791 ± 14.237  ms/op
ObjectPlanetPNGEncoderBenchmark.encode              example.png  avgt    3    25.882 ±  0.670  ms/op
ObjectPlanetPNGEncoderBenchmark.encode  looklet-look-scale6.png  avgt    3   639.232 ± 23.186  ms/op
PNGEncoderBenchmark.encode                          example.png  avgt    3    29.218 ±  0.965  ms/op
PNGEncoderBenchmark.encode              looklet-look-scale6.png  avgt    3   573.997 ± 16.234  ms/op
PNGEncoderBenchmark.encodeFastest                   example.png  avgt    3    17.628 ±  0.511  ms/op
PNGEncoderBenchmark.encodeFastest       looklet-look-scale6.png  avgt    3   362.208 ±  4.346  ms/op

Although I still need to improve those Benchmarks so they compare based on similar achieved file-sizes and also need to reflect different JDKs.

veluca93 commented 10 months ago

Thanks for doing this comparison! Please keep me posted as you have more benchmarks :)

On Wed, 15 Nov 2023 at 07:58, manticore-projects @.***> wrote:

Greetings!

Thank you and compliments for this great library. I wrapped it into a Java Library pursuing for the fastest PNG Encoder. Please see https://github.com/manticore-projects/fpng-java

As it looks by now, FPNGE is the winner by size and also performance:

Benchmark (imageName) Mode Cnt Score Error Units FPNGEBenchmark.encode example.png avgt 3 5.895 ± 0.369 ms/op FPNGEBenchmark.encode looklet-look-scale6.png avgt 3 242.326 ± 3.215 ms/op FPNGEncoderBenchmark.encode example.png avgt 3 7.267 ± 4.725 ms/op FPNGEncoderBenchmark.encode looklet-look-scale6.png avgt 3 353.969 ± 14.833 ms/op ImageIOEncoderBenchmark.encode example.png avgt 3 54.096 ± 0.742 ms/op ImageIOEncoderBenchmark.encode looklet-look-scale6.png avgt 3 1285.791 ± 14.237 ms/op ObjectPlanetPNGEncoderBenchmark.encode example.png avgt 3 25.882 ± 0.670 ms/op ObjectPlanetPNGEncoderBenchmark.encode looklet-look-scale6.png avgt 3 639.232 ± 23.186 ms/op PNGEncoderBenchmark.encode example.png avgt 3 29.218 ± 0.965 ms/op PNGEncoderBenchmark.encode looklet-look-scale6.png avgt 3 573.997 ± 16.234 ms/op PNGEncoderBenchmark.encodeFastest example.png avgt 3 17.628 ± 0.511 ms/op PNGEncoderBenchmark.encodeFastest looklet-look-scale6.png avgt 3 362.208 ± 4.346 ms/op

Although I still need to improve those Benchmarks so they compare based on similar achieved file-sizes and also need to reflect different JDKs.

— Reply to this email directly, view it on GitHub https://github.com/veluca93/fpnge/issues/27, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAOPAIZ755CKC6ZPGPRF6OLYERRZZAVCNFSM6AAAAAA7L75NTCVHI2DSMVQWIX3LMV43ASLTON2WKOZRHE4TIMJWGQ3TAMA . You are receiving this because you are subscribed to this thread.Message ID: @.***>

manticore-projects commented 10 months ago

I am glad that you like it.

One thing: The pure Java PNG Encoder (last entry in the list) supports a "Parallel/Multi-Core" mode which is blazing fast, especially for large pictures.

For obvious reasons, it outperforms even FPNGE (when many free cores/threads are available):

PNGEncoderBenchmark.encode                          example.png  avgt    3     5.587 ±   0.882  ms/op
PNGEncoderBenchmark.encode              looklet-look-scale6.png  avgt    3    92.921 ±  11.868  ms/op
PNGEncoderBenchmark.encodeFastest                   example.png  avgt    3     3.694 ±   0.868  ms/op
PNGEncoderBenchmark.encodeFastest       looklet-look-scale6.png  avgt    3    90.635 ±  21.768  ms/op

Is there a chance to add a multi threaded mode to FPNGE?

veluca93 commented 10 months ago

It is certainly possible (for example, by splitting the image in multiple stripes and encoding each stripe separately), although I am not sure I will have time to dedicate to this in the near future...

On Wed, 15 Nov 2023 at 10:45, manticore-projects @.***> wrote:

I am glad that you like it.

One thing: The pure Java PNG Encoder https://github.com/pngencoder/pngencoder (last entry in the list) supports a "Parallel/Multi-Core" mode which is blazing fast, especially for large pictures.

For obvious reasons, it outperforms even FPNGE (when many free cores/threads are available):

PNGEncoderBenchmark.encode example.png avgt 3 5.587 ± 0.882 ms/op PNGEncoderBenchmark.encode looklet-look-scale6.png avgt 3 92.921 ± 11.868 ms/op PNGEncoderBenchmark.encodeFastest example.png avgt 3 3.694 ± 0.868 ms/op PNGEncoderBenchmark.encodeFastest looklet-look-scale6.png avgt 3 90.635 ± 21.768 ms/op

Is there a chance to add a multi threaded mode to FPNGE?

— Reply to this email directly, view it on GitHub https://github.com/veluca93/fpnge/issues/27#issuecomment-1812119202, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAOPAI6QD35FSBOV7QEZAXTYESFNJAVCNFSM6AAAAAA7L75NTCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQMJSGEYTSMRQGI . You are receiving this because you commented.Message ID: @.***>

manticore-projects commented 10 months ago

No problem at all. My usecase is specifically on "many smaller PNGs" (like a kind of screen recording), so I don't need the multi-threaded mode.

I just wanted to point out, that FPNGE is not under all circumstances the fastest.

manticore-projects commented 10 months ago

I have replaced the slow/bad/expensive Java 4Byte ABGR to RGBA translation with SSE bit shuffling calls. (AVX was slower, likely due to the 32 bit alignment requirement).

Now, FPNGE Java is undisputed, encoding a 28MB Image withing 182 ms is just awesome.

GRAALVM 11
Benchmark                                           (imageName)  Mode  Cnt     Score     Error  Units
FPNGEBenchmark.encode                               example.png  avgt    3     2.731 ±   0.018  ms/op
FPNGEBenchmark.encode                   looklet-look-scale6.png  avgt    3   182.363 ± 159.723  ms/op
FPNGEncoderBenchmark.encode                         example.png  avgt    3     6.491 ±   0.526  ms/op
FPNGEncoderBenchmark.encode             looklet-look-scale6.png  avgt    3   313.017 ±  71.408  ms/op
ImageIOEncoderBenchmark.encode                      example.png  avgt    3    47.353 ±   3.971  ms/op
ImageIOEncoderBenchmark.encode          looklet-look-scale6.png  avgt    3  1199.796 ±  47.642  ms/op
ObjectPlanetPNGEncoderBenchmark.encode              example.png  avgt    3    28.079 ±   0.101  ms/op
ObjectPlanetPNGEncoderBenchmark.encode  looklet-look-scale6.png  avgt    3   660.480 ±  79.759  ms/op
PNGEncoderBenchmark.encode                          example.png  avgt    3    29.172 ±   0.288  ms/op
PNGEncoderBenchmark.encode              looklet-look-scale6.png  avgt    3   574.485 ±  16.903  ms/op
PNGEncoderBenchmark.encodeFastest                   example.png  avgt    3    17.516 ±   0.135  ms/op
PNGEncoderBenchmark.encodeFastest       looklet-look-scale6.png  avgt    3   360.417 ±   8.995  ms/op
manticore-projects commented 10 months ago

Greetings! We have just released FPNG-JAVA stable version 1.1.0 with binaries for Windows, Linux and MacOS.

I had to add some Macros for getting the Windows DLL work.

Please try it and let us know about your benchmarks. Thank you a lot and cheers!

manticore-projects commented 10 months ago

Question please:

For "small" size PNGs, the FPNGe encoded size is very competitive, especially when considering the huge performance gain. Of course, with the other encoders even smaller encodings are possible, but that would come with much worse performance.

However, for large size PNGs, there seem to be a material penalty in encoded size. Almost 70% larger than ImageIO. Is that expected an explainable by design? If so, what is the expected "sweet spot" where compression rates fall off? What is the reason that compression gets worse for the large image?

image

For this benchmark, Compression Level = 5 has been set.

veluca93 commented 10 months ago

That depends a lot on the specific image, could I see what images you are compressing here?

manticore-projects commented 10 months ago

That depends a lot on the specific image, could I see what images you are compressing here?

Yes, of course, Its all in the Repo, sub project benchmark: https://github.com/manticore-projects/fpng-java/tree/main/benchmark/src/test/resources If Java is not too much of a burden for you, you can just run the benchmarks, its all included and "./gradlew jmh" should work out of the box.

manticore-projects commented 10 months ago

What I find most weird is Standard Java ImageIO. It does not provide any switches, just encode and that's it. So how come that it score so well by size on the large picture, although it does not well in terms of size on the small picture.

I feel like compression is not working for FPNG/FPNGe on the large picture and I wonder why.

animetosho commented 9 months ago

So how come that it score so well by size on the large picture, although it does not well in terms of size on the small picture

I don't think a sample size of one is enough to justify that conclusion.

Perhaps LZ77 is more effective on your larger image (fpnge only does RLE, and in limited cases; I see a lot of the same colour in that image, so maybe fpnge's RLE isn't triggered optimally). fpnge takes some shortcuts compared to traditional PNG encoders to achieve its speed, which means that the compression loss can vary depending on how well the image suits the model fpnge takes.

manticore-projects commented 9 months ago

Thank you for this explanation. Fair point raised, I will need to add more tests.