You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

170 lines
3.3 KiB

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