0

I would like to load image in separate thread if it is possible and to display some stub of image dimensions while image is loading, but finally, I want to display image itself.

Here I found https://stackoverflow.com/a/1560052/258483 how to read dimensions without reading entire image.

Now, what if I want to take this dimensions, then don't want to loose work done and continue with this and achieve BufferedImage finally?

Community
  • 1
  • 1
Dims
  • 47,675
  • 117
  • 331
  • 600
  • 1
    Have you tried `readImage(null)` or `read(0)` on the reader? – Mark Jeronimus Feb 28 '17 at 15:51
  • Yes, but I don't understand the logic. Why should I iterate over readers? What it there are many readers? Is it possible that dimensions are available on one reader while image is available on another? – Dims Mar 01 '17 at 09:24
  • Also I don't unserstand, why should I call ImageReader#setInput although this reader was obtained from that input. Why doesn't it set automatically? – Dims Mar 01 '17 at 09:29
  • 1
    No, readers are just classes that 'claim to be able to decode the file format'. Stick with one. Even in the unlikely case that there are multiple, the main difference would be performance. – Mark Jeronimus Mar 01 '17 at 11:50

1 Answers1

0

Here's one way to implement background reading, and report back dimensions ASAP, and then continue reading the image in the background.

To try to answer the questions from your comments:

  • You don't need to iterate over the readers. The below code doesn't, it simply tests if there's at least one reader that can read the given format, and tries reading using that. You could, if you wanted to, iterate, and try the next reader if the first failed in some way. But the logic for doing so is quite complex, and usually not needed as there's usually zero or one reader only.
  • It could in theory be that one reader could read the dimensions, and fail reading the image. But again, as said above, this isn't the common case. It's usually impossible to read the image data, without knowing its dimensions.
  • ImageReader instances are reusable (but not thread safe, so don't share between threads), and can be used to read many different inputs (in the same format). So this is a performance consideration in the API, I guess. You can also obtain readers based on file name, and in that case you would need to somehow pass the input anyway.

The code should be pretty self-explanatory, if you understand the code in the linked answer.

public class BackgroundImageReader implements Callable<BufferedImage> {

    private final Object input;

    public BackgroundImageReader(File input) {
        this.input = input;
    }

    public BackgroundImageReader(InputStream input) {
        this.input = input;
    }

    @Override
    public BufferedImage call() throws IOException {
        try (ImageInputStream stream = ImageIO.createImageInputStream(input)) {
            Iterator<ImageReader> readers = ImageIO.getImageReaders(stream);

            if (readers.hasNext()) {
                ImageReader reader = readers.next();

                try {
                    reader.setInput(stream);

                    updateImageDimensions(new Dimension(reader.getWidth(0), reader.getHeight(0)));

                    return reader.read(0);
                } finally {
                    reader.dispose();
                }
            }
            throw new IOException("Could not read image");
        }
    }

    public void updateImageDimensions(Dimension dimension) {
        // TODO: Implement callback mechanism
    }
}
Harald K
  • 26,314
  • 7
  • 65
  • 111