barby 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/barby +40 -0
- data/lib/barby.rb +3 -0
- data/lib/barby/barcode.rb +6 -0
- data/lib/barby/barcode/code_128.rb +16 -3
- data/lib/barby/barcode/code_25.rb +161 -0
- data/lib/barby/barcode/code_25_interleaved.rb +73 -0
- data/lib/barby/barcode/code_93.rb +225 -0
- data/lib/barby/barcode/qr_code.rb +93 -0
- data/lib/barby/outputter.rb +56 -2
- data/lib/barby/outputter/ascii_outputter.rb +20 -1
- data/lib/barby/outputter/cairo_outputter.rb +38 -7
- data/lib/barby/outputter/pdfwriter_outputter.rb +44 -35
- data/lib/barby/outputter/png_outputter.rb +48 -16
- data/lib/barby/outputter/prawn_outputter.rb +100 -0
- data/lib/barby/outputter/rmagick_outputter.rb +48 -20
- data/lib/barby/vendor.rb +3 -0
- data/vendor/rqrcode/CHANGELOG +21 -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 +35 -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 +134 -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 +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
|
data/lib/barby/outputter.rb
CHANGED
@@ -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
|
-
|
66
|
-
|
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
|
-
|
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.
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
-
|
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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
|
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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
29
|
-
|
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
|
-
|
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
|
|