...
1 package qr
2
3 import (
4 "image"
5 "image/color"
6 "math"
7
8 "github.com/boombuler/barcode"
9 "github.com/boombuler/barcode/utils"
10 )
11
12 type qrcode struct {
13 dimension int
14 data *utils.BitList
15 content string
16 }
17
18 func (qr *qrcode) Content() string {
19 return qr.content
20 }
21
22 func (qr *qrcode) Metadata() barcode.Metadata {
23 return barcode.Metadata{barcode.TypeQR, 2}
24 }
25
26 func (qr *qrcode) ColorModel() color.Model {
27 return color.Gray16Model
28 }
29
30 func (qr *qrcode) Bounds() image.Rectangle {
31 return image.Rect(0, 0, qr.dimension, qr.dimension)
32 }
33
34 func (qr *qrcode) At(x, y int) color.Color {
35 if qr.Get(x, y) {
36 return color.Black
37 }
38 return color.White
39 }
40
41 func (qr *qrcode) Get(x, y int) bool {
42 return qr.data.GetBit(x*qr.dimension + y)
43 }
44
45 func (qr *qrcode) Set(x, y int, val bool) {
46 qr.data.SetBit(x*qr.dimension+y, val)
47 }
48
49 func (qr *qrcode) calcPenalty() uint {
50 return qr.calcPenaltyRule1() + qr.calcPenaltyRule2() + qr.calcPenaltyRule3() + qr.calcPenaltyRule4()
51 }
52
53 func (qr *qrcode) calcPenaltyRule1() uint {
54 var result uint
55 for x := 0; x < qr.dimension; x++ {
56 checkForX := false
57 var cntX uint
58 checkForY := false
59 var cntY uint
60
61 for y := 0; y < qr.dimension; y++ {
62 if qr.Get(x, y) == checkForX {
63 cntX++
64 } else {
65 checkForX = !checkForX
66 if cntX >= 5 {
67 result += cntX - 2
68 }
69 cntX = 1
70 }
71
72 if qr.Get(y, x) == checkForY {
73 cntY++
74 } else {
75 checkForY = !checkForY
76 if cntY >= 5 {
77 result += cntY - 2
78 }
79 cntY = 1
80 }
81 }
82
83 if cntX >= 5 {
84 result += cntX - 2
85 }
86 if cntY >= 5 {
87 result += cntY - 2
88 }
89 }
90
91 return result
92 }
93
94 func (qr *qrcode) calcPenaltyRule2() uint {
95 var result uint
96 for x := 0; x < qr.dimension-1; x++ {
97 for y := 0; y < qr.dimension-1; y++ {
98 check := qr.Get(x, y)
99 if qr.Get(x, y+1) == check && qr.Get(x+1, y) == check && qr.Get(x+1, y+1) == check {
100 result += 3
101 }
102 }
103 }
104 return result
105 }
106
107 func (qr *qrcode) calcPenaltyRule3() uint {
108 pattern1 := []bool{true, false, true, true, true, false, true, false, false, false, false}
109 pattern2 := []bool{false, false, false, false, true, false, true, true, true, false, true}
110
111 var result uint
112 for x := 0; x <= qr.dimension-len(pattern1); x++ {
113 for y := 0; y < qr.dimension; y++ {
114 pattern1XFound := true
115 pattern2XFound := true
116 pattern1YFound := true
117 pattern2YFound := true
118
119 for i := 0; i < len(pattern1); i++ {
120 iv := qr.Get(x+i, y)
121 if iv != pattern1[i] {
122 pattern1XFound = false
123 }
124 if iv != pattern2[i] {
125 pattern2XFound = false
126 }
127 iv = qr.Get(y, x+i)
128 if iv != pattern1[i] {
129 pattern1YFound = false
130 }
131 if iv != pattern2[i] {
132 pattern2YFound = false
133 }
134 }
135 if pattern1XFound || pattern2XFound {
136 result += 40
137 }
138 if pattern1YFound || pattern2YFound {
139 result += 40
140 }
141 }
142 }
143
144 return result
145 }
146
147 func (qr *qrcode) calcPenaltyRule4() uint {
148 totalNum := qr.data.Len()
149 trueCnt := 0
150 for i := 0; i < totalNum; i++ {
151 if qr.data.GetBit(i) {
152 trueCnt++
153 }
154 }
155 percDark := float64(trueCnt) * 100 / float64(totalNum)
156 floor := math.Abs(math.Floor(percDark/5) - 10)
157 ceil := math.Abs(math.Ceil(percDark/5) - 10)
158 return uint(math.Min(floor, ceil) * 10)
159 }
160
161 func newBarcode(dim int) *qrcode {
162 res := new(qrcode)
163 res.dimension = dim
164 res.data = utils.NewBitList(dim * dim)
165 return res
166 }
167
View as plain text