Byte array to buffered image conversion slow
Asked Answered
K

3

7

I have a simple server-side code that receives a byte array representing an image in JPEG format and returns the dimensions of the image.

public String processImage(byte[] data) {
    long startTime = System.currentTimeMillis();
    ByteArrayInputStream stream = new ByteArrayInputStream(data);
    BufferedImage bufferedImage;
    bufferedImage = ImageIO.read(stream);

    int height = bufferedImage.getHeight();
    int width = bufferedImage.getWidth();

    long endTime = System.currentTimeMillis();

    return "height="+height+" | width="+width+" | elapsed="+(endTime-startTime);
}

It works, but the problem is it's unacceptably slow. For an image that's 100KB, it's taking 6s. For an image that's 900KB, it's taking 30s. Is that expected? Is there a way to make byte array to bufferedImage conversion faster?

FYI, grabbing height/width isn't the only thing I intend to do. I eventually want to process the bufferedImage. So getting height/width was just an example code.

Kendrakendrah answered 21/11, 2013 at 22:3 Comment(0)
B
7

I think the problem might be related to the fact that ImageIO by default uses disk caching (to a temp file), even if your source is a ByteArrayInputStream. So if your file system is slow, reading will also be slow, regardless of input source.

You can disable the disk caching (at the cost of using more memory) with ImageIO.setUseCache(false). This will still cache your streams (to allow backwards seeking), but only in memory.

It's also possible to set the cache directory to a specific path using ImageIO.setCacheDirectory(cacheDirectory), if you have a faster disk/ramdisk or similar to store your temp files.

That said, your reported read times seems unreasonably high, even for disk cached reads. If the problem persists, I suggest using a profiler to find out where the time is spent, and look at possible optimizations.

PS: I also have a custom ByteArrayImageInputStream that might help reduce both disk access and memory consumption, should this really be the problem.

Bournemouth answered 22/11, 2013 at 9:35 Comment(0)
H
2

Try running your java program with the following command line option and see if it speeds things up at all:

-Djava.awt.headless=true
Herbartian answered 21/11, 2013 at 22:5 Comment(2)
Thanks, I haven't tried this yet, but I tried running the same code on an isolated environment and it only took 20ms for 200KB. So the issue doesn't look like it's the code. What does the above setting do exactly?Kendrakendrah
@baekacaek: It takes the graphics card out of the equation. If you're never planning on showing the BufferedImage on the display there's no need to waste time loading it into the graphics card's RAM. I tried your code snippet locally and the above command line option took the running time on my test image from about 250ms down to about 140ms. YMMV.Herbartian
G
2

From where are you reading the image? From where comes the byte[]? If you're reading the image from a hdd it maybe would help to read it by using a BufferedInputStream.

This can speed loading up. But this helps only if you're reading from a FileInputStream for example. When reading from the ByteArrayInputStream it won't help.

EDIT: Is there maybe more information you could give us? Where the byte array comes from?

Geldens answered 21/11, 2013 at 22:37 Comment(1)
The byte array is from HTTP body, handled by apache tomcat server to call this function.Kendrakendrah

© 2022 - 2024 — McMap. All rights reserved.