KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > krysalis > barcode > impl > DefaultCode128Encoder


1 /*
2  * $Id: DefaultCode128Encoder.java,v 1.3 2003/06/11 09:25:12 jmaerki Exp $
3  * ============================================================================
4  * The Krysalis Patchy Software License, Version 1.1_01
5  * Copyright (c) 2002-2003 Nicola Ken Barozzi. All rights reserved.
6  *
7  * This Licence is compatible with the BSD licence as described and
8  * approved by http://www.opensource.org/, and is based on the
9  * Apache Software Licence Version 1.1.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright
16  * notice, this list of conditions and the following disclaimer.
17  *
18  * 2. Redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in
20  * the documentation and/or other materials provided with the
21  * distribution.
22  *
23  * 3. The end-user documentation included with the redistribution,
24  * if any, must include the following acknowledgment:
25  * "This product includes software developed for project
26  * Krysalis (http://www.krysalis.org/)."
27  * Alternately, this acknowledgment may appear in the software itself,
28  * if and wherever such third-party acknowledgments normally appear.
29  *
30  * 4. The names "Krysalis" and "Nicola Ken Barozzi" and
31  * "Krysalis Barcode" must not be used to endorse or promote products
32  * derived from this software without prior written permission. For
33  * written permission, please contact nicolaken@krysalis.org.
34  *
35  * 5. Products derived from this software may not be called "Krysalis",
36  * "Krysalis Barcode", nor may "Krysalis" appear in their name,
37  * without prior written permission of Nicola Ken Barozzi.
38  *
39  * 6. This software may contain voluntary contributions made by many
40  * individuals, who decided to donate the code to this project in
41  * respect of this licence, and was originally created by
42  * Jeremias Maerki <jeremias@maerki.org>.
43  *
44  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
45  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
46  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
47  * DISCLAIMED. IN NO EVENT SHALL THE KRYSALIS PROJECT OR
48  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
49  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
50  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
51  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
52  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
53  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
54  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55  * SUCH DAMAGE.
56  * ====================================================================
57  */

58 package org.krysalis.barcode.impl;
59
60 /**
61  * Default encoder algorithm for Code128 barcode messages.
62  *
63  * @author Jeremias Maerki
64  */

