Possible BufferedImage.getRGB optimization
Jeremy Wood
mickleness at gmail.com
Sat Aug 30 05:30:23 UTC 2025
Daniel,
I agree BufferedImage.getRGB can be much too slow, and it looks like you
already found the work-around I’ve been using for years:
image.getRaster().getDataElements(..)
But I’m not a reviewer for the client-libs project so I don’t think I
can’t speak to your bigger question:
> Does this look like a good change to those of you who know this part
of the code?
Until one (or more) veteran reviewers respond, I’d turn this topic
around and ask a different question:
Do you think there’d be an appetite for a separate GitHub project that
enhanced the BufferedImage? Over time if it gained traction that might
make applying some of its enhancements to BufferedImage.java more
persuasive to this group.
Regards,
- Jeremy
------ Original Message ------
>From "Daniel Gredler" <djgredler at gmail.com>
To client-libs-dev at openjdk.org
Date 8/22/2025 8:03:38 AM
Subject Possible BufferedImage.getRGB optimization
>Hi all,
>
>`BufferedImage.getRGB(int, int, int, int, int[], int, int)` is often
>used for processing of individual image pixels. A common pattern is to
>loop through each row of pixels, calling this method once per row to
>populate the row pixel `int[]` and then process it.
>
>There are many types of `BufferedImage`, but one of the most common
>types is `TYPE_INT_ARGB`. Based on a quick search on GitHub, about one
>third of all BufferedImages are of this type [1]. This is also the
>representation which `BufferedImage.getRGB(int, int, int, int, int[],
>int, int)` uses for its output.
>
>I think there may be an opportunity here (in `BufferedImage.getRGB(int,
>int, int, int, int[], int, int)`) to skip the pixel-by-pixel color
>model conversion if the `BufferedImage` is already of type
>`TYPE_INT_ARGB`, which is relatively common. See here [2] for what this
>optimization could look like.
>
>In my local testing, a simple test program [3] went from running in 220
>seconds without the change to running in 7 seconds with the change.
>Separately, a real-world program which uses the row-by-row pixel access
>pattern went from running in 45 seconds to running in 29 seconds.
>
>Does this look like a good change to those of you who know this part of
>the code? Am I missing something that might make this dangerous or
>undesirable? Is it making too many assumptions? I know this area is
>fraught with gotchas -- color models, color spaces, strides, etc.
>
>Thanks!
>
>Daniel
>
>---
>
>[1]
>BufferedImage.TYPE_CUSTOM: 2k
>BufferedImage.TYPE_INT_RGB: 114k
>BufferedImage.TYPE_INT_ARGB: 93k << 35%
>BufferedImage.TYPE_INT_ARGB_PRE: 5k
>BufferedImage.TYPE_INT_BGR: 4k
>BufferedImage.TYPE_3BYTE_BGR: 10k
>BufferedImage.TYPE_4BYTE_ABGR: 9k
>BufferedImage.TYPE_4BYTE_ABGR_PRE: 2k
>BufferedImage.TYPE_USHORT_565_RGB: 1k
>BufferedImage.TYPE_USHORT_555_RGB: 1k
>BufferedImage.TYPE_BYTE_GRAY: 11k
>BufferedImage.TYPE_USHORT_GRAY: 2k
>BufferedImage.TYPE_BYTE_BINARY: 5k
>BufferedImage.TYPE_BYTE_INDEXED: 3k
>Total: 262k
>
>[2]
>https://github.com/gredler/jdk/commit/b98f6cdf7573b7e89067c757890193517aeb472e
>
>[3]
>public final class PerfTest {
> public static void main(final String[] args) {
> int w = 1_000;
> int h = 1_000;
> int accumulator = 0;
> BufferedImage image = new BufferedImage(w, h,
>BufferedImage.TYPE_INT_ARGB);
> int[] row = new int[w];
> long start = System.currentTimeMillis();
> for (int i = 0; i < 100_000; i++) {
> for (int y = 0; y < h; y++) {
> image.getRGB(0, y, w, 1, row, 0, w);
> accumulator += row[i % w];
> }
> }
> long end = System.currentTimeMillis();
> System.out.println("Total time: " + ((end - start) / 1_000) + "
>seconds");
> System.out.println("Accumulator: " + accumulator);
> }
>}
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/client-libs-dev/attachments/20250830/3ad66cf7/attachment-0001.htm>
More information about the client-libs-dev
mailing list