0

I am using Robot's screenCapture method which returns BufferedImage, and then send using Socket to client on Android. If I don't reduce Quality then It works fine but it is very slow as Image is large and takes much time to send. I am trying to Reduce quality of BufferedImage(using ImageResizer Class), It works but for very limited time and then crash on server end.... It gives me following exception

Exception in thread "Thread-7" Exception in thread "Thread-8" java.lang.OutOfMemoryError: Java heap space
    at sun.awt.windows.WRobotPeer.getRGBPixels(WRobotPeer.java:64)
    at java.awt.Robot.createScreenCapture(Robot.java:444)
    at SystemController.screenCap(SystemController.java:71)
    at Server$ImageServer.run(Server.java:356)
    at java.lang.Thread.run(Thread.java:722)**

I am using following class for resizing

public class ImageResizer {
    public static ByteArrayOutputStream resizeImage(BufferedImage image) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            float quality = 0.3f; // Change this as needed
            // get all image writers for JPG format
            Iterator<ImageWriter> writers = ImageIO
                    .getImageWritersByFormatName("jpg");
            if (!writers.hasNext()) {
                throw new IllegalStateException("No writers found");
            }
            ImageWriter writer = writers.next();
            //ImageOutputStream ios = ImageIO.createImageOutputStream(os);
            try (ImageOutputStream ios = ImageIO.createImageOutputStream(out)) {
                writer.setOutput(ios);
                // set compression quality
                ImageWriteParam param = writer.getDefaultWriteParam();
                param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
                param.setCompressionQuality(quality);
                writer.write(null, new IIOImage(image, null, null), param);
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return out;
    }
}

And this method is used for capturing

public ByteArrayOutputStream screenCap(Rectangle captureSize, int i) {
        robot = new Robot();
        screenImage = robot.createScreenCapture(captureSize);
        return ImageResizer.resizeImage(screenImage);
    }

What am I doing wrong?

fzkhan
  • 121
  • 3
  • 16
  • *`public static ByteArrayOutputStream resizeImage(`* Is the code holding references to these BAIS instances? For better help sooner, post an [SSCCE](http://sscce.org/). – Andrew Thompson Jun 24 '13 at 12:57
  • do you mean ByteArrayOutputStream?? resizeImage return ByteArrayOutputStream Object after sending that object over socket I am closing it... ot = new DataOutputStream(s.getOutputStream()); byte[] imageData = null; try (ByteArrayOutputStream baos = screenCap(new Rectangle(0,0,1000,500))) { byte[] bytesOut = baos.toByteArray(); imageData = encodeImage(bytesOut); ot.writeLong(imageData.length); ot.write(imageData); ot.flush(); } catch (Exception e) { } – fzkhan Jun 24 '13 at 13:52
  • *"do you mean.."* I mean *post an [SSCCE](http://sscce.org/).* Also, don't put code in comments, it is unreadable. – Andrew Thompson Jun 24 '13 at 14:05

1 Answers1

0

OutOfMemory errors are not uncommon while working with BufferedImage that's because BufferedImage works with the uncompressed image in memory, so a image that's JPEG encoded and takes maybe 300kb on disc could take up 10mb of memory, and depending on how you tackle the image resizing procedure this can take up much more (by creating lot's of BufferedImages).

My suggestion to you is using a image scaling library such as imgscalr, I've used imgscalr sucessfuly in the past to improve memory usage in a legacy Java application that used BufferedImages like crazy to resize images

Using imgscalr can be as simple as:

BufferedImage thumbnail = Scalr.resize(image, 150);

Rafael Oltra
  • 1,239
  • 9
  • 15
  • this would decrease no of pixels in bufferedImage ,,, but i want same no of pixels but less size by reducing quality of it.... – fzkhan Jun 24 '13 at 13:47