javafx realizes picture zooming and dragging

foreword

This article uses the image zoom operation effect realized by running javafx of jdk8.

method one

By changing the FitHeight and FitWidth of the ImageView to change and adjust the length and width to zoom, you can refer to this article JavaFX image browsing and zooming

The ImageView in the fxml file is as follows:

<ImageView fx:id="image" fitHeight="600.0" fitWidth="600.0" pickOnBounds="true" preserveRatio="true" />

The java code is as follows:

     static double size = 1;
     static double count = 1.0;
    
     //鼠标滚轮控制图片缩放
     image.setOnScroll(event -> {
    
    
            // 缩放具体逻辑
            if (event.getDeltaY() > 0) {
    
    
                // 这里是向上滚动滚轮(即放大图片)
                count = count + 1.0 / 10;
                size = 1.0 / 200 * (count - 1) * (count - 1) * (count - 1) + 1;
                image.setFitWidth(image.getFitWidth() * size);
                image.setFitHeight(image.getFitHeight() * size);
                count++;
            } else {
    
    
                // 这里是乡下滚动滚轮(即缩小图片)
                count = count - 1.0 / 10;
                double y = 1.0 / 200 * (count - 1) * (count - 1) * (count - 1) + 1;
                size = y < 0 ? size : y;
                image.setFitWidth(image.getFitWidth() / size);
                image.setFitHeight(image.getFitHeight() / size);
                count--;
            }
     });

way two

The above method can indeed realize the mouse wheel to zoom the image, but when it zooms, the entire stage page where the ImageView is located will also zoom.
Then how to make the picture zoom in a frame, that is, let the picture only be displayed and zoomed in the specified frame area, you can use the setViewport method in ImageView and use Rectangle2D to set the position, width and height of the graphic, you can refer to
this Article: Zooming an Image in ImageView (javafx)

1. Zoom with scroll bar

(1) Code

You can directly copy the following code and run it to see the effect (using jdk8)


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import javafx.application.Application;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.stage.FileChooser.ExtensionFilter;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;

public class MainServer extends Application {
    
    
    static double initx;
    static double inity;
    static int height;
    static int width;
    public static String path;
    static Scene initialScene, View;
    static double offSetX, offSetY, zoomlvl;

    @Override
    public void start(Stage s) {
    
    
        s.setResizable(false);
        GridPane grid = new GridPane();
        grid.setHgap(20);
        grid.setVgap(20);
        grid.setAlignment(Pos.CENTER);

        Label hint = new Label("你选择的图片:");
        TextField URL = new TextField();
        URL.setEditable(false);
        URL.setPrefWidth(350);

        Button browse = new Button("选择图片");
        //现在只能选择jpg、png格式的图片
        FileChooser fc = new FileChooser();
        ExtensionFilter png = new ExtensionFilter("png", "*.png");
        ExtensionFilter jpg = new ExtensionFilter("jpg", "*.jpg");
        fc.getExtensionFilters().addAll(jpg,png);
        //点击选择图片按钮的事件
        browse.setOnAction(e -> {
    
    
            URL.setText(fc.showOpenDialog(s).getAbsolutePath());
        });

        Button open = new Button("打开");
        //点击打开按钮的事件
        open.setOnAction(e -> {
    
    
            //获取图片路径到
            path = URL.getText();
            //初始化显示图片
            initView();
            s.setScene(View);
        });

        grid.add(hint, 0, 0);
        grid.add(URL, 1, 0);
        grid.add(browse, 2, 0);
        grid.add(open, 2, 1);

        initialScene = new Scene(grid, 600, 100);
        s.setScene(initialScene);
        s.show();
    }

