• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2008 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.datamatrix;
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 import com.google.zxing.datamatrix.encoder.DefaultPlacement;
24 import com.google.zxing.Dimension;
25 import com.google.zxing.datamatrix.encoder.ErrorCorrection;
26 import com.google.zxing.datamatrix.encoder.HighLevelEncoder;
27 import com.google.zxing.datamatrix.encoder.MinimalEncoder;
28 import com.google.zxing.datamatrix.encoder.SymbolInfo;
29 import com.google.zxing.datamatrix.encoder.SymbolShapeHint;
30 import com.google.zxing.qrcode.encoder.ByteMatrix;
31 
32 import java.util.Map;
33 import java.nio.charset.Charset;
34 
35 /**
36  * This object renders a Data Matrix code as a BitMatrix 2D array of greyscale values.
37  *
38  * @author dswitkin@google.com (Daniel Switkin)
39  * @author Guillaume Le Biller Added to zxing lib.
40  */
41 public final class DataMatrixWriter implements Writer {
42 
43   @Override
encode(String contents, BarcodeFormat format, int width, int height)44   public BitMatrix encode(String contents, BarcodeFormat format, int width, int height) {
45     return encode(contents, format, width, height, null);
46   }
47 
48   @Override
encode(String contents, BarcodeFormat format, int width, int height, Map<EncodeHintType,?> hints)49   public BitMatrix encode(String contents, BarcodeFormat format, int width, int height, Map<EncodeHintType,?> hints) {
50 
51     if (contents.isEmpty()) {
52       throw new IllegalArgumentException("Found empty contents");
53     }
54 
55     if (format != BarcodeFormat.DATA_MATRIX) {
56       throw new IllegalArgumentException("Can only encode DATA_MATRIX, but got " + format);
57     }
58 
59     if (width < 0 || height < 0) {
60       throw new IllegalArgumentException("Requested dimensions can't be negative: " + width + 'x' + height);
61     }
62 
63     // Try to get force shape & min / max size
64     SymbolShapeHint shape = SymbolShapeHint.FORCE_NONE;
65     Dimension minSize = null;
66     Dimension maxSize = null;
67     if (hints != null) {
68       SymbolShapeHint requestedShape = (SymbolShapeHint) hints.get(EncodeHintType.DATA_MATRIX_SHAPE);
69       if (requestedShape != null) {
70         shape = requestedShape;
71       }
72       @SuppressWarnings("deprecation")
73       Dimension requestedMinSize = (Dimension) hints.get(EncodeHintType.MIN_SIZE);
74       if (requestedMinSize != null) {
75         minSize = requestedMinSize;
76       }
77       @SuppressWarnings("deprecation")
78       Dimension requestedMaxSize = (Dimension) hints.get(EncodeHintType.MAX_SIZE);
79       if (requestedMaxSize != null) {
80         maxSize = requestedMaxSize;
81       }
82     }
83 
84 
85     //1. step: Data encodation
86     String encoded;
87 
88     boolean hasCompactionHint = hints != null && hints.containsKey(EncodeHintType.DATA_MATRIX_COMPACT) &&
89         Boolean.parseBoolean(hints.get(EncodeHintType.DATA_MATRIX_COMPACT).toString());
90     if (hasCompactionHint) {
91 
92       boolean hasGS1FormatHint = hints.containsKey(EncodeHintType.GS1_FORMAT) &&
93           Boolean.parseBoolean(hints.get(EncodeHintType.GS1_FORMAT).toString());
94 
95       Charset charset = null;
96       boolean hasEncodingHint = hints.containsKey(EncodeHintType.CHARACTER_SET);
97       if (hasEncodingHint) {
98         charset = Charset.forName(hints.get(EncodeHintType.CHARACTER_SET).toString());
99       }
100       encoded = MinimalEncoder.encodeHighLevel(contents, charset, hasGS1FormatHint ? 0x1D : -1, shape);
101     } else {
102       boolean hasForceC40Hint = hints != null && hints.containsKey(EncodeHintType.FORCE_C40) &&
103           Boolean.parseBoolean(hints.get(EncodeHintType.FORCE_C40).toString());
104       encoded = HighLevelEncoder.encodeHighLevel(contents, shape, minSize, maxSize, hasForceC40Hint);
105     }
106 
107     SymbolInfo symbolInfo = SymbolInfo.lookup(encoded.length(), shape, minSize, maxSize, true);
108 
109     //2. step: ECC generation
110     String codewords = ErrorCorrection.encodeECC200(encoded, symbolInfo);
111 
112     //3. step: Module placement in Matrix
113     DefaultPlacement placement =
114         new DefaultPlacement(codewords, symbolInfo.getSymbolDataWidth(), symbolInfo.getSymbolDataHeight());
115     placement.place();
116 
117     //4. step: low-level encoding
118     return encodeLowLevel(placement, symbolInfo, width, height);
119   }
120 
121   /**
122    * Encode the given symbol info to a bit matrix.
123    *
124    * @param placement  The DataMatrix placement.
125    * @param symbolInfo The symbol info to encode.
126    * @return The bit matrix generated.
127    */
encodeLowLevel(DefaultPlacement placement, SymbolInfo symbolInfo, int width, int height)128   private static BitMatrix encodeLowLevel(DefaultPlacement placement, SymbolInfo symbolInfo, int width, int height) {
129     int symbolWidth = symbolInfo.getSymbolDataWidth();
130     int symbolHeight = symbolInfo.getSymbolDataHeight();
131 
132     ByteMatrix matrix = new ByteMatrix(symbolInfo.getSymbolWidth(), symbolInfo.getSymbolHeight());
133 
134     int matrixY = 0;
135 
136     for (int y = 0; y < symbolHeight; y++) {
137       // Fill the top edge with alternate 0 / 1
138       int matrixX;
139       if ((y % symbolInfo.matrixHeight) == 0) {
140         matrixX = 0;
141         for (int x = 0; x < symbolInfo.getSymbolWidth(); x++) {
142           matrix.set(matrixX, matrixY, (x % 2) == 0);
143           matrixX++;
144         }
145         matrixY++;
146       }
147       matrixX = 0;
148       for (int x = 0; x < symbolWidth; x++) {
149         // Fill the right edge with full 1
150         if ((x % symbolInfo.matrixWidth) == 0) {
151           matrix.set(matrixX, matrixY, true);
152           matrixX++;
153         }
154         matrix.set(matrixX, matrixY, placement.getBit(x, y));
155         matrixX++;
156         // Fill the right edge with alternate 0 / 1
157         if ((x % symbolInfo.matrixWidth) == symbolInfo.matrixWidth - 1) {
158           matrix.set(matrixX, matrixY, (y % 2) == 0);
159           matrixX++;
160         }
161       }
162       matrixY++;
163       // Fill the bottom edge with full 1
164       if ((y % symbolInfo.matrixHeight) == symbolInfo.matrixHeight - 1) {
165         matrixX = 0;
166         for (int x = 0; x < symbolInfo.getSymbolWidth(); x++) {
167           matrix.set(matrixX, matrixY, true);
168           matrixX++;
169         }
170         matrixY++;
171       }
172     }
173 
174     return convertByteMatrixToBitMatrix(matrix, width, height);
175   }
176 
177   /**
178    * Convert the ByteMatrix to BitMatrix.
179    *
180    * @param reqHeight The requested height of the image (in pixels) with the Datamatrix code
181    * @param reqWidth The requested width of the image (in pixels) with the Datamatrix code
182    * @param matrix The input matrix.
183    * @return The output matrix.
184    */
convertByteMatrixToBitMatrix(ByteMatrix matrix, int reqWidth, int reqHeight)185   private static BitMatrix convertByteMatrixToBitMatrix(ByteMatrix matrix, int reqWidth, int reqHeight) {
186     int matrixWidth = matrix.getWidth();
187     int matrixHeight = matrix.getHeight();
188     int outputWidth = Math.max(reqWidth, matrixWidth);
189     int outputHeight = Math.max(reqHeight, matrixHeight);
190 
191     int multiple = Math.min(outputWidth / matrixWidth, outputHeight / matrixHeight);
192 
193     int leftPadding = (outputWidth - (matrixWidth * multiple)) / 2 ;
194     int topPadding = (outputHeight - (matrixHeight * multiple)) / 2 ;
195 
196     BitMatrix output;
197 
198     // remove padding if requested width and height are too small
199     if (reqHeight < matrixHeight || reqWidth < matrixWidth) {
200       leftPadding = 0;
201       topPadding = 0;
202       output = new BitMatrix(matrixWidth, matrixHeight);
203     } else {
204       output = new BitMatrix(reqWidth, reqHeight);
205     }
206 
207     output.clear();
208     for (int inputY = 0, outputY = topPadding; inputY < matrixHeight; inputY++, outputY += multiple) {
209       // Write the contents of this row of the bytematrix
210       for (int inputX = 0, outputX = leftPadding; inputX < matrixWidth; inputX++, outputX += multiple) {
211         if (matrix.get(inputX, inputY) == 1) {
212           output.setRegion(outputX, outputY, multiple, multiple);
213         }
214       }
215     }
216 
217     return output;
218   }
219 
220 }
221