Fastest way to generate random BufferedImage (in Java)

Today I decided to generate random image for an image stub, like this:

fillrandom01

All RGB values are uniformly random here.

How to generate such image in Java?

I wrote a simple program to test:

package com.inthemoon.snippets.swing;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.awt.image.VolatileImage;
import java.io.File;
import java.io.IOException;
import java.util.Locale;
import java.util.Random;

/**
 * Created by Dims on 28.02.2017.
 */
public class FastRandomImageGenerator {

   private final static int width = 1024;
   private final static int height = 768;
   private final static int count = 1000;

   private final static Random rnd = new Random();

   private static int[] array;


   public static void main(String[] args) throws IOException {

      long start, end;
      double elapsed;
      long fps;

      BufferedImage image;
      image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
      array = new int[image.getWidth() * image.getHeight() * image.getRaster().getNumBands()];


      start = System.currentTimeMillis();
      for(int i=0; i<count; ++i) {
         fillRandom00(image);
      }
      end = System.currentTimeMillis();

      elapsed = (double)(end - start) / count;
      fps = Math.round(1000. / elapsed);

      System.out.println(String.format(Locale.US, "Elapsed: %.2f milliseconds per one fillRandom00, expected fps is %d", elapsed, fps));
      //ImageIO.write(image, "PNG", new File("fillRandom01.png"));




      start = System.currentTimeMillis();
      for(int i=0; i<count; ++i) {
         fillRandom01(image);
      }
      end = System.currentTimeMillis();

      elapsed = (double)(end - start) / count;
      fps = Math.round(1000. / elapsed);

      System.out.println(String.format(Locale.US, "Elapsed: %.2f milliseconds per one fillRandom01, expected fps is %d", elapsed, fps));
      ImageIO.write(image, "PNG", new File("fillRandom01.png"));



      start = System.currentTimeMillis();
      for(int i=0; i<count; ++i) {
         fillRandom02(image);
      }
      end = System.currentTimeMillis();

      elapsed = (double)(end - start) / count;
      fps = Math.round(1000. / elapsed);

      System.out.println(String.format(Locale.US, "Elapsed: %.2f milliseconds per one fillRandom02, expected fps is %d", elapsed, fps));
      ImageIO.write(image, "PNG", new File("fillRandom02.png"));




      start = System.currentTimeMillis();
      for(int i=0; i<count; ++i) {
         fillRandom03(image);
      }
      end = System.currentTimeMillis();

      elapsed = (double)(end - start) / count;
      fps = Math.round(1000. / elapsed);

      System.out.println(String.format(Locale.US, "Elapsed: %.2f milliseconds per one fillRandom03, expected fps is %d", elapsed, fps));
      ImageIO.write(image, "PNG", new File("fillRandom03.png"));


   }


   public static void fillRandom00(BufferedImage image) {
      for(int x=0; x<image.getWidth(); ++x) {
         for(int y=0; y<image.getHeight(); ++y) {
            rnd.nextInt(0xFFFFFF);
         }
      }
   }


   public static void fillRandom01(BufferedImage image) {
      for(int x=0; x<image.getWidth(); ++x) {
         for(int y=0; y<image.getHeight(); ++y) {
            image.setRGB(x, y, rnd.nextInt(0xFFFFFF));
         }
      }
   }


   public static void fillRandom02(BufferedImage image) {
      for(int i=0; i<array.length; ++i) {
         array[i] = rnd.nextInt(0xFF);
      }
      image.getRaster().setPixels(0, 0, image.getWidth(), image.getHeight(), array);
   }


   public static void fillRandom03(BufferedImage image) {
      int[] array = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
      for(int i=0; i<array.length; ++i) {
         array[i] = rnd.nextInt(0xFFFFFF);
      }
   }

}

“fillRandom00” method is just generating WxH number of random values.

“fillRandom01” is using straightforward method utilizing BufferedImage#setRGB()

“fillRandom02” is trying to prepare array of ints separately and bitblt them onto BufferedImage.

And the latest method “fillRandom03” is using direct access to BuffereImage data.

Output of the program is following:

Elapsed: 7.97 milliseconds per one fillRandom00, expected fps is 125
Elapsed: 32.01 milliseconds per one fillRandom01, expected fps is 31
Elapsed: 28.75 milliseconds per one fillRandom02, expected fps is 35
Elapsed: 7.90 milliseconds per one fillRandom03, expected fps is 127

As it can be expected, the latest method appeared as fastest. But surprise is that it appeared even faster, than just generating numbers. Probably, this is effect of nested loop?