package input // qrCodeGrid is a symbol under construction; fixed marks function modules. type qrCodeGrid struct { v int dark, fixed [][]bool } func newQRCodeGrid(v int) *qrCodeGrid { n := 4*v + 17 g := &qrCodeGrid{v: v, dark: make([][]bool, n), fixed: make([][]bool, n)} for i := range n { g.dark[i], g.fixed[i] = make([]bool, n), make([]bool, n) } for i := range n { g.set(6, i, i%2 == 0) g.set(i, 6, i%2 == 0) } g.finder(3, 3) g.finder(n-4, 3) g.finder(3, n-4) al := qrCodeAlignment(v) for i, x := range al { for j, y := range al { if i == 0 && j == 0 || i == 0 && j == len(al)-1 || i == len(al)-1 && j == 0 { continue } for dy := -2; dy <= 2; dy++ { for dx := -2; dx <= 2; dx++ { g.set(x+dx, y+dy, max(qrCodeAbs(dx), qrCodeAbs(dy)) != 1) } } } } // Reserve format and version areas; apply fills them. g.format(-1, 0) g.version(false) return g } func qrCodeAbs(v int) int { return max(v, -v) } func (g *qrCodeGrid) set(x, y int, dark bool) { g.dark[y][x], g.fixed[y][x] = dark, true } // finder draws a finder pattern and its separator centered at (cx, cy). func (g *qrCodeGrid) finder(cx, cy int) { n := len(g.dark) for dy := -4; dy <= 4; dy++ { for dx := -4; dx <= 4; dx++ { x, y := cx+dx, cy+dy if x < 0 || y < 0 || x >= n || y >= n { continue } d := max(qrCodeAbs(dx), qrCodeAbs(dy)) g.set(x, y, d != 2 && d != 4) } } } // format writes the 15 format bits and the dark module; levelBits -1 leaves them light. func (g *qrCodeGrid) format(levelBits, mask int) { data := levelBits<<3 | mask rem := data for range 10 { rem = rem<<1 ^ (rem>>9)*0x537 } b := (data<<10 | rem) ^ 0x5412 bit := func(i int) bool { return levelBits >= 0 && b>>i&1 == 1 } n := len(g.dark) for i := 0; i <= 5; i++ { g.set(8, i, bit(i)) } g.set(8, 7, bit(6)) g.set(8, 8, bit(7)) g.set(7, 8, bit(8)) for i := 9; i < 15; i++ { g.set(14-i, 8, bit(i)) } for i := range 8 { g.set(n-1-i, 8, bit(i)) } for i := 8; i < 15; i++ { g.set(8, n-15+i, bit(i)) } g.set(8, n-8, levelBits >= 0) } // version writes the 18 version bits from version 7 on, or light ones. func (g *qrCodeGrid) version(on bool) { if g.v < 7 { return } rem := g.v for range 12 { rem = rem<<1 ^ (rem>>11)*0x1F25 } b := g.v<<12 | rem n := len(g.dark) for i := range 18 { dark := on && b>>i&1 == 1 a, c := n-11+i%3, i/3 g.set(a, c, dark) g.set(c, a, dark) } } // place lays the codewords in the zigzag from the bottom right; remainder bits stay light. func (g *qrCodeGrid) place(words []byte) { n := len(g.dark) i := 0 for right := n - 1; right >= 1; right -= 2 { if right == 6 { right = 5 } for vert := range n { for j := range 2 { x := right - j up := (right+1)&2 == 0 y := vert if up { y = n - 1 - vert } if g.fixed[y][x] || i >= len(words)*8 { continue } g.dark[y][x] = words[i/8]>>(7-i%8)&1 == 1 i++ } } } } func (g *qrCodeGrid) clone() *qrCodeGrid { t := &qrCodeGrid{v: g.v, dark: make([][]bool, len(g.dark)), fixed: g.fixed} for i, row := range g.dark { t.dark[i] = append([]bool(nil), row...) } return t } // apply XORs mask over the data modules; the information areas stay light, as 7.8.3 evaluates them. func (g *qrCodeGrid) apply(mask int) { for y, row := range g.dark { for x := range row { if g.fixed[y][x] { continue } var flip bool switch mask { case 0: flip = (x+y)%2 == 0 case 1: flip = y%2 == 0 case 2: flip = x%3 == 0 case 3: flip = (x+y)%3 == 0 case 4: flip = (x/3+y/2)%2 == 0 case 5: flip = x*y%2+x*y%3 == 0 case 6: flip = (x*y%2+x*y%3)%2 == 0 case 7: flip = ((x+y)%2+x*y%3)%2 == 0 } row[x] = row[x] != flip } } } // penalty scores the symbol by the four rules of ISO/IEC 18004 7.8.3. func (g *qrCodeGrid) penalty() int { n := len(g.dark) p, dark := 0, 0 row, col := make([]bool, n), make([]bool, n) for i := range n { for j := range n { row[j], col[j] = g.dark[i][j], g.dark[j][i] if row[j] { dark++ } if i > 0 && j > 0 && row[j] == row[j-1] && row[j] == g.dark[i-1][j] && row[j] == g.dark[i-1][j-1] { p += 3 } } p += qrCodeRuns(row) + qrCodeFinders(row) + qrCodeRuns(col) + qrCodeFinders(col) } return p + 10*(qrCodeAbs(dark*100-50*n*n)/(5*n*n)) } // qrCodeRuns scores runs of five or more equal modules. func qrCodeRuns(seq []bool) int { p, run := 0, 1 for j := 1; j <= len(seq); j++ { if j < len(seq) && seq[j] == seq[j-1] { run++ continue } if run >= 5 { p += run - 2 } run = 1 } return p } // qrCodeFinders scores 1:1:3:1:1 patterns with four light modules on a side. func qrCodeFinders(seq []bool) int { core := [7]bool{true, false, true, true, true, false, true} n, p := len(seq), 0 light := func(a, b int) bool { for i := max(a, 0); i < min(b, n); i++ { if seq[i] { return false } } return true } for idx := 0; idx+7 <= n; { match := true for i, d := range core { if seq[idx+i] != d { match = false break } } if !match { idx++ continue } if idx == 0 || idx == n-7 || light(idx-4, idx) || light(idx+7, idx+11) { p += 40 idx += 7 } else { idx += 4 } } return p }