Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java Wrapper #27

Open
manticore-projects opened this issue Nov 15, 2023 · 12 comments
Open

Java Wrapper #27

manticore-projects opened this issue Nov 15, 2023 · 12 comments

Comments

@manticore-projects
Copy link

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
Copy link
Owner

veluca93 commented Nov 15, 2023 via email

@manticore-projects
Copy link
Author

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
Copy link
Owner

veluca93 commented Nov 15, 2023 via email

@manticore-projects
Copy link
Author

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
Copy link
Author

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
Copy link
Author

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
Copy link
Author

manticore-projects commented Nov 24, 2023

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
Copy link
Owner

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

@manticore-projects
Copy link
Author

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
Copy link
Author

manticore-projects commented Nov 24, 2023

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
Copy link
Contributor

animetosho commented Nov 29, 2023

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
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants