arena_barby 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/README +29 -0
  2. data/bin/barby +41 -0
  3. data/lib/barby.rb +17 -0
  4. data/lib/barby/barcode.rb +116 -0
  5. data/lib/barby/barcode/bookland.rb +37 -0
  6. data/lib/barby/barcode/code_128.rb +410 -0
  7. data/lib/barby/barcode/code_25.rb +193 -0
  8. data/lib/barby/barcode/code_25_iata.rb +23 -0
  9. data/lib/barby/barcode/code_25_interleaved.rb +73 -0
  10. data/lib/barby/barcode/code_39.rb +233 -0
  11. data/lib/barby/barcode/code_93.rb +230 -0
  12. data/lib/barby/barcode/ean_13.rb +178 -0
  13. data/lib/barby/barcode/ean_8.rb +32 -0
  14. data/lib/barby/barcode/gs1_128.rb +42 -0
  15. data/lib/barby/barcode/pdf_417.rb +76 -0
  16. data/lib/barby/barcode/qr_code.rb +101 -0
  17. data/lib/barby/outputter.rb +127 -0
  18. data/lib/barby/outputter/ascii_outputter.rb +41 -0
  19. data/lib/barby/outputter/cairo_outputter.rb +185 -0
  20. data/lib/barby/outputter/pdfwriter_outputter.rb +83 -0
  21. data/lib/barby/outputter/png_outputter.rb +97 -0
  22. data/lib/barby/outputter/prawn_outputter.rb +99 -0
  23. data/lib/barby/outputter/rmagick_outputter.rb +126 -0
  24. data/lib/barby/outputter/svg_outputter.rb +225 -0
  25. data/lib/barby/vendor.rb +3 -0
  26. data/lib/barby/version.rb +9 -0
  27. data/vendor/Pdf417lib-java-0.91/lib/Pdf417lib.jar +0 -0
  28. data/vendor/Pdf417lib-java-0.91/lib/Pdf417lib.java +1471 -0
  29. data/vendor/rqrcode/CHANGELOG +29 -0
  30. data/vendor/rqrcode/COPYING +19 -0
  31. data/vendor/rqrcode/README +98 -0
  32. data/vendor/rqrcode/Rakefile +65 -0
  33. data/vendor/rqrcode/lib/rqrcode.rb +13 -0
  34. data/vendor/rqrcode/lib/rqrcode/core_ext.rb +5 -0
  35. data/vendor/rqrcode/lib/rqrcode/core_ext/array.rb +5 -0
  36. data/vendor/rqrcode/lib/rqrcode/core_ext/array/behavior.rb +9 -0
  37. data/vendor/rqrcode/lib/rqrcode/core_ext/integer.rb +5 -0
  38. data/vendor/rqrcode/lib/rqrcode/core_ext/integer/bitwise.rb +11 -0
  39. data/vendor/rqrcode/lib/rqrcode/qrcode.rb +4 -0
  40. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_8bit_byte.rb +37 -0
  41. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_bit_buffer.rb +56 -0
  42. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_code.rb +421 -0
  43. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_math.rb +63 -0
  44. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_polynomial.rb +78 -0
  45. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_rs_block.rb +313 -0
  46. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_util.rb +254 -0
  47. data/vendor/rqrcode/test/runtest.rb +78 -0
  48. data/vendor/rqrcode/test/test_data.rb +21 -0
  49. 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
@@ -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']})")
@@ -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