Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/363.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何制作Javafx图像裁剪应用程序_Java_Image_Canvas_Graphics_Javafx - Fatal编程技术网

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

如何制作Javafx图像裁剪应用程序,java,image,canvas,graphics,javafx,Java,Image,Canvas,Graphics,Javafx,我正在为我的同事构建一个裁剪图像的应用程序。 我使用FXML和场景生成器来构建GUI。用户单击按钮从计算机中选择图像。然后,图像显示在GUI中。用户可以在窗格中缩放和移动。最后,单击一个按钮将编辑后的图像保存到他的计算机中。然而,我真的不知道应该使用哪个库来构建应用程序。这是我第一次处理图形。我不知道如何读取图像、裁剪图像和写入图像。对于窗格?除了java文档之外,还有什么好的资源可以阅读,以了解如何执行此操作?关于StackOverflow,您的问题太多了,无法回答。我建议你从阅读这本书开始

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

然而,我真的不知道应该使用哪个库来构建应用程序。
这是我第一次处理图形。我不知道如何读取图像、裁剪图像和写入图像。对于窗格?

除了java文档之外,还有什么好的资源可以阅读,以了解如何执行此操作?

关于StackOverflow,您的问题太多了,无法回答。我建议你从阅读这本书开始

然而,由于这是一个有趣的话题,下面是代码中的答案

您需要考虑以下几点:

  • 将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;


        }
    }
}
导入java.awt.Graphics2D;
导入java.awt.image.buffereImage;
导入java.io.File;
导入java.io.IOException;
导入javafx.application.application;
导入javafx.embed.swing.SwingFXUtils;
导入javafx.event.ActionEvent;
导入javafx.event.EventHandler;
导入javafx.geometry.Bounds;
导入javafx.geometry.Rectangle2D;
导入javafx.scene.Group;
导入javafx.scene.scene;
导入javafx.scene.Snapshot参数;
导入javafx.scene.control.ContextMenu;
导入javafx.scene.control.MenuItem;
导入javafx.scene.control.ScrollPane;
导入javafx.scene.image.image;
导入javafx.scene.image.ImageView;
导入javafx.scene.image.WritableImage;
导入javafx.scene.input.MouseEvent;
导入javafx.scene.layout.BorderPane;
导入javafx.scene.paint.Color;
导入javafx.scene.shape.Rectangle;
导入javafx.scene.shape.StrokeLineCap;
导入javafx.stage.FileChooser;
导入javafx.stage.stage;
导入javax.imageio.imageio;
/**
*加载图像,提供矩形以便选择橡胶带。按鼠标右键“裁剪”上下文菜单,然后在选择矩形处裁剪图像并将其保存为jpg。
*/
公共类ImageCropWithRubberBand扩展了应用程序{
橡皮筋选择橡皮筋选择;
图像视图图像视图;
初级阶段;
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
公共无效开始(阶段primaryStage){
this.primaryStage=primaryStage;
初级阶段。设置标题(“图像裁剪”);
BorderPane根=新的BorderPane();
//图像层的容器
ScrollPane ScrollPane=新的ScrollPane();
//图像层:一组图像
Group imageLayer=新组();
//加载图像
//Image Image=newimage(getClass().getResource(“cat.jpg”).toExternalForm());
图像=新图像(“https://upload.wikimedia.org/wikipedia/commons/thumb/1/14/Gatto_europeo4.jpg/1024px-Gatto_europeo4.jpg");
//作为javafx节点的图像容器
imageView=新的imageView(图像);
//将图像添加到图层
imageLayer.getChildren().add(imageView);
//如果图像较大,请使用滚动窗格查看图像
scrollPane.setContent(imageLayer);
//在场景中放置滚动窗格
root.setCenter(滚动窗格);
//橡胶带选择
rubberBandSelection=新的rubberBandSelection(imageLayer);
//创建上下文菜单和菜单项
ContextMenu ContextMenu=新建ContextMenu();
MenuItem cropMenuItem=新MenuItem(“作物”);
setOnAction(新的EventHandler()){
公共无效句柄(ActionEvent e){
//获取图像裁剪的边界
Bounds selectionBounds=rubberBandSelection.getBounds();
//显示边界信息
System.out.println(“所选区域:+selectionBounds”);
//裁剪图像
裁剪(选择边界);
}
});
contextMenu.getItems().add(cropMenuItem);
//设置图像层上的关联菜单
setOnMousePressed(新的EventHandler(){
@凌驾
公共无效句柄(MouseeEvent事件){
if(event.isSecondaryButtonDown()){
show(imageLayer,event.getScreenX(),event.getScreenY());
}
}
});
设置场景(新场景(根,1024768));
primaryStage.show();
}
私有无效裁剪(边界){
FileChooser FileChooser=newfilechooser();
setTitle(“保存图像”);
File File=fileChooser.showsavedilog(primaryStage);
if(file==null)
返回;
int width=(int)bounds.getWidth();
int height=(int)bounds.getHeight();
SnapshotParameters=新的SnapshotParameters();
参数。设置填充(颜色。透明);
parameters.setViewport(新的矩形2D(bounds.getMinX(),bounds.getMinY(),width,height));
WritableImage wi=新的WritableImage(宽度、高度);
imageView.snapshot(参数,wi);
//保存图像
//!!!由于透明性而存在错误(使用下面的方法)!!!
// --------------------------------
//试一试{
//write(SwingFXUtils.fromFXImage(wi,null),“jpg”,文件);
//}捕获(IOE异常){
//e.printStackTrace();
//      }
//保存图像(不带alpha)
// --------------------------------
BuffereImage bufImageARGB=SwingFXUtils.fromFXIm