mirror of
				https://github.com/go-gitea/gitea
				synced 2025-10-31 11:28:24 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			167 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package qr
 | |
| 
 | |
| import (
 | |
| 	"image"
 | |
| 	"image/color"
 | |
| 	"math"
 | |
| 
 | |
| 	"github.com/boombuler/barcode"
 | |
| 	"github.com/boombuler/barcode/utils"
 | |
| )
 | |
| 
 | |
| type qrcode struct {
 | |
| 	dimension int
 | |
| 	data      *utils.BitList
 | |
| 	content   string
 | |
| }
 | |
| 
 | |
| func (qr *qrcode) Content() string {
 | |
| 	return qr.content
 | |
| }
 | |
| 
 | |
| func (qr *qrcode) Metadata() barcode.Metadata {
 | |
| 	return barcode.Metadata{barcode.TypeQR, 2}
 | |
| }
 | |
| 
 | |
| func (qr *qrcode) ColorModel() color.Model {
 | |
| 	return color.Gray16Model
 | |
| }
 | |
| 
 | |
| 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 color.Black
 | |
| 	}
 | |
| 	return color.White
 | |
| }
 | |
| 
 | |
| 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 {
 | |
| 	var result uint
 | |
| 	for x := 0; x < qr.dimension; x++ {
 | |
| 		checkForX := false
 | |
| 		var cntX uint
 | |
| 		checkForY := false
 | |
| 		var cntY uint
 | |
| 
 | |
| 		for y := 0; y < qr.dimension; y++ {
 | |
| 			if qr.Get(x, y) == checkForX {
 | |
| 				cntX++
 | |
| 			} else {
 | |
| 				checkForX = !checkForX
 | |
| 				if cntX >= 5 {
 | |
| 					result += cntX - 2
 | |
| 				}
 | |
| 				cntX = 1
 | |
| 			}
 | |
| 
 | |
| 			if qr.Get(y, x) == checkForY {
 | |
| 				cntY++
 | |
| 			} else {
 | |
| 				checkForY = !checkForY
 | |
| 				if cntY >= 5 {
 | |
| 					result += cntY - 2
 | |
| 				}
 | |
| 				cntY = 1
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if cntX >= 5 {
 | |
| 			result += cntX - 2
 | |
| 		}
 | |
| 		if cntY >= 5 {
 | |
| 			result += cntY - 2
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| func (qr *qrcode) calcPenaltyRule2() uint {
 | |
| 	var result uint
 | |
| 	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 {
 | |
| 	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}
 | |
| 
 | |
| 	var result uint
 | |
| 	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) {
 | |
| 			trueCnt++
 | |
| 		}
 | |
| 	}
 | |
| 	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 newBarcode(dim int) *qrcode {
 | |
| 	res := new(qrcode)
 | |
| 	res.dimension = dim
 | |
| 	res.data = utils.NewBitList(dim * dim)
 | |
| 	return res
 | |
| }
 |