barcode1dtools 1.0.1.0 → 1.0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,65 +1,170 @@
1
- #--
2
- # Copyright 2012 Michael Chaney Consulting Corporation
1
+ # Barcode1DTools is a library for generating and decoding
2
+ # 1-dimensional barcode patterns for various code types. The
3
+ # library currently includes EAN-13, EAN-8, UPC-A, UPC-E, UPC
4
+ # Supplemental 2, UPC Supplemental 5, Interleaved 2 of 5 (I 2/5),
5
+ # COOP 2 of 5, Matrix 2 of 5, Industrial 2 of 5, IATA 2 of 5,
6
+ # PostNet, Plessey, MSI (Modified Plessey), Code 3 of 9, Code 93,
7
+ # Code 11, Code 128, and Codabar.
3
8
  #
4
- # Released under the terms of the MIT License or the GNU
5
- # General Public License, v. 2
6
- #++
7
-
8
- # encoding: utf-8
9
-
10
- $:.unshift(File.dirname(__FILE__))
11
-
9
+ # Contact Michael Chaney Consulting Corporation for commercial
10
+ # support for this code: sales@michaelchaney.com
11
+ #
12
+ # Author:: Michael Chaney (mdchaney@michaelchaney.com)
13
+ # Copyright:: Copyright (c) 2012 Michael Chaney Consulting Corporation
14
+ # License:: Diestributed under the terms of the MIT License of the GNU General Public License v. 2
15
+ #
16
+ # == Example
17
+ # ean13 = Barcode1DTools::EAN13.new('0012676510226', :line_character => 'x', :space_character => ' ')
18
+ # => #<Barcode1DTools::EAN13:0x10030d670 @check_digit=10, @manufacturers_code="12676", @encoded_string="001267651022610", @number_system="00", @value="0012676510226", @product_code="51022", @options={:line_character=>"1", :space_character=>"0"}>
19
+ # ean13.bars
20
+ # "x x xx x xx x x xx x xxxx xxx xx x xxxx x x x xxx xx xx xxx x xx xx xx xx x x x x"
21
+ # ean13.rle
22
+ # "11132112221212211141312111411111123122213211212221221114111"
23
+ # another_ean = EAN.decode(ean13.rle)
24
+ #
25
+ # Note that the Barcode1D objects are immutable.
26
+ #
27
+ # == Barcode Symbology Overview
28
+ #
29
+ # There are two broad families of barcodes: 1-dimensional (also
30
+ # "1D" or "linear") and 2-dimensional ("2D"). Nowadays, 2D
31
+ # barcodes are desired for a variety of reasons:
32
+ #
33
+ # * They have the ability to store vastly more information
34
+ # in the same space as most 1D barcodes
35
+ # * They use error correction - typically Reed-Solomon
36
+ # interleaving - to allow even a damaged code to be read.
37
+ # * Modern technology (cheap CCD cameras particularly) has made
38
+ # it easy to read them.
39
+ #
40
+ # Despite the advantages of 2D symbologies, 1D barcodes are
41
+ # still in wide use and likely will never go out of use.
42
+ #
43
+ # * There is still a huge installed base of dedicated scanners
44
+ # and hardware for dealing with 1D barcodes.
45
+ # * They are easier to read at a really long distance.
46
+ # * There's also a huge installed base of software that can
47
+ # generate such codes.
48
+ # * They encode enough information to be very useful.
49
+ #
50
+ # Within the 1D symbologies, there are some different
51
+ # classifications:
52
+ #
53
+ # 1. Continuous and Discrete - Any modern symbology is
54
+ # "continuous", which simply means that every bar and space -
55
+ # including inter-character spaces - are used to encode
56
+ # information. Discrete symbologies typically have characters
57
+ # that begin and end with a bar and have a narrow space between
58
+ # the characters.
59
+ #
60
+ # 2. Wide/Narrow (or "Two-width") and Many-width - Most modern
61
+ # symbologies are "many-width", meaning that the width of
62
+ # the bars and spaces has more than two varieties. The best
63
+ # symbologies - EAN/UPC and Code 128, use 4 widths for the
64
+ # bars and spaces to encode information. Many older
65
+ # symbologies use simply 2 widths (the "2 of 5" family, for
66
+ # instance, has 2 wide elements and 5 narrow elements for
67
+ # each character).
68
+ #
69
+ # 3. Self-checking - Self-checking symbologies will cause a
70
+ # mis-read if any single bar is misinterpreted. In other
71
+ # words, a single bar that is "wrong" can not cause the
72
+ # character to be interpreted as another.
73
+ #
74
+ # 4. Interleaved - Interleaved 2 of 5 is probably the best
75
+ # example - two characters are interleaved together with
76
+ # one coded as bars and the other as spaces.
77
+ #
78
+ # 5. Check digit - Most symbologies include a check digit that
79
+ # is generated based on the payload, although some, such as
80
+ # Code 128, actually generate the check digit based on the
81
+ # encoded information. Additionally, some symbologies have
82
+ # two check digits and some have multiple algorithms for
83
+ # generating the digit or digits.
84
+ #
85
+ # Additionally, different symbologies encode a different
86
+ # subset of characters. Some encode only digits, others encode
87
+ # digits plus a few symbols, some uppercase letters as well as
88
+ # digits and a few symbols, and some the full range of
89
+ # characters. The symbology that you choose for a given
90
+ # application should take into account what information you
91
+ # need to store and how to best store it.
92
+ #
93
+ # There are some excellent 2D barcode gems for Ruby that cover
94
+ # some of the more popular symbologies (QR Code is currently
95
+ # the most popular). This gem covers almost all 1D symbologies
96
+ # ever developed, and definitely all the most popular.
97
+ #
98
+ # == Standard Options
99
+ #
100
+ # When creating a barcode, there are a number of options available:
101
+ #
102
+ # 1. checksum_included - The checksum is included in the value
103
+ # and does not need to be generated. This checksum will be
104
+ # validated and an error raised if it is not proper.
105
+ #
106
+ # 2. skip_checksum - Do not include a checksum if it is optional.
107
+ # This option is not applicable to most barcode types and
108
+ # will be ignored unless it is applicable.
109
+ #
110
+ # 3. line_character, space_character - when generating a bar
111
+ # pattern, determines the characters which will represent bars
112
+ # and spaces in the pattern. These default to "1" for lines and
113
+ # "0" for spaces.
114
+ #
115
+ # 4. w_character, n_character - When generating a w/n pattern,
116
+ # determines the characters to be used for wide and narrow
117
+ # bars and spaces. Defaults to "w" and "n". Not applicable to
118
+ # all barcode types.
119
+ #
120
+ # == Standard Object Accessors
121
+ #
122
+ # 1. Barcode1D#value - The actual value of the payload. If there
123
+ # is a checksum, it is not part of the value. This may be a
124
+ # string or an integer depending on the type of barcode.
125
+ #
126
+ # 2. Barcode1D#check_digit - The checksum digit (or digits).
127
+ # This is usually an integer.
128
+ #
129
+ # 3. Barcode1D#encoded_string - The entire literal value that is
130
+ # encoded, including check digit(s) and start/stop characters
131
+ # for some symbologies.
132
+ #
133
+ # 4. Barcode1D#options - The options passed to the initializer.
134
+ #
135
+ # == Standard Object Methods
136
+ #
137
+ # 1. Barcode1D#width - The unit width of the entire barcode.
138
+ # This is a summation of all of the digits in the rle string
139
+ # (see below) and is the basis for determining an absolute
140
+ # width for each particular element.
141
+ #
142
+ # 2. Barcode1D#rle - RLE (run-length encoded) is the base format
143
+ # for many barcode symbologies. This string is a series of
144
+ # digits from 1 through 4 (depending on the symbology) that
145
+ # encodes the relative width of each bar and space. The first
146
+ # and last digits are always bars and there must always be an
147
+ # odd number of digits.
148
+ #
149
+ # 3. Barcode1D#wn - A wide/narrow representation is the base
150
+ # format for most symbologies that don't have an rle string
151
+ # as their base format. This is also known as a "two-width"
152
+ # code. The "2 of 5" family of codes and Code 39 are
153
+ # examples of wide/narrow codes. In this code the bars and
154
+ # spaces are either "wide" or "narrow", with "wide"
155
+ # typically being 2 or 3 times the width of "narrow". In
156
+ # practice, then, this is similar to an rle string of 1s and
157
+ # 2s or 1s and 3s. These objects all have an option of
158
+ # "wn_ratio" that lets you set the ratio yourself, with a
159
+ # default of "2".
160
+ #
161
+ # 4. Barcode1D#bars - A simple string of 1s and 0s (or whatever
162
+ # characters were set by options) that represents the bars
163
+ # (1s) and spaces (0s) of the barcode. The length of this
164
+ # string represents the unit width of the code. Generally
165
+ # speaking this is good for debugging but more difficult to
166
+ # render than the rle representation.
12
167
  module Barcode1DTools
