30

I'm trying to send multiple images over a socket using java but I need a faster way to convert the images to a byte array so I can send them. I tried the following code but it wrote about 10,000 images to my C:\ drive. Is there a way to make this conversion without writing to disk? Thanks!

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

                    //ImageIO.setUseCache(false);
                    ImageIO.write(bi.getImage(), "jpg", outputStream);

                    byte[] imageBytes = outputStream.toByteArray();
2
  • 1
    Note that a little extra time doing the image compression using a higher compression (lower quality) JPEG can save a lot of network time. I think you need to consider the byte size actually sent, which will be significantly larger with a pure BufferedImage. BTW - what is the source of these images? If it is screenshots for e.g., often PNG can provide a smaller byte size than a default compression JPEG. If it were continuous screenshots, perhaps even a video stream. Commented Apr 20, 2012 at 13:47
  • 1
    The source is continuous screenshots that I'm essentially making into a stream. But yes, I need to figure out how to compress the images without writing them to disk. That is my ultimate goal Commented Apr 20, 2012 at 15:08

6 Answers 6

52

This should work:

byte[] imageBytes = ((DataBufferByte) bufferedImage.getData().getDataBuffer()).getData();
Sign up to request clarification or add additional context in comments.

4 Comments

This will create a copy of the image. If you just want a direct reference to the bytes, call bufferedImage.getRaster().getDataBuffer() and cast it accordingly (it's not always safe to cast to a DataBufferByte)
this doesn't seem to work for me. I get java.awt.image.DataBufferInt cannot be cast to java.awt.image.DataBufferByte my bufferedimage is coming from a Robot.createScreenCapture() not sure if that matters
@user3712476 seems that Robot isn't a class from JRE libs, you could try to assign it to variable of type DataBufferInt and cast it to DataBufferInt .
bufferedImage.getData().getDataBuffer() is creating invalid byte array for buffered image
4

The code below it's really fast (few milliseconds)

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

public byte[] toByteArray(BufferedImage image) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();            
    JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(baos);
    encoder.encode(image);            
    return baos.toByteArray();
}

3 Comments

It's better to stay away with com.sun package.
Official post on why sun package should not be used: oracle.com/technetwork/java/faq-sun-packages-142232.html
Not an answer to the question.
4
ByteArrayOutputStream baos;
ImageIO.write(bufferedImage, "png", baos);
byte[] imageBytes = baos.toByteArray();

Comments

2

Try using:

ImageIO.setUseCache(false);

Before writing, maybe that helps.

4 Comments

I tried this, however, I believe this still writes to disk, it just deletes it after the operation is complete.
it shouldn't, at least according to docs : Setting this flag to false disallows the use of disk for future streams, which may be advantageous when working with small images, as the overhead of creating and destroying files is removed.. Maybe your program writes to disk somewhere else?
Yeah, I saw that in the docs as well. Either way, the operation is painfully slow for what I'm looking to do. Thanks though.
Image
AFAIU the setUseCache() flag only applies to input streams when reading an image from a stream. ImageIO either loads it into memory or moves it to a disk (when use cache = true), to support all kinds of random access operations normally not possible with InputStream. But the file format parsers (who operate on that ImageInputStream) will always create a BufferedImage as result, which will be completely in memory and uncompressed. Only Java Advanced Imaging has parsers to support tile based reading and conversion, without ever having to store the entire image in memory.
1
BufferedImage img = ImageIO.read(new ByteArrayInputStream(bytes));
byte[] bytes = new byte[buf.capacity()];
buf.get(bytes, 0, bytes.length);

Comments

0

Use Apache Commons IO Utils Apache Commons

IOUtils.copy(inputStream,outputStream);

IO Utils API supports the large buffers easily

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.