Traneptora / jxlatte

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

toBufferedImage seems to be defective(?) #22

Closed elbosso closed 1 year ago

elbosso commented 1 year ago
package de.elbosso.scratch.misc;

import com.thebombzen.jxlatte.JXLDecoder;
import com.thebombzen.jxlatte.JXLImage;
import com.thebombzen.jxlatte.io.PNGWriter;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class JpegXlTest
{
    public static void main(java.lang.String[] args) throws IOException
    {
        InputStream input = new java.io.FileInputStream("/home/elbosso/src/language_java/jxlatte/samples/ants.jxl");
        OutputStream output = new java.io.FileOutputStream("/tmp/ants.png");
        JXLDecoder decoder = new JXLDecoder(input);
        JXLImage image = decoder.decode();
        java.awt.image.BufferedImage bimg=image.asBufferedImage();
        System.out.println(bimg.getWidth()+" "+bimg.getHeight());
        java.io.File f=new java.io.File("/tmp/ants.png");
        javax.imageio.ImageIO.write(bimg,"png",f);
        System.out.println(f.length());
   }
}

gives 0 as the file length (the image dimensions however are output as 3264 and 2448 respectively) while

package de.elbosso.scratch.misc;

import com.thebombzen.jxlatte.JXLDecoder;
import com.thebombzen.jxlatte.JXLImage;
import com.thebombzen.jxlatte.io.PNGWriter;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class JpegXlTest
{
    public static void main(java.lang.String[] args) throws IOException
    {
        InputStream input = new java.io.FileInputStream("/home/elbosso/src/language_java/jxlatte/samples/ants.jxl");
        java.io.File f=new java.io.File("/tmp/ants.png");
        OutputStream output = new java.io.FileOutputStream(f);
        JXLDecoder decoder = new JXLDecoder(input);
        JXLImage image = decoder.decode();
        PNGWriter writer = new PNGWriter(image);
        writer.write(output);
        System.out.println(f.length());
    }
}

gives 18780871 (as should be)...

elbosso commented 1 year ago

The interesting thing is, though: Swing can use the BufferedImage - this:

        java.awt.image.BufferedImage bimg=image.asBufferedImage();
javax.swing.ImageIcon icon=new javax.swing.ImageIcon(bimg);
javax.swing.JLabel l=new javax.swing.JLabel("label");
l.setIcon(icon);
javax.swing.JOptionPane.showMessageDialog(null,l);

displays the image just fine...

elbosso commented 1 year ago

However, when I convert the BufferedImage to the format of my own imageprocessing library and then convert it back to a BufferedImage - everything works and i can save the png. I suspect, that we just found an error in Java - specifically in ImageIO: it seems that it can not cope with instances of java.awt.image.DataBufferFloat (my image processing library also could not until i happened upon for the first time in the BufferedImage instances your library creates). Interestingly enough - that seems to be a problem with ImageIO rather than its PNG encoder as the same problem exists trying to save the image as a jpeg with ImageIO

elbosso commented 1 year ago

I set up a branch containing a few junit tests for demonstrating the bug and will be issuing a bug report to Java concerning this. The branch is at https://github.com/elbosso/jxlatte/tree/bug_java_imageio_databufferfloat

elbosso commented 1 year ago

bug is reported - waiting for feedback: https://bugs.java.com/bugdatabase/view_bug?bug_id=9075375

Traneptora commented 1 year ago

This is because the BufferedImage returned by JXLDecoder.asBufferedImage() has TYPE_FLOAT which doesn't work with the default ImageIO implementation of PNG. To use ImageIO's PNG output, you need to create a compatible buffered image (e.g. via new BufferedImage(w, h, TYPE_3BYTE_BGR) and then draw the returned buffered image onto it, and feed that to ImageIO. This is a limitation of ImageIO.

elbosso commented 1 year ago

so that is a feature of imageio rather than a bug ? i did not know that...