13
- #= barcode1dtools.rb
14
- #
15
- # Barcode1DTools is a library for generating and decoding
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
- # COOP 2 of 5, Matrix 2 of 5, Industrial 2 of 5, IATA 2 of 5,
20
- # PostNet, Plessey, MSI (Modified Plessey), Code 3 of 9, Code 93,
21
- # Code 11, Code 128, and Codabar.
22
- #
23
- # Contact Michael Chaney Consulting Corporation for commercial
24
- # support for this code: sales@michaelchaney.com
25
- #
26
- #== Example
27
- # ean13 = Barcode1DTools::EAN13.new('0012676510226', :line_character => 'x', :space_character => ' ')
28
- # => #<Barcode1DTools::EAN13:0x10030d670 @check_digit=10, @manufacturers_code="12676", @encoded_string="001267651022610", @number_system="00", @value="0012676510226", @product_code="51022", @options={:line_character=>"1", :space_character=>"0"}>
29
- # ean13.bars
30
- # "x x xx x xx x x xx x xxxx xxx xx x xxxx x x x xxx xx xx xxx x xx xx xx xx x x x x"
31
- # ean13.rle
32
- # "11132112221212211141312111411111123122213211212221221114111"
33
- # another_ean = EAN.decode(ean13.rle)
34
- #
35
- #== Standard Options
36
- # When creating a barcode, there are a number of options available:
37
- #
38
- # 1. checksum_included - The checksum is included in the value
39
- # and does not need to be generated. This checksum will be
40
- # validated and an error raised if it is not proper.
41
- # 2. skip_checksum - Do not include a checksum if it is optional.
42
- # This option is not applicable to most barcode types and
43
- # will be ignored unless it is applicable.
44
- # 3. line_character, space_character - when generating a bar
45
- # pattern, determines the characters which will represent bars
46
- # and spaces in the pattern. These default to "1" for lines and
47
- # "0" for spaces.
48
- # 4. w_character, n_character - When generating a w/n pattern,
49
- # determines the characters to be used for wide and narrow
50
- # bars and spaces. Defaults to "w" and "n". Not applicable to
51
- # all barcode types.
52
- #
53
- #== Standard Object Accessors
54
- # 1. Barcode1D#value - The actual value of the payload. If there
55
- # is a checksum, it is not part of the value. This may be a
56
- # string or an integer depending on the type of barcode.
57
- # 2. Barcode1D#check_digit - The checksum digit (or digits).
58
- # This is an integer.
59
- # 3. Barcode1D#encoded_string - The entire literal value that is
60
- # encoded, including check digit(s).
61
- # 4. Barcode1D#options - The options passed to the initializer.
62
-
63
168
 
