Traneptora / jxlatte

Java JPEG XL decoder
MIT License
44 stars 5 forks source link

great stuff - how about turning it into a ImageIO CoDec? #20

Open elbosso opened 1 year ago

elbosso commented 1 year ago

The Reason for this would be that then any Java app loading an image resource could use JPEG XLs without changing its code - the only thing needed would be to put one more jar into the classpath...

I would be willing to participate in the effort as i wrote a few ImageIO codecs already - though not as complex ones as would be needed here...

One could maybe get inspiration for example from here: https://xmlgraphics.apache.org/batik/javadoc/org/apache/batik/ext/awt/image/codec/imageio/ImageIOJPEGImageWriter.html

Traneptora commented 1 year ago

It's on the list of things to do.

Also the file you linked is a writer, not a reader.

elbosso commented 1 year ago

yep, I know. But maybe this could be a far away stretch goal. I assume, that one would also find a reader somewhere in there...

elbosso commented 1 year ago

ok - a crude example implementation is done as a prototype. I can use my branch to load JPEG XL using ImageIO - however, there remains the issue that the BufferedImages created by this library seem to be incompatible with ImageIO image saving routines (compare #22)

haraldk commented 2 weeks ago

Hi,

I'm considering implementing an ImageIO plugin (ImageReader only for now) based on this project. Either by forking, or using this project as a library dependency.

I see issue #22 refers to a method JXImage.asBufferedImage or toBufferedImage, however I don't find these in the current code base..? Was this method removed, or was it only available in a special branch?


Update: I found the code in @elbosso's branch, and was able to adapt it to the current main branch + convert the images to more compatible BufferedImage types. I'm not super-familiar with JPEG XL, so I might be missing why the library uses 32 bit float or integer components for what is normally 8-16 bits...?

Traneptora commented 1 week ago

I removed all the BufferedImage and WritableRaster code because java.awt isn't available on android. Currently JXLImage produces an array of ImageBuffer which can be then turned into a BufferedImage by using a WritableRaster and a BandedSampleModel. ImageBuffer represents one channel and is backed by an int[][] or a float[][].

haraldk commented 1 week ago

@Traneptora Thanks! After looking some more at the code and testing with various sample images, I can only say, this is seriously impressive stuff! 🤩

I completely understand why you want to keep any AWT dependencies out of the project, keeping it like this makes things more flexible. 👍🏻

I've made an adapter class that can convert to BufferedImages in more "standard" types (8 or 16 bit/sample, pixel interleaved), depending on the bit count in the header. This should allow me to create an ImageIO plugin that creates images that can be easily displayed or converted to other formats.

I have loads of questions though, but I might open another issue for that. 😀

Traneptora commented 1 week ago

It's recommended to not use ImageIO.write() to output PNG files because it notably doesn't write any color information to the PNG file (this is why I rolled my own primitive png writer). Also be aware that some JXL files are HDR and thus jxlatte decodes them to an HDR image. If you need images in a particular color space you may want to call JXLImage.transform first.

elbosso commented 1 week ago

Hi,

I'm considering implementing an ImageIO plugin (ImageReader only for now) based on this project. Either by forking, or using this project as a library dependency.

I see issue #22 refers to a method JXImage.asBufferedImage or toBufferedImage, however I don't find these in the current code base..? Was this method removed, or was it only available in a special branch?

Update: I found the code in @elbosso's branch, and was able to adapt it to the current main branch + convert the images to more compatible BufferedImage types. I'm not super-familiar with JPEG XL, so I might be missing why the library uses 32 bit float or integer components for what is normally 8-16 bits...?

I am glad I could be of some (little) help and looking forward to the final result!

haraldk commented 1 week ago

It's recommended to not use ImageIO.write() to output PNG files because it notably doesn't write any color information to the PNG file (this is why I rolled my own primitive png writer).

I'm not sure if I understand what you mean? Do you mean that it would not write PNG files from the toBufferedImage method in the old branch? In that case, I have fixed this issue. Or do you mean it does not correctly preserve color information, like ICC profiles or HDR?

If you need images in a particular color space you may want to call JXLImage.transform first.

Excellent, that is actually what I needed! I had some issue with the images coming out way too "warn". Now, after doing the same transform as you do in your PNGWriter the images look just the same (I haven't compared pixel values directly, but they look equal).

samples/bbb.jxl transcoded to PNG using JXLatte PNGWriter:

bbb

samples/bbb.jxl transcoded to PNG using my preliminary code and ImageIO.write (ie. the built in PNGImageWriter):

bbb jxl_tm

PS: Is there any way to access the header information of the file, without having to read the entire file? I will need this for an efficient ImageIO plugin (ie. width, height, number of channels, ICC profile if any and other meta data). If not I will try to create a PR with such a method... 😀

Traneptora commented 1 week ago

Currently there is not. It is something I could do, but I haven't added it yet.