From a5045f4655d37d84eec15b5d7cae14bca1944562 Mon Sep 17 00:00:00 2001 From: Gioele Barabucci Date: Sat, 13 Aug 2011 12:01:36 +0200 Subject: [PATCH 01/20] Packaging files should be ignored by git --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..f35d6a2d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/pkg/ +/*.gemspec From 85679c2e0a71040ab055f6556e87e579c3f6b7bb Mon Sep 17 00:00:00 2001 From: Gioele Barabucci Date: Sat, 13 Aug 2011 11:51:37 +0200 Subject: [PATCH 02/20] The input string is required parameter --- lib/rqrcode/qrcode/qr_code.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/rqrcode/qrcode/qr_code.rb b/lib/rqrcode/qrcode/qr_code.rb index 50a306dd..d6868703 100644 --- a/lib/rqrcode/qrcode/qr_code.rb +++ b/lib/rqrcode/qrcode/qr_code.rb @@ -69,15 +69,15 @@ class QRCode # qr = RQRCode::QRCode.new('hello world', :size => 1, :level => :m ) # - def initialize( *args ) - raise QRCodeArgumentError unless args.first.kind_of?( String ) + def initialize( string, *args ) + raise QRCodeArgumentError unless string.is_a? String - @data = args.shift options = args.extract_options! level = options[:level] || :h raise QRCodeArgumentError unless %w(l m q h).include?(level.to_s) + @data = string @error_correct_level = QRERRORCORRECTLEVEL[ level.to_sym ] @type_number = options[:size] || 4 @module_count = @type_number * 4 + 17 From 6e3da6d7d9200891cd27f04a9663cedcafdd6ed4 Mon Sep 17 00:00:00 2001 From: Gioele Barabucci Date: Sat, 13 Aug 2011 11:53:51 +0200 Subject: [PATCH 03/20] Use the correction levels in QRERRORCORRECTLEVEL --- lib/rqrcode/qrcode/qr_code.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rqrcode/qrcode/qr_code.rb b/lib/rqrcode/qrcode/qr_code.rb index d6868703..75eb045d 100644 --- a/lib/rqrcode/qrcode/qr_code.rb +++ b/lib/rqrcode/qrcode/qr_code.rb @@ -75,7 +75,7 @@ def initialize( string, *args ) options = args.extract_options! level = options[:level] || :h - raise QRCodeArgumentError unless %w(l m q h).include?(level.to_s) + raise QRCodeArgumentError unless QRERRORCORRECTLEVEL.has_key?(level) @data = string @error_correct_level = QRERRORCORRECTLEVEL[ level.to_sym ] From cc08a1758954ac51cdc4d3e0c0af974c50216342 Mon Sep 17 00:00:00 2001 From: Gioele Barabucci Date: Sat, 13 Aug 2011 11:58:10 +0200 Subject: [PATCH 04/20] Better error reporting --- lib/rqrcode/qrcode/qr_code.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/rqrcode/qrcode/qr_code.rb b/lib/rqrcode/qrcode/qr_code.rb index 75eb045d..c063c2d2 100644 --- a/lib/rqrcode/qrcode/qr_code.rb +++ b/lib/rqrcode/qrcode/qr_code.rb @@ -70,12 +70,16 @@ class QRCode # def initialize( string, *args ) - raise QRCodeArgumentError unless string.is_a? String + if !string.is_a? String + raise QRCodeArgumentError, "The passed data is #{string.class}, not String" + end options = args.extract_options! level = options[:level] || :h - raise QRCodeArgumentError unless QRERRORCORRECTLEVEL.has_key?(level) + if !QRERRORCORRECTLEVEL.has_key?(level) + raise QRCodeArgumentError, "Unknown error correction level `#{level.inspect}`" + end @data = string @error_correct_level = QRERRORCORRECTLEVEL[ level.to_sym ] @@ -98,7 +102,7 @@ def initialize( string, *args ) def is_dark( row, col ) if row < 0 || @module_count <= row || col < 0 || @module_count <= col - raise QRCodeRunTimeError, "#{row},#{col}" + raise QRCodeRunTimeError, "Invalid row/column pair: #{row}, #{col}" end @modules[row][col] end From 1216a924d18616e82a51d8b1e8bb88812b336206 Mon Sep 17 00:00:00 2001 From: Gioele Barabucci Date: Sat, 13 Aug 2011 12:00:46 +0200 Subject: [PATCH 05/20] Make sure `level` is a Symbol --- lib/rqrcode/qrcode/qr_code.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/rqrcode/qrcode/qr_code.rb b/lib/rqrcode/qrcode/qr_code.rb index c063c2d2..f14e8b33 100644 --- a/lib/rqrcode/qrcode/qr_code.rb +++ b/lib/rqrcode/qrcode/qr_code.rb @@ -75,14 +75,14 @@ def initialize( string, *args ) end options = args.extract_options! - level = options[:level] || :h + level = (options[:level] || :h).to_sym if !QRERRORCORRECTLEVEL.has_key?(level) raise QRCodeArgumentError, "Unknown error correction level `#{level.inspect}`" end @data = string - @error_correct_level = QRERRORCORRECTLEVEL[ level.to_sym ] + @error_correct_level = QRERRORCORRECTLEVEL[level] @type_number = options[:size] || 4 @module_count = @type_number * 4 + 17 @modules = Array.new( @module_count ) From 0fa9eab19e4398edc29133f7f5f9cff4f09631a6 Mon Sep 17 00:00:00 2001 From: Gioele Barabucci Date: Sat, 13 Aug 2011 12:05:22 +0200 Subject: [PATCH 06/20] Move size to the options extraction section --- lib/rqrcode/qrcode/qr_code.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/rqrcode/qrcode/qr_code.rb b/lib/rqrcode/qrcode/qr_code.rb index f14e8b33..50f314d8 100644 --- a/lib/rqrcode/qrcode/qr_code.rb +++ b/lib/rqrcode/qrcode/qr_code.rb @@ -76,6 +76,7 @@ def initialize( string, *args ) options = args.extract_options! level = (options[:level] || :h).to_sym + size = options[:size] || 4 if !QRERRORCORRECTLEVEL.has_key?(level) raise QRCodeArgumentError, "Unknown error correction level `#{level.inspect}`" @@ -83,7 +84,7 @@ def initialize( string, *args ) @data = string @error_correct_level = QRERRORCORRECTLEVEL[level] - @type_number = options[:size] || 4 + @type_number = size @module_count = @type_number * 4 + 17 @modules = Array.new( @module_count ) @data_list = QR8bitByte.new( @data ) From 65cebadb16b438a3c0bde42a61d5fc8b2c2f4755 Mon Sep 17 00:00:00 2001 From: Gioele Barabucci Date: Sat, 13 Aug 2011 12:59:25 +0200 Subject: [PATCH 07/20] Separate function for counting max data bits --- lib/rqrcode/qrcode/qr_code.rb | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/rqrcode/qrcode/qr_code.rb b/lib/rqrcode/qrcode/qr_code.rb index 50f314d8..ba20de2f 100644 --- a/lib/rqrcode/qrcode/qr_code.rb +++ b/lib/rqrcode/qrcode/qr_code.rb @@ -327,6 +327,14 @@ def map_data( data, mask_pattern ) #:nodoc: end end + def QRCode.count_max_data_bits(rs_blocks) + max_data_bytes = rs_blocks.reduce(0) do |sum, rs_block| + sum + rs_block.data_count + end + + return max_data_bytes * 8 + end + def QRCode.create_data( type_number, error_correct_level, data_list ) #:nodoc: rs_blocks = QRRSBlock.get_rs_blocks( type_number, error_correct_level ) buffer = QRBitBuffer.new @@ -338,17 +346,14 @@ def QRCode.create_data( type_number, error_correct_level, data_list ) #:nodoc: ) data.write( buffer ) - total_data_count = 0 - ( 0...rs_blocks.size ).each do |i| - total_data_count = total_data_count + rs_blocks[i].data_count - end + max_data_bits = QRCode.count_max_data_bits(rs_blocks) - if buffer.get_length_in_bits > total_data_count * 8 + if buffer.get_length_in_bits > max_data_bits raise QRCodeRunTimeError, - "code length overflow. (#{buffer.get_length_in_bits}>#{total_data_count})" + "code length overflow. (#{buffer.get_length_in_bits}>#{max_data_bits})" end - if buffer.get_length_in_bits + 4 <= total_data_count * 8 + if buffer.get_length_in_bits + 4 <= max_data_bits buffer.put( 0, 4 ) end @@ -357,9 +362,9 @@ def QRCode.create_data( type_number, error_correct_level, data_list ) #:nodoc: end while true - break if buffer.get_length_in_bits >= total_data_count * 8 + break if buffer.get_length_in_bits >= max_data_bits buffer.put( QRCode::PAD0, 8 ) - break if buffer.get_length_in_bits >= total_data_count * 8 + break if buffer.get_length_in_bits >= max_data_bits buffer.put( QRCode::PAD1, 8 ) end From fad9406f0ff06b6e822aa947f2a84c39e311169e Mon Sep 17 00:00:00 2001 From: Gioele Barabucci Date: Sat, 13 Aug 2011 13:10:07 +0200 Subject: [PATCH 08/20] Use faster Ruby native counters instead of ranges --- lib/rqrcode/qrcode/qr_code.rb | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/rqrcode/qrcode/qr_code.rb b/lib/rqrcode/qrcode/qr_code.rb index ba20de2f..cb4df69b 100644 --- a/lib/rqrcode/qrcode/qr_code.rb +++ b/lib/rqrcode/qrcode/qr_code.rb @@ -379,9 +379,9 @@ def QRCode.create_bytes( buffer, rs_blocks ) #:nodoc: dcdata = Array.new( rs_blocks.size ) ecdata = Array.new( rs_blocks.size ) - ( 0...rs_blocks.size ).each do |r| - dc_count = rs_blocks[r].data_count - ec_count = rs_blocks[r].total_count - dc_count + rs_blocks.each_with_index do |rs_block, r| + dc_count = rs_block.data_count + ec_count = rs_block.total_count - dc_count max_dc_count = [ max_dc_count, dc_count ].max max_ec_count = [ max_ec_count, ec_count ].max dcdata[r] = Array.new( dc_count ) @@ -401,16 +401,15 @@ def QRCode.create_bytes( buffer, rs_blocks ) #:nodoc: end end - total_code_count = 0 - ( 0...rs_blocks.size ).each do |i| - total_code_count = total_code_count + rs_blocks[i].total_count + total_code_count = rs_blocks.reduce(0) do |sum, rs_block| + sum + rs_block.total_count end data = Array.new( total_code_count ) index = 0 - ( 0...max_dc_count ).each do |i| - ( 0...rs_blocks.size ).each do |r| + max_dc_count.times do |i| + rs_blocks.size.times do |r| if i < dcdata[r].size index += 1 data[index-1] = dcdata[r][i] @@ -418,8 +417,8 @@ def QRCode.create_bytes( buffer, rs_blocks ) #:nodoc: end end - ( 0...max_ec_count ).each do |i| - ( 0...rs_blocks.size ).each do |r| + max_ec_count.times do |i| + rs_blocks.size.times do |r| if i < ecdata[r].size index += 1 data[index-1] = ecdata[r][i] From a19cea7d4a2d99fad21295f584cb4e3682571462 Mon Sep 17 00:00:00 2001 From: Gioele Barabucci Date: Sat, 13 Aug 2011 13:12:46 +0200 Subject: [PATCH 09/20] Do not sum only to subtract --- lib/rqrcode/qrcode/qr_code.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/rqrcode/qrcode/qr_code.rb b/lib/rqrcode/qrcode/qr_code.rb index cb4df69b..e2f2d0f5 100644 --- a/lib/rqrcode/qrcode/qr_code.rb +++ b/lib/rqrcode/qrcode/qr_code.rb @@ -411,8 +411,8 @@ def QRCode.create_bytes( buffer, rs_blocks ) #:nodoc: max_dc_count.times do |i| rs_blocks.size.times do |r| if i < dcdata[r].size + data[index] = dcdata[r][i] index += 1 - data[index-1] = dcdata[r][i] end end end @@ -420,8 +420,8 @@ def QRCode.create_bytes( buffer, rs_blocks ) #:nodoc: max_ec_count.times do |i| rs_blocks.size.times do |r| if i < ecdata[r].size + data[index] = ecdata[r][i] index += 1 - data[index-1] = ecdata[r][i] end end end From 2d012c847ca5d340c98bb3b27a2bfebe6a3e40b5 Mon Sep 17 00:00:00 2001 From: Gioele Barabucci Date: Sat, 13 Aug 2011 13:20:49 +0200 Subject: [PATCH 10/20] Use each `dcdata` and `ecdata` array entry only once --- lib/rqrcode/qrcode/qr_code.rb | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/rqrcode/qrcode/qr_code.rb b/lib/rqrcode/qrcode/qr_code.rb index e2f2d0f5..06329699 100644 --- a/lib/rqrcode/qrcode/qr_code.rb +++ b/lib/rqrcode/qrcode/qr_code.rb @@ -384,21 +384,24 @@ def QRCode.create_bytes( buffer, rs_blocks ) #:nodoc: ec_count = rs_block.total_count - dc_count max_dc_count = [ max_dc_count, dc_count ].max max_ec_count = [ max_ec_count, ec_count ].max - dcdata[r] = Array.new( dc_count ) - ( 0...dcdata[r].size ).each do |i| - dcdata[r][i] = 0xff & buffer.buffer[ i + offset ] + dcdata_block = Array.new(dc_count) + dcdata_block.size.times do |i| + dcdata_block[i] = 0xff & buffer.buffer[ i + offset ] end + dcdata[r] = dcdata_block offset = offset + dc_count rs_poly = QRUtil.get_error_correct_polynomial( ec_count ) raw_poly = QRPolynomial.new( dcdata[r], rs_poly.get_length - 1 ) mod_poly = raw_poly.mod( rs_poly ) - ecdata[r] = Array.new( rs_poly.get_length - 1 ) - ( 0...ecdata[r].size ).each do |i| - mod_index = i + mod_poly.get_length - ecdata[r].size - ecdata[r][i] = mod_index >= 0 ? mod_poly.get( mod_index ) : 0 + + ecdata_block = Array.new(rs_poly.get_length - 1) + ecdata_block.size.times do |i| + mod_index = i + mod_poly.get_length - ecdata_block.size + ecdata_block[i] = mod_index >= 0 ? mod_poly.get( mod_index ) : 0 end + ecdata[r] = ecdata_block end total_code_count = rs_blocks.reduce(0) do |sum, rs_block| From 293580ba69953b684e764986320eb92408445093 Mon Sep 17 00:00:00 2001 From: Gioele Barabucci Date: Sat, 13 Aug 2011 15:06:49 +0200 Subject: [PATCH 11/20] Use pre-made Procs instead of long case/when construct Code such as case mask_pattern when QRMASKPATTERN[:pattern000] (i + j) % 2 == 0 when QRMASKPATTERN[:pattern001] i % 2 == 0 when QRMASKPATTERN[:pattern010] j % 3 == 0 is very slow because it requires an `Hash#[]` lookup and a `Kernel#===` call for every branch of the `case` construct, 3.5 * 2 function calls on average. We exploit the fact that `mask_pattern` is a Fixnum and pre-populate an array of possible computations. This takes exactly one `Array#[]` lookup and `Proc#call` execution per mask pattern. --- lib/rqrcode/qrcode/qr_code.rb | 11 +++++++++++ lib/rqrcode/qrcode/qr_util.rb | 21 +++------------------ 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/lib/rqrcode/qrcode/qr_code.rb b/lib/rqrcode/qrcode/qr_code.rb index 06329699..d3f7d991 100644 --- a/lib/rqrcode/qrcode/qr_code.rb +++ b/lib/rqrcode/qrcode/qr_code.rb @@ -36,6 +36,17 @@ module RQRCode #:nodoc: :pattern111 => 7 } + QRMASKCOMPUTATIONS = [ + Proc.new { |i,j| (i + j) % 2 == 0 }, + Proc.new { |i,j| i % 2 == 0 }, + Proc.new { |i,j| j % 3 == 0 }, + Proc.new { |i,j| (i + j) % 3 == 0 }, + Proc.new { |i,j| ((i / 2).floor + (j / 3).floor) % 2 == 0 }, + Proc.new { |i,j| (i * j) % 2 + (i * j) % 3 == 0 }, + Proc.new { |i,j| ((i * j) % 2 + (i * j) % 3) % 2 == 0 }, + Proc.new { |i,j| ((i * j) % 3 + (i + j) % 2) % 2 == 0 }, + ] + # StandardErrors class QRCodeArgumentError < ArgumentError; end diff --git a/lib/rqrcode/qrcode/qr_util.rb b/lib/rqrcode/qrcode/qr_util.rb index 17dc61e1..5eb3ab1d 100644 --- a/lib/rqrcode/qrcode/qr_util.rb +++ b/lib/rqrcode/qrcode/qr_util.rb @@ -98,26 +98,11 @@ def QRUtil.get_pattern_position( type_number ) def QRUtil.get_mask( mask_pattern, i, j ) - case mask_pattern - when QRMASKPATTERN[:pattern000] - (i + j) % 2 == 0 - when QRMASKPATTERN[:pattern001] - i % 2 == 0 - when QRMASKPATTERN[:pattern010] - j % 3 == 0 - when QRMASKPATTERN[:pattern011] - (i + j) % 3 == 0 - when QRMASKPATTERN[:pattern100] - ((i / 2).floor + (j / 3).floor ) % 2 == 0 - when QRMASKPATTERN[:pattern101] - (i * j) % 2 + (i * j) % 3 == 0 - when QRMASKPATTERN[:pattern110] - ( (i * j) % 2 + (i * j) % 3) % 2 == 0 - when QRMASKPATTERN[:pattern111] - ( (i * j) % 3 + (i + j) % 2) % 2 == 0 - else + if mask_pattern > QRMASKCOMPUTATIONS.size raise QRCodeRunTimeError, "bad mask_pattern: #{mask_pattern}" end + + return QRMASKCOMPUTATIONS[mask_pattern].call(i, j) end From 5eabc76e22249a762fb1ce1b8ec634dbda6edab4 Mon Sep 17 00:00:00 2001 From: Gioele Barabucci Date: Sat, 13 Aug 2011 15:40:55 +0200 Subject: [PATCH 12/20] Use `QRCode#modules` directly instead of `is_dark` --- lib/rqrcode/qrcode/qr_util.rb | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/lib/rqrcode/qrcode/qr_util.rb b/lib/rqrcode/qrcode/qr_util.rb index 5eb3ab1d..be0cac4c 100644 --- a/lib/rqrcode/qrcode/qr_util.rb +++ b/lib/rqrcode/qrcode/qr_util.rb @@ -161,6 +161,7 @@ def QRUtil.get_length_in_bits( mode, type ) def QRUtil.get_lost_point( qr_code ) + modules = qr_code.modules module_count = qr_code.module_count lost_point = 0 @@ -168,7 +169,7 @@ def QRUtil.get_lost_point( qr_code ) ( 0...module_count ).each do |row| ( 0...module_count ).each do |col| same_count = 0 - dark = qr_code.is_dark( row, col ) + dark = modules[row][col] ( -1..1 ).each do |r| next if row + r < 0 || module_count <= row + r @@ -176,7 +177,7 @@ def QRUtil.get_lost_point( qr_code ) ( -1..1 ).each do |c| next if col + c < 0 || module_count <= col + c next if r == 0 && c == 0 - if dark == qr_code.is_dark( row + r, col + c ) + if dark == modules[row + r][col + c] same_count += 1 end end @@ -192,10 +193,10 @@ def QRUtil.get_lost_point( qr_code ) ( 0...( module_count - 1 ) ).each do |row| ( 0...( module_count - 1 ) ).each do |col| count = 0 - count = count + 1 if qr_code.is_dark( row, col ) - count = count + 1 if qr_code.is_dark( row + 1, col ) - count = count + 1 if qr_code.is_dark( row, col + 1 ) - count = count + 1 if qr_code.is_dark( row + 1, col + 1 ) + count = count + 1 if modules[row][col] + count = count + 1 if modules[row + 1][col] + count = count + 1 if modules[row][col + 1] + count = count + 1 if modules[row + 1][col + 1] lost_point = lost_point + 3 if (count == 0 || count == 4) end end @@ -203,7 +204,13 @@ def QRUtil.get_lost_point( qr_code ) # level 3 ( 0...module_count ).each do |row| ( 0...( module_count - 6 ) ).each do |col| - 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 ) + if modules[row][col] && + !modules[row][col + 1] && + modules[row][col + 2] && + modules[row][col + 3] && + modules[row][col + 4] && + !modules[row][col + 5] && + modules[row][col + 6] lost_point = lost_point + 40 end end @@ -211,7 +218,13 @@ def QRUtil.get_lost_point( qr_code ) ( 0...module_count ).each do |col| ( 0...( module_count - 6 ) ).each do |row| - 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) + if modules[row][col] && + !modules[row + 1][col] && + modules[row + 2][col] && + modules[row + 3][col] && + modules[row + 4][col] && + !modules[row + 5][col] && + modules[row + 6][col] lost_point = lost_point + 40 end end @@ -222,7 +235,7 @@ def QRUtil.get_lost_point( qr_code ) ( 0...module_count ).each do |col| ( 0...module_count ).each do |row| - if qr_code.is_dark(row, col) + if modules[row][col] dark_count = dark_count + 1 end end From 9b7fa5314ab05c40046953bc2d1f4b164ff497c5 Mon Sep 17 00:00:00 2001 From: Gioele Barabucci Date: Sat, 13 Aug 2011 15:48:39 +0200 Subject: [PATCH 13/20] Simpler code for counting dark points --- lib/rqrcode/qrcode/qr_util.rb | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/rqrcode/qrcode/qr_util.rb b/lib/rqrcode/qrcode/qr_util.rb index be0cac4c..f29d1d71 100644 --- a/lib/rqrcode/qrcode/qr_util.rb +++ b/lib/rqrcode/qrcode/qr_util.rb @@ -231,14 +231,8 @@ def QRUtil.get_lost_point( qr_code ) end # level 4 - dark_count = 0 - - ( 0...module_count ).each do |col| - ( 0...module_count ).each do |row| - if modules[row][col] - dark_count = dark_count + 1 - end - end + dark_count = modules.reduce(0) do |sum, col| + sum + col.count(true) end ratio = (100 * dark_count / module_count / module_count - 50).abs / 5 From 84ff757b7b57e2fece07af558c44256acbcc53a4 Mon Sep 17 00:00:00 2001 From: Gioele Barabucci Date: Sat, 13 Aug 2011 16:20:03 +0200 Subject: [PATCH 14/20] Fixed calculation of ratio of darkness --- lib/rqrcode/qrcode/qr_util.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/rqrcode/qrcode/qr_util.rb b/lib/rqrcode/qrcode/qr_util.rb index f29d1d71..ac33a1f1 100644 --- a/lib/rqrcode/qrcode/qr_util.rb +++ b/lib/rqrcode/qrcode/qr_util.rb @@ -234,11 +234,11 @@ def QRUtil.get_lost_point( qr_code ) dark_count = modules.reduce(0) do |sum, col| sum + col.count(true) end + ratio = dark_count / (module_count * module_count) + ratio_delta = (100 * ratio - 50).abs / 5 + lost_point += ratio_delta * 10 - ratio = (100 * dark_count / module_count / module_count - 50).abs / 5 - lost_point = lost_point * 10 - - lost_point + return lost_point end end From ab7e5dcba0c4cfcd5187d3efd15dfe0151efa08e Mon Sep 17 00:00:00 2001 From: Gioele Barabucci Date: Sat, 13 Aug 2011 16:25:23 +0200 Subject: [PATCH 15/20] Use `DEMERIT_POINTS_*` instead of magic numbers --- lib/rqrcode/qrcode/qr_util.rb | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/rqrcode/qrcode/qr_util.rb b/lib/rqrcode/qrcode/qr_util.rb index ac33a1f1..5c2e6417 100644 --- a/lib/rqrcode/qrcode/qr_util.rb +++ b/lib/rqrcode/qrcode/qr_util.rb @@ -61,6 +61,10 @@ class QRUtil G18 = 1 << 12 | 1 << 11 | 1 << 10 | 1 << 9 | 1 << 8 | 1 << 5 | 1 << 2 | 1 << 0 G15_MASK = 1 << 14 | 1 << 12 | 1 << 10 | 1 << 4 | 1 << 1 + DEMERIT_POINTS_1 = 3 + DEMERIT_POINTS_2 = 3 + DEMERIT_POINTS_3 = 40 + DEMERIT_POINTS_4 = 10 def QRUtil.get_bch_type_info( data ) d = data << 10 @@ -184,7 +188,7 @@ def QRUtil.get_lost_point( qr_code ) end if same_count > 5 - lost_point += (3 + same_count - 5) + lost_point += (DEMERIT_POINTS_1 + same_count - 5) end end end @@ -197,7 +201,9 @@ def QRUtil.get_lost_point( qr_code ) count = count + 1 if modules[row + 1][col] count = count + 1 if modules[row][col + 1] count = count + 1 if modules[row + 1][col + 1] - lost_point = lost_point + 3 if (count == 0 || count == 4) + if (count == 0 || count == 4) + lost_point = lost_point + DEMERIT_POINTS_2 + end end end @@ -211,7 +217,7 @@ def QRUtil.get_lost_point( qr_code ) modules[row][col + 4] && !modules[row][col + 5] && modules[row][col + 6] - lost_point = lost_point + 40 + lost_point += DEMERIT_POINTS_3 end end end @@ -225,7 +231,7 @@ def QRUtil.get_lost_point( qr_code ) modules[row + 4][col] && !modules[row + 5][col] && modules[row + 6][col] - lost_point = lost_point + 40 + lost_point += DEMERIT_POINTS_3 end end end @@ -236,7 +242,7 @@ def QRUtil.get_lost_point( qr_code ) end ratio = dark_count / (module_count * module_count) ratio_delta = (100 * ratio - 50).abs / 5 - lost_point += ratio_delta * 10 + lost_point += ratio_delta * DEMERIT_POINTS_4 return lost_point end From 1c425012bb2699d403ec2b4a7750c8070b2ff083 Mon Sep 17 00:00:00 2001 From: Gioele Barabucci Date: Sat, 13 Aug 2011 16:55:13 +0200 Subject: [PATCH 16/20] Reuse row while scanning for row patterns --- lib/rqrcode/qrcode/qr_util.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/rqrcode/qrcode/qr_util.rb b/lib/rqrcode/qrcode/qr_util.rb index 5c2e6417..47c99238 100644 --- a/lib/rqrcode/qrcode/qr_util.rb +++ b/lib/rqrcode/qrcode/qr_util.rb @@ -208,15 +208,15 @@ def QRUtil.get_lost_point( qr_code ) end # level 3 - ( 0...module_count ).each do |row| - ( 0...( module_count - 6 ) ).each do |col| - if modules[row][col] && - !modules[row][col + 1] && - modules[row][col + 2] && - modules[row][col + 3] && - modules[row][col + 4] && - !modules[row][col + 5] && - modules[row][col + 6] + modules.each do |row| + (module_count - 6).times do |col_idx| + if row[col_idx] && + !row[col_idx + 1] && + row[col_idx + 2] && + row[col_idx + 3] && + row[col_idx + 4] && + !row[col_idx + 5] && + row[col_idx + 6] lost_point += DEMERIT_POINTS_3 end end From 06ccf4a5189cdb8547306d4176e1a77aeadba55d Mon Sep 17 00:00:00 2001 From: Gioele Barabucci Date: Sat, 13 Aug 2011 17:03:30 +0200 Subject: [PATCH 17/20] Use `count += 1` instead of `count = count + 1` --- lib/rqrcode/qrcode/qr_util.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/rqrcode/qrcode/qr_util.rb b/lib/rqrcode/qrcode/qr_util.rb index 47c99238..09e0dc8a 100644 --- a/lib/rqrcode/qrcode/qr_util.rb +++ b/lib/rqrcode/qrcode/qr_util.rb @@ -197,10 +197,10 @@ def QRUtil.get_lost_point( qr_code ) ( 0...( module_count - 1 ) ).each do |row| ( 0...( module_count - 1 ) ).each do |col| count = 0 - count = count + 1 if modules[row][col] - count = count + 1 if modules[row + 1][col] - count = count + 1 if modules[row][col + 1] - count = count + 1 if modules[row + 1][col + 1] + count += 1 if modules[row][col] + count += 1 if modules[row + 1][col] + count += 1 if modules[row][col + 1] + count += 1 if modules[row + 1][col + 1] if (count == 0 || count == 4) lost_point = lost_point + DEMERIT_POINTS_2 end From 37b014b1aedddb17760b48ba5b58da93294e6651 Mon Sep 17 00:00:00 2001 From: Gioele Barabucci Date: Sat, 13 Aug 2011 17:10:03 +0200 Subject: [PATCH 18/20] Decouple `QRUtil.get_lost_point` from `QRCode` --- lib/rqrcode/qrcode/qr_code.rb | 2 +- lib/rqrcode/qrcode/qr_util.rb | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/rqrcode/qrcode/qr_code.rb b/lib/rqrcode/qrcode/qr_code.rb index d3f7d991..6d4267e0 100644 --- a/lib/rqrcode/qrcode/qr_code.rb +++ b/lib/rqrcode/qrcode/qr_code.rb @@ -214,7 +214,7 @@ def get_best_mask_pattern #:nodoc: ( 0...8 ).each do |i| make_impl( true, i ) - lost_point = QRUtil.get_lost_point( self ) + lost_point = QRUtil.get_lost_points(self.modules) if i == 0 || min_lost_point > lost_point min_lost_point = lost_point diff --git a/lib/rqrcode/qrcode/qr_util.rb b/lib/rqrcode/qrcode/qr_util.rb index 09e0dc8a..2fec0d52 100644 --- a/lib/rqrcode/qrcode/qr_util.rb +++ b/lib/rqrcode/qrcode/qr_util.rb @@ -164,9 +164,8 @@ def QRUtil.get_length_in_bits( mode, type ) end - def QRUtil.get_lost_point( qr_code ) - modules = qr_code.modules - module_count = qr_code.module_count + def QRUtil.get_lost_points(modules) + module_count = modules.size lost_point = 0 # level1 From f56c29a10db74f2b78c62d943a3298805d268d04 Mon Sep 17 00:00:00 2001 From: Gioele Barabucci Date: Sat, 13 Aug 2011 17:25:46 +0200 Subject: [PATCH 19/20] Simplified code for `QRUtil.get_length_in_bits` --- lib/rqrcode/qrcode/qr_util.rb | 60 ++++++++++++++--------------------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/lib/rqrcode/qrcode/qr_util.rb b/lib/rqrcode/qrcode/qr_util.rb index 2fec0d52..99e04097 100644 --- a/lib/rqrcode/qrcode/qr_util.rb +++ b/lib/rqrcode/qrcode/qr_util.rb @@ -66,6 +66,13 @@ class QRUtil DEMERIT_POINTS_3 = 40 DEMERIT_POINTS_4 = 10 + BITS_FOR_MODE = { + QRMODE[:mode_number] => [10, 12, 14], + QRMODE[:mode_alpha_num] => [9, 11, 13], + QRMODE[:mode_8bit_byte] => [8, 16, 16], + QRMODE[:mode_kanji] => [8, 10, 12], + } + def QRUtil.get_bch_type_info( data ) d = data << 10 while QRUtil.get_bch_digit(d) - QRUtil.get_bch_digit(G15) >= 0 @@ -121,46 +128,27 @@ def QRUtil.get_error_correct_polynomial( error_correct_length ) end - def QRUtil.get_length_in_bits( mode, type ) - if 1 <= type && type < 10 - - # 1 - 9 - case mode - when QRMODE[:mode_number] then 10 - when QRMODE[:mode_alpha_num] then 9 - when QRMODE[:mode_8bit_byte] then 8 - when QRMODE[:mode_kanji] then 8 - else - raise QRCodeRunTimeError, "mode: #{mode}" - end - - elsif type < 27 - - # 10 -26 - case mode - when QRMODE[:mode_number] then 12 - when QRMODE[:mode_alpha_num] then 11 - when QRMODE[:mode_8bit_byte] then 16 - when QRMODE[:mode_kanji] then 10 - else - raise QRCodeRunTimeError, "mode: #{mode}" - end + def QRUtil.get_length_in_bits(mode, type) + if !QRMODE.value?(mode) + raise QRCodeRunTimeError, "Unknown mode: #{mode}" + end - elsif type < 41 + if type > 40 + raise QRCodeRunTimeError, "Unknown type: #{type}" + end + if 1 <= type && type <= 9 + # 1 - 9 + macro_type = 0 + elsif type <= 26 + # 10 - 26 + macro_type = 1 + elsif type <= 40 # 27 - 40 - case mode - when QRMODE[:mode_number] then 14 - when QRMODE[:mode_alpha_num] then 13 - when QRMODE[:mode_8bit_byte] then 16 - when QRMODE[:mode_kanji] then 12 - else - raise QRCodeRunTimeError, "mode: #{mode}" - end - - else - raise QRCodeRunTimeError, "type: #{type}" + macro_type = 2 end + + return BITS_FOR_MODE[mode][macro_type] end From 52c9caff6c35e3c746bdce3f33b59babe75d1a99 Mon Sep 17 00:00:00 2001 From: Gioele Barabucci Date: Sat, 13 Aug 2011 17:49:10 +0200 Subject: [PATCH 20/20] Split `QRUtil.get_lost_points` in four sub functions --- lib/rqrcode/qrcode/qr_util.rb | 65 +++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/lib/rqrcode/qrcode/qr_util.rb b/lib/rqrcode/qrcode/qr_util.rb index 99e04097..e589f71a 100644 --- a/lib/rqrcode/qrcode/qr_util.rb +++ b/lib/rqrcode/qrcode/qr_util.rb @@ -151,14 +151,24 @@ def QRUtil.get_length_in_bits(mode, type) return BITS_FOR_MODE[mode][macro_type] end - def QRUtil.get_lost_points(modules) + demerit_points = 0 + + demerit_points += QRUtil.demerit_points_1_same_color(modules) + demerit_points += QRUtil.demerit_points_2_full_blocks(modules) + demerit_points += QRUtil.demerit_points_3_dangerous_patterns(modules) + demerit_points += QRUtil.demerit_points_4_dark_ratio(modules) + + return demerit_points + end + + def QRUtil.demerit_points_1_same_color(modules) + demerit_points = 0 module_count = modules.size - lost_point = 0 # level1 - ( 0...module_count ).each do |row| - ( 0...module_count ).each do |col| + (0...module_count).each do |row| + (0...module_count).each do |col| same_count = 0 dark = modules[row][col] @@ -175,25 +185,39 @@ def QRUtil.get_lost_points(modules) end if same_count > 5 - lost_point += (DEMERIT_POINTS_1 + same_count - 5) - end + demerit_points += (DEMERIT_POINTS_1 + same_count - 5) + end end end + return demerit_points + end + + def QRUtil.demerit_points_2_full_blocks(modules) + demerit_points = 0 + module_count = modules.size + # level 2 - ( 0...( module_count - 1 ) ).each do |row| - ( 0...( module_count - 1 ) ).each do |col| + (0...(module_count - 1)).each do |row| + (0...(module_count - 1)).each do |col| count = 0 count += 1 if modules[row][col] count += 1 if modules[row + 1][col] count += 1 if modules[row][col + 1] count += 1 if modules[row + 1][col + 1] if (count == 0 || count == 4) - lost_point = lost_point + DEMERIT_POINTS_2 + demerit_points += DEMERIT_POINTS_2 end - end + end end + return demerit_points + end + + def QRUtil.demerit_points_3_dangerous_patterns(modules) + demerit_points = 0 + module_count = modules.size + # level 3 modules.each do |row| (module_count - 6).times do |col_idx| @@ -204,13 +228,13 @@ def QRUtil.get_lost_points(modules) row[col_idx + 4] && !row[col_idx + 5] && row[col_idx + 6] - lost_point += DEMERIT_POINTS_3 + demerit_points += DEMERIT_POINTS_3 end end end - ( 0...module_count ).each do |col| - ( 0...( module_count - 6 ) ).each do |row| + (0...module_count).each do |col| + (0...(module_count - 6)).each do |row| if modules[row][col] && !modules[row + 1][col] && modules[row + 2][col] && @@ -218,21 +242,26 @@ def QRUtil.get_lost_points(modules) modules[row + 4][col] && !modules[row + 5][col] && modules[row + 6][col] - lost_point += DEMERIT_POINTS_3 + demerit_points += DEMERIT_POINTS_3 end end end + return demerit_points + end + + def QRUtil.demerit_points_4_dark_ratio(modules) # level 4 dark_count = modules.reduce(0) do |sum, col| sum + col.count(true) end - ratio = dark_count / (module_count * module_count) + + ratio = dark_count / (modules.size * modules.size) ratio_delta = (100 * ratio - 50).abs / 5 - lost_point += ratio_delta * DEMERIT_POINTS_4 - return lost_point - end + demerit_points = ratio_delta * DEMERIT_POINTS_4 + return demerit_points + end end