summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/skip2/go-qrcode/symbol.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/skip2/go-qrcode/symbol.go')
-rw-r--r--vendor/github.com/skip2/go-qrcode/symbol.go309
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))
+}