From e636498b5e5b07bcfcdf27a3461ea3b5e127e418 Mon Sep 17 00:00:00 2001 From: "MakKi (makki_d)" Date: Fri, 9 Nov 2018 23:05:07 +0900 Subject: [PATCH] Support Full-ASCII in Code93Writer (#1104) * support extended characters in Code93Writer * remove redundancy * add test for convertToExtended * thanks for review * fix comment, use package-private for testing --- .../com/google/zxing/oned/Code93Reader.java | 2 +- .../com/google/zxing/oned/Code93Writer.java | 110 +++++++++++++----- .../zxing/oned/Code93WriterTestCase.java | 24 ++++ 3 files changed, 109 insertions(+), 27 deletions(-) diff --git a/core/src/main/java/com/google/zxing/oned/Code93Reader.java b/core/src/main/java/com/google/zxing/oned/Code93Reader.java index 74cc38264..c2dddbc02 100644 --- a/core/src/main/java/com/google/zxing/oned/Code93Reader.java +++ b/core/src/main/java/com/google/zxing/oned/Code93Reader.java @@ -52,7 +52,7 @@ public final class Code93Reader extends OneDReader { 0x12E, 0x1D4, 0x1D2, 0x1CA, 0x16E, 0x176, 0x1AE, // - - % 0x126, 0x1DA, 0x1D6, 0x132, 0x15E, // Control chars? $-* }; - private static final int ASTERISK_ENCODING = CHARACTER_ENCODINGS[47]; + static final int ASTERISK_ENCODING = CHARACTER_ENCODINGS[47]; private final StringBuilder decodeRowResult; private final int[] counters; diff --git a/core/src/main/java/com/google/zxing/oned/Code93Writer.java b/core/src/main/java/com/google/zxing/oned/Code93Writer.java index a52eabbbc..bd13f94b6 100644 --- a/core/src/main/java/com/google/zxing/oned/Code93Writer.java +++ b/core/src/main/java/com/google/zxing/oned/Code93Writer.java @@ -38,46 +38,44 @@ public class Code93Writer extends OneDimensionalCodeWriter { return super.encode(contents, format, width, height, hints); } + /** + * @param contents barcode contents to encode. It should not be encoded for extended characters. + * @return a {@code boolean[]} of horizontal pixels (false = white, true = black) + */ @Override public boolean[] encode(String contents) { + contents = convertToExtended(contents); int length = contents.length(); if (length > 80) { throw new IllegalArgumentException( - "Requested contents should be less than 80 digits long, but got " + length); + "Requested contents should be less than 80 digits long after converting to extended encoding, but got " + length); } - //each character is encoded by 9 of 0/1's - int[] widths = new int[9]; //length of code + 2 start/stop characters + 2 checksums, each of 9 bits, plus a termination bar int codeWidth = (contents.length() + 2 + 2) * 9 + 1; - //start character (*) - toIntArray(Code93Reader.CHARACTER_ENCODINGS[47], widths); - boolean[] result = new boolean[codeWidth]; - int pos = appendPattern(result, 0, widths); + + //start character (*) + int pos = appendPattern(result, 0, Code93Reader.ASTERISK_ENCODING); for (int i = 0; i < length; i++) { int indexInString = Code93Reader.ALPHABET_STRING.indexOf(contents.charAt(i)); - toIntArray(Code93Reader.CHARACTER_ENCODINGS[indexInString], widths); - pos += appendPattern(result, pos, widths); + pos += appendPattern(result, pos, Code93Reader.CHARACTER_ENCODINGS[indexInString]); } //add two checksums int check1 = computeChecksumIndex(contents, 20); - toIntArray(Code93Reader.CHARACTER_ENCODINGS[check1], widths); - pos += appendPattern(result, pos, widths); + pos += appendPattern(result, pos, Code93Reader.CHARACTER_ENCODINGS[check1]); //append the contents to reflect the first checksum added contents += Code93Reader.ALPHABET_STRING.charAt(check1); int check2 = computeChecksumIndex(contents, 15); - toIntArray(Code93Reader.CHARACTER_ENCODINGS[check2], widths); - pos += appendPattern(result, pos, widths); + pos += appendPattern(result, pos, Code93Reader.CHARACTER_ENCODINGS[check2]); //end character (*) - toIntArray(Code93Reader.CHARACTER_ENCODINGS[47], widths); - pos += appendPattern(result, pos, widths); + pos += appendPattern(result, pos, Code93Reader.ASTERISK_ENCODING); //termination bar (single black bar) result[pos] = true; @@ -85,13 +83,6 @@ public class Code93Writer extends OneDimensionalCodeWriter { return result; } - private static void toIntArray(int a, int[] toReturn) { - for (int i = 0; i < 9; i++) { - int temp = a & (1 << (8 - i)); - toReturn[i] = temp == 0 ? 0 : 1; - } - } - /** * @param target output to append to * @param pos start position @@ -102,16 +93,20 @@ public class Code93Writer extends OneDimensionalCodeWriter { */ @Deprecated protected static int appendPattern(boolean[] target, int pos, int[] pattern, boolean startColor) { - return appendPattern(target, pos, pattern); - } - - private static int appendPattern(boolean[] target, int pos, int[] pattern) { for (int bit : pattern) { target[pos++] = bit != 0; } return 9; } + private static int appendPattern(boolean[] target, int pos, int a) { + for (int i = 0; i < 9; i++) { + int temp = a & (1 << (8 - i)); + target[pos + i] = temp != 0; + } + return 9; + } + private static int computeChecksumIndex(String contents, int maxWeight) { int weight = 1; int total = 0; @@ -125,4 +120,67 @@ public class Code93Writer extends OneDimensionalCodeWriter { } return total % 47; } + + static String convertToExtended(String contents) { + int length = contents.length(); + StringBuilder extendedContent = new StringBuilder(length * 2); + for (int i = 0; i < length; i++) { + char character = contents.charAt(i); + // ($)=a, (%)=b, (/)=c, (+)=d. see Code93Reader.ALPHABET_STRING + if (character == 0) { + // NUL: (%)U + extendedContent.append("bU"); + } else if (character <= 26) { + // SOH - SUB: ($)A - ($)Z + extendedContent.append('a'); + extendedContent.append((char) ('A' + character - 1)); + } else if (character <= 31) { + // ESC - US: (%)A - (%)E + extendedContent.append('b'); + extendedContent.append((char) ('A' + character - 27)); + } else if (character == ' ' || character == '$' || character == '%' || character == '+') { + // space $ % + + extendedContent.append(character); + } else if (character <= ',') { + // ! " # & ' ( ) * ,: (/)A - (/)L + extendedContent.append('c'); + extendedContent.append((char) ('A' + character - '!')); + } else if (character <= '9') { + extendedContent.append(character); + } else if (character == ':') { + // :: (/)Z + extendedContent.append("cZ"); + } else if (character <= '?') { + // ; - ?: (%)F - (%)J + extendedContent.append('b'); + extendedContent.append((char) ('F' + character - ';')); + } else if (character == '@') { + // @: (%)V + extendedContent.append("bV"); + } else if (character <= 'Z') { + // A - Z + extendedContent.append(character); + } else if (character <= '_') { + // [ - _: (%)K - (%)O + extendedContent.append('b'); + extendedContent.append((char) ('K' + character - '[')); + } else if (character == '`') { + // `: (%)W + extendedContent.append("bW"); + } else if (character <= 'z') { + // a - z: (*)A - (*)Z + extendedContent.append('d'); + extendedContent.append((char) ('A' + character - 'a')); + } else if (character <= 127) { + // { - DEL: (%)P - (%)T + extendedContent.append('b'); + extendedContent.append((char) ('P' + character - '{')); + } else { + throw new IllegalArgumentException( + "Requested content contains a non-encodable character: '" + character + "'"); + } + } + return extendedContent.toString(); + } + } diff --git a/core/src/test/java/com/google/zxing/oned/Code93WriterTestCase.java b/core/src/test/java/com/google/zxing/oned/Code93WriterTestCase.java index baf007990..b9b9f672e 100644 --- a/core/src/test/java/com/google/zxing/oned/Code93WriterTestCase.java +++ b/core/src/test/java/com/google/zxing/oned/Code93WriterTestCase.java @@ -36,6 +36,22 @@ public final class Code93WriterTestCase extends Assert { "101100101101011001101001101100101101100110101011011001011001101001101101001110101000" + "101001010010001010001001010000101001010001001001001001000101010100001000100101000010" + "10100111010101000010101011110100000"); + + doTest("\u0000\u0001\u001a\u001b\u001f $%+!,09:;@AZ[_`az{\u007f", + "00000" + "101011110" + + "111011010" + "110010110" + "100100110" + "110101000" + // bU aA + "100100110" + "100111010" + "111011010" + "110101000" + // aZ bA + "111011010" + "110010010" + "111010010" + "111001010" + // bE space $ + "110101110" + "101110110" + "111010110" + "110101000" + // % + cA + "111010110" + "101011000" + "100010100" + "100001010" + // cL 0 9 + "111010110" + "100111010" + "111011010" + "110001010" + // cZ bF + "111011010" + "110011010" + "110101000" + "100111010" + // bV A Z + "111011010" + "100011010" + "111011010" + "100101100" + // bK bO + "111011010" + "101101100" + "100110010" + "110101000" + // bW dA + "100110010" + "100111010" + "111011010" + "100010110" + // dZ bP + "111011010" + "110100110" + // bT + "110100010" + "110101100" + // checksum: 12 28 + "101011110" + "100000"); } private static void doTest(String input, CharSequence expected) throws WriterException { @@ -43,4 +59,12 @@ public final class Code93WriterTestCase extends Assert { assertEquals(expected, BitMatrixTestCase.matrixToString(result)); } + @Test + public void testConvertToExtended() throws Exception { + // non-extended chars are not changed. + String src = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%"; + String dst = Code93Writer.convertToExtended(src); + assertEquals(src, dst); + } + }