    public static void initView() {
    
    
        VBox root = new VBox(20);
        root.setAlignment(Pos.CENTER);

        Label title = new Label(path.substring(path.lastIndexOf("\\") + 1));
        //加载图片
        Image source = null;
        try {
    
    
            source = new Image(new FileInputStream(path));
        } catch (FileNotFoundException e) {
    
    
            e.printStackTrace();
        }

        ImageView image = new ImageView(source);
        //获取图片长宽比
        double ratio = source.getWidth() / source.getHeight();
        //设置长宽
        if (500 / ratio < 500) {
    
    
            width = 500;
            height = (int) (500 / ratio);
        } else if (500 * ratio < 500) {
    
    
            height = 500;
            width = (int) (500 * ratio);
        } else {
    
    
            height = 500;
            width = 500;
        }
        //设置图片长宽
        image.setPreserveRatio(false);
        image.setFitWidth(width);
        image.setFitHeight(height);
        height = (int) source.getHeight();
        width = (int) source.getWidth();
        System.out.println("height = " + height + "\nwidth = " + width);

        //设置底部缩放滑动条,缩放程度限制为1到4
        HBox zoom = new HBox(10);
        zoom.setAlignment(Pos.CENTER);
        Slider zoomLvl = new Slider();
        zoomLvl.setMax(4);
        zoomLvl.setMin(1);
        zoomLvl.setMaxWidth(200);
        zoomLvl.setMinWidth(200);
        Label hint = new Label("缩放程度");
        Label value = new Label("1.0");
        zoom.getChildren().addAll(hint, zoomLvl, value);

        offSetX = width / 2;
        offSetY = height / 2;

        //设置顶部水平拖动滑动条
        Slider Hscroll = new Slider();
        Hscroll.setMin(0);
        Hscroll.setMax(width);
        Hscroll.setMaxWidth(image.getFitWidth());
        Hscroll.setMinWidth(image.getFitWidth());
        Hscroll.setTranslateY(-20);
        //设置右侧垂直拖动滑动条
        Slider Vscroll = new Slider();
        Vscroll.setMin(0);
        Vscroll.setMax(height);
        Vscroll.setMaxHeight(image.getFitHeight());
        Vscroll.setMinHeight(image.getFitHeight());
        Vscroll.setOrientation(Orientation.VERTICAL);
        Vscroll.setTranslateX(-20);

        //将三个滑动条和图片放到 imageView 布局上
        BorderPane imageView = new BorderPane();
        BorderPane.setAlignment(Hscroll, Pos.CENTER);
        BorderPane.setAlignment(Vscroll, Pos.CENTER_LEFT);
        imageView.setCenter(image);
        imageView.setTop(Hscroll);
        imageView.setRight(Vscroll);
        //设置鼠标手张开的图标
        imageView.setCursor(Cursor.OPEN_HAND);
        //顶部滑动条变化时的出发事件
        Hscroll.valueProperty().addListener(e -> {
    
    
            offSetX = Hscroll.getValue();
            zoomlvl = zoomLvl.getValue();
            double newValue = (double) ((int) (zoomlvl * 10)) / 10;
            value.setText(newValue + "");
            if (offSetX < (width / newValue) / 2) {
    
    
                offSetX = (width / newValue) / 2;
            }
            if (offSetX > width - ((width / newValue) / 2)) {
    
    
                offSetX = width - ((width / newValue) / 2);
            }
            image.setViewport(new Rectangle2D(offSetX - ((width / newValue) / 2), offSetY - ((height / newValue) / 2), width / newValue, height / newValue));
        });
        //右侧滑动条变化时的出发事件
        Vscroll.valueProperty().addListener(e -> {
    
    
            offSetY = height - Vscroll.getValue();
            zoomlvl = zoomLvl.getValue();
            double newValue = (double) ((int) (zoomlvl * 10)) / 10;
            value.setText(newValue + "");
            if (offSetY < (height / newValue) / 2) {
    
    
                offSetY = (height / newValue) / 2;
            }
            if (offSetY > height - ((height / newValue) / 2)) {
    
    
                offSetY = height - ((height / newValue) / 2);
            }
            image.setViewport(new Rectangle2D(offSetX - ((width / newValue) / 2), offSetY - ((height / newValue) / 2), width / newValue, height / newValue));
        });
        //底部滑动条变化时的出发事件
        zoomLvl.valueProperty().addListener(e -> {
    
    
            zoomlvl = zoomLvl.getValue();
            double newValue = (double) ((int) (zoomlvl * 10)) / 10;
            value.setText(newValue + "");
            if (offSetX < (width / newValue) / 2) {
    
    
                offSetX = (width / newValue) / 2;
            }
            if (offSetX > width - ((width / newValue) / 2)) {
    
    
                offSetX = width - ((width / newValue) / 2);
            }
            if (offSetY < (height / newValue) / 2) {
    
    
                offSetY = (height / newValue) / 2;
            }
            if (offSetY > height - ((height / newValue) / 2)) {
    
    
                offSetY = height - ((height / newValue) / 2);
            }
            Hscroll.setValue(offSetX);
            Vscroll.setValue(height - offSetY);
            image.setViewport(new Rectangle2D(offSetX - ((width / newValue) / 2), offSetY - ((height / newValue) / 2), width / newValue, height / newValue));
        });
        //鼠标在图片上按压的事件
        image.setOnMousePressed(e -> {
    
    
            initx = e.getSceneX();
            inity = e.getSceneY();
            imageView.setCursor(Cursor.CLOSED_HAND);
        });
        //鼠标在图片上松开的事件
        image.setOnMouseReleased(e -> {
    
    
            imageView.setCursor(Cursor.OPEN_HAND);
        });
        //鼠标在图片上拖动的事件
        image.setOnMouseDragged(e -> {
    
    
            Hscroll.setValue(Hscroll.getValue() + (initx - e.getSceneX()));
            Vscroll.setValue(Vscroll.getValue() - (inity - e.getSceneY()));
            initx = e.getSceneX();
            inity = e.getSceneY();
        });
        //鼠标在图片上滚轮滚动控制缩放的事件。缩放程度限制在1到4,每次滚动缩放0.3
        image.setOnScroll(event -> {
    
    
            zoomlvl = zoomLvl.getValue();
            if (event.getDeltaY() > 0) {
    
    
                if (zoomlvl < 4) {
    
    
                    zoomLvl.setValue(zoomlvl + 0.3);
                }
            } else {
    
    
                if (zoomlvl > 1) {
    
    
                    zoomLvl.setValue(zoomlvl - 0.3);
                }
            }
        });
        root.getChildren().addAll(title, imageView, zoom);
        //设置新窗口的大小
        View = new Scene(root, (image.getFitWidth()) + 90, (image.getFitHeight()) + 170);
    }

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

(2) Effect

Please add a picture description

Please add a picture description

2.fxml layout + java code

The above example is purely using java to layout and control the logic, and also has a slider. Next, adjust the layout using fxml, control the logic with java code, and hide all sliders.

You can refer to my writing below. If you want to run or view the complete sample project, you can see me: XTool project address on github

(1) fxml layout file

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.*?>
<?import com.jfoenix.controls.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.image.ImageView?>

<StackPane fx:id="root" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
    <children>
        <VBox  maxHeight="1050" maxWidth="1200" spacing="30" >
            <children>
                <HBox spacing="20" alignment="BASELINE_LEFT" style="-fx-padding:130 0 0 0 ">
                    <children>
                        <JFXButton fx:id="fileButton" layoutX="55.0"  style="-fx-background-color: #5cb85c;" text="打开图片" textFill="WHITE"  />
                        <JFXButton fx:id="identify" layoutX="170.0" layoutY="204.0" style="-fx-background-color: #5cb85c;" text="识别" textFill="WHITE" />
                        <JFXButton fx:id="copy" layoutX="199.0" layoutY="204.0" style="-fx-background-color: #5cb85c;" text="复制结果" textFill="WHITE" />
                        <JFXButton fx:id="clear" layoutX="219.0" layoutY="204.0" style="-fx-background-color: #c9302c;" text=" 清空 " textFill="WHITE" />
                    </children>
                </HBox>

