isahaq-barcode 1.8.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +107 -0
- package/LICENSE +21 -0
- package/README.md +319 -519
- package/bin/generate.js +171 -134
- package/browser.js +163 -170
- package/index.d.ts +497 -0
- package/index.js +118 -38
- package/package.json +68 -34
- package/src/builders/QrCodeBuilder.js +328 -165
- package/src/encoders/BarcodeEncoder.js +260 -0
- package/src/renderers/HTMLRenderer.js +36 -169
- package/src/renderers/PDFRenderer.js +108 -130
- package/src/renderers/PNGRenderer.js +7 -83
- package/src/renderers/RenderFormats.js +89 -38
- package/src/renderers/SVGRenderer.js +8 -182
- package/src/services/BarcodeService.js +96 -36
- package/src/types/BarcodeTypes.js +535 -144
- package/src/validators/Validator.js +140 -122
- package/.eslintrc.js +0 -29
- package/.prettierignore +0 -11
- package/.prettierrc +0 -11
- package/eslint.config.js +0 -67
- package/examples/basic-usage.js +0 -58
- package/examples/batch-example.json +0 -56
- package/examples/express-server.js +0 -163
- package/jest.config.js +0 -13
- package/tests/BarcodeGenerator.test.js +0 -187
- package/tests/BarcodeService.test.js +0 -76
- package/tests/QrCodeBuilder.test.js +0 -130
- package/tests/setup.js +0 -59
|
@@ -2,26 +2,11 @@
|
|
|
2
2
|
* SVG Renderer - Renders barcodes as SVG
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { BarcodeEncoder } = require('../encoders/BarcodeEncoder');
|
|
6
6
|
|
|
7
7
|
class SVGRenderer {
|
|
8
8
|
constructor() {
|
|
9
|
-
this.defaultOptions =
|
|
10
|
-
width: 2,
|
|
11
|
-
height: 100,
|
|
12
|
-
displayValue: true,
|
|
13
|
-
fontSize: 20,
|
|
14
|
-
textAlign: 'center',
|
|
15
|
-
textPosition: 'bottom',
|
|
16
|
-
textMargin: 2,
|
|
17
|
-
background: '#ffffff',
|
|
18
|
-
lineColor: '#000000',
|
|
19
|
-
margin: 10,
|
|
20
|
-
marginTop: 10,
|
|
21
|
-
marginBottom: 10,
|
|
22
|
-
marginLeft: 10,
|
|
23
|
-
marginRight: 10,
|
|
24
|
-
};
|
|
9
|
+
this.defaultOptions = BarcodeEncoder.getDefaultOptions();
|
|
25
10
|
}
|
|
26
11
|
|
|
27
12
|
/**
|
|
@@ -29,176 +14,17 @@ class SVGRenderer {
|
|
|
29
14
|
* @param {string} data - The data to encode
|
|
30
15
|
* @param {string} type - The barcode type
|
|
31
16
|
* @param {Object} options - Render options
|
|
32
|
-
* @returns {string} SVG
|
|
17
|
+
* @returns {string} SVG markup
|
|
33
18
|
*/
|
|
34
19
|
render(data, type, options = {}) {
|
|
35
20
|
try {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
// Create a temporary canvas element for JsBarcode
|
|
40
|
-
const canvas = document.createElement('canvas');
|
|
41
|
-
|
|
42
|
-
// Generate barcode using JsBarcode
|
|
43
|
-
JsBarcode(canvas, data, {
|
|
44
|
-
format: this.mapBarcodeType(type),
|
|
45
|
-
width: renderOptions.width,
|
|
46
|
-
height: renderOptions.height,
|
|
47
|
-
displayValue: renderOptions.displayValue,
|
|
48
|
-
fontSize: renderOptions.fontSize,
|
|
49
|
-
textAlign: renderOptions.textAlign,
|
|
50
|
-
textPosition: renderOptions.textPosition,
|
|
51
|
-
textMargin: renderOptions.textMargin,
|
|
52
|
-
background: renderOptions.background,
|
|
53
|
-
lineColor: renderOptions.lineColor,
|
|
54
|
-
margin: renderOptions.margin,
|
|
55
|
-
marginTop: renderOptions.marginTop,
|
|
56
|
-
marginBottom: renderOptions.marginBottom,
|
|
57
|
-
marginLeft: renderOptions.marginLeft,
|
|
58
|
-
marginRight: renderOptions.marginRight,
|
|
59
|
-
xmlDocument: this.createXMLDocument(),
|
|
21
|
+
return BarcodeEncoder.toSvg(data, type, {
|
|
22
|
+
...this.defaultOptions,
|
|
23
|
+
...options,
|
|
60
24
|
});
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const svgString = canvas.toSVG();
|
|
64
|
-
return svgString;
|
|
65
|
-
} catch {
|
|
66
|
-
// Fallback: create SVG manually
|
|
67
|
-
return this.createManualSVG(data, type, options);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Create SVG manually as fallback
|
|
73
|
-
* @param {string} data - The data to encode
|
|
74
|
-
* @param {string} type - The barcode type
|
|
75
|
-
* @param {Object} options - Render options
|
|
76
|
-
* @returns {string} SVG string
|
|
77
|
-
*/
|
|
78
|
-
createManualSVG(data, type, options = {}) {
|
|
79
|
-
const renderOptions = { ...this.defaultOptions, ...options };
|
|
80
|
-
|
|
81
|
-
// Simple SVG structure for basic barcodes
|
|
82
|
-
const width = 300;
|
|
83
|
-
const height = renderOptions.height + (renderOptions.displayValue ? 30 : 0);
|
|
84
|
-
|
|
85
|
-
let svg = `<svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg">`;
|
|
86
|
-
svg += `<rect width="${width}" height="${height}" fill="${renderOptions.background}"/>`;
|
|
87
|
-
|
|
88
|
-
// Add barcode representation (simplified)
|
|
89
|
-
if (type === 'qrcode') {
|
|
90
|
-
svg += this.createQRCodeSVG(data, width, height, renderOptions);
|
|
91
|
-
} else {
|
|
92
|
-
svg += this.createLinearBarcodeSVG(data, width, height, renderOptions);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Add text if displayValue is true
|
|
96
|
-
if (renderOptions.displayValue) {
|
|
97
|
-
svg += `<text x="${width / 2}" y="${
|
|
98
|
-
height - 5
|
|
99
|
-
}" text-anchor="middle" font-family="Arial" font-size="${
|
|
100
|
-
renderOptions.fontSize
|
|
101
|
-
}" fill="${renderOptions.lineColor}">${data}</text>`;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
svg += '</svg>';
|
|
105
|
-
return svg;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Create QR Code SVG representation
|
|
110
|
-
* @param {string} data - The data to encode
|
|
111
|
-
* @param {number} width - SVG width
|
|
112
|
-
* @param {number} height - SVG height
|
|
113
|
-
* @param {Object} options - Render options
|
|
114
|
-
* @returns {string} SVG content
|
|
115
|
-
*/
|
|
116
|
-
createQRCodeSVG(data, width, height, options) {
|
|
117
|
-
// This is a simplified representation
|
|
118
|
-
// In a real implementation, you would use a QR code library
|
|
119
|
-
const size = Math.min(width, height) - 40;
|
|
120
|
-
const x = (width - size) / 2;
|
|
121
|
-
const y = (height - size) / 2;
|
|
122
|
-
|
|
123
|
-
return `<rect x="${x}" y="${y}" width="${size}" height="${size}" fill="${options.lineColor}" stroke="${options.lineColor}" stroke-width="1"/>`;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Create linear barcode SVG representation
|
|
128
|
-
* @param {string} data - The data to encode
|
|
129
|
-
* @param {number} width - SVG width
|
|
130
|
-
* @param {number} height - SVG height
|
|
131
|
-
* @param {Object} options - Render options
|
|
132
|
-
* @returns {string} SVG content
|
|
133
|
-
*/
|
|
134
|
-
createLinearBarcodeSVG(data, width, height, options) {
|
|
135
|
-
// This is a simplified representation
|
|
136
|
-
// In a real implementation, you would use a barcode library
|
|
137
|
-
const barWidth = 2;
|
|
138
|
-
const barHeight = height - (options.displayValue ? 30 : 0);
|
|
139
|
-
const startX = 20;
|
|
140
|
-
let currentX = startX;
|
|
141
|
-
|
|
142
|
-
let svg = '';
|
|
143
|
-
for (let i = 0; i < data.length; i++) {
|
|
144
|
-
const char = data.charCodeAt(i);
|
|
145
|
-
const barCount = (char % 5) + 1;
|
|
146
|
-
|
|
147
|
-
for (let j = 0; j < barCount; j++) {
|
|
148
|
-
svg += `<rect x="${currentX}" y="10" width="${barWidth}" height="${barHeight}" fill="${options.lineColor}"/>`;
|
|
149
|
-
currentX += barWidth * 2;
|
|
150
|
-
}
|
|
25
|
+
} catch (error) {
|
|
26
|
+
throw new Error(`SVG rendering failed: ${error.message}`);
|
|
151
27
|
}
|
|
152
|
-
|
|
153
|
-
return svg;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Create XML document for JsBarcode
|
|
158
|
-
* @returns {Object} XML document
|
|
159
|
-
*/
|
|
160
|
-
createXMLDocument() {
|
|
161
|
-
// Create a minimal XML document for JsBarcode
|
|
162
|
-
return {
|
|
163
|
-
createElement: tagName => ({
|
|
164
|
-
tagName,
|
|
165
|
-
setAttribute: () => {},
|
|
166
|
-
appendChild: () => {},
|
|
167
|
-
toSVG: () => '<svg></svg>',
|
|
168
|
-
}),
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Map barcode type to JsBarcode format
|
|
174
|
-
* @param {string} type - The barcode type
|
|
175
|
-
* @returns {string} JsBarcode format
|
|
176
|
-
*/
|
|
177
|
-
mapBarcodeType(type) {
|
|
178
|
-
const typeMap = {
|
|
179
|
-
code128: 'CODE128',
|
|
180
|
-
code128a: 'CODE128A',
|
|
181
|
-
code128b: 'CODE128B',
|
|
182
|
-
code128c: 'CODE128C',
|
|
183
|
-
code128auto: 'CODE128',
|
|
184
|
-
code39: 'CODE39',
|
|
185
|
-
code39extended: 'CODE39',
|
|
186
|
-
code39checksum: 'CODE39',
|
|
187
|
-
code39auto: 'CODE39',
|
|
188
|
-
code93: 'CODE93',
|
|
189
|
-
ean13: 'EAN13',
|
|
190
|
-
ean8: 'EAN8',
|
|
191
|
-
upca: 'UPC',
|
|
192
|
-
upce: 'UPC',
|
|
193
|
-
codabar: 'codabar',
|
|
194
|
-
code11: 'CODE11',
|
|
195
|
-
msi: 'MSI',
|
|
196
|
-
pharmazentral: 'pharmazentral',
|
|
197
|
-
interleaved25: 'ITF',
|
|
198
|
-
standard25: 'STD25',
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
return typeMap[type] || 'CODE128';
|
|
202
28
|
}
|
|
203
29
|
|
|
204
30
|
/**
|
|
@@ -10,6 +10,9 @@ const HTMLRenderer = require('../renderers/HTMLRenderer');
|
|
|
10
10
|
const PDFRenderer = require('../renderers/PDFRenderer');
|
|
11
11
|
const { Validator } = require('../validators/Validator');
|
|
12
12
|
|
|
13
|
+
/** Formats that can be produced without any asynchronous work */
|
|
14
|
+
const SYNC_FORMATS = ['svg', 'html'];
|
|
15
|
+
|
|
13
16
|
class BarcodeService {
|
|
14
17
|
constructor() {
|
|
15
18
|
this.renderers = {
|
|
@@ -22,15 +25,13 @@ class BarcodeService {
|
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
/**
|
|
25
|
-
*
|
|
28
|
+
* Validate the arguments of a generate call and return the matching renderer
|
|
26
29
|
* @param {string} data - The data to encode
|
|
27
30
|
* @param {string} type - The barcode type
|
|
28
31
|
* @param {string} format - The output format
|
|
29
|
-
* @
|
|
30
|
-
* @returns {Buffer|string} Generated barcode
|
|
32
|
+
* @returns {Object} The renderer for the requested format
|
|
31
33
|
*/
|
|
32
|
-
|
|
33
|
-
// Validate inputs
|
|
34
|
+
resolve(data, type, format) {
|
|
34
35
|
if (!data || typeof data !== 'string') {
|
|
35
36
|
throw new Error('Data must be a non-empty string');
|
|
36
37
|
}
|
|
@@ -51,19 +52,45 @@ class BarcodeService {
|
|
|
51
52
|
);
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
// Validate data for the specific barcode type
|
|
55
55
|
const validation = this.validator.validate(data, type);
|
|
56
56
|
if (!validation.valid) {
|
|
57
57
|
throw new Error(`Invalid data for ${type}: ${validation.error}`);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
return this.renderers[format];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Generate a barcode
|
|
65
|
+
* @param {string} data - The data to encode
|
|
66
|
+
* @param {string} type - The barcode type
|
|
67
|
+
* @param {string} format - The output format
|
|
68
|
+
* @param {Object} options - Additional options
|
|
69
|
+
* @returns {Promise<Buffer|string>} Generated barcode
|
|
70
|
+
*/
|
|
71
|
+
async generate(data, type = 'code128', format = 'png', options = {}) {
|
|
72
|
+
const renderer = this.resolve(data, type, format);
|
|
73
|
+
return renderer.render(data, type, options);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Generate a barcode synchronously (SVG and HTML only)
|
|
78
|
+
* @param {string} data - The data to encode
|
|
79
|
+
* @param {string} type - The barcode type
|
|
80
|
+
* @param {string} format - The output format (svg or html)
|
|
81
|
+
* @param {Object} options - Additional options
|
|
82
|
+
* @returns {string} Generated barcode
|
|
83
|
+
*/
|
|
84
|
+
generateSync(data, type = 'code128', format = 'svg', options = {}) {
|
|
85
|
+
if (!SYNC_FORMATS.includes(format)) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
`Format ${format} cannot be generated synchronously. Synchronous formats: ${SYNC_FORMATS.join(
|
|
88
|
+
', '
|
|
89
|
+
)}`
|
|
90
|
+
);
|
|
64
91
|
}
|
|
65
92
|
|
|
66
|
-
|
|
93
|
+
const renderer = this.resolve(data, type, format);
|
|
67
94
|
return renderer.render(data, type, options);
|
|
68
95
|
}
|
|
69
96
|
|
|
@@ -72,9 +99,9 @@ class BarcodeService {
|
|
|
72
99
|
* @param {string} data - The data to encode
|
|
73
100
|
* @param {string} type - The barcode type
|
|
74
101
|
* @param {Object} options - Additional options
|
|
75
|
-
* @returns {Buffer} PNG buffer
|
|
102
|
+
* @returns {Promise<Buffer>} PNG buffer
|
|
76
103
|
*/
|
|
77
|
-
png(data, type = 'code128', options = {}) {
|
|
104
|
+
async png(data, type = 'code128', options = {}) {
|
|
78
105
|
return this.generate(data, type, 'png', options);
|
|
79
106
|
}
|
|
80
107
|
|
|
@@ -83,66 +110,99 @@ class BarcodeService {
|
|
|
83
110
|
* @param {string} data - The data to encode
|
|
84
111
|
* @param {string} type - The barcode type
|
|
85
112
|
* @param {Object} options - Additional options
|
|
86
|
-
* @returns {string} SVG
|
|
113
|
+
* @returns {Promise<string>} SVG markup
|
|
87
114
|
*/
|
|
88
|
-
svg(data, type = 'code128', options = {}) {
|
|
115
|
+
async svg(data, type = 'code128', options = {}) {
|
|
89
116
|
return this.generate(data, type, 'svg', options);
|
|
90
117
|
}
|
|
91
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Generate a barcode in SVG format synchronously
|
|
121
|
+
* @param {string} data - The data to encode
|
|
122
|
+
* @param {string} type - The barcode type
|
|
123
|
+
* @param {Object} options - Additional options
|
|
124
|
+
* @returns {string} SVG markup
|
|
125
|
+
*/
|
|
126
|
+
svgSync(data, type = 'code128', options = {}) {
|
|
127
|
+
return this.generateSync(data, type, 'svg', options);
|
|
128
|
+
}
|
|
129
|
+
|
|
92
130
|
/**
|
|
93
131
|
* Generate a barcode in HTML format
|
|
94
132
|
* @param {string} data - The data to encode
|
|
95
133
|
* @param {string} type - The barcode type
|
|
96
134
|
* @param {Object} options - Additional options
|
|
97
|
-
* @returns {string} HTML
|
|
135
|
+
* @returns {Promise<string>} HTML markup
|
|
98
136
|
*/
|
|
99
|
-
html(data, type = 'code128', options = {}) {
|
|
137
|
+
async html(data, type = 'code128', options = {}) {
|
|
100
138
|
return this.generate(data, type, 'html', options);
|
|
101
139
|
}
|
|
102
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Generate a barcode in HTML format synchronously
|
|
143
|
+
* @param {string} data - The data to encode
|
|
144
|
+
* @param {string} type - The barcode type
|
|
145
|
+
* @param {Object} options - Additional options
|
|
146
|
+
* @returns {string} HTML markup
|
|
147
|
+
*/
|
|
148
|
+
htmlSync(data, type = 'code128', options = {}) {
|
|
149
|
+
return this.generateSync(data, type, 'html', options);
|
|
150
|
+
}
|
|
151
|
+
|
|
103
152
|
/**
|
|
104
153
|
* Generate a barcode in PDF format
|
|
105
154
|
* @param {string} data - The data to encode
|
|
106
155
|
* @param {string} type - The barcode type
|
|
107
156
|
* @param {Object} options - Additional options
|
|
108
|
-
* @returns {Buffer} PDF buffer
|
|
157
|
+
* @returns {Promise<Buffer>} PDF buffer
|
|
109
158
|
*/
|
|
110
|
-
pdf(data, type = 'code128', options = {}) {
|
|
159
|
+
async pdf(data, type = 'code128', options = {}) {
|
|
111
160
|
return this.generate(data, type, 'pdf', options);
|
|
112
161
|
}
|
|
113
162
|
|
|
114
163
|
/**
|
|
115
|
-
* Generate multiple barcodes in batch
|
|
116
|
-
*
|
|
117
|
-
* @
|
|
164
|
+
* Generate multiple barcodes in batch. Individual failures are reported in
|
|
165
|
+
* the result instead of rejecting the whole batch.
|
|
166
|
+
* @param {Array<Object>} items - Array of barcode generation items
|
|
167
|
+
* @returns {Promise<Array<Object>>} Array of results
|
|
118
168
|
*/
|
|
119
|
-
batch(items) {
|
|
169
|
+
async batch(items) {
|
|
120
170
|
if (!Array.isArray(items)) {
|
|
121
171
|
throw new Error('Items must be an array');
|
|
122
172
|
}
|
|
123
173
|
|
|
124
|
-
|
|
174
|
+
const results = [];
|
|
175
|
+
|
|
176
|
+
for (const [index, item] of items.entries()) {
|
|
177
|
+
const {
|
|
178
|
+
data,
|
|
179
|
+
type = 'code128',
|
|
180
|
+
format = 'png',
|
|
181
|
+
options = {},
|
|
182
|
+
} = item || {};
|
|
183
|
+
|
|
125
184
|
try {
|
|
126
|
-
|
|
127
|
-
return {
|
|
185
|
+
results.push({
|
|
128
186
|
index,
|
|
129
187
|
success: true,
|
|
130
|
-
result: this.generate(data, type, format, options),
|
|
188
|
+
result: await this.generate(data, type, format, options),
|
|
131
189
|
data,
|
|
132
190
|
type,
|
|
133
191
|
format,
|
|
134
|
-
};
|
|
192
|
+
});
|
|
135
193
|
} catch (error) {
|
|
136
|
-
|
|
194
|
+
results.push({
|
|
137
195
|
index,
|
|
138
196
|
success: false,
|
|
139
197
|
error: error.message,
|
|
140
|
-
data
|
|
141
|
-
type
|
|
142
|
-
format
|
|
143
|
-
};
|
|
198
|
+
data,
|
|
199
|
+
type,
|
|
200
|
+
format,
|
|
201
|
+
});
|
|
144
202
|
}
|
|
145
|
-
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return results;
|
|
146
206
|
}
|
|
147
207
|
|
|
148
208
|
/**
|
|
@@ -157,7 +217,7 @@ class BarcodeService {
|
|
|
157
217
|
|
|
158
218
|
/**
|
|
159
219
|
* Get available barcode types
|
|
160
|
-
* @returns {
|
|
220
|
+
* @returns {string[]} Array of barcode types
|
|
161
221
|
*/
|
|
162
222
|
getBarcodeTypes() {
|
|
163
223
|
return BarcodeTypes.getAll();
|
|
@@ -165,7 +225,7 @@ class BarcodeService {
|
|
|
165
225
|
|
|
166
226
|
/**
|
|
167
227
|
* Get available render formats
|
|
168
|
-
* @returns {
|
|
228
|
+
* @returns {string[]} Array of render formats
|
|
169
229
|
*/
|
|
170
230
|
getRenderFormats() {
|
|
171
231
|
return RenderFormats.getAll();
|