64
169
  # Errors for barcodes
65
170
  class Barcode1DError < StandardError; end
@@ -71,11 +176,16 @@ module Barcode1DTools
71
176
  class NotImplementedError < Barcode1DError; end
72
177
  class UndecodableCharactersError < Barcode1DError; end
73
178
 
179
+ # Base class for all barcode classes.
74
180
  class Barcode1D
75
181
 
76
- attr_reader :check_digit
182
+ # The value that is encoded
77
183
  attr_reader :value
184
+ # The check digit(s), if any - may be nil
185
+ attr_reader :check_digit
186
+ # The actual string that is encoded, including check digits
78
187
  attr_reader :encoded_string
188
+ # Options, including defaults and those explicitly set
79
189
  attr_reader :options
80
190
 
81
191
  class << self
@@ -101,6 +211,8 @@ module Barcode1DTools
101
211
  rle_str.tr('123456789', 'nwwwwwwww').tr('wn', wn_pair(options))
102
212
  end
103
213
 
214
+ private
215
+
104
216
  # Get an "wn" pair from the options
105
217
  def wn_pair(options = {})
106
218
  (options[:w_character] || 'w') + (options[:n_character] || 'n')
@@ -114,6 +226,7 @@ module Barcode1DTools
114
226
  end
115
227
  end
