如何从中心而不是左上方缩放JavaFX的图像(ImageView)

问题描述 投票:1回答:1

我需要缩放或缩放图像,但是当我尝试缩放它时,它始终位于左上角的中心。如何根据自己的喜好从中心或其他任何地方缩放?

完整链接project

@FXML
void plusButton(ActionEvent event) throws IOException {
    double height = ImageView.getFitHeight();
    double width = ImageView.getFitWidth();

    ImageView.setFitHeight(height + 100);
    ImageView.setFitWidth(width + 100);

    //TODO
    //Rectangle2D rectangle2D = new Rectangle2D(800, 800, 800, 800);
    //ImageView.setViewport(rectangle2D);
}
javafx imageview fxml
1个回答
0
投票

原因是您要更改ImageView的整个宽度和高度,它是Image的容器。为了在JavaFX中缩放或缩放图像,您需要使用ViewPort中的ImageView

无论何时放大或缩小,都需要设置新的ViewPort

imageView.setViewport(new Rectangle2D(minX, minY, width, height));

根据Oracle's documentation

参数:
minX-Rectangle2D左上角的x坐标>
[minY-Rectangle2D]左上角的y坐标>
[width-Rectangle2D的宽度
height-Rectangle2D的高度

我没有调试您的代码,但是以下代码会很有帮助。尝试对其进行调整并学习概念,然后将更改应用于代码要容易得多。

import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.Tooltip;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class PlutoExplorer extends Application {

    private static final String IMAGE_CREDIT_URL = "http://www.nasa.gov/image-feature/global-mosaic-of-pluto-in-true-color";
    private static final String IMAGE_URL = "https://www.nasa.gov/sites/default/files/thumbnails/image/global-mosaic-of-pluto-in-true-color.jpg";

    private static final int MIN_PIXELS = 10;

    @Override
    public void start(Stage primaryStage) {
        Image image = new Image(IMAGE_URL);
        double width = image.getWidth();
        double height = image.getHeight();

        ImageView imageView = new ImageView(image);
        imageView.setPreserveRatio(true);
        reset(imageView, width / 2, height / 2);

        ObjectProperty<Point2D> mouseDown = new SimpleObjectProperty<>();

        imageView.setOnMousePressed(e -> {

            Point2D mousePress = imageViewToImage(imageView, new Point2D(e.getX(), e.getY()));
            mouseDown.set(mousePress);
        });

        imageView.setOnMouseDragged(e -> {
            Point2D dragPoint = imageViewToImage(imageView, new Point2D(e.getX(), e.getY()));
            shift(imageView, dragPoint.subtract(mouseDown.get()));
            mouseDown.set(imageViewToImage(imageView, new Point2D(e.getX(), e.getY())));
        });

        imageView.setOnScroll(e -> {
            double delta = e.getDeltaY();
            Rectangle2D viewport = imageView.getViewport();

            double scale = clamp(Math.pow(1.01, delta),

                // don't scale so we're zoomed in to fewer than MIN_PIXELS in any direction:
                Math.min(MIN_PIXELS / viewport.getWidth(), MIN_PIXELS / viewport.getHeight()),

                // don't scale so that we're bigger than image dimensions:
                Math.max(width / viewport.getWidth(), height / viewport.getHeight())

            );

            Point2D mouse = imageViewToImage(imageView, new Point2D(e.getX(), e.getY()));

            double newWidth = viewport.getWidth() * scale;
            double newHeight = viewport.getHeight() * scale;

            // To keep the visual point under the mouse from moving, we need
            // (x - newViewportMinX) / (x - currentViewportMinX) = scale
            // where x is the mouse X coordinate in the image

            // solving this for newViewportMinX gives

            // newViewportMinX = x - (x - currentViewportMinX) * scale 

            // we then clamp this value so the image never scrolls out
            // of the imageview:

            double newMinX = clamp(mouse.getX() - (mouse.getX() - viewport.getMinX()) * scale, 
                    0, width - newWidth);
            double newMinY = clamp(mouse.getY() - (mouse.getY() - viewport.getMinY()) * scale, 
                    0, height - newHeight);

            imageView.setViewport(new Rectangle2D(newMinX, newMinY, newWidth, newHeight));
        });

            imageView.setOnMouseClicked(e -> {
                if (e.getClickCount() == 2) {
                reset(imageView, width, height);
            }
        });

        Hyperlink link = new Hyperlink("Image Credit: NASA/JHUAPL/SwRI");
        link.setOnAction(e -> getHostServices().showDocument(IMAGE_CREDIT_URL));

        link.setPadding(new Insets(10));
        link.setTooltip(new Tooltip(IMAGE_CREDIT_URL));

        HBox buttons = createButtons(width, height, imageView);
        Tooltip tooltip = new Tooltip("Scroll to zoom, drag to pan");
        Tooltip.install(buttons, tooltip);

        Pane container = new Pane(imageView);
        container.setPrefSize(800, 600);

        imageView.fitWidthProperty().bind(container.widthProperty());
        imageView.fitHeightProperty().bind(container.heightProperty());
        VBox root = new VBox(link, container, buttons);
        root.setFillWidth(true);
        VBox.setVgrow(container, Priority.ALWAYS);

        primaryStage.setScene(new Scene(root));
        primaryStage.setTitle("Pluto explorer");
        primaryStage.show();
    }

    private HBox createButtons(double width, double height, ImageView imageView) {
        Button reset = new Button("Reset");
        reset.setOnAction(e -> reset(imageView, width / 2, height / 2));
        Button full = new Button("Full view");
        full.setOnAction(e -> reset(imageView, width, height));
        HBox buttons = new HBox(10, reset, full);
        buttons.setAlignment(Pos.CENTER);
        buttons.setPadding(new Insets(10));
        return buttons;
    }

    // reset to the top left:
    private void reset(ImageView imageView, double width, double height) {
        imageView.setViewport(new Rectangle2D(0, 0, width, height));
    }

    // shift the viewport of the imageView by the specified delta, clamping so
    // the viewport does not move off the actual image:
    private void shift(ImageView imageView, Point2D delta) {
        Rectangle2D viewport = imageView.getViewport();

        double width = imageView.getImage().getWidth() ;
        double height = imageView.getImage().getHeight() ;

        double maxX = width - viewport.getWidth();
        double maxY = height - viewport.getHeight();

        double minX = clamp(viewport.getMinX() - delta.getX(), 0, maxX);
        double minY = clamp(viewport.getMinY() - delta.getY(), 0, maxY);

        imageView.setViewport(new Rectangle2D(minX, minY, viewport.getWidth(), viewport.getHeight()));
    }

    private double clamp(double value, double min, double max) {

        if (value < min)
            return min;
        if (value > max)
            return max;
        return value;
    }

    // convert mouse coordinates in the imageView to coordinates in the actual image:
    private Point2D imageViewToImage(ImageView imageView, Point2D imageViewCoordinates) {
        double xProportion = imageViewCoordinates.getX() / imageView.getBoundsInLocal().getWidth();
        double yProportion = imageViewCoordinates.getY() / imageView.getBoundsInLocal().getHeight();

        Rectangle2D viewport = imageView.getViewport();
        return new Point2D(
                viewport.getMinX() + xProportion * viewport.getWidth(), 
                viewport.getMinY() + yProportion * viewport.getHeight());
    }

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

上述代码是从GitHub导入的。

© www.soinside.com 2019 - 2024. All rights reserved.