29

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();
tier1
  • 6,303
  • 6
  • 44
  • 75
  • 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. – Andrew Thompson Apr 20 '12 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 – tier1 Apr 20 '12 at 15:08

6 Answers6

53

This should work:

byte[] imageBytes = ((DataBufferByte) bufferedImage.getData().getDataBuffer()).getData();
stacker
  • 68,052
  • 28
  • 140
  • 210
  • 18
    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) – Sam Barnum Feb 25 '13 at 22:49
  • 5
    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 Nov 15 '16 at 19:41
  • 1
    @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 . – stacker Nov 15 '16 at 19:45
  • 3
    bufferedImage.getData().getDataBuffer() is creating invalid byte array for buffered image – Surabhi Mundra Oct 16 '19 at 06:53
5

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();
}
EderBaum
  • 993
  • 13
  • 16
4
ByteArrayOutputStream baos;
ImageIO.write(bufferedImage, "png", baos);
byte[] imageBytes = baos.toByteArray();
bugCracker
  • 3,656
  • 9
  • 37
  • 58
2

Try using:

ImageIO.setUseCache(false);

Before writing, maybe that helps.

soulcheck
  • 36,297
  • 6
  • 91
  • 90
  • 1
    I tried this, however, I believe this still writes to disk, it just deletes it after the operation is complete. – tier1 Apr 20 '12 at 13:34
  • 1
    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? – soulcheck Apr 20 '12 at 13:37
  • 1
    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. – tier1 Apr 20 '12 at 13:39
  • 1
    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. – Alexander Klimetschek Nov 02 '13 at 02:10
1
BufferedImage img = ImageIO.read(new ByteArrayInputStream(bytes));
byte[] bytes = new byte[buf.capacity()];
buf.get(bytes, 0, bytes.length);
Zaz Gmy
  • 4,236
  • 3
  • 19
  • 30
0

Use Apache Commons IO Utils Apache Commons

IOUtils.copy(inputStream,outputStream);

IO Utils API supports the large buffers easily

Phani
  • 5,319
  • 6
  • 35
  • 43