116
228
 
229
+ $:.unshift(File.dirname(__FILE__))
117
230
  require 'barcode1dtools/interleaved2of5'
118
231
  require 'barcode1dtools/ean13'
119
232
  require 'barcode1dtools/ean8'
@@ -24,11 +24,12 @@ module Barcode1DTools
24
24
  # characters as part of the value. When decoding, the start/stop
25
25
  # characters will be presented as A, B, C, or D.
26
26
  #
27
- # val = "A29322930C"
28
- # bc = Barcode1DTools::Codabar.new(val)
29
- # pattern = bc.bars
30
- # rle_pattern = bc.rle
31
- # width = bc.width
27
+ # == Example
28
+ # val = "A29322930C"
29
+ # bc = Barcode1DTools::Codabar.new(val)
30
+ # pattern = bc.bars
31
+ # rle_pattern = bc.rle
32
+ # width = bc.width
32
33
  #
33
34
  # The object created is immutable.
34
35
  #
@@ -44,27 +45,28 @@ module Barcode1DTools
44
45
  # (dot, forward slash, colon, and plus sign) each have three wide
45
46
  # bars and all narrow spaces.
46
47
  #
48
+ # == Formats
47
49
  # There are three formats for the returned pattern:
48
50
  #
49
- # bars - 1s and 0s specifying black lines and white spaces. Actual
50
- # characters can be changed from "1" and 0" with options
51
- # :line_character and :space_character.
51
+ # *bars* - 1s and 0s specifying black lines and white spaces. Actual
52
+ # characters can be changed from "1" and 0" with options
53
+ # :line_character and :space_character.
52
54
  #
53
- # rle - Run-length-encoded version of the pattern. The first
54
- # number is always a black line, with subsequent digits
55
- # alternating between spaces and lines. The digits specify
56
- # the width of each line or space.
55
+ # *rle* - Run-length-encoded version of the pattern. The first
56
+ # number is always a black line, with subsequent digits
57
+ # alternating between spaces and lines. The digits specify
58
+ # the width of each line or space.
57
59
  #
58
- # wn - The native format for this barcode type. The string
59
- # consists of a series of "w" and "n" characters. The first
60
- # item is always a black line, with subsequent characters
61
- # alternating between spaces and lines. A "wide" item
62
- # is twice the width of a "narrow" item.
60
+ # *wn* - The native format for this barcode type. The string
61
+ # consists of a series of "w" and "n" characters. The first
62
+ # item is always a black line, with subsequent characters
63
+ # alternating between spaces and lines. A "wide" item
64
+ # is twice the width of a "narrow" item.
63
65
  #
64
66
  # The "width" method will tell you the total end-to-end width, in
65
67
  # units, of the entire barcode.
66
68
  #
67
- #== Rendering
69
+ # == Rendering
68
70
  #
69
71
  # The original Codabar specification actually included a varied
70
72
  # w/n ratio depending on whether there were two or three wide
@@ -122,21 +124,31 @@ module Barcode1DTools
122
124
  :varied_wn_ratio => false
123
125
  }
124
126
 
125
- attr_reader :start_character, :stop_character, :payload
127
+ # Holds the start character
128
+ attr_reader :start_character
129
+ # Holds the stop character
130
+ attr_reader :stop_character
131
+ # The actual payload (between start/stop characters)
132
+ attr_reader :payload
126
133
 
127
134
  class << self
128
- # Codabar can encode digits, dash, dollar, colon, forward
129
- # slash, dot, and plus. The string must start and stop with
130
- # start/stop characters.
135
+
136
+ # Returns true if the value presented can be encoded in a
137
+ # Codabar barcode. Codabar can encode digits, dash,
138
+ # dollar, colon, forward slash, dot, and plus. The string
139
+ # must start and stop with start/stop characters.
131
140
  def can_encode?(value)
