2010-03-21 20 views
34

Ok, quindi ho intenzione di togliere la possibilità che qualcuno qui abbia usato zxing prima. Sto sviluppando un'applicazione Java e una delle cose che deve fare è codificare una matrice di byte di dati in un QR Code e quindi decodificarla in un secondo momento.Codifica e decodifica del codice QR con zxing

Ecco un esempio di ciò che il mio encoder assomiglia:

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

L'array di byte dall'inizio in questo codice è solo utilizzato per testarlo. I dati byte effettivi saranno variati.

Ecco ciò che il mio decoder assomiglia:

//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) è un metodo che converte un array di byte in una stringa di caratteri esadecimali.

Quando si tenta di eseguire questi due blocchi di codice insieme, questa è l'uscita:

48454c4c4f 
202b0b78cc00ec11ec11ec11ec11ec11ec11ec 

Chiaramente il testo viene codificato, ma i byte effettivi dei dati sono completamente spento. Qualsiasi aiuto sarebbe apprezzato qui.

+0

captureActivity dalla fotocamera e dopo la decodifica, è mostra i risultati in base al tipo di dati memorizzati nel codice QR. per esempio. se l'URL del sito web è codificato nel codice QR, la schermata dei risultati avrà un pulsante per aprire quell'URL e, a sua volta, anche. Ho bisogno di leggere l'immagine dalla scheda SD, decodificarla e gestire l'uscita nello stesso modo che fa zxing in caso di decodifica tramite captureActivity. Cosa devo fare dopo aver ricevuto l'output in "Risultato risultato"? –

+0

Dovresti pubblicare una nuova domanda per chiedere questo, con esempi del tuo codice. Otterrai una risposta migliore in tal senso di quella che potrei fornire qui. – LandonSchropp

risposta

44

Quindi, per riferimento futuro per chiunque non desideri trascorrere due giorni a cercare su Internet per capire come funziona, quando si codificano gli array di byte in codici QR, è necessario utilizzare il set di caratteri ISO-8859-1, non UTF-8.

+2

non è vero - vedi la mia risposta con il codice WORKING allegato su UTF-8 wi zxing qrencoder, e ogni decoder provato da iphone ha funzionato – Shaybc

+10

Questa è in realtà una buona risposta. Le specifiche del codice QR non consentono nulla tranne ISO-8859-1. A volte i decodificatori inducono a interpretare correttamente l'UTF-8, ma non sempre riescono a farlo correttamente. –

+1

È vero. mentre stavo usando "UTF-8", la mia applicazione stava lavorando su alcuni sanners di androide e Iphone ma non tutti. Quando ho cambiato questa codifica in "ISO-8859-1", tutti gli scanner/decodificatori sono stati in grado di scansionare l'immagine QR codificata. – Khushboo

1

Se è davvero necessario codificare UTF-8, è possibile provare a eseguire la preposizione del contrassegno di ordine byte unicode. Non ho idea di quanto sia diffuso il supporto per questo metodo è, ma ZXing almeno sembra sostenerlo: http://code.google.com/p/zxing/issues/detail?id=103

Ho letto su modalità QR di recente, e io penso che ho visto lo stesso pratica menzionata altrove, ma non ho il più pallido dove.

0

Ho provato a utilizzare ISO-8859-1 come detto nella prima risposta. Tutto è andato bene sulla codifica, ma quando ho cercato di ottenere il byte [] usando la stringa di risultati sulla decodifica, tutti i byte negativi sono diventati il ​​carattere 63 (punto interrogativo). Il seguente codice non funziona:

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

Sembra così strano perché l'API in una versione molto vecchia (non so esattamente) aveva un metodo Thar funziona bene:

Vector byteSegments = result.getByteSegments(); 

Così ho provato per cercare perché questo metodo è stato rimosso e capito che c'è un modo per ottenere ByteSegments, attraverso i metadati. Quindi il mio metodo di decodifica assomiglia:

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

questo è il mio esempio di lavoro di codice Java per codificare il codice QR utilizzando ZXing con codifica UTF-8, si prega di notare: è necessario modificare i dati del percorso e utf8 al vostro percorso e i caratteri di lingua

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

Anche questo pezzo di codice funziona sulla mia parte. Anche se, il mio codice non è esattamente lo stesso. Non sto salvando l'immagine restituita dalla codifica(). Tuttavia, sto convertendo l'istanza di BitMatrix in BitMap. – Khushboo

+2

Shaybc, la tua immagine QR codificata potrebbe essere analizzata da alcune app di Android o Iphone ma non tutte. È necessario utilizzare "ISO-8859-1" invece di "UTF-8" per la corretta codifica delle immagini QR. Puoi testare la tua immagine Qr codificata usando l'app Red Laser o QR Droid da Google Play. – Khushboo

+2

Appena controllato sia Red Laser che QR Droid ed entrambi riescono a leggere i dati codificati UTF8 – GetUsername

5

per quel che vale, il mio picco Groovy sembra funzionare sia con UTF-8 e codifiche di carattere ISO-8859-1. Non sono sicuro di cosa accadrà quando un decodificatore non zxing tenta di decodificare l'immagine codificata UTF-8 sebbene ... probabilmente vari a seconda del dispositivo.

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

Forse vale la pena guardare QRGen, che è costruito in cima ZXing e supporta UTF-8 con questo tipo di sintassi: l'immagine del codice di acquisizione QR

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