以XML JavaFX存储图像

时间:2015-04-17 20:32:23

标签: xml javafx

我有一个类,我使用XML来保存其数据,其中一个数据是默认情况下无法保存在XML中的图像,正如我读here,我必须转换它,但我没有在图像类中找不到任何parse()方法来解组它。是否可以将图像转换为字符串并将其转换回图像?

由于

1 个答案:

答案 0 :(得分:2)

我的“示例”项目中有这个例子。 (我不知道为什么要写它。)它基本上可以像@jewelsea在他的评论中描述的那样。

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintWriter;
import java.util.Base64;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

import javafx.embed.swing.SwingFXUtils;
import javafx.scene.image.Image;

import javax.imageio.ImageIO;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.XMLEvent;


public class ImageXMLAccessor {

    private final ExecutorService exec = Executors.newCachedThreadPool(r -> {
        Thread thread = new Thread(r);
        thread.setDaemon(true);
        return thread ;
    });

    public void saveImage(XMLEventWriter writer, XMLEventFactory eventFactory, Image image) 
            throws IOException, XMLStreamException {

        BufferedImage buffImage = SwingFXUtils.fromFXImage(image, null);
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        ImageIO.write(buffImage, "png", bytes);
        String encodedImage = Base64.getEncoder().encodeToString(bytes.toByteArray());
        writer.add(eventFactory.createCharacters(encodedImage));
    }

    public Image readImage(XMLEventReader eventReader) 
            throws IOException, XMLStreamException, InterruptedException, ExecutionException {

        PipedInputStream pipedInput = new PipedInputStream();

        FutureTask<Image> imageTask = new FutureTask<>(new Callable<Image>() {
            @Override
            public Image call() throws Exception {
                try (InputStream imageStream = Base64.getDecoder().wrap(pipedInput)) {

                    BufferedImage buffImage = ImageIO.read(imageStream);
                    return SwingFXUtils.toFXImage(buffImage, null);
                }
            }
        });

        exec.submit(imageTask);

        try (PrintWriter output = new PrintWriter(new PipedOutputStream(pipedInput))) {
            for (boolean done = false ; eventReader.hasNext() && ! done; ) {
                XMLEvent event = eventReader.nextEvent();
                if (event.isCharacters()) {
                    Characters characters = event.asCharacters();
                    String data = characters.getData();
                    output.write(data);
                } else if (event.isEndElement()) {
                    output.close();
                    done = true ;
                }
            }
        } 

        return imageTask.get();
    }

}

这是一个使用它的测试程序。您可以打开JPG或PNG文件,然后将其另存为XML(或打开类似结构的XML文件):

import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.nio.file.Files;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import javafx.stage.Stage;

import javax.xml.namespace.QName;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;

public class ImageXMLTest extends Application {

    @Override
    public void start(Stage primaryStage) {
        ImageXMLAccessor accessor = new ImageXMLAccessor();
        FileChooser chooser = new FileChooser();
        chooser.getExtensionFilters().add(new ExtensionFilter("Image Files", "*.jpg", "*.JPG", "*.png", "*.PNG"));
        chooser.getExtensionFilters().add(new ExtensionFilter("XML files", "*.xml", "*.XML"));
        Button openButton = new Button("Open...");
        ObjectProperty<Image> currentImage = new SimpleObjectProperty<>();
        openButton.setOnAction(event -> {
            File imageFile = chooser.showOpenDialog(primaryStage);
            if (imageFile != null) {
                if (imageFile.toString().toLowerCase().endsWith(".xml")) {
                    openFromXMLFile(imageFile, currentImage, accessor);
                } else {
                    openFromImageFile(imageFile, currentImage);                 
                }
            }
        });
        Button saveButton = new Button("Save to XML...");
        saveButton.setOnAction(event -> {
            File xmlFile = chooser.showSaveDialog(primaryStage);
            if (xmlFile != null) {
                try {
                    saveImageToXML(accessor, currentImage, xmlFile);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        saveButton.disableProperty().bind(currentImage.isNull());
        HBox controls = new HBox(5, openButton, saveButton);
        controls.setPadding(new Insets(10));
        controls.setAlignment(Pos.CENTER);
        ImageView imageView = new ImageView();
        imageView.setFitHeight(600);
        imageView.setFitWidth(800);
        imageView.setPreserveRatio(true);
        imageView.imageProperty().bind(currentImage);
        BorderPane root = new BorderPane(imageView, null, null, controls, null);
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private void saveImageToXML(ImageXMLAccessor accessor,
            ObjectProperty<Image> currentImage, File xmlFile)
            throws IOException, FactoryConfigurationError, XMLStreamException {
        Writer writer = Files.newBufferedWriter(xmlFile.toPath());
        XMLEventFactory eventFactory = XMLEventFactory.newFactory();
        XMLEventWriter eventWriter = XMLOutputFactory.newFactory().createXMLEventWriter(writer);
        eventWriter.add(eventFactory.createStartDocument());
        QName imageElement = new QName("image");
        eventWriter.add(eventFactory.createStartElement(imageElement, null, null));
        accessor.saveImage(eventWriter, eventFactory, currentImage.get());
        eventWriter.add(eventFactory.createEndElement(imageElement, null));
        eventWriter.add(eventFactory.createEndDocument());
        writer.close();
    }

    private void openFromImageFile(File imageFile,
            ObjectProperty<Image> currentImage) {
        try {
            currentImage.set(new Image(imageFile.toURI().toURL().toExternalForm(), true));
        } catch (Exception exc) {
            exc.printStackTrace();
        }
    }



    public void openFromXMLFile(File xmlFile, ObjectProperty<Image> currentImage, ImageXMLAccessor accessor) {

        new Thread(() -> {
            XMLInputFactory inputFactory = XMLInputFactory.newFactory() ;
            XMLEventReader eventReader = null ;
            try {
                eventReader = inputFactory.createXMLEventReader(Files.newBufferedReader(xmlFile.toPath()));
                while (eventReader.hasNext()) {
                    XMLEvent event = eventReader.nextEvent();
                    if (event.isStartElement()) {
                        StartElement startEl = event.asStartElement();
                        if ("image".equals(startEl.getName().getLocalPart())) {
                            Image image;
                            try {
                                image = accessor.readImage(eventReader);
                                Platform.runLater(() -> currentImage.set(image));
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (eventReader != null ){
                    try {
                        eventReader.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

    }

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