barby 0.1.2 → 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.
Files changed (37) hide show
  1. data/bin/barby +40 -0
  2. data/lib/barby.rb +3 -0
  3. data/lib/barby/barcode.rb +6 -0
  4. data/lib/barby/barcode/code_128.rb +16 -3
  5. data/lib/barby/barcode/code_25.rb +161 -0
  6. data/lib/barby/barcode/code_25_interleaved.rb +73 -0
  7. data/lib/barby/barcode/code_93.rb +225 -0
  8. data/lib/barby/barcode/qr_code.rb +93 -0
  9. data/lib/barby/outputter.rb +56 -2
  10. data/lib/barby/outputter/ascii_outputter.rb +20 -1
  11. data/lib/barby/outputter/cairo_outputter.rb +38 -7
  12. data/lib/barby/outputter/pdfwriter_outputter.rb +44 -35
  13. data/lib/barby/outputter/png_outputter.rb +48 -16
  14. data/lib/barby/outputter/prawn_outputter.rb +100 -0
  15. data/lib/barby/outputter/rmagick_outputter.rb +48 -20
  16. data/lib/barby/vendor.rb +3 -0
  17. data/vendor/rqrcode/CHANGELOG +21 -0
  18. data/vendor/rqrcode/COPYING +19 -0
  19. data/vendor/rqrcode/README +98 -0
  20. data/vendor/rqrcode/Rakefile +65 -0
  21. data/vendor/rqrcode/lib/rqrcode.rb +13 -0
  22. data/vendor/rqrcode/lib/rqrcode/core_ext.rb +5 -0
  23. data/vendor/rqrcode/lib/rqrcode/core_ext/array.rb +5 -0
  24. data/vendor/rqrcode/lib/rqrcode/core_ext/array/behavior.rb +9 -0
  25. data/vendor/rqrcode/lib/rqrcode/core_ext/integer.rb +5 -0
  26. data/vendor/rqrcode/lib/rqrcode/core_ext/integer/bitwise.rb +11 -0
  27. data/vendor/rqrcode/lib/rqrcode/qrcode.rb +4 -0
  28. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_8bit_byte.rb +35 -0
  29. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_bit_buffer.rb +56 -0
  30. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_code.rb +421 -0
  31. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_math.rb +63 -0
  32. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_polynomial.rb +78 -0
  33. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_rs_block.rb +134 -0
  34. data/vendor/rqrcode/lib/rqrcode/qrcode/qr_util.rb +254 -0
  35. data/vendor/rqrcode/test/runtest.rb +78 -0
  36. data/vendor/rqrcode/test/test_data.rb +21 -0
  37. metadata +86 -44
