How to apply a blur only to a rectangular area within a pane?

别等时光非礼了梦想. 提交于 2020-06-28 06:36:35

问题


Let's say I've got a StackPane which has a BackgroundImage as background and another StackPane (or another component, if neccessary) as a child. The child covers only a part of the parent StackPane.

I'd like to know how to apply a GaussianBlur just to the area the child covers, so that the BackgroundImageis blurry in this area.

The size of the child changes when the parent is resized. It would be perfect to get a solution that will resize just in time, too.


回答1:


If you want to do it manually, you can use the snapshot function to create a snapshot image, blur it and apply it to the child every time the parent is resized.

However, invoking snapshot all the time will cause performance loss. I rather suggest you create 2 images, one normal and one blurred, and display a viewport of the blurred one.

Here's a more "complex" example with a circle where the viewport isn't sufficient. The clip method is used in this case:

public class Lens extends Application {

    Image image = new Image( "http://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Siberischer_tiger_de_edit02.jpg/800px-Siberischer_tiger_de_edit02.jpg");

    CirclePane circlePane;

    @Override
    public void start(Stage primaryStage) {

        ImageView normalImageView = new ImageView( image);
        ImageView blurredImageView = new ImageView( image);
        blurredImageView.setEffect(new GaussianBlur( 40));

        Group root = new Group();

        root.getChildren().addAll( normalImageView);

        Scene scene = new Scene( root, 1024, 768);

        primaryStage.setScene( scene);
        primaryStage.show();

        // pane with clipped area
        circlePane = new CirclePane( blurredImageView);
        makeDraggable( circlePane);

        root.getChildren().addAll( circlePane);

    }

    public static void main(String[] args) {
        launch(args);
    }


    private class CirclePane extends Pane {

        ImageView blurredImageView;
        ImageView clippedView = new ImageView();

        public CirclePane( ImageView blurredImageView) {

            this.blurredImageView = blurredImageView;

            // new imageview
            update();

            getChildren().addAll( clippedView);

        }

        public void update() {

            // create circle
            Circle circle = new Circle( 200);
            circle.relocate( getLayoutX(), getLayoutY());

            // clip image by circle
            blurredImageView.setClip(circle);

            // non-clip area should be transparent
            SnapshotParameters parameters = new SnapshotParameters();
            parameters.setFill(Color.TRANSPARENT); 

            // new image from clipped image
            WritableImage wim = null;
            wim = blurredImageView.snapshot(parameters, wim);

            clippedView.setImage( wim);

        }

    }

    // make node draggable
    class DragContext { 
        double x;
        double y; 
    } 

    public void makeDraggable( Node node) {

        final DragContext dragDelta = new DragContext();

        node.setOnMousePressed(mouseEvent -> {

            dragDelta.x = node.getBoundsInParent().getMinX() - mouseEvent.getScreenX();
            dragDelta.y = node.getBoundsInParent().getMinY() - mouseEvent.getScreenY();

        });

        node.setOnMouseDragged(mouseEvent -> {

            node.relocate( mouseEvent.getScreenX() + dragDelta.x, mouseEvent.getScreenY() + dragDelta.y);
            circlePane.update();

        });

    }

}

Just click on the circle and drag it around.

enter image description here



来源:https://stackoverflow.com/questions/29190062/how-to-apply-a-blur-only-to-a-rectangular-area-within-a-pane

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!