Search code examples
javajavafx

JavaFX Image with different corners


As answered in this thread, ImageViews can be clipped to achieve corner rounding (Corner rounding of imageViews cannot be achieved with CSS). However, I am trying to have different corner radii, very much like described by this bit of CSS:

.background {
    -fx-background-radius: 64 0 16 0;
}

What i want the image to look like (Image = black area) is pretty much: enter image description here

The problem I am currently facing is that it is not possible to clip imageViews with a VBox, for instance. I could clip, however, the imageView with a Rectangle, but this again, does not give me the possibility to have different corner radii.

How could I achieve the same effect as the above CSS code (which of course does not work with an imageView) and have an image have different corners?


Solution

  • Clip ImageView with Path

    clip imageview javafx

    In this approach an ImageView is clipped with a Path . That path will adapt at FitWidth and FitHeight values of each imageView passed to getClip method . The second and third arguments passed are values to calculate radius of top and bottom round corner based on Fitheight .

    getClip method will draw a path like so :

    path

    This is a single class javafx app you can try

    App.java

    public class App extends Application {
    
        @Override
        public void start(Stage stage) {
    
            ImageView imageView = new ImageView("https://ioppublishing.org/wp-content/uploads/2017/03/cat-web-cc0.jpg");
            imageView.setFitHeight(300);
            imageView.setFitWidth(300);
            imageView.setClip(getClip(imageView, 0.1,0.3));
    
            ImageView imageView1 = new ImageView("https://ioppublishing.org/wp-content/uploads/2017/03/cat-web-cc0.jpg");
            imageView1.setFitHeight(400);
            imageView1.setFitWidth(400);
            imageView1.setClip(getClip(imageView1, 0.2,0.3));
    
            VBox vBox = new VBox(imageView, imageView1);
            vBox.setSpacing(20);
            vBox.setPadding(new Insets(20));
            vBox.setAlignment(Pos.CENTER);
            vBox.setFillWidth(true);
            var scene = new Scene(new StackPane(vBox), 1024, 800);
    
            stage.setScene(scene);
            stage.setTitle("clipping with path");
            stage.show();
    
        }
    
        public static void main(String[] args) {
            launch();
        }
    
        private Node getClip(ImageView imageView, double radiusTop,double radiusBot) {
            Path clip;
    
            double height = imageView.getFitHeight();
            double width = imageView.getFitWidth();
            double radius1 = height * radiusTop;
            double radius2 = height * radiusBot;
            clip = new Path(new MoveTo(0, radius1), new ArcTo(radius1, radius1, 0, radius1, 0, false, true),
                    new HLineTo(width),
                    new VLineTo(height - radius2),
                    new ArcTo(radius2, radius2, 0, width - radius2, height, false, true),
                    new HLineTo(0));
    
            clip.setFill(Color.ALICEBLUE);
    
            return clip;
    
        }
    
    }
    

    Update for all corners clip all corners javafx

    App.java

    public class App extends Application {
    
        @Override
        public void start(Stage stage) {
    
            ImageView imageView = new ImageView("https://ioppublishing.org/wp-content/uploads/2017/03/cat-web-cc0.jpg");
            imageView.setFitHeight(300);
            imageView.setFitWidth(300);
            imageView.setClip(getClip(imageView, 0.3, 0.1, 0.2, 0.1));
    
            ImageView imageView1 = new ImageView("https://ioppublishing.org/wp-content/uploads/2017/03/cat-web-cc0.jpg");
            imageView1.setFitHeight(400);
            imageView1.setFitWidth(400);
            imageView1.setClip(getClip(imageView1, 0.3, 0.2, 0.1, 0.2));
    
            VBox vBox = new VBox(imageView, imageView1);
            vBox.setSpacing(20);
            vBox.setPadding(new Insets(20));
            vBox.setAlignment(Pos.CENTER);
            vBox.setFillWidth(true);
            var scene = new Scene(new StackPane(vBox), 1024, 800);
    
            stage.setScene(scene);
            stage.setTitle("clipping with path");
            stage.show();
    
        }
    
        public static void main(String[] args) {
            launch();
        }
    
        private Node getClip(ImageView imageView, double topLeft, double topRight, double bottomLeft, double bottomRight) {
            Path clip;
    
            double height = imageView.getFitHeight();
            double width = imageView.getFitWidth();
            double radius1 = height * topLeft;
            double radius2 = height * topRight;
            double radius3 = height * bottomLeft;
            double radius4 = height * bottomRight;
    
            clip = new Path(new MoveTo(0, radius1),
                    new ArcTo(radius1, radius1, 0, radius1, 0, false, true),
                    new HLineTo(width - radius2),
                    new ArcTo(radius2, radius2, 0, width, radius2, false, true),
                    new VLineTo(height - radius4),
                    new ArcTo(radius4, radius4, 0, width - radius4, height, false, true),
                    new HLineTo(radius3),
                    new ArcTo(radius3, radius3, 0, 0, height - radius3, false, true));
    
            clip.setFill(Color.ALICEBLUE);
    
            return clip;
    
        }
    
    }