10
  1. What is the fastest way to read Images from a File into a BufferedImage in Java/Grails?
  2. What is the fastest way to write Images from a BufferedImage into a File in Java/Grails?

my variant (read):

byte [] imageByteArray = new File(basePath+imageSource).readBytes()
InputStream inStream = new ByteArrayInputStream(imageByteArray)
BufferedImage bufferedImage = ImageIO.read(inStream)

my variant (write):

BufferedImage bufferedImage = // some image
def fullPath = // image page + file name
byte [] currentImage

try{

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ImageIO.write( bufferedImage, "jpg", baos );
    baos.flush();
    currentImage = baos.toByteArray();
    baos.close();

    }catch(IOException e){
        System.out.println(e.getMessage());
    }       
   }    


def newFile = new FileOutputStream(fullPath)
newFile.write(currentImage)
newFile.close()
Harald K
  • 26,314
  • 7
  • 65
  • 111

3 Answers3

9

Your solution to read is basically reading the bytes twice, once from the file and once from the ByteArrayInputStream. Don't do that

With Java 7 to read

BufferedImage bufferedImage = ImageIO.read(Files.newInputStream(Paths.get(basePath + imageSource)));

With Java 7 to write

ImageIO.write(bufferedImage, "jpg", Files.newOutputStream(Paths.get(fullPath)));

The call to Files.newInputStream will return a ChannelInputStream which (AFAIK) is not buffered. You'll want to wrap it

new BufferedInputStream(Files.newInputStream(...));

So that there are less IO calls to disk, depending on how you use it.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • I read that Java Toolkit is much fast for read isn't that true? Can you modify your answer if this is true? –  Aug 29 '13 at 23:21
  • @stephan1001 I'm sorry, I'm not familiar with UI related packages. – Sotirios Delimanolis Aug 29 '13 at 23:28
  • What is the full package of Files and Paths? –  Aug 29 '13 at 23:30
  • 1
    @stephan1001 Those are Java 7 classes. Package is [`java.nio.file.Files`](http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html) and [`java.nio.file.Paths`](http://docs.oracle.com/javase/7/docs/api/java/nio/file/Paths.html). – Sotirios Delimanolis Aug 29 '13 at 23:32
  • @stephan1001 It's not a recommendation. You don't have a choice. Those methods throw `IOException`. – Sotirios Delimanolis Aug 29 '13 at 23:37
  • Is your solution the the fastest? –  Aug 29 '13 at 23:48
  • @stephan1001 It would probably help if you wrapped the `IOStream` returned by the `Files.newIOStream()` methods in `BufferedIOStream` instances. – Sotirios Delimanolis Aug 29 '13 at 23:51
  • What will be the difference? Can you please update your answer? –  Aug 30 '13 at 00:09
  • 1
    @stephan1001 An un-buffered `FileInputStream` will make a lot of IO OS calls to read from the disk. By buffering, you read more than you need so as to make less calls to the disk. In situations like this, it makes sense, because you will end up reading the whole file anyway. – Sotirios Delimanolis Aug 30 '13 at 00:17
  • Great and do I have to change something for the write operation as well? –  Aug 30 '13 at 00:26
  • 1
    @stephan1001 Use the corresponding `BufferedOutputStream` the same way. – Sotirios Delimanolis Aug 30 '13 at 00:27
  • So to get you right when I use BufferedInputStream and BufferedOutputStream this makes read and write faster? –  Aug 30 '13 at 00:50
  • @stephan1001 Not always. Read here: http://stackoverflow.com/questions/2964044/should-i-always-wrap-an-inputstream-as-bufferedinputstream – Sotirios Delimanolis Aug 30 '13 at 01:04
5

I'm late to the party, but anyway...

Actually, using:

ImageIO.read(new File(basePath + imageSource));

and

ImageIO.write(bufferedImage, "jpeg", new File(fullPath));

...might prove faster (try it, using a profiler, to make sure).

This is because these variants use RandomAccessFile-backed ImageInputStream/ImageOutputStream implementations behind the scenes, while the InputStream/OutputStream-based versions will by default use a disk-backed seekable stream implementation. The disk-backing involves writing the entire contents of the stream to a temporary file and possibly reading back from it (this is because image I/O often benefits from non-linear data access).

If you want to avoid extra I/O with the stream based versions, at the cost of using more memory, it is possible to call the ambiguously named ImageIO.setUseCache(false), to disable disk caching of the seekable input streams. This is obviously not a good idea if you are dealing with very large images.

Harald K
  • 26,314
  • 7
  • 65
  • 111
  • So this version ImageIO.read(new File(basePath + imageSource)); is faster than ImageIO.read(new BufferedInputStream(Files.newInputStream(Paths.get(basePath + imageSource)))); is this true? –  Aug 30 '13 at 13:57
  • 1
    @stephan1001 In theory, yes (assuming the default setting for `useCahce` `false`). But as I say, measure to be sure. :-) – Harald K Aug 30 '13 at 14:00
  • 1
    Just for the heck of it, I wrote a sample program, that read a medium sized JPEG 100 times using the file version, the stream version and the stream version without disk cache. Timings are average times. time using file: 36.76ms time using stream: 40.32ms time using stream (useCache==false): 37.63ms JDK 1.6.0_26-b03-383 on OS X, 2.66GHz i7 + SSD. Your milage may vary... – Harald K Aug 30 '13 at 14:41
  • Does read and write with ImageIO of BufferedImages changes anything on the image quality? –  Aug 30 '13 at 15:12
  • @stephan1001 Compared to what? I don't think I understand the question... Reading a JPEG and re-encoding as JPEG will always cause some quality loss, but that has nothing to do with ImageIO or BufferedImages. – Harald K Aug 30 '13 at 15:23
  • 1
    The question is: When I load a jpg image into a BufferedImage and save it back from this BufferedImage to a jpg file does this result in quality losses? –  Aug 30 '13 at 16:06
  • @stephan1001 I answered that question in my previous comment. If you want to go more in-depth on JPEG quality, I suggest you ask a new SO question. It's too a wide topic to discuss in the comments section. :-) – Harald K Aug 30 '13 at 17:25
0

You are almost good for writing. Just don't use the intermediate ByteArrayOutputStream. It is a giant bottleneck in your code. Instead wrap the FileOutputStream in a BufferedOutputStream and do the same.

Same goes indeed for your reading. Remove the Itermediate ByteArrayInputStream.

Martijn Courteaux
  • 67,591
  • 47
  • 198
  • 287