barcode1dtools 0.9.3.0 → 0.9.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -13,12 +13,11 @@ module Barcode1DTools
13
13
  #= barcode1dtools.rb
14
14
  #
15
15
  # Barcode1DTools is a library for generating and decoding
16
- # 1-dimensional barcode patterns for various code types.
17
- # The library currently includes EAN-13, EAN-8, UPC-A,
18
- # UPC-E, UPC Supplemental 2, UPC Supplemental 5,
19
- # Interleaved 2 of 5 (I 2/5), and Code 3 of 9, but will be
20
- # expanded to include most 1D symbologies in the near
21
- # future.
16
+ # 1-dimensional barcode patterns for various code types. The
17
+ # library currently includes EAN-13, EAN-8, UPC-A, UPC-E, UPC
18
+ # Supplemental 2, UPC Supplemental 5, Interleaved 2 of 5 (I 2/5),
19
+ # Code 3 of 9, and Code 93, but will be expanded to include most 1D
20
+ # symbologies in the near future.
22
21
  #
23
22
  #== Example
24
23
  # ean13 = Barcode1DTools::EAN13.new('0012676510226', :line_character => 'x', :space_character => ' ')
@@ -119,3 +118,4 @@ require 'barcode1dtools/upc_e'
119
118
  require 'barcode1dtools/upc_supplemental_2'
120
119
  require 'barcode1dtools/upc_supplemental_5'
121
120
  require 'barcode1dtools/code3of9'
121
+ require 'barcode1dtools/code93'
@@ -72,6 +72,13 @@ module Barcode1DTools
72
72
  # only for shifting. However, if you need to use a full character
73
73
  # set, Code 128 is probably a better choice.
74
74
  #
75
+ # Note:
76
+ # Please note that Code 3 of 9 is not suggested for new applications
77
+ # due to the fact that the code is sparse and doesn't encode a full
78
+ # range of characters without using the "full ascii extensions",
79
+ # which cause it to be even more sparse. For newer 1D applications
80
+ # use Code 128.
81
+ #
75
82
  #== Rendering
76
83
  #
77
84
  # Code 3 of 9 may be rendered however the programmer wishes. Since
@@ -140,6 +147,156 @@ module Barcode1DTools
140
147
 
141
148
  SIDE_GUARD_PATTERN = 'nwnnwnwnn'
142
149
 
