A Dude
A Dude

Reputation: 37

Automatically Crop Image in JavaFX

I have a program which visualizes several Images through an ImageView , which are Fit to a size of 55x55 pixels up from around 32x32 pixels. Unfortunately, all images have a "border" of transparent background, so the images are displayed with a gap inbetween. Is there a way to crop an Image in javaFX so that it gets reduced to the actual picture?

Example:

desired look (Badly cropped out by hand)

enter image description here

actual look

enter image description here

Upvotes: 0

Views: 232

Answers (1)

fabian
fabian

Reputation: 82491

Afaik there is no build in method for this. As @Slaw mentioned in his comment, you need to use the PixelReader to check for empty rows/columns. Based on that info you can set the viewport property for the ImageView:

@Override
public void start(Stage primaryStage) {
    // using stackoverflow logo, since your image is completely opaque
    Image image = new Image("https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-icon.png");
    ImageView imageView = new ImageView(image);

    int w = (int) image.getWidth();
    int h = (int) image.getHeight();

    int firstNonEmptyColumn = 0;
    int firstNonEmptyRow = 0;
    int lastNonEmptyColumn = w - 1;
    int lastNonEmptyRow = h - 1;

    PixelReader reader = image.getPixelReader();

    outer: for (; firstNonEmptyColumn < w; firstNonEmptyColumn++) {
        for (int y = 0; y < h; y++) {
            // stop, if most significant byte (alpha channel) is != 0
            if ((reader.getArgb(firstNonEmptyColumn, y) & 0xFF000000) != 0) {
                break outer;
            }
        }
    }

    if (firstNonEmptyColumn == w) {
        imageView.setImage(null); // image completely transparent
    } else {
        outer: for (; lastNonEmptyColumn > firstNonEmptyColumn; lastNonEmptyColumn--) {
            for (int y = 0; y < h; y++) {
                if ((reader.getArgb(lastNonEmptyColumn, y) & 0xFF000000) != 0) {
                    break outer;
                }
            }
        }

        outer: for (; firstNonEmptyRow < h; firstNonEmptyRow++) {
            // use info for columns to reduce the amount of pixels that need checking
            for (int x = firstNonEmptyColumn; x <= lastNonEmptyColumn; x++) {
                if ((reader.getArgb(x, firstNonEmptyRow) & 0xFF000000) != 0) {
                    break outer;
                }
            }
        }

        outer: for (; lastNonEmptyRow > firstNonEmptyRow; lastNonEmptyRow--) {
            for (int x = firstNonEmptyColumn; x <= lastNonEmptyColumn; x++) {
                if ((reader.getArgb(x, lastNonEmptyRow) & 0xFF000000) != 0) {
                    break outer;
                }
            }
        }

        // set viewport to only show the opaque parts
        imageView.setViewport(new Rectangle2D(
                firstNonEmptyColumn,
                firstNonEmptyRow,
                lastNonEmptyColumn - firstNonEmptyColumn + 1,
                lastNonEmptyRow - firstNonEmptyRow + 1));

    }

    // visualize image bounds
    Rectangle rect = new Rectangle(imageView.prefWidth(-1), imageView.prefHeight(-1), Color.LIGHTGREEN);

    StackPane root = new StackPane(rect, imageView);
    root.setStyle("-fx-background-color:blue");


    Scene scene = new Scene(root);
    primaryStage.setScene(scene);
    primaryStage.show();
}

Upvotes: 2

Related Questions