UNPKG

@syncfusion/ej2-barcode-generator

Version:

Barcode generator component is a pure JavaScript library which will convert a string to Barcode and show it to the user. This supports major 1D and 2D barcodes including coda bar, code 128, QR Code.

955 lines (834 loc) 40.2 kB
import { QuietZone, DataMatrixEncoding, DataMatrixSize } from '../barcode/enum/enum'; import { PdfDataMatrixSymbolAttribute } from '../barcode/rendering/canvas-interface'; import { DisplayTextModel } from '../barcode/primitives/displaytext-model'; import { MarginModel } from '../barcode/primitives/margin-model'; import { Size } from '../barcode/primitives/size'; import { BarcodeRenderer } from '../barcode/rendering/renderer'; import { BaseAttributes } from '../barcode/rendering/canvas-interface'; import { Rect } from '../barcode/primitives/rect'; import { createMeasureElements, measureText } from '../barcode/utility/dom-util'; import { getBaseAttributes } from '../barcode/utility/barcode-util'; /** * DataMatrix used to calculate the DataMatrix barcode */ export class DataMatrix { /** @private */ public encodingValue: DataMatrixEncoding; /** @private */ public height: string | number; /** @private */ public width: string | number; /** @private */ public margin: MarginModel; /** @private */ public displayText: DisplayTextModel; /** @private */ public foreColor: string; /** @private */ public isSvgMode: boolean; /** @private */ public value: string; private barcodeRenderer: BarcodeRenderer; /** @private */ public size: DataMatrixSize; private mXDimension: number = 1; private mDataMatrixArray: number[][] = []; private actualColumns: number; private actualRows: number; // eslint-disable-next-line /** @private */ public set XDimension(value: number) { this.mXDimension = value; } private encodedCodeword: number[] | string; private mSymbolAttribute: PdfDataMatrixSymbolAttribute; private GetData(): number[] { const givenString: string = this.value; const asciiValue: number[] = []; for (let i: number = 0; i < givenString.length; i++) { asciiValue.push(givenString.charCodeAt(i)); } return asciiValue; } private fillZero(destinationArray: number[]): number[] { for (let i: number = 0; i < destinationArray.length; i++) { destinationArray[parseInt(i.toString(), 10)] = 0; } return destinationArray; } private DataMatrixNumericEncoder(dataCodeword: number[]): number[] { let destinationArray: number[] = dataCodeword; let isEven: boolean = true; if ((destinationArray.length % 2) === 1) { isEven = false; destinationArray = Array(dataCodeword.length + 1); destinationArray = this.fillZero(destinationArray); destinationArray = this.copy(dataCodeword, 0, destinationArray, 0, dataCodeword.length); } let result: number[] = Array(destinationArray.length / 2); result = this.fillZero(result); for (let i: number = 0; i < result.length; i++) { if (!isEven && i === result.length - 1) { result[parseInt(i.toString(), 10)] = (destinationArray[2 * i] + 1); } else { result[parseInt(i.toString(), 10)] = ((((destinationArray[2 * i] - 48) * 10) + (destinationArray[(2 * i) + 1] - 48)) + 130); } } return result; } private ComputeBase256Codeword(val: number, index: number): number { const num: number = ((149 * (index + 1)) % 255) + 1; const num2: number = val + num; if (num2 <= 255) { return num2; } return (num2 - 256); } private DataMatrixBaseEncoder(dataCodeword: number[]): number[] { let num: number = 1; if (dataCodeword.length > 249) { num++; } let result: number[] = Array((1 + num) + dataCodeword.length); result = this.fillZero(result); result[0] = 231; if (dataCodeword.length <= 249) { result[1] = dataCodeword.length; } else { result[1] = ((dataCodeword.length / 250) + 249); result[2] = (dataCodeword.length % 250); } result = this.copy(dataCodeword, 0, result, 1 + num, dataCodeword.length); for (let i: number = 1; i < result.length; i++) { result[parseInt(i.toString(), 10)] = this.ComputeBase256Codeword(result[parseInt(i.toString(), 10)], i); } return result; } private copy( sourceArray: number[], sourceIndex: number, destinationArray: number[], destinationIndex: number, length: number): number[] { for (let i: number = 0; i < length; i++) { destinationArray[destinationIndex + i] = sourceArray[sourceIndex + i]; } return destinationArray; } private DataMatrixEncoder(dataCodeword: number[]): number[] { const result: number[] = new Array(dataCodeword.length); let index: number = 0; for (let i: number = 0; i < dataCodeword.length; i++) { //checks the codeword is digit or not. if (dataCodeword[parseInt(i.toString(), 10)] >= 48 && dataCodeword[parseInt(i.toString(), 10)] <= 57) { let prevIndex: number = 0; if (i !== 0) { prevIndex = index - 1; } const prevValue: number = (result[parseInt(prevIndex.toString(), 10)] - 1); let priorValue: number = 0; if (i !== 0 && index !== 1) { priorValue = result[prevIndex - 1]; } //Check the prevValue is digit or non convertable value //if it is true ,then combine the 2 digits if (priorValue !== 235 && prevValue >= 48 && prevValue <= 57) { //Bug 851922: DataMatrix barcode not working for alphanumeric value // Modified (prevValue - 0) into (prevValue - 48) for proper calculation as the '0' corresponds to the decimal value 48 in the ASCII table. result[parseInt(prevIndex.toString(), 10)] = (10 * (prevValue - 48) + (dataCodeword[parseInt(i.toString(), 10)] - 48) + 130); } else { result[parseInt(index.toString(), 10)] = (dataCodeword[parseInt(i.toString(), 10)] + 1); index++; } } else if (dataCodeword[parseInt(i.toString(), 10)] < 127) { result[parseInt(index.toString(), 10)] = (dataCodeword[parseInt(i.toString(), 10)] + 1); index++; } else { result[parseInt(index.toString(), 10)] = (((dataCodeword[parseInt(i.toString(), 10)] - 127))); index++; } } let encodedData: number[] = Array(index); encodedData = this.fillZero(encodedData); //Bug 851922: DataMatrix barcode not working for alphanumeric value // Modified the "encodedData = result" code into below for proper assignement of value from result to encodedData. for (let i: number = 0; i < index; i++) { encodedData[parseInt(i.toString(), 10)] = result[parseInt(i.toString(), 10)]; } return encodedData; } private PrepareDataCodeword(dataCodeword: number[]): number[] | string { if (this.encodingValue === 'Auto' || this.encodingValue === 'ASCIINumeric') { let number: boolean = true; // eslint-disable-next-line const extended: boolean = false; // eslint-disable-next-line const num: number = 0; const data: number[] = dataCodeword; let encoding: string = 'ASCII'; for (let i: number = 0; i < data.length; i++) { if ((data[parseInt(i.toString(), 10)] < 48) || (data[parseInt(i.toString(), 10)] > 57)) { number = false; } } if (number) { encoding = 'ASCIINumeric'; } if (this.encodingValue === 'ASCIINumeric' && this.encodingValue !== encoding) { return 'Data contains invalid characters and cannot be encoded as ASCIINumeric.'; } this.encodingValue = encoding as DataMatrixEncoding; } let result: number[] = []; switch (this.encodingValue) { case 'ASCII': result = this.DataMatrixEncoder(dataCodeword); break; case 'ASCIINumeric': result = this.DataMatrixNumericEncoder(dataCodeword); break; case 'Base256': result = this.DataMatrixBaseEncoder(dataCodeword); break; } return result; } private PdfDataMatrixSymbolAttribute( symbolRow: number, symbolColumn: number, horizontalDataRegion: number, verticalDataRegion: number, dataCodewords: number, correctionCodewords: number, interleavedBlock: number, interleavedDataBlock: number): PdfDataMatrixSymbolAttribute { const mSymbolAttribute: PdfDataMatrixSymbolAttribute = { SymbolRow: symbolRow, SymbolColumn: symbolColumn, HorizontalDataRegion: horizontalDataRegion, VerticalDataRegion: verticalDataRegion, DataCodewords: dataCodewords, CorrectionCodewords: correctionCodewords, InterleavedBlock: interleavedBlock, InterleavedDataBlock: interleavedDataBlock }; return mSymbolAttribute; } private getmSymbolAttributes(): PdfDataMatrixSymbolAttribute[] { const getmSymbolAttributeValue: PdfDataMatrixSymbolAttribute[] = []; getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(10, 10, 1, 1, 3, 5, 1, 3)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(12, 12, 1, 1, 5, 7, 1, 5)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(14, 14, 1, 1, 8, 10, 1, 8)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(16, 16, 1, 1, 12, 12, 1, 12)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(18, 18, 1, 1, 18, 14, 1, 18)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(20, 20, 1, 1, 22, 18, 1, 22)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(22, 22, 1, 1, 30, 20, 1, 30)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(24, 24, 1, 1, 36, 24, 1, 36)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(26, 26, 1, 1, 44, 28, 1, 44)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(32, 32, 2, 2, 62, 36, 1, 62)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(36, 36, 2, 2, 86, 42, 1, 86)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(40, 40, 2, 2, 114, 48, 1, 114)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(44, 44, 2, 2, 144, 56, 1, 144)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(48, 48, 2, 2, 174, 68, 1, 174)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(52, 52, 2, 2, 204, 84, 2, 102)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(64, 64, 4, 4, 280, 112, 2, 140)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(72, 72, 4, 4, 368, 144, 4, 92)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(80, 80, 4, 4, 456, 192, 4, 114)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(88, 88, 4, 4, 576, 224, 4, 144)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(96, 96, 4, 4, 696, 272, 4, 174)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(104, 104, 4, 4, 816, 336, 6, 136)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(120, 120, 6, 6, 1050, 408, 6, 175)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(132, 132, 6, 6, 1304, 496, 8, 163)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(144, 144, 6, 6, 1558, 620, 10, 156)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(8, 18, 1, 1, 5, 7, 1, 5)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(8, 32, 2, 1, 10, 11, 1, 10)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(12, 26, 1, 1, 16, 14, 1, 16)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(12, 36, 2, 1, 22, 18, 1, 22)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(16, 36, 2, 1, 32, 24, 1, 32)); getmSymbolAttributeValue.push(this.PdfDataMatrixSymbolAttribute(16, 48, 2, 1, 49, 28, 1, 49)); return getmSymbolAttributeValue; } private PadCodewords(dataCWLength: number, temp: number[], codeword: number[]): number[] { let l: number = temp.length; const ms: number[] = []; for (let i: number = 0; i < l; i++) { ms.push(temp[parseInt(i.toString(), 10)]); } if (l < dataCWLength) { ms.push(129); } l = ms.length; while (l < dataCWLength) { // more padding let v: number = 129 + (((l + 1) * 149) % 253) + 1; // see Annex H if (v > 254) { v -= 254; } ms.push(v); l = ms.length; } codeword = Array(ms.length); codeword = ms; return codeword; } private EccProduct(a: number, b: number): number { if (a === 0 || b === 0) { return 0; } let mLog: number[] = Array(256); mLog = this.CreateLogArrays(true); let mALog: number[] = Array(256); mALog = this.CreateLogArrays(false); return mALog[(mLog[parseInt(a.toString(), 10)] + mLog[parseInt(b.toString(), 10)]) % 255]; } /** * Validate the given input to check whether the input is valid one or not.\ * * @returns {boolean | string} Validate the given input to check whether the input is valid one or not . * @param {HTMLElement} char - Provide the canvas element . * @param {HTMLElement} characters - Provide the canvas element . * @private */ // eslint-disable-next-line private validateInput(char: string, characters: string): boolean | string { return char; } private ComputeErrorCorrection(): number[] | string { let dataLength: number = this.encodedCodeword.length; this.mSymbolAttribute = this.PdfDataMatrixSymbolAttribute(0, 0, 0, 0, 0, 0, 0, 0); let mSymbolAttributes: PdfDataMatrixSymbolAttribute[] = this.getmSymbolAttributes(); if (!this.size) { mSymbolAttributes = this.getmSymbolAttributes(); for (let i: number = 0; i < mSymbolAttributes.length; i++) { const attr: PdfDataMatrixSymbolAttribute = mSymbolAttributes[parseInt(i.toString(), 10)]; if (attr.DataCodewords >= dataLength) { this.mSymbolAttribute = attr; break; } } } else { this.mSymbolAttribute = mSymbolAttributes[this.size - 1]; } let temp: number[]; if (this.mSymbolAttribute.DataCodewords > dataLength) { temp = this.PadCodewords(this.mSymbolAttribute.DataCodewords, (this.encodedCodeword as number[]), temp); this.encodedCodeword = Array(temp.length); this.encodedCodeword = temp; dataLength = this.encodedCodeword.length; } else if (this.mSymbolAttribute.DataCodewords === 0) { return (this.validateInput('Data cannot be encoded as barcode', undefined) as string); } else if (this.mSymbolAttribute.DataCodewords < dataLength) { // eslint-disable-next-line const r: string = this.mSymbolAttribute.SymbolRow.toString(); // eslint-disable-next-line const c: string = this.mSymbolAttribute.SymbolColumn.toString(); return 'Data too long for {0}x{1} barcode.'; } const k: number = this.mSymbolAttribute.CorrectionCodewords; let ctArray: number[] = []; ctArray = this.create1DMatrixArray(k + this.mSymbolAttribute.DataCodewords, ctArray); const step: number = this.mSymbolAttribute.InterleavedBlock; const symbolDataWords: number = this.mSymbolAttribute.DataCodewords; const blockErrorWords: number = this.mSymbolAttribute.CorrectionCodewords / step; const total: number = symbolDataWords + blockErrorWords * step; const mrsPolynomial: number[] = this.CreateRSPolynomial(step, this.mSymbolAttribute); const mBlockLength: number = 68; let b: number[] = []; b = this.create1DMatrixArray(mBlockLength, b); for (let block: number = 0; block < step; block++) { for (let bI: number = 0; bI < b.length; bI++) { b[parseInt(bI.toString(), 10)] = 0; } for (let i: number = block; i < symbolDataWords; i += step) { const val: number = this.EccSum(b[blockErrorWords - 1], (this.encodedCodeword[parseInt(i.toString(), 10)] as number)); for (let j: number = blockErrorWords - 1; j > 0; j--) { b[parseInt(j.toString(), 10)] = this.EccSum(b[j - 1], this.EccProduct(mrsPolynomial[parseInt(j.toString(), 10)], val)); } b[0] = this.EccProduct(mrsPolynomial[0], val); } let blockDataWords: number = 0; if (block >= 8 && this.size & DataMatrixSize.Size144x144) { blockDataWords = this.mSymbolAttribute.DataCodewords / step; } else { blockDataWords = this.mSymbolAttribute.InterleavedDataBlock; let bIndex: number = blockErrorWords; for (let i: number = block + (step * blockDataWords); i < total; i += step) { ctArray[parseInt(i.toString(), 10)] = b[--bIndex]; } if (bIndex !== 0) { return 'Error in error correction code generation!'; } } } if (ctArray.length > k) { const tmp: number[] = ctArray; ctArray = []; ctArray = this.create1DMatrixArray(k, ctArray); let z: number = 0; for (let i: number = tmp.length - 1; i > this.mSymbolAttribute.DataCodewords; i--) { ctArray[z++] = tmp[parseInt(i.toString(), 10)]; } } return ctArray.reverse(); } private CreateLogArrays(value: boolean): number[] { const mLog: number[] = Array(256); const maLog: number[] = Array(256); mLog[0] = -255; maLog[0] = 1; for (let i: number = 1; i <= 255; i++) { maLog[parseInt(i.toString(), 10)] = maLog[i - 1] * 2; if (maLog[parseInt(i.toString(), 10)] >= 256) { maLog[parseInt(i.toString(), 10)] = maLog[parseInt(i.toString(), 10)] ^ 301; } mLog[maLog[parseInt(i.toString(), 10)]] = i; } if (value) { return mLog; } else { return maLog; } } private EccSum(a: number, b: number): number { return (a ^ b); } private EccDoublify(a: number, b: number): number { if (a === 0) { return 0; } if (b === 0) { return a; } let mLog: number[] = Array(256); mLog = this.CreateLogArrays(true); let maLog: number[] = Array(256); maLog = this.CreateLogArrays(false); return maLog[(mLog[parseInt(a.toString(), 10)] + b) % 255]; } private CreateRSPolynomial(step: number, mSymbolAttribute: PdfDataMatrixSymbolAttribute): number[] { const mBlockLength: number = 69; const mrsPolynomial: number[] = Array(mBlockLength); const blockErrorWords: number = mSymbolAttribute.CorrectionCodewords / step; for (let i: number = 0; i < mrsPolynomial.length; i++) { mrsPolynomial[parseInt(i.toString(), 10)] = 0x01; } for (let i: number = 1; i <= blockErrorWords; i++) { for (let j: number = i - 1; j >= 0; j--) { mrsPolynomial[parseInt(j.toString(), 10)] = this.EccDoublify(mrsPolynomial[parseInt(j.toString(), 10)], i); if (j > 0) { mrsPolynomial[parseInt(j.toString(), 10)] = this.EccSum(mrsPolynomial[parseInt(j.toString(), 10)], mrsPolynomial[j - 1]); } } } return mrsPolynomial; } private PrepareCodeword(dataCodeword: number[]): number[] | string { this.encodedCodeword = this.PrepareDataCodeword(dataCodeword); if (isNaN((this.encodedCodeword[0] as number))) { return this.encodedCodeword; } const correctCodeword: string | number[] = this.ComputeErrorCorrection(); if ((isNaN(correctCodeword[0] as number))) { return correctCodeword as string; } this.encodedCodeword = (this.encodedCodeword as number[]); const finalCodeword: number[] = Array(this.encodedCodeword.length + (correctCodeword as number[]).length); this.copyArray(finalCodeword, 0, this.encodedCodeword); this.copyArray(finalCodeword, this.encodedCodeword.length, (correctCodeword as number[])); return finalCodeword; } private copyArray(array: number[], index: number, correctCodeword: number[]): void { for (let i: number = 0; i < correctCodeword.length; i++) { array[index + i] = correctCodeword[parseInt(i.toString(), 10)]; } } private ecc200placementbit(array: number[], NR: number, NC: number, r: number, c: number, p: number, b: number): void { if (r < 0) { r += NR; c += 4 - ((NR + 4) % 8); } if (c < 0) { c += NC; r += 4 - ((NC + 4) % 8); } array[r * NC + c] = (p << 3) + b; } private ecc200placementblock(array: number[], NR: number, NC: number, r: number, c: number, p: number): void { this.ecc200placementbit(array, NR, NC, r - 2, c - 2, p, 7); this.ecc200placementbit(array, NR, NC, r - 2, c - 1, p, 6); this.ecc200placementbit(array, NR, NC, r - 1, c - 2, p, 5); this.ecc200placementbit(array, NR, NC, r - 1, c - 1, p, 4); this.ecc200placementbit(array, NR, NC, r - 1, c - 0, p, 3); this.ecc200placementbit(array, NR, NC, r - 0, c - 2, p, 2); this.ecc200placementbit(array, NR, NC, r - 0, c - 1, p, 1); this.ecc200placementbit(array, NR, NC, r - 0, c - 0, p, 0); } private ecc200placementcornerD(array: number[], NR: number, NC: number, p: number): void { this.ecc200placementbit(array, NR, NC, NR - 1, 0, p, 7); this.ecc200placementbit(array, NR, NC, NR - 1, NC - 1, p, 6); this.ecc200placementbit(array, NR, NC, 0, NC - 3, p, 5); this.ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4); this.ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3); this.ecc200placementbit(array, NR, NC, 1, NC - 3, p, 2); this.ecc200placementbit(array, NR, NC, 1, NC - 2, p, 1); this.ecc200placementbit(array, NR, NC, 1, NC - 1, p, 0); } private ecc200placementcornerA(array: number[], NR: number, NC: number, p: number): void { this.ecc200placementbit(array, NR, NC, NR - 1, 0, p, 7); this.ecc200placementbit(array, NR, NC, NR - 1, 1, p, 6); this.ecc200placementbit(array, NR, NC, NR - 1, 2, p, 5); const value: number = 4; this.ecc200placementbit(array, NR, NC, 0, NC - 2, p, value); this.ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3); const value1: number = 2; this.ecc200placementbit(array, NR, NC, 1, NC - 1, p, value1); this.ecc200placementbit(array, NR, NC, 2, NC - 1, p, 1); this.ecc200placementbit(array, NR, NC, 3, NC - 1, p, 0); } private ecc200placementcornerB(array: number[], NR: number, NC: number, p: number): void { const value: number = 7; this.ecc200placementbit(array, NR, NC, NR - 3, 0, p, value); this.ecc200placementbit(array, NR, NC, NR - 2, 0, p, 6); this.ecc200placementbit(array, NR, NC, NR - 1, 0, p, 5); this.ecc200placementbit(array, NR, NC, 0, NC - 4, p, 4); this.ecc200placementbit(array, NR, NC, 0, NC - 3, p, 3); this.ecc200placementbit(array, NR, NC, 0, NC - 2, p, 2); this.ecc200placementbit(array, NR, NC, 0, NC - 1, p, 1); this.ecc200placementbit(array, NR, NC, 1, NC - 1, p, 0); } private ecc200placementcornerC(array: number[], NR: number, NC: number, p: number): void { this.ecc200placementbit(array, NR, NC, NR - 3, 0, p, 7); this.ecc200placementbit(array, NR, NC, NR - 2, 0, p, 6); this.ecc200placementbit(array, NR, NC, NR - 1, 0, p, 5); this.ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4); this.ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3); this.ecc200placementbit(array, NR, NC, 1, NC - 1, p, 2); this.ecc200placementbit(array, NR, NC, 2, NC - 1, p, 1); this.ecc200placementbit(array, NR, NC, 3, NC - 1, p, 0); } private ecc200placement(array: number[], NR: number, NC: number): void { let r: number; let c: number; let p: number; for (let r: number = 0; r < NR; r++) { for (let c: number = 0; c < NC; c++) { array[r * NC + c] = 0; } } p = 1; r = 4; c = 0; do { // check corner if (r === NR && !(c !== 0)) { this.ecc200placementcornerA(array, NR, NC, p++); } if ((r === NR - 2) && !(c !== 0) && ((NC % 4) !== 0)) { this.ecc200placementcornerB(array, NR, NC, p++); } if (r === NR - 2 && !(c !== 0) && (NC % 8) === 4) { this.ecc200placementcornerC(array, NR, NC, p++); } if (r === NR + 4 && c === 2 && !((NC % 8) !== 0)) { this.ecc200placementcornerD(array, NR, NC, p++); } // up/right do { if (r < NR && c >= 0 && !(array[r * NC + c] !== 0)) { this.ecc200placementblock(array, NR, NC, r, c, p++); } r -= 2; c += 2; } while (r >= 0 && c < NC); r++; c += 3; // down/left do { if (r >= 0 && c < NC && !(array[r * NC + c] !== 0)) { this.ecc200placementblock(array, NR, NC, r, c, p++); } r += 2; c -= 2; } while (r < NR && c >= 0); r += 3; c++; } while (r < NR || c < NC); // unfilled corner if (!(array[NR * NC - 1] !== 0)) { array[NR * NC - 1] = array[NR * NC - NC - 2] = 1; } } private getActualRows(): number { return this.mSymbolAttribute.SymbolRow + (QuietZone.All); } private getActualColumns(): number { return this.mSymbolAttribute.SymbolColumn + (QuietZone.All); } private AddQuiteZone(tempArray2: number[][]): void { this.actualRows = this.getActualRows(); this.actualColumns = this.getActualColumns(); const w: number = this.actualRows; const h: number = this.actualColumns; const quietZone: number = QuietZone.All - 1; this.mDataMatrixArray = this.create2DMartixArray(w, h, this.mDataMatrixArray); // Top quietzone. for (let i: number = 0; i < h; i++) { this.mDataMatrixArray[0][parseInt(i.toString(), 10)] = 0; } for (let i: number = quietZone; i < w - quietZone; i++) { // Left quietzone. this.mDataMatrixArray[parseInt(i.toString(), 10)][0] = 0; for (let j: number = quietZone; j < h - quietZone; j++) { this.mDataMatrixArray[parseInt(i.toString(), 10)][parseInt(j.toString(), 10)] = tempArray2[i - quietZone][j - quietZone]; } // Right quietzone. this.mDataMatrixArray[parseInt(i.toString(), 10)][h - quietZone] = 0; } //Bottom quietzone. for (let i: number = 0; i < h; i++) { this.mDataMatrixArray[w - quietZone][parseInt(i.toString(), 10)] = 0; } } private drawImage( canvas: HTMLCanvasElement, options: BaseAttributes[]) : void { // render image for the datamtrix generator const barcodeRenderer: BarcodeRenderer = this.getInstance(canvas.id); for (let i: number = 0; i < options.length; i++) { barcodeRenderer.renderRectElement(canvas as HTMLCanvasElement, options[parseInt(i.toString(), 10)]); } } private CreateMatrix(codeword: number[]): void { let x: number; let y: number; // let NC: number; // let NR: number; // const places: number[]; const W: number = this.mSymbolAttribute.SymbolColumn; const H: number = this.mSymbolAttribute.SymbolRow; const FW: number = W / this.mSymbolAttribute.HorizontalDataRegion; const FH: number = H / this.mSymbolAttribute.VerticalDataRegion; const NC: number = W - 2 * (W / FW); const NR: number = H - 2 * (H / FH); const places: number[] = Array(NC * NR); this.ecc200placement(places, NR, NC); let matrix: number[] = []; matrix = this.create1DMatrixArray(W * H, matrix); for (let y: number = 0; y < H; y += FH) { for (let x: number = 0; x < W; x++) { matrix[y * W + x] = 1; } for (let x: number = 0; x < W; x += 2) { matrix[(y + FH - 1) * W + x] = 1; } } for (x = 0; x < W; x += FW) { for (y = 0; y < H; y++) { matrix[y * W + x] = 1; } for (y = 0; y < H; y += 2) { matrix[y * W + x + FW - 1] = 1; } } for (let y: number = 0; y < NR; y++) { for (let x: number = 0; x < NC; x++) { const v: number = places[(NR - y - 1) * NC + x]; if (v === 1 || v > 7 && (codeword[(v >> 3) - 1] & (1 << (v & 7))) !== 0) { matrix[(1 + Math.floor(y) + 2 * Math.floor(Math.floor(y) / Math.floor(FH - 2))) * Math.floor(W) + 1 + Math.floor(x) + 2 * Math.floor(Math.floor(x) / Math.floor(FW - 2))] = 1; } } } const w: number = this.mSymbolAttribute.SymbolColumn; const h: number = this.mSymbolAttribute.SymbolRow; let tempArray: number[][] = []; tempArray = this.create2DMartixArray(w, h, tempArray); for (let x1: number = 0; x1 < w; x1++) { for (let y1: number = 0; y1 < h; y1++) { tempArray[parseInt(x1.toString(), 10)][parseInt(y1.toString(), 10)] = matrix[w * y1 + x1]; } } let tempArray2: number[][] = []; tempArray2 = this.create2DMartixArray(w, h, tempArray2); for (let i: number = 0; i < h; i++) { for (let j: number = 0; j < w; j++) { tempArray2[h - 1 - i][parseInt(j.toString(), 10)] = tempArray[parseInt(j.toString(), 10)][parseInt(i.toString(), 10)]; } } this.AddQuiteZone(tempArray2); } private create1DMatrixArray(w: number, tempArray: number[]): number[] { for (let i: number = 0; i < w; i++) { tempArray[parseInt(i.toString(), 10)] = 0; } return tempArray; } private create2DMartixArray(w: number, h: number, tempArray: number[][]): number[][] { for (let i: number = 0; i < w; i++) { tempArray.push([i]); for (let j: number = 0; j < h; j++) { tempArray[parseInt(i.toString(), 10)][parseInt(j.toString(), 10)] = 0; } } return tempArray; } /** * Build the datamatrix.\ * * @returns {number[] | string} Build the datamatrix . * @private */ public BuildDataMatrix(): number[] | string { let codeword: number[] | string = []; codeword = (this.PrepareCodeword(this.GetData())); if ((isNaN(codeword[0] as number))) { return (codeword as string); } else { this.CreateMatrix(codeword as number[]); return this.mDataMatrixArray[0]; } } private drawText(canvas: HTMLCanvasElement, options: BaseAttributes): void { const barcodeRenderer: BarcodeRenderer = this.getInstance(canvas.id); barcodeRenderer.renderTextElement(canvas as HTMLCanvasElement, options); } private getInstance(id: string): BarcodeRenderer { const barCode: HTMLElement = document.getElementById(id); const barcodeRenderer: BarcodeRenderer = new BarcodeRenderer(barCode.id, this.isSvgMode); return barcodeRenderer; } private drawDisplayText( canvas: HTMLCanvasElement, x: number, y: number, width: number, height: number, scaleValue: number, foreColor: string): BaseAttributes { const displayText: DisplayTextModel = this.displayText; createMeasureElements(); const textOptions: BaseAttributes = getBaseAttributes(width, height, x, y, 'black'); textOptions.string = (displayText.text ? displayText.text : this.value); textOptions.fontStyle = displayText.font; textOptions.color = foreColor; textOptions.stringSize = displayText.size; textOptions.visibility = displayText.visibility; let textSize: Size = measureText(textOptions); if (!this.isSvgMode) { textSize = { width: textSize.width * scaleValue, height: textSize.height * scaleValue }; } const textHeight: number = (textSize.height / 2) + (this.isSvgMode ? 2 : 2 * 1.5); textOptions.height = textHeight; if (width > textSize.width) { if (this.displayText.alignment === 'Center') { textOptions.x += (((x + width - x)) / 2) - textSize.width * .5; } else if (this.displayText.alignment === 'Left') { textOptions.x = x + this.displayText.margin.left; } else { textOptions.x = (((this.width as number) - this.margin.left) - textSize.width) - this.displayText.margin.right; } } if (textOptions.x < x) { textOptions.x = x; } if (this.displayText.position === 'Bottom') { if (this.displayText.margin.top > 0) { textOptions.y = ((y + height)); } if (this.displayText.margin.bottom > 0) { textOptions.y = ((y + height)) - displayText.margin.bottom; } else { if (this.margin.top < 10) { textOptions.y = height + textSize.height / 2; } else { textOptions.y = height + this.margin.top; } } } else { if (this.displayText.margin.top > 0) { textOptions.y = y + this.displayText.margin.top + textSize.height / 2; } else { textOptions.y = y + textSize.height / 2; } } if (this.displayText.visibility) { if (!this.isSvgMode) { textOptions.stringSize = textOptions.stringSize * 1.5; } this.drawText(canvas as HTMLCanvasElement, textOptions); } return textOptions; } private getDrawableSize(margin: MarginModel, actualWidth: number, actualHeight: number): Rect | number { const barcodeSize: number = (actualWidth >= actualHeight) ? actualHeight : actualWidth; return barcodeSize; } /** * Draw the barcode SVG.\ * * @returns {void} Draw the barcode SVG . * @param {HTMLElement} canvas - Provide the canvas element . * @private */ public draw(canvas: HTMLElement): void { const scaleValue: number = 1.5; const isSvg: boolean = this.isSvgMode; const isSquareMatrix: boolean = this.size < 25; let dimension: number = this.mDataMatrixArray.length; const width: number = (this.width as number); const height: number = (this.height as number); let dimensionX: number; let dimensionY: number; const leftValue: number = this.margin.left; const rightValue: number = this.margin.right; const topValue: number = this.margin.top; const bottomVal: number = this.margin.bottom; const actualWidth: number = width - ((isSvg ? leftValue : leftValue * scaleValue) + (isSvg ? rightValue : rightValue * scaleValue)); let actualHeight: number = height - ((isSvg ? topValue : topValue * scaleValue) + (isSvg ? bottomVal : bottomVal * scaleValue)); let size: number = (this.getDrawableSize(this.margin, actualWidth, actualHeight) as number); size = (actualWidth >= actualHeight) ? actualHeight : actualWidth; let x: number = (actualWidth - size) / 2; let y: number = (actualHeight - size) / 2; y += isSvg ? this.margin.top : this.margin.top * scaleValue; x += isSvg ? this.margin.left : this.margin.left * scaleValue; const textBounds: BaseAttributes = this.drawDisplayText( canvas as HTMLCanvasElement, x, y, size, actualHeight, scaleValue, this.foreColor); actualHeight -= (textBounds.height); if (this.displayText.margin.bottom > 0) { if (this.displayText.position === 'Top') { y += (this.displayText.margin.bottom); actualHeight -= (this.displayText.margin.bottom); } else { actualHeight -= this.displayText.margin.bottom; } } if (this.displayText.margin.top > 0) { if (this.displayText.position === 'Top') { y += (this.displayText.margin.top); actualHeight -= (this.displayText.margin.top); } else { actualHeight -= this.displayText.margin.top; } } size = (actualWidth >= actualHeight) ? actualHeight : actualWidth; if (!isSquareMatrix) { dimensionX = size / this.mDataMatrixArray[0].length; dimensionY = size / this.mDataMatrixArray.length; } dimension = size / this.mDataMatrixArray.length; const w: number = this.actualRows; const h: number = this.actualColumns; let option: BaseAttributes; const options: BaseAttributes[] = []; for (let i: number = 0; i < w; i++) { for (let j: number = 0; j < h; j++) { let color: string; if (this.mDataMatrixArray[parseInt(i.toString(), 10)][parseInt(j.toString(), 10)] === 1) { color = this.foreColor; } else { color = 'white'; } if (color !== 'white') { option = getBaseAttributes( isSquareMatrix ? dimension : dimensionX, isSquareMatrix ? dimension : dimensionY, x, this.displayText.position === 'Bottom' ? y : y + textBounds.height / 2, color); options.push(option); } x = x + (isSquareMatrix ? dimension : dimensionX); } y = y + (isSquareMatrix ? dimension : dimensionY); x = ((actualWidth - size) / 2) + (isSvg ? this.margin.left : this.margin.left * scaleValue); } this.drawImage(canvas as HTMLCanvasElement, options); this.mDataMatrixArray = undefined; } }