150
+ FULL_ASCII_LOOKUP = [
151
+ '%U', '$A', '$B', '$C', '$D', '$E', '$F', '$G', '$H', '$I',
152
+ '$J', '$K', '$L', '$M', '$N', '$O', '$P', '$Q', '$R', '$S',
153
+ '$T', '$U', '$V', '$W', '$X', '$Y', '$Z', '%A', '%B', '%C',
154
+ '%D', '%E', ' ', '/A', '/B', '/C', '/D', '/E', '/F', '/G',
155
+ '/H', '/I', '/J', '/K', '/L', '-', '.', '/O', '0', '1', '2',
156
+ '3', '4', '5', '6', '7', '8', '9', '/Z', '%F', '%G', '%H',
157
+ '%I', '%J', '%V', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
158
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
159
+ 'U', 'V', 'W', 'X', 'Y', 'Z', '%K', '%L', '%M', '%N', '%O',
160
+ '%W', '+A', '+B', '+C', '+D', '+E', '+F', '+G', '+H', '+I',
161
+ '+J', '+K', '+L', '+M', '+N', '+O', '+P', '+Q', '+R', '+S',
162
+ '+T', '+U', '+V', '+W', '+X', '+Y', '+Z', '%P', '%Q', '%R',
163
+ '%S', '%T'
164
+ ]
165
+
166
+ FULL_ASCII_REVERSE_LOOKUP = {
167
+ '%U' => { 'position' => 0, 'name' => '<NUL>' },
168
+ '$A' => { 'position' => 1, 'name' => '<SOH>' },
169
+ '$B' => { 'position' => 2, 'name' => '<STX>' },
170
+ '$C' => { 'position' => 3, 'name' => '<ETX>' },
171
+ '$D' => { 'position' => 4, 'name' => '<EOT>' },
172
+ '$E' => { 'position' => 5, 'name' => '<ENQ>' },
173
+ '$F' => { 'position' => 6, 'name' => '<ACK>' },
174
+ '$G' => { 'position' => 7, 'name' => '<BEL>' },
175
+ '$H' => { 'position' => 8, 'name' => '<BS>' },
176
+ '$I' => { 'position' => 9, 'name' => '<HT>' },
177
+ '$J' => { 'position' => 10, 'name' => '<LF>' },
178
+ '$K' => { 'position' => 11, 'name' => '<VT>' },
179
+ '$L' => { 'position' => 12, 'name' => '<FF>' },
180
+ '$M' => { 'position' => 13, 'name' => '<CR>' },
181
+ '$N' => { 'position' => 14, 'name' => '<SO>' },
182
+ '$O' => { 'position' => 15, 'name' => '<SI>' },
183
+ '$P' => { 'position' => 16, 'name' => '<DLE>' },
184
+ '$Q' => { 'position' => 17, 'name' => '<DC1>' },
185
+ '$R' => { 'position' => 18, 'name' => '<DC2>' },
186
+ '$S' => { 'position' => 19, 'name' => '<DC3>' },
187
+ '$T' => { 'position' => 20, 'name' => '<DC4>' },
188
+ '$U' => { 'position' => 21, 'name' => '<NAK>' },
189
+ '$V' => { 'position' => 22, 'name' => '<SYN>' },
190
+ '$W' => { 'position' => 23, 'name' => '<ETB>' },
191
+ '$X' => { 'position' => 24, 'name' => '<CAN>' },
192
+ '$Y' => { 'position' => 25, 'name' => '<EM>' },
193
+ '$Z' => { 'position' => 26, 'name' => '<SUB>' },
194
+ '%A' => { 'position' => 27, 'name' => '<ESC>' },
195
+ '%B' => { 'position' => 28, 'name' => '<FS>' },
196
+ '%C' => { 'position' => 29, 'name' => '<GS>' },
197
+ '%D' => { 'position' => 30, 'name' => '<RS>' },
198
+ '%E' => { 'position' => 31, 'name' => '<US>' },
199
+ ' ' => { 'position' => 32, 'name' => ' ' },
200
+ '/A' => { 'position' => 33, 'name' => '!' },
201
+ '/B' => { 'position' => 34, 'name' => '"' },
202
+ '/C' => { 'position' => 35, 'name' => '#' },
203
+ '/D' => { 'position' => 36, 'name' => '$' },
204
+ '/E' => { 'position' => 37, 'name' => '%' },
205
+ '/F' => { 'position' => 38, 'name' => '&' },
206
+ '/G' => { 'position' => 39, 'name' => "'" },
207
+ '/H' => { 'position' => 40, 'name' => '(' },
208
+ '/I' => { 'position' => 41, 'name' => ')' },
209
+ '/J' => { 'position' => 42, 'name' => '*' },
210
+ '/K' => { 'position' => 43, 'name' => '+' },
211
+ '/L' => { 'position' => 44, 'name' => ',' },
212
+ '-' => { 'position' => 45, 'name' => '-' },
213
+ '.' => { 'position' => 46, 'name' => '.' },
214
+ '/O' => { 'position' => 47, 'name' => '/' },
215
+ '0' => { 'position' => 48, 'name' => '0' },
216
+ '1' => { 'position' => 49, 'name' => '1' },
217
+ '2' => { 'position' => 50, 'name' => '2' },
218
+ '3' => { 'position' => 51, 'name' => '3' },
219
+ '4' => { 'position' => 52, 'name' => '4' },
220
+ '5' => { 'position' => 53, 'name' => '5' },
221
+ '6' => { 'position' => 54, 'name' => '6' },
222
+ '7' => { 'position' => 55, 'name' => '7' },
223
+ '8' => { 'position' => 56, 'name' => '8' },
224
+ '9' => { 'position' => 57, 'name' => '9' },
225
+ '/Z' => { 'position' => 58, 'name' => ':' },
226
+ '%F' => { 'position' => 59, 'name' => ';' },
227
+ '%G' => { 'position' => 60, 'name' => '<' },
228
+ '%H' => { 'position' => 61, 'name' => '=' },
229
+ '%I' => { 'position' => 62, 'name' => '>' },
230
+ '%J' => { 'position' => 63, 'name' => '?' },
231
+ '%V' => { 'position' => 64, 'name' => '@' },
232
+ 'A' => { 'position' => 65, 'name' => 'A' },
233
+ 'B' => { 'position' => 66, 'name' => 'B' },
234
+ 'C' => { 'position' => 67, 'name' => 'C' },
235
+ 'D' => { 'position' => 68, 'name' => 'D' },
236
+ 'E' => { 'position' => 69, 'name' => 'E' },
237
+ 'F' => { 'position' => 70, 'name' => 'F' },
238
+ 'G' => { 'position' => 71, 'name' => 'G' },
239
+ 'H' => { 'position' => 72, 'name' => 'H' },
240
+ 'I' => { 'position' => 73, 'name' => 'I' },
241
+ 'J' => { 'position' => 74, 'name' => 'J' },
242
+ 'K' => { 'position' => 75, 'name' => 'K' },
243
+ 'L' => { 'position' => 76, 'name' => 'L' },
244
+ 'M' => { 'position' => 77, 'name' => 'M' },
245
+ 'N' => { 'position' => 78, 'name' => 'N' },
246
+ 'O' => { 'position' => 79, 'name' => 'O' },
247
+ 'P' => { 'position' => 80, 'name' => 'P' },
248
+ 'Q' => { 'position' => 81, 'name' => 'Q' },
249
+ 'R' => { 'position' => 82, 'name' => 'R' },
250
+ 'S' => { 'position' => 83, 'name' => 'S' },
251
+ 'T' => { 'position' => 84, 'name' => 'T' },
252
+ 'U' => { 'position' => 85, 'name' => 'U' },
253
+ 'V' => { 'position' => 86, 'name' => 'V' },
254
+ 'W' => { 'position' => 87, 'name' => 'W' },
255
+ 'X' => { 'position' => 88, 'name' => 'X' },
256
+ 'Y' => { 'position' => 89, 'name' => 'Y' },
257
+ 'Z' => { 'position' => 90, 'name' => 'Z' },
258
+ '%K' => { 'position' => 91, 'name' => '[' },
259
+ '%L' => { 'position' => 92, 'name' => '\\' },
260
+ '%M' => { 'position' => 93, 'name' => ']' },
261
+ '%N' => { 'position' => 94, 'name' => '^' },
262
+ '%O' => { 'position' => 95, 'name' => '_' },
263
+ '%W' => { 'position' => 96, 'name' => '`' },
264
+ '+A' => { 'position' => 97, 'name' => 'a' },
265
+ '+B' => { 'position' => 98, 'name' => 'b' },
266
+ '+C' => { 'position' => 99, 'name' => 'c' },
267
+ '+D' => { 'position' => 100, 'name' => 'd' },
268
+ '+E' => { 'position' => 101, 'name' => 'e' },
269
+ '+F' => { 'position' => 102, 'name' => 'f' },
270
+ '+G' => { 'position' => 103, 'name' => 'g' },
271
+ '+H' => { 'position' => 104, 'name' => 'h' },
272
+ '+I' => { 'position' => 105, 'name' => 'i' },
273
+ '+J' => { 'position' => 106, 'name' => 'j' },
274
+ '+K' => { 'position' => 107, 'name' => 'k' },
275
+ '+L' => { 'position' => 108, 'name' => 'l' },
276
+ '+M' => { 'position' => 109, 'name' => 'm' },
277
+ '+N' => { 'position' => 110, 'name' => 'n' },
278
+ '+O' => { 'position' => 111, 'name' => 'o' },
279
+ '+P' => { 'position' => 112, 'name' => 'p' },
280
+ '+Q' => { 'position' => 113, 'name' => 'q' },
281
+ '+R' => { 'position' => 114, 'name' => 'r' },
282
+ '+S' => { 'position' => 115, 'name' => 's' },
283
+ '+T' => { 'position' => 116, 'name' => 't' },
284
+ '+U' => { 'position' => 117, 'name' => 'u' },
285
+ '+V' => { 'position' => 118, 'name' => 'v' },
286
+ '+W' => { 'position' => 119, 'name' => 'w' },
287
+ '+X' => { 'position' => 120, 'name' => 'x' },
288
+ '+Y' => { 'position' => 121, 'name' => 'y' },
289
+ '+Z' => { 'position' => 122, 'name' => 'z' },
290
+ '%P' => { 'position' => 123, 'name' => '{' },
291
+ '%Q' => { 'position' => 124, 'name' => '|' },
292
+ '%R' => { 'position' => 125, 'name' => '}' },
293
+ '%S' => { 'position' => 126, 'name' => '~' },
294
+ '%T' => { 'position' => 127, 'name' => '<DEL>' },
295
+ '%X' => { 'position' => 127, 'name' => '<DEL>' },
296
+ '%Y' => { 'position' => 127, 'name' => '<DEL>' },
297
+ '%Z' => { 'position' => 127, 'name' => '<DEL>' }
298
+ }
299
+
143
300
  WN_RATIO = 2
144
301
 