132
141
  value.to_s =~ /\A[ABCD][0-9\$:\/\.\+\-]*[ABCD]\z/ || value.to_s =~ /\A[TN\*E][0-9\$:\/\.\+\-]*[TN\*E]\z/
133
142
  end
134
143
 
135
- # We don't generate a check digit
144
+ # Generate a check digit. For Codabar, this
145
+ # will raise a NotImplementedError.
136
146
  def generate_check_digit_for(value)
137
147
  raise NotImplementedError
138
148
  end
139
149
 
150
+ # Validate the check digit. For Codabar, this
151
+ # will raise a NotImplementedError.
140
152
  def validate_check_digit_for(value)
141
153
  raise NotImplementedError
142
154
  end
@@ -195,8 +207,8 @@ module Barcode1DTools
195
207
 
196
208
  end
197
209
 
198
- # Options are :line_character, :space_character, :w_character,
199
- # :n_character, and :varied_wn_ratio.
210
+ # Create a new Codabar object. Options are :line_character,
211
+ # :space_character, :w_character, :n_character, and :varied_wn_ratio.
200
212
  def initialize(value, options = {})
201
213
 
202
214
  @options = DEFAULT_OPTIONS.merge(options)
@@ -217,7 +229,7 @@ module Barcode1DTools
217
229
  @wn ||= wn_str.tr('wn', @options[:w_character].to_s + @options[:n_character].to_s)
218
230
  end
219
231
 
220
- # returns a run-length-encoded string representation
232
+ # Returns a run-length-encoded string representation
221
233
  def rle
222
234
  if @options[:varied_wn_ratio]
223
235
  @rle ||= @encoded_string.split('').collect { |c| PATTERNS[c]['wn'] }.collect { |p| p.tr('wn',(p=~/.*w.*w.*w/ ? '21' : '31')) }.join('1')
@@ -226,12 +238,12 @@ module Barcode1DTools
226
238
  end
227
239
  end
228
240
 
229
- # returns 1s and 0s (for "black" and "white")
241
+ # Returns the bar pattern
230
242
  def bars
231
243
  @bars ||= self.class.rle_to_bars(self.rle, @options)
232
244
  end
233
245
 
234
- # returns the total unit width of the bar code
246
+ # Returns the total unit width of the bar code
235
247
  def width
236
248
  @width ||= rle.split('').inject(0) { |a,c| a + c.to_i }
237
249
  end
@@ -19,11 +19,12 @@ module Barcode1DTools
19
19
  # Code 11 is used in the telecom industry for equipment
20
20
  # labeling. It should not be used in any new applications.
21
21
  #
22
- # val = "29382-38"
23
- # bc = Barcode1DTools::Code11.new(val)
24
- # pattern = bc.bars
25
- # rle_pattern = bc.rle
26
- # width = bc.width
22
+ # ==Example
23
+ # val = "29382-38"
24
+ # bc = Barcode1DTools::Code11.new(val)
25
+ # pattern = bc.bars
26
+ # rle_pattern = bc.rle
27
+ # width = bc.width
27
28
  #
28
29
  # The object created is immutable.
29
30
  #
@@ -35,27 +36,28 @@ module Barcode1DTools
35
36
  # space between them. Three of the characters- 0, 9, and "-" -
36
37
  # are 6 units wide. The rest are 7 units wide.
37
38
  #
39
+ # == Formats
38
40
  # There are three formats for the returned pattern:
39
41
  #
40
- # bars - 1s and 0s specifying black lines and white spaces. Actual
41
- # characters can be changed from "1" and 0" with options
42
- # :line_character and :space_character.
42
+ # *bars* - 1s and 0s specifying black lines and white spaces. Actual
43
+ # characters can be changed from "1" and 0" with options
44
+ # :line_character and :space_character.
43
45
  #
44
- # rle - Run-length-encoded version of the pattern. The first
45
- # number is always a black line, with subsequent digits
46
- # alternating between spaces and lines. The digits specify
47
- # the width of each line or space.
46
+ # *rle* - Run-length-encoded version of the pattern. The first
47
+ # number is always a black line, with subsequent digits
48
+ # alternating between spaces and lines. The digits specify
49
+ # the width of each line or space.
48
50
  #