                <HBox spacing="20"  maxHeight="550" prefHeight="550" >
                    <children>

                        <SplitPane layoutX="55.0" layoutY="14.0" prefHeight="550.0" prefWidth="700.0" maxHeight="550" style="-fx-padding:10 10 -400 50;-fx-font: 15 arial;" >
                            <VBox  maxHeight="550"  prefHeight="550" style="-fx-padding:0 10 0 40">
                                <children>
                                    <!-- 使用  visible="false" 隐藏顶部滚动条-->
                                    <Slider fx:id="Hscroll"  min="0" translateY="-20" maxHeight="0" maxWidth="0" visible="false"></Slider>
                                    <ImageView fx:id="image"  pickOnBounds="true" preserveRatio="false" />
                                    <!-- 使用  visible="false" 隐藏底部滚动条 使用 maxWidth="0" 让宽度设为0也为了不显示-->
                                    <Slider fx:id="zoomLvl" maxWidth="0"  max="6" min="1" visible="false"></Slider>
                                    <!-- 使用  visible="false" 隐藏底部滚动条的名称 使用 maxHeight、maxWidth 让长宽为0也为了不显示-->
                                    <Label fx:id="hint"  maxHeight="0" maxWidth="0" visible="false">缩放程度</Label>
                                    <!-- 使用  visible="false" 隐藏右侧滚动条 使用 maxHeight、maxWidth 让长宽为0也为了不显示-->
                                    <Slider fx:id="Vscroll" min="0" translateX="-20" orientation="VERTICAL"  maxHeight="0" maxWidth="0" visible="false"></Slider>
                                    <!-- 使用  visible="false" 隐藏底部滚动条的值 使用 maxHeight、maxWidth 让长宽为0也为了不显示-->
                                    <Label fx:id="value"  maxHeight="0" maxWidth="0" visible="false">1.0</Label>
                                </children>
                            </VBox>
                        </SplitPane>