145
302
  DEFAULT_OPTIONS = {
@@ -219,6 +376,26 @@ module Barcode1DTools
219
376
 
220
377
  Code3of9.new(decoded_string, options)
221
378
  end
379
+
380
+ # Provide encoding into the "full ascii" format. This
381
+ # allows us to encode any ascii character (0-127) in a Code 3
382
+ # of 9, but it is up to the application to anticipate and
383
+ # handle this. In this encoding, four of the characters
384
+ # ($, %, /, and +) are used as "shift" characters, paired
385
+ # with a letter A-Z that encodes a character that's not
386
+ # available in Code 3 of 9. Because no special characters
387
+ # are used, it's not possible to know if this encoding is
388
+ # used.
389
+ def encode_full_ascii(str)
390
+ str.bytes.collect { |c| FULL_ASCII_LOOKUP[c] }.join
391
+ end
392
+
393
+ # Decodes a "full ascii" string from Code 3 of 9 into standard
394
+ # ascii. Note that this will silently fail if a string is
395
+ # malformed.
396
+ def decode_full_ascii(str)
397
+ str.scan(/[\$%\/+]?[A-Z0-9 \.\-]/).collect { |c| FULL_ASCII_REVERSE_LOOKUP[c]['position'] }.pack('C*')
398
+ end
222
399
  end
223
400
 
224
401
  # Options are :line_character, :space_character, :w_character,
@@ -0,0 +1,479 @@
1
+ #--
2
+ # Copyright 2012 Michael Chaney Consulting Corporation
3
+ #
4
+ # Released under the terms of the MIT License or the GNU
5
+ # General Public License, v. 2
6
+ #++
7
+
8
+ module Barcode1DTools
9
+
10
+ # Barcode1DTools::Code93 - Create and decode bar patterns for
11
+ # Code93. The value encoded is a string, and two checksum "digits"
12
+ # (actually characters) will be added to the end before encoding.
13
+ # You may use the option :checksum_included => true when
14
+ # initializing to specify that you have already included a
15
+ # checksum, A ChecksumError will be raised if
16
+ # :checksum_included => true and the checksum is invalid.
17
+ #
18
+ # Code 93 can encode any ascii character (0-127) but will be most
19
+ # efficient for those characters that may be natively encoded as
20
+ # a single character: digits, uppercase letters, and the symbols
21
+ # dash "-", period ".", dollar sign "$", forward slash "/", plus
22
+ # sign "+", percent sign "%", as well as a space " ".
23
+ #
24
+ # val = "THIS IS A TEST"
25
+ # bc = Barcode1DTools::Code93.new(val)
26
+ # pattern = bc.bars
27
+ # rle_pattern = bc.rle
28
+ # width = bc.width
29
+ # # Note that the check digits are actually two of the characters.
30
+ # check_digit = Barcode1DTools::Code93.generate_check_digit_for(num)
31
+ #
32
+ # The object created is immutable.
33
+ #
34
+ # Barcode1DTools::Code93 creates the patterns that you need to
35
+ # display Code 93 barcodes. It can also decode a simple w/n
36
+ # string.
37
+ #
38
+ # Code 93 barcodes consist of lines and spaces that are from
39
+ # one to four units wide each. A particular character has 3 bars
40
+ # and 3 spaces.
41
+ #
42
+ # There are two formats for the returned pattern:
43
+ #
44
+ # bars - 1s and 0s specifying black lines and white spaces. Actual
45
+ # characters can be changed from "1" and 0" with options
46
+ # :line_character and :space_character.
47
+ #
48
+ # rle - Run-length-encoded version of the pattern. The first
49
+ # number is always a black line, with subsequent digits
50
+ # alternating between spaces and lines. The digits specify
51
+ # the width of each line or space.
52
+ #
53
+ # The "width" method will tell you the total end-to-end width, in
54
+ # units, of the entire barcode. Note that the w/n format is
55
+ # unavailable for this symbology.
56
+ #
57
+ #== Miscellaneous Information
58
+ #
59
+ # Code 93 can encode any ascii character from 0 to 127. The design
60
+ # is identical to Code 3 of 9 in most respects, with the main
61
+ # difference being that the "shift" characters are separate from the
62
+ # regular encoded characters and it is thus possible to tell if a
63
+ # particular code is "regular" or "full ascii". This symbology is
64
+ # most efficient if only the native characters are used.
65
+ #
66
+ # This module will automatically promote the code to "full ascii"
67
+ # only if it is needed. In practical terms that means that a dollar
68
+ # sign, for instance, may be rendered one of two ways. If the
69
+ # payload contains only "native" characters, it will be encoded
70
+ # normally. But if any "extended" characters are used, such as a
71
+ # lowercase letter, the dollar sign will be likewise encoded as
72
+ # "(/)D". You can use the accessor "full_ascii" to see if full
73
+ # ascii mode is in effect. The option :force_full_ascii will
74
+ # cause that mode to be used whether needed or not.
75
+ #
76
+ # Internally, the four shift characters are represented as characters
77
+ # 128 "($)", 129 "(%)", 130 "(/)", and 131 "(+)".
78
+ #
79
+ #== Rendering
80
+ #
81
+ # Code 93 may be rendered however the programmer wishes. Since
82
+ # there is a simple mapping between number of characters and length of
83
+ # code, a variable length code should be allowed to grow and shrink to
84
+ # assure the bars are neither too large or too small. Code 93 is
85
+ # often implemented as a font.
86
+ #
87
+ # There is no standard for human-readable text associated with the
88
+ # code, and in fact some applications leave out the human-readable
89
+ # element altogether. The text is typically shown below the barcode
90
+ # where applicable.
91
+
92
+ class Code93 < Barcode1D
93
+
94
+ # Character sequence - 0-based offset in this string is character
95
+ # number
96
+ CHAR_SEQUENCE = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%\x80\x81\x82\x83"
97
+
98
+ # Patterns for making bar codes
99
+ PATTERNS = {
100
+ '0'=> {'position' => 0, 'display' => '0', 'rle' => '131112', 'bars' => '100010100'},
101
+ '1'=> {'position' => 1, 'display' => '1', 'rle' => '111213', 'bars' => '101001000'},
102
+ '2'=> {'position' => 2, 'display' => '2', 'rle' => '111312', 'bars' => '101000100'},
103
+ '3'=> {'position' => 3, 'display' => '3', 'rle' => '111411', 'bars' => '101000010'},
104
+ '4'=> {'position' => 4, 'display' => '4', 'rle' => '121113', 'bars' => '100101000'},
105
+ '5'=> {'position' => 5, 'display' => '5', 'rle' => '121212', 'bars' => '100100100'},
106
+ '6'=> {'position' => 6, 'display' => '6', 'rle' => '121311', 'bars' => '100100010'},
107
+ '7'=> {'position' => 7, 'display' => '7', 'rle' => '111114', 'bars' => '101010000'},
108
+ '8'=> {'position' => 8, 'display' => '8', 'rle' => '131211', 'bars' => '100010010'},
109
+ '9'=> {'position' => 9, 'display' => '9', 'rle' => '141111', 'bars' => '100001010'},
110
+ 'A' => {'position' => 10, 'display' => 'A', 'rle' => '211113', 'bars' => '110101000'},
111
+ 'B' => {'position' => 11, 'display' => 'B', 'rle' => '211212', 'bars' => '110100100'},
112
+ 'C' => {'position' => 12, 'display' => 'C', 'rle' => '211311', 'bars' => '110100010'},
113
+ 'D' => {'position' => 13, 'display' => 'D', 'rle' => '221112', 'bars' => '110010100'},
114
+ 'E' => {'position' => 14, 'display' => 'E', 'rle' => '221211', 'bars' => '110010010'},
115
+ 'F' => {'position' => 15, 'display' => 'F', 'rle' => '231111', 'bars' => '110001010'},
116
+ 'G' => {'position' => 16, 'display' => 'G', 'rle' => '112113', 'bars' => '101101000'},
117
+ 'H' => {'position' => 17, 'display' => 'H', 'rle' => '112212', 'bars' => '101100100'},
118
+ 'I' => {'position' => 18, 'display' => 'I', 'rle' => '112311', 'bars' => '101100010'},
119
+ 'J' => {'position' => 19, 'display' => 'J', 'rle' => '122112', 'bars' => '100110100'},
120
+ 'K' => {'position' => 20, 'display' => 'K', 'rle' => '132111', 'bars' => '100011010'},
121
+ 'L' => {'position' => 21, 'display' => 'L', 'rle' => '111123', 'bars' => '101011000'},
122
+ 'M' => {'position' => 22, 'display' => 'M', 'rle' => '111222', 'bars' => '101001100'},
123
+ 'N' => {'position' => 23, 'display' => 'N', 'rle' => '111321', 'bars' => '101000110'},
124
+ 'O' => {'position' => 24, 'display' => 'O', 'rle' => '121122', 'bars' => '100101100'},
125
+ 'P' => {'position' => 25, 'display' => 'P', 'rle' => '131121', 'bars' => '100010110'},
126
+ 'Q' => {'position' => 26, 'display' => 'Q', 'rle' => '212112', 'bars' => '110110100'},
127
+ 'R' => {'position' => 27, 'display' => 'R', 'rle' => '212211', 'bars' => '110110010'},
128
+ 'S' => {'position' => 28, 'display' => 'S', 'rle' => '211122', 'bars' => '110101100'},
129
+ 'T' => {'position' => 29, 'display' => 'T', 'rle' => '211221', 'bars' => '110100110'},
130
+ 'U' => {'position' => 30, 'display' => 'U', 'rle' => '221121', 'bars' => '110010110'},
131
+ 'V' => {'position' => 31, 'display' => 'V', 'rle' => '222111', 'bars' => '110011010'},
132
+ 'W' => {'position' => 32, 'display' => 'W', 'rle' => '112122', 'bars' => '101101100'},
133
+ 'X' => {'position' => 33, 'display' => 'X', 'rle' => '112221', 'bars' => '101100110'},
134
+ 'Y' => {'position' => 34, 'display' => 'Y', 'rle' => '122121', 'bars' => '100110110'},
135
+ 'Z' => {'position' => 35, 'display' => 'Z', 'rle' => '123111', 'bars' => '100111010'},
136
+ '-' => {'position' => 36, 'display' => '-', 'rle' => '121131', 'bars' => '100101110'},
137
+ '.' => {'position' => 37, 'display' => '.', 'rle' => '311112', 'bars' => '111010100'},
138
+ ' ' => {'position' => 38, 'display' => ' ', 'rle' => '311211', 'bars' => '111010010'},
139
+ '$' => {'position' => 39, 'display' => '$', 'rle' => '321111', 'bars' => '111001010'},
140
+ '/' => {'position' => 40, 'display' => '/', 'rle' => '112131', 'bars' => '101101110'},
141
+ '+' => {'position' => 41, 'display' => '+', 'rle' => '113121', 'bars' => '101110110'},
142
+ '%' => {'position' => 42, 'display' => '%', 'rle' => '211131', 'bars' => '110101110'},
143
+ "\x80" => {'position' => 43, 'display' => '($)', 'rle' => '121221', 'bars' => '100100110'},
144
+ "\x81" => {'position' => 44, 'display' => '(%)', 'rle' => '312111', 'bars' => '111011010'},
145
+ "\x82" => {'position' => 45, 'display' => '(/)', 'rle' => '311121', 'bars' => '111010110'},
146
+ "\x83" => {'position' => 46, 'display' => '(+)', 'rle' => '122211', 'bars' => '100110010'},
147
+ }
148
+
149
+ # Note that the right side has another thin line
150
+ LEFT_GUARD_PATTERN = '101011110'
151
+ LEFT_GUARD_PATTERN_RLE = '111141'
152
+ RIGHT_GUARD_PATTERN = LEFT_GUARD_PATTERN + '1'
153
+ RIGHT_GUARD_PATTERN_RLE = LEFT_GUARD_PATTERN_RLE + '1'
154
+
155
+ FULL_ASCII_LOOKUP = [
156
+ "\x81U", "\x80A", "\x80B", "\x80C", "\x80D", "\x80E", "\x80F", "\x80G", "\x80H", "\x80I",
157
+ "\x80J", "\x80K", "\x80L", "\x80M", "\x80N", "\x80O", "\x80P", "\x80Q", "\x80R", "\x80S",
158
+ "\x80T", "\x80U", "\x80V", "\x80W", "\x80X", "\x80Y", "\x80Z", "\x81A", "\x81B", "\x81C",
159
+ "\x81D", "\x81E", " ", "\x82A", "\x82B", "\x82C", "\x82D", "\x82E", "\x82F", "\x82G",
160
+ "\x82H", "\x82I", "\x82J", "\x82K", "\x82L", "-", ".", "\x82O", "0", "1", "2",
161
+ "3", "4", "5", "6", "7", "8", "9", "\x82Z", "\x81F", "\x81G", "\x81H",
162
+ "\x81I", "\x81J", "\x81V", "A", "B", "C", "D", "E", "F", "G", "H",
163
+ "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
164
+ "U", "V", "W", "X", "Y", "Z", "\x81K", "\x81L", "\x81M", "\x81N", "\x81O",
165
+ "\x81W", "\x83A", "\x83B", "\x83C", "\x83D", "\x83E", "\x83F", "\x83G", "\x83H", "\x83I",
166
+ "\x83J", "\x83K", "\x83L", "\x83M", "\x83N", "\x83O", "\x83P", "\x83Q", "\x83R", "\x83S",
167
+ "\x83T", "\x83U", "\x83V", "\x83W", "\x83X", "\x83Y", "\x83Z", "\x81P", "\x81Q", "\x81R",
168
+ "\x81S", "\x81T"
169
+ ]
170
+
171
+ FULL_ASCII_REVERSE_LOOKUP = {
172
+ "\x81U" => { 'position' => 0, 'name' => '<NUL>' },
173
+ "\x80A" => { 'position' => 1, 'name' => '<SOH>' },
174
+ "\x80B" => { 'position' => 2, 'name' => '<STX>' },
175
+ "\x80C" => { 'position' => 3, 'name' => '<ETX>' },
176
+ "\x80D" => { 'position' => 4, 'name' => '<EOT>' },
177
+ "\x80E" => { 'position' => 5, 'name' => '<ENQ>' },
178
+ "\x80F" => { 'position' => 6, 'name' => '<ACK>' },
179
+ "\x80G" => { 'position' => 7, 'name' => '<BEL>' },
180
+ "\x80H" => { 'position' => 8, 'name' => '<BS>' },
181
+ "\x80I" => { 'position' => 9, 'name' => '<HT>' },
182
+ "\x80J" => { 'position' => 10, 'name' => '<LF>' },
183
+ "\x80K" => { 'position' => 11, 'name' => '<VT>' },
184
+ "\x80L" => { 'position' => 12, 'name' => '<FF>' },
185
+ "\x80M" => { 'position' => 13, 'name' => '<CR>' },
186
+ "\x80N" => { 'position' => 14, 'name' => '<SO>' },
187
+ "\x80O" => { 'position' => 15, 'name' => '<SI>' },
188
+ "\x80P" => { 'position' => 16, 'name' => '<DLE>' },
189
+ "\x80Q" => { 'position' => 17, 'name' => '<DC1>' },
190
+ "\x80R" => { 'position' => 18, 'name' => '<DC2>' },
191
+ "\x80S" => { 'position' => 19, 'name' => '<DC3>' },
192
+ "\x80T" => { 'position' => 20, 'name' => '<DC4>' },
193
+ "\x80U" => { 'position' => 21, 'name' => '<NAK>' },
194
+ "\x80V" => { 'position' => 22, 'name' => '<SYN>' },
195
+ "\x80W" => { 'position' => 23, 'name' => '<ETB>' },
196
+ "\x80X" => { 'position' => 24, 'name' => '<CAN>' },
197
+ "\x80Y" => { 'position' => 25, 'name' => '<EM>' },
198
+ "\x80Z" => { 'position' => 26, 'name' => '<SUB>' },
199
+ "\x81A" => { 'position' => 27, 'name' => '<ESC>' },
200
+ "\x81B" => { 'position' => 28, 'name' => '<FS>' },
201
+ "\x81C" => { 'position' => 29, 'name' => '<GS>' },
202
+ "\x81D" => { 'position' => 30, 'name' => '<RS>' },
203
+ "\x81E" => { 'position' => 31, 'name' => '<US>' },
204
+ " " => { 'position' => 32, 'name' => ' ' },
205
+ "\x82A" => { 'position' => 33, 'name' => '!' },
206
+ "\x82B" => { 'position' => 34, 'name' => '"' },
207
+ "\x82C" => { 'position' => 35, 'name' => '#' },
208
+ "\x82D" => { 'position' => 36, 'name' => '$' },
209
+ "\x82E" => { 'position' => 37, 'name' => '%' },
210
+ "\x82F" => { 'position' => 38, 'name' => '&' },
211
+ "\x82G" => { 'position' => 39, 'name' => "'" },
212
+ "\x82H" => { 'position' => 40, 'name' => '(' },
213
+ "\x82I" => { 'position' => 41, 'name' => ')' },
214
+ "\x82J" => { 'position' => 42, 'name' => '*' },
215
+ "\x82K" => { 'position' => 43, 'name' => '+' },
216
+ "\x82L" => { 'position' => 44, 'name' => ',' },
217
+ "-" => { 'position' => 45, 'name' => '-' },
218
+ "." => { 'position' => 46, 'name' => '.' },
219
+ "\x82O" => { 'position' => 47, 'name' => '/' },
220
+ "0" => { 'position' => 48, 'name' => '0' },
221
+ "1" => { 'position' => 49, 'name' => '1' },
222
+ "2" => { 'position' => 50, 'name' => '2' },
223
+ "3" => { 'position' => 51, 'name' => '3' },
224
+ "4" => { 'position' => 52, 'name' => '4' },
225
+ "5" => { 'position' => 53, 'name' => '5' },
226
+ "6" => { 'position' => 54, 'name' => '6' },
227
+ "7" => { 'position' => 55, 'name' => '7' },
228
+ "8" => { 'position' => 56, 'name' => '8' },
229
+ "9" => { 'position' => 57, 'name' => '9' },
230
+ "\x82Z" => { 'position' => 58, 'name' => ':' },
231
+ "\x81F" => { 'position' => 59, 'name' => ';' },
232
+ "\x81G" => { 'position' => 60, 'name' => '<' },
233
+ "\x81H" => { 'position' => 61, 'name' => '=' },
234
+ "\x81I" => { 'position' => 62, 'name' => '>' },
235
+ "\x81J" => { 'position' => 63, 'name' => '?' },
236
+ "\x81V" => { 'position' => 64, 'name' => '@' },
237
+ "A" => { 'position' => 65, 'name' => 'A' },
238
+ "B" => { 'position' => 66, 'name' => 'B' },
239
+ "C" => { 'position' => 67, 'name' => 'C' },
240
+ "D" => { 'position' => 68, 'name' => 'D' },
241
+ "E" => { 'position' => 69, 'name' => 'E' },
242
+ "F" => { 'position' => 70, 'name' => 'F' },
243
+ "G" => { 'position' => 71, 'name' => 'G' },
244
+ "H" => { 'position' => 72, 'name' => 'H' },
245
+ "I" => { 'position' => 73, 'name' => 'I' },
246
+ "J" => { 'position' => 74, 'name' => 'J' },
247
+ "K" => { 'position' => 75, 'name' => 'K' },
248
+ "L" => { 'position' => 76, 'name' => 'L' },
249
+ "M" => { 'position' => 77, 'name' => 'M' },
250
+ "N" => { 'position' => 78, 'name' => 'N' },
251
+ "O" => { 'position' => 79, 'name' => 'O' },
252
+ "P" => { 'position' => 80, 'name' => 'P' },
253
+ "Q" => { 'position' => 81, 'name' => 'Q' },
254
+ "R" => { 'position' => 82, 'name' => 'R' },
255
+ "S" => { 'position' => 83, 'name' => 'S' },
256
+ "T" => { 'position' => 84, 'name' => 'T' },
257
+ "U" => { 'position' => 85, 'name' => 'U' },
258
+ "V" => { 'position' => 86, 'name' => 'V' },
259
+ "W" => { 'position' => 87, 'name' => 'W' },
260
+ "X" => { 'position' => 88, 'name' => 'X' },
261
+ "Y" => { 'position' => 89, 'name' => 'Y' },
262
+ "Z" => { 'position' => 90, 'name' => 'Z' },
263
+ "\x81K" => { 'position' => 91, 'name' => '[' },
264
+ "\x81L" => { 'position' => 92, 'name' => '\\' },
265
+ "\x81M" => { 'position' => 93, 'name' => ']' },
266
+ "\x81N" => { 'position' => 94, 'name' => '^' },
267
+ "\x81O" => { 'position' => 95, 'name' => '_' },
268
+ "\x81W" => { 'position' => 96, 'name' => '`' },
269
+ "\x83A" => { 'position' => 97, 'name' => 'a' },
270
+ "\x83B" => { 'position' => 98, 'name' => 'b' },
271
+ "\x83C" => { 'position' => 99, 'name' => 'c' },
272
+ "\x83D" => { 'position' => 100, 'name' => 'd' },
273
+ "\x83E" => { 'position' => 101, 'name' => 'e' },
274
+ "\x83F" => { 'position' => 102, 'name' => 'f' },
275
+ "\x83G" => { 'position' => 103, 'name' => 'g' },
276
+ "\x83H" => { 'position' => 104, 'name' => 'h' },
277
+ "\x83I" => { 'position' => 105, 'name' => 'i' },
278
+ "\x83J" => { 'position' => 106, 'name' => 'j' },
279
+ "\x83K" => { 'position' => 107, 'name' => 'k' },
280
+ "\x83L" => { 'position' => 108, 'name' => 'l' },
281
+ "\x83M" => { 'position' => 109, 'name' => 'm' },
282
+ "\x83N" => { 'position' => 110, 'name' => 'n' },
283
+ "\x83O" => { 'position' => 111, 'name' => 'o' },
284
+ "\x83P" => { 'position' => 112, 'name' => 'p' },
285
+ "\x83Q" => { 'position' => 113, 'name' => 'q' },
286
+ "\x83R" => { 'position' => 114, 'name' => 'r' },
287
+ "\x83S" => { 'position' => 115, 'name' => 's' },
288
+ "\x83T" => { 'position' => 116, 'name' => 't' },
289
+ "\x83U" => { 'position' => 117, 'name' => 'u' },
290
+ "\x83V" => { 'position' => 118, 'name' => 'v' },
291
+ "\x83W" => { 'position' => 119, 'name' => 'w' },
292
+ "\x83X" => { 'position' => 120, 'name' => 'x' },
293
+ "\x83Y" => { 'position' => 121, 'name' => 'y' },
294
+ "\x83Z" => { 'position' => 122, 'name' => 'z' },
295
+ "\x81P" => { 'position' => 123, 'name' => '{' },
296
+ "\x81Q" => { 'position' => 124, 'name' => '|' },
297
+ "\x81R" => { 'position' => 125, 'name' => '}' },
298
+ "\x81S" => { 'position' => 126, 'name' => '~' },
299
+ "\x81T" => { 'position' => 127, 'name' => '<DEL>' },
300
+ "\x81X" => { 'position' => 127, 'name' => '<DEL>' },
301
+ "\x81Y" => { 'position' => 127, 'name' => '<DEL>' },
302
+ "\x81Z" => { 'position' => 127, 'name' => '<DEL>' }
303
+ }
304
+
305
+ DEFAULT_OPTIONS = {
306
+ :line_character => '1',
307
+ :space_character => '0',
308
+ :force_full_ascii => false
309
+ }
310
+
311
+ attr_accessor :full_ascii
312
+ attr_accessor :full_ascii_value
313
+
314
+ class << self
315
+ # Code 93 can technically encode anything 0-127
316
+ def can_encode?(value)
317
+ value.to_s =~ /\A[\x00-\x7f]*\z/
318
+ end
319
+
320
+ def requires_full_ascii?(value)
321
+ value.to_s !~ /\A[0-9A-Z\-\. \$\/\+%]*\z/
322
+ end
323
+
324
+ # Generates check digit given a string to encode. It assumes there
325
+ # is no check digit on the "value". The check "digit" is
326
+ # actually two characters, and the "position" value in PATTERNS can
327
+ # be used to find the numeric value. Note that the string must
328
+ # already be promoted to full ascii before sending it here.
329
+ def generate_check_digit_for(value)
330
+ mult = 0
331
+ sum_c = value.to_s.reverse.split('').inject(0) { |a,c| mult = (mult == 20 ? 1 : mult + 1); a + mult * PATTERNS[c]['position'] }
332
+ check_c = CHAR_SEQUENCE[sum_c % 47,1]
333
+ mult = 0
334
+ sum_k = (value.to_s + check_c).reverse.split('').inject(0) { |a,c| mult = (mult == 15 ? 1 : mult + 1); a + mult * PATTERNS[c]['position'] }
335
+ check_k = CHAR_SEQUENCE[sum_k % 47,1]
336
+ "#{check_c}#{check_k}"
337
+ end
338
+
339
+ # validates the check digit given a string - assumes check digit
340
+ # is last digit of string.
341
+ def validate_check_digit_for(value)
342
+ md = value.to_s.match(/^(.*)(..)$/)
343
+ self.generate_check_digit_for(md[1]) == md[2]
344
+ end
345
+
346
+ # Decode a string in wn format. This will return a Code93
347
+ # object.
348
+ def decode(str, options = {})
349
+ if str =~ /[^1-4]/
350
+ raise UnencodableCharactersError, "Pattern must be rle"
351
+ end
352
+
353
+ if str.reverse =~ /^#{LEFT_GUARD_PATTERN_RLE}.*?#{RIGHT_GUARD_PATTERN_RLE}$/
354
+ str.reverse!
355
+ end
356
+
357
+ unless str =~ /^#{LEFT_GUARD_PATTERN_RLE}(.*?)#{RIGHT_GUARD_PATTERN_RLE}$/
358
+ raise UnencodableCharactersError, "Start/stop pattern is not detected."
359
+ end
360
+
361
+ rle_pattern = $1
362
+
363
+ unless rle_pattern.size % 6 == 0
364
+ raise UnencodableCharactersError, "Wrong number of bars."
365
+ end
366
+
367
+ decoded_string = ''
368
+
369
+ rle_pattern.scan(/.{6}/).each do |chunk|
370
+
371
+ found = false
372
+
373
+ PATTERNS.each do |char,hsh|
374
+ if chunk == hsh['rle']
375
+ decoded_string += char
376
+ found = true
377
+ break;
378
+ end
379
+ end
380
+
381
+ raise UndecodableCharactersError, "Invalid sequence: #{chunk}" unless found
382
+
383
+ end
384
+
385
+ # assume the last two characters are a checksum
386
+ raise ChecksumError unless self.validate_check_digit_for(decoded_string)
387
+
388
+ md = decoded_string.match(/\A(.*?)(..)\z/)
389
+ payload, checksum = md[1], md[2]
390
+
391
+ decoded_string = decode_full_ascii(payload)
392
+
393
+ Code93.new(decoded_string, options.merge(:checksum_included => false))
394
+ end
395
+
396
+ # Provide encoding into the "full ascii" format. This
397
+ # allows us to encode any ascii character (0-127) in a
398
+ # Code 93.
399
+ def encode_full_ascii(str)
400
+ str.bytes.collect { |c| FULL_ASCII_LOOKUP[c] }.join
401
+ end
402
+
403
+ # Decodes a "full ascii" string from Code 3 of 9 into standard
404
+ # ascii. Note that this will silently fail if a string is
405
+ # malformed.
406
+ def decode_full_ascii(str)
407
+ if str =~ /[\x80-\x83]/
408
+ str.scan(/[\x80-\x83]?[A-Z0-9 \.\-]/).collect { |c| FULL_ASCII_REVERSE_LOOKUP[c]['position'] }.pack('C*')
409
+ else
410
+ str
411
+ end
412
+ end
413
+ end
414
+
415
+ # Options are :line_character, :space_character, :force_full_ascii,
416
+ # and :checksum_included.
417
+ def initialize(value, options = {})
418
+
419
+ @options = DEFAULT_OPTIONS.merge(options)
420
+
421
+ # Can we encode this value?
422
+ raise UnencodableCharactersError unless self.class.can_encode?(value)
423
+
424
+ value = value.to_s
425
+
426
+ if @options[:checksum_included]
427
+ raise ChecksumError unless self.class.validate_check_digit_for(value)
428
+ @encoded_string = value
429
+ md = value.match(/\A(.*?)(..)\z/)
430
+ @value, @check_digit = md[1], md[2]
431
+ else
432
+ @value = value
433
+ if options[:force_full_ascii] || self.class.requires_full_ascii?(value)
434
+ @full_ascii_value = self.class.encode_full_ascii(value)
435
+ @full_ascii = true
436
+ @check_digit = self.class.generate_check_digit_for(@full_ascii_value)
437
+ @encoded_string = "#{@full_ascii_value}#{@check_digit}"
438
+ else
439
+ @full_ascii = false
440
+ @full_ascii_value = @value
441
+ @check_digit = self.class.generate_check_digit_for(@value)
442
+ @encoded_string = "#{@value}#{@check_digit}"
443
+ end
444
+ end
445
+ end
446
+
447
+ # Returns a string of "w" or "n" ("wide" and "narrow")
448
+ def wn
449
+ raise NotImplementedError
450
+ end
451
+
452
+ # returns a run-length-encoded string representation
453
+ def rle
454
+ @rle ||= gen_rle(@encoded_string)
455
+ end
456
+
457
+ # returns 1s and 0s (for "black" and "white")
458
+ def bars
459
+ @bars ||= self.class.rle_to_bars(self.rle, @options)
460
+ end
461
+
462
+ # returns the total unit width of the bar code
463
+ def width
464
+ @width ||= rle.split('').inject(0) { |a,c| a + c.to_i }
465
+ end
466
+
467
+ private
468
+
469
+ # Creates the actual w/n pattern. Note that there is a narrow space
470
+ # between each character.
471
+ def gen_rle(str)
472
+ @rle_str ||=
473
+ ([LEFT_GUARD_PATTERN_RLE] +
474
+ str.split('').collect { |c| PATTERNS[c]['rle'] } +
475
+ [RIGHT_GUARD_PATTERN_RLE]).join
476
+ end
477
+
478
+ end
479
+ end
@@ -139,5 +139,20 @@ module Barcode1DTools
139
139
  end
140
140
  end
141
141
 
142
+ # Returns a UPC_E object with the same value
143
+ def to_upc_e
144
+ UPC_E.new(UPC_E.upca_value_to_upce_value(@value), options.merge(:checksum_included => false))
145
+ end
146
+
147
+ # Returns true if the current value may be encoded as UPC-E
148
+ def upc_e_encodable?
149
+ begin
150
+ UPC_E.new(UPC_E.upca_value_to_upce_value(@value), options.merge(:checksum_included => false))
151
+ return true
152
+ rescue UnencodableCharactersError
153
+ return false
154
+ end
155
+ end
156
+
142
157
  end
143
158
  end
@@ -264,6 +264,11 @@ module Barcode1DTools
264
264
  @width ||= rle.split('').inject(0) { |a,c| a + c.to_i }
265
265
  end
266
266
 
267
+ # Returns a UPC_A object with the same value
268
+ def to_upc_a
269
+ UPC_A.new(self.class.upce_value_to_upca_value(@value), options.merge(:checksum_included => false))
270
+ end
271
+
267
272
  private
268
273
 
269
274
  def gen_rle(payload, parity_digit)
@@ -21,6 +21,28 @@ class Barcode1DToolsCode3of9Test < Test::Unit::TestCase
21
21
  (0..x-1).inject('') { |a,c| a + Barcode1DTools::Code3of9::CHAR_SEQUENCE[rand(num_chars),1] }
22
22
  end
23
23
 
24
+ def random_x_character_full_ascii_string(x)
25
+ (1..x).collect { rand(128) }.pack('C*')
26
+ end
27
+
28
+ def all_ascii_random_order
29
+ arr = (0..127).to_a
30
+ ret = []
31
+ while arr.size > 0
32
+ ret.push(arr.delete_at(rand(arr.size)))
33
+ end
34
+ ret.pack("C*")
35
+ end
36
+
37
+ def test_full_ascii
38
+ random_string = random_x_character_full_ascii_string(rand(20) + 10)
39
+ encoded1 = Barcode1DTools::Code3of9.encode_full_ascii(random_string)
40
+ assert_equal random_string, Barcode1DTools::Code3of9.decode_full_ascii(encoded1)
41
+ assert_equal "T+H+I+S +I+S +A +T+E+S+T/A", Barcode1DTools::Code3of9.encode_full_ascii("This is a test!")
42
+ big_random_string = all_ascii_random_order
43
+ assert_equal big_random_string, Barcode1DTools::Code3of9.decode_full_ascii(Barcode1DTools::Code3of9.encode_full_ascii(big_random_string))
44
+ end
45
+
24
46
  def test_checksum_generation
25
47
  assert_equal 'I', Barcode1DTools::Code3of9.generate_check_digit_for('THIS IS A TEST')
26
48
  end
@@ -0,0 +1,104 @@
1
+ #--
2
+ # Copyright 2012 Michael Chaney Consulting Corporation
3
+ #
4
+ # Released under the terms of the MIT License or the GNU
5
+ # General Public License, v. 2
6
+ #++
7
+
8
+ require 'test/unit'
9
+ require 'barcode1dtools'
10
+
11
+ class Barcode1DToolsCode93Test < Test::Unit::TestCase
12
+ def setup
13
+ end
14
+
15
+ def teardown
16
+ end
17
+
18
+ # Creates a random number from 1 to 10 digits long
19
+ def random_x_character_string(x)
20
+ num_chars = Barcode1DTools::Code93::CHAR_SEQUENCE.size - 4
21
+ (0..x-1).inject('') { |a,c| a + Barcode1DTools::Code93::CHAR_SEQUENCE[rand(num_chars),1] }
22
+ end
23
+
24
+ def random_x_character_full_ascii_string(x)
25
+ (1..x).collect { rand(128) }.pack('C*')
26
+ end
27
+
28
+ def all_ascii_random_order
29
+ arr = (0..127).to_a
30
+ ret = []
31
+ while arr.size > 0
32
+ ret.push(arr.delete_at(rand(arr.size)))
33
+ end
34
+ ret.pack("C*")
35
+ end
36
+
37
+ def test_full_ascii
38
+ random_string = random_x_character_full_ascii_string(rand(20) + 10)
39
+ encoded1 = Barcode1DTools::Code93.encode_full_ascii(random_string)
40
+ assert_equal random_string, Barcode1DTools::Code93.decode_full_ascii(encoded1)
41
+ big_random_string = all_ascii_random_order
42
+ assert_equal big_random_string, Barcode1DTools::Code93.decode_full_ascii(Barcode1DTools::Code93.encode_full_ascii(big_random_string))
43
+ end
44
+
45
+ def test_checksum_generation
46
+ assert_equal '6$', Barcode1DTools::Code93.generate_check_digit_for('WIKIPEDIA')
47
+ end
48
+
49
+ def test_checksum_validation
50
+ assert Barcode1DTools::Code93.validate_check_digit_for('WIKIPEDIA6$')
51
+ end
52
+
53
+ def test_attr_readers
54
+ c3of9 = Barcode1DTools::Code93.new('WIKIPEDIA')
55
+ assert_equal '6$', c3of9.check_digit
56
+ assert_equal 'WIKIPEDIA', c3of9.value
57
+ assert_equal 'WIKIPEDIA6$', c3of9.encoded_string
58
+ end
59
+
60
+ def test_checksum_error
61
+ # proper checksum is 6$
62
+ assert_raise(Barcode1DTools::ChecksumError) { Barcode1DTools::Code93.new('WIKIPEDIA$$', :checksum_included => true) }
63
+ end
64
+
65
+ # Test promotion to full ascii
66
+ def test_promotion_to_full_ascii
67
+ assert Barcode1DTools::Code93.requires_full_ascii?('This is a test')
68
+ assert !Barcode1DTools::Code93.requires_full_ascii?('THIS IS A TEST')
69
+ assert Barcode1DTools::Code93.new('This is a test').full_ascii
70
+ assert !Barcode1DTools::Code93.new('THIS IS A TEST').full_ascii
71
+ end
72
+
73
+ # Test force promotion to full ascii
74
+ def test_force_promotion_to_full_ascii
75
+ bc = Barcode1DTools::Code93.new('THIS IS A TEST!', :force_full_ascii => true)
76
+ assert bc.full_ascii
77
+ assert_equal 'THIS IS A TEST' + Barcode1DTools::Code93::FULL_ASCII_LOOKUP['!'.bytes.first], bc.full_ascii_value
78
+ end
79
+
80
+ # Only need to test rle
81
+ def test_barcode_generation
82
+ c3of9 = Barcode1DTools::Code93.new('WIKIPEDIA')
83
+ assert_equal "1111411121221123111321111123111311212212112211121123112111131213113211111111411", c3of9.rle
84
+ end
85
+
86
+ def test_decode_error
87
+ assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::Code93.decode('x') }
88
+ assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::Code93.decode('x'*60) }
89
+ # proper start & stop, but crap in middle
90
+ assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::Code93.decode(Barcode1DTools::Code93::LEFT_GUARD_PATTERN_RLE + '11111' + Barcode1DTools::Code93::RIGHT_GUARD_PATTERN_RLE) }
91
+ # wrong start/stop
92
+ assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::Code93.decode('22222222222222222') }
93
+ end
94
+
95
+ def test_decoding
96
+ random_c3of9_str=random_x_character_string(rand(10)+5)
97
+ c3of9 = Barcode1DTools::Code93.new(random_c3of9_str)
98
+ c3of92 = Barcode1DTools::Code93.decode(c3of9.rle)
99
+ assert_equal c3of9.value, c3of92.value
100
+ # Should also work in reverse
101
+ c3of94 = Barcode1DTools::Code93.decode(c3of9.rle.reverse)
102
+ assert_equal c3of9.value, c3of94.value
103
+ end
104
+ end
@@ -99,4 +99,13 @@ class Barcode1DToolsUPC_ATest < Test::Unit::TestCase
99
99
  ean4 = Barcode1DTools::UPC_A.decode(ean.bars.reverse)
