代码之家  ›  专栏  ›  技术社区  ›  LandonSchropp

使用ZXing进行二维码编码和解码

  •  35
  • LandonSchropp  · 技术社区  · 14 年前

    好吧,所以我要放弃以前这里有人用过ZXing的机会。我正在开发一个Java应用程序,它需要做的一件事是把一个字节数组数据编码成一个QR代码,然后在以后解码它。

    下面是我的编码器的一个示例:

    byte[] b = {0x48, 0x45, 0x4C, 0x4C, 0x4F};
    //convert the byte array into a UTF-8 string
    String data;
    try {
        data = new String(b, "UTF8");
    }
    catch (UnsupportedEncodingException e) {
     //the program shouldn't be able to get here
     return;
    }
    
    //get a byte matrix for the data
    ByteMatrix matrix;
    com.google.zxing.Writer writer = new QRCodeWriter();
    try {
     matrix = writer.encode(data, com.google.zxing.BarcodeFormat.QR_CODE, width, height);
    }
    catch (com.google.zxing.WriterException e) {
     //exit the method
     return;
    }
    
    //generate an image from the byte matrix
    int width = matrix.getWidth(); 
    int height = matrix.getHeight(); 
    
    byte[][] array = matrix.getArray();
    
    //create buffered image to draw to
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    
    //iterate through the matrix and draw the pixels to the image
    for (int y = 0; y < height; y++) { 
     for (int x = 0; x < width; x++) { 
      int grayValue = array[y][x] & 0xff; 
      image.setRGB(x, y, (grayValue == 0 ? 0 : 0xFFFFFF));
     }
    }
    
    //write the image to the output stream
    ImageIO.write(image, "png", outputStream);
    

    此代码中的起始字节数组仅用于测试它。实际字节数据将有所不同。

    我的解码器如下:

    //get the data from the input stream
    BufferedImage image = ImageIO.read(inputStream);
    
    //convert the image to a binary bitmap source
    LuminanceSource source = new BufferedImageLuminanceSource(image);
    BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
    
    //decode the barcode
    QRCodeReader reader = new QRCodeReader();
    
    Result result;
    try {
     result = reader.decode(bitmap, hints);
    } catch (ReaderException e) {
     //the data is improperly formatted
     throw new MCCDatabaseMismatchException();
    }
    
    byte[] b = result.getRawBytes();
    System.out.println(ByteHelper.convertUnsignedBytesToHexString(result.getText().getBytes("UTF8")));
    System.out.println(ByteHelper.convertUnsignedBytesToHexString(b));
    

    convertUnsignedBytesToHexString(byte) 是转换十六进制字符字符串中的字节数组的方法。

    当我尝试同时运行这两个代码块时,这是输出:

    48454c4c4f
    202b0b78cc00ec11ec11ec11ec11ec11ec11ec
    

    显然,正在对文本进行编码,但实际的数据字节完全关闭。如果有任何帮助,我们将不胜感激。

    6 回复  |  直到 10 年前
        1
  •  47
  •   LandonSchropp    11 年前

    因此,为了将来参考任何不想花两天时间搜索互联网来解决这个问题的人,当你将字节数组编码成二维码时,你必须使用 ISO-8859-1 字符集,不是 UTF-8 .

        2
  •  18
  •   Flexo - Save the data dump sunny moon    13 年前

    这是我的工作示例Java代码,使用ZUTY用UTF-8编码来编码QR代码,请注意:您需要将路径和UTF8数据更改为您的路径和语言字符。

    package com.mypackage.qr;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.nio.ByteBuffer;
    import java.nio.CharBuffer;
    import java.nio.charset.CharacterCodingException;
    import java.nio.charset.Charset;
    import java.nio.charset.CharsetEncoder;
    import java.util.Hashtable;
    
    import com.google.zxing.EncodeHintType;
    import com.google.zxing.MultiFormatWriter;
    import com.google.zxing.client.j2se.MatrixToImageWriter;
    import com.google.zxing.common.*;
    
    public class CreateQR {
    
    public static void main(String[] args)
    {
        Charset charset = Charset.forName("UTF-8");
        CharsetEncoder encoder = charset.newEncoder();
        byte[] b = null;
        try {
            // Convert a string to UTF-8 bytes in a ByteBuffer
            ByteBuffer bbuf = encoder.encode(CharBuffer.wrap("utf 8 characters - i used hebrew, but you should write some of your own language characters"));
            b = bbuf.array();
        } catch (CharacterCodingException e) {
            System.out.println(e.getMessage());
        }
    
        String data;
        try {
            data = new String(b, "UTF-8");
            // get a byte matrix for the data
            BitMatrix matrix = null;
            int h = 100;
            int w = 100;
            com.google.zxing.Writer writer = new MultiFormatWriter();
            try {
                Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>(2);
                hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
                matrix = writer.encode(data,
                com.google.zxing.BarcodeFormat.QR_CODE, w, h, hints);
            } catch (com.google.zxing.WriterException e) {
                System.out.println(e.getMessage());
            }
    
            // change this path to match yours (this is my mac home folder, you can use: c:\\qr_png.png if you are on windows)
                    String filePath = "/Users/shaybc/Desktop/OutlookQR/qr_png.png";
            File file = new File(filePath);
            try {
                MatrixToImageWriter.writeToFile(matrix, "PNG", file);
                System.out.println("printing to " + file.getAbsolutePath());
            } catch (IOException e) {
                System.out.println(e.getMessage());
            }
        } catch (UnsupportedEncodingException e) {
            System.out.println(e.getMessage());
        }
    }
    
    }
    
        3
  •  5
  •   klassek    13 年前

    值得一提的是,我的groovy峰值似乎可以同时使用utf-8和iso-8859-1字符编码。但不确定非ZXing解码器尝试解码UTF-8编码图像时会发生什么…可能因设备而异。

    // ------------------------------------------------------------------------------------
    // Requires: groovy-1.7.6, jdk1.6.0_03, ./lib with zxing core-1.7.jar, javase-1.7.jar 
    // Javadocs: http://zxing.org/w/docs/javadoc/overview-summary.html
    // Run with: groovy -cp "./lib/*" zxing.groovy
    // ------------------------------------------------------------------------------------
    
    import com.google.zxing.*
    import com.google.zxing.common.*
    import com.google.zxing.client.j2se.*
    
    import java.awt.image.BufferedImage
    import javax.imageio.ImageIO
    
    def class zxing {
        def static main(def args) {
            def filename = "./qrcode.png"
            def data = "This is a test to see if I can encode and decode this data..."
            def charset = "UTF-8" //"ISO-8859-1" 
            def hints = new Hashtable<EncodeHintType, String>([(EncodeHintType.CHARACTER_SET): charset])
    
            writeQrCode(filename, data, charset, hints, 100, 100)
    
            assert data == readQrCode(filename, charset, hints)
        }
    
        def static writeQrCode(def filename, def data, def charset, def hints, def width, def height) {
            BitMatrix matrix = new MultiFormatWriter().encode(new String(data.getBytes(charset), charset), BarcodeFormat.QR_CODE, width, height, hints)
            MatrixToImageWriter.writeToFile(matrix, filename.substring(filename.lastIndexOf('.')+1), new File(filename))
        }
    
        def static readQrCode(def filename, def charset, def hints) {
            BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(ImageIO.read(new FileInputStream(filename)))))
            Result result = new MultiFormatReader().decode(binaryBitmap, hints)
    
            result.getText()        
        }
    
    }
    
        4
  •  2
  •   lucrussell    10 年前

    也许值得一看 QRGen ,它构建在zxing之上,支持使用这种语法的utf-8:

    // if using special characters don't forget to supply the encoding
    VCard johnSpecial = new VCard("Jöhn Dɵe")
                            .setAdress("ëåäöƞ Sträät 1, 1234 Döestüwn");
    QRCode.from(johnSpecial).withCharset("UTF-8").file();
    
        5
  •  1
  •   perennialmind    14 年前

    如果您真的需要对UTF-8进行编码,您可以尝试在Unicode字节顺序标记之前进行编码。我不知道这种方法的支持有多广泛,但ZXing至少似乎支持它: http://code.google.com/p/zxing/issues/detail?id=103

    我最近一直在读二维码模式,我 认为 我在其他地方也看到过同样的做法,但我不知道在哪里。

        6
  •  0
  •   Bruno Medeiros    13 年前

    我试着使用ISO-8859-1,如第一个答案中所述。在编码方面一切正常,但当我尝试使用解码时的结果字符串获取字节[]时,所有负字节都变成了字符63(问号)。以下代码不起作用:

    // Encoding works great
    byte[] contents = new byte[]{-1};
    QRCodeWriter codeWriter = new QRCodeWriter();
    BitMatrix bitMatrix = codeWriter.encode(new String(contents, Charset.forName("ISO-8859-1")), BarcodeFormat.QR_CODE, w, h);
    
    // Decodes like this fails
    LuminanceSource ls = new BufferedImageLuminanceSource(encodedBufferedImage);
    Result result = new QRCodeReader().decode(new BinaryBitmap( new HybridBinarizer(ls)));
    byte[] resultBytes = result.getText().getBytes(Charset.forName("ISO-8859-1")); // a byte[] with byte 63 is given
    return resultBytes;
    

    这看起来很奇怪,因为在一个非常老的版本(不知道确切的)中,API有一个方法thar可以很好地工作:

    Vector byteSegments = result.getByteSegments();
    

    所以我尝试搜索为什么删除了这个方法,并意识到有一种方法可以通过元数据获取字节集。所以我的解码方法如下:

    // Decodes like this works perfectly
    LuminanceSource ls = new BufferedImageLuminanceSource(encodedBufferedImage);
    Result result = new QRCodeReader().decode(new BinaryBitmap( new HybridBinarizer(ls)));
    Vector byteSegments = (Vector) result.getResultMetadata().get(ResultMetadataType.BYTE_SEGMENTS);  
    int i = 0;
    int tam = 0;
    for (Object o : byteSegments) {
        byte[] bs = (byte[])o;
        tam += bs.length;
    }
    byte[] resultBytes = new byte[tam];
    i = 0;
    for (Object o : byteSegments) {
        byte[] bs = (byte[])o;
        for (byte b : bs) {
            resultBytes[i++] = b;
        }
    }
    return resultBytes;