Code QR encodage et décodage à l'aide de zxing
Ok, donc je vais prendre le risque que quelqu'un ici a déjà utilisé zxing avant. Je développe une application Java, et l'une des choses qu'elle doit faire est d'encoder un tableau octet de données dans un code QR et de le décoder plus tard.
voici un exemple de ce à quoi ressemble mon encoder:
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);
début de tableau d'octets dans ce code est utilisé pour le tester. Les données actuelles sur les octets varieront.
voici à quoi ressemble mon décodeur comme:
//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)
c'est une méthode qui convertit un tableau d'octets en une chaîne de caractères hexadécimaux.
Lorsque j'essaie d'exécuter ces deux blocs de code, c'est la sortie:
48454c4c4f
202b0b78cc00ec11ec11ec11ec11ec11ec11ec
il est clair que le texte est encodé, mais les octets réels des données sont complètement désactivés. Toute aide serait appréciée ici.
6 réponses
donc, pour référence future pour quiconque ne veut pas passer deux jours à chercher sur internet pour comprendre cela, quand vous encodez des tableaux bytes dans des Codes QR, vous devez utiliser le ISO-8859-1
jeu de caractères, pas UTF-8
.
ceci est mon exemple de travail Code Java pour encoder Code QR en utilisant ZXing avec encodage UTF-8, s'il vous plaît noter: vous aurez besoin de changer le chemin et les données utf8 à votre chemin et les caractères de langue
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());
}
}
}
pour ce que ça vaut, mon Groovy spike semble fonctionner avec les deux codages de caractères UTF-8 et ISO-8859-1. Pas sûr de ce qui se passera quand un décodeur Non zxing essaie de décoder L'image encodée UTF-8... varie probablement en fonction de l'appareil.
// ------------------------------------------------------------------------------------
// 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()
}
}
Peut-être intéressant de regarder QRGen, qui est construit sur ZXing et supporte UTF-8 avec ce genre de syntaxe:
// 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();
si vous avez vraiment besoin d'encoder UTF-8, Vous pouvez essayer de préparer l'ordre des octets unicode. Je n'ai aucune idée de l'ampleur du soutien à cette méthode, mais ZXing semble au moins la soutenir: http://code.google.com/p/zxing/issues/detail?id=103
j'ai lu sur des QR Mode récemment, et j' penser j'ai vu la même pratique mentionnée ailleurs, mais je n'ai pas le plus flou où.
j'ai essayé D'utiliser ISO-8859-1 comme indiqué dans la première réponse. Tout allait bien sur le codage, mais quand j'ai essayé d'obtenir le byte[] en utilisant la chaîne de résultat sur le décodage, tous les octets négatifs sont devenus le caractère 63 (point d'interrogation). Le code suivant ne fonctionne pas:
// 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;
cela semble si étrange parce que L'API dans une très ancienne version (ne sait pas exactement) avait une méthode qui fonctionne bien:
Vector byteSegments = result.getByteSegments();
alors j'ai essayé de chercher pourquoi cette méthode a été retirée et j'ai réalisé qu'il y avait un moyen de obtenez ByteSegments, à travers les métadonnées. Ainsi, ma méthode de décodage ressemble à:
// 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;