Javafx 如何序列化包含图像对象的映射?

Javafx 如何序列化包含图像对象的映射?,javafx,serialization,Javafx,Serialization,我正在创建一个图像库,其中包含相册,每个相册都包含图片。这些IREM存储在如下的哈希映射中 HashMap<Album, ArrayList<Picture>> albums=new HashMap<>(); 我总是得到这个异常:java.io.NotSerializableException:javafx.scene.image.image 有没有办法使我的图片可以序列化?您需要自定义图片的序列化。要自定义对象的序列化,请使用以下两种方法: void r

我正在创建一个图像库,其中包含相册,每个相册都包含图片。这些IREM存储在如下的哈希映射中

HashMap<Album, ArrayList<Picture>> albums=new HashMap<>();
我总是得到这个异常:java.io.NotSerializableException:javafx.scene.image.image


有没有办法使我的图片可以序列化?

您需要自定义
图片的序列化。要自定义对象的序列化,请使用以下两种方法:

  • void readObject(ObjectInputStream)抛出ClassNotFoundException、IOException
  • void writeObject(ObjectOutputStream)抛出IOException
这些方法可以有任何访问修饰符,但通常是(?)
private

如果您有以下课程:

public class Picture implements Serializable {

    private final String name;
    private final String place;
    private final String description;
    private transient Image image;

    public Picture(String name, String place, String description, Image image) {
        this.name = name;
        this.place = place;
        this.description = description;
        this.image = image;
    }

    public String getName() {
        return name;
    }

    public String getPlace() {
        return place;
    }

    public String getDescription() {
        return description;
    }

    public Image getImage() {
        return image;
    }

}
关于
图像的序列化,您至少有三个选项

  • 序列化映像的位置

    private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException {
        in.defaultReadObject();
        String url = (String) in.readObject();
        if (url != null) {
            image = new Image(url);
        }
    }
    
    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObjet();
        out.writeObject(image == null ? null : image.getUrl());
    }
    
    该方法是在JavaFX9中添加的

  • 通过
    PixelReader
    序列化
    图像的像素数据。反序列化时,您将使用
    PixelWriter

    private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException {
        in.defaultReadObject();
        if (in.readBoolean()) {
            int w = in.readInt();
            int h = in.readInt();
    
            byte[] b = new byte[w * h * 4];
            in.readFully(b);
    
            WritableImage wImage = new WritableImage(w, h);
            wImage.getPixelWriter().setPixels(0, 0, w, h, PixelFormat.getByteBgraInstance(), b, 0, w * 4);
    
            image = wImage;
        }
    }
    
    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
        out.writeBoolean(image != null);
        if (image != null) {
            int w = (int) image.getWidth();
            int h = (int) image.getHeight();
    
            byte[] b = new byte[w * h * 4];
            image.getPixelReader().getPixels(0, 0, w, h, PixelFormat.getByteBgraInstance(), b, 0, w * 4);
    
            out.writeInt(w);
            out.writeInt(h);
            out.write(b);
        }
    }
    
    警告:以这种方式序列化像素数据将以未压缩格式保存图像。图像可能非常大,使用此方法时可能会给您带来问题

    这取决于可用的
    PixelReader
    ,但情况并非总是如此。如果您阅读了的文档,您将看到(emphasis我的):


    此方法返回一个
    PixelReader
    ,如果图像可读,则该方法提供读取图像像素的访问权限。如果此方法返回null,则此图像此时不支持读取。如果图像是从源加载的,并且仍然不完整,则此方法将返回null{如果您想将
    图像
    保留为
    图片
    的成员,则必须自定义序列化。您希望如何序列化
    图像
    实际像素数据或图像的位置?我不知道确切的用例,但为什么要序列化图像?(假设您的意思是序列化像素数据。)如果直接进行,数据的大小将非常大,您将不得不执行大量IO。这就是为什么图像存储为PNG、JPEG等,因为您希望使用数据压缩。这也可以通过序列化来完成,但数据库中的blob不是更好的选择吗?@Slaw我需要序列化像素数据,每个图像都是loa由文件选择器编辑,然后由ImageView对象显示
    private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException {
        in.defaultReadObject();
        if (in.readBoolean()) {
            int w = in.readInt();
            int h = in.readInt();
    
            byte[] b = new byte[w * h * 4];
            in.readFully(b);
    
            WritableImage wImage = new WritableImage(w, h);
            wImage.getPixelWriter().setPixels(0, 0, w, h, PixelFormat.getByteBgraInstance(), b, 0, w * 4);
    
            image = wImage;
        }
    }
    
    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
        out.writeBoolean(image != null);
        if (image != null) {
            int w = (int) image.getWidth();
            int h = (int) image.getHeight();
    
            byte[] b = new byte[w * h * 4];
            image.getPixelReader().getPixels(0, 0, w, h, PixelFormat.getByteBgraInstance(), b, 0, w * 4);
    
            out.writeInt(w);
            out.writeInt(h);
            out.write(b);
        }
    }
    
    private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException {
        in.defaultReadObject();
        if (in.readBoolean()) {
            byte[] bytes = new byte[in.readInt()];
            in.readFully(bytes);
            image = new Image(new ByteArrayInputStream(bytes));
        }
    }
    
    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
        out.writeBoolean(image != null);
        if (image != null) {
            byte[] bytes;
            try (InputStream is = new URL(image.getUrl()).openStream()) {
                bytes = is.readAllBytes();
            }
            out.writeInt(bytes.length);
            out.write(bytes);
        }
    }