From 05d470fcca97edfcd90e5734b3216a80e17e90ce Mon Sep 17 00:00:00 2001 From: Project Nayuki Date: Thu, 17 Aug 2017 20:28:28 +0000 Subject: [PATCH] Added BitBuffer-based constructor to Java QrSegment class, updated existing library and demo code to use it. --- .../nayuki/qrcodegen/QrCodeGeneratorDemo.java | 18 +++++---- java/io/nayuki/qrcodegen/QrSegment.java | 40 ++++++++++++++----- .../nayuki/qrcodegen/QrSegmentAdvanced.java | 2 +- 3 files changed, 41 insertions(+), 19 deletions(-) diff --git a/java/io/nayuki/qrcodegen/QrCodeGeneratorDemo.java b/java/io/nayuki/qrcodegen/QrCodeGeneratorDemo.java index 31efd0c..b0a59bd 100644 --- a/java/io/nayuki/qrcodegen/QrCodeGeneratorDemo.java +++ b/java/io/nayuki/qrcodegen/QrCodeGeneratorDemo.java @@ -141,14 +141,18 @@ public final class QrCodeGeneratorDemo { qr = QrCode.encodeText(madoka, QrCode.Ecc.LOW); writePng(qr.toImage(9, 4), "madoka-utf8-QR.png"); - byte[] packedKanjiData = { // Kanji mode encoding (13 bits per character) - (byte)0x01, (byte)0xAC, (byte)0x00, (byte)0x9F, (byte)0x80, (byte)0xAE, (byte)0xD5, (byte)0x6B, (byte)0x85, (byte)0x70, - (byte)0x28, (byte)0xE1, (byte)0x29, (byte)0x02, (byte)0xC8, (byte)0x6F, (byte)0x43, (byte)0x1A, (byte)0x18, (byte)0xA0, - (byte)0x1B, (byte)0x05, (byte)0x04, (byte)0x28, (byte)0x80, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x92, (byte)0x44, - (byte)0x80, (byte)0x24, (byte)0x90, (byte)0x00, (byte)0x04, (byte)0x10, (byte)0x20, (byte)0xA1, (byte)0x13, (byte)0x08, - (byte)0xA8, (byte)0x00, (byte)0x04, (byte)0x10, (byte)0x1F, (byte)0xF0, (byte)0x04, (byte)0x00, + int[] packedKanjiData = { // Kanji mode encoding (13 bits per character) + 0x0035, 0x1002, 0x0FC0, 0x0AED, 0x0AD7, + 0x015C, 0x0147, 0x0129, 0x0059, 0x01BD, + 0x018D, 0x018A, 0x0036, 0x0141, 0x0144, + 0x0001, 0x0000, 0x0249, 0x0240, 0x0249, + 0x0000, 0x0104, 0x0105, 0x0113, 0x0115, + 0x0000, 0x0208, 0x01FF, 0x0008, }; - segs = Arrays.asList(new QrSegment(QrSegment.Mode.KANJI, madoka.length(), packedKanjiData, madoka.length() * 13)); + BitBuffer bb = new BitBuffer(); + for (int c : packedKanjiData) + bb.appendBits(c, 13); + segs = Arrays.asList(new QrSegment(QrSegment.Mode.KANJI, madoka.length(), bb)); qr = QrCode.encodeSegments(segs, QrCode.Ecc.LOW); writePng(qr.toImage(9, 4), "madoka-kanji-QR.png"); } diff --git a/java/io/nayuki/qrcodegen/QrSegment.java b/java/io/nayuki/qrcodegen/QrSegment.java index e68a944..2a7d557 100644 --- a/java/io/nayuki/qrcodegen/QrSegment.java +++ b/java/io/nayuki/qrcodegen/QrSegment.java @@ -51,7 +51,10 @@ public final class QrSegment { */ public static QrSegment makeBytes(byte[] data) { Objects.requireNonNull(data); - return new QrSegment(Mode.BYTE, data.length, data, data.length * 8); + BitBuffer bb = new BitBuffer(); + for (byte b : data) + bb.appendBits(b & 0xFF, 8); + return new QrSegment(Mode.BYTE, data.length, bb); } @@ -74,7 +77,7 @@ public final class QrSegment { int rem = digits.length() - i; if (rem > 0) // 1 or 2 digits remaining bb.appendBits(Integer.parseInt(digits.substring(i)), rem * 3 + 1); - return new QrSegment(Mode.NUMERIC, digits.length(), bb.getBytes(), bb.bitLength()); + return new QrSegment(Mode.NUMERIC, digits.length(), bb); } @@ -100,7 +103,7 @@ public final class QrSegment { } if (i < text.length()) // 1 character remaining bb.appendBits(ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)), 6); - return new QrSegment(Mode.ALPHANUMERIC, text.length(), bb.getBytes(), bb.bitLength()); + return new QrSegment(Mode.ALPHANUMERIC, text.length(), bb); } @@ -135,16 +138,18 @@ public final class QrSegment { * @throws IllegalArgumentException if the value is outside the range [0, 106) */ public static QrSegment makeEci(int assignVal) { - byte[] data; + BitBuffer bb = new BitBuffer(); if (0 <= assignVal && assignVal < (1 << 7)) - data = new byte[]{(byte)assignVal}; - else if ((1 << 7) <= assignVal && assignVal < (1 << 14)) - data = new byte[]{(byte)(0x80 | (assignVal >>> 8)), (byte)assignVal}; - else if ((1 << 14) <= assignVal && assignVal < 999999) - data = new byte[]{(byte)(0xC0 | (assignVal >>> 16)), (byte)(assignVal >>> 8), (byte)assignVal}; - else + bb.appendBits(assignVal, 8); + else if ((1 << 7) <= assignVal && assignVal < (1 << 14)) { + bb.appendBits(2, 2); + bb.appendBits(assignVal, 14); + } else if ((1 << 14) <= assignVal && assignVal < 999999) { + bb.appendBits(6, 3); + bb.appendBits(assignVal, 21); + } else throw new IllegalArgumentException("ECI assignment value out of range"); - return new QrSegment(Mode.ECI, 0, data, data.length * 8); + return new QrSegment(Mode.ECI, 0, bb); } @@ -166,6 +171,19 @@ public final class QrSegment { /*---- Constructor ----*/ + /** + * Creates a new QR Code data segment with the specified parameters and data. + * @param md the mode, which is not {@code null} + * @param numCh the data length in characters, which is non-negative + * @param data the data bits of this segment, which is not {@code null} + * @throws NullPointerException if the mode or bit buffer is {@code null} + * @throws IllegalArgumentException if the character count is negative + */ + public QrSegment(Mode md, int numCh, BitBuffer data) { + this(md, numCh, data.getBytes(), data.bitLength()); + } + + /** * Creates a new QR Code data segment with the specified parameters and data. * @param md the mode, which is not {@code null} diff --git a/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java b/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java index 39c6563..34847e4 100644 --- a/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java +++ b/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java @@ -246,7 +246,7 @@ public final class QrSegmentAdvanced { throw new IllegalArgumentException("String contains non-kanji-mode characters"); bb.appendBits(val, 13); } - return new QrSegment(QrSegment.Mode.KANJI, text.length(), bb.getBytes(), bb.bitLength()); + return new QrSegment(QrSegment.Mode.KANJI, text.length(), bb); }