如何用 BitMatrix 对象序列化 HashMap? (二维码/zxing)

How can I serialize a HashMap with BitMatrix objects? (QR Codes / zxing)

我有一个名为 QRGenerator 的 "static class",其目的是生成 BitMatrix 对象并从中生成 BufferedImage 对象。这是它的代码:

package ericsonwrp.republica.vintage.caixa;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.EnumMap;
import java.util.Map;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

public class QRGenerator {

    private static BufferedImage image = null;
    private static int size = 250;
    private static BitMatrix byteMatrix = null;

    public static BitMatrix generateBitMatrix(String codeText) {
        try {
            Map<EncodeHintType, Object> hintMap = new EnumMap<EncodeHintType, Object>(EncodeHintType.class);
            hintMap.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            hintMap.put(EncodeHintType.MARGIN, 1);
            hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
            QRCodeWriter qrCodeWriter = new QRCodeWriter();
            byteMatrix = qrCodeWriter.encode(codeText, BarcodeFormat.QR_CODE, size,
                    size, hintMap);
        } catch (WriterException e) {
            e.printStackTrace();
        }
        return byteMatrix;
    }

    public static BufferedImage generateImage(BitMatrix byteMatrix) {
        int width = byteMatrix.getWidth();
        image = new BufferedImage(width, width,
                BufferedImage.TYPE_INT_RGB);
        image.createGraphics();
        Graphics2D graphics = (Graphics2D) image.getGraphics();
        graphics.setColor(Color.WHITE);
        graphics.fillRect(0, 0, width, width);
        graphics.setColor(Color.BLACK);
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < width; j++) {
                if (byteMatrix.get(i, j)) {
                    graphics.fillRect(i, j, 1, 1);
                }
            }
        }
        return image;
    }

}

我有另一个 class 叫做 "RepublicaVintageFile",其目的是定义一个唯一的文件来存储我的应用程序的 "content",并提供一种方法来序列化(并读取, 这与问题无关) this "content".这是它的代码:

package ericsonwrp.republica.vintage.caixa;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.util.HashMap;

public class RepublicaVintageFile {

    private HashMap<String, Object> content;

    public RepublicaVintageFile() {
        setContent(new HashMap<String, Object>());
    }

    public void serializeContent(String path) throws IOException {
        FileOutputStream fout = new FileOutputStream(path, true);
        ObjectOutput out = null;
        try {
          out = new ObjectOutputStream(fout);   
          out.writeObject(getContent());
        } finally {
          try {
            if (out != null) {
              out.close();
            }
          } catch (IOException ex) {
            // ignore close exception
          }
          try {
            fout.close();
          } catch (IOException ex) {
            // ignore close exception
          }
        }
    }

    public HashMap<String, Object> getContent() {
        return content;
    }

    public void setContent(HashMap<String, Object> content) {
        this.content = content;
    }

}

我的应用程序的 "content" 包含 BitMatrix 对象,这些对象保存在不同文件 (private HashMap<String, BitMatrix> qrItems;) 中 HashMap 内的标签下。由于序列化最终的 BufferedImage 给了我一个 java.io.NotSerializableException,我尝试序列化 BitMatrix 对象。但是,令我失望的是,这也是不可能的。这是堆栈跟踪:

java.io.NotSerializableException: com.google.zxing.common.BitMatrix
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.writeObject(Unknown Source)
    at java.util.HashMap.internalWriteEntries(Unknown Source)
    at java.util.HashMap.writeObject(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
    at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.writeObject(Unknown Source)
    at java.util.HashMap.internalWriteEntries(Unknown Source)
    at java.util.HashMap.writeObject(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
    at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.writeObject(Unknown Source)
    at ericsonwrp.republica.vintage.caixa.RepublicaVintageFile.serializeContent(RepublicaVintageFile.java:26)
    at ericsonwrp.republica.vintage.caixa.MainFrame.openSaveAsDialog(MainFrame.java:204)
    at ericsonwrp.republica.vintage.caixa.MainFrame.access(MainFrame.java:177)
    at ericsonwrp.republica.vintage.caixa.MainFrame.actionPerformed(MainFrame.java:112)
    at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
    at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
    at javax.swing.AbstractButton.doClick(Unknown Source)
    at javax.swing.plaf.basic.BasicMenuItemUI.doClick(Unknown Source)
    at javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(Unknown Source)
    at java.awt.Component.processMouseEvent(Unknown Source)
    at javax.swing.JComponent.processMouseEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    at java.awt.Container.processEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access0(Unknown Source)
    at java.awt.EventQueue.run(Unknown Source)
    at java.awt.EventQueue.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.run(Unknown Source)
    at java.awt.EventQueue.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

考虑到所有这些,我提出了我的问题:如何使用 BitMatrix 对象序列化 HashMap?这很重要,因为我不想在一个文件夹中存储 100 个(或更多)单独的 .png 文件并且必须一直读取图像才能获取它们的内容。

我已经设法 "save" 和 "load" BitMatrix 对象将它们转换为布尔二维数组。

private HashMap<String, BitMatrix> qrMatrixes;
private HashMap<String, boolean[][]> qrMatrixBooleanArrays;

如您所见,我有一个 的 HashMap,具有 boolean[][] 格式的等价物。这就是我如何制作这样的 "translation"(将位从每个 BitMatrix 对象传输到 boolean[][] 数组):

for (Map.Entry<String, BitMatrix> e : getQrMatrixes().entrySet()) {
    boolean[][] b = new boolean[e.getValue().getHeight()][e.getValue().getWidth()];
    for (int j = 0; j < e.getValue().getHeight(); j++) {
        for (int k = 0; k < e.getValue().getWidth(); k++) {
            b[j][k] = e.getValue().get(j, k);
        }
    }
    qrMatrixBooleanArrays.put(e.getKey(), b);
}

Java 的 Serializer 序列化这样的对象 (HashMap< String, boolean[][] >) 没有问题,不管它是如何嵌套的(我想象它可以与原始类型一起工作,带有老式数组)。这是加载文件后使用二维码更新列表的完整方法:

    public void updateList() {
        if (MainFrame.getCurrentFile() != null) {
            setQrMatrixes(new HashMap<String, BitMatrix>());
            setQrMatrixBooleanArrays(new HashMap<String, boolean[][]>());
            for (Map.Entry<String, boolean[][]> e : ((HashMap<String, boolean[][]>) MainFrame.getCurrentFile().getContent().get("Qr Codes")).entrySet()) {
                getQrMatrixBooleanArrays().put(e.getKey(), e.getValue());
            }
            for (Map.Entry<String, boolean[][]> e : getQrMatrixBooleanArrays().entrySet()) {
                BitMatrix b = new BitMatrix(e.getValue().length, e.getValue().length);
                for (int i = 0; i < e.getValue().length; i++) {
                    for (int j = 0; j < e.getValue()[i].length; j++) {
                        if (e.getValue()[i][j] == true) {
                            b.set(i, j);
                        }
                    }
                }
                getQrMatrixes().put(e.getKey(), b);
                qrListModel.addElement(e.getKey());
            }
        } else {
            System.out.println("No file is loaded.");
        }
    }

恐怕要说清楚有点难。 Explore the docs 对于 BitMatrix 对象,只需将内容复制到原始二维数组中。祝你好运!