Forseth11
Forseth11

Reputation: 1438

Why does this method sometimes give me an error if I call it more than once

I have a method which I am making to save an image and show its progress while saving. Overall the method seems to work, but if I call it more than once it sometimes gives me a IllegalArgumentException error.

This is the stack trace:

java.lang.IllegalArgumentException: input == null!
    at javax.imageio.ImageIO.getImageReaders(ImageIO.java:641)
    at com.forseth11.ColorEncoder.Encoder.saveImage(Encoder.java:308)
    at com.forseth11.ColorEncoder.Encoder.encode(Encoder.java:82)
    at com.forseth11.ColorEncoder.Encoder$3.run(Encoder.java:376)
    at java.lang.Thread.run(Thread.java:745)

I don't know why I get this error or how to fix it. I need to be able to call this method multiple times to save multiple images in a row.

Here is the method:

private void saveImage(final BufferedImage image, final String string, final File outputfile) throws IOException, InterruptedException {
        Thread thread = new Thread(new Runnable(){

            public void run() {
                try {
                    ImageIO.write(image, string, outputfile);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        });
        thread.start();

        try {
            ImageInputStream iis = ImageIO.createImageInputStream(outputfile);
            Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);
            if (readers.hasNext()) {
                ImageReader reader = readers.next();
                reader.setInput(iis);
                try {
                    BufferedImage img = reader.read(0);

                    ByteArrayOutputStream baos = new ByteArrayOutputStream();//This is the line the error is pointing to.
                    try {
                        ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
                        Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("png");
                        if (writers.hasNext()) {
                            ImageWriter writer = writers.next();
                            writer.addIIOWriteProgressListener(new IIOWriteProgressListener() {
                                public void imageStarted(ImageWriter source, int imageIndex) {
                                }

                                public void imageProgress(ImageWriter source, float percentageDone) {
                                    System.out.println("UPDATE: " + percentageDone);//TODO
                                }

                                public void imageComplete(ImageWriter source) {
                                }

                                public void thumbnailStarted(ImageWriter source, int imageIndex, int thumbnailIndex) {
                                }

                                public void thumbnailProgress(ImageWriter source, float percentageDone) {
                                }

                                public void thumbnailComplete(ImageWriter source) {
                                }

                                public void writeAborted(ImageWriter source) {
                                }
                            });

                            writer.setOutput(ios);
                            try {
                                writer.write(img);
                            } finally {
                                writer.removeAllIIOWriteProgressListeners();
                            }
                        }
                    } finally {
                        reader.removeAllIIOReadProgressListeners();
                    }
                } finally {
                    reader.removeAllIIOReadProgressListeners();
                }
            }
        } catch (IOException exp) {
            exp.printStackTrace();
        }

        thread.join();//I added this so it will not leave the method until the image is saved.
    }

I got the code for getting the percentage the image is saved from here. I modified it a bit.

How can I make this method to save an image and print its percentage saved without getting an error? Also why does it not always give me an error when I call the method two times in a row?

Upvotes: 0

Views: 416

Answers (3)

Forseth11
Forseth11

Reputation: 1438

It turns out that I did not understand the code I was using. Apparently it was trying to read a file when I only wanted to write to own.

Here is my new method which seems to work in case anyone has a similar problem:

private void saveImage(final BufferedImage image, final String string, final File outputfile) throws IOException, InterruptedException {
        Thread thread = new Thread(new Runnable(){

            public void run() {
                try {
                    ImageIO.write(image, string, outputfile);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        });
        thread.start();

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
            Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(string);
            if (writers.hasNext()) {
                ImageWriter writer = writers.next();
                writer.addIIOWriteProgressListener(new IIOWriteProgressListener() {
                    public void imageStarted(ImageWriter source, int imageIndex) {
                    }

                    public void imageProgress(ImageWriter source, float percentageDone) {
                        System.out.println("UPDATE: " + percentageDone);//TODO
                    }

                    public void imageComplete(ImageWriter source) {
                    }

                    public void thumbnailStarted(ImageWriter source, int imageIndex, int thumbnailIndex) {
                    }

                    public void thumbnailProgress(ImageWriter source, float percentageDone) {
                    }

                    public void thumbnailComplete(ImageWriter source) {
                    }

                    public void writeAborted(ImageWriter source) {
                    }
                });

                writer.setOutput(ios);
                try {
                    writer.write(image);
                } finally {
                    writer.removeAllIIOWriteProgressListeners();
                }
            }

        thread.join();
    }

Upvotes: 0

jatal
jatal

Reputation: 840

The error is a result of these lines, per the stack trace, so your:

        ImageInputStream iis = ImageIO.createImageInputStream(outputfile);
        Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);

I googled for the ImageIO source code and found it here: ImageIO source on GrepCode

The source code snippet throwing the exception is:

     public static Iterator<ImageReader> More ...getImageReaders(Object input) {
640         if (input == null) {
641             throw new IllegalArgumentException("input == null!");
642         }
643         Iterator iter;
644         // Ensure category is present
645         try {
646             iter = theRegistry.getServiceProviders(ImageReaderSpi.class,
647                                               new CanDecodeInputFilter(input),
648                                               true);
649         } catch (IllegalArgumentException e) {
650             return Collections.emptyIterator();
651         }
652 
653         return new ImageReaderIterator(iter);
654     }

There are multiple cases from the "ImageIO.createImageInputStream(outputfile)" method call that can cause issues, based on looking at the source: Either the call to the registry for service providers is throwing an exception, or the returned service providers iterator has no members. In both cases, you get null return.

I would suggest downloading the jar code local and setting a conditional breakpoint in this source so you can see exactly which case is happening.

Hope that helps get to the source of the issue.

Upvotes: 0

Ahmet Karakaya
Ahmet Karakaya

Reputation: 10147

do not use following thread

Thread thread = new Thread(new Runnable(){
    public void run() {
        try {
            ImageIO.write(image, string, outputfile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
});
thread.start();

Since when outputfile is not ready you continue with following code

ImageInputStream iis = ImageIO.createImageInputStream(outputfile);
Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);

Upvotes: 2

Related Questions