mirror of
				https://github.com/go-gitea/gitea
				synced 2025-11-03 21:08:25 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			167 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
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
 | 
						|
}
 |