diff options
Diffstat (limited to 'vendor/github.com/skip2/go-qrcode/symbol.go')
-rw-r--r-- | vendor/github.com/skip2/go-qrcode/symbol.go | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/vendor/github.com/skip2/go-qrcode/symbol.go b/vendor/github.com/skip2/go-qrcode/symbol.go new file mode 100644 index 00000000..0cb1327c --- /dev/null +++ b/vendor/github.com/skip2/go-qrcode/symbol.go @@ -0,0 +1,309 @@ +// go-qrcode +// Copyright 2014 Tom Harwood + +package qrcode + +// symbol is a 2D array of bits representing a QR Code symbol. +// +// A symbol consists of size*size modules, with each module normally drawn as a +// black or white square. The symbol also has a border of quietZoneSize modules. +// +// A (fictional) size=2, quietZoneSize=1 QR Code looks like: +// +// +----+ +// | | +// | ab | +// | cd | +// | | +// +----+ +// +// For ease of implementation, the functions to set/get bits ignore the border, +// so (0,0)=a, (0,1)=b, (1,0)=c, and (1,1)=d. The entire symbol (including the +// border) is returned by bitmap(). +// +type symbol struct { + // Value of module at [y][x]. True is set. + module [][]bool + + // True if the module at [y][x] is used (to either true or false). + // Used to identify unused modules. + isUsed [][]bool + + // Combined width/height of the symbol and quiet zones. + // + // size = symbolSize + 2*quietZoneSize. + size int + + // Width/height of the symbol only. + symbolSize int + + // Width/height of a single quiet zone. + quietZoneSize int +} + +// newSymbol constructs a symbol of size size*size, with a border of +// quietZoneSize. +func newSymbol(size int, quietZoneSize int) *symbol { + var m symbol + + m.module = make([][]bool, size+2*quietZoneSize) + m.isUsed = make([][]bool, size+2*quietZoneSize) + + for i := range m.module { + m.module[i] = make([]bool, size+2*quietZoneSize) + m.isUsed[i] = make([]bool, size+2*quietZoneSize) + } + + m.size = size + 2*quietZoneSize + m.symbolSize = size + m.quietZoneSize = quietZoneSize + + return &m +} + +// get returns the module value at (x, y). +func (m *symbol) get(x int, y int) (v bool) { + v = m.module[y+m.quietZoneSize][x+m.quietZoneSize] + return +} + +// empty returns true if the module at (x, y) has not been set (to either true +// or false). +func (m *symbol) empty(x int, y int) bool { + return !m.isUsed[y+m.quietZoneSize][x+m.quietZoneSize] +} + +// numEmptyModules returns the number of empty modules. +// +// Initially numEmptyModules is symbolSize * symbolSize. After every module has +// been set (to either true or false), the number of empty modules is zero. +func (m *symbol) numEmptyModules() int { + var count int + for y := 0; y < m.symbolSize; y++ { + for x := 0; x < m.symbolSize; x++ { + if !m.isUsed[y+m.quietZoneSize][x+m.quietZoneSize] { + count++ + } + } + } + + return count +} + +// set sets the module at (x, y) to v. +func (m *symbol) set(x int, y int, v bool) { + m.module[y+m.quietZoneSize][x+m.quietZoneSize] = v + m.isUsed[y+m.quietZoneSize][x+m.quietZoneSize] = true +} + +// set2dPattern sets a 2D array of modules, starting at (x, y). +func (m *symbol) set2dPattern(x int, y int, v [][]bool) { + for j, row := range v { + for i, value := range row { + m.set(x+i, y+j, value) + } + } +} + +// bitmap returns the entire symbol, including the quiet zone. +func (m *symbol) bitmap() [][]bool { + module := make([][]bool, len(m.module)) + + for i := range m.module { + module[i] = m.module[i][:] + } + + return module +} + +// string returns a pictorial representation of the symbol, suitable for +// printing in a TTY. +func (m *symbol) string() string { + var result string + + for _, row := range m.module { + for _, value := range row { + switch value { + case true: + result += " " + case false: + // Unicode 'FULL BLOCK' (U+2588). + result += "██" + } + } + result += "\n" + } + + return result +} + +// Constants used to weight penalty calculations. Specified by ISO/IEC +// 18004:2006. +const ( + penaltyWeight1 = 3 + penaltyWeight2 = 3 + penaltyWeight3 = 40 + penaltyWeight4 = 10 +) + +// penaltyScore returns the penalty score of the symbol. The penalty score +// consists of the sum of the four individual penalty types. +func (m *symbol) penaltyScore() int { + return m.penalty1() + m.penalty2() + m.penalty3() + m.penalty4() +} + +// penalty1 returns the penalty score for "adjacent modules in row/column with +// same colour". +// +// The numbers of adjacent matching modules and scores are: +// 0-5: score = 0 +// 6+ : score = penaltyWeight1 + (numAdjacentModules - 5) +func (m *symbol) penalty1() int { + penalty := 0 + + for x := 0; x < m.symbolSize; x++ { + lastValue := m.get(x, 0) + count := 1 + + for y := 1; y < m.symbolSize; y++ { + v := m.get(x, y) + + if v != lastValue { + count = 1 + lastValue = v + } else { + count++ + if count == 6 { + penalty += penaltyWeight1 + 1 + } else if count > 6 { + penalty++ + } + } + } + } + + for y := 0; y < m.symbolSize; y++ { + lastValue := m.get(0, y) + count := 1 + + for x := 1; x < m.symbolSize; x++ { + v := m.get(x, y) + + if v != lastValue { + count = 1 + lastValue = v + } else { + count++ + if count == 6 { + penalty += penaltyWeight1 + 1 + } else if count > 6 { + penalty++ + } + } + } + } + + return penalty +} + +// penalty2 returns the penalty score for "block of modules in the same colour". +// +// m*n: score = penaltyWeight2 * (m-1) * (n-1). +func (m *symbol) penalty2() int { + penalty := 0 + + for y := 1; y < m.symbolSize; y++ { + for x := 1; x < m.symbolSize; x++ { + topLeft := m.get(x-1, y-1) + above := m.get(x, y-1) + left := m.get(x-1, y) + current := m.get(x, y) + + if current == left && current == above && current == topLeft { + penalty++ + } + } + } + + return penalty * penaltyWeight2 +} + +// penalty3 returns the penalty score for "1:1:3:1:1 ratio +// (dark:light:dark:light:dark) pattern in row/column, preceded or followed by +// light area 4 modules wide". +// +// Existence of the pattern scores penaltyWeight3. +func (m *symbol) penalty3() int { + penalty := 0 + + for y := 0; y < m.symbolSize; y++ { + var bitBuffer int16 = 0x00 + + for x := 0; x < m.symbolSize; x++ { + bitBuffer <<= 1 + if v := m.get(x, y); v { + bitBuffer |= 1 + } + + switch bitBuffer & 0x7ff { + // 0b000 0101 1101 or 0b10111010000 + // 0x05d or 0x5d0 + case 0x05d, 0x5d0: + penalty += penaltyWeight3 + bitBuffer = 0xFF + default: + if x == m.symbolSize-1 && (bitBuffer&0x7f) == 0x5d { + penalty += penaltyWeight3 + bitBuffer = 0xFF + } + } + } + } + + for x := 0; x < m.symbolSize; x++ { + var bitBuffer int16 = 0x00 + + for y := 0; y < m.symbolSize; y++ { + bitBuffer <<= 1 + if v := m.get(x, y); v { + bitBuffer |= 1 + } + + switch bitBuffer & 0x7ff { + // 0b000 0101 1101 or 0b10111010000 + // 0x05d or 0x5d0 + case 0x05d, 0x5d0: + penalty += penaltyWeight3 + bitBuffer = 0xFF + default: + if y == m.symbolSize-1 && (bitBuffer&0x7f) == 0x5d { + penalty += penaltyWeight3 + bitBuffer = 0xFF + } + } + } + } + + return penalty +} + +// penalty4 returns the penalty score... +func (m *symbol) penalty4() int { + numModules := m.symbolSize * m.symbolSize + numDarkModules := 0 + + for x := 0; x < m.symbolSize; x++ { + for y := 0; y < m.symbolSize; y++ { + if v := m.get(x, y); v { + numDarkModules++ + } + } + } + + numDarkModuleDeviation := numModules/2 - numDarkModules + if numDarkModuleDeviation < 0 { + numDarkModuleDeviation *= -1 + } + + return penaltyWeight4 * (numDarkModuleDeviation / (numModules / 20)) +} |