                        <TextArea fx:id="resultArea" layoutX="55.0" layoutY="238.0" prefHeight="550.0" prefWidth="700.0" promptText="识别结果(仅支持识别中英文)" style="-fx-padding: 5 5 5 5;-fx-font: 15 arial;" >
                            <opaqueInsets>
                                <Insets />
                            </opaqueInsets>
                        </TextArea>
                    </children>
                </HBox>

            </children>
        </VBox>
    </children>
</StackPane>


(2) java code

import com.jfoenix.controls.JFXButton;
import io.datafx.controller.ViewController;
import javafx.fxml.FXML;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Cursor;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.control.TextArea;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.layout.BorderPane;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import net.sourceforge.tess4j.Tesseract;
import net.sourceforge.tess4j.TesseractException;
import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

@ViewController(value = "/fxml/ui/Ocr.fxml", title = "OCR图片识字")
public class OcrController {
    
    
    @FXML
    private JFXButton fileButton;
    @FXML
    private JFXButton identify;
    @FXML
    private JFXButton copy;
    @FXML
    private JFXButton clear;
    @FXML
    private TextArea borderArea;
    @FXML
    private ImageView image;
    @FXML
    private TextArea resultArea;
    @FXML
    private Slider Hscroll;
    @FXML
    private Label hint;
    @FXML
    private Slider zoomLvl;
    @FXML
    private Label value;
    @FXML
    private Slider Vscroll;

    private static double size = 1;
    private static double count = 1.0;
    private String imagePath = "";//图像路径
    private static int width = 0;
    static int height = 0;
    static double ratio = 0;
    private Image source = null;
    private static double offSetX, offSetY, zoomlvl;
    private static double initx;
    private static double inity;

