Skip to content

Commit

Permalink
Merge pull request #63 from yeqown/v3
Browse files Browse the repository at this point in the history
preparation for v3 milestone: refactor matrix and support halftone pattern in standard writer
  • Loading branch information
yeqown authored Feb 17, 2022
2 parents 17d8b68 + 511dc53 commit 3dec383
Show file tree
Hide file tree
Showing 37 changed files with 1,130 additions and 734 deletions.
Binary file modified assets/repository_qrcode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 6 additions & 8 deletions debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import (
"log"
"os"
"sync"

"github.com/yeqown/go-qrcode/v2/matrix"
)

var (
Expand Down Expand Up @@ -44,7 +42,7 @@ func debugLogf(format string, v ...interface{}) {
log.Printf("[qrcode] DEBUG: "+format, v...)
}

func debugDraw(filename string, mat matrix.Matrix) error {
func debugDraw(filename string, mat Matrix) error {
if !debugEnabled() {
return nil
}
Expand All @@ -60,7 +58,7 @@ func debugDraw(filename string, mat matrix.Matrix) error {
return debugDrawTo(fd, mat)
}

func debugDrawTo(w io.Writer, mat matrix.Matrix) error {
func debugDrawTo(w io.Writer, mat Matrix) error {
if !debugEnabled() {
return nil
}
Expand All @@ -81,18 +79,18 @@ func debugDrawTo(w io.Writer, mat matrix.Matrix) error {
}

// background
rectangle(0, 0, width, height, img, color.White)
rectangle(0, 0, width, height, img, color.Gray16{Y: 0xff12})

mat.Iterate(matrix.COLUMN, func(x int, y int, v matrix.State) {
mat.iter(IterDirection_COLUMN, func(x int, y int, v qrvalue) {
sx := x*blockWidth + padding
sy := y*blockWidth + padding
es := (x+1)*blockWidth + padding
ey := (y+1)*blockWidth + padding

// choose color, false use black, others use black on white background
var gray color.Gray16
switch v {
case matrix.StateFalse:
switch v.qrbool() {
case false:
gray = color.White
default:
gray = color.Black
Expand Down
4 changes: 2 additions & 2 deletions encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
type encMode uint

const (
// a value of EncModeAuto will trigger a detection of the letter set from the input data,
// a qrbool of EncModeAuto will trigger a detection of the letter set from the input data,
EncModeAuto = 0
// EncModeNone mode ...
EncModeNone encMode = 1 << iota
Expand Down Expand Up @@ -345,6 +345,6 @@ func analyzeAlphaNum(byt byte) bool {
}

//// analyzeByte is byt in bytes.
//func analyzeByte(byt byte) bool {
//func analyzeByte(byt byte) qrbool {
// return false
//}
12 changes: 7 additions & 5 deletions example/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.17

require (
github.com/yeqown/go-qrcode v1.5.10
github.com/yeqown/go-qrcode/v2 v2.0.1
github.com/yeqown/go-qrcode/v2 v2.1.0
github.com/yeqown/go-qrcode/writer/standard v1.1.1
github.com/yeqown/go-qrcode/writer/terminal v1.0.0-beta
)
Expand All @@ -16,9 +16,11 @@ require (
github.com/nsf/termbox-go v1.1.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/yeqown/reedsolomon v1.0.0 // indirect
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 // indirect
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect
)

replace github.com/yeqown/go-qrcode/v2 => ../
replace github.com/yeqown/go-qrcode/writer/standard => ../writer/standard
//replace github.com/yeqown/go-qrcode/writer/terminal v1.0.0-beta => ../writer/terminal
replace (
github.com/yeqown/go-qrcode/v2 => ../
github.com/yeqown/go-qrcode/writer/standard => ../writer/standard
github.com/yeqown/go-qrcode/writer/terminal v1.0.0-beta => ../writer/terminal
)
2 changes: 1 addition & 1 deletion example/simple/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

func main() {
qrc, err := qrcode.NewWith("github.com/yeqown/qo-qrcode",
qrc, err := qrcode.NewWith("github.com/yeqown/go-qrcode",
qrcode.WithEncodingMode(qrcode.EncModeByte),
qrcode.WithErrorCorrectionLevel(qrcode.ErrorCorrectionQuart),
)
Expand Down
6 changes: 3 additions & 3 deletions example/with-custom-shape/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func newShape(radiusPercent float64) standard.IShape {

func (sc *smallerCircle) Draw(ctx *standard.DrawContext) {
w, h := ctx.Edge()
upperLeft := ctx.UpperLeft()
x, y := ctx.UpperLeft()
color := ctx.Color()

// choose a proper radius values
Expand All @@ -35,8 +35,8 @@ func (sc *smallerCircle) Draw(ctx *standard.DrawContext) {
// 80 percent smaller
radius = int(float64(radius) * sc.smallerPercent)

cx, cy := upperLeft.X+w/2, upperLeft.Y+h/2 // get center point
ctx.DrawCircle(float64(cx), float64(cy), float64(radius))
cx, cy := x+float64(w)/2.0, y+float64(h)/2.0 // get center point
ctx.DrawCircle(cx, cy, float64(radius))
ctx.SetColor(color)
ctx.Fill()

Expand Down
Binary file added example/with-halftone/halftone-qr.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions example/with-halftone/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package main

import (
"github.com/yeqown/go-qrcode/v2"
"github.com/yeqown/go-qrcode/writer/standard"
)

func main() {
qrc, err := qrcode.New("https://github.com/yeqown/go-qrcode")
if err != nil {
panic(err)
}

w0, err := standard.New("./repository_qrcode.png",
standard.WithHalftone("./test.jpeg"),
standard.WithQRWidth(21),
)
handleErr(err)
err = qrc.Save(w0)
handleErr(err)
}

func handleErr(err error) {
if err != nil {
panic(err)
}
}
Binary file added example/with-halftone/test.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 5 additions & 7 deletions kmp_variant_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,14 @@ import (
"testing"

"github.com/stretchr/testify/assert"

"github.com/yeqown/go-qrcode/v2/matrix"
)

func Test_kmp(t *testing.T) {
src := binaryToStateSlice("11001010010111001010010101011100")
src := binaryToQRValueSlice("11001010010111001010010101011100")

type args struct {
src []matrix.State
pattern []matrix.State
src []qrvalue
pattern []qrvalue
}
tests := []struct {
name string
Expand All @@ -24,15 +22,15 @@ func Test_kmp(t *testing.T) {
name: "test1",
args: args{
src: src,
pattern: binaryToStateSlice("0101"),
pattern: binaryToQRValueSlice("0101"),
},
wantCount: 6,
},
{
name: "test1",
args: args{
src: src,
pattern: binaryToStateSlice("1001010"),
pattern: binaryToQRValueSlice("1001010"),
},
wantCount: 3,
},
Expand Down
18 changes: 7 additions & 11 deletions mask.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package qrcode

import (
"github.com/yeqown/go-qrcode/v2/matrix"
)

// maskPatternModulo ...
// mask Pattern ref to: https://www.thonky.com/qr-code-tutorial/mask-patterns
type maskPatternModulo uint32
Expand All @@ -28,13 +24,13 @@ const (
)

type mask struct {
mat *matrix.Matrix // matrix
mat *Matrix // matrix
mode maskPatternModulo // mode
moduloFn moduloFunc // moduloFn masking function
}

// newMask ...
func newMask(mat *matrix.Matrix, mode maskPatternModulo) *mask {
func newMask(mat *Matrix, mode maskPatternModulo) *mask {
m := &mask{
mat: mat.Copy(),
mode: mode,
Expand Down Expand Up @@ -79,16 +75,16 @@ func (m *mask) masking() {
panic("impossible panic, contact maintainer plz")
}

m.mat.Iterate(matrix.COLUMN, func(x, y int, s matrix.State) {
m.mat.iter(IterDirection_COLUMN, func(x, y int, s qrvalue) {
// skip the function modules
if state, _ := m.mat.Get(x, y); state != matrix.StateInit {
_ = m.mat.Set(x, y, matrix.StateInit)
if v, _ := m.mat.at(x, y); v.qrtype() != QRType_INIT {
_ = m.mat.set(x, y, QRValue_INIT_V0)
return
}
if moduloFn(x, y) {
_ = m.mat.Set(x, y, matrix.StateTrue)
_ = m.mat.set(x, y, QRValue_DATA_V1)
} else {
_ = m.mat.Set(x, y, matrix.StateFalse)
_ = m.mat.set(x, y, QRValue_DATA_V0)
}
})
}
Expand Down
44 changes: 21 additions & 23 deletions mask_evaluation.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@ package qrcode

import (
"math"

"github.com/yeqown/go-qrcode/v2/matrix"
)

// evaluation calculate a score after masking matrix.
//
// reference:
// - https://www.thonky.com/qr-code-tutorial/data-masking#Determining-the-Best-Mask
func evaluation(mat *matrix.Matrix) (score int) {
func evaluation(mat *Matrix) (score int) {
debugLogf("calculate maskScore starting")

score1 := rule1(mat)
Expand All @@ -27,7 +25,7 @@ func evaluation(mat *matrix.Matrix) (score int) {
// add 3 to the penalty. If there are more modules of the same color after the first five,
// add 1 for each additional module of the same color. Afterward, check each column one-by-one,
// checking for the same condition. Add the horizontal and vertical total to obtain penalty score
func rule1(mat *matrix.Matrix) (score int) {
func rule1(mat *Matrix) (score int) {
// prerequisites:
// mat.Width() == mat.Height()
if mat.Width() != mat.Height() {
Expand All @@ -36,24 +34,24 @@ func rule1(mat *matrix.Matrix) (score int) {
}

dimension := mat.Width()
scoreLine := func(arr []matrix.State) int {
lineScore, cnt, curState := 0, 0, matrix.StateInit
scoreLine := func(arr []qrvalue) int {
lScore, cnt, cur := 0, 0, QRValue_INIT_V0
for _, v := range arr {
if !samestate(v, curState) {
curState = v
if !samestate(v, cur) {
cur = v
cnt = 1
continue
}

cnt++
if cnt == 5 {
lineScore += 3
lScore += 3
} else if cnt > 5 {
lineScore++
lScore++
}
}

return lineScore
return lScore
}

for cur := 0; cur < dimension; cur++ {
Expand All @@ -70,17 +68,17 @@ func rule1(mat *matrix.Matrix) (score int) {
// look for areas of the same color that are at least 2x2 modules or larger.
// The QR code specification says that for a solid-color block of size m × n,
// the penalty score is 3 × (m - 1) × (n - 1).
func rule2(mat *matrix.Matrix) int {
func rule2(mat *Matrix) int {
var (
score int
s0, s1, s2, s3 matrix.State
s0, s1, s2, s3 qrvalue
)
for x := 0; x < mat.Width()-1; x++ {
for y := 0; y < mat.Height()-1; y++ {
s0, _ = mat.Get(x, y)
s1, _ = mat.Get(x+1, y)
s2, _ = mat.Get(x, y+1)
s3, _ = mat.Get(x+1, y+1)
s0, _ = mat.at(x, y)
s1, _ = mat.at(x+1, y)
s2, _ = mat.at(x, y+1)
s3, _ = mat.at(x+1, y+1)

if s0 == s1 && s2 == s3 && s1 == s2 {
score += 3
Expand All @@ -97,10 +95,10 @@ func rule2(mat *matrix.Matrix) int {
// following two patterns: 1011101 0000 or 0000 1011101.
//
// Each time this pattern is found, add 40 to the penalty score.
func rule3(mat *matrix.Matrix) (score int) {
func rule3(mat *Matrix) (score int) {
var (
pattern1 = binaryToStateSlice("1011101 0000")
pattern2 = binaryToStateSlice("0000 1011101")
pattern1 = binaryToQRValueSlice("1011101 0000")
pattern2 = binaryToQRValueSlice("0000 1011101")
pattern1Next = kmpGetNext(pattern1)
pattern2Next = kmpGetNext(pattern2)
)
Expand Down Expand Up @@ -135,11 +133,11 @@ func rule3(mat *matrix.Matrix) (score int) {
// 2. Count how many dark modules there are in the matrix.
// 3. Calculate the percent of modules in the matrix that are dark: (darkmodules / totalmodules) * 100
// 4. Determine the previous and next multiple of five of this percent.
// 5. Subtract 50 from each of these multiples of five and take the absolute value of the result.
// 5. Subtract 50 from each of these multiples of five and take the absolute qrbool of the result.
// 6. Divide each of these by five. For example, 10/5 = 2 and 5/5 = 1.
// 7. Finally, take the smallest of the two numbers and multiply it by 10.
//
func rule4(mat *matrix.Matrix) int {
func rule4(mat *Matrix) int {
// prerequisites:
//
// mat.Width() == mat.Height()
Expand All @@ -155,7 +153,7 @@ func rule4(mat *matrix.Matrix) int {

// count dark modules
for j := 0; j < dimension; j++ {
if samestate(col[j], matrix.StateTrue) {
if samestate(col[j], QRValue_DATA_V1) {
dark++
}
}
Expand Down
6 changes: 3 additions & 3 deletions mask_evaluation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

//func Test_rule3_refactor(t *testing.T) {
// qrc, err := New("baidu.com google.com qq.com sina.com apple.com")
// qrc, err := newMatrix("baidu.com google.com qq.com sina.com apple.com")
// assert.NoError(t, err)
// _ = qrc
// old := rule3_backup(qrc.mat)
Expand All @@ -26,7 +26,7 @@ func Benchmark_rule3(b *testing.B) {
}

//func Test_rule1_refactor(t *testing.T) {
// qrc, err := New("baidu.com google.com qq.com sina.com apple.com")
// qrc, err := newMatrix("baidu.com google.com qq.com sina.com apple.com")
// assert.NoError(t, err)
// qrc.mat.Print()
//
Expand All @@ -46,7 +46,7 @@ func Benchmark_rule1(b *testing.B) {
}

//func Test_rule4_refactor(t *testing.T) {
// qrc, err := New("baidu.com google.com qq.com sina.com apple.com")
// qrc, err := newMatrix("baidu.com google.com qq.com sina.com apple.com")
// assert.NoError(t, err)
// //qrc.mat.Print()
//
Expand Down
Loading

0 comments on commit 3dec383

Please sign in to comment.