@@ -0,0 +1,93 @@
1
+ require 'rqrcode'
2
+ require 'barby/barcode'
3
+
4
+ module Barby
5
+
6
+
7
+ #QrCode is a thin wrapper around the RQRCode library
8
+ class QrCode < Barcode2D
9
+
10
+ #Maximum sizes for each correction level for binary data
11
+ #It's an array
12
+ SIZES = {
13
+ #L M Q H
14
+ 1 => [17, 14, 11, 7], 2 => [32, 26, 20, 14],
15
+ 3 => [53, 42, 32, 24], 4 => [78, 62, 46, 34],
16
+ 5 => [106, 84, 60, 44], 6 => [134, 106, 74, 58],
17
+ 7 => [154, 122, 86, 64], 8 => [192, 152, 108, 84],
18
+ 9 => [230, 180, 130, 98], 10 => [271, 213, 151, 119]#,
19
+
20
+ #I think RQRCode only supports sizes up to 10
21
+ # 11 => [321, 251, 177, 137], 12 => [367, 287, 203, 155],
22
+ # 13 => [425, 331, 241, 177], 14 => [458, 362, 258, 194],
23
+ # 15 => [520, 412, 292, 220], 16 => [586, 450, 322, 250],
24
+ # 17 => [644, 504, 364, 280], 18 => [718, 560, 394, 310],
25
+ # 19 => [792, 624, 442, 338], 20 => [858, 666, 482, 382],
26
+ # 21 => [929, 711, 509, 403], 22 => [1003, 779, 565, 439],
27
+ # 23 => [1091, 857, 611, 461], 24 => [1171, 911, 661, 511],
28
+ # 25 => [1273, 997, 715, 535], 26 => [1367, 1059, 751, 593],
29
+ # 27 => [1465, 1125, 805, 625], 28 => [1528, 1190, 868, 658],
30
+ # 29 => [1628, 1264, 908, 698], 30 => [1732, 1370, 982, 742],
31
+ # 31 => [1840, 1452, 1030, 790], 32 => [1952, 1538, 1112, 842],
32
+ # 33 => [2068, 1628, 1168, 898], 34 => [2188, 1722, 1228, 958],
33
+ # 35 => [2303, 1809, 1283, 983], 36 => [2431, 1911, 1351, 1051],
34
+ # 37 => [2563, 1989, 1423, 1093], 38 => [2699, 2099, 1499, 1139],
35
+ # 39 => [2809, 2213, 1579, 1219], 40 => [2953, 2331, 1663, 1273]
36
+ }.sort
37
+
38
+ LEVELS = { :l => 0, :m => 1, :q => 2, :h => 3 }
39
+
40
+ attr_reader :data
41
+ attr_writer :level
42
+
43
+
44
+ def initialize(data, options={})
45
+ self.data = data
46
+ options.each{|k,v| send("#{k}=", v) }
47
+ raise(ArgumentError, "data too large") unless size
48
+ end
49
+
50
+
51
+ def data=(data)
52
+ @data = data
53
+ end
54
+
55
+
56
+ def encoding
57
+ rqrcode.modules.map{|r| r.inject(''){|s,m| s << (m ? '1' : '0') } }
58
+ end
59
+
60
+
61
+ #Error correction level
62
+ #Can be one of [:l, :m, :q, :h] (7%, 15%, 25%, 30%)
63
+ def level
64
+ @level || :l
65
+ end
66
+
67
+
68
+ def size
69
+ level_index = LEVELS[level]
70
+ length = data.length
71
+ found_size = nil
72
+ SIZES.each do |size,max_values|
73
+ if max_values[level_index] >= length
74
+ found_size = size
75
+ break
76
+ end
77
+ end
78
+ found_size
79
+ end
80
+
81
+
82
+ private
83
+
84
+ #Generate an RQRCode object with the available values
85
+ def rqrcode
86
+ RQRCode::QRCode.new(data, :level => level, :size => size)
87
+ end
88
+
89
+
90
+ end
91
+
92
+
93
+ end
@@ -62,8 +62,62 @@ module Barby
62
62
 
63
63
  #Converts the barcode's encoding (a string containing 1s and 0s)
64
64
  #to true and false values (1 == true == "black bar")
