summaryrefslogtreecommitdiff
path: root/vendor/github.com/boombuler/barcode/code128/encode.go
blob: 757347ed48ecbb69fce7c6772b8b4c7e9b7bde9e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Package code128 can create Code128 barcodes
package code128

import (
	"fmt"
	"strings"
	"unicode/utf8"

	"github.com/boombuler/barcode"
	"github.com/boombuler/barcode/utils"
)

func strToRunes(str string) []rune {
	result := make([]rune, utf8.RuneCountInString(str))
	i := 0
	for _, r := range str {
		result[i] = r
		i++
	}
	return result
}

func shouldUseCTable(nextRunes []rune, curEncoding byte) bool {
	requiredDigits := 4
	if curEncoding == startCSymbol {
		requiredDigits = 2
	}
	if len(nextRunes) < requiredDigits {
		return false
	}
	for i := 0; i < requiredDigits; i++ {
		if i%2 == 0 && nextRunes[i] == FNC1 {
			requiredDigits++
			if len(nextRunes) < requiredDigits {
				return false
			}
			continue
		}
		if nextRunes[i] < '0' || nextRunes[i] > '9' {
			return false
		}
	}
	return true
}

func getCodeIndexList(content []rune) *utils.BitList {
	result := new(utils.BitList)
	curEncoding := byte(0)
	for i := 0; i < len(content); i++ {
		if shouldUseCTable(content[i:], curEncoding) {
			if curEncoding != startCSymbol {
				if curEncoding == byte(0) {
					result.AddByte(startCSymbol)
				} else {
					result.AddByte(codeCSymbol)
				}
				curEncoding = startCSymbol
			}
			if content[i] == FNC1 {
				result.AddByte(102)
			} else {

				idx := (content[i] - '0') * 10
				i++
				idx = idx + (content[i] - '0')
				result.AddByte(byte(idx))
			}
		} else {
			if curEncoding != startBSymbol {
				if curEncoding == byte(0) {
					result.AddByte(startBSymbol)
				} else {
					result.AddByte(codeBSymbol)
				}
				curEncoding = startBSymbol
			}
			var idx int
			switch content[i] {
			case FNC1:
				idx = 102
				break
			case FNC2:
				idx = 97
				break
			case FNC3:
				idx = 96
				break
			case FNC4:
				idx = 100
				break
			default:
				idx = strings.IndexRune(bTable, content[i])
				break
			}

			if idx < 0 {
				return nil
			}
			result.AddByte(byte(idx))
		}
	}
	return result
}

// Encode creates a Code 128 barcode for the given content
func Encode(content string) (barcode.Barcode, error) {
	contentRunes := strToRunes(content)
	if len(contentRunes) <= 0 || len(contentRunes) > 80 {
		return nil, fmt.Errorf("content length should be between 1 and 80 runes but got %d", len(contentRunes))
	}
	idxList := getCodeIndexList(contentRunes)

	if idxList == nil {
		return nil, fmt.Errorf("\"%s\" could not be encoded", content)
	}

	result := new(utils.BitList)
	sum := 0
	for i, idx := range idxList.GetBytes() {
		if i == 0 {
			sum = int(idx)
		} else {
			sum += i * int(idx)
		}
		result.AddBit(encodingTable[idx]...)
	}
	result.AddBit(encodingTable[sum%103]...)
	result.AddBit(encodingTable[stopSymbol]...)
	return utils.New1DCode("Code 128", content, result, sum%103), nil
}