b65c2070fcb5ff6759b78bbd044304899a2c5d65
[zxing.git] / core / src / com / google / zxing / oned / UPCEANWriter.java
1 /*
2  * Copyright 2009 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.Writer;
21 import com.google.zxing.WriterException;
22 import com.google.zxing.common.ByteMatrix;
23
24 import java.util.Hashtable;
25
26 /**
27  * <p>Encapsulates functionality and implementation that is common to UPC and EAN families
28  * of one-dimensional barcodes.</p>
29  *
30  * @author aripollak@gmail.com (Ari Pollak)
31  */
32 public abstract class UPCEANWriter implements Writer {
33
34   public ByteMatrix encode(String contents, BarcodeFormat format, int width, int height)
35   throws WriterException {
36     return encode(contents, format, width, height, null);
37   }
38
39   public ByteMatrix encode(String contents, BarcodeFormat format, int width, int height,
40       Hashtable hints) throws WriterException {
41     if (contents == null || contents.length() == 0) {
42       throw new IllegalArgumentException("Found empty contents");
43     }
44
45     if (width < 0 || height < 0) {
46       throw new IllegalArgumentException("Requested dimensions are too small: "
47           + width + 'x' + height);
48     }
49
50     byte[] code = encode(contents);
51     return renderResult(code, width, height);
52   }
53
54   /** @return a byte array of horizontal pixels (0 = white, 1 = black) */
55   private static ByteMatrix renderResult(byte[] code, int width, int height) {
56     int inputWidth = code.length;
57     // Add quiet zone on both sides
58     int fullWidth = inputWidth + (UPCEANReader.START_END_PATTERN.length << 1);
59     int outputWidth = Math.max(width, fullWidth);
60     int outputHeight = Math.max(1, height);
61
62     int multiple = outputWidth / fullWidth;
63     int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
64
65     ByteMatrix output = new ByteMatrix(outputWidth, outputHeight);
66     byte[][] outputArray = output.getArray();
67
68     byte[] row = new byte[outputWidth];
69
70     // a. Write the white pixels at the left of each row
71     for (int x = 0; x < leftPadding; x++) {
72       row[x] = (byte) 255;
73     }
74
75     // b. Write the contents of this row of the barcode
76     int offset = leftPadding;
77     for (int x = 0; x < inputWidth; x++) {
78       byte value = (code[x] == 1) ? 0 : (byte) 255;
79       for (int z = 0; z < multiple; z++) {
80         row[offset + z] = value;
81       }
82       offset += multiple;
83     }
84
85     // c. Write the white pixels at the right of each row
86     offset = leftPadding + (inputWidth * multiple);
87     for (int x = offset; x < outputWidth; x++) {
88       row[x] = (byte) 255;
89     }
90
91     // d. Write the completed row multiple times
92     for (int z = 0; z < outputHeight; z++) {
93       System.arraycopy(row, 0, outputArray[z], 0, outputWidth);
94     }
95
96     return output;
97   }
98
99
100   /**
101    * Appends the given pattern to the target array starting at pos.
102    *
103    * @param startColor
104    *          starting color - 0 for white, 1 for black
105    * @return the number of elements added to target.
106    */
107    protected static int appendPattern(byte[] target, int pos, int[] pattern, int startColor) {
108     if (startColor != 0 && startColor != 1) {
109       throw new IllegalArgumentException(
110           "startColor must be either 0 or 1, but got: " + startColor);
111     }
112
113     byte color = (byte) startColor;
114     int numAdded = 0;
115     for (int i = 0; i < pattern.length; i++) {
116       for (int j = 0; j < pattern[i]; j++) {
117         target[pos] = color;
118         pos += 1;
119         numAdded += 1;
120       }
121       color ^= 1; // flip color after each segment
122     }
123     return numAdded;
124   }
125
126   /** @return a byte array of horizontal pixels (0 = white, 1 = black) */
127   public abstract byte[] encode(String contents);
128
129 }