B4J Question Canvas Snapshot Size Limit

RobertK

Member
Licensed User
When using Canvas methods Snapshot or Snapshot2 to convert the contents of a Canvas to an Image,
it throws the following exception when the size of the Canvas is too large.

Does anyone know how I can determine what is the maximum WIDTH * HEIGHT, and how this upper limit can be changed?

Thanks in advance.


Error message:
java.lang.IllegalArgumentException: WIDTH * HEIGHT is too large
    at javafx.graphics/com.sun.pisces.AbstractSurface.<init>(AbstractSurface.java:43)
    at javafx.graphics/com.sun.pisces.JavaSurface.<init>(JavaSurface.java:37)
    at javafx.graphics/com.sun.prism.sw.SWRTTexture.<init>(SWRTTexture.java:51)
    at javafx.graphics/com.sun.prism.sw.SWResourceFactory.createRTTexture(SWResourceFactory.java:135)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit$QuantumImage.getRT(QuantumToolkit.java:1302)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit$5.run(QuantumToolkit.java:1439)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
    at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305)
    at javafx.graphics/com.sun.javafx.tk.RenderJob.run(RenderJob.java:58)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:125)
    at java.base/java.lang.Thread.run(Thread.java:834)

tools._getmodulearea (java line: 1934)
java.lang.IllegalArgumentException: Unrecognized image loader: null
    at javafx.graphics/javafx.scene.image.WritableImage.loadTkImage(WritableImage.java:242)
    at javafx.graphics/javafx.scene.image.WritableImage.access$000(WritableImage.java:46)
    at javafx.graphics/javafx.scene.image.WritableImage$1.loadTkImage(WritableImage.java:51)
    at javafx.graphics/javafx.scene.Scene.doSnapshot(Scene.java:1340)
    at javafx.graphics/javafx.scene.Node.doSnapshot(Node.java:2129)
    at javafx.graphics/javafx.scene.Node.snapshot(Node.java:2207)
    at anywheresoftware.b4j.objects.NodeWrapper.Snapshot2(NodeWrapper.java:370)
    at exe.rangefinder.desk.tools._getmodulearea(tools.java:1934)
    at exe.rangefinder.desk.main._appstart(main.java:212)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:91)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:78)
    at exe.rangefinder.desk.main.start(main.java:37)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    at java.base/java.lang.Thread.run(Thread.java:834)
 

RobertK

Member
Licensed User
Based on the code here: https://github.com/ojdkbuild/lookas...main/java/com/sun/pisces/AbstractSurface.java it should be very large. What is your canvas size?

Hello Erel. Thanks for your prompt reply and the link.

Abstract Surface Class:
        final int nbits = 32-Integer.numberOfLeadingZeros(width) + 32-Integer.numberOfLeadingZeros(height);
        if (nbits > 31) {
            throw new IllegalArgumentException("WIDTH * HEIGHT is too large");
        }

Based on the above, it seems the upper limit of the surface area is (2^31)/8 = 268,435,456 square pixels. That is in keeping with
my experience, since a canvas of size 7037x18,108 pixels (127,425,996) works, but one measuring 29,320x14,761 (432,792,520) crashes.

This may sound greedy, but can you think of any way to make it even larger?
 
Upvote 0

RobertK

Member
Licensed User
Correction.

The upper limit of the surface area is (2^32) bits, or (2^32)/32 = 134,217,728 square pixels, or about 11,585x11,585 pixels if the canvas has a 1:1 aspect ratio.

I just confirmed this with a bit of experimentation.

That is big but not immense, and of course one always asks for more. :)
 
Upvote 0
Top