• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 ZXing authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.zxing.oned;
18 
19 import com.google.zxing.BarcodeFormat;
20 import com.google.zxing.EncodeHintType;
21 import com.google.zxing.Writer;
22 import com.google.zxing.common.BitMatrix;
23 
24 import java.util.Collection;
25 import java.util.Map;
26 import java.util.regex.Pattern;
27 
28 /**
29  * <p>Encapsulates functionality and implementation that is common to one-dimensional barcodes.</p>
30  *
31  * @author dsbnatut@gmail.com (Kazuki Nishiura)
32  */
33 public abstract class OneDimensionalCodeWriter implements Writer {
34   private static final Pattern NUMERIC = Pattern.compile("[0-9]+");
35 
36   /**
37    * Encode the contents to boolean array expression of one-dimensional barcode.
38    * Start code and end code should be included in result, and side margins should not be included.
39    *
40    * @param contents barcode contents to encode
41    * @return a {@code boolean[]} of horizontal pixels (false = white, true = black)
42    */
encode(String contents)43   public abstract boolean[] encode(String contents);
44 
45   /**
46    * Can be overwritten if the encode requires to read the hints map. Otherwise it defaults to {@code encode}.
47    * @param contents barcode contents to encode
48    * @param hints encoding hints
49    * @return a {@code boolean[]} of horizontal pixels (false = white, true = black)
50    */
encode(String contents, Map<EncodeHintType,?> hints)51   public boolean[] encode(String contents, Map<EncodeHintType,?> hints) {
52     return encode(contents);
53   }
54 
55   @Override
encode(String contents, BarcodeFormat format, int width, int height)56   public final BitMatrix encode(String contents, BarcodeFormat format, int width, int height) {
57     return encode(contents, format, width, height, null);
58   }
59 
60   /**
61    * Encode the contents following specified format.
62    * {@code width} and {@code height} are required size. This method may return bigger size
63    * {@code BitMatrix} when specified size is too small. The user can set both {@code width} and
64    * {@code height} to zero to get minimum size barcode. If negative value is set to {@code width}
65    * or {@code height}, {@code IllegalArgumentException} is thrown.
66    */
67   @Override
encode(String contents, BarcodeFormat format, int width, int height, Map<EncodeHintType,?> hints)68   public BitMatrix encode(String contents,
69                           BarcodeFormat format,
70                           int width,
71                           int height,
72                           Map<EncodeHintType,?> hints) {
73     if (contents.isEmpty()) {
74       throw new IllegalArgumentException("Found empty contents");
75     }
76 
77     if (width < 0 || height < 0) {
78       throw new IllegalArgumentException("Negative size is not allowed. Input: "
79                                              + width + 'x' + height);
80     }
81     Collection<BarcodeFormat> supportedFormats = getSupportedWriteFormats();
82     if (supportedFormats != null && !supportedFormats.contains(format)) {
83       throw new IllegalArgumentException("Can only encode " + supportedFormats +
84         ", but got " + format);
85     }
86 
87     int sidesMargin = getDefaultMargin();
88     if (hints != null && hints.containsKey(EncodeHintType.MARGIN)) {
89       sidesMargin = Integer.parseInt(hints.get(EncodeHintType.MARGIN).toString());
90     }
91 
92     boolean[] code = encode(contents, hints);
93     return renderResult(code, width, height, sidesMargin);
94   }
95 
getSupportedWriteFormats()96   protected Collection<BarcodeFormat> getSupportedWriteFormats() {
97     return null;
98   }
99 
100   /**
101    * @return a byte array of horizontal pixels (0 = white, 1 = black)
102    */
renderResult(boolean[] code, int width, int height, int sidesMargin)103   private static BitMatrix renderResult(boolean[] code, int width, int height, int sidesMargin) {
104     int inputWidth = code.length;
105     // Add quiet zone on both sides.
106     int fullWidth = inputWidth + sidesMargin;
107     int outputWidth = Math.max(width, fullWidth);
108     int outputHeight = Math.max(1, height);
109 
110     int multiple = outputWidth / fullWidth;
111     int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
112 
113     BitMatrix output = new BitMatrix(outputWidth, outputHeight);
114     for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) {
115       if (code[inputX]) {
116         output.setRegion(outputX, 0, multiple, outputHeight);
117       }
118     }
119     return output;
120   }
121 
122   /**
123    * @param contents string to check for numeric characters
124    * @throws IllegalArgumentException if input contains characters other than digits 0-9.
125    */
checkNumeric(String contents)126   protected static void checkNumeric(String contents) {
127     if (!NUMERIC.matcher(contents).matches()) {
128       throw new IllegalArgumentException("Input should only contain digits 0-9");
129     }
130   }
131 
132   /**
133    * @param target encode black/white pattern into this array
134    * @param pos position to start encoding at in {@code target}
135    * @param pattern lengths of black/white runs to encode
136    * @param startColor starting color - false for white, true for black
137    * @return the number of elements added to target.
138    */
appendPattern(boolean[] target, int pos, int[] pattern, boolean startColor)139   protected static int appendPattern(boolean[] target, int pos, int[] pattern, boolean startColor) {
140     boolean color = startColor;
141     int numAdded = 0;
142     for (int len : pattern) {
143       for (int j = 0; j < len; j++) {
144         target[pos++] = color;
145       }
146       numAdded += len;
147       color = !color; // flip color after each segment
148     }
149     return numAdded;
150   }
151 
getDefaultMargin()152   public int getDefaultMargin() {
153     // CodaBar spec requires a side margin to be more than ten times wider than narrow space.
154     // This seems like a decent idea for a default for all formats.
155     return 10;
156   }
157 }
158 
159