123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- // 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))
- }
|