-
Notifications
You must be signed in to change notification settings - Fork 0
/
barcode.go
298 lines (289 loc) · 9.3 KB
/
barcode.go
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
package barcode
import (
"fmt"
"image"
"image/color"
"strings"
"github.com/LLKennedy/imagetemplate/v3/render"
"github.com/boombuler/barcode/qr"
"golang.org/x/tools/godoc/vfs"
)
// Component implements the Component interface for images
type Component struct {
NamedPropertiesMap map[string][]string
Content string
Type render.BarcodeType
TopLeft image.Point
Width int
Height int
DataColour color.NRGBA
BackgroundColour color.NRGBA
Extra render.BarcodeExtraData
}
type barcodeFormat struct {
Content string `json:"content"`
Type string `json:"barcodeType"`
TopLeftX string `json:"topLeftX"`
TopLeftY string `json:"topLeftY"`
Width string `json:"width"`
Height string `json:"height"`
DataColour struct {
Red string `json:"R"`
Green string `json:"G"`
Blue string `json:"B"`
Alpha string `json:"A"`
} `json:"dataColour"`
BackgroundColour struct {
Red string `json:"R"`
Green string `json:"G"`
Blue string `json:"B"`
Alpha string `json:"A"`
} `json:"backgroundColour"`
}
// Write draws a barcode on the canvas
func (component Component) Write(canvas render.Canvas) (render.Canvas, error) {
if len(component.NamedPropertiesMap) != 0 {
return canvas, fmt.Errorf("cannot draw barcode, not all named properties are set: %v", component.NamedPropertiesMap)
}
c := canvas
var err error
c, err = c.Barcode(component.Type, []byte(component.Content), component.Extra, component.TopLeft, component.Width, component.Height, component.DataColour, component.BackgroundColour)
if err != nil {
return canvas, err
}
return c, nil
}
// SetNamedProperties proceses the named properties and sets them into the barcode properties
func (component Component) SetNamedProperties(properties render.NamedProperties) (render.Component, error) {
c := component
setFunc := func(name string, value interface{}) error {
switch name {
case "content":
stringVal, ok := value.(string)
if !ok {
return fmt.Errorf("error converting %v to string", value)
}
c.Content = stringVal
return nil
case "barcodeType":
stringVal, ok := value.(render.BarcodeType)
if !ok {
return fmt.Errorf("error converting %v to barcode type", value)
}
c.Extra = render.BarcodeExtraData{}
switch stringVal {
case render.BarcodeType2of5:
case render.BarcodeType2of5Interleaved:
case render.BarcodeTypeAztec:
c.Extra.AztecMinECCPercent = 50 //TODO: get a beter value for this, or set it from the file
c.Extra.AztecUserSpecifiedLayers = 4 //TODO: get a better value for this, or set it from the file
case render.BarcodeTypeCodabar:
case render.BarcodeTypeCode128:
case render.BarcodeTypeCode39:
c.Extra.Code39IncludeChecksum = true
c.Extra.Code39FullASCIIMode = true
case render.BarcodeTypeCode93:
c.Extra.Code93IncludeChecksum = true
c.Extra.Code93FullASCIIMode = true
case render.BarcodeTypeDataMatrix:
case render.BarcodeTypeEAN13:
case render.BarcodeTypeEAN8:
case render.BarcodeTypePDF:
c.Extra.PDFSecurityLevel = 4 //TODO: get a better value for this, or set it from the file
case render.BarcodeTypeQR:
c.Extra.QRLevel = qr.Q
c.Extra.QRMode = qr.Unicode
}
c.Type = stringVal
return nil
}
if strings.Contains("dRdGdBdAbRbGbBbA", name) && len(name) == 2 {
//Process colours
colourVal, ok := value.(uint8)
if !ok {
return fmt.Errorf("error converting %v to uint8", value)
}
switch name {
case "dR":
c.DataColour.R = colourVal
return nil
case "dG":
c.DataColour.G = colourVal
return nil
case "dB":
c.DataColour.B = colourVal
return nil
case "dA":
c.DataColour.A = colourVal
return nil
case "bR":
c.BackgroundColour.R = colourVal
return nil
case "bG":
c.BackgroundColour.G = colourVal
return nil
case "bB":
c.BackgroundColour.B = colourVal
return nil
case "bA":
c.BackgroundColour.A = colourVal
return nil
default:
//What? How did you get here?
return fmt.Errorf("name was a string inside RGBA and Value was a valid uint8, but Name wasn't R, G, B, or A. Name was: %v", name)
}
}
numberVal, ok := value.(int)
if !ok {
return fmt.Errorf("error converting %v to int", value)
}
switch name {
case "topLeftX":
c.TopLeft.X = numberVal
return nil
case "topLeftY":
c.TopLeft.Y = numberVal
return nil
case "width":
c.Width = numberVal
return nil
case "height":
c.Height = numberVal
return nil
default:
return fmt.Errorf("invalid component property in named property map: %v", name)
}
}
var err error
c.NamedPropertiesMap, err = render.StandardSetNamedProperties(properties, component.NamedPropertiesMap, setFunc)
if err != nil {
return component, err
}
return c, nil
}
// GetJSONFormat returns the JSON structure of a barcode component
func (component Component) GetJSONFormat() interface{} {
return &barcodeFormat{}
}
// VerifyAndSetJSONData processes the data parsed from JSON and uses it to set barcode properties and fill the named properties map
func (component Component) VerifyAndSetJSONData(data interface{}) (render.Component, render.NamedProperties, error) {
c := component
props := make(render.NamedProperties)
stringStruct, ok := data.(*barcodeFormat)
if !ok {
return component, props, fmt.Errorf("failed to convert returned data to component properties")
}
// Get named properties and assign each real property
var newVal interface{}
var err error
c.NamedPropertiesMap, newVal, err = render.ExtractSingleProp(stringStruct.Type, "barcodeType", render.StringType, c.NamedPropertiesMap)
if err != nil {
return component, props, err
}
if newVal != nil {
c.Type, err = render.ToBarcodeType(newVal.(string))
if err != nil {
return component, props, fmt.Errorf("for barcode type %s: %v", newVal, err)
}
}
c.NamedPropertiesMap, newVal, err = render.ExtractSingleProp(stringStruct.Content, "content", render.StringType, c.NamedPropertiesMap)
if err != nil {
return component, props, err
}
if newVal != nil {
c.Content = newVal.(string)
}
c.NamedPropertiesMap, newVal, err = render.ExtractSingleProp(stringStruct.TopLeftX, "topLeftX", render.IntType, c.NamedPropertiesMap)
if err != nil {
return component, props, err
}
if newVal != nil {
c.TopLeft.X = newVal.(int)
}
c.NamedPropertiesMap, newVal, err = render.ExtractSingleProp(stringStruct.TopLeftY, "topLeftY", render.IntType, c.NamedPropertiesMap)
if err != nil {
return component, props, err
}
if newVal != nil {
c.TopLeft.Y = newVal.(int)
}
c.NamedPropertiesMap, newVal, err = render.ExtractSingleProp(stringStruct.Width, "width", render.IntType, c.NamedPropertiesMap)
if err != nil {
return component, props, err
}
if newVal != nil {
c.Width = newVal.(int)
}
c.NamedPropertiesMap, newVal, err = render.ExtractSingleProp(stringStruct.Height, "height", render.IntType, c.NamedPropertiesMap)
if err != nil {
return component, props, err
}
if newVal != nil {
c.Height = newVal.(int)
}
c.NamedPropertiesMap, newVal, err = render.ExtractSingleProp(stringStruct.DataColour.Red, "dR", render.Uint8Type, c.NamedPropertiesMap)
if err != nil {
return component, props, err
}
if newVal != nil {
c.DataColour.R = newVal.(uint8)
}
c.NamedPropertiesMap, newVal, err = render.ExtractSingleProp(stringStruct.DataColour.Green, "dG", render.Uint8Type, c.NamedPropertiesMap)
if err != nil {
return component, props, err
}
if newVal != nil {
c.DataColour.G = newVal.(uint8)
}
c.NamedPropertiesMap, newVal, err = render.ExtractSingleProp(stringStruct.DataColour.Blue, "dB", render.Uint8Type, c.NamedPropertiesMap)
if err != nil {
return component, props, err
}
if newVal != nil {
c.DataColour.B = newVal.(uint8)
}
c.NamedPropertiesMap, newVal, err = render.ExtractSingleProp(stringStruct.DataColour.Alpha, "dA", render.Uint8Type, c.NamedPropertiesMap)
if err != nil {
return component, props, err
}
if newVal != nil {
c.DataColour.A = newVal.(uint8)
}
c.NamedPropertiesMap, newVal, err = render.ExtractSingleProp(stringStruct.BackgroundColour.Red, "bR", render.Uint8Type, c.NamedPropertiesMap)
if err != nil {
return component, props, err
}
if newVal != nil {
c.BackgroundColour.R = newVal.(uint8)
}
c.NamedPropertiesMap, newVal, err = render.ExtractSingleProp(stringStruct.BackgroundColour.Green, "bG", render.Uint8Type, c.NamedPropertiesMap)
if err != nil {
return component, props, err
}
if newVal != nil {
c.BackgroundColour.G = newVal.(uint8)
}
c.NamedPropertiesMap, newVal, err = render.ExtractSingleProp(stringStruct.BackgroundColour.Blue, "bB", render.Uint8Type, c.NamedPropertiesMap)
if err != nil {
return component, props, err
}
if newVal != nil {
c.BackgroundColour.B = newVal.(uint8)
}
c.NamedPropertiesMap, newVal, err = render.ExtractSingleProp(stringStruct.BackgroundColour.Alpha, "bA", render.Uint8Type, c.NamedPropertiesMap)
if err != nil {
return component, props, err
}
if newVal != nil {
c.BackgroundColour.A = newVal.(uint8)
}
for key := range c.NamedPropertiesMap {
props[key] = struct{ Message string }{Message: "Please replace me with real data"}
}
return c, props, nil
}
func init() {
for _, name := range []string{"barcode", "bar", "code", "Barcode", "BARCODE", "BAR", "Bar Code", "bar code"} {
render.RegisterComponent(name, func(vfs.FileSystem) render.Component { return Component{} })
}
}