Proposal: Exposing a GraphicsContext-like API for WritableImage via Software Renderer
John Hendrikx
john.hendrikx at gmail.com
Fri Jun 27 10:15:31 UTC 2025
Hi list,
I'm exploring whether there is interest in exposing a (Canvas)
GraphicsContext-like interface for WritableImage backed by the existing
software rendering pipeline. Currently, JavaFX offers two main
choices for drawing and pixel manipulation, each with different trade-offs:
- Canvas provides rich drawing primitives via GraphicsContext, but
offers no direct pixel access—requiring costly GPU readbacks (e.g.,
snapshot()).
- WritableImage, on the other hand, allows direct pixel manipulation via
PixelReader/PixelWriter, but has no built-in support for drawing
operations like shapes, fills, or blending.
My proposal would combine the strengths of both:
- Expose drawing operations (shapes, fills, etc.) for WritableImage
- Direct access to image data before or after rendering without GPU
readbacks / snapshots
- Reuse of JavaFX’s software rendering stack (SWGraphics,
PiscesRenderer, etc.) without activating the software pipeline globally
I’ve successfully tested this approach in a non-modular FX application
by accessing internal APIs from com.sun.prism.sw. With minor adjustments
(--add-exports), it may also work in modular environments.
Work needed to support this as a public API might include:
- Creating a new GraphicsContext-like interface ("DrawingContext" ?)
- Exposing a method on WritableImage to obtain such a context
- Optionally, refactoring Canvas' GraphicsContext to implement this new
interface (method signatures are likely compatible)
- Implementing the new interface on top of the software renderer
See the end of the post for a working example (assuming you place the
code in the "com.sun.prism.sw" package and deal with the module
restrictions). Note that you do not need to enable the software
pipeline (and you don't want to either, as the whole point is to remain
GPU accelerated but have software renderer backed drawing primitives for
images).
Any feedback appreciated!
--John
packagecom.sun.prism.sw;
importcom.sun.glass.ui.Screen;
importcom.sun.glass.utils.NativeLibLoader;
importcom.sun.pisces.JavaSurface;
importcom.sun.pisces.PiscesRenderer;
importcom.sun.pisces.RendererBase;
importcom.sun.prism.paint.Color;
importjava.nio.IntBuffer;
importjavafx.application.Application;
importjavafx.scene.Scene;
importjavafx.scene.image.ImageView;
importjavafx.scene.image.PixelWriter;
importjavafx.scene.image.WritableImage;
importjavafx.scene.layout.StackPane;
importjavafx.stage.Stage;
publicclassSWRendererExample {
static{
NativeLibLoader.loadLibrary("prism_sw");
}
publicstaticvoidmain(String[] args) {
Application.launch(App.class);
}
publicstaticclassApp extendsApplication {
@Override
publicvoidstart(Stage primaryStage) {
WritableImage writableImage = createImageWithSWPipeline();
Scene scene = newScene(newStackPane(newImageView(writableImage)));
primaryStage.setScene(scene);
primaryStage.show();
}
}
publicstaticWritableImage createImageWithSWPipeline() {
intwidth = 400;
intheight = 300;
SWResourceFactory resourceFactory =
newSWResourceFactory(Screen.getMainScreen());
SWRTTexture texture = newSWRTTexture(resourceFactory, width, height);
SWContext swContext = newSWContext(resourceFactory);
// Set up a surface to draw on and create the renderer:
int[] backingArray = newint[width * height];
IntBuffer pixelBuffer = IntBuffer.wrap(backingArray);
JavaSurface surface = newJavaSurface(backingArray,
RendererBase.TYPE_INT_ARGB_PRE, width, height);
PiscesRenderer renderer = newPiscesRenderer(surface);
// Create SWGraphics for drawing (software renderer)
SWGraphics swGraphics = newSWGraphics(texture, swContext, renderer);
swGraphics.clear(Color.WHITE);
swGraphics.setPaint(Color.BLUE);
swGraphics.fillRect(50, 50, 100, 100);
swGraphics.setPaint(Color.RED);
swGraphics.fillEllipse(75, 75, 10, 20);
// Take the result and place it in a writable image:
WritableImage writableImage = newWritableImage(width, height);
PixelWriter pw = writableImage.getPixelWriter();
pw.setPixels(0, 0, width, height,
javafx.scene.image.PixelFormat.getIntArgbPreInstance(),
pixelBuffer.array(), 0, width);
returnwritableImage;
}
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/openjfx-dev/attachments/20250627/838e6608/attachment-0001.htm>
More information about the openjfx-dev
mailing list