barcode/qr/qrcode.go

177 lines
3.5 KiB
Go
Raw Permalink Normal View History

2013-12-11 13:31:11 +00:00
package qr
import (
"image"
"image/color"
"math"
2014-08-11 08:34:45 +00:00
2025-01-03 19:41:46 +00:00
"git.bbr-dev.info/brajkovic/barcode"
"git.bbr-dev.info/brajkovic/barcode/utils"
2013-12-11 13:31:11 +00:00
)
type qrcode struct {
dimension int
data *utils.BitList
2013-12-11 13:31:11 +00:00
content string
color barcode.ColorScheme
2013-12-11 13:31:11 +00:00
}
func (qr *qrcode) Content() string {
return qr.content
}
func (qr *qrcode) Metadata() barcode.Metadata {
2017-06-17 21:42:17 +00:00
return barcode.Metadata{barcode.TypeQR, 2}
2013-12-11 13:31:11 +00:00
}
func (qr *qrcode) ColorModel() color.Model {
return qr.color.Model
2013-12-11 13:31:11 +00:00
}
func (c *qrcode) ColorScheme() barcode.ColorScheme {
return c.color
}
2013-12-11 13:31:11 +00:00
func (qr *qrcode) Bounds() image.Rectangle {
return image.Rect(0, 0, qr.dimension, qr.dimension)
}
func (qr *qrcode) At(x, y int) color.Color {
if qr.Get(x, y) {
return qr.color.Foreground
2013-12-11 13:31:11 +00:00
}
return qr.color.Background
2013-12-11 13:31:11 +00:00
}
func (qr *qrcode) Get(x, y int) bool {
return qr.data.GetBit(x*qr.dimension + y)
}
func (qr *qrcode) Set(x, y int, val bool) {
qr.data.SetBit(x*qr.dimension+y, val)
}
func (qr *qrcode) calcPenalty() uint {
return qr.calcPenaltyRule1() + qr.calcPenaltyRule2() + qr.calcPenaltyRule3() + qr.calcPenaltyRule4()
}
func (qr *qrcode) calcPenaltyRule1() uint {
2014-08-11 08:34:45 +00:00
var result uint
2013-12-11 13:31:11 +00:00
for x := 0; x < qr.dimension; x++ {
checkForX := false
2014-08-11 08:34:45 +00:00
var cntX uint
2013-12-11 13:31:11 +00:00
checkForY := false
2014-08-11 08:34:45 +00:00
var cntY uint
2013-12-11 13:31:11 +00:00
for y := 0; y < qr.dimension; y++ {
if qr.Get(x, y) == checkForX {
2014-08-11 08:34:45 +00:00
cntX++
2013-12-11 13:31:11 +00:00
} else {
checkForX = !checkForX
if cntX >= 5 {
result += cntX - 2
}
2013-12-12 13:04:36 +00:00
cntX = 1
2013-12-11 13:31:11 +00:00
}
if qr.Get(y, x) == checkForY {
2014-08-11 08:34:45 +00:00
cntY++
2013-12-11 13:31:11 +00:00
} else {
checkForY = !checkForY
if cntY >= 5 {
result += cntY - 2
}
2013-12-12 13:04:36 +00:00
cntY = 1
2013-12-11 13:31:11 +00:00
}
}
if cntX >= 5 {
result += cntX - 2
}
if cntY >= 5 {
result += cntY - 2
}
}
return result
}
func (qr *qrcode) calcPenaltyRule2() uint {
2014-08-11 08:34:45 +00:00
var result uint
2013-12-11 13:31:11 +00:00
for x := 0; x < qr.dimension-1; x++ {
for y := 0; y < qr.dimension-1; y++ {
check := qr.Get(x, y)
if qr.Get(x, y+1) == check && qr.Get(x+1, y) == check && qr.Get(x+1, y+1) == check {
result += 3
}
}
}
return result
}
func (qr *qrcode) calcPenaltyRule3() uint {
2014-08-11 08:34:45 +00:00
pattern1 := []bool{true, false, true, true, true, false, true, false, false, false, false}
pattern2 := []bool{false, false, false, false, true, false, true, true, true, false, true}
2013-12-11 13:31:11 +00:00
2014-08-11 08:34:45 +00:00
var result uint
2013-12-11 13:31:11 +00:00
for x := 0; x <= qr.dimension-len(pattern1); x++ {
for y := 0; y < qr.dimension; y++ {
pattern1XFound := true
pattern2XFound := true
pattern1YFound := true
pattern2YFound := true
for i := 0; i < len(pattern1); i++ {
iv := qr.Get(x+i, y)
if iv != pattern1[i] {
pattern1XFound = false
}
if iv != pattern2[i] {
pattern2XFound = false
}
iv = qr.Get(y, x+i)
if iv != pattern1[i] {
pattern1YFound = false
}
if iv != pattern2[i] {
pattern2YFound = false
}
}
if pattern1XFound || pattern2XFound {
result += 40
}
if pattern1YFound || pattern2YFound {
result += 40
}
}
}
return result
}
func (qr *qrcode) calcPenaltyRule4() uint {
totalNum := qr.data.Len()
trueCnt := 0
for i := 0; i < totalNum; i++ {
if qr.data.GetBit(i) {
2014-08-11 08:34:45 +00:00
trueCnt++
2013-12-11 13:31:11 +00:00
}
}
percDark := float64(trueCnt) * 100 / float64(totalNum)
floor := math.Abs(math.Floor(percDark/5) - 10)
ceil := math.Abs(math.Ceil(percDark/5) - 10)
return uint(math.Min(floor, ceil) * 10)
}
func newBarCodeWithColor(dim int, color barcode.ColorScheme) *qrcode {
2013-12-11 13:31:11 +00:00
res := new(qrcode)
res.dimension = dim
res.data = utils.NewBitList(dim * dim)
res.color = color
2013-12-11 13:31:11 +00:00
return res
}
func newBarcode(dim int) *qrcode {
return newBarCodeWithColor(dim, barcode.ColorScheme16)
}