Class: Barcode1DTools::EAN13
- Defined in:
- lib/barcode1dtools/ean13.rb
Overview
Barcode1DTools::EAN_13 - Create pattern for EAN-13 barcodes. The value encoded is an integer, and a checksum digit will be added. You can add the option :checksum_included => true when initializing to specify that you have already included a checksum.
Example
# Note that this number is a UPC-A, with the number system of 08,
# manufacturer's code of "28999", product code of "00682", and a
# checksum of "3" (not included)
num = '082899900682'
bc = Barcode1DTools::EAN13.new(num)
pattern = bc.
rle_pattern = bc.rle
width = bc.width
check_digit = Barcode1DTools::EAN13.generate_check_digit_for(num)
The object created is immutable.
Formats
There are two formats for the returned pattern (wn format is not available):
bars - 1s and 0s specifying black lines and white spaces. Actual characters can be changed from “1” and 0“ with options :line_character and :space_character.
rle - Run-length-encoded version of the pattern. The first number is always a black line, with subsequent digits alternating between spaces and lines. The digits specify the width of each line or space.
The “width” method will tell you the total end-to-end width, in units, of the entire barcode.
Unlike some of the other barcodes, e.g. Code 3 of 9, there is no “w/n” format for EAN & UPC style barcodes because the bars and spaces are variable width from 1 to 4 units.
Miscellaneous Information
An EAN-13 with an initial “number system” digit of “0” is a UPC-A. The BarcodeTools::UPC_A module actually just uses this EAN13 module.
An EAN-13 barcode has 4 elements:
-
A two-digit “number system” designation
-
A 5-digit manufacturer’s code
-
A 5-digit product code
-
A single digit checksum
There is some flexibility in EAN-13 on the digit layout. Sometimes, the first three digits indicate numbering system, i.e. some number systems are further split up. An example is “74”, which is used for Central America with “740” for Guatemala, “741” for El Salvador, etc.
Note that JAN codes (Japanese) are simply EAN-13’s, and they always start with “49”. The table below shows “49” to be “Japan”.
Also note that many books use a “bookland” code, perhaps along with a UPC Supplemental. The bookland code is really an EAN-13 with the initial 3 digits of “978”. The next 9 digits are the first 9 digits of the ISBN, and of course we still include the final check digit. An ISBN is 10 digits, however, the final digit is also a check digit, so it is not necessary.
Here is the complete table from www.barcodeisland.com:
00-13: USA & Canada 590: Poland 780: Chile
20-29: In-Store Functions 594: Romania 784: Paraguay
30-37: France 599: Hungary 785: Peru
40-44: Germany 600 & 601: South Africa 786: Ecuador
45: Japan (also 49) 609: Mauritius 789: Brazil
46: Russian Federation 611: Morocco 80 - 83: Italy
471: Taiwan 613: Algeria 84: Spain
474: Estonia 619: Tunisia 850: Cuba
475: Latvia 622: Egypt 858: Slovakia
477: Lithuania 625: Jordan 859: Czech Republic
479: Sri Lanka 626: Iran 860: Yugloslavia
480: Philippines 64: Finland 869: Turkey
482: Ukraine 690-692: China 87: Netherlands
484: Moldova 70: Norway 880: South Korea
485: Armenia 729: Israel 885: Thailand
486: Georgia 73: Sweden 888: Singapore
487: Kazakhstan 740: Guatemala 890: India
489: Hong Kong 741: El Salvador 893: Vietnam
49: Japan (JAN-13) 742: Honduras 899: Indonesia
50: United Kingdom 743: Nicaragua 90 & 91: Austria
520: Greece 744: Costa Rica 93: Australia
528: Lebanon 746: Dominican Republic 94: New Zealand
529: Cyprus 750: Mexico 955: Malaysia
531: Macedonia 759: Venezuela 977: ISSN
535: Malta 76: Switzerland 978: ISBN
539: Ireland 770: Colombia 979: ISMN
54: Belgium & Luxembourg 773: Uruguay 980: Refund receipts
560: Portugal 775: Peru 981 & 982: CCC
569: Iceland 777: Bolivia 99: Coupons
57: Denmark 779: Argentina
- ISSN
-
International Standard Serial Number for Periodicals
- ISBN
-
International Standard Book Numbering
- ISMN
-
International Standard Music Number
- CCC
-
Common Currency Coupons
Rendering
When rendered, the initial digit of the number system is shown to the left and above the rest of the digits. The other two sets of six digits each are shown at the bottom of the code, aligned with the bottom of the code, and with the middle guard pattern bars extending down between them. The lower digits may be aligned flush with the bottom of the barcode, or the center of the text may be aligned with the bottom of the barcode. Typically, the barcode is 1-1.5“ across and 60% or more of the width in height. There should be at least 10 units of quiet space on each side.
Direct Known Subclasses
Constant Summary collapse
- LEFT_PATTERNS =
Patterns for the left side, split between odd and even parity
{ '0' => { 'o' => '0001101', 'e' => '0100111'}, '1' => { 'o' => '0011001', 'e' => '0110011'}, '2' => { 'o' => '0010011', 'e' => '0011011'}, '3' => { 'o' => '0111101', 'e' => '0100001'}, '4' => { 'o' => '0100011', 'e' => '0011101'}, '5' => { 'o' => '0110001', 'e' => '0111001'}, '6' => { 'o' => '0101111', 'e' => '0000101'}, '7' => { 'o' => '0111011', 'e' => '0010001'}, '8' => { 'o' => '0110111', 'e' => '0001001'}, '9' => { 'o' => '0001011', 'e' => '0010111'}, }
- LEFT_PATTERNS_RLE =
Patterns for the left side, split between odd and even parity, in RLE format. Note that all left side patterns start with a space and end with a bar.
{ '0' => { 'o' => '3211', 'e' => '1123'}, '1' => { 'o' => '2221', 'e' => '1222'}, '2' => { 'o' => '2122', 'e' => '2212'}, '3' => { 'o' => '1411', 'e' => '1141'}, '4' => { 'o' => '1132', 'e' => '2311'}, '5' => { 'o' => '1231', 'e' => '1321'}, '6' => { 'o' => '1114', 'e' => '4111'}, '7' => { 'o' => '1312', 'e' => '2131'}, '8' => { 'o' => '1213', 'e' => '3121'}, '9' => { 'o' => '3112', 'e' => '2113'}, }
- LEFT_PARITY_PATTERNS =
Left parity patterns. An extra digit is encoded in the parity.
{ '0' => 'oooooo', '1' => 'ooeoee', '2' => 'ooeeoe', '3' => 'ooeeeo', '4' => 'oeooee', '5' => 'oeeooe', '6' => 'oeeeoo', '7' => 'oeoeoe', '8' => 'oeoeeo', '9' => 'oeeoeo', }
- RIGHT_PATTERNS =
Bar patterns for right side.
{ '0' => '1110010', '1' => '1100110', '2' => '1101100', '3' => '1000010', '4' => '1011100', '5' => '1001110', '6' => '1010000', '7' => '1000100', '8' => '1001000', '9' => '1110100', }
- RIGHT_PATTERNS_RLE =
Bar patterns for right side as RLE. Note that on the right side each pattern starts with a bar and ends with a space.
{ '0' => '3211', '1' => '2221', '2' => '2122', '3' => '1411', '4' => '1132', '5' => '1231', '6' => '1114', '7' => '1312', '8' => '1213', '9' => '3112', }
- SIDE_GUARD_PATTERN =
AAAAHHHHHHHHH side + middle + side is 666, the number of the beast
'101'
- MIDDLE_GUARD_PATTERN =
'01010'
- SIDE_GUARD_PATTERN_RLE =
Side guard pattern - Starts with bar
'111'
- MIDDLE_GUARD_PATTERN_RLE =
Middle guard pattern - Starts with space
'11111'
- DEFAULT_OPTIONS =
{ :line_character => '1', :space_character => '0' }
Instance Attribute Summary collapse
-
#manufacturers_code ⇒ Object
readonly
Specific for EAN - the manufacturer’s code part of the payload.
-
#number_system ⇒ Object
readonly
Specific for EAN - the number system part of the payload.
-
#product_code ⇒ Object
readonly
Specific for EAN - the product code part of the payload.
Attributes inherited from Barcode1D
#check_digit, #encoded_string, #options, #value
Class Method Summary collapse
-
.can_encode?(value, options = nil) ⇒ Boolean
Returns true if value can be encoded.
-
.decode(str) ⇒ Object
Decode a string representing an rle or bar pattern EAN-13.
-
.generate_check_digit_for(value) ⇒ Object
Generates check digit given a string to encode.
-
.validate_check_digit_for(value) ⇒ Object
Validates the check digit given a string - assumes check digit is last digit of string.
Instance Method Summary collapse
-
#bars ⇒ Object
Returns 1s and 0s (for “black” and “white”).
-
#initialize(value, options = {}) ⇒ EAN13
constructor
Create a new EAN-13 barcode object.
-
#rle ⇒ Object
Returns a run-length-encoded string representation.
-
#width ⇒ Object
Returns the total unit width of the bar code.
-
#wn ⇒ Object
Note that EANs cannot produce a w/n string, so this will raise an error.
Methods inherited from Barcode1D
bar_pair, bars_to_rle, rle_to_bars, rle_to_wn, wn_pair, wn_to_rle
Constructor Details
#initialize(value, options = {}) ⇒ EAN13
Create a new EAN-13 barcode object. Options are :line_character, :space_character, and :checksum_included.
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 |
# File 'lib/barcode1dtools/ean13.rb', line 341 def initialize(value, = {}) @options = DEFAULT_OPTIONS.merge() # Can we encode this value? raise UnencodableCharactersError unless self.class.can_encode?(value, @options) if @options[:checksum_included] @encoded_string = value.to_s raise ChecksumError unless self.class.validate_check_digit_for(@encoded_string) md = @encoded_string.match(/^(\d+?)(\d)$/) @value, @check_digit = md[1], md[2].to_i else # need to add a checksum @value = value.to_s @check_digit = self.class.generate_check_digit_for(@value) @encoded_string = "#{@value}#{@check_digit}" end md = @value.match(/^(\d{2})(\d{5})(\d{5})/) @number_system, @manufacturers_code, @product_code = md[1], md[2], md[3] end |
Instance Attribute Details
#manufacturers_code ⇒ Object (readonly)
Specific for EAN - the manufacturer’s code part of the payload
216 217 218 |
# File 'lib/barcode1dtools/ean13.rb', line 216 def manufacturers_code @manufacturers_code end |
#number_system ⇒ Object (readonly)
Specific for EAN - the number system part of the payload
214 215 216 |
# File 'lib/barcode1dtools/ean13.rb', line 214 def number_system @number_system end |
#product_code ⇒ Object (readonly)
Specific for EAN - the product code part of the payload
218 219 220 |
# File 'lib/barcode1dtools/ean13.rb', line 218 def product_code @product_code end |
Class Method Details
.can_encode?(value, options = nil) ⇒ Boolean
Returns true if value can be encoded. Must be 12 or 13 digits.
222 223 224 225 226 227 228 229 230 |
# File 'lib/barcode1dtools/ean13.rb', line 222 def can_encode?(value, = nil) if ! value.to_s =~ /^[0-9]{12,13}$/ elsif ([:checksum_included]) value.to_s =~ /^[0-9]{13}$/ else value.to_s =~ /^[0-9]{12}$/ end end |
.decode(str) ⇒ Object
Decode a string representing an rle or bar pattern EAN-13. Note that the string might be backward or forward. This will return an EAN13 object.
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
# File 'lib/barcode1dtools/ean13.rb', line 252 def decode(str) if str.length == 95 # bar pattern str = (str) elsif str.length == 59 # rle else raise UnencodableCharactersError, "Pattern must be 95 unit bar pattern or 59 character rle." end # Check the guard patterns unless str[0..2] == SIDE_GUARD_PATTERN_RLE && str[56..58] == SIDE_GUARD_PATTERN_RLE && str[27..31] == MIDDLE_GUARD_PATTERN_RLE raise UnencodableCharactersError, "Missing or incorrect guard patterns" end # Now I have an rle pattern, simply need to decode # according to the LEFT_PATTERNS_RLE, keeping track # of the parity for each position. # Set up the decoder left_parity_sequence = '' left_digits = '' right_parity_sequence = '' right_digits = '' left_initial_offset = SIDE_GUARD_PATTERN_RLE.length right_initial_offset = SIDE_GUARD_PATTERN_RLE.length + (4*6) + MIDDLE_GUARD_PATTERN_RLE.length # Decode the left side (0..5).each do |left_offset| found = false digit_rle = str[(left_initial_offset + left_offset*4),4] ['o','e'].each do |parity| ('0'..'9').each do |digit| if LEFT_PATTERNS_RLE[digit][parity] == digit_rle left_parity_sequence += parity left_digits += digit found = true break end end end raise UndecodableCharactersError, "Invalid sequence: #{digit_rle}" unless found end # Decode the right side (0..5).each do |right_offset| found = false digit_rle = str[(right_initial_offset + right_offset*4),4] ['o','e'].each do |parity| ('0'..'9').each do |digit| if LEFT_PATTERNS_RLE[digit][parity] == digit_rle right_parity_sequence += parity right_digits += digit found = true break end end end raise UndecodableCharactersError, "Invalid sequence: #{digit_rle}" unless found end # If left parity sequence is 'eeeeee', the string is reversed if left_parity_sequence == 'eeeeee' left_digits, right_digits, left_parity_sequence = right_digits.reverse, left_digits.reverse, right_parity_sequence.reverse.tr('eo','oe') end # Now, find the parity digit parity_digit = nil ('0'..'9').each do |x| if LEFT_PARITY_PATTERNS[x] == left_parity_sequence parity_digit = x break end end raise UndecodableCharactersError, "Weird parity: #{left_parity_sequence}" unless parity_digit # Debugging #puts "Left digits: #{left_digits} Left parity: #{left_parity_sequence}" #puts "Right digits: #{right_digits} Right parity: #{right_parity_sequence}" #puts "Parity: #{parity_digit}" EAN13.new(parity_digit + left_digits + right_digits, :checksum_included => true) end |
.generate_check_digit_for(value) ⇒ Object
Generates check digit given a string to encode. It assumes there is no check digit on the “value”.
234 235 236 237 238 239 |
# File 'lib/barcode1dtools/ean13.rb', line 234 def generate_check_digit_for(value) raise UnencodableCharactersError unless self.can_encode?(value, :checksum_included => false) mult = 3 value = value.split('').inject(0) { |a,c| mult = 4 - mult ; a + c.to_i * mult } (10 - (value % 10)) % 10 end |
.validate_check_digit_for(value) ⇒ Object
Validates the check digit given a string - assumes check digit is last digit of string.
243 244 245 246 247 |
# File 'lib/barcode1dtools/ean13.rb', line 243 def validate_check_digit_for(value) raise UnencodableCharactersError unless self.can_encode?(value, :checksum_included => true) md = value.match(/^(\d{12})(\d)$/) self.generate_check_digit_for(md[1]) == md[2].to_i end |
Instance Method Details
#bars ⇒ Object
Returns 1s and 0s (for “black” and “white”)
381 382 383 |
# File 'lib/barcode1dtools/ean13.rb', line 381 def @bars ||= self.class.(self.rle, @options) end |
#rle ⇒ Object
Returns a run-length-encoded string representation
371 372 373 374 375 376 377 378 |
# File 'lib/barcode1dtools/ean13.rb', line 371 def rle if @rle @rle else md = @encoded_string.match(/^(\d)(\d{6})(\d{6})/) @rle = gen_rle(md[1], md[2], md[3]) end end |
#width ⇒ Object
Returns the total unit width of the bar code
386 387 388 |
# File 'lib/barcode1dtools/ean13.rb', line 386 def width @width ||= rle.split('').inject(0) { |a,c| a + c.to_i } end |
#wn ⇒ Object
Note that EANs cannot produce a w/n string, so this will raise an error.
366 367 368 |
# File 'lib/barcode1dtools/ean13.rb', line 366 def wn raise NotImplementedError end |