65
- def booleans#:doc:
66
- barcode.encoding.split(//).map{|c| c == '1' }
65
+ #
66
+ #If the barcode is 2D, each line will be converted to an array
67
+ #in the same way
68
+ def booleans(reload=false)#:doc:
69
+ if barcode.two_dimensional?
70
+ encoding(reload).map{|l| l.split(//).map{|c| c == '1' } }
71
+ else
72
+ encoding(reload).split(//).map{|c| c == '1' }
73
+ end
74
+ end
75
+
76
+
77
+ #Returns the barcode's encoding. The encoding
78
+ #is cached and can be reloaded by passing true
79
+ def encoding(reload=false)#:doc:
80
+ @encoding = barcode.encoding if reload
81
+ @encoding ||= barcode.encoding
82
+ end
83
+
84
+
85
+ #Collects continuous groups of bars and spaces (1 and 0)
86
+ #into arrays where the first item is true or false (1 or 0)
87
+ #and the second is the size of the group
88
+ #
89
+ #For example, "1100111000" becomes [[true,2],[false,2],[true,3],[false,3]]
90
+ def boolean_groups(reload=false)
91
+ if barcode.two_dimensional?
92
+ encoding(reload).map do |line|
93
+ line.scan(/1+|0+/).map do |group|
94
+ [group[0,1] == '1', group.size]
95
+ end
96
+ end
97
+ else
98
+ encoding(reload).scan(/1+|0+/).map do |group|
99
+ [group[0,1] == '1', group.size]
100
+ end
101
+ end
102
+ end
103
+
104
+
105
+ def with_options(options={})
106
+ original_options = options.inject({}) do |origs,pair|
107
+ if respond_to?(pair.first) && respond_to?("#{pair.first}=")
108
+ origs[pair.first] = send(pair.first)
109
+ send("#{pair.first}=", pair.last)
110
+ end
111
+ origs
112
+ end
113
+
114
+ rv = yield
115
+
116
+ original_options.each do |attribute,value|
117
+ send("#{attribute}=", value)
118
+ end
119
+
120
+ rv
67
121
  end
68
122
 
69
123
 
@@ -4,19 +4,38 @@ module Barby
4
4
 
5
5
  #Outputs an ASCII representation of the barcode. This is mostly useful for printing
6
6
  #the barcode directly to the terminal for testing.
7
+ #
8
+ #Registers to_ascii
7
9
  class ASCIIOutputter < Outputter
8
10
 
9
11
  register :to_ascii
10
12
 
11
13
 
12
14
  def to_ascii(opts={})
13
- opts = {:height => 10, :xdim => 1, :bar => '#', :space => ' '}.merge(opts)
15
+ default_opts = {:height => 10, :xdim => 1, :bar => '#', :space => ' '}
16
+ default_opts.update(:height => 1, :bar => ' X ', :space => ' ') if barcode.two_dimensional?
17
+ opts = default_opts.merge(opts)
18
+
19
+ if barcode.two_dimensional?
20
+ booleans.map do |bools|
21
+ line_to_ascii(bools, opts)
22
+ end.join("\n")
23
+ else
24
+ line_to_ascii(booleans, opts)
25
+ end
26
+ end
27
+
28
+
29
+ private
30
+
31
+ def line_to_ascii(booleans, opts)
14
32
  Array.new(
15
33
  opts[:height],
16
34
  booleans.map{|b| (b ? opts[:bar] : opts[:space]) * opts[:xdim] }.join
17
35
  ).join("\n")
18
36
  end
19
37
 
38
+
20
39
  end
21
40
 
22
41
  end
@@ -1,7 +1,12 @@
1
+ require 'barby/outputter'
1
2
  require 'cairo'
2
3
  require 'stringio'
3
4
 
4
5
  module Barby
6
+
7
+ #Uses Cairo to render a barcode to a number of formats: PNG, PS, EPS, PDF and SVG
8
+ #
9
+ #Registers methods render_to_cairo_context, to_png, to_ps, to_eps, to_pdf and to_svg
5
10
  class CairoOutputter < Outputter
6
11
 
7
12
  register :render_to_cairo_context
@@ -18,6 +23,7 @@ module Barby
18
23
  attr_writer :x, :y, :xdim, :height, :margin
19
24
 
20
25
 
26
+ #Render the barcode onto a Cairo context
21
27
  def render_to_cairo_context(context, options={})
22
28
  if context.respond_to?(:have_current_point?) and
23
29
  context.have_current_point?
@@ -29,15 +35,30 @@ module Barby
29
35
 
30
36
  _xdim = xdim(options)
31
37
  _height = height(options)
38
+ original_current_x = current_x
32
39
  context.save do
33
40
  context.set_source_color(:black)
34
41
  context.fill do
35
- barcode.encoding.scan(/(?:0+|1+)/).each do |codes|
36
- current_width = _xdim * codes.size
37
- if codes[0] == ?1
38
- context.rectangle(current_x, current_y, current_width, _height)
42
+ if barcode.two_dimensional?
43
+ boolean_groups.each do |groups|
44
+ groups.each do |bar,amount|
45
+ current_width = _xdim * amount
46
+ if bar
47
+ context.rectangle(current_x, current_y, current_width, _xdim)
48
+ end
49
+ current_x += current_width
50
+ end
51
+ current_x = original_current_x
52
+ current_y += _xdim
53
+ end
54
+ else
55
+ boolean_groups.each do |bar,amount|
56
+ current_width = _xdim * amount
57
+ if bar
58
+ context.rectangle(current_x, current_y, current_width, _height)
59
+ end
60
+ current_x += current_width
39
61
  end
40
- current_x += current_width
41
62
  end
42
63
  end
43
64
  end
@@ -46,6 +67,7 @@ module Barby
46
67
  end
47
68
 
48
69
 
70
+ #Render the barcode to a PNG image
49
71
  def to_png(options={})
50
72
  output_to_string_io do |io|
51
73
  Cairo::ImageSurface.new(options[:format],
@@ -58,6 +80,7 @@ module Barby
58
80
  end
59
81
 
60
82
 
83
+ #Render the barcode to a PS document
61
84
  def to_ps(options={})
62
85
  output_to_string_io do |io|
63
86
  Cairo::PSSurface.new(io,
@@ -70,11 +93,13 @@ module Barby
70
93
  end
71
94
 
72
95
 
96
+ #Render the barcode to an EPS document
73
97
  def to_eps(options={})
74
98
  to_ps(options.merge(:eps => true))
75
99
  end
76
100
 
77
101
 
102
+ #Render the barcode to a PDF document
78
103
  def to_pdf(options={})
79
104
  output_to_string_io do |io|
80
105
  Cairo::PDFSurface.new(io,
@@ -86,6 +111,7 @@ module Barby
86
111
  end
87
112
 
88
113
 
114
+ #Render the barcode to an SVG document
89
115
  def to_svg(options={})
90
116
  output_to_string_io do |io|
91
117
  Cairo::SVGSurface.new(io,
@@ -106,11 +132,15 @@ module Barby
106
132
  end
107
133
 
108
134
  def width(options={})
109
- barcode.encoding.length * xdim(options)
135
+ (barcode.two_dimensional? ? encoding.first.length : encoding.length) * xdim(options)
110
136
  end
111
137
 
112
138
  def height(options={})
113
- @height || options[:height] || 50
139
+ if barcode.two_dimensional?
140
+ encoding.size * xdim(options)
141
+ else
142
+ @height || options[:height] || 50
143
+ end
114
144
  end
115
145
 
116
146
  def full_width(options={})
@@ -151,4 +181,5 @@ module Barby
151
181
 
152
182
 
153
183
  end
184
+
154
185
  end
@@ -2,6 +2,9 @@ require 'barby/outputter'
2
2
 
3
3
  module Barby
4
4
 
5
+ #Annotates a PDFWriter document with the barcode
6
+ #
7
+ #Registers the annotate_pdf method
5
8
  class PDFWriterOutputter < Outputter
6
9
 
7
10
  register :annotate_pdf
@@ -9,25 +12,50 @@ module Barby
9
12
  attr_accessor :x, :y, :height, :xdim
10
13
 
11
14
 
15
+ #Annotate a PDFWriter document with the barcode
16
+ #
17
+ #Valid options are:
18
+ #
19
+ #x, y - The point in the document to start rendering from
20
+ #height - The height of the bars in PDF units
21
+ #xdim - The X dimension in PDF units
12
22
  def annotate_pdf(pdf, options={})
13
- previous_options = options.map{|k,v| [k, send(k)] }
14
- options.each{|k,v| send("#{k}=", v) if respond_to?("#{k}=") }
15
-
16
- xpos, ypos = x, y
17
-
18
- widths.each do |array|
19
- if array.first
20
- pdf.move_to(xpos, ypos).
21
- line_to(xpos, ypos+height).
22
- line_to(xpos+(xdim*array.size), ypos+height).
23
- line_to(xpos+(xdim*array.size), ypos).
24
- line_to(xpos, ypos).
25
- fill
23
+ with_options options do
24
+
25
+ xpos, ypos = x, y
26
+ orig_xpos = xpos
27
+
28
+ if barcode.two_dimensional?
29
+ boolean_groups.reverse_each do |groups|
30
+ groups.each do |bar,amount|
31
+ if bar
32
+ pdf.move_to(xpos, ypos).
33
+ line_to(xpos, ypos+xdim).
34
+ line_to(xpos+(xdim*amount), ypos+xdim).
35
+ line_to(xpos+(xdim*amount), ypos).
36
+ line_to(xpos, ypos).
37
+ fill
38
+ end
39
+ xpos += (xdim*amount)
40
+ end
41
+ xpos = orig_xpos
42
+ ypos += xdim
43
+ end
44
+ else
45
+ boolean_groups.each do |bar,amount|
46
+ if bar
47
+ pdf.move_to(xpos, ypos).
48
+ line_to(xpos, ypos+height).
49
+ line_to(xpos+(xdim*amount), ypos+height).
50
+ line_to(xpos+(xdim*amount), ypos).
51
+ line_to(xpos, ypos).
52
+ fill
53
+ end
54
+ xpos += (xdim*amount)
55
+ end
26
56
  end
27
- xpos += (xdim*array.size)
28
- end
29
57
 
30
- previous_options.each{|k,v| send("#{k}=", v) }
58
+ end
31
59
 
32
60
  pdf
33
61
  end
@@ -49,25 +77,6 @@ module Barby
49
77
  @xdim || 1
50
78
  end
51
79
 
52
- def widths
53
- widths = []
54
- count = nil
55
-
56
- booleans.inject nil do |previous,current|
57
- if current != previous
58
- widths << count if count
59
- count = [current]
60
- else
61
- count << current
62
- end
63
- current
64
- end
65
-
66
- widths << count
67
-
68
- widths
69
- end
70
-
71
80
 
72
81
  end
73
82
 
@@ -1,46 +1,70 @@
1
+ require 'barby/outputter'
1
2
  require 'png'
2
3
 
3
4
  module Barby
4
5
 
6
+ #Renders the barcode to a PNG image using the "png" gem (gem install png)
7
+ #
8
+ #Registers the to_png and to_canvas methods
5
9
  class PngOutputter < Outputter
6
10
 
7
11
  register :to_png, :to_canvas
8
12
 
9
- attr_accessor :xdim, :width, :height, :margin
13
+ attr_accessor :xdim, :ydim, :width, :height, :margin
10
14
 
11
15
 
16
+ #Creates a PNG::Canvas object and renders the barcode on it
12
17
  def to_canvas(opts={})
13
- orig_opts = opts.inject({}){|h,p| send("#{p.first}=", p.last) if respond_to?("#{p.first}="); h.update(p.first => p.last) }
14
- canvas = PNG::Canvas.new(full_width, full_height, PNG::Color::White)
15
-
16
- x, y = margin, margin
17
- booleans.each do |bar|
18
- if bar
19
- x.upto(x+(xdim-1)) do |xx|
20
- y.upto y+(height-1) do |yy|
21
- canvas[xx,yy] = PNG::Color::Black
18
+ with_options opts do
19
+ canvas = PNG::Canvas.new(full_width, full_height, PNG::Color::White)
20
+
21
+ if barcode.two_dimensional?
22
+ x, y = margin, margin
23
+ booleans.reverse_each do |line|
24
+ line.each do |bar|
25
+ if bar
26
+ x.upto(x+(xdim-1)) do |xx|
27
+ y.upto y+(ydim-1) do |yy|
28
+ canvas[xx,yy] = PNG::Color::Black
29
+ end
30
+ end
31
+ end
32
+ x += xdim
22
33
  end
34
+ y += ydim
35
+ x = margin
36
+ end
37
+ else
38
+ x, y = margin, margin
39
+ booleans.each do |bar|
40
+ if bar
41
+ x.upto(x+(xdim-1)) do |xx|
42
+ y.upto y+(height-1) do |yy|
43
+ canvas[xx,yy] = PNG::Color::Black
44
+ end
45
+ end
46
+ end
47
+ x += xdim
23
48
  end
24
49
  end
25
- x += xdim
26
- end
27
50
 
28
- orig_opts.each{|k,v| send("#{k}=", v) if respond_to?("#{k}=") }
29
- canvas
51
+ canvas
52
+ end
30
53
  end
31
54
 
32
55
 
56
+ #Renders the barcode to a PNG image
33
57
  def to_png(*a)
34
58
  PNG.new(to_canvas(*a)).to_blob
35
59
  end
36
60
 
37
61
 
38
62
  def width
39
- barcode.encoding.length * xdim
63
+ length * xdim
40
64
  end
41
65
 
42
66
  def height
43
- @height || 100
67
+ barcode.two_dimensional? ? (ydim * encoding.length) : (@height || 100)
44
68
  end
45
69
 
46
70
  def full_width
@@ -55,10 +79,18 @@ module Barby
55
79
  @xdim || 1
56
80
  end
57
81
 
82
+ def ydim
83
+ @ydim || xdim
84
+ end
85
+
58
86
  def margin
59
87
  @margin || 10
60
88
  end
61
89
 
90
+ def length
91
+ barcode.two_dimensional? ? encoding.first.length : encoding.length
92
+ end
93
+
62
94
 
63
95
  end
64
96