    @PostConstruct
    public void init() {
    
    
        //选择文件按钮
        fileButton.setOnAction(action -> {
    
    
            FileChooser fileChooser = new FileChooser();
            fileChooser.setTitle("选择图像文件");
            File file = fileChooser.showOpenDialog(new Stage());
            if (file != null) {
    
    
                //获取图像路径
                imagePath = file.getAbsolutePath();
                System.out.println(imagePath);
                FileInputStream input = null;
                try {
    
    
                    input = new FileInputStream(imagePath);
                } catch (FileNotFoundException e) {
    
    
                    e.printStackTrace();
                }
                //获取图像为Image对象
                source = new Image(input);
                //获取长宽比
                getWidthHeight();
                //设置图像的长宽和设置到ImageView对象
                image.setImage(source);
                image.setPreserveRatio(false);
                image.setFitWidth(width);
                image.setFitHeight(height);
                height = (int) source.getHeight();
                width = (int) source.getWidth();

                offSetX = width / 2;
                offSetY = height / 2;
                //设置顶部滚动条
                Hscroll.setMax(width);
                Hscroll.setMaxWidth(image.getFitWidth());
                Hscroll.setMinWidth(image.getFitWidth());
                //设置右侧滚动条
                Vscroll.setMax(height);
                Vscroll.setMaxHeight(image.getFitHeight());
                Vscroll.setMinHeight(image.getFitHeight());
                BorderPane.setAlignment(Hscroll, Pos.CENTER);
                BorderPane.setAlignment(Vscroll, Pos.CENTER_LEFT);
                //顶部滚动条监听
                Hscroll.valueProperty().addListener(e -> {
    
    
                    offSetX = Hscroll.getValue();
                    zoomlvl = zoomLvl.getValue();
                    double newValue = (double) ((int) (zoomlvl * 10)) / 10;
                    value.setText(newValue + "");
                    if (offSetX < (width / newValue) / 2) {
    
    
                        offSetX = (width / newValue) / 2;
                    }
                    if (offSetX > width - ((width / newValue) / 2)) {
    
    
                        offSetX = width - ((width / newValue) / 2);
                    }

                    image.setViewport(new Rectangle2D(offSetX - ((width / newValue) / 2), offSetY - ((height / newValue) / 2), width / newValue, height / newValue));
                });
                //右侧滚动条监听
                Vscroll.valueProperty().addListener(e -> {
    
    
                    offSetY = height - Vscroll.getValue();
                    zoomlvl = zoomLvl.getValue();
                    double newValue = (double) ((int) (zoomlvl * 10)) / 10;
                    value.setText(newValue + "");
                    if (offSetY < (height / newValue) / 2) {
    
    
                        offSetY = (height / newValue) / 2;
                    }
                    if (offSetY > height - ((height / newValue) / 2)) {
    
    
                        offSetY = height - ((height / newValue) / 2);
                    }

                    image.setViewport(new Rectangle2D(offSetX - ((width / newValue) / 2), offSetY - ((height / newValue) / 2), width / newValue, height / newValue));
                });
                //底部缩放滚动条监听
                zoomLvl.valueProperty().addListener(e -> {
    
    
                    zoomlvl = zoomLvl.getValue();
                    double newValue = (double) ((int) (zoomlvl * 10)) / 10;
                    value.setText(newValue + "");
                    if (offSetX < (width / newValue) / 2) {
    
    
                        offSetX = (width / newValue) / 2;
                    }
                    if (offSetX > width - ((width / newValue) / 2)) {
    
    
                        offSetX = width - ((width / newValue) / 2);
                    }
                    if (offSetY < (height / newValue) / 2) {
    
    
                        offSetY = (height / newValue) / 2;
                    }
                    if (offSetY > height - ((height / newValue) / 2)) {
    
    
                        offSetY = height - ((height / newValue) / 2);
                    }
                    Hscroll.setValue(offSetX);
                    Vscroll.setValue(height - offSetY);
                    image.setViewport(new Rectangle2D(offSetX - ((width / newValue) / 2), offSetY - ((height / newValue) / 2), width / newValue, height / newValue));
                });
                //鼠标在图片上按压的事件
                image.setOnMousePressed(e -> {
    
    
                    initx = e.getSceneX();
                    inity = e.getSceneY();
                    image.setCursor(Cursor.CLOSED_HAND);
                });
                //鼠标在图片上松开的事件
                image.setOnMouseReleased(e -> {
    
    
                    image.setCursor(Cursor.OPEN_HAND);
                });
                //鼠标在图片上拖动的事件
                image.setOnMouseDragged(e -> {
    
    
                    Hscroll.setValue(Hscroll.getValue() + (initx - e.getSceneX()));
                    Vscroll.setValue(Vscroll.getValue() - (inity - e.getSceneY()));
                    initx = e.getSceneX();
                    inity = e.getSceneY();
                });
            }
        });

        //鼠标图片缩放控制
        image.setOnScroll(event -> {
    
    
            zoomlvl = zoomLvl.getValue();
            if (event.getDeltaY() > 0) {
    
    
                if (zoomlvl < 6) {
    
    
                    zoomLvl.setValue(zoomlvl + 0.3);
                }
            } else {
    
    
                if (zoomlvl > 1) {
    
    
                    zoomLvl.setValue(zoomlvl - 0.3);
                }
            }
        });

        //识别按钮
        identify.setOnAction(action -> {
    
    
            if (imagePath.length() == 0) {
    
    
                return;
            }
            long start = System.currentTimeMillis();
            //加载要识别的图片
            File image = new File(imagePath);
            //设置配置文件夹微视、识别语言、识别模式
            Tesseract tesseract = new Tesseract();
            tesseract.setDatapath("src/main/resources/tessdata");
            tesseract.setLanguage("chi_sim");
            tesseract.setPageSegMode(1);
            //设置引擎模式
            tesseract.setOcrEngineMode(1);
            //开始识别图片中的文字
            String result = null;
            try {
    
    
                result = tesseract.doOCR(image);
            } catch (TesseractException e) {
    
    
                e.printStackTrace();
            }
            long time = System.currentTimeMillis() - start;
            System.out.println("识别结束,耗时:" + time + " 毫秒,识别结果如下:");
            System.out.println();
            System.out.println(result);
            resultArea.setText(result);
        });

        //复制按钮事件
        copy.setOnAction(action -> {
    
    
            String str = resultArea.getText();
            Clipboard clipboard = Clipboard.getSystemClipboard();
            ClipboardContent content = new ClipboardContent();
            content.putString(str);
            clipboard.setContent(content);
        });

        //清除按钮事件
        clear.setOnAction(action -> {
    
    
            source = null;
            image.setImage(null);
            imagePath = "";
            ratio = 0;
            width = 0;
            height = 0;
            resultArea.setText("");
            zoomlvl = 1;
            initx = 0;
            inity = 0;
            zoomLvl.setValue(1);
        });
    }

    //获取长宽、长宽比
    private void getWidthHeight() {
    
    
        width = (int) source.getWidth();
        height = (int) source.getHeight();
        ratio = source.getWidth() / source.getHeight();//获取长宽比
        if (500 / ratio < 500) {
    
    
            width = 500;
            height = (int) (500 / ratio);
        } else if (500 * ratio < 500) {
    
    
            height = 500;
            width = (int) (500 * ratio);
        } else {
    
    
            height = 500;
            width = 500;
        }
    }
}

(3) Effect

Please add a picture description


Reference:
JavaFX image browsing and zooming
Zooming an Image in ImageView (javafx)

Guess you like

Origin blog.csdn.net/qq_33697094/article/details/131476654