barcode1dtools 1.0.1.0 → 1.0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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