diff --git a/mask.go b/mask.go index 687a10d..c9c6b81 100644 --- a/mask.go +++ b/mask.go @@ -126,7 +126,8 @@ func rule2(mat *matrix.Matrix) int { } // 如果存在看起来类似于取景器模式的模式,则第三规则给QR码一个大的惩罚 -// dark-light-dark-dark-dark-light-dark // 1011101 0000 or 0000 1011101 +// dark-light-dark-dark-dark-light-dark +// 1011101 0000 or 0000 1011101 func rule3(mat *matrix.Matrix) int { var ( score int @@ -204,27 +205,29 @@ func abs(x int) int { } type mask struct { - mat *matrix.Matrix // matrix - mode maskPatternModulo // mode + mat *matrix.Matrix // matrix + mode maskPatternModulo // mode + moduloFn moduloFunc // moduloFn masking function } // newMask ... -func newMask(m *matrix.Matrix, mode maskPatternModulo) *mask { - mask := &mask{ - mat: m.Copy(), - mode: mode, +func newMask(mat *matrix.Matrix, mode maskPatternModulo) *mask { + m := &mask{ + mat: mat.Copy(), + mode: mode, + moduloFn: getModuloFunc(mode), } - mask.init() - return mask + m.masking() + + return m } // moduloFunc to define what's modulo func type moduloFunc func(int, int) bool -// init generate maks by mode -func (m *mask) init() { - var f moduloFunc - switch m.mode { +func getModuloFunc(mode maskPatternModulo) (f moduloFunc) { + f = nil + switch mode { case modulo0: f = modulo0Func case modulo1: @@ -243,13 +246,23 @@ func (m *mask) init() { f = modulo7Func } + return +} + +// init generate maks by mode +func (m *mask) masking() { + moduloFn := m.moduloFn + if moduloFn == nil { + panic("impossible panic, contact maintainer plz") + } + m.mat.Iterate(matrix.ROW, func(x, y int, s matrix.State) { // skip the function modules if state, _ := m.mat.Get(x, y); state != matrix.StateInit { _ = m.mat.Set(x, y, matrix.StateInit) return } - if f(x, y) { + if moduloFn(x, y) { _ = m.mat.Set(x, y, matrix.StateTrue) } else { _ = m.mat.Set(x, y, matrix.StateFalse) diff --git a/mask_test.go b/mask_test.go index 41cd413..1a4ea5a 100644 --- a/mask_test.go +++ b/mask_test.go @@ -3,21 +3,29 @@ package qrcode import ( "testing" + "github.com/stretchr/testify/require" + "github.com/yeqown/go-qrcode/matrix" ) func TestMask(t *testing.T) { - qrc, _ := New("baidu.com google.com qq.com sina.com apple.com") - qrc.initMatrix() + qrc := &QRCode{ + content: "baidu.com google.com qq.com sina.com apple.com", + mode: DefaultConfig().EncMode, + ecLv: DefaultConfig().EcLevel, + needAnalyze: true, + outputOption: defaultOutputImageOption(), + } + err := qrc.init() + require.NoError(t, err) var stateInitCnt int - qrc.mat.Iterate(matrix.ROW, func(x, y int, s matrix.State) { if s == matrix.StateInit { stateInitCnt++ } }) - t.Logf("all state init count: %d", stateInitCnt) + t.Logf("all StateInit block count: %d", stateInitCnt) cpyMat := qrc.mat.Copy() _ = drawAndSaveToFile("./testdata/mask_origin.jpeg", *cpyMat, nil) diff --git a/qrcode.go b/qrcode.go index 17ac6d3..838521e 100644 --- a/qrcode.go +++ b/qrcode.go @@ -86,7 +86,7 @@ func NewWithConfig(text string, encOpts *Config, opts ...ImageOption) (*QRCode, } // QRCode contains fields to generate QRCode matrix, outputImageOptions to Draw image, -// and etc. +// etc. type QRCode struct { content string // input text content rawData []byte // raw Data to transfer @@ -99,7 +99,7 @@ type QRCode struct { ver int // version num ecLv ecLevel // error correction level mode encMode // encMode - encoder *encoder // encoder ptr to call it's methods ~ + encoder *encoder // encoder ptr to call its methods ~ needAnalyze bool // auto analyze form content or specified `mode, recoverLv, ver` @@ -116,7 +116,7 @@ func (q *QRCode) init() error { //}) q.rawData = []byte(q.content) if q.needAnalyze { - // analyze the input data to choose adapt version + // analyze the input data to choose to adapt version if err := q.analyze(); err != nil { return fmt.Errorf("could not analyze the data: %v", err) } @@ -160,6 +160,9 @@ func (q *QRCode) init() error { // append remainder bits q.dataBSet.AppendNumBools(q.v.RemainderBits, false) + // initial the 2d matrix + q.prefillMatrix() + return nil } @@ -329,9 +332,9 @@ func (q *QRCode) arrangeBits(dataBlocks []dataBlock, ecBlocks []ecBlock) { debugLogf("ec bitsets: %s", q.ecBSet.String()) } -// InitMatrix with version info: ref to: +// prefillMatrix with version info: ref to: // http://www.thonky.com/qr-code-tutorial/module-placement-matrix -func (q *QRCode) initMatrix() { +func (q *QRCode) prefillMatrix() { dimension := q.v.Dimension() if q.mat == nil { q.mat = matrix.New(dimension, dimension) @@ -515,6 +518,10 @@ func reserveFormatBlock(m *matrix.Matrix, dimension int) { _ = m.Set(dimension-pos, 8, matrix.StateFormat) // top-right-row _ = m.Set(8, dimension-pos, matrix.StateFormat) // bottom-left-column } + + // fix(@yeqown): b4b5ae3 reduced two format reversed blocks on top-left-column and top-left-row. + _ = m.Set(0, 8, matrix.StateFormat) + _ = m.Set(8, 0, matrix.StateFormat) } // reserveVersionBlock maintain the position in matrix for version info @@ -666,9 +673,6 @@ func (q *QRCode) masking() { dimension := q.v.Dimension() - // initial the 2d matrix - q.initMatrix() - // init mask and mats for i := 0; i < 8; i++ { masks[i] = newMask(q.mat, maskPatternModulo(i))