100
100
  assert_equal ean.value, ean4.value
101
101
  end
102
+
103
+ def test_upc_e_conversion
104
+ upc_e = Barcode1DTools::UPC_E.new('0384754')
105
+ upc_a = upc_e.to_upc_a
106
+ assert_equal upc_e.value, upc_a.to_upc_e.value
107
+ assert upc_a.upc_e_encodable?
108
+ upc_a_2 = Barcode1DTools::UPC_A.new('012676510226', :checksum_included => true)
109
+ assert !upc_a_2.upc_e_encodable?
110
+ end
102
111
  end
@@ -124,4 +124,10 @@ class Barcode1DToolsUPC_ETest < Test::Unit::TestCase
124
124
  upce4 = Barcode1DTools::UPC_E.decode(upce.bars.reverse)
125
125
  assert_equal upce.value, upce4.value
126
126
  end
127
+
128
+ def test_upc_a_conversion
129
+ upc_e = Barcode1DTools::UPC_E.new('0384754')
130
+ upc_a = upc_e.to_upc_a
131
+ assert_equal upc_e.value, upc_a.to_upc_e.value
132
+ end
127
133
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: barcode1dtools
3
3
  version: !ruby/object:Gem::Version
4
- hash: 11
4
+ hash: 21
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 9
9
- - 3
10
- - 0
11
- version: 0.9.3.0
9
+ - 4
10
+ - 1
11
+ version: 0.9.4.1
12
12
  platform: ruby
