├── .gitignore ├── go.mod ├── utils ├── runeint.go ├── runeint_test.go ├── reedsolomon.go ├── galoisfield.go ├── base1dcode.go ├── galoisfield_test.go ├── bitlist.go └── gfpoly.go ├── qr ├── unicode_test.go ├── automatic.go ├── errorcorrection.go ├── unicode.go ├── automatic_test.go ├── numeric_test.go ├── alphanumeric_test.go ├── numeric.go ├── alphanumeric.go ├── blocks.go ├── blocks_test.go ├── qrcode_test.go ├── encoder_test.go ├── qrcode.go ├── versioninfo_test.go ├── errorcorrection_test.go └── versioninfo.go ├── .golangci.yml ├── datamatrix ├── errorcorrection_test.go ├── errorcorrection.go ├── datamatrixcode.go ├── codesize.go ├── encoder.go ├── datamatrix_test.go └── codelayout.go ├── .github └── workflows │ ├── golangci-lint.yml │ └── test.yml ├── codabar ├── encoder_test.go └── encoder.go ├── pdf417 ├── pdfcode.go ├── dimensions.go ├── highlevel_test.go ├── encoder.go ├── errorcorrection_test.go ├── errorcorrection.go └── highlevel.go ├── LICENSE ├── code39 ├── encoder_test.go └── encoder.go ├── barcode.go ├── code93 ├── encoder_test.go └── encoder.go ├── README.md ├── twooffive ├── encoder_test.go └── encoder.go ├── color_scheme.go ├── ean ├── encoder_test.go └── encoder.go ├── aztec ├── azteccode.go ├── errorcorrection.go ├── token.go ├── encoder_test.go ├── highlevel_test.go ├── aztec_test.go ├── highlevel.go ├── state.go └── encoder.go ├── scaledbarcode.go └── code128 ├── encode_test.go ├── encode.go └── encodingtable.go /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/boombuler/barcode 2 | -------------------------------------------------------------------------------- /utils/runeint.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | // RuneToInt converts a rune between '0' and '9' to an integer between 0 and 9 4 | // If the rune is outside of this range -1 is returned. 5 | func RuneToInt(r rune) int { 6 | if r >= '0' && r <= '9' { 7 | return int(r - '0') 8 | } 9 | return -1 10 | } 11 | 12 | // IntToRune converts a digit 0 - 9 to the rune '0' - '9'. If the given int is outside 13 | // of this range 'F' is returned! 14 | func IntToRune(i int) rune { 15 | if i >= 0 && i <= 9 { 16 | return rune(i + '0') 17 | } 18 | return 'F' 19 | } 20 | -------------------------------------------------------------------------------- /qr/unicode_test.go: -------------------------------------------------------------------------------- 1 | package qr 2 | 3 | import ( 4 | "bytes" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func Test_UnicodeEncoding(t *testing.T) { 10 | encode := Unicode.getEncoder() 11 | x, vi, err := encode("A", H) // 65 12 | if x == nil || vi == nil || vi.Version != 1 || !bytes.Equal(x.GetBytes(), []byte{64, 20, 16, 236, 17, 236, 17, 236, 17}) { 13 | t.Errorf("\"A\" failed to encode: %s", err) 14 | } 15 | _, _, err = encode(strings.Repeat("A", 3000), H) 16 | if err == nil { 17 | t.Error("Unicode encoding should not be able to encode a 3kb string") 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | # Configuration of formatting and linting using https://golangci-lint.run/. 2 | version: "2" 3 | 4 | linters: 5 | default: none 6 | enable: 7 | - errcheck 8 | - govet 9 | - ineffassign 10 | - staticcheck 11 | - unused 12 | 13 | formatters: 14 | enable: 15 | - gofmt 16 | - goimports 17 | 18 | issues: 19 | # Show only new issues created after the introduction of the linter. 20 | new-from-rev: ea5ac7e13561f6334938261321e13a725d1c0180 21 | 22 | # Show issues in any part of update files (requires new-from-rev or new-from-patch). 23 | whole-files: true 24 | -------------------------------------------------------------------------------- /qr/automatic.go: -------------------------------------------------------------------------------- 1 | package qr 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/boombuler/barcode/utils" 7 | ) 8 | 9 | func encodeAuto(content string, ecl ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error) { 10 | bits, vi, _ := Numeric.getEncoder()(content, ecl) 11 | if bits != nil && vi != nil { 12 | return bits, vi, nil 13 | } 14 | bits, vi, _ = AlphaNumeric.getEncoder()(content, ecl) 15 | if bits != nil && vi != nil { 16 | return bits, vi, nil 17 | } 18 | bits, vi, _ = Unicode.getEncoder()(content, ecl) 19 | if bits != nil && vi != nil { 20 | return bits, vi, nil 21 | } 22 | return nil, nil, fmt.Errorf("no encoding found to encode %q", content) 23 | } 24 | -------------------------------------------------------------------------------- /datamatrix/errorcorrection_test.go: -------------------------------------------------------------------------------- 1 | package datamatrix 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | func Test_CalcECC(t *testing.T) { 9 | data := []byte{142, 164, 186} 10 | var size *dmCodeSize = nil 11 | for _, s := range codeSizes { 12 | if s.DataCodewords() >= len(data) { 13 | size = s 14 | break 15 | } 16 | } 17 | if size == nil { 18 | t.Error("size not found") 19 | } 20 | 21 | if !bytes.Equal(ec.calcECC(data, size), []byte{142, 164, 186, 114, 25, 5, 88, 102}) { 22 | t.Error("ECC Test 1 failed") 23 | } 24 | data = []byte{66, 129, 70} 25 | if !bytes.Equal(ec.calcECC(data, size), []byte{66, 129, 70, 138, 234, 82, 82, 95}) { 26 | t.Error("ECC Test 2 failed") 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.github/workflows/golangci-lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | golangci: 15 | name: lint 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - uses: actions/setup-go@v5 22 | with: 23 | go-version: stable 24 | 25 | - name: golangci-lint 26 | uses: golangci/golangci-lint-action@v8 27 | with: 28 | version: v2.1 29 | # Show only new issues until the entire repository 30 | # is compliant with the new linting rules. 31 | only-new-issues: true 32 | -------------------------------------------------------------------------------- /utils/runeint_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "testing" 4 | 5 | func Test_RuneToIntIntToRune(t *testing.T) { 6 | if IntToRune(0) != '0' { 7 | t.Errorf("failed IntToRune(0) returned %d", IntToRune(0)) 8 | } 9 | if IntToRune(9) != '9' { 10 | t.Errorf("failed IntToRune(9) returned %d", IntToRune(9)) 11 | } 12 | if IntToRune(10) != 'F' { 13 | t.Errorf("failed IntToRune(10) returned %d", IntToRune(10)) 14 | } 15 | if RuneToInt('0') != 0 { 16 | t.Errorf("failed RuneToInt('0') returned %d", RuneToInt(0)) 17 | } 18 | if RuneToInt('9') != 9 { 19 | t.Errorf("failed RuneToInt('9') returned %d", RuneToInt(9)) 20 | } 21 | if RuneToInt('F') != -1 { 22 | t.Errorf("failed RuneToInt('F') returned %d", RuneToInt('F')) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /qr/errorcorrection.go: -------------------------------------------------------------------------------- 1 | package qr 2 | 3 | import ( 4 | "github.com/boombuler/barcode/utils" 5 | ) 6 | 7 | type errorCorrection struct { 8 | rs *utils.ReedSolomonEncoder 9 | } 10 | 11 | var ec = newErrorCorrection() 12 | 13 | func newErrorCorrection() *errorCorrection { 14 | fld := utils.NewGaloisField(285, 256, 0) 15 | return &errorCorrection{utils.NewReedSolomonEncoder(fld)} 16 | } 17 | 18 | func (ec *errorCorrection) calcECC(data []byte, eccCount byte) []byte { 19 | dataInts := make([]int, len(data)) 20 | for i := 0; i < len(data); i++ { 21 | dataInts[i] = int(data[i]) 22 | } 23 | res := ec.rs.Encode(dataInts, int(eccCount)) 24 | result := make([]byte, len(res)) 25 | for i := 0; i < len(res); i++ { 26 | result[i] = byte(res[i]) 27 | } 28 | return result 29 | } 30 | -------------------------------------------------------------------------------- /qr/unicode.go: -------------------------------------------------------------------------------- 1 | package qr 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/boombuler/barcode/utils" 7 | ) 8 | 9 | func encodeUnicode(content string, ecl ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error) { 10 | data := []byte(content) 11 | 12 | vi := findSmallestVersionInfo(ecl, byteMode, len(data)*8) 13 | if vi == nil { 14 | return nil, nil, errors.New("too much data to encode") 15 | } 16 | 17 | // It's not correct to add the unicode bytes to the result directly but most readers can't handle the 18 | // required ECI header... 19 | res := new(utils.BitList) 20 | res.AddBits(int(byteMode), 4) 21 | res.AddBits(len(content), vi.charCountBits(byteMode)) 22 | for _, b := range data { 23 | res.AddByte(b) 24 | } 25 | addPaddingAndTerminator(res, vi) 26 | return res, vi, nil 27 | } 28 | -------------------------------------------------------------------------------- /codabar/encoder_test.go: -------------------------------------------------------------------------------- 1 | package codabar 2 | 3 | import ( 4 | "image/color" 5 | "testing" 6 | ) 7 | 8 | func Test_Encode(t *testing.T) { 9 | _, err := Encode("FOOBAR") 10 | if err == nil { 11 | t.Error("\"FOOBAR\" should not be encodable") 12 | } 13 | 14 | testEncode := func(txt, testResult string) { 15 | code, err := Encode(txt) 16 | if err != nil || code == nil { 17 | t.Fail() 18 | } else { 19 | if code.Bounds().Max.X != len(testResult) { 20 | t.Errorf("%v: length missmatch", txt) 21 | } else { 22 | for i, r := range testResult { 23 | if (code.At(i, 0) == color.Black) != (r == '1') { 24 | t.Errorf("%v: code missmatch on position %d", txt, i) 25 | } 26 | } 27 | } 28 | } 29 | } 30 | 31 | testEncode("A40156B", "10110010010101101001010101001101010110010110101001010010101101001001011") 32 | } 33 | -------------------------------------------------------------------------------- /qr/automatic_test.go: -------------------------------------------------------------------------------- 1 | package qr 2 | 3 | import ( 4 | "bytes" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func Test_AutomaticEncoding(t *testing.T) { 10 | tests := map[string]encodeFn{ 11 | "0123456789": Numeric.getEncoder(), 12 | "ALPHA NUMERIC": AlphaNumeric.getEncoder(), 13 | "unicode encoing": Unicode.getEncoder(), 14 | "very long unicode encoding" + strings.Repeat("A", 3000): nil, 15 | } 16 | 17 | for str, enc := range tests { 18 | testValue, _, _ := Auto.getEncoder()(str, M) 19 | if enc != nil { 20 | correctValue, _, _ := enc(str, M) 21 | if testValue == nil || !bytes.Equal(correctValue.GetBytes(), testValue.GetBytes()) { 22 | t.Errorf("wrong encoding used for '%s'", str) 23 | } 24 | } else { 25 | if testValue != nil { 26 | t.Errorf("wrong encoding used for '%s'", str) 27 | } 28 | } 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | test: 15 | runs-on: ubuntu-latest 16 | strategy: 17 | matrix: 18 | # Test currently supported Go releases. 19 | # 20 | # See: https://go.dev/doc/devel/release#policy 21 | go-version: 22 | - stable 23 | - oldstable 24 | 25 | steps: 26 | - uses: actions/checkout@v4 27 | 28 | - name: Set up Go ${{ matrix.go-version }} 29 | uses: actions/setup-go@v5 30 | with: 31 | go-version: ${{ matrix.go-version }} 32 | # Caching isn't really needed without any dependencies, 33 | # and without a go.sum this action will emit warnings. 34 | # 35 | # See: https://github.com/actions/setup-go/issues/476 36 | cache: false 37 | 38 | - name: Test 39 | run: go test -v ./... 40 | -------------------------------------------------------------------------------- /qr/numeric_test.go: -------------------------------------------------------------------------------- 1 | package qr 2 | 3 | import ( 4 | "bytes" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func Test_NumericEncoding(t *testing.T) { 10 | encode := Numeric.getEncoder() 11 | x, vi, err := encode("01234567", H) 12 | if err != nil { 13 | t.Fatal(err) 14 | } 15 | if x == nil || vi == nil || vi.Version != 1 || !bytes.Equal(x.GetBytes(), []byte{16, 32, 12, 86, 97, 128, 236, 17, 236}) { 16 | t.Error("\"01234567\" failed to encode") 17 | } 18 | x, vi, err = encode("0123456789012345", H) 19 | if err != nil { 20 | t.Fatal(err) 21 | } 22 | if x == nil || vi == nil || vi.Version != 1 || !bytes.Equal(x.GetBytes(), []byte{16, 64, 12, 86, 106, 110, 20, 234, 80}) { 23 | t.Error("\"0123456789012345\" failed to encode") 24 | } 25 | _, _, err = encode("foo", H) 26 | if err == nil { 27 | t.Error("Numeric encoding should not be able to encode \"foo\"") 28 | } 29 | x, vi, err = encode(strings.Repeat("1", 14297), H) 30 | if x != nil || vi != nil || err == nil { 31 | t.Fail() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /qr/alphanumeric_test.go: -------------------------------------------------------------------------------- 1 | package qr 2 | 3 | import ( 4 | "bytes" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func Test_AlphaNumericEncoding(t *testing.T) { 10 | encode := AlphaNumeric.getEncoder() 11 | 12 | x, vi, err := encode("HELLO WORLD", M) 13 | 14 | if x == nil || vi == nil || vi.Version != 1 || !bytes.Equal(x.GetBytes(), []byte{32, 91, 11, 120, 209, 114, 220, 77, 67, 64, 236, 17, 236, 17, 236, 17}) { 15 | t.Errorf("\"HELLO WORLD\" failed to encode: %s", err) 16 | } 17 | 18 | x, vi, err = encode(strings.Repeat("A", 4296), L) 19 | if x == nil || vi == nil || err != nil { 20 | t.Fail() 21 | } 22 | x, vi, err = encode(strings.Repeat("A", 4297), L) 23 | if x != nil || vi != nil || err == nil { 24 | t.Fail() 25 | } 26 | x, vi, err = encode("ABc", L) 27 | if x != nil || vi != nil || err == nil { 28 | t.Fail() 29 | } 30 | x, vi, err = encode("hello world", M) 31 | 32 | if x != nil || vi != nil || err == nil { 33 | t.Error("\"hello world\" should not be encodable in alphanumeric mode") 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /pdf417/pdfcode.go: -------------------------------------------------------------------------------- 1 | package pdf417 2 | 3 | import ( 4 | "image" 5 | "image/color" 6 | 7 | "github.com/boombuler/barcode" 8 | "github.com/boombuler/barcode/utils" 9 | ) 10 | 11 | type pdfBarcode struct { 12 | data string 13 | width int 14 | code *utils.BitList 15 | color barcode.ColorScheme 16 | } 17 | 18 | func (c *pdfBarcode) Metadata() barcode.Metadata { 19 | return barcode.Metadata{CodeKind: barcode.TypePDF, Dimensions: 2} 20 | } 21 | 22 | func (c *pdfBarcode) Content() string { 23 | return c.data 24 | } 25 | 26 | func (c *pdfBarcode) ColorModel() color.Model { 27 | return c.color.Model 28 | } 29 | 30 | func (c *pdfBarcode) ColorScheme() barcode.ColorScheme { 31 | return c.color 32 | } 33 | 34 | func (c *pdfBarcode) Bounds() image.Rectangle { 35 | height := c.code.Len() / c.width 36 | 37 | return image.Rect(0, 0, c.width, height*moduleHeight) 38 | } 39 | 40 | func (c *pdfBarcode) At(x, y int) color.Color { 41 | if c.code.GetBit((y/moduleHeight)*c.width + x) { 42 | return c.color.Foreground 43 | } 44 | return c.color.Background 45 | } 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Florian Sundermann 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pdf417/dimensions.go: -------------------------------------------------------------------------------- 1 | package pdf417 2 | 3 | import "math" 4 | 5 | const ( 6 | minCols = 2 7 | maxCols = 30 8 | maxRows = 30 9 | minRows = 2 10 | moduleHeight = 2 11 | preferred_ratio = 3.0 12 | ) 13 | 14 | func calculateNumberOfRows(m, k, c int) int { 15 | r := ((m + 1 + k) / c) + 1 16 | if c*r >= (m + 1 + k + c) { 17 | r-- 18 | } 19 | return r 20 | } 21 | 22 | func calcDimensions(dataWords, eccWords int) (cols, rows int) { 23 | ratio := 0.0 24 | cols = 0 25 | rows = 0 26 | 27 | for c := minCols; c <= maxCols; c++ { 28 | r := calculateNumberOfRows(dataWords, eccWords, c) 29 | 30 | if r < minRows { 31 | break 32 | } 33 | 34 | if r > maxRows { 35 | continue 36 | } 37 | 38 | newRatio := float64(17*cols+69) / float64(rows*moduleHeight) 39 | if rows != 0 && math.Abs(newRatio-preferred_ratio) > math.Abs(ratio-preferred_ratio) { 40 | continue 41 | } 42 | 43 | ratio = newRatio 44 | cols = c 45 | rows = r 46 | } 47 | 48 | if rows == 0 { 49 | r := calculateNumberOfRows(dataWords, eccWords, minCols) 50 | if r < minRows { 51 | rows = minRows 52 | cols = minCols 53 | } 54 | } 55 | 56 | return 57 | } 58 | -------------------------------------------------------------------------------- /code39/encoder_test.go: -------------------------------------------------------------------------------- 1 | package code39 2 | 3 | import ( 4 | "image/color" 5 | "testing" 6 | ) 7 | 8 | func doTest(t *testing.T, addCS, fullASCII bool, data, testResult string) { 9 | code, err := Encode(data, addCS, fullASCII) 10 | if err != nil { 11 | t.Error(err) 12 | } 13 | if len(testResult) != code.Bounds().Max.X { 14 | t.Errorf("Invalid code size. Expected %d got %d", len(testResult), code.Bounds().Max.X) 15 | } 16 | for i, r := range testResult { 17 | if (code.At(i, 0) == color.Black) != (r == '1') { 18 | t.Errorf("Failed at position %d", i) 19 | } 20 | } 21 | } 22 | 23 | func Test_Encode(t *testing.T) { 24 | doTest(t, false, false, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 25 | "1001011011010110101001011010110100101101101101001010101011001011011010110010101"+ 26 | "011011001010101010011011011010100110101011010011010101011001101011010101001101011010"+ 27 | "100110110110101001010101101001101101011010010101101101001010101011001101101010110010"+ 28 | "101101011001010101101100101100101010110100110101011011001101010101001011010110110010"+ 29 | "110101010011011010101010011011010110100101011010110010101101101100101010101001101011"+ 30 | "011010011010101011001101010101001011011011010010110101011001011010100101101101") 31 | } 32 | -------------------------------------------------------------------------------- /barcode.go: -------------------------------------------------------------------------------- 1 | package barcode 2 | 3 | import ( 4 | "image" 5 | ) 6 | 7 | const ( 8 | TypeAztec = "Aztec" 9 | TypeCodabar = "Codabar" 10 | TypeCode128 = "Code 128" 11 | TypeCode39 = "Code 39" 12 | TypeCode93 = "Code 93" 13 | TypeDataMatrix = "DataMatrix" 14 | TypeEAN8 = "EAN 8" 15 | TypeEAN13 = "EAN 13" 16 | TypePDF = "PDF417" 17 | TypeQR = "QR Code" 18 | Type2of5 = "2 of 5" 19 | Type2of5Interleaved = "2 of 5 (interleaved)" 20 | ) 21 | 22 | // Contains some meta information about a barcode 23 | type Metadata struct { 24 | // the name of the barcode kind 25 | CodeKind string 26 | // contains 1 for 1D barcodes or 2 for 2D barcodes 27 | Dimensions byte 28 | } 29 | 30 | // a rendered and encoded barcode 31 | type Barcode interface { 32 | image.Image 33 | // returns some meta information about the barcode 34 | Metadata() Metadata 35 | // the data that was encoded in this barcode 36 | Content() string 37 | } 38 | 39 | // Additional interface that some barcodes might implement to provide 40 | // the value of its checksum. 41 | type BarcodeIntCS interface { 42 | Barcode 43 | CheckSum() int 44 | } 45 | 46 | type BarcodeColor interface { 47 | ColorScheme() ColorScheme 48 | } 49 | -------------------------------------------------------------------------------- /utils/reedsolomon.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | type ReedSolomonEncoder struct { 8 | gf *GaloisField 9 | polynomes []*GFPoly 10 | m *sync.Mutex 11 | } 12 | 13 | func NewReedSolomonEncoder(gf *GaloisField) *ReedSolomonEncoder { 14 | return &ReedSolomonEncoder{ 15 | gf, []*GFPoly{NewGFPoly(gf, []int{1})}, new(sync.Mutex), 16 | } 17 | } 18 | 19 | func (rs *ReedSolomonEncoder) getPolynomial(degree int) *GFPoly { 20 | rs.m.Lock() 21 | defer rs.m.Unlock() 22 | 23 | if degree >= len(rs.polynomes) { 24 | last := rs.polynomes[len(rs.polynomes)-1] 25 | for d := len(rs.polynomes); d <= degree; d++ { 26 | next := last.Multiply(NewGFPoly(rs.gf, []int{1, rs.gf.ALogTbl[d-1+rs.gf.Base]})) 27 | rs.polynomes = append(rs.polynomes, next) 28 | last = next 29 | } 30 | } 31 | return rs.polynomes[degree] 32 | } 33 | 34 | func (rs *ReedSolomonEncoder) Encode(data []int, eccCount int) []int { 35 | generator := rs.getPolynomial(eccCount) 36 | info := NewGFPoly(rs.gf, data) 37 | info = info.MultByMonominal(eccCount, 1) 38 | _, remainder := info.Divide(generator) 39 | 40 | result := make([]int, eccCount) 41 | numZero := int(eccCount) - len(remainder.Coefficients) 42 | copy(result[numZero:], remainder.Coefficients) 43 | return result 44 | } 45 | -------------------------------------------------------------------------------- /datamatrix/errorcorrection.go: -------------------------------------------------------------------------------- 1 | package datamatrix 2 | 3 | import ( 4 | "github.com/boombuler/barcode/utils" 5 | ) 6 | 7 | type errorCorrection struct { 8 | rs *utils.ReedSolomonEncoder 9 | } 10 | 11 | var ec *errorCorrection = newErrorCorrection() 12 | 13 | func newErrorCorrection() *errorCorrection { 14 | gf := utils.NewGaloisField(301, 256, 1) 15 | 16 | return &errorCorrection{utils.NewReedSolomonEncoder(gf)} 17 | } 18 | 19 | func (ec *errorCorrection) calcECC(data []byte, size *dmCodeSize) []byte { 20 | dataSize := len(data) 21 | // make some space for error correction codes 22 | data = append(data, make([]byte, size.ECCCount)...) 23 | 24 | for block := 0; block < size.BlockCount; block++ { 25 | dataCnt := size.DataCodewordsForBlock(block) 26 | 27 | buff := make([]int, dataCnt) 28 | // copy the data for the current block to buff 29 | j := 0 30 | for i := block; i < dataSize; i += size.BlockCount { 31 | buff[j] = int(data[i]) 32 | j++ 33 | } 34 | // calc the error correction codes 35 | ecc := ec.rs.Encode(buff, size.ErrorCorrectionCodewordsPerBlock()) 36 | // and append them to the result 37 | j = 0 38 | for i := block; i < size.ErrorCorrectionCodewordsPerBlock()*size.BlockCount; i += size.BlockCount { 39 | data[dataSize+i] = byte(ecc[j]) 40 | j++ 41 | } 42 | } 43 | 44 | return data 45 | } 46 | -------------------------------------------------------------------------------- /pdf417/highlevel_test.go: -------------------------------------------------------------------------------- 1 | package pdf417 2 | 3 | import "testing" 4 | 5 | func compareIntSlice(t *testing.T, expected, actual []int, testStr string) { 6 | if len(actual) != len(expected) { 7 | t.Errorf("Invalid slice size. Expected %d got %d while encoding %q", len(expected), len(actual), testStr) 8 | return 9 | } 10 | for i, a := range actual { 11 | if e := expected[i]; e != a { 12 | t.Errorf("Unexpected value at position %d. Expected %d got %d while encoding %q", i, e, a, testStr) 13 | } 14 | } 15 | } 16 | 17 | func TestHighlevelEncode(t *testing.T) { 18 | runTest := func(msg string, expected ...int) { 19 | if codes, err := highlevelEncode(msg); err != nil { 20 | t.Error(err) 21 | } else { 22 | compareIntSlice(t, expected, codes, msg) 23 | } 24 | } 25 | 26 | runTest("01234", 902, 112, 434) 27 | runTest("Super !", 567, 615, 137, 809, 329) 28 | runTest("Super ", 567, 615, 137, 809) 29 | runTest("ABC123", 1, 88, 32, 119) 30 | runTest("123ABC", 841, 63, 840, 32) 31 | } 32 | 33 | func TestBinaryEncoder(t *testing.T) { 34 | runTest := func(msg string, expected ...int) { 35 | codes := encodeBinary([]byte(msg), encText) 36 | compareIntSlice(t, expected, codes, msg) 37 | } 38 | 39 | runTest("alcool", 924, 163, 238, 432, 766, 244) 40 | runTest("alcoolique", 901, 163, 238, 432, 766, 244, 105, 113, 117, 101) 41 | } 42 | -------------------------------------------------------------------------------- /code93/encoder_test.go: -------------------------------------------------------------------------------- 1 | package code93 2 | 3 | import ( 4 | "image/color" 5 | "testing" 6 | ) 7 | 8 | func doTest(t *testing.T, data, testResult string) { 9 | code, err := Encode(data, true, false) 10 | if err != nil { 11 | t.Error(err) 12 | } 13 | if len(testResult) != code.Bounds().Max.X { 14 | t.Errorf("Invalid code size. Expected %d got %d", len(testResult), code.Bounds().Max.X) 15 | } 16 | for i, r := range testResult { 17 | if (code.At(i, 0) == color.Black) != (r == '1') { 18 | t.Errorf("Failed at position %d", i) 19 | } 20 | } 21 | } 22 | 23 | func Test_CheckSum(t *testing.T) { 24 | if r := getChecksum("TEST93", 20); r != '+' { 25 | t.Errorf("Checksum C-Failed. Got %s", string(r)) 26 | } 27 | if r := getChecksum("TEST93+", 15); r != '6' { 28 | t.Errorf("Checksum K-Failed. Got %s", string(r)) 29 | } 30 | } 31 | 32 | func Test_Encode(t *testing.T) { 33 | doTest(t, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 34 | "1010111101101010001101001001101000101100101001100100101100010101011010001011001"+ 35 | "001011000101001101001000110101010110001010011001010001101001011001000101101101101001"+ 36 | "101100101101011001101001101100101101100110101011011001011001101001101101001110101000"+ 37 | "101001010010001010001001010000101001010001001001001001000101010100001000100101000010"+ 38 | "101001110101010000101010111101") 39 | } 40 | -------------------------------------------------------------------------------- /qr/numeric.go: -------------------------------------------------------------------------------- 1 | package qr 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "strconv" 7 | 8 | "github.com/boombuler/barcode/utils" 9 | ) 10 | 11 | func encodeNumeric(content string, ecl ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error) { 12 | contentBitCount := (len(content) / 3) * 10 13 | switch len(content) % 3 { 14 | case 1: 15 | contentBitCount += 4 16 | case 2: 17 | contentBitCount += 7 18 | } 19 | vi := findSmallestVersionInfo(ecl, numericMode, contentBitCount) 20 | if vi == nil { 21 | return nil, nil, errors.New("too much data to encode") 22 | } 23 | res := new(utils.BitList) 24 | res.AddBits(int(numericMode), 4) 25 | res.AddBits(len(content), vi.charCountBits(numericMode)) 26 | 27 | for pos := 0; pos < len(content); pos += 3 { 28 | var curStr string 29 | if pos+3 <= len(content) { 30 | curStr = content[pos : pos+3] 31 | } else { 32 | curStr = content[pos:] 33 | } 34 | 35 | i, err := strconv.Atoi(curStr) 36 | if err != nil || i < 0 { 37 | return nil, nil, fmt.Errorf("%q can not be encoded as %s", content, Numeric) 38 | } 39 | var bitCnt byte 40 | switch len(curStr) % 3 { 41 | case 0: 42 | bitCnt = 10 43 | case 1: 44 | bitCnt = 4 45 | case 2: 46 | bitCnt = 7 47 | } 48 | 49 | res.AddBits(i, bitCnt) 50 | } 51 | 52 | addPaddingAndTerminator(res, vi) 53 | return res, vi, nil 54 | } 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Join the chat at https://gitter.im/golang-barcode/Lobby](https://badges.gitter.im/golang-barcode/Lobby.svg)](https://gitter.im/golang-barcode/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 2 | 3 | ## Introduction ## 4 | 5 | This is a package for GO which can be used to create different types of barcodes. 6 | 7 | ## Supported Barcode Types ## 8 | * 2 of 5 9 | * Aztec Code 10 | * Codabar 11 | * Code 128 12 | * Code 39 13 | * Code 93 14 | * Datamatrix 15 | * EAN 13 16 | * EAN 8 17 | * PDF 417 18 | * QR Code 19 | 20 | ## Example ## 21 | 22 | This is a simple example on how to create a QR-Code and write it to a png-file 23 | ```go 24 | package main 25 | 26 | import ( 27 | "image/png" 28 | "os" 29 | 30 | "github.com/boombuler/barcode" 31 | "github.com/boombuler/barcode/qr" 32 | ) 33 | 34 | func main() { 35 | // Create the barcode 36 | qrCode, _ := qr.Encode("Hello World", qr.M, qr.Auto) 37 | 38 | // Scale the barcode to 200x200 pixels 39 | qrCode, _ = barcode.Scale(qrCode, 200, 200) 40 | 41 | // create the output file 42 | file, _ := os.Create("qrcode.png") 43 | defer file.Close() 44 | 45 | // encode the barcode as png 46 | png.Encode(file, qrCode) 47 | } 48 | ``` 49 | 50 | ## Documentation ## 51 | See [GoDoc](https://godoc.org/github.com/boombuler/barcode) 52 | 53 | To create a barcode use the Encode function from one of the subpackages. 54 | -------------------------------------------------------------------------------- /twooffive/encoder_test.go: -------------------------------------------------------------------------------- 1 | package twooffive 2 | 3 | import ( 4 | "image/color" 5 | "testing" 6 | ) 7 | 8 | func Test_AddCheckSum(t *testing.T) { 9 | if sum, err := AddCheckSum("1234567"); err != nil || sum != "12345670" { 10 | t.Fail() 11 | } 12 | if _, err := AddCheckSum("1ABC"); err == nil { 13 | t.Fail() 14 | } 15 | if _, err := AddCheckSum(""); err == nil { 16 | t.Fail() 17 | } 18 | } 19 | 20 | func Test_Encode(t *testing.T) { 21 | _, err := Encode("FOOBAR", false) 22 | if err == nil { 23 | t.Error("\"FOOBAR\" should not be encodable") 24 | } 25 | 26 | testEncode := func(interleaved bool, txt, testResult string) { 27 | code, err := Encode(txt, interleaved) 28 | if err != nil || code == nil { 29 | t.Fail() 30 | } else { 31 | if code.Bounds().Max.X != len(testResult) { 32 | t.Errorf("%v: length missmatch! %v != %v", txt, code.Bounds().Max.X, len(testResult)) 33 | } else { 34 | for i, r := range testResult { 35 | if (code.At(i, 0) == color.Black) != (r == '1') { 36 | t.Errorf("%v: code missmatch on position %d", txt, i) 37 | } 38 | } 39 | } 40 | } 41 | } 42 | 43 | testEncode(false, "12345670", "1101101011101010101110101110101011101110111010101010101110101110111010111010101011101110101010101011101110101011101110101101011") 44 | testEncode(true, "12345670", "101011101000101011100011101110100010100011101000111000101010101000111000111011101") 45 | } 46 | -------------------------------------------------------------------------------- /color_scheme.go: -------------------------------------------------------------------------------- 1 | package barcode 2 | 3 | import "image/color" 4 | 5 | // ColorScheme defines a structure for color schemes used in barcode rendering. 6 | // It includes the color model, background color, and foreground color. 7 | type ColorScheme struct { 8 | Model color.Model // Color model to be used (e.g., grayscale, RGB, RGBA) 9 | Background color.Color // Color of the background 10 | Foreground color.Color // Color of the foreground (e.g., bars in a barcode) 11 | } 12 | 13 | // ColorScheme8 represents a color scheme with 8-bit grayscale colors. 14 | var ColorScheme8 = ColorScheme{ 15 | Model: color.GrayModel, 16 | Background: color.Gray{Y: 255}, 17 | Foreground: color.Gray{Y: 0}, 18 | } 19 | 20 | // ColorScheme16 represents a color scheme with 16-bit grayscale colors. 21 | var ColorScheme16 = ColorScheme{ 22 | Model: color.Gray16Model, 23 | Background: color.White, 24 | Foreground: color.Black, 25 | } 26 | 27 | // ColorScheme24 represents a color scheme with 24-bit RGB colors. 28 | var ColorScheme24 = ColorScheme{ 29 | Model: color.RGBAModel, 30 | Background: color.RGBA{255, 255, 255, 255}, 31 | Foreground: color.RGBA{0, 0, 0, 255}, 32 | } 33 | 34 | // ColorScheme32 represents a color scheme with 32-bit RGBA colors, which is similar to ColorScheme24 but typically includes alpha for transparency. 35 | var ColorScheme32 = ColorScheme{ 36 | Model: color.RGBAModel, 37 | Background: color.RGBA{255, 255, 255, 255}, 38 | Foreground: color.RGBA{0, 0, 0, 255}, 39 | } 40 | -------------------------------------------------------------------------------- /ean/encoder_test.go: -------------------------------------------------------------------------------- 1 | package ean 2 | 3 | import ( 4 | "image/color" 5 | "testing" 6 | ) 7 | 8 | func testHelper(t *testing.T, testCode, testResult, kind string, checkMetadata bool) { 9 | code, err := Encode(testCode) 10 | if err != nil { 11 | t.Error(err) 12 | } 13 | if checkMetadata && (code.Metadata().Dimensions != 1 || code.Content() != testCode || code.Metadata().CodeKind != kind) { 14 | t.Error("Metadata missmatch") 15 | } 16 | if len(testResult) != code.Bounds().Max.X { 17 | t.Fail() 18 | } 19 | for i, r := range testResult { 20 | if (code.At(i, 0) == color.Black) != (r == '1') { 21 | t.Fail() 22 | } 23 | } 24 | } 25 | 26 | func Test_EncodeEAN(t *testing.T) { 27 | testHelper(t, "5901234123457", "10100010110100111011001100100110111101001110101010110011011011001000010101110010011101000100101", "EAN 13", true) 28 | testHelper(t, "55123457", "1010110001011000100110010010011010101000010101110010011101000100101", "EAN 8", true) 29 | testHelper(t, "5512345", "1010110001011000100110010010011010101000010101110010011101000100101", "EAN 8", false) 30 | _, err := Encode("55123458") //<-- Invalid checksum 31 | if err == nil { 32 | t.Error("Invalid checksum not detected") 33 | } 34 | _, err = Encode("invalid") 35 | if err == nil { 36 | t.Error("\"invalid\" should not be encodable") 37 | } 38 | _, err = Encode("invalid") 39 | if err == nil { 40 | t.Error("\"invalid\" should not be encodable") 41 | } 42 | bits := encodeEAN13("invalid error") 43 | if bits != nil { 44 | t.Error("\"invalid error\" should not be encodable") 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /aztec/azteccode.go: -------------------------------------------------------------------------------- 1 | package aztec 2 | 3 | import ( 4 | "bytes" 5 | "image" 6 | "image/color" 7 | 8 | "github.com/boombuler/barcode" 9 | "github.com/boombuler/barcode/utils" 10 | ) 11 | 12 | type aztecCode struct { 13 | *utils.BitList 14 | size int 15 | content []byte 16 | color barcode.ColorScheme 17 | } 18 | 19 | func newAztecCode(size int, color barcode.ColorScheme) *aztecCode { 20 | return &aztecCode{utils.NewBitList(size * size), size, nil, barcode.ColorScheme16} 21 | } 22 | 23 | func (c *aztecCode) Content() string { 24 | return string(c.content) 25 | } 26 | 27 | func (c *aztecCode) Metadata() barcode.Metadata { 28 | return barcode.Metadata{CodeKind: barcode.TypeAztec, Dimensions: 2} 29 | } 30 | 31 | func (c *aztecCode) ColorModel() color.Model { 32 | return c.color.Model 33 | } 34 | 35 | func (c *aztecCode) ColorScheme() barcode.ColorScheme { 36 | return c.color 37 | } 38 | 39 | func (c *aztecCode) Bounds() image.Rectangle { 40 | return image.Rect(0, 0, c.size, c.size) 41 | } 42 | 43 | func (c *aztecCode) At(x, y int) color.Color { 44 | if c.GetBit(x*c.size + y) { 45 | return c.color.Foreground 46 | } 47 | return c.color.Background 48 | } 49 | 50 | func (c *aztecCode) set(x, y int) { 51 | c.SetBit(x*c.size+y, true) 52 | } 53 | 54 | func (c *aztecCode) string() string { 55 | buf := new(bytes.Buffer) 56 | for y := 0; y < c.size; y++ { 57 | for x := 0; x < c.size; x++ { 58 | if c.GetBit(x*c.size + y) { 59 | buf.WriteString("X ") 60 | } else { 61 | buf.WriteString(" ") 62 | } 63 | } 64 | buf.WriteRune('\n') 65 | } 66 | return buf.String() 67 | } 68 | -------------------------------------------------------------------------------- /datamatrix/datamatrixcode.go: -------------------------------------------------------------------------------- 1 | package datamatrix 2 | 3 | import ( 4 | "image" 5 | "image/color" 6 | 7 | "github.com/boombuler/barcode" 8 | "github.com/boombuler/barcode/utils" 9 | ) 10 | 11 | type datamatrixCode struct { 12 | *utils.BitList 13 | *dmCodeSize 14 | content string 15 | color barcode.ColorScheme 16 | } 17 | 18 | func newDataMatrixCodeWithColor(size *dmCodeSize, color barcode.ColorScheme) *datamatrixCode { 19 | return &datamatrixCode{utils.NewBitList(size.Rows * size.Columns), size, "", color} 20 | } 21 | 22 | func newDataMatrixCode(size *dmCodeSize) *datamatrixCode { 23 | return &datamatrixCode{utils.NewBitList(size.Rows * size.Columns), size, "", barcode.ColorScheme16} 24 | } 25 | 26 | func (c *datamatrixCode) Content() string { 27 | return c.content 28 | } 29 | 30 | func (c *datamatrixCode) Metadata() barcode.Metadata { 31 | return barcode.Metadata{CodeKind: barcode.TypeDataMatrix, Dimensions: 2} 32 | } 33 | 34 | func (c *datamatrixCode) ColorModel() color.Model { 35 | return c.color.Model 36 | } 37 | 38 | func (c *datamatrixCode) ColorScheme() barcode.ColorScheme { 39 | return c.color 40 | } 41 | 42 | func (c *datamatrixCode) Bounds() image.Rectangle { 43 | return image.Rect(0, 0, c.Columns, c.Rows) 44 | } 45 | 46 | func (c *datamatrixCode) At(x, y int) color.Color { 47 | if c.get(x, y) { 48 | return c.color.Foreground 49 | } 50 | return c.color.Background 51 | } 52 | 53 | func (c *datamatrixCode) get(x, y int) bool { 54 | return c.GetBit(x*c.Rows + y) 55 | } 56 | 57 | func (c *datamatrixCode) set(x, y int, value bool) { 58 | c.SetBit(x*c.Rows+y, value) 59 | } 60 | -------------------------------------------------------------------------------- /utils/galoisfield.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | // GaloisField encapsulates galois field arithmetics 4 | type GaloisField struct { 5 | Size int 6 | Base int 7 | ALogTbl []int 8 | LogTbl []int 9 | } 10 | 11 | // NewGaloisField creates a new galois field 12 | func NewGaloisField(pp, fieldSize, b int) *GaloisField { 13 | result := new(GaloisField) 14 | 15 | result.Size = fieldSize 16 | result.Base = b 17 | result.ALogTbl = make([]int, fieldSize) 18 | result.LogTbl = make([]int, fieldSize) 19 | 20 | x := 1 21 | for i := 0; i < fieldSize; i++ { 22 | result.ALogTbl[i] = x 23 | x = x * 2 24 | if x >= fieldSize { 25 | x = (x ^ pp) & (fieldSize - 1) 26 | } 27 | } 28 | 29 | for i := 0; i < fieldSize; i++ { 30 | result.LogTbl[result.ALogTbl[i]] = int(i) 31 | } 32 | 33 | return result 34 | } 35 | 36 | func (gf *GaloisField) Zero() *GFPoly { 37 | return NewGFPoly(gf, []int{0}) 38 | } 39 | 40 | // AddOrSub add or substract two numbers 41 | func (gf *GaloisField) AddOrSub(a, b int) int { 42 | return a ^ b 43 | } 44 | 45 | // Multiply multiplys two numbers 46 | func (gf *GaloisField) Multiply(a, b int) int { 47 | if a == 0 || b == 0 { 48 | return 0 49 | } 50 | return gf.ALogTbl[(gf.LogTbl[a]+gf.LogTbl[b])%(gf.Size-1)] 51 | } 52 | 53 | // Divide divides two numbers 54 | func (gf *GaloisField) Divide(a, b int) int { 55 | if b == 0 { 56 | panic("divide by zero") 57 | } else if a == 0 { 58 | return 0 59 | } 60 | return gf.ALogTbl[(gf.LogTbl[a]-gf.LogTbl[b])%(gf.Size-1)] 61 | } 62 | 63 | func (gf *GaloisField) Invers(num int) int { 64 | return gf.ALogTbl[(gf.Size-1)-gf.LogTbl[num]] 65 | } 66 | -------------------------------------------------------------------------------- /qr/alphanumeric.go: -------------------------------------------------------------------------------- 1 | package qr 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "strings" 7 | 8 | "github.com/boombuler/barcode/utils" 9 | ) 10 | 11 | const charSet string = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:" 12 | 13 | func stringToAlphaIdx(content string) <-chan int { 14 | result := make(chan int) 15 | go func() { 16 | for _, r := range content { 17 | idx := strings.IndexRune(charSet, r) 18 | result <- idx 19 | if idx < 0 { 20 | break 21 | } 22 | } 23 | close(result) 24 | }() 25 | 26 | return result 27 | } 28 | 29 | func encodeAlphaNumeric(content string, ecl ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error) { 30 | 31 | contentLenIsOdd := len(content)%2 == 1 32 | contentBitCount := (len(content) / 2) * 11 33 | if contentLenIsOdd { 34 | contentBitCount += 6 35 | } 36 | vi := findSmallestVersionInfo(ecl, alphaNumericMode, contentBitCount) 37 | if vi == nil { 38 | return nil, nil, errors.New("too much data to encode") 39 | } 40 | 41 | res := new(utils.BitList) 42 | res.AddBits(int(alphaNumericMode), 4) 43 | res.AddBits(len(content), vi.charCountBits(alphaNumericMode)) 44 | 45 | encoder := stringToAlphaIdx(content) 46 | 47 | for idx := 0; idx < len(content)/2; idx++ { 48 | c1 := <-encoder 49 | c2 := <-encoder 50 | if c1 < 0 || c2 < 0 { 51 | return nil, nil, fmt.Errorf("%q can not be encoded as %s", content, AlphaNumeric) 52 | } 53 | res.AddBits(c1*45+c2, 11) 54 | } 55 | if contentLenIsOdd { 56 | c := <-encoder 57 | if c < 0 { 58 | return nil, nil, fmt.Errorf("%q can not be encoded as %s", content, AlphaNumeric) 59 | } 60 | res.AddBits(c, 6) 61 | } 62 | 63 | addPaddingAndTerminator(res, vi) 64 | 65 | return res, vi, nil 66 | } 67 | -------------------------------------------------------------------------------- /aztec/errorcorrection.go: -------------------------------------------------------------------------------- 1 | package aztec 2 | 3 | import ( 4 | "github.com/boombuler/barcode/utils" 5 | ) 6 | 7 | func bitsToWords(stuffedBits *utils.BitList, wordSize int, wordCount int) []int { 8 | message := make([]int, wordCount) 9 | 10 | for i := 0; i < wordCount; i++ { 11 | value := 0 12 | for j := 0; j < wordSize; j++ { 13 | if stuffedBits.GetBit(i*wordSize + j) { 14 | value |= (1 << uint(wordSize-j-1)) 15 | } 16 | } 17 | message[i] = value 18 | } 19 | return message 20 | } 21 | 22 | func generateCheckWords(bits *utils.BitList, totalBits, wordSize int) *utils.BitList { 23 | rs := utils.NewReedSolomonEncoder(getGF(wordSize)) 24 | 25 | // bits is guaranteed to be a multiple of the wordSize, so no padding needed 26 | messageWordCount := bits.Len() / wordSize 27 | totalWordCount := totalBits / wordSize 28 | eccWordCount := totalWordCount - messageWordCount 29 | 30 | messageWords := bitsToWords(bits, wordSize, messageWordCount) 31 | eccWords := rs.Encode(messageWords, eccWordCount) 32 | startPad := totalBits % wordSize 33 | 34 | messageBits := new(utils.BitList) 35 | messageBits.AddBits(0, byte(startPad)) 36 | 37 | for _, messageWord := range messageWords { 38 | messageBits.AddBits(messageWord, byte(wordSize)) 39 | } 40 | for _, eccWord := range eccWords { 41 | messageBits.AddBits(eccWord, byte(wordSize)) 42 | } 43 | return messageBits 44 | } 45 | 46 | func getGF(wordSize int) *utils.GaloisField { 47 | switch wordSize { 48 | case 4: 49 | return utils.NewGaloisField(0x13, 16, 1) 50 | case 6: 51 | return utils.NewGaloisField(0x43, 64, 1) 52 | case 8: 53 | return utils.NewGaloisField(0x012D, 256, 1) 54 | case 10: 55 | return utils.NewGaloisField(0x409, 1024, 1) 56 | case 12: 57 | return utils.NewGaloisField(0x1069, 4096, 1) 58 | default: 59 | return nil 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /qr/blocks.go: -------------------------------------------------------------------------------- 1 | package qr 2 | 3 | type block struct { 4 | data []byte 5 | ecc []byte 6 | } 7 | type blockList []*block 8 | 9 | func splitToBlocks(data <-chan byte, vi *versionInfo) blockList { 10 | result := make(blockList, vi.NumberOfBlocksInGroup1+vi.NumberOfBlocksInGroup2) 11 | 12 | for b := 0; b < int(vi.NumberOfBlocksInGroup1); b++ { 13 | blk := new(block) 14 | blk.data = make([]byte, vi.DataCodeWordsPerBlockInGroup1) 15 | for cw := 0; cw < int(vi.DataCodeWordsPerBlockInGroup1); cw++ { 16 | blk.data[cw] = <-data 17 | } 18 | blk.ecc = ec.calcECC(blk.data, vi.ErrorCorrectionCodewordsPerBlock) 19 | result[b] = blk 20 | } 21 | 22 | for b := 0; b < int(vi.NumberOfBlocksInGroup2); b++ { 23 | blk := new(block) 24 | blk.data = make([]byte, vi.DataCodeWordsPerBlockInGroup2) 25 | for cw := 0; cw < int(vi.DataCodeWordsPerBlockInGroup2); cw++ { 26 | blk.data[cw] = <-data 27 | } 28 | blk.ecc = ec.calcECC(blk.data, vi.ErrorCorrectionCodewordsPerBlock) 29 | result[int(vi.NumberOfBlocksInGroup1)+b] = blk 30 | } 31 | 32 | return result 33 | } 34 | 35 | func (bl blockList) interleave(vi *versionInfo) []byte { 36 | var maxCodewordCount int 37 | if vi.DataCodeWordsPerBlockInGroup1 > vi.DataCodeWordsPerBlockInGroup2 { 38 | maxCodewordCount = int(vi.DataCodeWordsPerBlockInGroup1) 39 | } else { 40 | maxCodewordCount = int(vi.DataCodeWordsPerBlockInGroup2) 41 | } 42 | resultLen := (vi.DataCodeWordsPerBlockInGroup1+vi.ErrorCorrectionCodewordsPerBlock)*vi.NumberOfBlocksInGroup1 + 43 | (vi.DataCodeWordsPerBlockInGroup2+vi.ErrorCorrectionCodewordsPerBlock)*vi.NumberOfBlocksInGroup2 44 | 45 | result := make([]byte, 0, resultLen) 46 | for i := 0; i < maxCodewordCount; i++ { 47 | for b := 0; b < len(bl); b++ { 48 | if len(bl[b].data) > i { 49 | result = append(result, bl[b].data[i]) 50 | } 51 | } 52 | } 53 | for i := 0; i < int(vi.ErrorCorrectionCodewordsPerBlock); i++ { 54 | for b := 0; b < len(bl); b++ { 55 | result = append(result, bl[b].ecc[i]) 56 | } 57 | } 58 | return result 59 | } 60 | -------------------------------------------------------------------------------- /aztec/token.go: -------------------------------------------------------------------------------- 1 | package aztec 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/boombuler/barcode/utils" 7 | ) 8 | 9 | type token interface { 10 | fmt.Stringer 11 | prev() token 12 | appendTo(bits *utils.BitList, text []byte) 13 | } 14 | 15 | type simpleToken struct { 16 | token 17 | value int 18 | bitCount byte 19 | } 20 | 21 | type binaryShiftToken struct { 22 | token 23 | bShiftStart int 24 | bShiftByteCnt int 25 | } 26 | 27 | func newSimpleToken(prev token, value int, bitCount byte) token { 28 | return &simpleToken{prev, value, bitCount} 29 | } 30 | func newShiftToken(prev token, bShiftStart int, bShiftCnt int) token { 31 | return &binaryShiftToken{prev, bShiftStart, bShiftCnt} 32 | } 33 | 34 | func (st *simpleToken) prev() token { 35 | return st.token 36 | } 37 | func (st *simpleToken) appendTo(bits *utils.BitList, text []byte) { 38 | bits.AddBits(st.value, st.bitCount) 39 | } 40 | func (st *simpleToken) String() string { 41 | value := st.value & ((1 << st.bitCount) - 1) 42 | value |= 1 << st.bitCount 43 | return "<" + fmt.Sprintf("%b", value)[1:] + ">" 44 | } 45 | 46 | func (bst *binaryShiftToken) prev() token { 47 | return bst.token 48 | } 49 | func (bst *binaryShiftToken) appendTo(bits *utils.BitList, text []byte) { 50 | for i := 0; i < bst.bShiftByteCnt; i++ { 51 | if i == 0 || (i == 31 && bst.bShiftByteCnt <= 62) { 52 | // We need a header before the first character, and before 53 | // character 31 when the total byte code is <= 62 54 | bits.AddBits(31, 5) // BINARY_SHIFT 55 | if bst.bShiftByteCnt > 62 { 56 | bits.AddBits(bst.bShiftByteCnt-31, 16) 57 | } else if i == 0 { 58 | // 1 <= binaryShiftByteCode <= 62 59 | if bst.bShiftByteCnt < 31 { 60 | bits.AddBits(bst.bShiftByteCnt, 5) 61 | } else { 62 | bits.AddBits(31, 5) 63 | } 64 | } else { 65 | // 32 <= binaryShiftCount <= 62 and i == 31 66 | bits.AddBits(bst.bShiftByteCnt-31, 5) 67 | } 68 | } 69 | bits.AddByte(text[bst.bShiftStart+i]) 70 | } 71 | } 72 | 73 | func (bst *binaryShiftToken) String() string { 74 | return fmt.Sprintf("<%d::%d>", bst.bShiftStart, (bst.bShiftStart + bst.bShiftByteCnt - 1)) 75 | } 76 | -------------------------------------------------------------------------------- /aztec/encoder_test.go: -------------------------------------------------------------------------------- 1 | package aztec 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | 7 | "github.com/boombuler/barcode/utils" 8 | ) 9 | 10 | func Test_StuffBits(t *testing.T) { 11 | testStuffBits := func(wordSize int, bits string, expected string) { 12 | bl := new(utils.BitList) 13 | for _, r := range bits { 14 | if r == 'X' { 15 | bl.AddBit(true) 16 | } else if r == '.' { 17 | bl.AddBit(false) 18 | } 19 | } 20 | stuffed := stuffBits(bl, wordSize) 21 | expectedBits := strings.Replace(expected, " ", "", -1) 22 | result := bitStr(stuffed) 23 | 24 | if result != expectedBits { 25 | t.Errorf("stuffBits failed for %q\nGot: %q", bits, result) 26 | } 27 | } 28 | 29 | testStuffBits(5, ".X.X. X.X.X .X.X.", 30 | ".X.X. X.X.X .X.X.") 31 | testStuffBits(5, ".X.X. ..... .X.X", 32 | ".X.X. ....X ..X.X") 33 | testStuffBits(3, "XX. ... ... ..X XXX .X. ..", 34 | "XX. ..X ..X ..X ..X .XX XX. .X. ..X") 35 | testStuffBits(6, ".X.X.. ...... ..X.XX", 36 | ".X.X.. .....X. ..X.XX XXXX.") 37 | testStuffBits(6, ".X.X.. ...... ...... ..X.X.", 38 | ".X.X.. .....X .....X ....X. X.XXXX") 39 | testStuffBits(6, ".X.X.. XXXXXX ...... ..X.XX", 40 | ".X.X.. XXXXX. X..... ...X.X XXXXX.") 41 | testStuffBits(6, 42 | "...... ..XXXX X..XX. .X.... .X.X.X .....X .X.... ...X.X .....X ....XX ..X... ....X. X..XXX X.XX.X", 43 | ".....X ...XXX XX..XX ..X... ..X.X. X..... X.X... ....X. X..... X....X X..X.. .....X X.X..X XXX.XX .XXXXX") 44 | } 45 | 46 | func Test_ModeMessage(t *testing.T) { 47 | testModeMessage := func(compact bool, layers, words int, expected string) { 48 | result := bitStr(generateModeMessage(compact, layers, words)) 49 | expectedBits := strings.Replace(expected, " ", "", -1) 50 | if result != expectedBits { 51 | t.Errorf("generateModeMessage(%v, %d, %d) failed.\nGot:%s", compact, layers, words, result) 52 | } 53 | } 54 | testModeMessage(true, 2, 29, ".X .XXX.. ...X XX.. ..X .XX. .XX.X") 55 | testModeMessage(true, 4, 64, "XX XXXXXX .X.. ...X ..XX .X.. XX..") 56 | testModeMessage(false, 21, 660, "X.X.. .X.X..X..XX .XXX ..X.. .XXX. .X... ..XXX") 57 | testModeMessage(false, 32, 4096, "XXXXX XXXXXXXXXXX X.X. ..... XXX.X ..X.. X.XXX") 58 | } 59 | -------------------------------------------------------------------------------- /datamatrix/codesize.go: -------------------------------------------------------------------------------- 1 | package datamatrix 2 | 3 | type dmCodeSize struct { 4 | Rows int 5 | Columns int 6 | RegionCountHorizontal int 7 | RegionCountVertical int 8 | ECCCount int 9 | BlockCount int 10 | } 11 | 12 | func (s *dmCodeSize) RegionRows() int { 13 | return (s.Rows - (s.RegionCountVertical * 2)) / s.RegionCountVertical 14 | } 15 | 16 | func (s *dmCodeSize) RegionColumns() int { 17 | return (s.Columns - (s.RegionCountHorizontal * 2)) / s.RegionCountHorizontal 18 | } 19 | 20 | func (s *dmCodeSize) MatrixRows() int { 21 | return s.RegionRows() * s.RegionCountVertical 22 | } 23 | 24 | func (s *dmCodeSize) MatrixColumns() int { 25 | return s.RegionColumns() * s.RegionCountHorizontal 26 | } 27 | 28 | func (s *dmCodeSize) DataCodewords() int { 29 | return ((s.MatrixColumns() * s.MatrixRows()) / 8) - s.ECCCount 30 | } 31 | 32 | func (s *dmCodeSize) DataCodewordsForBlock(idx int) int { 33 | if s.Rows == 144 && s.Columns == 144 { 34 | // Special Case... 35 | if idx < 8 { 36 | return 156 37 | } else { 38 | return 155 39 | } 40 | } 41 | return s.DataCodewords() / s.BlockCount 42 | } 43 | 44 | func (s *dmCodeSize) ErrorCorrectionCodewordsPerBlock() int { 45 | return s.ECCCount / s.BlockCount 46 | } 47 | 48 | var codeSizes []*dmCodeSize = []*dmCodeSize{ 49 | &dmCodeSize{10, 10, 1, 1, 5, 1}, 50 | &dmCodeSize{12, 12, 1, 1, 7, 1}, 51 | &dmCodeSize{14, 14, 1, 1, 10, 1}, 52 | &dmCodeSize{16, 16, 1, 1, 12, 1}, 53 | &dmCodeSize{18, 18, 1, 1, 14, 1}, 54 | &dmCodeSize{20, 20, 1, 1, 18, 1}, 55 | &dmCodeSize{22, 22, 1, 1, 20, 1}, 56 | &dmCodeSize{24, 24, 1, 1, 24, 1}, 57 | &dmCodeSize{26, 26, 1, 1, 28, 1}, 58 | &dmCodeSize{32, 32, 2, 2, 36, 1}, 59 | &dmCodeSize{36, 36, 2, 2, 42, 1}, 60 | &dmCodeSize{40, 40, 2, 2, 48, 1}, 61 | &dmCodeSize{44, 44, 2, 2, 56, 1}, 62 | &dmCodeSize{48, 48, 2, 2, 68, 1}, 63 | &dmCodeSize{52, 52, 2, 2, 84, 2}, 64 | &dmCodeSize{64, 64, 4, 4, 112, 2}, 65 | &dmCodeSize{72, 72, 4, 4, 144, 4}, 66 | &dmCodeSize{80, 80, 4, 4, 192, 4}, 67 | &dmCodeSize{88, 88, 4, 4, 224, 4}, 68 | &dmCodeSize{96, 96, 4, 4, 272, 4}, 69 | &dmCodeSize{104, 104, 4, 4, 336, 6}, 70 | &dmCodeSize{120, 120, 6, 6, 408, 6}, 71 | &dmCodeSize{132, 132, 6, 6, 496, 8}, 72 | &dmCodeSize{144, 144, 6, 6, 620, 10}, 73 | } 74 | -------------------------------------------------------------------------------- /utils/base1dcode.go: -------------------------------------------------------------------------------- 1 | // Package utils contain some utilities which are needed to create barcodes 2 | package utils 3 | 4 | import ( 5 | "image" 6 | "image/color" 7 | 8 | "github.com/boombuler/barcode" 9 | ) 10 | 11 | type base1DCode struct { 12 | *BitList 13 | kind string 14 | content string 15 | color barcode.ColorScheme 16 | } 17 | 18 | type base1DCodeIntCS struct { 19 | base1DCode 20 | checksum int 21 | } 22 | 23 | func (c *base1DCode) Content() string { 24 | return c.content 25 | } 26 | 27 | func (c *base1DCode) Metadata() barcode.Metadata { 28 | return barcode.Metadata{CodeKind: c.kind, Dimensions: 1} 29 | } 30 | 31 | func (c *base1DCode) ColorModel() color.Model { 32 | return c.color.Model 33 | } 34 | 35 | func (c *base1DCode) ColorScheme() barcode.ColorScheme { 36 | return c.color 37 | } 38 | 39 | func (c *base1DCode) Bounds() image.Rectangle { 40 | return image.Rect(0, 0, c.Len(), 1) 41 | } 42 | 43 | func (c *base1DCode) At(x, y int) color.Color { 44 | if c.GetBit(x) { 45 | return c.color.Foreground 46 | } 47 | return c.color.Background 48 | } 49 | 50 | func (c *base1DCodeIntCS) CheckSum() int { 51 | return c.checksum 52 | } 53 | 54 | // New1DCodeIntCheckSum creates a new 1D barcode where the bars are represented by the bits in the bars BitList 55 | func New1DCodeIntCheckSum(codeKind, content string, bars *BitList, checksum int) barcode.BarcodeIntCS { 56 | return &base1DCodeIntCS{base1DCode{bars, codeKind, content, barcode.ColorScheme16}, checksum} 57 | } 58 | 59 | // New1DCodeIntCheckSum creates a new 1D barcode where the bars are represented by the bits in the bars BitList 60 | func New1DCodeIntCheckSumWithColor(codeKind, content string, bars *BitList, checksum int, color barcode.ColorScheme) barcode.BarcodeIntCS { 61 | return &base1DCodeIntCS{base1DCode{bars, codeKind, content, color}, checksum} 62 | } 63 | 64 | // New1DCode creates a new 1D barcode where the bars are represented by the bits in the bars BitList 65 | func New1DCode(codeKind, content string, bars *BitList) barcode.Barcode { 66 | return &base1DCode{bars, codeKind, content, barcode.ColorScheme16} 67 | } 68 | 69 | // New1DCode creates a new 1D barcode where the bars are represented by the bits in the bars BitList 70 | func New1DCodeWithColor(codeKind, content string, bars *BitList, color barcode.ColorScheme) barcode.Barcode { 71 | return &base1DCode{bars, codeKind, content, color} 72 | } 73 | -------------------------------------------------------------------------------- /qr/blocks_test.go: -------------------------------------------------------------------------------- 1 | package qr 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | func Test_Blocks(t *testing.T) { 9 | byteIt := make(chan byte) 10 | go func() { 11 | for _, b := range []byte{67, 85, 70, 134, 87, 38, 85, 194, 119, 50, 6, 18, 6, 103, 38, 246, 246, 66, 7, 118, 134, 242, 7, 38, 86, 22, 198, 199, 146, 6, 182, 230, 247, 119, 50, 7, 118, 134, 87, 38, 82, 6, 134, 151, 50, 7, 70, 247, 118, 86, 194, 6, 151, 50, 16, 236, 17, 236, 17, 236, 17, 236} { 12 | byteIt <- b 13 | } 14 | close(byteIt) 15 | }() 16 | vi := &versionInfo{5, Q, 18, 2, 15, 2, 16} 17 | 18 | data := splitToBlocks(byteIt, vi).interleave(vi) 19 | if !bytes.Equal(data, []byte{67, 246, 182, 70, 85, 246, 230, 247, 70, 66, 247, 118, 134, 7, 119, 86, 87, 118, 50, 194, 38, 134, 7, 6, 85, 242, 118, 151, 194, 7, 134, 50, 119, 38, 87, 16, 50, 86, 38, 236, 6, 22, 82, 17, 18, 198, 6, 236, 6, 199, 134, 17, 103, 146, 151, 236, 38, 6, 50, 17, 7, 236, 213, 87, 148, 235, 199, 204, 116, 159, 11, 96, 177, 5, 45, 60, 212, 173, 115, 202, 76, 24, 247, 182, 133, 147, 241, 124, 75, 59, 223, 157, 242, 33, 229, 200, 238, 106, 248, 134, 76, 40, 154, 27, 195, 255, 117, 129, 230, 172, 154, 209, 189, 82, 111, 17, 10, 2, 86, 163, 108, 131, 161, 163, 240, 32, 111, 120, 192, 178, 39, 133, 141, 236}) { 20 | t.Fail() 21 | } 22 | 23 | byteIt2 := make(chan byte) 24 | go func() { 25 | for _, b := range []byte{67, 85, 70, 134, 87, 38, 85, 194, 119, 50, 6, 18, 6, 103, 38, 246, 246, 66, 7, 118, 134, 242, 7, 38, 86, 22, 198, 199, 146, 6, 182, 230, 247, 119, 50, 7, 118, 134, 87, 38, 82, 6, 134, 151, 50, 7, 70, 247, 118, 86, 194, 6, 151, 50, 16, 236, 17, 236, 17, 236, 17, 236} { 26 | byteIt2 <- b 27 | } 28 | close(byteIt2) 29 | }() 30 | vi = &versionInfo{5, Q, 18, 2, 16, 2, 15} 31 | 32 | data = splitToBlocks(byteIt2, vi).interleave(vi) 33 | if !bytes.Equal(data, []byte{67, 246, 247, 247, 85, 66, 119, 118, 70, 7, 50, 86, 134, 118, 7, 194, 87, 134, 118, 6, 38, 242, 134, 151, 85, 7, 87, 50, 194, 38, 38, 16, 119, 86, 82, 236, 50, 22, 6, 17, 6, 198, 134, 236, 18, 199, 151, 17, 6, 146, 50, 236, 103, 6, 7, 17, 38, 182, 70, 236, 246, 230, 71, 101, 27, 62, 13, 91, 166, 86, 138, 16, 78, 229, 102, 11, 199, 107, 2, 182, 132, 103, 89, 66, 136, 69, 78, 255, 116, 129, 126, 163, 219, 234, 158, 216, 42, 234, 97, 62, 186, 59, 123, 148, 220, 191, 254, 145, 82, 95, 129, 79, 236, 254, 30, 174, 228, 50, 181, 110, 150, 205, 34, 235, 242, 0, 115, 147, 58, 243, 28, 140, 221, 219}) { 34 | t.Fail() 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /codabar/encoder.go: -------------------------------------------------------------------------------- 1 | // Package codabar can create Codabar barcodes 2 | package codabar 3 | 4 | import ( 5 | "fmt" 6 | "regexp" 7 | 8 | "github.com/boombuler/barcode" 9 | "github.com/boombuler/barcode/utils" 10 | ) 11 | 12 | var encodingTable = map[rune][]bool{ 13 | '0': []bool{true, false, true, false, true, false, false, true, true}, 14 | '1': []bool{true, false, true, false, true, true, false, false, true}, 15 | '2': []bool{true, false, true, false, false, true, false, true, true}, 16 | '3': []bool{true, true, false, false, true, false, true, false, true}, 17 | '4': []bool{true, false, true, true, false, true, false, false, true}, 18 | '5': []bool{true, true, false, true, false, true, false, false, true}, 19 | '6': []bool{true, false, false, true, false, true, false, true, true}, 20 | '7': []bool{true, false, false, true, false, true, true, false, true}, 21 | '8': []bool{true, false, false, true, true, false, true, false, true}, 22 | '9': []bool{true, true, false, true, false, false, true, false, true}, 23 | '-': []bool{true, false, true, false, false, true, true, false, true}, 24 | '$': []bool{true, false, true, true, false, false, true, false, true}, 25 | ':': []bool{true, true, false, true, false, true, true, false, true, true}, 26 | '/': []bool{true, true, false, true, true, false, true, false, true, true}, 27 | '.': []bool{true, true, false, true, true, false, true, true, false, true}, 28 | '+': []bool{true, false, true, true, false, true, true, false, true, true}, 29 | 'A': []bool{true, false, true, true, false, false, true, false, false, true}, 30 | 'B': []bool{true, false, false, true, false, false, true, false, true, true}, 31 | 'C': []bool{true, false, true, false, false, true, false, false, true, true}, 32 | 'D': []bool{true, false, true, false, false, true, true, false, false, true}, 33 | } 34 | 35 | // Encode creates a codabar barcode for the given content and color scheme 36 | func EncodeWithColor(content string, color barcode.ColorScheme) (barcode.Barcode, error) { 37 | checkValid, _ := regexp.Compile(`[ABCD][0123456789\-\$\:/\.\+]*[ABCD]$`) 38 | if content == "!" || checkValid.ReplaceAllString(content, "!") != "!" { 39 | return nil, fmt.Errorf("can not encode %q", content) 40 | } 41 | resBits := new(utils.BitList) 42 | for i, r := range content { 43 | if i > 0 { 44 | resBits.AddBit(false) 45 | } 46 | resBits.AddBit(encodingTable[r]...) 47 | } 48 | return utils.New1DCodeWithColor(barcode.TypeCodabar, content, resBits, color), nil 49 | } 50 | 51 | // Encode creates a codabar barcode for the given content 52 | func Encode(content string) (barcode.Barcode, error) { 53 | return EncodeWithColor(content, barcode.ColorScheme16) 54 | } 55 | -------------------------------------------------------------------------------- /datamatrix/encoder.go: -------------------------------------------------------------------------------- 1 | // Package datamatrix can create Datamatrix barcodes 2 | package datamatrix 3 | 4 | import ( 5 | "errors" 6 | 7 | "github.com/boombuler/barcode" 8 | ) 9 | 10 | // FNC1 is the codeword for the Function 1 Symbol Character to 11 | // differentiate a GS1 DataMatrix from other Data Matrix symbols. 12 | // 13 | // It is used as both a start character and a separator of GS1 element 14 | // strings. 15 | const FNC1 byte = 232 16 | 17 | // Encode returns a Datamatrix barcode for the given content and color scheme 18 | func EncodeWithColor(content string, color barcode.ColorScheme) (barcode.Barcode, error) { 19 | data := encodeText(content) 20 | 21 | var size *dmCodeSize 22 | for _, s := range codeSizes { 23 | if s.DataCodewords() >= len(data) { 24 | size = s 25 | break 26 | } 27 | } 28 | if size == nil { 29 | return nil, errors.New("too much data to encode") 30 | } 31 | data = addPadding(data, size.DataCodewords()) 32 | data = ec.calcECC(data, size) 33 | code := render(data, size, color) 34 | if code != nil { 35 | code.content = content 36 | return code, nil 37 | } 38 | return nil, errors.New("unable to render barcode") 39 | } 40 | 41 | // Encode returns a Datamatrix barcode for the given content 42 | func Encode(content string) (barcode.Barcode, error) { 43 | return EncodeWithColor(content, barcode.ColorScheme16) 44 | } 45 | 46 | func render(data []byte, size *dmCodeSize, color barcode.ColorScheme) *datamatrixCode { 47 | cl := newCodeLayout(size, color) 48 | 49 | cl.SetValues(data) 50 | 51 | return cl.Merge() 52 | } 53 | 54 | func encodeText(content string) []byte { 55 | var result []byte 56 | input := []byte(content) 57 | 58 | isGS1 := len(input) > 0 && input[0] == FNC1 59 | 60 | for i := 0; i < len(input); { 61 | c := input[i] 62 | i++ 63 | 64 | if c >= '0' && c <= '9' && i < len(input) && input[i] >= '0' && input[i] <= '9' { 65 | // two numbers... 66 | c2 := input[i] 67 | i++ 68 | cw := byte(((c-'0')*10 + (c2 - '0')) + 130) 69 | result = append(result, cw) 70 | } else if isGS1 && c == FNC1 { 71 | result = append(result, c) 72 | } else if c > 127 { 73 | // not correct... needs to be redone later... 74 | result = append(result, 235, c-127) 75 | } else { 76 | result = append(result, c+1) 77 | } 78 | } 79 | return result 80 | } 81 | 82 | func addPadding(data []byte, toCount int) []byte { 83 | if len(data) < toCount { 84 | data = append(data, 129) 85 | } 86 | for len(data) < toCount { 87 | R := ((149 * (len(data) + 1)) % 253) + 1 88 | tmp := 129 + R 89 | if tmp > 254 { 90 | tmp = tmp - 254 91 | } 92 | 93 | data = append(data, byte(tmp)) 94 | } 95 | return data 96 | } 97 | -------------------------------------------------------------------------------- /utils/galoisfield_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func Test_GF(t *testing.T) { 8 | log := []int{ 9 | 0, 255, 1, 240, 2, 225, 241, 53, 3, 38, 226, 133, 242, 43, 54, 210, 10 | 4, 195, 39, 114, 227, 106, 134, 28, 243, 140, 44, 23, 55, 118, 211, 234, 11 | 5, 219, 196, 96, 40, 222, 115, 103, 228, 78, 107, 125, 135, 8, 29, 162, 12 | 244, 186, 141, 180, 45, 99, 24, 49, 56, 13, 119, 153, 212, 199, 235, 91, 13 | 6, 76, 220, 217, 197, 11, 97, 184, 41, 36, 223, 253, 116, 138, 104, 193, 14 | 229, 86, 79, 171, 108, 165, 126, 145, 136, 34, 9, 74, 30, 32, 163, 84, 15 | 245, 173, 187, 204, 142, 81, 181, 190, 46, 88, 100, 159, 25, 231, 50, 207, 16 | 57, 147, 14, 67, 120, 128, 154, 248, 213, 167, 200, 63, 236, 110, 92, 176, 17 | 7, 161, 77, 124, 221, 102, 218, 95, 198, 90, 12, 152, 98, 48, 185, 179, 18 | 42, 209, 37, 132, 224, 52, 254, 239, 117, 233, 139, 22, 105, 27, 194, 113, 19 | 230, 206, 87, 158, 80, 189, 172, 203, 109, 175, 166, 62, 127, 247, 146, 66, 20 | 137, 192, 35, 252, 10, 183, 75, 216, 31, 83, 33, 73, 164, 144, 85, 170, 21 | 246, 65, 174, 61, 188, 202, 205, 157, 143, 169, 82, 72, 182, 215, 191, 251, 22 | 47, 178, 89, 151, 101, 94, 160, 123, 26, 112, 232, 21, 51, 238, 208, 131, 23 | 58, 69, 148, 18, 15, 16, 68, 17, 121, 149, 129, 19, 155, 59, 249, 70, 24 | 214, 250, 168, 71, 201, 156, 64, 60, 237, 130, 111, 20, 93, 122, 177, 150, 25 | } 26 | 27 | alog := []int{ 28 | 1, 2, 4, 8, 16, 32, 64, 128, 45, 90, 180, 69, 138, 57, 114, 228, 29 | 229, 231, 227, 235, 251, 219, 155, 27, 54, 108, 216, 157, 23, 46, 92, 184, 30 | 93, 186, 89, 178, 73, 146, 9, 18, 36, 72, 144, 13, 26, 52, 104, 208, 31 | 141, 55, 110, 220, 149, 7, 14, 28, 56, 112, 224, 237, 247, 195, 171, 123, 32 | 246, 193, 175, 115, 230, 225, 239, 243, 203, 187, 91, 182, 65, 130, 41, 82, 33 | 164, 101, 202, 185, 95, 190, 81, 162, 105, 210, 137, 63, 126, 252, 213, 135, 34 | 35, 70, 140, 53, 106, 212, 133, 39, 78, 156, 21, 42, 84, 168, 125, 250, 35 | 217, 159, 19, 38, 76, 152, 29, 58, 116, 232, 253, 215, 131, 43, 86, 172, 36 | 117, 234, 249, 223, 147, 11, 22, 44, 88, 176, 77, 154, 25, 50, 100, 200, 37 | 189, 87, 174, 113, 226, 233, 255, 211, 139, 59, 118, 236, 245, 199, 163, 107, 38 | 214, 129, 47, 94, 188, 85, 170, 121, 242, 201, 191, 83, 166, 97, 194, 169, 39 | 127, 254, 209, 143, 51, 102, 204, 181, 71, 142, 49, 98, 196, 165, 103, 206, 40 | 177, 79, 158, 17, 34, 68, 136, 61, 122, 244, 197, 167, 99, 198, 161, 111, 41 | 222, 145, 15, 30, 60, 120, 240, 205, 183, 67, 134, 33, 66, 132, 37, 74, 42 | 148, 5, 10, 20, 40, 80, 160, 109, 218, 153, 31, 62, 124, 248, 221, 151, 43 | 3, 6, 12, 24, 48, 96, 192, 173, 119, 238, 241, 207, 179, 75, 150, 1, 44 | } 45 | 46 | gf := NewGaloisField(301, 256, 1) 47 | if len(gf.LogTbl) != len(gf.ALogTbl) || len(gf.LogTbl) != len(log) { 48 | t.Fail() 49 | } 50 | for i := 0; i < len(log); i++ { 51 | if gf.LogTbl[i] != log[i] { 52 | t.Error("Invalid Log Table") 53 | } 54 | if gf.ALogTbl[i] != alog[i] { 55 | t.Error("Invalid ALog Table") 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /qr/qrcode_test.go: -------------------------------------------------------------------------------- 1 | package qr 2 | 3 | import ( 4 | "image/color" 5 | "testing" 6 | ) 7 | 8 | func Test_NewQRCode(t *testing.T) { 9 | bc := newBarcode(2) 10 | if bc == nil { 11 | t.Fail() 12 | return 13 | } 14 | if bc.data.Len() != 4 { 15 | t.Fail() 16 | } 17 | if bc.dimension != 2 { 18 | t.Fail() 19 | } 20 | } 21 | 22 | func Test_QRBasics(t *testing.T) { 23 | qr := newBarcode(10) 24 | if qr.ColorModel() != color.Gray16Model { 25 | t.Fail() 26 | } 27 | code, _ := Encode("test", L, Unicode) 28 | if code.Content() != "test" { 29 | t.Fail() 30 | } 31 | if code.Metadata().Dimensions != 2 { 32 | t.Fail() 33 | } 34 | bounds := code.Bounds() 35 | if bounds.Min.X != 0 || bounds.Min.Y != 0 || bounds.Max.X != 21 || bounds.Max.Y != 21 { 36 | t.Fail() 37 | } 38 | if code.At(0, 0) != color.Black || code.At(0, 7) != color.White { 39 | t.Fail() 40 | } 41 | qr = code.(*qrcode) 42 | if !qr.Get(0, 0) || qr.Get(0, 7) { 43 | t.Fail() 44 | } 45 | sum := qr.calcPenaltyRule1() + qr.calcPenaltyRule2() + qr.calcPenaltyRule3() + qr.calcPenaltyRule4() 46 | if qr.calcPenalty() != sum { 47 | t.Fail() 48 | } 49 | } 50 | 51 | func Test_Penalty1(t *testing.T) { 52 | qr := newBarcode(7) 53 | if qr.calcPenaltyRule1() != 70 { 54 | t.Fail() 55 | } 56 | qr.Set(0, 0, true) 57 | if qr.calcPenaltyRule1() != 68 { 58 | t.Fail() 59 | } 60 | qr.Set(0, 6, true) 61 | if qr.calcPenaltyRule1() != 66 { 62 | t.Fail() 63 | } 64 | } 65 | 66 | func Test_Penalty2(t *testing.T) { 67 | qr := newBarcode(3) 68 | if qr.calcPenaltyRule2() != 12 { 69 | t.Fail() 70 | } 71 | qr.Set(0, 0, true) 72 | qr.Set(1, 1, true) 73 | qr.Set(2, 0, true) 74 | if qr.calcPenaltyRule2() != 0 { 75 | t.Fail() 76 | } 77 | qr.Set(1, 1, false) 78 | if qr.calcPenaltyRule2() != 6 { 79 | t.Fail() 80 | } 81 | } 82 | 83 | func Test_Penalty3(t *testing.T) { 84 | runTest := func(content string, result uint) { 85 | code, _ := Encode(content, L, AlphaNumeric) 86 | qr := code.(*qrcode) 87 | if qr.calcPenaltyRule3() != result { 88 | t.Errorf("Failed Penalty Rule 3 for content %q got %d but expected %d", content, qr.calcPenaltyRule3(), result) 89 | } 90 | } 91 | runTest("A", 80) 92 | runTest("FOO", 40) 93 | runTest("0815", 0) 94 | } 95 | 96 | func Test_Penalty4(t *testing.T) { 97 | qr := newBarcode(3) 98 | if qr.calcPenaltyRule4() != 100 { 99 | t.Fail() 100 | } 101 | qr.Set(0, 0, true) 102 | if qr.calcPenaltyRule4() != 70 { 103 | t.Fail() 104 | } 105 | qr.Set(0, 1, true) 106 | if qr.calcPenaltyRule4() != 50 { 107 | t.Fail() 108 | } 109 | qr.Set(0, 2, true) 110 | if qr.calcPenaltyRule4() != 30 { 111 | t.Fail() 112 | } 113 | qr.Set(1, 0, true) 114 | if qr.calcPenaltyRule4() != 10 { 115 | t.Fail() 116 | } 117 | qr.Set(1, 1, true) 118 | if qr.calcPenaltyRule4() != 10 { 119 | t.Fail() 120 | } 121 | qr = newBarcode(2) 122 | qr.Set(0, 0, true) 123 | qr.Set(1, 0, true) 124 | if qr.calcPenaltyRule4() != 0 { 125 | t.Fail() 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /utils/bitlist.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | // BitList is a list that contains bits 4 | type BitList struct { 5 | count int 6 | data []int32 7 | } 8 | 9 | // NewBitList returns a new BitList with the given length 10 | // all bits are initialize with false 11 | func NewBitList(capacity int) *BitList { 12 | bl := new(BitList) 13 | bl.count = capacity 14 | x := 0 15 | if capacity%32 != 0 { 16 | x = 1 17 | } 18 | bl.data = make([]int32, capacity/32+x) 19 | return bl 20 | } 21 | 22 | // Len returns the number of contained bits 23 | func (bl *BitList) Len() int { 24 | return bl.count 25 | } 26 | 27 | func (bl *BitList) grow() { 28 | growBy := len(bl.data) 29 | if growBy < 128 { 30 | growBy = 128 31 | } else if growBy >= 1024 { 32 | growBy = 1024 33 | } 34 | 35 | nd := make([]int32, len(bl.data)+growBy) 36 | copy(nd, bl.data) 37 | bl.data = nd 38 | } 39 | 40 | // AddBit appends the given bits to the end of the list 41 | func (bl *BitList) AddBit(bits ...bool) { 42 | for _, bit := range bits { 43 | itmIndex := bl.count / 32 44 | for itmIndex >= len(bl.data) { 45 | bl.grow() 46 | } 47 | bl.SetBit(bl.count, bit) 48 | bl.count++ 49 | } 50 | } 51 | 52 | // SetBit sets the bit at the given index to the given value 53 | func (bl *BitList) SetBit(index int, value bool) { 54 | itmIndex := index / 32 55 | itmBitShift := 31 - (index % 32) 56 | if value { 57 | bl.data[itmIndex] = bl.data[itmIndex] | 1<> uint(itmBitShift)) & 1) == 1 68 | } 69 | 70 | // AddByte appends all 8 bits of the given byte to the end of the list 71 | func (bl *BitList) AddByte(b byte) { 72 | for i := 7; i >= 0; i-- { 73 | bl.AddBit(((b >> uint(i)) & 1) == 1) 74 | } 75 | } 76 | 77 | // AddBits appends the last (LSB) 'count' bits of 'b' the the end of the list 78 | func (bl *BitList) AddBits(b int, count byte) { 79 | for i := int(count) - 1; i >= 0; i-- { 80 | bl.AddBit(((b >> uint(i)) & 1) == 1) 81 | } 82 | } 83 | 84 | // GetBytes returns all bits of the BitList as a []byte 85 | func (bl *BitList) GetBytes() []byte { 86 | len := bl.count >> 3 87 | if (bl.count % 8) != 0 { 88 | len++ 89 | } 90 | result := make([]byte, len) 91 | for i := 0; i < len; i++ { 92 | shift := (3 - (i % 4)) * 8 93 | result[i] = (byte)((bl.data[i/4] >> uint(shift)) & 0xFF) 94 | } 95 | return result 96 | } 97 | 98 | // IterateBytes iterates through all bytes contained in the BitList 99 | func (bl *BitList) IterateBytes() <-chan byte { 100 | res := make(chan byte) 101 | 102 | go func() { 103 | c := bl.count 104 | shift := 24 105 | i := 0 106 | for c > 0 { 107 | res <- byte((bl.data[i] >> uint(shift)) & 0xFF) 108 | shift -= 8 109 | if shift < 0 { 110 | shift = 24 111 | i++ 112 | } 113 | c -= 8 114 | } 115 | close(res) 116 | }() 117 | 118 | return res 119 | } 120 | -------------------------------------------------------------------------------- /qr/encoder_test.go: -------------------------------------------------------------------------------- 1 | package qr 2 | 3 | import ( 4 | "fmt" 5 | "image/png" 6 | "os" 7 | "testing" 8 | 9 | "github.com/boombuler/barcode" 10 | ) 11 | 12 | type test struct { 13 | Text string 14 | Mode Encoding 15 | ECL ErrorCorrectionLevel 16 | Result string 17 | } 18 | 19 | var tests = []test{ 20 | test{ 21 | Text: "hello world", 22 | Mode: Unicode, 23 | ECL: H, 24 | Result: ` 25 | +++++++.+.+.+...+.+++++++ 26 | +.....+.++...+++..+.....+ 27 | +.+++.+.+.+.++.++.+.+++.+ 28 | +.+++.+....++.++..+.+++.+ 29 | +.+++.+..+...++.+.+.+++.+ 30 | +.....+.+..+..+++.+.....+ 31 | +++++++.+.+.+.+.+.+++++++ 32 | ........++..+..+......... 33 | ..+++.+.+++.+.++++++..+++ 34 | +++..+..+...++.+...+..+.. 35 | +...+.++++....++.+..++.++ 36 | ++.+.+.++...+...+.+....++ 37 | ..+..+++.+.+++++.++++++++ 38 | +.+++...+..++..++..+..+.. 39 | +.....+..+.+.....+++++.++ 40 | +.+++.....+...+.+.+++...+ 41 | +.+..+++...++.+.+++++++.. 42 | ........+....++.+...+.+.. 43 | +++++++......++++.+.+.+++ 44 | +.....+....+...++...++.+. 45 | +.+++.+.+.+...+++++++++.. 46 | +.+++.+.++...++...+.++..+ 47 | +.+++.+.++.+++++..++.+..+ 48 | +.....+..+++..++.+.++...+ 49 | +++++++....+..+.+..+..+++`, 50 | }, 51 | } 52 | 53 | func Test_GetUnknownEncoder(t *testing.T) { 54 | if unknownEncoding.getEncoder() != nil { 55 | t.Fail() 56 | } 57 | } 58 | 59 | func Test_EncodingStringer(t *testing.T) { 60 | tests := map[Encoding]string{ 61 | Auto: "Auto", 62 | Numeric: "Numeric", 63 | AlphaNumeric: "AlphaNumeric", 64 | Unicode: "Unicode", 65 | unknownEncoding: "", 66 | } 67 | 68 | for enc, str := range tests { 69 | if enc.String() != str { 70 | t.Fail() 71 | } 72 | } 73 | } 74 | 75 | func Test_InvalidEncoding(t *testing.T) { 76 | _, err := Encode("hello world", H, Numeric) 77 | if err == nil { 78 | t.Fail() 79 | } 80 | } 81 | 82 | func imgStrToBools(str string) []bool { 83 | res := make([]bool, 0, len(str)) 84 | for _, r := range str { 85 | if r == '+' { 86 | res = append(res, true) 87 | } else if r == '.' { 88 | res = append(res, false) 89 | } 90 | } 91 | return res 92 | } 93 | 94 | func Test_Encode(t *testing.T) { 95 | for _, tst := range tests { 96 | res, err := Encode(tst.Text, tst.ECL, tst.Mode) 97 | if err != nil { 98 | t.Error(err) 99 | } 100 | qrCode, ok := res.(*qrcode) 101 | if !ok { 102 | t.Fail() 103 | } 104 | testRes := imgStrToBools(tst.Result) 105 | if (qrCode.dimension * qrCode.dimension) != len(testRes) { 106 | t.Fail() 107 | } 108 | t.Logf("dim %d", qrCode.dimension) 109 | for i := 0; i < len(testRes); i++ { 110 | x := i % qrCode.dimension 111 | y := i / qrCode.dimension 112 | if qrCode.Get(x, y) != testRes[i] { 113 | t.Errorf("Failed at index %d", i) 114 | } 115 | } 116 | } 117 | } 118 | 119 | func ExampleEncode() { 120 | f, _ := os.Create("qrcode.png") 121 | defer f.Close() 122 | 123 | qrcode, err := Encode("hello world", L, Auto) 124 | if err != nil { 125 | fmt.Println(err) 126 | } else { 127 | qrcode, err = barcode.Scale(qrcode, 100, 100) 128 | if err != nil { 129 | fmt.Println(err) 130 | } else { 131 | png.Encode(f, qrcode) 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /utils/gfpoly.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | type GFPoly struct { 4 | gf *GaloisField 5 | Coefficients []int 6 | } 7 | 8 | func (gp *GFPoly) Degree() int { 9 | return len(gp.Coefficients) - 1 10 | } 11 | 12 | func (gp *GFPoly) Zero() bool { 13 | return gp.Coefficients[0] == 0 14 | } 15 | 16 | // GetCoefficient returns the coefficient of x ^ degree 17 | func (gp *GFPoly) GetCoefficient(degree int) int { 18 | return gp.Coefficients[gp.Degree()-degree] 19 | } 20 | 21 | func (gp *GFPoly) AddOrSubstract(other *GFPoly) *GFPoly { 22 | if gp.Zero() { 23 | return other 24 | } else if other.Zero() { 25 | return gp 26 | } 27 | smallCoeff := gp.Coefficients 28 | largeCoeff := other.Coefficients 29 | if len(smallCoeff) > len(largeCoeff) { 30 | largeCoeff, smallCoeff = smallCoeff, largeCoeff 31 | } 32 | sumDiff := make([]int, len(largeCoeff)) 33 | lenDiff := len(largeCoeff) - len(smallCoeff) 34 | copy(sumDiff, largeCoeff[:lenDiff]) 35 | for i := lenDiff; i < len(largeCoeff); i++ { 36 | sumDiff[i] = int(gp.gf.AddOrSub(int(smallCoeff[i-lenDiff]), int(largeCoeff[i]))) 37 | } 38 | return NewGFPoly(gp.gf, sumDiff) 39 | } 40 | 41 | func (gp *GFPoly) MultByMonominal(degree int, coeff int) *GFPoly { 42 | if coeff == 0 { 43 | return gp.gf.Zero() 44 | } 45 | size := len(gp.Coefficients) 46 | result := make([]int, size+degree) 47 | for i := 0; i < size; i++ { 48 | result[i] = int(gp.gf.Multiply(int(gp.Coefficients[i]), int(coeff))) 49 | } 50 | return NewGFPoly(gp.gf, result) 51 | } 52 | 53 | func (gp *GFPoly) Multiply(other *GFPoly) *GFPoly { 54 | if gp.Zero() || other.Zero() { 55 | return gp.gf.Zero() 56 | } 57 | aCoeff := gp.Coefficients 58 | aLen := len(aCoeff) 59 | bCoeff := other.Coefficients 60 | bLen := len(bCoeff) 61 | product := make([]int, aLen+bLen-1) 62 | for i := 0; i < aLen; i++ { 63 | ac := int(aCoeff[i]) 64 | for j := 0; j < bLen; j++ { 65 | bc := int(bCoeff[j]) 66 | product[i+j] = int(gp.gf.AddOrSub(int(product[i+j]), gp.gf.Multiply(ac, bc))) 67 | } 68 | } 69 | return NewGFPoly(gp.gf, product) 70 | } 71 | 72 | func (gp *GFPoly) Divide(other *GFPoly) (quotient *GFPoly, remainder *GFPoly) { 73 | quotient = gp.gf.Zero() 74 | remainder = gp 75 | fld := gp.gf 76 | denomLeadTerm := other.GetCoefficient(other.Degree()) 77 | inversDenomLeadTerm := fld.Invers(int(denomLeadTerm)) 78 | for remainder.Degree() >= other.Degree() && !remainder.Zero() { 79 | degreeDiff := remainder.Degree() - other.Degree() 80 | scale := int(fld.Multiply(int(remainder.GetCoefficient(remainder.Degree())), inversDenomLeadTerm)) 81 | term := other.MultByMonominal(degreeDiff, scale) 82 | itQuot := NewMonominalPoly(fld, degreeDiff, scale) 83 | quotient = quotient.AddOrSubstract(itQuot) 84 | remainder = remainder.AddOrSubstract(term) 85 | } 86 | return 87 | } 88 | 89 | func NewMonominalPoly(field *GaloisField, degree int, coeff int) *GFPoly { 90 | if coeff == 0 { 91 | return field.Zero() 92 | } 93 | result := make([]int, degree+1) 94 | result[0] = coeff 95 | return NewGFPoly(field, result) 96 | } 97 | 98 | func NewGFPoly(field *GaloisField, coefficients []int) *GFPoly { 99 | for len(coefficients) > 1 && coefficients[0] == 0 { 100 | coefficients = coefficients[1:] 101 | } 102 | return &GFPoly{field, coefficients} 103 | } 104 | -------------------------------------------------------------------------------- /scaledbarcode.go: -------------------------------------------------------------------------------- 1 | package barcode 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "image" 7 | "image/color" 8 | "math" 9 | ) 10 | 11 | type wrapFunc func(x, y int) color.Color 12 | 13 | type scaledBarcode struct { 14 | wrapped Barcode 15 | wrapperFunc wrapFunc 16 | rect image.Rectangle 17 | } 18 | 19 | type intCSscaledBC struct { 20 | scaledBarcode 21 | } 22 | 23 | func (bc *scaledBarcode) Content() string { 24 | return bc.wrapped.Content() 25 | } 26 | 27 | func (bc *scaledBarcode) Metadata() Metadata { 28 | return bc.wrapped.Metadata() 29 | } 30 | 31 | func (bc *scaledBarcode) ColorModel() color.Model { 32 | return bc.wrapped.ColorModel() 33 | } 34 | 35 | func (bc *scaledBarcode) Bounds() image.Rectangle { 36 | return bc.rect 37 | } 38 | 39 | func (bc *scaledBarcode) At(x, y int) color.Color { 40 | return bc.wrapperFunc(x, y) 41 | } 42 | 43 | func (bc *intCSscaledBC) CheckSum() int { 44 | if cs, ok := bc.wrapped.(BarcodeIntCS); ok { 45 | return cs.CheckSum() 46 | } 47 | return 0 48 | } 49 | 50 | // Scale returns a resized barcode with the given width and height. 51 | func Scale(bc Barcode, width, height int) (Barcode, error) { 52 | var fill color.Color 53 | if v, ok := bc.(BarcodeColor); ok { 54 | fill = v.ColorScheme().Background 55 | } else { 56 | fill = color.White 57 | } 58 | return ScaleWithFill(bc, width, height, fill) 59 | } 60 | 61 | // Scale returns a resized barcode with the given width, height and fill color. 62 | func ScaleWithFill(bc Barcode, width, height int, fill color.Color) (Barcode, error) { 63 | switch bc.Metadata().Dimensions { 64 | case 1: 65 | return scale1DCode(bc, width, height, fill) 66 | case 2: 67 | return scale2DCode(bc, width, height, fill) 68 | } 69 | 70 | return nil, errors.New("unsupported barcode format") 71 | } 72 | 73 | func newScaledBC(wrapped Barcode, wrapperFunc wrapFunc, rect image.Rectangle) Barcode { 74 | result := &scaledBarcode{ 75 | wrapped: wrapped, 76 | wrapperFunc: wrapperFunc, 77 | rect: rect, 78 | } 79 | 80 | if _, ok := wrapped.(BarcodeIntCS); ok { 81 | return &intCSscaledBC{*result} 82 | } 83 | return result 84 | } 85 | 86 | func scale2DCode(bc Barcode, width, height int, fill color.Color) (Barcode, error) { 87 | orgBounds := bc.Bounds() 88 | orgWidth := orgBounds.Max.X - orgBounds.Min.X 89 | orgHeight := orgBounds.Max.Y - orgBounds.Min.Y 90 | 91 | factor := int(math.Min(float64(width)/float64(orgWidth), float64(height)/float64(orgHeight))) 92 | if factor <= 0 { 93 | return nil, fmt.Errorf("can not scale barcode to an image smaller than %dx%d", orgWidth, orgHeight) 94 | } 95 | 96 | offsetX := (width - (orgWidth * factor)) / 2 97 | offsetY := (height - (orgHeight * factor)) / 2 98 | 99 | wrap := func(x, y int) color.Color { 100 | if x < offsetX || y < offsetY { 101 | return fill 102 | } 103 | x = (x - offsetX) / factor 104 | y = (y - offsetY) / factor 105 | if x >= orgWidth || y >= orgHeight { 106 | return fill 107 | } 108 | return bc.At(x, y) 109 | } 110 | 111 | return newScaledBC( 112 | bc, 113 | wrap, 114 | image.Rect(0, 0, width, height), 115 | ), nil 116 | } 117 | 118 | func scale1DCode(bc Barcode, width, height int, fill color.Color) (Barcode, error) { 119 | orgBounds := bc.Bounds() 120 | orgWidth := orgBounds.Max.X - orgBounds.Min.X 121 | factor := int(float64(width) / float64(orgWidth)) 122 | 123 | if factor <= 0 { 124 | return nil, fmt.Errorf("can not scale barcode to an image smaller than %dx1", orgWidth) 125 | } 126 | offsetX := (width - (orgWidth * factor)) / 2 127 | 128 | wrap := func(x, y int) color.Color { 129 | if x < offsetX { 130 | return fill 131 | } 132 | x = (x - offsetX) / factor 133 | 134 | if x >= orgWidth { 135 | return fill 136 | } 137 | return bc.At(x, 0) 138 | } 139 | 140 | return newScaledBC( 141 | bc, 142 | wrap, 143 | image.Rect(0, 0, width, height), 144 | ), nil 145 | } 146 | -------------------------------------------------------------------------------- /datamatrix/datamatrix_test.go: -------------------------------------------------------------------------------- 1 | package datamatrix 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | func codeFromStr(str string, size *dmCodeSize) *datamatrixCode { 9 | code := newDataMatrixCode(size) 10 | idx := 0 11 | for _, r := range str { 12 | x := idx % size.Columns 13 | y := idx / size.Columns 14 | 15 | switch r { 16 | case '#': 17 | code.set(x, y, true) 18 | case '.': 19 | code.set(x, y, false) 20 | default: 21 | continue 22 | } 23 | 24 | idx++ 25 | } 26 | return code 27 | } 28 | 29 | func Test_Issue12(t *testing.T) { 30 | data := `{"po":12,"batchAction":"start_end"}` 31 | realData := addPadding(encodeText(data), 36) 32 | wantedData := []byte{124, 35, 113, 112, 35, 59, 142, 45, 35, 99, 98, 117, 100, 105, 66, 100, 117, 106, 112, 111, 35, 59, 35, 116, 117, 98, 115, 117, 96, 102, 111, 101, 35, 126, 129, 181} 33 | 34 | if !bytes.Equal(realData, wantedData) { 35 | t.Error("Data Encoding failed") 36 | return 37 | } 38 | 39 | var codeSize *dmCodeSize 40 | for _, s := range codeSizes { 41 | if s.DataCodewords() >= len(wantedData) { 42 | codeSize = s 43 | break 44 | } 45 | } 46 | realECC := ec.calcECC(realData, codeSize)[len(realData):] 47 | wantedECC := []byte{196, 53, 147, 192, 151, 213, 107, 61, 98, 251, 50, 71, 186, 15, 43, 111, 165, 243, 209, 79, 128, 109, 251, 4} 48 | if !bytes.Equal(realECC, wantedECC) { 49 | t.Errorf("Error correction calculation failed\nGot: %v", realECC) 50 | return 51 | } 52 | 53 | barcode := ` 54 | #.#.#.#.#.#.#.#.#.#.#.#. 55 | #....###..#..#....#...## 56 | ##.......#...#.#.#....#. 57 | #.###...##..#...##.##..# 58 | ##...####..##..#.#.#.##. 59 | #.###.##.###..#######.## 60 | #..###...##.##..#.##.##. 61 | #.#.#.#.#.#.###....#.#.# 62 | ##.#...#.#.#..#...#####. 63 | #...####..#...##..#.#..# 64 | ##...#...##.###.#.....#. 65 | #.###.#.##.#.....###..## 66 | ##..#####...#..##...###. 67 | ###...#.####.##.#.#.#..# 68 | #..###..#.#.####.#.###.. 69 | ###.#.#..#..#.###.#.##.# 70 | #####.##.###..#.####.#.. 71 | #.##.#......#.#..#.#.### 72 | ###.#....######.#...##.. 73 | ##...#..##.###..#...#### 74 | #.######.###.##..#...##. 75 | #..#..#.##.#..####...#.# 76 | ###.###..#..##.#.##...#. 77 | ########################` 78 | 79 | bc, err := Encode(data) 80 | 81 | if err != nil { 82 | t.Error(err) 83 | return 84 | } 85 | realResult := bc.(*datamatrixCode) 86 | if realResult.Columns != 24 || realResult.Rows != 24 { 87 | t.Errorf("Got wrong barcode size %dx%d", realResult.Columns, realResult.Rows) 88 | return 89 | } 90 | 91 | wantedResult := codeFromStr(barcode, realResult.dmCodeSize) 92 | 93 | for x := 0; x < wantedResult.Columns; x++ { 94 | for y := 0; y < wantedResult.Rows; y++ { 95 | r := realResult.get(x, y) 96 | w := wantedResult.get(x, y) 97 | if w != r { 98 | t.Errorf("Failed at: c%d/r%d", x, y) 99 | } 100 | } 101 | } 102 | } 103 | 104 | func Test_GS1DataMatrix(t *testing.T) { 105 | // Example 2 from the GS1 DataMatrix Guideline. 106 | // 107 | // (01)09501101020917(17)190508(10)ABCD1234(21)10 108 | // 109 | // See: https://www.gs1.org/standards/gs1-datamatrix-guideline/25#2-Encoding-data+2-3-Human-readable-interpretation-(HRI) 110 | data := new(bytes.Buffer) 111 | data.WriteByte(FNC1) // Start Character 112 | data.WriteString("0109501101020917") // AI (01) 113 | data.WriteString("17190508") // AI (17) 114 | data.WriteString("10ABCD1234") // AI (10) does not have pre-defined length 115 | data.WriteByte(FNC1) // Separator Character 116 | data.WriteString("2110") // AI (20) 117 | 118 | // Codewords from decoding example 2 with "dmtxread -c". 119 | wantedData := []byte{ 120 | 232, // FNC1 121 | 131, 139, 180, 141, 131, 132, 139, 147, 122 | 147, 149, 135, 138, 123 | 140, 66, 67, 68, 69, 142, 164, 124 | 232, // FNC1 125 | 151, 140, 126 | } 127 | 128 | realData := encodeText(data.String()) 129 | if bytes.Compare(realData, wantedData) != 0 { 130 | t.Errorf("GS1 DataMatrix encoding failed\nwant: %v\ngot: %v\n", wantedData, realData) 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /twooffive/encoder.go: -------------------------------------------------------------------------------- 1 | // Package twooffive can create interleaved and standard "2 of 5" barcodes. 2 | package twooffive 3 | 4 | import ( 5 | "errors" 6 | "fmt" 7 | 8 | "github.com/boombuler/barcode" 9 | "github.com/boombuler/barcode/utils" 10 | ) 11 | 12 | const patternWidth = 5 13 | 14 | type pattern [patternWidth]bool 15 | type encodeInfo struct { 16 | start []bool 17 | end []bool 18 | widths map[bool]int 19 | } 20 | 21 | var ( 22 | encodingTable = map[rune]pattern{ 23 | '0': pattern{false, false, true, true, false}, 24 | '1': pattern{true, false, false, false, true}, 25 | '2': pattern{false, true, false, false, true}, 26 | '3': pattern{true, true, false, false, false}, 27 | '4': pattern{false, false, true, false, true}, 28 | '5': pattern{true, false, true, false, false}, 29 | '6': pattern{false, true, true, false, false}, 30 | '7': pattern{false, false, false, true, true}, 31 | '8': pattern{true, false, false, true, false}, 32 | '9': pattern{false, true, false, true, false}, 33 | } 34 | 35 | modes = map[bool]encodeInfo{ 36 | false: encodeInfo{ // non-interleaved 37 | start: []bool{true, true, false, true, true, false, true, false}, 38 | end: []bool{true, true, false, true, false, true, true}, 39 | widths: map[bool]int{ 40 | true: 3, 41 | false: 1, 42 | }, 43 | }, 44 | true: encodeInfo{ // interleaved 45 | start: []bool{true, false, true, false}, 46 | end: []bool{true, true, true, false, true}, 47 | widths: map[bool]int{ 48 | true: 3, 49 | false: 1, 50 | }, 51 | }, 52 | } 53 | nonInterleavedSpace = pattern{false, false, false, false, false} 54 | ) 55 | 56 | // AddCheckSum calculates the correct check-digit and appends it to the given content. 57 | func AddCheckSum(content string) (string, error) { 58 | if content == "" { 59 | return "", errors.New("content is empty") 60 | } 61 | 62 | even := len(content)%2 == 1 63 | sum := 0 64 | for _, r := range content { 65 | if _, ok := encodingTable[r]; ok { 66 | value := utils.RuneToInt(r) 67 | if even { 68 | sum += value * 3 69 | } else { 70 | sum += value 71 | } 72 | even = !even 73 | } else { 74 | return "", fmt.Errorf("can not encode %s", content) 75 | } 76 | } 77 | 78 | return content + string(utils.IntToRune(sum%10)), nil 79 | } 80 | 81 | // Encode creates a codabar barcode for the given content and color scheme 82 | func EncodeWithColor(content string, interleaved bool, color barcode.ColorScheme) (barcode.Barcode, error) { 83 | if content == "" { 84 | return nil, errors.New("content is empty") 85 | } 86 | 87 | if interleaved && len(content)%2 == 1 { 88 | return nil, errors.New("can only encode even number of digits in interleaved mode") 89 | } 90 | 91 | mode := modes[interleaved] 92 | resBits := new(utils.BitList) 93 | resBits.AddBit(mode.start...) 94 | 95 | var lastRune *rune 96 | for _, r := range content { 97 | var a, b pattern 98 | if interleaved { 99 | if lastRune == nil { 100 | lastRune = new(rune) 101 | *lastRune = r 102 | continue 103 | } else { 104 | var o1, o2 bool 105 | a, o1 = encodingTable[*lastRune] 106 | b, o2 = encodingTable[r] 107 | if !o1 || !o2 { 108 | return nil, fmt.Errorf("can not encode %q", content) 109 | } 110 | lastRune = nil 111 | } 112 | } else { 113 | var ok bool 114 | a, ok = encodingTable[r] 115 | if !ok { 116 | return nil, fmt.Errorf("can not encode %q", content) 117 | } 118 | b = nonInterleavedSpace 119 | } 120 | 121 | for i := 0; i < patternWidth; i++ { 122 | for x := 0; x < mode.widths[a[i]]; x++ { 123 | resBits.AddBit(true) 124 | } 125 | for x := 0; x < mode.widths[b[i]]; x++ { 126 | resBits.AddBit(false) 127 | } 128 | } 129 | } 130 | 131 | resBits.AddBit(mode.end...) 132 | 133 | if interleaved { 134 | return utils.New1DCodeWithColor(barcode.Type2of5Interleaved, content, resBits, color), nil 135 | } else { 136 | return utils.New1DCodeWithColor(barcode.Type2of5, content, resBits, color), nil 137 | } 138 | } 139 | 140 | // Encode creates a codabar barcode for the given content 141 | func Encode(content string, interleaved bool) (barcode.Barcode, error) { 142 | return EncodeWithColor(content, interleaved, barcode.ColorScheme16) 143 | } 144 | -------------------------------------------------------------------------------- /qr/qrcode.go: -------------------------------------------------------------------------------- 1 | package qr 2 | 3 | import ( 4 | "image" 5 | "image/color" 6 | "math" 7 | 8 | "github.com/boombuler/barcode" 9 | "github.com/boombuler/barcode/utils" 10 | ) 11 | 12 | type qrcode struct { 13 | dimension int 14 | data *utils.BitList 15 | content string 16 | color barcode.ColorScheme 17 | } 18 | 19 | func (qr *qrcode) Content() string { 20 | return qr.content 21 | } 22 | 23 | func (qr *qrcode) Metadata() barcode.Metadata { 24 | return barcode.Metadata{CodeKind: barcode.TypeQR, Dimensions: 2} 25 | } 26 | 27 | func (qr *qrcode) ColorModel() color.Model { 28 | return qr.color.Model 29 | } 30 | 31 | func (c *qrcode) ColorScheme() barcode.ColorScheme { 32 | return c.color 33 | } 34 | 35 | func (qr *qrcode) Bounds() image.Rectangle { 36 | return image.Rect(0, 0, qr.dimension, qr.dimension) 37 | } 38 | 39 | func (qr *qrcode) At(x, y int) color.Color { 40 | if qr.Get(x, y) { 41 | return qr.color.Foreground 42 | } 43 | return qr.color.Background 44 | } 45 | 46 | func (qr *qrcode) Get(x, y int) bool { 47 | return qr.data.GetBit(x*qr.dimension + y) 48 | } 49 | 50 | func (qr *qrcode) Set(x, y int, val bool) { 51 | qr.data.SetBit(x*qr.dimension+y, val) 52 | } 53 | 54 | func (qr *qrcode) calcPenalty() uint { 55 | return qr.calcPenaltyRule1() + qr.calcPenaltyRule2() + qr.calcPenaltyRule3() + qr.calcPenaltyRule4() 56 | } 57 | 58 | func (qr *qrcode) calcPenaltyRule1() uint { 59 | var result uint 60 | for x := 0; x < qr.dimension; x++ { 61 | checkForX := false 62 | var cntX uint 63 | checkForY := false 64 | var cntY uint 65 | 66 | for y := 0; y < qr.dimension; y++ { 67 | if qr.Get(x, y) == checkForX { 68 | cntX++ 69 | } else { 70 | checkForX = !checkForX 71 | if cntX >= 5 { 72 | result += cntX - 2 73 | } 74 | cntX = 1 75 | } 76 | 77 | if qr.Get(y, x) == checkForY { 78 | cntY++ 79 | } else { 80 | checkForY = !checkForY 81 | if cntY >= 5 { 82 | result += cntY - 2 83 | } 84 | cntY = 1 85 | } 86 | } 87 | 88 | if cntX >= 5 { 89 | result += cntX - 2 90 | } 91 | if cntY >= 5 { 92 | result += cntY - 2 93 | } 94 | } 95 | 96 | return result 97 | } 98 | 99 | func (qr *qrcode) calcPenaltyRule2() uint { 100 | var result uint 101 | for x := 0; x < qr.dimension-1; x++ { 102 | for y := 0; y < qr.dimension-1; y++ { 103 | check := qr.Get(x, y) 104 | if qr.Get(x, y+1) == check && qr.Get(x+1, y) == check && qr.Get(x+1, y+1) == check { 105 | result += 3 106 | } 107 | } 108 | } 109 | return result 110 | } 111 | 112 | func (qr *qrcode) calcPenaltyRule3() uint { 113 | pattern1 := []bool{true, false, true, true, true, false, true, false, false, false, false} 114 | pattern2 := []bool{false, false, false, false, true, false, true, true, true, false, true} 115 | 116 | var result uint 117 | for x := 0; x <= qr.dimension-len(pattern1); x++ { 118 | for y := 0; y < qr.dimension; y++ { 119 | pattern1XFound := true 120 | pattern2XFound := true 121 | pattern1YFound := true 122 | pattern2YFound := true 123 | 124 | for i := 0; i < len(pattern1); i++ { 125 | iv := qr.Get(x+i, y) 126 | if iv != pattern1[i] { 127 | pattern1XFound = false 128 | } 129 | if iv != pattern2[i] { 130 | pattern2XFound = false 131 | } 132 | iv = qr.Get(y, x+i) 133 | if iv != pattern1[i] { 134 | pattern1YFound = false 135 | } 136 | if iv != pattern2[i] { 137 | pattern2YFound = false 138 | } 139 | } 140 | if pattern1XFound || pattern2XFound { 141 | result += 40 142 | } 143 | if pattern1YFound || pattern2YFound { 144 | result += 40 145 | } 146 | } 147 | } 148 | 149 | return result 150 | } 151 | 152 | func (qr *qrcode) calcPenaltyRule4() uint { 153 | totalNum := qr.data.Len() 154 | trueCnt := 0 155 | for i := 0; i < totalNum; i++ { 156 | if qr.data.GetBit(i) { 157 | trueCnt++ 158 | } 159 | } 160 | percDark := float64(trueCnt) * 100 / float64(totalNum) 161 | floor := math.Abs(math.Floor(percDark/5) - 10) 162 | ceil := math.Abs(math.Ceil(percDark/5) - 10) 163 | return uint(math.Min(floor, ceil) * 10) 164 | } 165 | 166 | func newBarCodeWithColor(dim int, color barcode.ColorScheme) *qrcode { 167 | res := new(qrcode) 168 | res.dimension = dim 169 | res.data = utils.NewBitList(dim * dim) 170 | res.color = color 171 | return res 172 | } 173 | 174 | func newBarcode(dim int) *qrcode { 175 | return newBarCodeWithColor(dim, barcode.ColorScheme16) 176 | } 177 | -------------------------------------------------------------------------------- /code128/encode_test.go: -------------------------------------------------------------------------------- 1 | package code128 2 | 3 | import ( 4 | "image/color" 5 | "testing" 6 | ) 7 | 8 | func testEncode(t *testing.T, txt, testResult string) { 9 | code, err := Encode(txt) 10 | if err != nil || code == nil { 11 | t.Error(err) 12 | } else { 13 | if code.Bounds().Max.X != len(testResult) { 14 | t.Errorf("%v: length missmatch. Got %d expected %d", txt, code.Bounds().Max.X, len(testResult)) 15 | } else { 16 | encoded := "" 17 | failed := false 18 | for i, r := range testResult { 19 | if code.At(i, 0) == color.Black { 20 | encoded += "1" 21 | } else { 22 | encoded += "0" 23 | } 24 | 25 | if (code.At(i, 0) == color.Black) != (r == '1') { 26 | failed = true 27 | t.Errorf("%v: code missmatch on position %d", txt, i) 28 | } 29 | } 30 | if failed { 31 | t.Log("Encoded: ", encoded) 32 | } 33 | } 34 | } 35 | } 36 | 37 | func Test_EncodeFunctionChars(t *testing.T) { 38 | encFNC1 := "11110101110" 39 | encFNC2 := "11110101000" 40 | encFNC3 := "10111100010" 41 | encFNC4 := "10111101110" 42 | encStartB := "11010010000" 43 | encStop := "1100011101011" 44 | 45 | // Special Case FC1 can also be encoded to C Table therefor using 123 as suffix might have unexpected results. 46 | testEncode(t, string(FNC1)+"A23", encStartB+encFNC1+"10100011000"+"11001110010"+"11001011100"+"10100011110"+encStop) 47 | testEncode(t, string(FNC2)+"123", encStartB+encFNC2+"10011100110"+"11001110010"+"11001011100"+"11100010110"+encStop) 48 | testEncode(t, string(FNC3)+"123", encStartB+encFNC3+"10011100110"+"11001110010"+"11001011100"+"11101000110"+encStop) 49 | testEncode(t, string(FNC4)+"123", encStartB+encFNC4+"10011100110"+"11001110010"+"11001011100"+"11100011010"+encStop) 50 | } 51 | 52 | func Test_Unencodable(t *testing.T) { 53 | if _, err := Encode(""); err == nil { 54 | t.Fail() 55 | } 56 | if _, err := Encode("ä"); err == nil { 57 | t.Fail() 58 | } 59 | } 60 | 61 | func Test_EncodeCTable(t *testing.T) { 62 | testEncode(t, "HI345678H", "110100100001100010100011000100010101110111101000101100011100010110110000101001011110111011000101000111011000101100011101011") 63 | testEncode(t, "334455", "11010011100101000110001000110111011101000110100100111101100011101011") 64 | 65 | testEncode(t, string(FNC1)+"1234", 66 | "11010011100"+ // Start C 67 | "11110101110"+ // FNC1 68 | "10110011100"+ // 12 69 | "10001011000"+ // 34 70 | "11101001100"+ // CheckSum == 24 71 | "1100011101011") // Stop 72 | } 73 | 74 | func Test_shouldUseCTable(t *testing.T) { 75 | if !shouldUseCTable([]rune{FNC1, '1', '2'}, startCSymbol) { 76 | t.Error("[FNC1]12 failed") 77 | } 78 | if shouldUseCTable([]rune{FNC1, '1'}, startCSymbol) { 79 | t.Error("[FNC1]1 failed") 80 | } 81 | if shouldUseCTable([]rune{'0', FNC1, '1'}, startCSymbol) { 82 | t.Error("0[FNC1]1 failed") 83 | } 84 | if !shouldUseCTable([]rune{'0', '1', FNC1, '2', '3'}, startBSymbol) { 85 | t.Error("01[FNC1]23 failed") 86 | } 87 | if shouldUseCTable([]rune{'0', '1', FNC1}, startBSymbol) { 88 | t.Error("01[FNC1] failed") 89 | } 90 | } 91 | 92 | func Test_Issue16(t *testing.T) { 93 | if !shouldUseATable([]rune{'\r', 'A'}, 0) { 94 | t.Error("Code should start with A-Table if the text start with \\r") 95 | } 96 | if !shouldUseATable([]rune{FNC1, '\r'}, 0) { 97 | t.Error("Code should start with A-Table if the text start with \\r") 98 | } 99 | if shouldUseATable([]rune{FNC1, '1', '2', '3'}, 0) { 100 | t.Error("Code should not start with A-Table if the text start with 123") 101 | } 102 | testEncode(t, string(FNC3)+"$P\rI", "110100001001011110001010010001100111011101101111011101011000100010110001010001100011101011") 103 | } 104 | 105 | func Test_Datalogic(t *testing.T) { 106 | // $P\r 107 | testEncode(t, string(FNC3)+"$P\r", 108 | "11010000100"+ // 109 | "10111100010"+ // 110 | "10010001100"+ // $ 111 | "11101110110"+ // P 112 | "11110111010"+ // CR 113 | "11000100010"+ // checksum = 'I' 114 | "1100011101011") // STOP 115 | 116 | // $P,Ae,P 117 | testEncode(t, string(FNC3)+"$P,Ae,P\r", 118 | "11010010000"+ // 119 | "10111100010"+ // 120 | "10010001100"+ // $ 121 | "11101110110"+ // P 122 | "10110011100"+ // , 123 | "10100011000"+ // A 124 | "10110010000"+ // e 125 | "10110011100"+ // , 126 | "11101110110"+ // P 127 | "11101011110"+ // 128 | "11110111010"+ // 129 | "10110001000"+ // checksum = 'D' 130 | "1100011101011") // STOP 131 | } 132 | -------------------------------------------------------------------------------- /pdf417/encoder.go: -------------------------------------------------------------------------------- 1 | // Package pdf417 can create PDF-417 barcodes 2 | package pdf417 3 | 4 | import ( 5 | "fmt" 6 | 7 | "github.com/boombuler/barcode" 8 | "github.com/boombuler/barcode/utils" 9 | ) 10 | 11 | const ( 12 | padding_codeword = 900 13 | ) 14 | 15 | // Encodes the given data and color scheme as PDF417 barcode. 16 | // securityLevel should be between 0 and 8. The higher the number, the more 17 | // additional error-correction codes are added. 18 | func EncodeWithColor(data string, securityLevel byte, color barcode.ColorScheme) (barcode.Barcode, error) { 19 | if securityLevel >= 9 { 20 | return nil, fmt.Errorf("invalid security level %d", securityLevel) 21 | } 22 | 23 | sl := securitylevel(securityLevel) 24 | 25 | dataWords, err := highlevelEncode(data) 26 | if err != nil { 27 | return nil, err 28 | } 29 | 30 | columns, rows := calcDimensions(len(dataWords), sl.ErrorCorrectionWordCount()) 31 | if columns < minCols || columns > maxCols || rows < minRows || rows > maxRows { 32 | return nil, fmt.Errorf("unable to fit data in barcode") 33 | } 34 | 35 | barcode := new(pdfBarcode) 36 | barcode.data = data 37 | barcode.color = color 38 | 39 | codeWords, err := encodeData(dataWords, columns, sl) 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | grid := [][]int{} 45 | for i := 0; i < len(codeWords); i += columns { 46 | grid = append(grid, codeWords[i:min(i+columns, len(codeWords))]) 47 | } 48 | 49 | codes := [][]int{} 50 | 51 | for rowNum, row := range grid { 52 | table := rowNum % 3 53 | rowCodes := make([]int, 0, columns+4) 54 | 55 | rowCodes = append(rowCodes, start_word) 56 | rowCodes = append(rowCodes, getCodeword(table, getLeftCodeWord(rowNum, rows, columns, securityLevel))) 57 | 58 | for _, word := range row { 59 | rowCodes = append(rowCodes, getCodeword(table, word)) 60 | } 61 | 62 | rowCodes = append(rowCodes, getCodeword(table, getRightCodeWord(rowNum, rows, columns, securityLevel))) 63 | rowCodes = append(rowCodes, stop_word) 64 | 65 | codes = append(codes, rowCodes) 66 | } 67 | 68 | barcode.code = renderBarcode(codes) 69 | barcode.width = (columns+4)*17 + 1 70 | 71 | return barcode, nil 72 | } 73 | 74 | // Encodes the given data as PDF417 barcode. 75 | // securityLevel should be between 0 and 8. The higher the number, the more 76 | // additional error-correction codes are added. 77 | func Encode(data string, securityLevel byte) (barcode.Barcode, error) { 78 | return EncodeWithColor(data, securityLevel, barcode.ColorScheme16) 79 | } 80 | 81 | func encodeData(dataWords []int, columns int, sl securitylevel) ([]int, error) { 82 | dataCount := len(dataWords) 83 | 84 | ecCount := sl.ErrorCorrectionWordCount() 85 | 86 | padWords := getPadding(dataCount, ecCount, columns) 87 | dataWords = append(dataWords, padWords...) 88 | 89 | length := len(dataWords) + 1 90 | dataWords = append([]int{length}, dataWords...) 91 | 92 | ecWords := sl.Compute(dataWords) 93 | 94 | return append(dataWords, ecWords...), nil 95 | } 96 | 97 | func getLeftCodeWord(rowNum int, rows int, columns int, securityLevel byte) int { 98 | tableId := rowNum % 3 99 | 100 | var x int 101 | 102 | switch tableId { 103 | case 0: 104 | x = (rows - 3) / 3 105 | case 1: 106 | x = int(securityLevel) * 3 107 | x += (rows - 1) % 3 108 | case 2: 109 | x = columns - 1 110 | } 111 | 112 | return 30*(rowNum/3) + x 113 | } 114 | 115 | func getRightCodeWord(rowNum int, rows int, columns int, securityLevel byte) int { 116 | tableId := rowNum % 3 117 | 118 | var x int 119 | 120 | switch tableId { 121 | case 0: 122 | x = columns - 1 123 | case 1: 124 | x = (rows - 1) / 3 125 | case 2: 126 | x = int(securityLevel) * 3 127 | x += (rows - 1) % 3 128 | } 129 | 130 | return 30*(rowNum/3) + x 131 | } 132 | 133 | func min(a, b int) int { 134 | if a <= b { 135 | return a 136 | } 137 | return b 138 | } 139 | 140 | func getPadding(dataCount int, ecCount int, columns int) []int { 141 | totalCount := dataCount + ecCount + 1 142 | mod := totalCount % columns 143 | 144 | padding := []int{} 145 | 146 | if mod > 0 { 147 | padCount := columns - mod 148 | padding = make([]int, padCount) 149 | for i := 0; i < padCount; i++ { 150 | padding[i] = padding_codeword 151 | } 152 | } 153 | 154 | return padding 155 | } 156 | 157 | func renderBarcode(codes [][]int) *utils.BitList { 158 | bl := new(utils.BitList) 159 | for _, row := range codes { 160 | lastIdx := len(row) - 1 161 | for i, col := range row { 162 | if i == lastIdx { 163 | bl.AddBits(col, 18) 164 | } else { 165 | bl.AddBits(col, 17) 166 | } 167 | } 168 | } 169 | return bl 170 | } 171 | -------------------------------------------------------------------------------- /qr/versioninfo_test.go: -------------------------------------------------------------------------------- 1 | package qr 2 | 3 | import "testing" 4 | 5 | var testvi = &versionInfo{7, M, 0, 1, 10, 2, 5} // Fake versionInfo to run some of the tests 6 | 7 | func Test_ErrorCorrectionStringer(t *testing.T) { 8 | tests := map[ErrorCorrectionLevel]string{ 9 | L: "L", M: "M", Q: "Q", H: "H", ErrorCorrectionLevel(99): "unknown", 10 | } 11 | for ecl, str := range tests { 12 | if ecl.String() != str { 13 | t.Fail() 14 | } 15 | } 16 | } 17 | 18 | func Test_CharCountBits(t *testing.T) { 19 | v1 := &versionInfo{5, M, 0, 0, 0, 0, 0} 20 | v2 := &versionInfo{15, M, 0, 0, 0, 0, 0} 21 | v3 := &versionInfo{30, M, 0, 0, 0, 0, 0} 22 | 23 | if v1.charCountBits(numericMode) != 10 { 24 | t.Fail() 25 | } 26 | if v1.charCountBits(alphaNumericMode) != 9 { 27 | t.Fail() 28 | } 29 | if v1.charCountBits(byteMode) != 8 { 30 | t.Fail() 31 | } 32 | if v1.charCountBits(kanjiMode) != 8 { 33 | t.Fail() 34 | } 35 | if v2.charCountBits(numericMode) != 12 { 36 | t.Fail() 37 | } 38 | if v2.charCountBits(alphaNumericMode) != 11 { 39 | t.Fail() 40 | } 41 | if v2.charCountBits(byteMode) != 16 { 42 | t.Fail() 43 | } 44 | if v2.charCountBits(kanjiMode) != 10 { 45 | t.Fail() 46 | } 47 | if v3.charCountBits(numericMode) != 14 { 48 | t.Fail() 49 | } 50 | if v3.charCountBits(alphaNumericMode) != 13 { 51 | t.Fail() 52 | } 53 | if v3.charCountBits(byteMode) != 16 { 54 | t.Fail() 55 | } 56 | if v3.charCountBits(kanjiMode) != 12 { 57 | t.Fail() 58 | } 59 | if v1.charCountBits(encodingMode(3)) != 0 { 60 | t.Fail() 61 | } 62 | } 63 | 64 | func Test_TotalDataBytes(t *testing.T) { 65 | if testvi.totalDataBytes() != 20 { 66 | t.Fail() 67 | } 68 | } 69 | 70 | func Test_ModulWidth(t *testing.T) { 71 | if testvi.modulWidth() != 45 { 72 | t.Fail() 73 | } 74 | } 75 | 76 | func Test_FindSmallestVersionInfo(t *testing.T) { 77 | if findSmallestVersionInfo(H, alphaNumericMode, 10208) != nil { 78 | t.Error("there should be no version with this capacity") 79 | } 80 | test := func(cap int, tVersion byte) { 81 | v := findSmallestVersionInfo(H, alphaNumericMode, cap) 82 | if v == nil || v.Version != tVersion { 83 | t.Errorf("version %d should be returned.", tVersion) 84 | } 85 | } 86 | test(10191, 40) 87 | test(5591, 29) 88 | test(5592, 30) 89 | test(190, 3) 90 | test(200, 4) 91 | } 92 | 93 | type aligmnentTest struct { 94 | version byte 95 | patterns []int 96 | } 97 | 98 | var allAligmnentTests = []*aligmnentTest{ 99 | &aligmnentTest{1, []int{}}, 100 | &aligmnentTest{2, []int{6, 18}}, 101 | &aligmnentTest{3, []int{6, 22}}, 102 | &aligmnentTest{4, []int{6, 26}}, 103 | &aligmnentTest{5, []int{6, 30}}, 104 | &aligmnentTest{6, []int{6, 34}}, 105 | &aligmnentTest{7, []int{6, 22, 38}}, 106 | &aligmnentTest{8, []int{6, 24, 42}}, 107 | &aligmnentTest{9, []int{6, 26, 46}}, 108 | &aligmnentTest{10, []int{6, 28, 50}}, 109 | &aligmnentTest{11, []int{6, 30, 54}}, 110 | &aligmnentTest{12, []int{6, 32, 58}}, 111 | &aligmnentTest{13, []int{6, 34, 62}}, 112 | &aligmnentTest{14, []int{6, 26, 46, 66}}, 113 | &aligmnentTest{15, []int{6, 26, 48, 70}}, 114 | &aligmnentTest{16, []int{6, 26, 50, 74}}, 115 | &aligmnentTest{17, []int{6, 30, 54, 78}}, 116 | &aligmnentTest{18, []int{6, 30, 56, 82}}, 117 | &aligmnentTest{19, []int{6, 30, 58, 86}}, 118 | &aligmnentTest{20, []int{6, 34, 62, 90}}, 119 | &aligmnentTest{21, []int{6, 28, 50, 72, 94}}, 120 | &aligmnentTest{22, []int{6, 26, 50, 74, 98}}, 121 | &aligmnentTest{23, []int{6, 30, 54, 78, 102}}, 122 | &aligmnentTest{24, []int{6, 28, 54, 80, 106}}, 123 | &aligmnentTest{25, []int{6, 32, 58, 84, 110}}, 124 | &aligmnentTest{26, []int{6, 30, 58, 86, 114}}, 125 | &aligmnentTest{27, []int{6, 34, 62, 90, 118}}, 126 | &aligmnentTest{28, []int{6, 26, 50, 74, 98, 122}}, 127 | &aligmnentTest{29, []int{6, 30, 54, 78, 102, 126}}, 128 | &aligmnentTest{30, []int{6, 26, 52, 78, 104, 130}}, 129 | &aligmnentTest{31, []int{6, 30, 56, 82, 108, 134}}, 130 | &aligmnentTest{32, []int{6, 34, 60, 86, 112, 138}}, 131 | &aligmnentTest{33, []int{6, 30, 58, 86, 114, 142}}, 132 | &aligmnentTest{34, []int{6, 34, 62, 90, 118, 146}}, 133 | &aligmnentTest{35, []int{6, 30, 54, 78, 102, 126, 150}}, 134 | &aligmnentTest{36, []int{6, 24, 50, 76, 102, 128, 154}}, 135 | &aligmnentTest{37, []int{6, 28, 54, 80, 106, 132, 158}}, 136 | &aligmnentTest{38, []int{6, 32, 58, 84, 110, 136, 162}}, 137 | &aligmnentTest{39, []int{6, 26, 54, 82, 110, 138, 166}}, 138 | &aligmnentTest{40, []int{6, 30, 58, 86, 114, 142, 170}}, 139 | } 140 | 141 | func Test_AlignmentPatternPlacements(t *testing.T) { 142 | for _, at := range allAligmnentTests { 143 | vi := &versionInfo{at.version, M, 0, 0, 0, 0, 0} 144 | 145 | res := vi.alignmentPatternPlacements() 146 | if len(res) != len(at.patterns) { 147 | t.Errorf("number of alignmentpatterns missmatch for version %d", at.version) 148 | } 149 | for i := 0; i < len(res); i++ { 150 | if res[i] != at.patterns[i] { 151 | t.Errorf("alignmentpatterns for version %d missmatch on index %d", at.version, i) 152 | } 153 | } 154 | 155 | } 156 | 157 | } 158 | -------------------------------------------------------------------------------- /aztec/highlevel_test.go: -------------------------------------------------------------------------------- 1 | package aztec 2 | 3 | import ( 4 | "bytes" 5 | "strings" 6 | "testing" 7 | 8 | "github.com/boombuler/barcode/utils" 9 | ) 10 | 11 | func bitStr(bl *utils.BitList) string { 12 | buf := new(bytes.Buffer) 13 | 14 | for i := 0; i < bl.Len(); i++ { 15 | if bl.GetBit(i) { 16 | buf.WriteRune('X') 17 | } else { 18 | buf.WriteRune('.') 19 | } 20 | } 21 | return buf.String() 22 | } 23 | 24 | func testHighLevelEncodeString(t *testing.T, s, expectedBits string) { 25 | bits := highlevelEncode([]byte(s)) 26 | result := bitStr(bits) 27 | expectedBits = strings.Replace(expectedBits, " ", "", -1) 28 | 29 | if result != expectedBits { 30 | t.Errorf("invalid result for highlevelEncode(%q). Got:\n%s", s, result) 31 | } 32 | } 33 | func testHighLevelEncodeStringCnt(t *testing.T, s string, expectedBitCnt int) { 34 | bits := highlevelEncode([]byte(s)) 35 | 36 | if bits.Len() != expectedBitCnt { 37 | t.Errorf("invalid result for highlevelEncode(%q). Got %d, expected %d bits", s, bits.Len(), expectedBitCnt) 38 | } 39 | } 40 | 41 | func Test_HighLevelEncode(t *testing.T) { 42 | testHighLevelEncodeString(t, "A. b.", 43 | // 'A' P/S '. ' L/L b D/L '.' 44 | "...X. ..... ...XX XXX.. ...XX XXXX. XX.X") 45 | testHighLevelEncodeString(t, "Lorem ipsum.", 46 | // 'L' L/L 'o' 'r' 'e' 'm' ' ' 'i' 'p' 's' 'u' 'm' D/L '.' 47 | ".XX.X XXX.. X.... X..XX ..XX. .XXX. ....X .X.X. X...X X.X.. X.XX. .XXX. XXXX. XX.X") 48 | testHighLevelEncodeString(t, "Lo. Test 123.", 49 | // 'L' L/L 'o' P/S '. ' U/S 'T' 'e' 's' 't' D/L ' ' '1' '2' '3' '.' 50 | ".XX.X XXX.. X.... ..... ...XX XXX.. X.X.X ..XX. X.X.. X.X.X XXXX. ...X ..XX .X.. .X.X XX.X") 51 | testHighLevelEncodeString(t, "Lo...x", 52 | // 'L' L/L 'o' D/L '.' '.' '.' U/L L/L 'x' 53 | ".XX.X XXX.. X.... XXXX. XX.X XX.X XX.X XXX. XXX.. XX..X") 54 | testHighLevelEncodeString(t, ". x://abc/.", 55 | //P/S '. ' L/L 'x' P/S ':' P/S '/' P/S '/' 'a' 'b' 'c' P/S '/' D/L '.' 56 | "..... ...XX XXX.. XX..X ..... X.X.X ..... X.X.. ..... X.X.. ...X. ...XX ..X.. ..... X.X.. XXXX. XX.X") 57 | // Uses Binary/Shift rather than Lower/Shift to save two bits. 58 | testHighLevelEncodeString(t, "ABCdEFG", 59 | //'A' 'B' 'C' B/S =1 'd' 'E' 'F' 'G' 60 | "...X. ...XX ..X.. XXXXX ....X .XX..X.. ..XX. ..XXX .X...") 61 | 62 | testHighLevelEncodeStringCnt(t, 63 | // Found on an airline boarding pass. Several stretches of Binary shift are 64 | // necessary to keep the bitcount so low. 65 | "09 UAG ^160MEUCIQC0sYS/HpKxnBELR1uB85R20OoqqwFGa0q2uEi"+ 66 | "Ygh6utAIgLl1aBVM4EOTQtMQQYH9M2Z3Dp4qnA/fwWuQ+M8L3V8U=", 67 | 823) 68 | } 69 | 70 | func Test_HighLevelEncodeBinary(t *testing.T) { 71 | // binary short form single byte 72 | testHighLevelEncodeString(t, "N\u0000N", 73 | // 'N' B/S =1 '\0' N 74 | ".XXXX XXXXX ....X ........ .XXXX") // Encode "N" in UPPER 75 | 76 | testHighLevelEncodeString(t, "N\u0000n", 77 | // 'N' B/S =2 '\0' 'n' 78 | ".XXXX XXXXX ...X. ........ .XX.XXX.") // Encode "n" in BINARY 79 | 80 | // binary short form consecutive bytes 81 | testHighLevelEncodeString(t, "N\x00\x80 A", 82 | // 'N' B/S =2 '\0' \u0080 ' ' 'A' 83 | ".XXXX XXXXX ...X. ........ X....... ....X ...X.") 84 | 85 | // binary skipping over single character 86 | testHighLevelEncodeString(t, "\x00a\xFF\x80 A", 87 | // B/S =4 '\0' 'a' '\3ff' '\200' ' ' 'A' 88 | "XXXXX ..X.. ........ .XX....X XXXXXXXX X....... ....X ...X.") 89 | 90 | // getting into binary mode from digit mode 91 | testHighLevelEncodeString(t, "1234\u0000", 92 | //D/L '1' '2' '3' '4' U/L B/S =1 \0 93 | "XXXX. ..XX .X.. .X.X .XX. XXX. XXXXX ....X ........") 94 | 95 | // Create a string in which every character requires binary 96 | sb := new(bytes.Buffer) 97 | for i := 0; i <= 3000; i++ { 98 | sb.WriteByte(byte(128 + (i % 30))) 99 | } 100 | 101 | // Test the output generated by Binary/Switch, particularly near the 102 | // places where the encoding changes: 31, 62, and 2047+31=2078 103 | for _, i := range []int{1, 2, 3, 10, 29, 30, 31, 32, 33, 60, 61, 62, 63, 64, 2076, 2077, 2078, 2079, 2080, 2100} { 104 | // This is the expected length of a binary string of length "i" 105 | expectedLength := (8 * i) 106 | switch { 107 | case i <= 31: 108 | expectedLength += 10 109 | case i <= 62: 110 | expectedLength += 20 111 | case i <= 2078: 112 | expectedLength += 21 113 | default: 114 | expectedLength += 31 115 | } 116 | data := string(sb.Bytes()[:i]) 117 | 118 | // Verify that we are correct about the length. 119 | testHighLevelEncodeStringCnt(t, data, expectedLength) 120 | if i != 1 && i != 32 && i != 2079 { 121 | // The addition of an 'a' at the beginning or end gets merged into the binary code 122 | // in those cases where adding another binary character only adds 8 or 9 bits to the result. 123 | // So we exclude the border cases i=1,32,2079 124 | // A lower case letter at the beginning will be merged into binary mode 125 | testHighLevelEncodeStringCnt(t, "a"+string(sb.Bytes()[:i-1]), expectedLength) 126 | // A lower case letter at the end will also be merged into binary mode 127 | testHighLevelEncodeStringCnt(t, string(sb.Bytes()[:i-1])+"a", expectedLength) 128 | } 129 | // A lower case letter at both ends will enough to latch us into LOWER. 130 | testHighLevelEncodeStringCnt(t, "a"+data+"b", expectedLength+15) 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /code93/encoder.go: -------------------------------------------------------------------------------- 1 | // Package code93 can create Code93 barcodes 2 | package code93 3 | 4 | import ( 5 | "errors" 6 | "strings" 7 | 8 | "github.com/boombuler/barcode" 9 | "github.com/boombuler/barcode/utils" 10 | ) 11 | 12 | type encodeInfo struct { 13 | value int 14 | data int 15 | } 16 | 17 | const ( 18 | // Special Function 1 ($) 19 | FNC1 = '\u00f1' 20 | // Special Function 2 (%) 21 | FNC2 = '\u00f2' 22 | // Special Function 3 (/) 23 | FNC3 = '\u00f3' 24 | // Special Function 4 (+) 25 | FNC4 = '\u00f4' 26 | ) 27 | 28 | var encodeTable = map[rune]encodeInfo{ 29 | '0': encodeInfo{0, 0x114}, '1': encodeInfo{1, 0x148}, '2': encodeInfo{2, 0x144}, 30 | '3': encodeInfo{3, 0x142}, '4': encodeInfo{4, 0x128}, '5': encodeInfo{5, 0x124}, 31 | '6': encodeInfo{6, 0x122}, '7': encodeInfo{7, 0x150}, '8': encodeInfo{8, 0x112}, 32 | '9': encodeInfo{9, 0x10A}, 'A': encodeInfo{10, 0x1A8}, 'B': encodeInfo{11, 0x1A4}, 33 | 'C': encodeInfo{12, 0x1A2}, 'D': encodeInfo{13, 0x194}, 'E': encodeInfo{14, 0x192}, 34 | 'F': encodeInfo{15, 0x18A}, 'G': encodeInfo{16, 0x168}, 'H': encodeInfo{17, 0x164}, 35 | 'I': encodeInfo{18, 0x162}, 'J': encodeInfo{19, 0x134}, 'K': encodeInfo{20, 0x11A}, 36 | 'L': encodeInfo{21, 0x158}, 'M': encodeInfo{22, 0x14C}, 'N': encodeInfo{23, 0x146}, 37 | 'O': encodeInfo{24, 0x12C}, 'P': encodeInfo{25, 0x116}, 'Q': encodeInfo{26, 0x1B4}, 38 | 'R': encodeInfo{27, 0x1B2}, 'S': encodeInfo{28, 0x1AC}, 'T': encodeInfo{29, 0x1A6}, 39 | 'U': encodeInfo{30, 0x196}, 'V': encodeInfo{31, 0x19A}, 'W': encodeInfo{32, 0x16C}, 40 | 'X': encodeInfo{33, 0x166}, 'Y': encodeInfo{34, 0x136}, 'Z': encodeInfo{35, 0x13A}, 41 | '-': encodeInfo{36, 0x12E}, '.': encodeInfo{37, 0x1D4}, ' ': encodeInfo{38, 0x1D2}, 42 | '$': encodeInfo{39, 0x1CA}, '/': encodeInfo{40, 0x16E}, '+': encodeInfo{41, 0x176}, 43 | '%': encodeInfo{42, 0x1AE}, FNC1: encodeInfo{43, 0x126}, FNC2: encodeInfo{44, 0x1DA}, 44 | FNC3: encodeInfo{45, 0x1D6}, FNC4: encodeInfo{46, 0x132}, '*': encodeInfo{47, 0x15E}, 45 | } 46 | 47 | var extendedTable = []string{ 48 | "\u00f2U", "\u00f1A", "\u00f1B", "\u00f1C", "\u00f1D", "\u00f1E", "\u00f1F", "\u00f1G", 49 | "\u00f1H", "\u00f1I", "\u00f1J", "\u00f1K", "\u00f1L", "\u00f1M", "\u00f1N", "\u00f1O", 50 | "\u00f1P", "\u00f1Q", "\u00f1R", "\u00f1S", "\u00f1T", "\u00f1U", "\u00f1V", "\u00f1W", 51 | "\u00f1X", "\u00f1Y", "\u00f1Z", "\u00f2A", "\u00f2B", "\u00f2C", "\u00f2D", "\u00f2E", 52 | " ", "\u00f3A", "\u00f3B", "\u00f3C", "\u00f3D", "\u00f3E", "\u00f3F", "\u00f3G", 53 | "\u00f3H", "\u00f3I", "\u00f3J", "\u00f3K", "\u00f3L", "-", ".", "\u00f3O", 54 | "0", "1", "2", "3", "4", "5", "6", "7", 55 | "8", "9", "\u00f3Z", "\u00f2F", "\u00f2G", "\u00f2H", "\u00f2I", "\u00f2J", 56 | "\u00f2V", "A", "B", "C", "D", "E", "F", "G", 57 | "H", "I", "J", "K", "L", "M", "N", "O", 58 | "P", "Q", "R", "S", "T", "U", "V", "W", 59 | "X", "Y", "Z", "\u00f2K", "\u00f2L", "\u00f2M", "\u00f2N", "\u00f2O", 60 | "\u00f2W", "\u00f4A", "\u00f4B", "\u00f4C", "\u00f4D", "\u00f4E", "\u00f4F", "\u00f4G", 61 | "\u00f4H", "\u00f4I", "\u00f4J", "\u00f4K", "\u00f4L", "\u00f4M", "\u00f4N", "\u00f4O", 62 | "\u00f4P", "\u00f4Q", "\u00f4R", "\u00f4S", "\u00f4T", "\u00f4U", "\u00f4V", "\u00f4W", 63 | "\u00f4X", "\u00f4Y", "\u00f4Z", "\u00f2P", "\u00f2Q", "\u00f2R", "\u00f2S", "\u00f2T", 64 | } 65 | 66 | func prepare(content string) (string, error) { 67 | result := "" 68 | for _, r := range content { 69 | if r > 127 { 70 | return "", errors.New("only ASCII strings can be encoded") 71 | } 72 | result += extendedTable[int(r)] 73 | } 74 | return result, nil 75 | } 76 | 77 | // Encode returns a code93 barcode for the given content and color scheme 78 | // if includeChecksum is set to true, two checksum characters are calculated and added to the content 79 | func EncodeWithColor(content string, includeChecksum bool, fullASCIIMode bool, color barcode.ColorScheme) (barcode.Barcode, error) { 80 | if fullASCIIMode { 81 | var err error 82 | content, err = prepare(content) 83 | if err != nil { 84 | return nil, err 85 | } 86 | } else if strings.ContainsRune(content, '*') { 87 | return nil, errors.New("invalid data! content may not contain '*'") 88 | } 89 | 90 | data := content + string(getChecksum(content, 20)) 91 | if includeChecksum { 92 | data += string(getChecksum(data, 15)) 93 | } 94 | 95 | data = "*" + data + "*" 96 | result := new(utils.BitList) 97 | 98 | for _, r := range data { 99 | info, ok := encodeTable[r] 100 | if !ok { 101 | return nil, errors.New("invalid data") 102 | } 103 | result.AddBits(info.data, 9) 104 | } 105 | result.AddBit(true) 106 | 107 | return utils.New1DCodeWithColor(barcode.TypeCode93, content, result, color), nil 108 | } 109 | 110 | // Encode returns a code93 barcode for the given content 111 | // if includeChecksum is set to true, two checksum characters are calculated and added to the content 112 | func Encode(content string, includeChecksum bool, fullASCIIMode bool) (barcode.Barcode, error) { 113 | return EncodeWithColor(content, includeChecksum, fullASCIIMode, barcode.ColorScheme16) 114 | } 115 | 116 | func getChecksum(content string, maxWeight int) rune { 117 | weight := 1 118 | total := 0 119 | 120 | data := []rune(content) 121 | for i := len(data) - 1; i >= 0; i-- { 122 | r := data[i] 123 | info, ok := encodeTable[r] 124 | if !ok { 125 | return ' ' 126 | } 127 | total += info.value * weight 128 | if weight++; weight > maxWeight { 129 | weight = 1 130 | } 131 | } 132 | total = total % 47 133 | for r, info := range encodeTable { 134 | if info.value == total { 135 | return r 136 | } 137 | } 138 | return ' ' 139 | } 140 | -------------------------------------------------------------------------------- /code128/encode.go: -------------------------------------------------------------------------------- 1 | // Package code128 can create Code128 barcodes 2 | package code128 3 | 4 | import ( 5 | "fmt" 6 | "strings" 7 | "unicode/utf8" 8 | 9 | "github.com/boombuler/barcode" 10 | "github.com/boombuler/barcode/utils" 11 | ) 12 | 13 | func strToRunes(str string) []rune { 14 | result := make([]rune, utf8.RuneCountInString(str)) 15 | i := 0 16 | for _, r := range str { 17 | result[i] = r 18 | i++ 19 | } 20 | return result 21 | } 22 | 23 | func shouldUseCTable(nextRunes []rune, curEncoding byte) bool { 24 | requiredDigits := 4 25 | if curEncoding == startCSymbol { 26 | requiredDigits = 2 27 | } 28 | if len(nextRunes) < requiredDigits { 29 | return false 30 | } 31 | for i := 0; i < requiredDigits; i++ { 32 | if i%2 == 0 && nextRunes[i] == FNC1 { 33 | requiredDigits++ 34 | if len(nextRunes) < requiredDigits { 35 | return false 36 | } 37 | continue 38 | } 39 | if nextRunes[i] < '0' || nextRunes[i] > '9' { 40 | return false 41 | } 42 | } 43 | return true 44 | } 45 | 46 | func tableContainsRune(table string, r rune) bool { 47 | return strings.ContainsRune(table, r) || r == FNC1 || r == FNC2 || r == FNC3 || r == FNC4 48 | } 49 | 50 | func shouldUseATable(nextRunes []rune, curEncoding byte) bool { 51 | nextRune := nextRunes[0] 52 | if !tableContainsRune(bTable, nextRune) || curEncoding == startASymbol { 53 | return tableContainsRune(aTable, nextRune) 54 | } 55 | if curEncoding == 0 { 56 | for _, r := range nextRunes { 57 | if tableContainsRune(abTable, r) { 58 | continue 59 | } 60 | if strings.ContainsRune(aOnlyTable, r) { 61 | return true 62 | } 63 | break 64 | } 65 | } 66 | return false 67 | } 68 | 69 | func getCodeIndexList(content []rune) *utils.BitList { 70 | result := new(utils.BitList) 71 | curEncoding := byte(0) 72 | for i := 0; i < len(content); i++ { 73 | if shouldUseCTable(content[i:], curEncoding) { 74 | if curEncoding != startCSymbol { 75 | if curEncoding == byte(0) { 76 | result.AddByte(startCSymbol) 77 | } else { 78 | result.AddByte(codeCSymbol) 79 | } 80 | curEncoding = startCSymbol 81 | } 82 | if content[i] == FNC1 { 83 | result.AddByte(102) 84 | } else { 85 | idx := (content[i] - '0') * 10 86 | i++ 87 | idx = idx + (content[i] - '0') 88 | result.AddByte(byte(idx)) 89 | } 90 | } else if shouldUseATable(content[i:], curEncoding) { 91 | if curEncoding != startASymbol { 92 | if curEncoding == byte(0) { 93 | result.AddByte(startASymbol) 94 | } else { 95 | result.AddByte(codeASymbol) 96 | } 97 | curEncoding = startASymbol 98 | } 99 | var idx int 100 | switch content[i] { 101 | case FNC1: 102 | idx = 102 103 | case FNC2: 104 | idx = 97 105 | case FNC3: 106 | idx = 96 107 | case FNC4: 108 | idx = 101 109 | default: 110 | idx = strings.IndexRune(aTable, content[i]) 111 | } 112 | if idx < 0 { 113 | return nil 114 | } 115 | result.AddByte(byte(idx)) 116 | } else { 117 | if curEncoding != startBSymbol { 118 | if curEncoding == byte(0) { 119 | result.AddByte(startBSymbol) 120 | } else { 121 | result.AddByte(codeBSymbol) 122 | } 123 | curEncoding = startBSymbol 124 | } 125 | var idx int 126 | switch content[i] { 127 | case FNC1: 128 | idx = 102 129 | case FNC2: 130 | idx = 97 131 | case FNC3: 132 | idx = 96 133 | case FNC4: 134 | idx = 100 135 | default: 136 | idx = strings.IndexRune(bTable, content[i]) 137 | } 138 | 139 | if idx < 0 { 140 | return nil 141 | } 142 | result.AddByte(byte(idx)) 143 | } 144 | } 145 | return result 146 | } 147 | 148 | // Encode creates a Code 128 barcode for the given content and color scheme 149 | func EncodeWithColor(content string, color barcode.ColorScheme) (barcode.BarcodeIntCS, error) { 150 | contentRunes := strToRunes(content) 151 | if len(contentRunes) <= 0 || len(contentRunes) > 80 { 152 | return nil, fmt.Errorf("content length should be between 1 and 80 runes but got %d", len(contentRunes)) 153 | } 154 | idxList := getCodeIndexList(contentRunes) 155 | 156 | if idxList == nil { 157 | return nil, fmt.Errorf("%q could not be encoded", content) 158 | } 159 | 160 | result := new(utils.BitList) 161 | sum := 0 162 | for i, idx := range idxList.GetBytes() { 163 | if i == 0 { 164 | sum = int(idx) 165 | } else { 166 | sum += i * int(idx) 167 | } 168 | result.AddBit(encodingTable[idx]...) 169 | } 170 | sum = sum % 103 171 | result.AddBit(encodingTable[sum]...) 172 | result.AddBit(encodingTable[stopSymbol]...) 173 | return utils.New1DCodeIntCheckSumWithColor(barcode.TypeCode128, content, result, sum, color), nil 174 | } 175 | 176 | // Encode creates a Code 128 barcode for the given content 177 | func Encode(content string) (barcode.BarcodeIntCS, error) { 178 | return EncodeWithColor(content, barcode.ColorScheme16) 179 | } 180 | 181 | func EncodeWithoutChecksum(content string) (barcode.Barcode, error) { 182 | return EncodeWithoutChecksumWithColor(content, barcode.ColorScheme16) 183 | } 184 | 185 | func EncodeWithoutChecksumWithColor(content string, color barcode.ColorScheme) (barcode.Barcode, error) { 186 | contentRunes := strToRunes(content) 187 | if len(contentRunes) <= 0 || len(contentRunes) > 80 { 188 | return nil, fmt.Errorf("content length should be between 1 and 80 runes but got %d", len(contentRunes)) 189 | } 190 | idxList := getCodeIndexList(contentRunes) 191 | 192 | if idxList == nil { 193 | return nil, fmt.Errorf("%q could not be encoded", content) 194 | } 195 | 196 | result := new(utils.BitList) 197 | for _, idx := range idxList.GetBytes() { 198 | result.AddBit(encodingTable[idx]...) 199 | } 200 | result.AddBit(encodingTable[stopSymbol]...) 201 | return utils.New1DCodeWithColor(barcode.TypeCode128, content, result, color), nil 202 | } 203 | -------------------------------------------------------------------------------- /aztec/aztec_test.go: -------------------------------------------------------------------------------- 1 | package aztec 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func encodeTest(t *testing.T, data, wanted string) { 8 | result, err := Encode([]byte(data), DEFAULT_EC_PERCENT, DEFAULT_LAYERS) 9 | if err != nil { 10 | t.Error(err) 11 | } else { 12 | ac, ok := result.(*aztecCode) 13 | if !ok { 14 | t.Error("returned barcode is no aztec code...") 15 | } else if draw := ac.string(); draw != wanted { 16 | t.Errorf("Invalid Barcode returned:\n%s", draw) 17 | } 18 | 19 | } 20 | } 21 | 22 | func Test_Encode1(t *testing.T) { 23 | encodeTest(t, "This is an example Aztec symbol for Wikipedia.", 24 | "X X X X X X X X \n"+ 25 | "X X X X X X X X X X \n"+ 26 | "X X X X X X X X X X X \n"+ 27 | "X X X X X X X X X X X \n"+ 28 | " X X X X X X X X X X X \n"+ 29 | " X X X X X X X X X X X X X \n"+ 30 | " X X X X X X X X X X X X \n"+ 31 | "X X X X X X X X X X X X X X X X \n"+ 32 | "X X X X X X X X X X X \n"+ 33 | "X X X X X X X X X X X X X X X X \n"+ 34 | "X X X X X X X X X X \n"+ 35 | "X X X X X X X X X X \n"+ 36 | " X X X X X X X X X X \n"+ 37 | " X X X X X X X X X X X X X X X X X X \n"+ 38 | " X X X X X X X X X X X X \n"+ 39 | " X X X X X X X X X X X X X X X X \n"+ 40 | " X X X X X X X X X X X \n"+ 41 | " X X X X X X X X \n"+ 42 | " X X X X X X X X X X X X X X X X \n"+ 43 | " X X X X X X X X X X X X \n"+ 44 | " X X X \n"+ 45 | " X X X X X X X X X X \n"+ 46 | " X X X X X X X X X X \n") 47 | } 48 | 49 | func Test_Encode2(t *testing.T) { 50 | encodeTest(t, "Aztec Code is a public domain 2D matrix barcode symbology"+ 51 | " of nominally square symbols built on a square grid with a "+ 52 | "distinctive square bullseye pattern at their center.", 53 | " X X X X X X X X X X X X X X X \n"+ 54 | " X X X X X X X X X X X X X X X \n"+ 55 | " X X X X X X X X X X X X X X X X X X X \n"+ 56 | "X X X X X X X X X X X X X X \n"+ 57 | "X X X X X X X X X X X X X X X X X X X X X \n"+ 58 | " X X X X X X X X X X X X X X X X \n"+ 59 | "X X X X X X X X X X X X X X X X X X X X \n"+ 60 | " X X X X X X X X X X X X X X X X X X X X X X \n"+ 61 | "X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"+ 62 | " X X X X X X X X X X X X X X X X X X X X \n"+ 63 | " X X X X X X X X X X X X X X X X X X X X \n"+ 64 | " X X X X X X X X X X X X X X X X X X X X X X X \n"+ 65 | "X X X X X X X X X X X X X X X X X X X X X \n"+ 66 | " X X X X X X X X X X X X X X X \n"+ 67 | " X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"+ 68 | " X X X X X X X X X X X \n"+ 69 | " X X X X X X X X X X X X X X X X X X X X X X X X X \n"+ 70 | " X X X X X X X X X X X X X X X \n"+ 71 | "X X X X X X X X X X X X X X X X X X X X X X X X X X \n"+ 72 | "X X X X X X X X X X X X X X X X X X X X \n"+ 73 | "X X X X X X X X X X X X X X X X X X X X X \n"+ 74 | " X X X X X X X X X X X X \n"+ 75 | " X X X X X X X X X X X X X X X X X X X X X X X \n"+ 76 | "X X X X X X X X X X X X X X X X X \n"+ 77 | " X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"+ 78 | " X X X X X X X X X X X X X X X X \n"+ 79 | " X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"+ 80 | " X X X X X X X X X X X X X X X X X \n"+ 81 | "X X X X X X X X X X X X X X X X X \n"+ 82 | "X X X X X X X X X X X X X X X X X X X X X X X X \n"+ 83 | " X X X X X X X X X X X X X X X X X X X X \n"+ 84 | "X X X X X X X X X X X X X X X \n"+ 85 | " X X X X X X X X X X X X X X X X X X X X X X X X X \n"+ 86 | " X X X X X X X X X X X X X X X X X \n"+ 87 | "X X X X X X X X X X X X X X X X X X \n"+ 88 | "X X X X X X X X X X X X X X X X X X X X X X X \n"+ 89 | "X X X X X X X X X X X X X X X X X X X X X \n"+ 90 | "X X X X X X X X X X X X X X X X \n"+ 91 | "X X X X X X X X X X X X X X X X X X X X X \n"+ 92 | " X X X X X X X X X X X X X X X X \n"+ 93 | "X X X X X X X X X X X X X \n") 94 | } 95 | -------------------------------------------------------------------------------- /ean/encoder.go: -------------------------------------------------------------------------------- 1 | // Package ean can create EAN 8 and EAN 13 barcodes. 2 | package ean 3 | 4 | import ( 5 | "errors" 6 | 7 | "github.com/boombuler/barcode" 8 | "github.com/boombuler/barcode/utils" 9 | ) 10 | 11 | type encodedNumber struct { 12 | LeftOdd []bool 13 | LeftEven []bool 14 | Right []bool 15 | CheckSum []bool 16 | } 17 | 18 | var encoderTable = map[rune]encodedNumber{ 19 | '0': encodedNumber{ 20 | []bool{false, false, false, true, true, false, true}, 21 | []bool{false, true, false, false, true, true, true}, 22 | []bool{true, true, true, false, false, true, false}, 23 | []bool{false, false, false, false, false, false}, 24 | }, 25 | '1': encodedNumber{ 26 | []bool{false, false, true, true, false, false, true}, 27 | []bool{false, true, true, false, false, true, true}, 28 | []bool{true, true, false, false, true, true, false}, 29 | []bool{false, false, true, false, true, true}, 30 | }, 31 | '2': encodedNumber{ 32 | []bool{false, false, true, false, false, true, true}, 33 | []bool{false, false, true, true, false, true, true}, 34 | []bool{true, true, false, true, true, false, false}, 35 | []bool{false, false, true, true, false, true}, 36 | }, 37 | '3': encodedNumber{ 38 | []bool{false, true, true, true, true, false, true}, 39 | []bool{false, true, false, false, false, false, true}, 40 | []bool{true, false, false, false, false, true, false}, 41 | []bool{false, false, true, true, true, false}, 42 | }, 43 | '4': encodedNumber{ 44 | []bool{false, true, false, false, false, true, true}, 45 | []bool{false, false, true, true, true, false, true}, 46 | []bool{true, false, true, true, true, false, false}, 47 | []bool{false, true, false, false, true, true}, 48 | }, 49 | '5': encodedNumber{ 50 | []bool{false, true, true, false, false, false, true}, 51 | []bool{false, true, true, true, false, false, true}, 52 | []bool{true, false, false, true, true, true, false}, 53 | []bool{false, true, true, false, false, true}, 54 | }, 55 | '6': encodedNumber{ 56 | []bool{false, true, false, true, true, true, true}, 57 | []bool{false, false, false, false, true, false, true}, 58 | []bool{true, false, true, false, false, false, false}, 59 | []bool{false, true, true, true, false, false}, 60 | }, 61 | '7': encodedNumber{ 62 | []bool{false, true, true, true, false, true, true}, 63 | []bool{false, false, true, false, false, false, true}, 64 | []bool{true, false, false, false, true, false, false}, 65 | []bool{false, true, false, true, false, true}, 66 | }, 67 | '8': encodedNumber{ 68 | []bool{false, true, true, false, true, true, true}, 69 | []bool{false, false, false, true, false, false, true}, 70 | []bool{true, false, false, true, false, false, false}, 71 | []bool{false, true, false, true, true, false}, 72 | }, 73 | '9': encodedNumber{ 74 | []bool{false, false, false, true, false, true, true}, 75 | []bool{false, false, true, false, true, true, true}, 76 | []bool{true, true, true, false, true, false, false}, 77 | []bool{false, true, true, false, true, false}, 78 | }, 79 | } 80 | 81 | func calcCheckNum(code string) rune { 82 | x3 := len(code) == 7 83 | sum := 0 84 | for _, r := range code { 85 | curNum := utils.RuneToInt(r) 86 | if curNum < 0 || curNum > 9 { 87 | return 'B' 88 | } 89 | if x3 { 90 | curNum = curNum * 3 91 | } 92 | x3 = !x3 93 | sum += curNum 94 | } 95 | 96 | return utils.IntToRune((10 - (sum % 10)) % 10) 97 | } 98 | 99 | func encodeEAN8(code string) *utils.BitList { 100 | result := new(utils.BitList) 101 | result.AddBit(true, false, true) 102 | 103 | for cpos, r := range code { 104 | num, ok := encoderTable[r] 105 | if !ok { 106 | return nil 107 | } 108 | var data []bool 109 | if cpos < 4 { 110 | data = num.LeftOdd 111 | } else { 112 | data = num.Right 113 | } 114 | 115 | if cpos == 4 { 116 | result.AddBit(false, true, false, true, false) 117 | } 118 | result.AddBit(data...) 119 | } 120 | result.AddBit(true, false, true) 121 | 122 | return result 123 | } 124 | 125 | func encodeEAN13(code string) *utils.BitList { 126 | result := new(utils.BitList) 127 | result.AddBit(true, false, true) 128 | 129 | var firstNum []bool 130 | for cpos, r := range code { 131 | num, ok := encoderTable[r] 132 | if !ok { 133 | return nil 134 | } 135 | if cpos == 0 { 136 | firstNum = num.CheckSum 137 | continue 138 | } 139 | 140 | var data []bool 141 | if cpos < 7 { // Left 142 | if firstNum[cpos-1] { 143 | data = num.LeftEven 144 | } else { 145 | data = num.LeftOdd 146 | } 147 | } else { 148 | data = num.Right 149 | } 150 | 151 | if cpos == 7 { 152 | result.AddBit(false, true, false, true, false) 153 | } 154 | result.AddBit(data...) 155 | } 156 | result.AddBit(true, false, true) 157 | return result 158 | } 159 | 160 | // Encode returns a EAN 8 or EAN 13 barcode for the given code and color scheme 161 | func EncodeWithColor(code string, color barcode.ColorScheme) (barcode.BarcodeIntCS, error) { 162 | var checkSum int 163 | if len(code) == 7 || len(code) == 12 { 164 | code += string(calcCheckNum(code)) 165 | checkSum = utils.RuneToInt(calcCheckNum(code)) 166 | } else if len(code) == 8 || len(code) == 13 { 167 | check := code[0 : len(code)-1] 168 | check += string(calcCheckNum(check)) 169 | if check != code { 170 | return nil, errors.New("checksum missmatch") 171 | } 172 | checkSum = utils.RuneToInt(rune(code[len(code)-1])) 173 | } 174 | 175 | if len(code) == 8 { 176 | result := encodeEAN8(code) 177 | if result != nil { 178 | return utils.New1DCodeIntCheckSumWithColor(barcode.TypeEAN8, code, result, checkSum, color), nil 179 | } 180 | } else if len(code) == 13 { 181 | result := encodeEAN13(code) 182 | if result != nil { 183 | return utils.New1DCodeIntCheckSumWithColor(barcode.TypeEAN13, code, result, checkSum, color), nil 184 | } 185 | } 186 | return nil, errors.New("invalid ean code data") 187 | } 188 | 189 | // Encode returns a EAN 8 or EAN 13 barcode for the given code 190 | func Encode(code string) (barcode.BarcodeIntCS, error) { 191 | return EncodeWithColor(code, barcode.ColorScheme16) 192 | } 193 | -------------------------------------------------------------------------------- /aztec/highlevel.go: -------------------------------------------------------------------------------- 1 | package aztec 2 | 3 | import ( 4 | "github.com/boombuler/barcode/utils" 5 | ) 6 | 7 | func highlevelEncode(data []byte) *utils.BitList { 8 | states := stateSlice{initialState} 9 | 10 | for index := 0; index < len(data); index++ { 11 | pairCode := 0 12 | nextChar := byte(0) 13 | if index+1 < len(data) { 14 | nextChar = data[index+1] 15 | } 16 | 17 | switch cur := data[index]; { 18 | case cur == '\r' && nextChar == '\n': 19 | pairCode = 2 20 | case cur == '.' && nextChar == ' ': 21 | pairCode = 3 22 | case cur == ',' && nextChar == ' ': 23 | pairCode = 4 24 | case cur == ':' && nextChar == ' ': 25 | pairCode = 5 26 | } 27 | if pairCode > 0 { 28 | // We have one of the four special PUNCT pairs. Treat them specially. 29 | // Get a new set of states for the two new characters. 30 | states = updateStateListForPair(states, data, index, pairCode) 31 | index++ 32 | } else { 33 | // Get a new set of states for the new character. 34 | states = updateStateListForChar(states, data, index) 35 | } 36 | } 37 | minBitCnt := int((^uint(0)) >> 1) 38 | var result *state = nil 39 | for _, s := range states { 40 | if s.bitCount < minBitCnt { 41 | minBitCnt = s.bitCount 42 | result = s 43 | } 44 | } 45 | if result != nil { 46 | return result.toBitList(data) 47 | } else { 48 | return new(utils.BitList) 49 | } 50 | } 51 | 52 | func simplifyStates(states stateSlice) stateSlice { 53 | var result stateSlice = nil 54 | for _, newState := range states { 55 | add := true 56 | var newResult stateSlice = nil 57 | 58 | for _, oldState := range result { 59 | if add && oldState.isBetterThanOrEqualTo(newState) { 60 | add = false 61 | } 62 | if !(add && newState.isBetterThanOrEqualTo(oldState)) { 63 | newResult = append(newResult, oldState) 64 | } 65 | } 66 | 67 | if add { 68 | result = append(newResult, newState) 69 | } else { 70 | result = newResult 71 | } 72 | 73 | } 74 | 75 | return result 76 | } 77 | 78 | // We update a set of states for a new character by updating each state 79 | // for the new character, merging the results, and then removing the 80 | // non-optimal states. 81 | func updateStateListForChar(states stateSlice, data []byte, index int) stateSlice { 82 | var result stateSlice = nil 83 | for _, s := range states { 84 | if r := updateStateForChar(s, data, index); len(r) > 0 { 85 | result = append(result, r...) 86 | } 87 | } 88 | return simplifyStates(result) 89 | } 90 | 91 | // Return a set of states that represent the possible ways of updating this 92 | // state for the next character. The resulting set of states are added to 93 | // the "result" list. 94 | func updateStateForChar(s *state, data []byte, index int) stateSlice { 95 | var result stateSlice = nil 96 | ch := data[index] 97 | charInCurrentTable := charMap[s.mode][ch] > 0 98 | 99 | var stateNoBinary *state = nil 100 | for mode := mode_upper; mode <= mode_punct; mode++ { 101 | charInMode := charMap[mode][ch] 102 | if charInMode > 0 { 103 | if stateNoBinary == nil { 104 | // Only create stateNoBinary the first time it's required. 105 | stateNoBinary = s.endBinaryShift(index) 106 | } 107 | // Try generating the character by latching to its mode 108 | if !charInCurrentTable || mode == s.mode || mode == mode_digit { 109 | // If the character is in the current table, we don't want to latch to 110 | // any other mode except possibly digit (which uses only 4 bits). Any 111 | // other latch would be equally successful *after* this character, and 112 | // so wouldn't save any bits. 113 | res := stateNoBinary.latchAndAppend(mode, charInMode) 114 | result = append(result, res) 115 | } 116 | // Try generating the character by switching to its mode. 117 | if _, ok := shiftTable[s.mode][mode]; !charInCurrentTable && ok { 118 | // It never makes sense to temporarily shift to another mode if the 119 | // character exists in the current mode. That can never save bits. 120 | res := stateNoBinary.shiftAndAppend(mode, charInMode) 121 | result = append(result, res) 122 | } 123 | } 124 | } 125 | if s.bShiftByteCount > 0 || charMap[s.mode][ch] == 0 { 126 | // It's never worthwhile to go into binary shift mode if you're not already 127 | // in binary shift mode, and the character exists in your current mode. 128 | // That can never save bits over just outputting the char in the current mode. 129 | res := s.addBinaryShiftChar(index) 130 | result = append(result, res) 131 | } 132 | return result 133 | } 134 | 135 | // We update a set of states for a new character by updating each state 136 | // for the new character, merging the results, and then removing the 137 | // non-optimal states. 138 | func updateStateListForPair(states stateSlice, data []byte, index int, pairCode int) stateSlice { 139 | var result stateSlice = nil 140 | for _, s := range states { 141 | if r := updateStateForPair(s, data, index, pairCode); len(r) > 0 { 142 | result = append(result, r...) 143 | } 144 | } 145 | return simplifyStates(result) 146 | } 147 | 148 | func updateStateForPair(s *state, data []byte, index int, pairCode int) stateSlice { 149 | var result stateSlice 150 | stateNoBinary := s.endBinaryShift(index) 151 | // Possibility 1. Latch to MODE_PUNCT, and then append this code 152 | result = append(result, stateNoBinary.latchAndAppend(mode_punct, pairCode)) 153 | if s.mode != mode_punct { 154 | // Possibility 2. Shift to MODE_PUNCT, and then append this code. 155 | // Every state except MODE_PUNCT (handled above) can shift 156 | result = append(result, stateNoBinary.shiftAndAppend(mode_punct, pairCode)) 157 | } 158 | if pairCode == 3 || pairCode == 4 { 159 | // both characters are in DIGITS. Sometimes better to just add two digits 160 | digitState := stateNoBinary. 161 | latchAndAppend(mode_digit, 16-pairCode). // period or comma in DIGIT 162 | latchAndAppend(mode_digit, 1) // space in DIGIT 163 | result = append(result, digitState) 164 | } 165 | if s.bShiftByteCount > 0 { 166 | // It only makes sense to do the characters as binary if we're already 167 | // in binary mode. 168 | result = append(result, s.addBinaryShiftChar(index).addBinaryShiftChar(index+1)) 169 | } 170 | return result 171 | } 172 | -------------------------------------------------------------------------------- /pdf417/errorcorrection_test.go: -------------------------------------------------------------------------------- 1 | package pdf417 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | var inputData = []int{16, 902, 1, 278, 827, 900, 295, 902, 2, 326, 823, 544, 900, 149, 900, 900} 8 | 9 | func TestReedSolomonComputeLevel0(t *testing.T) { 10 | var level securitylevel = 0 11 | expected := []int{156, 765} 12 | compareIntSlice(t, expected, level.Compute(inputData), "SecLvl 0") 13 | } 14 | 15 | func TestReedSolomonComputeLevel1(t *testing.T) { 16 | var level securitylevel = 1 17 | expected := []int{168, 875, 63, 355} 18 | compareIntSlice(t, expected, level.Compute(inputData), "SecLvl 1") 19 | } 20 | 21 | func TestReedSolomonComputeLevel2(t *testing.T) { 22 | var level securitylevel = 2 23 | expected := []int{628, 715, 393, 299, 863, 601, 169, 708} 24 | compareIntSlice(t, expected, level.Compute(inputData), "SecLvl 2") 25 | } 26 | 27 | func TestReedSolomonComputeLevel3(t *testing.T) { 28 | var level securitylevel = 3 29 | expected := []int{232, 176, 793, 616, 476, 406, 855, 445, 84, 518, 522, 721, 607, 2, 42, 578} 30 | compareIntSlice(t, expected, level.Compute(inputData), "SecLvl 3") 31 | } 32 | 33 | func TestReedSolomonComputeLevel4(t *testing.T) { 34 | var level securitylevel = 4 35 | expected := []int{281, 156, 276, 668, 44, 252, 877, 30, 549, 856, 773, 639, 420, 330, 693, 329, 283, 723, 480, 482, 102, 925, 535, 892, 374, 472, 837, 331, 343, 608, 390, 364} 36 | compareIntSlice(t, expected, level.Compute(inputData), "SecLvl 4") 37 | } 38 | 39 | func TestReedSolomonComputeLevel5(t *testing.T) { 40 | var level securitylevel = 5 41 | expected := []int{31, 850, 18, 870, 53, 477, 837, 130, 533, 186, 266, 450, 39, 492, 542, 653, 499, 887, 618, 103, 364, 313, 906, 396, 270, 735, 593, 81, 557, 712, 810, 48, 167, 533, 205, 577, 503, 126, 449, 189, 859, 471, 493, 849, 554, 76, 878, 893, 168, 497, 251, 704, 311, 650, 283, 268, 462, 223, 659, 763, 176, 34, 544, 304} 42 | compareIntSlice(t, expected, level.Compute(inputData), "SecLvl 5") 43 | } 44 | 45 | func TestReedSolomonComputeLevel6(t *testing.T) { 46 | var level securitylevel = 6 47 | expected := []int{345, 775, 909, 489, 650, 568, 869, 577, 574, 349, 885, 317, 492, 222, 783, 451, 647, 385, 168, 366, 118, 655, 643, 551, 179, 880, 880, 752, 132, 206, 765, 862, 727, 240, 32, 266, 911, 287, 813, 437, 868, 201, 681, 867, 567, 398, 508, 564, 504, 676, 785, 554, 831, 566, 424, 93, 515, 275, 61, 544, 272, 621, 374, 922, 779, 663, 789, 295, 631, 536, 755, 465, 485, 416, 76, 412, 76, 431, 28, 614, 767, 419, 600, 779, 94, 584, 647, 846, 121, 97, 790, 205, 424, 793, 263, 271, 694, 522, 437, 817, 382, 164, 113, 849, 178, 602, 554, 261, 415, 737, 401, 675, 203, 271, 649, 120, 765, 209, 522, 687, 420, 32, 60, 266, 270, 228, 304, 270} 48 | compareIntSlice(t, expected, level.Compute(inputData), "SecLvl 6") 49 | } 50 | 51 | func TestReedSolomonComputeLevel7(t *testing.T) { 52 | var level securitylevel = 7 53 | expected := []int{142, 203, 799, 4, 105, 137, 793, 914, 225, 636, 60, 171, 490, 180, 414, 141, 399, 599, 829, 288, 108, 268, 444, 481, 795, 146, 655, 778, 189, 32, 597, 206, 208, 711, 845, 608, 642, 636, 540, 795, 845, 466, 492, 659, 138, 800, 912, 171, 92, 438, 225, 301, 777, 449, 230, 448, 326, 182, 892, 681, 543, 582, 732, 758, 162, 587, 685, 378, 646, 356, 354, 25, 839, 839, 556, 253, 501, 771, 745, 616, 473, 293, 669, 822, 613, 684, 229, 265, 110, 438, 144, 727, 317, 605, 414, 497, 82, 278, 267, 323, 43, 894, 624, 282, 790, 579, 430, 255, 802, 553, 922, 604, 68, 692, 809, 909, 663, 589, 735, 670, 298, 158, 201, 68, 124, 64, 67, 338, 694, 373, 225, 579, 309, 699, 920, 432, 717, 72, 126, 819, 142, 755, 473, 630, 331, 758, 730, 65, 359, 451, 236, 16, 56, 31, 87, 587, 125, 385, 384, 197, 352, 383, 173, 271, 38, 558, 810, 260, 521, 680, 7, 319, 650, 334, 695, 708, 0, 562, 365, 204, 114, 185, 560, 746, 767, 449, 797, 688, 63, 135, 818, 805, 3, 536, 908, 532, 400, 698, 49, 212, 630, 93, 157, 275, 3, 20, 611, 179, 302, 282, 876, 665, 241, 206, 474, 80, 217, 460, 462, 751, 719, 571, 536, 794, 522, 385, 598, 756, 162, 212, 758, 662, 361, 223, 587, 857, 503, 382, 615, 86, 283, 541, 847, 518, 406, 736, 486, 408, 226, 342, 784, 772, 211, 888, 234, 335} 54 | compareIntSlice(t, expected, level.Compute(inputData), "SecLvl 7") 55 | } 56 | 57 | func TestReedSolomonComputeLevel8(t *testing.T) { 58 | var level securitylevel = 8 59 | expected := []int{538, 446, 840, 510, 163, 708, 177, 666, 423, 600, 707, 913, 770, 571, 156, 683, 676, 697, 898, 776, 128, 851, 163, 854, 135, 661, 880, 279, 92, 324, 397, 207, 379, 223, 574, 9, 70, 858, 878, 579, 61, 551, 261, 388, 315, 856, 266, 865, 923, 38, 313, 62, 381, 198, 265, 256, 385, 878, 347, 532, 821, 53, 855, 225, 697, 826, 263, 334, 207, 565, 460, 496, 705, 599, 383, 289, 178, 168, 401, 268, 555, 190, 922, 284, 180, 810, 891, 832, 636, 813, 894, 495, 701, 484, 204, 793, 129, 164, 444, 228, 636, 98, 809, 57, 736, 697, 727, 534, 889, 480, 898, 773, 234, 851, 880, 843, 714, 443, 412, 489, 578, 468, 367, 663, 11, 686, 319, 352, 345, 670, 106, 106, 219, 466, 439, 350, 538, 66, 852, 175, 465, 731, 332, 110, 926, 491, 18, 422, 736, 797, 624, 376, 728, 526, 735, 200, 502, 923, 789, 529, 923, 706, 384, 869, 172, 548, 520, 463, 813, 384, 793, 231, 190, 653, 864, 351, 400, 525, 487, 828, 654, 307, 141, 638, 770, 775, 282, 54, 758, 197, 492, 320, 86, 790, 275, 237, 923, 25, 591, 605, 61, 824, 79, 631, 532, 337, 867, 423, 340, 597, 682, 923, 287, 408, 503, 361, 881, 196, 468, 759, 746, 389, 124, 784, 198, 865, 538, 451, 178, 772, 653, 121, 497, 598, 711, 716, 241, 159, 429, 88, 799, 761, 639, 105, 54, 807, 351, 435, 793, 873, 360, 8, 881, 479, 693, 576, 849, 875, 771, 621, 134, 863, 8, 171, 799, 924, 103, 63, 491, 538, 597, 855, 697, 499, 7, 886, 286, 85, 107, 220, 319, 124, 197, 150, 729, 899, 585, 540, 676, 414, 256, 856, 596, 259, 882, 436, 26, 273, 753, 127, 679, 390, 654, 42, 276, 420, 247, 629, 116, 803, 131, 25, 403, 645, 462, 897, 151, 622, 108, 167, 227, 831, 887, 662, 739, 263, 829, 56, 624, 317, 908, 378, 39, 393, 861, 338, 202, 179, 907, 109, 360, 736, 554, 342, 594, 125, 433, 394, 195, 698, 844, 912, 530, 842, 337, 294, 528, 231, 735, 93, 8, 579, 42, 148, 609, 233, 782, 887, 888, 915, 620, 78, 137, 161, 282, 217, 775, 564, 33, 195, 36, 584, 679, 775, 476, 309, 230, 303, 708, 143, 679, 502, 814, 193, 508, 532, 542, 580, 603, 641, 338, 361, 542, 537, 810, 394, 764, 136, 167, 611, 881, 775, 267, 433, 142, 202, 828, 363, 101, 728, 660, 583, 483, 786, 717, 190, 809, 422, 567, 741, 695, 310, 120, 177, 47, 494, 345, 508, 16, 639, 402, 625, 286, 298, 358, 54, 705, 916, 291, 424, 375, 883, 655, 675, 498, 498, 884, 862, 365, 310, 805, 763, 855, 354, 777, 543, 53, 773, 120, 408, 234, 728, 438, 914, 3, 670, 546, 465, 449, 923, 51, 546, 709, 648, 96, 320, 682, 326, 848, 234, 855, 791, 20, 97, 901, 351, 317, 764, 767, 312, 206, 139, 610, 578, 646, 264, 389, 238, 675, 595, 430, 88} 60 | compareIntSlice(t, expected, level.Compute(inputData), "SecLvl 8") 61 | } 62 | -------------------------------------------------------------------------------- /pdf417/errorcorrection.go: -------------------------------------------------------------------------------- 1 | package pdf417 2 | 3 | type securitylevel byte 4 | 5 | func (level securitylevel) ErrorCorrectionWordCount() int { 6 | return 1 << (uint(level) + 1) 7 | } 8 | 9 | var correctionFactors = [][]int{ 10 | // Level 0 11 | []int{27, 917}, 12 | 13 | // Level 1 14 | []int{522, 568, 723, 809}, 15 | 16 | // Level 2 17 | []int{237, 308, 436, 284, 646, 653, 428, 379}, 18 | 19 | // Level 3 20 | []int{ 21 | 274, 562, 232, 755, 599, 524, 801, 132, 295, 116, 442, 428, 295, 42, 22 | 176, 65, 23 | }, 24 | 25 | // Level 4 26 | []int{ 27 | 361, 575, 922, 525, 176, 586, 640, 321, 536, 742, 677, 742, 687, 28 | 284, 193, 517, 273, 494, 263, 147, 593, 800, 571, 320, 803, 133, 29 | 231, 390, 685, 330, 63, 410, 30 | }, 31 | 32 | // Level 5 33 | []int{ 34 | 539, 422, 6, 93, 862, 771, 453, 106, 610, 287, 107, 505, 733, 877, 35 | 381, 612, 723, 476, 462, 172, 430, 609, 858, 822, 543, 376, 511, 36 | 400, 672, 762, 283, 184, 440, 35, 519, 31, 460, 594, 225, 535, 517, 37 | 352, 605, 158, 651, 201, 488, 502, 648, 733, 717, 83, 404, 97, 280, 38 | 771, 840, 629, 4, 381, 843, 623, 264, 543, 39 | }, 40 | 41 | // Level 6 42 | []int{ 43 | 521, 310, 864, 547, 858, 580, 296, 379, 53, 779, 897, 444, 400, 925, 44 | 749, 415, 822, 93, 217, 208, 928, 244, 583, 620, 246, 148, 447, 631, 45 | 292, 908, 490, 704, 516, 258, 457, 907, 594, 723, 674, 292, 272, 96, 46 | 684, 432, 686, 606, 860, 569, 193, 219, 129, 186, 236, 287, 192, 47 | 775, 278, 173, 40, 379, 712, 463, 646, 776, 171, 491, 297, 763, 156, 48 | 732, 95, 270, 447, 90, 507, 48, 228, 821, 808, 898, 784, 663, 627, 49 | 378, 382, 262, 380, 602, 754, 336, 89, 614, 87, 432, 670, 616, 157, 50 | 374, 242, 726, 600, 269, 375, 898, 845, 454, 354, 130, 814, 587, 51 | 804, 34, 211, 330, 539, 297, 827, 865, 37, 517, 834, 315, 550, 86, 52 | 801, 4, 108, 539, 53 | }, 54 | 55 | // Level 7 56 | []int{ 57 | 524, 894, 75, 766, 882, 857, 74, 204, 82, 586, 708, 250, 905, 786, 58 | 138, 720, 858, 194, 311, 913, 275, 190, 375, 850, 438, 733, 194, 59 | 280, 201, 280, 828, 757, 710, 814, 919, 89, 68, 569, 11, 204, 796, 60 | 605, 540, 913, 801, 700, 799, 137, 439, 418, 592, 668, 353, 859, 61 | 370, 694, 325, 240, 216, 257, 284, 549, 209, 884, 315, 70, 329, 793, 62 | 490, 274, 877, 162, 749, 812, 684, 461, 334, 376, 849, 521, 307, 63 | 291, 803, 712, 19, 358, 399, 908, 103, 511, 51, 8, 517, 225, 289, 64 | 470, 637, 731, 66, 255, 917, 269, 463, 830, 730, 433, 848, 585, 136, 65 | 538, 906, 90, 2, 290, 743, 199, 655, 903, 329, 49, 802, 580, 355, 66 | 588, 188, 462, 10, 134, 628, 320, 479, 130, 739, 71, 263, 318, 374, 67 | 601, 192, 605, 142, 673, 687, 234, 722, 384, 177, 752, 607, 640, 68 | 455, 193, 689, 707, 805, 641, 48, 60, 732, 621, 895, 544, 261, 852, 69 | 655, 309, 697, 755, 756, 60, 231, 773, 434, 421, 726, 528, 503, 118, 70 | 49, 795, 32, 144, 500, 238, 836, 394, 280, 566, 319, 9, 647, 550, 71 | 73, 914, 342, 126, 32, 681, 331, 792, 620, 60, 609, 441, 180, 791, 72 | 893, 754, 605, 383, 228, 749, 760, 213, 54, 297, 134, 54, 834, 299, 73 | 922, 191, 910, 532, 609, 829, 189, 20, 167, 29, 872, 449, 83, 402, 74 | 41, 656, 505, 579, 481, 173, 404, 251, 688, 95, 497, 555, 642, 543, 75 | 307, 159, 924, 558, 648, 55, 497, 10, 76 | }, 77 | 78 | // Level 8 79 | []int{ 80 | 352, 77, 373, 504, 35, 599, 428, 207, 409, 574, 118, 498, 285, 380, 81 | 350, 492, 197, 265, 920, 155, 914, 299, 229, 643, 294, 871, 306, 88, 82 | 87, 193, 352, 781, 846, 75, 327, 520, 435, 543, 203, 666, 249, 346, 83 | 781, 621, 640, 268, 794, 534, 539, 781, 408, 390, 644, 102, 476, 84 | 499, 290, 632, 545, 37, 858, 916, 552, 41, 542, 289, 122, 272, 383, 85 | 800, 485, 98, 752, 472, 761, 107, 784, 860, 658, 741, 290, 204, 681, 86 | 407, 855, 85, 99, 62, 482, 180, 20, 297, 451, 593, 913, 142, 808, 87 | 684, 287, 536, 561, 76, 653, 899, 729, 567, 744, 390, 513, 192, 516, 88 | 258, 240, 518, 794, 395, 768, 848, 51, 610, 384, 168, 190, 826, 328, 89 | 596, 786, 303, 570, 381, 415, 641, 156, 237, 151, 429, 531, 207, 90 | 676, 710, 89, 168, 304, 402, 40, 708, 575, 162, 864, 229, 65, 861, 91 | 841, 512, 164, 477, 221, 92, 358, 785, 288, 357, 850, 836, 827, 736, 92 | 707, 94, 8, 494, 114, 521, 2, 499, 851, 543, 152, 729, 771, 95, 248, 93 | 361, 578, 323, 856, 797, 289, 51, 684, 466, 533, 820, 669, 45, 902, 94 | 452, 167, 342, 244, 173, 35, 463, 651, 51, 699, 591, 452, 578, 37, 95 | 124, 298, 332, 552, 43, 427, 119, 662, 777, 475, 850, 764, 364, 578, 96 | 911, 283, 711, 472, 420, 245, 288, 594, 394, 511, 327, 589, 777, 97 | 699, 688, 43, 408, 842, 383, 721, 521, 560, 644, 714, 559, 62, 145, 98 | 873, 663, 713, 159, 672, 729, 624, 59, 193, 417, 158, 209, 563, 564, 99 | 343, 693, 109, 608, 563, 365, 181, 772, 677, 310, 248, 353, 708, 100 | 410, 579, 870, 617, 841, 632, 860, 289, 536, 35, 777, 618, 586, 424, 101 | 833, 77, 597, 346, 269, 757, 632, 695, 751, 331, 247, 184, 45, 787, 102 | 680, 18, 66, 407, 369, 54, 492, 228, 613, 830, 922, 437, 519, 644, 103 | 905, 789, 420, 305, 441, 207, 300, 892, 827, 141, 537, 381, 662, 104 | 513, 56, 252, 341, 242, 797, 838, 837, 720, 224, 307, 631, 61, 87, 105 | 560, 310, 756, 665, 397, 808, 851, 309, 473, 795, 378, 31, 647, 915, 106 | 459, 806, 590, 731, 425, 216, 548, 249, 321, 881, 699, 535, 673, 107 | 782, 210, 815, 905, 303, 843, 922, 281, 73, 469, 791, 660, 162, 498, 108 | 308, 155, 422, 907, 817, 187, 62, 16, 425, 535, 336, 286, 437, 375, 109 | 273, 610, 296, 183, 923, 116, 667, 751, 353, 62, 366, 691, 379, 687, 110 | 842, 37, 357, 720, 742, 330, 5, 39, 923, 311, 424, 242, 749, 321, 111 | 54, 669, 316, 342, 299, 534, 105, 667, 488, 640, 672, 576, 540, 316, 112 | 486, 721, 610, 46, 656, 447, 171, 616, 464, 190, 531, 297, 321, 762, 113 | 752, 533, 175, 134, 14, 381, 433, 717, 45, 111, 20, 596, 284, 736, 114 | 138, 646, 411, 877, 669, 141, 919, 45, 780, 407, 164, 332, 899, 165, 115 | 726, 600, 325, 498, 655, 357, 752, 768, 223, 849, 647, 63, 310, 863, 116 | 251, 366, 304, 282, 738, 675, 410, 389, 244, 31, 121, 303, 263, 117 | }, 118 | } 119 | 120 | func (level securitylevel) Compute(data []int) []int { 121 | // Correction factors for the given level 122 | factors := correctionFactors[int(level)] 123 | 124 | // Number of correction code words 125 | count := level.ErrorCorrectionWordCount() 126 | 127 | // Correction code words array, prepopulated with zeros 128 | ecWords := make([]int, count) 129 | 130 | for _, value := range data { 131 | temp := (value + ecWords[0]) % 929 132 | 133 | for i := count - 1; i >= 0; i-- { 134 | add := 0 135 | 136 | if i > 0 { 137 | add = ecWords[count-i] 138 | } 139 | 140 | ecWords[count-1-i] = (add + 929 - (temp*factors[i])%929) % 929 141 | } 142 | } 143 | 144 | for key, word := range ecWords { 145 | if word > 0 { 146 | ecWords[key] = 929 - word 147 | } 148 | } 149 | 150 | return ecWords 151 | } 152 | -------------------------------------------------------------------------------- /datamatrix/codelayout.go: -------------------------------------------------------------------------------- 1 | package datamatrix 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/boombuler/barcode" 7 | "github.com/boombuler/barcode/utils" 8 | ) 9 | 10 | type codeLayout struct { 11 | matrix *utils.BitList 12 | occupy *utils.BitList 13 | size *dmCodeSize 14 | color barcode.ColorScheme 15 | } 16 | 17 | func newCodeLayout(size *dmCodeSize, color barcode.ColorScheme) *codeLayout { 18 | result := new(codeLayout) 19 | result.matrix = utils.NewBitList(size.MatrixColumns() * size.MatrixRows()) 20 | result.occupy = utils.NewBitList(size.MatrixColumns() * size.MatrixRows()) 21 | result.size = size 22 | result.color = color 23 | return result 24 | } 25 | 26 | func (l *codeLayout) Occupied(row, col int) bool { 27 | return l.occupy.GetBit(col + row*l.size.MatrixColumns()) 28 | } 29 | 30 | func (l *codeLayout) Set(row, col int, value, bitNum byte) { 31 | val := ((value >> (7 - bitNum)) & 1) == 1 32 | if row < 0 { 33 | row += l.size.MatrixRows() 34 | col += 4 - ((l.size.MatrixRows() + 4) % 8) 35 | } 36 | if col < 0 { 37 | col += l.size.MatrixColumns() 38 | row += 4 - ((l.size.MatrixColumns() + 4) % 8) 39 | } 40 | if l.Occupied(row, col) { 41 | panic("Field already occupied row: " + strconv.Itoa(row) + " col: " + strconv.Itoa(col)) 42 | } 43 | 44 | l.occupy.SetBit(col+row*l.size.MatrixColumns(), true) 45 | 46 | l.matrix.SetBit(col+row*l.size.MatrixColumns(), val) 47 | } 48 | 49 | func (l *codeLayout) SetSimple(row, col int, value byte) { 50 | l.Set(row-2, col-2, value, 0) 51 | l.Set(row-2, col-1, value, 1) 52 | l.Set(row-1, col-2, value, 2) 53 | l.Set(row-1, col-1, value, 3) 54 | l.Set(row-1, col-0, value, 4) 55 | l.Set(row-0, col-2, value, 5) 56 | l.Set(row-0, col-1, value, 6) 57 | l.Set(row-0, col-0, value, 7) 58 | } 59 | 60 | func (l *codeLayout) Corner1(value byte) { 61 | l.Set(l.size.MatrixRows()-1, 0, value, 0) 62 | l.Set(l.size.MatrixRows()-1, 1, value, 1) 63 | l.Set(l.size.MatrixRows()-1, 2, value, 2) 64 | l.Set(0, l.size.MatrixColumns()-2, value, 3) 65 | l.Set(0, l.size.MatrixColumns()-1, value, 4) 66 | l.Set(1, l.size.MatrixColumns()-1, value, 5) 67 | l.Set(2, l.size.MatrixColumns()-1, value, 6) 68 | l.Set(3, l.size.MatrixColumns()-1, value, 7) 69 | } 70 | 71 | func (l *codeLayout) Corner2(value byte) { 72 | l.Set(l.size.MatrixRows()-3, 0, value, 0) 73 | l.Set(l.size.MatrixRows()-2, 0, value, 1) 74 | l.Set(l.size.MatrixRows()-1, 0, value, 2) 75 | l.Set(0, l.size.MatrixColumns()-4, value, 3) 76 | l.Set(0, l.size.MatrixColumns()-3, value, 4) 77 | l.Set(0, l.size.MatrixColumns()-2, value, 5) 78 | l.Set(0, l.size.MatrixColumns()-1, value, 6) 79 | l.Set(1, l.size.MatrixColumns()-1, value, 7) 80 | } 81 | 82 | func (l *codeLayout) Corner3(value byte) { 83 | l.Set(l.size.MatrixRows()-3, 0, value, 0) 84 | l.Set(l.size.MatrixRows()-2, 0, value, 1) 85 | l.Set(l.size.MatrixRows()-1, 0, value, 2) 86 | l.Set(0, l.size.MatrixColumns()-2, value, 3) 87 | l.Set(0, l.size.MatrixColumns()-1, value, 4) 88 | l.Set(1, l.size.MatrixColumns()-1, value, 5) 89 | l.Set(2, l.size.MatrixColumns()-1, value, 6) 90 | l.Set(3, l.size.MatrixColumns()-1, value, 7) 91 | } 92 | 93 | func (l *codeLayout) Corner4(value byte) { 94 | l.Set(l.size.MatrixRows()-1, 0, value, 0) 95 | l.Set(l.size.MatrixRows()-1, l.size.MatrixColumns()-1, value, 1) 96 | l.Set(0, l.size.MatrixColumns()-3, value, 2) 97 | l.Set(0, l.size.MatrixColumns()-2, value, 3) 98 | l.Set(0, l.size.MatrixColumns()-1, value, 4) 99 | l.Set(1, l.size.MatrixColumns()-3, value, 5) 100 | l.Set(1, l.size.MatrixColumns()-2, value, 6) 101 | l.Set(1, l.size.MatrixColumns()-1, value, 7) 102 | } 103 | 104 | func (l *codeLayout) SetValues(data []byte) { 105 | idx := 0 106 | row := 4 107 | col := 0 108 | 109 | for (row < l.size.MatrixRows()) || (col < l.size.MatrixColumns()) { 110 | if (row == l.size.MatrixRows()) && (col == 0) { 111 | l.Corner1(data[idx]) 112 | idx++ 113 | } 114 | if (row == l.size.MatrixRows()-2) && (col == 0) && (l.size.MatrixColumns()%4 != 0) { 115 | l.Corner2(data[idx]) 116 | idx++ 117 | } 118 | if (row == l.size.MatrixRows()-2) && (col == 0) && (l.size.MatrixColumns()%8 == 4) { 119 | l.Corner3(data[idx]) 120 | idx++ 121 | } 122 | 123 | if (row == l.size.MatrixRows()+4) && (col == 2) && (l.size.MatrixColumns()%8 == 0) { 124 | l.Corner4(data[idx]) 125 | idx++ 126 | } 127 | 128 | for { 129 | if (row < l.size.MatrixRows()) && (col >= 0) && !l.Occupied(row, col) { 130 | l.SetSimple(row, col, data[idx]) 131 | idx++ 132 | } 133 | row -= 2 134 | col += 2 135 | if (row < 0) || (col >= l.size.MatrixColumns()) { 136 | break 137 | } 138 | } 139 | row += 1 140 | col += 3 141 | 142 | for { 143 | if (row >= 0) && (col < l.size.MatrixColumns()) && !l.Occupied(row, col) { 144 | l.SetSimple(row, col, data[idx]) 145 | idx++ 146 | } 147 | row += 2 148 | col -= 2 149 | if (row >= l.size.MatrixRows()) || (col < 0) { 150 | break 151 | } 152 | } 153 | row += 3 154 | col += 1 155 | } 156 | 157 | if !l.Occupied(l.size.MatrixRows()-1, l.size.MatrixColumns()-1) { 158 | l.Set(l.size.MatrixRows()-1, l.size.MatrixColumns()-1, 255, 0) 159 | l.Set(l.size.MatrixRows()-2, l.size.MatrixColumns()-2, 255, 0) 160 | } 161 | } 162 | 163 | func (l *codeLayout) Merge() *datamatrixCode { 164 | result := newDataMatrixCodeWithColor(l.size, l.color) 165 | 166 | //dotted horizontal lines 167 | for r := 0; r < l.size.Rows; r += (l.size.RegionRows() + 2) { 168 | for c := 0; c < l.size.Columns; c += 2 { 169 | result.set(c, r, true) 170 | } 171 | } 172 | 173 | //solid horizontal line 174 | for r := l.size.RegionRows() + 1; r < l.size.Rows; r += (l.size.RegionRows() + 2) { 175 | for c := 0; c < l.size.Columns; c++ { 176 | result.set(c, r, true) 177 | } 178 | } 179 | 180 | //dotted vertical lines 181 | for c := l.size.RegionColumns() + 1; c < l.size.Columns; c += (l.size.RegionColumns() + 2) { 182 | for r := 1; r < l.size.Rows; r += 2 { 183 | result.set(c, r, true) 184 | } 185 | } 186 | 187 | //solid vertical line 188 | for c := 0; c < l.size.Columns; c += (l.size.RegionColumns() + 2) { 189 | for r := 0; r < l.size.Rows; r++ { 190 | result.set(c, r, true) 191 | } 192 | } 193 | count := 0 194 | for hRegion := 0; hRegion < l.size.RegionCountHorizontal; hRegion++ { 195 | for vRegion := 0; vRegion < l.size.RegionCountVertical; vRegion++ { 196 | for x := 0; x < l.size.RegionColumns(); x++ { 197 | colMatrix := (l.size.RegionColumns() * hRegion) + x 198 | colResult := ((2 + l.size.RegionColumns()) * hRegion) + x + 1 199 | 200 | for y := 0; y < l.size.RegionRows(); y++ { 201 | rowMatrix := (l.size.RegionRows() * vRegion) + y 202 | rowResult := ((2 + l.size.RegionRows()) * vRegion) + y + 1 203 | val := l.matrix.GetBit(colMatrix + rowMatrix*l.size.MatrixColumns()) 204 | if val { 205 | count++ 206 | } 207 | 208 | result.set(colResult, rowResult, val) 209 | } 210 | } 211 | } 212 | } 213 | 214 | return result 215 | } 216 | -------------------------------------------------------------------------------- /aztec/state.go: -------------------------------------------------------------------------------- 1 | package aztec 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/boombuler/barcode/utils" 7 | ) 8 | 9 | type encodingMode byte 10 | 11 | const ( 12 | mode_upper encodingMode = iota // 5 bits 13 | mode_lower // 5 bits 14 | mode_digit // 4 bits 15 | mode_mixed // 5 bits 16 | mode_punct // 5 bits 17 | ) 18 | 19 | var ( 20 | // The Latch Table shows, for each pair of Modes, the optimal method for 21 | // getting from one mode to another. In the worst possible case, this can 22 | // be up to 14 bits. In the best possible case, we are already there! 23 | // The high half-word of each entry gives the number of bits. 24 | // The low half-word of each entry are the actual bits necessary to change 25 | latchTable = map[encodingMode]map[encodingMode]int{ 26 | mode_upper: { 27 | mode_upper: 0, 28 | mode_lower: (5 << 16) + 28, 29 | mode_digit: (5 << 16) + 30, 30 | mode_mixed: (5 << 16) + 29, 31 | mode_punct: (10 << 16) + (29 << 5) + 30, 32 | }, 33 | mode_lower: { 34 | mode_upper: (9 << 16) + (30 << 4) + 14, 35 | mode_lower: 0, 36 | mode_digit: (5 << 16) + 30, 37 | mode_mixed: (5 << 16) + 29, 38 | mode_punct: (10 << 16) + (29 << 5) + 30, 39 | }, 40 | mode_digit: { 41 | mode_upper: (4 << 16) + 14, 42 | mode_lower: (9 << 16) + (14 << 5) + 28, 43 | mode_digit: 0, 44 | mode_mixed: (9 << 16) + (14 << 5) + 29, 45 | mode_punct: (14 << 16) + (14 << 10) + (29 << 5) + 30, 46 | }, 47 | mode_mixed: { 48 | mode_upper: (5 << 16) + 29, 49 | mode_lower: (5 << 16) + 28, 50 | mode_digit: (10 << 16) + (29 << 5) + 30, 51 | mode_mixed: 0, 52 | mode_punct: (5 << 16) + 30, 53 | }, 54 | mode_punct: { 55 | mode_upper: (5 << 16) + 31, 56 | mode_lower: (10 << 16) + (31 << 5) + 28, 57 | mode_digit: (10 << 16) + (31 << 5) + 30, 58 | mode_mixed: (10 << 16) + (31 << 5) + 29, 59 | mode_punct: 0, 60 | }, 61 | } 62 | // A map showing the available shift codes. (The shifts to BINARY are not shown) 63 | shiftTable = map[encodingMode]map[encodingMode]int{ 64 | mode_upper: { 65 | mode_punct: 0, 66 | }, 67 | mode_lower: { 68 | mode_punct: 0, 69 | mode_upper: 28, 70 | }, 71 | mode_mixed: { 72 | mode_punct: 0, 73 | }, 74 | mode_digit: { 75 | mode_punct: 0, 76 | mode_upper: 15, 77 | }, 78 | } 79 | charMap map[encodingMode][]int 80 | ) 81 | 82 | type state struct { 83 | mode encodingMode 84 | tokens token 85 | bShiftByteCount int 86 | bitCount int 87 | } 88 | type stateSlice []*state 89 | 90 | var initialState *state = &state{ 91 | mode: mode_upper, 92 | tokens: nil, 93 | bShiftByteCount: 0, 94 | bitCount: 0, 95 | } 96 | 97 | func init() { 98 | charMap = make(map[encodingMode][]int) 99 | charMap[mode_upper] = make([]int, 256) 100 | charMap[mode_lower] = make([]int, 256) 101 | charMap[mode_digit] = make([]int, 256) 102 | charMap[mode_mixed] = make([]int, 256) 103 | charMap[mode_punct] = make([]int, 256) 104 | 105 | charMap[mode_upper][' '] = 1 106 | for c := 'A'; c <= 'Z'; c++ { 107 | charMap[mode_upper][int(c)] = int(c - 'A' + 2) 108 | } 109 | 110 | charMap[mode_lower][' '] = 1 111 | for c := 'a'; c <= 'z'; c++ { 112 | charMap[mode_lower][c] = int(c - 'a' + 2) 113 | } 114 | charMap[mode_digit][' '] = 1 115 | for c := '0'; c <= '9'; c++ { 116 | charMap[mode_digit][c] = int(c - '0' + 2) 117 | } 118 | charMap[mode_digit][','] = 12 119 | charMap[mode_digit]['.'] = 13 120 | 121 | mixedTable := []int{ 122 | 0, ' ', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 123 | 11, 12, 13, 27, 28, 29, 30, 31, '@', '\\', '^', 124 | '_', '`', '|', '~', 127, 125 | } 126 | for i, v := range mixedTable { 127 | charMap[mode_mixed][v] = i 128 | } 129 | 130 | punctTable := []int{ 131 | 0, '\r', 0, 0, 0, 0, '!', '\'', '#', '$', '%', '&', '\'', 132 | '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', 133 | '[', ']', '{', '}', 134 | } 135 | for i, v := range punctTable { 136 | if v > 0 { 137 | charMap[mode_punct][v] = i 138 | } 139 | } 140 | } 141 | 142 | func (em encodingMode) BitCount() byte { 143 | if em == mode_digit { 144 | return 4 145 | } 146 | return 5 147 | } 148 | 149 | // Create a new state representing this state with a latch to a (not 150 | // necessary different) mode, and then a code. 151 | func (s *state) latchAndAppend(mode encodingMode, value int) *state { 152 | bitCount := s.bitCount 153 | tokens := s.tokens 154 | 155 | if mode != s.mode { 156 | latch := latchTable[s.mode][mode] 157 | tokens = newSimpleToken(tokens, latch&0xFFFF, byte(latch>>16)) 158 | bitCount += latch >> 16 159 | } 160 | tokens = newSimpleToken(tokens, value, mode.BitCount()) 161 | return &state{ 162 | mode: mode, 163 | tokens: tokens, 164 | bShiftByteCount: 0, 165 | bitCount: bitCount + int(mode.BitCount()), 166 | } 167 | } 168 | 169 | // Create a new state representing this state, with a temporary shift 170 | // to a different mode to output a single value. 171 | func (s *state) shiftAndAppend(mode encodingMode, value int) *state { 172 | tokens := s.tokens 173 | 174 | // Shifts exist only to UPPER and PUNCT, both with tokens size 5. 175 | tokens = newSimpleToken(tokens, shiftTable[s.mode][mode], s.mode.BitCount()) 176 | tokens = newSimpleToken(tokens, value, 5) 177 | 178 | return &state{ 179 | mode: s.mode, 180 | tokens: tokens, 181 | bShiftByteCount: 0, 182 | bitCount: s.bitCount + int(s.mode.BitCount()) + 5, 183 | } 184 | } 185 | 186 | // Create a new state representing this state, but an additional character 187 | // output in Binary Shift mode. 188 | func (s *state) addBinaryShiftChar(index int) *state { 189 | tokens := s.tokens 190 | mode := s.mode 191 | bitCnt := s.bitCount 192 | if s.mode == mode_punct || s.mode == mode_digit { 193 | latch := latchTable[s.mode][mode_upper] 194 | tokens = newSimpleToken(tokens, latch&0xFFFF, byte(latch>>16)) 195 | bitCnt += latch >> 16 196 | mode = mode_upper 197 | } 198 | deltaBitCount := 8 199 | if s.bShiftByteCount == 0 || s.bShiftByteCount == 31 { 200 | deltaBitCount = 18 201 | } else if s.bShiftByteCount == 62 { 202 | deltaBitCount = 9 203 | } 204 | result := &state{ 205 | mode: mode, 206 | tokens: tokens, 207 | bShiftByteCount: s.bShiftByteCount + 1, 208 | bitCount: bitCnt + deltaBitCount, 209 | } 210 | if result.bShiftByteCount == 2047+31 { 211 | // The string is as long as it's allowed to be. We should end it. 212 | result = result.endBinaryShift(index + 1) 213 | } 214 | 215 | return result 216 | } 217 | 218 | // Create the state identical to this one, but we are no longer in 219 | // Binary Shift mode. 220 | func (s *state) endBinaryShift(index int) *state { 221 | if s.bShiftByteCount == 0 { 222 | return s 223 | } 224 | tokens := newShiftToken(s.tokens, index-s.bShiftByteCount, s.bShiftByteCount) 225 | return &state{ 226 | mode: s.mode, 227 | tokens: tokens, 228 | bShiftByteCount: 0, 229 | bitCount: s.bitCount, 230 | } 231 | } 232 | 233 | // Returns true if "this" state is better (or equal) to be in than "other" 234 | // state under all possible circumstances. 235 | func (s *state) isBetterThanOrEqualTo(other *state) bool { 236 | mySize := s.bitCount + (latchTable[s.mode][other.mode] >> 16) 237 | 238 | if other.bShiftByteCount > 0 && (s.bShiftByteCount == 0 || s.bShiftByteCount > other.bShiftByteCount) { 239 | mySize += 10 // Cost of entering Binary Shift mode. 240 | } 241 | return mySize <= other.bitCount 242 | } 243 | 244 | func (s *state) toBitList(text []byte) *utils.BitList { 245 | tokens := make([]token, 0) 246 | se := s.endBinaryShift(len(text)) 247 | 248 | for t := se.tokens; t != nil; t = t.prev() { 249 | tokens = append(tokens, t) 250 | } 251 | res := new(utils.BitList) 252 | for i := len(tokens) - 1; i >= 0; i-- { 253 | tokens[i].appendTo(res, text) 254 | } 255 | return res 256 | } 257 | 258 | func (s *state) String() string { 259 | tokens := make([]token, 0) 260 | for t := s.tokens; t != nil; t = t.prev() { 261 | tokens = append([]token{t}, tokens...) 262 | } 263 | return fmt.Sprintf("M:%d bits=%d bytes=%d: %v", s.mode, s.bitCount, s.bShiftByteCount, tokens) 264 | } 265 | -------------------------------------------------------------------------------- /code39/encoder.go: -------------------------------------------------------------------------------- 1 | // Package code39 can create Code39 barcodes 2 | package code39 3 | 4 | import ( 5 | "errors" 6 | "strconv" 7 | "strings" 8 | 9 | "github.com/boombuler/barcode" 10 | "github.com/boombuler/barcode/utils" 11 | ) 12 | 13 | type encodeInfo struct { 14 | value int 15 | data []bool 16 | } 17 | 18 | var encodeTable = map[rune]encodeInfo{ 19 | '0': encodeInfo{0, []bool{true, false, true, false, false, true, true, false, true, true, false, true}}, 20 | '1': encodeInfo{1, []bool{true, true, false, true, false, false, true, false, true, false, true, true}}, 21 | '2': encodeInfo{2, []bool{true, false, true, true, false, false, true, false, true, false, true, true}}, 22 | '3': encodeInfo{3, []bool{true, true, false, true, true, false, false, true, false, true, false, true}}, 23 | '4': encodeInfo{4, []bool{true, false, true, false, false, true, true, false, true, false, true, true}}, 24 | '5': encodeInfo{5, []bool{true, true, false, true, false, false, true, true, false, true, false, true}}, 25 | '6': encodeInfo{6, []bool{true, false, true, true, false, false, true, true, false, true, false, true}}, 26 | '7': encodeInfo{7, []bool{true, false, true, false, false, true, false, true, true, false, true, true}}, 27 | '8': encodeInfo{8, []bool{true, true, false, true, false, false, true, false, true, true, false, true}}, 28 | '9': encodeInfo{9, []bool{true, false, true, true, false, false, true, false, true, true, false, true}}, 29 | 'A': encodeInfo{10, []bool{true, true, false, true, false, true, false, false, true, false, true, true}}, 30 | 'B': encodeInfo{11, []bool{true, false, true, true, false, true, false, false, true, false, true, true}}, 31 | 'C': encodeInfo{12, []bool{true, true, false, true, true, false, true, false, false, true, false, true}}, 32 | 'D': encodeInfo{13, []bool{true, false, true, false, true, true, false, false, true, false, true, true}}, 33 | 'E': encodeInfo{14, []bool{true, true, false, true, false, true, true, false, false, true, false, true}}, 34 | 'F': encodeInfo{15, []bool{true, false, true, true, false, true, true, false, false, true, false, true}}, 35 | 'G': encodeInfo{16, []bool{true, false, true, false, true, false, false, true, true, false, true, true}}, 36 | 'H': encodeInfo{17, []bool{true, true, false, true, false, true, false, false, true, true, false, true}}, 37 | 'I': encodeInfo{18, []bool{true, false, true, true, false, true, false, false, true, true, false, true}}, 38 | 'J': encodeInfo{19, []bool{true, false, true, false, true, true, false, false, true, true, false, true}}, 39 | 'K': encodeInfo{20, []bool{true, true, false, true, false, true, false, true, false, false, true, true}}, 40 | 'L': encodeInfo{21, []bool{true, false, true, true, false, true, false, true, false, false, true, true}}, 41 | 'M': encodeInfo{22, []bool{true, true, false, true, true, false, true, false, true, false, false, true}}, 42 | 'N': encodeInfo{23, []bool{true, false, true, false, true, true, false, true, false, false, true, true}}, 43 | 'O': encodeInfo{24, []bool{true, true, false, true, false, true, true, false, true, false, false, true}}, 44 | 'P': encodeInfo{25, []bool{true, false, true, true, false, true, true, false, true, false, false, true}}, 45 | 'Q': encodeInfo{26, []bool{true, false, true, false, true, false, true, true, false, false, true, true}}, 46 | 'R': encodeInfo{27, []bool{true, true, false, true, false, true, false, true, true, false, false, true}}, 47 | 'S': encodeInfo{28, []bool{true, false, true, true, false, true, false, true, true, false, false, true}}, 48 | 'T': encodeInfo{29, []bool{true, false, true, false, true, true, false, true, true, false, false, true}}, 49 | 'U': encodeInfo{30, []bool{true, true, false, false, true, false, true, false, true, false, true, true}}, 50 | 'V': encodeInfo{31, []bool{true, false, false, true, true, false, true, false, true, false, true, true}}, 51 | 'W': encodeInfo{32, []bool{true, true, false, false, true, true, false, true, false, true, false, true}}, 52 | 'X': encodeInfo{33, []bool{true, false, false, true, false, true, true, false, true, false, true, true}}, 53 | 'Y': encodeInfo{34, []bool{true, true, false, false, true, false, true, true, false, true, false, true}}, 54 | 'Z': encodeInfo{35, []bool{true, false, false, true, true, false, true, true, false, true, false, true}}, 55 | '-': encodeInfo{36, []bool{true, false, false, true, false, true, false, true, true, false, true, true}}, 56 | '.': encodeInfo{37, []bool{true, true, false, false, true, false, true, false, true, true, false, true}}, 57 | ' ': encodeInfo{38, []bool{true, false, false, true, true, false, true, false, true, true, false, true}}, 58 | '$': encodeInfo{39, []bool{true, false, false, true, false, false, true, false, false, true, false, true}}, 59 | '/': encodeInfo{40, []bool{true, false, false, true, false, false, true, false, true, false, false, true}}, 60 | '+': encodeInfo{41, []bool{true, false, false, true, false, true, false, false, true, false, false, true}}, 61 | '%': encodeInfo{42, []bool{true, false, true, false, false, true, false, false, true, false, false, true}}, 62 | '*': encodeInfo{-1, []bool{true, false, false, true, false, true, true, false, true, true, false, true}}, 63 | } 64 | 65 | var extendedTable = map[rune]string{ 66 | 0: `%U`, 1: `$A`, 2: `$B`, 3: `$C`, 4: `$D`, 5: `$E`, 6: `$F`, 7: `$G`, 8: `$H`, 9: `$I`, 10: `$J`, 67 | 11: `$K`, 12: `$L`, 13: `$M`, 14: `$N`, 15: `$O`, 16: `$P`, 17: `$Q`, 18: `$R`, 19: `$S`, 20: `$T`, 68 | 21: `$U`, 22: `$V`, 23: `$W`, 24: `$X`, 25: `$Y`, 26: `$Z`, 27: `%A`, 28: `%B`, 29: `%C`, 30: `%D`, 69 | 31: `%E`, 33: `/A`, 34: `/B`, 35: `/C`, 36: `/D`, 37: `/E`, 38: `/F`, 39: `/G`, 40: `/H`, 41: `/I`, 70 | 42: `/J`, 43: `/K`, 44: `/L`, 47: `/O`, 58: `/Z`, 59: `%F`, 60: `%G`, 61: `%H`, 62: `%I`, 63: `%J`, 71 | 64: `%V`, 91: `%K`, 92: `%L`, 93: `%M`, 94: `%N`, 95: `%O`, 96: `%W`, 97: `+A`, 98: `+B`, 99: `+C`, 72 | 100: `+D`, 101: `+E`, 102: `+F`, 103: `+G`, 104: `+H`, 105: `+I`, 106: `+J`, 107: `+K`, 108: `+L`, 73 | 109: `+M`, 110: `+N`, 111: `+O`, 112: `+P`, 113: `+Q`, 114: `+R`, 115: `+S`, 116: `+T`, 117: `+U`, 74 | 118: `+V`, 119: `+W`, 120: `+X`, 121: `+Y`, 122: `+Z`, 123: `%P`, 124: `%Q`, 125: `%R`, 126: `%S`, 75 | 127: `%T`, 76 | } 77 | 78 | func getChecksum(content string) string { 79 | sum := 0 80 | for _, r := range content { 81 | info, ok := encodeTable[r] 82 | if !ok || info.value < 0 { 83 | return "#" 84 | } 85 | 86 | sum += info.value 87 | } 88 | 89 | sum = sum % 43 90 | for r, v := range encodeTable { 91 | if v.value == sum { 92 | return string(r) 93 | } 94 | } 95 | return "#" 96 | } 97 | 98 | func prepare(content string) (string, error) { 99 | result := "" 100 | for _, r := range content { 101 | if r > 127 { 102 | return "", errors.New("only ASCII strings can be encoded") 103 | } 104 | val, ok := extendedTable[r] 105 | if ok { 106 | result += val 107 | } else { 108 | result += string([]rune{r}) 109 | } 110 | } 111 | return result, nil 112 | } 113 | 114 | // Encode returns a code39 barcode for the given content and color scheme 115 | // if includeChecksum is set to true, a checksum character is calculated and added to the content 116 | func EncodeWithColor(content string, includeChecksum bool, fullASCIIMode bool, color barcode.ColorScheme) (barcode.BarcodeIntCS, error) { 117 | if fullASCIIMode { 118 | var err error 119 | content, err = prepare(content) 120 | if err != nil { 121 | return nil, err 122 | } 123 | } else if strings.ContainsRune(content, '*') { 124 | return nil, errors.New("invalid data! try full ascii mode") 125 | } 126 | 127 | data := "*" + content 128 | if includeChecksum { 129 | data += getChecksum(content) 130 | } 131 | data += "*" 132 | 133 | result := new(utils.BitList) 134 | 135 | for i, r := range data { 136 | if i != 0 { 137 | result.AddBit(false) 138 | } 139 | 140 | info, ok := encodeTable[r] 141 | if !ok { 142 | return nil, errors.New("invalid data! try full ascii mode") 143 | } 144 | result.AddBit(info.data...) 145 | } 146 | 147 | checkSum, err := strconv.ParseInt(getChecksum(content), 10, 64) 148 | if err != nil { 149 | checkSum = 0 150 | } 151 | return utils.New1DCodeIntCheckSumWithColor(barcode.TypeCode39, content, result, int(checkSum), color), nil 152 | } 153 | 154 | // Encode returns a code39 barcode for the given content 155 | // if includeChecksum is set to true, a checksum character is calculated and added to the content 156 | func Encode(content string, includeChecksum bool, fullASCIIMode bool) (barcode.BarcodeIntCS, error) { 157 | return EncodeWithColor(content, includeChecksum, fullASCIIMode, barcode.ColorScheme16) 158 | } 159 | -------------------------------------------------------------------------------- /aztec/encoder.go: -------------------------------------------------------------------------------- 1 | // Package aztec can create Aztec Code barcodes 2 | package aztec 3 | 4 | import ( 5 | "fmt" 6 | 7 | "github.com/boombuler/barcode" 8 | "github.com/boombuler/barcode/utils" 9 | ) 10 | 11 | const ( 12 | DEFAULT_EC_PERCENT = 33 13 | DEFAULT_LAYERS = 0 14 | max_nb_bits = 32 15 | max_nb_bits_compact = 4 16 | ) 17 | 18 | var ( 19 | word_size = []int{ 20 | 4, 6, 6, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 21 | 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 22 | } 23 | ) 24 | 25 | func totalBitsInLayer(layers int, compact bool) int { 26 | tmp := 112 27 | if compact { 28 | tmp = 88 29 | } 30 | return (tmp + 16*layers) * layers 31 | } 32 | 33 | func stuffBits(bits *utils.BitList, wordSize int) *utils.BitList { 34 | out := new(utils.BitList) 35 | n := bits.Len() 36 | mask := (1 << uint(wordSize)) - 2 37 | for i := 0; i < n; i += wordSize { 38 | word := 0 39 | for j := 0; j < wordSize; j++ { 40 | if i+j >= n || bits.GetBit(i+j) { 41 | word |= 1 << uint(wordSize-1-j) 42 | } 43 | } 44 | if (word & mask) == mask { 45 | out.AddBits(word&mask, byte(wordSize)) 46 | i-- 47 | } else if (word & mask) == 0 { 48 | out.AddBits(word|1, byte(wordSize)) 49 | i-- 50 | } else { 51 | out.AddBits(word, byte(wordSize)) 52 | } 53 | } 54 | return out 55 | } 56 | 57 | func generateModeMessage(compact bool, layers, messageSizeInWords int) *utils.BitList { 58 | modeMessage := new(utils.BitList) 59 | if compact { 60 | modeMessage.AddBits(layers-1, 2) 61 | modeMessage.AddBits(messageSizeInWords-1, 6) 62 | modeMessage = generateCheckWords(modeMessage, 28, 4) 63 | } else { 64 | modeMessage.AddBits(layers-1, 5) 65 | modeMessage.AddBits(messageSizeInWords-1, 11) 66 | modeMessage = generateCheckWords(modeMessage, 40, 4) 67 | } 68 | return modeMessage 69 | } 70 | 71 | func drawModeMessage(matrix *aztecCode, compact bool, matrixSize int, modeMessage *utils.BitList) { 72 | center := matrixSize / 2 73 | if compact { 74 | for i := 0; i < 7; i++ { 75 | offset := center - 3 + i 76 | if modeMessage.GetBit(i) { 77 | matrix.set(offset, center-5) 78 | } 79 | if modeMessage.GetBit(i + 7) { 80 | matrix.set(center+5, offset) 81 | } 82 | if modeMessage.GetBit(20 - i) { 83 | matrix.set(offset, center+5) 84 | } 85 | if modeMessage.GetBit(27 - i) { 86 | matrix.set(center-5, offset) 87 | } 88 | } 89 | } else { 90 | for i := 0; i < 10; i++ { 91 | offset := center - 5 + i + i/5 92 | if modeMessage.GetBit(i) { 93 | matrix.set(offset, center-7) 94 | } 95 | if modeMessage.GetBit(i + 10) { 96 | matrix.set(center+7, offset) 97 | } 98 | if modeMessage.GetBit(29 - i) { 99 | matrix.set(offset, center+7) 100 | } 101 | if modeMessage.GetBit(39 - i) { 102 | matrix.set(center-7, offset) 103 | } 104 | } 105 | } 106 | } 107 | 108 | func drawBullsEye(matrix *aztecCode, center, size int) { 109 | for i := 0; i < size; i += 2 { 110 | for j := center - i; j <= center+i; j++ { 111 | matrix.set(j, center-i) 112 | matrix.set(j, center+i) 113 | matrix.set(center-i, j) 114 | matrix.set(center+i, j) 115 | } 116 | } 117 | matrix.set(center-size, center-size) 118 | matrix.set(center-size+1, center-size) 119 | matrix.set(center-size, center-size+1) 120 | matrix.set(center+size, center-size) 121 | matrix.set(center+size, center-size+1) 122 | matrix.set(center+size, center+size-1) 123 | } 124 | 125 | // Encode returns an aztec barcode with the given content 126 | func Encode(data []byte, minECCPercent int, userSpecifiedLayers int) (barcode.Barcode, error) { 127 | return EncodeWithColor(data, minECCPercent, userSpecifiedLayers, barcode.ColorScheme16) 128 | } 129 | 130 | // Encode returns an aztec barcode with the given content and color scheme 131 | func EncodeWithColor(data []byte, minECCPercent int, userSpecifiedLayers int, color barcode.ColorScheme) (barcode.Barcode, error) { 132 | bits := highlevelEncode(data) 133 | eccBits := ((bits.Len() * minECCPercent) / 100) + 11 134 | totalSizeBits := bits.Len() + eccBits 135 | var layers, TotalBitsInLayer, wordSize int 136 | var compact bool 137 | var stuffedBits *utils.BitList 138 | if userSpecifiedLayers != DEFAULT_LAYERS { 139 | compact = userSpecifiedLayers < 0 140 | if compact { 141 | layers = -userSpecifiedLayers 142 | } else { 143 | layers = userSpecifiedLayers 144 | } 145 | if (compact && layers > max_nb_bits_compact) || (!compact && layers > max_nb_bits) { 146 | return nil, fmt.Errorf("illegal value %d for layers", userSpecifiedLayers) 147 | } 148 | TotalBitsInLayer = totalBitsInLayer(layers, compact) 149 | wordSize = word_size[layers] 150 | usableBitsInLayers := TotalBitsInLayer - (TotalBitsInLayer % wordSize) 151 | stuffedBits = stuffBits(bits, wordSize) 152 | if stuffedBits.Len()+eccBits > usableBitsInLayers { 153 | return nil, fmt.Errorf("data too large for user specified layer") 154 | } 155 | if compact && stuffedBits.Len() > wordSize*64 { 156 | return nil, fmt.Errorf("data too large for user specified layer") 157 | } 158 | } else { 159 | wordSize = 0 160 | stuffedBits = nil 161 | // We look at the possible table sizes in the order Compact1, Compact2, Compact3, 162 | // Compact4, Normal4,... Normal(i) for i < 4 isn't typically used since Compact(i+1) 163 | // is the same size, but has more data. 164 | for i := 0; ; i++ { 165 | if i > max_nb_bits { 166 | return nil, fmt.Errorf("data too large for an aztec code") 167 | } 168 | compact = i <= 3 169 | layers = i 170 | if compact { 171 | layers = i + 1 172 | } 173 | TotalBitsInLayer = totalBitsInLayer(layers, compact) 174 | if totalSizeBits > TotalBitsInLayer { 175 | continue 176 | } 177 | // [Re]stuff the bits if this is the first opportunity, or if the 178 | // wordSize has changed 179 | if wordSize != word_size[layers] { 180 | wordSize = word_size[layers] 181 | stuffedBits = stuffBits(bits, wordSize) 182 | } 183 | usableBitsInLayers := TotalBitsInLayer - (TotalBitsInLayer % wordSize) 184 | if compact && stuffedBits.Len() > wordSize*64 { 185 | // Compact format only allows 64 data words, though C4 can hold more words than that 186 | continue 187 | } 188 | if stuffedBits.Len()+eccBits <= usableBitsInLayers { 189 | break 190 | } 191 | } 192 | } 193 | messageBits := generateCheckWords(stuffedBits, TotalBitsInLayer, wordSize) 194 | messageSizeInWords := stuffedBits.Len() / wordSize 195 | modeMessage := generateModeMessage(compact, layers, messageSizeInWords) 196 | 197 | // allocate symbol 198 | var baseMatrixSize int 199 | if compact { 200 | baseMatrixSize = 11 + layers*4 201 | } else { 202 | baseMatrixSize = 14 + layers*4 203 | } 204 | alignmentMap := make([]int, baseMatrixSize) 205 | var matrixSize int 206 | 207 | if compact { 208 | // no alignment marks in compact mode, alignmentMap is a no-op 209 | matrixSize = baseMatrixSize 210 | for i := 0; i < len(alignmentMap); i++ { 211 | alignmentMap[i] = i 212 | } 213 | } else { 214 | matrixSize = baseMatrixSize + 1 + 2*((baseMatrixSize/2-1)/15) 215 | origCenter := baseMatrixSize / 2 216 | center := matrixSize / 2 217 | for i := 0; i < origCenter; i++ { 218 | newOffset := i + i/15 219 | alignmentMap[origCenter-i-1] = center - newOffset - 1 220 | alignmentMap[origCenter+i] = center + newOffset + 1 221 | } 222 | } 223 | code := newAztecCode(matrixSize, color) 224 | code.content = data 225 | 226 | // draw data bits 227 | for i, rowOffset := 0, 0; i < layers; i++ { 228 | rowSize := (layers - i) * 4 229 | if compact { 230 | rowSize += 9 231 | } else { 232 | rowSize += 12 233 | } 234 | 235 | for j := 0; j < rowSize; j++ { 236 | columnOffset := j * 2 237 | for k := 0; k < 2; k++ { 238 | if messageBits.GetBit(rowOffset + columnOffset + k) { 239 | code.set(alignmentMap[i*2+k], alignmentMap[i*2+j]) 240 | } 241 | if messageBits.GetBit(rowOffset + rowSize*2 + columnOffset + k) { 242 | code.set(alignmentMap[i*2+j], alignmentMap[baseMatrixSize-1-i*2-k]) 243 | } 244 | if messageBits.GetBit(rowOffset + rowSize*4 + columnOffset + k) { 245 | code.set(alignmentMap[baseMatrixSize-1-i*2-k], alignmentMap[baseMatrixSize-1-i*2-j]) 246 | } 247 | if messageBits.GetBit(rowOffset + rowSize*6 + columnOffset + k) { 248 | code.set(alignmentMap[baseMatrixSize-1-i*2-j], alignmentMap[i*2+k]) 249 | } 250 | } 251 | } 252 | rowOffset += rowSize * 8 253 | } 254 | 255 | // draw mode message 256 | drawModeMessage(code, compact, matrixSize, modeMessage) 257 | 258 | // draw alignment marks 259 | if compact { 260 | drawBullsEye(code, matrixSize/2, 5) 261 | } else { 262 | drawBullsEye(code, matrixSize/2, 7) 263 | for i, j := 0, 0; i < baseMatrixSize/2-1; i, j = i+15, j+16 { 264 | for k := (matrixSize / 2) & 1; k < matrixSize; k += 2 { 265 | code.set(matrixSize/2-j, k) 266 | code.set(matrixSize/2+j, k) 267 | code.set(k, matrixSize/2-j) 268 | code.set(k, matrixSize/2+j) 269 | } 270 | } 271 | } 272 | return code, nil 273 | } 274 | -------------------------------------------------------------------------------- /pdf417/highlevel.go: -------------------------------------------------------------------------------- 1 | package pdf417 2 | 3 | import ( 4 | "errors" 5 | "math/big" 6 | 7 | "github.com/boombuler/barcode/utils" 8 | ) 9 | 10 | type encodingMode byte 11 | 12 | type subMode byte 13 | 14 | const ( 15 | encText encodingMode = iota 16 | encNumeric 17 | encBinary 18 | 19 | subUpper subMode = iota 20 | subLower 21 | subMixed 22 | subPunct 23 | 24 | latch_to_text = 900 25 | latch_to_byte_padded = 901 26 | latch_to_numeric = 902 27 | latch_to_byte = 924 28 | shift_to_byte = 913 29 | 30 | min_numeric_count = 13 31 | ) 32 | 33 | var ( 34 | mixedMap map[rune]int 35 | punctMap map[rune]int 36 | ) 37 | 38 | func init() { 39 | mixedMap = make(map[rune]int) 40 | mixedRaw := []rune{ 41 | 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 38, 13, 9, 44, 58, 42 | 35, 45, 46, 36, 47, 43, 37, 42, 61, 94, 0, 32, 0, 0, 0, 43 | } 44 | for idx, ch := range mixedRaw { 45 | if ch > 0 { 46 | mixedMap[ch] = idx 47 | } 48 | } 49 | 50 | punctMap = make(map[rune]int) 51 | punctRaw := []rune{ 52 | 59, 60, 62, 64, 91, 92, 93, 95, 96, 126, 33, 13, 9, 44, 58, 53 | 10, 45, 46, 36, 47, 34, 124, 42, 40, 41, 63, 123, 125, 39, 0, 54 | } 55 | for idx, ch := range punctRaw { 56 | if ch > 0 { 57 | punctMap[ch] = idx 58 | } 59 | } 60 | } 61 | 62 | func determineConsecutiveDigitCount(data []rune) int { 63 | cnt := 0 64 | for _, r := range data { 65 | if utils.RuneToInt(r) == -1 { 66 | break 67 | } 68 | cnt++ 69 | } 70 | return cnt 71 | } 72 | 73 | func encodeNumeric(digits []rune) ([]int, error) { 74 | digitCount := len(digits) 75 | chunkCount := digitCount / 44 76 | if digitCount%44 != 0 { 77 | chunkCount++ 78 | } 79 | 80 | codeWords := []int{} 81 | 82 | for i := 0; i < chunkCount; i++ { 83 | start := i * 44 84 | end := start + 44 85 | if end > digitCount { 86 | end = digitCount 87 | } 88 | chunk := digits[start:end] 89 | 90 | chunkNum := big.NewInt(0) 91 | _, ok := chunkNum.SetString("1"+string(chunk), 10) 92 | 93 | if !ok { 94 | return nil, errors.New("Failed converting: " + string(chunk)) 95 | } 96 | 97 | cws := []int{} 98 | 99 | for chunkNum.Cmp(big.NewInt(0)) > 0 { 100 | newChunk, cw := chunkNum.DivMod(chunkNum, big.NewInt(900), big.NewInt(0)) 101 | chunkNum = newChunk 102 | cws = append([]int{int(cw.Int64())}, cws...) 103 | } 104 | 105 | codeWords = append(codeWords, cws...) 106 | } 107 | 108 | return codeWords, nil 109 | } 110 | 111 | func determineConsecutiveTextCount(msg []rune) int { 112 | result := 0 113 | 114 | isText := func(ch rune) bool { 115 | return ch == '\t' || ch == '\n' || ch == '\r' || (ch >= 32 && ch <= 126) 116 | } 117 | 118 | for i, ch := range msg { 119 | numericCount := determineConsecutiveDigitCount(msg[i:]) 120 | if numericCount >= min_numeric_count || (numericCount == 0 && !isText(ch)) { 121 | break 122 | } 123 | 124 | result++ 125 | } 126 | return result 127 | } 128 | 129 | func encodeText(text []rune, submode subMode) (subMode, []int) { 130 | isAlphaUpper := func(ch rune) bool { 131 | return ch == ' ' || (ch >= 'A' && ch <= 'Z') 132 | } 133 | isAlphaLower := func(ch rune) bool { 134 | return ch == ' ' || (ch >= 'a' && ch <= 'z') 135 | } 136 | isMixed := func(ch rune) bool { 137 | _, ok := mixedMap[ch] 138 | return ok 139 | } 140 | isPunctuation := func(ch rune) bool { 141 | _, ok := punctMap[ch] 142 | return ok 143 | } 144 | 145 | idx := 0 146 | var tmp []int 147 | for idx < len(text) { 148 | ch := text[idx] 149 | switch submode { 150 | case subUpper: 151 | if isAlphaUpper(ch) { 152 | if ch == ' ' { 153 | tmp = append(tmp, 26) //space 154 | } else { 155 | tmp = append(tmp, int(ch-'A')) 156 | } 157 | } else { 158 | if isAlphaLower(ch) { 159 | submode = subLower 160 | tmp = append(tmp, 27) // lower latch 161 | continue 162 | } else if isMixed(ch) { 163 | submode = subMixed 164 | tmp = append(tmp, 28) // mixed latch 165 | continue 166 | } else { 167 | tmp = append(tmp, 29) // punctuation switch 168 | tmp = append(tmp, punctMap[ch]) 169 | } 170 | } 171 | case subLower: 172 | if isAlphaLower(ch) { 173 | if ch == ' ' { 174 | tmp = append(tmp, 26) //space 175 | } else { 176 | tmp = append(tmp, int(ch-'a')) 177 | } 178 | } else { 179 | if isAlphaUpper(ch) { 180 | tmp = append(tmp, 27) //upper switch 181 | tmp = append(tmp, int(ch-'A')) 182 | } else if isMixed(ch) { 183 | submode = subMixed 184 | tmp = append(tmp, 28) //mixed latch 185 | continue 186 | } else { 187 | tmp = append(tmp, 29) //punctuation switch 188 | tmp = append(tmp, punctMap[ch]) 189 | } 190 | } 191 | case subMixed: 192 | if isMixed(ch) { 193 | tmp = append(tmp, mixedMap[ch]) 194 | } else { 195 | if isAlphaUpper(ch) { 196 | submode = subUpper 197 | tmp = append(tmp, 28) //upper latch 198 | continue 199 | } else if isAlphaLower(ch) { 200 | submode = subLower 201 | tmp = append(tmp, 27) //lower latch 202 | continue 203 | } else { 204 | if idx+1 < len(text) { 205 | next := text[idx+1] 206 | if isPunctuation(next) { 207 | submode = subPunct 208 | tmp = append(tmp, 25) //punctuation latch 209 | continue 210 | } 211 | } 212 | tmp = append(tmp, 29) //punctuation switch 213 | tmp = append(tmp, punctMap[ch]) 214 | } 215 | } 216 | default: //subPunct 217 | if isPunctuation(ch) { 218 | tmp = append(tmp, punctMap[ch]) 219 | } else { 220 | submode = subUpper 221 | tmp = append(tmp, 29) //upper latch 222 | } 223 | } 224 | idx++ 225 | } 226 | 227 | h := 0 228 | result := []int{} 229 | for i, val := range tmp { 230 | if i%2 != 0 { 231 | h = (h * 30) + val 232 | result = append(result, h) 233 | } else { 234 | h = val 235 | } 236 | } 237 | if len(tmp)%2 != 0 { 238 | result = append(result, (h*30)+29) 239 | } 240 | return submode, result 241 | } 242 | 243 | func determineConsecutiveBinaryCount(msg []byte) int { 244 | result := 0 245 | 246 | for i := range msg { 247 | numericCount := determineConsecutiveDigitCount([]rune(string(msg[i:]))) 248 | if numericCount >= min_numeric_count { 249 | break 250 | } 251 | textCount := determineConsecutiveTextCount([]rune(string(msg[i:]))) 252 | if textCount > 5 { 253 | break 254 | } 255 | result++ 256 | } 257 | return result 258 | } 259 | 260 | func encodeBinary(data []byte, startmode encodingMode) []int { 261 | result := []int{} 262 | 263 | count := len(data) 264 | if count == 1 && startmode == encText { 265 | result = append(result, shift_to_byte) 266 | } else if (count % 6) == 0 { 267 | result = append(result, latch_to_byte) 268 | } else { 269 | result = append(result, latch_to_byte_padded) 270 | } 271 | 272 | idx := 0 273 | // Encode sixpacks 274 | if count >= 6 { 275 | words := make([]int, 5) 276 | for (count - idx) >= 6 { 277 | var t int64 = 0 278 | for i := 0; i < 6; i++ { 279 | t = t << 8 280 | t += int64(data[idx+i]) 281 | } 282 | for i := 0; i < 5; i++ { 283 | words[4-i] = int(t % 900) 284 | t = t / 900 285 | } 286 | result = append(result, words...) 287 | idx += 6 288 | } 289 | } 290 | //Encode rest (remaining n<5 bytes if any) 291 | for i := idx; i < count; i++ { 292 | result = append(result, int(data[i]&0xff)) 293 | } 294 | return result 295 | } 296 | 297 | func highlevelEncode(dataStr string) ([]int, error) { 298 | encodingMode := encText 299 | textSubMode := subUpper 300 | 301 | result := []int{} 302 | 303 | data := []byte(dataStr) 304 | 305 | for len(data) > 0 { 306 | numericCount := determineConsecutiveDigitCount([]rune(string(data))) 307 | if numericCount >= min_numeric_count || numericCount == len(data) { 308 | result = append(result, latch_to_numeric) 309 | encodingMode = encNumeric 310 | textSubMode = subUpper 311 | numData, err := encodeNumeric([]rune(string(data[:numericCount]))) 312 | if err != nil { 313 | return nil, err 314 | } 315 | result = append(result, numData...) 316 | data = data[numericCount:] 317 | } else { 318 | textCount := determineConsecutiveTextCount([]rune(string(data))) 319 | if textCount >= 5 || textCount == len(data) { 320 | if encodingMode != encText { 321 | result = append(result, latch_to_text) 322 | encodingMode = encText 323 | textSubMode = subUpper 324 | } 325 | var txtData []int 326 | textSubMode, txtData = encodeText([]rune(string(data[:textCount])), textSubMode) 327 | result = append(result, txtData...) 328 | data = data[textCount:] 329 | } else { 330 | binaryCount := determineConsecutiveBinaryCount(data) 331 | if binaryCount == 0 { 332 | binaryCount = 1 333 | } 334 | bytes := data[:binaryCount] 335 | if len(bytes) != 1 || encodingMode != encText { 336 | encodingMode = encBinary 337 | textSubMode = subUpper 338 | } 339 | byteData := encodeBinary(bytes, encodingMode) 340 | result = append(result, byteData...) 341 | data = data[binaryCount:] 342 | } 343 | } 344 | } 345 | 346 | return result, nil 347 | } 348 | -------------------------------------------------------------------------------- /qr/errorcorrection_test.go: -------------------------------------------------------------------------------- 1 | package qr 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | func Test_ErrorCorrection(t *testing.T) { 9 | doTest := func(b []byte, ecc []byte) { 10 | cnt := byte(len(ecc)) 11 | res := ec.calcECC(b, cnt) 12 | if !bytes.Equal(res, ecc) { 13 | t.Errorf("ECC error!\nGot: %v\nExpected:%v", res, ecc) 14 | } 15 | } 16 | // Issue #5 17 | doTest([]byte{66, 196, 148, 21, 99, 19, 151, 151, 53, 149, 54, 195, 4, 133, 87, 84, 115, 85, 22, 148, 52, 71, 102, 68, 134, 182, 247, 119, 22, 68, 117, 134, 35, 4, 134, 38, 21, 84, 21, 117, 87, 164, 135, 115, 211, 208, 236, 17, 236, 17, 236, 17, 236, 17, 236}, []byte{187, 187, 171, 253, 164, 129, 104, 133, 3, 75, 87, 98, 241, 146, 138}) 18 | 19 | // Other tests 20 | doTest([]byte{17, 168, 162, 241, 255, 205, 240, 179, 88, 101, 71, 130, 2, 54, 147, 111, 232, 58, 202, 171, 85, 22, 229, 187}, []byte{30, 142, 171, 131, 189}) 21 | doTest([]byte{36, 153, 55, 100, 228, 252, 0, 35, 85, 7, 237, 117, 182, 73, 83, 244, 8, 64, 55, 252, 200, 250, 72, 92, 97, 125, 96}, []byte{129, 124, 218, 148, 49, 108, 68, 255, 58, 212, 56, 60, 142, 45, 216, 124, 253, 214, 206, 208, 145, 169, 43}) 22 | doTest([]byte{250, 195, 230, 128, 31, 168, 86, 123, 244, 129, 74, 130, 222, 225, 140, 129, 114, 132, 128, 88, 96, 13, 165, 132, 116, 22, 42, 81, 219, 3, 102, 156, 69, 70, 90, 68, 7, 245, 150, 160, 252, 121, 20}, []byte{124, 23, 233, 71, 200, 211, 54, 141, 10, 23, 206, 147, 116, 35, 45, 218, 158, 193, 80, 194, 129, 147, 8, 78, 229, 112, 89, 161, 167, 203, 11, 245, 186, 187, 17, 7, 175}) 23 | doTest([]byte{121, 234, 24, 188, 218, 238, 248, 223, 98, 124, 237, 30, 98, 12, 9, 126, 5, 160, 240, 27, 174, 60, 152, 134, 71, 122, 125, 238, 223, 91, 231, 248, 230, 152, 250, 44, 17, 149, 0, 20, 109, 188, 227, 202}, []byte{209, 71, 225, 216, 240, 127, 111, 98, 194, 133, 114, 63, 35, 167, 184, 4, 209, 211, 40, 14, 74, 37, 21, 76, 95, 206, 90, 152, 110, 64, 6, 92, 80, 255, 127, 35, 111, 25, 1, 73}) 24 | doTest([]byte{165, 233, 141, 34, 247, 216, 35, 163, 61, 61, 81, 146, 116, 96, 113, 10, 0, 6, 148, 244, 55, 201, 17, 220, 109, 111}, []byte{93, 173, 231, 160}) 25 | doTest([]byte{173, 242, 89, 205, 24, 33, 213, 147, 96, 189, 100, 15, 213, 67, 91, 189, 218, 127, 32, 160, 162, 99, 187, 221, 53, 121, 238, 219, 215, 176, 181, 135, 56, 71, 246, 74, 228}, []byte{194, 130, 43, 168, 223, 144, 223, 49, 5, 162, 62, 218, 50, 205, 249, 84, 188, 25, 109, 110, 49, 224, 194, 244, 83, 221, 236, 71, 197, 159, 182}) 26 | doTest([]byte{82, 138, 221, 169, 67, 161, 132, 31, 243, 110, 83, 1, 238, 79, 255, 57, 74, 54, 123, 151, 159, 50, 250, 188, 176, 8, 221, 215, 141, 77, 16}, []byte{197, 122, 225, 65, 40, 69, 153, 100, 73, 245, 150, 213, 104, 127, 3}) 27 | doTest([]byte{5, 206, 21, 196, 185, 120, 60, 177, 90, 251, 109, 131, 174, 199, 55, 56, 14, 171, 19, 104, 236, 218, 31, 144, 33, 249, 58, 195, 173, 145, 166, 93, 122, 171, 232, 128, 233, 116, 144, 189, 62, 230, 68, 55, 140, 56, 1, 65, 165, 158, 127}, []byte{73, 141, 230, 252, 225, 173, 251, 194, 150, 98, 141, 241, 246, 11, 16, 8, 42}) 28 | doTest([]byte{112, 106, 43, 174, 133, 163, 192, 61, 121, 3, 200, 84, 15, 9, 3, 222, 183, 78, 153, 26, 85, 41, 5, 149, 232, 3, 233, 247, 249, 29, 15, 18, 4, 96, 9, 64, 188, 210}, []byte{16, 254, 143, 110, 63, 167, 213, 242, 95, 78, 215, 145, 231, 59, 158, 36, 149, 247, 123, 114, 247, 202, 15, 56, 229, 163, 186, 73, 82, 230, 111, 108, 111, 182, 193, 46, 116}) 29 | doTest([]byte{208, 128, 197, 227, 124, 226, 125, 46, 253, 98, 238, 80, 229, 134, 167, 70, 101, 150, 198, 130, 185, 200, 68, 91}, []byte{229, 167, 187, 39, 92, 90, 210, 25, 206, 237, 90, 194, 206, 39, 2, 11, 78, 48, 247}) 30 | doTest([]byte{79, 175, 255, 194, 34, 229, 234, 200, 74, 213, 100, 33, 24, 5, 133, 186, 249, 151, 46, 190, 44, 126, 184, 195, 219, 37, 11, 225, 23, 8, 59, 106, 239, 198, 146, 205, 47, 59, 63, 9, 102, 29, 60, 209, 226, 67, 126, 193, 252, 255, 206, 172, 44, 53, 137, 209, 246}, []byte{237, 8, 12, 44, 90, 243, 24, 100, 123, 216, 185, 91, 182, 60, 9, 145, 126, 254, 139, 24, 211, 150, 219, 28, 138, 197, 13, 109, 227, 31, 60, 128, 237, 181, 183, 2, 138, 232, 112, 5}) 31 | doTest([]byte{253, 217, 8, 176, 66, 153, 249, 49, 82, 114, 184, 139, 190, 87}, []byte{28, 55, 193, 193, 179, 246, 222, 5, 95, 96, 13, 242}) 32 | doTest([]byte{15, 65, 231, 224, 151, 167, 74, 228, 23}, []byte{200, 90, 82}) 33 | doTest([]byte{61, 186, 61, 193, 215, 243, 84, 66, 48, 93, 108, 249, 55, 232}, []byte{0, 180, 53, 152, 134, 252, 165, 168}) 34 | doTest([]byte{78, 68, 116, 15, 85}, []byte{36}) 35 | doTest([]byte{122, 143}, []byte{245}) 36 | doTest([]byte{78, 85, 143, 35}, []byte{226, 85}) 37 | doTest([]byte{11, 188, 118, 21, 177, 224, 151, 105, 21, 245, 251, 162, 72, 175, 248, 134, 123, 251, 160, 163, 42, 57, 53, 222, 195, 49, 199, 151, 5, 236, 160, 57, 212, 241, 44, 43}, []byte{186, 106}) 38 | doTest([]byte{157, 99, 220, 166, 63, 18, 225, 215, 71, 95, 99, 200, 218, 147, 131, 245, 222, 209, 135, 152, 82, 128, 24, 0, 100, 40, 84, 193, 205, 86, 130, 204, 235, 100, 94, 61}, []byte{41, 171, 66, 233}) 39 | doTest([]byte{249, 34, 253, 235, 233, 104, 52, 60, 17, 13, 182, 223, 19, 91, 164, 2, 196, 29, 74, 219, 65, 23, 190, 31, 10, 241, 221, 150, 221, 118, 53, 69, 45, 90, 215, 100, 155, 102, 150, 176, 203, 39, 22, 70, 10, 238}, []byte{161, 49, 179, 149, 178, 146, 208, 144, 19, 158, 180, 152, 243, 138, 143, 243, 82, 112, 229, 10, 113, 255, 139, 246}) 40 | doTest([]byte{39, 232, 159, 64, 242, 235, 66, 226, 100, 221, 225, 247, 139, 157, 95, 155}, []byte{41, 9, 244}) 41 | doTest([]byte{177, 185, 131, 64, 103, 93, 134, 153, 15, 26, 0, 119, 21, 27, 174, 181, 111, 245, 214, 244, 83, 66, 24, 244, 255, 189, 133, 158, 37, 46, 199, 123, 110, 153, 61, 137, 163, 231, 129, 65, 186, 89, 219, 39, 226, 236, 199, 197, 73, 213}, []byte{37, 59, 125, 211, 249, 177, 107, 79, 107, 47, 242, 168, 49, 38, 168, 198, 199, 91, 212, 22, 107, 244}) 42 | doTest([]byte{196, 226, 29, 110, 161, 143, 64, 169, 216, 231, 115}, []byte{253, 93, 218, 129, 37}) 43 | doTest([]byte{133, 8, 124, 221, 36, 17, 135, 115, 149, 58, 250, 103, 241, 18, 19, 246, 191, 85, 80, 255, 93, 182, 140, 123, 206, 232, 20, 166, 216, 105, 210, 229, 249, 212, 93, 227, 75, 231, 36, 195, 166, 246, 47, 168, 35, 7, 176, 124, 44, 179, 24, 145}, []byte{78, 57, 134, 181, 215, 149, 111, 51, 172, 58, 114, 3, 140, 186, 126, 40, 190}) 44 | doTest([]byte{245, 206, 124, 0, 15, 59, 253, 225, 155}, []byte{65, 14, 188, 213, 18, 113, 161, 16}) 45 | doTest([]byte{20, 109, 28, 180, 48, 170, 216, 48, 140, 89, 103}, []byte{193, 147, 50, 209, 160}) 46 | doTest([]byte{87, 198, 56, 151, 121, 37, 81, 64, 193, 24, 222, 142, 102, 74, 216, 233, 198, 197, 90, 4, 65, 14, 154, 147, 200, 252, 8, 64, 97, 150, 136, 141}, []byte{231, 190, 32, 90, 100, 40, 41, 103, 200, 200, 243, 75, 177, 7, 93, 28, 83, 47, 188, 236, 20, 95, 69, 104, 155, 102, 110, 197}) 47 | doTest([]byte{168, 72, 2, 101, 103, 118, 218, 38, 82, 85, 62, 37, 201, 96, 255, 71, 198}, []byte{129, 33, 28, 228, 195, 120, 101, 46, 119, 126}) 48 | doTest([]byte{130, 162, 73, 44, 165, 207, 124, 28, 17, 223, 43, 143, 81, 70, 205, 161, 143, 230, 97, 94, 228, 41, 26, 187, 69, 85, 162, 51, 168, 64, 26, 207, 245, 128}, []byte{6, 171}) 49 | doTest([]byte{95, 28, 93, 149, 234, 89, 201, 71, 39, 197, 236, 223, 251, 190, 112, 96, 101, 53, 40, 88, 136, 141, 230, 80, 45, 73, 116, 208, 197, 91, 154, 209, 128, 214, 66, 114, 137, 204, 115, 139, 96, 211, 148, 127, 104, 194}, []byte{10, 102, 57, 95, 61, 212, 130, 71, 74, 58, 82, 115, 238, 213, 251, 184, 203, 250, 55, 186, 37, 16, 71, 247, 146, 194, 74, 208, 221, 6, 81, 172, 204, 73, 102, 40, 247, 174, 213, 37, 225, 246, 8, 58}) 50 | doTest([]byte{207, 185, 106, 191, 87, 109, 110, 210, 54, 12, 103, 161, 228}, []byte{214, 138, 159, 195, 154, 236, 33, 243, 53, 79, 227}) 51 | doTest([]byte{203, 43, 26, 94, 37, 123, 254, 215, 153, 193, 157, 248, 180, 249, 103, 232, 107, 17, 138, 0, 11, 240, 218, 122, 19, 103, 112, 60, 125, 100, 209, 166, 103, 81, 200, 84, 77, 100, 18, 110, 209, 225, 209, 254, 185, 116, 186, 216, 206, 36, 252, 144, 90, 247, 117, 219, 81, 160}, []byte{185, 176, 106, 253, 76, 153, 185, 211, 187, 153, 210, 31, 99, 4, 46, 145, 221, 99, 236, 19, 126, 138, 66, 26, 40, 217, 170, 217, 147}) 52 | doTest([]byte{11, 193, 90, 52, 239, 247, 144, 99, 48, 19, 154, 6, 255, 28, 47, 41, 30, 220}, []byte{235, 165, 125, 82, 28, 116, 21, 133, 243, 222, 241, 20, 134}) 53 | doTest([]byte{173, 151, 109, 88, 104, 65, 76, 111, 219, 237, 2, 173, 25, 84, 98, 16, 135, 157, 14, 194, 228, 86, 167, 187, 137, 245, 144, 61, 200, 76, 188, 117, 223, 172, 16, 116, 84, 1, 203, 173, 170, 32, 135, 67, 16}, []byte{150, 31, 11, 211, 82, 221, 251, 84, 254, 121, 68, 34, 211, 142, 197, 246, 138, 204, 60, 197, 210, 238, 142, 234, 187, 200, 179, 228}) 54 | doTest([]byte{171, 185, 30, 162, 129, 205, 254, 186, 86, 239, 178, 206, 115, 177, 14, 166, 143, 48, 141, 205, 109, 67, 238, 187, 134, 210, 96, 23, 195, 206, 100, 171, 156, 8, 229, 131, 169, 169, 59, 167, 224, 241, 185, 132, 162, 50, 87, 252, 156, 122, 248, 19, 130, 31, 127}, []byte{62, 42, 216, 109, 23, 176, 255, 137, 139, 90, 7, 186, 175, 243, 160, 206, 37, 94, 157, 217, 11, 169, 126, 41, 73, 133, 212, 232, 249, 117, 70, 147, 137, 156, 43, 243, 234, 155, 94, 38, 59, 211, 218, 165, 3, 33, 231, 237, 92, 16, 128}) 55 | doTest([]byte{98, 28, 174, 108, 231, 247, 135, 139, 6, 50, 107, 203, 138, 252, 229, 245, 230, 236, 124, 138, 105, 25, 83, 122}, []byte{97, 214, 25, 2, 14, 48, 65, 212, 241, 200, 81, 57, 176, 59, 16, 55, 20, 91, 66}) 56 | doTest([]byte{73, 214, 80, 41, 125, 136, 126, 184, 70, 141, 140, 58, 249, 250, 49, 249, 155, 0, 236, 49, 17, 125, 18, 29}, []byte{128, 16, 47, 235, 125, 128, 97, 245, 177, 210, 219, 195}) 57 | doTest([]byte{3, 220, 98, 73, 200, 52, 8, 107, 173, 177, 58, 221, 180, 226, 76, 210, 182, 88, 104, 171, 243, 129, 88, 112, 126, 83, 141, 50, 106, 204, 195, 51, 141, 75, 132, 161}, []byte{110, 178, 213, 174, 1, 241, 95}) 58 | doTest([]byte{196, 88, 50, 142, 76, 128, 190, 189, 76, 9, 228, 62, 198, 186, 180, 240, 62, 130, 132, 242}, []byte{244, 89, 17, 143, 3, 180, 150, 242, 167, 214, 209, 133, 120, 213, 173, 59, 25, 158, 251}) 59 | doTest([]byte{166, 214, 1, 225, 237, 7, 80, 104, 94, 170, 125, 184, 148, 16, 121, 101, 52, 216, 177, 192, 6, 132, 77, 44, 5, 9, 126, 156, 12, 2, 29, 99, 51, 78, 177, 92, 140, 107, 146, 183, 109, 227, 171, 57, 193, 14, 37}, []byte{245, 46, 189, 11, 202, 195, 89, 53, 215, 172, 132, 196, 145, 141, 239, 160, 242, 7, 85, 251, 193, 85}) 60 | } 61 | -------------------------------------------------------------------------------- /code128/encodingtable.go: -------------------------------------------------------------------------------- 1 | package code128 2 | 3 | var encodingTable = [107][]bool{ 4 | []bool{true, true, false, true, true, false, false, true, true, false, false}, 5 | []bool{true, true, false, false, true, true, false, true, true, false, false}, 6 | []bool{true, true, false, false, true, true, false, false, true, true, false}, 7 | []bool{true, false, false, true, false, false, true, true, false, false, false}, 8 | []bool{true, false, false, true, false, false, false, true, true, false, false}, 9 | []bool{true, false, false, false, true, false, false, true, true, false, false}, 10 | []bool{true, false, false, true, true, false, false, true, false, false, false}, 11 | []bool{true, false, false, true, true, false, false, false, true, false, false}, 12 | []bool{true, false, false, false, true, true, false, false, true, false, false}, 13 | []bool{true, true, false, false, true, false, false, true, false, false, false}, 14 | []bool{true, true, false, false, true, false, false, false, true, false, false}, 15 | []bool{true, true, false, false, false, true, false, false, true, false, false}, 16 | []bool{true, false, true, true, false, false, true, true, true, false, false}, 17 | []bool{true, false, false, true, true, false, true, true, true, false, false}, 18 | []bool{true, false, false, true, true, false, false, true, true, true, false}, 19 | []bool{true, false, true, true, true, false, false, true, true, false, false}, 20 | []bool{true, false, false, true, true, true, false, true, true, false, false}, 21 | []bool{true, false, false, true, true, true, false, false, true, true, false}, 22 | []bool{true, true, false, false, true, true, true, false, false, true, false}, 23 | []bool{true, true, false, false, true, false, true, true, true, false, false}, 24 | []bool{true, true, false, false, true, false, false, true, true, true, false}, 25 | []bool{true, true, false, true, true, true, false, false, true, false, false}, 26 | []bool{true, true, false, false, true, true, true, false, true, false, false}, 27 | []bool{true, true, true, false, true, true, false, true, true, true, false}, 28 | []bool{true, true, true, false, true, false, false, true, true, false, false}, 29 | []bool{true, true, true, false, false, true, false, true, true, false, false}, 30 | []bool{true, true, true, false, false, true, false, false, true, true, false}, 31 | []bool{true, true, true, false, true, true, false, false, true, false, false}, 32 | []bool{true, true, true, false, false, true, true, false, true, false, false}, 33 | []bool{true, true, true, false, false, true, true, false, false, true, false}, 34 | []bool{true, true, false, true, true, false, true, true, false, false, false}, 35 | []bool{true, true, false, true, true, false, false, false, true, true, false}, 36 | []bool{true, true, false, false, false, true, true, false, true, true, false}, 37 | []bool{true, false, true, false, false, false, true, true, false, false, false}, 38 | []bool{true, false, false, false, true, false, true, true, false, false, false}, 39 | []bool{true, false, false, false, true, false, false, false, true, true, false}, 40 | []bool{true, false, true, true, false, false, false, true, false, false, false}, 41 | []bool{true, false, false, false, true, true, false, true, false, false, false}, 42 | []bool{true, false, false, false, true, true, false, false, false, true, false}, 43 | []bool{true, true, false, true, false, false, false, true, false, false, false}, 44 | []bool{true, true, false, false, false, true, false, true, false, false, false}, 45 | []bool{true, true, false, false, false, true, false, false, false, true, false}, 46 | []bool{true, false, true, true, false, true, true, true, false, false, false}, 47 | []bool{true, false, true, true, false, false, false, true, true, true, false}, 48 | []bool{true, false, false, false, true, true, false, true, true, true, false}, 49 | []bool{true, false, true, true, true, false, true, true, false, false, false}, 50 | []bool{true, false, true, true, true, false, false, false, true, true, false}, 51 | []bool{true, false, false, false, true, true, true, false, true, true, false}, 52 | []bool{true, true, true, false, true, true, true, false, true, true, false}, 53 | []bool{true, true, false, true, false, false, false, true, true, true, false}, 54 | []bool{true, true, false, false, false, true, false, true, true, true, false}, 55 | []bool{true, true, false, true, true, true, false, true, false, false, false}, 56 | []bool{true, true, false, true, true, true, false, false, false, true, false}, 57 | []bool{true, true, false, true, true, true, false, true, true, true, false}, 58 | []bool{true, true, true, false, true, false, true, true, false, false, false}, 59 | []bool{true, true, true, false, true, false, false, false, true, true, false}, 60 | []bool{true, true, true, false, false, false, true, false, true, true, false}, 61 | []bool{true, true, true, false, true, true, false, true, false, false, false}, 62 | []bool{true, true, true, false, true, true, false, false, false, true, false}, 63 | []bool{true, true, true, false, false, false, true, true, false, true, false}, 64 | []bool{true, true, true, false, true, true, true, true, false, true, false}, 65 | []bool{true, true, false, false, true, false, false, false, false, true, false}, 66 | []bool{true, true, true, true, false, false, false, true, false, true, false}, 67 | []bool{true, false, true, false, false, true, true, false, false, false, false}, 68 | []bool{true, false, true, false, false, false, false, true, true, false, false}, 69 | []bool{true, false, false, true, false, true, true, false, false, false, false}, 70 | []bool{true, false, false, true, false, false, false, false, true, true, false}, 71 | []bool{true, false, false, false, false, true, false, true, true, false, false}, 72 | []bool{true, false, false, false, false, true, false, false, true, true, false}, 73 | []bool{true, false, true, true, false, false, true, false, false, false, false}, 74 | []bool{true, false, true, true, false, false, false, false, true, false, false}, 75 | []bool{true, false, false, true, true, false, true, false, false, false, false}, 76 | []bool{true, false, false, true, true, false, false, false, false, true, false}, 77 | []bool{true, false, false, false, false, true, true, false, true, false, false}, 78 | []bool{true, false, false, false, false, true, true, false, false, true, false}, 79 | []bool{true, true, false, false, false, false, true, false, false, true, false}, 80 | []bool{true, true, false, false, true, false, true, false, false, false, false}, 81 | []bool{true, true, true, true, false, true, true, true, false, true, false}, 82 | []bool{true, true, false, false, false, false, true, false, true, false, false}, 83 | []bool{true, false, false, false, true, true, true, true, false, true, false}, 84 | []bool{true, false, true, false, false, true, true, true, true, false, false}, 85 | []bool{true, false, false, true, false, true, true, true, true, false, false}, 86 | []bool{true, false, false, true, false, false, true, true, true, true, false}, 87 | []bool{true, false, true, true, true, true, false, false, true, false, false}, 88 | []bool{true, false, false, true, true, true, true, false, true, false, false}, 89 | []bool{true, false, false, true, true, true, true, false, false, true, false}, 90 | []bool{true, true, true, true, false, true, false, false, true, false, false}, 91 | []bool{true, true, true, true, false, false, true, false, true, false, false}, 92 | []bool{true, true, true, true, false, false, true, false, false, true, false}, 93 | []bool{true, true, false, true, true, false, true, true, true, true, false}, 94 | []bool{true, true, false, true, true, true, true, false, true, true, false}, 95 | []bool{true, true, true, true, false, true, true, false, true, true, false}, 96 | []bool{true, false, true, false, true, true, true, true, false, false, false}, 97 | []bool{true, false, true, false, false, false, true, true, true, true, false}, 98 | []bool{true, false, false, false, true, false, true, true, true, true, false}, 99 | []bool{true, false, true, true, true, true, false, true, false, false, false}, 100 | []bool{true, false, true, true, true, true, false, false, false, true, false}, 101 | []bool{true, true, true, true, false, true, false, true, false, false, false}, 102 | []bool{true, true, true, true, false, true, false, false, false, true, false}, 103 | []bool{true, false, true, true, true, false, true, true, true, true, false}, 104 | []bool{true, false, true, true, true, true, false, true, true, true, false}, 105 | []bool{true, true, true, false, true, false, true, true, true, true, false}, 106 | []bool{true, true, true, true, false, true, false, true, true, true, false}, 107 | []bool{true, true, false, true, false, false, false, false, true, false, false}, 108 | []bool{true, true, false, true, false, false, true, false, false, false, false}, 109 | []bool{true, true, false, true, false, false, true, true, true, false, false}, 110 | []bool{true, true, false, false, false, true, true, true, false, true, false, true, true}, 111 | } 112 | 113 | const startASymbol byte = 103 114 | const startBSymbol byte = 104 115 | const startCSymbol byte = 105 116 | 117 | const codeASymbol byte = 101 118 | const codeBSymbol byte = 100 119 | const codeCSymbol byte = 99 120 | 121 | const stopSymbol byte = 106 122 | 123 | const ( 124 | // FNC1 - Special Function 1 125 | FNC1 = '\u00f1' 126 | // FNC2 - Special Function 2 127 | FNC2 = '\u00f2' 128 | // FNC3 - Special Function 3 129 | FNC3 = '\u00f3' 130 | // FNC4 - Special Function 4 131 | FNC4 = '\u00f4' 132 | ) 133 | 134 | const abTable = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" 135 | const bTable = abTable + "`abcdefghijklmnopqrstuvwxyz{|}~\u007F" 136 | const aOnlyTable = "\u0000\u0001\u0002\u0003\u0004" + // NUL, SOH, STX, ETX, EOT 137 | "\u0005\u0006\u0007\u0008\u0009" + // ENQ, ACK, BEL, BS, HT 138 | "\u000A\u000B\u000C\u000D\u000E" + // LF, VT, FF, CR, SO 139 | "\u000F\u0010\u0011\u0012\u0013" + // SI, DLE, DC1, DC2, DC3 140 | "\u0014\u0015\u0016\u0017\u0018" + // DC4, NAK, SYN, ETB, CAN 141 | "\u0019\u001A\u001B\u001C\u001D" + // EM, SUB, ESC, FS, GS 142 | "\u001E\u001F" // RS, US 143 | const aTable = abTable + aOnlyTable 144 | -------------------------------------------------------------------------------- /qr/versioninfo.go: -------------------------------------------------------------------------------- 1 | package qr 2 | 3 | import "math" 4 | 5 | // ErrorCorrectionLevel indicates the amount of "backup data" stored in the QR code 6 | type ErrorCorrectionLevel byte 7 | 8 | const ( 9 | // L recovers 7% of data 10 | L ErrorCorrectionLevel = iota 11 | // M recovers 15% of data 12 | M 13 | // Q recovers 25% of data 14 | Q 15 | // H recovers 30% of data 16 | H 17 | ) 18 | 19 | func (ecl ErrorCorrectionLevel) String() string { 20 | switch ecl { 21 | case L: 22 | return "L" 23 | case M: 24 | return "M" 25 | case Q: 26 | return "Q" 27 | case H: 28 | return "H" 29 | } 30 | return "unknown" 31 | } 32 | 33 | type encodingMode byte 34 | 35 | const ( 36 | numericMode encodingMode = 1 37 | alphaNumericMode encodingMode = 2 38 | byteMode encodingMode = 4 39 | kanjiMode encodingMode = 8 40 | ) 41 | 42 | type versionInfo struct { 43 | Version byte 44 | Level ErrorCorrectionLevel 45 | ErrorCorrectionCodewordsPerBlock byte 46 | NumberOfBlocksInGroup1 byte 47 | DataCodeWordsPerBlockInGroup1 byte 48 | NumberOfBlocksInGroup2 byte 49 | DataCodeWordsPerBlockInGroup2 byte 50 | } 51 | 52 | var versionInfos = []*versionInfo{ 53 | &versionInfo{1, L, 7, 1, 19, 0, 0}, 54 | &versionInfo{1, M, 10, 1, 16, 0, 0}, 55 | &versionInfo{1, Q, 13, 1, 13, 0, 0}, 56 | &versionInfo{1, H, 17, 1, 9, 0, 0}, 57 | &versionInfo{2, L, 10, 1, 34, 0, 0}, 58 | &versionInfo{2, M, 16, 1, 28, 0, 0}, 59 | &versionInfo{2, Q, 22, 1, 22, 0, 0}, 60 | &versionInfo{2, H, 28, 1, 16, 0, 0}, 61 | &versionInfo{3, L, 15, 1, 55, 0, 0}, 62 | &versionInfo{3, M, 26, 1, 44, 0, 0}, 63 | &versionInfo{3, Q, 18, 2, 17, 0, 0}, 64 | &versionInfo{3, H, 22, 2, 13, 0, 0}, 65 | &versionInfo{4, L, 20, 1, 80, 0, 0}, 66 | &versionInfo{4, M, 18, 2, 32, 0, 0}, 67 | &versionInfo{4, Q, 26, 2, 24, 0, 0}, 68 | &versionInfo{4, H, 16, 4, 9, 0, 0}, 69 | &versionInfo{5, L, 26, 1, 108, 0, 0}, 70 | &versionInfo{5, M, 24, 2, 43, 0, 0}, 71 | &versionInfo{5, Q, 18, 2, 15, 2, 16}, 72 | &versionInfo{5, H, 22, 2, 11, 2, 12}, 73 | &versionInfo{6, L, 18, 2, 68, 0, 0}, 74 | &versionInfo{6, M, 16, 4, 27, 0, 0}, 75 | &versionInfo{6, Q, 24, 4, 19, 0, 0}, 76 | &versionInfo{6, H, 28, 4, 15, 0, 0}, 77 | &versionInfo{7, L, 20, 2, 78, 0, 0}, 78 | &versionInfo{7, M, 18, 4, 31, 0, 0}, 79 | &versionInfo{7, Q, 18, 2, 14, 4, 15}, 80 | &versionInfo{7, H, 26, 4, 13, 1, 14}, 81 | &versionInfo{8, L, 24, 2, 97, 0, 0}, 82 | &versionInfo{8, M, 22, 2, 38, 2, 39}, 83 | &versionInfo{8, Q, 22, 4, 18, 2, 19}, 84 | &versionInfo{8, H, 26, 4, 14, 2, 15}, 85 | &versionInfo{9, L, 30, 2, 116, 0, 0}, 86 | &versionInfo{9, M, 22, 3, 36, 2, 37}, 87 | &versionInfo{9, Q, 20, 4, 16, 4, 17}, 88 | &versionInfo{9, H, 24, 4, 12, 4, 13}, 89 | &versionInfo{10, L, 18, 2, 68, 2, 69}, 90 | &versionInfo{10, M, 26, 4, 43, 1, 44}, 91 | &versionInfo{10, Q, 24, 6, 19, 2, 20}, 92 | &versionInfo{10, H, 28, 6, 15, 2, 16}, 93 | &versionInfo{11, L, 20, 4, 81, 0, 0}, 94 | &versionInfo{11, M, 30, 1, 50, 4, 51}, 95 | &versionInfo{11, Q, 28, 4, 22, 4, 23}, 96 | &versionInfo{11, H, 24, 3, 12, 8, 13}, 97 | &versionInfo{12, L, 24, 2, 92, 2, 93}, 98 | &versionInfo{12, M, 22, 6, 36, 2, 37}, 99 | &versionInfo{12, Q, 26, 4, 20, 6, 21}, 100 | &versionInfo{12, H, 28, 7, 14, 4, 15}, 101 | &versionInfo{13, L, 26, 4, 107, 0, 0}, 102 | &versionInfo{13, M, 22, 8, 37, 1, 38}, 103 | &versionInfo{13, Q, 24, 8, 20, 4, 21}, 104 | &versionInfo{13, H, 22, 12, 11, 4, 12}, 105 | &versionInfo{14, L, 30, 3, 115, 1, 116}, 106 | &versionInfo{14, M, 24, 4, 40, 5, 41}, 107 | &versionInfo{14, Q, 20, 11, 16, 5, 17}, 108 | &versionInfo{14, H, 24, 11, 12, 5, 13}, 109 | &versionInfo{15, L, 22, 5, 87, 1, 88}, 110 | &versionInfo{15, M, 24, 5, 41, 5, 42}, 111 | &versionInfo{15, Q, 30, 5, 24, 7, 25}, 112 | &versionInfo{15, H, 24, 11, 12, 7, 13}, 113 | &versionInfo{16, L, 24, 5, 98, 1, 99}, 114 | &versionInfo{16, M, 28, 7, 45, 3, 46}, 115 | &versionInfo{16, Q, 24, 15, 19, 2, 20}, 116 | &versionInfo{16, H, 30, 3, 15, 13, 16}, 117 | &versionInfo{17, L, 28, 1, 107, 5, 108}, 118 | &versionInfo{17, M, 28, 10, 46, 1, 47}, 119 | &versionInfo{17, Q, 28, 1, 22, 15, 23}, 120 | &versionInfo{17, H, 28, 2, 14, 17, 15}, 121 | &versionInfo{18, L, 30, 5, 120, 1, 121}, 122 | &versionInfo{18, M, 26, 9, 43, 4, 44}, 123 | &versionInfo{18, Q, 28, 17, 22, 1, 23}, 124 | &versionInfo{18, H, 28, 2, 14, 19, 15}, 125 | &versionInfo{19, L, 28, 3, 113, 4, 114}, 126 | &versionInfo{19, M, 26, 3, 44, 11, 45}, 127 | &versionInfo{19, Q, 26, 17, 21, 4, 22}, 128 | &versionInfo{19, H, 26, 9, 13, 16, 14}, 129 | &versionInfo{20, L, 28, 3, 107, 5, 108}, 130 | &versionInfo{20, M, 26, 3, 41, 13, 42}, 131 | &versionInfo{20, Q, 30, 15, 24, 5, 25}, 132 | &versionInfo{20, H, 28, 15, 15, 10, 16}, 133 | &versionInfo{21, L, 28, 4, 116, 4, 117}, 134 | &versionInfo{21, M, 26, 17, 42, 0, 0}, 135 | &versionInfo{21, Q, 28, 17, 22, 6, 23}, 136 | &versionInfo{21, H, 30, 19, 16, 6, 17}, 137 | &versionInfo{22, L, 28, 2, 111, 7, 112}, 138 | &versionInfo{22, M, 28, 17, 46, 0, 0}, 139 | &versionInfo{22, Q, 30, 7, 24, 16, 25}, 140 | &versionInfo{22, H, 24, 34, 13, 0, 0}, 141 | &versionInfo{23, L, 30, 4, 121, 5, 122}, 142 | &versionInfo{23, M, 28, 4, 47, 14, 48}, 143 | &versionInfo{23, Q, 30, 11, 24, 14, 25}, 144 | &versionInfo{23, H, 30, 16, 15, 14, 16}, 145 | &versionInfo{24, L, 30, 6, 117, 4, 118}, 146 | &versionInfo{24, M, 28, 6, 45, 14, 46}, 147 | &versionInfo{24, Q, 30, 11, 24, 16, 25}, 148 | &versionInfo{24, H, 30, 30, 16, 2, 17}, 149 | &versionInfo{25, L, 26, 8, 106, 4, 107}, 150 | &versionInfo{25, M, 28, 8, 47, 13, 48}, 151 | &versionInfo{25, Q, 30, 7, 24, 22, 25}, 152 | &versionInfo{25, H, 30, 22, 15, 13, 16}, 153 | &versionInfo{26, L, 28, 10, 114, 2, 115}, 154 | &versionInfo{26, M, 28, 19, 46, 4, 47}, 155 | &versionInfo{26, Q, 28, 28, 22, 6, 23}, 156 | &versionInfo{26, H, 30, 33, 16, 4, 17}, 157 | &versionInfo{27, L, 30, 8, 122, 4, 123}, 158 | &versionInfo{27, M, 28, 22, 45, 3, 46}, 159 | &versionInfo{27, Q, 30, 8, 23, 26, 24}, 160 | &versionInfo{27, H, 30, 12, 15, 28, 16}, 161 | &versionInfo{28, L, 30, 3, 117, 10, 118}, 162 | &versionInfo{28, M, 28, 3, 45, 23, 46}, 163 | &versionInfo{28, Q, 30, 4, 24, 31, 25}, 164 | &versionInfo{28, H, 30, 11, 15, 31, 16}, 165 | &versionInfo{29, L, 30, 7, 116, 7, 117}, 166 | &versionInfo{29, M, 28, 21, 45, 7, 46}, 167 | &versionInfo{29, Q, 30, 1, 23, 37, 24}, 168 | &versionInfo{29, H, 30, 19, 15, 26, 16}, 169 | &versionInfo{30, L, 30, 5, 115, 10, 116}, 170 | &versionInfo{30, M, 28, 19, 47, 10, 48}, 171 | &versionInfo{30, Q, 30, 15, 24, 25, 25}, 172 | &versionInfo{30, H, 30, 23, 15, 25, 16}, 173 | &versionInfo{31, L, 30, 13, 115, 3, 116}, 174 | &versionInfo{31, M, 28, 2, 46, 29, 47}, 175 | &versionInfo{31, Q, 30, 42, 24, 1, 25}, 176 | &versionInfo{31, H, 30, 23, 15, 28, 16}, 177 | &versionInfo{32, L, 30, 17, 115, 0, 0}, 178 | &versionInfo{32, M, 28, 10, 46, 23, 47}, 179 | &versionInfo{32, Q, 30, 10, 24, 35, 25}, 180 | &versionInfo{32, H, 30, 19, 15, 35, 16}, 181 | &versionInfo{33, L, 30, 17, 115, 1, 116}, 182 | &versionInfo{33, M, 28, 14, 46, 21, 47}, 183 | &versionInfo{33, Q, 30, 29, 24, 19, 25}, 184 | &versionInfo{33, H, 30, 11, 15, 46, 16}, 185 | &versionInfo{34, L, 30, 13, 115, 6, 116}, 186 | &versionInfo{34, M, 28, 14, 46, 23, 47}, 187 | &versionInfo{34, Q, 30, 44, 24, 7, 25}, 188 | &versionInfo{34, H, 30, 59, 16, 1, 17}, 189 | &versionInfo{35, L, 30, 12, 121, 7, 122}, 190 | &versionInfo{35, M, 28, 12, 47, 26, 48}, 191 | &versionInfo{35, Q, 30, 39, 24, 14, 25}, 192 | &versionInfo{35, H, 30, 22, 15, 41, 16}, 193 | &versionInfo{36, L, 30, 6, 121, 14, 122}, 194 | &versionInfo{36, M, 28, 6, 47, 34, 48}, 195 | &versionInfo{36, Q, 30, 46, 24, 10, 25}, 196 | &versionInfo{36, H, 30, 2, 15, 64, 16}, 197 | &versionInfo{37, L, 30, 17, 122, 4, 123}, 198 | &versionInfo{37, M, 28, 29, 46, 14, 47}, 199 | &versionInfo{37, Q, 30, 49, 24, 10, 25}, 200 | &versionInfo{37, H, 30, 24, 15, 46, 16}, 201 | &versionInfo{38, L, 30, 4, 122, 18, 123}, 202 | &versionInfo{38, M, 28, 13, 46, 32, 47}, 203 | &versionInfo{38, Q, 30, 48, 24, 14, 25}, 204 | &versionInfo{38, H, 30, 42, 15, 32, 16}, 205 | &versionInfo{39, L, 30, 20, 117, 4, 118}, 206 | &versionInfo{39, M, 28, 40, 47, 7, 48}, 207 | &versionInfo{39, Q, 30, 43, 24, 22, 25}, 208 | &versionInfo{39, H, 30, 10, 15, 67, 16}, 209 | &versionInfo{40, L, 30, 19, 118, 6, 119}, 210 | &versionInfo{40, M, 28, 18, 47, 31, 48}, 211 | &versionInfo{40, Q, 30, 34, 24, 34, 25}, 212 | &versionInfo{40, H, 30, 20, 15, 61, 16}, 213 | } 214 | 215 | func (vi *versionInfo) totalDataBytes() int { 216 | g1Data := int(vi.NumberOfBlocksInGroup1) * int(vi.DataCodeWordsPerBlockInGroup1) 217 | g2Data := int(vi.NumberOfBlocksInGroup2) * int(vi.DataCodeWordsPerBlockInGroup2) 218 | return (g1Data + g2Data) 219 | } 220 | 221 | func (vi *versionInfo) charCountBits(m encodingMode) byte { 222 | switch m { 223 | case numericMode: 224 | if vi.Version < 10 { 225 | return 10 226 | } else if vi.Version < 27 { 227 | return 12 228 | } 229 | return 14 230 | 231 | case alphaNumericMode: 232 | if vi.Version < 10 { 233 | return 9 234 | } else if vi.Version < 27 { 235 | return 11 236 | } 237 | return 13 238 | 239 | case byteMode: 240 | if vi.Version < 10 { 241 | return 8 242 | } 243 | return 16 244 | 245 | case kanjiMode: 246 | if vi.Version < 10 { 247 | return 8 248 | } else if vi.Version < 27 { 249 | return 10 250 | } 251 | return 12 252 | default: 253 | return 0 254 | } 255 | } 256 | 257 | func (vi *versionInfo) modulWidth() int { 258 | return ((int(vi.Version) - 1) * 4) + 21 259 | } 260 | 261 | func (vi *versionInfo) alignmentPatternPlacements() []int { 262 | if vi.Version == 1 { 263 | return make([]int, 0) 264 | } 265 | 266 | first := 6 267 | last := vi.modulWidth() - 7 268 | space := float64(last - first) 269 | count := int(math.Ceil(space/28)) + 1 270 | 271 | result := make([]int, count) 272 | result[0] = first 273 | result[len(result)-1] = last 274 | if count > 2 { 275 | step := int(math.Ceil(float64(last-first) / float64(count-1))) 276 | if step%2 == 1 { 277 | frac := float64(last-first) / float64(count-1) 278 | _, x := math.Modf(frac) 279 | if x >= 0.5 { 280 | frac = math.Ceil(frac) 281 | } else { 282 | frac = math.Floor(frac) 283 | } 284 | 285 | if int(frac)%2 == 0 { 286 | step-- 287 | } else { 288 | step++ 289 | } 290 | } 291 | 292 | for i := 1; i <= count-2; i++ { 293 | result[i] = last - (step * (count - 1 - i)) 294 | } 295 | } 296 | 297 | return result 298 | } 299 | 300 | func findSmallestVersionInfo(ecl ErrorCorrectionLevel, mode encodingMode, dataBits int) *versionInfo { 301 | dataBits = dataBits + 4 // mode indicator 302 | for _, vi := range versionInfos { 303 | if vi.Level == ecl { 304 | if (vi.totalDataBytes() * 8) >= (dataBits + int(vi.charCountBits(mode))) { 305 | return vi 306 | } 307 | } 308 | } 309 | return nil 310 | } 311 | --------------------------------------------------------------------------------