I am using Node.snapshot() to create an image of an live node that I can use as a clip for a different node. This worked fine with version 2.2 but when I updated to Java 8 build 80 I get the following stacktrace:
java.lang.ArrayIndexOutOfBoundsException
at java.lang.System.arraycopy(Native Method)
at com.sun.javafx.image.impl.BaseIntToIntConverter$IntAnyToSameConverter.doConvert(BaseIntToIntConverter.java:172)
at com.sun.javafx.image.impl.BaseIntToIntConverter.convert(BaseIntToIntConverter.java:95)
at com.sun.javafx.image.impl.BaseIntToIntConverter$IntAnyToSameConverter.convert(BaseIntToIntConverter.java:161)
at com.sun.prism.sw.SWTexture.update(SWTexture.java:190)
at com.sun.prism.impl.BaseResourceFactory.createTexture(BaseResourceFactory.java:177)
at com.sun.prism.impl.BaseResourceFactory.getCachedTexture(BaseResourceFactory.java:148)
at com.sun.javafx.sg.prism.NGImageView.renderContent(NGImageView.java:121)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:428)
at com.sun.javafx.sg.prism.NGImageView.doRender(NGImageView.java:103)
at com.sun.javafx.sg.prism.NGImageView.doRender(NGImageView.java:41)
at com.sun.javafx.sg.BaseNode.render(BaseNode.java:1278)
at com.sun.javafx.sg.prism.NGNode.renderClip(NGNode.java:630)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:424)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:69)
at com.sun.javafx.sg.BaseNode.render(BaseNode.java:1278)
I have narrowed down the issue and can workaround it by cloning the snapshot image into a new WritableImage. Please try my test class below and click on the right hand rectangle to see the error. The left hand rectangle is clipped with a cloned version of the snapshot image.
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class SnapshotClipTest extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setWidth(800);
primaryStage.setHeight(600);
primaryStage.centerOnScreen();
HBox stageRoot = new HBox(100);
stageRoot.setAlignment(Pos.CENTER);
Circle clipCircle = new Circle(100, 100, 100);
SnapshotParameters params = new SnapshotParameters();
params.setFill(Color.TRANSPARENT);
final WritableImage clipImage = clipCircle.snapshot(params, null);
final Rectangle rect1 = new Rectangle(200, 200);
rect1.setFill(Color.DODGERBLUE);
WritableImage clipImageClone = new WritableImage(clipImage.getPixelReader(),
(int)clipImage.getWidth(), (int)clipImage.getHeight());
rect1.setClip( new ImageView(clipImageClone) );
Rectangle rect2 = new Rectangle(200, 200);
rect2.setFill(Color.DODGERBLUE);
rect2.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent arg0) {
rect1.setClip( new ImageView(clipImage) );
}
});
stageRoot.getChildren().addAll(rect1, rect2);
primaryStage.setScene( new Scene(stageRoot, Color.WHITESMOKE));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
java.lang.ArrayIndexOutOfBoundsException
at java.lang.System.arraycopy(Native Method)
at com.sun.javafx.image.impl.BaseIntToIntConverter$IntAnyToSameConverter.doConvert(BaseIntToIntConverter.java:172)
at com.sun.javafx.image.impl.BaseIntToIntConverter.convert(BaseIntToIntConverter.java:95)
at com.sun.javafx.image.impl.BaseIntToIntConverter$IntAnyToSameConverter.convert(BaseIntToIntConverter.java:161)
at com.sun.prism.sw.SWTexture.update(SWTexture.java:190)
at com.sun.prism.impl.BaseResourceFactory.createTexture(BaseResourceFactory.java:177)
at com.sun.prism.impl.BaseResourceFactory.getCachedTexture(BaseResourceFactory.java:148)
at com.sun.javafx.sg.prism.NGImageView.renderContent(NGImageView.java:121)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:428)
at com.sun.javafx.sg.prism.NGImageView.doRender(NGImageView.java:103)
at com.sun.javafx.sg.prism.NGImageView.doRender(NGImageView.java:41)
at com.sun.javafx.sg.BaseNode.render(BaseNode.java:1278)
at com.sun.javafx.sg.prism.NGNode.renderClip(NGNode.java:630)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:424)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:69)
at com.sun.javafx.sg.BaseNode.render(BaseNode.java:1278)
I have narrowed down the issue and can workaround it by cloning the snapshot image into a new WritableImage. Please try my test class below and click on the right hand rectangle to see the error. The left hand rectangle is clipped with a cloned version of the snapshot image.
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class SnapshotClipTest extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setWidth(800);
primaryStage.setHeight(600);
primaryStage.centerOnScreen();
HBox stageRoot = new HBox(100);
stageRoot.setAlignment(Pos.CENTER);
Circle clipCircle = new Circle(100, 100, 100);
SnapshotParameters params = new SnapshotParameters();
params.setFill(Color.TRANSPARENT);
final WritableImage clipImage = clipCircle.snapshot(params, null);
final Rectangle rect1 = new Rectangle(200, 200);
rect1.setFill(Color.DODGERBLUE);
WritableImage clipImageClone = new WritableImage(clipImage.getPixelReader(),
(int)clipImage.getWidth(), (int)clipImage.getHeight());
rect1.setClip( new ImageView(clipImageClone) );
Rectangle rect2 = new Rectangle(200, 200);
rect2.setFill(Color.DODGERBLUE);
rect2.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent arg0) {
rect1.setClip( new ImageView(clipImage) );
}
});
stageRoot.getChildren().addAll(rect1, rect2);
primaryStage.setScene( new Scene(stageRoot, Color.WHITESMOKE));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}