QR Code encoding and decoding using zxing

前端 未结 6 2079
孤城傲影
孤城傲影 2020-11-27 10:05

Okay, so I\'m going to take the off chance that someone here has used zxing before. I\'m developing a Java application, and one of the things it needs to do is encode a byte

相关标签:
6条回答
  • 2020-11-27 10:46

    this is my working example Java code to encode QR code using ZXing with UTF-8 encoding, please note: you will need to change the path and utf8 data to your path and language characters

    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());
        }
    }
    
    }
    
    0 讨论(0)
  • 2020-11-27 10:48

    For what it's worth, my groovy spike seems to work with both UTF-8 and ISO-8859-1 character encodings. Not sure what will happen when a non zxing decoder tries to decode the UTF-8 encoded image though... probably varies depending on the device.

    // ------------------------------------------------------------------------------------
    // 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()        
        }
    
    }
    
    0 讨论(0)
  • 2020-11-27 10:51

    Maybe worth looking at QRGen, which is built on top of ZXing and supports UTF-8 with this kind of syntax:

    // 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();
    
    0 讨论(0)
  • 2020-11-27 10:57

    I tried using ISO-8859-1 as said in the first answer. All went ok on encoding, but when I tried to get the byte[] using result string on decoding, all negative bytes became the character 63 (question mark). The following code does not work:

    // 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;
    

    It looks so strange because the API in a very old version (don't know exactly) had a method thar works well:

    Vector byteSegments = result.getByteSegments();
    

    So I tried to search why this method was removed and realized that there is a way to get ByteSegments, through metadata. So my decode method looks like:

    // 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;
    
    0 讨论(0)
  • 2020-11-27 11:03

    If you really need to encode UTF-8, you can try prepending the unicode byte order mark. I have no idea how widespread the support for this method is, but ZXing at least appears to support it: http://code.google.com/p/zxing/issues/detail?id=103

    I've been reading up on QR Mode recently, and I think I've seen the same practice mentioned elsewhere, but I've not the foggiest where.

    0 讨论(0)
  • 2020-11-27 11:04

    So, for future reference for anybody who doesn't want to spend two days searching the internet to figure this out, when you encode byte arrays into QR Codes, you have to use the ISO-8859-1character set, not UTF-8.

    0 讨论(0)
提交回复
热议问题