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.code39;
28  
29  import net.sourceforge.barbecue.BarcodeException;
30  import net.sourceforge.barbecue.CompositeModule;
31  import net.sourceforge.barbecue.Module;
32  import net.sourceforge.barbecue.SeparatorModule;
33  import net.sourceforge.barbecue.linear.LinearBarcode;
34  
35  import java.text.CharacterIterator;
36  import java.text.StringCharacterIterator;
37  import java.util.ArrayList;
38  import java.util.List;
39  
40  /**
41   * This is a concrete implementation of the Code 39 barcode, AKA 3of9,
42   * USD-3.
43   *
44   * @author <a href="mailto:opensource@ianbourke.com">Ian Bourke</a>
45   */
46  public class Code39Barcode extends LinearBarcode {
47      /**
48       * A list of type identifiers for the Code39 barcode format
49       */
50      public static final String[] TYPES = new String[]{
51          "Code39", "USD3", "3of9"
52      };
53      private final boolean requiresChecksum;
54      private final String label;
55  
56      /**
57       * Constructs a basic mode Code 39 barcode with the specified data and an optional
58       * checksum.
59       *
60       * @param data             The data to encode
61       * @param requiresChecksum A flag indicating whether a checksum is required or not
62       * @throws BarcodeException If the data to be encoded is invalid
63       */
64      public Code39Barcode(String data, boolean requiresChecksum) throws BarcodeException {
65          this(data, requiresChecksum, false);
66      }
67  
68      /**
69       * Constructs an extended mode Code 39 barcode with the specified data and an optional
70       * checksum. The extended mode encodes all 128 ASCII characters using two character pairs
71       * from the basic Code 39 character set. Note that most barcode scanners will need to
72       * be configured to accept extended Code 39.
73       *
74       * @param data             The data to encode
75       * @param requiresChecksum A flag indicating whether a checksum is required or not
76       * @param extendedMode     Puts the barcode into extended mode, where all 128 ASCII characters can be encoded
77       * @throws BarcodeException If the data to be encoded is invalid
78       */
79      public Code39Barcode(String data, boolean requiresChecksum, boolean extendedMode) throws BarcodeException {
80          super(extendedMode ? encodeExtendedChars(data) : validateBasicChars(data));
81          this.requiresChecksum = requiresChecksum;
82          this.label = data;
83      }
84  
85      /**
86       * Returns the text that will be displayed underneath the barcode (if requested).
87       *
88       * @return The text label for the barcode
89       */
90      public String getLabel() {
91          return label;
92      }
93  
94      /**
95       * Returns the encoded data for the barcode.
96       *
97       * @return An array of modules that represent the data as a barcode
98       */
99      protected Module[] encodeData() {
100         List modules = new ArrayList();
101         for (int i = 0; i < data.length(); i++) {
102             char c = data.charAt(i);
103             modules.add(new SeparatorModule(1));
104             Module module = ModuleFactory.getModule(String.valueOf(c));
105             modules.add(module);
106         }
107         modules.add(new SeparatorModule(1));
108         return (Module[]) modules.toArray(new Module[0]);
109     }
110 
111     /**
112      * Returns the checksum for the barcode, pre-encoded as a Module.
113      *
114      * @return Null if no checksum is required, a Mod-43 calculated checksum otherwise
115      */
116     protected Module calculateChecksum() {
117         if (requiresChecksum) {
118             int checkIndex = calculateMod43(data);
119             CompositeModule compositeModule = new CompositeModule();
120             compositeModule.add(ModuleFactory.getModuleForIndex(checkIndex));
121             compositeModule.add(new SeparatorModule(1));
122             return compositeModule;
123         }
124         return null;
125     }
126 
127     /**
128      * Returns the for the Mod-43 checkIndex for the barcode as an int
129      *
130      * @return Mod-43 checkIndex for the given data String
131      */
132     public static int calculateMod43(final String givenData) {
133         int sum = 0;
134         StringCharacterIterator iter = new StringCharacterIterator(givenData);
135         for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
136             sum += ModuleFactory.getIndex(String.valueOf(c));
137         }
138         int checkIndex = sum % 43;
139         return checkIndex;
140     }
141 
142     /**
143      * Returns the pre-amble for the barcode.
144      *
145      * @return ModuleFactory.START_STOP
146      */
147     protected Module getPreAmble() {
148         return ModuleFactory.START_STOP;
149     }
150 
151     /**
152      * Returns the post-amble for the barcode.
153      *
154      * @return ModuleFactory.START_STOP
155      */
156     protected Module getPostAmble() {
157         return ModuleFactory.START_STOP;
158     }
159 
160     private static String validateBasicChars(String data) throws BarcodeException {
161         StringCharacterIterator iter = new StringCharacterIterator(data);
162         for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
163             if (!ModuleFactory.hasModule(String.valueOf(c), false)) {
164                 throw new BarcodeException("Illegal character - try using extended mode if you need "
165                         + "to encode the full ASCII character set");
166             }
167         }
168         return data;
169     }
170 
171     private static String encodeExtendedChars(String data) {
172         StringBuffer buf = new StringBuffer();
173         StringCharacterIterator iter = new StringCharacterIterator(data);
174         for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
175             if (!ModuleFactory.hasModule(String.valueOf(c), true)) {
176                 buf.append(ModuleFactory.getExtendedCharacter(c));
177             } else {
178                 buf.append(c);
179             }
180         }
181         return buf.toString();
182     }
183 }