如何制作Javafx图像裁剪应用程序

我正在为同事构建一个应用程序来裁剪图像。 我在场景生成器中使用FXML来构建GUI。 用户单击按钮从他的计算机中选择图像。 然后,图像显示在GUI中。 用户可以在窗格中缩放和移动。 最后,单击按钮将编辑的图像保存到他的计算机。

但是,我真的不知道应该用什么库来构建应用程序。
这是我第一次处理图形。 我不知道如何阅读图像,裁剪图像和写入图像。 Javafx Canvas for Pane?

除了java doc之外的任何好资源都可以阅读以了解我该如何做到这一点?

您的问题太多,无法在StackOverflow上得到解答。 我建议你先阅读有关JavaFX的官方Oracle文档 。

但是,由于这是一个有趣的话题,这里是代码中的答案。

您需要考虑以下几点:

  • 使用ImageView作为容器
  • 如果图像较大,请使用ScrollPane
  • 提供选择机制
  • 裁剪图像本身
  • 将图像保存到文件,提供文件选择器对话框

这就是它。 在下面的示例中,使用鼠标左键进行选择,使用鼠标右键选择裁剪上下文菜单,然后在选择边界处获取ImageView节点的快照,然后将图像保存到文件中。

import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javafx.application.Application; import javafx.embed.swing.SwingFXUtils; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Bounds; import javafx.geometry.Rectangle2D; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.SnapshotParameters; import javafx.scene.control.ContextMenu; import javafx.scene.control.MenuItem; import javafx.scene.control.ScrollPane; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.image.WritableImage; import javafx.scene.input.MouseEvent; import javafx.scene.layout.BorderPane; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.scene.shape.StrokeLineCap; import javafx.stage.FileChooser; import javafx.stage.Stage; import javax.imageio.ImageIO; /** * Load image, provide rectangle for rubberband selection. Press right mouse button for "crop" context menu which then crops the image at the selection rectangle and saves it as jpg. */ public class ImageCropWithRubberBand extends Application { RubberBandSelection rubberBandSelection; ImageView imageView; Stage primaryStage; public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { this.primaryStage = primaryStage; primaryStage.setTitle("Image Crop"); BorderPane root = new BorderPane(); // container for image layers ScrollPane scrollPane = new ScrollPane(); // image layer: a group of images Group imageLayer = new Group(); // load the image // Image image = new Image( getClass().getResource( "cat.jpg").toExternalForm()); Image image = new Image("https://upload.wikimedia.org/wikipedia/commons/thumb/1/14/Gatto_europeo4.jpg/1024px-Gatto_europeo4.jpg"); // the container for the image as a javafx node imageView = new ImageView( image); // add image to layer imageLayer.getChildren().add( imageView); // use scrollpane for image view in case the image is large scrollPane.setContent(imageLayer); // put scrollpane in scene root.setCenter(scrollPane); // rubberband selection rubberBandSelection = new RubberBandSelection(imageLayer); // create context menu and menu items ContextMenu contextMenu = new ContextMenu(); MenuItem cropMenuItem = new MenuItem("Crop"); cropMenuItem.setOnAction(new EventHandler() { public void handle(ActionEvent e) { // get bounds for image crop Bounds selectionBounds = rubberBandSelection.getBounds(); // show bounds info System.out.println( "Selected area: " + selectionBounds); // crop the image crop( selectionBounds); } }); contextMenu.getItems().add( cropMenuItem); // set context menu on image layer imageLayer.setOnMousePressed(new EventHandler() { @Override public void handle(MouseEvent event) { if (event.isSecondaryButtonDown()) { contextMenu.show(imageLayer, event.getScreenX(), event.getScreenY()); } } }); primaryStage.setScene(new Scene(root, 1024, 768)); primaryStage.show(); } private void crop( Bounds bounds) { FileChooser fileChooser = new FileChooser(); fileChooser.setTitle("Save Image"); File file = fileChooser.showSaveDialog( primaryStage); if (file == null) return; int width = (int) bounds.getWidth(); int height = (int) bounds.getHeight(); SnapshotParameters parameters = new SnapshotParameters(); parameters.setFill(Color.TRANSPARENT); parameters.setViewport(new Rectangle2D( bounds.getMinX(), bounds.getMinY(), width, height)); WritableImage wi = new WritableImage( width, height); imageView.snapshot(parameters, wi); // save image // !!! has bug because of transparency (use approach below) !!! // -------------------------------- // try { // ImageIO.write(SwingFXUtils.fromFXImage( wi, null), "jpg", file); // } catch (IOException e) { // e.printStackTrace(); // } // save image (without alpha) // -------------------------------- BufferedImage bufImageARGB = SwingFXUtils.fromFXImage(wi, null); BufferedImage bufImageRGB = new BufferedImage(bufImageARGB.getWidth(), bufImageARGB.getHeight(), BufferedImage.OPAQUE); Graphics2D graphics = bufImageRGB.createGraphics(); graphics.drawImage(bufImageARGB, 0, 0, null); try { ImageIO.write(bufImageRGB, "jpg", file); System.out.println( "Image saved to " + file.getAbsolutePath()); } catch (IOException e) { e.printStackTrace(); } graphics.dispose(); } /** * Drag rectangle with mouse cursor in order to get selection bounds */ public static class RubberBandSelection { final DragContext dragContext = new DragContext(); Rectangle rect = new Rectangle(); Group group; public Bounds getBounds() { return rect.getBoundsInParent(); } public RubberBandSelection( Group group) { this.group = group; rect = new Rectangle( 0,0,0,0); rect.setStroke(Color.BLUE); rect.setStrokeWidth(1); rect.setStrokeLineCap(StrokeLineCap.ROUND); rect.setFill(Color.LIGHTBLUE.deriveColor(0, 1.2, 1, 0.6)); group.addEventHandler(MouseEvent.MOUSE_PRESSED, onMousePressedEventHandler); group.addEventHandler(MouseEvent.MOUSE_DRAGGED, onMouseDraggedEventHandler); group.addEventHandler(MouseEvent.MOUSE_RELEASED, onMouseReleasedEventHandler); } EventHandler onMousePressedEventHandler = new EventHandler() { @Override public void handle(MouseEvent event) { if( event.isSecondaryButtonDown()) return; // remove old rect rect.setX(0); rect.setY(0); rect.setWidth(0); rect.setHeight(0); group.getChildren().remove( rect); // prepare new drag operation dragContext.mouseAnchorX = event.getX(); dragContext.mouseAnchorY = event.getY(); rect.setX(dragContext.mouseAnchorX); rect.setY(dragContext.mouseAnchorY); rect.setWidth(0); rect.setHeight(0); group.getChildren().add( rect); } }; EventHandler onMouseDraggedEventHandler = new EventHandler() { @Override public void handle(MouseEvent event) { if( event.isSecondaryButtonDown()) return; double offsetX = event.getX() - dragContext.mouseAnchorX; double offsetY = event.getY() - dragContext.mouseAnchorY; if( offsetX > 0) rect.setWidth( offsetX); else { rect.setX(event.getX()); rect.setWidth(dragContext.mouseAnchorX - rect.getX()); } if( offsetY > 0) { rect.setHeight( offsetY); } else { rect.setY(event.getY()); rect.setHeight(dragContext.mouseAnchorY - rect.getY()); } } }; EventHandler onMouseReleasedEventHandler = new EventHandler() { @Override public void handle(MouseEvent event) { if( event.isSecondaryButtonDown()) return; // remove rectangle // note: we want to keep the ruuberband selection for the cropping => code is just commented out /* rect.setX(0); rect.setY(0); rect.setWidth(0); rect.setHeight(0); group.getChildren().remove( rect); */ } }; private static final class DragContext { public double mouseAnchorX; public double mouseAnchorY; } } } 

截图:

在此处输入图像描述

裁剪后的图片:

在此处输入图像描述