Bootstrap

JavaFX-自定义图片模板导入图片合成

功能实现:使用一张图片作为模板底层,导入图片并合成新图片

界面如下:
在这里插入图片描述
1.绿色方框是可以自由移动和拉伸的,通过调整绿色方框确定导入图片位置和大小
2.保存模板:可以保存当前绿色方框的位置和大小,并生成一个按钮
3.导入合成:导入一张图片,自动调整拉伸到绿色方框位置,自动合成新图片并保存到桌面
4.初始化:使绿色方框恢复到程序打开时状态

在这里插入图片描述
(导出图片)

完整代码如下:

package com.test;

import javafx.application.Application;
import javafx.scene.Cursor;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import net.coobird.thumbnailator.Thumbnails;

import javax.imageio.ImageIO;
import javax.swing.filechooser.FileSystemView;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

public class TemplateTest extends Application {

    private String templatePath = "C:\\Users\\wen\\Desktop\\2020-07-16\\1_.png";
    private AnchorPane page = new AnchorPane();
    private Group group = new Group();
    // 初始化的模板块
    Rectangle demo = new Rectangle(0, 0, 200, 200);

    //窗体拉伸属性
    private final static int RESIZE_WIDTH = 5;// 判定是否为调整窗口状态的范围与边界距离

    private double mouseX;
    private double mouseY;
    double picX;
    double picY;
    double width;
    double height;
    javafx.scene.Cursor cursorType;
//    javafx.scene.Cursor cursorType;
    // 模板按钮对应的参数map
    Map<String, Map<String, Double>> buttonMap = new HashMap<>();

    // 添加底层模板
    public Image addTemplate() throws Exception {
        File templateFile = new File(templatePath);
        FileInputStream temFis = new FileInputStream(templateFile);
        Image temImage = new Image(temFis);
        // 生成临时文件,用于获取修改后的模板参数
        File file = new File(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ".jpg");
        if (temImage.getWidth() > 1500 || temImage.getHeight() > 1500) {
            Thumbnails.of(templateFile)
                    .size((int) (temImage.getWidth() / 1.5), (int) (temImage.getHeight() / 1.5))
                    .outputQuality(1.0).toFile(file);
        } else {
            Thumbnails.of(templateFile)
                    .size((int) temImage.getWidth(), (int) temImage.getHeight())
                    .outputQuality(1.0).toFile(file);
        }
        FileInputStream fis = new FileInputStream(file);
        Image image = new Image(fis);
        ImageView imageView = new ImageView(image);
        page.getChildren().add(imageView);
        fis.close();
        file.delete();
        return image;
    }

