2010-03-21 25 views
34

Bien, entonces voy a aprovechar la posibilidad de que alguien aquí haya usado zxing antes. Estoy desarrollando una aplicación Java, y una de las cosas que necesita hacer es codificar una matriz de datos de bytes en un Código QR y luego decodificarlo en un momento posterior.Codificación y codificación de código QR usando zxing

He aquí un ejemplo de lo que mi codificador parece:

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

La matriz de bytes principio en este código se usa sólo para probarlo. Los datos de bytes reales serán variados.

Aquí es lo que mi decodificador ve así:

//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) es un método que convierte una matriz de bytes en una cadena de caracteres hexadecimales.

Cuando trato de ejecutar estos dos bloques de código juntos, esta es la salida:

48454c4c4f 
202b0b78cc00ec11ec11ec11ec11ec11ec11ec 

Es evidente que se está codificando el texto, pero los bytes de datos son completamente apagado. Cualquier ayuda sería apreciada aquí.

+0

captureActivity de la cámara y después de la decodificación de ella, muestra los resultados según el tipo de datos almacenados en el código QR. p.ej. si la URL del sitio web está codificada en código QR, la pantalla de resultados tendrá un botón para abrir esa URL y así poder verla. Necesito leer la imagen de la tarjeta SD, decodificarla y manejar la salida de la misma manera que lo hace zxing en caso de descodificación a través de captureActivity. ¿Qué debo hacer después de obtener la salida en "Result result"? –

+0

Debería publicar una nueva pregunta preguntándole esto, con ejemplos de su código. Obtendrás una mejor respuesta haciendo eso de la que podría brindar aquí. – LandonSchropp

Respuesta

44

Por lo tanto, para futuras referencias para cualquiera que no desee pasar dos días buscando en Internet para resolver esto, cuando codifica matrices de bytes en códigos QR, debe usar el conjunto de caracteres ISO-8859-1, no UTF-8.

+2

no es cierto - por favor vea mi respuesta con el código de TRABAJO adjunto sobre UTF-8 wi zxing qrencoder, y cada decodificador que intenté de iphone funcionó – Shaybc

+10

Esa es realmente una buena respuesta. La especificación del código QR no permite nada excepto ISO-8859-1. Los decodificadores suponen UTF-8 correctamente a veces, pero no siempre pueden hacerlo bien. –

+1

Eso es verdad. mientras estaba usando "UTF-8", mi aplicación estaba trabajando en algunos sanners de Android y Iphone, pero no en todos. Cuando cambié esta codificación a "ISO-8859-1", todos los escáneres/decodificadores pudieron escanear la imagen QR codificada. – Khushboo

1

Si realmente necesita codificar UTF-8, puede probar anteponiendo la marca de orden de bytes Unicode. No tengo idea de cuán extendido está el apoyo a este método es, pero ZXing al menos parece apoyarlo: http://code.google.com/p/zxing/issues/detail?id=103

He estado leyendo sobre el modo QR recientemente, y yo creo que he visto el mismo práctica mencionada en otro lugar, pero no tengo la más mínima idea de dónde.

0

Intenté usar ISO-8859-1 como dije en la primera respuesta. Todo fue bien en la codificación, pero cuando traté de obtener el byte [] utilizando la cadena de resultados en la decodificación, todos los bytes negativos se convirtieron en el carácter 63 (signo de interrogación). El código siguiente no funciona:

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

Se ve tan extraño porque la API de una versión muy antigua (no sé exactamente) tenía una Thar método funciona así:

Vector byteSegments = result.getByteSegments(); 

Así que probé para buscar por qué se eliminó este método y se dio cuenta de que hay una forma de obtener ByteSegments a través de metadatos. Así que mi método de decodificación se parece a:

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

esta es mi ejemplo de trabajo de código Java para codificar código QR utilizando ZXing con codificación UTF-8, por favor tenga en cuenta: tendrá que cambiar los datos de la trayectoria y utf8 a su camino y caracteres del idioma

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

Esta pieza de código también está funcionando en mi extremo. Aunque, mi código no es exactamente el mismo. No estoy guardando la Imagen devuelta por la codificación(). Sin embargo, estoy convirtiendo la instancia de BitMatrix a BitMap. – Khushboo

+2

Shaybc, su imagen QR codificada podría ser escaneada por algunas aplicaciones de Android o Iphone, pero no todas. Necesita utilizar "ISO-8859-1" en lugar de "UTF-8" para una codificación de imagen QR exitosa. Puede probar su Qr Image codificada utilizando la aplicación láser roja o la aplicación QR Droid de Google Play. – Khushboo

+2

Acabo de comprobar tanto Red Laser como QR Droid y ambos lograron leer datos codificados en UTF8 – GetUsername

5

Por lo que vale la pena, mi pico maravilloso parece que funciona tanto con las codificaciones de caracteres ISO-8859-1 UTF-8 y. Sin embargo, no estoy seguro de qué sucederá cuando un decodificador no zxing intente decodificar la imagen codificada en UTF-8 ... probablemente varíe dependiendo 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

Tal vez vale la pena mirar QRGen, que se construye en la parte superior de ZXing y compatible con UTF-8 con este tipo de sintaxis: imagen de código de captura de 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(); 
Cuestiones relacionadas