Сохранение javafx WritableImage с ImageIO не работает - PullRequest
0 голосов
/ 19 мая 2019

Я создаю инструмент, способный создавать маски для изображений (подготовка набора данных для обучения нейронной сети).Предполагается, что пользователь рисует курсором на холсте, который вложен в область привязки, в качестве фона которой используется изображение.Холст имеет непрозрачность 0,5.

Это проект, созданный Maven на Intellij Idea.

Я думаю, что стоит упомянуть, что объект Canvas не хранит информацию об изображении, он имеет черный цвет и, рисуя, пользователь создает на нем белые кружки.

Я застрял насохранение изображения в файл.Я прочитал много вопросов по SO, и ни один из них не помог мне.

Снимок экрана из моего приложения: Screenshot of my app

Письменное изображение (это должен быть черный фон с этой белой V-образной меткой):

Screenshot of rendered image

Вот код для прослушивателя onClick для кнопки (сохранение файла).Я установил цвет снимка как прозрачный и ненасыщенный изображение в оттенках серого.

@FXML
    public void onClickButton(ActionEvent evt) throws IOException {

        SnapshotParameters sp = new SnapshotParameters();
        sp.setFill(Color.TRANSPARENT);

        WritableImage image = user_mask_canvas.snapshot(sp, null);

        //desaturafion to get grayscale image
        ImageView desaturated = new ImageView(image);
        ColorAdjust desaturate = new ColorAdjust();
        desaturate.setSaturation(-1);
        desaturated.setEffect(desaturate);

        BufferedImage i =SwingFXUtils.fromFXImage(desaturated.getImage(), null);


        File file = new File("image.bmp");
        if(!file.exists()){
            file.createNewFile();
        }
        System.out.println(file.getAbsolutePath());
        try {
            ImageIO.write(i, "bmp", file);
            System.out.println("written");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

Вот полный код.

Основной:

package sample;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("/sample.fxml"));
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }


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

Контроллер:

package sample;

import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.SnapshotParameters;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;

public class Controller implements Initializable {

    @FXML
    private Button button;

    @FXML
    private AnchorPane image_placeholder;

    @FXML
    private Canvas user_mask_canvas;
    //this is supposed to be in the anchor pane

    private String imgRef;

    final WritableImage wb = new WritableImage(96,96);


    @FXML
    public void onClickButton(ActionEvent evt) throws IOException {

        SnapshotParameters sp = new SnapshotParameters();
        sp.setFill(Color.TRANSPARENT);

        WritableImage image = user_mask_canvas.snapshot(sp, null);

        //desaturafion to get grayscale image
        ImageView desaturated = new ImageView(image);
        ColorAdjust desaturate = new ColorAdjust();
        desaturate.setSaturation(-1);
        desaturated.setEffect(desaturate);

        BufferedImage i =SwingFXUtils.fromFXImage(desaturated.getImage(), null);


        File file = new File("image.bmp");
        if(!file.exists()){
            file.createNewFile();
        }
        System.out.println(file.getAbsolutePath());
        try {
            ImageIO.write(i, "bmp", file);
            System.out.println("written");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public void initialize(URL location, ResourceBundle resources) {

        WritableImage image = new WritableImage(96,96);
        try {
            SwingFXUtils.toFXImage(ImageIO.read(getClass().getResource("/1.tif")), image);
        } catch (java.io.IOException e) {
            e.printStackTrace();
        }
        BackgroundImage myBI= new BackgroundImage(image,
                BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.DEFAULT,
                BackgroundSize.DEFAULT);
        image_placeholder.setBackground(new Background(myBI));

        final GraphicsContext graphicsContext = user_mask_canvas.getGraphicsContext2D();
        graphicsContext.setFill(Color.BLACK);
        graphicsContext.fillRect(0, 0, user_mask_canvas.getWidth(), user_mask_canvas.getHeight());
        graphicsContext.setFill(Color.WHITE);
        graphicsContext.setStroke(Color.WHITE);

        user_mask_canvas.addEventHandler(MouseEvent.MOUSE_PRESSED,
                new EventHandler<MouseEvent>(){
                    public void handle(MouseEvent event) {
                        //graphicsContext.beginPath();
                        graphicsContext.moveTo(event.getX(), event.getY());
                        graphicsContext.stroke();

                    }
                });

        user_mask_canvas.addEventHandler(MouseEvent.MOUSE_DRAGGED,
                new EventHandler<MouseEvent>(){
                    public void handle(MouseEvent event) {
                        graphicsContext.lineTo(event.getX(), event.getY());
                        graphicsContext.stroke();
                        graphicsContext.fillOval(event.getX(), event.getY(), 8, 8);
                        //graphicsContext.closePath();
                        //graphicsContext.beginPath();
                        graphicsContext.moveTo(event.getX(), event.getY());
                    }
                });

        user_mask_canvas.addEventHandler(MouseEvent.MOUSE_RELEASED,
                new EventHandler<MouseEvent>(){
                    public void handle(MouseEvent event) {
                        graphicsContext.lineTo(event.getX(), event.getY());
                        graphicsContext.stroke();
                        //graphicsContext.closePath();
                    }
                });
    }
}

sample.fxml:

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

<?import javafx.scene.canvas.Canvas?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
    <center>
        <HBox prefHeight="100.0" prefWidth="200.0" BorderPane.alignment="CENTER">
            <children>
                <Canvas height="200.0" width="200.0" />
                <AnchorPane fx:id="image_placeholder" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="96.0" prefWidth="96.0">
               <children>
                        <Canvas fx:id="user_mask_canvas" height="96.0" opacity="0.5" width="96.0" />
               </children>
                </AnchorPane>
            <Button fx:id="button" mnemonicParsing="false" onAction="#onClickButton" text="Button" />
            </children>
        </HBox>
    </center>
</BorderPane>
...