View Javadoc

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.linear.codabar;
28  
29  import net.sourceforge.barbecue.BarcodeException;
30  import net.sourceforge.barbecue.BlankModule;
31  import net.sourceforge.barbecue.Module;
32  import net.sourceforge.barbecue.SeparatorModule;
33  import net.sourceforge.barbecue.linear.LinearBarcode;
34  
35  import java.util.ArrayList;
36  import java.util.List;
37  import java.text.CharacterIterator;
38  import java.text.StringCharacterIterator;
39  
40  /**
41   * This is a concrete implementation of the Codabar barcode, AKA USD-4,
42   * Monarch, NW-7 and 2of7. This implementation imposes no restrictions
43   * on your choice of start and stop characters, so you will need to check
44   * that you are using chars acceptable to your barcode scanner. This
45   * implementation does support the traditional a, b, c, d, e, t, n and * start/stop chars.
46   * Omitting the start/stop chars from your data will cause the barcode to use
47   * the default start/stops chars, A and C, respectively.
48   * <br/>
49   * This implementation provides no support for check digits (as they are not
50   * included in the Codabar specification). However, many uses of Codabars
51   * mandate the use of a check digit, and the algorithms used vary from
52   * application to application. The most common algorithm is Mod-16. If you wish
53   * to implement a check digit in your Codabar barcode, you must calculate it
54   * yourself and insert it into the data to be encoded before the Stop char (or at
55   * the end of the data if you are letting barbecue insert start and stop chars for
56   * you).
57   *
58   * @author <a href="mailto:opensource@ianbourke.com">Ian Bourke</a>
59   */
60  public class CodabarBarcode extends LinearBarcode {
61      /** The default codabar start character */
62      public static final String DEFAULT_START = "A";
63      /** The default codabar stop character */
64      public static final String DEFAULT_STOP = "C";
65      
66      private String label;
67      
68      /**
69       * Constructs a new Codabar barcode with thte specified data.
70       * @param data The data to encode
71       * @throws BarcodeException If the data is invalid
72       */
73      public CodabarBarcode(String data) throws BarcodeException {
74          super(data);
75          this.label = data;
76          validateData();
77      }
78      
79      /**
80       * Returns the text label to be displayed underneath the barcode.
81       * @return The barcode label
82       */
83      public String getLabel() {
84          return label;
85      }
86      
87      /**
88       * Encodes the data of the barcode into bars.
89       * @return The encoded bar data
90       */
91      protected Module[] encodeData() {
92          List modules = new ArrayList();
93          for (int i = 0; i < data.length(); i++) {
94              if (i > 0) {
95                  modules.add(new SeparatorModule(1));
96              }
97              char c = data.charAt(i);
98              Module module = ModuleFactory.getModule(String.valueOf(c));
99              modules.add(module);
100         }
101         return (Module[]) modules.toArray(new Module[0]);
102     }
103     
104     /**
105      * Calculates the check sum digit for the barcode.
106      * @return Null - Codabar has no checksum
107      */
108     protected Module calculateChecksum() {
109         return null; // No checksum - return null
110     }
111     
112     /**
113      * Returns the pre-amble for the barcode.
114      * @return A BlankModule
115      */
116     protected Module getPreAmble() {
117         if(drawingQuietSection) {
118             return new BlankModule(0);
119         } else {
120             return null;
121         }
122     }
123     
124     /**
125      * Returns the post-amble for the barcode.
126      * @return A BlankModule
127      */
128     protected Module getPostAmble() {
129         if(drawingQuietSection) {
130             return new BlankModule(0);
131         } else {
132             return null;
133         }
134     }
135     
136     private void validateData() throws BarcodeException {
137         replaceTraditionalStartStopWithModern();
138         addDefaultStartStopIfRequired();
139         int index = 0;
140         StringBuffer buf = new StringBuffer();
141         StringCharacterIterator iter = new StringCharacterIterator(data);
142         for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
143             if (!Character.isWhitespace(c)) {
144                 if (!ModuleFactory.isValid(String.valueOf(c))) {
145                     throw new BarcodeException(c
146                     + " is not a valid character for Codabar encoding");
147                 }
148                 checkStartStop(c, index);
149                 buf.append(c);
150             }
151             index += 1;
152         }
153         data = buf.toString();
154     }
155     
156     private void addDefaultStartStopIfRequired() {
157         StringBuffer newData = new StringBuffer();
158         if (!Character.isLetter(data.charAt(0))) {
159             newData.append(DEFAULT_START);
160         }
161         newData.append(data);
162         if (!Character.isLetter(data.charAt(data.length() - 1))) {
163             newData.append(DEFAULT_STOP);
164         }
165         data = newData.toString();
166     }
167     
168     private void replaceTraditionalStartStopWithModern() {
169         data = data.replace('a', 'A');
170         data = data.replace('t', 'A');
171         data = data.replace('b', 'B');
172         data = data.replace('n', 'B');
173         data = data.replace('c', 'C');
174         data = data.replace('*', 'C');
175         data = data.replace('d', 'D');
176         data = data.replace('e', 'D');
177     }
178     
179     private void checkStartStop(char c, int index) throws BarcodeException {
180         if (Character.isLetter(c) && index > 0 && index < data.length() - 1) {
181             throw new BarcodeException(c
182             + " is only allowed as the first and last characters for Codabar barcodes");
183         }
184     }
185 }