2

I have an int array where each value stores a bitpacked rgb value (8 bits per channel) and alpha is always 255(opaque) and i want to display that in javafx.

My current approach is using a canvas like this:

GraphicsContext graphics = canvas.getGraphicsContext2D();
PixelWriter pw = graphics.getPixelWriter();
pw.setPixels(0, 0, width, height, PixelFormat.getIntArgbInstance(), pixels, 0, width);

However before that i actually have to set the alpha component of each pixel by iterating each pixel and OR'ing it with a mask that turns the pixel from rgb to argb like this:

for (int i = 0; i < pixels.length; i++) {
    pixels[i] = 0xFF000000 | pixels[i];
}

Is there a more efficient to do this (as the pixels array is updated many times every second)?

I was hoping there's a IntRgbInstance but unfortunately there isn't (only ByteRgbInstance)

Other approaches i've tested:

Approach 1: Creating a IntBuffer that is filled up like this:

IntBuffer buffer = IntBuffer.allocate(pixels.length * 4);
for (int pixel : pixels) {
    buffer.put(0xFF000000 | pixel);
}

And then generating a PixelBuffer that uses this buffer, the pixel buffer is then used as an input to this WritableImage constructor: https://openjfx.io/javadoc/17/javafx.graphics/javafx/scene/image/WritableImage.html#%3Cinit%3E(javafx.scene.image.PixelBuffer) and then i display that WritableImage using a ImageView

This however still didn't speed up anything(rather made it a bit slower) and im guessing that because i have to construct a new WritableImage instance each time the pixels int array is updated.

Approach 2 (that didn't work for some reason, i.e. it displayed nothing in the screen): Creating a buffer the same way as above and using that in one of the setPixels() methods that takes in a buffer:

IntBuffer buffer = IntBuffer.allocate(pixels.length * 4);
for (int pixel : pixels) {
    buffer.put(0xFF000000 | pixel);
}
pw.setPixels(0, 0, width, height, PixelFormat.getIntArgbInstance(), buffer, width);

After a bit of more research i found out that i don't need to create a new WritableImage instance each time the pixels array is updated but i can just use the updateBuffer method here: https://openjfx.io/javadoc/17/javafx.graphics/javafx/scene/image/PixelBuffer.html#updateBuffer(javafx.util.Callback)

So the code currently looks like this:

pb.updateBuffer(callback -> {
    buffer.clear();
    for (int pixel : pixels) {
        buffer.put(0xFF000000 | pixel);
    }
    return null;
});

Where pb, buffer is only created once like this:

IntBuffer buffer = IntBuffer.allocate(pixels.length * 4);
PixelBuffer<IntBuffer> pb = new PixelBuffer<>(width, height, buffer, PixelFormat.getIntArgbPreInstance());
view.setImage(new WritableImage(pb));

and this did indeed result in a nice speedup (close to 2x compared to my initial approach)

1 Answer 1

1

Maybe this https://openjfx.io/javadoc/17/javafx.graphics/javafx/scene/image/WritableImage.html#%3Cinit%3E(javafx.scene.image.PixelBuffer) is what you are looking for. You could create a PixelBuffer from an IntBuffer of your data.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, together with using PixelBuffer#updateBuffer() i did indeed get a rather nice speedup (about 2x compared to my initial approach) i will wait a few days for other answers just in case (altho i think this is the best approach there is) and after that i'll accept this answer
Yes, using updateBuffer() is the essential part of the PixelBuffer. It would not make much sense without it. I used it for real-time rendering of 4K videos from VLC in JavaFX. You can even use double-buffering that way if you want to.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.