Hi, I've been trying to send a BufferedImage through a socket.
I can get it to work once, but when I try to get another screenshot, it fails.
The server usually gives me a java.lang.IndexOutOfBoundsException at ImageIO.write(capture, "png", client.getOutputStream());
Server Code:

//already told server i'm expecting an image
try {
                        Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
                        BufferedImage capture = new Robot().createScreenCapture(screenRect);
                        client.getOutputStream().flush();
                        ImageIO.write(capture, "png", client.getOutputStream());
                        client.getOutputStream().flush();
                    } catch (Exception e) {
                        out.println("Error getting screenshot");
                        log(e, "Error getting screenshot");
                    }

Client Code:

public void screenshot() {
    try {
                BufferedImage image = ImageIO.read(socket.getInputStream());

                if(image != null) {
                    new ImageWindow(image); //creates a viewing frame for the image
                } else {
                    System.out.println("Screenshot failed"); //2nd and 3rd.. etc. screenshot fails (only 1st works)
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

    }

So why does the image transfer work the first time, but fails the 2nd time? Something is wrong with sockets. Also, there probably is a better way to send the image, so just tell me if you have any ideas

Recommended Answers

All 2 Replies

I have done some experiments. I never encountered an IndexOutOfBoundsException, but it seems that ImageIO is unreliable when there are multiple images on a single stream. I found that ImageIO.read would return null a few times after each image when it should have been blocking to wait for the next image. I also found this thread: https://forums.oracle.com/forums/thread.jspa?threadID=2056383

The javax.imageio.ImageIO documentation is shamefully sparse. It doesn't say anything directly about what happens when you have more than one image on a stream, but it does make puzzling comments about whether each read or write method closes the stream. Most of them don't close the stream, but just mentioning it implies that someone considered the possibility of closing the stream. The only explanation I can imagine for why those methods might close the stream is that the end of the image is also expected to be the end of the stream. Naturally for image files the end of the image will always be the end of the stream, so perhaps that assumption is being made somewhere in the implementation, even though according to Wikipedia the PNG file format includes an end-of-image delimiter.

One way to be really safe about this would be to write to a java.io.ByteArrayOutputStream and read from a java.io.ByteArrayInputStream. That way you can store the size of the image in the stream and give ImageIO a stream that contains only the image you expect it to read or write. Since you have the image in memory already, the memory cost of a byte array for the compressed image can't be terrible.

Aside from that trouble, using ImageIO to encode the image as a PNG seems wise. PNG stands for Portable Network Graphics, which says to me that it is intended for doing things like this, and surely you wouldn't want to send the image without compression.

If you are sending screen captures for a remote monitoring kind of app then you may find this thread interesting. A few of us tried all kinds of ideas, and found the best performance by keeping a connection open, and sending only the differences between each screen and te previous one using a simple protocol that we hacked together in a few lines of code.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.