rqrcode 0.1.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.
- data/CHANGELOG +3 -0
- data/README +91 -0
- data/lib/rqrcode.rb +13 -0
- data/lib/rqrcode/core_ext.rb +5 -0
- data/lib/rqrcode/core_ext/array.rb +5 -0
- data/lib/rqrcode/core_ext/array/behavior.rb +9 -0
- data/lib/rqrcode/core_ext/integer.rb +5 -0
- data/lib/rqrcode/core_ext/integer/bitwise.rb +11 -0
- data/lib/rqrcode/qrcode.rb +924 -0
- data/test/test_helper.rb +2 -0
- data/test/unit/qrcode_test.rb +75 -0
- data/test/unit/test_data.rb +21 -0
- metadata +78 -0
data/CHANGELOG
ADDED
data/README
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
= Project: rQRCode, Encode QRCodes
|
2
|
+
|
3
|
+
rQRCode is a library for encoding QR Codes in Ruby. It has a simple interface with all the standard qrcode options. It was adapted from the Javascript library by Kazuhiko Arase.
|
4
|
+
|
5
|
+
= An Overview
|
6
|
+
|
7
|
+
Let's clear up some rQRCode stuff.
|
8
|
+
|
9
|
+
# rQRCode is a *standalone library*. It requires no other libraries. Just Ruby!
|
10
|
+
# It is an encoding library. You can't decode QR codes with it.
|
11
|
+
# The interface is simple and assumes you just want to encode a string into a QR code
|
12
|
+
# QR code is trademarked by Denso Wave inc
|
13
|
+
|
14
|
+
= Rescources
|
15
|
+
|
16
|
+
# wikipedia [http://en.wikipedia.org/wiki/QR_Code]
|
17
|
+
# Denso-Wave website [http://www.denso-wave.com/qrcode/index-e.html]
|
18
|
+
# kaywa [http://qrcode.kaywa.com/]
|
19
|
+
|
20
|
+
|
21
|
+
== Installing
|
22
|
+
|
23
|
+
You may get the latest stable version from Rubyforge. Source gems are also available.
|
24
|
+
|
25
|
+
$ gem install rqrcode
|
26
|
+
|
27
|
+
=== Loading rQRCode Itself
|
28
|
+
|
29
|
+
You have installed the gem already, yeah?
|
30
|
+
|
31
|
+
require 'rubygems'
|
32
|
+
require 'qrqcode'
|
33
|
+
|
34
|
+
=== Simple QRCode generation to screen
|
35
|
+
|
36
|
+
qr = RQRCode::QRCode.new( 'my string to generate', :size => 4, :level => :h )
|
37
|
+
qr.to_console
|
38
|
+
#
|
39
|
+
# Prints:
|
40
|
+
# xxxxxxx x x x x x xx xxxxxxx
|
41
|
+
# x x xxx xxxxxx xxx x x
|
42
|
+
# x xxx x xxxxx x xx x xxx x
|
43
|
+
# ... etc
|
44
|
+
|
45
|
+
=== Simple QRCode generation to view (RubyOnRails)
|
46
|
+
|
47
|
+
controller:
|
48
|
+
@qr = RQRCode::QRCode.new( 'my string to generate', :size => 4, :level => :h )
|
49
|
+
|
50
|
+
view: (minimal styling added)
|
51
|
+
<style type="text/css">
|
52
|
+
table {
|
53
|
+
border-width: 0;
|
54
|
+
border-style: none;
|
55
|
+
border-color: #0000ff;
|
56
|
+
border-collapse: collapse;
|
57
|
+
}
|
58
|
+
td {
|
59
|
+
border-width: 0;
|
60
|
+
border-style: none;
|
61
|
+
border-color: #0000ff;
|
62
|
+
border-collapse: collapse;
|
63
|
+
padding: 0;
|
64
|
+
margin: 0;
|
65
|
+
width: 10px;
|
66
|
+
height: 10px;
|
67
|
+
}
|
68
|
+
td.black { background-color: #000; }
|
69
|
+
td.white { background-color: #fff; }
|
70
|
+
</style>
|
71
|
+
|
72
|
+
<table>
|
73
|
+
<% (0...@qr.module_count).each do |x| %>
|
74
|
+
<tr>
|
75
|
+
<% (0...@qr.module_count).each do |y| %>
|
76
|
+
<% if @qr.is_dark(x,y) %>
|
77
|
+
<td class="black"/>
|
78
|
+
<% else %>
|
79
|
+
<td class="white"/>
|
80
|
+
<% end %>
|
81
|
+
<% end %>
|
82
|
+
</tr>
|
83
|
+
<% end %>
|
84
|
+
</table>
|
85
|
+
|
86
|
+
== Contact
|
87
|
+
|
88
|
+
Author:: Duncan Robertson
|
89
|
+
Email:: duncan@whomwah.com
|
90
|
+
Home Page:: http://whomwah.com
|
91
|
+
License:: MIT Licence (http://www.opensource.org/licenses/mit-license.html)
|
data/lib/rqrcode.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#--
|
4
|
+
# Copyright 2004 by Duncan Robertson (duncan@whomwah.com).
|
5
|
+
# All rights reserved.
|
6
|
+
|
7
|
+
# Permission is granted for use, copying, modification, distribution,
|
8
|
+
# and distribution of modified versions of this work as long as the
|
9
|
+
# above copyright notice is included.
|
10
|
+
#++
|
11
|
+
|
12
|
+
require "rqrcode/core_ext"
|
13
|
+
require "rqrcode/qrcode"
|
@@ -0,0 +1,924 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#--
|
4
|
+
# Copyright 2004 by Duncan Robertson (duncan@whomwah.com).
|
5
|
+
# All rights reserved.
|
6
|
+
|
7
|
+
# Permission is granted for use, copying, modification, distribution,
|
8
|
+
# and distribution of modified versions of this work as long as the
|
9
|
+
# above copyright notice is included.
|
10
|
+
#++
|
11
|
+
|
12
|
+
module RQRCode
|
13
|
+
|
14
|
+
QRMODE = {
|
15
|
+
:mode_number => 1 << 0,
|
16
|
+
:mode_alpha_num => 1 << 1,
|
17
|
+
:mode_8bit_byte => 1 << 2,
|
18
|
+
:mode_kanji => 1 << 3
|
19
|
+
}
|
20
|
+
|
21
|
+
QRERRORCORRECTLEVEL = {
|
22
|
+
:l => 1,
|
23
|
+
:m => 0,
|
24
|
+
:q => 3,
|
25
|
+
:h => 2
|
26
|
+
}
|
27
|
+
|
28
|
+
QRMASKPATTERN = {
|
29
|
+
:pattern000 => 0,
|
30
|
+
:pattern001 => 1,
|
31
|
+
:pattern010 => 2,
|
32
|
+
:pattern011 => 3,
|
33
|
+
:pattern100 => 4,
|
34
|
+
:pattern101 => 5,
|
35
|
+
:pattern110 => 6,
|
36
|
+
:pattern111 => 7
|
37
|
+
}
|
38
|
+
|
39
|
+
class QRCodeArgumentError < ArgumentError; end
|
40
|
+
class QRCodeRunTimeError < RuntimeError; end
|
41
|
+
|
42
|
+
class QRCode
|
43
|
+
attr_reader :modules, :module_count
|
44
|
+
|
45
|
+
PAD0 = 0xEC
|
46
|
+
PAD1 = 0x11
|
47
|
+
|
48
|
+
def initialize( *args )
|
49
|
+
raise QRCodeArgumentError unless args.first.kind_of?( String )
|
50
|
+
|
51
|
+
@data = args.shift
|
52
|
+
options = args.extract_options!
|
53
|
+
level = options[:level] || :h
|
54
|
+
@error_correct_level = QRERRORCORRECTLEVEL[ level.to_sym ]
|
55
|
+
@type_number = options[:size] || 4
|
56
|
+
@module_count = @type_number * 4 + 17
|
57
|
+
@modules = nil
|
58
|
+
@data_cache = nil
|
59
|
+
@data_list = QR8bitByte.new( @data )
|
60
|
+
|
61
|
+
self.make # let's go !
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
def is_dark( row, col )
|
66
|
+
if row < 0 || @module_count <= row || col < 0 || @module_count <= col
|
67
|
+
raise QRCodeRunTimeError, "#{row},#{col}"
|
68
|
+
end
|
69
|
+
@modules[row][col]
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_console
|
73
|
+
(0...@module_count).each do |col|
|
74
|
+
tmp = []
|
75
|
+
(0...@module_count).each do |row|
|
76
|
+
if is_dark(col,row)
|
77
|
+
tmp << "x"
|
78
|
+
else
|
79
|
+
tmp << " "
|
80
|
+
end
|
81
|
+
end
|
82
|
+
puts tmp.join
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
protected
|
87
|
+
|
88
|
+
def make
|
89
|
+
make_impl( false, get_best_mask_pattern )
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
|
95
|
+
def make_impl( test, mask_pattern )
|
96
|
+
@modules = Array.new( @module_count )
|
97
|
+
|
98
|
+
( 0...@module_count ).each do |row|
|
99
|
+
@modules[row] = Array.new( @module_count )
|
100
|
+
end
|
101
|
+
|
102
|
+
setup_position_probe_pattern( 0, 0 )
|
103
|
+
setup_position_probe_pattern( @module_count - 7, 0 )
|
104
|
+
setup_position_probe_pattern( 0, @module_count - 7 )
|
105
|
+
setup_position_adjust_pattern
|
106
|
+
setup_timing_pattern
|
107
|
+
setup_type_info( test, mask_pattern )
|
108
|
+
setup_type_number( test ) if @type_number >= 7
|
109
|
+
|
110
|
+
if @data_cache.nil?
|
111
|
+
@data_cache = QRCode.create_data(
|
112
|
+
@type_number, @error_correct_level, @data_list
|
113
|
+
)
|
114
|
+
end
|
115
|
+
|
116
|
+
map_data( @data_cache, mask_pattern )
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
def setup_position_probe_pattern( row, col )
|
121
|
+
( -1..7 ).each do |r|
|
122
|
+
next if ( row + r ) <= -1 || @module_count <= ( row + r )
|
123
|
+
( -1..7 ).each do |c|
|
124
|
+
next if ( col + c ) <= -1 || @module_count <= ( col + c )
|
125
|
+
if 0 <= r && r <= 6 && ( c == 0 || c == 6 ) || 0 <= c && c <= 6 && ( r == 0 || r == 6 ) || 2 <= r && r <= 4 && 2 <= c && c <= 4
|
126
|
+
@modules[row + r][col + c] = true;
|
127
|
+
else
|
128
|
+
@modules[row + r][col + c] = false;
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
def get_best_mask_pattern
|
136
|
+
min_lost_point = 0
|
137
|
+
pattern = 0
|
138
|
+
|
139
|
+
( 0...8 ).each do |i|
|
140
|
+
make_impl( true, i )
|
141
|
+
lost_point = QRUtil.get_lost_point( self )
|
142
|
+
|
143
|
+
if i == 0 || min_lost_point > lost_point
|
144
|
+
min_lost_point = lost_point
|
145
|
+
pattern = i
|
146
|
+
end
|
147
|
+
end
|
148
|
+
pattern
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
def setup_timing_pattern
|
153
|
+
( 8...@module_count - 8 ).each do |r|
|
154
|
+
next unless @modules[r][6].nil?
|
155
|
+
@modules[r][6] = (r % 2 == 0)
|
156
|
+
end
|
157
|
+
|
158
|
+
( 8...@module_count - 8 ).each do |c|
|
159
|
+
next unless @modules[6][c].nil?
|
160
|
+
@modules[6][c] = (c % 2 == 0)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
def setup_position_adjust_pattern
|
166
|
+
pos = QRUtil.get_pattern_position(@type_number)
|
167
|
+
|
168
|
+
( 0...pos.size ).each do |i|
|
169
|
+
( 0...pos.size ).each do |j|
|
170
|
+
row = pos[i]
|
171
|
+
col = pos[j]
|
172
|
+
|
173
|
+
next unless @modules[row][col].nil?
|
174
|
+
|
175
|
+
( -2..2 ).each do |r|
|
176
|
+
( -2..2 ).each do |c|
|
177
|
+
if r == -2 || r == 2 || c == -2 || c == 2 || ( r == 0 && c == 0 )
|
178
|
+
@modules[row + r][col + c] = true
|
179
|
+
else
|
180
|
+
@modules[row + r][col + c] = false
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
|
189
|
+
def setup_type_number( test )
|
190
|
+
bits = QRUtil.get_bch_type_number( @type_number )
|
191
|
+
|
192
|
+
( 0...18 ).each do |i|
|
193
|
+
mod = ( !test && ( (bits >> i) & 1) == 1 )
|
194
|
+
@modules[ (i / 3).floor ][ i % 3 + @module_count - 8 - 3 ] = mod
|
195
|
+
end
|
196
|
+
|
197
|
+
( 0...18 ).each do |i|
|
198
|
+
mod = ( !test && ( (bits >> i) & 1) == 1 )
|
199
|
+
@modules[ i % 3 + @module_count - 8 - 3 ][ (i / 3).floor ] = mod
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
|
204
|
+
def setup_type_info( test, mask_pattern )
|
205
|
+
data = (@error_correct_level << 3 | mask_pattern)
|
206
|
+
bits = QRUtil.get_bch_type_info( data )
|
207
|
+
|
208
|
+
# vertical
|
209
|
+
( 0...15 ).each do |i|
|
210
|
+
mod = (!test && ( (bits >> i) & 1) == 1)
|
211
|
+
|
212
|
+
if i < 6
|
213
|
+
@modules[i][8] = mod
|
214
|
+
elsif i < 8
|
215
|
+
@modules[ i + 1 ][8] = mod
|
216
|
+
else
|
217
|
+
@modules[ @module_count - 15 + i ][8] = mod
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
# horizontal
|
223
|
+
( 0...15 ).each do |i|
|
224
|
+
mod = (!test && ( (bits >> i) & 1) == 1)
|
225
|
+
|
226
|
+
if i < 8
|
227
|
+
@modules[8][ @module_count - i - 1 ] = mod
|
228
|
+
elsif i < 9
|
229
|
+
@modules[8][ 15 - i - 1 + 1 ] = mod
|
230
|
+
else
|
231
|
+
@modules[8][ 15 - i - 1 ] = mod
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
# fixed module
|
236
|
+
@modules[ @module_count - 8 ][8] = !test
|
237
|
+
end
|
238
|
+
|
239
|
+
|
240
|
+
def map_data( data, mask_pattern )
|
241
|
+
inc = -1
|
242
|
+
row = @module_count - 1
|
243
|
+
bit_index = 7
|
244
|
+
byte_index = 0
|
245
|
+
|
246
|
+
( @module_count - 1 ).step( 1, -2 ) do |col|
|
247
|
+
col = col - 1 if col <= 6
|
248
|
+
|
249
|
+
while true do
|
250
|
+
( 0...2 ).each do |c|
|
251
|
+
|
252
|
+
if @modules[row][ col - c ].nil?
|
253
|
+
dark = false
|
254
|
+
if byte_index < data.size
|
255
|
+
dark = (( (data[byte_index]).rszf( bit_index ) & 1) == 1 )
|
256
|
+
end
|
257
|
+
mask = QRUtil.get_mask( mask_pattern, row, col - c )
|
258
|
+
dark = !dark if mask
|
259
|
+
@modules[row][ col - c ] = dark
|
260
|
+
bit_index -= 1
|
261
|
+
|
262
|
+
if bit_index == -1
|
263
|
+
byte_index += 1
|
264
|
+
bit_index = 7
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
row += inc
|
270
|
+
|
271
|
+
if row < 0 || @module_count <= row
|
272
|
+
row -= inc
|
273
|
+
inc = -inc
|
274
|
+
break
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def QRCode.create_data( type_number, error_correct_level, data_list )
|
281
|
+
rs_blocks = QRRSBlock.get_rs_blocks( type_number, error_correct_level )
|
282
|
+
buffer = QRBitBuffer.new
|
283
|
+
|
284
|
+
data = data_list
|
285
|
+
buffer.put( data.mode, 4 )
|
286
|
+
buffer.put(
|
287
|
+
data.get_length, QRUtil.get_length_in_bits( data.mode, type_number )
|
288
|
+
)
|
289
|
+
data.write( buffer )
|
290
|
+
|
291
|
+
total_data_count = 0
|
292
|
+
( 0...rs_blocks.size ).each do |i|
|
293
|
+
total_data_count = total_data_count + rs_blocks[i].data_count
|
294
|
+
end
|
295
|
+
|
296
|
+
if buffer.get_length_in_bits > total_data_count * 8
|
297
|
+
raise QRCodeRunTimeError,
|
298
|
+
"code length overflow. (#{buffer.get_length_in_bits}>#{total_data_count})"
|
299
|
+
end
|
300
|
+
|
301
|
+
if buffer.get_length_in_bits + 4 <= total_data_count * 8
|
302
|
+
buffer.put( 0, 4 )
|
303
|
+
end
|
304
|
+
|
305
|
+
while buffer.get_length_in_bits % 8 != 0
|
306
|
+
buffer.put_bit( false )
|
307
|
+
end
|
308
|
+
|
309
|
+
while true
|
310
|
+
break if buffer.get_length_in_bits >= total_data_count * 8
|
311
|
+
buffer.put( QRCode::PAD0, 8 )
|
312
|
+
break if buffer.get_length_in_bits >= total_data_count * 8
|
313
|
+
buffer.put( QRCode::PAD1, 8 )
|
314
|
+
end
|
315
|
+
|
316
|
+
QRCode.create_bytes( buffer, rs_blocks )
|
317
|
+
end
|
318
|
+
|
319
|
+
|
320
|
+
def QRCode.create_bytes( buffer, rs_blocks )
|
321
|
+
offset = 0
|
322
|
+
max_dc_count = 0
|
323
|
+
max_ec_count = 0
|
324
|
+
dcdata = Array.new( rs_blocks.size )
|
325
|
+
ecdata = Array.new( rs_blocks.size )
|
326
|
+
|
327
|
+
( 0...rs_blocks.size ).each do |r|
|
328
|
+
dc_count = rs_blocks[r].data_count
|
329
|
+
ec_count = rs_blocks[r].total_count - dc_count
|
330
|
+
max_dc_count = [ max_dc_count, dc_count ].max
|
331
|
+
max_ec_count = [ max_ec_count, ec_count ].max
|
332
|
+
dcdata[r] = Array.new( dc_count )
|
333
|
+
|
334
|
+
( 0...dcdata[r].size ).each do |i|
|
335
|
+
dcdata[r][i] = 0xff & buffer.buffer[ i + offset ]
|
336
|
+
end
|
337
|
+
|
338
|
+
offset = offset + dc_count
|
339
|
+
rs_poly = QRUtil.get_error_correct_polynomial( ec_count )
|
340
|
+
raw_poly = QRPolynomial.new( dcdata[r], rs_poly.get_length - 1 )
|
341
|
+
mod_poly = raw_poly.mod( rs_poly )
|
342
|
+
ecdata[r] = Array.new( rs_poly.get_length - 1 )
|
343
|
+
( 0...ecdata[r].size ).each do |i|
|
344
|
+
mod_index = i + mod_poly.get_length - ecdata[r].size
|
345
|
+
ecdata[r][i] = mod_index >= 0 ? mod_poly.get( mod_index ) : 0
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
total_code_count = 0
|
350
|
+
( 0...rs_blocks.size ).each do |i|
|
351
|
+
total_code_count = total_code_count + rs_blocks[i].total_count
|
352
|
+
end
|
353
|
+
|
354
|
+
data = Array.new( total_code_count )
|
355
|
+
index = 0
|
356
|
+
|
357
|
+
( 0...max_dc_count ).each do |i|
|
358
|
+
( 0...rs_blocks.size ).each do |r|
|
359
|
+
if i < dcdata[r].size
|
360
|
+
index += 1
|
361
|
+
data[index-1] = dcdata[r][i]
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
( 0...max_ec_count ).each do |i|
|
367
|
+
( 0...rs_blocks.size ).each do |r|
|
368
|
+
if i < ecdata[r].size
|
369
|
+
index += 1
|
370
|
+
data[index-1] = ecdata[r][i]
|
371
|
+
end
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
data
|
376
|
+
end
|
377
|
+
|
378
|
+
end
|
379
|
+
|
380
|
+
|
381
|
+
class QR8bitByte
|
382
|
+
attr_reader :mode
|
383
|
+
|
384
|
+
def initialize( data )
|
385
|
+
@mode = QRMODE[:mode_8bit_byte]
|
386
|
+
@data = data;
|
387
|
+
end
|
388
|
+
|
389
|
+
|
390
|
+
def get_length
|
391
|
+
@data.size
|
392
|
+
end
|
393
|
+
|
394
|
+
|
395
|
+
def write( buffer )
|
396
|
+
( 0...@data.size ).each do |i|
|
397
|
+
buffer.put( @data[i], 8 )
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
end
|
402
|
+
|
403
|
+
|
404
|
+
class QRPolynomial
|
405
|
+
|
406
|
+
def initialize( num, shift )
|
407
|
+
raise QRCodeRunTimeError, "#{num.size}/#{shift}" if num.empty?
|
408
|
+
offset = 0
|
409
|
+
|
410
|
+
while offset < num.size && num[offset] == 0
|
411
|
+
offset = offset + 1
|
412
|
+
end
|
413
|
+
|
414
|
+
@num = Array.new( num.size - offset + shift )
|
415
|
+
|
416
|
+
( 0...num.size - offset ).each do |i|
|
417
|
+
@num[i] = num[i + offset]
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
|
422
|
+
def get( index )
|
423
|
+
@num[index]
|
424
|
+
end
|
425
|
+
|
426
|
+
|
427
|
+
def get_length
|
428
|
+
@num.size
|
429
|
+
end
|
430
|
+
|
431
|
+
|
432
|
+
def multiply( e )
|
433
|
+
num = Array.new( get_length + e.get_length - 1 )
|
434
|
+
|
435
|
+
( 0...get_length ).each do |i|
|
436
|
+
( 0...e.get_length ).each do |j|
|
437
|
+
tmp = num[i + j].nil? ? 0 : num[i + j]
|
438
|
+
num[i + j] = tmp ^ QRMath.gexp(QRMath.glog( get(i) ) + QRMath.glog(e.get(j)))
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
return QRPolynomial.new( num, 0 )
|
443
|
+
end
|
444
|
+
|
445
|
+
|
446
|
+
def mod( e )
|
447
|
+
if get_length - e.get_length < 0
|
448
|
+
return self
|
449
|
+
end
|
450
|
+
|
451
|
+
ratio = QRMath.glog(get(0)) - QRMath.glog(e.get(0))
|
452
|
+
num = Array.new(get_length)
|
453
|
+
|
454
|
+
( 0...get_length ).each do |i|
|
455
|
+
num[i] = get(i)
|
456
|
+
end
|
457
|
+
|
458
|
+
( 0...e.get_length ).each do |i|
|
459
|
+
tmp = num[i].nil? ? 0 : num[i]
|
460
|
+
num[i] = tmp ^ QRMath.gexp(QRMath.glog(e.get(i)) + ratio)
|
461
|
+
end
|
462
|
+
|
463
|
+
return QRPolynomial.new( num, 0 ).mod(e)
|
464
|
+
end
|
465
|
+
|
466
|
+
end
|
467
|
+
|
468
|
+
|
469
|
+
class QRRSBlock
|
470
|
+
attr_reader :data_count, :total_count
|
471
|
+
|
472
|
+
def initialize( total_count, data_count )
|
473
|
+
@total_count = total_count
|
474
|
+
@data_count = data_count
|
475
|
+
end
|
476
|
+
|
477
|
+
RS_BLOCK_TABLE = [
|
478
|
+
|
479
|
+
# L
|
480
|
+
# M
|
481
|
+
# Q
|
482
|
+
# H
|
483
|
+
|
484
|
+
# 1
|
485
|
+
[1, 26, 19],
|
486
|
+
[1, 26, 16],
|
487
|
+
[1, 26, 13],
|
488
|
+
[1, 26, 9],
|
489
|
+
|
490
|
+
# 2
|
491
|
+
[1, 44, 34],
|
492
|
+
[1, 44, 28],
|
493
|
+
[1, 44, 22],
|
494
|
+
[1, 44, 16],
|
495
|
+
|
496
|
+
# 3
|
497
|
+
[1, 70, 55],
|
498
|
+
[1, 70, 44],
|
499
|
+
[2, 35, 17],
|
500
|
+
[2, 35, 13],
|
501
|
+
|
502
|
+
# 4
|
503
|
+
[1, 100, 80],
|
504
|
+
[2, 50, 32],
|
505
|
+
[2, 50, 24],
|
506
|
+
[4, 25, 9],
|
507
|
+
|
508
|
+
# 5
|
509
|
+
[1, 134, 108],
|
510
|
+
[2, 67, 43],
|
511
|
+
[2, 33, 15, 2, 34, 16],
|
512
|
+
[2, 33, 11, 2, 34, 12],
|
513
|
+
|
514
|
+
# 6
|
515
|
+
[2, 86, 68],
|
516
|
+
[4, 43, 27],
|
517
|
+
[4, 43, 19],
|
518
|
+
[4, 43, 15],
|
519
|
+
|
520
|
+
# 7
|
521
|
+
[2, 98, 78],
|
522
|
+
[4, 49, 31],
|
523
|
+
[2, 32, 14, 4, 33, 15],
|
524
|
+
[4, 39, 13, 1, 40, 14],
|
525
|
+
|
526
|
+
# 8
|
527
|
+
[2, 121, 97],
|
528
|
+
[2, 60, 38, 2, 61, 39],
|
529
|
+
[4, 40, 18, 2, 41, 19],
|
530
|
+
[4, 40, 14, 2, 41, 15],
|
531
|
+
|
532
|
+
# 9
|
533
|
+
[2, 146, 116],
|
534
|
+
[3, 58, 36, 2, 59, 37],
|
535
|
+
[4, 36, 16, 4, 37, 17],
|
536
|
+
[4, 36, 12, 4, 37, 13],
|
537
|
+
|
538
|
+
# 10
|
539
|
+
[2, 86, 68, 2, 87, 69],
|
540
|
+
[4, 69, 43, 1, 70, 44],
|
541
|
+
[6, 43, 19, 2, 44, 20],
|
542
|
+
[6, 43, 15, 2, 44, 16]
|
543
|
+
|
544
|
+
]
|
545
|
+
|
546
|
+
|
547
|
+
def QRRSBlock.get_rs_blocks( type_no, error_correct_level )
|
548
|
+
rs_block = QRRSBlock.get_rs_block_table( type_no, error_correct_level )
|
549
|
+
|
550
|
+
if rs_block.nil?
|
551
|
+
raise QRCodeRunTimeError,
|
552
|
+
"bad rsblock @ typeno: #{type_no}/error_correct_level:#{error_correct_level}"
|
553
|
+
end
|
554
|
+
|
555
|
+
length = rs_block.size / 3
|
556
|
+
list = []
|
557
|
+
|
558
|
+
( 0...length ).each do |i|
|
559
|
+
count = rs_block[i * 3 + 0]
|
560
|
+
total_count = rs_block[i * 3 + 1]
|
561
|
+
data_count = rs_block[i * 3 + 2]
|
562
|
+
|
563
|
+
( 0...count ).each do |j|
|
564
|
+
list << QRRSBlock.new( total_count, data_count )
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
list
|
569
|
+
end
|
570
|
+
|
571
|
+
|
572
|
+
def QRRSBlock.get_rs_block_table( type_number, error_correct_level )
|
573
|
+
case error_correct_level
|
574
|
+
when QRERRORCORRECTLEVEL[:l]
|
575
|
+
QRRSBlock::RS_BLOCK_TABLE[(type_number - 1) * 4 + 0]
|
576
|
+
when QRERRORCORRECTLEVEL[:m]
|
577
|
+
QRRSBlock::RS_BLOCK_TABLE[(type_number - 1) * 4 + 1]
|
578
|
+
when QRERRORCORRECTLEVEL[:q]
|
579
|
+
QRRSBlock::RS_BLOCK_TABLE[(type_number - 1) * 4 + 2]
|
580
|
+
when QRERRORCORRECTLEVEL[:h]
|
581
|
+
QRRSBlock::RS_BLOCK_TABLE[(type_number - 1) * 4 + 3]
|
582
|
+
else
|
583
|
+
nil
|
584
|
+
end
|
585
|
+
end
|
586
|
+
|
587
|
+
end
|
588
|
+
|
589
|
+
|
590
|
+
class QRBitBuffer
|
591
|
+
attr_reader :buffer
|
592
|
+
|
593
|
+
def initialize
|
594
|
+
@buffer = []
|
595
|
+
@length = 0
|
596
|
+
end
|
597
|
+
|
598
|
+
|
599
|
+
def get( index )
|
600
|
+
buf_index = (index / 8).floor
|
601
|
+
(( (@buffer[buf_index]).rszf(7 - index % 8)) & 1) == 1
|
602
|
+
end
|
603
|
+
|
604
|
+
|
605
|
+
def put( num, length )
|
606
|
+
( 0...length ).each do |i|
|
607
|
+
put_bit((((num).rszf(length - i - 1)) & 1) == 1)
|
608
|
+
end
|
609
|
+
end
|
610
|
+
|
611
|
+
|
612
|
+
def get_length_in_bits
|
613
|
+
@length
|
614
|
+
end
|
615
|
+
|
616
|
+
|
617
|
+
def put_bit( bit )
|
618
|
+
buf_index = ( @length / 8 ).floor
|
619
|
+
if @buffer.size <= buf_index
|
620
|
+
@buffer << 0
|
621
|
+
end
|
622
|
+
|
623
|
+
if bit
|
624
|
+
@buffer[buf_index] |= ((0x80).rszf(@length % 8))
|
625
|
+
end
|
626
|
+
|
627
|
+
@length += 1
|
628
|
+
end
|
629
|
+
|
630
|
+
end
|
631
|
+
|
632
|
+
|
633
|
+
class QRUtil
|
634
|
+
|
635
|
+
PATTERN_POSITION_TABLE = [
|
636
|
+
|
637
|
+
[],
|
638
|
+
[6, 18],
|
639
|
+
[6, 22],
|
640
|
+
[6, 26],
|
641
|
+
[6, 30],
|
642
|
+
[6, 34],
|
643
|
+
[6, 22, 38],
|
644
|
+
[6, 24, 42],
|
645
|
+
[6, 26, 46],
|
646
|
+
[6, 28, 50],
|
647
|
+
[6, 30, 54],
|
648
|
+
[6, 32, 58],
|
649
|
+
[6, 34, 62],
|
650
|
+
[6, 26, 46, 66],
|
651
|
+
[6, 26, 48, 70],
|
652
|
+
[6, 26, 50, 74],
|
653
|
+
[6, 30, 54, 78],
|
654
|
+
[6, 30, 56, 82],
|
655
|
+
[6, 30, 58, 86],
|
656
|
+
[6, 34, 62, 90],
|
657
|
+
[6, 28, 50, 72, 94],
|
658
|
+
[6, 26, 50, 74, 98],
|
659
|
+
[6, 30, 54, 78, 102],
|
660
|
+
[6, 28, 54, 80, 106],
|
661
|
+
[6, 32, 58, 84, 110],
|
662
|
+
[6, 30, 58, 86, 114],
|
663
|
+
[6, 34, 62, 90, 118],
|
664
|
+
[6, 26, 50, 74, 98, 122],
|
665
|
+
[6, 30, 54, 78, 102, 126],
|
666
|
+
[6, 26, 52, 78, 104, 130],
|
667
|
+
[6, 30, 56, 82, 108, 134],
|
668
|
+
[6, 34, 60, 86, 112, 138],
|
669
|
+
[6, 30, 58, 86, 114, 142],
|
670
|
+
[6, 34, 62, 90, 118, 146],
|
671
|
+
[6, 30, 54, 78, 102, 126, 150],
|
672
|
+
[6, 24, 50, 76, 102, 128, 154],
|
673
|
+
[6, 28, 54, 80, 106, 132, 158],
|
674
|
+
[6, 32, 58, 84, 110, 136, 162],
|
675
|
+
[6, 26, 54, 82, 110, 138, 166],
|
676
|
+
[6, 30, 58, 86, 114, 142, 170]
|
677
|
+
]
|
678
|
+
|
679
|
+
G15 = 1 << 10 | 1 << 8 | 1 << 5 | 1 << 4 | 1 << 2 | 1 << 1 | 1 << 0
|
680
|
+
G18 = 1 << 12 | 1 << 11 | 1 << 10 | 1 << 9 | 1 << 8 | 1 << 5 | 1 << 2 | 1 << 0
|
681
|
+
G15_MASK = 1 << 14 | 1 << 12 | 1 << 10 | 1 << 4 | 1 << 1
|
682
|
+
|
683
|
+
|
684
|
+
def QRUtil.get_bch_type_info( data )
|
685
|
+
d = data << 10
|
686
|
+
while QRUtil.get_bch_digit(d) - QRUtil.get_bch_digit(G15) >= 0
|
687
|
+
d ^= (G15 << (QRUtil.get_bch_digit(d) - QRUtil.get_bch_digit(G15)))
|
688
|
+
end
|
689
|
+
(( data << 10 ) | d) ^ G15_MASK
|
690
|
+
end
|
691
|
+
|
692
|
+
|
693
|
+
def QRUtil.get_bch_type_number( data )
|
694
|
+
d = data << 12
|
695
|
+
while QRUtil.get_bch_digit(d) - QRUtil.get_bch_digit(G18) >= 0
|
696
|
+
d ^= (G18 << (QRUtil.get_bch_digit(d) - QRUtil.get_bch_digit(G18)))
|
697
|
+
end
|
698
|
+
( data << 12 ) | d
|
699
|
+
end
|
700
|
+
|
701
|
+
|
702
|
+
def QRUtil.get_bch_digit( data )
|
703
|
+
digit = 0
|
704
|
+
|
705
|
+
while data != 0
|
706
|
+
digit = digit + 1
|
707
|
+
data = (data).rszf(1)
|
708
|
+
end
|
709
|
+
|
710
|
+
digit
|
711
|
+
end
|
712
|
+
|
713
|
+
|
714
|
+
def QRUtil.get_pattern_position( type_number )
|
715
|
+
PATTERN_POSITION_TABLE[ type_number - 1 ]
|
716
|
+
end
|
717
|
+
|
718
|
+
|
719
|
+
def QRUtil.get_mask( mask_pattern, i, j )
|
720
|
+
case mask_pattern
|
721
|
+
when QRMASKPATTERN[:pattern000]
|
722
|
+
(i + j) % 2 == 0
|
723
|
+
when QRMASKPATTERN[:pattern001]
|
724
|
+
i % 2 == 0
|
725
|
+
when QRMASKPATTERN[:pattern010]
|
726
|
+
j % 3 == 0
|
727
|
+
when QRMASKPATTERN[:pattern011]
|
728
|
+
(i + j) % 3 == 0
|
729
|
+
when QRMASKPATTERN[:pattern100]
|
730
|
+
((i / 2).floor + (j / 3).floor ) % 2 == 0
|
731
|
+
when QRMASKPATTERN[:pattern101]
|
732
|
+
(i * j) % 2 + (i * j) % 3 == 0
|
733
|
+
when QRMASKPATTERN[:pattern110]
|
734
|
+
( (i * j) % 2 + (i * j) % 3) % 2 == 0
|
735
|
+
when QRMASKPATTERN[:pattern111]
|
736
|
+
( (i * j) % 3 + (i + j) % 2) % 2 == 0
|
737
|
+
else
|
738
|
+
raise QRCodeRunTimeError, "bad mask_pattern: #{mask_pattern}"
|
739
|
+
end
|
740
|
+
end
|
741
|
+
|
742
|
+
|
743
|
+
def QRUtil.get_error_correct_polynomial( error_correct_length )
|
744
|
+
a = QRPolynomial.new( [1], 0 )
|
745
|
+
|
746
|
+
( 0...error_correct_length ).each do |i|
|
747
|
+
a = a.multiply( QRPolynomial.new( [1, QRMath.gexp(i)], 0 ) )
|
748
|
+
end
|
749
|
+
|
750
|
+
a
|
751
|
+
end
|
752
|
+
|
753
|
+
|
754
|
+
def QRUtil.get_length_in_bits( mode, type )
|
755
|
+
if 1 <= type && type < 10
|
756
|
+
|
757
|
+
# 1 - 9
|
758
|
+
case mode
|
759
|
+
when QRMODE[:mode_number] : 10
|
760
|
+
when QRMODE[:mode_alpha_num] : 9
|
761
|
+
when QRMODE[:mode_8bit_byte] : 8
|
762
|
+
when QRMODE[:mode_kanji] : 8
|
763
|
+
else
|
764
|
+
raise QRCodeRunTimeError, "mode: #{mode}"
|
765
|
+
end
|
766
|
+
|
767
|
+
elsif type < 27
|
768
|
+
|
769
|
+
# 10 -26
|
770
|
+
case mode
|
771
|
+
when QRMODE[:mode_number] : 12
|
772
|
+
when QRMODE[:mode_alpha_num] : 11
|
773
|
+
when QRMODE[:mode_8bit_byte] : 16
|
774
|
+
when QRMODE[:mode_kanji] : 10
|
775
|
+
else
|
776
|
+
raise QRCodeRunTimeError, "mode: #{mode}"
|
777
|
+
end
|
778
|
+
|
779
|
+
elsif type < 41
|
780
|
+
|
781
|
+
# 27 - 40
|
782
|
+
case mode
|
783
|
+
when QRMODE[:mode_number] : 14
|
784
|
+
when QRMODE[:mode_alpha_num] : 13
|
785
|
+
when QRMODE[:mode_8bit_byte] : 16
|
786
|
+
when QRMODE[:mode_kanji] : 12
|
787
|
+
else
|
788
|
+
raise QRCodeRunTimeError, "mode: #{mode}"
|
789
|
+
end
|
790
|
+
|
791
|
+
else
|
792
|
+
raise QRCodeRunTimeError, "type: #{type}"
|
793
|
+
end
|
794
|
+
end
|
795
|
+
|
796
|
+
|
797
|
+
def QRUtil.get_lost_point( qr_code )
|
798
|
+
module_count = qr_code.module_count
|
799
|
+
lost_point = 0
|
800
|
+
|
801
|
+
# level1
|
802
|
+
( 0...module_count ).each do |row|
|
803
|
+
( 0...module_count ).each do |col|
|
804
|
+
same_count = 0
|
805
|
+
dark = qr_code.is_dark( row, col )
|
806
|
+
|
807
|
+
( -1..1 ).each do |r|
|
808
|
+
next if row + r < 0 || module_count <= row + r
|
809
|
+
|
810
|
+
( -1..1 ).each do |c|
|
811
|
+
next if col + c < 0 || module_count <= col + c
|
812
|
+
next if r == 0 && c == 0
|
813
|
+
if dark == qr_code.is_dark( row + r, col + c )
|
814
|
+
same_count += 1
|
815
|
+
end
|
816
|
+
end
|
817
|
+
end
|
818
|
+
|
819
|
+
if same_count > 5
|
820
|
+
lost_point += (3 + same_count - 5)
|
821
|
+
end
|
822
|
+
end
|
823
|
+
end
|
824
|
+
|
825
|
+
# level 2
|
826
|
+
( 0...( module_count - 1 ) ).each do |row|
|
827
|
+
( 0...( module_count - 1 ) ).each do |col|
|
828
|
+
count = 0
|
829
|
+
count = count + 1 if qr_code.is_dark( row, col )
|
830
|
+
count = count + 1 if qr_code.is_dark( row + 1, col )
|
831
|
+
count = count + 1 if qr_code.is_dark( row, col + 1 )
|
832
|
+
count = count + 1 if qr_code.is_dark( row + 1, col + 1 )
|
833
|
+
lost_point = lost_point + 3 if (count == 0 || count == 4)
|
834
|
+
end
|
835
|
+
end
|
836
|
+
|
837
|
+
# level 3
|
838
|
+
( 0...module_count ).each do |row|
|
839
|
+
( 0...( module_count - 6 ) ).each do |col|
|
840
|
+
if qr_code.is_dark( row, col ) && !qr_code.is_dark( row, col + 1 ) && qr_code.is_dark( row, col + 2 ) && qr_code.is_dark( row, col + 3 ) && qr_code.is_dark( row, col + 4 ) && !qr_code.is_dark( row, col + 5 ) && qr_code.is_dark( row, col + 6 )
|
841
|
+
lost_point = lost_point + 40
|
842
|
+
end
|
843
|
+
end
|
844
|
+
end
|
845
|
+
|
846
|
+
( 0...module_count ).each do |col|
|
847
|
+
( 0...( module_count - 6 ) ).each do |row|
|
848
|
+
if qr_code.is_dark(row, col) && !qr_code.is_dark(row + 1, col) && qr_code.is_dark(row + 2, col) && qr_code.is_dark(row + 3, col) && qr_code.is_dark(row + 4, col) && !qr_code.is_dark(row + 5, col) && qr_code.is_dark(row + 6, col)
|
849
|
+
lost_point = lost_point + 40
|
850
|
+
end
|
851
|
+
end
|
852
|
+
end
|
853
|
+
|
854
|
+
# level 4
|
855
|
+
dark_count = 0
|
856
|
+
|
857
|
+
( 0...module_count ).each do |col|
|
858
|
+
( 0...module_count ).each do |row|
|
859
|
+
if qr_code.is_dark(row, col)
|
860
|
+
dark_count = dark_count + 1
|
861
|
+
end
|
862
|
+
end
|
863
|
+
end
|
864
|
+
|
865
|
+
ratio = (100 * dark_count / module_count / module_count - 50).abs / 5
|
866
|
+
lost_point = lost_point * 10
|
867
|
+
|
868
|
+
lost_point
|
869
|
+
end
|
870
|
+
|
871
|
+
end
|
872
|
+
|
873
|
+
|
874
|
+
class QRMath
|
875
|
+
|
876
|
+
module_eval {
|
877
|
+
exp_table = Array.new(256)
|
878
|
+
log_table = Array.new(256)
|
879
|
+
|
880
|
+
( 0...8 ).each do |i|
|
881
|
+
exp_table[i] = 1 << i
|
882
|
+
end
|
883
|
+
|
884
|
+
( 8...256 ).each do |i|
|
885
|
+
exp_table[i] = exp_table[i - 4] \
|
886
|
+
^ exp_table[i - 5] \
|
887
|
+
^ exp_table[i - 6] \
|
888
|
+
^ exp_table[i - 8]
|
889
|
+
end
|
890
|
+
|
891
|
+
( 0...255 ).each do |i|
|
892
|
+
log_table[exp_table[i] ] = i
|
893
|
+
end
|
894
|
+
|
895
|
+
EXP_TABLE = exp_table
|
896
|
+
LOG_TABLE = log_table
|
897
|
+
}
|
898
|
+
|
899
|
+
class << self
|
900
|
+
|
901
|
+
def glog(n)
|
902
|
+
raise QRCodeRunTimeError, "glog(#{n})" if ( n < 1 )
|
903
|
+
LOG_TABLE[n]
|
904
|
+
end
|
905
|
+
|
906
|
+
|
907
|
+
def gexp(n)
|
908
|
+
while n < 0
|
909
|
+
n = n + 255
|
910
|
+
end
|
911
|
+
|
912
|
+
while n >= 256
|
913
|
+
n = n - 255
|
914
|
+
end
|
915
|
+
|
916
|
+
EXP_TABLE[n]
|
917
|
+
end
|
918
|
+
|
919
|
+
end
|
920
|
+
|
921
|
+
end
|
922
|
+
|
923
|
+
|
924
|
+
end
|