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