123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- // Package pdf417 can create PDF-417 barcodes
- package pdf417
- import (
- "fmt"
- "github.com/boombuler/barcode"
- "github.com/boombuler/barcode/utils"
- )
- const (
- padding_codeword = 900
- )
- // Encodes the given data as PDF417 barcode.
- // securityLevel should be between 0 and 8. The higher the number, the more
- // additional error-correction codes are added.
- func Encode(data string, securityLevel byte) (barcode.Barcode, error) {
- if securityLevel >= 9 {
- return nil, fmt.Errorf("Invalid security level %d", securityLevel)
- }
- sl := securitylevel(securityLevel)
- dataWords, err := highlevelEncode(data)
- if err != nil {
- return nil, err
- }
- columns, rows := calcDimensions(len(dataWords), sl.ErrorCorrectionWordCount())
- if columns < minCols || columns > maxCols || rows < minRows || rows > maxRows {
- return nil, fmt.Errorf("Unable to fit data in barcode")
- }
- barcode := new(pdfBarcode)
- barcode.data = data
- codeWords, err := encodeData(dataWords, columns, sl)
- if err != nil {
- return nil, err
- }
- grid := [][]int{}
- for i := 0; i < len(codeWords); i += columns {
- grid = append(grid, codeWords[i:min(i+columns, len(codeWords))])
- }
- codes := [][]int{}
- for rowNum, row := range grid {
- table := rowNum % 3
- rowCodes := make([]int, 0, columns+4)
- rowCodes = append(rowCodes, start_word)
- rowCodes = append(rowCodes, getCodeword(table, getLeftCodeWord(rowNum, rows, columns, securityLevel)))
- for _, word := range row {
- rowCodes = append(rowCodes, getCodeword(table, word))
- }
- rowCodes = append(rowCodes, getCodeword(table, getRightCodeWord(rowNum, rows, columns, securityLevel)))
- rowCodes = append(rowCodes, stop_word)
- codes = append(codes, rowCodes)
- }
- barcode.code = renderBarcode(codes)
- barcode.width = (columns+4)*17 + 1
- return barcode, nil
- }
- func encodeData(dataWords []int, columns int, sl securitylevel) ([]int, error) {
- dataCount := len(dataWords)
- ecCount := sl.ErrorCorrectionWordCount()
- padWords := getPadding(dataCount, ecCount, columns)
- dataWords = append(dataWords, padWords...)
- length := len(dataWords) + 1
- dataWords = append([]int{length}, dataWords...)
- ecWords := sl.Compute(dataWords)
- return append(dataWords, ecWords...), nil
- }
- func getLeftCodeWord(rowNum int, rows int, columns int, securityLevel byte) int {
- tableId := rowNum % 3
- var x int
- switch tableId {
- case 0:
- x = (rows - 3) / 3
- case 1:
- x = int(securityLevel) * 3
- x += (rows - 1) % 3
- case 2:
- x = columns - 1
- }
- return 30*(rowNum/3) + x
- }
- func getRightCodeWord(rowNum int, rows int, columns int, securityLevel byte) int {
- tableId := rowNum % 3
- var x int
- switch tableId {
- case 0:
- x = columns - 1
- case 1:
- x = (rows - 1) / 3
- case 2:
- x = int(securityLevel) * 3
- x += (rows - 1) % 3
- }
- return 30*(rowNum/3) + x
- }
- func min(a, b int) int {
- if a <= b {
- return a
- }
- return b
- }
- func getPadding(dataCount int, ecCount int, columns int) []int {
- totalCount := dataCount + ecCount + 1
- mod := totalCount % columns
- padding := []int{}
- if mod > 0 {
- padCount := columns - mod
- padding = make([]int, padCount)
- for i := 0; i < padCount; i++ {
- padding[i] = padding_codeword
- }
- }
- return padding
- }
- func renderBarcode(codes [][]int) *utils.BitList {
- bl := new(utils.BitList)
- for _, row := range codes {
- lastIdx := len(row) - 1
- for i, col := range row {
- if i == lastIdx {
- bl.AddBits(col, 18)
- } else {
- bl.AddBits(col, 17)
- }
- }
- }
- return bl
- }
|