rqrcode-with-patches 0.5.1

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.
@@ -0,0 +1,42 @@
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
+ class QR8bitByte
15
+ attr_reader :mode
16
+
17
+ def initialize( data )
18
+ @mode = QRMODE[:mode_8bit_byte]
19
+ @data = data;
20
+ end
21
+
22
+
23
+ def get_length
24
+ @data.size
25
+ end
26
+
27
+
28
+ def write( buffer)
29
+
30
+ buffer.byte_encoding_start(get_length)
31
+
32
+ ( 0...@data.size ).each do |i|
33
+ c = @data[i]
34
+ c = c.ord if c.respond_to?(:ord)#String#[] returns single-char string in 1.9, .ord gets ASCII pos
35
+ buffer.put( c, 8 )
36
+
37
+
38
+ end
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,47 @@
1
+ module RQRCode
2
+
3
+ ALPHANUMERIC = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',' ','$','%','*','+','-','.','/',':']
4
+
5
+ class QRAlphanumeric
6
+ attr_reader :mode
7
+
8
+ def initialize( data )
9
+ @mode = QRMODE[:mode_alpha_numk]
10
+
11
+ raise QRCodeArgumentError, "Not a alpha numeric uppercase string `#{data}`" unless QRAlphanumeric.valid_data?(data)
12
+
13
+ @data = data;
14
+ end
15
+
16
+
17
+ def get_length
18
+ @data.size
19
+ end
20
+
21
+ def self.valid_data? data
22
+ data.each_char do |s|
23
+ return false if ALPHANUMERIC.index(s).nil?
24
+ end
25
+ true
26
+ end
27
+
28
+
29
+ def write( buffer)
30
+ buffer.alphanumeric_encoding_start(get_length)
31
+
32
+ (@data.size).times do |i|
33
+ if i % 2 == 0
34
+ if i == (@data.size - 1)
35
+ value = ALPHANUMERIC.index(@data[i])
36
+ buffer.put( value, 6 )
37
+ else
38
+ value = (ALPHANUMERIC.index(@data[i]) * 45) + ALPHANUMERIC.index(@data[i+1])
39
+ buffer.put( value, 11 )
40
+ end
41
+ end
42
+ end
43
+
44
+
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,92 @@
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
+ class QRBitBuffer
15
+ attr_reader :buffer
16
+
17
+ PAD0 = 0xEC
18
+ PAD1 = 0x11
19
+
20
+ def initialize(version)
21
+ @version = version
22
+ @buffer = []
23
+ @length = 0
24
+ end
25
+
26
+
27
+ def get( index )
28
+ buf_index = (index / 8).floor
29
+ (( (@buffer[buf_index]).rszf(7 - index % 8)) & 1) == 1
30
+ end
31
+
32
+
33
+ def put( num, length )
34
+ ( 0...length ).each do |i|
35
+ put_bit((((num).rszf(length - i - 1)) & 1) == 1)
36
+ end
37
+ end
38
+
39
+
40
+ def get_length_in_bits
41
+ @length
42
+ end
43
+
44
+
45
+ def put_bit( bit )
46
+ buf_index = ( @length / 8 ).floor
47
+ if @buffer.size <= buf_index
48
+ @buffer << 0
49
+ end
50
+
51
+ if bit
52
+ @buffer[buf_index] |= ((0x80).rszf(@length % 8))
53
+ end
54
+
55
+ @length += 1
56
+ end
57
+
58
+ def byte_encoding_start(length)
59
+
60
+ put( QRMODE[:mode_8bit_byte], 4 )
61
+ put(length, QRUtil.get_length_in_bits(QRMODE[:mode_8bit_byte], @version))
62
+
63
+ end
64
+
65
+ def alphanumeric_encoding_start(length)
66
+
67
+ put( QRMODE[:mode_alpha_numk], 4 )
68
+ put(length, QRUtil.get_length_in_bits(QRMODE[:mode_alpha_numk], @version))
69
+
70
+ end
71
+
72
+ def pad_until(prefered_size)
73
+ # Align on byte
74
+ while get_length_in_bits % 8 != 0
75
+ put_bit( false )
76
+ end
77
+
78
+ # Pad with padding code words
79
+ while get_length_in_bits < prefered_size
80
+ put( QRBitBuffer::PAD0, 8 )
81
+ put( QRBitBuffer::PAD1, 8 ) if get_length_in_bits < prefered_size
82
+ end
83
+ end
84
+
85
+ def end_of_message(max_data_bits)
86
+ put( 0, 4 ) unless get_length_in_bits+4 > max_data_bits
87
+ end
88
+
89
+
90
+ end
91
+
92
+ end
@@ -0,0 +1,464 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #--
4
+ # Copyright 2008 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 #:nodoc:
13
+
14
+ QRMODE = {
15
+ :mode_number => 1 << 0,
16
+ :mode_alpha_numk => 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
+ QRMASKCOMPUTATIONS = [
40
+ Proc.new { |i,j| (i + j) % 2 == 0 },
41
+ Proc.new { |i,j| i % 2 == 0 },
42
+ Proc.new { |i,j| j % 3 == 0 },
43
+ Proc.new { |i,j| (i + j) % 3 == 0 },
44
+ Proc.new { |i,j| ((i / 2).floor + (j / 3).floor) % 2 == 0 },
45
+ Proc.new { |i,j| (i * j) % 2 + (i * j) % 3 == 0 },
46
+ Proc.new { |i,j| ((i * j) % 2 + (i * j) % 3) % 2 == 0 },
47
+ Proc.new { |i,j| ((i * j) % 3 + (i + j) % 2) % 2 == 0 },
48
+ ]
49
+
50
+
51
+
52
+ QRPOSITIONPATTERNLENGTH = (7 + 1) * 2 + 1
53
+ QRFORMATINFOLENGTH = 15
54
+
55
+ #http://www.denso-wave.com/qrcode/vertable1-e.html
56
+ QRMAXDIGITS = {
57
+ :l => {:mode_number => [41, 77, 127, 187, 255, 322, 370, 461, 552, 652],
58
+ :mode_alpha_numk => [25, 47, 77, 114, 154, 195, 224, 279, 335, 395],
59
+ :mode_8bit_byte => [17, 32, 53, 78, 106, 134, 154, 192, 230, 271, 321, 367, 425, 458, 520, 586, 644, 718, 792, 858],
60
+ :mode_kanji => [10, 20, 32, 48, 65, 82, 95, 118, 141, 167]},
61
+ :m => {:mode_number => [34, 63, 101, 149, 202, 255, 293, 365, 432, 513],
62
+ :mode_alpha_numk => [20, 38, 61, 90, 122, 154, 178, 221, 262, 311],
63
+ :mode_8bit_byte => [14, 26, 42, 62, 84, 106, 122, 152, 180, 213, 251, 287, 331, 362, 412, 450, 504, 560, 624, 666],
64
+ :mode_kanji => [ 8, 16, 26, 38, 54, 65, 75, 93, 111, 131]},
65
+ :q => {:mode_number => [27, 48, 77, 111, 144, 178, 207, 259, 312, 364],
66
+ :mode_alpha_numk => [16, 29, 47, 67, 87, 108, 125, 157, 189, 221],
67
+ :mode_8bit_byte => [11, 20, 32, 46, 60, 74, 86, 108, 130, 151, 177, 203, 241, 258, 292, 22, 364, 394, 442, 482],
68
+ :mode_kanji => [ 7, 12, 20, 28, 37, 45, 53, 66, 80, 93]},
69
+ :h => {:mode_number => [17, 34, 58, 82, 106, 139, 154, 202, 235, 288],
70
+ :mode_alpha_numk => [10, 20, 35, 50, 64, 84, 93, 122, 143, 174],
71
+ :mode_8bit_byte => [ 7, 14, 24, 34, 44, 58, 64, 84, 98, 119, 137, 155, 177, 194, 220, 250, 280, 310, 338, 382],
72
+ :mode_kanji => [ 4, 8, 15, 21, 27, 36, 39, 52, 60, 74]},
73
+ }
74
+
75
+
76
+ # StandardErrors
77
+
78
+ class QRCodeArgumentError < ArgumentError; end
79
+ class QRCodeRunTimeError < RuntimeError; end
80
+
81
+ # == Creation
82
+ #
83
+ # QRCode objects expect only one required constructor parameter
84
+ # and an optional hash of any other. Here's a few examples:
85
+ #
86
+ # qr = RQRCode::QRCode.new('hello world')
87
+ # qr = RQRCode::QRCode.new('hello world', :size => 1, :level => :m )
88
+ #
89
+
90
+ class QRCode
91
+ attr_reader :modules, :module_count, :version, :error_correction_level
92
+
93
+ # Expects a string to be parsed in, other args are optional
94
+ #
95
+ # # string - the string you wish to encode
96
+ # # size - the size of the qrcode (default 4)
97
+ # # level - the error correction level, can be:
98
+ # * Level :l 7% of code can be restored
99
+ # * Level :m 15% of code can be restored
100
+ # * Level :q 25% of code can be restored
101
+ # * Level :h 30% of code can be restored (default :h)
102
+ #
103
+ # qr = RQRCode::QRCode.new('hello world', :size => 1, :level => :m )
104
+ #
105
+
106
+ def initialize( string, *args )
107
+ if !string.is_a? String
108
+ raise QRCodeArgumentError, "The passed data is #{string.class}, not String"
109
+ end
110
+
111
+ options = args.extract_options!
112
+ level = (options[:level] || :h).to_sym
113
+
114
+ if !QRERRORCORRECTLEVEL.has_key?(level)
115
+ raise QRCodeArgumentError, "Unknown error correction level `#{level.inspect}`"
116
+ end
117
+ @data = string
118
+ max_size_array = QRAlphanumeric.valid_data?( @data ) ? QRMAXDIGITS[level][:mode_alpha_numk] : QRMAXDIGITS[level][:mode_8bit_byte]
119
+ size = options[:size] || smallest_size_for(string, max_size_array)
120
+
121
+
122
+
123
+ @error_correct_level = QRERRORCORRECTLEVEL[level]
124
+ @version = size
125
+ @module_count = @version * 4 + QRPOSITIONPATTERNLENGTH
126
+ @modules = Array.new( @module_count )
127
+ @data_list = QRAlphanumeric.valid_data?( @data ) ? QRAlphanumeric.new( @data ) : QR8bitByte.new( @data )
128
+ @data_cache = nil
129
+ self.make
130
+ end
131
+
132
+ # <tt>is_dark</tt> is called with a +col+ and +row+ parameter. This will
133
+ # return true or false based on whether that coordinate exists in the
134
+ # matrix returned. It would normally be called while iterating through
135
+ # <tt>modules</tt>. A simple example would be:
136
+ #
137
+ # instance.is_dark( 10, 10 ) => true
138
+ #
139
+
140
+ def is_dark( row, col )
141
+ if !row.between?(0, @module_count - 1) || !col.between?(0, @module_count - 1)
142
+ raise QRCodeRunTimeError, "Invalid row/column pair: #{row}, #{col}"
143
+ end
144
+ @modules[row][col]
145
+ end
146
+
147
+ alias dark? is_dark
148
+
149
+ # This is a public method that returns the QR Code you have
150
+ # generated as a string. It will not be able to be read
151
+ # in this format by a QR Code reader, but will give you an
152
+ # idea if the final outout. It takes two optional args
153
+ # +:true+ and +:false+ which are there for you to choose
154
+ # how the output looks. Here's an example of it's use:
155
+ #
156
+ # instance.to_s =>
157
+ # xxxxxxx x x x x x xx xxxxxxx
158
+ # x x xxx xxxxxx xxx x x
159
+ # x xxx x xxxxx x xx x xxx x
160
+ #
161
+ # instance._to_s( :true => 'E', :false => 'Q') =>
162
+ # EEEEEEEQEQQEQEQQQEQEQQEEQQEEEEEEE
163
+ # EQQQQQEQQEEEQQEEEEEEQEEEQQEQQQQQE
164
+ # EQEEEQEQQEEEEEQEQQQQQQQEEQEQEEEQE
165
+ #
166
+
167
+ def to_s( *args )
168
+ options = args.extract_options!
169
+ row = options[:true] || 'x'
170
+ col = options[:false] || ' '
171
+
172
+ res = []
173
+
174
+ @modules.each_index do |c|
175
+ tmp = []
176
+ @modules.each_index do |r|
177
+ if is_dark(c,r)
178
+ tmp << row
179
+ else
180
+ tmp << col
181
+ end
182
+ end
183
+ res << tmp.join
184
+ end
185
+ res.join("\n")
186
+ end
187
+
188
+ protected
189
+
190
+ def make #:nodoc:
191
+ prepare_common_patterns
192
+ make_impl( false, get_best_mask_pattern )
193
+ end
194
+
195
+ private
196
+
197
+ def prepare_common_patterns
198
+ @modules.map! { |row| Array.new(@module_count) }
199
+
200
+ place_position_probe_pattern(0, 0)
201
+ place_position_probe_pattern(@module_count - 7, 0)
202
+ place_position_probe_pattern(0, @module_count - 7)
203
+ place_position_adjust_pattern
204
+ place_timing_pattern
205
+
206
+ @common_patterns = @modules.map(&:clone)
207
+ end
208
+
209
+ def make_impl( test, mask_pattern ) #:nodoc:
210
+ @modules = @common_patterns.map(&:clone)
211
+
212
+ place_format_info(test, mask_pattern)
213
+ place_version_info(test) if @version >= 7
214
+
215
+ if @data_cache.nil?
216
+ @data_cache = QRCode.create_data(
217
+ @version, @error_correct_level, @data_list
218
+ )
219
+ end
220
+
221
+ map_data( @data_cache, mask_pattern )
222
+ end
223
+
224
+
225
+ def place_position_probe_pattern( row, col ) #:nodoc:
226
+ (-1..7).each do |r|
227
+ next if !(row + r).between?(0, @module_count - 1)
228
+
229
+ (-1..7).each do |c|
230
+ next if !(col + c).between?(0, @module_count - 1)
231
+
232
+ is_vert_line = (r.between?(0, 6) && (c == 0 || c == 6))
233
+ is_horiz_line = (c.between?(0, 6) && (r == 0 || r == 6))
234
+ is_square = r.between?(2,4) && c.between?(2, 4)
235
+
236
+ is_part_of_probe = is_vert_line || is_horiz_line || is_square
237
+ @modules[row + r][col + c] = is_part_of_probe
238
+ end
239
+ end
240
+ end
241
+
242
+
243
+ def get_best_mask_pattern #:nodoc:
244
+ min_lost_point = 0
245
+ pattern = 0
246
+
247
+ ( 0...8 ).each do |i|
248
+ make_impl( true, i )
249
+ lost_point = QRUtil.get_lost_points(self.modules)
250
+
251
+ if i == 0 || min_lost_point > lost_point
252
+ min_lost_point = lost_point
253
+ pattern = i
254
+ end
255
+ end
256
+ pattern
257
+ end
258
+
259
+
260
+ def place_timing_pattern #:nodoc:
261
+ ( 8...@module_count - 8 ).each do |i|
262
+ @modules[i][6] = @modules[6][i] = i % 2 == 0
263
+ end
264
+ end
265
+
266
+
267
+ def place_position_adjust_pattern #:nodoc:
268
+ positions = QRUtil.get_pattern_positions(@version)
269
+
270
+ positions.each do |row|
271
+ positions.each do |col|
272
+ next unless @modules[row][col].nil?
273
+
274
+ ( -2..2 ).each do |r|
275
+ ( -2..2 ).each do |c|
276
+ is_part_of_pattern = (r.abs == 2 || c.abs == 2 || ( r == 0 && c == 0 ))
277
+ @modules[row + r][col + c] = is_part_of_pattern
278
+ end
279
+ end
280
+ end
281
+ end
282
+ end
283
+
284
+
285
+ def place_version_info(test) #:nodoc:
286
+ bits = QRUtil.get_bch_version(@version)
287
+
288
+ ( 0...18 ).each do |i|
289
+ mod = ( !test && ( (bits >> i) & 1) == 1 )
290
+ @modules[ (i / 3).floor ][ i % 3 + @module_count - 8 - 3 ] = mod
291
+ @modules[ i % 3 + @module_count - 8 - 3 ][ (i / 3).floor ] = mod
292
+ end
293
+ end
294
+
295
+
296
+ def place_format_info(test, mask_pattern) #:nodoc:
297
+ data = (@error_correct_level << 3 | mask_pattern)
298
+ bits = QRUtil.get_bch_format_info(data)
299
+
300
+ QRFORMATINFOLENGTH.times do |i|
301
+ mod = (!test && ( (bits >> i) & 1) == 1)
302
+
303
+ # vertical
304
+ if i < 6
305
+ row = i
306
+ elsif i < 8
307
+ row = i + 1
308
+ else
309
+ row = @module_count - 15 + i
310
+ end
311
+ @modules[row][8] = mod
312
+
313
+ # horizontal
314
+ if i < 8
315
+ col = @module_count - i - 1
316
+ elsif i < 9
317
+ col = 15 - i - 1 + 1
318
+ else
319
+ col = 15 - i - 1
320
+ end
321
+ @modules[8][col] = mod
322
+ end
323
+
324
+ # fixed module
325
+ @modules[ @module_count - 8 ][8] = !test
326
+ end
327
+
328
+
329
+ def map_data( data, mask_pattern ) #:nodoc:
330
+ inc = -1
331
+ row = @module_count - 1
332
+ bit_index = 7
333
+ byte_index = 0
334
+
335
+ ( @module_count - 1 ).step( 1, -2 ) do |col|
336
+ col = col - 1 if col <= 6
337
+
338
+ while true do
339
+ ( 0...2 ).each do |c|
340
+
341
+ if @modules[row][ col - c ].nil?
342
+ dark = false
343
+ if byte_index < data.size && !data[byte_index].nil?
344
+ dark = (( (data[byte_index]).rszf( bit_index ) & 1) == 1 )
345
+ end
346
+ mask = QRUtil.get_mask( mask_pattern, row, col - c )
347
+ dark = !dark if mask
348
+ @modules[row][ col - c ] = dark
349
+ bit_index -= 1
350
+
351
+ if bit_index == -1
352
+ byte_index += 1
353
+ bit_index = 7
354
+ end
355
+ end
356
+ end
357
+
358
+ row += inc
359
+
360
+ if row < 0 || @module_count <= row
361
+ row -= inc
362
+ inc = -inc
363
+ break
364
+ end
365
+ end
366
+ end
367
+ end
368
+
369
+ def smallest_size_for(string, max_size_array) #:nodoc:
370
+ l = string.length
371
+ ver = max_size_array.index{|i| i >= l}
372
+ raise QRCodeRunTimeError,"code length overflow. (#{1} digits > any version capacity)" unless ver
373
+ ver + 1
374
+ end
375
+
376
+ def QRCode.count_max_data_bits(rs_blocks)
377
+ max_data_bytes = rs_blocks.reduce(0) do |sum, rs_block|
378
+ sum + rs_block.data_count
379
+ end
380
+
381
+ return max_data_bytes * 8
382
+ end
383
+
384
+ def QRCode.create_data(version, error_correct_level, data_list) #:nodoc:
385
+ rs_blocks = QRRSBlock.get_rs_blocks(version, error_correct_level)
386
+ max_data_bits = QRCode.count_max_data_bits(rs_blocks)
387
+ buffer = QRBitBuffer.new(version)
388
+
389
+ data_list.write(buffer)
390
+ buffer.end_of_message(max_data_bits)
391
+
392
+ if buffer.get_length_in_bits > max_data_bits
393
+ raise QRCodeRunTimeError, "code length overflow. (#{buffer.get_length_in_bits}>#{max_data_bits})"
394
+ end
395
+
396
+ buffer.pad_until(max_data_bits)
397
+
398
+ QRCode.create_bytes( buffer, rs_blocks )
399
+ end
400
+
401
+
402
+ def QRCode.create_bytes( buffer, rs_blocks ) #:nodoc:
403
+ offset = 0
404
+ max_dc_count = 0
405
+ max_ec_count = 0
406
+ dcdata = Array.new( rs_blocks.size )
407
+ ecdata = Array.new( rs_blocks.size )
408
+
409
+ rs_blocks.each_with_index do |rs_block, r|
410
+ dc_count = rs_block.data_count
411
+ ec_count = rs_block.total_count - dc_count
412
+ max_dc_count = [ max_dc_count, dc_count ].max
413
+ max_ec_count = [ max_ec_count, ec_count ].max
414
+
415
+ dcdata_block = Array.new(dc_count)
416
+ dcdata_block.size.times do |i|
417
+ dcdata_block[i] = 0xff & buffer.buffer[ i + offset ]
418
+ end
419
+ dcdata[r] = dcdata_block
420
+
421
+ offset = offset + dc_count
422
+ rs_poly = QRUtil.get_error_correct_polynomial( ec_count )
423
+ raw_poly = QRPolynomial.new( dcdata[r], rs_poly.get_length - 1 )
424
+ mod_poly = raw_poly.mod( rs_poly )
425
+
426
+ ecdata_block = Array.new(rs_poly.get_length - 1)
427
+ ecdata_block.size.times do |i|
428
+ mod_index = i + mod_poly.get_length - ecdata_block.size
429
+ ecdata_block[i] = mod_index >= 0 ? mod_poly.get( mod_index ) : 0
430
+ end
431
+ ecdata[r] = ecdata_block
432
+ end
433
+
434
+ total_code_count = rs_blocks.reduce(0) do |sum, rs_block|
435
+ sum + rs_block.total_count
436
+ end
437
+
438
+ data = Array.new( total_code_count )
439
+ index = 0
440
+
441
+ max_dc_count.times do |i|
442
+ rs_blocks.size.times do |r|
443
+ if i < dcdata[r].size
444
+ data[index] = dcdata[r][i]
445
+ index += 1
446
+ end
447
+ end
448
+ end
449
+
450
+ max_ec_count.times do |i|
451
+ rs_blocks.size.times do |r|
452
+ if i < ecdata[r].size
453
+ data[index] = ecdata[r][i]
454
+ index += 1
455
+ end
456
+ end
457
+ end
458
+
459
+ data
460
+ end
461
+
462
+ end
463
+
464
+ end