Search code examples
javaimagejarsizebufferedimage

Image size returns -1 in JAR but proper size in IDE. Image loaded via Toolkit....createImage(url)


Intention: Get BufferedImage from resource (be it in IDE or running JAR).

Problem: Getting an Image always works, converting to BufferedImage requires knowledge of size, but size always returns -1, even after waiting with MediaTracker. In IDE, size after MediaTracker is proper, before it is -1. Waiting with while-loop until size >-1 seems to never end in running JAR. (Tried with code language level 6 and 8 using JDK/JRE 8.)

Output of SSCCE in IDE:

IMAGE: sun.awt.image.ToolkitImage@15975490

WIDTH: -1

DURATION: 38 ms

WIDTH: 32

BUFFEREDIMAGE: BufferedImage@6adede5: type = 1 DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0 IntegerInterleavedRaster: width = 32 height = 32 #Bands = 3 xOff = 0 yOff = 0 dataOffset[0] 0

EDIT: MediaTracker's "isErrorAny()" returns false.

Output of SSCCE in running JAR:

IMAGE: sun.awt.image.ToolkitImage@2a84aee7

WIDTH: -1

DURATION: 23 ms

WIDTH: -1

Exception in thread "main" java.lang.IllegalArgumentException: Width (-1) and height (-1) cannot be <= 0 at java.awt.image.DirectColorModel.createCompatibleWritableRaster(Unknown Source) at java.awt.image.BufferedImage.(Unknown Source) at ImageSizeProblem.createBufferedImageFromImage(ImageSizeProblem.java:82) at ImageSizeProblem.main(ImageSizeProblem.java:26)

EDIT: MediaTracker's "isErrorAny()" returns true. But I have no way of finding out what the error is - also, the image does load properly, since it can be successfully used in an JToolBar via making an ImageIcon from it. (I already tried abusing ImageIcon's getIconWidth() or getImage() methods - they bring no improvement at all.)

SSCCE:

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.net.URL;

public class ImageSizeProblem {

    public static void main(final String[] args) {

        final Image img = createImageFromResource("test.png");

        System.out.println("IMAGE: " + img);
        System.out.println("WIDTH: " + img.getWidth(null));

        final long startTime = System.currentTimeMillis();
        waitForImage(img);
        final long duration = System.currentTimeMillis() - startTime;
        System.out.println("\nDURATION: " + duration + " ms");

        System.out.println("\nWIDTH: " + img.getWidth(null));

        final BufferedImage buffImg = createBufferedImageFromImage(img, false);
        System.out.println("\nBUFFEREDIMAGE: " + buffImg);

        System.exit(0);
    }

    private static Image createImageFromResource(final String resourceFileName_dontForgetToAddItsFolderToClasspath) {

        final Toolkit kit = Toolkit.getDefaultToolkit();
        final URL url = ClassLoader.getSystemResource(resourceFileName_dontForgetToAddItsFolderToClasspath);
        if (url != null) {
            final Image img = kit.createImage(url);
            if (img == null) {
                System.err.println("Image resource could not be loaded.");
                return null;
            }
            return img;
        } else {
            System.err.println("Image resource not found.");
            return null;
        }
    }

    private static boolean waitForImage(final Image img) {
        final MediaTracker mediaTracker = new MediaTracker(new JPanel());
        mediaTracker.addImage(img, 1);
        try {
            mediaTracker.waitForID(1);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        return !mediaTracker.isErrorAny();
    }


    // improved version of http://stackoverflow.com/a/13605411/3500521
    private static BufferedImage createBufferedImageFromImage(final Image img, final boolean withTransparency) {

        if (img instanceof BufferedImage) {
            return (BufferedImage) img;
        } else if (img == null) {
            return null;
        }

        final int w = img.getWidth(null);
        final int h = img.getWidth(null);

        final BufferedImage bufferedImage;
        if (withTransparency) {
            bufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
        } else {
            bufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        }

        final Graphics2D g = bufferedImage.createGraphics();
        g.drawImage(img, 0, 0, null);
        g.dispose();
        return bufferedImage;
    }
}

Note that the image used for testing was loaded and used successfully in another application via new ImageIcon(image) in a JToolBar. Getting the size from the ImageIcon also returns -1, also from the image returned by ImageIcon.getImage().


Solution

  • The problem was path depth.

    I also tried Avira, because the problem is technically a program accessing its own file, which could well seem suspicious, but while Avira was uninstalling, I tried the executables in a different location with a shorter path, and everything worked like a charm.