arena_barby 0.3.2
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.
- data/README +29 -0
- data/bin/barby +41 -0
- data/lib/barby.rb +17 -0
- data/lib/barby/barcode.rb +116 -0
- data/lib/barby/barcode/bookland.rb +37 -0
- data/lib/barby/barcode/code_128.rb +410 -0
- data/lib/barby/barcode/code_25.rb +193 -0
- data/lib/barby/barcode/code_25_iata.rb +23 -0
- data/lib/barby/barcode/code_25_interleaved.rb +73 -0
- data/lib/barby/barcode/code_39.rb +233 -0
- data/lib/barby/barcode/code_93.rb +230 -0
- data/lib/barby/barcode/ean_13.rb +178 -0
- data/lib/barby/barcode/ean_8.rb +32 -0
- data/lib/barby/barcode/gs1_128.rb +42 -0
- data/lib/barby/barcode/pdf_417.rb +76 -0
- data/lib/barby/barcode/qr_code.rb +101 -0
- data/lib/barby/outputter.rb +127 -0
- data/lib/barby/outputter/ascii_outputter.rb +41 -0
- data/lib/barby/outputter/cairo_outputter.rb +185 -0
- data/lib/barby/outputter/pdfwriter_outputter.rb +83 -0
- data/lib/barby/outputter/png_outputter.rb +97 -0
- data/lib/barby/outputter/prawn_outputter.rb +99 -0
- data/lib/barby/outputter/rmagick_outputter.rb +126 -0
- data/lib/barby/outputter/svg_outputter.rb +225 -0
- data/lib/barby/vendor.rb +3 -0
- data/lib/barby/version.rb +9 -0
- data/vendor/Pdf417lib-java-0.91/lib/Pdf417lib.jar +0 -0
- data/vendor/Pdf417lib-java-0.91/lib/Pdf417lib.java +1471 -0
- data/vendor/rqrcode/CHANGELOG +29 -0
- data/vendor/rqrcode/COPYING +19 -0
- data/vendor/rqrcode/README +98 -0
- data/vendor/rqrcode/Rakefile +65 -0
- data/vendor/rqrcode/lib/rqrcode.rb +13 -0
- data/vendor/rqrcode/lib/rqrcode/core_ext.rb +5 -0
- data/vendor/rqrcode/lib/rqrcode/core_ext/array.rb +5 -0
- data/vendor/rqrcode/lib/rqrcode/core_ext/array/behavior.rb +9 -0
- data/vendor/rqrcode/lib/rqrcode/core_ext/integer.rb +5 -0
- data/vendor/rqrcode/lib/rqrcode/core_ext/integer/bitwise.rb +11 -0
- data/vendor/rqrcode/lib/rqrcode/qrcode.rb +4 -0
- data/vendor/rqrcode/lib/rqrcode/qrcode/qr_8bit_byte.rb +37 -0
- data/vendor/rqrcode/lib/rqrcode/qrcode/qr_bit_buffer.rb +56 -0
- data/vendor/rqrcode/lib/rqrcode/qrcode/qr_code.rb +421 -0
- data/vendor/rqrcode/lib/rqrcode/qrcode/qr_math.rb +63 -0
- data/vendor/rqrcode/lib/rqrcode/qrcode/qr_polynomial.rb +78 -0
- data/vendor/rqrcode/lib/rqrcode/qrcode/qr_rs_block.rb +313 -0
- data/vendor/rqrcode/lib/rqrcode/qrcode/qr_util.rb +254 -0
- data/vendor/rqrcode/test/runtest.rb +78 -0
- data/vendor/rqrcode/test/test_data.rb +21 -0
- metadata +114 -0
data/README
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
Barby is a Ruby barcode generator. It does not depend on other libraries
|
2
|
+
(for the core functionality) and is easily extentable.
|
3
|
+
|
4
|
+
The barcode objects are separated from the process of generating graphical
|
5
|
+
(or other) representations. A barcode's only responsibility is to provide
|
6
|
+
a string representation consisting of 1s and 0s representing bars and spaces.
|
7
|
+
This string can then be used to generate (for example) an image with the
|
8
|
+
RMagickOutputter, or an ASCII string such as the one below.
|
9
|
+
|
10
|
+
See Barby::Barcode and Barby::Outputter for more information.
|
11
|
+
|
12
|
+
require 'barby'
|
13
|
+
require 'barby/outputter/ascii_outputter'
|
14
|
+
|
15
|
+
barcode = Barby::Code128B.new('BARBY')
|
16
|
+
|
17
|
+
puts barcode.to_ascii
|
18
|
+
|
19
|
+
## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ##
|
20
|
+
## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ##
|
21
|
+
## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ##
|
22
|
+
## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ##
|
23
|
+
## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ##
|
24
|
+
## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ##
|
25
|
+
## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ##
|
26
|
+
## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ##
|
27
|
+
## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ##
|
28
|
+
## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ##
|
29
|
+
B A R B Y
|
data/bin/barby
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
#$: << File.join(File.dirname(__FILE__), '..', 'lib')
|
6
|
+
require 'barby'
|
7
|
+
|
8
|
+
options = {
|
9
|
+
:outputter => 'Png',
|
10
|
+
:outputter_method => 'to_png',
|
11
|
+
:barcode => 'Code128B'
|
12
|
+
}
|
13
|
+
|
14
|
+
ARGV.options do |o|
|
15
|
+
o.banner = " Usage: #{File.basename(__FILE__)} [OPTIONS] data"
|
16
|
+
o.define_head ' Generates barcodes and prints the generated output to STDOUT'
|
17
|
+
|
18
|
+
o.separator ''
|
19
|
+
o.separator ' EXPERIMENTAL'
|
20
|
+
o.separator ''
|
21
|
+
|
22
|
+
o.on('-b', '--barcode=ClassName', String, 'Barcode type (Code128B)'){|v| options[:barcode] = v }
|
23
|
+
o.on('-o', '--outputter=ClassName', String, 'Outputter (Png)'){|v| options[:outputter] = v }
|
24
|
+
o.on('-m', '--method=method_name', String, 'Outputter method (to_png)'){|v| options[:outputter_method] = v }
|
25
|
+
|
26
|
+
o.on_tail("-h", "--help", "Show this help message.") { puts o; exit }
|
27
|
+
|
28
|
+
o.parse!
|
29
|
+
end
|
30
|
+
|
31
|
+
#p STDIN.read
|
32
|
+
#exit
|
33
|
+
|
34
|
+
require "barby/outputter/#{options[:outputter].gsub(/[A-Z]/){|c| '_'+c.downcase }[1..-1]}_outputter"
|
35
|
+
|
36
|
+
barcode_class = Barby.const_get(options[:barcode])
|
37
|
+
barcode = barcode_class.new($*.empty? ? STDIN.read.chomp : $*)
|
38
|
+
outputter_class = Barby.const_get("#{options[:outputter]}Outputter")
|
39
|
+
outputter = outputter_class.new(barcode)
|
40
|
+
|
41
|
+
print eval("outputter.#{options[:outputter_method]}(#{ENV['OPTIONS']})")
|
data/lib/barby.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'barby/vendor'
|
2
|
+
require 'barby/version'
|
3
|
+
|
4
|
+
require 'barby/barcode'
|
5
|
+
require 'barby/barcode/code_128'
|
6
|
+
require 'barby/barcode/gs1_128'
|
7
|
+
require 'barby/barcode/code_39'
|
8
|
+
require 'barby/barcode/code_93'
|
9
|
+
require 'barby/barcode/ean_13'
|
10
|
+
require 'barby/barcode/ean_8'
|
11
|
+
require 'barby/barcode/bookland'
|
12
|
+
require 'barby/barcode/qr_code'
|
13
|
+
require 'barby/barcode/code_25'
|
14
|
+
require 'barby/barcode/code_25_interleaved'
|
15
|
+
require 'barby/barcode/code_25_iata'
|
16
|
+
|
17
|
+
require 'barby/outputter'
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module Barby
|
2
|
+
|
3
|
+
|
4
|
+
#The base class for all barcodes. It includes some method_missing magic
|
5
|
+
#that is used to find registered outputters.
|
6
|
+
#
|
7
|
+
#The only interface requirement of a barcode class is that is has an encoding
|
8
|
+
#method that returns a string consisting of 1s and 0s representing the barcode's
|
9
|
+
#"black" and "white" parts. One digit is the width of the "X dimension"; that is,
|
10
|
+
#"101100" represents a single-width bar followed by a single-width space, then
|
11
|
+
#a bar and a space twice that width.
|
12
|
+
#
|
13
|
+
#Example implementation:
|
14
|
+
#
|
15
|
+
# class StaticBarcode < Barby::Barcode1D
|
16
|
+
# def encoding
|
17
|
+
# '101100111000111100001'
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# require 'barby/outputter/ascii_outputter'
|
22
|
+
# puts StaticBarcode.new.to_ascii(:height => 3)
|
23
|
+
#
|
24
|
+
# # ## ### #### #
|
25
|
+
# # ## ### #### #
|
26
|
+
# # ## ### #### #
|
27
|
+
#
|
28
|
+
#2D implementation:
|
29
|
+
#
|
30
|
+
# class Static2DBarcode < Barby::Barcode2D
|
31
|
+
# def encoding
|
32
|
+
# ['1010101', '010101110', '0001010100']
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
class Barcode
|
36
|
+
|
37
|
+
|
38
|
+
#Every barcode must have an encoding method. This method returns
|
39
|
+
#a string containing a series of 1 and 0, representing bars and
|
40
|
+
#spaces. One digit is the width of one "module" or X dimension.
|
41
|
+
#
|
42
|
+
#If the barcode is 2D, it returns an array of strings representing
|
43
|
+
#each line in the barcode
|
44
|
+
def encoding
|
45
|
+
raise NotImplementedError, 'Every barcode should implement this method'
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
#Is this barcode valid?
|
50
|
+
def valid?
|
51
|
+
false
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def to_s
|
56
|
+
self.class.name.split('::').last
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
#Is this barcode 2D?
|
61
|
+
def two_dimensional?
|
62
|
+
is_a? Barcode2D
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def method_missing(name, *args, &b)#:nodoc:
|
67
|
+
#See if an outputter has registered this method
|
68
|
+
if self.class.outputters.include?(name)
|
69
|
+
klass, method_name = self.class.outputters[name]
|
70
|
+
klass.new(self).send(method_name, *args, &b)
|
71
|
+
else
|
72
|
+
super
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
#Returns an instantiated outputter for +name+ if any outputter
|
78
|
+
#has registered that name
|
79
|
+
def outputter_for(name, *a, &b)
|
80
|
+
outputter_class_for(name).new(self, *a, &b)
|
81
|
+
end
|
82
|
+
|
83
|
+
#Get the outputter class object for +name+
|
84
|
+
def outputter_class_for(name)
|
85
|
+
self.class.outputters[name].first
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
class << self
|
90
|
+
|
91
|
+
def outputters
|
92
|
+
@@outputters ||= {}
|
93
|
+
end
|
94
|
+
|
95
|
+
#Registers an outputter with +name+ so that a call to
|
96
|
+
#+name+ on a Barcode instance will be delegated to this outputter
|
97
|
+
def register_outputter(name, klass, method_name)
|
98
|
+
outputters[name] = [klass, method_name]
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
#Most barcodes are one-dimensional. They have bars.
|
107
|
+
class Barcode1D < Barcode
|
108
|
+
end
|
109
|
+
|
110
|
+
#2D barcodes are 1D barcodes stacked on top of each other.
|
111
|
+
#Their encoding method must return an array of strings
|
112
|
+
class Barcode2D < Barcode
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'barby/barcode/ean_13'
|
2
|
+
|
3
|
+
module Barby
|
4
|
+
|
5
|
+
#Bookland barcodes are EAN-13 barcodes with number system
|
6
|
+
#978 (hence "Bookland"). The data they encode is an ISBN
|
7
|
+
#with its check digit removed. This is a convenience class
|
8
|
+
#that takes an ISBN no instead of "pure" EAN-13 data.
|
9
|
+
class Bookland < EAN13
|
10
|
+
|
11
|
+
BOOKLAND_NUMBER_SYSTEM = '978'
|
12
|
+
|
13
|
+
attr_accessor :isbn
|
14
|
+
|
15
|
+
def initialize(isbn)
|
16
|
+
self.isbn = isbn
|
17
|
+
raise ArgumentError, 'data not valid' unless valid?
|
18
|
+
end
|
19
|
+
|
20
|
+
def data
|
21
|
+
BOOKLAND_NUMBER_SYSTEM+isbn_only
|
22
|
+
end
|
23
|
+
|
24
|
+
#Removes any non-digit characters, number system and check digit
|
25
|
+
#from ISBN, so "978-82-92526-14-9" would result in "829252614"
|
26
|
+
def isbn_only
|
27
|
+
s = isbn.gsub(/[^0-9]/, '')
|
28
|
+
if s.size > 10#Includes number system
|
29
|
+
s[3,9]
|
30
|
+
else#No number system, may include check digit
|
31
|
+
s[0,9]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,410 @@
|
|
1
|
+
require 'barby/barcode'
|
2
|
+
|
3
|
+
module Barby
|
4
|
+
|
5
|
+
|
6
|
+
#Code 128 barcodes
|
7
|
+
#
|
8
|
+
#Note that you must provide a type for each object, either by passing a string
|
9
|
+
#as a second parameter to Code128.new or by instantiating one of the child classes.
|
10
|
+
#
|
11
|
+
#You can switch type by using the CODEA, CODEB and CODEC characters:
|
12
|
+
#
|
13
|
+
# "\305" => A
|
14
|
+
# "\306" => B
|
15
|
+
# "\307" => C
|
16
|
+
#
|
17
|
+
#As an example, here's one that starts out as type A and then switches to B and then C:
|
18
|
+
#
|
19
|
+
# Code128A.new("ABC123\306def\3074567")
|
20
|
+
class Code128 < Barcode1D
|
21
|
+
|
22
|
+
ENCODINGS = {
|
23
|
+
0 => "11011001100", 1 => "11001101100", 2 => "11001100110",
|
24
|
+
3 => "10010011000", 4 => "10010001100", 5 => "10001001100",
|
25
|
+
6 => "10011001000", 7 => "10011000100", 8 => "10001100100",
|
26
|
+
9 => "11001001000", 10 => "11001000100", 11 => "11000100100",
|
27
|
+
12 => "10110011100", 13 => "10011011100", 14 => "10011001110",
|
28
|
+
15 => "10111001100", 16 => "10011101100", 17 => "10011100110",
|
29
|
+
18 => "11001110010", 19 => "11001011100", 20 => "11001001110",
|
30
|
+
21 => "11011100100", 22 => "11001110100", 23 => "11101101110",
|
31
|
+
24 => "11101001100", 25 => "11100101100", 26 => "11100100110",
|
32
|
+
27 => "11101100100", 28 => "11100110100", 29 => "11100110010",
|
33
|
+
30 => "11011011000", 31 => "11011000110", 32 => "11000110110",
|
34
|
+
33 => "10100011000", 34 => "10001011000", 35 => "10001000110",
|
35
|
+
36 => "10110001000", 37 => "10001101000", 38 => "10001100010",
|
36
|
+
39 => "11010001000", 40 => "11000101000", 41 => "11000100010",
|
37
|
+
42 => "10110111000", 43 => "10110001110", 44 => "10001101110",
|
38
|
+
45 => "10111011000", 46 => "10111000110", 47 => "10001110110",
|
39
|
+
48 => "11101110110", 49 => "11010001110", 50 => "11000101110",
|
40
|
+
51 => "11011101000", 52 => "11011100010", 53 => "11011101110",
|
41
|
+
54 => "11101011000", 55 => "11101000110", 56 => "11100010110",
|
42
|
+
57 => "11101101000", 58 => "11101100010", 59 => "11100011010",
|
43
|
+
60 => "11101111010", 61 => "11001000010", 62 => "11110001010",
|
44
|
+
63 => "10100110000", 64 => "10100001100", 65 => "10010110000",
|
45
|
+
66 => "10010000110", 67 => "10000101100", 68 => "10000100110",
|
46
|
+
69 => "10110010000", 70 => "10110000100", 71 => "10011010000",
|
47
|
+
72 => "10011000010", 73 => "10000110100", 74 => "10000110010",
|
48
|
+
75 => "11000010010", 76 => "11001010000", 77 => "11110111010",
|
49
|
+
78 => "11000010100", 79 => "10001111010", 80 => "10100111100",
|
50
|
+
81 => "10010111100", 82 => "10010011110", 83 => "10111100100",
|
51
|
+
84 => "10011110100", 85 => "10011110010", 86 => "11110100100",
|
52
|
+
87 => "11110010100", 88 => "11110010010", 89 => "11011011110",
|
53
|
+
90 => "11011110110", 91 => "11110110110", 92 => "10101111000",
|
54
|
+
93 => "10100011110", 94 => "10001011110", 95 => "10111101000",
|
55
|
+
96 => "10111100010", 97 => "11110101000", 98 => "11110100010",
|
56
|
+
99 => "10111011110", 100 => "10111101110", 101 => "11101011110",
|
57
|
+
102 => "11110101110", 103 => "11010000100", 104 => "11010010000",
|
58
|
+
105 => "11010011100"
|
59
|
+
}
|
60
|
+
|
61
|
+
VALUES = {
|
62
|
+
'A' => {
|
63
|
+
0 => " ", 1 => "!", 2 => "\"",
|
64
|
+
3 => "#", 4 => "$", 5 => "%",
|
65
|
+
6 => "&", 7 => "'", 8 => "(",
|
66
|
+
9 => ")", 10 => "*", 11 => "+",
|
67
|
+
12 => ",", 13 => "-", 14 => ".",
|
68
|
+
15 => "/", 16 => "0", 17 => "1",
|
69
|
+
18 => "2", 19 => "3", 20 => "4",
|
70
|
+
21 => "5", 22 => "6", 23 => "7",
|
71
|
+
24 => "8", 25 => "9", 26 => ":",
|
72
|
+
27 => ";", 28 => "<", 29 => "=",
|
73
|
+
30 => ">", 31 => "?", 32 => "@",
|
74
|
+
33 => "A", 34 => "B", 35 => "C",
|
75
|
+
36 => "D", 37 => "E", 38 => "F",
|
76
|
+
39 => "G", 40 => "H", 41 => "I",
|
77
|
+
42 => "J", 43 => "K", 44 => "L",
|
78
|
+
45 => "M", 46 => "N", 47 => "O",
|
79
|
+
48 => "P", 49 => "Q", 50 => "R",
|
80
|
+
51 => "S", 52 => "T", 53 => "U",
|
81
|
+
54 => "V", 55 => "W", 56 => "X",
|
82
|
+
57 => "Y", 58 => "Z", 59 => "[",
|
83
|
+
60 => "\\", 61 => "]", 62 => "^",
|
84
|
+
63 => "_", 64 => "\000", 65 => "\001",
|
85
|
+
66 => "\002", 67 => "\003", 68 => "\004",
|
86
|
+
69 => "\005", 70 => "\006", 71 => "\a",
|
87
|
+
72 => "\b", 73 => "\t", 74 => "\n",
|
88
|
+
75 => "\v", 76 => "\f", 77 => "\r",
|
89
|
+
78 => "\016", 79 => "\017", 80 => "\020",
|
90
|
+
81 => "\021", 82 => "\022", 83 => "\023",
|
91
|
+
84 => "\024", 85 => "\025", 86 => "\026",
|
92
|
+
87 => "\027", 88 => "\030", 89 => "\031",
|
93
|
+
90 => "\032", 91 => "\e", 92 => "\034",
|
94
|
+
93 => "\035", 94 => "\036", 95 => "\037",
|
95
|
+
96 => "\303", 97 => "\302", 98 => "SHIFT",
|
96
|
+
99 => "\307", 100 => "\306", 101 => "\304",
|
97
|
+
102 => "\301", 103 => "STARTA", 104 => "STARTB",
|
98
|
+
105 => "STARTC"
|
99
|
+
}.invert,
|
100
|
+
|
101
|
+
'B' => {
|
102
|
+
0 => " ", 1 => "!", 2 => "\"", 3 => "#", 4 => "$", 5 => "%",
|
103
|
+
6 => "&", 7 => "'", 8 => "(", 9 => ")", 10 => "*", 11 => "+",
|
104
|
+
12 => ",", 13 => "-", 14 => ".", 15 => "/", 16 => "0", 17 => "1",
|
105
|
+
18 => "2", 19 => "3", 20 => "4", 21 => "5", 22 => "6", 23 => "7",
|
106
|
+
24 => "8", 25 => "9", 26 => ":", 27 => ";", 28 => "<", 29 => "=",
|
107
|
+
30 => ">", 31 => "?", 32 => "@", 33 => "A", 34 => "B", 35 => "C",
|
108
|
+
36 => "D", 37 => "E", 38 => "F", 39 => "G", 40 => "H", 41 => "I",
|
109
|
+
42 => "J", 43 => "K", 44 => "L", 45 => "M", 46 => "N", 47 => "O",
|
110
|
+
48 => "P", 49 => "Q", 50 => "R", 51 => "S", 52 => "T", 53 => "U",
|
111
|
+
54 => "V", 55 => "W", 56 => "X", 57 => "Y", 58 => "Z", 59 => "[",
|
112
|
+
60 => "\\", 61 => "]", 62 => "^", 63 => "_", 64 => "`", 65 => "a",
|
113
|
+
66 => "b", 67 => "c", 68 => "d", 69 => "e", 70 => "f", 71 => "g",
|
114
|
+
72 => "h", 73 => "i", 74 => "j", 75 => "k", 76 => "l", 77 => "m",
|
115
|
+
78 => "n", 79 => "o", 80 => "p", 81 => "q", 82 => "r", 83 => "s",
|
116
|
+
84 => "t", 85 => "u", 86 => "v", 87 => "w", 88 => "x", 89 => "y",
|
117
|
+
90 => "z", 91 => "{", 92 => "|", 93 => "}", 94 => "~", 95 => "\177",
|
118
|
+
96 => "\303", 97 => "\302", 98 => "SHIFT", 99 => "\307", 100 => "\304",
|
119
|
+
101 => "\305", 102 => "\301", 103 => "STARTA", 104 => "STARTB",
|
120
|
+
105 => "STARTC",
|
121
|
+
}.invert,
|
122
|
+
|
123
|
+
'C' => {
|
124
|
+
0 => "00", 1 => "01", 2 => "02", 3 => "03", 4 => "04", 5 => "05",
|
125
|
+
6 => "06", 7 => "07", 8 => "08", 9 => "09", 10 => "10", 11 => "11",
|
126
|
+
12 => "12", 13 => "13", 14 => "14", 15 => "15", 16 => "16", 17 => "17",
|
127
|
+
18 => "18", 19 => "19", 20 => "20", 21 => "21", 22 => "22", 23 => "23",
|
128
|
+
24 => "24", 25 => "25", 26 => "26", 27 => "27", 28 => "28", 29 => "29",
|
129
|
+
30 => "30", 31 => "31", 32 => "32", 33 => "33", 34 => "34", 35 => "35",
|
130
|
+
36 => "36", 37 => "37", 38 => "38", 39 => "39", 40 => "40", 41 => "41",
|
131
|
+
42 => "42", 43 => "43", 44 => "44", 45 => "45", 46 => "46", 47 => "47",
|
132
|
+
48 => "48", 49 => "49", 50 => "50", 51 => "51", 52 => "52", 53 => "53",
|
133
|
+
54 => "54", 55 => "55", 56 => "56", 57 => "57", 58 => "58", 59 => "59",
|
134
|
+
60 => "60", 61 => "61", 62 => "62", 63 => "63", 64 => "64", 65 => "65",
|
135
|
+
66 => "66", 67 => "67", 68 => "68", 69 => "69", 70 => "70", 71 => "71",
|
136
|
+
72 => "72", 73 => "73", 74 => "74", 75 => "75", 76 => "76", 77 => "77",
|
137
|
+
78 => "78", 79 => "79", 80 => "80", 81 => "81", 82 => "82", 83 => "83",
|
138
|
+
84 => "84", 85 => "85", 86 => "86", 87 => "87", 88 => "88", 89 => "89",
|
139
|
+
90 => "90", 91 => "91", 92 => "92", 93 => "93", 94 => "94", 95 => "95",
|
140
|
+
96 => "96", 97 => "97", 98 => "98", 99 => "99", 100 => "\306", 101 => "\305",
|
141
|
+
102 => "\301", 103 => "STARTA", 104 => "STARTB", 105 => "STARTC"
|
142
|
+
}.invert
|
143
|
+
}
|
144
|
+
|
145
|
+
FNC1 = "\xc1"
|
146
|
+
FNC2 = "\xc2"
|
147
|
+
FNC3 = "\xc3"
|
148
|
+
FNC4 = "\xc4"
|
149
|
+
CODEA = "\xc5"
|
150
|
+
CODEB = "\xc6"
|
151
|
+
CODEC = "\xc7"
|
152
|
+
|
153
|
+
STOP = '11000111010'
|
154
|
+
TERMINATE = '11'
|
155
|
+
|
156
|
+
attr_reader :type
|
157
|
+
|
158
|
+
|
159
|
+
def initialize(data, type)
|
160
|
+
self.type = type
|
161
|
+
self.data = "#{data}"
|
162
|
+
raise ArgumentError, 'Data not valid' unless valid?
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
def type=(type)
|
167
|
+
type.upcase!
|
168
|
+
raise ArgumentError, 'type must be A, B or C' unless type =~ /^[ABC]$/
|
169
|
+
@type = type
|
170
|
+
end
|
171
|
+
|
172
|
+
|
173
|
+
def to_s
|
174
|
+
full_data
|
175
|
+
end
|
176
|
+
|
177
|
+
|
178
|
+
def data
|
179
|
+
@data
|
180
|
+
end
|
181
|
+
|
182
|
+
#Returns the data for this barcode plus that for the entire extra chain,
|
183
|
+
#excluding all change codes
|
184
|
+
def full_data
|
185
|
+
data + full_extra_data
|
186
|
+
end
|
187
|
+
|
188
|
+
#Returns the data for this barcode plus that for the entire extra chain,
|
189
|
+
#including all change codes prefixing each extra
|
190
|
+
def full_data_with_change_codes
|
191
|
+
data + full_extra_data_with_change_code
|
192
|
+
end
|
193
|
+
|
194
|
+
#Returns the full_data for the extra or an empty string if there is no extra
|
195
|
+
def full_extra_data
|
196
|
+
return '' unless extra
|
197
|
+
extra.full_data
|
198
|
+
end
|
199
|
+
|
200
|
+
#Returns the full_data for the extra with the change code for the extra
|
201
|
+
#prepended. If there is no extra, an empty string is returned
|
202
|
+
def full_extra_data_with_change_code
|
203
|
+
return '' unless extra
|
204
|
+
change_code_for(extra) + extra.full_data_with_change_codes
|
205
|
+
end
|
206
|
+
|
207
|
+
#Set the data for this barcode. If the barcode changes
|
208
|
+
#character set, an extra will be created.
|
209
|
+
def data=(data)
|
210
|
+
data, *extra = data.split(/([#{CODEA+CODEB+CODEC}])/n)
|
211
|
+
@data = data || ''
|
212
|
+
self.extra = extra.join unless extra.empty?
|
213
|
+
end
|
214
|
+
|
215
|
+
#An "extra" is present if the barcode changes character set. If
|
216
|
+
#a 128A barcode changes to C, the extra will be an instance of
|
217
|
+
#Code128C. Extras can themselves have an extra if the barcode
|
218
|
+
#changes character set again. It's like a linked list, and when
|
219
|
+
#there are no more extras, the barcode ends with that object.
|
220
|
+
#Most barcodes probably don't change charsets and don't have extras.
|
221
|
+
def extra
|
222
|
+
@extra
|
223
|
+
end
|
224
|
+
|
225
|
+
#Set the extra for this barcode. The argument is a string starting with the
|
226
|
+
#"change character set" symbol. The string may contain several character
|
227
|
+
#sets, in which case the extra will itself have an extra.
|
228
|
+
def extra=(extra)
|
229
|
+
raise ArgumentError, "Extra must begin with \\305, \\306 or \\307" unless extra =~ /^[#{CODEA+CODEB+CODEC}]/n
|
230
|
+
type, data = extra[0,1], extra[1..-1]
|
231
|
+
@extra = class_for(type).new(data)
|
232
|
+
end
|
233
|
+
|
234
|
+
#Get an array of the individual characters for this barcode. Special
|
235
|
+
#characters like FNC1 will be present. Characters from extras are not
|
236
|
+
#present.
|
237
|
+
def characters
|
238
|
+
chars = data.split(//n)
|
239
|
+
|
240
|
+
if type == 'C'
|
241
|
+
result = []
|
242
|
+
count = 0
|
243
|
+
while count < chars.size
|
244
|
+
if chars[count] =~ /^\d$/
|
245
|
+
result << "#{chars[count]}#{chars[count+1]}"
|
246
|
+
count += 2
|
247
|
+
else
|
248
|
+
result << chars[count]
|
249
|
+
count += 1
|
250
|
+
end
|
251
|
+
end
|
252
|
+
result
|
253
|
+
else
|
254
|
+
chars
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
#Return the encoding of this barcode as a string of 1 and 0
|
259
|
+
def encoding
|
260
|
+
start_encoding+data_encoding+extra_encoding+checksum_encoding+stop_encoding
|
261
|
+
end
|
262
|
+
|
263
|
+
#Returns the encoding for the data part of this barcode, without any extras
|
264
|
+
def data_encoding
|
265
|
+
characters.map do |char|
|
266
|
+
encoding_for char
|
267
|
+
end.join
|
268
|
+
end
|
269
|
+
|
270
|
+
#Returns the data encoding of this barcode and extras.
|
271
|
+
def data_encoding_with_extra_encoding
|
272
|
+
data_encoding+extra_encoding
|
273
|
+
end
|
274
|
+
|
275
|
+
#Returns the data encoding of this barcode's extra and its
|
276
|
+
#extra until the barcode ends.
|
277
|
+
def extra_encoding
|
278
|
+
return '' unless extra
|
279
|
+
change_code_encoding_for(extra) + extra.data_encoding + extra.extra_encoding
|
280
|
+
end
|
281
|
+
|
282
|
+
|
283
|
+
#Calculate the checksum for the data in this barcode. The data includes
|
284
|
+
#data from extras.
|
285
|
+
def checksum
|
286
|
+
pos = 0
|
287
|
+
(numbers+extra_numbers).inject(start_num) do |sum,number|
|
288
|
+
pos += 1
|
289
|
+
sum + (number * pos)
|
290
|
+
end % 103
|
291
|
+
end
|
292
|
+
|
293
|
+
#Get the encoding for the checksum
|
294
|
+
def checksum_encoding
|
295
|
+
encodings[checksum]
|
296
|
+
end
|
297
|
+
|
298
|
+
|
299
|
+
#protected
|
300
|
+
|
301
|
+
#Returns the numeric values for the characters in the barcode in an array
|
302
|
+
def numbers
|
303
|
+
characters.map do |char|
|
304
|
+
values[char]
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
#Returns the numeric values for extras
|
309
|
+
def extra_numbers
|
310
|
+
return [] unless extra
|
311
|
+
[change_code_number_for(extra)] + extra.numbers + extra.extra_numbers
|
312
|
+
end
|
313
|
+
|
314
|
+
def encodings
|
315
|
+
ENCODINGS
|
316
|
+
end
|
317
|
+
|
318
|
+
#The start encoding starts the barcode
|
319
|
+
def stop_encoding
|
320
|
+
STOP+TERMINATE
|
321
|
+
end
|
322
|
+
|
323
|
+
#Find the encoding for the specified character for this barcode
|
324
|
+
def encoding_for(char)
|
325
|
+
encodings[values[char]]
|
326
|
+
end
|
327
|
+
|
328
|
+
def change_code_for_class(klass)
|
329
|
+
{Code128A => CODEA, Code128B => CODEB, Code128C => CODEC}[klass]
|
330
|
+
end
|
331
|
+
|
332
|
+
#Find the character that changes the character set to the one
|
333
|
+
#represented in +barcode+
|
334
|
+
def change_code_for(barcode)
|
335
|
+
change_code_for_class(barcode.class)
|
336
|
+
end
|
337
|
+
|
338
|
+
#Find the numeric value for the character that changes the character
|
339
|
+
#set to the one represented in +barcode+
|
340
|
+
def change_code_number_for(barcode)
|
341
|
+
values[change_code_for(barcode)]
|
342
|
+
end
|
343
|
+
|
344
|
+
#Find the encoding to change to the character set in +barcode+
|
345
|
+
def change_code_encoding_for(barcode)
|
346
|
+
encodings[change_code_number_for(barcode)]
|
347
|
+
end
|
348
|
+
|
349
|
+
def class_for(character)
|
350
|
+
case character
|
351
|
+
when 'A' then Code128A
|
352
|
+
when 'B' then Code128B
|
353
|
+
when 'C' then Code128C
|
354
|
+
when CODEA then Code128A
|
355
|
+
when CODEB then Code128B
|
356
|
+
when CODEC then Code128C
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
#Is the data in this barcode valid? Does a lookup of every character
|
361
|
+
#and checks if it exists in the character set. An empty data string
|
362
|
+
#will also be reported as invalid.
|
363
|
+
def valid?
|
364
|
+
characters.any? && characters.all?{|c| values.include?(c) }
|
365
|
+
end
|
366
|
+
|
367
|
+
def values
|
368
|
+
VALUES[type]
|
369
|
+
end
|
370
|
+
|
371
|
+
def start_num
|
372
|
+
values["START#{type}"]
|
373
|
+
end
|
374
|
+
|
375
|
+
def start_encoding
|
376
|
+
encodings[start_num]
|
377
|
+
end
|
378
|
+
|
379
|
+
|
380
|
+
end
|
381
|
+
|
382
|
+
|
383
|
+
class Code128A < Code128
|
384
|
+
|
385
|
+
def initialize(data)
|
386
|
+
super(data, 'A')
|
387
|
+
end
|
388
|
+
|
389
|
+
end
|
390
|
+
|
391
|
+
|
392
|
+
class Code128B < Code128
|
393
|
+
|
394
|
+
def initialize(data)
|
395
|
+
super(data, 'B')
|
396
|
+
end
|
397
|
+
|
398
|
+
end
|
399
|
+
|
400
|
+
|
401
|
+
class Code128C < Code128
|
402
|
+
|
403
|
+
def initialize(data)
|
404
|
+
super(data, 'C')
|
405
|
+
end
|
406
|
+
|
407
|
+
end
|
408
|
+
|
409
|
+
|
410
|
+
end
|