• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2010 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.oned;
18 
19 import com.google.zxing.BarcodeFormat;
20 import com.google.zxing.common.BitMatrix;
21 
22 import java.util.Collection;
23 import java.util.Collections;
24 
25 /**
26  * This object renders a CODE39 code as a {@link BitMatrix}.
27  *
28  * @author erik.barbara@gmail.com (Erik Barbara)
29  */
30 public final class Code39Writer extends OneDimensionalCodeWriter {
31 
32   @Override
getSupportedWriteFormats()33   protected Collection<BarcodeFormat> getSupportedWriteFormats() {
34     return Collections.singleton(BarcodeFormat.CODE_39);
35   }
36 
37   @Override
encode(String contents)38   public boolean[] encode(String contents) {
39     int length = contents.length();
40     if (length > 80) {
41       throw new IllegalArgumentException(
42           "Requested contents should be less than 80 digits long, but got " + length);
43     }
44 
45     for (int i = 0; i < length; i++) {
46       int indexInString = Code39Reader.ALPHABET_STRING.indexOf(contents.charAt(i));
47       if (indexInString < 0) {
48         contents = tryToConvertToExtendedMode(contents);
49         length = contents.length();
50         if (length > 80) {
51           throw new IllegalArgumentException("Requested contents should be less than 80 digits long, but got " +
52               length + " (extended full ASCII mode)");
53         }
54         break;
55       }
56     }
57 
58     int[] widths = new int[9];
59     int codeWidth = 24 + 1 + (13 * length);
60     boolean[] result = new boolean[codeWidth];
61     toIntArray(Code39Reader.ASTERISK_ENCODING, widths);
62     int pos = appendPattern(result, 0, widths, true);
63     int[] narrowWhite = {1};
64     pos += appendPattern(result, pos, narrowWhite, false);
65     //append next character to byte matrix
66     for (int i = 0; i < length; i++) {
67       int indexInString = Code39Reader.ALPHABET_STRING.indexOf(contents.charAt(i));
68       toIntArray(Code39Reader.CHARACTER_ENCODINGS[indexInString], widths);
69       pos += appendPattern(result, pos, widths, true);
70       pos += appendPattern(result, pos, narrowWhite, false);
71     }
72     toIntArray(Code39Reader.ASTERISK_ENCODING, widths);
73     appendPattern(result, pos, widths, true);
74     return result;
75   }
76 
toIntArray(int a, int[] toReturn)77   private static void toIntArray(int a, int[] toReturn) {
78     for (int i = 0; i < 9; i++) {
79       int temp = a & (1 << (8 - i));
80       toReturn[i] = temp == 0 ? 1 : 2;
81     }
82   }
83 
tryToConvertToExtendedMode(String contents)84   private static String tryToConvertToExtendedMode(String contents) {
85     int length = contents.length();
86     StringBuilder extendedContent = new StringBuilder();
87     for (int i = 0; i < length; i++) {
88       char character = contents.charAt(i);
89       switch (character) {
90         case '\u0000':
91           extendedContent.append("%U");
92           break;
93         case ' ':
94         case '-':
95         case '.':
96           extendedContent.append(character);
97           break;
98         case '@':
99           extendedContent.append("%V");
100           break;
101         case '`':
102           extendedContent.append("%W");
103           break;
104         default:
105           if (character <= 26) {
106             extendedContent.append('$');
107             extendedContent.append((char) ('A' + (character - 1)));
108           } else if (character < ' ') {
109             extendedContent.append('%');
110             extendedContent.append((char) ('A' + (character - 27)));
111           } else if (character <= ',' || character == '/' || character == ':') {
112             extendedContent.append('/');
113             extendedContent.append((char) ('A' + (character - 33)));
114           } else if (character <= '9') {
115             extendedContent.append((char) ('0' + (character - 48)));
116           } else if (character <= '?') {
117             extendedContent.append('%');
118             extendedContent.append((char) ('F' + (character - 59)));
119           } else if (character <= 'Z') {
120             extendedContent.append((char) ('A' + (character - 65)));
121           } else if (character <= '_') {
122             extendedContent.append('%');
123             extendedContent.append((char) ('K' + (character - 91)));
124           } else if (character <= 'z') {
125             extendedContent.append('+');
126             extendedContent.append((char) ('A' + (character - 97)));
127           } else if (character <= 127) {
128             extendedContent.append('%');
129             extendedContent.append((char) ('P' + (character - 123)));
130           } else {
131             throw new IllegalArgumentException(
132                 "Requested content contains a non-encodable character: '" + contents.charAt(i) + "'");
133           }
134           break;
135       }
136     }
137 
138     return extendedContent.toString();
139   }
140 
141 }
142