13
13
  authors:
14
14
  - Michael Chaney
@@ -20,7 +20,14 @@ date: 2012-08-05 00:00:00 -05:00
20
20
  default_executable:
21
21
  dependencies: []
22
22
 
23
- description: " Barcode1D is a small library for handling many kinds of\n 1-dimensional barcodes. Currently implemented are Code 3 of 9,\n Interleaved 2 of 5, EAN-13, EAN-8, UPC-A, UPC-E, UPC Supplemental 2,\n and UPC Supplemental 5. Patterns are created in either a simple\n format of bars and spaces or as a run-length encoded string. This\n only generates and decodes the patterns; actual display or reading\n from a device must be implemented by the programmer. More\n symbologies will be added as time permits.\n"
23
+ description: "\t Barcode1D is a small library for handling many kinds of\n\
24
+ \t 1-dimensional barcodes. Currently implemented are Code 3 of 9, Code\n\
25
+ \t 93, Interleaved 2 of 5, EAN-13, EAN-8, UPC-A, UPC-E, UPC\n\
26
+ \t Supplemental 2, and UPC Supplemental 5. Patterns are created in\n\
27
+ \t either a simple format of bars and spaces or as a run-length encoded\n\
28
+ \t string. This only generates and decodes the patterns; actual\n\
29
+ \t display or reading from a device must be implemented by the\n\
30
+ \t programmer. More symbologies will be added as time permits.\n"
24
31
  email: mdchaney@michaelchaney.com
