true false false ruby # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # Description: QR code PCell # # This PCell will generate a QR code from a given text. # It provides a couple of options for the QR code (error correction level, # format) and for adjusting the layout (bias, pixel size, reverse tone). # It supports QR codes with 8 bit encoding (default), numeric and # alphanumeric encoding. # For numeric and alphanumeric encoding it is necessary to have only # digits or the characters allowed for alphanumeric encoding in the text. # module QRCodeLibModule # ----------------------------------------------------------------- # QR code generator classes # A generator class for the ECC bytes class ECCGenerator ALPHA = 0x1d # GF(256) arithmetics: addition def plus(x, y) return x ^ y end # GF(256) arithmetics: multiplication def times(x, y) s = 0 m = 8 m.times do |i| if (y & 1) != 0 s ^= x end y >>= 1 c = x & (1 << (m - 1)) x ^= c x <<= 1 if c != 0 x ^= ALPHA end end s end # GF(256) arithmetics: power function def pow(x, n) s = 1 n.times do s = times(s, x) end s end # Produce the ECC data for the given input data, total length (l) and # raw data count (k) def eccdata(data, l, k) @g || init_tables n = l - k p = @g[n] b = n.times.collect { 0 } k.times do |i| bb = [0] + b d = plus(bb[n], data[i]) n.times do |j| b[j] = plus(bb[j], times(p[j], d)) end end return b.reverse end # Initialize the polynom factor tables def init_tables nmax = 46 p = [1] g = [] g << p.dup u = 1 nmax.times do |i| pp = [0] + p p.size.times do |j| pp[j] = plus(pp[j], times(p[j], u)) end p = pp g << p.dup u = times(u, 2) end @g = g end end # A bit stream collector # This class acts as a receiver of words with arbitrary bit length # and builds a byte stream from this data. Useful for building the # data words. class BitStream def initialize @data = [] @nbits = 0 end def add(data, bits) if bits > 8 add(data >> 8, bits - 8) add(data & 0xff, 8) elsif @nbits % 8 == 0 @data << (data << (8 - bits)) @nbits += bits elsif (@nbits % 8) + bits <= 8 @data[-1] |= (data << (8 - (@nbits % 8) - bits)) @nbits += bits else n = (@nbits % 8) + bits - 8 @data[-1] |= (data >> n) @data << ((data << (8 - n)) & 0xff) @nbits += bits end end def data @data end end # The basic encoder class # The core function is "generate" which will produce the QR code. class QREncoder # "L" EC level Data codeword capacity for version 1 to 40 Capacity_l = [ 19, 34, 55, 80, 108, 136, 156, 194, 232, 274, 324, 370, 428, 461, 523, 589, 647, 721, 795, 861, 932, 1006, 1094, 1174, 1276, 1370, 1468, 1531, 1631, 1735, 1843, 1955, 2071, 2191, 2306, 2434, 2566, 2702, 2812, 2956 ] # "M" EC level Data codeword capacity for version 1 to 40 Capacity_m = [ 16, 28, 44, 64, 86, 108, 124, 154, 182, 216, 254, 290, 334, 365, 415, 453, 507, 563, 627, 669, 714, 782, 860, 914, 1000, 1062, 1128, 1193, 1267, 1373, 1455, 1541, 1631, 1725, 1812, 1914, 1992, 2102, 2216, 2334 ] # "Q" EC level Data codeword capacity for version 1 to 40 Capacity_q = [ 13, 22, 34, 48, 62, 76, 88, 110, 132, 154, 180, 206, 244, 261, 295, 325, 367, 397, 445, 485, 512, 568, 614, 664, 718, 754, 808, 871, 911, 985, 1033, 1115, 1171, 1231, 1286, 1354, 1426, 1502, 1582, 1666 ] # "H" EC level Data codeword capacity for version 1 to 40 Capacity_h = [ 9, 16, 26, 36, 46, 60, 66, 86, 100, 122, 140, 158, 180, 197, 223, 253, 283, 313, 341, 385, 406, 442, 464, 514, 538, 596, 628, 661, 701, 745, 793, 845, 901, 961, 986, 1054, 1096, 1142, 1222, 1276 ] # Number of codewords (all, data) for the different ECC levels per version # The data is [ number_of_blocks, total_number_of_codewords, data_codewords ] ECC_parameters = [ [ # version 1 [ [ 1, 26, 19 ] ], # "L" [ [ 1, 26, 16 ] ], # "M" [ [ 1, 26, 13 ] ], # "Q" [ [ 1, 26, 9 ] ], # "H" ], [ # version 2 [ [ 1, 44, 34 ] ], # "L" [ [ 1, 44, 28 ] ], # "M" [ [ 1, 44, 22 ] ], # "Q" [ [ 1, 44, 16 ] ], # "H" ], [ # version 3 [ [ 1, 70, 55 ] ], # "L" [ [ 1, 70, 44 ] ], # "M" [ [ 2, 35, 17 ] ], # "Q" [ [ 2, 35, 13 ] ], # "H" ], [ # version 4 [ [ 1, 100, 80 ] ], # "L" [ [ 2, 50, 32 ] ], # "M" [ [ 2, 50, 24 ] ], # "Q" [ [ 4, 25, 9 ] ], # "H" ], [ # version 5 [ [ 1, 134, 108 ] ], # "L" [ [ 2, 67, 43 ] ], # "M" [ [ 2, 33, 15 ], [ 2, 34, 16 ] ], # "Q" [ [ 2, 33, 11 ], [ 2, 34, 12 ] ], # "H" ], [ # version 6 [ [ 2, 86, 68 ] ], # "L" [ [ 4, 43, 27 ] ], # "M" [ [ 4, 43, 19 ] ], # "Q" [ [ 4, 43, 15 ] ], # "H" ], [ # version 7 [ [ 2, 98, 78 ] ], # "L" [ [ 4, 49, 31 ] ], # "M" [ [ 2, 32, 14 ], [ 4, 33, 15 ] ], # "Q" [ [ 4, 39, 13 ], [ 1, 40, 14 ] ], # "H" ], [ # version 8 [ [ 2, 121, 97 ] ], # "L" [ [ 2, 60, 38 ], [ 2, 61, 39 ] ], # "M" [ [ 4, 40, 18 ], [ 2, 41, 19 ] ], # "Q" [ [ 4, 40, 14 ], [ 2, 41, 15 ] ], # "H" ], [ # version 9 [ [ 2, 146, 116 ] ], # "L" [ [ 3, 58, 36 ], [ 2, 59, 37 ] ], # "M" [ [ 4, 36, 16 ], [ 4, 37, 17 ] ], # "Q" [ [ 4, 36, 12 ], [ 4, 37, 13 ] ], # "H" ], [ # version 10 [ [ 2, 86, 68 ], [ 2, 87, 69 ] ], # "L" [ [ 4, 69, 43 ], [ 1, 70, 44 ] ], # "M" [ [ 6, 43, 19 ], [ 2, 44, 20 ] ], # "Q" [ [ 6, 43, 15 ], [ 2, 44, 16 ] ], # "H" ], [ # version 11 [ [ 4, 101, 81 ] ], # "L" [ [ 1, 80, 50 ], [ 4, 81, 51 ] ], # "M" [ [ 4, 50, 22 ], [ 4, 51, 23 ] ], # "Q" [ [ 3, 36, 12 ], [ 8, 37, 13 ] ], # "H" ], [ # version 12 [ [ 2, 116, 92 ], [ 2, 117, 93 ] ], # "L" [ [ 6, 58, 36 ], [ 2, 59, 37 ] ], # "M" [ [ 4, 46, 20 ], [ 6, 47, 21 ] ], # "Q" [ [ 7, 42, 14 ], [ 4, 43, 15 ] ], # "H" ], [ # version 13 [ [ 4, 133, 107 ] ], # "L" [ [ 8, 59, 37 ], [ 1, 60, 38 ] ], # "M" [ [ 8, 44, 20 ], [ 4, 45, 21 ] ], # "Q" [ [ 12, 33, 11 ], [ 4, 34, 12 ] ], # "H" ], [ # version 14 [ [ 3, 145, 115 ], [ 1, 146, 116 ] ], # "L" [ [ 4, 64, 40 ], [ 5, 65, 41 ] ], # "M" [ [ 11, 36, 16 ], [ 5, 37, 17 ] ], # "Q" [ [ 11, 36, 12 ], [ 5, 37, 13 ] ], # "H" ], [ # version 15 [ [ 5, 109, 87 ], [ 1, 110, 88 ] ], # "L" [ [ 5, 65, 41 ], [ 5, 66, 42 ] ], # "M" [ [ 5, 54, 24 ], [ 7, 55, 25 ] ], # "Q" [ [ 11, 36, 12 ], [ 7, 37, 13 ] ], # "H" ], [ # version 16 [ [ 5, 122, 98 ], [ 1, 123, 99 ] ], # "L" [ [ 7, 73, 45 ], [ 3, 74, 46 ] ], # "M" [ [ 15, 43, 19 ], [ 2, 44, 20 ] ], # "Q" [ [ 3, 45, 15 ], [ 13, 46, 16 ] ], # "H" ], [ # version 17 [ [ 1, 135, 107 ], [ 5, 136, 108 ] ], # "L" [ [ 10, 74, 46 ], [ 1, 75, 47 ] ], # "M" [ [ 1, 50, 22 ], [ 15, 51, 23 ] ], # "Q" [ [ 2, 42, 14 ], [ 17, 43, 15 ] ], # "H" ], [ # version 18 [ [ 5, 150, 120 ], [ 1, 151, 121 ] ], # "L" [ [ 9, 69, 43 ], [ 4, 70, 44 ] ], # "M" [ [ 17, 50, 22 ], [ 1, 51, 23 ] ], # "Q" [ [ 2, 42, 14 ], [ 19, 43, 15 ] ], # "H" ], [ # version 19 [ [ 3, 141, 113 ], [ 4, 142, 114 ] ], # "L" [ [ 3, 70, 44 ], [ 11, 71, 45 ] ], # "M" [ [ 17, 47, 21 ], [ 4, 48, 22 ] ], # "Q" [ [ 9, 39, 13 ], [ 16, 40, 14 ] ], # "H" ], [ # version 20 [ [ 3, 135, 107 ], [ 5, 136, 108 ] ], # "L" [ [ 3, 67, 41 ], [ 13, 68, 42 ] ], # "M" [ [ 15, 54, 24 ], [ 5, 55, 25 ] ], # "Q" [ [ 15, 43, 15 ], [ 10, 44, 16 ] ], # "H" ], [ # version 21 [ [ 4, 144, 116 ], [ 4, 145, 117 ] ], # "L" [ [ 17, 68, 42 ] ], # "M" [ [ 17, 50, 22 ], [ 6, 51, 23 ] ], # "Q" [ [ 19, 46, 16 ], [ 6, 47, 17 ] ], # "H" ], [ # version 22 [ [ 2, 139, 111 ], [ 7, 140, 112 ] ], # "L" [ [ 17, 74, 46 ] ], # "M" [ [ 7, 54, 24 ], [ 16, 55, 25 ] ], # "Q" [ [ 34, 37, 13 ] ], # "H" ], [ # version 23 [ [ 4, 151, 121 ], [ 5, 152, 122 ] ], # "L" [ [ 4, 75, 47 ], [ 14, 76, 48 ] ], # "M" [ [ 11, 54, 24 ], [ 14, 55, 25 ] ], # "Q" [ [ 16, 45, 15 ], [ 14, 46, 16 ] ], # "H" ], [ # version 24 [ [ 6, 147, 117 ], [ 4, 148, 118 ] ], # "L" [ [ 6, 73, 45 ], [ 14, 74, 46 ] ], # "M" [ [ 11, 54, 24 ], [ 16, 55, 25 ] ], # "Q" [ [ 30, 46, 16 ], [ 2, 47, 17 ] ], # "H" ], [ # version 25 [ [ 8, 132, 106 ], [ 4, 133, 107 ] ], # "L" [ [ 8, 75, 47 ], [ 13, 76, 48 ] ], # "M" [ [ 7, 54, 24 ], [ 22, 55, 25 ] ], # "Q" [ [ 22, 45, 15 ], [ 13, 46, 16 ] ], # "H" ], [ # version 26 [ [ 10, 142, 114 ], [ 2, 143, 115 ] ], # "L" [ [ 19, 74, 46 ], [ 4, 75, 47 ] ], # "M" [ [ 28, 50, 22 ], [ 6, 51, 23 ] ], # "Q" [ [ 33, 46, 16 ], [ 4, 47, 17 ] ], # "H" ], [ # version 27 [ [ 8, 152, 122 ], [ 4, 153, 123 ] ], # "L" [ [ 22, 73, 45 ], [ 3, 74, 46 ] ], # "M" [ [ 8, 53, 23 ], [ 26, 54, 24 ] ], # "Q" [ [ 12, 45, 15 ], [ 28, 46, 16 ] ], # "H" ], [ # version 28 [ [ 3, 147, 117 ], [ 10, 148, 118 ] ], # "L" [ [ 3, 73, 45 ], [ 23, 74, 46 ] ], # "M" [ [ 4, 54, 24 ], [ 31, 55, 25 ] ], # "Q" [ [ 11, 45, 15 ], [ 31, 46, 16 ] ], # "H" ], [ # version 29 [ [ 7, 146, 116 ], [ 7, 147, 117 ] ], # "L" [ [ 21, 73, 45 ], [ 7, 74, 46 ] ], # "M" [ [ 1, 53, 23 ], [ 37, 54, 24 ] ], # "Q" [ [ 19, 45, 15 ], [ 26, 46, 16 ] ], # "H" ], [ # version 30 [ [ 5, 145, 115 ], [ 10, 146, 116 ] ], # "L" [ [ 19, 75, 47 ], [ 10, 76, 48 ] ], # "M" [ [ 15, 54, 24 ], [ 25, 55, 25 ] ], # "Q" [ [ 23, 45, 15 ], [ 25, 46, 16 ] ], # "H" ], [ # version 31 [ [ 13, 145, 115 ], [ 3, 146, 116 ] ], # "L" [ [ 2, 74, 46 ], [ 29, 75, 47 ] ], # "M" [ [ 42, 54, 24 ], [ 1, 55, 25 ] ], # "Q" [ [ 23, 45, 15 ], [ 28, 46, 16 ] ], # "H" ], [ # version 32 [ [ 17, 145, 115 ] ], # "L" [ [ 10, 74, 46 ], [ 23, 75, 47 ] ], # "M" [ [ 10, 54, 24 ], [ 35, 55, 25 ] ], # "Q" [ [ 19, 45, 15 ], [ 35, 46, 16 ] ], # "H" ], [ # version 33 [ [ 17, 145, 115 ], [ 1, 146, 116 ] ], # "L" [ [ 14, 74, 46 ], [ 21, 75, 47 ] ], # "M" [ [ 29, 54, 24 ], [ 19, 55, 25 ] ], # "Q" [ [ 11, 45, 15 ], [ 46, 46, 16 ] ], # "H" ], [ # version 34 [ [ 13, 145, 115 ], [ 6, 146, 116 ] ], # "L" [ [ 14, 74, 46 ], [ 23, 75, 47 ] ], # "M" [ [ 44, 54, 24 ], [ 7, 55, 25 ] ], # "Q" [ [ 59, 46, 16 ], [ 1, 47, 17 ] ], # "H" ], [ # version 35 [ [ 12, 151, 121 ], [ 7, 152, 122 ] ], # "L" [ [ 12, 75, 47 ], [ 26, 76, 48 ] ], # "M" [ [ 39, 54, 24 ], [ 14, 55, 25 ] ], # "Q" [ [ 22, 45, 15 ], [ 41, 46, 16 ] ], # "H" ], [ # version 36 [ [ 6, 151, 121 ], [ 14, 152, 122 ] ], # "L" [ [ 6, 75, 47 ], [ 34, 76, 48 ] ], # "M" [ [ 46, 54, 24 ], [ 10, 55, 25 ] ], # "Q" [ [ 2, 45, 15 ], [ 64, 46, 16 ] ], # "H" ], [ # version 37 [ [ 17, 152, 122 ], [ 4, 153, 123 ] ], # "L" [ [ 29, 74, 46 ], [ 14, 75, 47 ] ], # "M" [ [ 49, 54, 24 ], [ 10, 55, 25 ] ], # "Q" [ [ 24, 45, 15 ], [ 46, 46, 16 ] ], # "H" ], [ # version 38 [ [ 4, 152, 122 ], [ 18, 153, 123 ] ], # "L" [ [ 13, 74, 46 ], [ 32, 75, 47 ] ], # "M" [ [ 48, 54, 24 ], [ 14, 55, 25 ] ], # "Q" [ [ 42, 45, 15 ], [ 32, 46, 16 ] ], # "H" ], [ # version 39 [ [ 20, 147, 117 ], [ 4, 148, 118 ] ], # "L" [ [ 40, 75, 47 ], [ 7, 76, 48 ] ], # "M" [ [ 43, 54, 24 ], [ 22, 55, 25 ] ], # "Q" [ [ 10, 45, 15 ], [ 67, 46, 16 ] ], # "H" ], [ # version 40 [ [ 19, 148, 118 ], [ 6, 149, 119 ] ], # "L" [ [ 18, 75, 47 ], [ 31, 76, 48 ] ], # "M" [ [ 34, 54, 24 ], [ 34, 55, 25 ] ], # "Q" [ [ 20, 45, 15 ], [ 61, 46, 16 ] ], # "H" ] ] # Fetch version and compression level for the given text, format and compression level. # The return value is a pair of version and level information. # Version is the version number (1..40) and level the ECC level (0: L, 1: M, 2: Q, 3: H). # The format is either :bytes, :numeric or :alphanumeric. def QREncoder.version_and_level(text, format = :bytes, level = nil) # compute required bits bits1 = 0 # version 1 to 9 bits2 = 0 # version 10 to 26 bits3 = 0 # version 27 to 40 n = text.size if format == :bytes bits1 = 4 + 8 + 8 * n bits2 = bits3 = 4 + 16 + 8 * n elsif format == :numeric bits1 = 4 + 10 + (n + 2) / 3 bits2 = bits1 + 2 bits3 = bits2 + 2 elsif format == :alphanumeric bits1 = 4 + 9 + (n / 2) * 11 + (n % 2) * 6 bits2 = bits1 + 2 bits3 = bits2 + 2 else raise("Invalid format #{format}") end bytes1 = (bits1 + 7) / 8 bytes2 = (bits2 + 7) / 8 bytes3 = (bits3 + 7) / 8 # choose the version using the capacity. # Note: for version > 9 we need to add 3 bytes for encoding and length # for version <= 9 we need to add 2 bytes. if !level && bytes3 > Capacity_l[-1] raise "Data too big" elsif !level && bytes3 > Capacity_m[-1] level = 0 # "L" version = Capacity_l.size elsif !level && bytes3 > Capacity_q[-1] level = 1 # "M" version = Capacity_m.size elsif !level && bytes3 > Capacity_h[-1] level = 2 # "Q" version = Capacity_q.size else level ||= 3 # "H" capacity = [ Capacity_l, Capacity_m, Capacity_q, Capacity_h ][level] version = nil capacity.each_with_index do |c,i| req = i < 9 ? bytes1 : (i < 26 ? bytes2 : bytes3) if c >= req version = i + 1 break end end end version || raise("Capacity not sufficient to hold the requested number of bytes.") [ version, level ] end # Self-test the encoder tables def QREncoder.self_test # Compare capacities with the capacities computed from the ECC_parameters # Note: this ensures I have entered the tables correctly ... [ Capacity_l, Capacity_m, Capacity_q, Capacity_h ].each_with_index do |capacity,level| 40.times do |version| ndata = 0 nwords_ref = 0 ECC_parameters[version][0].each do |ecc| nwords_ref += ecc[0] * ecc[1] end nwords = 0 ECC_parameters[version][level].each do |ecc| ndata += ecc[0] * ecc[2] nwords += ecc[0] * ecc[1] end if nwords != nwords_ref raise "Mismatch: level = #{level}, version=#{version + 1}: nwords = #{nwords}, nwords(level 0) = #{nwords_ref}" end if ndata != capacity[version] raise "Mismatch: level = #{level}, version=#{version + 1}: cap = #{capacity[version]}, ecc = #{ndata}" end end end end # Builds the field mask. The fiels mask will indicate where there are # function pattern (value is true or false) and where are data pattern (value is nil). def build_field_mask(version) n = 17 + 4 * version # The basic field descriptor. # Values mean: # true: pixel set (function pattern) # false: pixel unset (function pattern) # nil: data and ECC # Indexing of the field is [row][column], where 0 is the topmost row. @field_mask = n.times.collect { n.times.collect { nil } } # create the finder pattern [ [ -1, -1 ], [ n - 8, -1 ], [ -1, n - 8 ] ].each do |nx, ny| [ 0x00, 0xfe, 0x82, 0xba, 0xba, 0xba, 0x82, 0xfe, 0x00 ].each_with_index do |p, i| 9.times do |j| if nx + i >= 0 && nx + i < n && ny + j >= 0 && ny + j < n @field_mask[ny + j][nx + i] = (p & 0x100) != 0 end p <<= 1 end end end # create the timing pattern (9 .. (n - 9)).each do |i| @field_mask[6][i] = (i % 2) == 0 @field_mask[i][6] = (i % 2) == 0 end # preset the format information fields with true @field_mask[8][8] = true 8.times do |i| @field_mask[8][i] = true @field_mask[8][n - 1 - i] = true @field_mask[n - 1 - i][8] = true @field_mask[i][8] = true end # encode the version information if @version >= 7 # precomputed pattern per version version_pattern = [ 0x07C94, # Version 7 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6, 0x0C762, 0x0D847, 0x0E60D, 0x0F928, # Version 8 to 15 0x10B78, 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683, 0x168C9, 0x177EC, # Version 16 to 23 0x18EC4, 0x191E1, 0x1AFAB, 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250, # Version 24 to 31 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B, 0x2542E, 0x26A64, 0x27541, # Version 32 to 39 0x28C69 # Version 40 ] p = version_pattern[@version - 7] (0..5).each do |j| (0..2).each do |i| @field_mask[j][n - 11 + i] = (p & 1) != 0 @field_mask[n - 11 + i][j] = (p & 1) != 0 p >>= 1 end end end # create alignment pattern acoords = [ [ ], [ 6, 18 ], [ 6, 22 ], [ 6, 26 ], [ 6, 30 ], [ 6, 34 ], [ 6, 22, 38 ], [ 6, 24, 42 ], [ 6, 26, 46 ], [ 6, 28, 50 ], [ 6, 30, 54 ], [ 6, 32, 58 ], [ 6, 34, 62 ], [ 6, 26, 46, 66 ], [ 6, 26, 48, 70 ], [ 6, 26, 50, 74 ], [ 6, 30, 54, 78 ], [ 6, 30, 56, 82 ], [ 6, 30, 58, 86 ], [ 6, 34, 62, 90 ], [ 6, 28, 50, 72, 94 ], [ 6, 26, 50, 74, 98 ], [ 6, 30, 54, 78, 102 ], [ 6, 28, 54, 80, 106 ], [ 6, 32, 58, 84, 110 ], [ 6, 30, 58, 86, 114 ], [ 6, 34, 62, 90, 118 ], [ 6, 26, 50, 74, 98, 122 ], [ 6, 30, 54, 78, 102, 126 ], [ 6, 26, 52, 78, 104, 130 ], [ 6, 30, 56, 82, 108, 134 ], [ 6, 34, 60, 86, 112, 138 ], [ 6, 30, 58, 86, 114, 142 ], [ 6, 34, 62, 90, 118, 146 ], [ 6, 30, 54, 78, 102, 126, 150 ], [ 6, 24, 50, 76, 102, 128, 154 ], [ 6, 28, 54, 80, 106, 132, 158 ], [ 6, 32, 58, 84, 110, 136, 162 ], [ 6, 26, 54, 82, 110, 138, 166 ], [ 6, 30, 58, 86, 114, 142, 170 ] ] ac = acoords[version - 1] ac.each_with_index do |r,ri| ac.each_with_index do |c,ci| if !((ri == 0 && ci == 0) || (ri == ac.size - 1 && ci == 0) || (ri == 0 && ci == ac.size - 1)) (-2 .. 2).each do |i| (-2 .. 2).each do |j| b = (i == 0 && j == 0) || (i.abs == 2 || j.abs == 2) @field_mask[r - i][c - j] = b end end end end end end # Encodes the text for the given format. # Format it :bytes, :numeric or :alphanumeric. The text will be encoded, # ECC bytes will be added and the result will be returned as an array # of integers (bytes). def encode(text, format) @eccgen ||= ECCGenerator::new bs = BitStream::new n = text.size # build byte stream if format == :bytes bs.add(4, 4) if @version >= 10 # 16 bit length bs.add(n, 16) else # 8 bit length bs.add(n, 8) end n.times do |i| bs.add(text[i].ord, 8) end elsif format == :numeric bs.add(1, 4) if @version >= 27 bs.add(n, 14) elsif @version >= 10 bs.add(n, 12) else bs.add(n, 10) end parts = [] n.times do |i| if i % 3 == 0 parts << "" end c = text[i] if c !~ /^\d$/ raise("Numeric format requires numeric string - string has non-numeric character '#{c}'") end parts[-1] += c end parts.each do |p| bs.add(p.to_i, 10) end elsif format == :alphanumeric bs.add(2, 4) if @version >= 27 bs.add(n, 13) elsif @version >= 10 bs.add(n, 11) else bs.add(n, 9) end codes = { "0" => 0, "1" => 1, "2" => 2, "3" => 3, "4" => 4, "5" => 5, "6" => 6, "7" => 7, "8" => 8, "9" => 9, "A" => 10, "B" => 11, "C" => 12, "D" => 13, "E" => 14, "F" => 15, "G" => 16, "H" => 17, "I" => 18, "J" => 19, "K" => 20, "L" => 21, "M" => 22, "N" => 23, "O" => 24, "P" => 25, "Q" => 26, "R" => 27, "S" => 28, "T" => 29, "U" => 30, "V" => 31, "W" => 32, "X" => 33, "Y" => 34, "Z" => 35, " " => 36, "$" => 37, "%" => 38, "*" => 39, "+" => 40, "-" => 41, "." => 42, "/" => 43, ":" => 44 } parts = [] n.times do |i| if i % 2 == 0 parts << [] end c = text[i] if ! codes[c] raise("Alphanumeric format error - string has non-alphanumeric character '#{c}'") end parts[-1] << codes[c] end parts.each do |p| if p.size == 1 bs.add(p[0], 6) else bs.add(p[1] * 45 + p[0], 11) end end else raise("Invalid format #{format}") end data = bs.data # split into blocks and generate ECC data blocks = [] ecc_blocks = [] fill = [ 0xec, 0x11 ] fi = 0 i = 0 ECC_parameters[@version - 1][@level].each do |ecc| ecc[0].times do block = [] ecc[2].times do d = data[i] if !d d = fill[fi] fi = (fi + 1) % 2 end block << d i += 1 end blocks << block ecc_blocks << @eccgen.eccdata(block, ecc[1], ecc[2]) end end # produce the final data stream data = [] blocks[-1].size.times do |i| blocks.each do |b| b[i] && (data << b[i]) end end ecc_blocks[-1].size.times do |i| ecc_blocks.each do |b| b[i] && (data << b[i]) end end return data end # Fills the data bits with the data provided def fill_data(data) n = 17 + 4 * @version @field_data = [] n.times do |i| @field_data << @field_mask[i].dup end r = c = n - 1 up = true data.each do |d| 8.times do if r < 0 || r >= n || c < 0 || c >= n raise "Internal error: invalid pixel fill position (#{r}/#{c} pixel ##{i})" end bit = ((d & 0x80) != 0) @field_data[r][c] = bit d <<= 1 while (r >= 0 && c >= 0 && @field_data[r][c] != nil) if (c > 6 && (c % 2) == 0) || (c < 6 && (c % 2) == 1) c -= 1 else if (r == 0 && up) || (r == n - 1 && !up) c -= (c == 7 ? 2 : 1) up = !up else c += 1 r += (up ? -1 : 1) end end end end end # fill the remaining bits with false while (r >= 0 && c >= 0) if @field_data[r][c] == nil @field_data[r][c] = false end if (c > 6 && (c % 2) == 0) || (c < 6 && (c % 2) == 1) c -= 1 else if (r == 0 && up) || (r == n - 1 && !up) c -= (c == 7 ? 2 : 1) up = !up else c += 1 r += (up ? -1 : 1) end end end end # Reverse (for testing): extract the data bits into an array of bytes. def extract_data n = 17 + 4 * @version r = c = n - 1 up = true data = [] while true d = 0 bits = 0 8.times do if r < 0 || r >= n || c < 0 || c >= n break end d <<= 1 @field_data[r][c] && (d |= 1) bits += 1 while (r >= 0 && c >= 0) if (c > 6 && (c % 2) == 0) || (c < 6 && (c % 2) == 1) c -= 1 else if (r == 0 && up) || (r == n - 1 && !up) c -= (c == 7 ? 2 : 1) up = !up else c += 1 r += (up ? -1 : 1) end end if @field_mask[r][c] == nil break end end end if bits == 8 data << d else break end end data end # Returns the format code bit set (15 bits, 5 bits for the # format information and 10 bits for ECC data). # Input is the ECC level (0: L .. 3: H) and mask version # (0 to 7). def format_code(level, mask_version) code = (([ 1, 0, 3, 2 ][level] << 3) | mask_version) << 10 res = code p = 0x537 << 4 pm = 0x400 << 4 5.times do (res & pm) != 0 && res ^= p p >>= 1 pm >>= 1 end (res | code) ^ 0x5412 end # Installs the format information in the format bits of the # pattern. # Input is the ECC level (0: L .. 3: H) and mask version # (0 to 7). def set_format(level, mask_version) fc = format_code(level, mask_version) n = 17 + @version * 4 8.times do |i| bit = ((fc & 1) != 0) @field_data[8][n - 1 - i] = bit @field_data[i >= 6 ? i + 1 : i][8] = bit fc >>= 1 end 7.times do |i| bit = ((fc & 1) != 0) @field_data[n - 7 + i][8] = bit @field_data[8][(i >= 2 ? 6 : 7) - i] = bit fc >>= 1 end end # Computes the score value for a given mask version. # The field data must contain the unmasked data. def mask_score(mask_version) field_data = @field_data.collect { |d| d.dup } apply_mask(mask_version, field_data) n = 17 + @version * 4 score = 0 n1 = 3 n2 = 3 n3 = 40 n4 = 10 count = 0 n.times do |i| (n - 1).times do |j| c = 0 if field_data[i][j] == field_data[i][j + 1] c += 1 end if c > 5 count += c - 5 end c = 0 if field_data[j][i] == field_data[j + 1][i] c += 1 end if c > 5 count += c - 5 end end end score += n1 * count # TODO: implement block of count = 0 n.times do |i| (n - 7).times do |j| if field_data[i][j] == true && field_data[i][j + 1] == false && field_data[i][j + 2] == true && field_data[i][j + 3] == true && field_data[i][j + 4] == true && field_data[i][j + 5] == false && field_data[i][j + 6] == true count += 1 end if field_data[j][i] == true && field_data[j + 1][i] == false && field_data[j + 2][i] == true && field_data[j + 3][i] == true && field_data[j + 4][i] == true && field_data[j + 5][i] == false && field_data[j + 6][i] == true count += 1 end end end count -= 12 score += n3 * count count = 0 n.times do |i| n.times do |j| if field_data[i][j] count += 1 end end end k = (10 * (count - n * n / 2).abs) / (n * n / 2) score += n4 * k score end # Applies a given mask (version 0 to 7) to the # field data or the data passed in the field_data parameter. def apply_mask(mask_version, field_data = nil) field_data ||= @field_data if mask_version == 0 field_data.each_with_index do |d,i| dm = @field_mask[i] d.size.times do |j| if dm[j] == nil mask = (((i + j) % 2) == 0) d[j] = (mask != d[j]) end end end elsif mask_version == 1 field_data.each_with_index do |d,i| dm = @field_mask[i] d.size.times do |j| if dm[j] == nil mask = ((i % 2) == 0) d[j] = (mask != d[j]) end end end elsif mask_version == 2 field_data.each_with_index do |d,i| dm = @field_mask[i] d.size.times do |j| if dm[j] == nil mask = ((j % 3) == 0) d[j] = (mask != d[j]) end end end elsif mask_version == 3 field_data.each_with_index do |d,i| dm = @field_mask[i] d.size.times do |j| if dm[j] == nil mask = (((i + j) % 3) == 0) d[j] = (mask != d[j]) end end end elsif mask_version == 4 field_data.each_with_index do |d,i| dm = @field_mask[i] d.size.times do |j| if dm[j] == nil mask = ((((i / 2) + (j / 3)) % 2) == 0) d[j] = (mask != d[j]) end end end elsif mask_version == 5 field_data.each_with_index do |d,i| dm = @field_mask[i] d.size.times do |j| if dm[j] == nil mask = (((i * j) % 2 + (i * j) % 3) == 0) d[j] = (mask != d[j]) end end end elsif mask_version == 6 field_data.each_with_index do |d,i| dm = @field_mask[i] d.size.times do |j| if dm[j] == nil mask = ((((i * j) % 2 + (i * j) % 3) % 2) == 0) d[j] = (mask != d[j]) end end end elsif mask_version == 7 field_data.each_with_index do |d,i| dm = @field_mask[i] d.size.times do |j| if dm[j] == nil mask = ((((i * j) % 3 + (i + j) % 2) % 2) == 0) d[j] = (mask != d[j]) end end end else raise("Invalid mask version #{mask_version}") end end # (For testing) Loads the field data with a given set of bits def load(field) @version = (field.size - 17) / 4 self.build_field_mask(@version) @field_data = field.collect { |d| d.dup } @level = 0 end # Constructor. def initialize @version = @level = @field_data = @field_mask = nil end # Generates a QR code # Input is: the text, the format (:bytes, :numeric or :alphanumeric), the # ECC level (0: L .. 3: H) and the mask version (0 to 7). All arguments # except the first two are optional. In that case, the encoder will make # a suitable choice. def generate(text = "", format = :bytes, level = nil, mask_version = nil) ( @version, @level ) = QREncoder.version_and_level(text, format, level) self.build_field_mask(@version) data = encode(text, format) fill_data(data) if !mask_version max_score = nil 8.times do |mv| score = mask_score(mv) max_score ||= score if score <= max_score mask_version = mv max_score = score end end end apply_mask(mask_version, @field_data) set_format(@level, mask_version) end # Returns the field data def field_data @field_data end # Returns the image size in pixels def image_size @version * 4 + 17 end # (for testing): dump as hex words def dump_hex @field_data.each do |p| d = 0 p.each do |b| d <<= 1 if b d |= 1 end end puts "%x" % d end end # (for testing): dump as ASCII bitmap def dump @field_data.each do |p| s = "" p.each do |b| if b == nil s += "." elsif b == true s += "#" elsif b == false s += "+" else s += "?" end end puts s end end # (for testing): produce a packet binary representation def to_packed_bin data = [] @field_data.each do |p| d = 0 p.each do |b| d = (d << 1) | (b ? 1 : 0) end data << d end data end # (for testing): produce PBM image data def to_pbm(factor, file) n = 17 + @version * 4 file.puts("P1") file.puts("# QR code") file.puts("#{(n + 8) * factor} #{(n + 8) * factor}") (4 * factor).times do file.puts "0 " * (factor * (n + 8)) end n.times do |i| d = @field_data[i] factor.times do line = "0 " * (4 * factor) n.times do |j| factor.times do line += "#{d[j] ? 1 : 0} " end end line += "0 " * (4 * factor) file.puts line end end (4 * factor).times do file.puts "0 " * (factor * (n + 8)) end end end # ----------------------------------------------------------------- # The actual PCell code # Remove any definition of our classes (this helps when # reexecuting this code after a change has been applied) QRCodeLibModule.constants.member?(:QRCode) && remove_const(:QRCode) QRCodeLibModule.constants.member?(:QRCodeLib) && remove_const(:QRCodeLib) # The QRCode PCell declaration class QRCode < RBA::PCellDeclarationHelper def initialize # Important: initialize the super class super # declare the parameters param(:text, TypeString, "Text", :default => "") param(:layer, TypeLayer, "Layer", :default => RBA::LayerInfo::new(1, 0)) param(:pixel_size, TypeDouble, "Pixel size", :default => 1.0) param(:bias, TypeDouble, "Pixel bias", :default => 0.0) param(:format, TypeInt, "Format", :default => 0, :choices => [ [ "Bytes", 0 ], [ "Numeric", 1 ], [ "Alphanumeric", 2 ] ]) param(:ecc_level, TypeInt, "ECC level", :default => 0, :choices => [ [ "Auto", 0 ], [ "L", 1 ], [ "M", 2 ], [ "Q", 3 ], [ "H", 4 ] ]) param(:inverse, TypeBoolean, "Inverse") @qe = nil end def display_text_impl "QR Code (#{self.layer.to_s}, ...)" end def produce_impl @qe ||= QREncoder::new f = :bytes if self.format == 1 f = :numeric elsif self.format == 2 f = :alphanumeric end l = (self.ecc_level > 0 ? self.ecc_level - 1 : nil) @qe.generate(self.text, f, l) fd = @qe.field_data dim = @qe.image_size px = (self.pixel_size / layout.dbu + 0.5).to_i region = RBA::Region::new dim.times do |i| dim.times do |j| if fd[i][j] region.insert(RBA::Box::new(j * px, (dim - 1 - i) * px, (j + 1) * px, (dim - i) * px)) end end end region.size((self.bias / layout.dbu + 0.5).to_i) if self.inverse background = RBA::Region::new background.insert(RBA::Box::new(-4 * px, -4 * px, (dim + 4) * px, (dim + 4) * px)) region = background - region end cell.shapes(layer_layer).insert(region) end end # The PCell library declaration class QRCodeLib < RBA::Library def initialize self.description = "QR code library" # register the PCell declarations layout.register_pcell("QRCode", QRCode::new) # register our library register("QRCodeLib") end end # instantiate and register the library QRCodeLib::new end