65 public class DefaultCode128Encoder implements Code128Encoder {
66
67     private static final int CODESET_A = 1;
68     private static final int CODESET_B = 2;
69     private static final int CODESET_C = 4;
70
71     private static final int START_A = 103;
72     private static final int START_B = 104;
73     private static final int START_C = 105;
74     private static final int GOTO_A = 101;
75     private static final int GOTO_B = 100;
76     private static final int GOTO_C = 99;
77     private static final int FNC_1 = 102;
78     private static final int FNC_2 = 97;
79     private static final int FNC_3 = 96;
80     private static final int SHIFT = 98;
81     
82
83     private final boolean inCodeset(char c, int codeset) {
84         switch (codeset) {
85             case CODESET_A: return Code128LogicImpl.isInCodeSetA(c);
86             case CODESET_B: return Code128LogicImpl.isInCodeSetB(c);
87             case CODESET_C: return Code128LogicImpl.canBeInCodeSetC(c);
88             default: throw new IllegalArgumentException JavaDoc("Invalid codeset");
89         }
90     }
91     
92     private boolean needA(char c) {
93         //Character can't be encoded in B
94
return (c < 32);
95     }
96     
97     private boolean needB(char c) {
98         //Character can't be encoded in A
99
return (c >= 96) && (c < 128);
100     }
101     
102     private int determineAorB(char c) {
103         if (needA(c)) {
104             return CODESET_A;
105         } else if (Code128LogicImpl.isInCodeSetB(c)) {
106             return CODESET_B;
107         }
108         return 0;
109     }
110     
111     private int getStartControl(int codeset) {
112         switch (codeset) {
113             case CODESET_A: return START_A;
114             case CODESET_B: return START_B;
115             case CODESET_C: return START_C;
116             default: throw new IllegalArgumentException JavaDoc("Invalid codeset");
117         }
118     }
119
120     private boolean nextLotInCodeset(String JavaDoc msg, int startpos, int codeset, int count) {
121         if (startpos + count > msg.length()) {
122             //Prevent ArrayOutOfBoundsException
123
return false;
124         }
125         for (int i = 0; i < count; i++) {
126             if (!inCodeset(msg.charAt(startpos + i), codeset)) {
127                 return false;
128             }
129         }
130         return true;
131     }
132     
133     private int countCharsInSameCodeset(String JavaDoc msg, int startpos, int codeset) {
134         int count = 0;
135         while (startpos + count < msg.length()) {
136             if (!inCodeset(msg.charAt(startpos + count), codeset)) {
137                 break;
138             }
139             count++;
140         }
141         return count;
142     }
143     
144     private int encodeAorB(char c, int codeset) {
145         //Function chars
146
if (c == Code128LogicImpl.FNC_1) {
147             return FNC_1;
148         }
149         if (c == Code128LogicImpl.FNC_2) {
150             return FNC_2;
151         }
152         if (c == Code128LogicImpl.FNC_3) {
153             return FNC_3;
154         }
155         if (c == Code128LogicImpl.FNC_4) {
156             if (codeset == CODESET_A) {
157                 return 101;
158             } else {
159                 return 100;
160             }
161         }
162         //Convert normal characters
163
if (codeset == CODESET_A) {
164             if ((c >= 0) && (c < 32)) {
165                 return c + 64;
166             } else if ((c >= 32) && (c <= 95)) {
167                 return c - 32;
168             } else {
169                 throw new IllegalArgumentException JavaDoc("Illegal character: " + c);
170             }
171         } else if (codeset == CODESET_B) {
172             if ((c >= 32) && (c < 128)) {
173                 return c - 32;
174             } else {
175                 throw new IllegalArgumentException JavaDoc("Illegal character: " + c);
176             }
177         } else {
178             throw new IllegalArgumentException JavaDoc("Only A or B allowed");
179         }
180     }
181
182     /** @see org.krysalis.barcode.impl.Code128Encoder */
183     public int[] encode(String JavaDoc msg) {
184         //Allocate enough space
185
int[] encoded = new int[msg.length() * 2 + 5];
186         int currentCodeset;
187         int respos = 0;
188         int msgpos = 0;
189         //Determine start control
190
if ((msg.length() == 2)
191                 && nextLotInCodeset(msg, 0, CODESET_C, 2)) {
192             currentCodeset = CODESET_C;
193         } else if ((msg.length() >= 4)
194                 && nextLotInCodeset(msg, 0, CODESET_C, 4)) {
195             currentCodeset = CODESET_C;
196         } else {
197             currentCodeset = determineAorB(msg.charAt(0));
198             if (currentCodeset == 0) {
199                 currentCodeset = CODESET_B; //default
200
}
201         }
202         encoded[respos] = getStartControl(currentCodeset);
203         respos++;
204         
205         //Start encoding
206
while (msgpos < msg.length()) {
207             switch (currentCodeset) {
208                 case CODESET_C:
209                     if (msg.charAt(msgpos) == Code128LogicImpl.FNC_1) {
210                         //FNC_1 is the only valid function in Codeset C
211
encoded[respos] = FNC_1;
212                         respos++;
213                         msgpos++;
214                     } else if (nextLotInCodeset(msg, msgpos, CODESET_C, 2)) {
215                         //Encode the next two digits
216
encoded[respos] =
217                             Character.digit(msg.charAt(msgpos), 10) * 10
218                             + Character.digit(msg.charAt(msgpos + 1), 10);
219                         respos++;
220                         msgpos += 2;
221                     } else {
222                         //Need to change codeset
223
currentCodeset = determineAorB(msg.charAt(msgpos));
224                         if (currentCodeset == 0) {
225                             currentCodeset = CODESET_B;
226                         }
227                         if (currentCodeset == CODESET_A) {
228                             encoded[respos] = GOTO_A;
229                         } else {
230                             encoded[respos] = GOTO_B;
231                         }
232                         respos++;
233                     }
234                     break;
235                 case CODESET_B:
236                 case CODESET_A:
237                     int c = countCharsInSameCodeset(msg, msgpos, CODESET_C);
238                     if (c >= 4) {
239                         //Change to Codeset C
240
if ((c % 2) != 0) {
241                             //Odd number of digits in next passage
242
//Encode the first digit in the old codeset
243
encoded[respos] = Character.digit(msg.charAt(msgpos), 10) + 16;
244                             respos++;
245                             msgpos++;
246                         }
247                         encoded[respos] = GOTO_C;
248                         respos++;
249                         currentCodeset = CODESET_C;
250                     } else if ((currentCodeset == CODESET_A) && needB(msg.charAt(msgpos))) {
251                         //SHIFT or GOTO?
252
if (msgpos + 1 < msg.length()) {
253                             int preview = determineAorB(msg.charAt(msgpos + 1));
254                             if (preview == CODESET_B) {
255                                 //More than one B character
256
encoded[respos] = GOTO_B;
257                                 respos++;
258                                 currentCodeset = CODESET_B;
259                             }
260                         }
261                         if (currentCodeset == CODESET_A) {
262                             //No GOTO issued, we encode with SHIFT
263
encoded[respos] = SHIFT;
264                             respos++;
265                             encoded[respos] = encodeAorB(msg.charAt(msgpos), CODESET_B);
266                             respos++;
267                             msgpos++;
268                         }
269                     } else if ((currentCodeset == CODESET_B) && needA(msg.charAt(msgpos))) {
270                         //SHIFT or GOTO?
271
if (msgpos + 1 < msg.length()) {
272                             int preview = determineAorB(msg.charAt(msgpos + 1));
273                             if (preview == CODESET_A) {
274                                 //More than one A character
275
encoded[respos] = GOTO_A;
276                                 respos++;
277                                 currentCodeset = CODESET_A;
278                             }
279                         }
280                         if (currentCodeset == CODESET_B) {
281                             //No GOTO issued, we encode with SHIFT
282
encoded[respos] = SHIFT;
283                             respos++;
284                             encoded[respos] = encodeAorB(msg.charAt(msgpos), CODESET_A);
285                             respos++;
286                             msgpos++;
287                         }
288                     } else {
289                         encoded[respos] = encodeAorB(msg.charAt(msgpos), currentCodeset);
290                         respos++;
291                         msgpos++;
292                     }
293                     break;
294             } /*switch*/
295         }
296         int[] result = new int[respos];
297         System.arraycopy(encoded, 0, result, 0, result.length);
298         return result;
299     }
300
301
302 }
303
Popular Tags