You can write arrays of Integers directly on the WritableRaster of the BufferedImage:
public static BufferedImage createRandomImage(final int width, final int height) { final BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); final long bytesPerPixel = 4L; final int[] pixelData = new SplittableRandom().ints(bytesPerPixel * width * height, 0, 256).toArray(); result.getRaster().setPixels(0, 0, width, height, pixelData); return result; }
This performs more than three times faster on my machine in a very crude benchmark (3.92S vs 1.26S), with the caveat that for very big images like the one you desire, you have a lot of data duplication, because you basically have to allocate twice the amount of memory, since you're writing the random data to a buffer first.
This can easily be solved by writing arrays of random Integers line by line though, which nets comparable performance:
public static BufferedImage createRandomImage(final int width, final int height) { final BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); final long bytesPerPixel = 4L; for (int y = 0; y < height; y++) { final int[] pixelData = new SplittableRandom().ints(bytesPerPixel * width, 0, 256) .toArray(); result.getRaster().setPixels(0, y, width, 1, pixelData); } return result; }
BufferedImage.setRGB is very slow, because for every pixel you set, it has to go fetch the corresponding data element:
public void setRGB(int x, int y, int rgb) { raster.setDataElements(x, y, colorModel.getDataElements(rgb, null)); }
which is a comparatively heavy operation.
Parallelization
Crude parallelization improves performance slightly, but it does not scale linearly with number of cores. On my 24 thread machine, the following yields a 30-40% improvement compared to the loop WritableRaster variant:
public static BufferedImage createRandomImage(final int width, final int height) { final BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); final long bytesPerPixel = 4L; IntStream.range(0, height).parallel().forEach(y -> { final int[] pixelData = new SplittableRandom().ints(bytesPerPixel * width, 0, 256) .toArray(); result.getRaster().setPixels(0, y, width, 1, pixelData); }); return result; }