Skip to content

Commit 77b6b39

Browse files
committed
feat(Barcode Generator): use bwip-js to add more barcode types
Including Datamatrix, fix CorentinTh#1343
1 parent 47917dc commit 77b6b39

File tree

6 files changed

+274
-54
lines changed

6 files changed

+274
-54
lines changed

components.d.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,6 @@ declare module '@vue/runtime-core' {
247247
NCode: typeof import('naive-ui')['NCode']
248248
NCollapseTransition: typeof import('naive-ui')['NCollapseTransition']
249249
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
250-
NDivider: typeof import('naive-ui')['NDivider']
251250
NEllipsis: typeof import('naive-ui')['NEllipsis']
252251
NginxFormatter: typeof import('./src/tools/nginx-formatter/nginx-formatter.vue')['default']
253252
NH1: typeof import('naive-ui')['NH1']

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
"apache-md5": "^1.1.8",
7777
"arr-diff": "^4.0.0",
7878
"bcryptjs": "^2.4.3",
79+
"bwip-js": "^4.5.1",
7980
"big.js": "^6.2.2",
8081
"change-case": "^4.1.2",
8182
"chatgpt-prompt-splitter": "^1.0.5",

pnpm-lock.yaml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/tools/barcode-generator/barcode-generator.vue

Lines changed: 71 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,61 @@
11
<script setup lang="ts">
2-
import VueBarcode from '@chenfengyuan/vue-barcode';
3-
import JsBarcode from 'jsbarcode';
2+
import bwipjs, { type RenderOptions } from 'bwip-js/browser';
3+
import { Base64 } from 'js-base64';
4+
import formats from './barcode.formats.json';
45
import { useDownloadFileFromBase64 } from '@/composable/downloadBase64';
56
import { useQueryParamOrStorage } from '@/composable/queryParams';
67
7-
const foreground = useQueryParamOrStorage({ name: 'fg', storageName: 'barcode-gen:fg', defaultValue: '#000000ff' });
8-
const background = useQueryParamOrStorage({ name: 'bg', storageName: 'barcode-gen:bg', defaultValue: '#ffffffff' });
9-
const width = useQueryParamOrStorage({ name: 'width', storageName: 'barcode-gen:width', defaultValue: 2 });
10-
const height = useQueryParamOrStorage({ name: 'height', storageName: 'barcode-gen:height', defaultValue: 100 });
8+
const foreground = useQueryParamOrStorage({ name: 'fg', storageName: 'barcode-gen:fg', defaultValue: '#000000' });
9+
const background = useQueryParamOrStorage({ name: 'bg', storageName: 'barcode-gen:bg', defaultValue: '#FFFFFF' });
10+
const scale = useQueryParamOrStorage({ name: 'scale', storageName: 'barcode-gen:scale', defaultValue: 2 });
11+
const height = useQueryParamOrStorage({ name: 'height', storageName: 'barcode-gen:height', defaultValue: 25 });
1112
const margin = useQueryParamOrStorage({ name: 'margin', storageName: 'barcode-gen:margin', defaultValue: 10 });
12-
const format = useQueryParamOrStorage({ name: 'format', storageName: 'barcode-gen:format', defaultValue: 'auto' });
13+
const format = useQueryParamOrStorage({ name: 'format', storageName: 'barcode-gen:format', defaultValue: 'code128' });
1314
const displayValue = useQueryParamOrStorage({ name: 'display', storageName: 'barcode-gen:display', defaultValue: true });
14-
const ean128 = useQueryParamOrStorage({ name: 'ean128', storageName: 'barcode-gen:ean128', defaultValue: false });
1515
const value = ref('123456789');
16+
const barcodeCanvas = ref<HTMLCanvasElement>();
1617
17-
const options = computed(() => ({
18-
lineColor: foreground.value,
19-
background: background.value,
20-
width: width.value,
18+
const options = computed<RenderOptions>(() => ({
19+
barcolor: foreground.value,
20+
textcolor: foreground.value,
21+
backgroundcolor: background.value,
22+
scale: scale.value,
2123
height: height.value,
22-
margin: margin.value,
23-
format: format.value === 'auto' ? 'CODE128' : format.value,
24-
displayValue: displayValue.value,
25-
ean128: ean128.value,
24+
padding: margin.value,
25+
bcid: format.value === 'auto' ? 'code128' : format.value,
26+
includetext: displayValue.value,
2627
text: value.value,
28+
textxalign: 'center',
2729
}));
2830
29-
const formats = [
30-
'auto',
31-
'CODE39',
32-
'CODE128', 'CODE128A', 'CODE128B', 'CODE128C',
33-
'EAN13', 'EAN8', 'EAN5', 'EAN2', 'UPC', 'UPCE',
34-
'ITF14',
35-
'ITF',
36-
'MSI', 'MSI10', 'MSI11', 'MSI1010', 'MSI1110',
37-
'pharmacode',
38-
'codabar',
39-
'GenericBarcode',
40-
];
31+
const error = ref('');
32+
watchEffect(() => {
33+
if (!barcodeCanvas.value) {
34+
return;
35+
}
36+
37+
try {
38+
bwipjs.toCanvas(barcodeCanvas.value, options.value);
39+
}
40+
catch (e: any) {
41+
error.value = e.toString();
42+
}
43+
});
4144
4245
const barcodePNG = computed(() => {
43-
const canvas = document.createElement('canvas');
44-
JsBarcode(canvas, value.value, options.value);
45-
return canvas.toDataURL('image/png');
46+
return barcodeCanvas.value?.toDataURL('image/png') || '';
47+
});
48+
const barcodeSVG = computed(() => {
49+
try {
50+
return Base64.encode(bwipjs.toSVG(options.value));
51+
}
52+
catch (e: any) {
53+
return '';
54+
}
4655
});
4756
48-
const { download } = useDownloadFileFromBase64({ source: barcodePNG, filename: 'barcode.png' });
57+
const { download: downloadPNG } = useDownloadFileFromBase64({ source: barcodePNG, filename: 'barcode.png' });
58+
const { download: downloadSVG } = useDownloadFileFromBase64({ source: barcodeSVG, filename: 'barcode.svg' });
4959
</script>
5060

5161
<template>
@@ -61,20 +71,31 @@ const { download } = useDownloadFileFromBase64({ source: barcodePNG, filename: '
6171
multiline
6272
rows="1"
6373
autosize
64-
placeholder="Your text..."
74+
placeholder="Your barcode..."
6575
mb-6
6676
/>
6777
<n-form label-width="130" label-placement="left">
78+
<c-select
79+
v-model:value="format"
80+
label="Format:"
81+
label-position="left"
82+
label-width="130px"
83+
label-align="right"
84+
:options="formats"
85+
searchable
86+
mb-4
87+
/>
88+
6889
<n-form-item label="Foreground color:">
69-
<n-color-picker v-model:value="foreground" :modes="['hex']" />
90+
<n-color-picker v-model:value="foreground" :modes="['hex']" :show-alpha="false" />
7091
</n-form-item>
7192
<n-form-item label="Background color:">
72-
<n-color-picker v-model:value="background" :modes="['hex']" />
93+
<n-color-picker v-model:value="background" :modes="['hex']" :show-alpha="false" />
7394
</n-form-item>
74-
<n-form-item label="Width:">
75-
<n-input-number v-model:value="width" :min="0" />
95+
<n-form-item label="Scale:">
96+
<n-input-number v-model:value="scale" :min="0" />
7697
</n-form-item>
77-
<n-form-item label="Height:">
98+
<n-form-item label="Height (mm):">
7899
<n-input-number v-model:value="height" :min="0" />
79100
</n-form-item>
80101
<n-form-item label="Margin:">
@@ -83,25 +104,22 @@ const { download } = useDownloadFileFromBase64({ source: barcodePNG, filename: '
83104
<n-form-item label="Display text:">
84105
<n-checkbox v-model:checked="displayValue" />
85106
</n-form-item>
86-
<c-select
87-
v-model:value="format"
88-
label="Format:"
89-
label-position="left"
90-
label-width="130px"
91-
label-align="right"
92-
:options="formats.map((value) => ({ label: value, value }))"
93-
/>
94107
</n-form>
95108
</n-gi>
96109
<n-gi>
97110
<div flex flex-col items-center gap-3>
98-
<VueBarcode
99-
:options="options"
100-
:value="value"
101-
/>
102-
<c-button @click="download">
103-
Download barcode
104-
</c-button>
111+
<c-alert v-if="error">
112+
{{ error }}
113+
</c-alert>
114+
<canvas ref="barcodeCanvas" />
115+
<div flex justify-center>
116+
<c-button mr-2 @click="downloadPNG">
117+
Download PNG barcode
118+
</c-button>
119+
<c-button @click="downloadSVG">
120+
Download SVG barcode
121+
</c-button>
122+
</div>
105123
</div>
106124
</n-gi>
107125
</n-grid>
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
[
2+
{ "value": "auspost", "label": "AusPost 4 State Customer Code" },
3+
{ "value": "azteccode", "label": "Aztec Code" },
4+
{ "value": "azteccodecompact", "label": "Compact Aztec Code" },
5+
{ "value": "aztecrune", "label": "Aztec Runes" },
6+
{ "value": "bc412", "label": "BC412" },
7+
{ "value": "channelcode", "label": "Channel Code" },
8+
{ "value": "codablockf", "label": "Codablock F" },
9+
{ "value": "code11", "label": "Code 11" },
10+
{ "value": "code128", "label": "Code 128" },
11+
{ "value": "code16k", "label": "Code 16K" },
12+
{ "value": "code2of5", "label": "Code 25" },
13+
{ "value": "code32", "label": "Italian Pharmacode" },
14+
{ "value": "code39", "label": "Code 39" },
15+
{ "value": "code39ext", "label": "Code 39 Extended" },
16+
{ "value": "code49", "label": "Code 49" },
17+
{ "value": "code93", "label": "Code 93" },
18+
{ "value": "code93ext", "label": "Code 93 Extended" },
19+
{ "value": "codeone", "label": "Code One" },
20+
{ "value": "coop2of5", "label": "COOP 2 of 5" },
21+
{ "value": "daft", "label": "Custom 4 state symbology" },
22+
{ "value": "databarexpanded", "label": "GS1 DataBar Expanded" },
23+
{ "value": "databarexpandedcomposite", "label": "GS1 DataBar Expanded Composite" },
24+
{ "value": "databarexpandedstacked", "label": "GS1 DataBar Expanded Stacked" },
25+
{ "value": "databarexpandedstackedcomposite", "label": "GS1 DataBar Expanded Stacked Composite" },
26+
{ "value": "databarlimited", "label": "GS1 DataBar Limited" },
27+
{ "value": "databarlimitedcomposite", "label": "GS1 DataBar Limited Composite" },
28+
{ "value": "databaromni", "label": "GS1 DataBar Omnidirectional" },
29+
{ "value": "databaromnicomposite", "label": "GS1 DataBar Omnidirectional Composite" },
30+
{ "value": "databarstacked", "label": "GS1 DataBar Stacked" },
31+
{ "value": "databarstackedcomposite", "label": "GS1 DataBar Stacked Composite" },
32+
{ "value": "databarstackedomni", "label": "GS1 DataBar Stacked Omnidirectional" },
33+
{ "value": "databarstackedomnicomposite", "label": "GS1 DataBar Stacked Omnidirectional Composite" },
34+
{ "value": "databartruncated", "label": "GS1 DataBar Truncated" },
35+
{ "value": "databartruncatedcomposite", "label": "GS1 DataBar Truncated Composite" },
36+
{ "value": "datalogic2of5", "label": "Datalogic 2 of 5" },
37+
{ "value": "datamatrix", "label": "Data Matrix" },
38+
{ "value": "datamatrixrectangular", "label": "Data Matrix Rectangular" },
39+
{ "value": "datamatrixrectangularextension", "label": "Data Matrix Rectangular Extension" },
40+
{ "value": "dotcode", "label": "DotCode" },
41+
{ "value": "ean13", "label": "EAN-13" },
42+
{ "value": "ean13composite", "label": "EAN-13 Composite" },
43+
{ "value": "ean14", "label": "GS1-14" },
44+
{ "value": "ean2", "label": "EAN-2 (2 digit addon)" },
45+
{ "value": "ean5", "label": "EAN-5 (5 digit addon)" },
46+
{ "value": "ean8", "label": "EAN-8" },
47+
{ "value": "ean8composite", "label": "EAN-8 Composite" },
48+
{ "value": "flattermarken", "label": "Flattermarken" },
49+
{ "value": "gs1-128", "label": "GS1-128" },
50+
{ "value": "gs1-128composite", "label": "GS1-128 Composite" },
51+
{ "value": "gs1-cc", "label": "GS1 Composite 2D Component" },
52+
{ "value": "gs1datamatrix", "label": "GS1 Data Matrix" },
53+
{ "value": "gs1datamatrixrectangular", "label": "GS1 Data Matrix Rectangular" },
54+
{ "value": "gs1dldatamatrix", "label": "GS1 Digital Link Data Matrix" },
55+
{ "value": "gs1dlqrcode", "label": "GS1 Digital Link QR Code" },
56+
{ "value": "gs1dotcode", "label": "GS1 DotCode" },
57+
{ "value": "gs1northamericancoupon", "label": "GS1 North American Coupon" },
58+
{ "value": "gs1qrcode", "label": "GS1 QR Code" },
59+
{ "value": "hanxin", "label": "Han Xin Code" },
60+
{ "value": "hibcazteccode", "label": "HIBC Aztec Code" },
61+
{ "value": "hibccodablockf", "label": "HIBC Codablock F" },
62+
{ "value": "hibccode128", "label": "HIBC Code 128" },
63+
{ "value": "hibccode39", "label": "HIBC Code 39" },
64+
{ "value": "hibcdatamatrix", "label": "HIBC Data Matrix" },
65+
{ "value": "hibcdatamatrixrectangular", "label": "HIBC Data Matrix Rectangular" },
66+
{ "value": "hibcmicropdf417", "label": "HIBC MicroPDF417" },
67+
{ "value": "hibcpdf417", "label": "HIBC PDF417" },
68+
{ "value": "hibcqrcode", "label": "HIBC QR Code" },
69+
{ "value": "iata2of5", "label": "IATA 2 of 5" },
70+
{ "value": "identcode", "label": "Deutsche Post Identcode" },
71+
{ "value": "industrial2of5", "label": "Industrial 2 of 5" },
72+
{ "value": "interleaved2of5", "label": "Interleaved 2 of 5 (ITF)" },
73+
{ "value": "isbn", "label": "ISBN" },
74+
{ "value": "ismn", "label": "ISMN" },
75+
{ "value": "issn", "label": "ISSN" },
76+
{ "value": "itf14", "label": "ITF-14" },
77+
{ "value": "japanpost", "label": "Japan Post 4 State Customer Code" },
78+
{ "value": "kix", "label": "Royal Dutch TPG Post KIX" },
79+
{ "value": "leitcode", "label": "Deutsche Post Leitcode" },
80+
{ "value": "mailmark", "label": "Royal Mail Mailmark" },
81+
{ "value": "mands", "label": "Marks & Spencer" },
82+
{ "value": "matrix2of5", "label": "Matrix 2 of 5" },
83+
{ "value": "maxicode", "label": "MaxiCode" },
84+
{ "value": "micropdf417", "label": "MicroPDF417" },
85+
{ "value": "microqrcode", "label": "Micro QR Code" },
86+
{ "value": "msi", "label": "MSI Modified Plessey" },
87+
{ "value": "onecode", "label": "USPS Intelligent Mail" },
88+
{ "value": "pdf417", "label": "PDF417" },
89+
{ "value": "pdf417compact", "label": "Compact PDF417" },
90+
{ "value": "pharmacode", "label": "Pharmaceutical Binary Code" },
91+
{ "value": "pharmacode2", "label": "Two-track Pharmacode" },
92+
{ "value": "planet", "label": "USPS PLANET" },
93+
{ "value": "plessey", "label": "Plessey UK" },
94+
{ "value": "posicode", "label": "PosiCode" },
95+
{ "value": "postnet", "label": "USPS POSTNET" },
96+
{ "value": "pzn", "label": "Pharmazentralnummer (PZN)" },
97+
{ "value": "qrcode", "label": "QR Code" },
98+
{ "value": "rationalizedCodabar", "label": "Codabar" },
99+
{ "value": "raw", "label": "Custom 1D symbology" },
100+
{ "value": "rectangularmicroqrcode", "label": "Rectangular Micro QR Code" },
101+
{ "value": "royalmail", "label": "Royal Mail 4 State Customer Code" },
102+
{ "value": "sscc18", "label": "SSCC-18" },
103+
{ "value": "swissqrcode", "label": "Swiss QR Code" },
104+
{ "value": "symbol", "label": "Miscellaneous symbols" },
105+
{ "value": "telepen", "label": "Telepen" },
106+
{ "value": "telepennumeric", "label": "Telepen Numeric" },
107+
{ "value": "ultracode", "label": "Ultracode" },
108+
{ "value": "upca", "label": "UPC-A" },
109+
{ "value": "upcacomposite", "label": "UPC-A Composite" },
110+
{ "value": "upce", "label": "UPC-E" },
111+
{ "value": "upcecomposite", "label": "UPC-E Composite" }
112+
]

0 commit comments

Comments
 (0)