diff --git a/src/app/barcode-data-matrix/barcode-data-matrix.component.ts b/src/app/barcode-data-matrix/barcode-data-matrix.component.ts index 929e004..00fa93a 100644 --- a/src/app/barcode-data-matrix/barcode-data-matrix.component.ts +++ b/src/app/barcode-data-matrix/barcode-data-matrix.component.ts @@ -1,6 +1,7 @@ import {AfterViewInit, Component, Input, OnInit} from '@angular/core'; import bwipjs from 'bwip-js'; import {AppDefaults} from '../models/appDefaults.interface'; +import DrawingSVG from './draw-svg.js'; @Component({ selector: 'app-barcode-data-matrix', @@ -21,7 +22,7 @@ export class BarcodeDataMatrixComponent implements OnInit { renderBarcode(): void { if (!!(bwipjs && bwipjs.toCanvas && this.settings && this.format)) { - bwipjs.toCanvas('barcodeCanvas', { + const opts = { bcid: this.format, text: this.value, scale: 1, @@ -31,7 +32,9 @@ export class BarcodeDataMatrixComponent implements OnInit { // textalign: 'center', // version: '12x64', // padding: this.settings.labelLayout.marginSize, - }); + }; + const barcodeSVG = bwipjs.render(opts, DrawingSVG(opts), bwipjs.FontLib); + // bwipjs.toCanvas('barcodeCanvas', ); } } } diff --git a/src/app/barcode-data-matrix/draw-svg.js b/src/app/barcode-data-matrix/draw-svg.js new file mode 100644 index 0000000..c812826 --- /dev/null +++ b/src/app/barcode-data-matrix/draw-svg.js @@ -0,0 +1,270 @@ +// bwip-js/examples/drawing-svg.js +// +// This is an advanced demonstation of using the drawing interface. +// +// It converts the drawing primitives into the equivalent SVG. Linear barcodes +// are rendered as a series of stroked paths. 2D barcodes are rendered as a +// series of filled paths. +// +// Rotation is handled during drawing. The resulting SVG will contain the +// already-rotated barcode without an SVG transform. +// +// If the requested barcode image contains text, the glyph paths are +// extracted from the font file (via the builtin FontLib and stb_truetype.js) +// and added as filled SVG paths. +// +// This code can run in the browser and in nodejs. +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + define([], factory); + } else if (typeof module === 'object' && module.exports) { + module.exports = factory(); + } else { + root.DrawingSVG = factory(); + } +}(typeof self !== 'undefined' ? self : this, function () { +"use strict"; + +function DrawingSVG(opts, FontLib) { + // Unrolled x,y rotate/translate matrix + var tx0 = 0, tx1 = 0, tx2 = 0, tx3 = 0; + var ty0 = 0, ty1 = 0, ty2 = 0, ty3 = 0; + + var svg = ''; + var path; + var lines = {}; + + // Magic number to approximate an ellipse/circle using 4 cubic beziers. + var ELLIPSE_MAGIC = 0.55228475 - 0.00045; + + // Global graphics state + var gs_width, gs_height; // image size, in pixels + var gs_dx, gs_dy; // x,y translate (padding) + + return { + // Make no adjustments + scale(sx, sy) { + }, + // Measure text. This and scale() are the only drawing primitives that + // are called before init(). + // + // `font` is the font name typically OCR-A or OCR-B. + // `fwidth` and `fheight` are the requested font cell size. They will + // usually be the same, except when the scaling is not symetric. + measure(str, font, fwidth, fheight) { + fwidth = fwidth|0; + fheight = fheight|0; + + var fontid = FontLib.lookup(font); + var width = 0; + var ascent = 0; + var descent = 0; + for (var i = 0; i < str.length; i++) { + var ch = str.charCodeAt(i); + var glyph = FontLib.getpaths(fontid, ch, fwidth, fheight); + if (!glyph) { + continue; + } + ascent = Math.max(ascent, glyph.ascent); + descent = Math.max(descent, -glyph.descent); + width += glyph.advance; + } + return { width, ascent, descent }; + }, + + // width and height represent the maximum bounding box the graphics will occupy. + // The dimensions are for an unrotated rendering. Adjust as necessary. + init(width, height) { + // Add in the effects of padding. These are always set before the + // drawing constructor is called. + var padl = opts.paddingleft; + var padr = opts.paddingright; + var padt = opts.paddingtop; + var padb = opts.paddingbottom; + var rot = opts.rotate || 'N'; + + width += padl + padr; + height += padt + padb; + + // Transform indexes are: x, y, w, h + switch (rot) { + // tx = w-y, ty = x + case 'R': tx1 = -1; tx2 = 1; ty0 = 1; break; + // tx = w-x, ty = h-y + case 'I': tx0 = -1; tx2 = 1; ty1 = -1; ty3 = 1; break; + // tx = y, ty = h-x + case 'L': tx1 = 1; ty0 = -1; ty3 = 1; break; + // tx = x, ty = y + default: tx0 = ty1 = 1; break; + } + + // Setup the graphics state + var swap = rot == 'L' || rot == 'R'; + gs_width = swap ? height : width; + gs_height = swap ? width : height; + gs_dx = padl; + gs_dy = padt; + + svg = ''; + }, + // Unconnected stroked lines are used to draw the bars in linear barcodes. + // No line cap should be applied. These lines are always orthogonal. + line(x0, y0, x1, y1, lw, rgb) { + // Try to get non-blurry lines... + x0 = x0|0; + y0 = y0|0; + x1 = x1|0; + y1 = y1|0; + lw = Math.round(lw); + + // Try to keep the lines "crisp" by using with the SVG line drawing spec to + // our advantage. + if (lw & 1) { + if (x0 == x1) { + x0 += 0.5; + x1 += 0.5; + } + if (y0 == y1) { + y0 += 0.5; + y1 += 0.5; + } + } + + // Group together all lines of the same width and emit as single paths. + // Dramatically reduces resulting text size. + var key = '' + lw + '#' + rgb; + if (!lines[key]) { + lines[key] = '\n'; + path = null; + } + }, + // Draw text with optional inter-character spacing. `y` is the baseline. + // font is an object with properties { name, width, height, dx } + // width and height are the font cell size. + // dx is extra space requested between characters (usually zero). + text(x, y, str, rgb, font) { + var fontid = FontLib.lookup(font.name); + var fwidth = font.width|0; + var fheight = font.height|0; + var dx = font.dx|0; + var path = ''; + for (var k = 0; k < str.length; k++) { + var ch = str.charCodeAt(k); + var glyph = FontLib.getpaths(fontid, ch, fwidth, fheight); + if (!glyph) { + continue; + } + if (glyph.length) { + // A glyph is composed of sequence of curve and line segments. + // M is move-to + // L is line-to + // Q is quadratic bezier curve-to + // C is cubic bezier curve-to + for (var i = 0, l = glyph.length; i < l; i++) { + let seg = glyph[i]; + if (seg.type == 'M' || seg.type == 'L') { + path += seg.type + transform(seg.x + x, y - seg.y); + } else if (seg.type == 'Q') { + path += seg.type + transform(seg.cx + x, y - seg.cy) + ' ' + + transform(seg.x + x, y - seg.y); + } else if (seg.type == 'C') { + path += seg.type + transform(seg.cx1 + x, y - seg.cy1) + ' ' + + transform(seg.cx2 + x, y - seg.cy2) + ' ' + + transform(seg.x + x, y - seg.y); + } + } + // Close the shape + path += 'Z'; + } + x += glyph.advance + dx; + } + if (path) { + svg += '\n'; + } + }, + // Called after all drawing is complete. The return value from this method + // is the return value from `bwipjs.render()`. + end() { + var linesvg = ''; + for (var key in lines) { + linesvg += lines[key] + '" />\n'; + } + var bg = opts.backgroundcolor; + return '\n' + + (/^[0-9A-Fa-f]{6}$/.test(''+bg) + ? '\n' + : '') + + linesvg + svg + '\n'; + }, + }; + + // translate/rotate and return as an SVG coordinate pair + function transform(x, y) { + x += gs_dx; + y += gs_dy; + var tx = tx0 * x + tx1 * y + tx2 * (gs_width-1) + tx3 * (gs_height-1); + var ty = ty0 * x + ty1 * y + ty2 * (gs_width-1) + ty3 * (gs_height-1); + return '' + ((tx|0) == tx ? tx : tx.toFixed(2)) + ' ' + + ((ty|0) == ty ? ty : ty.toFixed(2)); + } +} + +return DrawingSVG; +})); diff --git a/src/app/config/defaults.ts b/src/app/config/defaults.ts index 65a03b5..a9d3b6e 100644 --- a/src/app/config/defaults.ts +++ b/src/app/config/defaults.ts @@ -2,10 +2,10 @@ import {AppDefaultsOptions} from '../models/appDefaults.interface'; import {LabelLayout} from '../models/labelLayout.interface'; export const labelLayouts = { - round_32mm_1up: new LabelLayout({ - name: '32mm Round Label - 1up', + circle_1up_32mm_x_32mm_qrcode: new LabelLayout({ + name: '32mm Round Label - QR Code (1up)', barcodeType: 'qrcode', - type: 'round_32mm_1up', + type: 'circle_1up_32mm_x_32mm_qrcode', numCols: 1, columnGap: 0, barcodeWidth: 28.6, @@ -14,10 +14,10 @@ export const labelLayouts = { topTextMargin: 0, bottomTextMargin: 0, }), - round_32mm_2up: new LabelLayout({ - name: '32mm Round Label - 2up', + circle_2up_32mm_x_32mm_qrcode: new LabelLayout({ + name: '32mm Round Label - QR Code (2up)', barcodeType: 'qrcode', - type: 'round_32mm_2up', + type: 'circle_2up_64mm_x_32mm_qrcode', numCols: 2, columnGap: 3.4, barcodeWidth: 28.6, @@ -26,10 +26,10 @@ export const labelLayouts = { topTextMargin: 0, bottomTextMargin: 0, }), - rectangular_54x32: new LabelLayout({ - name: '2in x 1.25in Rectangular Label', - barcodeType: 'datamatrix', - type: 'rectangular_54x32', + rectangular_54mm_x_34mm_code128: new LabelLayout({ + name: '2in x 1.25in Rectangular Label - CODE128', + barcodeType: 'code128', + type: 'rectangular_54mm_x_34mm_code128', numCols: 1, columnGap: 0, columnWidth: 54, @@ -40,35 +40,38 @@ export const labelLayouts = { topTextMargin: 0, bottomTextMargin: 0, }), - rectangular_sm: new LabelLayout({ - name: '96mm x 15mm Rectangular Label', + rectangular_54mm_x_34mm_datamatrix: new LabelLayout({ + name: '2in x 1.25in Rectangular Label - DataMatrix', barcodeType: 'datamatrix', - type: 'rectangular_sm', + type: 'rectangular_54mm_x_34mm_datamatrix', numCols: 1, columnGap: 0, - barcodeWidth: 32, - barcodeHeight: 16, - marginSize: 6, - sideTextMargin: 2, - topTextMargin: 3, - bottomTextMargin: 3, + columnWidth: 54, + columnHeight: 34, + barcodeWidth: 10, + barcodeHeight: 10, + sideTextMargin: 0, + topTextMargin: 0, + bottomTextMargin: 0, }), }; export const defaultOptions: AppDefaultsOptions = { - barCodeNumLength: 9, // Number of digits in Bar Code. - barCodeRegExp: /^[\d]{14}$|^[\d]{9}$/, // Pattern for Bar Code data. Scanned barcodes will be either 9 or 14 digits long. - // Manually-entered ID numbers will be exactly 9 digits long. - countsCollection: 'counts', // Name of collection for Line Counts in Firebase. - dateDisplayFormat: 'MM/dd/yyyy, hh:mm aa', // Format for dates when displayed to user. - dateEncodedFormat: 'yyyyMMddHHmm', // Format for dates when encoded in IDs for database records. + barCodeNumLength: 9, // Number of digits in Bar Code. + barCodeRegExp: /^[\d]{14}$|^[\d]{9}$/, // Pattern for Bar Code data. + // Scanned barcodes will be either 9 or 14 digits long. + // Manually-entered ID numbers will be exactly 9 digits long. + countsCollection: 'counts', // Name of collection for Line Counts in Firebase. + dateDisplayFormat: 'MM/dd/yyyy, hh:mm aa', // Format for dates when displayed to user. + dateEncodedFormat: 'yyyyMMddHHmm', // Format for dates when encoded in IDs for database records. initialsLength: 5, initialsRegExp: /^[a-zA-Z]{2,5}$/, - labelLayout: labelLayouts.round_32mm_1up, // Which label layout to use for printing. Can be overridden by user setting. - lineCountRegExp: /^[\d]{4}-[\d]{12}$/, // ID format for Line Count records. - locationId: '0000', // Default location ID. Can be overridden by user setting. - locationIdRegExp: /^[\d]{4}$/, // ID format for Line Count records. - numCopies: 1, // Default number of copies of labels to print. Can be overridden by user setting. - qrCodeRegExp: /^[\d]{9}-[a-zA-Z]+-[\d]{12}-[\d]{4}$/, // ID format for QR Code records. - samplesCollection: 'samples', // Name of collection for Line Counts in Firebase. + labelLayout: labelLayouts.circle_1up_32mm_x_32mm_qrcode, // Which label layout to use for printing. Can be overridden by user setting. + lineCountRegExp: /^[\d]{4}-[\d]{12}$/, // ID format for Line Count records. + locationId: '0000', // Default location ID. Can be overridden by user setting. + locationIdRegExp: /^[\d]{4}$/, // ID format for Line Count records. + numCopies: 1, // Default number of copies of labels to print. + // Can be overridden by user setting. + qrCodeRegExp: /^[\d]{9}-[a-zA-Z]+-[\d]{12}-[\d]{4}$/, // ID format for QR Code records. + samplesCollection: 'samples', // Name of collection for Line Counts in Firebase. }; diff --git a/src/app/models/labelLayout.interface.ts b/src/app/models/labelLayout.interface.ts index e4b6330..6a3c6ea 100644 --- a/src/app/models/labelLayout.interface.ts +++ b/src/app/models/labelLayout.interface.ts @@ -21,9 +21,9 @@ export interface LayoutOptions { } export class LabelLayout { + name = '32mm Round Label - QR Code (1up)'; barcodeType = 'qrcode'; - type = 'round_32mm_1up'; - name = '32mm Round Label - 1up'; + type = 'circle_1up_32mm_x_32mm_qrcode'; units = 'mm'; pointsPerUnit = 0.3528; barcodeHeight = 28.6; diff --git a/src/app/settings/settings.component.html b/src/app/settings/settings.component.html index 630ddaf..3f2759a 100644 --- a/src/app/settings/settings.component.html +++ b/src/app/settings/settings.component.html @@ -28,7 +28,16 @@ #labelLayoutSelect="matSelect" [formControl]="labelLayoutFormControl" > - {{layout.name}} + +
+
+ {{layout.name}} +
+
+ {{layout.name}} +
+
+
This field is required. diff --git a/src/assets/formats/circle_1up_32mm_x_32mm_qrcode.svg b/src/assets/formats/circle_1up_32mm_x_32mm_qrcode.svg new file mode 100644 index 0000000..78951df --- /dev/null +++ b/src/assets/formats/circle_1up_32mm_x_32mm_qrcode.svg @@ -0,0 +1,143 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + #987654321 + 200912ABC + T1234 + L4040 + + + + diff --git a/src/assets/formats/circle_2up_64mm_x_32mm_qrcode.svg b/src/assets/formats/circle_2up_64mm_x_32mm_qrcode.svg new file mode 100644 index 0000000..6d172e5 --- /dev/null +++ b/src/assets/formats/circle_2up_64mm_x_32mm_qrcode.svg @@ -0,0 +1,225 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + #987654321 + 200912ABC + T1234 + L4040 + + + + + + #987654321 + 200912ABC + T1234 + L4040 + + + diff --git a/src/assets/formats/rectangular_54mm_x_34mm_code128.svg b/src/assets/formats/rectangular_54mm_x_34mm_code128.svg new file mode 100644 index 0000000..5eaec98 --- /dev/null +++ b/src/assets/formats/rectangular_54mm_x_34mm_code128.svg @@ -0,0 +1,572 @@ + + + + + + + + + + image/svg+xml + + + + + + + 123456789-ABCDE-202011101110-1010 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UP + + + + + + + UP + + + + + + + + diff --git a/src/assets/formats/rectangular_54mm_x_34mm_datamatrix.svg b/src/assets/formats/rectangular_54mm_x_34mm_datamatrix.svg new file mode 100644 index 0000000..3db474e --- /dev/null +++ b/src/assets/formats/rectangular_54mm_x_34mm_datamatrix.svg @@ -0,0 +1,161 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + UP + + + + + + + UP + + + + + + + + + + + + #9876543212021-01-23 12:34ABCDE 0404 + +