25
32
  executables: []
26
33
 
@@ -30,6 +37,7 @@ extra_rdoc_files: []
30
37
 
31
38
  files:
32
39
  - lib/barcode1dtools/code3of9.rb
40
+ - lib/barcode1dtools/code93.rb
33
41
  - lib/barcode1dtools/ean13.rb
34
42
  - lib/barcode1dtools/ean8.rb
35
43
  - lib/barcode1dtools/interleaved2of5.rb
@@ -41,6 +49,7 @@ files:
41
49
  - MIT-LICENSE
42
50
  - test/test_barcode1d.rb
43
51
  - test/test_barcode1dcode3of9.rb
52
+ - test/test_barcode1dcode93.rb
44
53
  - test/test_barcode1dean13.rb
45
54
  - test/test_barcode1dean8.rb
46
55
  - test/test_barcode1di2of5.rb
@@ -88,6 +97,7 @@ summary: Pattern generators for 1D barcodes
88
97
  test_files:
89
98
  - test/test_barcode1d.rb
90
99
  - test/test_barcode1dcode3of9.rb
100
+ - test/test_barcode1dcode93.rb
91
101
  - test/test_barcode1dean13.rb
92
102
  - test/test_barcode1dean8.rb
93
103
  - test/test_barcode1di2of5.rb