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.
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