    // 添加模板块
    public void addMoudle() {
        demo.setFill(Color.GREEN);
        group.getChildren().add(demo);
        page.getChildren().add(group);
        // 鼠标拖动监听
        demo.addEventFilter(MouseEvent.MOUSE_DRAGGED, e -> {
            // 用于判断移动或拉伸
            if (e.getX() > demo.getX() &&
                    e.getX() < demo.getX() + demo.getWidth() &&
                    e.getY() > demo.getY() &&
                    e.getY() < demo.getY() + demo.getHeight() &&
                    // 如果光标类型没有改变就代表是移动,避免事件冲突
//                    cursorType == Cursor.DEFAULT_CURSOR
                    cursorType == Cursor.DEFAULT
            ) {
                demo.setX(picX + e.getX() - mouseX);
                demo.setY(picY + e.getY() - mouseY);
            } else {
                if (cursorType == Cursor.N_RESIZE) { // 向上拉伸
                    demo.setY(picY + (e.getY() - mouseY));
                    if (e.getY() - mouseY > 0) {
                        demo.setHeight(height - (e.getY() - mouseY));
                    } else {
                        demo.setHeight(height - (e.getY() - mouseY));
                    }
                } else if (cursorType == Cursor.S_RESIZE) { // 向下拉伸
                    if (e.getY() - mouseY > 0) {
                        demo.setHeight(height + (e.getY() - mouseY));
                    } else {
                        demo.setHeight(height + (e.getY() - mouseY));
                    }
                } else if (cursorType == Cursor.W_RESIZE) { // 向左拉伸
                    demo.setX(picX + (e.getX() - mouseX));
                    if (e.getX() - mouseX > 0) {
                        demo.setWidth(width - (e.getX() - mouseX));
                    } else {
                        demo.setWidth(width - (e.getX() - mouseX));
                    }
                } else if (cursorType == Cursor.E_RESIZE) { // 向右拉伸
                    if (e.getX() - mouseX > 0) {
                        demo.setWidth(width + (e.getX() - mouseX));
                    } else {
                        demo.setWidth(width + (e.getX() - mouseX));
                    }
                } else if (cursorType == Cursor.NW_RESIZE) { // 向左上拉伸
                    if (e.getY() - mouseY > 0 || e.getX() - mouseX > 0) {
                        demo.setY(picY + (e.getY() - mouseY));
                        demo.setHeight(height - (e.getY() - mouseY));
                        demo.setX(picX + (e.getX() - mouseX));
                        demo.setWidth(width - (e.getX() - mouseX));
                    } else if (e.getY() - mouseY < 0 || e.getX() - mouseX < 0) {
                        demo.setY(picY + (e.getY() - mouseY));
                        demo.setHeight(height - (e.getY() - mouseY));
                        demo.setX(picX + (e.getX() - mouseX));
                        demo.setWidth(width - (e.getX() - mouseX));
                    }
                } else if (cursorType == Cursor.NE_RESIZE) { // 向右上拉伸
                    if (e.getY() - mouseY > 0 || e.getX() - mouseX > 0) {
                        demo.setY(picY + (e.getY() - mouseY));
                        demo.setHeight(height - (e.getY() - mouseY));
                        demo.setWidth(width + (e.getX() - mouseX));
                    } else if (e.getY() - mouseY < 0 || e.getX() - mouseX < 0) {
                        demo.setY(picY + (e.getY() - mouseY));
                        demo.setHeight(height - (e.getY() - mouseY));
                        demo.setWidth(width + (e.getX() - mouseX));
                    }
                } else if (cursorType == Cursor.SW_RESIZE) { // 向左下拉伸
                    if (e.getY() - mouseY > 0 || e.getX() - mouseX > 0) {
                        demo.setHeight(height + (e.getY() - mouseY));
                        demo.setX(picX + (e.getX() - mouseX));
                        demo.setWidth(width - (e.getX() - mouseX));
                    } else if (e.getY() - mouseY < 0 || e.getX() - mouseX < 0) {
                        demo.setHeight(height + (e.getY() - mouseY));
                        demo.setX(picX + (e.getX() - mouseX));
                        demo.setWidth(width - (e.getX() - mouseX));
                    }
                } else if (cursorType == Cursor.SE_RESIZE) { // 向右下拉伸
                    if (e.getY() - mouseY > 0 || e.getX() - mouseX > 0) {
                        demo.setHeight(height + (e.getY() - mouseY));
                        demo.setWidth(width + (e.getX() - mouseX));
                    } else if (e.getY() - mouseY < 0 || e.getX() - mouseX < 0) {
                        demo.setHeight(height + (e.getY() - mouseY));
                        demo.setWidth(width + (e.getX() - mouseX));
                    }
                }
            }
        });
        // 鼠标移动监听
        demo.addEventFilter(MouseEvent.MOUSE_MOVED, e -> {
            double mouseX = e.getX();
            double mouseY = e.getY();
            // 设置鼠标默认类型
//            cursorType = Cursor.DEFAULT_CURSOR;
            cursorType = Cursor.DEFAULT;

            if (mouseY >= demo.getY() && mouseY <= demo.getY() + RESIZE_WIDTH &&
                    mouseX >= demo.getX() && mouseX <= demo.getX() + RESIZE_WIDTH) { // 光标在左上角
//                cursorType = Cursor.NW_RESIZE_CURSOR;
                cursorType = Cursor.NW_RESIZE;
            } else if (mouseY >= demo.getY() && mouseY <= demo.getY() + RESIZE_WIDTH &&
                    mouseX <= demo.getX() + width && mouseX >= demo.getX() + width - RESIZE_WIDTH) { // 光标在右上角
//                cursorType = Cursor.NE_RESIZE_CURSOR;
                cursorType = Cursor.NE_RESIZE;
            } else if (mouseY <= demo.getY() + height && mouseY >= demo.getY() + height - RESIZE_WIDTH &&
                    mouseX >= demo.getX() && mouseX <= demo.getX() + RESIZE_WIDTH) { // 光标在左下角
//                cursorType = Cursor.SW_RESIZE_CURSOR;
                cursorType = Cursor.SW_RESIZE;
            } else if (mouseY <= demo.getY() + height && mouseY >= demo.getY() + height - RESIZE_WIDTH &&
                    mouseX <= demo.getX() + width && mouseX >= demo.getX() + width - RESIZE_WIDTH) { // 光标在右下角
//                cursorType = Cursor.SE_RESIZE_CURSOR;
                cursorType = Cursor.SE_RESIZE;
            } else if (mouseY >= demo.getY() && mouseY <= demo.getY() + RESIZE_WIDTH &&
                    mouseX > demo.getX() && mouseX < demo.getX() + width) { // 光标在上边界
//                cursorType = Cursor.N_RESIZE_CURSOR;
                cursorType = Cursor.N_RESIZE;
            } else if (mouseY <= demo.getY() + height && mouseY >= demo.getY() + height - RESIZE_WIDTH &&
                    mouseX > demo.getX() && mouseX < demo.getX() + width) { // 光标在下边界
//                cursorType = Cursor.S_RESIZE_CURSOR;
                cursorType = Cursor.S_RESIZE;
            } else if (mouseX >= demo.getX() && mouseX <= demo.getX() + RESIZE_WIDTH &&
                    mouseY > demo.getY() && mouseY < demo.getY() + height) { // 光标在左边界
//                cursorType = Cursor.W_RESIZE_CURSOR;
                cursorType = Cursor.W_RESIZE;
            } else if (mouseX <= demo.getX() + width && mouseX >= demo.getX() + width - RESIZE_WIDTH &&
                    mouseY > demo.getY() && mouseY < demo.getY() + height) { // 光标在右边界
//                cursorType = Cursor.E_RESIZE_CURSOR;
                cursorType = Cursor.E_RESIZE;
            }
            // 改变光标类型
            group.setCursor(cursorType);
//            group.setCursor(Cursor.getPredefinedCursor(cursorType));
        });
        // 鼠标按下监听
        demo.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> {
            mouseX = e.getX();
            mouseY = e.getY();
            picX = demo.getX();
            picY = demo.getY();
            width = demo.getWidth();
            height = demo.getHeight();
        });
        // 鼠标释放监听
        demo.addEventFilter(MouseEvent.MOUSE_RELEASED, e -> {
            mouseX = e.getX();
            mouseY = e.getY();
            picX = demo.getX();
            picY = demo.getY();
            width = demo.getWidth();
            height = demo.getHeight();
        });
    }

    public void addButton(Image temImage) {
        Button out = new Button();
        out.setText("初始化");
        page.getChildren().add(out);
        AnchorPane.setRightAnchor(out, 30.0);
        AnchorPane.setBottomAnchor(out, 8.0);
        // 恢复模板块初始化参数
        out.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
            picX = 0;
            picY = 0;
            width = 200;
            height = 200;
            demo.setX(picX);
            demo.setY(picY);
            demo.setWidth(width);
            demo.setHeight(height);
        });

        Button synthesis = new Button();
        synthesis.setText("导入合成");
        page.getChildren().add(synthesis);
        AnchorPane.setRightAnchor(synthesis, 90.0);
        AnchorPane.setBottomAnchor(synthesis, 8.0);
        // 导入并合成图片
        synthesis.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
            FileChooser fileChooser = new FileChooser();
            fileChooser.setTitle("请选择导入合成图片");
            fileChooser.getExtensionFilters().addAll(
                    new FileChooser.ExtensionFilter("All Images", "*.*"),
                    new FileChooser.ExtensionFilter("JPG", "*.jpg"),
                    new FileChooser.ExtensionFilter("GIF", "*.gif"),
                    new FileChooser.ExtensionFilter("BMP", "*.bmp"),
                    new FileChooser.ExtensionFilter("PNG", "*.png")
            );
            File file = fileChooser.showOpenDialog(new Stage());
            // 生成临时文件,用于获取修改后的模板参数
            File synthesisFile = new File(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ".jpg");
            if (file != null) {
//                System.out.println(file);
                try {
                    Thumbnails.of(file)
                            .size((int) width, (int) height)
                            .outputQuality(1.0).toFile(synthesisFile);
                    // 创建图片对象
                    BufferedImage temBufferedImage = new BufferedImage((int) temImage.getWidth(), (int) temImage.getHeight(), BufferedImage.TYPE_INT_RGB);
                    // 基于图片创建绘图
                    Graphics2D g2D = temBufferedImage.createGraphics();
                     // 绘制图片
                    g2D.drawImage(ImageIO.read(new File(templatePath)), 0, 0, (int) temImage.getWidth(), (int) temImage.getHeight(), null);
                    g2D.drawImage(ImageIO.read(synthesisFile), (int) picX, (int) picY, (int) width, (int) height, null);
                    // 获取桌面路径
                    String deskPath = FileSystemView.getFileSystemView().getHomeDirectory().getAbsolutePath();
                    File outFile = new File(deskPath + "\\lin.jpg");
                    ImageIO.write(temBufferedImage, "jpg", outFile);
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                }
            }
            synthesisFile.delete();
        });

        Button save = new Button();
        save.setText("保存模板");
        page.getChildren().add(save);
        AnchorPane.setRightAnchor(save, 165.0);
        AnchorPane.setBottomAnchor(save, 8.0);
        // 保存模板块参数并生成按钮
        save.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
            int mapNum = buttonMap.size();
            if (mapNum < 1) {
                mapNum = 1;
            } else {
                mapNum++;
            }
            String buttonName = "button" + mapNum;
            Button button = new Button();
            button.setText("模板" + mapNum);
            page.getChildren().add(button);
            AnchorPane.setLeftAnchor(button, 30.0 + (mapNum - 1) * 60);
            AnchorPane.setBottomAnchor(button, 8.0);
            // 保存模板按钮对应的参数
            Map<String, Double> parameterMap = new HashMap<>();
            parameterMap.put("x", picX);
            parameterMap.put("y", picY);
            parameterMap.put("width", width);
            parameterMap.put("height", height);
            buttonMap.put(buttonName, parameterMap);
            // 监听生成的模板按钮并设置参数
            button.addEventFilter(MouseEvent.MOUSE_CLICKED, event -> {
//                System.out.println(buttonName);
                Map<String, Double> parameter = buttonMap.get(buttonName);
                picX = parameter.get("x");
                picY = parameter.get("y");
                width = parameter.get("width");
                height = parameter.get("height");
                demo.setX(picX);
                demo.setY(picY);
                demo.setWidth(width);
                demo.setHeight(height);
            });
        });

    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("Lin");
        // 添加底层模板
        Image temImage = addTemplate();
        // 添加模板块
        addMoudle();
        // 添加按钮
        addButton(temImage);
        // 创建场景(留出一点下边界放按钮)
        Scene scene = new Scene(page, temImage.getWidth(), temImage.getHeight() + 40);
        primaryStage.setScene(scene);
        primaryStage.setResizable(false);
        primaryStage.sizeToScene();
        primaryStage.show();
    }

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

由于这只是我个人练习和总结,所以就只是简单的功能实现而已,代码直接复制就可以运行了~

;