Skip to main content
added 20 characters in body
Source Link
Marv
  • 390
  • 4
  • 12
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;

    for IntStream.range(int y = 0;0, height).parallel().forEach(y < height; y++)-> {
        final int[] pixelData = new SplittableRandom().ints(bytesPerPixel * width, 0, 256)
                                                      .toArray();
        result.getRaster().setPixels(0, y, width, 1, pixelData);
    });

    return result;
}
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;

    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;
}
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;
}
added 812 characters in body
Source Link
Marv
  • 390
  • 4
  • 12

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;

    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;
}

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;

    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;
}
Source Link
Marv
  • 390
  • 4
  • 12

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.