Кодирование и декодирование QR-кода с использованием zxing

Ладно, так что я собираюсь взять шанс, что кто-то здесь раньше использовал zxing. Я разрабатываю Java-приложение, и одна из его задач – кодировать массив байтов данных в 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)); - //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 

Очевидно, что текст кодируется, но фактические байты данных полностью отключены. Любая помощь будет оценена здесь.

Таким образом, для будущих ссылок для тех, кто не хочет тратить два дня на поиск в Интернете, чтобы понять это, когда вы кодируете байт-массивы в QR-коды, вы должны использовать набор символов ISO-8859-1 , а не UTF-8 ,

это мой рабочий пример Java-кода для кодирования QR-кода с использованием ZXing с кодировкой UTF-8, обратите внимание: вам нужно будет изменить данные пути и 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 hints = new Hashtable(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()); } } } 

Для чего это стоит, мой отличный звук, похоже, работает как с кодировками символов 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.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() } } 

Возможно, стоит посмотреть на QRGen , который построен поверх ZXing и поддерживает 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(); 

Если вам действительно нужно кодировать UTF-8, вы можете попробовать добавить символ порядка байтов в юникоде. Я не знаю, насколько широко поддерживается поддержка этого метода, но ZXing, по крайней мере, поддерживает его: http://code.google.com/p/zxing/issues/detail?id=103

Недавно я просматривал QR-режим, и я думаю, что видел ту же самую практику, о которой упоминалось в другом месте, но я не самый тупой.

Я попытался использовать 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 в очень старой версии (точно не знаю) использовал метод thar:

 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; 
Interesting Posts

Двойные мониторы на Optiplex 755

Разница между innerText и innerHTML

Как получить название города из координат широты и долготы в Картах Google?

Есть ли способ заставить компьютер Windows 7 обрабатывать autoruns.inf на USB-накопителе?

JQuery multiselect – установить значение, выбранное в раскрывающемся списке «Мультиселекция»

Перечисление всех развернутых конечных точек restа (весенняя загрузка, трикотаж)

Использовать gnu-screen и X вместо рабочей среды?

Windows для быстрого удаления текста?

gcc может скомпилировать вариационный шаблон, в то время как clang не может

Программа, которая выводит экран каждые 15 минут и сохраняет его в файл

Есть ли способ установить текущее местоположение вручную в Windows 8?

Запуск команды в новом окне терминала Mac OS X

Могут ли нестатические методы изменять статические переменные

Попытка запуска службы при загрузке на Android

Разрешения на закрытый ключ в папке .ssh?

Давайте будем гением компьютера.