@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
text/typescript
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;
}
}