1 /***********************************************************************************************************************
2 Copyright (c) 2003, International Barcode Consortium
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7
8 * Redistributions of source code must retain the above copyright notice, this list of
9 conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright notice, this list of
11 conditions and the following disclaimer in the documentation and/or other materials
12 provided with the distribution.
13 * Neither the name of the International Barcode Consortium nor the names of any contributors may be used to endorse
14 or promote products derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
19 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 POSSIBILITY OF SUCH DAMAGE.
25 ***********************************************************************************************************************/
26
27 package net.sourceforge.barbecue.twod.pdf417;
28
29 import net.sourceforge.barbecue.Module;
30 import net.sourceforge.barbecue.output.Output;
31 import net.sourceforge.barbecue.output.OutputException;
32
33 /**
34 * Specific module implementation that draws an entire PDF417 barcode
35 * as one barbecue module. This is not an ideal implementation, but was
36 * the best way of integrating the PDF417 code short of re-writing it.
37 *
38 * <p/>Contributed by Alex Ferrer <alex@ftconsult.com>
39 *
40 * @author Alex Ferrer
41 * @author <a href="mailto:opensource@ianbourke.com">Ian Bourke</a>
42 *
43 * @todo Do we really want to fix the DATACOLS to 12?
44 */
45 public class PDF417Module extends Module {
46 private static final int DATACOLS = 12;
47
48 private final String data;
49 private int[] out;
50 private int outlen;
51 private int outrows;
52 private int col = 0;
53 private int xp;
54 private int yp;
55 private int startX;
56 private int wsize = 0;
57 private int barWidth;
58
59 /**
60 * Constructs the PDF417 barcode with the specified data.
61 * @param data The data to encode
62 */
63 public PDF417Module(String data) {
64 super(new int[0]);
65 this.data = data;
66 }
67
68 /**
69 * Returns the barcode width;
70 * @return The barcode width
71 */
72 private int getBarcodeWidth() {
73 return wsize - startX;
74 }
75
76 /**
77 * Returns the barcode height.
78 * @return The barcode height
79 */
80 int getBarcodeHeight() {
81 return yp;
82 }
83
84 /**
85 * Draw the barcode to the specified outputter, at the specified origin.
86 * @param outputter The outputter
87 * @param x The X component of the origin
88 * @param y The Y component of the origin
89 * @param barWidth
90 * @param barHeight
91 * @return The total width drawn
92 */
93 protected int draw(Output outputter, int x, int y, int barWidth, int barHeight) throws OutputException {
94 this.xp = (int) x;
95 this.startX = (int) x;
96 this.yp = (int) y;
97 this.barWidth = (int) barWidth;
98 createCodewords(data.toCharArray(), data.length());
99 createBits(out, outlen, outrows);
100 encode(out, outrows, outputter);
101
102 return getBarcodeWidth();
103 }
104
105 /**
106 * I have no idea what this does.
107 * @param data The barcode data
108 * @param length The length of the data
109 * @param ecLength The length of the EC (2)
110 */
111 private void generateEC(int[] data, int length, int ecLength) {
112 int b0 = 0;
113 int b1 = 0;
114 int g0 = 27;
115 int g1 = 917;
116
117
118 data[length] = 0;
119 data[length + 1] = 0;
120
121
122 if (ecLength != 2) {
123 return;
124 }
125
126
127 for (int i = 0; i < length; ++i) {
128 int wrap = (b1 + data[i]) % 929;
129
130 if (wrap != 0) {
131 wrap = 929 - wrap;
132 }
133
134 b1 = (b0 + g1 * wrap) % 929;
135 b0 = (0 + g0 * wrap) % 929;
136 }
137
138
139 if (b0 != 0) {
140 b0 = 929 - b0;
141 }
142
143 if (b1 != 0) {
144 b1 = 929 - b1;
145 }
146
147 data[length] = b1;
148 data[length + 1] = b0;
149 }
150
151 private void outbit(int bit, Output params) throws OutputException {
152 params.drawBar(xp, yp, 1, 1, bit == 1);
153
154 xp = xp + barWidth;
155 if (col++ == wsize - 1) {
156 col = 0;
157 yp = yp + 1;
158 xp = startX;
159 }
160 }
161
162 private void createCodewords(char[] data, int len) {
163 int ecLength = 2;
164
165
166 if (DATACOLS < 1 || DATACOLS > 30) {
167 return;
168 }
169
170 outlen = 2 + (len / 6) * 5 + (len % 6) + ecLength;
171
172
173 outrows = outlen / DATACOLS;
174 if ((outlen % DATACOLS) != 0) {
175 ++outrows;
176 }
177 if (outrows < 3) {
178 outrows = 3;
179 }
180 if (outrows > 90) {
181 return;
182 }
183 outlen = outrows * DATACOLS;
184
185 if (outlen > 928) {
186 return;
187 }
188
189
190
191 out = new int[outlen];
192 out[0] = 2 + (len / 6) * 5 + (len % 6);
193 if (len % 6 != 0) {
194 out[1] = 901;
195 } else {
196 out[1] = 924;
197 }
198
199
200 int inp = 0;
201 int outp = 2;
202 while (inp + 5 < len) {
203
204 long codeval = 0;
205 for (int i = 0; i < 6; ++i) {
206 codeval <<= 8;
207 codeval += data[inp++];
208 }
209
210 for (int i = 0; i < 5; i++) {
211 out[outp + 4 - i] = new Long(codeval % 900).intValue();
212 codeval /= 900;
213 }
214 outp += 5;
215 }
216
217
218 while (inp < len) {
219 out[outp++] = data[inp++];
220 }
221
222
223 while (outp < outlen - ecLength) {
224 out[outp++] = 900;
225 }
226
227 generateEC(out, outp, ecLength);
228 }
229
230 private void createBits(int[] codes, int codelen, int datarows) {
231 int row, inp, outp;
232 if (DATACOLS < 1 || DATACOLS > 30
233 || datarows < 3 || datarows > 90
234 || codelen != DATACOLS * datarows) {
235 return;
236 }
237
238 int outlen = datarows * (DATACOLS + 4);
239 int[] out = new int[outlen];
240 outp = 0;
241 inp = 0;
242
243 for (row = 0; row < datarows; ++row) {
244
245 int v = DATACOLS - 1;
246 int w = row % 3;
247 int x = row / 3;
248 int y = datarows / 3;
249 int z = 0 * 3 + datarows % 3;
250 out[outp++] = PDF417Data.PDF417_START;
251 switch (w) {
252 case 0:
253 out[outp++] = PDF417Data.PDF417_BITS[w][30 * x + y];
254 break;
255 case 1:
256 out[outp++] = PDF417Data.PDF417_BITS[w][30 * x + z];
257 break;
258 case 2:
259 out[outp++] = PDF417Data.PDF417_BITS[w][30 * x + v];
260 break;
261 }
262 for (int i = 0; i < DATACOLS; ++i) {
263 out[outp++] = PDF417Data.PDF417_BITS[w][codes[inp++]];
264 }
265 switch (w) {
266 case 0:
267 out[outp++] = PDF417Data.PDF417_BITS[w][30 * x + v];
268 break;
269 case 1:
270 out[outp++] = PDF417Data.PDF417_BITS[w][30 * x + y];
271 break;
272 case 2:
273 out[outp++] = PDF417Data.PDF417_BITS[w][30 * x + z];
274 break;
275 }
276 out[outp++] = PDF417Data.PDF417_STOP;
277 }
278 this.out = out;
279 this.outlen = outlen;
280 }
281
282 private void encode(int[] data, int datarows, Output params) throws OutputException {
283 int bitpattern;
284 int row_height = 7;
285 int npix = 2;
286 wsize = ((DATACOLS + 4) * 17 + barWidth + 4) * npix;
287
288
289 for (int i = 0; i < 2 * npix; i++) {
290 for (int j = 0; j < ((DATACOLS + 4) * 17 + 1 + 4) * npix; j++) {
291 outbit(0, params);
292 }
293 }
294
295 for (int i = 0; i < datarows; i++) {
296 for (int k = 0; k < row_height; k++) {
297
298
299 for (int pixn = 0; pixn < 2 * npix; pixn++) {
300 outbit(0, params);
301 }
302
303 for (int j = 0; j < (DATACOLS + 4); j++) {
304 bitpattern = data[(DATACOLS + 4) * i + j];
305
306 for (int bitm = 16; bitm >= 0; bitm--) {
307 for (int pixn = 0; pixn < npix; pixn++) {
308
309 if ((bitpattern & (1 << bitm)) != 0) {
310 outbit(1, params);
311 } else {
312 outbit(0, params);
313 }
314 }
315 }
316 }
317
318 for (int pixn = 0; pixn < npix; pixn++) {
319 outbit(1, params);
320 }
321
322
323 for (int pixn = 0; pixn < 2 * npix; pixn++) {
324 outbit(0, params);
325 }
326 }
327 }
328
329
330 for (int i = 0; i < 2 * npix; ++i) {
331 for (int j = 0; j < ((DATACOLS + 4) * 17 + 1 + 4) * npix; ++j) {
332 outbit(0, params);
333 }
334 }
335 }
336 }