49
- # wn - The native format for this barcode type. The string
50
- # consists of a series of "w" and "n" characters. The first
51
- # item is always a black line, with subsequent characters
52
- # alternating between spaces and lines. A "wide" item
53
- # is twice the width of a "narrow" item.
51
+ # *wn* - The native format for this barcode type. The string
52
+ # consists of a series of "w" and "n" characters. The first
53
+ # item is always a black line, with subsequent characters
54
+ # alternating between spaces and lines. A "wide" item
55
+ # is twice the width of a "narrow" item.
54
56
  #
55
57
  # The "width" method will tell you the total end-to-end width, in
56
58
  # units, of the entire barcode.
57
59
  #
58
- #== Rendering
60
+ # == Rendering
59
61
  #
60
62
  # The standard w/n ratio seems to be 2:1. There seem to be no real
61
63
  # standards for display.
@@ -81,6 +83,7 @@ module Barcode1DTools
81
83
  '-'=> {'val'=>10 ,'wn'=>'nnwnn'}
82
84
  }
83
85
 
86
+ # Guard pattern for Code 11
84
87
  GUARD_PATTERN_WN = 'nnwwn'
85
88
 
86
89
  DEFAULT_OPTIONS = {
@@ -91,14 +94,16 @@ module Barcode1DTools
91
94
  :wn_ratio => '2'
92
95
  }
93
96
 
94
- attr_reader :start_character, :stop_character, :payload
95
-
96
97
  class << self
98
+ # Returns true if the value presented can be encoded in Code 11.
97
99
  # Code11 can encode digits and dashes.
98
100
  def can_encode?(value)
99
101
  value.to_s =~ /\A[0-9\-]+\z/
100
102
  end
101
103
 
104
+ # Generates a check digit for the given value. Note that Code 11
105
+ # barcodes may have two check digits if the size of the value is
106
+ # 10 or more characters.
102
107
  def generate_check_digit_for(value)
103
108
  mult = 0
104
109
  sum_c = value.to_s.reverse.split('').inject(0) { |a,c| mult = (mult == 11 ? 1 : mult + 1); a + mult * PATTERNS[c]['val'] }
@@ -113,11 +118,16 @@ module Barcode1DTools
113
118
  "#{check_c}#{check_k}"
114
119
  end
115
120
 
121
+ # Returns true if the given check digit(s) is correct.
122
+ # The check digit is the last one or two characters of
123
+ # the value that is passed.
116
124
  def validate_check_digit_for(value)
117
125
  payload, check_digits = split_payload_and_check_digits(value)
118
126
  self.generate_check_digit_for(payload) == check_digits
119
127
  end
120
128
 
129
+ # Split the given value into a payload and check digit or
130
+ # digits.
121
131
  def split_payload_and_check_digits(value)
122
132
  if value.to_s.size > 11
123
133
  # two check digits
@@ -180,6 +190,7 @@ module Barcode1DTools
180
190
 
181
191
  end
182
192
 
193
+ # Create a new Code 11 object with a value.
183
194
  # Options are :line_character, :space_character, :w_character,
184
195
  # :n_character, :checksum_included, and :skip_checksum.
185
196
  def initialize(value, options = {})
@@ -211,17 +222,17 @@ module Barcode1DTools
211
222
  @wn ||= wn_str.tr('wn', @options[:w_character].to_s + @options[:n_character].to_s)
212
223
  end
213
224
 
214
- # returns a run-length-encoded string representation
225
+ # Returns a run-length-encoded string representation
215
226
  def rle
216
227
  @rle ||= self.class.wn_to_rle(self.wn, @options)
217
228
  end
218
229
 
219
- # returns 1s and 0s (for "black" and "white")
230
+ # Returns the bar/space pattern as 1s and 0s.
220
231
  def bars
221
232
  @bars ||= self.class.rle_to_bars(self.rle, @options)
222
233
  end
223
234
 
224
- # returns the total unit width of the bar code
235
+ # Returns the total unit width of the bar code
225
236
  def width
226
237
  @width ||= rle.split('').inject(0) { |a,c| a + c.to_i }
227
238
  end