2010-03-21 213 views
34

好的,所以我打算把這裏有人使用zxing的機會拿過來。我正在開發一個Java應用程序,它需要做的事情之一就是將一個字節數組數據編碼成QR碼,然後在稍後解碼。使用zxing的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 

顯然,文本被編碼,但實際的數據字節是完全關閉。任何幫助將不勝感激。

+0

captureActivity拍攝QR碼的圖像後對其進行解碼,它根據QR碼中存儲的數據類型顯示結果。例如如果網站URL使用QR碼編碼,結果屏幕將會有一個按鈕來打開該URL和likevise。 我需要從SD卡讀取圖像,對它進行解碼並以相同的方式處理輸出zxing在通過captureActivity解碼的情況下。 在「結果結果」中輸出結果後需要做什麼? – 2012-03-28 12:31:33

+0

您應該發佈一個新問題,詢問這個問題,並附上您的代碼示例。你會得到比我在這裏提供的更好的答案。 – LandonSchropp 2012-03-29 01:24:07

回答

44

因此,對於任何不想花費兩天時間搜索互聯網的人來說,當您將字節數組編碼爲QR碼時,您必須使用ISO-8859-1字符集,而不是UTF-8

+2

不正確 - 請參閱我的答案,附上關於UTF-8 wi zxing qrencoder的工作代碼,並且我嘗試從iphone上運行的每個解碼器都工作 – Shaybc 2011-10-13 15:51:15

+10

這實際上是一個很好的答案。 QR碼規範不允許任何內容,但ISO-8859-1。解碼器有時會正確猜測UTF-8,但不能總是正確。 – 2011-10-14 05:47:58

+1

的確如此。當我使用「UTF-8」時,我的應用程序正在研究Android和Iphone的一些技術,但不是全部。當我將此編碼更改爲「ISO-8859-1」時,所有掃描器/解碼器都能夠掃描編碼的QR圖像。 – Khushboo 2012-04-18 06:40:23

1

如果您確實需要編碼UTF-8,您可以嘗試預先添加unicode字節順序標記。我不知道這種方法的支持有多普遍,但斑馬線至少出現來支持它: http://code.google.com/p/zxing/issues/detail?id=103

我一直在QR模式下閱讀了最近,我認爲我已經看到了同樣在其他地方提到的做法,但我並不是最迷糊的地方。

0

我試着在第一個答案中使用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(並不確切地知道)有一個方法塔爾效果很好:

Vector byteSegments = result.getByteSegments(); 

所以,我想搜索爲什麼這個方法被刪除,並意識到有一種方法可以通過元數據獲取ByteSegments。所以,我的解碼方法如下所示:

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

這是我的工作示例的Java代碼中使用斑馬線用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()); 
    } 
} 

} 
+0

這段代碼也在我的最後工作。雖然,我的代碼不完全一樣。我沒有保存由encode()返回的圖像。但是,我將BitMatrix轉換爲BitMap實例。 – Khushboo 2012-04-16 13:05:51

+2

Shaybc,您編碼的QR圖像可能會被某些android或iphone的應用掃描,但不是全部。您需要使用「ISO-8859-1」而不是「UTF-8」來成功QR圖像編碼。您可以使用Google Play上的紅色激光應用或QR Droid應用測試編碼的Qr圖像。 – Khushboo 2012-04-18 06:43:22

+2

剛剛檢查過紅激光和QR Droid,他們都成功讀取UTF8編碼數據 – GetUsername 2013-09-17 07:36:52

5

對於它的價值,我的常規秒殺似乎與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()   
    } 

} 
1

也許值得看的QRGen,這是建立在斑馬線之上,並且支持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();