From f653154da3f520ffccb01a366b6e21cea140af04 Mon Sep 17 00:00:00 2001 From: srowen Date: Mon, 16 Jul 2012 19:17:56 +0000 Subject: [PATCH] Issue 1314 add hint to control margin in Writer, and switch to more natural boolean[] representation git-svn-id: https://zxing.googlecode.com/svn/trunk@2353 59b500cc-1b3d-0410-9834-0bbf25fbcc57 --- core/src/com/google/zxing/EncodeHintType.java | 7 +++ .../com/google/zxing/oned/CodaBarWriter.java | 32 ++++++------ .../com/google/zxing/oned/Code128Writer.java | 8 +-- .../com/google/zxing/oned/Code39Writer.java | 16 +++--- .../com/google/zxing/oned/EAN13Writer.java | 14 +++--- .../src/com/google/zxing/oned/EAN8Writer.java | 18 ++++--- core/src/com/google/zxing/oned/ITFWriter.java | 17 ++++--- .../zxing/oned/OneDimensionalCodeWriter.java | 50 ++++++++++--------- .../com/google/zxing/oned/UPCEANWriter.java | 6 ++- .../com/google/zxing/qrcode/QRCodeWriter.java | 13 +++-- 10 files changed, 98 insertions(+), 83 deletions(-) diff --git a/core/src/com/google/zxing/EncodeHintType.java b/core/src/com/google/zxing/EncodeHintType.java index 3d2df658e..5d56ed9a8 100644 --- a/core/src/com/google/zxing/EncodeHintType.java +++ b/core/src/com/google/zxing/EncodeHintType.java @@ -35,6 +35,13 @@ public enum EncodeHintType { */ CHARACTER_SET, + /** + * Specifies margin, in pixels, to use when generating the barcode. The meaning can vary + * by format; for example it controls margin before and after the barcode horizontally for + * most 1D formats. (Type {@link Integer}). + */ + MARGIN, + /** * Specifies whether to use compact mode for PDF417 (type {@link Boolean}). */ diff --git a/core/src/com/google/zxing/oned/CodaBarWriter.java b/core/src/com/google/zxing/oned/CodaBarWriter.java index 5ebc73e01..e615bbc59 100644 --- a/core/src/com/google/zxing/oned/CodaBarWriter.java +++ b/core/src/com/google/zxing/oned/CodaBarWriter.java @@ -18,6 +18,8 @@ package com.google.zxing.oned; import com.google.zxing.common.BitMatrix; +import java.util.Arrays; + /** * This class renders CodaBar as {@link BitMatrix}. * @@ -25,29 +27,23 @@ import com.google.zxing.common.BitMatrix; */ public final class CodaBarWriter extends OneDimensionalCodeWriter { - public CodaBarWriter() { - // Super constructor requires the sum of the left and right margin length. - // CodaBar spec requires a side margin to be more than ten times wider than narrow space. - // In this implementation, narrow space has a unit length, so 20 is required minimum. - super(20); - } + private static final char[] START_CHARS = {'A', 'B', 'C', 'D'}; + private static final char[] END_CHARS = {'T', 'N', '*', 'E'}; /* - * @see OneDimensionalCodeWriter#encode(java.lang.String) + * @see OneDimensionalCodeWriter#encode(String) */ @Override - public byte[] encode(String contents) { + public boolean[] encode(String contents) { // Verify input and calculate decoded length. - if (!CodaBarReader.arrayContains( - new char[]{'A', 'B', 'C', 'D'}, Character.toUpperCase(contents.charAt(0)))) { + if (!CodaBarReader.arrayContains(START_CHARS, Character.toUpperCase(contents.charAt(0)))) { throw new IllegalArgumentException( - "Codabar should start with one of the following: 'A', 'B', 'C' or 'D'"); + "Codabar should start with one of the following: " + Arrays.toString(START_CHARS)); } - if (!CodaBarReader.arrayContains(new char[]{'T', 'N', '*', 'E'}, - Character.toUpperCase(contents.charAt(contents.length() - 1)))) { + if (!CodaBarReader.arrayContains(END_CHARS, Character.toUpperCase(contents.charAt(contents.length() - 1)))) { throw new IllegalArgumentException( - "Codabar should end with one of the following: 'T', 'N', '*' or 'E'"); + "Codabar should end with one of the following: " + Arrays.toString(END_CHARS)); } // The start character and the end character are decoded to 10 length each. int resultLength = 20; @@ -66,7 +62,7 @@ public final class CodaBarWriter extends OneDimensionalCodeWriter { // A blank is placed between each character. resultLength += contents.length() - 1; - byte[] result = new byte[resultLength]; + boolean[] result = new boolean[resultLength]; int position = 0; for (int index = 0; index < contents.length(); index++) { char c = Character.toUpperCase(contents.charAt(index)); @@ -95,14 +91,14 @@ public final class CodaBarWriter extends OneDimensionalCodeWriter { break; } } - byte color = 1; + boolean color = true; int counter = 0; int bit = 0; while (bit < 7) { // A character consists of 7 digit. result[position] = color; position++; if (((code >> (6 - bit)) & 1) == 0 || counter == 1) { - color ^= 1; // Flip the color. + color = !color; // Flip the color. bit++; counter = 0; } else { @@ -110,7 +106,7 @@ public final class CodaBarWriter extends OneDimensionalCodeWriter { } } if (index < contents.length() - 1) { - result[position] = 0; + result[position] = false; position++; } } diff --git a/core/src/com/google/zxing/oned/Code128Writer.java b/core/src/com/google/zxing/oned/Code128Writer.java index c3ba62840..b3f60d377 100644 --- a/core/src/com/google/zxing/oned/Code128Writer.java +++ b/core/src/com/google/zxing/oned/Code128Writer.java @@ -30,7 +30,7 @@ import java.util.Map; * * @author erik.barbara@gmail.com (Erik Barbara) */ -public final class Code128Writer extends UPCEANWriter { +public final class Code128Writer extends OneDimensionalCodeWriter { private static final int CODE_START_B = 104; private static final int CODE_START_C = 105; @@ -62,7 +62,7 @@ public final class Code128Writer extends UPCEANWriter { } @Override - public byte[] encode(String contents) { + public boolean[] encode(String contents) { int length = contents.length(); // Check length if (length < 1 || length > 80) { @@ -176,10 +176,10 @@ public final class Code128Writer extends UPCEANWriter { } // Compute result - byte[] result = new byte[codeWidth]; + boolean[] result = new boolean[codeWidth]; int pos = 0; for (int[] pattern : patterns) { - pos += appendPattern(result, pos, pattern, 1); + pos += appendPattern(result, pos, pattern, true); } return result; diff --git a/core/src/com/google/zxing/oned/Code39Writer.java b/core/src/com/google/zxing/oned/Code39Writer.java index e0ba3201a..281face7a 100644 --- a/core/src/com/google/zxing/oned/Code39Writer.java +++ b/core/src/com/google/zxing/oned/Code39Writer.java @@ -28,7 +28,7 @@ import java.util.Map; * * @author erik.barbara@gmail.com (Erik Barbara) */ -public final class Code39Writer extends UPCEANWriter { +public final class Code39Writer extends OneDimensionalCodeWriter { @Override public BitMatrix encode(String contents, @@ -43,7 +43,7 @@ public final class Code39Writer extends UPCEANWriter { } @Override - public byte[] encode(String contents) { + public boolean[] encode(String contents) { int length = contents.length(); if (length > 80) { throw new IllegalArgumentException( @@ -59,20 +59,20 @@ public final class Code39Writer extends UPCEANWriter { codeWidth += width; } } - byte[] result = new byte[codeWidth]; + boolean[] result = new boolean[codeWidth]; toIntArray(Code39Reader.CHARACTER_ENCODINGS[39], widths); - int pos = appendPattern(result, 0, widths, 1); + int pos = appendPattern(result, 0, widths, true); int[] narrowWhite = {1}; - pos += appendPattern(result, pos, narrowWhite, 0); + pos += appendPattern(result, pos, narrowWhite, false); //append next character to bytematrix for(int i = length-1; i >= 0; i--) { int indexInString = Code39Reader.ALPHABET_STRING.indexOf(contents.charAt(i)); toIntArray(Code39Reader.CHARACTER_ENCODINGS[indexInString], widths); - pos += appendPattern(result, pos, widths, 1); - pos += appendPattern(result, pos, narrowWhite, 0); + pos += appendPattern(result, pos, widths, true); + pos += appendPattern(result, pos, narrowWhite, false); } toIntArray(Code39Reader.CHARACTER_ENCODINGS[39], widths); - pos += appendPattern(result, pos, widths, 1); + pos += appendPattern(result, pos, widths, true); return result; } diff --git a/core/src/com/google/zxing/oned/EAN13Writer.java b/core/src/com/google/zxing/oned/EAN13Writer.java index dda038e68..48dbe088a 100644 --- a/core/src/com/google/zxing/oned/EAN13Writer.java +++ b/core/src/com/google/zxing/oned/EAN13Writer.java @@ -50,7 +50,7 @@ public final class EAN13Writer extends UPCEANWriter { } @Override - public byte[] encode(String contents) { + public boolean[] encode(String contents) { if (contents.length() != 13) { throw new IllegalArgumentException( "Requested contents should be 13 digits long, but got " + contents.length()); @@ -58,10 +58,10 @@ public final class EAN13Writer extends UPCEANWriter { int firstDigit = Integer.parseInt(contents.substring(0, 1)); int parities = EAN13Reader.FIRST_DIGIT_ENCODINGS[firstDigit]; - byte[] result = new byte[CODE_WIDTH]; + boolean[] result = new boolean[CODE_WIDTH]; int pos = 0; - pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, 1); + pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, true); // See {@link #EAN13Reader} for a description of how the first digit & left bars are encoded for (int i = 1; i <= 6; i++) { @@ -69,16 +69,16 @@ public final class EAN13Writer extends UPCEANWriter { if ((parities >> (6 - i) & 1) == 1) { digit += 10; } - pos += appendPattern(result, pos, UPCEANReader.L_AND_G_PATTERNS[digit], 0); + pos += appendPattern(result, pos, UPCEANReader.L_AND_G_PATTERNS[digit], false); } - pos += appendPattern(result, pos, UPCEANReader.MIDDLE_PATTERN, 0); + pos += appendPattern(result, pos, UPCEANReader.MIDDLE_PATTERN, false); for (int i = 7; i <= 12; i++) { int digit = Integer.parseInt(contents.substring(i, i + 1)); - pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], 1); + pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], true); } - pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, 1); + pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, true); return result; } diff --git a/core/src/com/google/zxing/oned/EAN8Writer.java b/core/src/com/google/zxing/oned/EAN8Writer.java index d16b0d839..204278e13 100644 --- a/core/src/com/google/zxing/oned/EAN8Writer.java +++ b/core/src/com/google/zxing/oned/EAN8Writer.java @@ -50,31 +50,33 @@ public final class EAN8Writer extends UPCEANWriter { return super.encode(contents, format, width, height, hints); } - /** @return a byte array of horizontal pixels (0 = white, 1 = black) */ + /** + * @return a byte array of horizontal pixels (false = white, true = black) + */ @Override - public byte[] encode(String contents) { + public boolean[] encode(String contents) { if (contents.length() != 8) { throw new IllegalArgumentException( "Requested contents should be 8 digits long, but got " + contents.length()); } - byte[] result = new byte[CODE_WIDTH]; + boolean[] result = new boolean[CODE_WIDTH]; int pos = 0; - pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, 1); + pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, true); for (int i = 0; i <= 3; i++) { int digit = Integer.parseInt(contents.substring(i, i + 1)); - pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], 0); + pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], false); } - pos += appendPattern(result, pos, UPCEANReader.MIDDLE_PATTERN, 0); + pos += appendPattern(result, pos, UPCEANReader.MIDDLE_PATTERN, false); for (int i = 4; i <= 7; i++) { int digit = Integer.parseInt(contents.substring(i, i + 1)); - pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], 1); + pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], true); } - pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, 1); + pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, true); return result; } diff --git a/core/src/com/google/zxing/oned/ITFWriter.java b/core/src/com/google/zxing/oned/ITFWriter.java index c44e1fc6b..c52c58299 100644 --- a/core/src/com/google/zxing/oned/ITFWriter.java +++ b/core/src/com/google/zxing/oned/ITFWriter.java @@ -28,7 +28,10 @@ import java.util.Map; * * @author erik.barbara@gmail.com (Erik Barbara) */ -public final class ITFWriter extends UPCEANWriter { +public final class ITFWriter extends OneDimensionalCodeWriter { + + private static final int[] START_PATTERN = {1, 1, 1, 1}; + private static final int[] END_PATTERN = {3, 1, 1}; @Override public BitMatrix encode(String contents, @@ -44,7 +47,7 @@ public final class ITFWriter extends UPCEANWriter { } @Override - public byte[] encode(String contents) { + public boolean[] encode(String contents) { int length = contents.length(); if (length % 2 != 0) { throw new IllegalArgumentException("The lenght of the input should be even"); @@ -53,9 +56,8 @@ public final class ITFWriter extends UPCEANWriter { throw new IllegalArgumentException( "Requested contents should be less than 80 digits long, but got " + length); } - byte[] result = new byte[9 + 9 * length]; - int[] start = {1, 1, 1, 1}; - int pos = appendPattern(result, 0, start, 1); + boolean[] result = new boolean[9 + 9 * length]; + int pos = appendPattern(result, 0, START_PATTERN, true); for (int i = 0; i < length; i += 2) { int one = Character.digit(contents.charAt(i), 10); int two = Character.digit(contents.charAt(i+1), 10); @@ -64,10 +66,9 @@ public final class ITFWriter extends UPCEANWriter { encoding[(j << 1)] = ITFReader.PATTERNS[one][j]; encoding[(j << 1) + 1] = ITFReader.PATTERNS[two][j]; } - pos += appendPattern(result, pos, encoding, 1); + pos += appendPattern(result, pos, encoding, true); } - int[] end = {3, 1, 1}; - appendPattern(result, pos, end, 1); + appendPattern(result, pos, END_PATTERN, true); return result; } diff --git a/core/src/com/google/zxing/oned/OneDimensionalCodeWriter.java b/core/src/com/google/zxing/oned/OneDimensionalCodeWriter.java index 736c9409c..87ac46aff 100644 --- a/core/src/com/google/zxing/oned/OneDimensionalCodeWriter.java +++ b/core/src/com/google/zxing/oned/OneDimensionalCodeWriter.java @@ -31,12 +31,6 @@ import java.util.Map; */ public abstract class OneDimensionalCodeWriter implements Writer { - private final int sidesMargin; - - protected OneDimensionalCodeWriter(int sidesMargin) { - this.sidesMargin = sidesMargin; - } - @Override public BitMatrix encode(String contents, BarcodeFormat format, int width, int height) throws WriterException { @@ -65,14 +59,22 @@ public abstract class OneDimensionalCodeWriter implements Writer { + width + 'x' + height); } - byte[] code = encode(contents); - return renderResult(code, width, height); + int sidesMargin = getDefaultMargin(); + if (hints != null) { + Integer sidesMarginInt = (Integer) hints.get(EncodeHintType.MARGIN); + if (sidesMarginInt != null) { + sidesMargin = sidesMarginInt; + } + } + + boolean[] code = encode(contents); + return renderResult(code, width, height, sidesMargin); } /** * @return a byte array of horizontal pixels (0 = white, 1 = black) */ - private BitMatrix renderResult(byte[] code, int width, int height) { + private static BitMatrix renderResult(boolean[] code, int width, int height, int sidesMargin) { int inputWidth = code.length; // Add quiet zone on both sides. int fullWidth = inputWidth + sidesMargin; @@ -84,7 +86,7 @@ public abstract class OneDimensionalCodeWriter implements Writer { BitMatrix output = new BitMatrix(outputWidth, outputHeight); for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) { - if (code[inputX] == 1) { + if (code[inputX]) { output.setRegion(outputX, 0, multiple, outputHeight); } } @@ -95,34 +97,34 @@ public abstract class OneDimensionalCodeWriter implements Writer { /** * Appends the given pattern to the target array starting at pos. * - * @param startColor starting color - 0 for white, 1 for black + * @param startColor starting color - false for white, true for black * @return the number of elements added to target. */ - protected static int appendPattern(byte[] target, int pos, int[] pattern, int startColor) { - if (startColor != 0 && startColor != 1) { - throw new IllegalArgumentException( - "startColor must be either 0 or 1, but got: " + startColor); - } - - byte color = (byte) startColor; + protected static int appendPattern(boolean[] target, int pos, int[] pattern, boolean startColor) { + boolean color = startColor; int numAdded = 0; for (int len : pattern) { for (int j = 0; j < len; j++) { - target[pos] = color; - pos += 1; - numAdded += 1; + target[pos++] = color; } - color ^= 1; // flip color after each segment + numAdded += len; + color = !color; // flip color after each segment } return numAdded; } + public int getDefaultMargin() { + // CodaBar spec requires a side margin to be more than ten times wider than narrow space. + // This seems like a decent idea for a default for all formats. + return 10; + } + /** * Encode the contents to byte array expression of one-dimensional barcode. * Start code and end code should be included in result, and side margins should not be included. * - * @return a byte array of horizontal pixels (0 = white, 1 = black) + * @return a {@code boolean[]} of horizontal pixels (false = white, true = black) */ - public abstract byte[] encode(String contents); + public abstract boolean[] encode(String contents); } diff --git a/core/src/com/google/zxing/oned/UPCEANWriter.java b/core/src/com/google/zxing/oned/UPCEANWriter.java index a43dc55f7..a39937dbb 100644 --- a/core/src/com/google/zxing/oned/UPCEANWriter.java +++ b/core/src/com/google/zxing/oned/UPCEANWriter.java @@ -25,8 +25,10 @@ package com.google.zxing.oned; */ public abstract class UPCEANWriter extends OneDimensionalCodeWriter { - protected UPCEANWriter() { - super(UPCEANReader.START_END_PATTERN.length << 1); + @Override + public int getDefaultMargin() { + // Use a different default more appropriate for UPC/EAN + return UPCEANReader.START_END_PATTERN.length; } } diff --git a/core/src/com/google/zxing/qrcode/QRCodeWriter.java b/core/src/com/google/zxing/qrcode/QRCodeWriter.java index 4822ac416..50b78b168 100644 --- a/core/src/com/google/zxing/qrcode/QRCodeWriter.java +++ b/core/src/com/google/zxing/qrcode/QRCodeWriter.java @@ -65,28 +65,33 @@ public final class QRCodeWriter implements Writer { } ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.L; + int quietZone = QUIET_ZONE_SIZE; if (hints != null) { ErrorCorrectionLevel requestedECLevel = (ErrorCorrectionLevel) hints.get(EncodeHintType.ERROR_CORRECTION); if (requestedECLevel != null) { errorCorrectionLevel = requestedECLevel; } + Integer quietZoneInt = (Integer) hints.get(EncodeHintType.MARGIN); + if (quietZoneInt != null) { + quietZone = quietZoneInt; + } } QRCode code = Encoder.encode(contents, errorCorrectionLevel, hints); - return renderResult(code, width, height); + return renderResult(code, width, height, quietZone); } // Note that the input matrix uses 0 == white, 1 == black, while the output matrix uses // 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap). - private static BitMatrix renderResult(QRCode code, int width, int height) { + private static BitMatrix renderResult(QRCode code, int width, int height, int quietZone) { ByteMatrix input = code.getMatrix(); if (input == null) { throw new IllegalStateException(); } int inputWidth = input.getWidth(); int inputHeight = input.getHeight(); - int qrWidth = inputWidth + (QUIET_ZONE_SIZE << 1); - int qrHeight = inputHeight + (QUIET_ZONE_SIZE << 1); + int qrWidth = inputWidth + (quietZone << 1); + int qrHeight = inputHeight + (quietZone << 1); int outputWidth = Math.max(width, qrWidth); int outputHeight = Math.max(height, qrHeight);