我正在为我的同事构建一个裁剪图像的应用程序。我使用fxml和场景生成器来构建gui。用户单击按钮从计算机中选择图像。然后,图像显示在gui中。用户可以在窗格中缩放和移动。最后,点击一个按钮将编辑后的图像保存到他的电脑中。然而,我真的不知道我应该用什么库来构建应用程序。这是我第一次处理图形。我不知道如何读图像,裁剪图像和写图像。窗格的javafx画布?除了javadoc之外,还有什么好的资源可以用来学习如何做到这一点?
cwxwcias1#
你的问题太多了,不能马上回答。我建议您从阅读有关javafx的oracle官方文档开始。然而,由于这是一个有趣的主题,下面是代码中的答案。您需要考虑以下几点:使用imageview作为容器如果图像较大,请使用滚动窗格提供选择机制裁剪图像本身将图像保存到文件中,提供文件选择器对话框差不多就是这样。在下面的示例中,使用鼠标左键进行选择,使用鼠标右键进行裁剪上下文菜单,然后在选择边界处拍摄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<ActionEvent>() { 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<MouseEvent>() { @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<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() { @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<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() { @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<MouseEvent> onMouseReleasedEventHandler = new EventHandler<MouseEvent>() { @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; } } }
截图:裁剪图像:
1条答案
按热度按时间cwxwcias1#
你的问题太多了,不能马上回答。我建议您从阅读有关javafx的oracle官方文档开始。
然而,由于这是一个有趣的主题,下面是代码中的答案。
您需要考虑以下几点:
使用imageview作为容器
如果图像较大,请使用滚动窗格
提供选择机制
裁剪图像本身
将图像保存到文件中,提供文件选择器对话框
差不多就是这样。在下面的示例中,使用鼠标左键进行选择,使用鼠标右键进行裁剪上下文菜单,然后在选择边界处拍摄imageview节点的快照,然后将图像保存到文件中。
截图:
裁剪图像: