From d83348ca96aca7dfa35a6c622035b583b10a421c Mon Sep 17 00:00:00 2001
From: Erik Hughes
Date: Sat, 7 Nov 2020 19:56:17 +0100
Subject: [PATCH 01/53] feat: add image data luminance source
---
src/core/ImageDataLuminanceSource.ts | 169 ++++++++++++++++++++++
src/index.ts | 1 +
src/test/core/ImageDataLuminanceSource.ts | 21 +++
3 files changed, 191 insertions(+)
create mode 100644 src/core/ImageDataLuminanceSource.ts
create mode 100644 src/test/core/ImageDataLuminanceSource.ts
diff --git a/src/core/ImageDataLuminanceSource.ts b/src/core/ImageDataLuminanceSource.ts
new file mode 100644
index 00000000..0beefaa6
--- /dev/null
+++ b/src/core/ImageDataLuminanceSource.ts
@@ -0,0 +1,169 @@
+import InvertedLuminanceSource from '../core/InvertedLuminanceSource';
+import LuminanceSource from '../core/LuminanceSource';
+import IllegalArgumentException from '../core/IllegalArgumentException';
+
+/**
+* Used instead of HTMLCanvasElementLuminanceSource in cases where DOM is not available e.g. web workers.
+*/
+export default class ImageDataLuminanceSource extends LuminanceSource {
+ private buffer: Uint8ClampedArray;
+
+ public constructor(imageData: ImageData) {
+ super(imageData.width, imageData.height);
+ this.buffer = ImageDataLuminanceSource.toGrayscaleBuffer(imageData.data, imageData.width, imageData.height);
+ }
+
+ private static toGrayscaleBuffer(imageBuffer: Uint8ClampedArray, width: number, height: number): Uint8ClampedArray {
+ const grayscaleBuffer = new Uint8ClampedArray(width * height);
+ for (let i = 0, j = 0, length = imageBuffer.length; i < length; i += 4, j++) {
+ let gray;
+ const alpha = imageBuffer[i + 3];
+ // The color of fully-transparent pixels is irrelevant. They are often, technically, fully-transparent
+ // black (0 alpha, and then 0 RGB). They are often used, of course as the "white" area in a
+ // barcode image. Force any such pixel to be white:
+ if (alpha === 0) {
+ gray = 0xFF;
+ } else {
+ const pixelR = imageBuffer[i];
+ const pixelG = imageBuffer[i + 1];
+ const pixelB = imageBuffer[i + 2];
+ // .299R + 0.587G + 0.114B (YUV/YIQ for PAL and NTSC),
+ // (306*R) >> 10 is approximately equal to R*0.299, and so on.
+ // 0x200 >> 10 is 0.5, it implements rounding.
+ gray = (306 * pixelR +
+ 601 * pixelG +
+ 117 * pixelB +
+ 0x200) >> 10;
+ }
+ grayscaleBuffer[j] = gray;
+ }
+ return grayscaleBuffer;
+ }
+
+ public getRow(y: number, row: Uint8ClampedArray): Uint8ClampedArray {
+ if (y < 0 || y >= this.getHeight()) {
+ throw new IllegalArgumentException('Requested row is outside the image: ' + y);
+ }
+ const width: number = this.getWidth();
+ const start = y * width;
+ if (row === null) {
+ row = this.buffer.slice(start, start + width);
+ } else {
+ if (row.length < width) {
+ row = new Uint8ClampedArray(width);
+ }
+ // The underlying raster of image consists of bytes with the luminance values
+ // TODO: can avoid set/slice?
+ row.set(this.buffer.slice(start, start + width));
+ }
+
+ return row;
+ }
+
+ public getMatrix(): Uint8ClampedArray {
+ return this.buffer;
+ }
+
+ public isCropSupported(): boolean {
+ return true;
+ }
+
+ public crop(left: number, top: number, width: number, height: number): LuminanceSource {
+ super.crop(left, top, width, height);
+ return this;
+ }
+
+ /**
+ * This is always true, since the image is a gray-scale image.
+ *
+ * @return true
+ */
+ public isRotateSupported(): boolean {
+ return true;
+ }
+
+ public rotateCounterClockwise(): LuminanceSource {
+ this.rotate(-90);
+ return this;
+ }
+
+ public rotateCounterClockwise45(): LuminanceSource {
+ this.rotate(-45);
+ return this;
+ }
+
+ private rotate(angle: number) {
+ const length = this.buffer.length;
+ const width = this.getWidth();
+ const height = this.getHeight();
+ const radians = ImageDataLuminanceSource.degreesToRadians(angle);
+ const { width: newWidth, height: newHeight } = ImageDataLuminanceSource.expandBuffer(width, height, radians);
+ const newBuffer = new Uint8ClampedArray(newWidth * newHeight * 4);
+
+ // Loop through original buffer length
+ for (let i = 0; i < length; i += 4) {
+ // Convert index to coordinate
+ let { x, y } = ImageDataLuminanceSource.indexToCoordinate(i, width);
+ // Translate center of image to 0,0
+ x -= width / 2;
+ y -= height / 2;
+ // Rotate coordinate around 0,0 by given radians
+ let { x: rx, y: ry } = ImageDataLuminanceSource.rotateCoordinate(x, y, radians);
+ // Translate new coordinates back to new center
+ rx = Math.round(rx + newWidth / 2);
+ ry = Math.round(ry + newHeight / 2);
+ // Convert new coordinates to new index
+ const j = ImageDataLuminanceSource.coordinateToIndex(rx, ry, newWidth);
+ newBuffer[j + 0] = this.buffer[i + 0];
+ newBuffer[j + 1] = this.buffer[i + 1];
+ newBuffer[j + 2] = this.buffer[i + 2];
+ newBuffer[j + 3] = this.buffer[i + 3];
+ }
+
+ this.buffer = newBuffer;
+ return this;
+ }
+
+ public invert(): LuminanceSource {
+ return new InvertedLuminanceSource(this);
+ }
+
+ /* HELPERS */
+
+ static degreesToRadians(degrees: number) {
+ return degrees * (Math.PI / 180);
+ }
+
+ static indexToCoordinate(index: number, width: number) {
+ return {
+ x: (index / 4) % width,
+ y: (index / 4 / width) << 0
+ };
+ }
+
+ static coordinateToIndex(x: number, y: number, width: number) {
+ return (x + y * width) * 4;
+ }
+
+ static expandBuffer(width: number, height: number, radians: number) {
+ return {
+ width: Math.ceil(Math.abs(Math.cos(radians)) * width + Math.abs(Math.sin(radians)) * height),
+ height: Math.ceil(Math.abs(Math.sin(radians)) * width + Math.abs(Math.cos(radians)) * height)
+ };
+ }
+
+ static rotateCoordinate(x: number, y: number, radians: number) {
+ x = ImageDataLuminanceSource.shearHorizontal(x, y, radians);
+ y = ImageDataLuminanceSource.shearVertical(x, y, radians);
+ x = ImageDataLuminanceSource.shearHorizontal(x, y, radians);
+ return { x, y };
+ }
+
+ static shearHorizontal(x: number, y: number, radians: number) {
+ return Math.round(x + -y * Math.tan(radians / 2));
+ }
+
+ static shearVertical(x: number, y: number, radians: number) {
+ return Math.round(x * Math.sin(radians) + y);
+ }
+}
diff --git a/src/index.ts b/src/index.ts
index 372596c5..68f179ee 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -19,6 +19,7 @@ export { default as BarcodeFormat } from './core/BarcodeFormat';
export { default as Binarizer } from './core/Binarizer';
export { default as BinaryBitmap } from './core/BinaryBitmap';
export { default as DecodeHintType } from './core/DecodeHintType';
+export { default as ImageDataLuminanceSource } from './core/ImageDataLuminanceSource';
export { default as InvertedLuminanceSource } from './core/InvertedLuminanceSource';
export { default as LuminanceSource } from './core/LuminanceSource';
export { default as MultiFormatReader } from './core/MultiFormatReader';
diff --git a/src/test/core/ImageDataLuminanceSource.ts b/src/test/core/ImageDataLuminanceSource.ts
new file mode 100644
index 00000000..6bbe6443
--- /dev/null
+++ b/src/test/core/ImageDataLuminanceSource.ts
@@ -0,0 +1,21 @@
+import * as assert from 'assert';
+import AssertUtils from './util/AssertUtils';
+import { LuminanceSource } from '@zxing/library';
+import { ImageDataLuminanceSource } from '@zxing/library';
+
+describe('ImageDataLuminanceSource', () => {
+
+ // ImageData is RGBA with each being in an interval of 0-255
+ const SOURCE = new ImageDataLuminanceSource(new ImageData(Uint8ClampedArray.from([
+ 255, 0, 0, 255, /**/ 0, 255, 255, 255, /**/ 0, 0, 0, 255,
+ 0, 255, 0, 255, /**/ 255, 0, 255, 255, /**/ 0, 0, 0, 255,
+ 0, 0, 255, 255, /**/ 255, 255, 0, 255, /**/ 0, 0, 0, 255]), 3, 3));
+
+ it('testCrop', () => {
+ assert.strictEqual(SOURCE.isCropSupported(), true);
+ const cropped: LuminanceSource = SOURCE.crop(1, 1, 1, 1);
+ assert.strictEqual(cropped.getHeight(), 1);
+ assert.strictEqual(cropped.getWidth(), 1);
+ assert.strictEqual(AssertUtils.typedArraysAreEqual(Uint8ClampedArray.from([255, 0, 255, 255]), cropped.getRow(0, null)), true);
+ });
+});
From 347fc545d5107ecb9ed817d174859f92354c44e9 Mon Sep 17 00:00:00 2001
From: Erik Hughes
Date: Sat, 14 Nov 2020 19:29:49 +0100
Subject: [PATCH 02/53] refactor: removed browser support
migrated to https://github.com/zxing-js/browser
---
src/browser.ts | 13 -
src/browser/BrowserAztecCodeReader.ts | 20 -
src/browser/BrowserBarcodeReader.ts | 19 -
src/browser/BrowserCodeReader.ts | 1057 -----------------
src/browser/BrowserDatamatrixCodeReader.ts | 17 -
src/browser/BrowserMultiFormatReader.ts | 27 -
src/browser/BrowserPDF417Reader.ts | 17 -
src/browser/BrowserQRCodeReader.ts | 17 -
src/browser/BrowserQRCodeSvgWriter.ts | 168 ---
src/browser/BrowserSvgCodeWriter.ts | 180 ---
src/browser/DecodeContinuouslyCallback.ts | 7 -
.../HTMLCanvasElementLuminanceSource.ts | 140 ---
src/browser/HTMLVisualMediaElement.ts | 4 -
src/browser/VideoInputDevice.ts | 33 -
src/index.ts | 2 -
15 files changed, 1721 deletions(-)
delete mode 100644 src/browser.ts
delete mode 100644 src/browser/BrowserAztecCodeReader.ts
delete mode 100644 src/browser/BrowserBarcodeReader.ts
delete mode 100644 src/browser/BrowserCodeReader.ts
delete mode 100644 src/browser/BrowserDatamatrixCodeReader.ts
delete mode 100644 src/browser/BrowserMultiFormatReader.ts
delete mode 100644 src/browser/BrowserPDF417Reader.ts
delete mode 100644 src/browser/BrowserQRCodeReader.ts
delete mode 100644 src/browser/BrowserQRCodeSvgWriter.ts
delete mode 100644 src/browser/BrowserSvgCodeWriter.ts
delete mode 100644 src/browser/DecodeContinuouslyCallback.ts
delete mode 100644 src/browser/HTMLCanvasElementLuminanceSource.ts
delete mode 100644 src/browser/HTMLVisualMediaElement.ts
delete mode 100644 src/browser/VideoInputDevice.ts
diff --git a/src/browser.ts b/src/browser.ts
deleted file mode 100644
index 73da26fe..00000000
--- a/src/browser.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-// browser
-export * from './browser/BrowserAztecCodeReader';
-export * from './browser/BrowserBarcodeReader';
-export * from './browser/BrowserCodeReader';
-export * from './browser/BrowserDatamatrixCodeReader';
-export * from './browser/BrowserMultiFormatReader';
-export * from './browser/BrowserPDF417Reader';
-export * from './browser/BrowserQRCodeReader';
-export * from './browser/BrowserQRCodeSvgWriter';
-export * from './browser/DecodeContinuouslyCallback';
-export * from './browser/HTMLCanvasElementLuminanceSource';
-export * from './browser/HTMLVisualMediaElement';
-export * from './browser/VideoInputDevice';
diff --git a/src/browser/BrowserAztecCodeReader.ts b/src/browser/BrowserAztecCodeReader.ts
deleted file mode 100644
index d669599c..00000000
--- a/src/browser/BrowserAztecCodeReader.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { BrowserCodeReader } from './BrowserCodeReader';
-import AztecReader from '../core/aztec/AztecReader';
-
-/**
- * Aztec Code reader to use from browser.
- *
- * @class BrowserAztecCodeReader
- * @extends {BrowserCodeReader}
- */
-export class BrowserAztecCodeReader extends BrowserCodeReader {
- /**
- * Creates an instance of BrowserAztecCodeReader.
- * @param {number} [timeBetweenScansMillis=500] the time delay between subsequent decode tries
- *
- * @memberOf BrowserAztecCodeReader
- */
- public constructor(timeBetweenScansMillis: number = 500) {
- super(new AztecReader(), timeBetweenScansMillis);
- }
-}
diff --git a/src/browser/BrowserBarcodeReader.ts b/src/browser/BrowserBarcodeReader.ts
deleted file mode 100644
index ba1b1573..00000000
--- a/src/browser/BrowserBarcodeReader.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { BrowserCodeReader } from './BrowserCodeReader';
-import MultiFormatOneDReader from '../core/oned/MultiFormatOneDReader';
-import DecodeHintType from '../core/DecodeHintType';
-
-/**
- * @deprecated Moving to @zxing/browser
- *
- * Barcode reader reader to use from browser.
- */
-export class BrowserBarcodeReader extends BrowserCodeReader {
- /**
- * Creates an instance of BrowserBarcodeReader.
- * @param {number} [timeBetweenScansMillis=500] the time delay between subsequent decode tries
- * @param {Map} hints
- */
- public constructor(timeBetweenScansMillis: number = 500, hints?: Map) {
- super(new MultiFormatOneDReader(hints), timeBetweenScansMillis, hints);
- }
-}
diff --git a/src/browser/BrowserCodeReader.ts b/src/browser/BrowserCodeReader.ts
deleted file mode 100644
index 02001816..00000000
--- a/src/browser/BrowserCodeReader.ts
+++ /dev/null
@@ -1,1057 +0,0 @@
-import ArgumentException from '../core/ArgumentException';
-import BinaryBitmap from '../core/BinaryBitmap';
-import ChecksumException from '../core/ChecksumException';
-import HybridBinarizer from '../core/common/HybridBinarizer';
-import DecodeHintType from '../core/DecodeHintType';
-import FormatException from '../core/FormatException';
-import NotFoundException from '../core/NotFoundException';
-import Reader from '../core/Reader';
-import Result from '../core/Result';
-import { DecodeContinuouslyCallback } from './DecodeContinuouslyCallback';
-import { HTMLCanvasElementLuminanceSource } from './HTMLCanvasElementLuminanceSource';
-import { HTMLVisualMediaElement } from './HTMLVisualMediaElement';
-import { VideoInputDevice } from './VideoInputDevice';
-
-/**
- * @deprecated Moving to @zxing/browser
- *
- * Base class for browser code reader.
- */
-export class BrowserCodeReader {
-
- /**
- * If navigator is present.
- */
- public get hasNavigator() {
- return typeof navigator !== 'undefined';
- }
-
- /**
- * If mediaDevices under navigator is supported.
- */
- public get isMediaDevicesSuported() {
- return this.hasNavigator && !!navigator.mediaDevices;
- }
-
- /**
- * If enumerateDevices under navigator is supported.
- */
- public get canEnumerateDevices() {
- return !!(this.isMediaDevicesSuported && navigator.mediaDevices.enumerateDevices);
- }
-
- /**
- * This will break the loop.
- */
- private _stopContinuousDecode = false;
-
- /**
- * This will break the loop.
- */
- private _stopAsyncDecode = false;
-
- /**
- * Delay time between decode attempts made by the scanner.
- */
- protected _timeBetweenDecodingAttempts: number = 0;
-
- /** Time between two decoding tries in milli seconds. */
- get timeBetweenDecodingAttempts(): number {
- return this._timeBetweenDecodingAttempts;
- }
-
- /**
- * Change the time span the decoder waits between two decoding tries.
- *
- * @param {number} millis Time between two decoding tries in milli seconds.
- */
- set timeBetweenDecodingAttempts(millis: number) {
- this._timeBetweenDecodingAttempts = millis < 0 ? 0 : millis;
- }
-
- /**
- * The HTML canvas element, used to draw the video or image's frame for decoding.
- */
- protected captureCanvas: HTMLCanvasElement;
- /**
- * The HTML canvas element context.
- */
- protected captureCanvasContext: CanvasRenderingContext2D;
-
- /**
- * The HTML image element, used as a fallback for the video element when decoding.
- */
- protected imageElement: HTMLImageElement;
-
- /**
- * Should contain the current registered listener for image loading,
- * used to unregister that listener when needed.
- */
- protected imageLoadedListener: EventListener;
-
- /**
- * The stream output from camera.
- */
- protected stream: MediaStream;
-
- /**
- * The HTML video element, used to display the camera stream.
- */
- protected videoElement: HTMLVideoElement;
-
- /**
- * Should contain the current registered listener for video loaded-metadata,
- * used to unregister that listener when needed.
- */
- protected videoCanPlayListener: EventListener;
-
- /**
- * Should contain the current registered listener for video play-ended,
- * used to unregister that listener when needed.
- */
- protected videoEndedListener: EventListener;
-
- /**
- * Should contain the current registered listener for video playing,
- * used to unregister that listener when needed.
- */
- protected videoPlayingEventListener: EventListener;
-
- /**
- * Sets the hints.
- */
- set hints(hints: Map) {
- this._hints = hints || null;
- }
-
- /**
- * Sets the hints.
- */
- get hints(): Map {
- return this._hints;
- }
-
- /**
- * Creates an instance of BrowserCodeReader.
- * @param {Reader} reader The reader instance to decode the barcode
- * @param {number} [timeBetweenScansMillis=500] the time delay between subsequent successful decode tries
- *
- * @memberOf BrowserCodeReader
- */
- public constructor(protected readonly reader: Reader, protected timeBetweenScansMillis: number = 500, protected _hints?: Map) { }
-
- /**
- * Lists all the available video input devices.
- */
- public async listVideoInputDevices(): Promise {
-
- if (!this.hasNavigator) {
- throw new Error('Can\'t enumerate devices, navigator is not present.');
- }
-
- if (!this.canEnumerateDevices) {
- throw new Error('Can\'t enumerate devices, method not supported.');
- }
-
- const devices = await navigator.mediaDevices.enumerateDevices();
-
- const videoDevices: MediaDeviceInfo[] = [];
-
- for (const device of devices) {
-
- const kind = device.kind === 'video' ? 'videoinput' : device.kind;
-
- if (kind !== 'videoinput') {
- continue;
- }
-
- const deviceId = device.deviceId || (device).id;
- const label = device.label || `Video device ${videoDevices.length + 1}`;
- const groupId = device.groupId;
-
- const videoDevice = { deviceId, label, kind, groupId };
-
- videoDevices.push(videoDevice);
- }
-
- return videoDevices;
- }
-
-
- /**
- * Obtain the list of available devices with type 'videoinput'.
- *
- * @returns {Promise} an array of available video input devices
- *
- * @memberOf BrowserCodeReader
- *
- * @deprecated Use `listVideoInputDevices` instead.
- */
- public async getVideoInputDevices(): Promise {
-
- const devices = await this.listVideoInputDevices();
-
- return devices.map(d => new VideoInputDevice(d.deviceId, d.label));
- }
-
- /**
- * Let's you find a device using it's Id.
- */
- public async findDeviceById(deviceId: string): Promise {
-
- const devices = await this.listVideoInputDevices();
-
- if (!devices) {
- return null;
- }
-
- return devices.find(x => x.deviceId === deviceId);
- }
-
- /**
- * Decodes the barcode from the device specified by deviceId while showing the video in the specified video element.
- *
- * @param deviceId the id of one of the devices obtained after calling getVideoInputDevices. Can be undefined, in this case it will decode from one of the available devices, preffering the main camera (environment facing) if available.
- * @param video the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
- * @returns The decoding result.
- *
- * @memberOf BrowserCodeReader
- *
- * @deprecated Use `decodeOnceFromVideoDevice` instead.
- */
- public async decodeFromInputVideoDevice(deviceId?: string, videoSource?: string | HTMLVideoElement): Promise {
- return await this.decodeOnceFromVideoDevice(deviceId, videoSource);
- }
-
- /**
- * In one attempt, tries to decode the barcode from the device specified by deviceId while showing the video in the specified video element.
- *
- * @param deviceId the id of one of the devices obtained after calling getVideoInputDevices. Can be undefined, in this case it will decode from one of the available devices, preffering the main camera (environment facing) if available.
- * @param video the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
- * @returns The decoding result.
- *
- * @memberOf BrowserCodeReader
- */
- public async decodeOnceFromVideoDevice(deviceId?: string, videoSource?: string | HTMLVideoElement): Promise {
-
- this.reset();
-
- let videoConstraints: MediaTrackConstraints;
-
- if (!deviceId) {
- videoConstraints = { facingMode: 'environment' };
- } else {
- videoConstraints = { deviceId: { exact: deviceId } };
- }
-
- const constraints: MediaStreamConstraints = { video: videoConstraints };
-
- return await this.decodeOnceFromConstraints(constraints, videoSource);
- }
-
- /**
- * In one attempt, tries to decode the barcode from a stream obtained from the given constraints while showing the video in the specified video element.
- *
- * @param constraints the media stream constraints to get s valid media stream to decode from
- * @param video the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
- * @returns The decoding result.
- *
- * @memberOf BrowserCodeReader
- */
- public async decodeOnceFromConstraints(constraints: MediaStreamConstraints, videoSource?: string | HTMLVideoElement): Promise {
-
- const stream = await navigator.mediaDevices.getUserMedia(constraints);
-
- return await this.decodeOnceFromStream(stream, videoSource);
- }
-
- /**
- * In one attempt, tries to decode the barcode from a stream obtained from the given constraints while showing the video in the specified video element.
- *
- * @param {MediaStream} [constraints] the media stream constraints to get s valid media stream to decode from
- * @param {string|HTMLVideoElement} [video] the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
- * @returns {Promise} The decoding result.
- *
- * @memberOf BrowserCodeReader
- */
- public async decodeOnceFromStream(stream: MediaStream, videoSource?: string | HTMLVideoElement): Promise {
-
- this.reset();
-
- const video = await this.attachStreamToVideo(stream, videoSource);
- const result = await this.decodeOnce(video);
-
- return result;
- }
-
- /**
- * Continuously decodes the barcode from the device specified by device while showing the video in the specified video element.
- *
- * @param {string|null} [deviceId] the id of one of the devices obtained after calling getVideoInputDevices. Can be undefined, in this case it will decode from one of the available devices, preffering the main camera (environment facing) if available.
- * @param {string|HTMLVideoElement|null} [video] the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
- * @returns {Promise}
- *
- * @memberOf BrowserCodeReader
- *
- * @deprecated Use `decodeFromVideoDevice` instead.
- */
- public async decodeFromInputVideoDeviceContinuously(deviceId: string | null, videoSource: string | HTMLVideoElement | null, callbackFn: DecodeContinuouslyCallback): Promise {
- return await this.decodeFromVideoDevice(deviceId, videoSource, callbackFn);
- }
-
- /**
- * Continuously tries to decode the barcode from the device specified by device while showing the video in the specified video element.
- *
- * @param {string|null} [deviceId] the id of one of the devices obtained after calling getVideoInputDevices. Can be undefined, in this case it will decode from one of the available devices, preffering the main camera (environment facing) if available.
- * @param {string|HTMLVideoElement|null} [video] the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
- * @returns {Promise}
- *
- * @memberOf BrowserCodeReader
- */
- public async decodeFromVideoDevice(deviceId: string | null, videoSource: string | HTMLVideoElement | null, callbackFn: DecodeContinuouslyCallback): Promise {
-
- let videoConstraints: MediaTrackConstraints;
-
- if (!deviceId) {
- videoConstraints = { facingMode: 'environment' };
- } else {
- videoConstraints = { deviceId: { exact: deviceId } };
- }
-
- const constraints: MediaStreamConstraints = { video: videoConstraints };
-
- return await this.decodeFromConstraints(constraints, videoSource, callbackFn);
- }
-
- /**
- * Continuously tries to decode the barcode from a stream obtained from the given constraints while showing the video in the specified video element.
- *
- * @param {MediaStream} [constraints] the media stream constraints to get s valid media stream to decode from
- * @param {string|HTMLVideoElement} [video] the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
- * @returns {Promise} The decoding result.
- *
- * @memberOf BrowserCodeReader
- */
- public async decodeFromConstraints(constraints: MediaStreamConstraints, videoSource: string | HTMLVideoElement, callbackFn: DecodeContinuouslyCallback): Promise {
-
- const stream = await navigator.mediaDevices.getUserMedia(constraints);
-
- return await this.decodeFromStream(stream, videoSource, callbackFn);
- }
-
- /**
- * In one attempt, tries to decode the barcode from a stream obtained from the given constraints while showing the video in the specified video element.
- *
- * @param {MediaStream} [constraints] the media stream constraints to get s valid media stream to decode from
- * @param {string|HTMLVideoElement} [video] the video element in page where to show the video while decoding. Can be either an element id or directly an HTMLVideoElement. Can be undefined, in which case no video will be shown.
- * @returns {Promise} The decoding result.
- *
- * @memberOf BrowserCodeReader
- */
- public async decodeFromStream(stream: MediaStream, videoSource: string | HTMLVideoElement, callbackFn: DecodeContinuouslyCallback) {
-
- this.reset();
-
- const video = await this.attachStreamToVideo(stream, videoSource);
-
- return await this.decodeContinuously(video, callbackFn);
- }
-
- /**
- * Breaks the decoding loop.
- */
- public stopAsyncDecode() {
- this._stopAsyncDecode = true;
- }
-
- /**
- * Breaks the decoding loop.
- */
- public stopContinuousDecode() {
- this._stopContinuousDecode = true;
- }
-
- /**
- * Sets the new stream and request a new decoding-with-delay.
- *
- * @param stream The stream to be shown in the video element.
- * @param decodeFn A callback for the decode method.
- */
- protected async attachStreamToVideo(stream: MediaStream, videoSource: string | HTMLVideoElement): Promise {
-
- const videoElement = this.prepareVideoElement(videoSource);
-
- this.addVideoSource(videoElement, stream);
-
- this.videoElement = videoElement;
- this.stream = stream;
-
- await this.playVideoOnLoadAsync(videoElement);
-
- return videoElement;
- }
-
- /**
- *
- * @param videoElement
- */
- protected playVideoOnLoadAsync(videoElement: HTMLVideoElement): Promise {
- return new Promise((resolve, reject) => this.playVideoOnLoad(videoElement, () => resolve()));
- }
-
- /**
- * Binds listeners and callbacks to the videoElement.
- *
- * @param element
- * @param callbackFn
- */
- protected playVideoOnLoad(element: HTMLVideoElement, callbackFn: EventListener): void {
-
- this.videoEndedListener = () => this.stopStreams();
- this.videoCanPlayListener = () => this.tryPlayVideo(element);
-
- element.addEventListener('ended', this.videoEndedListener);
- element.addEventListener('canplay', this.videoCanPlayListener);
- element.addEventListener('playing', callbackFn);
-
- // if canplay was already fired, we won't know when to play, so just give it a try
- this.tryPlayVideo(element);
- }
-
- /**
- * Checks if the given video element is currently playing.
- */
- isVideoPlaying(video: HTMLVideoElement): boolean {
- return video.currentTime > 0 && !video.paused && !video.ended && video.readyState > 2;
- }
-
- /**
- * Just tries to play the video and logs any errors.
- * The play call is only made is the video is not already playing.
- */
- async tryPlayVideo(videoElement: HTMLVideoElement): Promise {
-
- if (this.isVideoPlaying(videoElement)) {
- console.warn('Trying to play video that is already playing.');
- return;
- }
-
- try {
- await videoElement.play();
- } catch {
- console.warn('It was not possible to play the video.');
- }
- }
-
- /**
- * Searches and validates a media element.
- */
- public getMediaElement(mediaElementId: string, type: string): HTMLVisualMediaElement {
-
- const mediaElement = document.getElementById(mediaElementId);
-
- if (!mediaElement) {
- throw new ArgumentException(`element with id '${mediaElementId}' not found`);
- }
-
- if (mediaElement.nodeName.toLowerCase() !== type.toLowerCase()) {
- throw new ArgumentException(`element with id '${mediaElementId}' must be an ${type} element`);
- }
-
- return mediaElement;
- }
-
- /**
- * Decodes the barcode from an image.
- *
- * @param {(string|HTMLImageElement)} [source] The image element that can be either an element id or the element itself. Can be undefined in which case the decoding will be done from the imageUrl parameter.
- * @param {string} [url]
- * @returns {Promise} The decoding result.
- *
- * @memberOf BrowserCodeReader
- */
- public decodeFromImage(source?: string | HTMLImageElement, url?: string): Promise {
-
- if (!source && !url) {
- throw new ArgumentException('either imageElement with a src set or an url must be provided');
- }
-
- if (url && !source) {
- return this.decodeFromImageUrl(url);
- }
-
- return this.decodeFromImageElement(source);
- }
-
- /**
- * Decodes the barcode from a video.
- *
- * @param {(string|HTMLImageElement)} [source] The image element that can be either an element id or the element itself. Can be undefined in which case the decoding will be done from the imageUrl parameter.
- * @param {string} [url]
- * @returns {Promise} The decoding result.
- *
- * @memberOf BrowserCodeReader
- */
- public decodeFromVideo(source?: string | HTMLVideoElement, url?: string): Promise {
-
- if (!source && !url) {
- throw new ArgumentException('Either an element with a src set or an URL must be provided');
- }
-
- if (url && !source) {
- return this.decodeFromVideoUrl(url);
- }
-
- return this.decodeFromVideoElement(source);
- }
-
- /**
- * Decodes continuously the barcode from a video.
- *
- * @param {(string|HTMLImageElement)} [source] The image element that can be either an element id or the element itself. Can be undefined in which case the decoding will be done from the imageUrl parameter.
- * @param {string} [url]
- * @returns {Promise} The decoding result.
- *
- * @memberOf BrowserCodeReader
- *
- * @experimental
- */
- public decodeFromVideoContinuously(source: string | HTMLVideoElement | null, url: string | null, callbackFn: DecodeContinuouslyCallback): Promise {
-
- if (undefined === source && undefined === url) {
- throw new ArgumentException('Either an element with a src set or an URL must be provided');
- }
-
- if (url && !source) {
- return this.decodeFromVideoUrlContinuously(url, callbackFn);
- }
-
- return this.decodeFromVideoElementContinuously(source, callbackFn);
- }
-
- /**
- * Decodes something from an image HTML element.
- */
- public decodeFromImageElement(source: string | HTMLImageElement): Promise {
-
- if (!source) {
- throw new ArgumentException('An image element must be provided.');
- }
-
- this.reset();
-
- const element = this.prepareImageElement(source);
-
- this.imageElement = element;
-
- let task: Promise;
-
- if (this.isImageLoaded(element)) {
- task = this.decodeOnce(element, false, true);
- } else {
- task = this._decodeOnLoadImage(element);
- }
-
- return task;
- }
-
- /**
- * Decodes something from an image HTML element.
- */
- public decodeFromVideoElement(source: string | HTMLVideoElement): Promise {
-
- const element = this._decodeFromVideoElementSetup(source);
-
- return this._decodeOnLoadVideo(element);
- }
-
- /**
- * Decodes something from an image HTML element.
- */
- public decodeFromVideoElementContinuously(source: string | HTMLVideoElement, callbackFn: DecodeContinuouslyCallback): Promise {
-
- const element = this._decodeFromVideoElementSetup(source);
-
- return this._decodeOnLoadVideoContinuously(element, callbackFn);
- }
-
- /**
- * Sets up the video source so it can be decoded when loaded.
- *
- * @param source The video source element.
- */
- private _decodeFromVideoElementSetup(source: string | HTMLVideoElement) {
-
- if (!source) {
- throw new ArgumentException('A video element must be provided.');
- }
-
- this.reset();
-
- const element = this.prepareVideoElement(source);
-
- // defines the video element before starts decoding
- this.videoElement = element;
-
- return element;
- }
-
- /**
- * Decodes an image from a URL.
- */
- public decodeFromImageUrl(url?: string): Promise {
-
- if (!url) {
- throw new ArgumentException('An URL must be provided.');
- }
-
- this.reset();
-
- const element = this.prepareImageElement();
-
- this.imageElement = element;
-
- const decodeTask = this._decodeOnLoadImage(element);
-
- element.src = url;
-
- return decodeTask;
- }
-
- /**
- * Decodes an image from a URL.
- */
- public decodeFromVideoUrl(url: string): Promise {
-
- if (!url) {
- throw new ArgumentException('An URL must be provided.');
- }
-
- this.reset();
-
- // creates a new element
- const element = this.prepareVideoElement();
-
- const decodeTask = this.decodeFromVideoElement(element);
-
- element.src = url;
-
- return decodeTask;
- }
-
- /**
- * Decodes an image from a URL.
- *
- * @experimental
- */
- public decodeFromVideoUrlContinuously(url: string, callbackFn: DecodeContinuouslyCallback): Promise {
-
- if (!url) {
- throw new ArgumentException('An URL must be provided.');
- }
-
- this.reset();
-
- // creates a new element
- const element = this.prepareVideoElement();
-
- const decodeTask = this.decodeFromVideoElementContinuously(element, callbackFn);
-
- element.src = url;
-
- return decodeTask;
- }
-
- private _decodeOnLoadImage(element: HTMLImageElement): Promise {
- return new Promise((resolve, reject) => {
- this.imageLoadedListener = () => this.decodeOnce(element, false, true).then(resolve, reject);
- element.addEventListener('load', this.imageLoadedListener);
- });
- }
-
- private async _decodeOnLoadVideo(videoElement: HTMLVideoElement): Promise {
- // plays the video
- await this.playVideoOnLoadAsync(videoElement);
- // starts decoding after played the video
- return await this.decodeOnce(videoElement);
- }
-
- private async _decodeOnLoadVideoContinuously(videoElement: HTMLVideoElement, callbackFn: DecodeContinuouslyCallback): Promise {
- // plays the video
- await this.playVideoOnLoadAsync(videoElement);
- // starts decoding after played the video
- this.decodeContinuously(videoElement, callbackFn);
- }
-
- public isImageLoaded(img: HTMLImageElement) {
- // During the onload event, IE correctly identifies any images that
- // werenβt downloaded as not complete. Others should too. Gecko-based
- // browsers act like NS4 in that they report this incorrectly.
- if (!img.complete) {
- return false;
- }
-
- // However, they do have two very useful properties: naturalWidth and
- // naturalHeight. These give the true size of the image. If it failed
- // to load, either of these should be zero.
-
- if (img.naturalWidth === 0) {
- return false;
- }
-
- // No other way of checking: assume itβs ok.
- return true;
- }
-
- public prepareImageElement(imageSource?: HTMLImageElement | string): HTMLImageElement {
-
- let imageElement: HTMLImageElement;
-
- if (typeof imageSource === 'undefined') {
- imageElement = document.createElement('img');
- imageElement.width = 200;
- imageElement.height = 200;
- }
-
- if (typeof imageSource === 'string') {
- imageElement = this.getMediaElement(imageSource, 'img');
- }
-
- if (imageSource instanceof HTMLImageElement) {
- imageElement = imageSource;
- }
-
- return imageElement;
- }
-
- /**
- * Sets a HTMLVideoElement for scanning or creates a new one.
- *
- * @param videoSource The HTMLVideoElement to be set.
- */
- public prepareVideoElement(videoSource?: HTMLVideoElement | string): HTMLVideoElement {
-
- let videoElement: HTMLVideoElement;
-
- if (!videoSource && typeof document !== 'undefined') {
- videoElement = document.createElement('video');
- videoElement.width = 200;
- videoElement.height = 200;
- }
-
- if (typeof videoSource === 'string') {
- videoElement = this.getMediaElement(videoSource, 'video');
- }
-
- if (videoSource instanceof HTMLVideoElement) {
- videoElement = videoSource;
- }
-
- // Needed for iOS 11
- videoElement.setAttribute('autoplay', 'true');
- videoElement.setAttribute('muted', 'true');
- videoElement.setAttribute('playsinline', 'true');
-
- return videoElement;
- }
-
- /**
- * Tries to decode from the video input until it finds some value.
- */
- public decodeOnce(element: HTMLVisualMediaElement, retryIfNotFound = true, retryIfChecksumOrFormatError = true): Promise {
-
- this._stopAsyncDecode = false;
-
- const loop = (resolve: (value?: Result | PromiseLike) => void, reject: (reason?: any) => void) => {
-
- if (this._stopAsyncDecode) {
- reject(new NotFoundException('Video stream has ended before any code could be detected.'));
- this._stopAsyncDecode = undefined;
- return;
- }
-
- try {
- const result = this.decode(element);
- resolve(result);
- } catch (e) {
-
- const ifNotFound = retryIfNotFound && e instanceof NotFoundException;
- const isChecksumOrFormatError = e instanceof ChecksumException || e instanceof FormatException;
- const ifChecksumOrFormat = isChecksumOrFormatError && retryIfChecksumOrFormatError;
-
- if (ifNotFound || ifChecksumOrFormat) {
- // trying again
- return setTimeout(loop, this._timeBetweenDecodingAttempts, resolve, reject);
- }
-
- reject(e);
- }
- };
-
- return new Promise((resolve, reject) => loop(resolve, reject));
- }
-
- /**
- * Continuously decodes from video input.
- */
- public decodeContinuously(element: HTMLVideoElement, callbackFn: DecodeContinuouslyCallback): void {
-
- this._stopContinuousDecode = false;
-
- const loop = () => {
-
- if (this._stopContinuousDecode) {
- this._stopContinuousDecode = undefined;
- return;
- }
-
- try {
- const result = this.decode(element);
- callbackFn(result, null);
- setTimeout(loop, this.timeBetweenScansMillis);
- } catch (e) {
-
- callbackFn(null, e);
-
- const isChecksumOrFormatError = e instanceof ChecksumException || e instanceof FormatException;
- const isNotFound = e instanceof NotFoundException;
-
- if (isChecksumOrFormatError || isNotFound) {
- // trying again
- setTimeout(loop, this._timeBetweenDecodingAttempts);
- }
-
- }
- };
-
- loop();
- }
-
- /**
- * Gets the BinaryBitmap for ya! (and decodes it)
- */
- public decode(element: HTMLVisualMediaElement): Result {
-
- // get binary bitmap for decode function
- const binaryBitmap = this.createBinaryBitmap(element);
-
- return this.decodeBitmap(binaryBitmap);
- }
-
- /**
- * Creates a binaryBitmap based in some image source.
- *
- * @param mediaElement HTML element containing drawable image source.
- */
- public createBinaryBitmap(mediaElement: HTMLVisualMediaElement): BinaryBitmap {
-
- const ctx = this.getCaptureCanvasContext(mediaElement);
-
- this.drawImageOnCanvas(ctx, mediaElement);
-
- const canvas = this.getCaptureCanvas(mediaElement);
-
- const luminanceSource = new HTMLCanvasElementLuminanceSource(canvas);
- const hybridBinarizer = new HybridBinarizer(luminanceSource);
-
- return new BinaryBitmap(hybridBinarizer);
- }
-
- /**
- *
- */
- protected getCaptureCanvasContext(mediaElement?: HTMLVisualMediaElement) {
-
- if (!this.captureCanvasContext) {
- const elem = this.getCaptureCanvas(mediaElement);
- const ctx = elem.getContext('2d');
- this.captureCanvasContext = ctx;
- }
-
- return this.captureCanvasContext;
- }
-
- /**
- *
- */
- protected getCaptureCanvas(mediaElement?: HTMLVisualMediaElement): HTMLCanvasElement {
-
- if (!this.captureCanvas) {
- const elem = this.createCaptureCanvas(mediaElement);
- this.captureCanvas = elem;
- }
-
- return this.captureCanvas;
- }
-
- /**
- * Ovewriting this allows you to manipulate the snapshot image in anyway you want before decode.
- */
- public drawImageOnCanvas(canvasElementContext: CanvasRenderingContext2D, srcElement: HTMLVisualMediaElement) {
- canvasElementContext.drawImage(srcElement, 0, 0);
- }
-
- /**
- * Call the encapsulated readers decode
- */
- public decodeBitmap(binaryBitmap: BinaryBitmap): Result {
- return this.reader.decode(binaryBitmap, this._hints);
- }
-
- /**
- * π Prepares the canvas for capture and scan frames.
- */
- public createCaptureCanvas(mediaElement?: HTMLVisualMediaElement): HTMLCanvasElement {
-
- if (typeof document === 'undefined') {
- this._destroyCaptureCanvas();
- return null;
- }
-
- const canvasElement = document.createElement('canvas');
-
- let width: number;
- let height: number;
-
- if (typeof mediaElement !== 'undefined') {
- if (mediaElement instanceof HTMLVideoElement) {
- width = mediaElement.videoWidth;
- height = mediaElement.videoHeight;
- } else if (mediaElement instanceof HTMLImageElement) {
- width = mediaElement.naturalWidth || mediaElement.width;
- height = mediaElement.naturalHeight || mediaElement.height;
- }
- }
-
- canvasElement.style.width = width + 'px';
- canvasElement.style.height = height + 'px';
- canvasElement.width = width;
- canvasElement.height = height;
-
- return canvasElement;
- }
-
- /**
- * Stops the continuous scan and cleans the stream.
- */
- protected stopStreams(): void {
- if (this.stream) {
- this.stream.getVideoTracks().forEach(t => t.stop());
- this.stream = undefined;
- }
- if (this._stopAsyncDecode === false) {
- this.stopAsyncDecode();
- }
- if (this._stopContinuousDecode === false) {
- this.stopContinuousDecode();
- }
- }
-
- /**
- * Resets the code reader to the initial state. Cancels any ongoing barcode scanning from video or camera.
- *
- * @memberOf BrowserCodeReader
- */
- public reset() {
-
- // stops the camera, preview and scan π΄
-
- this.stopStreams();
-
- // clean and forget about HTML elements
-
- this._destroyVideoElement();
- this._destroyImageElement();
- this._destroyCaptureCanvas();
- }
-
- private _destroyVideoElement(): void {
-
- if (!this.videoElement) {
- return;
- }
-
- // first gives freedon to the element π
-
- if (typeof this.videoEndedListener !== 'undefined') {
- this.videoElement.removeEventListener('ended', this.videoEndedListener);
- }
-
- if (typeof this.videoPlayingEventListener !== 'undefined') {
- this.videoElement.removeEventListener('playing', this.videoPlayingEventListener);
- }
-
- if (typeof this.videoCanPlayListener !== 'undefined') {
- this.videoElement.removeEventListener('loadedmetadata', this.videoCanPlayListener);
- }
-
- // then forgets about that element π’
-
- this.cleanVideoSource(this.videoElement);
-
- this.videoElement = undefined;
- }
-
- private _destroyImageElement(): void {
-
- if (!this.imageElement) {
- return;
- }
-
- // first gives freedon to the element π
-
- if (undefined !== this.imageLoadedListener) {
- this.imageElement.removeEventListener('load', this.imageLoadedListener);
- }
-
- // then forget about that element π’
-
- this.imageElement.src = undefined;
- this.imageElement.removeAttribute('src');
- this.imageElement = undefined;
- }
-
- /**
- * Cleans canvas references π
- */
- private _destroyCaptureCanvas(): void {
-
- // then forget about that element π’
-
- this.captureCanvasContext = undefined;
- this.captureCanvas = undefined;
- }
-
- /**
- * Defines what the videoElement src will be.
- *
- * @param videoElement
- * @param stream
- */
- public addVideoSource(videoElement: HTMLVideoElement, stream: MediaStream): void {
- // Older browsers may not have `srcObject`
- try {
- // @note Throws Exception if interrupted by a new loaded request
- videoElement.srcObject = stream;
- } catch (err) {
- // @note Avoid using this in new browsers, as it is going away.
- videoElement.src = URL.createObjectURL(stream);
- }
- }
-
- /**
- * Unbinds a HTML video src property.
- *
- * @param videoElement
- */
- private cleanVideoSource(videoElement: HTMLVideoElement): void {
-
- try {
- videoElement.srcObject = null;
- } catch (err) {
- videoElement.src = '';
- }
-
- this.videoElement.removeAttribute('src');
- }
-}
diff --git a/src/browser/BrowserDatamatrixCodeReader.ts b/src/browser/BrowserDatamatrixCodeReader.ts
deleted file mode 100644
index d5f86cd8..00000000
--- a/src/browser/BrowserDatamatrixCodeReader.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { BrowserCodeReader } from './BrowserCodeReader';
-import DataMatrixReader from '../core/datamatrix/DataMatrixReader';
-
-/**
- * @deprecated Moving to @zxing/browser
- *
- * QR Code reader to use from browser.
- */
-export class BrowserDatamatrixCodeReader extends BrowserCodeReader {
- /**
- * Creates an instance of BrowserQRCodeReader.
- * @param {number} [timeBetweenScansMillis=500] the time delay between subsequent decode tries
- */
- public constructor(timeBetweenScansMillis: number = 500) {
- super(new DataMatrixReader(), timeBetweenScansMillis);
- }
-}
diff --git a/src/browser/BrowserMultiFormatReader.ts b/src/browser/BrowserMultiFormatReader.ts
deleted file mode 100644
index a983f14d..00000000
--- a/src/browser/BrowserMultiFormatReader.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import { BrowserCodeReader } from './BrowserCodeReader';
-import MultiFormatReader from '../core/MultiFormatReader';
-import BinaryBitmap from '../core/BinaryBitmap';
-import Result from '../core/Result';
-import DecodeHintType from '../core/DecodeHintType';
-
-export class BrowserMultiFormatReader extends BrowserCodeReader {
-
- protected readonly reader: MultiFormatReader;
-
- public constructor(
- hints: Map = null,
- timeBetweenScansMillis: number = 500
- ) {
- const reader = new MultiFormatReader();
- reader.setHints(hints);
- super(reader, timeBetweenScansMillis);
- }
-
- /**
- * Overwrite decodeBitmap to call decodeWithState, which will pay
- * attention to the hints set in the constructor function
- */
- public decodeBitmap(binaryBitmap: BinaryBitmap): Result {
- return this.reader.decodeWithState(binaryBitmap);
- }
-}
diff --git a/src/browser/BrowserPDF417Reader.ts b/src/browser/BrowserPDF417Reader.ts
deleted file mode 100644
index ba8899a8..00000000
--- a/src/browser/BrowserPDF417Reader.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { BrowserCodeReader } from './BrowserCodeReader';
-import PDF417Reader from '../core/pdf417/PDF417Reader';
-
-/**
- * @deprecated Moving to @zxing/browser
- *
- * QR Code reader to use from browser.
- */
-export class BrowserPDF417Reader extends BrowserCodeReader {
- /**
- * Creates an instance of BrowserPDF417Reader.
- * @param {number} [timeBetweenScansMillis=500] the time delay between subsequent decode tries
- */
- public constructor(timeBetweenScansMillis: number = 500) {
- super(new PDF417Reader(), timeBetweenScansMillis);
- }
-}
diff --git a/src/browser/BrowserQRCodeReader.ts b/src/browser/BrowserQRCodeReader.ts
deleted file mode 100644
index 0af2194e..00000000
--- a/src/browser/BrowserQRCodeReader.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { BrowserCodeReader } from './BrowserCodeReader';
-import QRCodeReader from '../core/qrcode/QRCodeReader';
-
-/**
- * @deprecated Moving to @zxing/browser
- *
- * QR Code reader to use from browser.
- */
-export class BrowserQRCodeReader extends BrowserCodeReader {
- /**
- * Creates an instance of BrowserQRCodeReader.
- * @param {number} [timeBetweenScansMillis=500] the time delay between subsequent decode tries
- */
- public constructor(timeBetweenScansMillis: number = 500) {
- super(new QRCodeReader(), timeBetweenScansMillis);
- }
-}
diff --git a/src/browser/BrowserQRCodeSvgWriter.ts b/src/browser/BrowserQRCodeSvgWriter.ts
deleted file mode 100644
index c84ba10a..00000000
--- a/src/browser/BrowserQRCodeSvgWriter.ts
+++ /dev/null
@@ -1,168 +0,0 @@
-import EncodeHintType from '../core/EncodeHintType';
-import Encoder from '../core/qrcode/encoder/Encoder';
-import QRCode from '../core/qrcode/encoder/QRCode';
-import ErrorCorrectionLevel from '../core/qrcode/decoder/ErrorCorrectionLevel';
-import IllegalArgumentException from '../core/IllegalArgumentException';
-import IllegalStateException from '../core/IllegalStateException';
-
-/**
- * @deprecated Moving to @zxing/browser
- */
-class BrowserQRCodeSvgWriter {
-
- private static readonly QUIET_ZONE_SIZE = 4;
-
- /**
- * SVG markup NameSpace
- */
- private static readonly SVG_NS = 'http://www.w3.org/2000/svg';
-
- /**
- * Writes and renders a QRCode SVG element.
- *
- * @param contents
- * @param width
- * @param height
- * @param hints
- */
- public write(
- contents: string,
- width: number,
- height: number,
- hints: Map = null
- ): SVGSVGElement {
-
- if (contents.length === 0) {
- throw new IllegalArgumentException('Found empty contents');
- }
-
- // if (format != BarcodeFormat.QR_CODE) {
- // throw new IllegalArgumentException("Can only encode QR_CODE, but got " + format)
- // }
-
- if (width < 0 || height < 0) {
- throw new IllegalArgumentException('Requested dimensions are too small: ' + width + 'x' + height);
- }
-
- let errorCorrectionLevel = ErrorCorrectionLevel.L;
- let quietZone = BrowserQRCodeSvgWriter.QUIET_ZONE_SIZE;
-
- if (hints !== null) {
-
- if (undefined !== hints.get(EncodeHintType.ERROR_CORRECTION)) {
- errorCorrectionLevel = ErrorCorrectionLevel.fromString(hints.get(EncodeHintType.ERROR_CORRECTION).toString());
- }
-
- if (undefined !== hints.get(EncodeHintType.MARGIN)) {
- quietZone = Number.parseInt(hints.get(EncodeHintType.MARGIN).toString(), 10);
- }
- }
-
- const code = Encoder.encode(contents, errorCorrectionLevel, hints);
-
- return this.renderResult(code, width, height, quietZone);
- }
-
- /**
- * Renders the result and then appends it to the DOM.
- */
- public writeToDom(
- containerElement: string | HTMLElement,
- contents: string,
- width: number,
- height: number,
- hints: Map = null
- ): void {
-
- if (typeof containerElement === 'string') {
- containerElement = document.querySelector(containerElement);
- }
-
- const svgElement = this.write(contents, width, height, hints);
-
- if (containerElement)
- containerElement.appendChild(svgElement);
- }
-
- /**
- * Note that the input matrix uses 0 == white, 1 == black.
- * The output matrix uses 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap).
- */
- private renderResult(code: QRCode, width: number /*int*/, height: number /*int*/, quietZone: number /*int*/): SVGSVGElement {
-
- const input = code.getMatrix();
-
- if (input === null) {
- throw new IllegalStateException();
- }
-
- const inputWidth = input.getWidth();
- const inputHeight = input.getHeight();
- const qrWidth = inputWidth + (quietZone * 2);
- const qrHeight = inputHeight + (quietZone * 2);
- const outputWidth = Math.max(width, qrWidth);
- const outputHeight = Math.max(height, qrHeight);
-
- const multiple = Math.min(Math.floor(outputWidth / qrWidth), Math.floor(outputHeight / qrHeight));
-
- // Padding includes both the quiet zone and the extra white pixels to accommodate the requested
- // dimensions. For example, if input is 25x25 the QR will be 33x33 including the quiet zone.
- // If the requested size is 200x160, the multiple will be 4, for a QR of 132x132. These will
- // handle all the padding from 100x100 (the actual QR) up to 200x160.
- const leftPadding = Math.floor((outputWidth - (inputWidth * multiple)) / 2);
- const topPadding = Math.floor((outputHeight - (inputHeight * multiple)) / 2);
-
- const svgElement = this.createSVGElement(outputWidth, outputHeight);
-
- for (let inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++ , outputY += multiple) {
- // Write the contents of this row of the barcode
- for (let inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++ , outputX += multiple) {
- if (input.get(inputX, inputY) === 1) {
- const svgRectElement = this.createSvgRectElement(outputX, outputY, multiple, multiple);
- svgElement.appendChild(svgRectElement);
- }
- }
- }
-
- return svgElement;
- }
-
- /**
- * Creates a SVG element.
- *
- * @param w SVG's width attribute
- * @param h SVG's height attribute
- */
- private createSVGElement(w: number, h: number): SVGSVGElement {
-
- const svgElement = document.createElementNS(BrowserQRCodeSvgWriter.SVG_NS, 'svg');
-
- svgElement.setAttributeNS(null, 'height', w.toString());
- svgElement.setAttributeNS(null, 'width', h.toString());
-
- return svgElement;
- }
-
- /**
- * Creates a SVG rect element.
- *
- * @param x Element's x coordinate
- * @param y Element's y coordinate
- * @param w Element's width attribute
- * @param h Element's height attribute
- */
- private createSvgRectElement(x: number, y: number, w: number, h: number): SVGRectElement {
-
- const rect = document.createElementNS(BrowserQRCodeSvgWriter.SVG_NS, 'rect');
-
- rect.setAttributeNS(null, 'x', x.toString());
- rect.setAttributeNS(null, 'y', y.toString());
- rect.setAttributeNS(null, 'height', w.toString());
- rect.setAttributeNS(null, 'width', h.toString());
- rect.setAttributeNS(null, 'fill', '#000000');
-
- return rect;
- }
-}
-
-export { BrowserQRCodeSvgWriter };
diff --git a/src/browser/BrowserSvgCodeWriter.ts b/src/browser/BrowserSvgCodeWriter.ts
deleted file mode 100644
index 4351b225..00000000
--- a/src/browser/BrowserSvgCodeWriter.ts
+++ /dev/null
@@ -1,180 +0,0 @@
-import EncodeHintType from '../core/EncodeHintType';
-import Encoder from '../core/qrcode/encoder/Encoder';
-import QRCode from '../core/qrcode/encoder/QRCode';
-import ErrorCorrectionLevel from '../core/qrcode/decoder/ErrorCorrectionLevel';
-import IllegalArgumentException from '../core/IllegalArgumentException';
-import IllegalStateException from '../core/IllegalStateException';
-
-/**
- * @deprecated Moving to @zxing/browser
- */
-abstract class BrowserSvgCodeWriter {
-
- /**
- * Default quiet zone in pixels.
- */
- private static readonly QUIET_ZONE_SIZE = 4;
-
- /**
- * SVG markup NameSpace
- */
- private static readonly SVG_NS = 'http://www.w3.org/2000/svg';
-
- /**
- * A HTML container element for the image.
- */
- private containerElement: HTMLElement;
-
- /**
- * Constructs. π
- */
- public constructor(containerElement: string | HTMLElement) {
- if (typeof containerElement === 'string') {
- this.containerElement = document.getElementById(containerElement);
- } else {
- this.containerElement = containerElement;
- }
- }
-
- /**
- * Writes the QR code to a SVG and renders it in the container.
- */
- public write(
- contents: string,
- width: number,
- height: number,
- hints: Map = null
- ): SVGSVGElement {
-
- if (contents.length === 0) {
- throw new IllegalArgumentException('Found empty contents');
- }
-
- if (width < 0 || height < 0) {
- throw new IllegalArgumentException('Requested dimensions are too small: ' + width + 'x' + height);
- }
-
- let quietZone = hints && hints.get(EncodeHintType.MARGIN) !== undefined
- ? Number.parseInt(hints.get(EncodeHintType.MARGIN).toString(), 10)
- : BrowserSvgCodeWriter.QUIET_ZONE_SIZE;
-
- const code = this.encode(hints, contents);
-
- return this.renderResult(code, width, height, quietZone);
- }
-
- /**
- * Encodes the content to a Barcode type.
- */
- private encode(hints: Map, contents: string): QRCode {
-
- let errorCorrectionLevel = ErrorCorrectionLevel.L;
-
- if (hints && hints.get(EncodeHintType.ERROR_CORRECTION) !== undefined) {
- errorCorrectionLevel = ErrorCorrectionLevel.fromString(hints.get(EncodeHintType.ERROR_CORRECTION).toString());
- }
-
- const code = Encoder.encode(contents, errorCorrectionLevel, hints);
-
- return code;
- }
-
- /**
- * Renders the SVG in the container.
- *
- * @note the input matrix uses 0 == white, 1 == black. The output matrix uses 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap).
- */
- private renderResult(code: QRCode, width: number /*int*/, height: number /*int*/, quietZone: number /*int*/): SVGSVGElement {
-
- // if (this.format && format != this.format) {
- // throw new IllegalArgumentException("Can only encode QR_CODE, but got " + format)
- // }
-
- const input = code.getMatrix();
-
- if (input === null) {
- throw new IllegalStateException();
- }
-
- const inputWidth = input.getWidth();
- const inputHeight = input.getHeight();
- const qrWidth = inputWidth + (quietZone * 2);
- const qrHeight = inputHeight + (quietZone * 2);
- const outputWidth = Math.max(width, qrWidth);
- const outputHeight = Math.max(height, qrHeight);
-
- const multiple = Math.min(Math.floor(outputWidth / qrWidth), Math.floor(outputHeight / qrHeight));
-
- // Padding includes both the quiet zone and the extra white pixels to accommodate the requested
- // dimensions. For example, if input is 25x25 the QR will be 33x33 including the quiet zone.
- // If the requested size is 200x160, the multiple will be 4, for a QR of 132x132. These will
- // handle all the padding from 100x100 (the actual QR) up to 200x160.
- const leftPadding = Math.floor((outputWidth - (inputWidth * multiple)) / 2);
- const topPadding = Math.floor((outputHeight - (inputHeight * multiple)) / 2);
-
- const svgElement = this.createSVGElement(outputWidth, outputHeight);
-
- const placeholder = this.createSvgPathPlaceholderElement(width, height);
-
- svgElement.append(placeholder);
-
- this.containerElement.appendChild(svgElement);
-
- // 2D loop
- for (let inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++ , outputY += multiple) {
- // Write the contents of this row of the barcode
- for (let inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++ , outputX += multiple) {
- if (input.get(inputX, inputY) === 1) {
- const svgRectElement = this.createSvgRectElement(outputX, outputY, multiple, multiple);
- svgElement.appendChild(svgRectElement);
- }
- }
- }
-
- return svgElement;
- }
-
- /**
- * Creates a SVG element.
- */
- protected createSVGElement(w: number, h: number): SVGSVGElement {
-
- const el = document.createElementNS(BrowserSvgCodeWriter.SVG_NS, 'svg');
-
- el.setAttributeNS(null, 'width', h.toString());
- el.setAttributeNS(null, 'height', w.toString());
-
- return el;
- }
-
- /**
- * Creates a SVG rect.
- */
- protected createSvgPathPlaceholderElement(w: number, h: number): SVGPathElement {
-
- const el = document.createElementNS(BrowserSvgCodeWriter.SVG_NS, 'path');
-
- el.setAttributeNS(null, 'd', `M0 0h${w}v${h}H0z`);
- el.setAttributeNS(null, 'fill', 'none');
-
- return el;
- }
-
- /**
- * Creates a SVG rect.
- */
- protected createSvgRectElement(x: number, y: number, w: number, h: number): SVGRectElement {
-
- const el = document.createElementNS(BrowserSvgCodeWriter.SVG_NS, 'rect');
-
- el.setAttributeNS(null, 'x', x.toString());
- el.setAttributeNS(null, 'y', y.toString());
- el.setAttributeNS(null, 'height', w.toString());
- el.setAttributeNS(null, 'width', h.toString());
- el.setAttributeNS(null, 'fill', '#000000');
-
- return el;
- }
-}
-
-export { BrowserSvgCodeWriter };
diff --git a/src/browser/DecodeContinuouslyCallback.ts b/src/browser/DecodeContinuouslyCallback.ts
deleted file mode 100644
index 350464bb..00000000
--- a/src/browser/DecodeContinuouslyCallback.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import Exception from '../core/Exception';
-import Result from '../core/Result';
-
-/**
- * Callback format for continuous decode scan.
- */
-export type DecodeContinuouslyCallback = (result: Result, error?: Exception) => any;
diff --git a/src/browser/HTMLCanvasElementLuminanceSource.ts b/src/browser/HTMLCanvasElementLuminanceSource.ts
deleted file mode 100644
index fb5f6d98..00000000
--- a/src/browser/HTMLCanvasElementLuminanceSource.ts
+++ /dev/null
@@ -1,140 +0,0 @@
-import InvertedLuminanceSource from '../core/InvertedLuminanceSource';
-import LuminanceSource from '../core/LuminanceSource';
-import IllegalArgumentException from '../core/IllegalArgumentException';
-
-/**
- * @deprecated Moving to @zxing/browser
- */
-export class HTMLCanvasElementLuminanceSource extends LuminanceSource {
-
- private buffer: Uint8ClampedArray;
-
- private static DEGREE_TO_RADIANS = Math.PI / 180;
-
- private tempCanvasElement: HTMLCanvasElement = null;
-
- public constructor(private canvas: HTMLCanvasElement) {
- super(canvas.width, canvas.height);
- this.buffer = HTMLCanvasElementLuminanceSource.makeBufferFromCanvasImageData(canvas);
- }
-
- private static makeBufferFromCanvasImageData(canvas: HTMLCanvasElement): Uint8ClampedArray {
- const imageData = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height);
- return HTMLCanvasElementLuminanceSource.toGrayscaleBuffer(imageData.data, canvas.width, canvas.height);
- }
-
- private static toGrayscaleBuffer(imageBuffer: Uint8ClampedArray, width: number, height: number): Uint8ClampedArray {
- const grayscaleBuffer = new Uint8ClampedArray(width * height);
- for (let i = 0, j = 0, length = imageBuffer.length; i < length; i += 4, j++) {
- let gray;
- const alpha = imageBuffer[i + 3];
- // The color of fully-transparent pixels is irrelevant. They are often, technically, fully-transparent
- // black (0 alpha, and then 0 RGB). They are often used, of course as the "white" area in a
- // barcode image. Force any such pixel to be white:
- if (alpha === 0) {
- gray = 0xFF;
- } else {
- const pixelR = imageBuffer[i];
- const pixelG = imageBuffer[i + 1];
- const pixelB = imageBuffer[i + 2];
- // .299R + 0.587G + 0.114B (YUV/YIQ for PAL and NTSC),
- // (306*R) >> 10 is approximately equal to R*0.299, and so on.
- // 0x200 >> 10 is 0.5, it implements rounding.
- gray = (306 * pixelR +
- 601 * pixelG +
- 117 * pixelB +
- 0x200) >> 10;
- }
- grayscaleBuffer[j] = gray;
- }
- return grayscaleBuffer;
- }
-
- public getRow(y: number /*int*/, row: Uint8ClampedArray): Uint8ClampedArray {
- if (y < 0 || y >= this.getHeight()) {
- throw new IllegalArgumentException('Requested row is outside the image: ' + y);
- }
- const width: number /*int*/ = this.getWidth();
- const start = y * width;
- if (row === null) {
- row = this.buffer.slice(start, start + width);
- } else {
- if (row.length < width) {
- row = new Uint8ClampedArray(width);
- }
- // The underlying raster of image consists of bytes with the luminance values
- // TODO: can avoid set/slice?
- row.set(this.buffer.slice(start, start + width));
- }
-
- return row;
- }
-
- public getMatrix(): Uint8ClampedArray {
- return this.buffer;
- }
-
- public isCropSupported(): boolean {
- return true;
- }
-
- public crop(left: number /*int*/, top: number /*int*/, width: number /*int*/, height: number /*int*/): LuminanceSource {
- super.crop(left, top, width, height);
- return this;
- }
-
- /**
- * This is always true, since the image is a gray-scale image.
- *
- * @return true
- */
- public isRotateSupported(): boolean {
- return true;
- }
-
- public rotateCounterClockwise(): LuminanceSource {
- this.rotate(-90);
- return this;
- }
-
- public rotateCounterClockwise45(): LuminanceSource {
- this.rotate(-45);
- return this;
- }
-
- private getTempCanvasElement() {
- if (null === this.tempCanvasElement) {
- const tempCanvasElement = this.canvas.ownerDocument.createElement('canvas');
- tempCanvasElement.width = this.canvas.width;
- tempCanvasElement.height = this.canvas.height;
- this.tempCanvasElement = tempCanvasElement;
- }
-
- return this.tempCanvasElement;
- }
-
- private rotate(angle: number) {
- const tempCanvasElement = this.getTempCanvasElement();
- const tempContext = tempCanvasElement.getContext('2d');
- const angleRadians = angle * HTMLCanvasElementLuminanceSource.DEGREE_TO_RADIANS;
-
- // Calculate and set new dimensions for temp canvas
- const width = this.canvas.width;
- const height = this.canvas.height;
- const newWidth = Math.ceil( Math.abs(Math.cos(angleRadians)) * width + Math.abs(Math.sin(angleRadians)) * height );
- const newHeight = Math.ceil( Math.abs(Math.sin(angleRadians)) * width + Math.abs(Math.cos(angleRadians)) * height );
- tempCanvasElement.width = newWidth;
- tempCanvasElement.height = newHeight;
-
- // Draw at center of temp canvas to prevent clipping of image data
- tempContext.translate(newWidth / 2, newHeight / 2);
- tempContext.rotate(angleRadians);
- tempContext.drawImage(this.canvas, width / -2, height / -2);
- this.buffer = HTMLCanvasElementLuminanceSource.makeBufferFromCanvasImageData(tempCanvasElement);
- return this;
- }
-
- public invert(): LuminanceSource {
- return new InvertedLuminanceSource(this);
- }
-}
diff --git a/src/browser/HTMLVisualMediaElement.ts b/src/browser/HTMLVisualMediaElement.ts
deleted file mode 100644
index 446b4eb2..00000000
--- a/src/browser/HTMLVisualMediaElement.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * HTML elements that can be decoded.
- */
-export type HTMLVisualMediaElement = HTMLVideoElement | HTMLImageElement;
diff --git a/src/browser/VideoInputDevice.ts b/src/browser/VideoInputDevice.ts
deleted file mode 100644
index 7c00896e..00000000
--- a/src/browser/VideoInputDevice.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * @deprecated Moving to @zxing/browser
- *
- * Video input device metadata containing the id and label of the device if available.
- */
-export class VideoInputDevice implements MediaDeviceInfo {
-
- /** @inheritdoc */
- readonly kind = 'videoinput';
-
- /** @inheritdoc */
- readonly groupId: string;
-
- /**
- * Creates an instance of VideoInputDevice.
- *
- * @param {string} deviceId the video input device id
- * @param {string} label the label of the device if available
- */
- public constructor(public deviceId: string, public label: string, groupId?: string) {
- this.groupId = groupId || undefined;
- }
-
- /** @inheritdoc */
- toJSON() {
- return {
- kind: this.kind,
- groupId: this.groupId,
- deviceId: this.deviceId,
- label: this.label,
- };
- }
-}
diff --git a/src/index.ts b/src/index.ts
index 372596c5..45a849c7 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,5 +1,3 @@
-export * from './browser';
-
// Exceptions
export { default as ArgumentException } from './core/ArgumentException';
export { default as ArithmeticException } from './core/ArithmeticException';
From f9ff69b506edd54842014894a47d956a3ec5a69f Mon Sep 17 00:00:00 2001
From: Erik Hughes
Date: Sat, 14 Nov 2020 19:57:31 +0100
Subject: [PATCH 03/53] style: removed tslint and improved eslint
---
.eslintrc | 91 +++++++++++++++++++++++++++++++++++------
.unibeautify.json | 12 ------
.vscode/extensions.json | 11 +++--
.vscode/settings.json | 6 +--
tslint.json | 64 -----------------------------
5 files changed, 86 insertions(+), 98 deletions(-)
delete mode 100644 .unibeautify.json
delete mode 100644 tslint.json
diff --git a/.eslintrc b/.eslintrc
index ba03e236..53803064 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,16 +1,81 @@
{
- "parserOptions": {
- "ecmaVersion": 8,
- "sourceType": "module",
- "ecmaFeatures": {
- "jsx": false
+ "env": {
+ "node": true
+ },
+ "parser": "@typescript-eslint/parser",
+ "parserOptions": {
+ "project": "tsconfig.json",
+ "sourceType": "module"
+ },
+ "plugins": [
+ "@typescript-eslint"
+ ],
+ "rules": {
+ "@typescript-eslint/indent": [
+ "error",
+ 2
+ ],
+ "@typescript-eslint/member-delimiter-style": [
+ "error",
+ {
+ "multiline": {
+ "delimiter": "semi",
+ "requireLast": true
+ },
+ "singleline": {
+ "delimiter": "semi",
+ "requireLast": false
}
- },
- "rules": {
- "semi": "error",
- "quotes": ["error", "single"]
- },
- "env": {
- "es6": true
- }
+ }
+ ],
+ "@typescript-eslint/member-ordering": "off", /* to keep the same as with the java version */
+ "@typescript-eslint/naming-convention": "error",
+ "@typescript-eslint/prefer-namespace-keyword": "error",
+ "@typescript-eslint/quotes": [
+ "error",
+ "single"
+ ],
+ "@typescript-eslint/semi": [
+ "error",
+ "always"
+ ],
+ "@typescript-eslint/type-annotation-spacing": "error",
+ "brace-style": [
+ "error",
+ "1tbs"
+ ],
+ "eqeqeq": [
+ "error",
+ "smart"
+ ],
+ "id-blacklist": [
+ "error",
+ "any",
+ "Number",
+ "number",
+ "String",
+ "string",
+ "Boolean",
+ "boolean",
+ "Undefined",
+ "undefined"
+ ],
+ "id-match": "error",
+ "no-bitwise": "off", /* we use a lot of these */
+ "no-eval": "error",
+ "no-redeclare": "error",
+ "no-trailing-spaces": "error",
+ "no-underscore-dangle": "error",
+ "no-unsafe-finally": "error",
+ "no-var": "error",
+ "spaced-comment": [
+ "error",
+ "always",
+ {
+ "markers": [
+ "/"
+ ]
+ }
+ ]
+ }
}
diff --git a/.unibeautify.json b/.unibeautify.json
deleted file mode 100644
index 6019d591..00000000
--- a/.unibeautify.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "JavaScript": {
- "indent_size": 4,
- "indent_char": " ",
- "quotes": "single"
- },
- "TypeScript": {
- "indent_size": 4,
- "indent_char": " ",
- "quotes": "single"
- }
-}
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index 59d59217..f7c814bb 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -1,7 +1,6 @@
{
- "recommendations": [
- "EditorConfig.EditorConfig",
- "ms-vscode.vscode-typescript-tslint-plugin",
- "dbaeumer.vscode-eslint",
- ]
-}
+ "recommendations": [
+ "EditorConfig.EditorConfig",
+ "dbaeumer.vscode-eslint",
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
index c390cfaf..1cdfb39f 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,5 @@
// Place your settings in this file to overwrite default and user settings.
{
- "tslint.enable": true,
- "typescript.tsdk": "node_modules\\typescript\\lib"
-}
+ "typescript.tsdk": "node_modules\\typescript\\lib",
+ "eslint.format.enable": true
+}
\ No newline at end of file
diff --git a/tslint.json b/tslint.json
deleted file mode 100644
index 534acdce..00000000
--- a/tslint.json
+++ /dev/null
@@ -1,64 +0,0 @@
-{
- "extends": ["tslint-no-circular-imports"],
- "rules": {
- "class-name": true,
- "comment-format": [
- true,
- "check-space"
- ],
- "indent": [
- true,
- "spaces",
- 2
- ],
- "no-duplicate-variable": true,
- "no-eval": true,
- "no-internal-module": true,
- "no-trailing-whitespace": true,
- "no-unsafe-finally": true,
- "no-var-keyword": true,
- "one-line": [
- true,
- "check-open-brace",
- "check-whitespace"
- ],
- "quotemark": [
- true,
- "single"
- ],
- "semicolon": [
- true,
- "always"
- ],
- "triple-equals": [
- true,
- "allow-null-check"
- ],
- "typedef-whitespace": [
- true,
- {
- "call-signature": "nospace",
- "index-signature": "nospace",
- "parameter": "nospace",
- "property-declaration": "nospace",
- "variable-declaration": "nospace"
- }
- ],
- "variable-name": [
- true,
- "ban-keywords"
- ],
- "whitespace": [
- true,
- "check-branch",
- "check-decl",
- "check-operator",
- "check-separator",
- "check-type"
- ],
- "no-bitwise": false /* we use a lot of these */,
- "member-ordering": [
- false
- ] /* to keep the same as with the java version */
- }
-}
\ No newline at end of file
From 072a445d84b5e7bbbb9123bff50f273d1dfc6a15 Mon Sep 17 00:00:00 2001
From: Erik Hughes
Date: Sat, 14 Nov 2020 20:09:23 +0100
Subject: [PATCH 04/53] style: ran formatting rules on all source files
---
_config.yml | 2 +-
package.json | 2 +-
src/core/BarcodeFormat.ts | 68 +-
src/core/Binarizer.ts | 88 +-
src/core/BinaryBitmap.ts | 226 ++--
src/core/DecodeHintType.ts | 178 +--
src/core/Dimension.ts | 54 +-
src/core/EncodeHintType.ts | 136 +-
src/core/FormatException.ts | 6 +-
src/core/InvertedLuminanceSource.ts | 108 +-
src/core/MultiFormatReader.ts | 294 ++--
src/core/MultiFormatWriter.ts | 114 +-
src/core/OutOfMemoryError.ts | 2 +-
src/core/PlanarYUVLuminanceSource.ts | 230 ++--
src/core/RGBLuminanceSource.ts | 242 ++--
src/core/Reader.ts | 64 +-
src/core/Result.ts | 236 ++--
src/core/ResultMetadataType.ts | 118 +-
src/core/ResultPoint.ts | 172 +--
src/core/ResultPointCallback.ts | 2 +-
src/core/Writer.ts | 56 +-
src/core/aztec/AztecDetectorResult.ts | 44 +-
src/core/aztec/AztecReader.ts | 122 +-
src/core/aztec/AztecWriter.ts | 4 +-
src/core/aztec/decoder/Decoder.ts | 592 ++++-----
src/core/aztec/detector/Detector.ts | 1040 +++++++--------
src/core/aztec/encoder/Encoder.ts | 2 +-
src/core/aztec/encoder/EncoderConstants.ts | 12 +-
src/core/aztec/encoder/ShiftTable.ts | 2 +-
src/core/aztec/encoder/State.ts | 4 +-
src/core/common/BitMatrix.ts | 876 ++++++------
src/core/common/BitSource.ts | 168 +--
src/core/common/CharacterSetECI.ts | 340 ++---
src/core/common/DecoderResult.ts | 218 +--
src/core/common/DefaultGridSampler.ts | 112 +-
src/core/common/DetectorResult.ts | 24 +-
src/core/common/GlobalHistogramBinarizer.ts | 302 ++---
src/core/common/GridSampler.ts | 268 ++--
src/core/common/GridSamplerInstance.ts | 38 +-
src/core/common/HybridBinarizer.ts | 368 ++---
src/core/common/PerspectiveTransform.ts | 264 ++--
src/core/common/detector/CornerDetector.ts | 502 +++----
.../detector/MonochromeRectangleDetector.ts | 2 +-
.../common/detector/WhiteRectangleDetector.ts | 566 ++++----
.../reedsolomon/AbstractGenericGFPoly.ts | 188 +--
src/core/common/reedsolomon/GenericGFPoly.ts | 432 +++---
.../common/reedsolomon/ReedSolomonDecoder.ts | 274 ++--
.../common/reedsolomon/ReedSolomonEncoder.ts | 134 +-
.../datamatrix/decoder/BitMatrixParser.ts | 2 +-
src/core/datamatrix/decoder/DataBlock.ts | 4 +-
.../decoder/DecodedBitStreamParser.ts | 26 +-
src/core/datamatrix/decoder/Version.ts | 210 +--
src/core/datamatrix/detector/Detector.ts | 64 +-
src/core/oned/AbstractUPCEANReader.ts | 398 +++---
src/core/oned/Code128Reader.ts | 228 ++--
src/core/oned/Code39Reader.ts | 12 +-
src/core/oned/EAN13Reader.ts | 92 +-
src/core/oned/EAN8Reader.ts | 68 +-
src/core/oned/ITFReader.ts | 130 +-
src/core/oned/OneDReader.ts | 440 +++---
src/core/oned/UPCEANExtension2Support.ts | 114 +-
src/core/oned/UPCEANExtension5Support.ts | 228 ++--
src/core/oned/UPCEANExtensionSupport.ts | 24 +-
src/core/oned/UPCEANReader.ts | 232 ++--
src/core/oned/rss/AbstractRSSReader.ts | 44 +-
src/core/oned/rss/DataCharacter.ts | 48 +-
src/core/oned/rss/FinderPattern.ts | 62 +-
src/core/oned/rss/Pair.ts | 30 +-
src/core/oned/rss/RSS14Reader.ts | 730 +++++-----
src/core/oned/rss/RSSUtils.ts | 2 +-
.../oned/rss/expanded/RSSExpandedReader.ts | 4 +-
.../expanded/decoders/BlockParsedResult.ts | 2 +-
src/core/pdf417/PDF417Common.ts | 850 ++++++------
src/core/pdf417/PDF417Reader.ts | 4 +-
src/core/pdf417/PDF417ResultMetadata.ts | 292 ++--
src/core/pdf417/decoder/BarcodeValue.ts | 6 +-
src/core/pdf417/decoder/BoundingBox.ts | 42 +-
src/core/pdf417/decoder/Codeword.ts | 6 +-
.../pdf417/decoder/DetectionResultColumn.ts | 98 +-
.../DetectionResultRowIndicatorColumn.ts | 28 +-
.../pdf417/decoder/PDF417CodewordDecoder.ts | 16 +-
.../pdf417/decoder/PDF417ScanningDecoder.ts | 4 +-
src/core/pdf417/detector/Detector.ts | 64 +-
.../pdf417/detector/PDF417DetectorResult.ts | 24 +-
src/core/qrcode/QRCodeWriter.ts | 134 +-
src/core/qrcode/decoder/BitMatrixParser.ts | 404 +++---
src/core/qrcode/decoder/DataBlock.ts | 156 +--
src/core/qrcode/decoder/ECB.ts | 24 +-
src/core/qrcode/decoder/ECBlocks.ts | 40 +-
.../qrcode/decoder/ErrorCorrectionLevel.ts | 100 +-
src/core/qrcode/decoder/FormatInformation.ts | 226 ++--
src/core/qrcode/decoder/Mode.ts | 152 +--
.../qrcode/decoder/QRCodeDecoderMetaData.ts | 44 +-
src/core/qrcode/decoder/Version.ts | 918 ++++++-------
src/core/qrcode/detector/AlignmentPattern.ts | 46 +-
.../qrcode/detector/AlignmentPatternFinder.ts | 402 +++---
src/core/qrcode/detector/FinderPattern.ts | 82 +-
.../qrcode/detector/FinderPatternFinder.ts | 1184 ++++++++---------
src/core/qrcode/detector/FinderPatternInfo.ts | 42 +-
src/core/qrcode/encoder/BlockPair.ts | 14 +-
src/core/qrcode/encoder/ByteMatrix.ts | 164 +--
src/core/qrcode/encoder/Encoder.ts | 1104 +++++++--------
src/core/qrcode/encoder/MaskUtil.ts | 350 ++---
src/core/qrcode/encoder/MatrixUtil.ts | 836 ++++++------
src/core/qrcode/encoder/QRCode.ts | 154 +--
src/core/util/System.ts | 30 +-
.../core/PlanarYUVLuminanceSource.spec.ts | 88 +-
src/test/core/RGBLuminanceSource.spec.ts | 62 +-
src/test/core/aztec/AztecBlackBox1.spec.ts | 8 +-
src/test/core/aztec/AztecBlackBox2.spec.ts | 8 +-
src/test/core/aztec/decoder/Decoder.spec.ts | 286 ++--
src/test/core/aztec/detector/Detector.spec.ts | 296 ++---
.../core/aztec/encoder/EncoderTest.spec.ts | 256 ++--
src/test/core/common/BitArray.spec.ts | 410 +++---
src/test/core/common/BitSource.spec.ts | 40 +-
src/test/core/common/BitSourceBuilder.ts | 62 +-
.../core/common/PerspectiveTransform.spec.ts | 68 +-
src/test/core/common/StringUtils.spec.ts | 80 +-
src/test/core/common/TestResult.ts | 54 +-
.../core/common/detector/MathUtils.spec.ts | 58 +-
.../common/reedsolomon/ReedSolomon.spec.ts | 1090 +++++++--------
.../datamatrix/DataMatrixBlackBox.1.spec.ts | 22 +-
.../decoder/DecodedBitStreamParser.spec.ts | 40 +-
src/test/core/oned/Code128BlackBox1.spec.ts | 18 +-
src/test/core/oned/Code39BlackBox1.spec.ts | 18 +-
src/test/core/oned/Code39BlackBox3.spec.ts | 18 +-
.../core/oned/Code39ExtendedBlackBox2.spec.ts | 18 +-
src/test/core/oned/Code39ExtendedMode.spec.ts | 46 +-
src/test/core/oned/Ean13BlackBox1.spec.ts | 18 +-
src/test/core/oned/Ean8BlackBox1.spec.ts | 18 +-
src/test/core/oned/ITFBlackBox.spec.ts | 18 +-
src/test/core/oned/rss/RSS14BlackBox1.spec.ts | 18 +-
src/test/core/oned/rss/RSS14BlackBox2.spec.ts | 18 +-
.../decoders/AI013103DecoderTest.java | 2 +-
.../expanded/decoders/AnyAIDecoderTest.java | 2 +-
.../RSSExpandedBlackBox3TestCase.java | 4 +-
.../RSSExpandedStackedBlackBox1TestCase.java | 4 +-
.../RSSExpandedStackedBlackBox2TestCase.java | 4 +-
.../decoders/AI013103DecoderTest.java | 2 +-
.../expanded/decoders/AnyAIDecoderTest.java | 2 +-
.../ec/AbstractErrorCorrection.spec.ts | 48 +-
.../pdf417/decoder/ec/ErrorCorrection.spec.ts | 210 +--
src/test/core/qrcode/HybridBinarizer.spec.ts | 18 +-
src/test/core/qrcode/QRCodeBlackBox.1.spec.ts | 22 +-
src/test/core/qrcode/QRCodeBlackBox.2.spec.ts | 22 +-
src/test/core/qrcode/QRCodeBlackBox.3.spec.ts | 22 +-
src/test/core/qrcode/QRCodeBlackBox.4.spec.ts | 22 +-
src/test/core/qrcode/QRCodeBlackBox.5.spec.ts | 22 +-
src/test/core/qrcode/QRCodeBlackBox.6.spec.ts | 22 +-
src/test/core/qrcode/QRCodeBlackBox.7.spec.ts | 22 +-
src/test/core/qrcode/QRCodeWriter.spec.ts | 178 +--
src/test/core/qrcode/decoder/DataMask.spec.ts | 132 +-
.../decoder/DecodedBitStreamParser.spec.ts | 258 ++--
.../decoder/ErrorCorrectionLevel.spec.ts | 24 +-
.../qrcode/decoder/FormatInformation.spec.ts | 74 +-
src/test/core/qrcode/decoder/Mode.spec.ts | 44 +-
src/test/core/qrcode/decoder/Version.spec.ts | 88 +-
.../core/qrcode/encoder/BitVector.spec.ts | 298 ++---
src/test/core/qrcode/encoder/Encoder.spec.ts | 1154 ++++++++--------
src/test/core/qrcode/encoder/MaskUtil.spec.ts | 440 +++---
.../core/qrcode/encoder/MatrixUtil.spec.ts | 514 +++----
src/test/core/qrcode/encoder/QRCode.spec.ts | 170 +--
src/test/core/util/Pattern.ts | 6 +-
src/test/core/util/textEncodingFactory.ts | 2 +-
src/test/resources/blackbox/code39-1/2.txt | 2 +-
src/test/resources/blackbox/qrcode-2/16.txt | 2 +-
src/test/resources/blackbox/qrcode-2/18.txt | 4 +-
src/test/resources/blackbox/qrcode-2/19.txt | 4 +-
src/test/resources/blackbox/qrcode-2/20.txt | 2 +-
src/test/resources/blackbox/qrcode-2/21.txt | 4 +-
src/test/resources/blackbox/qrcode-2/23.txt | 2 +-
src/test/resources/blackbox/qrcode-2/24.txt | 4 +-
src/test/resources/blackbox/qrcode-2/26.txt | 4 +-
src/test/resources/blackbox/qrcode-2/27.txt | 4 +-
src/test/resources/blackbox/qrcode-2/29.txt | 2 +-
src/test/resources/blackbox/qrcode-3/18.txt | 2 +-
src/test/resources/blackbox/qrcode-3/19.txt | 2 +-
src/test/resources/blackbox/qrcode-3/20.txt | 2 +-
src/test/resources/blackbox/qrcode-3/21.txt | 2 +-
src/test/resources/blackbox/qrcode-3/22.txt | 2 +-
src/test/resources/blackbox/qrcode-3/23.txt | 2 +-
src/test/resources/blackbox/qrcode-3/24.txt | 2 +-
src/test/resources/blackbox/qrcode-3/25.txt | 2 +-
src/test/resources/blackbox/qrcode-5/17.txt | 2 +-
184 files changed, 13775 insertions(+), 13775 deletions(-)
diff --git a/_config.yml b/_config.yml
index 2f7efbea..fff4ab92 100644
--- a/_config.yml
+++ b/_config.yml
@@ -1 +1 @@
-theme: jekyll-theme-minimal
\ No newline at end of file
+theme: jekyll-theme-minimal
diff --git a/package.json b/package.json
index 6a4ad5a5..867ac79b 100644
--- a/package.json
+++ b/package.json
@@ -112,4 +112,4 @@
"url": "https://opencollective.com/zxing-js",
"logo": "https://opencollective.com/zxing-js/logo.txt"
}
-}
+}
\ No newline at end of file
diff --git a/src/core/BarcodeFormat.ts b/src/core/BarcodeFormat.ts
index a6a5a148..73dd147d 100644
--- a/src/core/BarcodeFormat.ts
+++ b/src/core/BarcodeFormat.ts
@@ -26,56 +26,56 @@
* @author Sean Owen
*/
enum BarcodeFormat {
- /** Aztec 2D barcode format. */
- AZTEC,
+ /** Aztec 2D barcode format. */
+ AZTEC,
- /** CODABAR 1D format. */
- CODABAR,
+ /** CODABAR 1D format. */
+ CODABAR,
- /** Code 39 1D format. */
- CODE_39,
+ /** Code 39 1D format. */
+ CODE_39,
- /** Code 93 1D format. */
- CODE_93,
+ /** Code 93 1D format. */
+ CODE_93,
- /** Code 128 1D format. */
- CODE_128,
+ /** Code 128 1D format. */
+ CODE_128,
- /** Data Matrix 2D barcode format. */
- DATA_MATRIX,
+ /** Data Matrix 2D barcode format. */
+ DATA_MATRIX,
- /** EAN-8 1D format. */
- EAN_8,
+ /** EAN-8 1D format. */
+ EAN_8,
- /** EAN-13 1D format. */
- EAN_13,
+ /** EAN-13 1D format. */
+ EAN_13,
- /** ITF (Interleaved Two of Five) 1D format. */
- ITF,
+ /** ITF (Interleaved Two of Five) 1D format. */
+ ITF,
- /** MaxiCode 2D barcode format. */
- MAXICODE,
+ /** MaxiCode 2D barcode format. */
+ MAXICODE,
- /** PDF417 format. */
- PDF_417,
+ /** PDF417 format. */
+ PDF_417,
- /** QR Code 2D barcode format. */
- QR_CODE,
+ /** QR Code 2D barcode format. */
+ QR_CODE,
- /** RSS 14 */
- RSS_14,
+ /** RSS 14 */
+ RSS_14,
- /** RSS EXPANDED */
- RSS_EXPANDED,
+ /** RSS EXPANDED */
+ RSS_EXPANDED,
- /** UPC-A 1D format. */
- UPC_A,
+ /** UPC-A 1D format. */
+ UPC_A,
- /** UPC-E 1D format. */
- UPC_E,
+ /** UPC-E 1D format. */
+ UPC_E,
- /** UPC/EAN extension format. Not a stand-alone format. */
- UPC_EAN_EXTENSION
+ /** UPC/EAN extension format. Not a stand-alone format. */
+ UPC_EAN_EXTENSION
}
diff --git a/src/core/Binarizer.ts b/src/core/Binarizer.ts
index 54ba9a36..036f0b8d 100644
--- a/src/core/Binarizer.ts
+++ b/src/core/Binarizer.ts
@@ -30,56 +30,56 @@ import BitMatrix from './common/BitMatrix';
*/
abstract class Binarizer {
- protected constructor(private source: LuminanceSource) { }
+ protected constructor(private source: LuminanceSource) { }
- public getLuminanceSource(): LuminanceSource {
- return this.source;
- }
+ public getLuminanceSource(): LuminanceSource {
+ return this.source;
+ }
- /**
- * Converts one row of luminance data to 1 bit data. May actually do the conversion, or return
- * cached data. Callers should assume this method is expensive and call it as seldom as possible.
- * This method is intended for decoding 1D barcodes and may choose to apply sharpening.
- * For callers which only examine one row of pixels at a time, the same BitArray should be reused
- * and passed in with each call for performance. However it is legal to keep more than one row
- * at a time if needed.
- *
- * @param y The row to fetch, which must be in [0, bitmap height)
- * @param row An optional preallocated array. If null or too small, it will be ignored.
- * If used, the Binarizer will call BitArray.clear(). Always use the returned object.
- * @return The array of bits for this row (true means black).
- * @throws NotFoundException if row can't be binarized
- */
- public abstract getBlackRow(y: number/*iny*/, row: BitArray): BitArray; /*throws NotFoundException*/
+ /**
+ * Converts one row of luminance data to 1 bit data. May actually do the conversion, or return
+ * cached data. Callers should assume this method is expensive and call it as seldom as possible.
+ * This method is intended for decoding 1D barcodes and may choose to apply sharpening.
+ * For callers which only examine one row of pixels at a time, the same BitArray should be reused
+ * and passed in with each call for performance. However it is legal to keep more than one row
+ * at a time if needed.
+ *
+ * @param y The row to fetch, which must be in [0, bitmap height)
+ * @param row An optional preallocated array. If null or too small, it will be ignored.
+ * If used, the Binarizer will call BitArray.clear(). Always use the returned object.
+ * @return The array of bits for this row (true means black).
+ * @throws NotFoundException if row can't be binarized
+ */
+ public abstract getBlackRow(y: number/*iny*/, row: BitArray): BitArray; /*throws NotFoundException*/
- /**
- * Converts a 2D array of luminance data to 1 bit data. As above, assume this method is expensive
- * and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or
- * may not apply sharpening. Therefore, a row from this matrix may not be identical to one
- * fetched using getBlackRow(), so don't mix and match between them.
- *
- * @return The 2D array of bits for the image (true means black).
- * @throws NotFoundException if image can't be binarized to make a matrix
- */
- public abstract getBlackMatrix(): BitMatrix; /*throws NotFoundException*/
+ /**
+ * Converts a 2D array of luminance data to 1 bit data. As above, assume this method is expensive
+ * and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or
+ * may not apply sharpening. Therefore, a row from this matrix may not be identical to one
+ * fetched using getBlackRow(), so don't mix and match between them.
+ *
+ * @return The 2D array of bits for the image (true means black).
+ * @throws NotFoundException if image can't be binarized to make a matrix
+ */
+ public abstract getBlackMatrix(): BitMatrix; /*throws NotFoundException*/
- /**
- * Creates a new object with the same type as this Binarizer implementation, but with pristine
- * state. This is needed because Binarizer implementations may be stateful, e.g. keeping a cache
- * of 1 bit data. See Effective Java for why we can't use Java's clone() method.
- *
- * @param source The LuminanceSource this Binarizer will operate on.
- * @return A new concrete Binarizer implementation object.
- */
- public abstract createBinarizer(source: LuminanceSource): Binarizer;
+ /**
+ * Creates a new object with the same type as this Binarizer implementation, but with pristine
+ * state. This is needed because Binarizer implementations may be stateful, e.g. keeping a cache
+ * of 1 bit data. See Effective Java for why we can't use Java's clone() method.
+ *
+ * @param source The LuminanceSource this Binarizer will operate on.
+ * @return A new concrete Binarizer implementation object.
+ */
+ public abstract createBinarizer(source: LuminanceSource): Binarizer;
- public getWidth(): number /*int*/ {
- return this.source.getWidth();
- }
+ public getWidth(): number /*int*/ {
+ return this.source.getWidth();
+ }
- public getHeight(): number /*int*/ {
- return this.source.getHeight();
- }
+ public getHeight(): number /*int*/ {
+ return this.source.getHeight();
+ }
}
export default Binarizer;
diff --git a/src/core/BinaryBitmap.ts b/src/core/BinaryBitmap.ts
index 009b54c7..a8d986d4 100644
--- a/src/core/BinaryBitmap.ts
+++ b/src/core/BinaryBitmap.ts
@@ -30,122 +30,122 @@ import LuminanceSource from './LuminanceSource';
import IllegalArgumentException from './IllegalArgumentException';
export default class BinaryBitmap {
- private matrix: BitMatrix;
+ private matrix: BitMatrix;
- public constructor(private binarizer: Binarizer) {
- if (binarizer === null) {
- throw new IllegalArgumentException('Binarizer must be non-null.');
- }
+ public constructor(private binarizer: Binarizer) {
+ if (binarizer === null) {
+ throw new IllegalArgumentException('Binarizer must be non-null.');
}
-
- /**
- * @return The width of the bitmap.
- */
- public getWidth(): number /*int*/ {
- return this.binarizer.getWidth();
- }
-
- /**
- * @return The height of the bitmap.
- */
- public getHeight(): number /*int*/ {
- return this.binarizer.getHeight();
- }
-
- /**
- * Converts one row of luminance data to 1 bit data. May actually do the conversion, or return
- * cached data. Callers should assume this method is expensive and call it as seldom as possible.
- * This method is intended for decoding 1D barcodes and may choose to apply sharpening.
- *
- * @param y The row to fetch, which must be in [0, bitmap height)
- * @param row An optional preallocated array. If null or too small, it will be ignored.
- * If used, the Binarizer will call BitArray.clear(). Always use the returned object.
- * @return The array of bits for this row (true means black).
- * @throws NotFoundException if row can't be binarized
- */
- public getBlackRow(y: number /*int*/, row: BitArray): BitArray /*throws NotFoundException */ {
- return this.binarizer.getBlackRow(y, row);
- }
-
- /**
- * Converts a 2D array of luminance data to 1 bit. As above, assume this method is expensive
- * and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or
- * may not apply sharpening. Therefore, a row from this matrix may not be identical to one
- * fetched using getBlackRow(), so don't mix and match between them.
- *
- * @return The 2D array of bits for the image (true means black).
- * @throws NotFoundException if image can't be binarized to make a matrix
- */
- public getBlackMatrix(): BitMatrix /*throws NotFoundException*/ {
- // The matrix is created on demand the first time it is requested, then cached. There are two
- // reasons for this:
- // 1. This work will never be done if the caller only installs 1D Reader objects, or if a
- // 1D Reader finds a barcode before the 2D Readers run.
- // 2. This work will only be done once even if the caller installs multiple 2D Readers.
- if (this.matrix === null || this.matrix === undefined) {
- this.matrix = this.binarizer.getBlackMatrix();
- }
- return this.matrix;
- }
-
- /**
- * @return Whether this bitmap can be cropped.
- */
- public isCropSupported(): boolean {
- return this.binarizer.getLuminanceSource().isCropSupported();
+ }
+
+ /**
+ * @return The width of the bitmap.
+ */
+ public getWidth(): number /*int*/ {
+ return this.binarizer.getWidth();
+ }
+
+ /**
+ * @return The height of the bitmap.
+ */
+ public getHeight(): number /*int*/ {
+ return this.binarizer.getHeight();
+ }
+
+ /**
+ * Converts one row of luminance data to 1 bit data. May actually do the conversion, or return
+ * cached data. Callers should assume this method is expensive and call it as seldom as possible.
+ * This method is intended for decoding 1D barcodes and may choose to apply sharpening.
+ *
+ * @param y The row to fetch, which must be in [0, bitmap height)
+ * @param row An optional preallocated array. If null or too small, it will be ignored.
+ * If used, the Binarizer will call BitArray.clear(). Always use the returned object.
+ * @return The array of bits for this row (true means black).
+ * @throws NotFoundException if row can't be binarized
+ */
+ public getBlackRow(y: number /*int*/, row: BitArray): BitArray /*throws NotFoundException */ {
+ return this.binarizer.getBlackRow(y, row);
+ }
+
+ /**
+ * Converts a 2D array of luminance data to 1 bit. As above, assume this method is expensive
+ * and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or
+ * may not apply sharpening. Therefore, a row from this matrix may not be identical to one
+ * fetched using getBlackRow(), so don't mix and match between them.
+ *
+ * @return The 2D array of bits for the image (true means black).
+ * @throws NotFoundException if image can't be binarized to make a matrix
+ */
+ public getBlackMatrix(): BitMatrix /*throws NotFoundException*/ {
+ // The matrix is created on demand the first time it is requested, then cached. There are two
+ // reasons for this:
+ // 1. This work will never be done if the caller only installs 1D Reader objects, or if a
+ // 1D Reader finds a barcode before the 2D Readers run.
+ // 2. This work will only be done once even if the caller installs multiple 2D Readers.
+ if (this.matrix === null || this.matrix === undefined) {
+ this.matrix = this.binarizer.getBlackMatrix();
}
-
- /**
- * Returns a new object with cropped image data. Implementations may keep a reference to the
- * original data rather than a copy. Only callable if isCropSupported() is true.
- *
- * @param left The left coordinate, which must be in [0,getWidth())
- * @param top The top coordinate, which must be in [0,getHeight())
- * @param width The width of the rectangle to crop.
- * @param height The height of the rectangle to crop.
- * @return A cropped version of this object.
- */
- public crop(left: number /*int*/, top: number /*int*/, width: number /*int*/, height: number /*int*/): BinaryBitmap {
- const newSource: LuminanceSource = this.binarizer.getLuminanceSource().crop(left, top, width, height);
- return new BinaryBitmap(this.binarizer.createBinarizer(newSource));
- }
-
- /**
- * @return Whether this bitmap supports counter-clockwise rotation.
- */
- public isRotateSupported(): boolean {
- return this.binarizer.getLuminanceSource().isRotateSupported();
- }
-
- /**
- * Returns a new object with rotated image data by 90 degrees counterclockwise.
- * Only callable if {@link #isRotateSupported()} is true.
- *
- * @return A rotated version of this object.
- */
- public rotateCounterClockwise(): BinaryBitmap {
- const newSource: LuminanceSource = this.binarizer.getLuminanceSource().rotateCounterClockwise();
- return new BinaryBitmap(this.binarizer.createBinarizer(newSource));
- }
-
- /**
- * Returns a new object with rotated image data by 45 degrees counterclockwise.
- * Only callable if {@link #isRotateSupported()} is true.
- *
- * @return A rotated version of this object.
- */
- public rotateCounterClockwise45(): BinaryBitmap {
- const newSource: LuminanceSource = this.binarizer.getLuminanceSource().rotateCounterClockwise45();
- return new BinaryBitmap(this.binarizer.createBinarizer(newSource));
- }
-
- /*@Override*/
- public toString(): string {
- try {
- return this.getBlackMatrix().toString();
- } catch (e /*: NotFoundException*/) {
- return '';
- }
+ return this.matrix;
+ }
+
+ /**
+ * @return Whether this bitmap can be cropped.
+ */
+ public isCropSupported(): boolean {
+ return this.binarizer.getLuminanceSource().isCropSupported();
+ }
+
+ /**
+ * Returns a new object with cropped image data. Implementations may keep a reference to the
+ * original data rather than a copy. Only callable if isCropSupported() is true.
+ *
+ * @param left The left coordinate, which must be in [0,getWidth())
+ * @param top The top coordinate, which must be in [0,getHeight())
+ * @param width The width of the rectangle to crop.
+ * @param height The height of the rectangle to crop.
+ * @return A cropped version of this object.
+ */
+ public crop(left: number /*int*/, top: number /*int*/, width: number /*int*/, height: number /*int*/): BinaryBitmap {
+ const newSource: LuminanceSource = this.binarizer.getLuminanceSource().crop(left, top, width, height);
+ return new BinaryBitmap(this.binarizer.createBinarizer(newSource));
+ }
+
+ /**
+ * @return Whether this bitmap supports counter-clockwise rotation.
+ */
+ public isRotateSupported(): boolean {
+ return this.binarizer.getLuminanceSource().isRotateSupported();
+ }
+
+ /**
+ * Returns a new object with rotated image data by 90 degrees counterclockwise.
+ * Only callable if {@link #isRotateSupported()} is true.
+ *
+ * @return A rotated version of this object.
+ */
+ public rotateCounterClockwise(): BinaryBitmap {
+ const newSource: LuminanceSource = this.binarizer.getLuminanceSource().rotateCounterClockwise();
+ return new BinaryBitmap(this.binarizer.createBinarizer(newSource));
+ }
+
+ /**
+ * Returns a new object with rotated image data by 45 degrees counterclockwise.
+ * Only callable if {@link #isRotateSupported()} is true.
+ *
+ * @return A rotated version of this object.
+ */
+ public rotateCounterClockwise45(): BinaryBitmap {
+ const newSource: LuminanceSource = this.binarizer.getLuminanceSource().rotateCounterClockwise45();
+ return new BinaryBitmap(this.binarizer.createBinarizer(newSource));
+ }
+
+ /*@Override*/
+ public toString(): string {
+ try {
+ return this.getBlackMatrix().toString();
+ } catch (e /*: NotFoundException*/) {
+ return '';
}
+ }
}
diff --git a/src/core/DecodeHintType.ts b/src/core/DecodeHintType.ts
index e07470fe..db4eda7b 100644
--- a/src/core/DecodeHintType.ts
+++ b/src/core/DecodeHintType.ts
@@ -27,95 +27,95 @@
*/
enum DecodeHintType {
- /**
- * Unspecified, application-specific hint. Maps to an unspecified {@link Object}.
- */
- OTHER/*(Object.class)*/,
-
- /**
- * Image is a pure monochrome image of a barcode. Doesn't matter what it maps to;
- * use {@link Boolean#TRUE}.
- */
- PURE_BARCODE/*(Void.class)*/,
-
- /**
- * Image is known to be of one of a few possible formats.
- * Maps to a {@link List} of {@link BarcodeFormat}s.
- */
- POSSIBLE_FORMATS/*(List.class)*/,
-
- /**
- * Spend more time to try to find a barcode; optimize for accuracy, not speed.
- * Doesn't matter what it maps to; use {@link Boolean#TRUE}.
- */
- TRY_HARDER/*(Void.class)*/,
-
- /**
- * Specifies what character encoding to use when decoding, where applicable (type String)
- */
- CHARACTER_SET/*(String.class)*/,
-
- /**
- * Allowed lengths of encoded data -- reject anything else. Maps to an {@code Int32Array}.
- */
- ALLOWED_LENGTHS/*(Int32Array.class)*/,
-
- /**
- * Assume Code 39 codes employ a check digit. Doesn't matter what it maps to;
- * use {@link Boolean#TRUE}.
- */
- ASSUME_CODE_39_CHECK_DIGIT/*(Void.class)*/,
-
- /**
- * Assume the barcode is being processed as a GS1 barcode, and modify behavior as needed.
- * For example this affects FNC1 handling for Code 128 (aka GS1-128). Doesn't matter what it maps to;
- * use {@link Boolean#TRUE}.
- */
- ASSUME_GS1/*(Void.class)*/,
-
- /**
- * If true, return the start and end digits in a Codabar barcode instead of stripping them. They
- * are alpha, whereas the rest are numeric. By default, they are stripped, but this causes them
- * to not be. Doesn't matter what it maps to; use {@link Boolean#TRUE}.
- */
- RETURN_CODABAR_START_END/*(Void.class)*/,
-
- /**
- * The caller needs to be notified via callback when a possible {@link ResultPoint}
- * is found. Maps to a {@link ResultPointCallback}.
- */
- NEED_RESULT_POINT_CALLBACK/*(ResultPointCallback.class)*/,
-
-
- /**
- * Allowed extension lengths for EAN or UPC barcodes. Other formats will ignore this.
- * Maps to an {@code Int32Array} of the allowed extension lengths, for example [2], [5], or [2, 5].
- * If it is optional to have an extension, do not set this hint. If this is set,
- * and a UPC or EAN barcode is found but an extension is not, then no result will be returned
- * at all.
- */
- ALLOWED_EAN_EXTENSIONS/*(Int32Array.class)*/,
-
- // End of enumeration values.
-
-
- /**
- * Data type the hint is expecting.
- * Among the possible values the {@link Void} stands out as being used for
- * hints that do not expect a value to be supplied (flag hints). Such hints
- * will possibly have their value ignored, or replaced by a
- * {@link Boolean#TRUE}. Hint suppliers should probably use
- * {@link Boolean#TRUE} as directed by the actual hint documentation.
- */
- // private valueType: Class>
-
- // DecodeHintType(valueType: Class>) {
- // this.valueType = valueType
- // }
-
- // public getValueType(): Class> {
- // return valueType
- // }
+ /**
+ * Unspecified, application-specific hint. Maps to an unspecified {@link Object}.
+ */
+ OTHER/*(Object.class)*/,
+
+ /**
+ * Image is a pure monochrome image of a barcode. Doesn't matter what it maps to;
+ * use {@link Boolean#TRUE}.
+ */
+ PURE_BARCODE/*(Void.class)*/,
+
+ /**
+ * Image is known to be of one of a few possible formats.
+ * Maps to a {@link List} of {@link BarcodeFormat}s.
+ */
+ POSSIBLE_FORMATS/*(List.class)*/,
+
+ /**
+ * Spend more time to try to find a barcode; optimize for accuracy, not speed.
+ * Doesn't matter what it maps to; use {@link Boolean#TRUE}.
+ */
+ TRY_HARDER/*(Void.class)*/,
+
+ /**
+ * Specifies what character encoding to use when decoding, where applicable (type String)
+ */
+ CHARACTER_SET/*(String.class)*/,
+
+ /**
+ * Allowed lengths of encoded data -- reject anything else. Maps to an {@code Int32Array}.
+ */
+ ALLOWED_LENGTHS/*(Int32Array.class)*/,
+
+ /**
+ * Assume Code 39 codes employ a check digit. Doesn't matter what it maps to;
+ * use {@link Boolean#TRUE}.
+ */
+ ASSUME_CODE_39_CHECK_DIGIT/*(Void.class)*/,
+
+ /**
+ * Assume the barcode is being processed as a GS1 barcode, and modify behavior as needed.
+ * For example this affects FNC1 handling for Code 128 (aka GS1-128). Doesn't matter what it maps to;
+ * use {@link Boolean#TRUE}.
+ */
+ ASSUME_GS1/*(Void.class)*/,
+
+ /**
+ * If true, return the start and end digits in a Codabar barcode instead of stripping them. They
+ * are alpha, whereas the rest are numeric. By default, they are stripped, but this causes them
+ * to not be. Doesn't matter what it maps to; use {@link Boolean#TRUE}.
+ */
+ RETURN_CODABAR_START_END/*(Void.class)*/,
+
+ /**
+ * The caller needs to be notified via callback when a possible {@link ResultPoint}
+ * is found. Maps to a {@link ResultPointCallback}.
+ */
+ NEED_RESULT_POINT_CALLBACK/*(ResultPointCallback.class)*/,
+
+
+ /**
+ * Allowed extension lengths for EAN or UPC barcodes. Other formats will ignore this.
+ * Maps to an {@code Int32Array} of the allowed extension lengths, for example [2], [5], or [2, 5].
+ * If it is optional to have an extension, do not set this hint. If this is set,
+ * and a UPC or EAN barcode is found but an extension is not, then no result will be returned
+ * at all.
+ */
+ ALLOWED_EAN_EXTENSIONS/*(Int32Array.class)*/,
+
+ // End of enumeration values.
+
+
+ /**
+ * Data type the hint is expecting.
+ * Among the possible values the {@link Void} stands out as being used for
+ * hints that do not expect a value to be supplied (flag hints). Such hints
+ * will possibly have their value ignored, or replaced by a
+ * {@link Boolean#TRUE}. Hint suppliers should probably use
+ * {@link Boolean#TRUE} as directed by the actual hint documentation.
+ */
+ // private valueType: Class>
+
+ // DecodeHintType(valueType: Class>) {
+ // this.valueType = valueType
+ // }
+
+ // public getValueType(): Class> {
+ // return valueType
+ // }
}
diff --git a/src/core/Dimension.ts b/src/core/Dimension.ts
index 581c2cc8..9c8b85cc 100644
--- a/src/core/Dimension.ts
+++ b/src/core/Dimension.ts
@@ -22,37 +22,37 @@ import IllegalArgumentException from './IllegalArgumentException';
* Simply encapsulates a width and height.
*/
export default class Dimension {
- public constructor(private width: number /*int*/, private height: number /*int*/) {
- if (width < 0 || height < 0) {
- throw new IllegalArgumentException();
- }
+ public constructor(private width: number /*int*/, private height: number /*int*/) {
+ if (width < 0 || height < 0) {
+ throw new IllegalArgumentException();
}
+ }
- public getWidth(): number /*int*/ {
- return this.width;
- }
-
- public getHeight(): number /*int*/ {
- return this.height;
- }
+ public getWidth(): number /*int*/ {
+ return this.width;
+ }
- /*@Override*/
- public equals(other: any): boolean {
- if (other instanceof Dimension) {
- const d = other;
- return this.width === d.width && this.height === d.height;
- }
- return false;
- }
-
- /*@Override*/
- public hashCode(): number /*int*/ {
- return this.width * 32713 + this.height;
- }
+ public getHeight(): number /*int*/ {
+ return this.height;
+ }
- /*@Override*/
- public toString(): string {
- return this.width + 'x' + this.height;
+ /*@Override*/
+ public equals(other: any): boolean {
+ if (other instanceof Dimension) {
+ const d = other;
+ return this.width === d.width && this.height === d.height;
}
+ return false;
+ }
+
+ /*@Override*/
+ public hashCode(): number /*int*/ {
+ return this.width * 32713 + this.height;
+ }
+
+ /*@Override*/
+ public toString(): string {
+ return this.width + 'x' + this.height;
+ }
}
diff --git a/src/core/EncodeHintType.ts b/src/core/EncodeHintType.ts
index d50be2d3..41d396f4 100644
--- a/src/core/EncodeHintType.ts
+++ b/src/core/EncodeHintType.ts
@@ -23,84 +23,84 @@
*/
enum EncodeHintType {
- /**
- * Specifies what degree of error correction to use, for example in QR Codes.
- * Type depends on the encoder. For example for QR codes it's type
- * {@link com.google.zxing.qrcode.decoder.ErrorCorrectionLevel ErrorCorrectionLevel}.
- * For Aztec it is of type {@link Integer}, representing the minimal percentage of error correction words.
- * For PDF417 it is of type {@link Integer}, valid values being 0 to 8.
- * In all cases, it can also be a {@link String} representation of the desired value as well.
- * Note: an Aztec symbol should have a minimum of 25% EC words.
- */
- ERROR_CORRECTION,
+ /**
+ * Specifies what degree of error correction to use, for example in QR Codes.
+ * Type depends on the encoder. For example for QR codes it's type
+ * {@link com.google.zxing.qrcode.decoder.ErrorCorrectionLevel ErrorCorrectionLevel}.
+ * For Aztec it is of type {@link Integer}, representing the minimal percentage of error correction words.
+ * For PDF417 it is of type {@link Integer}, valid values being 0 to 8.
+ * In all cases, it can also be a {@link String} representation of the desired value as well.
+ * Note: an Aztec symbol should have a minimum of 25% EC words.
+ */
+ ERROR_CORRECTION,
- /**
- * Specifies what character encoding to use where applicable (type {@link String})
- */
- CHARACTER_SET,
+ /**
+ * Specifies what character encoding to use where applicable (type {@link String})
+ */
+ CHARACTER_SET,
- /**
- * Specifies the matrix shape for Data Matrix (type {@link com.google.zxing.datamatrix.encoder.SymbolShapeHint})
- */
- DATA_MATRIX_SHAPE,
+ /**
+ * Specifies the matrix shape for Data Matrix (type {@link com.google.zxing.datamatrix.encoder.SymbolShapeHint})
+ */
+ DATA_MATRIX_SHAPE,
- /**
- * Specifies a minimum barcode size (type {@link Dimension}). Only applicable to Data Matrix now.
- *
- * @deprecated use width/height params in
- * {@link com.google.zxing.datamatrix.DataMatrixWriter#encode(String, BarcodeFormat, int, int)}
- */
- /*@Deprecated*/
- MIN_SIZE,
+ /**
+ * Specifies a minimum barcode size (type {@link Dimension}). Only applicable to Data Matrix now.
+ *
+ * @deprecated use width/height params in
+ * {@link com.google.zxing.datamatrix.DataMatrixWriter#encode(String, BarcodeFormat, int, int)}
+ */
+ /*@Deprecated*/
+ MIN_SIZE,
- /**
- * Specifies a maximum barcode size (type {@link Dimension}). Only applicable to Data Matrix now.
- *
- * @deprecated without replacement
- */
- /*@Deprecated*/
- MAX_SIZE,
+ /**
+ * Specifies a maximum barcode size (type {@link Dimension}). Only applicable to Data Matrix now.
+ *
+ * @deprecated without replacement
+ */
+ /*@Deprecated*/
+ MAX_SIZE,
- /**
- * Specifies margin, in pixels, to use when generating the barcode. The meaning can vary
- * by format; for example it controls margin before and after the barcode horizontally for
- * most 1D formats. (Type {@link Integer}, or {@link String} representation of the integer value).
- */
- MARGIN,
+ /**
+ * Specifies margin, in pixels, to use when generating the barcode. The meaning can vary
+ * by format; for example it controls margin before and after the barcode horizontally for
+ * most 1D formats. (Type {@link Integer}, or {@link String} representation of the integer value).
+ */
+ MARGIN,
- /**
- * Specifies whether to use compact mode for PDF417 (type {@link Boolean}, or "true" or "false"
- * {@link String} value).
- */
- PDF417_COMPACT,
+ /**
+ * Specifies whether to use compact mode for PDF417 (type {@link Boolean}, or "true" or "false"
+ * {@link String} value).
+ */
+ PDF417_COMPACT,
- /**
- * Specifies what compaction mode to use for PDF417 (type
- * {@link com.google.zxing.pdf417.encoder.Compaction Compaction} or {@link String} value of one of its
- * enum values).
- */
- PDF417_COMPACTION,
+ /**
+ * Specifies what compaction mode to use for PDF417 (type
+ * {@link com.google.zxing.pdf417.encoder.Compaction Compaction} or {@link String} value of one of its
+ * enum values).
+ */
+ PDF417_COMPACTION,
- /**
- * Specifies the minimum and maximum number of rows and columns for PDF417 (type
- * {@link com.google.zxing.pdf417.encoder.Dimensions Dimensions}).
- */
- PDF417_DIMENSIONS,
+ /**
+ * Specifies the minimum and maximum number of rows and columns for PDF417 (type
+ * {@link com.google.zxing.pdf417.encoder.Dimensions Dimensions}).
+ */
+ PDF417_DIMENSIONS,
- /**
- * Specifies the required number of layers for an Aztec code.
- * A negative number (-1, -2, -3, -4) specifies a compact Aztec code.
- * 0 indicates to use the minimum number of layers (the default).
- * A positive number (1, 2, .. 32) specifies a normal (non-compact) Aztec code.
- * (Type {@link Integer}, or {@link String} representation of the integer value).
- */
- AZTEC_LAYERS,
+ /**
+ * Specifies the required number of layers for an Aztec code.
+ * A negative number (-1, -2, -3, -4) specifies a compact Aztec code.
+ * 0 indicates to use the minimum number of layers (the default).
+ * A positive number (1, 2, .. 32) specifies a normal (non-compact) Aztec code.
+ * (Type {@link Integer}, or {@link String} representation of the integer value).
+ */
+ AZTEC_LAYERS,
- /**
- * Specifies the exact version of QR code to be encoded.
- * (Type {@link Integer}, or {@link String} representation of the integer value).
- */
- QR_VERSION,
+ /**
+ * Specifies the exact version of QR code to be encoded.
+ * (Type {@link Integer}, or {@link String} representation of the integer value).
+ */
+ QR_VERSION,
}
export default EncodeHintType;
diff --git a/src/core/FormatException.ts b/src/core/FormatException.ts
index fb636b9a..2c24d277 100644
--- a/src/core/FormatException.ts
+++ b/src/core/FormatException.ts
@@ -7,7 +7,7 @@ export default class FormatException extends Exception {
static readonly kind: string = 'FormatException';
- static getFormatInstance(): FormatException {
- return new FormatException();
- }
+ static getFormatInstance(): FormatException {
+ return new FormatException();
+ }
}
diff --git a/src/core/InvertedLuminanceSource.ts b/src/core/InvertedLuminanceSource.ts
index d24caae4..7f356bd8 100644
--- a/src/core/InvertedLuminanceSource.ts
+++ b/src/core/InvertedLuminanceSource.ts
@@ -26,65 +26,65 @@ import LuminanceSource from './LuminanceSource';
*/
export default class InvertedLuminanceSource extends LuminanceSource {
- public constructor(private delegate: LuminanceSource) {
- super(delegate.getWidth(), delegate.getHeight());
+ public constructor(private delegate: LuminanceSource) {
+ super(delegate.getWidth(), delegate.getHeight());
+ }
+
+ /*@Override*/
+ public getRow(y: number /*int*/, row?: Uint8ClampedArray): Uint8ClampedArray {
+ const sourceRow = this.delegate.getRow(y, row);
+ const width: number /*int*/ = this.getWidth();
+ for (let i = 0; i < width; i++) {
+ sourceRow[i] = /*(byte)*/ (255 - (sourceRow[i] & 0xFF));
}
+ return sourceRow;
+ }
- /*@Override*/
- public getRow(y: number /*int*/, row?: Uint8ClampedArray): Uint8ClampedArray {
- const sourceRow = this.delegate.getRow(y, row);
- const width: number /*int*/ = this.getWidth();
- for (let i = 0; i < width; i++) {
- sourceRow[i] = /*(byte)*/ (255 - (sourceRow[i] & 0xFF));
- }
- return sourceRow;
- }
-
- /*@Override*/
- public getMatrix(): Uint8ClampedArray {
-
- const matrix: Uint8ClampedArray = this.delegate.getMatrix();
- const length: number /*int*/ = this.getWidth() * this.getHeight();
- const invertedMatrix = new Uint8ClampedArray(length);
-
- for (let i = 0; i < length; i++) {
- invertedMatrix[i] = /*(byte)*/ (255 - (matrix[i] & 0xFF));
- }
-
- return invertedMatrix;
- }
-
- /*@Override*/
- public isCropSupported(): boolean {
- return this.delegate.isCropSupported();
- }
-
- /*@Override*/
- public crop(left: number /*int*/, top: number /*int*/, width: number /*int*/, height: number /*int*/): LuminanceSource {
- return new InvertedLuminanceSource(this.delegate.crop(left, top, width, height));
- }
+ /*@Override*/
+ public getMatrix(): Uint8ClampedArray {
- /*@Override*/
- public isRotateSupported(): boolean {
- return this.delegate.isRotateSupported();
- }
+ const matrix: Uint8ClampedArray = this.delegate.getMatrix();
+ const length: number /*int*/ = this.getWidth() * this.getHeight();
+ const invertedMatrix = new Uint8ClampedArray(length);
- /**
- * @return original delegate {@link LuminanceSource} since invert undoes itself
- */
- /*@Override*/
- public invert(): LuminanceSource {
- return this.delegate;
+ for (let i = 0; i < length; i++) {
+ invertedMatrix[i] = /*(byte)*/ (255 - (matrix[i] & 0xFF));
}
- /*@Override*/
- public rotateCounterClockwise(): LuminanceSource {
- return new InvertedLuminanceSource(this.delegate.rotateCounterClockwise());
- }
-
- /*@Override*/
- public rotateCounterClockwise45(): LuminanceSource {
- return new InvertedLuminanceSource(this.delegate.rotateCounterClockwise45());
- }
+ return invertedMatrix;
+ }
+
+ /*@Override*/
+ public isCropSupported(): boolean {
+ return this.delegate.isCropSupported();
+ }
+
+ /*@Override*/
+ public crop(left: number /*int*/, top: number /*int*/, width: number /*int*/, height: number /*int*/): LuminanceSource {
+ return new InvertedLuminanceSource(this.delegate.crop(left, top, width, height));
+ }
+
+ /*@Override*/
+ public isRotateSupported(): boolean {
+ return this.delegate.isRotateSupported();
+ }
+
+ /**
+ * @return original delegate {@link LuminanceSource} since invert undoes itself
+ */
+ /*@Override*/
+ public invert(): LuminanceSource {
+ return this.delegate;
+ }
+
+ /*@Override*/
+ public rotateCounterClockwise(): LuminanceSource {
+ return new InvertedLuminanceSource(this.delegate.rotateCounterClockwise());
+ }
+
+ /*@Override*/
+ public rotateCounterClockwise45(): LuminanceSource {
+ return new InvertedLuminanceSource(this.delegate.rotateCounterClockwise45());
+ }
}
diff --git a/src/core/MultiFormatReader.ts b/src/core/MultiFormatReader.ts
index 3b0c1de4..69dcfd8f 100644
--- a/src/core/MultiFormatReader.ts
+++ b/src/core/MultiFormatReader.ts
@@ -40,164 +40,164 @@ import ReaderException from './ReaderException';
*/
export default class MultiFormatReader implements Reader {
- private hints: Map | null;
- private readers: Reader[];
-
- /**
- * This version of decode honors the intent of Reader.decode(BinaryBitmap) in that it
- * passes null as a hint to the decoders. However, that makes it inefficient to call repeatedly.
- * Use setHints() followed by decodeWithState() for continuous scan applications.
- *
- * @param image The pixel data to decode
- * @return The contents of the image
- *
- * @throws NotFoundException Any errors which occurred
- */
- /*@Override*/
- // public decode(image: BinaryBitmap): Result {
- // setHints(null)
- // return decodeInternal(image)
- // }
-
- /**
- * Decode an image using the hints provided. Does not honor existing state.
- *
- * @param image The pixel data to decode
- * @param hints The hints to use, clearing the previous state.
- * @return The contents of the image
- *
- * @throws NotFoundException Any errors which occurred
- */
- /*@Override*/
- public decode(image: BinaryBitmap, hints?: Map): Result {
- this.setHints(hints);
- return this.decodeInternal(image);
+ private hints: Map | null;
+ private readers: Reader[];
+
+ /**
+ * This version of decode honors the intent of Reader.decode(BinaryBitmap) in that it
+ * passes null as a hint to the decoders. However, that makes it inefficient to call repeatedly.
+ * Use setHints() followed by decodeWithState() for continuous scan applications.
+ *
+ * @param image The pixel data to decode
+ * @return The contents of the image
+ *
+ * @throws NotFoundException Any errors which occurred
+ */
+ /*@Override*/
+ // public decode(image: BinaryBitmap): Result {
+ // setHints(null)
+ // return decodeInternal(image)
+ // }
+
+ /**
+ * Decode an image using the hints provided. Does not honor existing state.
+ *
+ * @param image The pixel data to decode
+ * @param hints The hints to use, clearing the previous state.
+ * @return The contents of the image
+ *
+ * @throws NotFoundException Any errors which occurred
+ */
+ /*@Override*/
+ public decode(image: BinaryBitmap, hints?: Map): Result {
+ this.setHints(hints);
+ return this.decodeInternal(image);
+ }
+
+ /**
+ * Decode an image using the state set up by calling setHints() previously. Continuous scan
+ * clients will get a large speed increase by using this instead of decode().
+ *
+ * @param image The pixel data to decode
+ * @return The contents of the image
+ *
+ * @throws NotFoundException Any errors which occurred
+ */
+ public decodeWithState(image: BinaryBitmap): Result {
+ // Make sure to set up the default state so we don't crash
+ if (this.readers === null || this.readers === undefined) {
+ this.setHints(null);
}
-
- /**
- * Decode an image using the state set up by calling setHints() previously. Continuous scan
- * clients will get a large speed increase by using this instead of decode().
- *
- * @param image The pixel data to decode
- * @return The contents of the image
- *
- * @throws NotFoundException Any errors which occurred
- */
- public decodeWithState(image: BinaryBitmap): Result {
- // Make sure to set up the default state so we don't crash
- if (this.readers === null || this.readers === undefined) {
- this.setHints(null);
- }
- return this.decodeInternal(image);
+ return this.decodeInternal(image);
+ }
+
+ /**
+ * This method adds state to the MultiFormatReader. By setting the hints once, subsequent calls
+ * to decodeWithState(image) can reuse the same set of readers without reallocating memory. This
+ * is important for performance in continuous scan clients.
+ *
+ * @param hints The set of hints to use for subsequent calls to decode(image)
+ */
+ public setHints(hints?: Map | null): void {
+ this.hints = hints;
+
+ const tryHarder: boolean = hints !== null && hints !== undefined && undefined !== hints.get(DecodeHintType.TRY_HARDER);
+ /*@SuppressWarnings("unchecked")*/
+ const formats = hints === null || hints === undefined ? null : hints.get(DecodeHintType.POSSIBLE_FORMATS);
+ const readers = new Array();
+ if (formats !== null && formats !== undefined) {
+ const addOneDReader: boolean = formats.some(f =>
+ f === BarcodeFormat.UPC_A ||
+ f === BarcodeFormat.UPC_E ||
+ f === BarcodeFormat.EAN_13 ||
+ f === BarcodeFormat.EAN_8 ||
+ f === BarcodeFormat.CODABAR ||
+ f === BarcodeFormat.CODE_39 ||
+ f === BarcodeFormat.CODE_93 ||
+ f === BarcodeFormat.CODE_128 ||
+ f === BarcodeFormat.ITF ||
+ f === BarcodeFormat.RSS_14 ||
+ f === BarcodeFormat.RSS_EXPANDED
+ );
+ // Put 1D readers upfront in "normal" mode
+
+ // TYPESCRIPTPORT: TODO: uncomment below as they are ported
+
+ if (addOneDReader && !tryHarder) {
+ readers.push(new MultiFormatOneDReader(hints));
+ }
+ if (formats.includes(BarcodeFormat.QR_CODE)) {
+ readers.push(new QRCodeReader());
+ }
+ if (formats.includes(BarcodeFormat.DATA_MATRIX)) {
+ readers.push(new DataMatrixReader());
+ }
+ if (formats.includes(BarcodeFormat.AZTEC)) {
+ readers.push(new AztecReader());
+ }
+ if (formats.includes(BarcodeFormat.PDF_417)) {
+ readers.push(new PDF417Reader());
+ }
+ // if (formats.includes(BarcodeFormat.MAXICODE)) {
+ // readers.push(new MaxiCodeReader())
+ // }
+ // At end in "try harder" mode
+ if (addOneDReader && tryHarder) {
+ readers.push(new MultiFormatOneDReader(hints));
+ }
}
-
- /**
- * This method adds state to the MultiFormatReader. By setting the hints once, subsequent calls
- * to decodeWithState(image) can reuse the same set of readers without reallocating memory. This
- * is important for performance in continuous scan clients.
- *
- * @param hints The set of hints to use for subsequent calls to decode(image)
- */
- public setHints(hints?: Map | null): void {
- this.hints = hints;
-
- const tryHarder: boolean = hints !== null && hints !== undefined && undefined !== hints.get(DecodeHintType.TRY_HARDER);
- /*@SuppressWarnings("unchecked")*/
- const formats = hints === null || hints === undefined ? null : hints.get(DecodeHintType.POSSIBLE_FORMATS);
- const readers = new Array();
- if (formats !== null && formats !== undefined) {
- const addOneDReader: boolean = formats.some(f =>
- f === BarcodeFormat.UPC_A ||
- f === BarcodeFormat.UPC_E ||
- f === BarcodeFormat.EAN_13 ||
- f === BarcodeFormat.EAN_8 ||
- f === BarcodeFormat.CODABAR ||
- f === BarcodeFormat.CODE_39 ||
- f === BarcodeFormat.CODE_93 ||
- f === BarcodeFormat.CODE_128 ||
- f === BarcodeFormat.ITF ||
- f === BarcodeFormat.RSS_14 ||
- f === BarcodeFormat.RSS_EXPANDED
- );
- // Put 1D readers upfront in "normal" mode
-
- // TYPESCRIPTPORT: TODO: uncomment below as they are ported
-
- if (addOneDReader && !tryHarder) {
- readers.push(new MultiFormatOneDReader(hints));
- }
- if (formats.includes(BarcodeFormat.QR_CODE)) {
- readers.push(new QRCodeReader());
- }
- if (formats.includes(BarcodeFormat.DATA_MATRIX)) {
- readers.push(new DataMatrixReader());
- }
- if (formats.includes(BarcodeFormat.AZTEC)) {
- readers.push(new AztecReader());
- }
- if (formats.includes(BarcodeFormat.PDF_417)) {
- readers.push(new PDF417Reader());
- }
- // if (formats.includes(BarcodeFormat.MAXICODE)) {
- // readers.push(new MaxiCodeReader())
- // }
- // At end in "try harder" mode
- if (addOneDReader && tryHarder) {
- readers.push(new MultiFormatOneDReader(hints));
- }
- }
- if (readers.length === 0) {
- if (!tryHarder) {
- readers.push(new MultiFormatOneDReader(hints));
- }
-
- readers.push(new QRCodeReader());
- readers.push(new DataMatrixReader());
- readers.push(new AztecReader());
- readers.push(new PDF417Reader());
- // readers.push(new MaxiCodeReader())
-
- if (tryHarder) {
- readers.push(new MultiFormatOneDReader(hints));
- }
- }
- this.readers = readers; // .toArray(new Reader[readers.size()])
+ if (readers.length === 0) {
+ if (!tryHarder) {
+ readers.push(new MultiFormatOneDReader(hints));
+ }
+
+ readers.push(new QRCodeReader());
+ readers.push(new DataMatrixReader());
+ readers.push(new AztecReader());
+ readers.push(new PDF417Reader());
+ // readers.push(new MaxiCodeReader())
+
+ if (tryHarder) {
+ readers.push(new MultiFormatOneDReader(hints));
+ }
}
-
- /*@Override*/
- public reset(): void {
- if (this.readers !== null) {
- for (const reader of this.readers) {
- reader.reset();
- }
- }
+ this.readers = readers; // .toArray(new Reader[readers.size()])
+ }
+
+ /*@Override*/
+ public reset(): void {
+ if (this.readers !== null) {
+ for (const reader of this.readers) {
+ reader.reset();
+ }
}
+ }
- /**
- * @throws NotFoundException
- */
- private decodeInternal(image: BinaryBitmap): Result {
-
- if (this.readers === null) {
- throw new ReaderException('No readers where selected, nothing can be read.');
- }
+ /**
+ * @throws NotFoundException
+ */
+ private decodeInternal(image: BinaryBitmap): Result {
- for (const reader of this.readers) {
+ if (this.readers === null) {
+ throw new ReaderException('No readers where selected, nothing can be read.');
+ }
- // Trying to decode with ${reader} reader.
+ for (const reader of this.readers) {
- try {
- return reader.decode(image, this.hints);
- } catch (ex) {
- if (ex instanceof ReaderException) {
- continue;
- }
+ // Trying to decode with ${reader} reader.
- // Bad Exception.
- }
+ try {
+ return reader.decode(image, this.hints);
+ } catch (ex) {
+ if (ex instanceof ReaderException) {
+ continue;
}
- throw new NotFoundException('No MultiFormat Readers were able to detect the code.');
+ // Bad Exception.
+ }
}
+ throw new NotFoundException('No MultiFormat Readers were able to detect the code.');
+ }
+
}
diff --git a/src/core/MultiFormatWriter.ts b/src/core/MultiFormatWriter.ts
index c551a6e8..781acfdc 100644
--- a/src/core/MultiFormatWriter.ts
+++ b/src/core/MultiFormatWriter.ts
@@ -45,65 +45,65 @@ import IllegalArgumentException from './IllegalArgumentException';
*/
export default class MultiFormatWriter implements Writer {
- /*@Override*/
- // public encode(contents: string,
- // format: BarcodeFormat,
- // width: number /*int*/,
- // height: number /*int*/): BitMatrix /*throws WriterException */ {
- // return encode(contents, format, width, height, null)
- // }
+ /*@Override*/
+ // public encode(contents: string,
+ // format: BarcodeFormat,
+ // width: number /*int*/,
+ // height: number /*int*/): BitMatrix /*throws WriterException */ {
+ // return encode(contents, format, width, height, null)
+ // }
- /*@Override*/
- public encode(contents: string,
- format: BarcodeFormat,
- width: number /*int*/, height: number /*int*/,
- hints: Map): BitMatrix /*throws WriterException */ {
+ /*@Override*/
+ public encode(contents: string,
+ format: BarcodeFormat,
+ width: number /*int*/, height: number /*int*/,
+ hints: Map): BitMatrix /*throws WriterException */ {
- let writer: Writer;
- switch (format) {
- // case BarcodeFormat.EAN_8:
- // writer = new EAN8Writer()
- // break
- // case BarcodeFormat.UPC_E:
- // writer = new UPCEWriter()
- // break
- // case BarcodeFormat.EAN_13:
- // writer = new EAN13Writer()
- // break
- // case BarcodeFormat.UPC_A:
- // writer = new UPCAWriter()
- // break
- case BarcodeFormat.QR_CODE:
- writer = new QRCodeWriter();
- break;
- // case BarcodeFormat.CODE_39:
- // writer = new Code39Writer()
- // break
- // case BarcodeFormat.CODE_93:
- // writer = new Code93Writer()
- // break
- // case BarcodeFormat.CODE_128:
- // writer = new Code128Writer()
- // break
- // case BarcodeFormat.ITF:
- // writer = new ITFWriter()
- // break
- // case BarcodeFormat.PDF_417:
- // writer = new PDF417Writer()
- // break
- // case BarcodeFormat.CODABAR:
- // writer = new CodaBarWriter()
- // break
- // case BarcodeFormat.DATA_MATRIX:
- // writer = new DataMatrixWriter()
- // break
- // case BarcodeFormat.AZTEC:
- // writer = new AztecWriter()
- // break
- default:
- throw new IllegalArgumentException('No encoder available for format ' + format);
- }
- return writer.encode(contents, format, width, height, hints);
+ let writer: Writer;
+ switch (format) {
+ // case BarcodeFormat.EAN_8:
+ // writer = new EAN8Writer()
+ // break
+ // case BarcodeFormat.UPC_E:
+ // writer = new UPCEWriter()
+ // break
+ // case BarcodeFormat.EAN_13:
+ // writer = new EAN13Writer()
+ // break
+ // case BarcodeFormat.UPC_A:
+ // writer = new UPCAWriter()
+ // break
+ case BarcodeFormat.QR_CODE:
+ writer = new QRCodeWriter();
+ break;
+ // case BarcodeFormat.CODE_39:
+ // writer = new Code39Writer()
+ // break
+ // case BarcodeFormat.CODE_93:
+ // writer = new Code93Writer()
+ // break
+ // case BarcodeFormat.CODE_128:
+ // writer = new Code128Writer()
+ // break
+ // case BarcodeFormat.ITF:
+ // writer = new ITFWriter()
+ // break
+ // case BarcodeFormat.PDF_417:
+ // writer = new PDF417Writer()
+ // break
+ // case BarcodeFormat.CODABAR:
+ // writer = new CodaBarWriter()
+ // break
+ // case BarcodeFormat.DATA_MATRIX:
+ // writer = new DataMatrixWriter()
+ // break
+ // case BarcodeFormat.AZTEC:
+ // writer = new AztecWriter()
+ // break
+ default:
+ throw new IllegalArgumentException('No encoder available for format ' + format);
}
+ return writer.encode(contents, format, width, height, hints);
+ }
}
diff --git a/src/core/OutOfMemoryError.ts b/src/core/OutOfMemoryError.ts
index 210af964..6e3f6440 100644
--- a/src/core/OutOfMemoryError.ts
+++ b/src/core/OutOfMemoryError.ts
@@ -3,4 +3,4 @@ import Exception from './Exception';
/**
* Custom Error class of type Exception.
*/
-export default class OutOfMemoryError extends Exception {}
+export default class OutOfMemoryError extends Exception { }
diff --git a/src/core/PlanarYUVLuminanceSource.ts b/src/core/PlanarYUVLuminanceSource.ts
index 50106001..f50628f1 100644
--- a/src/core/PlanarYUVLuminanceSource.ts
+++ b/src/core/PlanarYUVLuminanceSource.ts
@@ -34,134 +34,134 @@ import IllegalArgumentException from './IllegalArgumentException';
*/
export default class PlanarYUVLuminanceSource extends LuminanceSource {
- private static THUMBNAIL_SCALE_FACTOR: number /*int*/ = 2;
-
- public constructor(private yuvData: Uint8ClampedArray,
- private dataWidth: number /*int*/,
- private dataHeight: number /*int*/,
- private left: number /*int*/,
- private top: number /*int*/,
- width: number /*int*/,
- height: number /*int*/,
- reverseHorizontal: boolean) {
- super(width, height);
-
- if (left + width > dataWidth || top + height > dataHeight) {
- throw new IllegalArgumentException('Crop rectangle does not fit within image data.');
- }
-
- if (reverseHorizontal) {
- this.reverseHorizontal(width, height);
- }
+ private static THUMBNAIL_SCALE_FACTOR: number /*int*/ = 2;
+
+ public constructor(private yuvData: Uint8ClampedArray,
+ private dataWidth: number /*int*/,
+ private dataHeight: number /*int*/,
+ private left: number /*int*/,
+ private top: number /*int*/,
+ width: number /*int*/,
+ height: number /*int*/,
+ reverseHorizontal: boolean) {
+ super(width, height);
+
+ if (left + width > dataWidth || top + height > dataHeight) {
+ throw new IllegalArgumentException('Crop rectangle does not fit within image data.');
}
- /*@Override*/
- public getRow(y: number /*int*/, row?: Uint8ClampedArray): Uint8ClampedArray {
- if (y < 0 || y >= this.getHeight()) {
- throw new IllegalArgumentException('Requested row is outside the image: ' + y);
- }
- const width: number /*int*/ = this.getWidth();
- if (row === null || row === undefined || row.length < width) {
- row = new Uint8ClampedArray(width);
- }
- const offset = (y + this.top) * this.dataWidth + this.left;
- System.arraycopy(this.yuvData, offset, row, 0, width);
- return row;
+ if (reverseHorizontal) {
+ this.reverseHorizontal(width, height);
}
+ }
- /*@Override*/
- public getMatrix(): Uint8ClampedArray {
- const width: number /*int*/ = this.getWidth();
- const height: number /*int*/ = this.getHeight();
-
- // If the caller asks for the entire underlying image, save the copy and give them the
- // original data. The docs specifically warn that result.length must be ignored.
- if (width === this.dataWidth && height === this.dataHeight) {
- return this.yuvData;
- }
-
- const area = width * height;
- const matrix = new Uint8ClampedArray(area);
- let inputOffset = this.top * this.dataWidth + this.left;
-
- // If the width matches the full width of the underlying data, perform a single copy.
- if (width === this.dataWidth) {
- System.arraycopy(this.yuvData, inputOffset, matrix, 0, area);
- return matrix;
- }
-
- // Otherwise copy one cropped row at a time.
- for (let y = 0; y < height; y++) {
- const outputOffset = y * width;
- System.arraycopy(this.yuvData, inputOffset, matrix, outputOffset, width);
- inputOffset += this.dataWidth;
- }
- return matrix;
+ /*@Override*/
+ public getRow(y: number /*int*/, row?: Uint8ClampedArray): Uint8ClampedArray {
+ if (y < 0 || y >= this.getHeight()) {
+ throw new IllegalArgumentException('Requested row is outside the image: ' + y);
}
-
- /*@Override*/
- public isCropSupported(): boolean {
- return true;
+ const width: number /*int*/ = this.getWidth();
+ if (row === null || row === undefined || row.length < width) {
+ row = new Uint8ClampedArray(width);
}
-
- /*@Override*/
- public crop(left: number /*int*/, top: number /*int*/, width: number /*int*/, height: number /*int*/): LuminanceSource {
- return new PlanarYUVLuminanceSource(this.yuvData,
- this.dataWidth,
- this.dataHeight,
- this.left + left,
- this.top + top,
- width,
- height,
- false);
+ const offset = (y + this.top) * this.dataWidth + this.left;
+ System.arraycopy(this.yuvData, offset, row, 0, width);
+ return row;
+ }
+
+ /*@Override*/
+ public getMatrix(): Uint8ClampedArray {
+ const width: number /*int*/ = this.getWidth();
+ const height: number /*int*/ = this.getHeight();
+
+ // If the caller asks for the entire underlying image, save the copy and give them the
+ // original data. The docs specifically warn that result.length must be ignored.
+ if (width === this.dataWidth && height === this.dataHeight) {
+ return this.yuvData;
}
- public renderThumbnail(): Int32Array {
- const width: number /*int*/ = this.getWidth() / PlanarYUVLuminanceSource.THUMBNAIL_SCALE_FACTOR;
- const height: number /*int*/ = this.getHeight() / PlanarYUVLuminanceSource.THUMBNAIL_SCALE_FACTOR;
- const pixels = new Int32Array(width * height);
- const yuv = this.yuvData;
- let inputOffset = this.top * this.dataWidth + this.left;
-
- for (let y = 0; y < height; y++) {
- const outputOffset = y * width;
- for (let x = 0; x < width; x++) {
- const grey = yuv[inputOffset + x * PlanarYUVLuminanceSource.THUMBNAIL_SCALE_FACTOR] & 0xff;
- pixels[outputOffset + x] = 0xFF000000 | (grey * 0x00010101);
- }
- inputOffset += this.dataWidth * PlanarYUVLuminanceSource.THUMBNAIL_SCALE_FACTOR;
- }
- return pixels;
- }
+ const area = width * height;
+ const matrix = new Uint8ClampedArray(area);
+ let inputOffset = this.top * this.dataWidth + this.left;
- /**
- * @return width of image from {@link #renderThumbnail()}
- */
- public getThumbnailWidth(): number /*int*/ {
- return this.getWidth() / PlanarYUVLuminanceSource.THUMBNAIL_SCALE_FACTOR;
+ // If the width matches the full width of the underlying data, perform a single copy.
+ if (width === this.dataWidth) {
+ System.arraycopy(this.yuvData, inputOffset, matrix, 0, area);
+ return matrix;
}
- /**
- * @return height of image from {@link #renderThumbnail()}
- */
- public getThumbnailHeight(): number /*int*/ {
- return this.getHeight() / PlanarYUVLuminanceSource.THUMBNAIL_SCALE_FACTOR;
+ // Otherwise copy one cropped row at a time.
+ for (let y = 0; y < height; y++) {
+ const outputOffset = y * width;
+ System.arraycopy(this.yuvData, inputOffset, matrix, outputOffset, width);
+ inputOffset += this.dataWidth;
}
-
- private reverseHorizontal(width: number /*int*/, height: number /*int*/): void {
- const yuvData = this.yuvData;
- for (let y = 0, rowStart = this.top * this.dataWidth + this.left; y < height; y++ , rowStart += this.dataWidth) {
- const middle = rowStart + width / 2;
- for (let x1 = rowStart, x2 = rowStart + width - 1; x1 < middle; x1++ , x2--) {
- const temp = yuvData[x1];
- yuvData[x1] = yuvData[x2];
- yuvData[x2] = temp;
- }
- }
+ return matrix;
+ }
+
+ /*@Override*/
+ public isCropSupported(): boolean {
+ return true;
+ }
+
+ /*@Override*/
+ public crop(left: number /*int*/, top: number /*int*/, width: number /*int*/, height: number /*int*/): LuminanceSource {
+ return new PlanarYUVLuminanceSource(this.yuvData,
+ this.dataWidth,
+ this.dataHeight,
+ this.left + left,
+ this.top + top,
+ width,
+ height,
+ false);
+ }
+
+ public renderThumbnail(): Int32Array {
+ const width: number /*int*/ = this.getWidth() / PlanarYUVLuminanceSource.THUMBNAIL_SCALE_FACTOR;
+ const height: number /*int*/ = this.getHeight() / PlanarYUVLuminanceSource.THUMBNAIL_SCALE_FACTOR;
+ const pixels = new Int32Array(width * height);
+ const yuv = this.yuvData;
+ let inputOffset = this.top * this.dataWidth + this.left;
+
+ for (let y = 0; y < height; y++) {
+ const outputOffset = y * width;
+ for (let x = 0; x < width; x++) {
+ const grey = yuv[inputOffset + x * PlanarYUVLuminanceSource.THUMBNAIL_SCALE_FACTOR] & 0xff;
+ pixels[outputOffset + x] = 0xFF000000 | (grey * 0x00010101);
+ }
+ inputOffset += this.dataWidth * PlanarYUVLuminanceSource.THUMBNAIL_SCALE_FACTOR;
}
-
- public invert(): LuminanceSource {
- return new InvertedLuminanceSource(this);
+ return pixels;
+ }
+
+ /**
+ * @return width of image from {@link #renderThumbnail()}
+ */
+ public getThumbnailWidth(): number /*int*/ {
+ return this.getWidth() / PlanarYUVLuminanceSource.THUMBNAIL_SCALE_FACTOR;
+ }
+
+ /**
+ * @return height of image from {@link #renderThumbnail()}
+ */
+ public getThumbnailHeight(): number /*int*/ {
+ return this.getHeight() / PlanarYUVLuminanceSource.THUMBNAIL_SCALE_FACTOR;
+ }
+
+ private reverseHorizontal(width: number /*int*/, height: number /*int*/): void {
+ const yuvData = this.yuvData;
+ for (let y = 0, rowStart = this.top * this.dataWidth + this.left; y < height; y++, rowStart += this.dataWidth) {
+ const middle = rowStart + width / 2;
+ for (let x1 = rowStart, x2 = rowStart + width - 1; x1 < middle; x1++, x2--) {
+ const temp = yuvData[x1];
+ yuvData[x1] = yuvData[x2];
+ yuvData[x2] = temp;
+ }
}
+ }
+
+ public invert(): LuminanceSource {
+ return new InvertedLuminanceSource(this);
+ }
}
diff --git a/src/core/RGBLuminanceSource.ts b/src/core/RGBLuminanceSource.ts
index fd63cacd..c689c057 100644
--- a/src/core/RGBLuminanceSource.ts
+++ b/src/core/RGBLuminanceSource.ts
@@ -32,136 +32,136 @@ import IllegalArgumentException from './IllegalArgumentException';
*/
export default class RGBLuminanceSource extends LuminanceSource {
- // public constructor(width: number /*int*/, height: number /*int*/, const pixels: Int32Array) {
- // super(width, height)
-
- // dataWidth = width
- // dataHeight = height
- // left = 0
- // top = 0
-
- // // In order to measure pure decoding speed, we convert the entire image to a greyscale array
- // // up front, which is the same as the Y channel of the YUVLuminanceSource in the real app.
- // //
- // // Total number of pixels suffices, can ignore shape
- // const size = width * height;
- // luminances = new byte[size]
- // for (let offset = 0; offset < size; offset++) {
- // const pixel = pixels[offset]
- // const r = (pixel >> 16) & 0xff; // red
- // const g2 = (pixel >> 7) & 0x1fe; // 2 * green
- // const b = pixel & 0xff; // blue
- // // Calculate green-favouring average cheaply
- // luminances[offset] = (byte) ((r + g2 + b) / 4)
- // }
- // }
-
- private luminances: Uint8ClampedArray;
-
- public constructor(luminances: Uint8ClampedArray | Int32Array,
- width: number /*int*/,
- height: number /*int*/,
- private dataWidth?: number /*int*/,
- private dataHeight?: number /*int*/,
- private left?: number /*int*/,
- private top?: number /*int*/) {
- super(width, height);
-
- if (luminances.BYTES_PER_ELEMENT === 4) {// Int32Array
- const size = width * height;
- const luminancesUint8Array = new Uint8ClampedArray(size);
- for (let offset = 0; offset < size; offset++) {
- const pixel = luminances[offset];
- const r = (pixel >> 16) & 0xff; // red
- const g2 = (pixel >> 7) & 0x1fe; // 2 * green
- const b = pixel & 0xff; // blue
- // Calculate green-favouring average cheaply
- luminancesUint8Array[offset] = /*(byte) */((r + g2 + b) / 4) & 0xFF;
- }
- this.luminances = luminancesUint8Array;
- } else {
- this.luminances = luminances;
- }
-
- if (undefined === dataWidth) {
- this.dataWidth = width;
- }
- if (undefined === dataHeight) {
- this.dataHeight = height;
- }
- if (undefined === left) {
- this.left = 0;
- }
- if (undefined === top) {
- this.top = 0;
- }
- if (this.left + width > this.dataWidth || this.top + height > this.dataHeight) {
- throw new IllegalArgumentException('Crop rectangle does not fit within image data.');
- }
+ // public constructor(width: number /*int*/, height: number /*int*/, const pixels: Int32Array) {
+ // super(width, height)
+
+ // dataWidth = width
+ // dataHeight = height
+ // left = 0
+ // top = 0
+
+ // // In order to measure pure decoding speed, we convert the entire image to a greyscale array
+ // // up front, which is the same as the Y channel of the YUVLuminanceSource in the real app.
+ // //
+ // // Total number of pixels suffices, can ignore shape
+ // const size = width * height;
+ // luminances = new byte[size]
+ // for (let offset = 0; offset < size; offset++) {
+ // const pixel = pixels[offset]
+ // const r = (pixel >> 16) & 0xff; // red
+ // const g2 = (pixel >> 7) & 0x1fe; // 2 * green
+ // const b = pixel & 0xff; // blue
+ // // Calculate green-favouring average cheaply
+ // luminances[offset] = (byte) ((r + g2 + b) / 4)
+ // }
+ // }
+
+ private luminances: Uint8ClampedArray;
+
+ public constructor(luminances: Uint8ClampedArray | Int32Array,
+ width: number /*int*/,
+ height: number /*int*/,
+ private dataWidth?: number /*int*/,
+ private dataHeight?: number /*int*/,
+ private left?: number /*int*/,
+ private top?: number /*int*/) {
+ super(width, height);
+
+ if (luminances.BYTES_PER_ELEMENT === 4) {// Int32Array
+ const size = width * height;
+ const luminancesUint8Array = new Uint8ClampedArray(size);
+ for (let offset = 0; offset < size; offset++) {
+ const pixel = luminances[offset];
+ const r = (pixel >> 16) & 0xff; // red
+ const g2 = (pixel >> 7) & 0x1fe; // 2 * green
+ const b = pixel & 0xff; // blue
+ // Calculate green-favouring average cheaply
+ luminancesUint8Array[offset] = /*(byte) */((r + g2 + b) / 4) & 0xFF;
+ }
+ this.luminances = luminancesUint8Array;
+ } else {
+ this.luminances = luminances;
}
- /*@Override*/
- public getRow(y: number /*int*/, row?: Uint8ClampedArray): Uint8ClampedArray {
- if (y < 0 || y >= this.getHeight()) {
- throw new IllegalArgumentException('Requested row is outside the image: ' + y);
- }
- const width = this.getWidth();
- if (row === null || row === undefined || row.length < width) {
- row = new Uint8ClampedArray(width);
- }
- const offset = (y + this.top) * this.dataWidth + this.left;
- System.arraycopy(this.luminances, offset, row, 0, width);
- return row;
+ if (undefined === dataWidth) {
+ this.dataWidth = width;
}
+ if (undefined === dataHeight) {
+ this.dataHeight = height;
+ }
+ if (undefined === left) {
+ this.left = 0;
+ }
+ if (undefined === top) {
+ this.top = 0;
+ }
+ if (this.left + width > this.dataWidth || this.top + height > this.dataHeight) {
+ throw new IllegalArgumentException('Crop rectangle does not fit within image data.');
+ }
+ }
- /*@Override*/
- public getMatrix(): Uint8ClampedArray {
-
- const width = this.getWidth();
- const height = this.getHeight();
-
- // If the caller asks for the entire underlying image, save the copy and give them the
- // original data. The docs specifically warn that result.length must be ignored.
- if (width === this.dataWidth && height === this.dataHeight) {
- return this.luminances;
- }
-
- const area = width * height;
- const matrix = new Uint8ClampedArray(area);
- let inputOffset = this.top * this.dataWidth + this.left;
-
- // If the width matches the full width of the underlying data, perform a single copy.
- if (width === this.dataWidth) {
- System.arraycopy(this.luminances, inputOffset, matrix, 0, area);
- return matrix;
- }
-
- // Otherwise copy one cropped row at a time.
- for (let y = 0; y < height; y++) {
- const outputOffset = y * width;
- System.arraycopy(this.luminances, inputOffset, matrix, outputOffset, width);
- inputOffset += this.dataWidth;
- }
- return matrix;
+ /*@Override*/
+ public getRow(y: number /*int*/, row?: Uint8ClampedArray): Uint8ClampedArray {
+ if (y < 0 || y >= this.getHeight()) {
+ throw new IllegalArgumentException('Requested row is outside the image: ' + y);
}
+ const width = this.getWidth();
+ if (row === null || row === undefined || row.length < width) {
+ row = new Uint8ClampedArray(width);
+ }
+ const offset = (y + this.top) * this.dataWidth + this.left;
+ System.arraycopy(this.luminances, offset, row, 0, width);
+ return row;
+ }
+
+ /*@Override*/
+ public getMatrix(): Uint8ClampedArray {
- /*@Override*/
- public isCropSupported(): boolean {
- return true;
+ const width = this.getWidth();
+ const height = this.getHeight();
+
+ // If the caller asks for the entire underlying image, save the copy and give them the
+ // original data. The docs specifically warn that result.length must be ignored.
+ if (width === this.dataWidth && height === this.dataHeight) {
+ return this.luminances;
}
- /*@Override*/
- public crop(left: number /*int*/, top: number /*int*/, width: number /*int*/, height: number /*int*/): LuminanceSource {
- return new RGBLuminanceSource(this.luminances,
- width,
- height,
- this.dataWidth,
- this.dataHeight,
- this.left + left,
- this.top + top, );
+ const area = width * height;
+ const matrix = new Uint8ClampedArray(area);
+ let inputOffset = this.top * this.dataWidth + this.left;
+
+ // If the width matches the full width of the underlying data, perform a single copy.
+ if (width === this.dataWidth) {
+ System.arraycopy(this.luminances, inputOffset, matrix, 0, area);
+ return matrix;
}
- public invert(): LuminanceSource {
- return new InvertedLuminanceSource(this);
+ // Otherwise copy one cropped row at a time.
+ for (let y = 0; y < height; y++) {
+ const outputOffset = y * width;
+ System.arraycopy(this.luminances, inputOffset, matrix, outputOffset, width);
+ inputOffset += this.dataWidth;
}
+ return matrix;
+ }
+
+ /*@Override*/
+ public isCropSupported(): boolean {
+ return true;
+ }
+
+ /*@Override*/
+ public crop(left: number /*int*/, top: number /*int*/, width: number /*int*/, height: number /*int*/): LuminanceSource {
+ return new RGBLuminanceSource(this.luminances,
+ width,
+ height,
+ this.dataWidth,
+ this.dataHeight,
+ this.left + left,
+ this.top + top);
+ }
+
+ public invert(): LuminanceSource {
+ return new InvertedLuminanceSource(this);
+ }
}
diff --git a/src/core/Reader.ts b/src/core/Reader.ts
index 0757759d..1260f514 100644
--- a/src/core/Reader.ts
+++ b/src/core/Reader.ts
@@ -38,39 +38,39 @@ export default Reader;
*/
interface Reader {
- /**
- * Locates and decodes a barcode in some format within an image.
- *
- * @param image image of barcode to decode
- * @return which: string the barcode encodes
- * @throws NotFoundException if no potential barcode is found
- * @throws ChecksumException if a potential barcode is found but does not pass its checksum
- * @throws FormatException if a potential barcode is found but format is invalid
- */
- // decode(image: BinaryBitmap): Result /*throws NotFoundException, ChecksumException, FormatException*/
+ /**
+ * Locates and decodes a barcode in some format within an image.
+ *
+ * @param image image of barcode to decode
+ * @return which: string the barcode encodes
+ * @throws NotFoundException if no potential barcode is found
+ * @throws ChecksumException if a potential barcode is found but does not pass its checksum
+ * @throws FormatException if a potential barcode is found but format is invalid
+ */
+ // decode(image: BinaryBitmap): Result /*throws NotFoundException, ChecksumException, FormatException*/
- /**
- * Locates and decodes a barcode in some format within an image. This method also accepts
- * hints, each possibly associated to some data, which may help the implementation decode.
- *
- * @param image image of barcode to decode
- * @param hints passed as a {@link Map} from {@link DecodeHintType}
- * to arbitrary data. The
- * meaning of the data depends upon the hint type. The implementation may or may not do
- * anything with these hints.
- *
- * @return which: string the barcode encodes
- *
- * @throws NotFoundException if no potential barcode is found
- * @throws ChecksumException if a potential barcode is found but does not pass its checksum
- * @throws FormatException if a potential barcode is found but format is invalid
- */
- decode(image: BinaryBitmap, hints?: Map | null): Result;
+ /**
+ * Locates and decodes a barcode in some format within an image. This method also accepts
+ * hints, each possibly associated to some data, which may help the implementation decode.
+ *
+ * @param image image of barcode to decode
+ * @param hints passed as a {@link Map} from {@link DecodeHintType}
+ * to arbitrary data. The
+ * meaning of the data depends upon the hint type. The implementation may or may not do
+ * anything with these hints.
+ *
+ * @return which: string the barcode encodes
+ *
+ * @throws NotFoundException if no potential barcode is found
+ * @throws ChecksumException if a potential barcode is found but does not pass its checksum
+ * @throws FormatException if a potential barcode is found but format is invalid
+ */
+ decode(image: BinaryBitmap, hints?: Map | null): Result;
- /**
- * Resets any internal state the implementation has after a decode, to prepare it
- * for reuse.
- */
- reset(): void;
+ /**
+ * Resets any internal state the implementation has after a decode, to prepare it
+ * for reuse.
+ */
+ reset(): void;
}
diff --git a/src/core/Result.ts b/src/core/Result.ts
index 3af8b8e2..3a92d034 100644
--- a/src/core/Result.ts
+++ b/src/core/Result.ts
@@ -30,130 +30,130 @@ import ResultMetadataType from './ResultMetadataType';
*/
export default class Result {
- private resultMetadata: Map;
-
- // public constructor(private text: string,
- // Uint8Array rawBytes,
- // ResultPoconst resultPoints: Int32Array,
- // BarcodeFormat format) {
- // this(text, rawBytes, resultPoints, format, System.currentTimeMillis())
- // }
-
- // public constructor(text: string,
- // Uint8Array rawBytes,
- // ResultPoconst resultPoints: Int32Array,
- // BarcodeFormat format,
- // long timestamp) {
- // this(text, rawBytes, rawBytes == null ? 0 : 8 * rawBytes.length,
- // resultPoints, format, timestamp)
- // }
-
- public constructor(private text: string,
- private rawBytes: Uint8Array,
- private numBits: number /*int*/ = rawBytes == null ? 0 : 8 * rawBytes.length,
- private resultPoints: ResultPoint[],
- private format: BarcodeFormat,
- private timestamp: number /*long*/ = System.currentTimeMillis()) {
- this.text = text;
- this.rawBytes = rawBytes;
- if (undefined === numBits || null === numBits) {
- this.numBits = (rawBytes === null || rawBytes === undefined) ? 0 : 8 * rawBytes.length;
- } else {
- this.numBits = numBits;
- }
- this.resultPoints = resultPoints;
- this.format = format;
- this.resultMetadata = null;
- if (undefined === timestamp || null === timestamp) {
- this.timestamp = System.currentTimeMillis();
- } else {
- this.timestamp = timestamp;
- }
+ private resultMetadata: Map;
+
+ // public constructor(private text: string,
+ // Uint8Array rawBytes,
+ // ResultPoconst resultPoints: Int32Array,
+ // BarcodeFormat format) {
+ // this(text, rawBytes, resultPoints, format, System.currentTimeMillis())
+ // }
+
+ // public constructor(text: string,
+ // Uint8Array rawBytes,
+ // ResultPoconst resultPoints: Int32Array,
+ // BarcodeFormat format,
+ // long timestamp) {
+ // this(text, rawBytes, rawBytes == null ? 0 : 8 * rawBytes.length,
+ // resultPoints, format, timestamp)
+ // }
+
+ public constructor(private text: string,
+ private rawBytes: Uint8Array,
+ private numBits: number /*int*/ = rawBytes == null ? 0 : 8 * rawBytes.length,
+ private resultPoints: ResultPoint[],
+ private format: BarcodeFormat,
+ private timestamp: number /*long*/ = System.currentTimeMillis()) {
+ this.text = text;
+ this.rawBytes = rawBytes;
+ if (undefined === numBits || null === numBits) {
+ this.numBits = (rawBytes === null || rawBytes === undefined) ? 0 : 8 * rawBytes.length;
+ } else {
+ this.numBits = numBits;
}
-
- /**
- * @return raw text encoded by the barcode
- */
- public getText(): string {
- return this.text;
- }
-
- /**
- * @return raw bytes encoded by the barcode, if applicable, otherwise {@code null}
- */
- public getRawBytes(): Uint8Array {
- return this.rawBytes;
- }
-
- /**
- * @return how many bits of {@link #getRawBytes()} are valid; typically 8 times its length
- * @since 3.3.0
- */
- public getNumBits(): number /*int*/ {
- return this.numBits;
- }
-
- /**
- * @return points related to the barcode in the image. These are typically points
- * identifying finder patterns or the corners of the barcode. The exact meaning is
- * specific to the type of barcode that was decoded.
- */
- public getResultPoints(): Array {
- return this.resultPoints;
- }
-
- /**
- * @return {@link BarcodeFormat} representing the format of the barcode that was decoded
- */
- public getBarcodeFormat(): BarcodeFormat {
- return this.format;
- }
-
- /**
- * @return {@link Map} mapping {@link ResultMetadataType} keys to values. May be
- * {@code null}. This contains optional metadata about what was detected about the barcode,
- * like orientation.
- */
- public getResultMetadata(): Map {
- return this.resultMetadata;
+ this.resultPoints = resultPoints;
+ this.format = format;
+ this.resultMetadata = null;
+ if (undefined === timestamp || null === timestamp) {
+ this.timestamp = System.currentTimeMillis();
+ } else {
+ this.timestamp = timestamp;
}
-
- public putMetadata(type: ResultMetadataType, value: Object): void {
- if (this.resultMetadata === null) {
- this.resultMetadata = new Map();
- }
- this.resultMetadata.set(type, value);
+ }
+
+ /**
+ * @return raw text encoded by the barcode
+ */
+ public getText(): string {
+ return this.text;
+ }
+
+ /**
+ * @return raw bytes encoded by the barcode, if applicable, otherwise {@code null}
+ */
+ public getRawBytes(): Uint8Array {
+ return this.rawBytes;
+ }
+
+ /**
+ * @return how many bits of {@link #getRawBytes()} are valid; typically 8 times its length
+ * @since 3.3.0
+ */
+ public getNumBits(): number /*int*/ {
+ return this.numBits;
+ }
+
+ /**
+ * @return points related to the barcode in the image. These are typically points
+ * identifying finder patterns or the corners of the barcode. The exact meaning is
+ * specific to the type of barcode that was decoded.
+ */
+ public getResultPoints(): Array {
+ return this.resultPoints;
+ }
+
+ /**
+ * @return {@link BarcodeFormat} representing the format of the barcode that was decoded
+ */
+ public getBarcodeFormat(): BarcodeFormat {
+ return this.format;
+ }
+
+ /**
+ * @return {@link Map} mapping {@link ResultMetadataType} keys to values. May be
+ * {@code null}. This contains optional metadata about what was detected about the barcode,
+ * like orientation.
+ */
+ public getResultMetadata(): Map {
+ return this.resultMetadata;
+ }
+
+ public putMetadata(type: ResultMetadataType, value: Object): void {
+ if (this.resultMetadata === null) {
+ this.resultMetadata = new Map();
}
-
- public putAllMetadata(metadata: Map): void {
- if (metadata !== null) {
- if (this.resultMetadata === null) {
- this.resultMetadata = metadata;
- } else {
- this.resultMetadata = new Map(metadata);
- }
- }
+ this.resultMetadata.set(type, value);
+ }
+
+ public putAllMetadata(metadata: Map): void {
+ if (metadata !== null) {
+ if (this.resultMetadata === null) {
+ this.resultMetadata = metadata;
+ } else {
+ this.resultMetadata = new Map(metadata);
+ }
}
-
- public addResultPoints(newPoints: Array): void {
- const oldPoints = this.resultPoints;
- if (oldPoints === null) {
- this.resultPoints = newPoints;
- } else if (newPoints !== null && newPoints.length > 0) {
- const allPoints = new Array(oldPoints.length + newPoints.length);
- System.arraycopy(oldPoints, 0, allPoints, 0, oldPoints.length);
- System.arraycopy(newPoints, 0, allPoints, oldPoints.length, newPoints.length);
- this.resultPoints = allPoints;
- }
+ }
+
+ public addResultPoints(newPoints: Array): void {
+ const oldPoints = this.resultPoints;
+ if (oldPoints === null) {
+ this.resultPoints = newPoints;
+ } else if (newPoints !== null && newPoints.length > 0) {
+ const allPoints = new Array(oldPoints.length + newPoints.length);
+ System.arraycopy(oldPoints, 0, allPoints, 0, oldPoints.length);
+ System.arraycopy(newPoints, 0, allPoints, oldPoints.length, newPoints.length);
+ this.resultPoints = allPoints;
}
+ }
- public getTimestamp(): number/*long*/ {
- return this.timestamp;
- }
+ public getTimestamp(): number/*long*/ {
+ return this.timestamp;
+ }
- /*@Override*/
- public toString(): string {
- return this.text;
- }
+ /*@Override*/
+ public toString(): string {
+ return this.text;
+ }
}
diff --git a/src/core/ResultMetadataType.ts b/src/core/ResultMetadataType.ts
index 67921d40..71d76ce7 100644
--- a/src/core/ResultMetadataType.ts
+++ b/src/core/ResultMetadataType.ts
@@ -24,75 +24,75 @@
*/
enum ResultMetadataType {
- /**
- * Unspecified, application-specific metadata. Maps to an unspecified {@link Object}.
- */
- OTHER,
+ /**
+ * Unspecified, application-specific metadata. Maps to an unspecified {@link Object}.
+ */
+ OTHER,
- /**
- * Denotes the likely approximate orientation of the barcode in the image. This value
- * is given as degrees rotated clockwise from the normal, upright orientation.
- * For example a 1D barcode which was found by reading top-to-bottom would be
- * said to have orientation "90". This key maps to an {@link Integer} whose
- * value is in the range [0,360).
- */
- ORIENTATION,
+ /**
+ * Denotes the likely approximate orientation of the barcode in the image. This value
+ * is given as degrees rotated clockwise from the normal, upright orientation.
+ * For example a 1D barcode which was found by reading top-to-bottom would be
+ * said to have orientation "90". This key maps to an {@link Integer} whose
+ * value is in the range [0,360).
+ */
+ ORIENTATION,
- /**
- *
2D barcode formats typically encode text, but allow for a sort of 'byte mode'
- * which is sometimes used to encode binary data. While {@link Result} makes available
- * the complete raw bytes in the barcode for these formats, it does not offer the bytes
- * from the byte segments alone.
- *
- *
This maps to a {@link java.util.List} of byte arrays corresponding to the
- * raw bytes in the byte segments in the barcode, in order.
- */
- BYTE_SEGMENTS,
+ /**
+ *
2D barcode formats typically encode text, but allow for a sort of 'byte mode'
+ * which is sometimes used to encode binary data. While {@link Result} makes available
+ * the complete raw bytes in the barcode for these formats, it does not offer the bytes
+ * from the byte segments alone.
+ *
+ *
This maps to a {@link java.util.List} of byte arrays corresponding to the
+ * raw bytes in the byte segments in the barcode, in order.
+ */
+ BYTE_SEGMENTS,
- /**
- * Error correction level used, if applicable. The value type depends on the
- * format, but is typically a String.
- */
- ERROR_CORRECTION_LEVEL,
+ /**
+ * Error correction level used, if applicable. The value type depends on the
+ * format, but is typically a String.
+ */
+ ERROR_CORRECTION_LEVEL,
- /**
- * For some periodicals, indicates the issue number as an {@link Integer}.
- */
- ISSUE_NUMBER,
+ /**
+ * For some periodicals, indicates the issue number as an {@link Integer}.
+ */
+ ISSUE_NUMBER,
- /**
- * For some products, indicates the suggested retail price in the barcode as a
- * formatted {@link String}.
- */
- SUGGESTED_PRICE,
+ /**
+ * For some products, indicates the suggested retail price in the barcode as a
+ * formatted {@link String}.
+ */
+ SUGGESTED_PRICE,
- /**
- * For some products, the possible country of manufacture as a {@link String} denoting the
- * ISO country code. Some map to multiple possible countries, like "US/CA".
- */
- POSSIBLE_COUNTRY,
+ /**
+ * For some products, the possible country of manufacture as a {@link String} denoting the
+ * ISO country code. Some map to multiple possible countries, like "US/CA".
+ */
+ POSSIBLE_COUNTRY,
- /**
- * For some products, the extension text
- */
- UPC_EAN_EXTENSION,
+ /**
+ * For some products, the extension text
+ */
+ UPC_EAN_EXTENSION,
- /**
- * PDF417-specific metadata
- */
- PDF417_EXTRA_METADATA,
+ /**
+ * PDF417-specific metadata
+ */
+ PDF417_EXTRA_METADATA,
- /**
- * If the code format supports structured append and the current scanned code is part of one then the
- * sequence number is given with it.
- */
- STRUCTURED_APPEND_SEQUENCE,
+ /**
+ * If the code format supports structured append and the current scanned code is part of one then the
+ * sequence number is given with it.
+ */
+ STRUCTURED_APPEND_SEQUENCE,
- /**
- * If the code format supports structured append and the current scanned code is part of one then the
- * parity is given with it.
- */
- STRUCTURED_APPEND_PARITY,
+ /**
+ * If the code format supports structured append and the current scanned code is part of one then the
+ * parity is given with it.
+ */
+ STRUCTURED_APPEND_PARITY,
}
diff --git a/src/core/ResultPoint.ts b/src/core/ResultPoint.ts
index 55578557..5e503350 100644
--- a/src/core/ResultPoint.ts
+++ b/src/core/ResultPoint.ts
@@ -28,99 +28,99 @@ import { float, int } from '../customTypings';
*/
export default class ResultPoint {
- public constructor(private x: float, private y: float) { }
+ public constructor(private x: float, private y: float) { }
- public getX(): float {
- return this.x;
- }
-
- public getY(): float {
- return this.y;
- }
-
- /*@Override*/
- public equals(other: Object): boolean {
- if (other instanceof ResultPoint) {
- const otherPoint = other;
- return this.x === otherPoint.x && this.y === otherPoint.y;
- }
- return false;
- }
+ public getX(): float {
+ return this.x;
+ }
- /*@Override*/
- public hashCode(): int {
- return 31 * Float.floatToIntBits(this.x) + Float.floatToIntBits(this.y);
- }
+ public getY(): float {
+ return this.y;
+ }
- /*@Override*/
- public toString(): string {
- return '(' + this.x + ',' + this.y + ')';
+ /*@Override*/
+ public equals(other: Object): boolean {
+ if (other instanceof ResultPoint) {
+ const otherPoint = other;
+ return this.x === otherPoint.x && this.y === otherPoint.y;
}
-
- /**
- * Orders an array of three ResultPoints in an order [A,B,C] such that AB is less than AC
- * and BC is less than AC, and the angle between BC and BA is less than 180 degrees.
- *
- * @param patterns array of three {@code ResultPoint} to order
- */
- public static orderBestPatterns(patterns: Array): void {
-
- // Find distances between pattern centers
- const zeroOneDistance = this.distance(patterns[0], patterns[1]);
- const oneTwoDistance = this.distance(patterns[1], patterns[2]);
- const zeroTwoDistance = this.distance(patterns[0], patterns[2]);
-
- let pointA: ResultPoint;
- let pointB: ResultPoint;
- let pointC: ResultPoint;
- // Assume one closest to other two is B; A and C will just be guesses at first
- if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance) {
- pointB = patterns[0];
- pointA = patterns[1];
- pointC = patterns[2];
- } else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance) {
- pointB = patterns[1];
- pointA = patterns[0];
- pointC = patterns[2];
- } else {
- pointB = patterns[2];
- pointA = patterns[0];
- pointC = patterns[1];
- }
-
- // Use cross product to figure out whether A and C are correct or flipped.
- // This asks whether BC x BA has a positive z component, which is the arrangement
- // we want for A, B, C. If it's negative, then we've got it flipped around and
- // should swap A and C.
- if (this.crossProductZ(pointA, pointB, pointC) < 0.0) {
- const temp = pointA;
- pointA = pointC;
- pointC = temp;
- }
-
- patterns[0] = pointA;
- patterns[1] = pointB;
- patterns[2] = pointC;
+ return false;
+ }
+
+ /*@Override*/
+ public hashCode(): int {
+ return 31 * Float.floatToIntBits(this.x) + Float.floatToIntBits(this.y);
+ }
+
+ /*@Override*/
+ public toString(): string {
+ return '(' + this.x + ',' + this.y + ')';
+ }
+
+ /**
+ * Orders an array of three ResultPoints in an order [A,B,C] such that AB is less than AC
+ * and BC is less than AC, and the angle between BC and BA is less than 180 degrees.
+ *
+ * @param patterns array of three {@code ResultPoint} to order
+ */
+ public static orderBestPatterns(patterns: Array): void {
+
+ // Find distances between pattern centers
+ const zeroOneDistance = this.distance(patterns[0], patterns[1]);
+ const oneTwoDistance = this.distance(patterns[1], patterns[2]);
+ const zeroTwoDistance = this.distance(patterns[0], patterns[2]);
+
+ let pointA: ResultPoint;
+ let pointB: ResultPoint;
+ let pointC: ResultPoint;
+ // Assume one closest to other two is B; A and C will just be guesses at first
+ if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance) {
+ pointB = patterns[0];
+ pointA = patterns[1];
+ pointC = patterns[2];
+ } else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance) {
+ pointB = patterns[1];
+ pointA = patterns[0];
+ pointC = patterns[2];
+ } else {
+ pointB = patterns[2];
+ pointA = patterns[0];
+ pointC = patterns[1];
}
- /**
- * @param pattern1 first pattern
- * @param pattern2 second pattern
- * @return distance between two points
- */
- public static distance(pattern1: ResultPoint, pattern2: ResultPoint): float {
- return MathUtils.distance(pattern1.x, pattern1.y, pattern2.x, pattern2.y);
+ // Use cross product to figure out whether A and C are correct or flipped.
+ // This asks whether BC x BA has a positive z component, which is the arrangement
+ // we want for A, B, C. If it's negative, then we've got it flipped around and
+ // should swap A and C.
+ if (this.crossProductZ(pointA, pointB, pointC) < 0.0) {
+ const temp = pointA;
+ pointA = pointC;
+ pointC = temp;
}
- /**
- * Returns the z component of the cross product between vectors BC and BA.
- */
- private static crossProductZ(pointA: ResultPoint,
- pointB: ResultPoint,
- pointC: ResultPoint): float {
- const bX = pointB.x;
- const bY = pointB.y;
- return ((pointC.x - bX) * (pointA.y - bY)) - ((pointC.y - bY) * (pointA.x - bX));
- }
+ patterns[0] = pointA;
+ patterns[1] = pointB;
+ patterns[2] = pointC;
+ }
+
+ /**
+ * @param pattern1 first pattern
+ * @param pattern2 second pattern
+ * @return distance between two points
+ */
+ public static distance(pattern1: ResultPoint, pattern2: ResultPoint): float {
+ return MathUtils.distance(pattern1.x, pattern1.y, pattern2.x, pattern2.y);
+ }
+
+ /**
+ * Returns the z component of the cross product between vectors BC and BA.
+ */
+ private static crossProductZ(pointA: ResultPoint,
+ pointB: ResultPoint,
+ pointC: ResultPoint): float {
+ const bX = pointB.x;
+ const bY = pointB.y;
+ return ((pointC.x - bX) * (pointA.y - bY)) - ((pointC.y - bY) * (pointA.x - bX));
+ }
}
diff --git a/src/core/ResultPointCallback.ts b/src/core/ResultPointCallback.ts
index 2d3c2e95..594b2f9e 100644
--- a/src/core/ResultPointCallback.ts
+++ b/src/core/ResultPointCallback.ts
@@ -28,6 +28,6 @@ export default ResultPointCallback;
*/
interface ResultPointCallback {
- foundPossibleResultPoint(point: ResultPoint): void;
+ foundPossibleResultPoint(point: ResultPoint): void;
}
diff --git a/src/core/Writer.ts b/src/core/Writer.ts
index 03f20cd2..b9ed79fa 100644
--- a/src/core/Writer.ts
+++ b/src/core/Writer.ts
@@ -31,33 +31,33 @@ export default Writer;
*/
interface Writer {
- /**
- * Encode a barcode using the default settings.
- *
- * @param contents The contents to encode in the barcode
- * @param format The barcode format to generate
- * @param width The preferred width in pixels
- * @param height The preferred height in pixels
- * @return {@link BitMatrix} representing encoded barcode image
- * @throws WriterException if contents cannot be encoded legally in a format
- */
- // encode(contents: string, format: BarcodeFormat, width: number /*int*/, height: number /*int*/): BitMatrix
-
- /**
- * @param contents The contents to encode in the barcode
- * @param format The barcode format to generate
- * @param width The preferred width in pixels
- * @param height The preferred height in pixels
- * @param hints Additional parameters to supply to the encoder
- * @return {@link BitMatrix} representing encoded barcode image
- * @throws WriterException if contents cannot be encoded legally in a format
- */
- encode(
- contents: string,
- format: BarcodeFormat,
- width: number /*int*/,
- height: number /*int*/,
- hints: Map
- ): BitMatrix;
+ /**
+ * Encode a barcode using the default settings.
+ *
+ * @param contents The contents to encode in the barcode
+ * @param format The barcode format to generate
+ * @param width The preferred width in pixels
+ * @param height The preferred height in pixels
+ * @return {@link BitMatrix} representing encoded barcode image
+ * @throws WriterException if contents cannot be encoded legally in a format
+ */
+ // encode(contents: string, format: BarcodeFormat, width: number /*int*/, height: number /*int*/): BitMatrix
+
+ /**
+ * @param contents The contents to encode in the barcode
+ * @param format The barcode format to generate
+ * @param width The preferred width in pixels
+ * @param height The preferred height in pixels
+ * @param hints Additional parameters to supply to the encoder
+ * @return {@link BitMatrix} representing encoded barcode image
+ * @throws WriterException if contents cannot be encoded legally in a format
+ */
+ encode(
+ contents: string,
+ format: BarcodeFormat,
+ width: number /*int*/,
+ height: number /*int*/,
+ hints: Map
+ ): BitMatrix;
}
diff --git a/src/core/aztec/AztecDetectorResult.ts b/src/core/aztec/AztecDetectorResult.ts
index 6a0c26ac..56e737fe 100644
--- a/src/core/aztec/AztecDetectorResult.ts
+++ b/src/core/aztec/AztecDetectorResult.ts
@@ -26,30 +26,30 @@ import DetectorResult from '../common/DetectorResult';
*/
export default class AztecDetectorResult extends DetectorResult {
- private compact: boolean;
- private nbDatablocks: number;
- private nbLayers: number;
+ private compact: boolean;
+ private nbDatablocks: number;
+ private nbLayers: number;
- public constructor(bits: BitMatrix,
- points: ResultPoint[],
- compact: boolean,
- nbDatablocks: number,
- nbLayers: number) {
- super(bits, points);
- this.compact = compact;
- this.nbDatablocks = nbDatablocks;
- this.nbLayers = nbLayers;
- }
+ public constructor(bits: BitMatrix,
+ points: ResultPoint[],
+ compact: boolean,
+ nbDatablocks: number,
+ nbLayers: number) {
+ super(bits, points);
+ this.compact = compact;
+ this.nbDatablocks = nbDatablocks;
+ this.nbLayers = nbLayers;
+ }
- public getNbLayers(): number {
- return this.nbLayers;
- }
+ public getNbLayers(): number {
+ return this.nbLayers;
+ }
- public getNbDatablocks(): number {
- return this.nbDatablocks;
- }
+ public getNbDatablocks(): number {
+ return this.nbDatablocks;
+ }
- public isCompact(): boolean {
- return this.compact;
- }
+ public isCompact(): boolean {
+ return this.compact;
+ }
}
diff --git a/src/core/aztec/AztecReader.ts b/src/core/aztec/AztecReader.ts
index e6352b57..05728ee9 100644
--- a/src/core/aztec/AztecReader.ts
+++ b/src/core/aztec/AztecReader.ts
@@ -40,75 +40,75 @@ import Exception from '../../core/Exception';
*/
export default class AztecReader implements Reader {
- /**
- * Locates and decodes a Data Matrix code in an image.
- *
- * @return a String representing the content encoded by the Data Matrix code
- * @throws NotFoundException if a Data Matrix code cannot be found
- * @throws FormatException if a Data Matrix code cannot be decoded
- */
- public decode(image: BinaryBitmap, hints: Map | null = null): Result {
+ /**
+ * Locates and decodes a Data Matrix code in an image.
+ *
+ * @return a String representing the content encoded by the Data Matrix code
+ * @throws NotFoundException if a Data Matrix code cannot be found
+ * @throws FormatException if a Data Matrix code cannot be decoded
+ */
+ public decode(image: BinaryBitmap, hints: Map | null = null): Result {
- let exception: Exception = null;
- let detector = new Detector(image.getBlackMatrix());
- let points: ResultPoint[] = null;
- let decoderResult: DecoderResult = null;
+ let exception: Exception = null;
+ let detector = new Detector(image.getBlackMatrix());
+ let points: ResultPoint[] = null;
+ let decoderResult: DecoderResult = null;
- try {
- let detectorResult = detector.detectMirror(false);
- points = detectorResult.getPoints();
- this.reportFoundResultPoints(hints, points);
- decoderResult = new Decoder().decode(detectorResult);
- } catch (e) {
- exception = e;
- }
- if (decoderResult == null) {
- try {
- let detectorResult = detector.detectMirror(true);
- points = detectorResult.getPoints();
- this.reportFoundResultPoints(hints, points);
- decoderResult = new Decoder().decode(detectorResult);
- } catch (e) {
- if (exception != null) {
- throw exception;
- }
- throw e;
- }
+ try {
+ let detectorResult = detector.detectMirror(false);
+ points = detectorResult.getPoints();
+ this.reportFoundResultPoints(hints, points);
+ decoderResult = new Decoder().decode(detectorResult);
+ } catch (e) {
+ exception = e;
+ }
+ if (decoderResult == null) {
+ try {
+ let detectorResult = detector.detectMirror(true);
+ points = detectorResult.getPoints();
+ this.reportFoundResultPoints(hints, points);
+ decoderResult = new Decoder().decode(detectorResult);
+ } catch (e) {
+ if (exception != null) {
+ throw exception;
}
+ throw e;
+ }
+ }
- let result = new Result(decoderResult.getText(),
- decoderResult.getRawBytes(),
- decoderResult.getNumBits(),
- points,
- BarcodeFormat.AZTEC,
- System.currentTimeMillis());
-
- let byteSegments = decoderResult.getByteSegments();
- if (byteSegments != null) {
- result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, byteSegments);
- }
- let ecLevel = decoderResult.getECLevel();
- if (ecLevel != null) {
- result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, ecLevel);
- }
+ let result = new Result(decoderResult.getText(),
+ decoderResult.getRawBytes(),
+ decoderResult.getNumBits(),
+ points,
+ BarcodeFormat.AZTEC,
+ System.currentTimeMillis());
- return result;
+ let byteSegments = decoderResult.getByteSegments();
+ if (byteSegments != null) {
+ result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, byteSegments);
}
-
- private reportFoundResultPoints(hints: Map, points: ResultPoint[]): void {
- if (hints != null) {
- let rpcb = hints.get(DecodeHintType.NEED_RESULT_POINT_CALLBACK);
- if (rpcb != null) {
- points.forEach((point, idx, arr) => {
- rpcb.foundPossibleResultPoint(point);
- });
- }
- }
+ let ecLevel = decoderResult.getECLevel();
+ if (ecLevel != null) {
+ result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, ecLevel);
}
- // @Override
- public reset(): void {
- // do nothing
+ return result;
+ }
+
+ private reportFoundResultPoints(hints: Map, points: ResultPoint[]): void {
+ if (hints != null) {
+ let rpcb = hints.get(DecodeHintType.NEED_RESULT_POINT_CALLBACK);
+ if (rpcb != null) {
+ points.forEach((point, idx, arr) => {
+ rpcb.foundPossibleResultPoint(point);
+ });
+ }
}
+ }
+
+ // @Override
+ public reset(): void {
+ // do nothing
+ }
}
diff --git a/src/core/aztec/AztecWriter.ts b/src/core/aztec/AztecWriter.ts
index b0a182a6..e177c370 100644
--- a/src/core/aztec/AztecWriter.ts
+++ b/src/core/aztec/AztecWriter.ts
@@ -97,9 +97,9 @@ export default /*public final*/ class AztecWriter implements Writer {
let output: BitMatrix = new BitMatrix(outputWidth, outputHeight);
- for (let inputY /*int*/ = 0, outputY = topPadding; inputY < inputHeight; inputY++ , outputY += multiple) {
+ for (let inputY /*int*/ = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) {
// Write the contents of this row of the barcode
- for (let inputX /*int*/ = 0, outputX = leftPadding; inputX < inputWidth; inputX++ , outputX += multiple) {
+ for (let inputX /*int*/ = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) {
if (input.get(inputX, inputY)) {
output.setRegion(outputX, outputY, multiple, multiple);
}
diff --git a/src/core/aztec/decoder/Decoder.ts b/src/core/aztec/decoder/Decoder.ts
index 7d891cae..e57c8eda 100644
--- a/src/core/aztec/decoder/Decoder.ts
+++ b/src/core/aztec/decoder/Decoder.ts
@@ -29,12 +29,12 @@ import { int } from '../../../customTypings';
// import java.util.Arrays;
enum Table {
- UPPER,
- LOWER,
- MIXED,
- DIGIT,
- PUNCT,
- BINARY
+ UPPER,
+ LOWER,
+ MIXED,
+ DIGIT,
+ PUNCT,
+ BINARY
}
/**
@@ -45,327 +45,327 @@ enum Table {
*/
export default class Decoder {
- private static UPPER_TABLE: string[] = [
- 'CTRL_PS', ' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
- 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'CTRL_LL', 'CTRL_ML', 'CTRL_DL', 'CTRL_BS'
- ];
+ private static UPPER_TABLE: string[] = [
+ 'CTRL_PS', ' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'CTRL_LL', 'CTRL_ML', 'CTRL_DL', 'CTRL_BS'
+ ];
- private static LOWER_TABLE: string[] = [
- 'CTRL_PS', ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
- 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'CTRL_US', 'CTRL_ML', 'CTRL_DL', 'CTRL_BS'
- ];
+ private static LOWER_TABLE: string[] = [
+ 'CTRL_PS', ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
+ 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'CTRL_US', 'CTRL_ML', 'CTRL_DL', 'CTRL_BS'
+ ];
- private static MIXED_TABLE: string[] = [
- // Module parse failed: Octal literal in strict mode (50:29)
- // so number string were scaped
- 'CTRL_PS', ' ', '\\1', '\\2', '\\3', '\\4', '\\5', '\\6', '\\7', '\b', '\t', '\n',
- '\\13', '\f', '\r', '\\33', '\\34', '\\35', '\\36', '\\37', '@', '\\', '^', '_',
- '`', '|', '~', '\\177', 'CTRL_LL', 'CTRL_UL', 'CTRL_PL', 'CTRL_BS'
- ];
+ private static MIXED_TABLE: string[] = [
+ // Module parse failed: Octal literal in strict mode (50:29)
+ // so number string were scaped
+ 'CTRL_PS', ' ', '\\1', '\\2', '\\3', '\\4', '\\5', '\\6', '\\7', '\b', '\t', '\n',
+ '\\13', '\f', '\r', '\\33', '\\34', '\\35', '\\36', '\\37', '@', '\\', '^', '_',
+ '`', '|', '~', '\\177', 'CTRL_LL', 'CTRL_UL', 'CTRL_PL', 'CTRL_BS'
+ ];
- private static PUNCT_TABLE: string[] = [
- '', '\r', '\r\n', '. ', ', ', ': ', '!', '"', '#', '$', '%', '&', '\'', '(', ')',
- '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', ']', '{', '}', 'CTRL_UL'
- ];
+ private static PUNCT_TABLE: string[] = [
+ '', '\r', '\r\n', '. ', ', ', ': ', '!', '"', '#', '$', '%', '&', '\'', '(', ')',
+ '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', ']', '{', '}', 'CTRL_UL'
+ ];
- private static DIGIT_TABLE: string[] = [
- 'CTRL_PS', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ',', '.', 'CTRL_UL', 'CTRL_US'
- ];
+ private static DIGIT_TABLE: string[] = [
+ 'CTRL_PS', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ',', '.', 'CTRL_UL', 'CTRL_US'
+ ];
- private ddata: AztecDetectorResult;
+ private ddata: AztecDetectorResult;
- public decode(detectorResult: AztecDetectorResult): DecoderResult {
- this.ddata = detectorResult;
- let matrix = detectorResult.getBits();
- let rawbits = this.extractBits(matrix);
- let correctedBits = this.correctBits(rawbits);
- let rawBytes = Decoder.convertBoolArrayToByteArray(correctedBits);
- let result = Decoder.getEncodedData(correctedBits);
- let decoderResult = new DecoderResult(rawBytes, result, null, null);
- decoderResult.setNumBits(correctedBits.length);
- return decoderResult;
- }
+ public decode(detectorResult: AztecDetectorResult): DecoderResult {
+ this.ddata = detectorResult;
+ let matrix = detectorResult.getBits();
+ let rawbits = this.extractBits(matrix);
+ let correctedBits = this.correctBits(rawbits);
+ let rawBytes = Decoder.convertBoolArrayToByteArray(correctedBits);
+ let result = Decoder.getEncodedData(correctedBits);
+ let decoderResult = new DecoderResult(rawBytes, result, null, null);
+ decoderResult.setNumBits(correctedBits.length);
+ return decoderResult;
+ }
- // This method is used for testing the high-level encoder
- public static highLevelDecode(correctedBits: boolean[]): string {
- return this.getEncodedData(correctedBits);
- }
+ // This method is used for testing the high-level encoder
+ public static highLevelDecode(correctedBits: boolean[]): string {
+ return this.getEncodedData(correctedBits);
+ }
- /**
- * Gets the string encoded in the aztec code bits
- *
- * @return the decoded string
- */
- private static getEncodedData(correctedBits: boolean[]): string {
- let endIndex: number = correctedBits.length;
- let latchTable = Table.UPPER; // table most recently latched to
- let shiftTable = Table.UPPER; // table to use for the next read
- let result: string = '';
- let index = 0;
- while (index < endIndex) {
- if (shiftTable === Table.BINARY) {
- if (endIndex - index < 5) {
- break;
- }
- let length = Decoder.readCode(correctedBits, index, 5);
- index += 5;
- if (length === 0) {
- if (endIndex - index < 11) {
- break;
- }
- length = Decoder.readCode(correctedBits, index, 11) + 31;
- index += 11;
- }
- for (let charCount = 0; charCount < length; charCount++) {
- if (endIndex - index < 8) {
- index = endIndex; // Force outer loop to exit
- break;
- }
- const code: int = Decoder.readCode(correctedBits, index, 8);
- result += /*(char)*/ StringUtils.castAsNonUtf8Char(code);
- index += 8;
- }
- // Go back to whatever mode we had been in
- shiftTable = latchTable;
- } else {
- let size = shiftTable === Table.DIGIT ? 4 : 5;
- if (endIndex - index < size) {
- break;
- }
- let code = Decoder.readCode(correctedBits, index, size);
- index += size;
- let str = Decoder.getCharacter(shiftTable, code);
- if (str.startsWith('CTRL_')) {
- // Table changes
- // ISO/IEC 24778:2008 prescribes ending a shift sequence in the mode from which it was invoked.
- // That's including when that mode is a shift.
- // Our test case dlusbs.png for issue #642 exercises that.
- latchTable = shiftTable; // Latch the current mode, so as to return to Upper after U/S B/S
- shiftTable = Decoder.getTable(str.charAt(5));
- if (str.charAt(6) === 'L') {
- latchTable = shiftTable;
- }
- } else {
- result += str;
- // Go back to whatever mode we had been in
- shiftTable = latchTable;
- }
- }
+ /**
+ * Gets the string encoded in the aztec code bits
+ *
+ * @return the decoded string
+ */
+ private static getEncodedData(correctedBits: boolean[]): string {
+ let endIndex: number = correctedBits.length;
+ let latchTable = Table.UPPER; // table most recently latched to
+ let shiftTable = Table.UPPER; // table to use for the next read
+ let result: string = '';
+ let index = 0;
+ while (index < endIndex) {
+ if (shiftTable === Table.BINARY) {
+ if (endIndex - index < 5) {
+ break;
+ }
+ let length = Decoder.readCode(correctedBits, index, 5);
+ index += 5;
+ if (length === 0) {
+ if (endIndex - index < 11) {
+ break;
+ }
+ length = Decoder.readCode(correctedBits, index, 11) + 31;
+ index += 11;
+ }
+ for (let charCount = 0; charCount < length; charCount++) {
+ if (endIndex - index < 8) {
+ index = endIndex; // Force outer loop to exit
+ break;
+ }
+ const code: int = Decoder.readCode(correctedBits, index, 8);
+ result += /*(char)*/ StringUtils.castAsNonUtf8Char(code);
+ index += 8;
+ }
+ // Go back to whatever mode we had been in
+ shiftTable = latchTable;
+ } else {
+ let size = shiftTable === Table.DIGIT ? 4 : 5;
+ if (endIndex - index < size) {
+ break;
+ }
+ let code = Decoder.readCode(correctedBits, index, size);
+ index += size;
+ let str = Decoder.getCharacter(shiftTable, code);
+ if (str.startsWith('CTRL_')) {
+ // Table changes
+ // ISO/IEC 24778:2008 prescribes ending a shift sequence in the mode from which it was invoked.
+ // That's including when that mode is a shift.
+ // Our test case dlusbs.png for issue #642 exercises that.
+ latchTable = shiftTable; // Latch the current mode, so as to return to Upper after U/S B/S
+ shiftTable = Decoder.getTable(str.charAt(5));
+ if (str.charAt(6) === 'L') {
+ latchTable = shiftTable;
+ }
+ } else {
+ result += str;
+ // Go back to whatever mode we had been in
+ shiftTable = latchTable;
}
- return result;
+ }
}
+ return result;
+ }
- /**
- * gets the table corresponding to the char passed
- */
- private static getTable(t: string): Table {
- switch (t) {
- case 'L':
- return Table.LOWER;
- case 'P':
- return Table.PUNCT;
- case 'M':
- return Table.MIXED;
- case 'D':
- return Table.DIGIT;
- case 'B':
- return Table.BINARY;
- case 'U':
- default:
- return Table.UPPER;
- }
+ /**
+ * gets the table corresponding to the char passed
+ */
+ private static getTable(t: string): Table {
+ switch (t) {
+ case 'L':
+ return Table.LOWER;
+ case 'P':
+ return Table.PUNCT;
+ case 'M':
+ return Table.MIXED;
+ case 'D':
+ return Table.DIGIT;
+ case 'B':
+ return Table.BINARY;
+ case 'U':
+ default:
+ return Table.UPPER;
}
+ }
- /**
- * Gets the character (or string) corresponding to the passed code in the given table
- *
- * @param table the table used
- * @param code the code of the character
- */
- private static getCharacter(table: Table, code: number): string {
- switch (table) {
- case Table.UPPER:
- return Decoder.UPPER_TABLE[code];
- case Table.LOWER:
- return Decoder.LOWER_TABLE[code];
- case Table.MIXED:
- return Decoder.MIXED_TABLE[code];
- case Table.PUNCT:
- return Decoder.PUNCT_TABLE[code];
- case Table.DIGIT:
- return Decoder.DIGIT_TABLE[code];
- default:
- // Should not reach here.
- throw new IllegalStateException('Bad table');
- }
+ /**
+ * Gets the character (or string) corresponding to the passed code in the given table
+ *
+ * @param table the table used
+ * @param code the code of the character
+ */
+ private static getCharacter(table: Table, code: number): string {
+ switch (table) {
+ case Table.UPPER:
+ return Decoder.UPPER_TABLE[code];
+ case Table.LOWER:
+ return Decoder.LOWER_TABLE[code];
+ case Table.MIXED:
+ return Decoder.MIXED_TABLE[code];
+ case Table.PUNCT:
+ return Decoder.PUNCT_TABLE[code];
+ case Table.DIGIT:
+ return Decoder.DIGIT_TABLE[code];
+ default:
+ // Should not reach here.
+ throw new IllegalStateException('Bad table');
}
+ }
- /**
- *
Performs RS error correction on an array of bits.
- *
- * @return the corrected array
- * @throws FormatException if the input contains too many errors
- */
- private correctBits(rawbits: boolean[]): boolean[] {
- let gf: GenericGF;
- let codewordSize: number;
+ /**
+ *
Performs RS error correction on an array of bits.
+ *
+ * @return the corrected array
+ * @throws FormatException if the input contains too many errors
+ */
+ private correctBits(rawbits: boolean[]): boolean[] {
+ let gf: GenericGF;
+ let codewordSize: number;
- if (this.ddata.getNbLayers() <= 2) {
- codewordSize = 6;
- gf = GenericGF.AZTEC_DATA_6;
- } else if (this.ddata.getNbLayers() <= 8) {
- codewordSize = 8;
- gf = GenericGF.AZTEC_DATA_8;
- } else if (this.ddata.getNbLayers() <= 22) {
- codewordSize = 10;
- gf = GenericGF.AZTEC_DATA_10;
- } else {
- codewordSize = 12;
- gf = GenericGF.AZTEC_DATA_12;
- }
+ if (this.ddata.getNbLayers() <= 2) {
+ codewordSize = 6;
+ gf = GenericGF.AZTEC_DATA_6;
+ } else if (this.ddata.getNbLayers() <= 8) {
+ codewordSize = 8;
+ gf = GenericGF.AZTEC_DATA_8;
+ } else if (this.ddata.getNbLayers() <= 22) {
+ codewordSize = 10;
+ gf = GenericGF.AZTEC_DATA_10;
+ } else {
+ codewordSize = 12;
+ gf = GenericGF.AZTEC_DATA_12;
+ }
- let numDataCodewords = this.ddata.getNbDatablocks();
- let numCodewords = rawbits.length / codewordSize;
- if (numCodewords < numDataCodewords) {
- throw new FormatException();
- }
- let offset = rawbits.length % codewordSize;
+ let numDataCodewords = this.ddata.getNbDatablocks();
+ let numCodewords = rawbits.length / codewordSize;
+ if (numCodewords < numDataCodewords) {
+ throw new FormatException();
+ }
+ let offset = rawbits.length % codewordSize;
- let dataWords: Int32Array = new Int32Array(numCodewords);
- for (let i = 0; i < numCodewords; i++ , offset += codewordSize) {
- dataWords[i] = Decoder.readCode(rawbits, offset, codewordSize);
- }
+ let dataWords: Int32Array = new Int32Array(numCodewords);
+ for (let i = 0; i < numCodewords; i++, offset += codewordSize) {
+ dataWords[i] = Decoder.readCode(rawbits, offset, codewordSize);
+ }
- try {
- let rsDecoder = new ReedSolomonDecoder(gf);
- rsDecoder.decode(dataWords, numCodewords - numDataCodewords);
- } catch (ex) {
- throw new FormatException(ex);
- }
+ try {
+ let rsDecoder = new ReedSolomonDecoder(gf);
+ rsDecoder.decode(dataWords, numCodewords - numDataCodewords);
+ } catch (ex) {
+ throw new FormatException(ex);
+ }
- // Now perform the unstuffing operation.
- // First, count how many bits are going to be thrown out as stuffing
- let mask = (1 << codewordSize) - 1;
- let stuffedBits = 0;
- for (let i = 0; i < numDataCodewords; i++) {
- let dataWord = dataWords[i];
- if (dataWord === 0 || dataWord === mask) {
- throw new FormatException();
- } else if (dataWord === 1 || dataWord === mask - 1) {
- stuffedBits++;
- }
- }
- // Now, actually unpack the bits and remove the stuffing
- let correctedBits: boolean[] = new Array(numDataCodewords * codewordSize - stuffedBits);
- let index = 0;
- for (let i = 0; i < numDataCodewords; i++) {
- let dataWord = dataWords[i];
- if (dataWord === 1 || dataWord === mask - 1) {
- // next codewordSize-1 bits are all zeros or all ones
- correctedBits.fill(dataWord > 1, index, index + codewordSize - 1);
- // Arrays.fill(correctedBits, index, index + codewordSize - 1, dataWord > 1);
- index += codewordSize - 1;
- } else {
- for (let bit = codewordSize - 1; bit >= 0; --bit) {
- correctedBits[index++] = (dataWord & (1 << bit)) !== 0;
- }
- }
+ // Now perform the unstuffing operation.
+ // First, count how many bits are going to be thrown out as stuffing
+ let mask = (1 << codewordSize) - 1;
+ let stuffedBits = 0;
+ for (let i = 0; i < numDataCodewords; i++) {
+ let dataWord = dataWords[i];
+ if (dataWord === 0 || dataWord === mask) {
+ throw new FormatException();
+ } else if (dataWord === 1 || dataWord === mask - 1) {
+ stuffedBits++;
+ }
+ }
+ // Now, actually unpack the bits and remove the stuffing
+ let correctedBits: boolean[] = new Array(numDataCodewords * codewordSize - stuffedBits);
+ let index = 0;
+ for (let i = 0; i < numDataCodewords; i++) {
+ let dataWord = dataWords[i];
+ if (dataWord === 1 || dataWord === mask - 1) {
+ // next codewordSize-1 bits are all zeros or all ones
+ correctedBits.fill(dataWord > 1, index, index + codewordSize - 1);
+ // Arrays.fill(correctedBits, index, index + codewordSize - 1, dataWord > 1);
+ index += codewordSize - 1;
+ } else {
+ for (let bit = codewordSize - 1; bit >= 0; --bit) {
+ correctedBits[index++] = (dataWord & (1 << bit)) !== 0;
}
- return correctedBits;
+ }
}
+ return correctedBits;
+ }
- /**
- * Gets the array of bits from an Aztec Code matrix
- *
- * @return the array of bits
- */
- private extractBits(matrix: BitMatrix): boolean[] {
- let compact = this.ddata.isCompact();
- let layers = this.ddata.getNbLayers();
- let baseMatrixSize = (compact ? 11 : 14) + layers * 4; // not including alignment lines
- let alignmentMap = new Int32Array(baseMatrixSize);
- let rawbits: boolean[] = new Array(this.totalBitsInLayer(layers, compact));
+ /**
+ * Gets the array of bits from an Aztec Code matrix
+ *
+ * @return the array of bits
+ */
+ private extractBits(matrix: BitMatrix): boolean[] {
+ let compact = this.ddata.isCompact();
+ let layers = this.ddata.getNbLayers();
+ let baseMatrixSize = (compact ? 11 : 14) + layers * 4; // not including alignment lines
+ let alignmentMap = new Int32Array(baseMatrixSize);
+ let rawbits: boolean[] = new Array(this.totalBitsInLayer(layers, compact));
- if (compact) {
- for (let i = 0; i < alignmentMap.length; i++) {
- alignmentMap[i] = i;
- }
- } else {
- let matrixSize = baseMatrixSize + 1 + 2 * Integer.truncDivision((Integer.truncDivision(baseMatrixSize, 2) - 1), 15);
- let origCenter = baseMatrixSize / 2;
- let center = Integer.truncDivision(matrixSize, 2);
- for (let i = 0; i < origCenter; i++) {
- let newOffset = i + Integer.truncDivision(i, 15);
- alignmentMap[origCenter - i - 1] = center - newOffset - 1;
- alignmentMap[origCenter + i] = center + newOffset + 1;
- }
- }
- for (let i = 0, rowOffset = 0; i < layers; i++) {
- let rowSize = (layers - i) * 4 + (compact ? 9 : 12);
- // The top-left most point of this layer is (not including alignment lines)
- let low = i * 2;
- // The bottom-right most point of this layer is (not including alignment lines)
- let high = baseMatrixSize - 1 - low;
- // We pull bits from the two 2 x rowSize columns and two rowSize x 2 rows
- for (let j = 0; j < rowSize; j++) {
- let columnOffset = j * 2;
- for (let k = 0; k < 2; k++) {
- // left column
- rawbits[rowOffset + columnOffset + k] =
- matrix.get(alignmentMap[low + k], alignmentMap[low + j]);
- // bottom row
- rawbits[rowOffset + 2 * rowSize + columnOffset + k] =
- matrix.get(alignmentMap[low + j], alignmentMap[high - k]);
- // right column
- rawbits[rowOffset + 4 * rowSize + columnOffset + k] =
- matrix.get(alignmentMap[high - k], alignmentMap[high - j]);
- // top row
- rawbits[rowOffset + 6 * rowSize + columnOffset + k] =
- matrix.get(alignmentMap[high - j], alignmentMap[low + k]);
- }
- }
- rowOffset += rowSize * 8;
- }
- return rawbits;
+ if (compact) {
+ for (let i = 0; i < alignmentMap.length; i++) {
+ alignmentMap[i] = i;
+ }
+ } else {
+ let matrixSize = baseMatrixSize + 1 + 2 * Integer.truncDivision((Integer.truncDivision(baseMatrixSize, 2) - 1), 15);
+ let origCenter = baseMatrixSize / 2;
+ let center = Integer.truncDivision(matrixSize, 2);
+ for (let i = 0; i < origCenter; i++) {
+ let newOffset = i + Integer.truncDivision(i, 15);
+ alignmentMap[origCenter - i - 1] = center - newOffset - 1;
+ alignmentMap[origCenter + i] = center + newOffset + 1;
+ }
}
-
- /**
- * Reads a code of given length and at given index in an array of bits
- */
- private static readCode(rawbits: boolean[], startIndex: number, length: number): number {
- let res = 0;
- for (let i = startIndex; i < startIndex + length; i++) {
- res <<= 1;
- if (rawbits[i]) {
- res |= 0x01;
- }
+ for (let i = 0, rowOffset = 0; i < layers; i++) {
+ let rowSize = (layers - i) * 4 + (compact ? 9 : 12);
+ // The top-left most point of this layer is (not including alignment lines)
+ let low = i * 2;
+ // The bottom-right most point of this layer is (not including alignment lines)
+ let high = baseMatrixSize - 1 - low;
+ // We pull bits from the two 2 x rowSize columns and two rowSize x 2 rows
+ for (let j = 0; j < rowSize; j++) {
+ let columnOffset = j * 2;
+ for (let k = 0; k < 2; k++) {
+ // left column
+ rawbits[rowOffset + columnOffset + k] =
+ matrix.get(alignmentMap[low + k], alignmentMap[low + j]);
+ // bottom row
+ rawbits[rowOffset + 2 * rowSize + columnOffset + k] =
+ matrix.get(alignmentMap[low + j], alignmentMap[high - k]);
+ // right column
+ rawbits[rowOffset + 4 * rowSize + columnOffset + k] =
+ matrix.get(alignmentMap[high - k], alignmentMap[high - j]);
+ // top row
+ rawbits[rowOffset + 6 * rowSize + columnOffset + k] =
+ matrix.get(alignmentMap[high - j], alignmentMap[low + k]);
}
- return res;
+ }
+ rowOffset += rowSize * 8;
}
+ return rawbits;
+ }
- /**
- * Reads a code of length 8 in an array of bits, padding with zeros
- */
- private static readByte(rawbits: boolean[], startIndex: number): number {
- let n = rawbits.length - startIndex;
- if (n >= 8) {
- return Decoder.readCode(rawbits, startIndex, 8);
- }
- return Decoder.readCode(rawbits, startIndex, n) << (8 - n);
+ /**
+ * Reads a code of given length and at given index in an array of bits
+ */
+ private static readCode(rawbits: boolean[], startIndex: number, length: number): number {
+ let res = 0;
+ for (let i = startIndex; i < startIndex + length; i++) {
+ res <<= 1;
+ if (rawbits[i]) {
+ res |= 0x01;
+ }
}
+ return res;
+ }
- /**
- * Packs a bit array into bytes, most significant bit first
- */
- public static convertBoolArrayToByteArray(boolArr: boolean[]): Uint8Array {
- let byteArr = new Uint8Array((boolArr.length + 7) / 8);
- for (let i = 0; i < byteArr.length; i++) {
- byteArr[i] = Decoder.readByte(boolArr, 8 * i);
- }
- return byteArr;
+ /**
+ * Reads a code of length 8 in an array of bits, padding with zeros
+ */
+ private static readByte(rawbits: boolean[], startIndex: number): number {
+ let n = rawbits.length - startIndex;
+ if (n >= 8) {
+ return Decoder.readCode(rawbits, startIndex, 8);
}
+ return Decoder.readCode(rawbits, startIndex, n) << (8 - n);
+ }
- private totalBitsInLayer(layers: number, compact: boolean): number {
- return ((compact ? 88 : 112) + 16 * layers) * layers;
+ /**
+ * Packs a bit array into bytes, most significant bit first
+ */
+ public static convertBoolArrayToByteArray(boolArr: boolean[]): Uint8Array {
+ let byteArr = new Uint8Array((boolArr.length + 7) / 8);
+ for (let i = 0; i < byteArr.length; i++) {
+ byteArr[i] = Decoder.readByte(boolArr, 8 * i);
}
+ return byteArr;
+ }
+
+ private totalBitsInLayer(layers: number, compact: boolean): number {
+ return ((compact ? 88 : 112) + 16 * layers) * layers;
+ }
}
diff --git a/src/core/aztec/detector/Detector.ts b/src/core/aztec/detector/Detector.ts
index 4e9b286a..fed079ad 100644
--- a/src/core/aztec/detector/Detector.ts
+++ b/src/core/aztec/detector/Detector.ts
@@ -28,30 +28,30 @@ import Integer from '../../util/Integer';
export class Point {
- private x: number;
- private y: number;
-
- public toResultPoint(): ResultPoint {
- return new ResultPoint(this.getX(), this.getY());
- }
-
- public constructor(x: number, y: number) {
- this.x = x;
- this.y = y;
- }
-
- public getX(): number {
- return this.x;
- }
-
- public getY(): number {
- return this.y;
- }
-
- // @Override
- // public String toString() {
- // return "<" + x + ' ' + y + '>';
- // }
+ private x: number;
+ private y: number;
+
+ public toResultPoint(): ResultPoint {
+ return new ResultPoint(this.getX(), this.getY());
+ }
+
+ public constructor(x: number, y: number) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public getX(): number {
+ return this.x;
+ }
+
+ public getY(): number {
+ return this.y;
+ }
+
+ // @Override
+ // public String toString() {
+ // return "<" + x + ' ' + y + '>';
+ // }
}
/**
@@ -63,550 +63,550 @@ export class Point {
*/
export default class Detector {
- private EXPECTED_CORNER_BITS = new Int32Array([
- 0xee0, // 07340 XXX .XX X.. ...
- 0x1dc, // 00734 ... XXX .XX X..
- 0x83b, // 04073 X.. ... XXX .XX
- 0x707, // 03407 .XX X.. ... XXX
- ]);
-
- private image: BitMatrix;
-
- private compact: boolean;
- private nbLayers: number;
- private nbDataBlocks: number;
- private nbCenterLayers: number;
- private shift: number;
-
- public constructor(image: BitMatrix) {
- this.image = image;
+ private EXPECTED_CORNER_BITS = new Int32Array([
+ 0xee0, // 07340 XXX .XX X.. ...
+ 0x1dc, // 00734 ... XXX .XX X..
+ 0x83b, // 04073 X.. ... XXX .XX
+ 0x707, // 03407 .XX X.. ... XXX
+ ]);
+
+ private image: BitMatrix;
+
+ private compact: boolean;
+ private nbLayers: number;
+ private nbDataBlocks: number;
+ private nbCenterLayers: number;
+ private shift: number;
+
+ public constructor(image: BitMatrix) {
+ this.image = image;
+ }
+
+ public detect(): AztecDetectorResult {
+ return this.detectMirror(false);
+ }
+
+ /**
+ * Detects an Aztec Code in an image.
+ *
+ * @param isMirror if true, image is a mirror-image of original
+ * @return {@link AztecDetectorResult} encapsulating results of detecting an Aztec Code
+ * @throws NotFoundException if no Aztec Code can be found
+ */
+ public detectMirror(isMirror: boolean): AztecDetectorResult {
+
+ // 1. Get the center of the aztec matrix
+ let pCenter = this.getMatrixCenter();
+
+ // 2. Get the center points of the four diagonal points just outside the bull's eye
+ // [topRight, bottomRight, bottomLeft, topLeft]
+ let bullsEyeCorners = this.getBullsEyeCorners(pCenter);
+
+ if (isMirror) {
+ let temp = bullsEyeCorners[0];
+ bullsEyeCorners[0] = bullsEyeCorners[2];
+ bullsEyeCorners[2] = temp;
}
- public detect(): AztecDetectorResult {
- return this.detectMirror(false);
+ // 3. Get the size of the matrix and other parameters from the bull's eye
+ this.extractParameters(bullsEyeCorners);
+
+
+ // 4. Sample the grid
+ let bits: BitMatrix = this.sampleGrid(this.image,
+ bullsEyeCorners[this.shift % 4],
+ bullsEyeCorners[(this.shift + 1) % 4],
+ bullsEyeCorners[(this.shift + 2) % 4],
+ bullsEyeCorners[(this.shift + 3) % 4]
+ );
+
+ // 5. Get the corners of the matrix.
+ let corners: ResultPoint[] = this.getMatrixCornerPoints(bullsEyeCorners);
+
+ return new AztecDetectorResult(bits, corners, this.compact, this.nbDataBlocks, this.nbLayers);
+ }
+
+ /**
+ * Extracts the number of data layers and data blocks from the layer around the bull's eye.
+ *
+ * @param bullsEyeCorners the array of bull's eye corners
+ * @throws NotFoundException in case of too many errors or invalid parameters
+ */
+ private extractParameters(bullsEyeCorners: ResultPoint[]): void {
+ if (!this.isValidPoint(bullsEyeCorners[0]) || !this.isValidPoint(bullsEyeCorners[1]) ||
+ !this.isValidPoint(bullsEyeCorners[2]) || !this.isValidPoint(bullsEyeCorners[3])) {
+ throw new NotFoundException();
}
+ let length = 2 * this.nbCenterLayers;
+ // Get the bits around the bull's eye
+ let sides = new Int32Array([
+ this.sampleLine(bullsEyeCorners[0], bullsEyeCorners[1], length), // Right side
+ this.sampleLine(bullsEyeCorners[1], bullsEyeCorners[2], length), // Bottom
+ this.sampleLine(bullsEyeCorners[2], bullsEyeCorners[3], length), // Left side
+ this.sampleLine(bullsEyeCorners[3], bullsEyeCorners[0], length) // Top
+ ]);
- /**
- * Detects an Aztec Code in an image.
- *
- * @param isMirror if true, image is a mirror-image of original
- * @return {@link AztecDetectorResult} encapsulating results of detecting an Aztec Code
- * @throws NotFoundException if no Aztec Code can be found
- */
- public detectMirror(isMirror: boolean): AztecDetectorResult {
-
- // 1. Get the center of the aztec matrix
- let pCenter = this.getMatrixCenter();
-
- // 2. Get the center points of the four diagonal points just outside the bull's eye
- // [topRight, bottomRight, bottomLeft, topLeft]
- let bullsEyeCorners = this.getBullsEyeCorners(pCenter);
-
- if (isMirror) {
- let temp = bullsEyeCorners[0];
- bullsEyeCorners[0] = bullsEyeCorners[2];
- bullsEyeCorners[2] = temp;
- }
-
- // 3. Get the size of the matrix and other parameters from the bull's eye
- this.extractParameters(bullsEyeCorners);
-
-
- // 4. Sample the grid
- let bits: BitMatrix = this.sampleGrid(this.image,
- bullsEyeCorners[this.shift % 4],
- bullsEyeCorners[(this.shift + 1) % 4],
- bullsEyeCorners[(this.shift + 2) % 4],
- bullsEyeCorners[(this.shift + 3) % 4]
- );
-
- // 5. Get the corners of the matrix.
- let corners: ResultPoint[] = this.getMatrixCornerPoints(bullsEyeCorners);
-
- return new AztecDetectorResult(bits, corners, this.compact, this.nbDataBlocks, this.nbLayers);
+ // bullsEyeCorners[shift] is the corner of the bulls'eye that has three
+ // orientation marks.
+ // sides[shift] is the row/column that goes from the corner with three
+ // orientation marks to the corner with two.
+ this.shift = this.getRotation(sides, length);
+
+ // Flatten the parameter bits into a single 28- or 40-bit long
+ let parameterData = 0;
+ for (let i = 0; i < 4; i++) {
+ let side = sides[(this.shift + i) % 4];
+ if (this.compact) {
+ // Each side of the form ..XXXXXXX. where Xs are parameter data
+ parameterData <<= 7;
+ parameterData += (side >> 1) & 0x7F;
+ } else {
+ // Each side of the form ..XXXXX.XXXXX. where Xs are parameter data
+ parameterData <<= 10;
+ parameterData += ((side >> 2) & (0x1f << 5)) + ((side >> 1) & 0x1F);
+ }
}
- /**
- * Extracts the number of data layers and data blocks from the layer around the bull's eye.
- *
- * @param bullsEyeCorners the array of bull's eye corners
- * @throws NotFoundException in case of too many errors or invalid parameters
- */
- private extractParameters(bullsEyeCorners: ResultPoint[]): void {
- if (!this.isValidPoint(bullsEyeCorners[0]) || !this.isValidPoint(bullsEyeCorners[1]) ||
- !this.isValidPoint(bullsEyeCorners[2]) || !this.isValidPoint(bullsEyeCorners[3])) {
- throw new NotFoundException();
- }
- let length = 2 * this.nbCenterLayers;
- // Get the bits around the bull's eye
- let sides = new Int32Array([
- this.sampleLine(bullsEyeCorners[0], bullsEyeCorners[1], length), // Right side
- this.sampleLine(bullsEyeCorners[1], bullsEyeCorners[2], length), // Bottom
- this.sampleLine(bullsEyeCorners[2], bullsEyeCorners[3], length), // Left side
- this.sampleLine(bullsEyeCorners[3], bullsEyeCorners[0], length) // Top
- ]);
-
- // bullsEyeCorners[shift] is the corner of the bulls'eye that has three
- // orientation marks.
- // sides[shift] is the row/column that goes from the corner with three
- // orientation marks to the corner with two.
- this.shift = this.getRotation(sides, length);
-
- // Flatten the parameter bits into a single 28- or 40-bit long
- let parameterData = 0;
- for (let i = 0; i < 4; i++) {
- let side = sides[(this.shift + i) % 4];
- if (this.compact) {
- // Each side of the form ..XXXXXXX. where Xs are parameter data
- parameterData <<= 7;
- parameterData += (side >> 1) & 0x7F;
- } else {
- // Each side of the form ..XXXXX.XXXXX. where Xs are parameter data
- parameterData <<= 10;
- parameterData += ((side >> 2) & (0x1f << 5)) + ((side >> 1) & 0x1F);
- }
- }
-
- // Corrects parameter data using RS. Returns just the data portion
- // without the error correction.
- let correctedData = this.getCorrectedParameterData(parameterData, this.compact);
-
- if (this.compact) {
- // 8 bits: 2 bits layers and 6 bits data blocks
- this.nbLayers = (correctedData >> 6) + 1;
- this.nbDataBlocks = (correctedData & 0x3F) + 1;
- } else {
- // 16 bits: 5 bits layers and 11 bits data blocks
- this.nbLayers = (correctedData >> 11) + 1;
- this.nbDataBlocks = (correctedData & 0x7FF) + 1;
- }
+ // Corrects parameter data using RS. Returns just the data portion
+ // without the error correction.
+ let correctedData = this.getCorrectedParameterData(parameterData, this.compact);
+
+ if (this.compact) {
+ // 8 bits: 2 bits layers and 6 bits data blocks
+ this.nbLayers = (correctedData >> 6) + 1;
+ this.nbDataBlocks = (correctedData & 0x3F) + 1;
+ } else {
+ // 16 bits: 5 bits layers and 11 bits data blocks
+ this.nbLayers = (correctedData >> 11) + 1;
+ this.nbDataBlocks = (correctedData & 0x7FF) + 1;
}
+ }
+
+ private getRotation(sides: Int32Array, length: number): number {
+ // In a normal pattern, we expect to See
+ // ** .* D A
+ // * *
+ //
+ // . *
+ // .. .. C B
+ //
+ // Grab the 3 bits from each of the sides the form the locator pattern and concatenate
+ // into a 12-bit integer. Start with the bit at A
+ let cornerBits = 0;
+ sides.forEach((side, idx, arr) => {
+ // XX......X where X's are orientation marks
+ let t = ((side >> (length - 2)) << 1) + (side & 1);
+ cornerBits = (cornerBits << 3) + t;
+ });
+ // for (var side in sides) {
+ // // XX......X where X's are orientation marks
+ // var t = ((side >> (length - 2)) << 1) + (side & 1);
+ // cornerBits = (cornerBits << 3) + t;
+ // }
- private getRotation(sides: Int32Array, length: number): number {
- // In a normal pattern, we expect to See
- // ** .* D A
- // * *
- //
- // . *
- // .. .. C B
- //
- // Grab the 3 bits from each of the sides the form the locator pattern and concatenate
- // into a 12-bit integer. Start with the bit at A
- let cornerBits = 0;
- sides.forEach((side, idx, arr) => {
- // XX......X where X's are orientation marks
- let t = ((side >> (length - 2)) << 1) + (side & 1);
- cornerBits = (cornerBits << 3) + t;
- });
- // for (var side in sides) {
- // // XX......X where X's are orientation marks
- // var t = ((side >> (length - 2)) << 1) + (side & 1);
- // cornerBits = (cornerBits << 3) + t;
- // }
-
- // Mov the bottom bit to the top, so that the three bits of the locator pattern at A are
- // together. cornerBits is now:
- // 3 orientation bits at A || 3 orientation bits at B || ... || 3 orientation bits at D
- cornerBits = ((cornerBits & 1) << 11) + (cornerBits >> 1);
- // The result shift indicates which element of BullsEyeCorners[] goes into the top-left
- // corner. Since the four rotation values have a Hamming distance of 8, we
- // can easily tolerate two errors.
- for (let shift = 0; shift < 4; shift++) {
- if (Integer.bitCount(cornerBits ^ this.EXPECTED_CORNER_BITS[shift]) <= 2) {
- return shift;
- }
- }
- throw new NotFoundException();
+ // Mov the bottom bit to the top, so that the three bits of the locator pattern at A are
+ // together. cornerBits is now:
+ // 3 orientation bits at A || 3 orientation bits at B || ... || 3 orientation bits at D
+ cornerBits = ((cornerBits & 1) << 11) + (cornerBits >> 1);
+ // The result shift indicates which element of BullsEyeCorners[] goes into the top-left
+ // corner. Since the four rotation values have a Hamming distance of 8, we
+ // can easily tolerate two errors.
+ for (let shift = 0; shift < 4; shift++) {
+ if (Integer.bitCount(cornerBits ^ this.EXPECTED_CORNER_BITS[shift]) <= 2) {
+ return shift;
+ }
}
-
- /**
- * Corrects the parameter bits using Reed-Solomon algorithm.
- *
- * @param parameterData parameter bits
- * @param compact true if this is a compact Aztec code
- * @throws NotFoundException if the array contains too many errors
- */
- private getCorrectedParameterData(parameterData: number, compact: boolean): number {
- let numCodewords;
- let numDataCodewords;
-
- if (compact) {
- numCodewords = 7;
- numDataCodewords = 2;
- } else {
- numCodewords = 10;
- numDataCodewords = 4;
- }
-
- let numECCodewords = numCodewords - numDataCodewords;
- let parameterWords: Int32Array = new Int32Array(numCodewords);
- for (let i = numCodewords - 1; i >= 0; --i) {
- parameterWords[i] = parameterData & 0xF;
- parameterData >>= 4;
- }
- try {
- let rsDecoder = new ReedSolomonDecoder(GenericGF.AZTEC_PARAM);
- rsDecoder.decode(parameterWords, numECCodewords);
- } catch (ignored) {
- throw new NotFoundException();
- }
- // Toss the error correction. Just return the data as an integer
- let result = 0;
- for (let i = 0; i < numDataCodewords; i++) {
- result = (result << 4) + parameterWords[i];
- }
- return result;
+ throw new NotFoundException();
+ }
+
+ /**
+ * Corrects the parameter bits using Reed-Solomon algorithm.
+ *
+ * @param parameterData parameter bits
+ * @param compact true if this is a compact Aztec code
+ * @throws NotFoundException if the array contains too many errors
+ */
+ private getCorrectedParameterData(parameterData: number, compact: boolean): number {
+ let numCodewords;
+ let numDataCodewords;
+
+ if (compact) {
+ numCodewords = 7;
+ numDataCodewords = 2;
+ } else {
+ numCodewords = 10;
+ numDataCodewords = 4;
}
- /**
- * Finds the corners of a bull-eye centered on the passed point.
- * This returns the centers of the diagonal points just outside the bull's eye
- * Returns [topRight, bottomRight, bottomLeft, topLeft]
- *
- * @param pCenter Center point
- * @return The corners of the bull-eye
- * @throws NotFoundException If no valid bull-eye can be found
- */
- private getBullsEyeCorners(pCenter: Point): ResultPoint[] {
-
-
- let pina = pCenter;
- let pinb = pCenter;
- let pinc = pCenter;
- let pind = pCenter;
-
- let color = true;
-
- for (this.nbCenterLayers = 1; this.nbCenterLayers < 9; this.nbCenterLayers++) {
-
- let pouta = this.getFirstDifferent(pina, color, 1, -1);
- let poutb = this.getFirstDifferent(pinb, color, 1, 1);
- let poutc = this.getFirstDifferent(pinc, color, -1, 1);
- let poutd = this.getFirstDifferent(pind, color, -1, -1);
-
- // d a
- //
- // c b
-
- if (this.nbCenterLayers > 2) {
- let q = (this.distancePoint(poutd, pouta) * this.nbCenterLayers) / (this.distancePoint(pind, pina) * (this.nbCenterLayers + 2));
- if (q < 0.75 || q > 1.25 || !this.isWhiteOrBlackRectangle(pouta, poutb, poutc, poutd)) {
- break;
- }
- }
-
- pina = pouta;
- pinb = poutb;
- pinc = poutc;
- pind = poutd;
-
- color = !color;
- }
-
- if (this.nbCenterLayers !== 5 && this.nbCenterLayers !== 7) {
- throw new NotFoundException();
+ let numECCodewords = numCodewords - numDataCodewords;
+ let parameterWords: Int32Array = new Int32Array(numCodewords);
+ for (let i = numCodewords - 1; i >= 0; --i) {
+ parameterWords[i] = parameterData & 0xF;
+ parameterData >>= 4;
+ }
+ try {
+ let rsDecoder = new ReedSolomonDecoder(GenericGF.AZTEC_PARAM);
+ rsDecoder.decode(parameterWords, numECCodewords);
+ } catch (ignored) {
+ throw new NotFoundException();
+ }
+ // Toss the error correction. Just return the data as an integer
+ let result = 0;
+ for (let i = 0; i < numDataCodewords; i++) {
+ result = (result << 4) + parameterWords[i];
+ }
+ return result;
+ }
+
+ /**
+ * Finds the corners of a bull-eye centered on the passed point.
+ * This returns the centers of the diagonal points just outside the bull's eye
+ * Returns [topRight, bottomRight, bottomLeft, topLeft]
+ *
+ * @param pCenter Center point
+ * @return The corners of the bull-eye
+ * @throws NotFoundException If no valid bull-eye can be found
+ */
+ private getBullsEyeCorners(pCenter: Point): ResultPoint[] {
+
+
+ let pina = pCenter;
+ let pinb = pCenter;
+ let pinc = pCenter;
+ let pind = pCenter;
+
+ let color = true;
+
+ for (this.nbCenterLayers = 1; this.nbCenterLayers < 9; this.nbCenterLayers++) {
+
+ let pouta = this.getFirstDifferent(pina, color, 1, -1);
+ let poutb = this.getFirstDifferent(pinb, color, 1, 1);
+ let poutc = this.getFirstDifferent(pinc, color, -1, 1);
+ let poutd = this.getFirstDifferent(pind, color, -1, -1);
+
+ // d a
+ //
+ // c b
+
+ if (this.nbCenterLayers > 2) {
+ let q = (this.distancePoint(poutd, pouta) * this.nbCenterLayers) / (this.distancePoint(pind, pina) * (this.nbCenterLayers + 2));
+ if (q < 0.75 || q > 1.25 || !this.isWhiteOrBlackRectangle(pouta, poutb, poutc, poutd)) {
+ break;
}
+ }
- this.compact = this.nbCenterLayers === 5;
-
- // Expand the square by .5 pixel in each direction so that we're on the border
- // between the white square and the black square
- let pinax = new ResultPoint(pina.getX() + 0.5, pina.getY() - 0.5);
- let pinbx = new ResultPoint(pinb.getX() + 0.5, pinb.getY() + 0.5);
- let pincx = new ResultPoint(pinc.getX() - 0.5, pinc.getY() + 0.5);
- let pindx = new ResultPoint(pind.getX() - 0.5, pind.getY() - 0.5);
+ pina = pouta;
+ pinb = poutb;
+ pinc = poutc;
+ pind = poutd;
- // Expand the square so that its corners are the centers of the points
- // just outside the bull's eye.
- return this.expandSquare([pinax, pinbx, pincx, pindx],
- 2 * this.nbCenterLayers - 3,
- 2 * this.nbCenterLayers);
+ color = !color;
}
- /**
- * Finds a candidate center point of an Aztec code from an image
- *
- * @return the center point
- */
- private getMatrixCenter(): Point {
-
- let pointA: ResultPoint;
- let pointB: ResultPoint;
- let pointC: ResultPoint;
- let pointD: ResultPoint;
-
- // Get a white rectangle that can be the border of the matrix in center bull's eye or
- try {
-
- let cornerPoints = new WhiteRectangleDetector(this.image).detect();
- pointA = cornerPoints[0];
- pointB = cornerPoints[1];
- pointC = cornerPoints[2];
- pointD = cornerPoints[3];
-
- } catch (e) {
-
- // This exception can be in case the initial rectangle is white
- // In that case, surely in the bull's eye, we try to expand the rectangle.
- let cx = this.image.getWidth() / 2;
- let cy = this.image.getHeight() / 2;
- pointA = this.getFirstDifferent(new Point(cx + 7, cy - 7), false, 1, -1).toResultPoint();
- pointB = this.getFirstDifferent(new Point(cx + 7, cy + 7), false, 1, 1).toResultPoint();
- pointC = this.getFirstDifferent(new Point(cx - 7, cy + 7), false, -1, 1).toResultPoint();
- pointD = this.getFirstDifferent(new Point(cx - 7, cy - 7), false, -1, -1).toResultPoint();
-
- }
-
- // Compute the center of the rectangle
- let cx = MathUtils.round((pointA.getX() + pointD.getX() + pointB.getX() + pointC.getX()) / 4.0);
- let cy = MathUtils.round((pointA.getY() + pointD.getY() + pointB.getY() + pointC.getY()) / 4.0);
-
- // Redetermine the white rectangle starting from previously computed center.
- // This will ensure that we end up with a white rectangle in center bull's eye
- // in order to compute a more accurate center.
- try {
- let cornerPoints = new WhiteRectangleDetector(this.image, 15, cx, cy).detect();
- pointA = cornerPoints[0];
- pointB = cornerPoints[1];
- pointC = cornerPoints[2];
- pointD = cornerPoints[3];
- } catch (e) {
- // This exception can be in case the initial rectangle is white
- // In that case we try to expand the rectangle.
- pointA = this.getFirstDifferent(new Point(cx + 7, cy - 7), false, 1, -1).toResultPoint();
- pointB = this.getFirstDifferent(new Point(cx + 7, cy + 7), false, 1, 1).toResultPoint();
- pointC = this.getFirstDifferent(new Point(cx - 7, cy + 7), false, -1, 1).toResultPoint();
- pointD = this.getFirstDifferent(new Point(cx - 7, cy - 7), false, -1, -1).toResultPoint();
- }
+ if (this.nbCenterLayers !== 5 && this.nbCenterLayers !== 7) {
+ throw new NotFoundException();
+ }
- // Recompute the center of the rectangle
- cx = MathUtils.round((pointA.getX() + pointD.getX() + pointB.getX() + pointC.getX()) / 4.0);
- cy = MathUtils.round((pointA.getY() + pointD.getY() + pointB.getY() + pointC.getY()) / 4.0);
+ this.compact = this.nbCenterLayers === 5;
+
+ // Expand the square by .5 pixel in each direction so that we're on the border
+ // between the white square and the black square
+ let pinax = new ResultPoint(pina.getX() + 0.5, pina.getY() - 0.5);
+ let pinbx = new ResultPoint(pinb.getX() + 0.5, pinb.getY() + 0.5);
+ let pincx = new ResultPoint(pinc.getX() - 0.5, pinc.getY() + 0.5);
+ let pindx = new ResultPoint(pind.getX() - 0.5, pind.getY() - 0.5);
+
+ // Expand the square so that its corners are the centers of the points
+ // just outside the bull's eye.
+ return this.expandSquare([pinax, pinbx, pincx, pindx],
+ 2 * this.nbCenterLayers - 3,
+ 2 * this.nbCenterLayers);
+ }
+
+ /**
+ * Finds a candidate center point of an Aztec code from an image
+ *
+ * @return the center point
+ */
+ private getMatrixCenter(): Point {
+
+ let pointA: ResultPoint;
+ let pointB: ResultPoint;
+ let pointC: ResultPoint;
+ let pointD: ResultPoint;
+
+ // Get a white rectangle that can be the border of the matrix in center bull's eye or
+ try {
+
+ let cornerPoints = new WhiteRectangleDetector(this.image).detect();
+ pointA = cornerPoints[0];
+ pointB = cornerPoints[1];
+ pointC = cornerPoints[2];
+ pointD = cornerPoints[3];
+
+ } catch (e) {
+
+ // This exception can be in case the initial rectangle is white
+ // In that case, surely in the bull's eye, we try to expand the rectangle.
+ let cx = this.image.getWidth() / 2;
+ let cy = this.image.getHeight() / 2;
+ pointA = this.getFirstDifferent(new Point(cx + 7, cy - 7), false, 1, -1).toResultPoint();
+ pointB = this.getFirstDifferent(new Point(cx + 7, cy + 7), false, 1, 1).toResultPoint();
+ pointC = this.getFirstDifferent(new Point(cx - 7, cy + 7), false, -1, 1).toResultPoint();
+ pointD = this.getFirstDifferent(new Point(cx - 7, cy - 7), false, -1, -1).toResultPoint();
- return new Point(cx, cy);
}
- /**
- * Gets the Aztec code corners from the bull's eye corners and the parameters.
- *
- * @param bullsEyeCorners the array of bull's eye corners
- * @return the array of aztec code corners
- */
- private getMatrixCornerPoints(bullsEyeCorners: ResultPoint[]): ResultPoint[] {
- return this.expandSquare(bullsEyeCorners, 2 * this.nbCenterLayers, this.getDimension());
+ // Compute the center of the rectangle
+ let cx = MathUtils.round((pointA.getX() + pointD.getX() + pointB.getX() + pointC.getX()) / 4.0);
+ let cy = MathUtils.round((pointA.getY() + pointD.getY() + pointB.getY() + pointC.getY()) / 4.0);
+
+ // Redetermine the white rectangle starting from previously computed center.
+ // This will ensure that we end up with a white rectangle in center bull's eye
+ // in order to compute a more accurate center.
+ try {
+ let cornerPoints = new WhiteRectangleDetector(this.image, 15, cx, cy).detect();
+ pointA = cornerPoints[0];
+ pointB = cornerPoints[1];
+ pointC = cornerPoints[2];
+ pointD = cornerPoints[3];
+ } catch (e) {
+ // This exception can be in case the initial rectangle is white
+ // In that case we try to expand the rectangle.
+ pointA = this.getFirstDifferent(new Point(cx + 7, cy - 7), false, 1, -1).toResultPoint();
+ pointB = this.getFirstDifferent(new Point(cx + 7, cy + 7), false, 1, 1).toResultPoint();
+ pointC = this.getFirstDifferent(new Point(cx - 7, cy + 7), false, -1, 1).toResultPoint();
+ pointD = this.getFirstDifferent(new Point(cx - 7, cy - 7), false, -1, -1).toResultPoint();
}
- /**
- * Creates a BitMatrix by sampling the provided image.
- * topLeft, topRight, bottomRight, and bottomLeft are the centers of the squares on the
- * diagonal just outside the bull's eye.
- */
- private sampleGrid(image: BitMatrix,
- topLeft: ResultPoint,
- topRight: ResultPoint,
- bottomRight: ResultPoint,
- bottomLeft: ResultPoint): BitMatrix {
-
- let sampler = GridSamplerInstance.getInstance();
- let dimension = this.getDimension();
-
- let low = dimension / 2 - this.nbCenterLayers;
- let high = dimension / 2 + this.nbCenterLayers;
-
- return sampler.sampleGrid(image,
- dimension,
- dimension,
- low, low, // topleft
- high, low, // topright
- high, high, // bottomright
- low, high, // bottomleft
- topLeft.getX(), topLeft.getY(),
- topRight.getX(), topRight.getY(),
- bottomRight.getX(), bottomRight.getY(),
- bottomLeft.getX(), bottomLeft.getY());
+ // Recompute the center of the rectangle
+ cx = MathUtils.round((pointA.getX() + pointD.getX() + pointB.getX() + pointC.getX()) / 4.0);
+ cy = MathUtils.round((pointA.getY() + pointD.getY() + pointB.getY() + pointC.getY()) / 4.0);
+
+ return new Point(cx, cy);
+ }
+
+ /**
+ * Gets the Aztec code corners from the bull's eye corners and the parameters.
+ *
+ * @param bullsEyeCorners the array of bull's eye corners
+ * @return the array of aztec code corners
+ */
+ private getMatrixCornerPoints(bullsEyeCorners: ResultPoint[]): ResultPoint[] {
+ return this.expandSquare(bullsEyeCorners, 2 * this.nbCenterLayers, this.getDimension());
+ }
+
+ /**
+ * Creates a BitMatrix by sampling the provided image.
+ * topLeft, topRight, bottomRight, and bottomLeft are the centers of the squares on the
+ * diagonal just outside the bull's eye.
+ */
+ private sampleGrid(image: BitMatrix,
+ topLeft: ResultPoint,
+ topRight: ResultPoint,
+ bottomRight: ResultPoint,
+ bottomLeft: ResultPoint): BitMatrix {
+
+ let sampler = GridSamplerInstance.getInstance();
+ let dimension = this.getDimension();
+
+ let low = dimension / 2 - this.nbCenterLayers;
+ let high = dimension / 2 + this.nbCenterLayers;
+
+ return sampler.sampleGrid(image,
+ dimension,
+ dimension,
+ low, low, // topleft
+ high, low, // topright
+ high, high, // bottomright
+ low, high, // bottomleft
+ topLeft.getX(), topLeft.getY(),
+ topRight.getX(), topRight.getY(),
+ bottomRight.getX(), bottomRight.getY(),
+ bottomLeft.getX(), bottomLeft.getY());
+ }
+
+ /**
+ * Samples a line.
+ *
+ * @param p1 start point (inclusive)
+ * @param p2 end point (exclusive)
+ * @param size number of bits
+ * @return the array of bits as an int (first bit is high-order bit of result)
+ */
+ private sampleLine(p1: ResultPoint, p2: ResultPoint, size: number): number {
+ let result = 0;
+
+ let d = this.distanceResultPoint(p1, p2);
+ let moduleSize = d / size;
+ let px = p1.getX();
+ let py = p1.getY();
+ let dx = moduleSize * (p2.getX() - p1.getX()) / d;
+ let dy = moduleSize * (p2.getY() - p1.getY()) / d;
+ for (let i = 0; i < size; i++) {
+ if (this.image.get(MathUtils.round(px + i * dx), MathUtils.round(py + i * dy))) {
+ result |= 1 << (size - i - 1);
+ }
}
-
- /**
- * Samples a line.
- *
- * @param p1 start point (inclusive)
- * @param p2 end point (exclusive)
- * @param size number of bits
- * @return the array of bits as an int (first bit is high-order bit of result)
- */
- private sampleLine(p1: ResultPoint, p2: ResultPoint, size: number): number {
- let result = 0;
-
- let d = this.distanceResultPoint(p1, p2);
- let moduleSize = d / size;
- let px = p1.getX();
- let py = p1.getY();
- let dx = moduleSize * (p2.getX() - p1.getX()) / d;
- let dy = moduleSize * (p2.getY() - p1.getY()) / d;
- for (let i = 0; i < size; i++) {
- if (this.image.get(MathUtils.round(px + i * dx), MathUtils.round(py + i * dy))) {
- result |= 1 << (size - i - 1);
- }
- }
- return result;
+ return result;
+ }
+
+ /**
+ * @return true if the border of the rectangle passed in parameter is compound of white points only
+ * or black points only
+ */
+ private isWhiteOrBlackRectangle(p1: Point,
+ p2: Point,
+ p3: Point,
+ p4: Point): boolean {
+
+ let corr = 3;
+ p1 = new Point(p1.getX() - corr, p1.getY() + corr);
+ p2 = new Point(p2.getX() - corr, p2.getY() - corr);
+ p3 = new Point(p3.getX() + corr, p3.getY() - corr);
+ p4 = new Point(p4.getX() + corr, p4.getY() + corr);
+
+ let cInit = this.getColor(p4, p1);
+
+ if (cInit === 0) {
+ return false;
}
- /**
- * @return true if the border of the rectangle passed in parameter is compound of white points only
- * or black points only
- */
- private isWhiteOrBlackRectangle(p1: Point,
- p2: Point,
- p3: Point,
- p4: Point): boolean {
-
- let corr = 3;
- p1 = new Point(p1.getX() - corr, p1.getY() + corr);
- p2 = new Point(p2.getX() - corr, p2.getY() - corr);
- p3 = new Point(p3.getX() + corr, p3.getY() - corr);
- p4 = new Point(p4.getX() + corr, p4.getY() + corr);
-
- let cInit = this.getColor(p4, p1);
-
- if (cInit === 0) {
- return false;
- }
-
- let c = this.getColor(p1, p2);
+ let c = this.getColor(p1, p2);
- if (c !== cInit) {
- return false;
- }
+ if (c !== cInit) {
+ return false;
+ }
- c = this.getColor(p2, p3);
+ c = this.getColor(p2, p3);
- if (c !== cInit) {
- return false;
- }
+ if (c !== cInit) {
+ return false;
+ }
- c = this.getColor(p3, p4);
+ c = this.getColor(p3, p4);
- return c === cInit;
+ return c === cInit;
- }
+ }
- /**
- * Gets the color of a segment
- *
- * @return 1 if segment more than 90% black, -1 if segment is more than 90% white, 0 else
- */
- private getColor(p1: Point, p2: Point): number {
- let d = this.distancePoint(p1, p2);
- let dx = (p2.getX() - p1.getX()) / d;
- let dy = (p2.getY() - p1.getY()) / d;
- let error = 0;
-
- let px = p1.getX();
- let py = p1.getY();
-
- let colorModel = this.image.get(p1.getX(), p1.getY());
-
- let iMax = Math.ceil(d);
- for (let i = 0; i < iMax; i++) {
- px += dx;
- py += dy;
- if (this.image.get(MathUtils.round(px), MathUtils.round(py)) !== colorModel) {
- error++;
- }
- }
+ /**
+ * Gets the color of a segment
+ *
+ * @return 1 if segment more than 90% black, -1 if segment is more than 90% white, 0 else
+ */
+ private getColor(p1: Point, p2: Point): number {
+ let d = this.distancePoint(p1, p2);
+ let dx = (p2.getX() - p1.getX()) / d;
+ let dy = (p2.getY() - p1.getY()) / d;
+ let error = 0;
- let errRatio = error / d;
+ let px = p1.getX();
+ let py = p1.getY();
- if (errRatio > 0.1 && errRatio < 0.9) {
- return 0;
- }
+ let colorModel = this.image.get(p1.getX(), p1.getY());
- return (errRatio <= 0.1) === colorModel ? 1 : -1;
+ let iMax = Math.ceil(d);
+ for (let i = 0; i < iMax; i++) {
+ px += dx;
+ py += dy;
+ if (this.image.get(MathUtils.round(px), MathUtils.round(py)) !== colorModel) {
+ error++;
+ }
}
- /**
- * Gets the coordinate of the first point with a different color in the given direction
- */
- private getFirstDifferent(init: Point, color: boolean, dx: number, dy: number): Point {
- let x = init.getX() + dx;
- let y = init.getY() + dy;
+ let errRatio = error / d;
- while (this.isValid(x, y) && this.image.get(x, y) === color) {
- x += dx;
- y += dy;
- }
-
- x -= dx;
- y -= dy;
-
- while (this.isValid(x, y) && this.image.get(x, y) === color) {
- x += dx;
- }
- x -= dx;
+ if (errRatio > 0.1 && errRatio < 0.9) {
+ return 0;
+ }
- while (this.isValid(x, y) && this.image.get(x, y) === color) {
- y += dy;
- }
- y -= dy;
+ return (errRatio <= 0.1) === colorModel ? 1 : -1;
+ }
- return new Point(x, y);
- }
+ /**
+ * Gets the coordinate of the first point with a different color in the given direction
+ */
+ private getFirstDifferent(init: Point, color: boolean, dx: number, dy: number): Point {
+ let x = init.getX() + dx;
+ let y = init.getY() + dy;
- /**
- * Expand the square represented by the corner points by pushing out equally in all directions
- *
- * @param cornerPoints the corners of the square, which has the bull's eye at its center
- * @param oldSide the original length of the side of the square in the target bit matrix
- * @param newSide the new length of the size of the square in the target bit matrix
- * @return the corners of the expanded square
- */
- private expandSquare(cornerPoints: ResultPoint[], oldSide: number, newSide: number): ResultPoint[] {
- let ratio = newSide / (2.0 * oldSide);
- let dx = cornerPoints[0].getX() - cornerPoints[2].getX();
- let dy = cornerPoints[0].getY() - cornerPoints[2].getY();
- let centerx = (cornerPoints[0].getX() + cornerPoints[2].getX()) / 2.0;
- let centery = (cornerPoints[0].getY() + cornerPoints[2].getY()) / 2.0;
-
- let result0 = new ResultPoint(centerx + ratio * dx, centery + ratio * dy);
- let result2 = new ResultPoint(centerx - ratio * dx, centery - ratio * dy);
-
- dx = cornerPoints[1].getX() - cornerPoints[3].getX();
- dy = cornerPoints[1].getY() - cornerPoints[3].getY();
- centerx = (cornerPoints[1].getX() + cornerPoints[3].getX()) / 2.0;
- centery = (cornerPoints[1].getY() + cornerPoints[3].getY()) / 2.0;
- let result1 = new ResultPoint(centerx + ratio * dx, centery + ratio * dy);
- let result3 = new ResultPoint(centerx - ratio * dx, centery - ratio * dy);
-
- let results: ResultPoint[] = [result0, result1, result2, result3];
- return results;
+ while (this.isValid(x, y) && this.image.get(x, y) === color) {
+ x += dx;
+ y += dy;
}
- private isValid(x: number, y: number): boolean {
- return x >= 0 && x < this.image.getWidth() && y > 0 && y < this.image.getHeight();
- }
+ x -= dx;
+ y -= dy;
- private isValidPoint(point: ResultPoint): boolean {
- let x = MathUtils.round(point.getX());
- let y = MathUtils.round(point.getY());
- return this.isValid(x, y);
+ while (this.isValid(x, y) && this.image.get(x, y) === color) {
+ x += dx;
}
+ x -= dx;
- private distancePoint(a: Point, b: Point): number {
- return MathUtils.distance(a.getX(), a.getY(), b.getX(), b.getY());
+ while (this.isValid(x, y) && this.image.get(x, y) === color) {
+ y += dy;
}
-
- private distanceResultPoint(a: ResultPoint, b: ResultPoint): number {
- return MathUtils.distance(a.getX(), a.getY(), b.getX(), b.getY());
+ y -= dy;
+
+ return new Point(x, y);
+ }
+
+ /**
+ * Expand the square represented by the corner points by pushing out equally in all directions
+ *
+ * @param cornerPoints the corners of the square, which has the bull's eye at its center
+ * @param oldSide the original length of the side of the square in the target bit matrix
+ * @param newSide the new length of the size of the square in the target bit matrix
+ * @return the corners of the expanded square
+ */
+ private expandSquare(cornerPoints: ResultPoint[], oldSide: number, newSide: number): ResultPoint[] {
+ let ratio = newSide / (2.0 * oldSide);
+ let dx = cornerPoints[0].getX() - cornerPoints[2].getX();
+ let dy = cornerPoints[0].getY() - cornerPoints[2].getY();
+ let centerx = (cornerPoints[0].getX() + cornerPoints[2].getX()) / 2.0;
+ let centery = (cornerPoints[0].getY() + cornerPoints[2].getY()) / 2.0;
+
+ let result0 = new ResultPoint(centerx + ratio * dx, centery + ratio * dy);
+ let result2 = new ResultPoint(centerx - ratio * dx, centery - ratio * dy);
+
+ dx = cornerPoints[1].getX() - cornerPoints[3].getX();
+ dy = cornerPoints[1].getY() - cornerPoints[3].getY();
+ centerx = (cornerPoints[1].getX() + cornerPoints[3].getX()) / 2.0;
+ centery = (cornerPoints[1].getY() + cornerPoints[3].getY()) / 2.0;
+ let result1 = new ResultPoint(centerx + ratio * dx, centery + ratio * dy);
+ let result3 = new ResultPoint(centerx - ratio * dx, centery - ratio * dy);
+
+ let results: ResultPoint[] = [result0, result1, result2, result3];
+ return results;
+ }
+
+ private isValid(x: number, y: number): boolean {
+ return x >= 0 && x < this.image.getWidth() && y > 0 && y < this.image.getHeight();
+ }
+
+ private isValidPoint(point: ResultPoint): boolean {
+ let x = MathUtils.round(point.getX());
+ let y = MathUtils.round(point.getY());
+ return this.isValid(x, y);
+ }
+
+ private distancePoint(a: Point, b: Point): number {
+ return MathUtils.distance(a.getX(), a.getY(), b.getX(), b.getY());
+ }
+
+ private distanceResultPoint(a: ResultPoint, b: ResultPoint): number {
+ return MathUtils.distance(a.getX(), a.getY(), b.getX(), b.getY());
+ }
+
+ private getDimension(): number {
+ if (this.compact) {
+ return 4 * this.nbLayers + 11;
}
-
- private getDimension(): number {
- if (this.compact) {
- return 4 * this.nbLayers + 11;
- }
- if (this.nbLayers <= 4) {
- return 4 * this.nbLayers + 15;
- }
- return 4 * this.nbLayers + 2 * (Integer.truncDivision((this.nbLayers - 4), 8) + 1) + 15;
+ if (this.nbLayers <= 4) {
+ return 4 * this.nbLayers + 15;
}
+ return 4 * this.nbLayers + 2 * (Integer.truncDivision((this.nbLayers - 4), 8) + 1) + 15;
+ }
}
diff --git a/src/core/aztec/encoder/Encoder.ts b/src/core/aztec/encoder/Encoder.ts
index 84d740e2..79c6f644 100644
--- a/src/core/aztec/encoder/Encoder.ts
+++ b/src/core/aztec/encoder/Encoder.ts
@@ -89,7 +89,7 @@ export default /*public final*/ class Encoder {
layers = Math.abs(userSpecifiedLayers);
if (layers > (compact ? Encoder.MAX_NB_BITS_COMPACT : Encoder.MAX_NB_BITS)) {
throw new IllegalArgumentException(
- StringUtils.format('Illegal value %s for layers', userSpecifiedLayers));
+ StringUtils.format('Illegal value %s for layers', userSpecifiedLayers));
}
totalBitsInLayer = Encoder.totalBitsInLayer(layers, compact);
wordSize = Encoder.WORD_SIZE[layers];
diff --git a/src/core/aztec/encoder/EncoderConstants.ts b/src/core/aztec/encoder/EncoderConstants.ts
index 5106e012..eca5467f 100644
--- a/src/core/aztec/encoder/EncoderConstants.ts
+++ b/src/core/aztec/encoder/EncoderConstants.ts
@@ -4,12 +4,12 @@ import SimpleToken from './SimpleToken';
import { int } from '../../../customTypings';
export const /*final*/ MODE_NAMES: String[] = [
- 'UPPER',
- 'LOWER',
- 'DIGIT',
- 'MIXED',
- 'PUNCT'
- ];
+ 'UPPER',
+ 'LOWER',
+ 'DIGIT',
+ 'MIXED',
+ 'PUNCT'
+];
export const /*final*/ MODE_UPPER: int = 0; // 5 bits
export const /*final*/ MODE_LOWER: int = 1; // 5 bits
diff --git a/src/core/aztec/encoder/ShiftTable.ts b/src/core/aztec/encoder/ShiftTable.ts
index b17a5baa..b4d97d05 100644
--- a/src/core/aztec/encoder/ShiftTable.ts
+++ b/src/core/aztec/encoder/ShiftTable.ts
@@ -14,4 +14,4 @@ export function static_SHIFT_TABLE(SHIFT_TABLE: Int32Array[]): Int32Array[] {
return SHIFT_TABLE;
}
-export const /*final*/ SHIFT_TABLE: Int32Array[] = static_SHIFT_TABLE(Arrays.createInt32Array(6, 6)); // mode shift codes, per table
\ No newline at end of file
+export const /*final*/ SHIFT_TABLE: Int32Array[] = static_SHIFT_TABLE(Arrays.createInt32Array(6, 6)); // mode shift codes, per table
diff --git a/src/core/aztec/encoder/State.ts b/src/core/aztec/encoder/State.ts
index 66a0b4d5..e6fc5d33 100644
--- a/src/core/aztec/encoder/State.ts
+++ b/src/core/aztec/encoder/State.ts
@@ -137,8 +137,8 @@ export default /*final*/ class State {
this.binaryShiftByteCount === 0 || this.binaryShiftByteCount === 31
? 18
: this.binaryShiftByteCount === 62
- ? 9
- : 8;
+ ? 9
+ : 8;
let result: State = new State(
token,
mode,
diff --git a/src/core/common/BitMatrix.ts b/src/core/common/BitMatrix.ts
index d1499c41..b4a52318 100644
--- a/src/core/common/BitMatrix.ts
+++ b/src/core/common/BitMatrix.ts
@@ -43,480 +43,480 @@ import { int } from '../../customTypings';
*/
export default class BitMatrix /*implements Cloneable*/ {
- /**
- * Creates an empty square {@link BitMatrix}.
- *
- * @param dimension height and width
- */
- // public constructor(dimension: number /*int*/) {
- // this(dimension, dimension)
- // }
-
- /**
- * Creates an empty {@link BitMatrix}.
- *
- * @param width bit matrix width
- * @param height bit matrix height
- */
- // public constructor(width: number /*int*/, height: number /*int*/) {
- // if (width < 1 || height < 1) {
- // throw new IllegalArgumentException("Both dimensions must be greater than 0")
- // }
- // this.width = width
- // this.height = height
- // this.rowSize = (width + 31) / 32
- // bits = new int[rowSize * height];
- // }
-
- public constructor(private width: number /*int*/, private height?: number /*int*/,
- private rowSize?: number /*int*/, private bits?: Int32Array) {
- if (undefined === height || null === height) {
- height = width;
- }
- this.height = height;
- if (width < 1 || height < 1) {
- throw new IllegalArgumentException('Both dimensions must be greater than 0');
- }
- if (undefined === rowSize || null === rowSize) {
- rowSize = Math.floor((width + 31) / 32);
- }
- this.rowSize = rowSize;
- if (undefined === bits || null === bits) {
- this.bits = new Int32Array(this.rowSize * this.height);
- }
+ /**
+ * Creates an empty square {@link BitMatrix}.
+ *
+ * @param dimension height and width
+ */
+ // public constructor(dimension: number /*int*/) {
+ // this(dimension, dimension)
+ // }
+
+ /**
+ * Creates an empty {@link BitMatrix}.
+ *
+ * @param width bit matrix width
+ * @param height bit matrix height
+ */
+ // public constructor(width: number /*int*/, height: number /*int*/) {
+ // if (width < 1 || height < 1) {
+ // throw new IllegalArgumentException("Both dimensions must be greater than 0")
+ // }
+ // this.width = width
+ // this.height = height
+ // this.rowSize = (width + 31) / 32
+ // bits = new int[rowSize * height];
+ // }
+
+ public constructor(private width: number /*int*/, private height?: number /*int*/,
+ private rowSize?: number /*int*/, private bits?: Int32Array) {
+ if (undefined === height || null === height) {
+ height = width;
}
-
- /**
- * Interprets a 2D array of booleans as a {@link BitMatrix}, where "true" means an "on" bit.
- *
- * @function parse
- * @param image bits of the image, as a row-major 2D array. Elements are arrays representing rows
- * @return {@link BitMatrix} representation of image
- */
- public static parseFromBooleanArray(image: boolean[][]): BitMatrix {
- const height = image.length;
- const width = image[0].length;
- const bits = new BitMatrix(width, height);
- for (let i = 0; i < height; i++) {
- const imageI = image[i];
- for (let j = 0; j < width; j++) {
- if (imageI[j]) {
- bits.set(j, i);
- }
- }
- }
- return bits;
+ this.height = height;
+ if (width < 1 || height < 1) {
+ throw new IllegalArgumentException('Both dimensions must be greater than 0');
}
-
- /**
- *
- * @function parse
- * @param stringRepresentation
- * @param setString
- * @param unsetString
- */
- public static parseFromString(stringRepresentation: string, setString: string, unsetString: string): BitMatrix {
- if (stringRepresentation === null) {
- throw new IllegalArgumentException('stringRepresentation cannot be null');
- }
-
- const bits = new Array(stringRepresentation.length);
- let bitsPos = 0;
- let rowStartPos = 0;
- let rowLength = -1;
- let nRows = 0;
- let pos = 0;
- while (pos < stringRepresentation.length) {
- if (stringRepresentation.charAt(pos) === '\n' ||
- stringRepresentation.charAt(pos) === '\r') {
- if (bitsPos > rowStartPos) {
- if (rowLength === -1) {
- rowLength = bitsPos - rowStartPos;
- } else if (bitsPos - rowStartPos !== rowLength) {
- throw new IllegalArgumentException('row lengths do not match');
- }
- rowStartPos = bitsPos;
- nRows++;
- }
- pos++;
- } else if (stringRepresentation.substring(pos, pos + setString.length) === setString) {
- pos += setString.length;
- bits[bitsPos] = true;
- bitsPos++;
- } else if (stringRepresentation.substring(pos, pos + unsetString.length) === unsetString) {
- pos += unsetString.length;
- bits[bitsPos] = false;
- bitsPos++;
- } else {
- throw new IllegalArgumentException(
- 'illegal character encountered: ' + stringRepresentation.substring(pos));
- }
+ if (undefined === rowSize || null === rowSize) {
+ rowSize = Math.floor((width + 31) / 32);
+ }
+ this.rowSize = rowSize;
+ if (undefined === bits || null === bits) {
+ this.bits = new Int32Array(this.rowSize * this.height);
+ }
+ }
+
+ /**
+ * Interprets a 2D array of booleans as a {@link BitMatrix}, where "true" means an "on" bit.
+ *
+ * @function parse
+ * @param image bits of the image, as a row-major 2D array. Elements are arrays representing rows
+ * @return {@link BitMatrix} representation of image
+ */
+ public static parseFromBooleanArray(image: boolean[][]): BitMatrix {
+ const height = image.length;
+ const width = image[0].length;
+ const bits = new BitMatrix(width, height);
+ for (let i = 0; i < height; i++) {
+ const imageI = image[i];
+ for (let j = 0; j < width; j++) {
+ if (imageI[j]) {
+ bits.set(j, i);
}
+ }
+ }
+ return bits;
+ }
+
+ /**
+ *
+ * @function parse
+ * @param stringRepresentation
+ * @param setString
+ * @param unsetString
+ */
+ public static parseFromString(stringRepresentation: string, setString: string, unsetString: string): BitMatrix {
+ if (stringRepresentation === null) {
+ throw new IllegalArgumentException('stringRepresentation cannot be null');
+ }
- // no EOL at end?
+ const bits = new Array(stringRepresentation.length);
+ let bitsPos = 0;
+ let rowStartPos = 0;
+ let rowLength = -1;
+ let nRows = 0;
+ let pos = 0;
+ while (pos < stringRepresentation.length) {
+ if (stringRepresentation.charAt(pos) === '\n' ||
+ stringRepresentation.charAt(pos) === '\r') {
if (bitsPos > rowStartPos) {
- if (rowLength === -1) {
- rowLength = bitsPos - rowStartPos;
- } else if (bitsPos - rowStartPos !== rowLength) {
- throw new IllegalArgumentException('row lengths do not match');
- }
- nRows++;
+ if (rowLength === -1) {
+ rowLength = bitsPos - rowStartPos;
+ } else if (bitsPos - rowStartPos !== rowLength) {
+ throw new IllegalArgumentException('row lengths do not match');
+ }
+ rowStartPos = bitsPos;
+ nRows++;
}
-
- const matrix = new BitMatrix(rowLength, nRows);
- for (let i = 0; i < bitsPos; i++) {
- if (bits[i]) {
- matrix.set(Math.floor(i % rowLength), Math.floor(i / rowLength));
- }
- }
- return matrix;
+ pos++;
+ } else if (stringRepresentation.substring(pos, pos + setString.length) === setString) {
+ pos += setString.length;
+ bits[bitsPos] = true;
+ bitsPos++;
+ } else if (stringRepresentation.substring(pos, pos + unsetString.length) === unsetString) {
+ pos += unsetString.length;
+ bits[bitsPos] = false;
+ bitsPos++;
+ } else {
+ throw new IllegalArgumentException(
+ 'illegal character encountered: ' + stringRepresentation.substring(pos));
+ }
}
- /**
- *
Gets the requested bit, where true means black.
- *
- * @param x The horizontal component (i.e. which column)
- * @param y The vertical component (i.e. which row)
- * @return value of given bit in matrix
- */
- public get(x: number /*int*/, y: number /*int*/): boolean {
- const offset = y * this.rowSize + Math.floor(x / 32);
- return ((this.bits[offset] >>> (x & 0x1f)) & 1) !== 0;
+ // no EOL at end?
+ if (bitsPos > rowStartPos) {
+ if (rowLength === -1) {
+ rowLength = bitsPos - rowStartPos;
+ } else if (bitsPos - rowStartPos !== rowLength) {
+ throw new IllegalArgumentException('row lengths do not match');
+ }
+ nRows++;
}
- /**
- *
Sets the given bit to true.
- *
- * @param x The horizontal component (i.e. which column)
- * @param y The vertical component (i.e. which row)
- */
- public set(x: number /*int*/, y: number /*int*/): void {
- const offset = y * this.rowSize + Math.floor(x / 32);
- this.bits[offset] |= (1 << (x & 0x1f)) & 0xFFFFFFFF;
+ const matrix = new BitMatrix(rowLength, nRows);
+ for (let i = 0; i < bitsPos; i++) {
+ if (bits[i]) {
+ matrix.set(Math.floor(i % rowLength), Math.floor(i / rowLength));
+ }
}
-
- public unset(x: number /*int*/, y: number /*int*/): void {
- const offset = y * this.rowSize + Math.floor(x / 32);
- this.bits[offset] &= ~((1 << (x & 0x1f)) & 0xFFFFFFFF);
+ return matrix;
+ }
+
+ /**
+ *
Gets the requested bit, where true means black.
+ *
+ * @param x The horizontal component (i.e. which column)
+ * @param y The vertical component (i.e. which row)
+ * @return value of given bit in matrix
+ */
+ public get(x: number /*int*/, y: number /*int*/): boolean {
+ const offset = y * this.rowSize + Math.floor(x / 32);
+ return ((this.bits[offset] >>> (x & 0x1f)) & 1) !== 0;
+ }
+
+ /**
+ *
Sets the given bit to true.
+ *
+ * @param x The horizontal component (i.e. which column)
+ * @param y The vertical component (i.e. which row)
+ */
+ public set(x: number /*int*/, y: number /*int*/): void {
+ const offset = y * this.rowSize + Math.floor(x / 32);
+ this.bits[offset] |= (1 << (x & 0x1f)) & 0xFFFFFFFF;
+ }
+
+ public unset(x: number /*int*/, y: number /*int*/): void {
+ const offset = y * this.rowSize + Math.floor(x / 32);
+ this.bits[offset] &= ~((1 << (x & 0x1f)) & 0xFFFFFFFF);
+ }
+
+ /**
+ *
Flips the given bit.
+ *
+ * @param x The horizontal component (i.e. which column)
+ * @param y The vertical component (i.e. which row)
+ */
+ public flip(x: number /*int*/, y: number /*int*/): void {
+ const offset = y * this.rowSize + Math.floor(x / 32);
+ this.bits[offset] ^= ((1 << (x & 0x1f)) & 0xFFFFFFFF);
+ }
+
+ /**
+ * Exclusive-or (XOR): Flip the bit in this {@code BitMatrix} if the corresponding
+ * mask bit is set.
+ *
+ * @param mask XOR mask
+ */
+ public xor(mask: BitMatrix): void {
+ if (this.width !== mask.getWidth() || this.height !== mask.getHeight()
+ || this.rowSize !== mask.getRowSize()) {
+ throw new IllegalArgumentException('input matrix dimensions do not match');
}
-
- /**
- *
Flips the given bit.
- *
- * @param x The horizontal component (i.e. which column)
- * @param y The vertical component (i.e. which row)
- */
- public flip(x: number /*int*/, y: number /*int*/): void {
- const offset = y * this.rowSize + Math.floor(x / 32);
- this.bits[offset] ^= ((1 << (x & 0x1f)) & 0xFFFFFFFF);
+ const rowArray = new BitArray(Math.floor(this.width / 32) + 1);
+ const rowSize = this.rowSize;
+ const bits = this.bits;
+ for (let y = 0, height = this.height; y < height; y++) {
+ const offset = y * rowSize;
+ const row = mask.getRow(y, rowArray).getBitArray();
+ for (let x = 0; x < rowSize; x++) {
+ bits[offset + x] ^= row[x];
+ }
}
-
- /**
- * Exclusive-or (XOR): Flip the bit in this {@code BitMatrix} if the corresponding
- * mask bit is set.
- *
- * @param mask XOR mask
- */
- public xor(mask: BitMatrix): void {
- if (this.width !== mask.getWidth() || this.height !== mask.getHeight()
- || this.rowSize !== mask.getRowSize()) {
- throw new IllegalArgumentException('input matrix dimensions do not match');
- }
- const rowArray = new BitArray(Math.floor(this.width / 32) + 1);
- const rowSize = this.rowSize;
- const bits = this.bits;
- for (let y = 0, height = this.height; y < height; y++) {
- const offset = y * rowSize;
- const row = mask.getRow(y, rowArray).getBitArray();
- for (let x = 0; x < rowSize; x++) {
- bits[offset + x] ^= row[x];
- }
- }
+ }
+
+ /**
+ * Clears all bits (sets to false).
+ */
+ public clear(): void {
+ const bits = this.bits;
+ const max = bits.length;
+ for (let i = 0; i < max; i++) {
+ bits[i] = 0;
}
-
- /**
- * Clears all bits (sets to false).
- */
- public clear(): void {
- const bits = this.bits;
- const max = bits.length;
- for (let i = 0; i < max; i++) {
- bits[i] = 0;
- }
+ }
+
+ /**
+ *
Sets a square region of the bit matrix to true.
+ *
+ * @param left The horizontal position to begin at (inclusive)
+ * @param top The vertical position to begin at (inclusive)
+ * @param width The width of the region
+ * @param height The height of the region
+ */
+ public setRegion(left: number /*int*/, top: number /*int*/, width: number /*int*/, height: number /*int*/): void {
+ if (top < 0 || left < 0) {
+ throw new IllegalArgumentException('Left and top must be nonnegative');
}
-
- /**
- *
Sets a square region of the bit matrix to true.
- *
- * @param left The horizontal position to begin at (inclusive)
- * @param top The vertical position to begin at (inclusive)
- * @param width The width of the region
- * @param height The height of the region
- */
- public setRegion(left: number /*int*/, top: number /*int*/, width: number /*int*/, height: number /*int*/): void {
- if (top < 0 || left < 0) {
- throw new IllegalArgumentException('Left and top must be nonnegative');
- }
- if (height < 1 || width < 1) {
- throw new IllegalArgumentException('Height and width must be at least 1');
- }
- const right = left + width;
- const bottom = top + height;
- if (bottom > this.height || right > this.width) {
- throw new IllegalArgumentException('The region must fit inside the matrix');
- }
- const rowSize = this.rowSize;
- const bits = this.bits;
- for (let y = top; y < bottom; y++) {
- const offset = y * rowSize;
- for (let x = left; x < right; x++) {
- bits[offset + Math.floor(x / 32)] |= ((1 << (x & 0x1f)) & 0xFFFFFFFF);
- }
- }
+ if (height < 1 || width < 1) {
+ throw new IllegalArgumentException('Height and width must be at least 1');
}
-
- /**
- * A fast method to retrieve one row of data from the matrix as a BitArray.
- *
- * @param y The row to retrieve
- * @param row An optional caller-allocated BitArray, will be allocated if null or too small
- * @return The resulting BitArray - this reference should always be used even when passing
- * your own row
- */
- public getRow(y: number /*int*/, row?: BitArray): BitArray {
- if (row === null || row === undefined || row.getSize() < this.width) {
- row = new BitArray(this.width);
- } else {
- row.clear();
- }
- const rowSize = this.rowSize;
- const bits = this.bits;
- const offset = y * rowSize;
- for (let x = 0; x < rowSize; x++) {
- row.setBulk(x * 32, bits[offset + x]);
- }
- return row;
+ const right = left + width;
+ const bottom = top + height;
+ if (bottom > this.height || right > this.width) {
+ throw new IllegalArgumentException('The region must fit inside the matrix');
}
-
- /**
- * @param y row to set
- * @param row {@link BitArray} to copy from
- */
- public setRow(y: number /*int*/, row: BitArray): void {
- System.arraycopy(row.getBitArray(), 0, this.bits, y * this.rowSize, this.rowSize);
+ const rowSize = this.rowSize;
+ const bits = this.bits;
+ for (let y = top; y < bottom; y++) {
+ const offset = y * rowSize;
+ for (let x = left; x < right; x++) {
+ bits[offset + Math.floor(x / 32)] |= ((1 << (x & 0x1f)) & 0xFFFFFFFF);
+ }
}
-
- /**
- * Modifies this {@code BitMatrix} to represent the same but rotated 180 degrees
- */
- public rotate180(): void {
- const width = this.getWidth();
- const height = this.getHeight();
- let topRow = new BitArray(width);
- let bottomRow = new BitArray(width);
- for (let i = 0, length = Math.floor((height + 1) / 2); i < length; i++) {
- topRow = this.getRow(i, topRow);
- bottomRow = this.getRow(height - 1 - i, bottomRow);
- topRow.reverse();
- bottomRow.reverse();
- this.setRow(i, bottomRow);
- this.setRow(height - 1 - i, topRow);
- }
+ }
+
+ /**
+ * A fast method to retrieve one row of data from the matrix as a BitArray.
+ *
+ * @param y The row to retrieve
+ * @param row An optional caller-allocated BitArray, will be allocated if null or too small
+ * @return The resulting BitArray - this reference should always be used even when passing
+ * your own row
+ */
+ public getRow(y: number /*int*/, row?: BitArray): BitArray {
+ if (row === null || row === undefined || row.getSize() < this.width) {
+ row = new BitArray(this.width);
+ } else {
+ row.clear();
}
-
- /**
- * This is useful in detecting the enclosing rectangle of a 'pure' barcode.
- *
- * @return {@code left,top,width,height} enclosing rectangle of all 1 bits, or null if it is all white
- */
- public getEnclosingRectangle(): Int32Array {
- const width = this.width;
- const height = this.height;
- const rowSize = this.rowSize;
- const bits = this.bits;
-
- let left = width;
- let top = height;
- let right = -1;
- let bottom = -1;
-
- for (let y = 0; y < height; y++) {
- for (let x32 = 0; x32 < rowSize; x32++) {
- const theBits = bits[y * rowSize + x32];
- if (theBits !== 0) {
- if (y < top) {
- top = y;
- }
- if (y > bottom) {
- bottom = y;
- }
- if (x32 * 32 < left) {
- let bit = 0;
- while (((theBits << (31 - bit)) & 0xFFFFFFFF) === 0) {
- bit++;
- }
- if ((x32 * 32 + bit) < left) {
- left = x32 * 32 + bit;
- }
- }
- if (x32 * 32 + 31 > right) {
- let bit = 31;
- while ((theBits >>> bit) === 0) {
- bit--;
- }
- if ((x32 * 32 + bit) > right) {
- right = x32 * 32 + bit;
- }
- }
- }
+ const rowSize = this.rowSize;
+ const bits = this.bits;
+ const offset = y * rowSize;
+ for (let x = 0; x < rowSize; x++) {
+ row.setBulk(x * 32, bits[offset + x]);
+ }
+ return row;
+ }
+
+ /**
+ * @param y row to set
+ * @param row {@link BitArray} to copy from
+ */
+ public setRow(y: number /*int*/, row: BitArray): void {
+ System.arraycopy(row.getBitArray(), 0, this.bits, y * this.rowSize, this.rowSize);
+ }
+
+ /**
+ * Modifies this {@code BitMatrix} to represent the same but rotated 180 degrees
+ */
+ public rotate180(): void {
+ const width = this.getWidth();
+ const height = this.getHeight();
+ let topRow = new BitArray(width);
+ let bottomRow = new BitArray(width);
+ for (let i = 0, length = Math.floor((height + 1) / 2); i < length; i++) {
+ topRow = this.getRow(i, topRow);
+ bottomRow = this.getRow(height - 1 - i, bottomRow);
+ topRow.reverse();
+ bottomRow.reverse();
+ this.setRow(i, bottomRow);
+ this.setRow(height - 1 - i, topRow);
+ }
+ }
+
+ /**
+ * This is useful in detecting the enclosing rectangle of a 'pure' barcode.
+ *
+ * @return {@code left,top,width,height} enclosing rectangle of all 1 bits, or null if it is all white
+ */
+ public getEnclosingRectangle(): Int32Array {
+ const width = this.width;
+ const height = this.height;
+ const rowSize = this.rowSize;
+ const bits = this.bits;
+
+ let left = width;
+ let top = height;
+ let right = -1;
+ let bottom = -1;
+
+ for (let y = 0; y < height; y++) {
+ for (let x32 = 0; x32 < rowSize; x32++) {
+ const theBits = bits[y * rowSize + x32];
+ if (theBits !== 0) {
+ if (y < top) {
+ top = y;
+ }
+ if (y > bottom) {
+ bottom = y;
+ }
+ if (x32 * 32 < left) {
+ let bit = 0;
+ while (((theBits << (31 - bit)) & 0xFFFFFFFF) === 0) {
+ bit++;
}
+ if ((x32 * 32 + bit) < left) {
+ left = x32 * 32 + bit;
+ }
+ }
+ if (x32 * 32 + 31 > right) {
+ let bit = 31;
+ while ((theBits >>> bit) === 0) {
+ bit--;
+ }
+ if ((x32 * 32 + bit) > right) {
+ right = x32 * 32 + bit;
+ }
+ }
}
-
- if (right < left || bottom < top) {
- return null;
- }
-
- return Int32Array.from([left, top, right - left + 1, bottom - top + 1]);
+ }
}
- /**
- * This is useful in detecting a corner of a 'pure' barcode.
- *
- * @return {@code x,y} coordinate of top-left-most 1 bit, or null if it is all white
- */
- public getTopLeftOnBit(): Int32Array {
- const rowSize = this.rowSize;
- const bits = this.bits;
-
- let bitsOffset = 0;
- while (bitsOffset < bits.length && bits[bitsOffset] === 0) {
- bitsOffset++;
- }
- if (bitsOffset === bits.length) {
- return null;
- }
- const y = bitsOffset / rowSize;
- let x = (bitsOffset % rowSize) * 32;
-
- const theBits = bits[bitsOffset];
- let bit = 0;
- while (((theBits << (31 - bit)) & 0xFFFFFFFF) === 0) {
- bit++;
- }
- x += bit;
- return Int32Array.from([x, y]);
+ if (right < left || bottom < top) {
+ return null;
}
- public getBottomRightOnBit(): Int32Array {
- const rowSize = this.rowSize;
- const bits = this.bits;
-
- let bitsOffset = bits.length - 1;
- while (bitsOffset >= 0 && bits[bitsOffset] === 0) {
- bitsOffset--;
- }
- if (bitsOffset < 0) {
- return null;
- }
-
- const y = Math.floor(bitsOffset / rowSize);
- let x = Math.floor(bitsOffset % rowSize) * 32;
-
- const theBits = bits[bitsOffset];
- let bit = 31;
- while ((theBits >>> bit) === 0) {
- bit--;
- }
- x += bit;
-
- return Int32Array.from([x, y]);
+ return Int32Array.from([left, top, right - left + 1, bottom - top + 1]);
+ }
+
+ /**
+ * This is useful in detecting a corner of a 'pure' barcode.
+ *
+ * @return {@code x,y} coordinate of top-left-most 1 bit, or null if it is all white
+ */
+ public getTopLeftOnBit(): Int32Array {
+ const rowSize = this.rowSize;
+ const bits = this.bits;
+
+ let bitsOffset = 0;
+ while (bitsOffset < bits.length && bits[bitsOffset] === 0) {
+ bitsOffset++;
}
-
- /**
- * @return The width of the matrix
- */
- public getWidth(): number /*int*/ {
- return this.width;
+ if (bitsOffset === bits.length) {
+ return null;
}
+ const y = bitsOffset / rowSize;
+ let x = (bitsOffset % rowSize) * 32;
- /**
- * @return The height of the matrix
- */
- public getHeight(): number /*int*/ {
- return this.height;
+ const theBits = bits[bitsOffset];
+ let bit = 0;
+ while (((theBits << (31 - bit)) & 0xFFFFFFFF) === 0) {
+ bit++;
}
+ x += bit;
+ return Int32Array.from([x, y]);
+ }
- /**
- * @return The row size of the matrix
- */
- public getRowSize(): number /*int*/ {
- return this.rowSize;
- }
+ public getBottomRightOnBit(): Int32Array {
+ const rowSize = this.rowSize;
+ const bits = this.bits;
- /*@Override*/
- public equals(o: Object): boolean {
- if (!(o instanceof BitMatrix)) {
- return false;
- }
- const other = o;
- return this.width === other.width && this.height === other.height && this.rowSize === other.rowSize &&
- Arrays.equals(this.bits, other.bits);
+ let bitsOffset = bits.length - 1;
+ while (bitsOffset >= 0 && bits[bitsOffset] === 0) {
+ bitsOffset--;
}
-
- /*@Override*/
- public hashCode(): int {
- let hash = this.width;
- hash = 31 * hash + this.width;
- hash = 31 * hash + this.height;
- hash = 31 * hash + this.rowSize;
- hash = 31 * hash + Arrays.hashCode(this.bits);
- return hash;
+ if (bitsOffset < 0) {
+ return null;
}
- /**
- * @return string representation using "X" for set and " " for unset bits
- */
- /*@Override*/
- // public toString(): string {
- // return toString(": "X, " ")
- // }
-
- /**
- * @param setString representation of a set bit
- * @param unsetString representation of an unset bit
- * @return string representation of entire matrix utilizing given strings
- */
- // public toString(setString: string = "X ", unsetString: string = " "): string {
- // return this.buildToString(setString, unsetString, "\n")
- // }
-
- /**
- * @param setString representation of a set bit
- * @param unsetString representation of an unset bit
- * @param lineSeparator newline character in string representation
- * @return string representation of entire matrix utilizing given strings and line separator
- * @deprecated call {@link #toString(String,String)} only, which uses \n line separator always
- */
- // @Deprecated
- public toString(setString: string = 'X ', unsetString: string = ' ', lineSeparator: string = '\n'): string {
- return this.buildToString(setString, unsetString, lineSeparator);
- }
+ const y = Math.floor(bitsOffset / rowSize);
+ let x = Math.floor(bitsOffset % rowSize) * 32;
- private buildToString(setString: string, unsetString: string, lineSeparator: string) {
- let result = new StringBuilder();
- // result.append(lineSeparator);
- for (let y = 0, height = this.height; y < height; y++) {
- for (let x = 0, width = this.width; x < width; x++) {
- result.append(this.get(x, y) ? setString : unsetString);
- }
- result.append(lineSeparator);
- }
- return result.toString();
+ const theBits = bits[bitsOffset];
+ let bit = 31;
+ while ((theBits >>> bit) === 0) {
+ bit--;
}
-
- /*@Override*/
- public clone(): BitMatrix {
- return new BitMatrix(this.width, this.height, this.rowSize, this.bits.slice());
+ x += bit;
+
+ return Int32Array.from([x, y]);
+ }
+
+ /**
+ * @return The width of the matrix
+ */
+ public getWidth(): number /*int*/ {
+ return this.width;
+ }
+
+ /**
+ * @return The height of the matrix
+ */
+ public getHeight(): number /*int*/ {
+ return this.height;
+ }
+
+ /**
+ * @return The row size of the matrix
+ */
+ public getRowSize(): number /*int*/ {
+ return this.rowSize;
+ }
+
+ /*@Override*/
+ public equals(o: Object): boolean {
+ if (!(o instanceof BitMatrix)) {
+ return false;
}
+ const other = o;
+ return this.width === other.width && this.height === other.height && this.rowSize === other.rowSize &&
+ Arrays.equals(this.bits, other.bits);
+ }
+
+ /*@Override*/
+ public hashCode(): int {
+ let hash = this.width;
+ hash = 31 * hash + this.width;
+ hash = 31 * hash + this.height;
+ hash = 31 * hash + this.rowSize;
+ hash = 31 * hash + Arrays.hashCode(this.bits);
+ return hash;
+ }
+
+ /**
+ * @return string representation using "X" for set and " " for unset bits
+ */
+ /*@Override*/
+ // public toString(): string {
+ // return toString(": "X, " ")
+ // }
+
+ /**
+ * @param setString representation of a set bit
+ * @param unsetString representation of an unset bit
+ * @return string representation of entire matrix utilizing given strings
+ */
+ // public toString(setString: string = "X ", unsetString: string = " "): string {
+ // return this.buildToString(setString, unsetString, "\n")
+ // }
+
+ /**
+ * @param setString representation of a set bit
+ * @param unsetString representation of an unset bit
+ * @param lineSeparator newline character in string representation
+ * @return string representation of entire matrix utilizing given strings and line separator
+ * @deprecated call {@link #toString(String,String)} only, which uses \n line separator always
+ */
+ // @Deprecated
+ public toString(setString: string = 'X ', unsetString: string = ' ', lineSeparator: string = '\n'): string {
+ return this.buildToString(setString, unsetString, lineSeparator);
+ }
+
+ private buildToString(setString: string, unsetString: string, lineSeparator: string) {
+ let result = new StringBuilder();
+ // result.append(lineSeparator);
+ for (let y = 0, height = this.height; y < height; y++) {
+ for (let x = 0, width = this.width; x < width; x++) {
+ result.append(this.get(x, y) ? setString : unsetString);
+ }
+ result.append(lineSeparator);
+ }
+ return result.toString();
+ }
+
+ /*@Override*/
+ public clone(): BitMatrix {
+ return new BitMatrix(this.width, this.height, this.rowSize, this.bits.slice());
+ }
}
diff --git a/src/core/common/BitSource.ts b/src/core/common/BitSource.ts
index bbfb9bb9..e0880e2b 100644
--- a/src/core/common/BitSource.ts
+++ b/src/core/common/BitSource.ts
@@ -30,96 +30,96 @@ import IllegalArgumentException from '../IllegalArgumentException';
*/
export default class BitSource {
- private byteOffset: number; /*int*/
- private bitOffset: number; /*int*/
-
- /**
- * @param bytes bytes from which this will read bits. Bits will be read from the first byte first.
- * Bits are read within a byte from most-significant to least-significant bit.
- */
- public constructor(private bytes: Uint8Array) {
- this.byteOffset = 0;
- this.bitOffset = 0;
+ private byteOffset: number; /*int*/
+ private bitOffset: number; /*int*/
+
+ /**
+ * @param bytes bytes from which this will read bits. Bits will be read from the first byte first.
+ * Bits are read within a byte from most-significant to least-significant bit.
+ */
+ public constructor(private bytes: Uint8Array) {
+ this.byteOffset = 0;
+ this.bitOffset = 0;
+ }
+
+ /**
+ * @return index of next bit in current byte which would be read by the next call to {@link #readBits(int)}.
+ */
+ public getBitOffset(): number /*int*/ {
+ return this.bitOffset;
+ }
+
+ /**
+ * @return index of next byte in input byte array which would be read by the next call to {@link #readBits(int)}.
+ */
+ public getByteOffset(): number /*int*/ {
+ return this.byteOffset;
+ }
+
+ /**
+ * @param numBits number of bits to read
+ * @return int representing the bits read. The bits will appear as the least-significant
+ * bits of the int
+ * @throws IllegalArgumentException if numBits isn't in [1,32] or more than is available
+ */
+ public readBits(numBits: number /*int*/): number /*int*/ {
+ if (numBits < 1 || numBits > 32 || numBits > this.available()) {
+ throw new IllegalArgumentException('' + numBits);
}
- /**
- * @return index of next bit in current byte which would be read by the next call to {@link #readBits(int)}.
- */
- public getBitOffset(): number /*int*/ {
- return this.bitOffset;
- }
+ let result = 0;
- /**
- * @return index of next byte in input byte array which would be read by the next call to {@link #readBits(int)}.
- */
- public getByteOffset(): number /*int*/ {
- return this.byteOffset;
- }
+ let bitOffset = this.bitOffset;
+ let byteOffset = this.byteOffset;
+
+ const bytes = this.bytes;
+ // First, read remainder from current byte
+ if (bitOffset > 0) {
+ const bitsLeft = 8 - bitOffset;
+ const toRead = numBits < bitsLeft ? numBits : bitsLeft;
+ const bitsToNotRead = bitsLeft - toRead;
+ const mask = (0xFF >> (8 - toRead)) << bitsToNotRead;
- /**
- * @param numBits number of bits to read
- * @return int representing the bits read. The bits will appear as the least-significant
- * bits of the int
- * @throws IllegalArgumentException if numBits isn't in [1,32] or more than is available
- */
- public readBits(numBits: number /*int*/): number /*int*/ {
- if (numBits < 1 || numBits > 32 || numBits > this.available()) {
- throw new IllegalArgumentException('' + numBits);
- }
-
- let result = 0;
-
- let bitOffset = this.bitOffset;
- let byteOffset = this.byteOffset;
-
- const bytes = this.bytes;
- // First, read remainder from current byte
- if (bitOffset > 0) {
- const bitsLeft = 8 - bitOffset;
- const toRead = numBits < bitsLeft ? numBits : bitsLeft;
- const bitsToNotRead = bitsLeft - toRead;
- const mask = (0xFF >> (8 - toRead)) << bitsToNotRead;
-
- result = (bytes[byteOffset] & mask) >> bitsToNotRead;
- numBits -= toRead;
- bitOffset += toRead;
-
- if (bitOffset === 8) {
- bitOffset = 0;
- byteOffset++;
- }
- }
-
- // Next read whole bytes
- if (numBits > 0) {
-
- while (numBits >= 8) {
- result = (result << 8) | (bytes[byteOffset] & 0xFF);
- byteOffset++;
- numBits -= 8;
- }
-
- // Finally read a partial byte
- if (numBits > 0) {
- const bitsToNotRead = 8 - numBits;
- const mask = (0xFF >> bitsToNotRead) << bitsToNotRead;
-
- result = (result << numBits) | ((bytes[byteOffset] & mask) >> bitsToNotRead);
- bitOffset += numBits;
- }
- }
-
- this.bitOffset = bitOffset;
- this.byteOffset = byteOffset;
-
- return result;
+ result = (bytes[byteOffset] & mask) >> bitsToNotRead;
+ numBits -= toRead;
+ bitOffset += toRead;
+
+ if (bitOffset === 8) {
+ bitOffset = 0;
+ byteOffset++;
+ }
}
- /**
- * @return number of bits that can be read successfully
- */
- public available(): number /*int*/ {
- return 8 * (this.bytes.length - this.byteOffset) - this.bitOffset;
+ // Next read whole bytes
+ if (numBits > 0) {
+
+ while (numBits >= 8) {
+ result = (result << 8) | (bytes[byteOffset] & 0xFF);
+ byteOffset++;
+ numBits -= 8;
+ }
+
+ // Finally read a partial byte
+ if (numBits > 0) {
+ const bitsToNotRead = 8 - numBits;
+ const mask = (0xFF >> bitsToNotRead) << bitsToNotRead;
+
+ result = (result << numBits) | ((bytes[byteOffset] & mask) >> bitsToNotRead);
+ bitOffset += numBits;
+ }
}
+ this.bitOffset = bitOffset;
+ this.byteOffset = byteOffset;
+
+ return result;
+ }
+
+ /**
+ * @return number of bits that can be read successfully
+ */
+ public available(): number /*int*/ {
+ return 8 * (this.bytes.length - this.byteOffset) - this.bitOffset;
+ }
+
}
diff --git a/src/core/common/CharacterSetECI.ts b/src/core/common/CharacterSetECI.ts
index 3b521e76..d46a4864 100644
--- a/src/core/common/CharacterSetECI.ts
+++ b/src/core/common/CharacterSetECI.ts
@@ -23,33 +23,33 @@ import FormatException from '../FormatException';
/*import java.util.Map;*/
export enum CharacterSetValueIdentifiers {
- Cp437,
- ISO8859_1,
- ISO8859_2,
- ISO8859_3,
- ISO8859_4,
- ISO8859_5,
- ISO8859_6,
- ISO8859_7,
- ISO8859_8,
- ISO8859_9,
- ISO8859_10,
- ISO8859_11,
- ISO8859_13,
- ISO8859_14,
- ISO8859_15,
- ISO8859_16,
- SJIS,
- Cp1250,
- Cp1251,
- Cp1252,
- Cp1256,
- UnicodeBigUnmarked,
- UTF8,
- ASCII,
- Big5,
- GB18030,
- EUC_KR,
+ Cp437,
+ ISO8859_1,
+ ISO8859_2,
+ ISO8859_3,
+ ISO8859_4,
+ ISO8859_5,
+ ISO8859_6,
+ ISO8859_7,
+ ISO8859_8,
+ ISO8859_9,
+ ISO8859_10,
+ ISO8859_11,
+ ISO8859_13,
+ ISO8859_14,
+ ISO8859_15,
+ ISO8859_16,
+ SJIS,
+ Cp1250,
+ Cp1251,
+ Cp1252,
+ Cp1256,
+ UnicodeBigUnmarked,
+ UTF8,
+ ASCII,
+ Big5,
+ GB18030,
+ EUC_KR,
}
/**
@@ -61,198 +61,198 @@ export enum CharacterSetValueIdentifiers {
export default class CharacterSetECI {
- private static VALUE_IDENTIFIER_TO_ECI = new Map();
- private static VALUES_TO_ECI = new Map();
- private static NAME_TO_ECI = new Map();
+ private static VALUE_IDENTIFIER_TO_ECI = new Map();
+ private static VALUES_TO_ECI = new Map();
+ private static NAME_TO_ECI = new Map();
- // Enum name is a Java encoding valid for java.lang and java.io
- // TYPESCRIPTPORT: changed the main label for ISO as the TextEncoder did not recognized them in the form from java
- // (eg ISO8859_1 must be ISO88591 or ISO8859-1 or ISO-8859-1)
- // later on: well, except 16 wich does not work with ISO885916 so used ISO-8859-1 form for default
- public static readonly Cp437 = new CharacterSetECI(
- CharacterSetValueIdentifiers.Cp437, Int32Array.from([0, 2]), 'Cp437');
+ // Enum name is a Java encoding valid for java.lang and java.io
+ // TYPESCRIPTPORT: changed the main label for ISO as the TextEncoder did not recognized them in the form from java
+ // (eg ISO8859_1 must be ISO88591 or ISO8859-1 or ISO-8859-1)
+ // later on: well, except 16 wich does not work with ISO885916 so used ISO-8859-1 form for default
+ public static readonly Cp437 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.Cp437, Int32Array.from([0, 2]), 'Cp437');
- public static readonly ISO8859_1 = new CharacterSetECI(
- CharacterSetValueIdentifiers.ISO8859_1, Int32Array.from([1, 3]), 'ISO-8859-1', 'ISO88591', 'ISO8859_1');
+ public static readonly ISO8859_1 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.ISO8859_1, Int32Array.from([1, 3]), 'ISO-8859-1', 'ISO88591', 'ISO8859_1');
- public static readonly ISO8859_2 = new CharacterSetECI(
- CharacterSetValueIdentifiers.ISO8859_2, 4, 'ISO-8859-2', 'ISO88592', 'ISO8859_2');
+ public static readonly ISO8859_2 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.ISO8859_2, 4, 'ISO-8859-2', 'ISO88592', 'ISO8859_2');
- public static readonly ISO8859_3 = new CharacterSetECI(
- CharacterSetValueIdentifiers.ISO8859_3, 5, 'ISO-8859-3', 'ISO88593', 'ISO8859_3');
+ public static readonly ISO8859_3 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.ISO8859_3, 5, 'ISO-8859-3', 'ISO88593', 'ISO8859_3');
- public static readonly ISO8859_4 = new CharacterSetECI(
- CharacterSetValueIdentifiers.ISO8859_4, 6, 'ISO-8859-4', 'ISO88594', 'ISO8859_4');
+ public static readonly ISO8859_4 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.ISO8859_4, 6, 'ISO-8859-4', 'ISO88594', 'ISO8859_4');
- public static readonly ISO8859_5 = new CharacterSetECI(
- CharacterSetValueIdentifiers.ISO8859_5, 7, 'ISO-8859-5', 'ISO88595', 'ISO8859_5');
+ public static readonly ISO8859_5 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.ISO8859_5, 7, 'ISO-8859-5', 'ISO88595', 'ISO8859_5');
- public static readonly ISO8859_6 = new CharacterSetECI(
- CharacterSetValueIdentifiers.ISO8859_6, 8, 'ISO-8859-6', 'ISO88596', 'ISO8859_6');
+ public static readonly ISO8859_6 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.ISO8859_6, 8, 'ISO-8859-6', 'ISO88596', 'ISO8859_6');
- public static readonly ISO8859_7 = new CharacterSetECI(
- CharacterSetValueIdentifiers.ISO8859_7, 9, 'ISO-8859-7', 'ISO88597', 'ISO8859_7');
+ public static readonly ISO8859_7 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.ISO8859_7, 9, 'ISO-8859-7', 'ISO88597', 'ISO8859_7');
- public static readonly ISO8859_8 = new CharacterSetECI(
- CharacterSetValueIdentifiers.ISO8859_8, 10, 'ISO-8859-8', 'ISO88598', 'ISO8859_8');
+ public static readonly ISO8859_8 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.ISO8859_8, 10, 'ISO-8859-8', 'ISO88598', 'ISO8859_8');
- public static readonly ISO8859_9 = new CharacterSetECI(
- CharacterSetValueIdentifiers.ISO8859_9, 11, 'ISO-8859-9', 'ISO88599', 'ISO8859_9');
+ public static readonly ISO8859_9 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.ISO8859_9, 11, 'ISO-8859-9', 'ISO88599', 'ISO8859_9');
- public static readonly ISO8859_10 = new CharacterSetECI(
- CharacterSetValueIdentifiers.ISO8859_10, 12, 'ISO-8859-10', 'ISO885910', 'ISO8859_10');
+ public static readonly ISO8859_10 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.ISO8859_10, 12, 'ISO-8859-10', 'ISO885910', 'ISO8859_10');
- public static readonly ISO8859_11 = new CharacterSetECI(
- CharacterSetValueIdentifiers.ISO8859_11, 13, 'ISO-8859-11', 'ISO885911', 'ISO8859_11');
+ public static readonly ISO8859_11 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.ISO8859_11, 13, 'ISO-8859-11', 'ISO885911', 'ISO8859_11');
- public static readonly ISO8859_13 = new CharacterSetECI(
- CharacterSetValueIdentifiers.ISO8859_13, 15, 'ISO-8859-13', 'ISO885913', 'ISO8859_13');
+ public static readonly ISO8859_13 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.ISO8859_13, 15, 'ISO-8859-13', 'ISO885913', 'ISO8859_13');
- public static readonly ISO8859_14 = new CharacterSetECI(
- CharacterSetValueIdentifiers.ISO8859_14, 16, 'ISO-8859-14', 'ISO885914', 'ISO8859_14');
+ public static readonly ISO8859_14 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.ISO8859_14, 16, 'ISO-8859-14', 'ISO885914', 'ISO8859_14');
- public static readonly ISO8859_15 = new CharacterSetECI(
- CharacterSetValueIdentifiers.ISO8859_15, 17, 'ISO-8859-15', 'ISO885915', 'ISO8859_15');
+ public static readonly ISO8859_15 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.ISO8859_15, 17, 'ISO-8859-15', 'ISO885915', 'ISO8859_15');
- public static readonly ISO8859_16 = new CharacterSetECI(
- CharacterSetValueIdentifiers.ISO8859_16, 18, 'ISO-8859-16', 'ISO885916', 'ISO8859_16');
+ public static readonly ISO8859_16 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.ISO8859_16, 18, 'ISO-8859-16', 'ISO885916', 'ISO8859_16');
- public static readonly SJIS = new CharacterSetECI(
- CharacterSetValueIdentifiers.SJIS, 20, 'SJIS', 'Shift_JIS');
+ public static readonly SJIS = new CharacterSetECI(
+ CharacterSetValueIdentifiers.SJIS, 20, 'SJIS', 'Shift_JIS');
- public static readonly Cp1250 = new CharacterSetECI(
- CharacterSetValueIdentifiers.Cp1250, 21, 'Cp1250', 'windows-1250');
+ public static readonly Cp1250 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.Cp1250, 21, 'Cp1250', 'windows-1250');
- public static readonly Cp1251 = new CharacterSetECI(
- CharacterSetValueIdentifiers.Cp1251, 22, 'Cp1251', 'windows-1251');
+ public static readonly Cp1251 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.Cp1251, 22, 'Cp1251', 'windows-1251');
- public static readonly Cp1252 = new CharacterSetECI(
- CharacterSetValueIdentifiers.Cp1252, 23, 'Cp1252', 'windows-1252');
+ public static readonly Cp1252 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.Cp1252, 23, 'Cp1252', 'windows-1252');
- public static readonly Cp1256 = new CharacterSetECI(
- CharacterSetValueIdentifiers.Cp1256, 24, 'Cp1256', 'windows-1256');
+ public static readonly Cp1256 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.Cp1256, 24, 'Cp1256', 'windows-1256');
- public static readonly UnicodeBigUnmarked = new CharacterSetECI(
- CharacterSetValueIdentifiers.UnicodeBigUnmarked, 25, 'UnicodeBigUnmarked', 'UTF-16BE', 'UnicodeBig');
+ public static readonly UnicodeBigUnmarked = new CharacterSetECI(
+ CharacterSetValueIdentifiers.UnicodeBigUnmarked, 25, 'UnicodeBigUnmarked', 'UTF-16BE', 'UnicodeBig');
- public static readonly UTF8 = new CharacterSetECI(
- CharacterSetValueIdentifiers.UTF8, 26, 'UTF8', 'UTF-8');
+ public static readonly UTF8 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.UTF8, 26, 'UTF8', 'UTF-8');
- public static readonly ASCII = new CharacterSetECI(
- CharacterSetValueIdentifiers.ASCII, Int32Array.from([27, 170]), 'ASCII', 'US-ASCII');
+ public static readonly ASCII = new CharacterSetECI(
+ CharacterSetValueIdentifiers.ASCII, Int32Array.from([27, 170]), 'ASCII', 'US-ASCII');
- public static readonly Big5 = new CharacterSetECI(
- CharacterSetValueIdentifiers.Big5, 28, 'Big5');
+ public static readonly Big5 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.Big5, 28, 'Big5');
- public static readonly GB18030 = new CharacterSetECI(
- CharacterSetValueIdentifiers.GB18030, 29, 'GB18030', 'GB2312', 'EUC_CN', 'GBK');
+ public static readonly GB18030 = new CharacterSetECI(
+ CharacterSetValueIdentifiers.GB18030, 29, 'GB18030', 'GB2312', 'EUC_CN', 'GBK');
- public static readonly EUC_KR = new CharacterSetECI(
- CharacterSetValueIdentifiers.EUC_KR, 30, 'EUC_KR', 'EUC-KR');
+ public static readonly EUC_KR = new CharacterSetECI(
+ CharacterSetValueIdentifiers.EUC_KR, 30, 'EUC_KR', 'EUC-KR');
- public values: Int32Array;
- public otherEncodingNames: string[];
+ public values: Int32Array;
+ public otherEncodingNames: string[];
- public constructor(
- public valueIdentifier: CharacterSetValueIdentifiers,
- valuesParam: Int32Array | number,
- public name: string, ...otherEncodingNames: string[]
- ) {
+ public constructor(
+ public valueIdentifier: CharacterSetValueIdentifiers,
+ valuesParam: Int32Array | number,
+ public name: string, ...otherEncodingNames: string[]
+ ) {
- if (typeof valuesParam === 'number') {
- this.values = Int32Array.from([valuesParam]);
- } else {
- this.values = valuesParam;
- }
-
- this.otherEncodingNames = otherEncodingNames;
-
- CharacterSetECI.VALUE_IDENTIFIER_TO_ECI.set(valueIdentifier, this);
- CharacterSetECI.NAME_TO_ECI.set(name, this);
-
- const values = this.values;
-
- for (let i = 0, length = values.length; i !== length; i++) {
- const v = values[i];
- CharacterSetECI.VALUES_TO_ECI.set(v, this);
- }
- for (const otherName of otherEncodingNames) {
- CharacterSetECI.NAME_TO_ECI.set(otherName, this);
- }
+ if (typeof valuesParam === 'number') {
+ this.values = Int32Array.from([valuesParam]);
+ } else {
+ this.values = valuesParam;
}
- // CharacterSetECI(value: number /*int*/) {
- // this(new Int32Array {value})
- // }
+ this.otherEncodingNames = otherEncodingNames;
- // CharacterSetECI(value: number /*int*/, String... otherEncodingNames) {
- // this.values = new Int32Array {value}
- // this.otherEncodingNames = otherEncodingNames
- // }
+ CharacterSetECI.VALUE_IDENTIFIER_TO_ECI.set(valueIdentifier, this);
+ CharacterSetECI.NAME_TO_ECI.set(name, this);
- // CharacterSetECI(values: Int32Array, String... otherEncodingNames) {
- // this.values = values
- // this.otherEncodingNames = otherEncodingNames
- // }
+ const values = this.values;
- public getValueIdentifier(): CharacterSetValueIdentifiers/*int*/ {
- return this.valueIdentifier;
+ for (let i = 0, length = values.length; i !== length; i++) {
+ const v = values[i];
+ CharacterSetECI.VALUES_TO_ECI.set(v, this);
}
-
- public getName(): string {
- return this.name;
+ for (const otherName of otherEncodingNames) {
+ CharacterSetECI.NAME_TO_ECI.set(otherName, this);
}
-
- public getValue(): number /*int*/ {
- return this.values[0];
+ }
+
+ // CharacterSetECI(value: number /*int*/) {
+ // this(new Int32Array {value})
+ // }
+
+ // CharacterSetECI(value: number /*int*/, String... otherEncodingNames) {
+ // this.values = new Int32Array {value}
+ // this.otherEncodingNames = otherEncodingNames
+ // }
+
+ // CharacterSetECI(values: Int32Array, String... otherEncodingNames) {
+ // this.values = values
+ // this.otherEncodingNames = otherEncodingNames
+ // }
+
+ public getValueIdentifier(): CharacterSetValueIdentifiers/*int*/ {
+ return this.valueIdentifier;
+ }
+
+ public getName(): string {
+ return this.name;
+ }
+
+ public getValue(): number /*int*/ {
+ return this.values[0];
+ }
+
+ /**
+ * @param value character set ECI value
+ * @return {@code CharacterSetECI} representing ECI of given value, or null if it is legal but
+ * unsupported
+ * @throws FormatException if ECI value is invalid
+ */
+ public static getCharacterSetECIByValue(value: number /*int*/): CharacterSetECI /*throws FormatException*/ {
+
+ if (value < 0 || value >= 900) {
+ throw new FormatException('incorect value');
}
- /**
- * @param value character set ECI value
- * @return {@code CharacterSetECI} representing ECI of given value, or null if it is legal but
- * unsupported
- * @throws FormatException if ECI value is invalid
- */
- public static getCharacterSetECIByValue(value: number /*int*/): CharacterSetECI /*throws FormatException*/ {
+ const characterSet = CharacterSetECI.VALUES_TO_ECI.get(value);
- if (value < 0 || value >= 900) {
- throw new FormatException('incorect value');
- }
-
- const characterSet = CharacterSetECI.VALUES_TO_ECI.get(value);
-
- if (undefined === characterSet) {
- throw new FormatException('incorect value');
- }
-
- return characterSet;
+ if (undefined === characterSet) {
+ throw new FormatException('incorect value');
}
- /**
- * @param name character set ECI encoding name
- * @return CharacterSetECI representing ECI for character encoding, or null if it is legal
- * but unsupported
- */
- public static getCharacterSetECIByName(name: string): CharacterSetECI {
+ return characterSet;
+ }
- const characterSet = CharacterSetECI.NAME_TO_ECI.get(name);
+ /**
+ * @param name character set ECI encoding name
+ * @return CharacterSetECI representing ECI for character encoding, or null if it is legal
+ * but unsupported
+ */
+ public static getCharacterSetECIByName(name: string): CharacterSetECI {
- if (undefined === characterSet) {
- throw new FormatException('incorect value');
- }
+ const characterSet = CharacterSetECI.NAME_TO_ECI.get(name);
- return characterSet;
+ if (undefined === characterSet) {
+ throw new FormatException('incorect value');
}
- public equals(o: CharacterSetECI) {
+ return characterSet;
+ }
- if (!(o instanceof CharacterSetECI)) {
- return false;
- }
+ public equals(o: CharacterSetECI) {
- const other = o as CharacterSetECI;
-
- return this.getName() === other.getName();
+ if (!(o instanceof CharacterSetECI)) {
+ return false;
}
+ const other = o as CharacterSetECI;
+
+ return this.getName() === other.getName();
+ }
+
}
diff --git a/src/core/common/DecoderResult.ts b/src/core/common/DecoderResult.ts
index dadb9d59..5b6008f3 100644
--- a/src/core/common/DecoderResult.ts
+++ b/src/core/common/DecoderResult.ts
@@ -27,114 +27,114 @@
*/
export default class DecoderResult {
- private numBits: number; /*int*/
- private errorsCorrected: number; /*Integer*/
- private erasures: number; /*Integer*/
- private other: any;
-
- // public constructor(rawBytes: Uint8Array,
- // text: string,
- // List byteSegments,
- // String ecLevel) {
- // this(rawBytes, text, byteSegments, ecLevel, -1, -1)
- // }
-
- public constructor(private rawBytes: Uint8Array,
- private text: string,
- private byteSegments: Uint8Array[],
- private ecLevel: string,
- private structuredAppendSequenceNumber: number /*int*/ = -1,
- private structuredAppendParity: number /*int*/ = -1) {
- this.numBits = (rawBytes === undefined || rawBytes === null) ? 0 : 8 * rawBytes.length;
- }
-
- /**
- * @return raw bytes representing the result, or {@code null} if not applicable
- */
- public getRawBytes(): Uint8Array {
- return this.rawBytes;
- }
-
- /**
- * @return how many bits of {@link #getRawBytes()} are valid; typically 8 times its length
- * @since 3.3.0
- */
- public getNumBits(): number /*int*/ {
- return this.numBits;
- }
-
- /**
- * @param numBits overrides the number of bits that are valid in {@link #getRawBytes()}
- * @since 3.3.0
- */
- public setNumBits(numBits: number /*int*/): void {
- this.numBits = numBits;
- }
-
- /**
- * @return text representation of the result
- */
- public getText(): string {
- return this.text;
- }
-
- /**
- * @return list of byte segments in the result, or {@code null} if not applicable
- */
- public getByteSegments(): Uint8Array[] {
- return this.byteSegments;
- }
-
- /**
- * @return name of error correction level used, or {@code null} if not applicable
- */
- public getECLevel(): string {
- return this.ecLevel;
- }
-
- /**
- * @return number of errors corrected, or {@code null} if not applicable
- */
- public getErrorsCorrected(): number/*Integer*/ {
- return this.errorsCorrected;
- }
-
- public setErrorsCorrected(errorsCorrected: number/*Integer*/): void {
- this.errorsCorrected = errorsCorrected;
- }
-
- /**
- * @return number of erasures corrected, or {@code null} if not applicable
- */
- public getErasures(): number/*Integer*/ {
- return this.erasures;
- }
-
- public setErasures(erasures: number/*Integer*/): void {
- this.erasures = erasures;
- }
-
- /**
- * @return arbitrary additional metadata
- */
- public getOther(): any {
- return this.other;
- }
-
- public setOther(other: any): void {
- this.other = other;
- }
-
- public hasStructuredAppend(): boolean {
- return this.structuredAppendParity >= 0 && this.structuredAppendSequenceNumber >= 0;
- }
-
- public getStructuredAppendParity(): number /*int*/ {
- return this.structuredAppendParity;
- }
-
- public getStructuredAppendSequenceNumber(): number /*int*/ {
- return this.structuredAppendSequenceNumber;
- }
+ private numBits: number; /*int*/
+ private errorsCorrected: number; /*Integer*/
+ private erasures: number; /*Integer*/
+ private other: any;
+
+ // public constructor(rawBytes: Uint8Array,
+ // text: string,
+ // List byteSegments,
+ // String ecLevel) {
+ // this(rawBytes, text, byteSegments, ecLevel, -1, -1)
+ // }
+
+ public constructor(private rawBytes: Uint8Array,
+ private text: string,
+ private byteSegments: Uint8Array[],
+ private ecLevel: string,
+ private structuredAppendSequenceNumber: number /*int*/ = -1,
+ private structuredAppendParity: number /*int*/ = -1) {
+ this.numBits = (rawBytes === undefined || rawBytes === null) ? 0 : 8 * rawBytes.length;
+ }
+
+ /**
+ * @return raw bytes representing the result, or {@code null} if not applicable
+ */
+ public getRawBytes(): Uint8Array {
+ return this.rawBytes;
+ }
+
+ /**
+ * @return how many bits of {@link #getRawBytes()} are valid; typically 8 times its length
+ * @since 3.3.0
+ */
+ public getNumBits(): number /*int*/ {
+ return this.numBits;
+ }
+
+ /**
+ * @param numBits overrides the number of bits that are valid in {@link #getRawBytes()}
+ * @since 3.3.0
+ */
+ public setNumBits(numBits: number /*int*/): void {
+ this.numBits = numBits;
+ }
+
+ /**
+ * @return text representation of the result
+ */
+ public getText(): string {
+ return this.text;
+ }
+
+ /**
+ * @return list of byte segments in the result, or {@code null} if not applicable
+ */
+ public getByteSegments(): Uint8Array[] {
+ return this.byteSegments;
+ }
+
+ /**
+ * @return name of error correction level used, or {@code null} if not applicable
+ */
+ public getECLevel(): string {
+ return this.ecLevel;
+ }
+
+ /**
+ * @return number of errors corrected, or {@code null} if not applicable
+ */
+ public getErrorsCorrected(): number/*Integer*/ {
+ return this.errorsCorrected;
+ }
+
+ public setErrorsCorrected(errorsCorrected: number/*Integer*/): void {
+ this.errorsCorrected = errorsCorrected;
+ }
+
+ /**
+ * @return number of erasures corrected, or {@code null} if not applicable
+ */
+ public getErasures(): number/*Integer*/ {
+ return this.erasures;
+ }
+
+ public setErasures(erasures: number/*Integer*/): void {
+ this.erasures = erasures;
+ }
+
+ /**
+ * @return arbitrary additional metadata
+ */
+ public getOther(): any {
+ return this.other;
+ }
+
+ public setOther(other: any): void {
+ this.other = other;
+ }
+
+ public hasStructuredAppend(): boolean {
+ return this.structuredAppendParity >= 0 && this.structuredAppendSequenceNumber >= 0;
+ }
+
+ public getStructuredAppendParity(): number /*int*/ {
+ return this.structuredAppendParity;
+ }
+
+ public getStructuredAppendSequenceNumber(): number /*int*/ {
+ return this.structuredAppendSequenceNumber;
+ }
}
diff --git a/src/core/common/DefaultGridSampler.ts b/src/core/common/DefaultGridSampler.ts
index 35c8189c..8d632fc5 100644
--- a/src/core/common/DefaultGridSampler.ts
+++ b/src/core/common/DefaultGridSampler.ts
@@ -29,66 +29,66 @@ import { float } from '../../customTypings';
*/
export default class DefaultGridSampler extends GridSampler {
- /*@Override*/
- public sampleGrid(image: BitMatrix,
- dimensionX: number /*int*/,
- dimensionY: number /*int*/,
- p1ToX: number/*float*/, p1ToY: number/*float*/,
- p2ToX: number/*float*/, p2ToY: number/*float*/,
- p3ToX: number/*float*/, p3ToY: number/*float*/,
- p4ToX: number/*float*/, p4ToY: number/*float*/,
- p1FromX: number/*float*/, p1FromY: number/*float*/,
- p2FromX: number/*float*/, p2FromY: number/*float*/,
- p3FromX: number/*float*/, p3FromY: number/*float*/,
- p4FromX: number/*float*/, p4FromY: number/*float*/): BitMatrix /*throws NotFoundException*/ {
+ /*@Override*/
+ public sampleGrid(image: BitMatrix,
+ dimensionX: number /*int*/,
+ dimensionY: number /*int*/,
+ p1ToX: number/*float*/, p1ToY: number/*float*/,
+ p2ToX: number/*float*/, p2ToY: number/*float*/,
+ p3ToX: number/*float*/, p3ToY: number/*float*/,
+ p4ToX: number/*float*/, p4ToY: number/*float*/,
+ p1FromX: number/*float*/, p1FromY: number/*float*/,
+ p2FromX: number/*float*/, p2FromY: number/*float*/,
+ p3FromX: number/*float*/, p3FromY: number/*float*/,
+ p4FromX: number/*float*/, p4FromY: number/*float*/): BitMatrix /*throws NotFoundException*/ {
- const transform = PerspectiveTransform.quadrilateralToQuadrilateral(
- p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY,
- p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY);
+ const transform = PerspectiveTransform.quadrilateralToQuadrilateral(
+ p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY,
+ p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY);
- return this.sampleGridWithTransform(image, dimensionX, dimensionY, transform);
- }
+ return this.sampleGridWithTransform(image, dimensionX, dimensionY, transform);
+ }
- /*@Override*/
- public sampleGridWithTransform(image: BitMatrix,
- dimensionX: number /*int*/,
- dimensionY: number /*int*/,
- transform: PerspectiveTransform): BitMatrix /*throws NotFoundException*/ {
- if (dimensionX <= 0 || dimensionY <= 0) {
- throw new NotFoundException();
- }
- const bits = new BitMatrix(dimensionX, dimensionY);
- const points = new Float32Array(2 * dimensionX);
- for (let y = 0; y < dimensionY; y++) {
- const max = points.length;
- const iValue: number /*float*/ = y + 0.5;
- for (let x = 0; x < max; x += 2) {
- points[x] = (x / 2) + 0.5;
- points[x + 1] = iValue;
- }
- transform.transformPoints(points);
- // Quick check to see if points transformed to something inside the image
- // sufficient to check the endpoints
- GridSampler.checkAndNudgePoints(image, points);
- try {
- for (let x = 0; x < max; x += 2) {
- if (image.get(Math.floor(points[x]), Math.floor(points[x + 1]))) {
- // Black(-ish) pixel
- bits.set(x / 2, y);
- }
- }
- } catch (aioobe/*: ArrayIndexOutOfBoundsException*/) {
- // This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting
- // transform gets "twisted" such that it maps a straight line of points to a set of points
- // whose endpoints are in bounds, but others are not. There is probably some mathematical
- // way to detect this about the transformation that I don't know yet.
- // This results in an ugly runtime exception despite our clever checks above -- can't have
- // that. We could check each point's coordinates but that feels duplicative. We settle for
- // catching and wrapping ArrayIndexOutOfBoundsException.
- throw new NotFoundException();
- }
+ /*@Override*/
+ public sampleGridWithTransform(image: BitMatrix,
+ dimensionX: number /*int*/,
+ dimensionY: number /*int*/,
+ transform: PerspectiveTransform): BitMatrix /*throws NotFoundException*/ {
+ if (dimensionX <= 0 || dimensionY <= 0) {
+ throw new NotFoundException();
+ }
+ const bits = new BitMatrix(dimensionX, dimensionY);
+ const points = new Float32Array(2 * dimensionX);
+ for (let y = 0; y < dimensionY; y++) {
+ const max = points.length;
+ const iValue: number /*float*/ = y + 0.5;
+ for (let x = 0; x < max; x += 2) {
+ points[x] = (x / 2) + 0.5;
+ points[x + 1] = iValue;
+ }
+ transform.transformPoints(points);
+ // Quick check to see if points transformed to something inside the image
+ // sufficient to check the endpoints
+ GridSampler.checkAndNudgePoints(image, points);
+ try {
+ for (let x = 0; x < max; x += 2) {
+ if (image.get(Math.floor(points[x]), Math.floor(points[x + 1]))) {
+ // Black(-ish) pixel
+ bits.set(x / 2, y);
+ }
}
- return bits;
+ } catch (aioobe/*: ArrayIndexOutOfBoundsException*/) {
+ // This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting
+ // transform gets "twisted" such that it maps a straight line of points to a set of points
+ // whose endpoints are in bounds, but others are not. There is probably some mathematical
+ // way to detect this about the transformation that I don't know yet.
+ // This results in an ugly runtime exception despite our clever checks above -- can't have
+ // that. We could check each point's coordinates but that feels duplicative. We settle for
+ // catching and wrapping ArrayIndexOutOfBoundsException.
+ throw new NotFoundException();
+ }
}
+ return bits;
+ }
}
diff --git a/src/core/common/DetectorResult.ts b/src/core/common/DetectorResult.ts
index ceb696b1..d526764b 100644
--- a/src/core/common/DetectorResult.ts
+++ b/src/core/common/DetectorResult.ts
@@ -28,20 +28,20 @@ import BitMatrix from './BitMatrix';
*/
export default class DetectorResult {
- private bits: BitMatrix;
- private points: Array;
+ private bits: BitMatrix;
+ private points: Array;
- public constructor(bits: BitMatrix, points: Array) {
- this.bits = bits;
- this.points = points;
- }
+ public constructor(bits: BitMatrix, points: Array) {
+ this.bits = bits;
+ this.points = points;
+ }
- public getBits(): BitMatrix {
- return this.bits;
- }
+ public getBits(): BitMatrix {
+ return this.bits;
+ }
- public getPoints(): Array {
- return this.points;
- }
+ public getPoints(): Array {
+ return this.points;
+ }
}
diff --git a/src/core/common/GlobalHistogramBinarizer.ts b/src/core/common/GlobalHistogramBinarizer.ts
index b59f0528..b86b7bda 100644
--- a/src/core/common/GlobalHistogramBinarizer.ts
+++ b/src/core/common/GlobalHistogramBinarizer.ts
@@ -36,173 +36,173 @@ import NotFoundException from '../NotFoundException';
*/
export default class GlobalHistogramBinarizer extends Binarizer {
- private static LUMINANCE_BITS = 5;
- private static LUMINANCE_SHIFT = 8 - GlobalHistogramBinarizer.LUMINANCE_BITS;
- private static LUMINANCE_BUCKETS = 1 << GlobalHistogramBinarizer.LUMINANCE_BITS;
- private static EMPTY = Uint8ClampedArray.from([0]);
-
- private luminances: Uint8ClampedArray;
- private buckets: Int32Array;
-
- public constructor(source: LuminanceSource) {
- super(source);
- this.luminances = GlobalHistogramBinarizer.EMPTY;
- this.buckets = new Int32Array(GlobalHistogramBinarizer.LUMINANCE_BUCKETS);
+ private static LUMINANCE_BITS = 5;
+ private static LUMINANCE_SHIFT = 8 - GlobalHistogramBinarizer.LUMINANCE_BITS;
+ private static LUMINANCE_BUCKETS = 1 << GlobalHistogramBinarizer.LUMINANCE_BITS;
+ private static EMPTY = Uint8ClampedArray.from([0]);
+
+ private luminances: Uint8ClampedArray;
+ private buckets: Int32Array;
+
+ public constructor(source: LuminanceSource) {
+ super(source);
+ this.luminances = GlobalHistogramBinarizer.EMPTY;
+ this.buckets = new Int32Array(GlobalHistogramBinarizer.LUMINANCE_BUCKETS);
+ }
+
+ // Applies simple sharpening to the row data to improve performance of the 1D Readers.
+ /*@Override*/
+ public getBlackRow(y: number /*int*/, row: BitArray): BitArray /*throws NotFoundException*/ {
+ const source = this.getLuminanceSource();
+ const width = source.getWidth();
+ if (row === undefined || row === null || row.getSize() < width) {
+ row = new BitArray(width);
+ } else {
+ row.clear();
}
- // Applies simple sharpening to the row data to improve performance of the 1D Readers.
- /*@Override*/
- public getBlackRow(y: number /*int*/, row: BitArray): BitArray /*throws NotFoundException*/ {
- const source = this.getLuminanceSource();
- const width = source.getWidth();
- if (row === undefined || row === null || row.getSize() < width) {
- row = new BitArray(width);
- } else {
- row.clear();
- }
-
- this.initArrays(width);
- const localLuminances = source.getRow(y, this.luminances);
- const localBuckets = this.buckets;
- for (let x = 0; x < width; x++) {
- localBuckets[(localLuminances[x] & 0xff) >> GlobalHistogramBinarizer.LUMINANCE_SHIFT]++;
- }
- const blackPoint = GlobalHistogramBinarizer.estimateBlackPoint(localBuckets);
-
- if (width < 3) {
- // Special case for very small images
- for (let x = 0; x < width; x++) {
- if ((localLuminances[x] & 0xff) < blackPoint) {
- row.set(x);
- }
- }
- } else {
- let left = localLuminances[0] & 0xff;
- let center = localLuminances[1] & 0xff;
- for (let x = 1; x < width - 1; x++) {
- const right = localLuminances[x + 1] & 0xff;
- // A simple -1 4 -1 box filter with a weight of 2.
- if (((center * 4) - left - right) / 2 < blackPoint) {
- row.set(x);
- }
- left = center;
- center = right;
- }
- }
- return row;
+ this.initArrays(width);
+ const localLuminances = source.getRow(y, this.luminances);
+ const localBuckets = this.buckets;
+ for (let x = 0; x < width; x++) {
+ localBuckets[(localLuminances[x] & 0xff) >> GlobalHistogramBinarizer.LUMINANCE_SHIFT]++;
}
+ const blackPoint = GlobalHistogramBinarizer.estimateBlackPoint(localBuckets);
- // Does not sharpen the data, as this call is intended to only be used by 2D Readers.
- /*@Override*/
- public getBlackMatrix(): BitMatrix /*throws NotFoundException*/ {
- const source = this.getLuminanceSource();
- const width = source.getWidth();
- const height = source.getHeight();
- const matrix = new BitMatrix(width, height);
-
- // Quickly calculates the histogram by sampling four rows from the image. This proved to be
- // more robust on the blackbox tests than sampling a diagonal as we used to do.
- this.initArrays(width);
- const localBuckets = this.buckets;
- for (let y = 1; y < 5; y++) {
- const row = Math.floor((height * y) / 5);
- const localLuminances = source.getRow(row, this.luminances);
- const right = Math.floor((width * 4) / 5);
- for (let x = Math.floor(width / 5); x < right; x++) {
- const pixel = localLuminances[x] & 0xff;
- localBuckets[pixel >> GlobalHistogramBinarizer.LUMINANCE_SHIFT]++;
- }
+ if (width < 3) {
+ // Special case for very small images
+ for (let x = 0; x < width; x++) {
+ if ((localLuminances[x] & 0xff) < blackPoint) {
+ row.set(x);
}
- const blackPoint = GlobalHistogramBinarizer.estimateBlackPoint(localBuckets);
-
- // We delay reading the entire image luminance until the black point estimation succeeds.
- // Although we end up reading four rows twice, it is consistent with our motto of
- // "fail quickly" which is necessary for continuous scanning.
- const localLuminances = source.getMatrix();
- for (let y = 0; y < height; y++) {
- const offset = y * width;
- for (let x = 0; x < width; x++) {
- const pixel = localLuminances[offset + x] & 0xff;
- if (pixel < blackPoint) {
- matrix.set(x, y);
- }
- }
+ }
+ } else {
+ let left = localLuminances[0] & 0xff;
+ let center = localLuminances[1] & 0xff;
+ for (let x = 1; x < width - 1; x++) {
+ const right = localLuminances[x + 1] & 0xff;
+ // A simple -1 4 -1 box filter with a weight of 2.
+ if (((center * 4) - left - right) / 2 < blackPoint) {
+ row.set(x);
}
-
- return matrix;
+ left = center;
+ center = right;
+ }
}
-
- /*@Override*/
- public createBinarizer(source: LuminanceSource): Binarizer {
- return new GlobalHistogramBinarizer(source);
+ return row;
+ }
+
+ // Does not sharpen the data, as this call is intended to only be used by 2D Readers.
+ /*@Override*/
+ public getBlackMatrix(): BitMatrix /*throws NotFoundException*/ {
+ const source = this.getLuminanceSource();
+ const width = source.getWidth();
+ const height = source.getHeight();
+ const matrix = new BitMatrix(width, height);
+
+ // Quickly calculates the histogram by sampling four rows from the image. This proved to be
+ // more robust on the blackbox tests than sampling a diagonal as we used to do.
+ this.initArrays(width);
+ const localBuckets = this.buckets;
+ for (let y = 1; y < 5; y++) {
+ const row = Math.floor((height * y) / 5);
+ const localLuminances = source.getRow(row, this.luminances);
+ const right = Math.floor((width * 4) / 5);
+ for (let x = Math.floor(width / 5); x < right; x++) {
+ const pixel = localLuminances[x] & 0xff;
+ localBuckets[pixel >> GlobalHistogramBinarizer.LUMINANCE_SHIFT]++;
+ }
}
-
- private initArrays(luminanceSize: number /*int*/): void {
- if (this.luminances.length < luminanceSize) {
- this.luminances = new Uint8ClampedArray(luminanceSize);
- }
- const buckets = this.buckets;
- for (let x = 0; x < GlobalHistogramBinarizer.LUMINANCE_BUCKETS; x++) {
- buckets[x] = 0;
+ const blackPoint = GlobalHistogramBinarizer.estimateBlackPoint(localBuckets);
+
+ // We delay reading the entire image luminance until the black point estimation succeeds.
+ // Although we end up reading four rows twice, it is consistent with our motto of
+ // "fail quickly" which is necessary for continuous scanning.
+ const localLuminances = source.getMatrix();
+ for (let y = 0; y < height; y++) {
+ const offset = y * width;
+ for (let x = 0; x < width; x++) {
+ const pixel = localLuminances[offset + x] & 0xff;
+ if (pixel < blackPoint) {
+ matrix.set(x, y);
}
+ }
}
- private static estimateBlackPoint(buckets: Int32Array): number /*int*/ /*throws NotFoundException*/ {
- // Find the tallest peak in the histogram.
- const numBuckets = buckets.length;
- let maxBucketCount = 0;
- let firstPeak = 0;
- let firstPeakSize = 0;
- for (let x = 0; x < numBuckets; x++) {
- if (buckets[x] > firstPeakSize) {
- firstPeak = x;
- firstPeakSize = buckets[x];
- }
- if (buckets[x] > maxBucketCount) {
- maxBucketCount = buckets[x];
- }
- }
+ return matrix;
+ }
- // Find the second-tallest peak which is somewhat far from the tallest peak.
- let secondPeak = 0;
- let secondPeakScore = 0;
-
- for (let x = 0; x < numBuckets; x++) {
- const distanceToBiggest = x - firstPeak;
- // Encourage more distant second peaks by multiplying by square of distance.
- const score = buckets[x] * distanceToBiggest * distanceToBiggest;
- if (score > secondPeakScore) {
- secondPeak = x;
- secondPeakScore = score;
- }
- }
+ /*@Override*/
+ public createBinarizer(source: LuminanceSource): Binarizer {
+ return new GlobalHistogramBinarizer(source);
+ }
- // Make sure firstPeak corresponds to the black peak.
- if (firstPeak > secondPeak) {
- const temp = firstPeak;
- firstPeak = secondPeak;
- secondPeak = temp;
- }
+ private initArrays(luminanceSize: number /*int*/): void {
+ if (this.luminances.length < luminanceSize) {
+ this.luminances = new Uint8ClampedArray(luminanceSize);
+ }
+ const buckets = this.buckets;
+ for (let x = 0; x < GlobalHistogramBinarizer.LUMINANCE_BUCKETS; x++) {
+ buckets[x] = 0;
+ }
+ }
+
+ private static estimateBlackPoint(buckets: Int32Array): number /*int*/ /*throws NotFoundException*/ {
+ // Find the tallest peak in the histogram.
+ const numBuckets = buckets.length;
+ let maxBucketCount = 0;
+ let firstPeak = 0;
+ let firstPeakSize = 0;
+ for (let x = 0; x < numBuckets; x++) {
+ if (buckets[x] > firstPeakSize) {
+ firstPeak = x;
+ firstPeakSize = buckets[x];
+ }
+ if (buckets[x] > maxBucketCount) {
+ maxBucketCount = buckets[x];
+ }
+ }
- // If there is too little contrast in the image to pick a meaningful black point, throw rather
- // than waste time trying to decode the image, and risk false positives.
- if (secondPeak - firstPeak <= numBuckets / 16) {
- throw new NotFoundException();
- }
+ // Find the second-tallest peak which is somewhat far from the tallest peak.
+ let secondPeak = 0;
+ let secondPeakScore = 0;
+
+ for (let x = 0; x < numBuckets; x++) {
+ const distanceToBiggest = x - firstPeak;
+ // Encourage more distant second peaks by multiplying by square of distance.
+ const score = buckets[x] * distanceToBiggest * distanceToBiggest;
+ if (score > secondPeakScore) {
+ secondPeak = x;
+ secondPeakScore = score;
+ }
+ }
- // Find a valley between them that is low and closer to the white peak.
- let bestValley = secondPeak - 1;
- let bestValleyScore = -1;
- for (let x = secondPeak - 1; x > firstPeak; x--) {
- const fromFirst = x - firstPeak;
- const score = fromFirst * fromFirst * (secondPeak - x) * (maxBucketCount - buckets[x]);
- if (score > bestValleyScore) {
- bestValley = x;
- bestValleyScore = score;
- }
- }
+ // Make sure firstPeak corresponds to the black peak.
+ if (firstPeak > secondPeak) {
+ const temp = firstPeak;
+ firstPeak = secondPeak;
+ secondPeak = temp;
+ }
- return bestValley << GlobalHistogramBinarizer.LUMINANCE_SHIFT;
+ // If there is too little contrast in the image to pick a meaningful black point, throw rather
+ // than waste time trying to decode the image, and risk false positives.
+ if (secondPeak - firstPeak <= numBuckets / 16) {
+ throw new NotFoundException();
}
+ // Find a valley between them that is low and closer to the white peak.
+ let bestValley = secondPeak - 1;
+ let bestValleyScore = -1;
+ for (let x = secondPeak - 1; x > firstPeak; x--) {
+ const fromFirst = x - firstPeak;
+ const score = fromFirst * fromFirst * (secondPeak - x) * (maxBucketCount - buckets[x]);
+ if (score > bestValleyScore) {
+ bestValley = x;
+ bestValleyScore = score;
+ }
+ }
+
+ return bestValley << GlobalHistogramBinarizer.LUMINANCE_SHIFT;
+ }
+
}
diff --git a/src/core/common/GridSampler.ts b/src/core/common/GridSampler.ts
index 7d9c7b1d..4d9934c2 100644
--- a/src/core/common/GridSampler.ts
+++ b/src/core/common/GridSampler.ts
@@ -36,143 +36,143 @@ import NotFoundException from '../NotFoundException';
*/
abstract class GridSampler {
- /**
- * Samples an image for a rectangular matrix of bits of the given dimension. The sampling
- * transformation is determined by the coordinates of 4 points, in the original and transformed
- * image space.
- *
- * @param image image to sample
- * @param dimensionX width of {@link BitMatrix} to sample from image
- * @param dimensionY height of {@link BitMatrix} to sample from image
- * @param p1ToX point 1 preimage X
- * @param p1ToY point 1 preimage Y
- * @param p2ToX point 2 preimage X
- * @param p2ToY point 2 preimage Y
- * @param p3ToX point 3 preimage X
- * @param p3ToY point 3 preimage Y
- * @param p4ToX point 4 preimage X
- * @param p4ToY point 4 preimage Y
- * @param p1FromX point 1 image X
- * @param p1FromY point 1 image Y
- * @param p2FromX point 2 image X
- * @param p2FromY point 2 image Y
- * @param p3FromX point 3 image X
- * @param p3FromY point 3 image Y
- * @param p4FromX point 4 image X
- * @param p4FromY point 4 image Y
- *
- * @return {@link BitMatrix} representing a grid of points sampled from the image within a region
- * defined by the "from" parameters
- *
- * @throws NotFoundException if image can't be sampled, for example, if the transformation defined
- * by the given points is invalid or results in sampling outside the image boundaries
- */
- public abstract sampleGrid(
- image: BitMatrix,
- dimensionX: number /*int*/,
- dimensionY: number /*int*/,
- p1ToX: number/*float*/, p1ToY: number/*float*/,
- p2ToX: number/*float*/, p2ToY: number/*float*/,
- p3ToX: number/*float*/, p3ToY: number/*float*/,
- p4ToX: number/*float*/, p4ToY: number/*float*/,
- p1FromX: number/*float*/, p1FromY: number/*float*/,
- p2FromX: number/*float*/, p2FromY: number/*float*/,
- p3FromX: number/*float*/, p3FromY: number/*float*/,
- p4FromX: number/*float*/, p4FromY: number/*float*/
- ): BitMatrix; /*throws NotFoundException*/
-
- public abstract sampleGridWithTransform(
- image: BitMatrix,
- dimensionX: number /*int*/,
- dimensionY: number /*int*/,
- transform: PerspectiveTransform
- ): BitMatrix; /*throws NotFoundException*/
-
- /**
- *
Checks a set of points that have been transformed to sample points on an image against
- * the image's dimensions to see if the point are even within the image.
- *
- *
This method will actually "nudge" the endpoints back onto the image if they are found to be
- * barely (less than 1 pixel) off the image. This accounts for imperfect detection of finder
- * patterns in an image where the QR Code runs all the way to the image border.
- *
- *
For efficiency, the method will check points from either end of the line until one is found
- * to be within the image. Because the set of points are assumed to be linear, this is valid.
- *
- * @param image image into which the points should map
- * @param points actual points in x1,y1,...,xn,yn form
- * @throws NotFoundException if an endpoint is lies outside the image boundaries
- */
- protected static checkAndNudgePoints(
- image: BitMatrix,
- points: Float32Array
- ): void /*throws NotFoundException*/ {
-
- const width: number /*int*/ = image.getWidth();
- const height: number /*int*/ = image.getHeight();
-
- // Check and nudge points from start until we see some that are OK:
- let nudged: boolean = true;
-
- for (let offset = 0; offset < points.length && nudged; offset += 2) {
-
- const x = Math.floor(points[offset]);
- const y = Math.floor(points[offset + 1]);
-
- if (x < -1 || x > width || y < -1 || y > height) {
- throw new NotFoundException();
- }
-
- nudged = false;
-
- if (x === -1) {
- points[offset] = 0.0;
- nudged = true;
- } else if (x === width) {
- points[offset] = width - 1;
- nudged = true;
- }
-
- if (y === -1) {
- points[offset + 1] = 0.0;
- nudged = true;
- } else if (y === height) {
- points[offset + 1] = height - 1;
- nudged = true;
- }
- }
-
- // Check and nudge points from end:
+ /**
+ * Samples an image for a rectangular matrix of bits of the given dimension. The sampling
+ * transformation is determined by the coordinates of 4 points, in the original and transformed
+ * image space.
+ *
+ * @param image image to sample
+ * @param dimensionX width of {@link BitMatrix} to sample from image
+ * @param dimensionY height of {@link BitMatrix} to sample from image
+ * @param p1ToX point 1 preimage X
+ * @param p1ToY point 1 preimage Y
+ * @param p2ToX point 2 preimage X
+ * @param p2ToY point 2 preimage Y
+ * @param p3ToX point 3 preimage X
+ * @param p3ToY point 3 preimage Y
+ * @param p4ToX point 4 preimage X
+ * @param p4ToY point 4 preimage Y
+ * @param p1FromX point 1 image X
+ * @param p1FromY point 1 image Y
+ * @param p2FromX point 2 image X
+ * @param p2FromY point 2 image Y
+ * @param p3FromX point 3 image X
+ * @param p3FromY point 3 image Y
+ * @param p4FromX point 4 image X
+ * @param p4FromY point 4 image Y
+ *
+ * @return {@link BitMatrix} representing a grid of points sampled from the image within a region
+ * defined by the "from" parameters
+ *
+ * @throws NotFoundException if image can't be sampled, for example, if the transformation defined
+ * by the given points is invalid or results in sampling outside the image boundaries
+ */
+ public abstract sampleGrid(
+ image: BitMatrix,
+ dimensionX: number /*int*/,
+ dimensionY: number /*int*/,
+ p1ToX: number/*float*/, p1ToY: number/*float*/,
+ p2ToX: number/*float*/, p2ToY: number/*float*/,
+ p3ToX: number/*float*/, p3ToY: number/*float*/,
+ p4ToX: number/*float*/, p4ToY: number/*float*/,
+ p1FromX: number/*float*/, p1FromY: number/*float*/,
+ p2FromX: number/*float*/, p2FromY: number/*float*/,
+ p3FromX: number/*float*/, p3FromY: number/*float*/,
+ p4FromX: number/*float*/, p4FromY: number/*float*/
+ ): BitMatrix; /*throws NotFoundException*/
+
+ public abstract sampleGridWithTransform(
+ image: BitMatrix,
+ dimensionX: number /*int*/,
+ dimensionY: number /*int*/,
+ transform: PerspectiveTransform
+ ): BitMatrix; /*throws NotFoundException*/
+
+ /**
+ *
Checks a set of points that have been transformed to sample points on an image against
+ * the image's dimensions to see if the point are even within the image.
+ *
+ *
This method will actually "nudge" the endpoints back onto the image if they are found to be
+ * barely (less than 1 pixel) off the image. This accounts for imperfect detection of finder
+ * patterns in an image where the QR Code runs all the way to the image border.
+ *
+ *
For efficiency, the method will check points from either end of the line until one is found
+ * to be within the image. Because the set of points are assumed to be linear, this is valid.
+ *
+ * @param image image into which the points should map
+ * @param points actual points in x1,y1,...,xn,yn form
+ * @throws NotFoundException if an endpoint is lies outside the image boundaries
+ */
+ protected static checkAndNudgePoints(
+ image: BitMatrix,
+ points: Float32Array
+ ): void /*throws NotFoundException*/ {
+
+ const width: number /*int*/ = image.getWidth();
+ const height: number /*int*/ = image.getHeight();
+
+ // Check and nudge points from start until we see some that are OK:
+ let nudged: boolean = true;
+
+ for (let offset = 0; offset < points.length && nudged; offset += 2) {
+
+ const x = Math.floor(points[offset]);
+ const y = Math.floor(points[offset + 1]);
+
+ if (x < -1 || x > width || y < -1 || y > height) {
+ throw new NotFoundException();
+ }
+
+ nudged = false;
+
+ if (x === -1) {
+ points[offset] = 0.0;
nudged = true;
+ } else if (x === width) {
+ points[offset] = width - 1;
+ nudged = true;
+ }
+
+ if (y === -1) {
+ points[offset + 1] = 0.0;
+ nudged = true;
+ } else if (y === height) {
+ points[offset + 1] = height - 1;
+ nudged = true;
+ }
+ }
+
+ // Check and nudge points from end:
+ nudged = true;
+
+ for (let offset = points.length - 2; offset >= 0 && nudged; offset -= 2) {
+
+ const x = Math.floor(points[offset]);
+ const y = Math.floor(points[offset + 1]);
- for (let offset = points.length - 2; offset >= 0 && nudged; offset -= 2) {
-
- const x = Math.floor(points[offset]);
- const y = Math.floor(points[offset + 1]);
-
- if (x < -1 || x > width || y < -1 || y > height) {
- throw new NotFoundException();
- }
-
- nudged = false;
-
- if (x === -1) {
- points[offset] = 0.0;
- nudged = true;
- } else if (x === width) {
- points[offset] = width - 1;
- nudged = true;
- }
-
- if (y === -1) {
- points[offset + 1] = 0.0;
- nudged = true;
- } else if (y === height) {
- points[offset + 1] = height - 1;
- nudged = true;
- }
- }
+ if (x < -1 || x > width || y < -1 || y > height) {
+ throw new NotFoundException();
+ }
+
+ nudged = false;
+
+ if (x === -1) {
+ points[offset] = 0.0;
+ nudged = true;
+ } else if (x === width) {
+ points[offset] = width - 1;
+ nudged = true;
+ }
+
+ if (y === -1) {
+ points[offset + 1] = 0.0;
+ nudged = true;
+ } else if (y === height) {
+ points[offset + 1] = height - 1;
+ nudged = true;
+ }
}
+ }
}
diff --git a/src/core/common/GridSamplerInstance.ts b/src/core/common/GridSamplerInstance.ts
index 288afd46..42d1c635 100644
--- a/src/core/common/GridSamplerInstance.ts
+++ b/src/core/common/GridSamplerInstance.ts
@@ -3,26 +3,26 @@ import DefaultGridSampler from './DefaultGridSampler';
export default class GridSamplerInstance {
- private static gridSampler: GridSampler = new DefaultGridSampler();
+ private static gridSampler: GridSampler = new DefaultGridSampler();
- /**
- * Sets the implementation of GridSampler used by the library. One global
- * instance is stored, which may sound problematic. But, the implementation provided
- * ought to be appropriate for the entire platform, and all uses of this library
- * in the whole lifetime of the JVM. For instance, an Android activity can swap in
- * an implementation that takes advantage of native platform libraries.
- *
- * @param newGridSampler The platform-specific object to install.
- */
- public static setGridSampler(newGridSampler: GridSampler): void {
- GridSamplerInstance.gridSampler = newGridSampler;
- }
+ /**
+ * Sets the implementation of GridSampler used by the library. One global
+ * instance is stored, which may sound problematic. But, the implementation provided
+ * ought to be appropriate for the entire platform, and all uses of this library
+ * in the whole lifetime of the JVM. For instance, an Android activity can swap in
+ * an implementation that takes advantage of native platform libraries.
+ *
+ * @param newGridSampler The platform-specific object to install.
+ */
+ public static setGridSampler(newGridSampler: GridSampler): void {
+ GridSamplerInstance.gridSampler = newGridSampler;
+ }
- /**
- * @return the current implementation of GridSampler
- */
- public static getInstance(): GridSampler {
- return GridSamplerInstance.gridSampler;
- }
+ /**
+ * @return the current implementation of GridSampler
+ */
+ public static getInstance(): GridSampler {
+ return GridSamplerInstance.gridSampler;
+ }
}
diff --git a/src/core/common/HybridBinarizer.ts b/src/core/common/HybridBinarizer.ts
index 11688a3e..01868fd8 100644
--- a/src/core/common/HybridBinarizer.ts
+++ b/src/core/common/HybridBinarizer.ts
@@ -40,202 +40,202 @@ import BitMatrix from './BitMatrix';
*/
export default class HybridBinarizer extends GlobalHistogramBinarizer {
- // This class uses 5x5 blocks to compute local luminance, where each block is 8x8 pixels.
- // So this is the smallest dimension in each axis we can accept.
- private static BLOCK_SIZE_POWER = 3;
- private static BLOCK_SIZE = 1 << HybridBinarizer.BLOCK_SIZE_POWER; // ...0100...00
- private static BLOCK_SIZE_MASK = HybridBinarizer.BLOCK_SIZE - 1; // ...0011...11
- private static MINIMUM_DIMENSION = HybridBinarizer.BLOCK_SIZE * 5;
- private static MIN_DYNAMIC_RANGE = 24;
-
- private matrix: BitMatrix | null = null;
-
- public constructor(source: LuminanceSource) {
- super(source);
+ // This class uses 5x5 blocks to compute local luminance, where each block is 8x8 pixels.
+ // So this is the smallest dimension in each axis we can accept.
+ private static BLOCK_SIZE_POWER = 3;
+ private static BLOCK_SIZE = 1 << HybridBinarizer.BLOCK_SIZE_POWER; // ...0100...00
+ private static BLOCK_SIZE_MASK = HybridBinarizer.BLOCK_SIZE - 1; // ...0011...11
+ private static MINIMUM_DIMENSION = HybridBinarizer.BLOCK_SIZE * 5;
+ private static MIN_DYNAMIC_RANGE = 24;
+
+ private matrix: BitMatrix | null = null;
+
+ public constructor(source: LuminanceSource) {
+ super(source);
+ }
+
+ /**
+ * Calculates the final BitMatrix once for all requests. This could be called once from the
+ * constructor instead, but there are some advantages to doing it lazily, such as making
+ * profiling easier, and not doing heavy lifting when callers don't expect it.
+ */
+ /*@Override*/
+ public getBlackMatrix(): BitMatrix /*throws NotFoundException*/ {
+ if (this.matrix !== null) {
+ return this.matrix;
}
-
- /**
- * Calculates the final BitMatrix once for all requests. This could be called once from the
- * constructor instead, but there are some advantages to doing it lazily, such as making
- * profiling easier, and not doing heavy lifting when callers don't expect it.
- */
- /*@Override*/
- public getBlackMatrix(): BitMatrix /*throws NotFoundException*/ {
- if (this.matrix !== null) {
- return this.matrix;
+ const source = this.getLuminanceSource();
+ const width = source.getWidth();
+ const height = source.getHeight();
+ if (width >= HybridBinarizer.MINIMUM_DIMENSION && height >= HybridBinarizer.MINIMUM_DIMENSION) {
+ const luminances = source.getMatrix();
+ let subWidth = width >> HybridBinarizer.BLOCK_SIZE_POWER;
+ if ((width & HybridBinarizer.BLOCK_SIZE_MASK) !== 0) {
+ subWidth++;
+ }
+ let subHeight = height >> HybridBinarizer.BLOCK_SIZE_POWER;
+ if ((height & HybridBinarizer.BLOCK_SIZE_MASK) !== 0) {
+ subHeight++;
+ }
+ const blackPoints = HybridBinarizer.calculateBlackPoints(luminances, subWidth, subHeight, width, height);
+
+ const newMatrix = new BitMatrix(width, height);
+ HybridBinarizer.calculateThresholdForBlock(luminances, subWidth, subHeight, width, height, blackPoints, newMatrix);
+ this.matrix = newMatrix;
+ } else {
+ // If the image is too small, fall back to the global histogram approach.
+ this.matrix = super.getBlackMatrix();
+ }
+ return this.matrix;
+ }
+
+ /*@Override*/
+ public createBinarizer(source: LuminanceSource): Binarizer {
+ return new HybridBinarizer(source);
+ }
+
+ /**
+ * For each block in the image, calculate the average black point using a 5x5 grid
+ * of the blocks around it. Also handles the corner cases (fractional blocks are computed based
+ * on the last pixels in the row/column which are also used in the previous block).
+ */
+ private static calculateThresholdForBlock(luminances: Uint8ClampedArray,
+ subWidth: number /*int*/,
+ subHeight: number /*int*/,
+ width: number /*int*/,
+ height: number /*int*/,
+ blackPoints: Int32Array[],
+ matrix: BitMatrix): void {
+ const maxYOffset = height - HybridBinarizer.BLOCK_SIZE;
+ const maxXOffset = width - HybridBinarizer.BLOCK_SIZE;
+ for (let y = 0; y < subHeight; y++) {
+ let yoffset = y << HybridBinarizer.BLOCK_SIZE_POWER;
+ if (yoffset > maxYOffset) {
+ yoffset = maxYOffset;
+ }
+ const top = HybridBinarizer.cap(y, 2, subHeight - 3);
+ for (let x = 0; x < subWidth; x++) {
+ let xoffset = x << HybridBinarizer.BLOCK_SIZE_POWER;
+ if (xoffset > maxXOffset) {
+ xoffset = maxXOffset;
}
- const source = this.getLuminanceSource();
- const width = source.getWidth();
- const height = source.getHeight();
- if (width >= HybridBinarizer.MINIMUM_DIMENSION && height >= HybridBinarizer.MINIMUM_DIMENSION) {
- const luminances = source.getMatrix();
- let subWidth = width >> HybridBinarizer.BLOCK_SIZE_POWER;
- if ((width & HybridBinarizer.BLOCK_SIZE_MASK) !== 0) {
- subWidth++;
- }
- let subHeight = height >> HybridBinarizer.BLOCK_SIZE_POWER;
- if ((height & HybridBinarizer.BLOCK_SIZE_MASK) !== 0) {
- subHeight++;
- }
- const blackPoints = HybridBinarizer.calculateBlackPoints(luminances, subWidth, subHeight, width, height);
-
- const newMatrix = new BitMatrix(width, height);
- HybridBinarizer.calculateThresholdForBlock(luminances, subWidth, subHeight, width, height, blackPoints, newMatrix);
- this.matrix = newMatrix;
- } else {
- // If the image is too small, fall back to the global histogram approach.
- this.matrix = super.getBlackMatrix();
+ const left = HybridBinarizer.cap(x, 2, subWidth - 3);
+ let sum = 0;
+ for (let z = -2; z <= 2; z++) {
+ const blackRow = blackPoints[top + z];
+ sum += blackRow[left - 2] + blackRow[left - 1] + blackRow[left] + blackRow[left + 1] + blackRow[left + 2];
}
- return this.matrix;
+ const average = sum / 25;
+ HybridBinarizer.thresholdBlock(luminances, xoffset, yoffset, average, width, matrix);
+ }
}
-
- /*@Override*/
- public createBinarizer(source: LuminanceSource): Binarizer {
- return new HybridBinarizer(source);
+ }
+
+ private static cap(value: number /*int*/, min: number /*int*/, max: number /*int*/): number /*int*/ {
+ return value < min ? min : value > max ? max : value;
+ }
+
+ /**
+ * Applies a single threshold to a block of pixels.
+ */
+ private static thresholdBlock(luminances: Uint8ClampedArray,
+ xoffset: number /*int*/,
+ yoffset: number /*int*/,
+ threshold: number /*int*/,
+ stride: number /*int*/,
+ matrix: BitMatrix): void {
+ for (let y = 0, offset = yoffset * stride + xoffset; y < HybridBinarizer.BLOCK_SIZE; y++, offset += stride) {
+ for (let x = 0; x < HybridBinarizer.BLOCK_SIZE; x++) {
+ // Comparison needs to be <= so that black == 0 pixels are black even if the threshold is 0.
+ if ((luminances[offset + x] & 0xFF) <= threshold) {
+ matrix.set(xoffset + x, yoffset + y);
+ }
+ }
}
-
- /**
- * For each block in the image, calculate the average black point using a 5x5 grid
- * of the blocks around it. Also handles the corner cases (fractional blocks are computed based
- * on the last pixels in the row/column which are also used in the previous block).
- */
- private static calculateThresholdForBlock(luminances: Uint8ClampedArray,
- subWidth: number /*int*/,
- subHeight: number /*int*/,
- width: number /*int*/,
- height: number /*int*/,
- blackPoints: Int32Array[],
- matrix: BitMatrix): void {
- const maxYOffset = height - HybridBinarizer.BLOCK_SIZE;
- const maxXOffset = width - HybridBinarizer.BLOCK_SIZE;
- for (let y = 0; y < subHeight; y++) {
- let yoffset = y << HybridBinarizer.BLOCK_SIZE_POWER;
- if (yoffset > maxYOffset) {
- yoffset = maxYOffset;
+ }
+
+ /**
+ * Calculates a single black point for each block of pixels and saves it away.
+ * See the following thread for a discussion of this algorithm:
+ * http://groups.google.com/group/zxing/browse_thread/thread/d06efa2c35a7ddc0
+ */
+ private static calculateBlackPoints(luminances: Uint8ClampedArray,
+ subWidth: number /*int*/,
+ subHeight: number /*int*/,
+ width: number /*int*/,
+ height: number /*int*/): Int32Array[] {
+ const maxYOffset = height - HybridBinarizer.BLOCK_SIZE;
+ const maxXOffset = width - HybridBinarizer.BLOCK_SIZE;
+ // tslint:disable-next-line:whitespace
+ const blackPoints = new Array(subHeight);// subWidth
+
+ for (let y = 0; y < subHeight; y++) {
+ blackPoints[y] = new Int32Array(subWidth);
+ let yoffset = y << HybridBinarizer.BLOCK_SIZE_POWER;
+ if (yoffset > maxYOffset) {
+ yoffset = maxYOffset;
+ }
+ for (let x = 0; x < subWidth; x++) {
+ let xoffset = x << HybridBinarizer.BLOCK_SIZE_POWER;
+ if (xoffset > maxXOffset) {
+ xoffset = maxXOffset;
+ }
+ let sum = 0;
+ let min = 0xFF;
+ let max = 0;
+ for (let yy = 0, offset = yoffset * width + xoffset; yy < HybridBinarizer.BLOCK_SIZE; yy++, offset += width) {
+ for (let xx = 0; xx < HybridBinarizer.BLOCK_SIZE; xx++) {
+ const pixel = luminances[offset + xx] & 0xFF;
+ sum += pixel;
+ // still looking for good contrast
+ if (pixel < min) {
+ min = pixel;
}
- const top = HybridBinarizer.cap(y, 2, subHeight - 3);
- for (let x = 0; x < subWidth; x++) {
- let xoffset = x << HybridBinarizer.BLOCK_SIZE_POWER;
- if (xoffset > maxXOffset) {
- xoffset = maxXOffset;
- }
- const left = HybridBinarizer.cap(x, 2, subWidth - 3);
- let sum = 0;
- for (let z = -2; z <= 2; z++) {
- const blackRow = blackPoints[top + z];
- sum += blackRow[left - 2] + blackRow[left - 1] + blackRow[left] + blackRow[left + 1] + blackRow[left + 2];
- }
- const average = sum / 25;
- HybridBinarizer.thresholdBlock(luminances, xoffset, yoffset, average, width, matrix);
+ if (pixel > max) {
+ max = pixel;
}
- }
- }
-
- private static cap(value: number /*int*/, min: number /*int*/, max: number /*int*/): number /*int*/ {
- return value < min ? min : value > max ? max : value;
- }
-
- /**
- * Applies a single threshold to a block of pixels.
- */
- private static thresholdBlock(luminances: Uint8ClampedArray,
- xoffset: number /*int*/,
- yoffset: number /*int*/,
- threshold: number /*int*/,
- stride: number /*int*/,
- matrix: BitMatrix): void {
- for (let y = 0, offset = yoffset * stride + xoffset; y < HybridBinarizer.BLOCK_SIZE; y++ , offset += stride) {
- for (let x = 0; x < HybridBinarizer.BLOCK_SIZE; x++) {
- // Comparison needs to be <= so that black == 0 pixels are black even if the threshold is 0.
- if ((luminances[offset + x] & 0xFF) <= threshold) {
- matrix.set(xoffset + x, yoffset + y);
- }
+ }
+ // short-circuit min/max tests once dynamic range is met
+ if (max - min > HybridBinarizer.MIN_DYNAMIC_RANGE) {
+ // finish the rest of the rows quickly
+ for (yy++, offset += width; yy < HybridBinarizer.BLOCK_SIZE; yy++, offset += width) {
+ for (let xx = 0; xx < HybridBinarizer.BLOCK_SIZE; xx++) {
+ sum += luminances[offset + xx] & 0xFF;
+ }
}
+ }
}
- }
- /**
- * Calculates a single black point for each block of pixels and saves it away.
- * See the following thread for a discussion of this algorithm:
- * http://groups.google.com/group/zxing/browse_thread/thread/d06efa2c35a7ddc0
- */
- private static calculateBlackPoints(luminances: Uint8ClampedArray,
- subWidth: number /*int*/,
- subHeight: number /*int*/,
- width: number /*int*/,
- height: number /*int*/): Int32Array[] {
- const maxYOffset = height - HybridBinarizer.BLOCK_SIZE;
- const maxXOffset = width - HybridBinarizer.BLOCK_SIZE;
- // tslint:disable-next-line:whitespace
- const blackPoints = new Array(subHeight);// subWidth
-
- for (let y = 0; y < subHeight; y++) {
- blackPoints[y] = new Int32Array(subWidth);
- let yoffset = y << HybridBinarizer.BLOCK_SIZE_POWER;
- if (yoffset > maxYOffset) {
- yoffset = maxYOffset;
- }
- for (let x = 0; x < subWidth; x++) {
- let xoffset = x << HybridBinarizer.BLOCK_SIZE_POWER;
- if (xoffset > maxXOffset) {
- xoffset = maxXOffset;
- }
- let sum = 0;
- let min = 0xFF;
- let max = 0;
- for (let yy = 0, offset = yoffset * width + xoffset; yy < HybridBinarizer.BLOCK_SIZE; yy++ , offset += width) {
- for (let xx = 0; xx < HybridBinarizer.BLOCK_SIZE; xx++) {
- const pixel = luminances[offset + xx] & 0xFF;
- sum += pixel;
- // still looking for good contrast
- if (pixel < min) {
- min = pixel;
- }
- if (pixel > max) {
- max = pixel;
- }
- }
- // short-circuit min/max tests once dynamic range is met
- if (max - min > HybridBinarizer.MIN_DYNAMIC_RANGE) {
- // finish the rest of the rows quickly
- for (yy++ , offset += width; yy < HybridBinarizer.BLOCK_SIZE; yy++ , offset += width) {
- for (let xx = 0; xx < HybridBinarizer.BLOCK_SIZE; xx++) {
- sum += luminances[offset + xx] & 0xFF;
- }
- }
- }
- }
-
- // The default estimate is the average of the values in the block.
- let average = sum >> (HybridBinarizer.BLOCK_SIZE_POWER * 2);
- if (max - min <= HybridBinarizer.MIN_DYNAMIC_RANGE) {
- // If variation within the block is low, assume this is a block with only light or only
- // dark pixels. In that case we do not want to use the average, as it would divide this
- // low contrast area into black and white pixels, essentially creating data out of noise.
- //
- // The default assumption is that the block is light/background. Since no estimate for
- // the level of dark pixels exists locally, use half the min for the block.
- average = min / 2;
-
- if (y > 0 && x > 0) {
- // Correct the "white background" assumption for blocks that have neighbors by comparing
- // the pixels in this block to the previously calculated black points. This is based on
- // the fact that dark barcode symbology is always surrounded by some amount of light
- // background for which reasonable black point estimates were made. The bp estimated at
- // the boundaries is used for the interior.
-
- // The (min < bp) is arbitrary but works better than other heuristics that were tried.
- const averageNeighborBlackPoint =
- (blackPoints[y - 1][x] + (2 * blackPoints[y][x - 1]) + blackPoints[y - 1][x - 1]) / 4;
- if (min < averageNeighborBlackPoint) {
- average = averageNeighborBlackPoint;
- }
- }
- }
- blackPoints[y][x] = average;
+ // The default estimate is the average of the values in the block.
+ let average = sum >> (HybridBinarizer.BLOCK_SIZE_POWER * 2);
+ if (max - min <= HybridBinarizer.MIN_DYNAMIC_RANGE) {
+ // If variation within the block is low, assume this is a block with only light or only
+ // dark pixels. In that case we do not want to use the average, as it would divide this
+ // low contrast area into black and white pixels, essentially creating data out of noise.
+ //
+ // The default assumption is that the block is light/background. Since no estimate for
+ // the level of dark pixels exists locally, use half the min for the block.
+ average = min / 2;
+
+ if (y > 0 && x > 0) {
+ // Correct the "white background" assumption for blocks that have neighbors by comparing
+ // the pixels in this block to the previously calculated black points. This is based on
+ // the fact that dark barcode symbology is always surrounded by some amount of light
+ // background for which reasonable black point estimates were made. The bp estimated at
+ // the boundaries is used for the interior.
+
+ // The (min < bp) is arbitrary but works better than other heuristics that were tried.
+ const averageNeighborBlackPoint =
+ (blackPoints[y - 1][x] + (2 * blackPoints[y][x - 1]) + blackPoints[y - 1][x - 1]) / 4;
+ if (min < averageNeighborBlackPoint) {
+ average = averageNeighborBlackPoint;
}
+ }
}
- return blackPoints;
+ blackPoints[y][x] = average;
+ }
}
+ return blackPoints;
+ }
}
diff --git a/src/core/common/PerspectiveTransform.ts b/src/core/common/PerspectiveTransform.ts
index 8f110e61..042b9640 100644
--- a/src/core/common/PerspectiveTransform.ts
+++ b/src/core/common/PerspectiveTransform.ts
@@ -25,145 +25,145 @@
*/
export default class PerspectiveTransform {
- private constructor(private a11: number/*float*/, private a21: number/*float*/, private a31: number/*float*/,
- private a12: number/*float*/, private a22: number/*float*/, private a32: number/*float*/,
- private a13: number/*float*/, private a23: number/*float*/, private a33: number/*float*/) { }
-
- public static quadrilateralToQuadrilateral(
- x0: number/*float*/, y0: number/*float*/,
- x1: number/*float*/, y1: number/*float*/,
- x2: number/*float*/, y2: number/*float*/,
- x3: number/*float*/, y3: number/*float*/,
- x0p: number/*float*/, y0p: number/*float*/,
- x1p: number/*float*/, y1p: number/*float*/,
- x2p: number/*float*/, y2p: number/*float*/,
- x3p: number/*float*/, y3p: number/*float*/
- ): PerspectiveTransform {
-
- const qToS = PerspectiveTransform.quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3);
- const sToQ = PerspectiveTransform.squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p);
-
- return sToQ.times(qToS);
+ private constructor(private a11: number/*float*/, private a21: number/*float*/, private a31: number/*float*/,
+ private a12: number/*float*/, private a22: number/*float*/, private a32: number/*float*/,
+ private a13: number/*float*/, private a23: number/*float*/, private a33: number/*float*/) { }
+
+ public static quadrilateralToQuadrilateral(
+ x0: number/*float*/, y0: number/*float*/,
+ x1: number/*float*/, y1: number/*float*/,
+ x2: number/*float*/, y2: number/*float*/,
+ x3: number/*float*/, y3: number/*float*/,
+ x0p: number/*float*/, y0p: number/*float*/,
+ x1p: number/*float*/, y1p: number/*float*/,
+ x2p: number/*float*/, y2p: number/*float*/,
+ x3p: number/*float*/, y3p: number/*float*/
+ ): PerspectiveTransform {
+
+ const qToS = PerspectiveTransform.quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3);
+ const sToQ = PerspectiveTransform.squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p);
+
+ return sToQ.times(qToS);
+ }
+
+ public transformPoints(points: Float32Array): void {
+
+ const max = points.length;
+
+ const a11 = this.a11;
+ const a12 = this.a12;
+ const a13 = this.a13;
+ const a21 = this.a21;
+ const a22 = this.a22;
+ const a23 = this.a23;
+ const a31 = this.a31;
+ const a32 = this.a32;
+ const a33 = this.a33;
+
+ for (let i = 0; i < max; i += 2) {
+ const x = points[i];
+ const y = points[i + 1];
+ const denominator = a13 * x + a23 * y + a33;
+ points[i] = (a11 * x + a21 * y + a31) / denominator;
+ points[i + 1] = (a12 * x + a22 * y + a32) / denominator;
}
+ }
- public transformPoints(points: Float32Array): void {
-
- const max = points.length;
-
- const a11 = this.a11;
- const a12 = this.a12;
- const a13 = this.a13;
- const a21 = this.a21;
- const a22 = this.a22;
- const a23 = this.a23;
- const a31 = this.a31;
- const a32 = this.a32;
- const a33 = this.a33;
-
- for (let i = 0; i < max; i += 2) {
- const x = points[i];
- const y = points[i + 1];
- const denominator = a13 * x + a23 * y + a33;
- points[i] = (a11 * x + a21 * y + a31) / denominator;
- points[i + 1] = (a12 * x + a22 * y + a32) / denominator;
- }
- }
-
- public transformPointsWithValues(xValues: Float32Array, yValues: Float32Array): void {
+ public transformPointsWithValues(xValues: Float32Array, yValues: Float32Array): void {
- const a11 = this.a11;
- const a12 = this.a12;
- const a13 = this.a13;
- const a21 = this.a21;
- const a22 = this.a22;
- const a23 = this.a23;
- const a31 = this.a31;
- const a32 = this.a32;
- const a33 = this.a33;
+ const a11 = this.a11;
+ const a12 = this.a12;
+ const a13 = this.a13;
+ const a21 = this.a21;
+ const a22 = this.a22;
+ const a23 = this.a23;
+ const a31 = this.a31;
+ const a32 = this.a32;
+ const a33 = this.a33;
- const n = xValues.length;
+ const n = xValues.length;
- for (let i = 0; i < n; i++) {
- const x = xValues[i];
- const y = yValues[i];
- const denominator = a13 * x + a23 * y + a33;
+ for (let i = 0; i < n; i++) {
+ const x = xValues[i];
+ const y = yValues[i];
+ const denominator = a13 * x + a23 * y + a33;
- xValues[i] = (a11 * x + a21 * y + a31) / denominator;
- yValues[i] = (a12 * x + a22 * y + a32) / denominator;
- }
+ xValues[i] = (a11 * x + a21 * y + a31) / denominator;
+ yValues[i] = (a12 * x + a22 * y + a32) / denominator;
}
-
- public static squareToQuadrilateral(
- x0: number/*float*/, y0: number/*float*/,
- x1: number/*float*/, y1: number/*float*/,
- x2: number/*float*/, y2: number/*float*/,
- x3: number/*float*/, y3: number/*float*/
- ): PerspectiveTransform {
-
- const dx3 = x0 - x1 + x2 - x3;
- const dy3 = y0 - y1 + y2 - y3;
-
- if (dx3 === 0.0 && dy3 === 0.0) {
- // Affine
- return new PerspectiveTransform(x1 - x0, x2 - x1, x0,
- y1 - y0, y2 - y1, y0,
- 0.0, 0.0, 1.0);
- } else {
- const dx1 = x1 - x2;
- const dx2 = x3 - x2;
- const dy1 = y1 - y2;
- const dy2 = y3 - y2;
-
- const denominator = dx1 * dy2 - dx2 * dy1;
-
- const a13 = (dx3 * dy2 - dx2 * dy3) / denominator;
- const a23 = (dx1 * dy3 - dx3 * dy1) / denominator;
-
- return new PerspectiveTransform(
- x1 - x0 + a13 * x1, x3 - x0 + a23 * x3, x0,
- y1 - y0 + a13 * y1, y3 - y0 + a23 * y3, y0,
- a13, a23, 1.0
- );
- }
- }
-
- public static quadrilateralToSquare(
- x0: number/*float*/, y0: number/*float*/,
- x1: number/*float*/, y1: number/*float*/,
- x2: number/*float*/, y2: number/*float*/,
- x3: number/*float*/, y3: number/*float*/
- ): PerspectiveTransform {
- // Here, the adjoint serves as the inverse:
- return PerspectiveTransform.squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3).buildAdjoint();
- }
-
- protected buildAdjoint(): PerspectiveTransform {
- // Adjoint is the transpose of the cofactor matrix:
- return new PerspectiveTransform(
- this.a22 * this.a33 - this.a23 * this.a32,
- this.a23 * this.a31 - this.a21 * this.a33,
- this.a21 * this.a32 - this.a22 * this.a31,
- this.a13 * this.a32 - this.a12 * this.a33,
- this.a11 * this.a33 - this.a13 * this.a31,
- this.a12 * this.a31 - this.a11 * this.a32,
- this.a12 * this.a23 - this.a13 * this.a22,
- this.a13 * this.a21 - this.a11 * this.a23,
- this.a11 * this.a22 - this.a12 * this.a21
- );
- }
-
- protected times(other: PerspectiveTransform): PerspectiveTransform {
- return new PerspectiveTransform(
- this.a11 * other.a11 + this.a21 * other.a12 + this.a31 * other.a13,
- this.a11 * other.a21 + this.a21 * other.a22 + this.a31 * other.a23,
- this.a11 * other.a31 + this.a21 * other.a32 + this.a31 * other.a33,
- this.a12 * other.a11 + this.a22 * other.a12 + this.a32 * other.a13,
- this.a12 * other.a21 + this.a22 * other.a22 + this.a32 * other.a23,
- this.a12 * other.a31 + this.a22 * other.a32 + this.a32 * other.a33,
- this.a13 * other.a11 + this.a23 * other.a12 + this.a33 * other.a13,
- this.a13 * other.a21 + this.a23 * other.a22 + this.a33 * other.a23,
- this.a13 * other.a31 + this.a23 * other.a32 + this.a33 * other.a33
- );
+ }
+
+ public static squareToQuadrilateral(
+ x0: number/*float*/, y0: number/*float*/,
+ x1: number/*float*/, y1: number/*float*/,
+ x2: number/*float*/, y2: number/*float*/,
+ x3: number/*float*/, y3: number/*float*/
+ ): PerspectiveTransform {
+
+ const dx3 = x0 - x1 + x2 - x3;
+ const dy3 = y0 - y1 + y2 - y3;
+
+ if (dx3 === 0.0 && dy3 === 0.0) {
+ // Affine
+ return new PerspectiveTransform(x1 - x0, x2 - x1, x0,
+ y1 - y0, y2 - y1, y0,
+ 0.0, 0.0, 1.0);
+ } else {
+ const dx1 = x1 - x2;
+ const dx2 = x3 - x2;
+ const dy1 = y1 - y2;
+ const dy2 = y3 - y2;
+
+ const denominator = dx1 * dy2 - dx2 * dy1;
+
+ const a13 = (dx3 * dy2 - dx2 * dy3) / denominator;
+ const a23 = (dx1 * dy3 - dx3 * dy1) / denominator;
+
+ return new PerspectiveTransform(
+ x1 - x0 + a13 * x1, x3 - x0 + a23 * x3, x0,
+ y1 - y0 + a13 * y1, y3 - y0 + a23 * y3, y0,
+ a13, a23, 1.0
+ );
}
+ }
+
+ public static quadrilateralToSquare(
+ x0: number/*float*/, y0: number/*float*/,
+ x1: number/*float*/, y1: number/*float*/,
+ x2: number/*float*/, y2: number/*float*/,
+ x3: number/*float*/, y3: number/*float*/
+ ): PerspectiveTransform {
+ // Here, the adjoint serves as the inverse:
+ return PerspectiveTransform.squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3).buildAdjoint();
+ }
+
+ protected buildAdjoint(): PerspectiveTransform {
+ // Adjoint is the transpose of the cofactor matrix:
+ return new PerspectiveTransform(
+ this.a22 * this.a33 - this.a23 * this.a32,
+ this.a23 * this.a31 - this.a21 * this.a33,
+ this.a21 * this.a32 - this.a22 * this.a31,
+ this.a13 * this.a32 - this.a12 * this.a33,
+ this.a11 * this.a33 - this.a13 * this.a31,
+ this.a12 * this.a31 - this.a11 * this.a32,
+ this.a12 * this.a23 - this.a13 * this.a22,
+ this.a13 * this.a21 - this.a11 * this.a23,
+ this.a11 * this.a22 - this.a12 * this.a21
+ );
+ }
+
+ protected times(other: PerspectiveTransform): PerspectiveTransform {
+ return new PerspectiveTransform(
+ this.a11 * other.a11 + this.a21 * other.a12 + this.a31 * other.a13,
+ this.a11 * other.a21 + this.a21 * other.a22 + this.a31 * other.a23,
+ this.a11 * other.a31 + this.a21 * other.a32 + this.a31 * other.a33,
+ this.a12 * other.a11 + this.a22 * other.a12 + this.a32 * other.a13,
+ this.a12 * other.a21 + this.a22 * other.a22 + this.a32 * other.a23,
+ this.a12 * other.a31 + this.a22 * other.a32 + this.a32 * other.a33,
+ this.a13 * other.a11 + this.a23 * other.a12 + this.a33 * other.a13,
+ this.a13 * other.a21 + this.a23 * other.a22 + this.a33 * other.a23,
+ this.a13 * other.a31 + this.a23 * other.a32 + this.a33 * other.a33
+ );
+ }
}
diff --git a/src/core/common/detector/CornerDetector.ts b/src/core/common/detector/CornerDetector.ts
index b7e1da7b..a96074ac 100644
--- a/src/core/common/detector/CornerDetector.ts
+++ b/src/core/common/detector/CornerDetector.ts
@@ -23,269 +23,269 @@ import NotFoundException from '../../NotFoundException';
*/
export default class CornerDetector {
- private image: BitMatrix;
- private height: number;
- private width: number;
- private leftInit: number;
- private rightInit: number;
- private downInit: number;
- private upInit: number;
- private targetMatrixSize: number;
-
-
- /**
- * @throws NotFoundException if image is too small to accommodate {@code initSize}
- */
- public constructor(image: BitMatrix, initSize: number, x: number, y: number, targetMatrixSize: number) {
- this.image = image;
- this.height = image.getHeight();
- this.width = image.getWidth();
- const halfsize = initSize / 2;
- this.leftInit = x - halfsize;
- this.rightInit = x + halfsize;
- this.upInit = y - halfsize;
- this.downInit = y + halfsize;
- this.targetMatrixSize = targetMatrixSize * 2;
- if (this.upInit < 0 || this.leftInit < 0 || this.downInit >= this.height || this.rightInit >= this.width) {
- throw new NotFoundException();
- }
+ private image: BitMatrix;
+ private height: number;
+ private width: number;
+ private leftInit: number;
+ private rightInit: number;
+ private downInit: number;
+ private upInit: number;
+ private targetMatrixSize: number;
+
+
+ /**
+ * @throws NotFoundException if image is too small to accommodate {@code initSize}
+ */
+ public constructor(image: BitMatrix, initSize: number, x: number, y: number, targetMatrixSize: number) {
+ this.image = image;
+ this.height = image.getHeight();
+ this.width = image.getWidth();
+ const halfsize = initSize / 2;
+ this.leftInit = x - halfsize;
+ this.rightInit = x + halfsize;
+ this.upInit = y - halfsize;
+ this.downInit = y + halfsize;
+ this.targetMatrixSize = targetMatrixSize * 2;
+ if (this.upInit < 0 || this.leftInit < 0 || this.downInit >= this.height || this.rightInit >= this.width) {
+ throw new NotFoundException();
}
+ }
+
+ /**
+ * @throws NotFoundException if no Data Matrix Code can be found
+ */
+ public detect(): ResultPoint[] {
+
+ let left = this.leftInit;
+ let right = this.rightInit;
+ let up = this.upInit;
+ let down = this.downInit;
+ let sizeExceeded = false;
+ let aBlackPointFoundOnBorder = true;
+ let atLeastOneBlackPointFoundOnBorder = false;
+
+ let atLeastOneBlackPointFoundOnRight = false;
+ let atLeastOneBlackPointFoundOnBottom = false;
+ let atLeastOneBlackPointFoundOnLeft = false;
+ let atLeastOneBlackPointFoundOnTop = false;
+
+ while (aBlackPointFoundOnBorder) {
+
+ aBlackPointFoundOnBorder = false;
+
+ // .....
+ // . |
+ // .....
+ let rightBorderNotWhite = true;
+ while ((rightBorderNotWhite || !atLeastOneBlackPointFoundOnRight) && right < this.width) {
+ rightBorderNotWhite = this.containsBlackPoint(up, down, right, false);
+ if (rightBorderNotWhite) {
+ right++;
+ aBlackPointFoundOnBorder = true;
+ atLeastOneBlackPointFoundOnRight = true;
+ } else if (!atLeastOneBlackPointFoundOnRight) {
+ right++;
+ }
+ }
+
+ if (right >= this.width) {
+ sizeExceeded = true;
+ break;
+ }
+
+ // .....
+ // . .
+ // .___.
+ let bottomBorderNotWhite = true;
+ while ((bottomBorderNotWhite || !atLeastOneBlackPointFoundOnBottom) && down < this.height) {
+ bottomBorderNotWhite = this.containsBlackPoint(left, right, down, true);
+ if (bottomBorderNotWhite) {
+ down++;
+ aBlackPointFoundOnBorder = true;
+ atLeastOneBlackPointFoundOnBottom = true;
+ } else if (!atLeastOneBlackPointFoundOnBottom) {
+ down++;
+ }
+ }
+
+ if (down >= this.height) {
+ sizeExceeded = true;
+ break;
+ }
+
+ // .....
+ // | .
+ // .....
+ let leftBorderNotWhite = true;
+ while ((leftBorderNotWhite || !atLeastOneBlackPointFoundOnLeft) && left >= 0) {
+ leftBorderNotWhite = this.containsBlackPoint(up, down, left, false);
+ if (leftBorderNotWhite) {
+ left--;
+ aBlackPointFoundOnBorder = true;
+ atLeastOneBlackPointFoundOnLeft = true;
+ } else if (!atLeastOneBlackPointFoundOnLeft) {
+ left--;
+ }
+ }
+
+ if (left < 0) {
+ sizeExceeded = true;
+ break;
+ }
+
+ // .___.
+ // . .
+ // .....
+ let topBorderNotWhite = true;
+ while ((topBorderNotWhite || !atLeastOneBlackPointFoundOnTop) && up >= 0) {
+ topBorderNotWhite = this.containsBlackPoint(left, right, up, true);
+ if (topBorderNotWhite) {
+ up--;
+ aBlackPointFoundOnBorder = true;
+ atLeastOneBlackPointFoundOnTop = true;
+ } else if (!atLeastOneBlackPointFoundOnTop) {
+ up--;
+ }
+ }
- /**
- * @throws NotFoundException if no Data Matrix Code can be found
- */
- public detect(): ResultPoint[] {
-
- let left = this.leftInit;
- let right = this.rightInit;
- let up = this.upInit;
- let down = this.downInit;
- let sizeExceeded = false;
- let aBlackPointFoundOnBorder = true;
- let atLeastOneBlackPointFoundOnBorder = false;
-
- let atLeastOneBlackPointFoundOnRight = false;
- let atLeastOneBlackPointFoundOnBottom = false;
- let atLeastOneBlackPointFoundOnLeft = false;
- let atLeastOneBlackPointFoundOnTop = false;
-
- while (aBlackPointFoundOnBorder) {
-
- aBlackPointFoundOnBorder = false;
-
- // .....
- // . |
- // .....
- let rightBorderNotWhite = true;
- while ((rightBorderNotWhite || !atLeastOneBlackPointFoundOnRight) && right < this.width) {
- rightBorderNotWhite = this.containsBlackPoint(up, down, right, false);
- if (rightBorderNotWhite) {
- right++;
- aBlackPointFoundOnBorder = true;
- atLeastOneBlackPointFoundOnRight = true;
- } else if (!atLeastOneBlackPointFoundOnRight) {
- right++;
- }
- }
-
- if (right >= this.width) {
- sizeExceeded = true;
- break;
- }
-
- // .....
- // . .
- // .___.
- let bottomBorderNotWhite = true;
- while ((bottomBorderNotWhite || !atLeastOneBlackPointFoundOnBottom) && down < this.height) {
- bottomBorderNotWhite = this.containsBlackPoint(left, right, down, true);
- if (bottomBorderNotWhite) {
- down++;
- aBlackPointFoundOnBorder = true;
- atLeastOneBlackPointFoundOnBottom = true;
- } else if (!atLeastOneBlackPointFoundOnBottom) {
- down++;
- }
- }
-
- if (down >= this.height) {
- sizeExceeded = true;
- break;
- }
-
- // .....
- // | .
- // .....
- let leftBorderNotWhite = true;
- while ((leftBorderNotWhite || !atLeastOneBlackPointFoundOnLeft) && left >= 0) {
- leftBorderNotWhite = this.containsBlackPoint(up, down, left, false);
- if (leftBorderNotWhite) {
- left--;
- aBlackPointFoundOnBorder = true;
- atLeastOneBlackPointFoundOnLeft = true;
- } else if (!atLeastOneBlackPointFoundOnLeft) {
- left--;
- }
- }
-
- if (left < 0) {
- sizeExceeded = true;
- break;
- }
+ if (up < 0) {
+ sizeExceeded = true;
+ break;
+ }
- // .___.
- // . .
- // .....
- let topBorderNotWhite = true;
- while ((topBorderNotWhite || !atLeastOneBlackPointFoundOnTop) && up >= 0) {
- topBorderNotWhite = this.containsBlackPoint(left, right, up, true);
- if (topBorderNotWhite) {
- up--;
- aBlackPointFoundOnBorder = true;
- atLeastOneBlackPointFoundOnTop = true;
- } else if (!atLeastOneBlackPointFoundOnTop) {
- up--;
- }
- }
+ if (aBlackPointFoundOnBorder) {
+ atLeastOneBlackPointFoundOnBorder = true;
+ }
+ }
- if (up < 0) {
- sizeExceeded = true;
- break;
+ if (!sizeExceeded && atLeastOneBlackPointFoundOnBorder) {
+ return this.findCorners(right, left, down, up);
+ } else {
+ throw new NotFoundException();
+ }
+ }
+
+ private findCorners(right: number, left: number, down: number, up: number): ResultPoint[] {
+ //
+ // A------------ ------------B
+ // | | up | |
+ // | -------|--------------|------- |
+ // | | | | | |
+ // | | | | | |
+ // ------------AP BP------------
+ // | |
+ // | |
+ // left | | right
+ // | |
+ // | |
+ // ------------DP CP------------
+ // | | | | | |
+ // | | | down | | |
+ // | -------|-------------|-------- |
+ // | | | |
+ // D-----------| |------------C
+ //
+
+
+ const width = right - left;
+ const height = down - up;
+ const sampler = 16 / this.targetMatrixSize;
+ const sampler2 = 4 / this.targetMatrixSize;
+ const deltaX = width * sampler2;
+ const deltaY = height * sampler2;
+ const areaWidth = deltaX + (right - left) * sampler;
+ const areaHeight = deltaY + (down - up) * sampler;
+
+ const a = new ResultPoint(left - deltaX, up - deltaY);
+ const b = new ResultPoint(right + deltaX, up - deltaY);
+ const c = new ResultPoint(right + deltaX, down + deltaY);
+ const d = new ResultPoint(left - deltaX, down + deltaY);
+
+ const ap = new ResultPoint(a.getX() + areaWidth, a.getY() + areaHeight);
+ const bp = new ResultPoint(b.getX() - areaWidth, b.getY() + areaHeight);
+ const cp = new ResultPoint(c.getX() - areaWidth, c.getY() - areaHeight);
+ const dp = new ResultPoint(d.getX() + areaWidth, d.getY() - areaHeight);
+
+ const topLeftCorner = this.getCornerFromArea(a.getX(), ap.getX(), a.getY(), ap.getY(), false, false);
+ const topRightCorner = this.getCornerFromArea(bp.getX(), b.getX(), b.getY(), bp.getY(), true, false);
+ const bottomRightCorner = this.getCornerFromArea(cp.getX(), c.getX(), cp.getY(), c.getY(), true, true);
+ const bottomLeftCorner = this.getCornerFromArea(d.getX(), dp.getX(), dp.getY(), d.getY(), false, true);
+
+ const xCorrection = (topRightCorner.getX() - topLeftCorner.getX()) / this.targetMatrixSize;
+ const yCorrection = (bottomRightCorner.getY() - topRightCorner.getY()) / this.targetMatrixSize;
+
+ const topLeftCornerCenter = new ResultPoint(topLeftCorner.getX() + xCorrection, topLeftCorner.getY() + yCorrection);
+ const topRightCornerCenter = new ResultPoint(topRightCorner.getX() - xCorrection, topRightCorner.getY() + yCorrection);
+ const bottomRightCornerCenter = new ResultPoint(bottomRightCorner.getX() - xCorrection, bottomRightCorner.getY() - yCorrection);
+ const bottomLeftCornerCenter = new ResultPoint(bottomLeftCorner.getX() + xCorrection, bottomLeftCorner.getY() - yCorrection);
+
+ const result: ResultPoint[] = [topLeftCornerCenter, topRightCornerCenter, bottomRightCornerCenter, bottomLeftCornerCenter];
+ return result;
+ }
+
+ private getCornerFromArea(left: number, right: number, top: number, bottom: number, maximizeX: boolean, maximizeY: boolean): ResultPoint {
+ let resX = maximizeX ? 0 : Number.MAX_VALUE;
+ let resY = maximizeY ? 0 : Number.MAX_VALUE;
+ for (let x = left; x < right; x++) {
+ for (let y = top; y < bottom; y++) {
+ if (x > 0 && y > 0 && x < this.image.getWidth() && y < this.image.getHeight()) {
+ if (this.image.get(x, y)) {
+ if (maximizeX) {
+ if (x > resX) {
+ resX = x;
+ }
+ } else {
+ if (x < resX) {
+ resX = x;
+ }
}
-
- if (aBlackPointFoundOnBorder) {
- atLeastOneBlackPointFoundOnBorder = true;
+ if (maximizeY) {
+ if (y > resY) {
+ resY = y;
+ }
+ } else {
+ if (y < resY) {
+ resY = y;
+ }
}
+ }
}
-
- if (!sizeExceeded && atLeastOneBlackPointFoundOnBorder) {
- return this.findCorners(right, left, down, up);
- } else {
- throw new NotFoundException();
- }
+ }
}
-
- private findCorners(right: number, left: number, down: number, up: number): ResultPoint[] {
- //
- // A------------ ------------B
- // | | up | |
- // | -------|--------------|------- |
- // | | | | | |
- // | | | | | |
- // ------------AP BP------------
- // | |
- // | |
- // left | | right
- // | |
- // | |
- // ------------DP CP------------
- // | | | | | |
- // | | | down | | |
- // | -------|-------------|-------- |
- // | | | |
- // D-----------| |------------C
- //
-
-
- const width = right - left;
- const height = down - up;
- const sampler = 16 / this.targetMatrixSize;
- const sampler2 = 4 / this.targetMatrixSize;
- const deltaX = width * sampler2;
- const deltaY = height * sampler2;
- const areaWidth = deltaX + (right - left) * sampler;
- const areaHeight = deltaY + (down - up) * sampler;
-
- const a = new ResultPoint(left - deltaX, up - deltaY);
- const b = new ResultPoint(right + deltaX, up - deltaY);
- const c = new ResultPoint(right + deltaX, down + deltaY);
- const d = new ResultPoint(left - deltaX, down + deltaY);
-
- const ap = new ResultPoint(a.getX() + areaWidth, a.getY() + areaHeight);
- const bp = new ResultPoint(b.getX() - areaWidth, b.getY() + areaHeight);
- const cp = new ResultPoint(c.getX() - areaWidth, c.getY() - areaHeight);
- const dp = new ResultPoint(d.getX() + areaWidth, d.getY() - areaHeight);
-
- const topLeftCorner = this.getCornerFromArea(a.getX(), ap.getX(), a.getY(), ap.getY(), false, false);
- const topRightCorner = this.getCornerFromArea(bp.getX(), b.getX(), b.getY(), bp.getY(), true, false);
- const bottomRightCorner = this.getCornerFromArea(cp.getX(), c.getX(), cp.getY(), c.getY(), true, true);
- const bottomLeftCorner = this.getCornerFromArea(d.getX(), dp.getX(), dp.getY(), d.getY(), false, true);
-
- const xCorrection = (topRightCorner.getX() - topLeftCorner.getX()) / this.targetMatrixSize;
- const yCorrection = (bottomRightCorner.getY() - topRightCorner.getY()) / this.targetMatrixSize;
-
- const topLeftCornerCenter = new ResultPoint(topLeftCorner.getX() + xCorrection, topLeftCorner.getY() + yCorrection);
- const topRightCornerCenter = new ResultPoint(topRightCorner.getX() - xCorrection, topRightCorner.getY() + yCorrection);
- const bottomRightCornerCenter = new ResultPoint(bottomRightCorner.getX() - xCorrection, bottomRightCorner.getY() - yCorrection);
- const bottomLeftCornerCenter = new ResultPoint(bottomLeftCorner.getX() + xCorrection, bottomLeftCorner.getY() - yCorrection);
-
- const result: ResultPoint[] = [topLeftCornerCenter, topRightCornerCenter, bottomRightCornerCenter, bottomLeftCornerCenter];
- return result;
+ if (resX === 0 || resY === 0) {
+ throw new NotFoundException();
+ } else {
+ return new ResultPoint(resX, resY);
}
-
- private getCornerFromArea(left: number, right: number, top: number, bottom: number, maximizeX: boolean, maximizeY: boolean): ResultPoint {
- let resX = maximizeX ? 0 : Number.MAX_VALUE;
- let resY = maximizeY ? 0 : Number.MAX_VALUE;
- for (let x = left; x < right; x++) {
- for (let y = top; y < bottom; y++) {
- if (x > 0 && y > 0 && x < this.image.getWidth() && y < this.image.getHeight()) {
- if (this.image.get(x, y)) {
- if (maximizeX) {
- if (x > resX) {
- resX = x;
- }
- } else {
- if (x < resX) {
- resX = x;
- }
- }
- if (maximizeY) {
- if (y > resY) {
- resY = y;
- }
- } else {
- if (y < resY) {
- resY = y;
- }
- }
- }
- }
- }
+ }
+
+
+ /**
+ * Determines whether a segment contains a black point
+ *
+ * @param a min value of the scanned coordinate
+ * @param b max value of the scanned coordinate
+ * @param fixed value of fixed coordinate
+ * @param horizontal set to true if scan must be horizontal, false if vertical
+ * @return true if a black point has been found, else false.
+ */
+ private containsBlackPoint(a: number, b: number, fixed: number, horizontal: boolean): boolean {
+
+ if (horizontal) {
+ for (let x = a; x <= b; x++) {
+ if (this.image.get(x, fixed)) {
+ return true;
}
- if (resX === 0 || resY === 0) {
- throw new NotFoundException();
- } else {
- return new ResultPoint(resX, resY);
+ }
+ } else {
+ for (let y = a; y <= b; y++) {
+ if (this.image.get(fixed, y)) {
+ return true;
}
+ }
}
-
- /**
- * Determines whether a segment contains a black point
- *
- * @param a min value of the scanned coordinate
- * @param b max value of the scanned coordinate
- * @param fixed value of fixed coordinate
- * @param horizontal set to true if scan must be horizontal, false if vertical
- * @return true if a black point has been found, else false.
- */
- private containsBlackPoint(a: number, b: number, fixed: number, horizontal: boolean): boolean {
-
- if (horizontal) {
- for (let x = a; x <= b; x++) {
- if (this.image.get(x, fixed)) {
- return true;
- }
- }
- } else {
- for (let y = a; y <= b; y++) {
- if (this.image.get(fixed, y)) {
- return true;
- }
- }
- }
-
- return false;
- }
+ return false;
+ }
}
diff --git a/src/core/common/detector/MonochromeRectangleDetector.ts b/src/core/common/detector/MonochromeRectangleDetector.ts
index c6d68e0b..d3e14acb 100644
--- a/src/core/common/detector/MonochromeRectangleDetector.ts
+++ b/src/core/common/detector/MonochromeRectangleDetector.ts
@@ -213,4 +213,4 @@
// return end > start ? new Int32Array{start, end} : null
// }
-// }
\ No newline at end of file
+// }
diff --git a/src/core/common/detector/WhiteRectangleDetector.ts b/src/core/common/detector/WhiteRectangleDetector.ts
index 8e675379..c65a88e3 100644
--- a/src/core/common/detector/WhiteRectangleDetector.ts
+++ b/src/core/common/detector/WhiteRectangleDetector.ts
@@ -34,314 +34,314 @@ import NotFoundException from '../../NotFoundException';
*/
export default class WhiteRectangleDetector {
- private static INIT_SIZE = 10;
- private static CORR = 1;
-
- private height: number; /*int*/
- private width: number; /*int*/
- private leftInit: number; /*int*/
- private rightInit: number; /*int*/
- private downInit: number; /*int*/
- private upInit: number; /*int*/
-
- // public constructor(private image: BitMatrix) /*throws NotFoundException*/ {
- // this(image, INIT_SIZE, image.getWidth() / 2, image.getHeight() / 2)
- // }
-
- /**
- * @param image barcode image to find a rectangle in
- * @param initSize initial size of search area around center
- * @param x x position of search center
- * @param y y position of search center
- * @throws NotFoundException if image is too small to accommodate {@code initSize}
- */
- public constructor(private image: BitMatrix, initSize?: number /*int*/, x?: number /*int*/, y?: number /*int*/) /*throws NotFoundException*/ {
- this.height = image.getHeight();
- this.width = image.getWidth();
- if (undefined === initSize || null === initSize) {
- initSize = WhiteRectangleDetector.INIT_SIZE;
+ private static INIT_SIZE = 10;
+ private static CORR = 1;
+
+ private height: number; /*int*/
+ private width: number; /*int*/
+ private leftInit: number; /*int*/
+ private rightInit: number; /*int*/
+ private downInit: number; /*int*/
+ private upInit: number; /*int*/
+
+ // public constructor(private image: BitMatrix) /*throws NotFoundException*/ {
+ // this(image, INIT_SIZE, image.getWidth() / 2, image.getHeight() / 2)
+ // }
+
+ /**
+ * @param image barcode image to find a rectangle in
+ * @param initSize initial size of search area around center
+ * @param x x position of search center
+ * @param y y position of search center
+ * @throws NotFoundException if image is too small to accommodate {@code initSize}
+ */
+ public constructor(private image: BitMatrix, initSize?: number /*int*/, x?: number /*int*/, y?: number /*int*/) /*throws NotFoundException*/ {
+ this.height = image.getHeight();
+ this.width = image.getWidth();
+ if (undefined === initSize || null === initSize) {
+ initSize = WhiteRectangleDetector.INIT_SIZE;
+ }
+ if (undefined === x || null === x) {
+ x = image.getWidth() / 2 | 0;
+ }
+ if (undefined === y || null === y) {
+ y = image.getHeight() / 2 | 0;
+ }
+ const halfsize = initSize / 2 | 0;
+ this.leftInit = x - halfsize;
+ this.rightInit = x + halfsize;
+ this.upInit = y - halfsize;
+ this.downInit = y + halfsize;
+ if (this.upInit < 0 || this.leftInit < 0 || this.downInit >= this.height || this.rightInit >= this.width) {
+ throw new NotFoundException();
+ }
+ }
+
+ /**
+ *
+ * Detects a candidate barcode-like rectangular region within an image. It
+ * starts around the center of the image, increases the size of the candidate
+ * region until it finds a white rectangular region.
+ *
+ *
+ * @return {@link ResultPoint}[] describing the corners of the rectangular
+ * region. The first and last points are opposed on the diagonal, as
+ * are the second and third. The first point will be the topmost
+ * point and the last, the bottommost. The second point will be
+ * leftmost and the third, the rightmost
+ * @throws NotFoundException if no Data Matrix Code can be found
+ */
+ public detect(): Array /*throws NotFoundException*/ {
+ let left = this.leftInit;
+ let right = this.rightInit;
+ let up = this.upInit;
+ let down = this.downInit;
+ let sizeExceeded: boolean = false;
+ let aBlackPointFoundOnBorder: boolean = true;
+ let atLeastOneBlackPointFoundOnBorder: boolean = false;
+
+ let atLeastOneBlackPointFoundOnRight: boolean = false;
+ let atLeastOneBlackPointFoundOnBottom: boolean = false;
+ let atLeastOneBlackPointFoundOnLeft: boolean = false;
+ let atLeastOneBlackPointFoundOnTop: boolean = false;
+
+ const width = this.width;
+ const height = this.height;
+
+ while (aBlackPointFoundOnBorder) {
+
+ aBlackPointFoundOnBorder = false;
+
+ // .....
+ // . |
+ // .....
+ let rightBorderNotWhite: boolean = true;
+ while ((rightBorderNotWhite || !atLeastOneBlackPointFoundOnRight) && right < width) {
+ rightBorderNotWhite = this.containsBlackPoint(up, down, right, false);
+ if (rightBorderNotWhite) {
+ right++;
+ aBlackPointFoundOnBorder = true;
+ atLeastOneBlackPointFoundOnRight = true;
+ } else if (!atLeastOneBlackPointFoundOnRight) {
+ right++;
}
- if (undefined === x || null === x) {
- x = image.getWidth() / 2 | 0;
+ }
+
+ if (right >= width) {
+ sizeExceeded = true;
+ break;
+ }
+
+ // .....
+ // . .
+ // .___.
+ let bottomBorderNotWhite: boolean = true;
+ while ((bottomBorderNotWhite || !atLeastOneBlackPointFoundOnBottom) && down < height) {
+ bottomBorderNotWhite = this.containsBlackPoint(left, right, down, true);
+ if (bottomBorderNotWhite) {
+ down++;
+ aBlackPointFoundOnBorder = true;
+ atLeastOneBlackPointFoundOnBottom = true;
+ } else if (!atLeastOneBlackPointFoundOnBottom) {
+ down++;
}
- if (undefined === y || null === y) {
- y = image.getHeight() / 2 | 0;
+ }
+
+ if (down >= height) {
+ sizeExceeded = true;
+ break;
+ }
+
+ // .....
+ // | .
+ // .....
+ let leftBorderNotWhite: boolean = true;
+ while ((leftBorderNotWhite || !atLeastOneBlackPointFoundOnLeft) && left >= 0) {
+ leftBorderNotWhite = this.containsBlackPoint(up, down, left, false);
+ if (leftBorderNotWhite) {
+ left--;
+ aBlackPointFoundOnBorder = true;
+ atLeastOneBlackPointFoundOnLeft = true;
+ } else if (!atLeastOneBlackPointFoundOnLeft) {
+ left--;
}
- const halfsize = initSize / 2 | 0;
- this.leftInit = x - halfsize;
- this.rightInit = x + halfsize;
- this.upInit = y - halfsize;
- this.downInit = y + halfsize;
- if (this.upInit < 0 || this.leftInit < 0 || this.downInit >= this.height || this.rightInit >= this.width) {
- throw new NotFoundException();
+ }
+
+ if (left < 0) {
+ sizeExceeded = true;
+ break;
+ }
+
+ // .___.
+ // . .
+ // .....
+ let topBorderNotWhite: boolean = true;
+ while ((topBorderNotWhite || !atLeastOneBlackPointFoundOnTop) && up >= 0) {
+ topBorderNotWhite = this.containsBlackPoint(left, right, up, true);
+ if (topBorderNotWhite) {
+ up--;
+ aBlackPointFoundOnBorder = true;
+ atLeastOneBlackPointFoundOnTop = true;
+ } else if (!atLeastOneBlackPointFoundOnTop) {
+ up--;
}
- }
+ }
- /**
- *
- * Detects a candidate barcode-like rectangular region within an image. It
- * starts around the center of the image, increases the size of the candidate
- * region until it finds a white rectangular region.
- *
- *
- * @return {@link ResultPoint}[] describing the corners of the rectangular
- * region. The first and last points are opposed on the diagonal, as
- * are the second and third. The first point will be the topmost
- * point and the last, the bottommost. The second point will be
- * leftmost and the third, the rightmost
- * @throws NotFoundException if no Data Matrix Code can be found
- */
- public detect(): Array /*throws NotFoundException*/ {
- let left = this.leftInit;
- let right = this.rightInit;
- let up = this.upInit;
- let down = this.downInit;
- let sizeExceeded: boolean = false;
- let aBlackPointFoundOnBorder: boolean = true;
- let atLeastOneBlackPointFoundOnBorder: boolean = false;
-
- let atLeastOneBlackPointFoundOnRight: boolean = false;
- let atLeastOneBlackPointFoundOnBottom: boolean = false;
- let atLeastOneBlackPointFoundOnLeft: boolean = false;
- let atLeastOneBlackPointFoundOnTop: boolean = false;
-
- const width = this.width;
- const height = this.height;
-
- while (aBlackPointFoundOnBorder) {
-
- aBlackPointFoundOnBorder = false;
-
- // .....
- // . |
- // .....
- let rightBorderNotWhite: boolean = true;
- while ((rightBorderNotWhite || !atLeastOneBlackPointFoundOnRight) && right < width) {
- rightBorderNotWhite = this.containsBlackPoint(up, down, right, false);
- if (rightBorderNotWhite) {
- right++;
- aBlackPointFoundOnBorder = true;
- atLeastOneBlackPointFoundOnRight = true;
- } else if (!atLeastOneBlackPointFoundOnRight) {
- right++;
- }
- }
-
- if (right >= width) {
- sizeExceeded = true;
- break;
- }
-
- // .....
- // . .
- // .___.
- let bottomBorderNotWhite: boolean = true;
- while ((bottomBorderNotWhite || !atLeastOneBlackPointFoundOnBottom) && down < height) {
- bottomBorderNotWhite = this.containsBlackPoint(left, right, down, true);
- if (bottomBorderNotWhite) {
- down++;
- aBlackPointFoundOnBorder = true;
- atLeastOneBlackPointFoundOnBottom = true;
- } else if (!atLeastOneBlackPointFoundOnBottom) {
- down++;
- }
- }
-
- if (down >= height) {
- sizeExceeded = true;
- break;
- }
-
- // .....
- // | .
- // .....
- let leftBorderNotWhite: boolean = true;
- while ((leftBorderNotWhite || !atLeastOneBlackPointFoundOnLeft) && left >= 0) {
- leftBorderNotWhite = this.containsBlackPoint(up, down, left, false);
- if (leftBorderNotWhite) {
- left--;
- aBlackPointFoundOnBorder = true;
- atLeastOneBlackPointFoundOnLeft = true;
- } else if (!atLeastOneBlackPointFoundOnLeft) {
- left--;
- }
- }
-
- if (left < 0) {
- sizeExceeded = true;
- break;
- }
-
- // .___.
- // . .
- // .....
- let topBorderNotWhite: boolean = true;
- while ((topBorderNotWhite || !atLeastOneBlackPointFoundOnTop) && up >= 0) {
- topBorderNotWhite = this.containsBlackPoint(left, right, up, true);
- if (topBorderNotWhite) {
- up--;
- aBlackPointFoundOnBorder = true;
- atLeastOneBlackPointFoundOnTop = true;
- } else if (!atLeastOneBlackPointFoundOnTop) {
- up--;
- }
- }
-
- if (up < 0) {
- sizeExceeded = true;
- break;
- }
-
- if (aBlackPointFoundOnBorder) {
- atLeastOneBlackPointFoundOnBorder = true;
- }
+ if (up < 0) {
+ sizeExceeded = true;
+ break;
+ }
- }
+ if (aBlackPointFoundOnBorder) {
+ atLeastOneBlackPointFoundOnBorder = true;
+ }
- if (!sizeExceeded && atLeastOneBlackPointFoundOnBorder) {
+ }
- const maxSize = right - left;
+ if (!sizeExceeded && atLeastOneBlackPointFoundOnBorder) {
- let z: ResultPoint | null = null;
- for (let i = 1; z === null && i < maxSize; i++) {
- z = this.getBlackPointOnSegment(left, down - i, left + i, down);
- }
+ const maxSize = right - left;
- if (z == null) {
- throw new NotFoundException();
- }
+ let z: ResultPoint | null = null;
+ for (let i = 1; z === null && i < maxSize; i++) {
+ z = this.getBlackPointOnSegment(left, down - i, left + i, down);
+ }
- let t: ResultPoint | null = null;
- // go down right
- for (let i = 1; t === null && i < maxSize; i++) {
- t = this.getBlackPointOnSegment(left, up + i, left + i, up);
- }
+ if (z == null) {
+ throw new NotFoundException();
+ }
- if (t == null) {
- throw new NotFoundException();
- }
+ let t: ResultPoint | null = null;
+ // go down right
+ for (let i = 1; t === null && i < maxSize; i++) {
+ t = this.getBlackPointOnSegment(left, up + i, left + i, up);
+ }
- let x: ResultPoint | null = null;
- // go down left
- for (let i = 1; x === null && i < maxSize; i++) {
- x = this.getBlackPointOnSegment(right, up + i, right - i, up);
- }
+ if (t == null) {
+ throw new NotFoundException();
+ }
- if (x == null) {
- throw new NotFoundException();
- }
+ let x: ResultPoint | null = null;
+ // go down left
+ for (let i = 1; x === null && i < maxSize; i++) {
+ x = this.getBlackPointOnSegment(right, up + i, right - i, up);
+ }
- let y: ResultPoint | null = null;
- // go up left
- for (let i = 1; y === null && i < maxSize; i++) {
- y = this.getBlackPointOnSegment(right, down - i, right - i, down);
- }
+ if (x == null) {
+ throw new NotFoundException();
+ }
- if (y == null) {
- throw new NotFoundException();
- }
+ let y: ResultPoint | null = null;
+ // go up left
+ for (let i = 1; y === null && i < maxSize; i++) {
+ y = this.getBlackPointOnSegment(right, down - i, right - i, down);
+ }
- return this.centerEdges(y, z, x, t);
+ if (y == null) {
+ throw new NotFoundException();
+ }
- } else {
- throw new NotFoundException();
- }
+ return this.centerEdges(y, z, x, t);
+
+ } else {
+ throw new NotFoundException();
}
+ }
- private getBlackPointOnSegment(aX: number/*float*/, aY: number/*float*/, bX: number/*float*/, bY: number/*float*/): ResultPoint | null {
- const dist = MathUtils.round(MathUtils.distance(aX, aY, bX, bY));
- const xStep: number /*float*/ = (bX - aX) / dist;
- const yStep: number /*float*/ = (bY - aY) / dist;
+ private getBlackPointOnSegment(aX: number/*float*/, aY: number/*float*/, bX: number/*float*/, bY: number/*float*/): ResultPoint | null {
+ const dist = MathUtils.round(MathUtils.distance(aX, aY, bX, bY));
+ const xStep: number /*float*/ = (bX - aX) / dist;
+ const yStep: number /*float*/ = (bY - aY) / dist;
- const image = this.image;
+ const image = this.image;
- for (let i = 0; i < dist; i++) {
- const x = MathUtils.round(aX + i * xStep);
- const y = MathUtils.round(aY + i * yStep);
- if (image.get(x, y)) {
- return new ResultPoint(x, y);
- }
- }
- return null;
+ for (let i = 0; i < dist; i++) {
+ const x = MathUtils.round(aX + i * xStep);
+ const y = MathUtils.round(aY + i * yStep);
+ if (image.get(x, y)) {
+ return new ResultPoint(x, y);
+ }
}
-
- /**
- * recenters the points of a constant distance towards the center
- *
- * @param y bottom most point
- * @param z left most point
- * @param x right most point
- * @param t top most point
- * @return {@link ResultPoint}[] describing the corners of the rectangular
- * region. The first and last points are opposed on the diagonal, as
- * are the second and third. The first point will be the topmost
- * point and the last, the bottommost. The second point will be
- * leftmost and the third, the rightmost
- */
- private centerEdges(y: ResultPoint, z: ResultPoint,
- x: ResultPoint, t: ResultPoint): Array {
-
- //
- // t t
- // z x
- // x OR z
- // y y
- //
-
- const yi: number /*float*/ = y.getX();
- const yj: number /*float*/ = y.getY();
- const zi: number /*float*/ = z.getX();
- const zj: number /*float*/ = z.getY();
- const xi: number /*float*/ = x.getX();
- const xj: number /*float*/ = x.getY();
- const ti: number /*float*/ = t.getX();
- const tj: number /*float*/ = t.getY();
-
- const CORR = WhiteRectangleDetector.CORR;
-
- if (yi < this.width / 2.0) {
- return [
- new ResultPoint(ti - CORR, tj + CORR),
- new ResultPoint(zi + CORR, zj + CORR),
- new ResultPoint(xi - CORR, xj - CORR),
- new ResultPoint(yi + CORR, yj - CORR)];
- } else {
- return [
- new ResultPoint(ti + CORR, tj + CORR),
- new ResultPoint(zi + CORR, zj - CORR),
- new ResultPoint(xi - CORR, xj + CORR),
- new ResultPoint(yi - CORR, yj - CORR)];
- }
+ return null;
+ }
+
+ /**
+ * recenters the points of a constant distance towards the center
+ *
+ * @param y bottom most point
+ * @param z left most point
+ * @param x right most point
+ * @param t top most point
+ * @return {@link ResultPoint}[] describing the corners of the rectangular
+ * region. The first and last points are opposed on the diagonal, as
+ * are the second and third. The first point will be the topmost
+ * point and the last, the bottommost. The second point will be
+ * leftmost and the third, the rightmost
+ */
+ private centerEdges(y: ResultPoint, z: ResultPoint,
+ x: ResultPoint, t: ResultPoint): Array {
+
+ //
+ // t t
+ // z x
+ // x OR z
+ // y y
+ //
+
+ const yi: number /*float*/ = y.getX();
+ const yj: number /*float*/ = y.getY();
+ const zi: number /*float*/ = z.getX();
+ const zj: number /*float*/ = z.getY();
+ const xi: number /*float*/ = x.getX();
+ const xj: number /*float*/ = x.getY();
+ const ti: number /*float*/ = t.getX();
+ const tj: number /*float*/ = t.getY();
+
+ const CORR = WhiteRectangleDetector.CORR;
+
+ if (yi < this.width / 2.0) {
+ return [
+ new ResultPoint(ti - CORR, tj + CORR),
+ new ResultPoint(zi + CORR, zj + CORR),
+ new ResultPoint(xi - CORR, xj - CORR),
+ new ResultPoint(yi + CORR, yj - CORR)];
+ } else {
+ return [
+ new ResultPoint(ti + CORR, tj + CORR),
+ new ResultPoint(zi + CORR, zj - CORR),
+ new ResultPoint(xi - CORR, xj + CORR),
+ new ResultPoint(yi - CORR, yj - CORR)];
}
-
- /**
- * Determines whether a segment contains a black point
- *
- * @param a min value of the scanned coordinate
- * @param b max value of the scanned coordinate
- * @param fixed value of fixed coordinate
- * @param horizontal set to true if scan must be horizontal, false if vertical
- * @return true if a black point has been found, else false.
- */
- private containsBlackPoint(a: number /*int*/, b: number /*int*/, fixed: number /*int*/, horizontal: boolean): boolean {
-
- const image = this.image;
-
- if (horizontal) {
- for (let x = a; x <= b; x++) {
- if (image.get(x, fixed)) {
- return true;
- }
- }
- } else {
- for (let y = a; y <= b; y++) {
- if (image.get(fixed, y)) {
- return true;
- }
- }
+ }
+
+ /**
+ * Determines whether a segment contains a black point
+ *
+ * @param a min value of the scanned coordinate
+ * @param b max value of the scanned coordinate
+ * @param fixed value of fixed coordinate
+ * @param horizontal set to true if scan must be horizontal, false if vertical
+ * @return true if a black point has been found, else false.
+ */
+ private containsBlackPoint(a: number /*int*/, b: number /*int*/, fixed: number /*int*/, horizontal: boolean): boolean {
+
+ const image = this.image;
+
+ if (horizontal) {
+ for (let x = a; x <= b; x++) {
+ if (image.get(x, fixed)) {
+ return true;
}
-
- return false;
+ }
+ } else {
+ for (let y = a; y <= b; y++) {
+ if (image.get(fixed, y)) {
+ return true;
+ }
+ }
}
+ return false;
+ }
+
}
diff --git a/src/core/common/reedsolomon/AbstractGenericGFPoly.ts b/src/core/common/reedsolomon/AbstractGenericGFPoly.ts
index fb575e6a..58328e14 100644
--- a/src/core/common/reedsolomon/AbstractGenericGFPoly.ts
+++ b/src/core/common/reedsolomon/AbstractGenericGFPoly.ts
@@ -30,108 +30,108 @@ import AbstractGenericGF from './AbstractGenericGF';
*/
export default abstract class AbstractGenericGFPoly {
- protected field: AbstractGenericGF;
- protected coefficients: Int32Array;
-
- public getCoefficients(): Int32Array {
- return this.coefficients;
+ protected field: AbstractGenericGF;
+ protected coefficients: Int32Array;
+
+ public getCoefficients(): Int32Array {
+ return this.coefficients;
+ }
+
+ /**
+ * @return degree of this polynomial
+ */
+ public getDegree(): number {
+ return this.coefficients.length - 1;
+ }
+
+ /**
+ * @return true iff this polynomial is the monomial "0"
+ */
+ public isZero(): boolean {
+ return this.coefficients[0] === 0;
+ }
+
+ /**
+ * @return coefficient of x^degree term in this polynomial
+ */
+ public getCoefficient(degree: number /*int*/): number {
+ return this.coefficients[this.coefficients.length - 1 - degree];
+ }
+
+ /**
+ * @return evaluation of this polynomial at a given point
+ */
+ public evaluateAt(a: number /*int*/): number {
+ if (a === 0) {
+ // Just return the x^0 coefficient
+ return this.getCoefficient(0);
}
-
- /**
- * @return degree of this polynomial
- */
- public getDegree(): number {
- return this.coefficients.length - 1;
+ const coefficients = this.coefficients;
+ let result: number;
+ if (a === 1) {
+ // Just the sum of the coefficients
+ result = 0;
+ for (let i = 0, length = coefficients.length; i !== length; i++) {
+ const coefficient = coefficients[i];
+ result = AbstractGenericGF.addOrSubtract(result, coefficient);
+ }
+ return result;
}
-
- /**
- * @return true iff this polynomial is the monomial "0"
- */
- public isZero(): boolean {
- return this.coefficients[0] === 0;
+ result = coefficients[0];
+ const size = coefficients.length;
+ const field = this.field;
+ for (let i = 1; i < size; i++) {
+ result = AbstractGenericGF.addOrSubtract(field.multiply(a, result), coefficients[i]);
}
+ return result;
+ }
- /**
- * @return coefficient of x^degree term in this polynomial
- */
- public getCoefficient(degree: number /*int*/): number {
- return this.coefficients[this.coefficients.length - 1 - degree];
- }
+ public abstract addOrSubtract(other: AbstractGenericGFPoly): AbstractGenericGFPoly;
- /**
- * @return evaluation of this polynomial at a given point
- */
- public evaluateAt(a: number /*int*/): number {
- if (a === 0) {
- // Just return the x^0 coefficient
- return this.getCoefficient(0);
- }
- const coefficients = this.coefficients;
- let result: number;
- if (a === 1) {
- // Just the sum of the coefficients
- result = 0;
- for (let i = 0, length = coefficients.length; i !== length; i++) {
- const coefficient = coefficients[i];
- result = AbstractGenericGF.addOrSubtract(result, coefficient);
- }
- return result;
+ public abstract multiply(other: AbstractGenericGFPoly): AbstractGenericGFPoly;
+
+ public abstract multiplyScalar(scalar: number /*int*/): AbstractGenericGFPoly;
+
+ public abstract multiplyByMonomial(degree: number /*int*/, coefficient: number /*int*/): AbstractGenericGFPoly;
+
+ public abstract divide(other: AbstractGenericGFPoly): AbstractGenericGFPoly[];
+
+ /*@Override*/
+ public toString(): string {
+ let result = '';
+ for (let degree = this.getDegree(); degree >= 0; degree--) {
+ let coefficient = this.getCoefficient(degree);
+ if (coefficient !== 0) {
+ if (coefficient < 0) {
+ result += ' - ';
+ coefficient = -coefficient;
+ } else {
+ if (result.length > 0) {
+ result += ' + ';
+ }
}
- result = coefficients[0];
- const size = coefficients.length;
- const field = this.field;
- for (let i = 1; i < size; i++) {
- result = AbstractGenericGF.addOrSubtract(field.multiply(a, result), coefficients[i]);
+ if (degree === 0 || coefficient !== 1) {
+ const alphaPower = this.field.log(coefficient);
+ if (alphaPower === 0) {
+ result += '1';
+ } else if (alphaPower === 1) {
+ result += 'a';
+ } else {
+ result += 'a^';
+ result += alphaPower;
+ }
}
- return result;
- }
-
- public abstract addOrSubtract(other: AbstractGenericGFPoly): AbstractGenericGFPoly;
-
- public abstract multiply(other: AbstractGenericGFPoly): AbstractGenericGFPoly;
-
- public abstract multiplyScalar(scalar: number /*int*/): AbstractGenericGFPoly;
-
- public abstract multiplyByMonomial(degree: number /*int*/, coefficient: number /*int*/): AbstractGenericGFPoly;
-
- public abstract divide(other: AbstractGenericGFPoly): AbstractGenericGFPoly[];
-
- /*@Override*/
- public toString(): string {
- let result = '';
- for (let degree = this.getDegree(); degree >= 0; degree--) {
- let coefficient = this.getCoefficient(degree);
- if (coefficient !== 0) {
- if (coefficient < 0) {
- result += ' - ';
- coefficient = -coefficient;
- } else {
- if (result.length > 0) {
- result += ' + ';
- }
- }
- if (degree === 0 || coefficient !== 1) {
- const alphaPower = this.field.log(coefficient);
- if (alphaPower === 0) {
- result += '1';
- } else if (alphaPower === 1) {
- result += 'a';
- } else {
- result += 'a^';
- result += alphaPower;
- }
- }
- if (degree !== 0) {
- if (degree === 1) {
- result += 'x';
- } else {
- result += 'x^';
- result += degree;
- }
- }
- }
+ if (degree !== 0) {
+ if (degree === 1) {
+ result += 'x';
+ } else {
+ result += 'x^';
+ result += degree;
+ }
}
- return result;
+ }
}
+ return result;
+ }
}
diff --git a/src/core/common/reedsolomon/GenericGFPoly.ts b/src/core/common/reedsolomon/GenericGFPoly.ts
index 9de5e245..d832c946 100644
--- a/src/core/common/reedsolomon/GenericGFPoly.ts
+++ b/src/core/common/reedsolomon/GenericGFPoly.ts
@@ -32,249 +32,249 @@ import IllegalArgumentException from '../../IllegalArgumentException';
*/
export default class GenericGFPoly {
- private field: AbstractGenericGF;
- private coefficients: Int32Array;
+ private field: AbstractGenericGF;
+ private coefficients: Int32Array;
- /**
- * @param field the {@link GenericGF} instance representing the field to use
- * to perform computations
- * @param coefficients coefficients as ints representing elements of GF(size), arranged
- * from most significant (highest-power term) coefficient to least significant
- * @throws IllegalArgumentException if argument is null or empty,
- * or if leading coefficient is 0 and this is not a
- * constant polynomial (that is, it is not the monomial "0")
- */
- public constructor(field: AbstractGenericGF, coefficients: Int32Array) {
- if (coefficients.length === 0) {
- throw new IllegalArgumentException();
- }
- this.field = field;
- const coefficientsLength = coefficients.length;
- if (coefficientsLength > 1 && coefficients[0] === 0) {
- // Leading term must be non-zero for anything except the constant polynomial "0"
- let firstNonZero = 1;
- while (firstNonZero < coefficientsLength && coefficients[firstNonZero] === 0) {
- firstNonZero++;
- }
- if (firstNonZero === coefficientsLength) {
- this.coefficients = Int32Array.from([0]);
- } else {
- this.coefficients = new Int32Array(coefficientsLength - firstNonZero);
- System.arraycopy(coefficients,
- firstNonZero,
- this.coefficients,
- 0,
- this.coefficients.length);
- }
- } else {
- this.coefficients = coefficients;
- }
+ /**
+ * @param field the {@link GenericGF} instance representing the field to use
+ * to perform computations
+ * @param coefficients coefficients as ints representing elements of GF(size), arranged
+ * from most significant (highest-power term) coefficient to least significant
+ * @throws IllegalArgumentException if argument is null or empty,
+ * or if leading coefficient is 0 and this is not a
+ * constant polynomial (that is, it is not the monomial "0")
+ */
+ public constructor(field: AbstractGenericGF, coefficients: Int32Array) {
+ if (coefficients.length === 0) {
+ throw new IllegalArgumentException();
}
-
- public getCoefficients(): Int32Array {
- return this.coefficients;
+ this.field = field;
+ const coefficientsLength = coefficients.length;
+ if (coefficientsLength > 1 && coefficients[0] === 0) {
+ // Leading term must be non-zero for anything except the constant polynomial "0"
+ let firstNonZero = 1;
+ while (firstNonZero < coefficientsLength && coefficients[firstNonZero] === 0) {
+ firstNonZero++;
+ }
+ if (firstNonZero === coefficientsLength) {
+ this.coefficients = Int32Array.from([0]);
+ } else {
+ this.coefficients = new Int32Array(coefficientsLength - firstNonZero);
+ System.arraycopy(coefficients,
+ firstNonZero,
+ this.coefficients,
+ 0,
+ this.coefficients.length);
+ }
+ } else {
+ this.coefficients = coefficients;
}
+ }
- /**
- * @return degree of this polynomial
- */
- public getDegree(): number {
- return this.coefficients.length - 1;
- }
+ public getCoefficients(): Int32Array {
+ return this.coefficients;
+ }
- /**
- * @return true iff this polynomial is the monomial "0"
- */
- public isZero(): boolean {
- return this.coefficients[0] === 0;
- }
+ /**
+ * @return degree of this polynomial
+ */
+ public getDegree(): number {
+ return this.coefficients.length - 1;
+ }
- /**
- * @return coefficient of x^degree term in this polynomial
- */
- public getCoefficient(degree: number /*int*/): number {
- return this.coefficients[this.coefficients.length - 1 - degree];
+ /**
+ * @return true iff this polynomial is the monomial "0"
+ */
+ public isZero(): boolean {
+ return this.coefficients[0] === 0;
+ }
+
+ /**
+ * @return coefficient of x^degree term in this polynomial
+ */
+ public getCoefficient(degree: number /*int*/): number {
+ return this.coefficients[this.coefficients.length - 1 - degree];
+ }
+
+ /**
+ * @return evaluation of this polynomial at a given point
+ */
+ public evaluateAt(a: number /*int*/): number {
+ if (a === 0) {
+ // Just return the x^0 coefficient
+ return this.getCoefficient(0);
+ }
+ const coefficients = this.coefficients;
+ let result: number;
+ if (a === 1) {
+ // Just the sum of the coefficients
+ result = 0;
+ for (let i = 0, length = coefficients.length; i !== length; i++) {
+ const coefficient = coefficients[i];
+ result = AbstractGenericGF.addOrSubtract(result, coefficient);
+ }
+ return result;
}
+ result = coefficients[0];
+ const size = coefficients.length;
+ const field = this.field;
+ for (let i = 1; i < size; i++) {
+ result = AbstractGenericGF.addOrSubtract(field.multiply(a, result), coefficients[i]);
+ }
+ return result;
+ }
- /**
- * @return evaluation of this polynomial at a given point
- */
- public evaluateAt(a: number /*int*/): number {
- if (a === 0) {
- // Just return the x^0 coefficient
- return this.getCoefficient(0);
- }
- const coefficients = this.coefficients;
- let result: number;
- if (a === 1) {
- // Just the sum of the coefficients
- result = 0;
- for (let i = 0, length = coefficients.length; i !== length; i++) {
- const coefficient = coefficients[i];
- result = AbstractGenericGF.addOrSubtract(result, coefficient);
- }
- return result;
- }
- result = coefficients[0];
- const size = coefficients.length;
- const field = this.field;
- for (let i = 1; i < size; i++) {
- result = AbstractGenericGF.addOrSubtract(field.multiply(a, result), coefficients[i]);
- }
- return result;
+ public addOrSubtract(other: GenericGFPoly): GenericGFPoly {
+ if (!this.field.equals(other.field)) {
+ throw new IllegalArgumentException('GenericGFPolys do not have same GenericGF field');
+ }
+ if (this.isZero()) {
+ return other;
+ }
+ if (other.isZero()) {
+ return this;
}
- public addOrSubtract(other: GenericGFPoly): GenericGFPoly {
- if (!this.field.equals(other.field)) {
- throw new IllegalArgumentException('GenericGFPolys do not have same GenericGF field');
- }
- if (this.isZero()) {
- return other;
- }
- if (other.isZero()) {
- return this;
- }
+ let smallerCoefficients = this.coefficients;
+ let largerCoefficients = other.coefficients;
+ if (smallerCoefficients.length > largerCoefficients.length) {
+ const temp = smallerCoefficients;
+ smallerCoefficients = largerCoefficients;
+ largerCoefficients = temp;
+ }
+ let sumDiff = new Int32Array(largerCoefficients.length);
+ const lengthDiff = largerCoefficients.length - smallerCoefficients.length;
+ // Copy high-order terms only found in higher-degree polynomial's coefficients
+ System.arraycopy(largerCoefficients, 0, sumDiff, 0, lengthDiff);
- let smallerCoefficients = this.coefficients;
- let largerCoefficients = other.coefficients;
- if (smallerCoefficients.length > largerCoefficients.length) {
- const temp = smallerCoefficients;
- smallerCoefficients = largerCoefficients;
- largerCoefficients = temp;
- }
- let sumDiff = new Int32Array(largerCoefficients.length);
- const lengthDiff = largerCoefficients.length - smallerCoefficients.length;
- // Copy high-order terms only found in higher-degree polynomial's coefficients
- System.arraycopy(largerCoefficients, 0, sumDiff, 0, lengthDiff);
+ for (let i = lengthDiff; i < largerCoefficients.length; i++) {
+ sumDiff[i] = AbstractGenericGF.addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
+ }
- for (let i = lengthDiff; i < largerCoefficients.length; i++) {
- sumDiff[i] = AbstractGenericGF.addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
- }
+ return new GenericGFPoly(this.field, sumDiff);
+ }
- return new GenericGFPoly(this.field, sumDiff);
+ public multiply(other: GenericGFPoly): GenericGFPoly {
+ if (!this.field.equals(other.field)) {
+ throw new IllegalArgumentException('GenericGFPolys do not have same GenericGF field');
}
-
- public multiply(other: GenericGFPoly): GenericGFPoly {
- if (!this.field.equals(other.field)) {
- throw new IllegalArgumentException('GenericGFPolys do not have same GenericGF field');
- }
- if (this.isZero() || other.isZero()) {
- return this.field.getZero();
- }
- const aCoefficients = this.coefficients;
- const aLength = aCoefficients.length;
- const bCoefficients = other.coefficients;
- const bLength = bCoefficients.length;
- const product = new Int32Array(aLength + bLength - 1);
- const field = this.field;
- for (let i = 0; i < aLength; i++) {
- const aCoeff = aCoefficients[i];
- for (let j = 0; j < bLength; j++) {
- product[i + j] = AbstractGenericGF.addOrSubtract(product[i + j],
- field.multiply(aCoeff, bCoefficients[j]));
- }
- }
- return new GenericGFPoly(field, product);
+ if (this.isZero() || other.isZero()) {
+ return this.field.getZero();
}
-
- public multiplyScalar(scalar: number /*int*/): GenericGFPoly {
- if (scalar === 0) {
- return this.field.getZero();
- }
- if (scalar === 1) {
- return this;
- }
- const size = this.coefficients.length;
- const field = this.field;
- const product = new Int32Array(size);
- const coefficients = this.coefficients;
- for (let i = 0; i < size; i++) {
- product[i] = field.multiply(coefficients[i], scalar);
- }
- return new GenericGFPoly(field, product);
+ const aCoefficients = this.coefficients;
+ const aLength = aCoefficients.length;
+ const bCoefficients = other.coefficients;
+ const bLength = bCoefficients.length;
+ const product = new Int32Array(aLength + bLength - 1);
+ const field = this.field;
+ for (let i = 0; i < aLength; i++) {
+ const aCoeff = aCoefficients[i];
+ for (let j = 0; j < bLength; j++) {
+ product[i + j] = AbstractGenericGF.addOrSubtract(product[i + j],
+ field.multiply(aCoeff, bCoefficients[j]));
+ }
}
+ return new GenericGFPoly(field, product);
+ }
- public multiplyByMonomial(degree: number /*int*/, coefficient: number /*int*/): GenericGFPoly {
- if (degree < 0) {
- throw new IllegalArgumentException();
- }
- if (coefficient === 0) {
- return this.field.getZero();
- }
- const coefficients = this.coefficients;
- const size = coefficients.length;
- const product = new Int32Array(size + degree);
- const field = this.field;
- for (let i = 0; i < size; i++) {
- product[i] = field.multiply(coefficients[i], coefficient);
- }
- return new GenericGFPoly(field, product);
+ public multiplyScalar(scalar: number /*int*/): GenericGFPoly {
+ if (scalar === 0) {
+ return this.field.getZero();
}
+ if (scalar === 1) {
+ return this;
+ }
+ const size = this.coefficients.length;
+ const field = this.field;
+ const product = new Int32Array(size);
+ const coefficients = this.coefficients;
+ for (let i = 0; i < size; i++) {
+ product[i] = field.multiply(coefficients[i], scalar);
+ }
+ return new GenericGFPoly(field, product);
+ }
- public divide(other: GenericGFPoly): GenericGFPoly[] {
- if (!this.field.equals(other.field)) {
- throw new IllegalArgumentException('GenericGFPolys do not have same GenericGF field');
- }
- if (other.isZero()) {
- throw new IllegalArgumentException('Divide by 0');
- }
+ public multiplyByMonomial(degree: number /*int*/, coefficient: number /*int*/): GenericGFPoly {
+ if (degree < 0) {
+ throw new IllegalArgumentException();
+ }
+ if (coefficient === 0) {
+ return this.field.getZero();
+ }
+ const coefficients = this.coefficients;
+ const size = coefficients.length;
+ const product = new Int32Array(size + degree);
+ const field = this.field;
+ for (let i = 0; i < size; i++) {
+ product[i] = field.multiply(coefficients[i], coefficient);
+ }
+ return new GenericGFPoly(field, product);
+ }
- const field = this.field;
+ public divide(other: GenericGFPoly): GenericGFPoly[] {
+ if (!this.field.equals(other.field)) {
+ throw new IllegalArgumentException('GenericGFPolys do not have same GenericGF field');
+ }
+ if (other.isZero()) {
+ throw new IllegalArgumentException('Divide by 0');
+ }
- let quotient: GenericGFPoly = field.getZero();
- let remainder: GenericGFPoly = this;
+ const field = this.field;
- const denominatorLeadingTerm = other.getCoefficient(other.getDegree());
- const inverseDenominatorLeadingTerm = field.inverse(denominatorLeadingTerm);
+ let quotient: GenericGFPoly = field.getZero();
+ let remainder: GenericGFPoly = this;
- while (remainder.getDegree() >= other.getDegree() && !remainder.isZero()) {
- const degreeDifference = remainder.getDegree() - other.getDegree();
- const scale = field.multiply(remainder.getCoefficient(remainder.getDegree()), inverseDenominatorLeadingTerm);
- const term = other.multiplyByMonomial(degreeDifference, scale);
- const iterationQuotient = field.buildMonomial(degreeDifference, scale);
- quotient = quotient.addOrSubtract(iterationQuotient);
- remainder = remainder.addOrSubtract(term);
- }
+ const denominatorLeadingTerm = other.getCoefficient(other.getDegree());
+ const inverseDenominatorLeadingTerm = field.inverse(denominatorLeadingTerm);
- return [quotient, remainder];
+ while (remainder.getDegree() >= other.getDegree() && !remainder.isZero()) {
+ const degreeDifference = remainder.getDegree() - other.getDegree();
+ const scale = field.multiply(remainder.getCoefficient(remainder.getDegree()), inverseDenominatorLeadingTerm);
+ const term = other.multiplyByMonomial(degreeDifference, scale);
+ const iterationQuotient = field.buildMonomial(degreeDifference, scale);
+ quotient = quotient.addOrSubtract(iterationQuotient);
+ remainder = remainder.addOrSubtract(term);
}
- /*@Override*/
- public toString(): string {
- let result = '';
- for (let degree = this.getDegree(); degree >= 0; degree--) {
- let coefficient = this.getCoefficient(degree);
- if (coefficient !== 0) {
- if (coefficient < 0) {
- result += ' - ';
- coefficient = -coefficient;
- } else {
- if (result.length > 0) {
- result += ' + ';
- }
- }
- if (degree === 0 || coefficient !== 1) {
- const alphaPower = this.field.log(coefficient);
- if (alphaPower === 0) {
- result += '1';
- } else if (alphaPower === 1) {
- result += 'a';
- } else {
- result += 'a^';
- result += alphaPower;
- }
- }
- if (degree !== 0) {
- if (degree === 1) {
- result += 'x';
- } else {
- result += 'x^';
- result += degree;
- }
- }
- }
+ return [quotient, remainder];
+ }
+
+ /*@Override*/
+ public toString(): string {
+ let result = '';
+ for (let degree = this.getDegree(); degree >= 0; degree--) {
+ let coefficient = this.getCoefficient(degree);
+ if (coefficient !== 0) {
+ if (coefficient < 0) {
+ result += ' - ';
+ coefficient = -coefficient;
+ } else {
+ if (result.length > 0) {
+ result += ' + ';
+ }
+ }
+ if (degree === 0 || coefficient !== 1) {
+ const alphaPower = this.field.log(coefficient);
+ if (alphaPower === 0) {
+ result += '1';
+ } else if (alphaPower === 1) {
+ result += 'a';
+ } else {
+ result += 'a^';
+ result += alphaPower;
+ }
+ }
+ if (degree !== 0) {
+ if (degree === 1) {
+ result += 'x';
+ } else {
+ result += 'x^';
+ result += degree;
+ }
}
- return result;
+ }
}
+ return result;
+ }
}
diff --git a/src/core/common/reedsolomon/ReedSolomonDecoder.ts b/src/core/common/reedsolomon/ReedSolomonDecoder.ts
index 1f2a5de8..ab9ab5ce 100644
--- a/src/core/common/reedsolomon/ReedSolomonDecoder.ts
+++ b/src/core/common/reedsolomon/ReedSolomonDecoder.ts
@@ -46,150 +46,150 @@ import IllegalStateException from '../../IllegalStateException';
*/
export default class ReedSolomonDecoder {
- public constructor(private field: GenericGF) { }
-
- /**
- *
Decodes given set of received codewords, which include both data and error-correction
- * codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place,
- * in the input.
- *
- * @param received data and error-correction codewords
- * @param twoS number of error-correction codewords available
- * @throws ReedSolomonException if decoding fails for any reason
- */
- public decode(received: Int32Array, twoS: number /*int*/): void /*throws ReedSolomonException*/ {
- const field = this.field;
- const poly = new GenericGFPoly(field, received);
- const syndromeCoefficients = new Int32Array(twoS);
- let noError: boolean = true;
- for (let i = 0; i < twoS; i++) {
- const evalResult = poly.evaluateAt(field.exp(i + field.getGeneratorBase()));
- syndromeCoefficients[syndromeCoefficients.length - 1 - i] = evalResult;
- if (evalResult !== 0) {
- noError = false;
- }
- }
- if (noError) {
- return;
- }
- const syndrome = new GenericGFPoly(field, syndromeCoefficients);
- const sigmaOmega = this.runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS);
- const sigma = sigmaOmega[0];
- const omega = sigmaOmega[1];
- const errorLocations = this.findErrorLocations(sigma);
- const errorMagnitudes = this.findErrorMagnitudes(omega, errorLocations);
- for (let i = 0; i < errorLocations.length; i++) {
- const position = received.length - 1 - field.log(errorLocations[i]);
- if (position < 0) {
- throw new ReedSolomonException('Bad error location');
- }
- received[position] = GenericGF.addOrSubtract(received[position], errorMagnitudes[i]);
- }
+ public constructor(private field: GenericGF) { }
+
+ /**
+ *
Decodes given set of received codewords, which include both data and error-correction
+ * codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place,
+ * in the input.
+ *
+ * @param received data and error-correction codewords
+ * @param twoS number of error-correction codewords available
+ * @throws ReedSolomonException if decoding fails for any reason
+ */
+ public decode(received: Int32Array, twoS: number /*int*/): void /*throws ReedSolomonException*/ {
+ const field = this.field;
+ const poly = new GenericGFPoly(field, received);
+ const syndromeCoefficients = new Int32Array(twoS);
+ let noError: boolean = true;
+ for (let i = 0; i < twoS; i++) {
+ const evalResult = poly.evaluateAt(field.exp(i + field.getGeneratorBase()));
+ syndromeCoefficients[syndromeCoefficients.length - 1 - i] = evalResult;
+ if (evalResult !== 0) {
+ noError = false;
+ }
+ }
+ if (noError) {
+ return;
+ }
+ const syndrome = new GenericGFPoly(field, syndromeCoefficients);
+ const sigmaOmega = this.runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS);
+ const sigma = sigmaOmega[0];
+ const omega = sigmaOmega[1];
+ const errorLocations = this.findErrorLocations(sigma);
+ const errorMagnitudes = this.findErrorMagnitudes(omega, errorLocations);
+ for (let i = 0; i < errorLocations.length; i++) {
+ const position = received.length - 1 - field.log(errorLocations[i]);
+ if (position < 0) {
+ throw new ReedSolomonException('Bad error location');
+ }
+ received[position] = GenericGF.addOrSubtract(received[position], errorMagnitudes[i]);
+ }
+ }
+
+ private runEuclideanAlgorithm(a: GenericGFPoly, b: GenericGFPoly, R: number /*int*/): GenericGFPoly[] {
+ // Assume a's degree is >= b's
+ if (a.getDegree() < b.getDegree()) {
+ const temp = a;
+ a = b;
+ b = temp;
}
- private runEuclideanAlgorithm(a: GenericGFPoly, b: GenericGFPoly, R: number /*int*/): GenericGFPoly[] {
- // Assume a's degree is >= b's
- if (a.getDegree() < b.getDegree()) {
- const temp = a;
- a = b;
- b = temp;
- }
-
- const field = this.field;
-
- let rLast = a;
- let r = b;
- let tLast = field.getZero();
- let t = field.getOne();
-
- // Run Euclidean algorithm until r's degree is less than R/2
- while (r.getDegree() >= (R / 2 | 0)) {
- let rLastLast = rLast;
- let tLastLast = tLast;
- rLast = r;
- tLast = t;
-
- // Divide rLastLast by rLast, with quotient in q and remainder in r
- if (rLast.isZero()) {
- // Oops, Euclidean algorithm already terminated?
- throw new ReedSolomonException('r_{i-1} was zero');
- }
- r = rLastLast;
- let q = field.getZero();
- const denominatorLeadingTerm = rLast.getCoefficient(rLast.getDegree());
- const dltInverse = field.inverse(denominatorLeadingTerm);
- while (r.getDegree() >= rLast.getDegree() && !r.isZero()) {
- const degreeDiff = r.getDegree() - rLast.getDegree();
- const scale = field.multiply(r.getCoefficient(r.getDegree()), dltInverse);
- q = q.addOrSubtract(field.buildMonomial(degreeDiff, scale));
- r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale));
- }
-
- t = q.multiply(tLast).addOrSubtract(tLastLast);
-
- if (r.getDegree() >= rLast.getDegree()) {
- throw new IllegalStateException('Division algorithm failed to reduce polynomial?');
- }
- }
-
- const sigmaTildeAtZero = t.getCoefficient(0);
- if (sigmaTildeAtZero === 0) {
- throw new ReedSolomonException('sigmaTilde(0) was zero');
- }
-
- const inverse = field.inverse(sigmaTildeAtZero);
- const sigma = t.multiplyScalar(inverse);
- const omega = r.multiplyScalar(inverse);
- return [sigma, omega];
+ const field = this.field;
+
+ let rLast = a;
+ let r = b;
+ let tLast = field.getZero();
+ let t = field.getOne();
+
+ // Run Euclidean algorithm until r's degree is less than R/2
+ while (r.getDegree() >= (R / 2 | 0)) {
+ let rLastLast = rLast;
+ let tLastLast = tLast;
+ rLast = r;
+ tLast = t;
+
+ // Divide rLastLast by rLast, with quotient in q and remainder in r
+ if (rLast.isZero()) {
+ // Oops, Euclidean algorithm already terminated?
+ throw new ReedSolomonException('r_{i-1} was zero');
+ }
+ r = rLastLast;
+ let q = field.getZero();
+ const denominatorLeadingTerm = rLast.getCoefficient(rLast.getDegree());
+ const dltInverse = field.inverse(denominatorLeadingTerm);
+ while (r.getDegree() >= rLast.getDegree() && !r.isZero()) {
+ const degreeDiff = r.getDegree() - rLast.getDegree();
+ const scale = field.multiply(r.getCoefficient(r.getDegree()), dltInverse);
+ q = q.addOrSubtract(field.buildMonomial(degreeDiff, scale));
+ r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale));
+ }
+
+ t = q.multiply(tLast).addOrSubtract(tLastLast);
+
+ if (r.getDegree() >= rLast.getDegree()) {
+ throw new IllegalStateException('Division algorithm failed to reduce polynomial?');
+ }
}
- private findErrorLocations(errorLocator: GenericGFPoly): Int32Array /*throws ReedSolomonException*/ {
- // This is a direct application of Chien's search
- const numErrors = errorLocator.getDegree();
- if (numErrors === 1) { // shortcut
- return Int32Array.from([errorLocator.getCoefficient(1)]);
- }
- const result = new Int32Array(numErrors);
- let e = 0;
- const field = this.field;
- for (let i = 1; i < field.getSize() && e < numErrors; i++) {
- if (errorLocator.evaluateAt(i) === 0) {
- result[e] = field.inverse(i);
- e++;
- }
- }
- if (e !== numErrors) {
- throw new ReedSolomonException('Error locator degree does not match number of roots');
- }
- return result;
+ const sigmaTildeAtZero = t.getCoefficient(0);
+ if (sigmaTildeAtZero === 0) {
+ throw new ReedSolomonException('sigmaTilde(0) was zero');
}
- private findErrorMagnitudes(errorEvaluator: GenericGFPoly, errorLocations: Int32Array): Int32Array {
- // This is directly applying Forney's Formula
- const s = errorLocations.length;
- const result = new Int32Array(s);
- const field = this.field;
- for (let i = 0; i < s; i++) {
- const xiInverse = field.inverse(errorLocations[i]);
- let denominator = 1;
- for (let j = 0; j < s; j++) {
- if (i !== j) {
- // denominator = field.multiply(denominator,
- // GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse)))
- // Above should work but fails on some Apple and Linux JDKs due to a Hotspot bug.
- // Below is a funny-looking workaround from Steven Parkes
- const term = field.multiply(errorLocations[j], xiInverse);
- const termPlus1 = (term & 0x1) === 0 ? term | 1 : term & ~1;
- denominator = field.multiply(denominator, termPlus1);
- }
- }
- result[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse),
- field.inverse(denominator));
- if (field.getGeneratorBase() !== 0) {
- result[i] = field.multiply(result[i], xiInverse);
- }
+ const inverse = field.inverse(sigmaTildeAtZero);
+ const sigma = t.multiplyScalar(inverse);
+ const omega = r.multiplyScalar(inverse);
+ return [sigma, omega];
+ }
+
+ private findErrorLocations(errorLocator: GenericGFPoly): Int32Array /*throws ReedSolomonException*/ {
+ // This is a direct application of Chien's search
+ const numErrors = errorLocator.getDegree();
+ if (numErrors === 1) { // shortcut
+ return Int32Array.from([errorLocator.getCoefficient(1)]);
+ }
+ const result = new Int32Array(numErrors);
+ let e = 0;
+ const field = this.field;
+ for (let i = 1; i < field.getSize() && e < numErrors; i++) {
+ if (errorLocator.evaluateAt(i) === 0) {
+ result[e] = field.inverse(i);
+ e++;
+ }
+ }
+ if (e !== numErrors) {
+ throw new ReedSolomonException('Error locator degree does not match number of roots');
+ }
+ return result;
+ }
+
+ private findErrorMagnitudes(errorEvaluator: GenericGFPoly, errorLocations: Int32Array): Int32Array {
+ // This is directly applying Forney's Formula
+ const s = errorLocations.length;
+ const result = new Int32Array(s);
+ const field = this.field;
+ for (let i = 0; i < s; i++) {
+ const xiInverse = field.inverse(errorLocations[i]);
+ let denominator = 1;
+ for (let j = 0; j < s; j++) {
+ if (i !== j) {
+ // denominator = field.multiply(denominator,
+ // GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse)))
+ // Above should work but fails on some Apple and Linux JDKs due to a Hotspot bug.
+ // Below is a funny-looking workaround from Steven Parkes
+ const term = field.multiply(errorLocations[j], xiInverse);
+ const termPlus1 = (term & 0x1) === 0 ? term | 1 : term & ~1;
+ denominator = field.multiply(denominator, termPlus1);
}
- return result;
+ }
+ result[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse),
+ field.inverse(denominator));
+ if (field.getGeneratorBase() !== 0) {
+ result[i] = field.multiply(result[i], xiInverse);
+ }
}
+ return result;
+ }
}
diff --git a/src/core/common/reedsolomon/ReedSolomonEncoder.ts b/src/core/common/reedsolomon/ReedSolomonEncoder.ts
index a97eec14..1029c283 100644
--- a/src/core/common/reedsolomon/ReedSolomonEncoder.ts
+++ b/src/core/common/reedsolomon/ReedSolomonEncoder.ts
@@ -33,77 +33,77 @@ import IllegalArgumentException from '../../IllegalArgumentException';
*/
export default class ReedSolomonEncoder {
- private field: GenericGF;
- private cachedGenerators: GenericGFPoly[];
+ private field: GenericGF;
+ private cachedGenerators: GenericGFPoly[];
- /**
- * A reed solomon error-correcting encoding constructor is created by
- * passing as Galois Field with of size equal to the number of code
- * words (symbols) in the alphabet (the number of values in each
- * element of arrays that are encoded/decoded).
- * @param field A galois field with a number of elements equal to the size
- * of the alphabet of symbols to encode.
- */
- public constructor(field: GenericGF) {
- this.field = field;
- this.cachedGenerators = [];
- this.cachedGenerators.push(new GenericGFPoly(field, Int32Array.from([1])));
- }
+ /**
+ * A reed solomon error-correcting encoding constructor is created by
+ * passing as Galois Field with of size equal to the number of code
+ * words (symbols) in the alphabet (the number of values in each
+ * element of arrays that are encoded/decoded).
+ * @param field A galois field with a number of elements equal to the size
+ * of the alphabet of symbols to encode.
+ */
+ public constructor(field: GenericGF) {
+ this.field = field;
+ this.cachedGenerators = [];
+ this.cachedGenerators.push(new GenericGFPoly(field, Int32Array.from([1])));
+ }
- private buildGenerator(degree: number /*int*/): GenericGFPoly {
- const cachedGenerators = this.cachedGenerators;
- if (degree >= cachedGenerators.length) {
- let lastGenerator = cachedGenerators[cachedGenerators.length - 1];
- const field = this.field;
- for (let d = cachedGenerators.length; d <= degree; d++) {
- const nextGenerator = lastGenerator.multiply(
- new GenericGFPoly(field, Int32Array.from([1, field.exp(d - 1 + field.getGeneratorBase())])));
- cachedGenerators.push(nextGenerator);
- lastGenerator = nextGenerator;
- }
- }
- return cachedGenerators[degree];
+ private buildGenerator(degree: number /*int*/): GenericGFPoly {
+ const cachedGenerators = this.cachedGenerators;
+ if (degree >= cachedGenerators.length) {
+ let lastGenerator = cachedGenerators[cachedGenerators.length - 1];
+ const field = this.field;
+ for (let d = cachedGenerators.length; d <= degree; d++) {
+ const nextGenerator = lastGenerator.multiply(
+ new GenericGFPoly(field, Int32Array.from([1, field.exp(d - 1 + field.getGeneratorBase())])));
+ cachedGenerators.push(nextGenerator);
+ lastGenerator = nextGenerator;
+ }
}
+ return cachedGenerators[degree];
+ }
- /**
- *
Encode a sequence of code words (symbols) using Reed-Solomon to allow decoders
- * to detect and correct errors that may have been introduced when the resulting
- * data is stored or transmitted.
- *
- * @param toEncode array used for both and output. Caller initializes the array with
- * the code words (symbols) to be encoded followed by empty elements allocated to make
- * space for error-correction code words in the encoded output. The array contains
- * the encdoded output when encode returns. Code words are encoded as numbers from
- * 0 to n-1, where n is the number of possible code words (symbols), as determined
- * by the size of the Galois Field passed in the constructor of this object.
- * @param ecBytes the number of elements reserved in the array (first parameter)
- * to store error-correction code words. Thus, the number of code words (symbols)
- * to encode in the first parameter is thus toEncode.length - ecBytes.
- * Note, the use of "bytes" in the name of this parameter is misleading, as there may
- * be more or fewer than 256 symbols being encoded, as determined by the number of
- * elements in the Galois Field passed as a constructor to this object.
- * @throws IllegalArgumentException thrown in response to validation errros.
- */
- public encode(toEncode: Int32Array, ecBytes: number /*int*/): void {
- if (ecBytes === 0) {
- throw new IllegalArgumentException('No error correction bytes');
- }
- const dataBytes = toEncode.length - ecBytes;
- if (dataBytes <= 0) {
- throw new IllegalArgumentException('No data bytes provided');
- }
- const generator = this.buildGenerator(ecBytes);
- const infoCoefficients: Int32Array = new Int32Array(dataBytes);
- System.arraycopy(toEncode, 0, infoCoefficients, 0, dataBytes);
- let info = new GenericGFPoly(this.field, infoCoefficients);
- info = info.multiplyByMonomial(ecBytes, 1);
- const remainder = info.divide(generator)[1];
- const coefficients = remainder.getCoefficients();
- const numZeroCoefficients = ecBytes - coefficients.length;
- for (let i = 0; i < numZeroCoefficients; i++) {
- toEncode[dataBytes + i] = 0;
- }
- System.arraycopy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.length);
+ /**
+ *
Encode a sequence of code words (symbols) using Reed-Solomon to allow decoders
+ * to detect and correct errors that may have been introduced when the resulting
+ * data is stored or transmitted.
+ *
+ * @param toEncode array used for both and output. Caller initializes the array with
+ * the code words (symbols) to be encoded followed by empty elements allocated to make
+ * space for error-correction code words in the encoded output. The array contains
+ * the encdoded output when encode returns. Code words are encoded as numbers from
+ * 0 to n-1, where n is the number of possible code words (symbols), as determined
+ * by the size of the Galois Field passed in the constructor of this object.
+ * @param ecBytes the number of elements reserved in the array (first parameter)
+ * to store error-correction code words. Thus, the number of code words (symbols)
+ * to encode in the first parameter is thus toEncode.length - ecBytes.
+ * Note, the use of "bytes" in the name of this parameter is misleading, as there may
+ * be more or fewer than 256 symbols being encoded, as determined by the number of
+ * elements in the Galois Field passed as a constructor to this object.
+ * @throws IllegalArgumentException thrown in response to validation errros.
+ */
+ public encode(toEncode: Int32Array, ecBytes: number /*int*/): void {
+ if (ecBytes === 0) {
+ throw new IllegalArgumentException('No error correction bytes');
+ }
+ const dataBytes = toEncode.length - ecBytes;
+ if (dataBytes <= 0) {
+ throw new IllegalArgumentException('No data bytes provided');
+ }
+ const generator = this.buildGenerator(ecBytes);
+ const infoCoefficients: Int32Array = new Int32Array(dataBytes);
+ System.arraycopy(toEncode, 0, infoCoefficients, 0, dataBytes);
+ let info = new GenericGFPoly(this.field, infoCoefficients);
+ info = info.multiplyByMonomial(ecBytes, 1);
+ const remainder = info.divide(generator)[1];
+ const coefficients = remainder.getCoefficients();
+ const numZeroCoefficients = ecBytes - coefficients.length;
+ for (let i = 0; i < numZeroCoefficients; i++) {
+ toEncode[dataBytes + i] = 0;
}
+ System.arraycopy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.length);
+ }
}
diff --git a/src/core/datamatrix/decoder/BitMatrixParser.ts b/src/core/datamatrix/decoder/BitMatrixParser.ts
index ea235a0d..c2423b1a 100644
--- a/src/core/datamatrix/decoder/BitMatrixParser.ts
+++ b/src/core/datamatrix/decoder/BitMatrixParser.ts
@@ -127,7 +127,7 @@ export default class BitMatrixParser {
// Sweep downward diagonally to the left
do {
if ((row >= 0) && (column < numColumns) && !this.readMappingMatrix.get(column, row)) {
- result[resultOffset++] = this.readUtah(row, column, numRows, numColumns) & 0xff;
+ result[resultOffset++] = this.readUtah(row, column, numRows, numColumns) & 0xff;
}
row += 2;
column -= 2;
diff --git a/src/core/datamatrix/decoder/DataBlock.ts b/src/core/datamatrix/decoder/DataBlock.ts
index 9e686fee..e5d6c523 100644
--- a/src/core/datamatrix/decoder/DataBlock.ts
+++ b/src/core/datamatrix/decoder/DataBlock.ts
@@ -46,7 +46,7 @@ export default class DataBlock {
* Data Matrix Code
*/
static getDataBlocks(rawCodewords: Int8Array,
- version: Version): DataBlock[] {
+ version: Version): DataBlock[] {
// Figure out the number and size of data blocks used by this version
const ecBlocks = version.getECBlocks();
@@ -54,7 +54,7 @@ export default class DataBlock {
let totalBlocks = 0;
const ecBlockArray = ecBlocks.getECBlocks();
for (let ecBlock of ecBlockArray) {
- totalBlocks += ecBlock.getCount();
+ totalBlocks += ecBlock.getCount();
}
// Now establish DataBlocks of the appropriate size and number of data codewords
diff --git a/src/core/datamatrix/decoder/DecodedBitStreamParser.ts b/src/core/datamatrix/decoder/DecodedBitStreamParser.ts
index 9f801292..757e2b5f 100644
--- a/src/core/datamatrix/decoder/DecodedBitStreamParser.ts
+++ b/src/core/datamatrix/decoder/DecodedBitStreamParser.ts
@@ -55,8 +55,8 @@ export default class DecodedBitStreamParser {
];
private static C40_SHIFT2_SET_CHARS: string[] = [
- '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.',
- '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_'
+ '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.',
+ '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_'
];
/**
@@ -74,10 +74,10 @@ export default class DecodedBitStreamParser {
private static TEXT_SHIFT3_SET_CHARS: string[] = [
'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
- 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', String.fromCharCode(127)
+ 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', String.fromCharCode(127)
];
- static decode(bytes: Uint8Array): DecoderResult {
+ static decode(bytes: Uint8Array): DecoderResult {
const bits = new BitSource(bytes);
const result = new StringBuilder();
const resultTrailer = new StringBuilder();
@@ -119,8 +119,8 @@ export default class DecodedBitStreamParser {
* See ISO 16022:2006, 5.2.3 and Annex C, Table C.2
*/
private static decodeAsciiSegment(bits: BitSource,
- result: StringBuilder,
- resultTrailer: StringBuilder): Mode {
+ result: StringBuilder,
+ resultTrailer: StringBuilder): Mode {
let upperShift = false;
do {
let oneByte = bits.readBits(8);
@@ -258,7 +258,7 @@ export default class DecodedBitStreamParser {
upperShift = true;
break;
default:
- throw new FormatException();
+ throw new FormatException();
}
}
shift = 0;
@@ -348,7 +348,7 @@ export default class DecodedBitStreamParser {
upperShift = true;
break;
default:
- throw new FormatException();
+ throw new FormatException();
}
}
shift = 0;
@@ -368,7 +368,7 @@ export default class DecodedBitStreamParser {
}
break;
default:
- throw new FormatException();
+ throw new FormatException();
}
}
} while (bits.available() > 0);
@@ -378,7 +378,7 @@ export default class DecodedBitStreamParser {
* See ISO 16022:2006, 5.2.7
*/
private static decodeAnsiX12Segment(bits: BitSource,
- result: StringBuilder): void {
+ result: StringBuilder): void {
// Three ANSI X12 values are encoded in a 16-bit value as
// (1600 * C1) + (40 * C2) + C3 + 1
@@ -469,8 +469,8 @@ export default class DecodedBitStreamParser {
* See ISO 16022:2006, 5.2.9 and Annex B, B.2
*/
private static decodeBase256Segment(bits: BitSource,
- result: StringBuilder,
- byteSegments: Uint8Array[]): void {
+ result: StringBuilder,
+ byteSegments: Uint8Array[]): void {
// Figure out how long the Base 256 Segment is.
let codewordPosition = 1 + bits.getByteOffset(); // position is 1-indexed
const d1 = this.unrandomize255State(bits.readBits(8), codewordPosition++);
@@ -509,7 +509,7 @@ export default class DecodedBitStreamParser {
* See ISO 16022:2006, Annex B, B.2
*/
private static unrandomize255State(randomizedBase256Codeword: number,
- base256CodewordPosition: number): number {
+ base256CodewordPosition: number): number {
const pseudoRandomNumber = ((149 * base256CodewordPosition) % 255) + 1;
const tempVariable = randomizedBase256Codeword - pseudoRandomNumber;
return tempVariable >= 0 ? tempVariable : tempVariable + 256;
diff --git a/src/core/datamatrix/decoder/Version.ts b/src/core/datamatrix/decoder/Version.ts
index 7c413249..8b63ca74 100644
--- a/src/core/datamatrix/decoder/Version.ts
+++ b/src/core/datamatrix/decoder/Version.ts
@@ -18,53 +18,53 @@ import FormatException from '../../FormatException';
*/
- /**
- *
Encapsulates a set of error-correction blocks in one symbol version. Most versions will
- * use blocks of differing sizes within one version, so, this encapsulates the parameters for
- * each set of blocks. It also holds the number of error-correction codewords per block since it
- * will be the same across all blocks within one version.
Encapsulates a set of error-correction blocks in one symbol version. Most versions will
+ * use blocks of differing sizes within one version, so, this encapsulates the parameters for
+ * each set of blocks. It also holds the number of error-correction codewords per block since it
+ * will be the same across all blocks within one version.
Encapsulates the parameters for one error-correction block in one symbol version.
- * This includes the number of data codewords, and the number of times a block with these
- * parameters is used consecutively in the Data Matrix code version's format.
- */
+/**
+ *
Encapsulates the parameters for one error-correction block in one symbol version.
+ * This includes the number of data codewords, and the number of times a block with these
+ * parameters is used consecutively in the Data Matrix code version's format.
+ */
export class ECB {
- private count: number;
- private dataCodewords: number;
+ private count: number;
+ private dataCodewords: number;
- constructor(count: number, dataCodewords: number) {
- this.count = count;
- this.dataCodewords = dataCodewords;
- }
+ constructor(count: number, dataCodewords: number) {
+ this.count = count;
+ this.dataCodewords = dataCodewords;
+ }
- getCount(): number {
- return this.count;
- }
+ getCount(): number {
+ return this.count;
+ }
- getDataCodewords(): number {
- return this.dataCodewords;
- }
+ getDataCodewords(): number {
+ return this.dataCodewords;
}
+}
/**
* The Version object encapsulates attributes about a particular
@@ -85,11 +85,11 @@ export default class Version {
private totalCodewords: number;
constructor(versionNumber,
- symbolSizeRows,
- symbolSizeColumns,
- dataRegionSizeRows,
- dataRegionSizeColumns,
- ecBlocks: ECBlocks) {
+ symbolSizeRows,
+ symbolSizeColumns,
+ dataRegionSizeRows,
+ dataRegionSizeColumns,
+ ecBlocks: ECBlocks) {
this.versionNumber = versionNumber;
this.symbolSizeRows = symbolSizeRows;
this.symbolSizeColumns = symbolSizeColumns;
@@ -157,7 +157,7 @@ export default class Version {
throw new FormatException();
}
-// @Override
+ // @Override
public toString(): string {
return '' + this.versionNumber;
}
@@ -167,67 +167,67 @@ export default class Version {
*/
private static buildVersions(): Version[] {
return [
- new Version(1, 10, 10, 8, 8,
- new ECBlocks(5, new ECB(1, 3))),
- new Version(2, 12, 12, 10, 10,
- new ECBlocks(7, new ECB(1, 5))),
- new Version(3, 14, 14, 12, 12,
- new ECBlocks(10, new ECB(1, 8))),
- new Version(4, 16, 16, 14, 14,
- new ECBlocks(12, new ECB(1, 12))),
- new Version(5, 18, 18, 16, 16,
- new ECBlocks(14, new ECB(1, 18))),
- new Version(6, 20, 20, 18, 18,
- new ECBlocks(18, new ECB(1, 22))),
- new Version(7, 22, 22, 20, 20,
- new ECBlocks(20, new ECB(1, 30))),
- new Version(8, 24, 24, 22, 22,
- new ECBlocks(24, new ECB(1, 36))),
- new Version(9, 26, 26, 24, 24,
- new ECBlocks(28, new ECB(1, 44))),
- new Version(10, 32, 32, 14, 14,
- new ECBlocks(36, new ECB(1, 62))),
- new Version(11, 36, 36, 16, 16,
- new ECBlocks(42, new ECB(1, 86))),
- new Version(12, 40, 40, 18, 18,
- new ECBlocks(48, new ECB(1, 114))),
- new Version(13, 44, 44, 20, 20,
- new ECBlocks(56, new ECB(1, 144))),
- new Version(14, 48, 48, 22, 22,
- new ECBlocks(68, new ECB(1, 174))),
- new Version(15, 52, 52, 24, 24,
- new ECBlocks(42, new ECB(2, 102))),
- new Version(16, 64, 64, 14, 14,
- new ECBlocks(56, new ECB(2, 140))),
- new Version(17, 72, 72, 16, 16,
- new ECBlocks(36, new ECB(4, 92))),
- new Version(18, 80, 80, 18, 18,
- new ECBlocks(48, new ECB(4, 114))),
- new Version(19, 88, 88, 20, 20,
- new ECBlocks(56, new ECB(4, 144))),
- new Version(20, 96, 96, 22, 22,
- new ECBlocks(68, new ECB(4, 174))),
- new Version(21, 104, 104, 24, 24,
- new ECBlocks(56, new ECB(6, 136))),
- new Version(22, 120, 120, 18, 18,
- new ECBlocks(68, new ECB(6, 175))),
- new Version(23, 132, 132, 20, 20,
- new ECBlocks(62, new ECB(8, 163))),
- new Version(24, 144, 144, 22, 22,
- new ECBlocks(62, new ECB(8, 156), new ECB(2, 155))),
- new Version(25, 8, 18, 6, 16,
- new ECBlocks(7, new ECB(1, 5))),
- new Version(26, 8, 32, 6, 14,
- new ECBlocks(11, new ECB(1, 10))),
- new Version(27, 12, 26, 10, 24,
- new ECBlocks(14, new ECB(1, 16))),
- new Version(28, 12, 36, 10, 16,
- new ECBlocks(18, new ECB(1, 22))),
- new Version(29, 16, 36, 14, 16,
- new ECBlocks(24, new ECB(1, 32))),
- new Version(30, 16, 48, 14, 22,
- new ECBlocks(28, new ECB(1, 49)))
- ];
+ new Version(1, 10, 10, 8, 8,
+ new ECBlocks(5, new ECB(1, 3))),
+ new Version(2, 12, 12, 10, 10,
+ new ECBlocks(7, new ECB(1, 5))),
+ new Version(3, 14, 14, 12, 12,
+ new ECBlocks(10, new ECB(1, 8))),
+ new Version(4, 16, 16, 14, 14,
+ new ECBlocks(12, new ECB(1, 12))),
+ new Version(5, 18, 18, 16, 16,
+ new ECBlocks(14, new ECB(1, 18))),
+ new Version(6, 20, 20, 18, 18,
+ new ECBlocks(18, new ECB(1, 22))),
+ new Version(7, 22, 22, 20, 20,
+ new ECBlocks(20, new ECB(1, 30))),
+ new Version(8, 24, 24, 22, 22,
+ new ECBlocks(24, new ECB(1, 36))),
+ new Version(9, 26, 26, 24, 24,
+ new ECBlocks(28, new ECB(1, 44))),
+ new Version(10, 32, 32, 14, 14,
+ new ECBlocks(36, new ECB(1, 62))),
+ new Version(11, 36, 36, 16, 16,
+ new ECBlocks(42, new ECB(1, 86))),
+ new Version(12, 40, 40, 18, 18,
+ new ECBlocks(48, new ECB(1, 114))),
+ new Version(13, 44, 44, 20, 20,
+ new ECBlocks(56, new ECB(1, 144))),
+ new Version(14, 48, 48, 22, 22,
+ new ECBlocks(68, new ECB(1, 174))),
+ new Version(15, 52, 52, 24, 24,
+ new ECBlocks(42, new ECB(2, 102))),
+ new Version(16, 64, 64, 14, 14,
+ new ECBlocks(56, new ECB(2, 140))),
+ new Version(17, 72, 72, 16, 16,
+ new ECBlocks(36, new ECB(4, 92))),
+ new Version(18, 80, 80, 18, 18,
+ new ECBlocks(48, new ECB(4, 114))),
+ new Version(19, 88, 88, 20, 20,
+ new ECBlocks(56, new ECB(4, 144))),
+ new Version(20, 96, 96, 22, 22,
+ new ECBlocks(68, new ECB(4, 174))),
+ new Version(21, 104, 104, 24, 24,
+ new ECBlocks(56, new ECB(6, 136))),
+ new Version(22, 120, 120, 18, 18,
+ new ECBlocks(68, new ECB(6, 175))),
+ new Version(23, 132, 132, 20, 20,
+ new ECBlocks(62, new ECB(8, 163))),
+ new Version(24, 144, 144, 22, 22,
+ new ECBlocks(62, new ECB(8, 156), new ECB(2, 155))),
+ new Version(25, 8, 18, 6, 16,
+ new ECBlocks(7, new ECB(1, 5))),
+ new Version(26, 8, 32, 6, 14,
+ new ECBlocks(11, new ECB(1, 10))),
+ new Version(27, 12, 26, 10, 24,
+ new ECBlocks(14, new ECB(1, 16))),
+ new Version(28, 12, 36, 10, 16,
+ new ECBlocks(18, new ECB(1, 22))),
+ new Version(29, 16, 36, 14, 16,
+ new ECBlocks(24, new ECB(1, 32))),
+ new Version(30, 16, 48, 14, 22,
+ new ECBlocks(28, new ECB(1, 49)))
+ ];
}
}
diff --git a/src/core/datamatrix/detector/Detector.ts b/src/core/datamatrix/detector/Detector.ts
index ff6c133c..0f3c4b97 100644
--- a/src/core/datamatrix/detector/Detector.ts
+++ b/src/core/datamatrix/detector/Detector.ts
@@ -54,7 +54,7 @@ export default class Detector {
points = this.detectSolid2(points);
points[3] = this.correctTopRight(points);
if (!points[3]) {
- throw new NotFoundException();
+ throw new NotFoundException();
}
points = this.shiftToModuleCenter(points);
@@ -78,12 +78,12 @@ export default class Detector {
}
let bits = Detector.sampleGrid(this.image,
- topLeft,
- bottomLeft,
- bottomRight,
- topRight,
- dimensionTop,
- dimensionRight);
+ topLeft,
+ bottomLeft,
+ bottomRight,
+ topRight,
+ dimensionTop,
+ dimensionRight);
return new DetectorResult(bits, [topLeft, bottomLeft, bottomRight, topRight]);
}
@@ -222,7 +222,7 @@ export default class Detector {
let candidate1 = new ResultPoint(
pointD.getX() + (pointC.getX() - pointB.getX()) / (trTop + 1),
pointD.getY() + (pointC.getY() - pointB.getY()) / (trTop + 1));
- let candidate2 = new ResultPoint(
+ let candidate2 = new ResultPoint(
pointD.getX() + (pointA.getX() - pointB.getX()) / (trRight + 1),
pointD.getY() + (pointA.getY() - pointB.getY()) / (trRight + 1));
@@ -306,34 +306,34 @@ export default class Detector {
}
private static sampleGrid(image: BitMatrix,
- topLeft: ResultPoint,
- bottomLeft: ResultPoint,
- bottomRight: ResultPoint,
- topRight: ResultPoint,
- dimensionX: int,
- dimensionY: int): BitMatrix {
+ topLeft: ResultPoint,
+ bottomLeft: ResultPoint,
+ bottomRight: ResultPoint,
+ topRight: ResultPoint,
+ dimensionX: int,
+ dimensionY: int): BitMatrix {
const sampler = GridSamplerInstance.getInstance();
return sampler.sampleGrid(image,
- dimensionX,
- dimensionY,
- 0.5,
- 0.5,
- dimensionX - 0.5,
- 0.5,
- dimensionX - 0.5,
- dimensionY - 0.5,
- 0.5,
- dimensionY - 0.5,
- topLeft.getX(),
- topLeft.getY(),
- topRight.getX(),
- topRight.getY(),
- bottomRight.getX(),
- bottomRight.getY(),
- bottomLeft.getX(),
- bottomLeft.getY());
+ dimensionX,
+ dimensionY,
+ 0.5,
+ 0.5,
+ dimensionX - 0.5,
+ 0.5,
+ dimensionX - 0.5,
+ dimensionY - 0.5,
+ 0.5,
+ dimensionY - 0.5,
+ topLeft.getX(),
+ topLeft.getY(),
+ topRight.getX(),
+ topRight.getY(),
+ bottomRight.getX(),
+ bottomRight.getY(),
+ bottomLeft.getX(),
+ bottomLeft.getY());
}
/**
diff --git a/src/core/oned/AbstractUPCEANReader.ts b/src/core/oned/AbstractUPCEANReader.ts
index 5704dc0f..5033d5bf 100644
--- a/src/core/oned/AbstractUPCEANReader.ts
+++ b/src/core/oned/AbstractUPCEANReader.ts
@@ -32,210 +32,210 @@ import { int } from '../../customTypings';
* @author alasdair@google.com (Alasdair Mackintosh)
*/
export default abstract class AbstractUPCEANReader extends OneDReader {
- // These two values are critical for determining how permissive the decoding will be.
- // We've arrived at these values through a lot of trial and error. Setting them any higher
- // lets false positives creep in quickly.
- private static MAX_AVG_VARIANCE = 0.48;
- private static MAX_INDIVIDUAL_VARIANCE = 0.7;
-
- /**
- * Start/end guard pattern.
- */
- public static START_END_PATTERN: Int32Array = Int32Array.from([1, 1, 1]);
-
- /**
- * Pattern marking the middle of a UPC/EAN pattern, separating the two halves.
- */
- public static MIDDLE_PATTERN: Int32Array = Int32Array.from([1, 1, 1, 1, 1]);
- /**
- * end guard pattern.
- */
- public static END_PATTERN: Int32Array = Int32Array.from([1, 1, 1, 1, 1, 1]);
- /**
- * "Odd", or "L" patterns used to encode UPC/EAN digits.
- */
- public static L_PATTERNS: Int32Array[] = [
- Int32Array.from([3, 2, 1, 1]), // 0
- Int32Array.from([2, 2, 2, 1]), // 1
- Int32Array.from([2, 1, 2, 2]), // 2
- Int32Array.from([1, 4, 1, 1]), // 3
- Int32Array.from([1, 1, 3, 2]), // 4
- Int32Array.from([1, 2, 3, 1]), // 5
- Int32Array.from([1, 1, 1, 4]), // 6
- Int32Array.from([1, 3, 1, 2]), // 7
- Int32Array.from([1, 2, 1, 3]), // 8
- Int32Array.from([3, 1, 1, 2]), // 9
- ];
-
- /**
- * As above but also including the "even", or "G" patterns used to encode UPC/EAN digits.
- */
- public static L_AND_G_PATTERNS: Int32Array[];
-
- protected decodeRowStringBuffer = '';
- // private final UPCEANExtensionSupport extensionReader;
- // private final EANManufacturerOrgSupport eanManSupport;
-
-
- /*
- protected UPCEANReader() {
- decodeRowStringBuffer = new StringBuilder(20);
- extensionReader = new UPCEANExtensionSupport();
- eanManSupport = new EANManufacturerOrgSupport();
+ // These two values are critical for determining how permissive the decoding will be.
+ // We've arrived at these values through a lot of trial and error. Setting them any higher
+ // lets false positives creep in quickly.
+ private static MAX_AVG_VARIANCE = 0.48;
+ private static MAX_INDIVIDUAL_VARIANCE = 0.7;
+
+ /**
+ * Start/end guard pattern.
+ */
+ public static START_END_PATTERN: Int32Array = Int32Array.from([1, 1, 1]);
+
+ /**
+ * Pattern marking the middle of a UPC/EAN pattern, separating the two halves.
+ */
+ public static MIDDLE_PATTERN: Int32Array = Int32Array.from([1, 1, 1, 1, 1]);
+ /**
+ * end guard pattern.
+ */
+ public static END_PATTERN: Int32Array = Int32Array.from([1, 1, 1, 1, 1, 1]);
+ /**
+ * "Odd", or "L" patterns used to encode UPC/EAN digits.
+ */
+ public static L_PATTERNS: Int32Array[] = [
+ Int32Array.from([3, 2, 1, 1]), // 0
+ Int32Array.from([2, 2, 2, 1]), // 1
+ Int32Array.from([2, 1, 2, 2]), // 2
+ Int32Array.from([1, 4, 1, 1]), // 3
+ Int32Array.from([1, 1, 3, 2]), // 4
+ Int32Array.from([1, 2, 3, 1]), // 5
+ Int32Array.from([1, 1, 1, 4]), // 6
+ Int32Array.from([1, 3, 1, 2]), // 7
+ Int32Array.from([1, 2, 1, 3]), // 8
+ Int32Array.from([3, 1, 1, 2]), // 9
+ ];
+
+ /**
+ * As above but also including the "even", or "G" patterns used to encode UPC/EAN digits.
+ */
+ public static L_AND_G_PATTERNS: Int32Array[];
+
+ protected decodeRowStringBuffer = '';
+ // private final UPCEANExtensionSupport extensionReader;
+ // private final EANManufacturerOrgSupport eanManSupport;
+
+
+ /*
+ protected UPCEANReader() {
+ decodeRowStringBuffer = new StringBuilder(20);
+ extensionReader = new UPCEANExtensionSupport();
+ eanManSupport = new EANManufacturerOrgSupport();
+ }
+ */
+
+ static findStartGuardPattern(row: BitArray): Int32Array {
+ let foundStart = false;
+ let startRange: Int32Array;
+ let nextStart = 0;
+ let counters = Int32Array.from([0, 0, 0]);
+ while (!foundStart) {
+ counters = Int32Array.from([0, 0, 0]);
+ startRange = AbstractUPCEANReader.findGuardPattern(row, nextStart, false, this.START_END_PATTERN, counters);
+ let start = startRange[0];
+ nextStart = startRange[1];
+ let quietStart = start - (nextStart - start);
+ if (quietStart >= 0) {
+ foundStart = row.isRange(quietStart, start, false);
+ }
}
- */
-
- static findStartGuardPattern(row: BitArray): Int32Array {
- let foundStart = false;
- let startRange: Int32Array;
- let nextStart = 0;
- let counters = Int32Array.from([0, 0, 0]);
- while (!foundStart) {
- counters = Int32Array.from([0, 0, 0]);
- startRange = AbstractUPCEANReader.findGuardPattern(row, nextStart, false, this.START_END_PATTERN, counters);
- let start = startRange[0];
- nextStart = startRange[1];
- let quietStart = start - (nextStart - start);
- if (quietStart >= 0) {
- foundStart = row.isRange(quietStart, start, false);
- }
- }
- return startRange;
+ return startRange;
+ }
+
+ public abstract decodeRow(rowNumber: number, row: BitArray, hints?: Map): Result;
+
+ static checkChecksum(s: string): boolean {
+ return AbstractUPCEANReader.checkStandardUPCEANChecksum(s);
+ }
+
+ static checkStandardUPCEANChecksum(s: string): boolean {
+ let length = s.length;
+ if (length === 0) return false;
+
+ let check = parseInt(s.charAt(length - 1), 10);
+ return AbstractUPCEANReader.getStandardUPCEANChecksum(s.substring(0, length - 1)) === check;
+ }
+
+ static getStandardUPCEANChecksum(s: string): number {
+ let length = s.length;
+ let sum = 0;
+ for (let i = length - 1; i >= 0; i -= 2) {
+ let digit = s.charAt(i).charCodeAt(0) - '0'.charCodeAt(0);
+ if (digit < 0 || digit > 9) {
+ throw new FormatException();
+ }
+ sum += digit;
}
-
- public abstract decodeRow(rowNumber: number, row: BitArray, hints?: Map): Result;
-
- static checkChecksum(s: string): boolean {
- return AbstractUPCEANReader.checkStandardUPCEANChecksum(s);
- }
-
- static checkStandardUPCEANChecksum(s: string): boolean {
- let length = s.length;
- if (length === 0) return false;
-
- let check = parseInt(s.charAt(length - 1), 10);
- return AbstractUPCEANReader.getStandardUPCEANChecksum(s.substring(0, length - 1)) === check;
+ sum *= 3;
+ for (let i = length - 2; i >= 0; i -= 2) {
+ let digit = s.charAt(i).charCodeAt(0) - '0'.charCodeAt(0);
+ if (digit < 0 || digit > 9) {
+ throw new FormatException();
+ }
+ sum += digit;
}
-
- static getStandardUPCEANChecksum(s: string): number {
- let length = s.length;
- let sum = 0;
- for (let i = length - 1; i >= 0; i -= 2) {
- let digit = s.charAt(i).charCodeAt(0) - '0'.charCodeAt(0);
- if (digit < 0 || digit > 9) {
- throw new FormatException();
- }
- sum += digit;
- }
- sum *= 3;
- for (let i = length - 2; i >= 0; i -= 2) {
- let digit = s.charAt(i).charCodeAt(0) - '0'.charCodeAt(0);
- if (digit < 0 || digit > 9) {
- throw new FormatException();
- }
- sum += digit;
+ return (1000 - sum) % 10;
+ }
+
+ static decodeEnd(row: BitArray, endStart: number): Int32Array {
+ return AbstractUPCEANReader.findGuardPattern(row, endStart, false, AbstractUPCEANReader.START_END_PATTERN, new Int32Array(AbstractUPCEANReader.START_END_PATTERN.length).fill(0));
+ }
+
+ /**
+ * @throws NotFoundException
+ */
+ static findGuardPatternWithoutCounters(
+ row: BitArray,
+ rowOffset: int,
+ whiteFirst: boolean,
+ pattern: Int32Array,
+ ): Int32Array {
+ return this.findGuardPattern(row, rowOffset, whiteFirst, pattern, new Int32Array(pattern.length));
+ }
+
+ /**
+ * @param row row of black/white values to search
+ * @param rowOffset position to start search
+ * @param whiteFirst if true, indicates that the pattern specifies white/black/white/...
+ * pixel counts, otherwise, it is interpreted as black/white/black/...
+ * @param pattern pattern of counts of number of black and white pixels that are being
+ * searched for as a pattern
+ * @param counters array of counters, as long as pattern, to re-use
+ * @return start/end horizontal offset of guard pattern, as an array of two ints
+ * @throws NotFoundException if pattern is not found
+ */
+ static findGuardPattern(row: BitArray, rowOffset: number, whiteFirst: boolean, pattern: Int32Array, counters: Int32Array): Int32Array {
+ let width = row.getSize();
+ rowOffset = whiteFirst ? row.getNextUnset(rowOffset) : row.getNextSet(rowOffset);
+ let counterPosition = 0;
+ let patternStart = rowOffset;
+ let patternLength = pattern.length;
+ let isWhite = whiteFirst;
+ for (let x = rowOffset; x < width; x++) {
+ if (row.get(x) !== isWhite) {
+ counters[counterPosition]++;
+ } else {
+ if (counterPosition === patternLength - 1) {
+ if (OneDReader.patternMatchVariance(counters, pattern, AbstractUPCEANReader.MAX_INDIVIDUAL_VARIANCE) < AbstractUPCEANReader.MAX_AVG_VARIANCE) {
+ return Int32Array.from([patternStart, x]);
+ }
+ patternStart += counters[0] + counters[1];
+
+ let slice = counters.slice(2, counters.length - 1);
+ for (let i = 0; i < counterPosition - 1; i++) {
+ counters[i] = slice[i];
+ }
+
+ counters[counterPosition - 1] = 0;
+ counters[counterPosition] = 0;
+ counterPosition--;
+ } else {
+ counterPosition++;
}
- return (1000 - sum) % 10;
- }
-
- static decodeEnd(row: BitArray, endStart: number): Int32Array {
- return AbstractUPCEANReader.findGuardPattern(row, endStart, false, AbstractUPCEANReader.START_END_PATTERN, new Int32Array(AbstractUPCEANReader.START_END_PATTERN.length).fill(0));
- }
-
- /**
- * @throws NotFoundException
- */
- static findGuardPatternWithoutCounters(
- row: BitArray,
- rowOffset: int,
- whiteFirst: boolean,
- pattern: Int32Array,
- ): Int32Array {
- return this.findGuardPattern(row, rowOffset, whiteFirst, pattern, new Int32Array(pattern.length));
+ counters[counterPosition] = 1;
+ isWhite = !isWhite;
+ }
}
-
- /**
- * @param row row of black/white values to search
- * @param rowOffset position to start search
- * @param whiteFirst if true, indicates that the pattern specifies white/black/white/...
- * pixel counts, otherwise, it is interpreted as black/white/black/...
- * @param pattern pattern of counts of number of black and white pixels that are being
- * searched for as a pattern
- * @param counters array of counters, as long as pattern, to re-use
- * @return start/end horizontal offset of guard pattern, as an array of two ints
- * @throws NotFoundException if pattern is not found
- */
- static findGuardPattern(row: BitArray, rowOffset: number, whiteFirst: boolean, pattern: Int32Array, counters: Int32Array): Int32Array {
- let width = row.getSize();
- rowOffset = whiteFirst ? row.getNextUnset(rowOffset) : row.getNextSet(rowOffset);
- let counterPosition = 0;
- let patternStart = rowOffset;
- let patternLength = pattern.length;
- let isWhite = whiteFirst;
- for (let x = rowOffset; x < width; x++) {
- if (row.get(x) !== isWhite) {
- counters[counterPosition]++;
- } else {
- if (counterPosition === patternLength - 1) {
- if (OneDReader.patternMatchVariance(counters, pattern, AbstractUPCEANReader.MAX_INDIVIDUAL_VARIANCE) < AbstractUPCEANReader.MAX_AVG_VARIANCE) {
- return Int32Array.from([patternStart, x]);
- }
- patternStart += counters[0] + counters[1];
-
- let slice = counters.slice(2, counters.length - 1);
- for (let i = 0; i < counterPosition - 1; i++) {
- counters[i] = slice[i];
- }
-
- counters[counterPosition - 1] = 0;
- counters[counterPosition] = 0;
- counterPosition--;
- } else {
- counterPosition++;
- }
- counters[counterPosition] = 1;
- isWhite = !isWhite;
- }
- }
- throw new NotFoundException();
+ throw new NotFoundException();
+ }
+
+ static decodeDigit(row: BitArray, counters: Int32Array, rowOffset: int, patterns: Int32Array[]) {
+ this.recordPattern(row, rowOffset, counters);
+ let bestVariance = this.MAX_AVG_VARIANCE;
+ let bestMatch = -1;
+ let max = patterns.length;
+ for (let i = 0; i < max; i++) {
+ let pattern = patterns[i];
+ let variance = OneDReader.patternMatchVariance(counters, pattern, AbstractUPCEANReader.MAX_INDIVIDUAL_VARIANCE);
+ if (variance < bestVariance) {
+ bestVariance = variance;
+ bestMatch = i;
+ }
}
-
- static decodeDigit(row: BitArray, counters: Int32Array, rowOffset: int, patterns: Int32Array[]) {
- this.recordPattern(row, rowOffset, counters);
- let bestVariance = this.MAX_AVG_VARIANCE;
- let bestMatch = -1;
- let max = patterns.length;
- for (let i = 0; i < max; i++) {
- let pattern = patterns[i];
- let variance = OneDReader.patternMatchVariance(counters, pattern, AbstractUPCEANReader.MAX_INDIVIDUAL_VARIANCE);
- if (variance < bestVariance) {
- bestVariance = variance;
- bestMatch = i;
- }
- }
- if (bestMatch >= 0) {
- return bestMatch;
- } else {
- throw new NotFoundException();
- }
+ if (bestMatch >= 0) {
+ return bestMatch;
+ } else {
+ throw new NotFoundException();
}
-
- /**
- * Get the format of this decoder.
- *
- * @return The 1D format.
- */
- public abstract getBarcodeFormat();
-
- /**
- * Subclasses override this to decode the portion of a barcode between the start
- * and end guard patterns.
- *
- * @param row row of black/white values to search
- * @param startRange start/end offset of start guard pattern
- * @param resultString {@link StringBuilder} to append decoded chars to
- * @return horizontal offset of first pixel after the "middle" that was decoded
- * @throws NotFoundException if decoding could not complete successfully
- */
- public abstract decodeMiddle(row: BitArray, startRange: Int32Array, resultString: /*StringBuilder*/string);
+ }
+
+ /**
+ * Get the format of this decoder.
+ *
+ * @return The 1D format.
+ */
+ public abstract getBarcodeFormat();
+
+ /**
+ * Subclasses override this to decode the portion of a barcode between the start
+ * and end guard patterns.
+ *
+ * @param row row of black/white values to search
+ * @param startRange start/end offset of start guard pattern
+ * @param resultString {@link StringBuilder} to append decoded chars to
+ * @return horizontal offset of first pixel after the "middle" that was decoded
+ * @throws NotFoundException if decoding could not complete successfully
+ */
+ public abstract decodeMiddle(row: BitArray, startRange: Int32Array, resultString: /*StringBuilder*/string);
}
diff --git a/src/core/oned/Code128Reader.ts b/src/core/oned/Code128Reader.ts
index 72c5bb68..1c9082ca 100644
--- a/src/core/oned/Code128Reader.ts
+++ b/src/core/oned/Code128Reader.ts
@@ -37,115 +37,115 @@ import OneDReader from './OneDReader';
*/
export default class Code128Reader extends OneDReader {
- private static CODE_PATTERNS: Int32Array[] = [
- Int32Array.from([2, 1, 2, 2, 2, 2]),
- Int32Array.from([2, 2, 2, 1, 2, 2]),
- Int32Array.from([2, 2, 2, 2, 2, 1]),
- Int32Array.from([1, 2, 1, 2, 2, 3]),
- Int32Array.from([1, 2, 1, 3, 2, 2]),
- Int32Array.from([1, 3, 1, 2, 2, 2]),
- Int32Array.from([1, 2, 2, 2, 1, 3]),
- Int32Array.from([1, 2, 2, 3, 1, 2]),
- Int32Array.from([1, 3, 2, 2, 1, 2]),
- Int32Array.from([2, 2, 1, 2, 1, 3]),
- Int32Array.from([2, 2, 1, 3, 1, 2]),
- Int32Array.from([2, 3, 1, 2, 1, 2]),
- Int32Array.from([1, 1, 2, 2, 3, 2]),
- Int32Array.from([1, 2, 2, 1, 3, 2]),
- Int32Array.from([1, 2, 2, 2, 3, 1]),
- Int32Array.from([1, 1, 3, 2, 2, 2]),
- Int32Array.from([1, 2, 3, 1, 2, 2]),
- Int32Array.from([1, 2, 3, 2, 2, 1]),
- Int32Array.from([2, 2, 3, 2, 1, 1]),
- Int32Array.from([2, 2, 1, 1, 3, 2]),
- Int32Array.from([2, 2, 1, 2, 3, 1]),
- Int32Array.from([2, 1, 3, 2, 1, 2]),
- Int32Array.from([2, 2, 3, 1, 1, 2]),
- Int32Array.from([3, 1, 2, 1, 3, 1]),
- Int32Array.from([3, 1, 1, 2, 2, 2]),
- Int32Array.from([3, 2, 1, 1, 2, 2]),
- Int32Array.from([3, 2, 1, 2, 2, 1]),
- Int32Array.from([3, 1, 2, 2, 1, 2]),
- Int32Array.from([3, 2, 2, 1, 1, 2]),
- Int32Array.from([3, 2, 2, 2, 1, 1]),
- Int32Array.from([2, 1, 2, 1, 2, 3]),
- Int32Array.from([2, 1, 2, 3, 2, 1]),
- Int32Array.from([2, 3, 2, 1, 2, 1]),
- Int32Array.from([1, 1, 1, 3, 2, 3]),
- Int32Array.from([1, 3, 1, 1, 2, 3]),
- Int32Array.from([1, 3, 1, 3, 2, 1]),
- Int32Array.from([1, 1, 2, 3, 1, 3]),
- Int32Array.from([1, 3, 2, 1, 1, 3]),
- Int32Array.from([1, 3, 2, 3, 1, 1]),
- Int32Array.from([2, 1, 1, 3, 1, 3]),
- Int32Array.from([2, 3, 1, 1, 1, 3]),
- Int32Array.from([2, 3, 1, 3, 1, 1]),
- Int32Array.from([1, 1, 2, 1, 3, 3]),
- Int32Array.from([1, 1, 2, 3, 3, 1]),
- Int32Array.from([1, 3, 2, 1, 3, 1]),
- Int32Array.from([1, 1, 3, 1, 2, 3]),
- Int32Array.from([1, 1, 3, 3, 2, 1]),
- Int32Array.from([1, 3, 3, 1, 2, 1]),
- Int32Array.from([3, 1, 3, 1, 2, 1]),
- Int32Array.from([2, 1, 1, 3, 3, 1]),
- Int32Array.from([2, 3, 1, 1, 3, 1]),
- Int32Array.from([2, 1, 3, 1, 1, 3]),
- Int32Array.from([2, 1, 3, 3, 1, 1]),
- Int32Array.from([2, 1, 3, 1, 3, 1]),
- Int32Array.from([3, 1, 1, 1, 2, 3]),
- Int32Array.from([3, 1, 1, 3, 2, 1]),
- Int32Array.from([3, 3, 1, 1, 2, 1]),
- Int32Array.from([3, 1, 2, 1, 1, 3]),
- Int32Array.from([3, 1, 2, 3, 1, 1]),
- Int32Array.from([3, 3, 2, 1, 1, 1]),
- Int32Array.from([3, 1, 4, 1, 1, 1]),
- Int32Array.from([2, 2, 1, 4, 1, 1]),
- Int32Array.from([4, 3, 1, 1, 1, 1]),
- Int32Array.from([1, 1, 1, 2, 2, 4]),
- Int32Array.from([1, 1, 1, 4, 2, 2]),
- Int32Array.from([1, 2, 1, 1, 2, 4]),
- Int32Array.from([1, 2, 1, 4, 2, 1]),
- Int32Array.from([1, 4, 1, 1, 2, 2]),
- Int32Array.from([1, 4, 1, 2, 2, 1]),
- Int32Array.from([1, 1, 2, 2, 1, 4]),
- Int32Array.from([1, 1, 2, 4, 1, 2]),
- Int32Array.from([1, 2, 2, 1, 1, 4]),
- Int32Array.from([1, 2, 2, 4, 1, 1]),
- Int32Array.from([1, 4, 2, 1, 1, 2]),
- Int32Array.from([1, 4, 2, 2, 1, 1]),
- Int32Array.from([2, 4, 1, 2, 1, 1]),
- Int32Array.from([2, 2, 1, 1, 1, 4]),
- Int32Array.from([4, 1, 3, 1, 1, 1]),
- Int32Array.from([2, 4, 1, 1, 1, 2]),
- Int32Array.from([1, 3, 4, 1, 1, 1]),
- Int32Array.from([1, 1, 1, 2, 4, 2]),
- Int32Array.from([1, 2, 1, 1, 4, 2]),
- Int32Array.from([1, 2, 1, 2, 4, 1]),
- Int32Array.from([1, 1, 4, 2, 1, 2]),
- Int32Array.from([1, 2, 4, 1, 1, 2]),
- Int32Array.from([1, 2, 4, 2, 1, 1]),
- Int32Array.from([4, 1, 1, 2, 1, 2]),
- Int32Array.from([4, 2, 1, 1, 1, 2]),
- Int32Array.from([4, 2, 1, 2, 1, 1]),
- Int32Array.from([2, 1, 2, 1, 4, 1]),
- Int32Array.from([2, 1, 4, 1, 2, 1]),
- Int32Array.from([4, 1, 2, 1, 2, 1]),
- Int32Array.from([1, 1, 1, 1, 4, 3]),
- Int32Array.from([1, 1, 1, 3, 4, 1]),
- Int32Array.from([1, 3, 1, 1, 4, 1]),
- Int32Array.from([1, 1, 4, 1, 1, 3]),
- Int32Array.from([1, 1, 4, 3, 1, 1]),
- Int32Array.from([4, 1, 1, 1, 1, 3]),
- Int32Array.from([4, 1, 1, 3, 1, 1]),
- Int32Array.from([1, 1, 3, 1, 4, 1]),
- Int32Array.from([1, 1, 4, 1, 3, 1]),
- Int32Array.from([3, 1, 1, 1, 4, 1]),
- Int32Array.from([4, 1, 1, 1, 3, 1]),
- Int32Array.from([2, 1, 1, 4, 1, 2]),
- Int32Array.from([2, 1, 1, 2, 1, 4]),
- Int32Array.from([2, 1, 1, 2, 3, 2]),
- Int32Array.from([2, 3, 3, 1, 1, 1, 2]),
- ];
+ private static CODE_PATTERNS: Int32Array[] = [
+ Int32Array.from([2, 1, 2, 2, 2, 2]),
+ Int32Array.from([2, 2, 2, 1, 2, 2]),
+ Int32Array.from([2, 2, 2, 2, 2, 1]),
+ Int32Array.from([1, 2, 1, 2, 2, 3]),
+ Int32Array.from([1, 2, 1, 3, 2, 2]),
+ Int32Array.from([1, 3, 1, 2, 2, 2]),
+ Int32Array.from([1, 2, 2, 2, 1, 3]),
+ Int32Array.from([1, 2, 2, 3, 1, 2]),
+ Int32Array.from([1, 3, 2, 2, 1, 2]),
+ Int32Array.from([2, 2, 1, 2, 1, 3]),
+ Int32Array.from([2, 2, 1, 3, 1, 2]),
+ Int32Array.from([2, 3, 1, 2, 1, 2]),
+ Int32Array.from([1, 1, 2, 2, 3, 2]),
+ Int32Array.from([1, 2, 2, 1, 3, 2]),
+ Int32Array.from([1, 2, 2, 2, 3, 1]),
+ Int32Array.from([1, 1, 3, 2, 2, 2]),
+ Int32Array.from([1, 2, 3, 1, 2, 2]),
+ Int32Array.from([1, 2, 3, 2, 2, 1]),
+ Int32Array.from([2, 2, 3, 2, 1, 1]),
+ Int32Array.from([2, 2, 1, 1, 3, 2]),
+ Int32Array.from([2, 2, 1, 2, 3, 1]),
+ Int32Array.from([2, 1, 3, 2, 1, 2]),
+ Int32Array.from([2, 2, 3, 1, 1, 2]),
+ Int32Array.from([3, 1, 2, 1, 3, 1]),
+ Int32Array.from([3, 1, 1, 2, 2, 2]),
+ Int32Array.from([3, 2, 1, 1, 2, 2]),
+ Int32Array.from([3, 2, 1, 2, 2, 1]),
+ Int32Array.from([3, 1, 2, 2, 1, 2]),
+ Int32Array.from([3, 2, 2, 1, 1, 2]),
+ Int32Array.from([3, 2, 2, 2, 1, 1]),
+ Int32Array.from([2, 1, 2, 1, 2, 3]),
+ Int32Array.from([2, 1, 2, 3, 2, 1]),
+ Int32Array.from([2, 3, 2, 1, 2, 1]),
+ Int32Array.from([1, 1, 1, 3, 2, 3]),
+ Int32Array.from([1, 3, 1, 1, 2, 3]),
+ Int32Array.from([1, 3, 1, 3, 2, 1]),
+ Int32Array.from([1, 1, 2, 3, 1, 3]),
+ Int32Array.from([1, 3, 2, 1, 1, 3]),
+ Int32Array.from([1, 3, 2, 3, 1, 1]),
+ Int32Array.from([2, 1, 1, 3, 1, 3]),
+ Int32Array.from([2, 3, 1, 1, 1, 3]),
+ Int32Array.from([2, 3, 1, 3, 1, 1]),
+ Int32Array.from([1, 1, 2, 1, 3, 3]),
+ Int32Array.from([1, 1, 2, 3, 3, 1]),
+ Int32Array.from([1, 3, 2, 1, 3, 1]),
+ Int32Array.from([1, 1, 3, 1, 2, 3]),
+ Int32Array.from([1, 1, 3, 3, 2, 1]),
+ Int32Array.from([1, 3, 3, 1, 2, 1]),
+ Int32Array.from([3, 1, 3, 1, 2, 1]),
+ Int32Array.from([2, 1, 1, 3, 3, 1]),
+ Int32Array.from([2, 3, 1, 1, 3, 1]),
+ Int32Array.from([2, 1, 3, 1, 1, 3]),
+ Int32Array.from([2, 1, 3, 3, 1, 1]),
+ Int32Array.from([2, 1, 3, 1, 3, 1]),
+ Int32Array.from([3, 1, 1, 1, 2, 3]),
+ Int32Array.from([3, 1, 1, 3, 2, 1]),
+ Int32Array.from([3, 3, 1, 1, 2, 1]),
+ Int32Array.from([3, 1, 2, 1, 1, 3]),
+ Int32Array.from([3, 1, 2, 3, 1, 1]),
+ Int32Array.from([3, 3, 2, 1, 1, 1]),
+ Int32Array.from([3, 1, 4, 1, 1, 1]),
+ Int32Array.from([2, 2, 1, 4, 1, 1]),
+ Int32Array.from([4, 3, 1, 1, 1, 1]),
+ Int32Array.from([1, 1, 1, 2, 2, 4]),
+ Int32Array.from([1, 1, 1, 4, 2, 2]),
+ Int32Array.from([1, 2, 1, 1, 2, 4]),
+ Int32Array.from([1, 2, 1, 4, 2, 1]),
+ Int32Array.from([1, 4, 1, 1, 2, 2]),
+ Int32Array.from([1, 4, 1, 2, 2, 1]),
+ Int32Array.from([1, 1, 2, 2, 1, 4]),
+ Int32Array.from([1, 1, 2, 4, 1, 2]),
+ Int32Array.from([1, 2, 2, 1, 1, 4]),
+ Int32Array.from([1, 2, 2, 4, 1, 1]),
+ Int32Array.from([1, 4, 2, 1, 1, 2]),
+ Int32Array.from([1, 4, 2, 2, 1, 1]),
+ Int32Array.from([2, 4, 1, 2, 1, 1]),
+ Int32Array.from([2, 2, 1, 1, 1, 4]),
+ Int32Array.from([4, 1, 3, 1, 1, 1]),
+ Int32Array.from([2, 4, 1, 1, 1, 2]),
+ Int32Array.from([1, 3, 4, 1, 1, 1]),
+ Int32Array.from([1, 1, 1, 2, 4, 2]),
+ Int32Array.from([1, 2, 1, 1, 4, 2]),
+ Int32Array.from([1, 2, 1, 2, 4, 1]),
+ Int32Array.from([1, 1, 4, 2, 1, 2]),
+ Int32Array.from([1, 2, 4, 1, 1, 2]),
+ Int32Array.from([1, 2, 4, 2, 1, 1]),
+ Int32Array.from([4, 1, 1, 2, 1, 2]),
+ Int32Array.from([4, 2, 1, 1, 1, 2]),
+ Int32Array.from([4, 2, 1, 2, 1, 1]),
+ Int32Array.from([2, 1, 2, 1, 4, 1]),
+ Int32Array.from([2, 1, 4, 1, 2, 1]),
+ Int32Array.from([4, 1, 2, 1, 2, 1]),
+ Int32Array.from([1, 1, 1, 1, 4, 3]),
+ Int32Array.from([1, 1, 1, 3, 4, 1]),
+ Int32Array.from([1, 3, 1, 1, 4, 1]),
+ Int32Array.from([1, 1, 4, 1, 1, 3]),
+ Int32Array.from([1, 1, 4, 3, 1, 1]),
+ Int32Array.from([4, 1, 1, 1, 1, 3]),
+ Int32Array.from([4, 1, 1, 3, 1, 1]),
+ Int32Array.from([1, 1, 3, 1, 4, 1]),
+ Int32Array.from([1, 1, 4, 1, 3, 1]),
+ Int32Array.from([3, 1, 1, 1, 4, 1]),
+ Int32Array.from([4, 1, 1, 1, 3, 1]),
+ Int32Array.from([2, 1, 1, 4, 1, 2]),
+ Int32Array.from([2, 1, 1, 2, 1, 4]),
+ Int32Array.from([2, 1, 1, 2, 3, 2]),
+ Int32Array.from([2, 3, 3, 1, 1, 1, 2]),
+ ];
private static MAX_AVG_VARIANCE = 0.25;
private static MAX_INDIVIDUAL_VARIANCE = 0.7;
@@ -171,11 +171,11 @@ export default class Code128Reader extends OneDReader {
const width = row.getSize();
const rowOffset = row.getNextSet(0);
- let counterPosition = 0;
- let counters = Int32Array.from([0, 0, 0, 0, 0, 0]);
- let patternStart = rowOffset;
- let isWhite = false;
- const patternLength = 6;
+ let counterPosition = 0;
+ let counters = Int32Array.from([0, 0, 0, 0, 0, 0]);
+ let patternStart = rowOffset;
+ let isWhite = false;
+ const patternLength = 6;
for (let i = rowOffset; i < width; i++) {
if (row.get(i) !== isWhite) {
diff --git a/src/core/oned/Code39Reader.ts b/src/core/oned/Code39Reader.ts
index 4a2c91af..06ef953b 100644
--- a/src/core/oned/Code39Reader.ts
+++ b/src/core/oned/Code39Reader.ts
@@ -42,11 +42,11 @@ export default class Code39Reader extends OneDReader {
* with 1s representing "wide" and 0s representing narrow.
*/
private static readonly CHARACTER_ENCODINGS: number[] = [
- 0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064, // 0-9
- 0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, // A-J
- 0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, // K-T
- 0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0, 0x085, 0x184, 0x0C4, 0x0A8, // U-$
- 0x0A2, 0x08A, 0x02A // /-%
+ 0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064, // 0-9
+ 0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, // A-J
+ 0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, // K-T
+ 0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0, 0x085, 0x184, 0x0C4, 0x0A8, // U-$
+ 0x0A2, 0x08A, 0x02A // /-%
];
private static readonly ASTERISK_ENCODING = 0x094;
@@ -186,7 +186,7 @@ export default class Code39Reader extends OneDReader {
if (counterPosition === patternLength - 1) {
// Look for whitespace before start pattern, >= 50% of width of start pattern
if (this.toNarrowWidePattern(counters) === Code39Reader.ASTERISK_ENCODING &&
- row.isRange(Math.max(0, patternStart - Math.floor((i - patternStart) / 2)), patternStart, false)) {
+ row.isRange(Math.max(0, patternStart - Math.floor((i - patternStart) / 2)), patternStart, false)) {
return [patternStart, i];
}
patternStart += counters[0] + counters[1];
diff --git a/src/core/oned/EAN13Reader.ts b/src/core/oned/EAN13Reader.ts
index 6412285e..e2736f40 100644
--- a/src/core/oned/EAN13Reader.ts
+++ b/src/core/oned/EAN13Reader.ts
@@ -28,64 +28,64 @@ import NotFoundException from '../NotFoundException';
* @author alasdair@google.com (Alasdair Mackintosh)
*/
export default class EAN13Reader extends UPCEANReader {
- private static FIRST_DIGIT_ENCODINGS: number[] = [0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A];
+ private static FIRST_DIGIT_ENCODINGS: number[] = [0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A];
private decodeMiddleCounters: Int32Array;
- public constructor() {
- super();
- this.decodeMiddleCounters = Int32Array.from([0, 0, 0, 0]);
- }
+ public constructor() {
+ super();
+ this.decodeMiddleCounters = Int32Array.from([0, 0, 0, 0]);
+ }
public decodeMiddle(row: BitArray, startRange: Int32Array, resultString: string) {
- let counters = this.decodeMiddleCounters;
- counters[0] = 0;
- counters[1] = 0;
- counters[2] = 0;
- counters[3] = 0;
- let end = row.getSize();
- let rowOffset = startRange[1];
-
- let lgPatternFound = 0;
+ let counters = this.decodeMiddleCounters;
+ counters[0] = 0;
+ counters[1] = 0;
+ counters[2] = 0;
+ counters[3] = 0;
+ let end = row.getSize();
+ let rowOffset = startRange[1];
- for (let x = 0; x < 6 && rowOffset < end; x++) {
- let bestMatch = UPCEANReader.decodeDigit(row, counters, rowOffset, UPCEANReader.L_AND_G_PATTERNS);
- resultString += String.fromCharCode(('0'.charCodeAt(0) + bestMatch % 10));
- for (let counter of counters) {
- rowOffset += counter;
- }
- if (bestMatch >= 10) {
- lgPatternFound |= 1 << (5 - x);
- }
- }
+ let lgPatternFound = 0;
- resultString = EAN13Reader.determineFirstDigit(resultString, lgPatternFound);
+ for (let x = 0; x < 6 && rowOffset < end; x++) {
+ let bestMatch = UPCEANReader.decodeDigit(row, counters, rowOffset, UPCEANReader.L_AND_G_PATTERNS);
+ resultString += String.fromCharCode(('0'.charCodeAt(0) + bestMatch % 10));
+ for (let counter of counters) {
+ rowOffset += counter;
+ }
+ if (bestMatch >= 10) {
+ lgPatternFound |= 1 << (5 - x);
+ }
+ }
- let middleRange = UPCEANReader.findGuardPattern(row, rowOffset, true, UPCEANReader.MIDDLE_PATTERN, new Int32Array(UPCEANReader.MIDDLE_PATTERN.length).fill(0));
- rowOffset = middleRange[1];
+ resultString = EAN13Reader.determineFirstDigit(resultString, lgPatternFound);
- for (let x = 0; x < 6 && rowOffset < end; x++) {
- let bestMatch = UPCEANReader.decodeDigit(row, counters, rowOffset, UPCEANReader.L_PATTERNS);
- resultString += String.fromCharCode(('0'.charCodeAt(0) + bestMatch));
- for (let counter of counters) {
- rowOffset += counter;
- }
- }
+ let middleRange = UPCEANReader.findGuardPattern(row, rowOffset, true, UPCEANReader.MIDDLE_PATTERN, new Int32Array(UPCEANReader.MIDDLE_PATTERN.length).fill(0));
+ rowOffset = middleRange[1];
- return {rowOffset, resultString};
+ for (let x = 0; x < 6 && rowOffset < end; x++) {
+ let bestMatch = UPCEANReader.decodeDigit(row, counters, rowOffset, UPCEANReader.L_PATTERNS);
+ resultString += String.fromCharCode(('0'.charCodeAt(0) + bestMatch));
+ for (let counter of counters) {
+ rowOffset += counter;
+ }
}
- public getBarcodeFormat(): BarcodeFormat {
- return BarcodeFormat.EAN_13;
- }
+ return { rowOffset, resultString };
+ }
+
+ public getBarcodeFormat(): BarcodeFormat {
+ return BarcodeFormat.EAN_13;
+ }
- static determineFirstDigit(resultString: string, lgPatternFound: number) {
- for (let d = 0; d < 10; d++) {
- if (lgPatternFound === this.FIRST_DIGIT_ENCODINGS[d]) {
- resultString = String.fromCharCode(('0'.charCodeAt(0) + d)) + resultString;
- return resultString;
- }
- }
- throw new NotFoundException();
+ static determineFirstDigit(resultString: string, lgPatternFound: number) {
+ for (let d = 0; d < 10; d++) {
+ if (lgPatternFound === this.FIRST_DIGIT_ENCODINGS[d]) {
+ resultString = String.fromCharCode(('0'.charCodeAt(0) + d)) + resultString;
+ return resultString;
+ }
}
+ throw new NotFoundException();
+ }
}
diff --git a/src/core/oned/EAN8Reader.ts b/src/core/oned/EAN8Reader.ts
index c49e55d5..c4f96763 100644
--- a/src/core/oned/EAN8Reader.ts
+++ b/src/core/oned/EAN8Reader.ts
@@ -25,47 +25,47 @@ import UPCEANReader from './UPCEANReader';
* @author Sean Owen
*/
export default class EAN8Reader extends UPCEANReader {
- private decodeMiddleCounters: Int32Array;
+ private decodeMiddleCounters: Int32Array;
- public constructor() {
- super();
- this.decodeMiddleCounters = Int32Array.from([0, 0, 0, 0]);
- }
-
- public decodeMiddle(row: BitArray, startRange: Int32Array, resultString: string) {
- const counters = this.decodeMiddleCounters;
- counters[0] = 0;
- counters[1] = 0;
- counters[2] = 0;
- counters[3] = 0;
- let end = row.getSize();
- let rowOffset = startRange[1];
+ public constructor() {
+ super();
+ this.decodeMiddleCounters = Int32Array.from([0, 0, 0, 0]);
+ }
- for (let x = 0; x < 4 && rowOffset < end; x++) {
- let bestMatch = UPCEANReader.decodeDigit(row, counters, rowOffset, UPCEANReader.L_PATTERNS);
- resultString += String.fromCharCode(('0'.charCodeAt(0) + bestMatch));
+ public decodeMiddle(row: BitArray, startRange: Int32Array, resultString: string) {
+ const counters = this.decodeMiddleCounters;
+ counters[0] = 0;
+ counters[1] = 0;
+ counters[2] = 0;
+ counters[3] = 0;
+ let end = row.getSize();
+ let rowOffset = startRange[1];
- for (let counter of counters) {
- rowOffset += counter;
- }
- }
+ for (let x = 0; x < 4 && rowOffset < end; x++) {
+ let bestMatch = UPCEANReader.decodeDigit(row, counters, rowOffset, UPCEANReader.L_PATTERNS);
+ resultString += String.fromCharCode(('0'.charCodeAt(0) + bestMatch));
- let middleRange = UPCEANReader.findGuardPattern(row, rowOffset, true, UPCEANReader.MIDDLE_PATTERN, new Int32Array(UPCEANReader.MIDDLE_PATTERN.length).fill(0));
- rowOffset = middleRange[1];
+ for (let counter of counters) {
+ rowOffset += counter;
+ }
+ }
- for (let x = 0; x < 4 && rowOffset < end; x++) {
- let bestMatch = UPCEANReader.decodeDigit(row, counters, rowOffset, UPCEANReader.L_PATTERNS);
- resultString += String.fromCharCode(('0'.charCodeAt(0) + bestMatch));
+ let middleRange = UPCEANReader.findGuardPattern(row, rowOffset, true, UPCEANReader.MIDDLE_PATTERN, new Int32Array(UPCEANReader.MIDDLE_PATTERN.length).fill(0));
+ rowOffset = middleRange[1];
- for (let counter of counters) {
- rowOffset += counter;
- }
- }
+ for (let x = 0; x < 4 && rowOffset < end; x++) {
+ let bestMatch = UPCEANReader.decodeDigit(row, counters, rowOffset, UPCEANReader.L_PATTERNS);
+ resultString += String.fromCharCode(('0'.charCodeAt(0) + bestMatch));
- return {rowOffset, resultString};
+ for (let counter of counters) {
+ rowOffset += counter;
+ }
}
- public getBarcodeFormat(): BarcodeFormat {
- return BarcodeFormat.EAN_8;
- }
+ return { rowOffset, resultString };
+ }
+
+ public getBarcodeFormat(): BarcodeFormat {
+ return BarcodeFormat.EAN_8;
+ }
}
diff --git a/src/core/oned/ITFReader.ts b/src/core/oned/ITFReader.ts
index e52e2535..e91c56e6 100644
--- a/src/core/oned/ITFReader.ts
+++ b/src/core/oned/ITFReader.ts
@@ -39,28 +39,28 @@ export default class ITFReader extends OneDReader {
// private static w = 2; // Pixel width of a 2x wide line
// private static N = 1; // Pixed width of a narrow line
- private static PATTERNS: Int32Array[] = [
- Int32Array.from([1, 1, 2, 2, 1]), // 0
- Int32Array.from([2, 1, 1, 1, 2]), // 1
- Int32Array.from([1, 2, 1, 1, 2]), // 2
- Int32Array.from([2, 2, 1, 1, 1]), // 3
- Int32Array.from([1, 1, 2, 1, 2]), // 4
- Int32Array.from([2, 1, 2, 1, 1]), // 5
- Int32Array.from([1, 2, 2, 1, 1]), // 6
- Int32Array.from([1, 1, 1, 2, 2]), // 7
- Int32Array.from([2, 1, 1, 2, 1]), // 8
- Int32Array.from([1, 2, 1, 2, 1]), // 9
- Int32Array.from([1, 1, 3, 3, 1]), // 0
- Int32Array.from([3, 1, 1, 1, 3]), // 1
- Int32Array.from([1, 3, 1, 1, 3]), // 2
- Int32Array.from([3, 3, 1, 1, 1]), // 3
- Int32Array.from([1, 1, 3, 1, 3]), // 4
- Int32Array.from([3, 1, 3, 1, 1]), // 5
- Int32Array.from([1, 3, 3, 1, 1]), // 6
- Int32Array.from([1, 1, 1, 3, 3]), // 7
- Int32Array.from([3, 1, 1, 3, 1]), // 8
- Int32Array.from([1, 3, 1, 3, 1]) // 9
- ];
+ private static PATTERNS: Int32Array[] = [
+ Int32Array.from([1, 1, 2, 2, 1]), // 0
+ Int32Array.from([2, 1, 1, 1, 2]), // 1
+ Int32Array.from([1, 2, 1, 1, 2]), // 2
+ Int32Array.from([2, 2, 1, 1, 1]), // 3
+ Int32Array.from([1, 1, 2, 1, 2]), // 4
+ Int32Array.from([2, 1, 2, 1, 1]), // 5
+ Int32Array.from([1, 2, 2, 1, 1]), // 6
+ Int32Array.from([1, 1, 1, 2, 2]), // 7
+ Int32Array.from([2, 1, 1, 2, 1]), // 8
+ Int32Array.from([1, 2, 1, 2, 1]), // 9
+ Int32Array.from([1, 1, 3, 3, 1]), // 0
+ Int32Array.from([3, 1, 1, 1, 3]), // 1
+ Int32Array.from([1, 3, 1, 1, 3]), // 2
+ Int32Array.from([3, 3, 1, 1, 1]), // 3
+ Int32Array.from([1, 1, 3, 1, 3]), // 4
+ Int32Array.from([3, 1, 3, 1, 1]), // 5
+ Int32Array.from([1, 3, 3, 1, 1]), // 6
+ Int32Array.from([1, 1, 1, 3, 3]), // 7
+ Int32Array.from([3, 1, 1, 3, 1]), // 8
+ Int32Array.from([1, 3, 1, 3, 1]) // 9
+ ];
private static MAX_AVG_VARIANCE = 0.38;
private static MAX_INDIVIDUAL_VARIANCE = 0.5;
@@ -73,17 +73,17 @@ export default class ITFReader extends OneDReader {
// Stores the actual narrow line width of the image being decoded.
private narrowLineWidth = -1;
- /*/!**
- * Start/end guard pattern.
- *
- * Note: The end pattern is reversed because the row is reversed before
- * searching for the END_PATTERN
- *!/*/
- private static START_PATTERN = Int32Array.from([1, 1, 1, 1]);
- private static END_PATTERN_REVERSED: Int32Array[] = [
- Int32Array.from([1, 1, 2]), // 2x
- Int32Array.from([1, 1, 3]) // 3x
- ];
+ /*/!**
+ * Start/end guard pattern.
+ *
+ * Note: The end pattern is reversed because the row is reversed before
+ * searching for the END_PATTERN
+ *!/*/
+ private static START_PATTERN = Int32Array.from([1, 1, 1, 1]);
+ private static END_PATTERN_REVERSED: Int32Array[] = [
+ Int32Array.from([1, 1, 2]), // 2x
+ Int32Array.from([1, 1, 3]) // 3x
+ ];
// See ITFWriter.PATTERNS
/*
@@ -169,9 +169,9 @@ export default class ITFReader extends OneDReader {
// Therefore, need to scan 10 lines and then
// split these into two arrays
- let counterDigitPair: Int32Array = new Int32Array(10); // 10
- let counterBlack: Int32Array = new Int32Array(5); // 5
- let counterWhite: Int32Array = new Int32Array(5); // 5
+ let counterDigitPair: Int32Array = new Int32Array(10); // 10
+ let counterBlack: Int32Array = new Int32Array(5); // 5
+ let counterWhite: Int32Array = new Int32Array(5); // 5
counterDigitPair.fill(0);
counterBlack.fill(0);
@@ -319,26 +319,26 @@ export default class ITFReader extends OneDReader {
}
}
- /*
- /!**
- * @param row row of black/white values to search
- * @param rowOffset position to start search
- * @param pattern pattern of counts of number of black and white pixels that are
- * being searched for as a pattern
- * @return start/end horizontal offset of guard pattern, as an array of two
- * ints
- * @throws NotFoundException if pattern is not found
- *!/*/
- private static findGuardPattern(
- row: BitArray,
- rowOffset: number,
- pattern: Int32Array
- ): number[] {
-
- let patternLength: number = pattern.length;
- let counters: Int32Array = new Int32Array(patternLength);
- let width: number = row.getSize();
- let isWhite: boolean = false;
+ /*
+ /!**
+ * @param row row of black/white values to search
+ * @param rowOffset position to start search
+ * @param pattern pattern of counts of number of black and white pixels that are
+ * being searched for as a pattern
+ * @return start/end horizontal offset of guard pattern, as an array of two
+ * ints
+ * @throws NotFoundException if pattern is not found
+ *!/*/
+ private static findGuardPattern(
+ row: BitArray,
+ rowOffset: number,
+ pattern: Int32Array
+ ): number[] {
+
+ let patternLength: number = pattern.length;
+ let counters: Int32Array = new Int32Array(patternLength);
+ let width: number = row.getSize();
+ let isWhite: boolean = false;
let counterPosition: number = 0;
let patternStart: number = rowOffset;
@@ -368,15 +368,15 @@ export default class ITFReader extends OneDReader {
throw new NotFoundException();
}
- /*/!**
- * Attempts to decode a sequence of ITF black/white lines into single
- * digit.
- *
- * @param counters the counts of runs of observed black/white/black/... values
- * @return The decoded digit
- * @throws NotFoundException if digit cannot be decoded
- *!/*/
- private static decodeDigit(counters: Int32Array): number {
+ /*/!**
+ * Attempts to decode a sequence of ITF black/white lines into single
+ * digit.
+ *
+ * @param counters the counts of runs of observed black/white/black/... values
+ * @return The decoded digit
+ * @throws NotFoundException if digit cannot be decoded
+ *!/*/
+ private static decodeDigit(counters: Int32Array): number {
let bestVariance: number = ITFReader.MAX_AVG_VARIANCE; // worst variance we'll accept
let bestMatch: number = -1;
diff --git a/src/core/oned/OneDReader.ts b/src/core/oned/OneDReader.ts
index 2969ff7d..072deee7 100644
--- a/src/core/oned/OneDReader.ts
+++ b/src/core/oned/OneDReader.ts
@@ -35,253 +35,253 @@ import NotFoundException from '../NotFoundException';
*/
export default abstract class OneDReader implements Reader {
- /*
- @Override
- public Result decode(BinaryBitmap image) throws NotFoundException, FormatException {
- return decode(image, null);
- }
- */
+ /*
+ @Override
+ public Result decode(BinaryBitmap image) throws NotFoundException, FormatException {
+ return decode(image, null);
+ }
+ */
- // Note that we don't try rotation without the try harder flag, even if rotation was supported.
- // @Override
- public decode(image: BinaryBitmap, hints?: Map): Result {
- try {
- return this.doDecode(image, hints);
- } catch (nfe) {
- const tryHarder = hints && (hints.get(DecodeHintType.TRY_HARDER) === true);
+ // Note that we don't try rotation without the try harder flag, even if rotation was supported.
+ // @Override
+ public decode(image: BinaryBitmap, hints?: Map): Result {
+ try {
+ return this.doDecode(image, hints);
+ } catch (nfe) {
+ const tryHarder = hints && (hints.get(DecodeHintType.TRY_HARDER) === true);
- if (tryHarder && image.isRotateSupported()) {
- const rotatedImage = image.rotateCounterClockwise();
- const result = this.doDecode(rotatedImage, hints);
- // Record that we found it rotated 90 degrees CCW / 270 degrees CW
- const metadata = result.getResultMetadata();
- let orientation = 270;
- if (metadata !== null && (metadata.get(ResultMetadataType.ORIENTATION) === true)) {
- // But if we found it reversed in doDecode(), add in that result here:
- orientation = (orientation + (metadata.get(ResultMetadataType.ORIENTATION) as number) % 360);
- }
- result.putMetadata(ResultMetadataType.ORIENTATION, orientation);
- // Update result points
- const points = result.getResultPoints();
- if (points !== null) {
- const height = rotatedImage.getHeight();
- for (let i = 0; i < points.length; i++) {
- points[i] = new ResultPoint(height - points[i].getY() - 1, points[i].getX());
- }
- }
- return result;
- } else {
- throw new NotFoundException();
- }
+ if (tryHarder && image.isRotateSupported()) {
+ const rotatedImage = image.rotateCounterClockwise();
+ const result = this.doDecode(rotatedImage, hints);
+ // Record that we found it rotated 90 degrees CCW / 270 degrees CW
+ const metadata = result.getResultMetadata();
+ let orientation = 270;
+ if (metadata !== null && (metadata.get(ResultMetadataType.ORIENTATION) === true)) {
+ // But if we found it reversed in doDecode(), add in that result here:
+ orientation = (orientation + (metadata.get(ResultMetadataType.ORIENTATION) as number) % 360);
+ }
+ result.putMetadata(ResultMetadataType.ORIENTATION, orientation);
+ // Update result points
+ const points = result.getResultPoints();
+ if (points !== null) {
+ const height = rotatedImage.getHeight();
+ for (let i = 0; i < points.length; i++) {
+ points[i] = new ResultPoint(height - points[i].getY() - 1, points[i].getX());
+ }
}
+ return result;
+ } else {
+ throw new NotFoundException();
+ }
}
+ }
- // @Override
- public reset(): void {
- // do nothing
- }
+ // @Override
+ public reset(): void {
+ // do nothing
+ }
- /**
- * We're going to examine rows from the middle outward, searching alternately above and below the
- * middle, and farther out each time. rowStep is the number of rows between each successive
- * attempt above and below the middle. So we'd scan row middle, then middle - rowStep, then
- * middle + rowStep, then middle - (2 * rowStep), etc.
- * rowStep is bigger as the image is taller, but is always at least 1. We've somewhat arbitrarily
- * decided that moving up and down by about 1/16 of the image is pretty good; we try more of the
- * image if "trying harder".
- *
- * @param image The image to decode
- * @param hints Any hints that were requested
- * @return The contents of the decoded barcode
- * @throws NotFoundException Any spontaneous errors which occur
- */
- private doDecode(image: BinaryBitmap, hints?: Map): Result {
- const width = image.getWidth();
- const height = image.getHeight();
- let row = new BitArray(width);
+ /**
+ * We're going to examine rows from the middle outward, searching alternately above and below the
+ * middle, and farther out each time. rowStep is the number of rows between each successive
+ * attempt above and below the middle. So we'd scan row middle, then middle - rowStep, then
+ * middle + rowStep, then middle - (2 * rowStep), etc.
+ * rowStep is bigger as the image is taller, but is always at least 1. We've somewhat arbitrarily
+ * decided that moving up and down by about 1/16 of the image is pretty good; we try more of the
+ * image if "trying harder".
+ *
+ * @param image The image to decode
+ * @param hints Any hints that were requested
+ * @return The contents of the decoded barcode
+ * @throws NotFoundException Any spontaneous errors which occur
+ */
+ private doDecode(image: BinaryBitmap, hints?: Map): Result {
+ const width = image.getWidth();
+ const height = image.getHeight();
+ let row = new BitArray(width);
- const tryHarder = hints && (hints.get(DecodeHintType.TRY_HARDER) === true);
- const rowStep = Math.max(1, height >> (tryHarder ? 8 : 5));
- let maxLines;
- if (tryHarder) {
- maxLines = height; // Look at the whole image, not just the center
- } else {
- maxLines = 15; // 15 rows spaced 1/32 apart is roughly the middle half of the image
- }
+ const tryHarder = hints && (hints.get(DecodeHintType.TRY_HARDER) === true);
+ const rowStep = Math.max(1, height >> (tryHarder ? 8 : 5));
+ let maxLines;
+ if (tryHarder) {
+ maxLines = height; // Look at the whole image, not just the center
+ } else {
+ maxLines = 15; // 15 rows spaced 1/32 apart is roughly the middle half of the image
+ }
- const middle = Math.trunc(height / 2);
- for (let x = 0; x < maxLines; x++) {
- // Scanning from the middle out. Determine which row we're looking at next:
- const rowStepsAboveOrBelow = Math.trunc((x + 1) / 2);
- const isAbove = (x & 0x01) === 0; // i.e. is x even?
- const rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow);
- if (rowNumber < 0 || rowNumber >= height) {
- // Oops, if we run off the top or bottom, stop
- break;
- }
+ const middle = Math.trunc(height / 2);
+ for (let x = 0; x < maxLines; x++) {
+ // Scanning from the middle out. Determine which row we're looking at next:
+ const rowStepsAboveOrBelow = Math.trunc((x + 1) / 2);
+ const isAbove = (x & 0x01) === 0; // i.e. is x even?
+ const rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow);
+ if (rowNumber < 0 || rowNumber >= height) {
+ // Oops, if we run off the top or bottom, stop
+ break;
+ }
- // Estimate black point for this row and load it:
- try {
- row = image.getBlackRow(rowNumber, row);
- } catch (ignored) { continue; }
+ // Estimate black point for this row and load it:
+ try {
+ row = image.getBlackRow(rowNumber, row);
+ } catch (ignored) { continue; }
- // While we have the image data in a BitArray, it's fairly cheap to reverse it in place to
- // handle decoding upside down barcodes.
- for (let attempt = 0; attempt < 2; attempt++) {
- if (attempt === 1) { // trying again?
- row.reverse(); // reverse the row and continue
+ // While we have the image data in a BitArray, it's fairly cheap to reverse it in place to
+ // handle decoding upside down barcodes.
+ for (let attempt = 0; attempt < 2; attempt++) {
+ if (attempt === 1) { // trying again?
+ row.reverse(); // reverse the row and continue
- // This means we will only ever draw result points *once* in the life of this method
- // since we want to avoid drawing the wrong points after flipping the row, and,
- // don't want to clutter with noise from every single row scan -- just the scans
- // that start on the center line.
- if (hints && (hints.get(DecodeHintType.NEED_RESULT_POINT_CALLBACK) === true)) {
- const newHints = new Map();
- hints.forEach((hint, key) => newHints.set(key, hint));
- newHints.delete(DecodeHintType.NEED_RESULT_POINT_CALLBACK);
- hints = newHints;
- }
- }
+ // This means we will only ever draw result points *once* in the life of this method
+ // since we want to avoid drawing the wrong points after flipping the row, and,
+ // don't want to clutter with noise from every single row scan -- just the scans
+ // that start on the center line.
+ if (hints && (hints.get(DecodeHintType.NEED_RESULT_POINT_CALLBACK) === true)) {
+ const newHints = new Map();
+ hints.forEach((hint, key) => newHints.set(key, hint));
+ newHints.delete(DecodeHintType.NEED_RESULT_POINT_CALLBACK);
+ hints = newHints;
+ }
+ }
- try {
- // Look for a barcode
- const result = this.decodeRow(rowNumber, row, hints);
- // We found our barcode
- if (attempt === 1) {
- // But it was upside down, so note that
- result.putMetadata(ResultMetadataType.ORIENTATION, 180);
- // And remember to flip the result points horizontally.
- const points = result.getResultPoints();
- if (points !== null) {
- points[0] = new ResultPoint(width - points[0].getX() - 1, points[0].getY());
- points[1] = new ResultPoint(width - points[1].getX() - 1, points[1].getY());
- }
- }
- return result;
- } catch (re) {
- // continue -- just couldn't decode this row
- }
+ try {
+ // Look for a barcode
+ const result = this.decodeRow(rowNumber, row, hints);
+ // We found our barcode
+ if (attempt === 1) {
+ // But it was upside down, so note that
+ result.putMetadata(ResultMetadataType.ORIENTATION, 180);
+ // And remember to flip the result points horizontally.
+ const points = result.getResultPoints();
+ if (points !== null) {
+ points[0] = new ResultPoint(width - points[0].getX() - 1, points[0].getY());
+ points[1] = new ResultPoint(width - points[1].getX() - 1, points[1].getY());
}
+ }
+ return result;
+ } catch (re) {
+ // continue -- just couldn't decode this row
}
-
- throw new NotFoundException();
+ }
}
- /**
- * Records the size of successive runs of white and black pixels in a row, starting at a given point.
- * The values are recorded in the given array, and the number of runs recorded is equal to the size
- * of the array. If the row starts on a white pixel at the given start point, then the first count
- * recorded is the run of white pixels starting from that point; likewise it is the count of a run
- * of black pixels if the row begin on a black pixels at that point.
- *
- * @param row row to count from
- * @param start offset into row to start at
- * @param counters array into which to record counts
- * @throws NotFoundException if counters cannot be filled entirely from row before running out
- * of pixels
- */
- protected static recordPattern(row: BitArray, start: number, counters: Int32Array): void {
- const numCounters = counters.length;
- for (let index = 0; index < numCounters; index++)
- counters[index] = 0;
+ throw new NotFoundException();
+ }
- const end = row.getSize();
- if (start >= end) {
- throw new NotFoundException();
- }
+ /**
+ * Records the size of successive runs of white and black pixels in a row, starting at a given point.
+ * The values are recorded in the given array, and the number of runs recorded is equal to the size
+ * of the array. If the row starts on a white pixel at the given start point, then the first count
+ * recorded is the run of white pixels starting from that point; likewise it is the count of a run
+ * of black pixels if the row begin on a black pixels at that point.
+ *
+ * @param row row to count from
+ * @param start offset into row to start at
+ * @param counters array into which to record counts
+ * @throws NotFoundException if counters cannot be filled entirely from row before running out
+ * of pixels
+ */
+ protected static recordPattern(row: BitArray, start: number, counters: Int32Array): void {
+ const numCounters = counters.length;
+ for (let index = 0; index < numCounters; index++)
+ counters[index] = 0;
- let isWhite = !row.get(start);
- let counterPosition = 0;
- let i = start;
- while (i < end) {
- if (row.get(i) !== isWhite) {
- counters[counterPosition]++;
- } else {
- if (++counterPosition === numCounters) {
- break;
- } else {
- counters[counterPosition] = 1;
- isWhite = !isWhite;
- }
- }
- i++;
- }
+ const end = row.getSize();
+ if (start >= end) {
+ throw new NotFoundException();
+ }
- // If we read fully the last section of pixels and filled up our counters -- or filled
- // the last counter but ran off the side of the image, OK. Otherwise, a problem.
- if (!(counterPosition === numCounters || (counterPosition === numCounters - 1 && i === end))) {
- throw new NotFoundException();
+ let isWhite = !row.get(start);
+ let counterPosition = 0;
+ let i = start;
+ while (i < end) {
+ if (row.get(i) !== isWhite) {
+ counters[counterPosition]++;
+ } else {
+ if (++counterPosition === numCounters) {
+ break;
+ } else {
+ counters[counterPosition] = 1;
+ isWhite = !isWhite;
}
+ }
+ i++;
}
- protected static recordPatternInReverse(row: BitArray, start: number, counters: Int32Array): void {
- // This could be more efficient I guess
- let numTransitionsLeft = counters.length;
- let last = row.get(start);
- while (start > 0 && numTransitionsLeft >= 0) {
- if (row.get(--start) !== last) {
- numTransitionsLeft--;
- last = !last;
- }
- }
- if (numTransitionsLeft >= 0) {
- throw new NotFoundException();
- }
+ // If we read fully the last section of pixels and filled up our counters -- or filled
+ // the last counter but ran off the side of the image, OK. Otherwise, a problem.
+ if (!(counterPosition === numCounters || (counterPosition === numCounters - 1 && i === end))) {
+ throw new NotFoundException();
+ }
+ }
- OneDReader.recordPattern(row, start + 1, counters);
+ protected static recordPatternInReverse(row: BitArray, start: number, counters: Int32Array): void {
+ // This could be more efficient I guess
+ let numTransitionsLeft = counters.length;
+ let last = row.get(start);
+ while (start > 0 && numTransitionsLeft >= 0) {
+ if (row.get(--start) !== last) {
+ numTransitionsLeft--;
+ last = !last;
+ }
+ }
+ if (numTransitionsLeft >= 0) {
+ throw new NotFoundException();
}
- /**
- * Determines how closely a set of observed counts of runs of black/white values matches a given
- * target pattern. This is reported as the ratio of the total variance from the expected pattern
- * proportions across all pattern elements, to the length of the pattern.
- *
- * @param counters observed counters
- * @param pattern expected pattern
- * @param maxIndividualVariance The most any counter can differ before we give up
- * @return ratio of total variance between counters and pattern compared to total pattern size
- */
- protected static patternMatchVariance(counters: Int32Array, pattern: Int32Array, maxIndividualVariance: number): number {
- const numCounters = counters.length;
- let total = 0;
- let patternLength = 0;
- for (let i = 0; i < numCounters; i++) {
- total += counters[i];
- patternLength += pattern[i];
- }
- if (total < patternLength) {
- // If we don't even have one pixel per unit of bar width, assume this is too small
- // to reliably match, so fail:
- return Number.POSITIVE_INFINITY;
- }
+ OneDReader.recordPattern(row, start + 1, counters);
+ }
- const unitBarWidth = total / patternLength;
- maxIndividualVariance *= unitBarWidth;
+ /**
+ * Determines how closely a set of observed counts of runs of black/white values matches a given
+ * target pattern. This is reported as the ratio of the total variance from the expected pattern
+ * proportions across all pattern elements, to the length of the pattern.
+ *
+ * @param counters observed counters
+ * @param pattern expected pattern
+ * @param maxIndividualVariance The most any counter can differ before we give up
+ * @return ratio of total variance between counters and pattern compared to total pattern size
+ */
+ protected static patternMatchVariance(counters: Int32Array, pattern: Int32Array, maxIndividualVariance: number): number {
+ const numCounters = counters.length;
+ let total = 0;
+ let patternLength = 0;
+ for (let i = 0; i < numCounters; i++) {
+ total += counters[i];
+ patternLength += pattern[i];
+ }
+ if (total < patternLength) {
+ // If we don't even have one pixel per unit of bar width, assume this is too small
+ // to reliably match, so fail:
+ return Number.POSITIVE_INFINITY;
+ }
- let totalVariance = 0.0;
- for (let x = 0; x < numCounters; x++) {
- const counter = counters[x];
- const scaledPattern = pattern[x] * unitBarWidth;
- const variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter;
- if (variance > maxIndividualVariance) {
- return Number.POSITIVE_INFINITY;
- }
- totalVariance += variance;
- }
- return totalVariance / total;
+ const unitBarWidth = total / patternLength;
+ maxIndividualVariance *= unitBarWidth;
+
+ let totalVariance = 0.0;
+ for (let x = 0; x < numCounters; x++) {
+ const counter = counters[x];
+ const scaledPattern = pattern[x] * unitBarWidth;
+ const variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter;
+ if (variance > maxIndividualVariance) {
+ return Number.POSITIVE_INFINITY;
+ }
+ totalVariance += variance;
}
+ return totalVariance / total;
+ }
- /**
- *
Attempts to decode a one-dimensional barcode format given a single row of
- * an image.
- *
- * @param rowNumber row number from top of the row
- * @param row the black/white pixel data of the row
- * @param hints decode hints
- * @return {@link Result} containing encoded string and start/end of barcode
- * @throws NotFoundException if no potential barcode is found
- * @throws ChecksumException if a potential barcode is found but does not pass its checksum
- * @throws FormatException if a potential barcode is found but format is invalid
- */
- public abstract decodeRow(rowNumber: number, row: BitArray, hints?: Map): Result;
+ /**
+ *
Attempts to decode a one-dimensional barcode format given a single row of
+ * an image.
Reads format information from one of its two locations within the QR Code.
+ *
+ * @return {@link FormatInformation} encapsulating the QR Code's format info
+ * @throws FormatException if both format information locations cannot be parsed as
+ * the valid encoding of format information
+ */
+ public readFormatInformation(): FormatInformation /*throws FormatException*/ {
+
+ if (this.parsedFormatInfo !== null && this.parsedFormatInfo !== undefined) {
+ return this.parsedFormatInfo;
}
- /**
- *
Reads format information from one of its two locations within the QR Code.
- *
- * @return {@link FormatInformation} encapsulating the QR Code's format info
- * @throws FormatException if both format information locations cannot be parsed as
- * the valid encoding of format information
- */
- public readFormatInformation(): FormatInformation /*throws FormatException*/ {
-
- if (this.parsedFormatInfo !== null && this.parsedFormatInfo !== undefined) {
- return this.parsedFormatInfo;
- }
-
- // Read top-left format info bits
- let formatInfoBits1 = 0;
- for (let i = 0; i < 6; i++) {
- formatInfoBits1 = this.copyBit(i, 8, formatInfoBits1);
- }
- // .. and skip a bit in the timing pattern ...
- formatInfoBits1 = this.copyBit(7, 8, formatInfoBits1);
- formatInfoBits1 = this.copyBit(8, 8, formatInfoBits1);
- formatInfoBits1 = this.copyBit(8, 7, formatInfoBits1);
- // .. and skip a bit in the timing pattern ...
- for (let j = 5; j >= 0; j--) {
- formatInfoBits1 = this.copyBit(8, j, formatInfoBits1);
- }
-
- // Read the top-right/bottom-left pattern too
- const dimension = this.bitMatrix.getHeight();
- let formatInfoBits2 = 0;
- const jMin = dimension - 7;
- for (let j = dimension - 1; j >= jMin; j--) {
- formatInfoBits2 = this.copyBit(8, j, formatInfoBits2);
- }
- for (let i = dimension - 8; i < dimension; i++) {
- formatInfoBits2 = this.copyBit(i, 8, formatInfoBits2);
- }
-
- this.parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits1, formatInfoBits2);
- if (this.parsedFormatInfo !== null) {
- return this.parsedFormatInfo;
- }
- throw new FormatException();
+ // Read top-left format info bits
+ let formatInfoBits1 = 0;
+ for (let i = 0; i < 6; i++) {
+ formatInfoBits1 = this.copyBit(i, 8, formatInfoBits1);
+ }
+ // .. and skip a bit in the timing pattern ...
+ formatInfoBits1 = this.copyBit(7, 8, formatInfoBits1);
+ formatInfoBits1 = this.copyBit(8, 8, formatInfoBits1);
+ formatInfoBits1 = this.copyBit(8, 7, formatInfoBits1);
+ // .. and skip a bit in the timing pattern ...
+ for (let j = 5; j >= 0; j--) {
+ formatInfoBits1 = this.copyBit(8, j, formatInfoBits1);
}
- /**
- *
Reads version information from one of its two locations within the QR Code.
- *
- * @return {@link Version} encapsulating the QR Code's version
- * @throws FormatException if both version information locations cannot be parsed as
- * the valid encoding of version information
- */
- public readVersion(): Version /*throws FormatException*/ {
+ // Read the top-right/bottom-left pattern too
+ const dimension = this.bitMatrix.getHeight();
+ let formatInfoBits2 = 0;
+ const jMin = dimension - 7;
+ for (let j = dimension - 1; j >= jMin; j--) {
+ formatInfoBits2 = this.copyBit(8, j, formatInfoBits2);
+ }
+ for (let i = dimension - 8; i < dimension; i++) {
+ formatInfoBits2 = this.copyBit(i, 8, formatInfoBits2);
+ }
- if (this.parsedVersion !== null && this.parsedVersion !== undefined) {
- return this.parsedVersion;
- }
+ this.parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits1, formatInfoBits2);
+ if (this.parsedFormatInfo !== null) {
+ return this.parsedFormatInfo;
+ }
+ throw new FormatException();
+ }
+
+ /**
+ *
Reads version information from one of its two locations within the QR Code.
+ *
+ * @return {@link Version} encapsulating the QR Code's version
+ * @throws FormatException if both version information locations cannot be parsed as
+ * the valid encoding of version information
+ */
+ public readVersion(): Version /*throws FormatException*/ {
+
+ if (this.parsedVersion !== null && this.parsedVersion !== undefined) {
+ return this.parsedVersion;
+ }
- const dimension = this.bitMatrix.getHeight();
+ const dimension = this.bitMatrix.getHeight();
- const provisionalVersion = Math.floor((dimension - 17) / 4);
- if (provisionalVersion <= 6) {
- return Version.getVersionForNumber(provisionalVersion);
- }
+ const provisionalVersion = Math.floor((dimension - 17) / 4);
+ if (provisionalVersion <= 6) {
+ return Version.getVersionForNumber(provisionalVersion);
+ }
- // Read top-right version info: 3 wide by 6 tall
- let versionBits = 0;
- const ijMin = dimension - 11;
- for (let j = 5; j >= 0; j--) {
- for (let i = dimension - 9; i >= ijMin; i--) {
- versionBits = this.copyBit(i, j, versionBits);
- }
- }
+ // Read top-right version info: 3 wide by 6 tall
+ let versionBits = 0;
+ const ijMin = dimension - 11;
+ for (let j = 5; j >= 0; j--) {
+ for (let i = dimension - 9; i >= ijMin; i--) {
+ versionBits = this.copyBit(i, j, versionBits);
+ }
+ }
- let theParsedVersion = Version.decodeVersionInformation(versionBits);
- if (theParsedVersion !== null && theParsedVersion.getDimensionForVersion() === dimension) {
- this.parsedVersion = theParsedVersion;
- return theParsedVersion;
- }
+ let theParsedVersion = Version.decodeVersionInformation(versionBits);
+ if (theParsedVersion !== null && theParsedVersion.getDimensionForVersion() === dimension) {
+ this.parsedVersion = theParsedVersion;
+ return theParsedVersion;
+ }
- // Hmm, failed. Try bottom left: 6 wide by 3 tall
- versionBits = 0;
- for (let i = 5; i >= 0; i--) {
- for (let j = dimension - 9; j >= ijMin; j--) {
- versionBits = this.copyBit(i, j, versionBits);
- }
- }
+ // Hmm, failed. Try bottom left: 6 wide by 3 tall
+ versionBits = 0;
+ for (let i = 5; i >= 0; i--) {
+ for (let j = dimension - 9; j >= ijMin; j--) {
+ versionBits = this.copyBit(i, j, versionBits);
+ }
+ }
- theParsedVersion = Version.decodeVersionInformation(versionBits);
- if (theParsedVersion !== null && theParsedVersion.getDimensionForVersion() === dimension) {
- this.parsedVersion = theParsedVersion;
- return theParsedVersion;
- }
- throw new FormatException();
- }
-
- private copyBit(i: number /*int*/, j: number /*int*/, versionBits: number /*int*/): number /*int*/ {
- const bit: boolean = this.isMirror ? this.bitMatrix.get(j, i) : this.bitMatrix.get(i, j);
- return bit ? (versionBits << 1) | 0x1 : versionBits << 1;
- }
-
- /**
- *
Reads the bits in the {@link BitMatrix} representing the finder pattern in the
- * correct order in order to reconstruct the codewords bytes contained within the
- * QR Code.
- *
- * @return bytes encoded within the QR Code
- * @throws FormatException if the exact number of bytes expected is not read
- */
- public readCodewords(): Uint8Array /*throws FormatException*/ {
-
- const formatInfo = this.readFormatInformation();
- const version = this.readVersion();
-
- // Get the data mask for the format used in this QR Code. This will exclude
- // some bits from reading as we wind through the bit matrix.
- const dataMask = DataMask.values.get(formatInfo.getDataMask());
- const dimension = this.bitMatrix.getHeight();
- dataMask.unmaskBitMatrix(this.bitMatrix, dimension);
-
- const functionPattern = version.buildFunctionPattern();
-
- let readingUp: boolean = true;
- const result = new Uint8Array(version.getTotalCodewords());
- let resultOffset = 0;
- let currentByte = 0;
- let bitsRead = 0;
- // Read columns in pairs, from right to left
- for (let j = dimension - 1; j > 0; j -= 2) {
- if (j === 6) {
- // Skip whole column with vertical alignment pattern
- // saves time and makes the other code proceed more cleanly
- j--;
+ theParsedVersion = Version.decodeVersionInformation(versionBits);
+ if (theParsedVersion !== null && theParsedVersion.getDimensionForVersion() === dimension) {
+ this.parsedVersion = theParsedVersion;
+ return theParsedVersion;
+ }
+ throw new FormatException();
+ }
+
+ private copyBit(i: number /*int*/, j: number /*int*/, versionBits: number /*int*/): number /*int*/ {
+ const bit: boolean = this.isMirror ? this.bitMatrix.get(j, i) : this.bitMatrix.get(i, j);
+ return bit ? (versionBits << 1) | 0x1 : versionBits << 1;
+ }
+
+ /**
+ *
Reads the bits in the {@link BitMatrix} representing the finder pattern in the
+ * correct order in order to reconstruct the codewords bytes contained within the
+ * QR Code.
+ *
+ * @return bytes encoded within the QR Code
+ * @throws FormatException if the exact number of bytes expected is not read
+ */
+ public readCodewords(): Uint8Array /*throws FormatException*/ {
+
+ const formatInfo = this.readFormatInformation();
+ const version = this.readVersion();
+
+ // Get the data mask for the format used in this QR Code. This will exclude
+ // some bits from reading as we wind through the bit matrix.
+ const dataMask = DataMask.values.get(formatInfo.getDataMask());
+ const dimension = this.bitMatrix.getHeight();
+ dataMask.unmaskBitMatrix(this.bitMatrix, dimension);
+
+ const functionPattern = version.buildFunctionPattern();
+
+ let readingUp: boolean = true;
+ const result = new Uint8Array(version.getTotalCodewords());
+ let resultOffset = 0;
+ let currentByte = 0;
+ let bitsRead = 0;
+ // Read columns in pairs, from right to left
+ for (let j = dimension - 1; j > 0; j -= 2) {
+ if (j === 6) {
+ // Skip whole column with vertical alignment pattern
+ // saves time and makes the other code proceed more cleanly
+ j--;
+ }
+ // Read alternatingly from bottom to top then top to bottom
+ for (let count = 0; count < dimension; count++) {
+ const i = readingUp ? dimension - 1 - count : count;
+ for (let col = 0; col < 2; col++) {
+ // Ignore bits covered by the function pattern
+ if (!functionPattern.get(j - col, i)) {
+ // Read a bit
+ bitsRead++;
+ currentByte <<= 1;
+ if (this.bitMatrix.get(j - col, i)) {
+ currentByte |= 1;
}
- // Read alternatingly from bottom to top then top to bottom
- for (let count = 0; count < dimension; count++) {
- const i = readingUp ? dimension - 1 - count : count;
- for (let col = 0; col < 2; col++) {
- // Ignore bits covered by the function pattern
- if (!functionPattern.get(j - col, i)) {
- // Read a bit
- bitsRead++;
- currentByte <<= 1;
- if (this.bitMatrix.get(j - col, i)) {
- currentByte |= 1;
- }
- // If we've made a whole byte, save it off
- if (bitsRead === 8) {
- result[resultOffset++] = /*(byte) */currentByte;
- bitsRead = 0;
- currentByte = 0;
- }
- }
- }
+ // If we've made a whole byte, save it off
+ if (bitsRead === 8) {
+ result[resultOffset++] = /*(byte) */currentByte;
+ bitsRead = 0;
+ currentByte = 0;
}
- readingUp = !readingUp; // readingUp ^= true; // readingUp = !readingUp; // switch directions
- }
- if (resultOffset !== version.getTotalCodewords()) {
- throw new FormatException();
+ }
}
- return result;
+ }
+ readingUp = !readingUp; // readingUp ^= true; // readingUp = !readingUp; // switch directions
}
-
- /**
- * Revert the mask removal done while reading the code words. The bit matrix should revert to its original state.
- */
- public remask(): void {
- if (this.parsedFormatInfo === null) {
- return; // We have no format information, and have no data mask
- }
- const dataMask = DataMask.values[this.parsedFormatInfo.getDataMask()];
- const dimension = this.bitMatrix.getHeight();
- dataMask.unmaskBitMatrix(this.bitMatrix, dimension);
- }
-
- /**
- * Prepare the parser for a mirrored operation.
- * This flag has effect only on the {@link #readFormatInformation()} and the
- * {@link #readVersion()}. Before proceeding with {@link #readCodewords()} the
- * {@link #mirror()} method should be called.
- *
- * @param mirror Whether to read version and format information mirrored.
- */
- public setMirror(isMirror: boolean): void {
- this.parsedVersion = null;
- this.parsedFormatInfo = null;
- this.isMirror = isMirror;
- }
-
- /** Mirror the bit matrix in order to attempt a second reading. */
- public mirror(): void {
- const bitMatrix = this.bitMatrix;
- for (let x = 0, width = bitMatrix.getWidth(); x < width; x++) {
- for (let y = x + 1, height = bitMatrix.getHeight(); y < height; y++) {
- if (bitMatrix.get(x, y) !== bitMatrix.get(y, x)) {
- bitMatrix.flip(y, x);
- bitMatrix.flip(x, y);
- }
- }
- }
+ if (resultOffset !== version.getTotalCodewords()) {
+ throw new FormatException();
+ }
+ return result;
+ }
+
+ /**
+ * Revert the mask removal done while reading the code words. The bit matrix should revert to its original state.
+ */
+ public remask(): void {
+ if (this.parsedFormatInfo === null) {
+ return; // We have no format information, and have no data mask
+ }
+ const dataMask = DataMask.values[this.parsedFormatInfo.getDataMask()];
+ const dimension = this.bitMatrix.getHeight();
+ dataMask.unmaskBitMatrix(this.bitMatrix, dimension);
+ }
+
+ /**
+ * Prepare the parser for a mirrored operation.
+ * This flag has effect only on the {@link #readFormatInformation()} and the
+ * {@link #readVersion()}. Before proceeding with {@link #readCodewords()} the
+ * {@link #mirror()} method should be called.
+ *
+ * @param mirror Whether to read version and format information mirrored.
+ */
+ public setMirror(isMirror: boolean): void {
+ this.parsedVersion = null;
+ this.parsedFormatInfo = null;
+ this.isMirror = isMirror;
+ }
+
+ /** Mirror the bit matrix in order to attempt a second reading. */
+ public mirror(): void {
+ const bitMatrix = this.bitMatrix;
+ for (let x = 0, width = bitMatrix.getWidth(); x < width; x++) {
+ for (let y = x + 1, height = bitMatrix.getHeight(); y < height; y++) {
+ if (bitMatrix.get(x, y) !== bitMatrix.get(y, x)) {
+ bitMatrix.flip(y, x);
+ bitMatrix.flip(x, y);
+ }
+ }
}
+ }
}
diff --git a/src/core/qrcode/decoder/DataBlock.ts b/src/core/qrcode/decoder/DataBlock.ts
index beb0b6e5..2ecbfc7b 100644
--- a/src/core/qrcode/decoder/DataBlock.ts
+++ b/src/core/qrcode/decoder/DataBlock.ts
@@ -32,93 +32,93 @@ import IllegalArgumentException from '../../IllegalArgumentException';
*/
export default class DataBlock {
- private constructor(private numDataCodewords: number /*int*/, private codewords: Uint8Array) { }
+ private constructor(private numDataCodewords: number /*int*/, private codewords: Uint8Array) { }
- /**
- *
When QR Codes use multiple data blocks, they are actually interleaved.
- * That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This
- * method will separate the data into original blocks.
- *
- * @param rawCodewords bytes as read directly from the QR Code
- * @param version version of the QR Code
- * @param ecLevel error-correction level of the QR Code
- * @return DataBlocks containing original bytes, "de-interleaved" from representation in the
- * QR Code
- */
- public static getDataBlocks(rawCodewords: Uint8Array,
- version: Version,
- ecLevel: ErrorCorrectionLevel): DataBlock[] {
+ /**
+ *
When QR Codes use multiple data blocks, they are actually interleaved.
+ * That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This
+ * method will separate the data into original blocks.
+ *
+ * @param rawCodewords bytes as read directly from the QR Code
+ * @param version version of the QR Code
+ * @param ecLevel error-correction level of the QR Code
+ * @return DataBlocks containing original bytes, "de-interleaved" from representation in the
+ * QR Code
+ */
+ public static getDataBlocks(rawCodewords: Uint8Array,
+ version: Version,
+ ecLevel: ErrorCorrectionLevel): DataBlock[] {
- if (rawCodewords.length !== version.getTotalCodewords()) {
- throw new IllegalArgumentException();
- }
-
- // Figure out the number and size of data blocks used by this version and
- // error correction level
- const ecBlocks: ECBlocks = version.getECBlocksForLevel(ecLevel);
-
- // First count the total number of data blocks
- let totalBlocks = 0;
- const ecBlockArray: ECB[] = ecBlocks.getECBlocks();
- for (const ecBlock of ecBlockArray) {
- totalBlocks += ecBlock.getCount();
- }
+ if (rawCodewords.length !== version.getTotalCodewords()) {
+ throw new IllegalArgumentException();
+ }
- // Now establish DataBlocks of the appropriate size and number of data codewords
- const result = new Array(totalBlocks);
- let numResultBlocks = 0;
- for (const ecBlock of ecBlockArray) {
- for (let i = 0; i < ecBlock.getCount(); i++) {
- const numDataCodewords = ecBlock.getDataCodewords();
- const numBlockCodewords = ecBlocks.getECCodewordsPerBlock() + numDataCodewords;
- result[numResultBlocks++] = new DataBlock(numDataCodewords, new Uint8Array(numBlockCodewords));
- }
- }
+ // Figure out the number and size of data blocks used by this version and
+ // error correction level
+ const ecBlocks: ECBlocks = version.getECBlocksForLevel(ecLevel);
- // All blocks have the same amount of data, except that the last n
- // (where n may be 0) have 1 more byte. Figure out where these start.
- const shorterBlocksTotalCodewords = result[0].codewords.length;
- let longerBlocksStartAt = result.length - 1;
- // TYPESCRIPTPORT: check length is correct here
- while (longerBlocksStartAt >= 0) {
- const numCodewords = result[longerBlocksStartAt].codewords.length;
- if (numCodewords === shorterBlocksTotalCodewords) {
- break;
- }
- longerBlocksStartAt--;
- }
- longerBlocksStartAt++;
+ // First count the total number of data blocks
+ let totalBlocks = 0;
+ const ecBlockArray: ECB[] = ecBlocks.getECBlocks();
+ for (const ecBlock of ecBlockArray) {
+ totalBlocks += ecBlock.getCount();
+ }
- const shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewordsPerBlock();
- // The last elements of result may be 1 element longer
- // first fill out as many elements as all of them have
- let rawCodewordsOffset = 0;
- for (let i = 0; i < shorterBlocksNumDataCodewords; i++) {
- for (let j = 0; j < numResultBlocks; j++) {
- result[j].codewords[i] = rawCodewords[rawCodewordsOffset++];
- }
- }
- // Fill out the last data block in the longer ones
- for (let j = longerBlocksStartAt; j < numResultBlocks; j++) {
- result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++];
- }
- // Now add in error correction blocks
- const max = result[0].codewords.length;
- for (let i = shorterBlocksNumDataCodewords; i < max; i++) {
- for (let j = 0; j < numResultBlocks; j++) {
- const iOffset = j < longerBlocksStartAt ? i : i + 1;
- result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];
- }
- }
- return result;
+ // Now establish DataBlocks of the appropriate size and number of data codewords
+ const result = new Array(totalBlocks);
+ let numResultBlocks = 0;
+ for (const ecBlock of ecBlockArray) {
+ for (let i = 0; i < ecBlock.getCount(); i++) {
+ const numDataCodewords = ecBlock.getDataCodewords();
+ const numBlockCodewords = ecBlocks.getECCodewordsPerBlock() + numDataCodewords;
+ result[numResultBlocks++] = new DataBlock(numDataCodewords, new Uint8Array(numBlockCodewords));
+ }
}
- public getNumDataCodewords(): number /*int*/ {
- return this.numDataCodewords;
+ // All blocks have the same amount of data, except that the last n
+ // (where n may be 0) have 1 more byte. Figure out where these start.
+ const shorterBlocksTotalCodewords = result[0].codewords.length;
+ let longerBlocksStartAt = result.length - 1;
+ // TYPESCRIPTPORT: check length is correct here
+ while (longerBlocksStartAt >= 0) {
+ const numCodewords = result[longerBlocksStartAt].codewords.length;
+ if (numCodewords === shorterBlocksTotalCodewords) {
+ break;
+ }
+ longerBlocksStartAt--;
}
+ longerBlocksStartAt++;
- public getCodewords(): Uint8Array {
- return this.codewords;
+ const shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewordsPerBlock();
+ // The last elements of result may be 1 element longer
+ // first fill out as many elements as all of them have
+ let rawCodewordsOffset = 0;
+ for (let i = 0; i < shorterBlocksNumDataCodewords; i++) {
+ for (let j = 0; j < numResultBlocks; j++) {
+ result[j].codewords[i] = rawCodewords[rawCodewordsOffset++];
+ }
}
+ // Fill out the last data block in the longer ones
+ for (let j = longerBlocksStartAt; j < numResultBlocks; j++) {
+ result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++];
+ }
+ // Now add in error correction blocks
+ const max = result[0].codewords.length;
+ for (let i = shorterBlocksNumDataCodewords; i < max; i++) {
+ for (let j = 0; j < numResultBlocks; j++) {
+ const iOffset = j < longerBlocksStartAt ? i : i + 1;
+ result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];
+ }
+ }
+ return result;
+ }
+
+ public getNumDataCodewords(): number /*int*/ {
+ return this.numDataCodewords;
+ }
+
+ public getCodewords(): Uint8Array {
+ return this.codewords;
+ }
}
diff --git a/src/core/qrcode/decoder/ECB.ts b/src/core/qrcode/decoder/ECB.ts
index f7e7e2bb..5ab5f90a 100644
--- a/src/core/qrcode/decoder/ECB.ts
+++ b/src/core/qrcode/decoder/ECB.ts
@@ -4,19 +4,19 @@
* parameters is used consecutively in the QR code version's format.
*/
export default class ECB {
- private count: number; /*int*/
- private dataCodewords: number; /*int*/
+ private count: number; /*int*/
+ private dataCodewords: number; /*int*/
- public constructor(count: number /*int*/, dataCodewords: number /*int*/) {
- this.count = count;
- this.dataCodewords = dataCodewords;
- }
+ public constructor(count: number /*int*/, dataCodewords: number /*int*/) {
+ this.count = count;
+ this.dataCodewords = dataCodewords;
+ }
- public getCount(): number /*int*/ {
- return this.count;
- }
+ public getCount(): number /*int*/ {
+ return this.count;
+ }
- public getDataCodewords(): number /*int*/ {
- return this.dataCodewords;
- }
+ public getDataCodewords(): number /*int*/ {
+ return this.dataCodewords;
+ }
}
diff --git a/src/core/qrcode/decoder/ECBlocks.ts b/src/core/qrcode/decoder/ECBlocks.ts
index fc7ffe2f..7243bc23 100644
--- a/src/core/qrcode/decoder/ECBlocks.ts
+++ b/src/core/qrcode/decoder/ECBlocks.ts
@@ -7,30 +7,30 @@ import ECB from './ECB';
* will be the same across all blocks within one version.
*/
export default class ECBlocks {
- private ecBlocks: ECB[];
+ private ecBlocks: ECB[];
- public constructor(private ecCodewordsPerBlock: number /*int*/, ...ecBlocks: ECB[]) {
- this.ecBlocks = ecBlocks;
- }
+ public constructor(private ecCodewordsPerBlock: number /*int*/, ...ecBlocks: ECB[]) {
+ this.ecBlocks = ecBlocks;
+ }
- public getECCodewordsPerBlock(): number /*int*/ {
- return this.ecCodewordsPerBlock;
- }
+ public getECCodewordsPerBlock(): number /*int*/ {
+ return this.ecCodewordsPerBlock;
+ }
- public getNumBlocks(): number /*int*/ {
- let total = 0;
- const ecBlocks = this.ecBlocks;
- for (const ecBlock of ecBlocks) {
- total += ecBlock.getCount();
- }
- return total;
+ public getNumBlocks(): number /*int*/ {
+ let total = 0;
+ const ecBlocks = this.ecBlocks;
+ for (const ecBlock of ecBlocks) {
+ total += ecBlock.getCount();
}
+ return total;
+ }
- public getTotalECCodewords(): number /*int*/ {
- return this.ecCodewordsPerBlock * this.getNumBlocks();
- }
+ public getTotalECCodewords(): number /*int*/ {
+ return this.ecCodewordsPerBlock * this.getNumBlocks();
+ }
- public getECBlocks(): ECB[] {
- return this.ecBlocks;
- }
+ public getECBlocks(): ECB[] {
+ return this.ecBlocks;
+ }
}
diff --git a/src/core/qrcode/decoder/ErrorCorrectionLevel.ts b/src/core/qrcode/decoder/ErrorCorrectionLevel.ts
index b63a1f02..59ad6fe9 100644
--- a/src/core/qrcode/decoder/ErrorCorrectionLevel.ts
+++ b/src/core/qrcode/decoder/ErrorCorrectionLevel.ts
@@ -21,10 +21,10 @@ import ArgumentException from '../../ArgumentException';
import IllegalArgumentException from '../../IllegalArgumentException';
export enum ErrorCorrectionLevelValues {
- L,
- M,
- Q,
- H
+ L,
+ M,
+ Q,
+ H
}
/**
@@ -35,61 +35,61 @@ export enum ErrorCorrectionLevelValues {
*/
export default class ErrorCorrectionLevel {
- private static FOR_BITS = new Map();
- private static FOR_VALUE = new Map();
+ private static FOR_BITS = new Map();
+ private static FOR_VALUE = new Map();
- /** L = ~7% correction */
- public static L = new ErrorCorrectionLevel(ErrorCorrectionLevelValues.L, 'L', 0x01);
- /** M = ~15% correction */
- public static M = new ErrorCorrectionLevel(ErrorCorrectionLevelValues.M, 'M', 0x00);
- /** Q = ~25% correction */
- public static Q = new ErrorCorrectionLevel(ErrorCorrectionLevelValues.Q, 'Q', 0x03);
- /** H = ~30% correction */
- public static H = new ErrorCorrectionLevel(ErrorCorrectionLevelValues.H, 'H', 0x02);
+ /** L = ~7% correction */
+ public static L = new ErrorCorrectionLevel(ErrorCorrectionLevelValues.L, 'L', 0x01);
+ /** M = ~15% correction */
+ public static M = new ErrorCorrectionLevel(ErrorCorrectionLevelValues.M, 'M', 0x00);
+ /** Q = ~25% correction */
+ public static Q = new ErrorCorrectionLevel(ErrorCorrectionLevelValues.Q, 'Q', 0x03);
+ /** H = ~30% correction */
+ public static H = new ErrorCorrectionLevel(ErrorCorrectionLevelValues.H, 'H', 0x02);
- private constructor(private value: ErrorCorrectionLevelValues, private stringValue: string, private bits: number /*int*/) {
- ErrorCorrectionLevel.FOR_BITS.set(bits, this);
- ErrorCorrectionLevel.FOR_VALUE.set(value, this);
- }
+ private constructor(private value: ErrorCorrectionLevelValues, private stringValue: string, private bits: number /*int*/) {
+ ErrorCorrectionLevel.FOR_BITS.set(bits, this);
+ ErrorCorrectionLevel.FOR_VALUE.set(value, this);
+ }
- public getValue(): ErrorCorrectionLevelValues/*int*/ {
- return this.value;
- }
+ public getValue(): ErrorCorrectionLevelValues/*int*/ {
+ return this.value;
+ }
- public getBits(): number /*int*/ {
- return this.bits;
- }
+ public getBits(): number /*int*/ {
+ return this.bits;
+ }
- public static fromString(s: string): ErrorCorrectionLevel {
- switch (s) {
- case 'L': return ErrorCorrectionLevel.L;
- case 'M': return ErrorCorrectionLevel.M;
- case 'Q': return ErrorCorrectionLevel.Q;
- case 'H': return ErrorCorrectionLevel.H;
- default: throw new ArgumentException(s + 'not available');
- }
+ public static fromString(s: string): ErrorCorrectionLevel {
+ switch (s) {
+ case 'L': return ErrorCorrectionLevel.L;
+ case 'M': return ErrorCorrectionLevel.M;
+ case 'Q': return ErrorCorrectionLevel.Q;
+ case 'H': return ErrorCorrectionLevel.H;
+ default: throw new ArgumentException(s + 'not available');
}
+ }
- public toString(): string {
- return this.stringValue;
- }
+ public toString(): string {
+ return this.stringValue;
+ }
- public equals(o: any): boolean {
- if (!(o instanceof ErrorCorrectionLevel)) {
- return false;
- }
- const other = o;
- return this.value === other.value;
+ public equals(o: any): boolean {
+ if (!(o instanceof ErrorCorrectionLevel)) {
+ return false;
}
- /**
- * @param bits int containing the two bits encoding a QR Code's error correction level
- * @return ErrorCorrectionLevel representing the encoded error correction level
- */
- public static forBits(bits: number /*int*/): ErrorCorrectionLevel {
- if (bits < 0 || bits >= ErrorCorrectionLevel.FOR_BITS.size) {
- throw new IllegalArgumentException();
- }
- return ErrorCorrectionLevel.FOR_BITS.get(bits);
+ const other = o;
+ return this.value === other.value;
+ }
+ /**
+ * @param bits int containing the two bits encoding a QR Code's error correction level
+ * @return ErrorCorrectionLevel representing the encoded error correction level
+ */
+ public static forBits(bits: number /*int*/): ErrorCorrectionLevel {
+ if (bits < 0 || bits >= ErrorCorrectionLevel.FOR_BITS.size) {
+ throw new IllegalArgumentException();
}
+ return ErrorCorrectionLevel.FOR_BITS.get(bits);
+ }
}
diff --git a/src/core/qrcode/decoder/FormatInformation.ts b/src/core/qrcode/decoder/FormatInformation.ts
index d93f59c1..14328999 100644
--- a/src/core/qrcode/decoder/FormatInformation.ts
+++ b/src/core/qrcode/decoder/FormatInformation.ts
@@ -29,132 +29,132 @@ import Integer from '../../util/Integer';
*/
export default class FormatInformation {
- private static FORMAT_INFO_MASK_QR = 0x5412;
+ private static FORMAT_INFO_MASK_QR = 0x5412;
- /**
- * See ISO 18004:2006, Annex C, Table C.1
- */
- private static FORMAT_INFO_DECODE_LOOKUP = [
- Int32Array.from([0x5412, 0x00]),
- Int32Array.from([0x5125, 0x01]),
- Int32Array.from([0x5E7C, 0x02]),
- Int32Array.from([0x5B4B, 0x03]),
- Int32Array.from([0x45F9, 0x04]),
- Int32Array.from([0x40CE, 0x05]),
- Int32Array.from([0x4F97, 0x06]),
- Int32Array.from([0x4AA0, 0x07]),
- Int32Array.from([0x77C4, 0x08]),
- Int32Array.from([0x72F3, 0x09]),
- Int32Array.from([0x7DAA, 0x0A]),
- Int32Array.from([0x789D, 0x0B]),
- Int32Array.from([0x662F, 0x0C]),
- Int32Array.from([0x6318, 0x0D]),
- Int32Array.from([0x6C41, 0x0E]),
- Int32Array.from([0x6976, 0x0F]),
- Int32Array.from([0x1689, 0x10]),
- Int32Array.from([0x13BE, 0x11]),
- Int32Array.from([0x1CE7, 0x12]),
- Int32Array.from([0x19D0, 0x13]),
- Int32Array.from([0x0762, 0x14]),
- Int32Array.from([0x0255, 0x15]),
- Int32Array.from([0x0D0C, 0x16]),
- Int32Array.from([0x083B, 0x17]),
- Int32Array.from([0x355F, 0x18]),
- Int32Array.from([0x3068, 0x19]),
- Int32Array.from([0x3F31, 0x1A]),
- Int32Array.from([0x3A06, 0x1B]),
- Int32Array.from([0x24B4, 0x1C]),
- Int32Array.from([0x2183, 0x1D]),
- Int32Array.from([0x2EDA, 0x1E]),
- Int32Array.from([0x2BED, 0x1F]),
- ];
+ /**
+ * See ISO 18004:2006, Annex C, Table C.1
+ */
+ private static FORMAT_INFO_DECODE_LOOKUP = [
+ Int32Array.from([0x5412, 0x00]),
+ Int32Array.from([0x5125, 0x01]),
+ Int32Array.from([0x5E7C, 0x02]),
+ Int32Array.from([0x5B4B, 0x03]),
+ Int32Array.from([0x45F9, 0x04]),
+ Int32Array.from([0x40CE, 0x05]),
+ Int32Array.from([0x4F97, 0x06]),
+ Int32Array.from([0x4AA0, 0x07]),
+ Int32Array.from([0x77C4, 0x08]),
+ Int32Array.from([0x72F3, 0x09]),
+ Int32Array.from([0x7DAA, 0x0A]),
+ Int32Array.from([0x789D, 0x0B]),
+ Int32Array.from([0x662F, 0x0C]),
+ Int32Array.from([0x6318, 0x0D]),
+ Int32Array.from([0x6C41, 0x0E]),
+ Int32Array.from([0x6976, 0x0F]),
+ Int32Array.from([0x1689, 0x10]),
+ Int32Array.from([0x13BE, 0x11]),
+ Int32Array.from([0x1CE7, 0x12]),
+ Int32Array.from([0x19D0, 0x13]),
+ Int32Array.from([0x0762, 0x14]),
+ Int32Array.from([0x0255, 0x15]),
+ Int32Array.from([0x0D0C, 0x16]),
+ Int32Array.from([0x083B, 0x17]),
+ Int32Array.from([0x355F, 0x18]),
+ Int32Array.from([0x3068, 0x19]),
+ Int32Array.from([0x3F31, 0x1A]),
+ Int32Array.from([0x3A06, 0x1B]),
+ Int32Array.from([0x24B4, 0x1C]),
+ Int32Array.from([0x2183, 0x1D]),
+ Int32Array.from([0x2EDA, 0x1E]),
+ Int32Array.from([0x2BED, 0x1F]),
+ ];
- private errorCorrectionLevel: ErrorCorrectionLevel;
- private dataMask: number; /*byte*/
+ private errorCorrectionLevel: ErrorCorrectionLevel;
+ private dataMask: number; /*byte*/
- private constructor(formatInfo: number /*int*/) {
- // Bits 3,4
- this.errorCorrectionLevel = ErrorCorrectionLevel.forBits((formatInfo >> 3) & 0x03);
- // Bottom 3 bits
- this.dataMask = /*(byte) */(formatInfo & 0x07);
- }
+ private constructor(formatInfo: number /*int*/) {
+ // Bits 3,4
+ this.errorCorrectionLevel = ErrorCorrectionLevel.forBits((formatInfo >> 3) & 0x03);
+ // Bottom 3 bits
+ this.dataMask = /*(byte) */(formatInfo & 0x07);
+ }
- public static numBitsDiffering(a: number /*int*/, b: number /*int*/): number /*int*/ {
- return Integer.bitCount(a ^ b);
- }
+ public static numBitsDiffering(a: number /*int*/, b: number /*int*/): number /*int*/ {
+ return Integer.bitCount(a ^ b);
+ }
- /**
- * @param maskedFormatInfo1 format info indicator, with mask still applied
- * @param maskedFormatInfo2 second copy of same info; both are checked at the same time
- * to establish best match
- * @return information about the format it specifies, or {@code null}
- * if doesn't seem to match any known pattern
- */
- public static decodeFormatInformation(maskedFormatInfo1: number /*int*/, maskedFormatInfo2: number /*int*/): FormatInformation {
- const formatInfo = FormatInformation.doDecodeFormatInformation(maskedFormatInfo1, maskedFormatInfo2);
- if (formatInfo !== null) {
- return formatInfo;
- }
- // Should return null, but, some QR codes apparently
- // do not mask this info. Try again by actually masking the pattern
- // first
- return FormatInformation.doDecodeFormatInformation(maskedFormatInfo1 ^ FormatInformation.FORMAT_INFO_MASK_QR,
- maskedFormatInfo2 ^ FormatInformation.FORMAT_INFO_MASK_QR);
+ /**
+ * @param maskedFormatInfo1 format info indicator, with mask still applied
+ * @param maskedFormatInfo2 second copy of same info; both are checked at the same time
+ * to establish best match
+ * @return information about the format it specifies, or {@code null}
+ * if doesn't seem to match any known pattern
+ */
+ public static decodeFormatInformation(maskedFormatInfo1: number /*int*/, maskedFormatInfo2: number /*int*/): FormatInformation {
+ const formatInfo = FormatInformation.doDecodeFormatInformation(maskedFormatInfo1, maskedFormatInfo2);
+ if (formatInfo !== null) {
+ return formatInfo;
}
+ // Should return null, but, some QR codes apparently
+ // do not mask this info. Try again by actually masking the pattern
+ // first
+ return FormatInformation.doDecodeFormatInformation(maskedFormatInfo1 ^ FormatInformation.FORMAT_INFO_MASK_QR,
+ maskedFormatInfo2 ^ FormatInformation.FORMAT_INFO_MASK_QR);
+ }
- private static doDecodeFormatInformation(maskedFormatInfo1: number /*int*/, maskedFormatInfo2: number /*int*/): FormatInformation {
- // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing
- let bestDifference = Number.MAX_SAFE_INTEGER;
- let bestFormatInfo = 0;
- for (const decodeInfo of FormatInformation.FORMAT_INFO_DECODE_LOOKUP) {
- const targetInfo = decodeInfo[0];
- if (targetInfo === maskedFormatInfo1 || targetInfo === maskedFormatInfo2) {
- // Found an exact match
- return new FormatInformation(decodeInfo[1]);
- }
- let bitsDifference = FormatInformation.numBitsDiffering(maskedFormatInfo1, targetInfo);
- if (bitsDifference < bestDifference) {
- bestFormatInfo = decodeInfo[1];
- bestDifference = bitsDifference;
- }
- if (maskedFormatInfo1 !== maskedFormatInfo2) {
- // also try the other option
- bitsDifference = FormatInformation.numBitsDiffering(maskedFormatInfo2, targetInfo);
- if (bitsDifference < bestDifference) {
- bestFormatInfo = decodeInfo[1];
- bestDifference = bitsDifference;
- }
- }
+ private static doDecodeFormatInformation(maskedFormatInfo1: number /*int*/, maskedFormatInfo2: number /*int*/): FormatInformation {
+ // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing
+ let bestDifference = Number.MAX_SAFE_INTEGER;
+ let bestFormatInfo = 0;
+ for (const decodeInfo of FormatInformation.FORMAT_INFO_DECODE_LOOKUP) {
+ const targetInfo = decodeInfo[0];
+ if (targetInfo === maskedFormatInfo1 || targetInfo === maskedFormatInfo2) {
+ // Found an exact match
+ return new FormatInformation(decodeInfo[1]);
+ }
+ let bitsDifference = FormatInformation.numBitsDiffering(maskedFormatInfo1, targetInfo);
+ if (bitsDifference < bestDifference) {
+ bestFormatInfo = decodeInfo[1];
+ bestDifference = bitsDifference;
+ }
+ if (maskedFormatInfo1 !== maskedFormatInfo2) {
+ // also try the other option
+ bitsDifference = FormatInformation.numBitsDiffering(maskedFormatInfo2, targetInfo);
+ if (bitsDifference < bestDifference) {
+ bestFormatInfo = decodeInfo[1];
+ bestDifference = bitsDifference;
}
- // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits
- // differing means we found a match
- if (bestDifference <= 3) {
- return new FormatInformation(bestFormatInfo);
- }
- return null;
+ }
}
-
- public getErrorCorrectionLevel(): ErrorCorrectionLevel {
- return this.errorCorrectionLevel;
+ // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits
+ // differing means we found a match
+ if (bestDifference <= 3) {
+ return new FormatInformation(bestFormatInfo);
}
+ return null;
+ }
- public getDataMask(): number/*byte*/ {
- return this.dataMask;
- }
+ public getErrorCorrectionLevel(): ErrorCorrectionLevel {
+ return this.errorCorrectionLevel;
+ }
- /*@Override*/
- public hashCode(): number /*int*/ {
- return (this.errorCorrectionLevel.getBits() << 3) | this.dataMask;
- }
+ public getDataMask(): number/*byte*/ {
+ return this.dataMask;
+ }
- /*@Override*/
- public equals(o: Object): boolean {
- if (!(o instanceof FormatInformation)) {
- return false;
- }
- const other = o;
- return this.errorCorrectionLevel === other.errorCorrectionLevel &&
- this.dataMask === other.dataMask;
+ /*@Override*/
+ public hashCode(): number /*int*/ {
+ return (this.errorCorrectionLevel.getBits() << 3) | this.dataMask;
+ }
+
+ /*@Override*/
+ public equals(o: Object): boolean {
+ if (!(o instanceof FormatInformation)) {
+ return false;
}
+ const other = o;
+ return this.errorCorrectionLevel === other.errorCorrectionLevel &&
+ this.dataMask === other.dataMask;
+ }
}
diff --git a/src/core/qrcode/decoder/Mode.ts b/src/core/qrcode/decoder/Mode.ts
index 191024ca..4bfc3eba 100644
--- a/src/core/qrcode/decoder/Mode.ts
+++ b/src/core/qrcode/decoder/Mode.ts
@@ -21,17 +21,17 @@ import Version from './Version';
import IllegalArgumentException from '../../IllegalArgumentException';
export enum ModeValues {
- TERMINATOR, // Not really a mode...
- NUMERIC,
- ALPHANUMERIC,
- STRUCTURED_APPEND, // Not supported
- BYTE,
- ECI, // character counts don't apply
- KANJI,
- FNC1_FIRST_POSITION,
- FNC1_SECOND_POSITION,
- /** See GBT 18284-2000; "Hanzi" is a transliteration of this mode name. */
- HANZI
+ TERMINATOR, // Not really a mode...
+ NUMERIC,
+ ALPHANUMERIC,
+ STRUCTURED_APPEND, // Not supported
+ BYTE,
+ ECI, // character counts don't apply
+ KANJI,
+ FNC1_FIRST_POSITION,
+ FNC1_SECOND_POSITION,
+ /** See GBT 18284-2000; "Hanzi" is a transliteration of this mode name. */
+ HANZI
}
/**
@@ -42,77 +42,77 @@ export enum ModeValues {
*/
export default class Mode {
- private static FOR_BITS = new Map();
- private static FOR_VALUE = new Map();
-
- public static TERMINATOR = new Mode(ModeValues.TERMINATOR, 'TERMINATOR', Int32Array.from([0, 0, 0]), 0x00); // Not really a mode...
- public static NUMERIC = new Mode(ModeValues.NUMERIC, 'NUMERIC', Int32Array.from([10, 12, 14]), 0x01);
- public static ALPHANUMERIC = new Mode(ModeValues.ALPHANUMERIC, 'ALPHANUMERIC', Int32Array.from([9, 11, 13]), 0x02);
- public static STRUCTURED_APPEND = new Mode(ModeValues.STRUCTURED_APPEND, 'STRUCTURED_APPEND', Int32Array.from([0, 0, 0]), 0x03); // Not supported
- public static BYTE = new Mode(ModeValues.BYTE, 'BYTE', Int32Array.from([8, 16, 16]), 0x04);
- public static ECI = new Mode(ModeValues.ECI, 'ECI', Int32Array.from([0, 0, 0]), 0x07); // character counts don't apply
- public static KANJI = new Mode(ModeValues.KANJI, 'KANJI', Int32Array.from([8, 10, 12]), 0x08);
- public static FNC1_FIRST_POSITION = new Mode(ModeValues.FNC1_FIRST_POSITION, 'FNC1_FIRST_POSITION', Int32Array.from([0, 0, 0]), 0x05);
- public static FNC1_SECOND_POSITION = new Mode(ModeValues.FNC1_SECOND_POSITION, 'FNC1_SECOND_POSITION', Int32Array.from([0, 0, 0]), 0x09);
- /** See GBT 18284-2000; "Hanzi" is a transliteration of this mode name. */
- public static HANZI = new Mode(ModeValues.HANZI, 'HANZI', Int32Array.from([8, 10, 12]), 0x0D);
-
- private constructor(private value: ModeValues, private stringValue: string, private characterCountBitsForVersions: Int32Array, private bits: number /*int*/) {
- Mode.FOR_BITS.set(bits, this);
- Mode.FOR_VALUE.set(value, this);
+ private static FOR_BITS = new Map();
+ private static FOR_VALUE = new Map();
+
+ public static TERMINATOR = new Mode(ModeValues.TERMINATOR, 'TERMINATOR', Int32Array.from([0, 0, 0]), 0x00); // Not really a mode...
+ public static NUMERIC = new Mode(ModeValues.NUMERIC, 'NUMERIC', Int32Array.from([10, 12, 14]), 0x01);
+ public static ALPHANUMERIC = new Mode(ModeValues.ALPHANUMERIC, 'ALPHANUMERIC', Int32Array.from([9, 11, 13]), 0x02);
+ public static STRUCTURED_APPEND = new Mode(ModeValues.STRUCTURED_APPEND, 'STRUCTURED_APPEND', Int32Array.from([0, 0, 0]), 0x03); // Not supported
+ public static BYTE = new Mode(ModeValues.BYTE, 'BYTE', Int32Array.from([8, 16, 16]), 0x04);
+ public static ECI = new Mode(ModeValues.ECI, 'ECI', Int32Array.from([0, 0, 0]), 0x07); // character counts don't apply
+ public static KANJI = new Mode(ModeValues.KANJI, 'KANJI', Int32Array.from([8, 10, 12]), 0x08);
+ public static FNC1_FIRST_POSITION = new Mode(ModeValues.FNC1_FIRST_POSITION, 'FNC1_FIRST_POSITION', Int32Array.from([0, 0, 0]), 0x05);
+ public static FNC1_SECOND_POSITION = new Mode(ModeValues.FNC1_SECOND_POSITION, 'FNC1_SECOND_POSITION', Int32Array.from([0, 0, 0]), 0x09);
+ /** See GBT 18284-2000; "Hanzi" is a transliteration of this mode name. */
+ public static HANZI = new Mode(ModeValues.HANZI, 'HANZI', Int32Array.from([8, 10, 12]), 0x0D);
+
+ private constructor(private value: ModeValues, private stringValue: string, private characterCountBitsForVersions: Int32Array, private bits: number /*int*/) {
+ Mode.FOR_BITS.set(bits, this);
+ Mode.FOR_VALUE.set(value, this);
+ }
+
+ /**
+ * @param bits four bits encoding a QR Code data mode
+ * @return Mode encoded by these bits
+ * @throws IllegalArgumentException if bits do not correspond to a known mode
+ */
+ public static forBits(bits: number /*int*/): Mode {
+ const mode = Mode.FOR_BITS.get(bits);
+ if (undefined === mode) {
+ throw new IllegalArgumentException();
}
-
- /**
- * @param bits four bits encoding a QR Code data mode
- * @return Mode encoded by these bits
- * @throws IllegalArgumentException if bits do not correspond to a known mode
- */
- public static forBits(bits: number /*int*/): Mode {
- const mode = Mode.FOR_BITS.get(bits);
- if (undefined === mode) {
- throw new IllegalArgumentException();
- }
- return mode;
+ return mode;
+ }
+
+ /**
+ * @param version version in question
+ * @return number of bits used, in this QR Code symbol {@link Version}, to encode the
+ * count of characters that will follow encoded in this Mode
+ */
+ public getCharacterCountBits(version: Version): number /*int*/ {
+ const versionNumber = version.getVersionNumber();
+
+ let offset;
+
+ if (versionNumber <= 9) {
+ offset = 0;
+ } else if (versionNumber <= 26) {
+ offset = 1;
+ } else {
+ offset = 2;
}
- /**
- * @param version version in question
- * @return number of bits used, in this QR Code symbol {@link Version}, to encode the
- * count of characters that will follow encoded in this Mode
- */
- public getCharacterCountBits(version: Version): number /*int*/ {
- const versionNumber = version.getVersionNumber();
-
- let offset;
-
- if (versionNumber <= 9) {
- offset = 0;
- } else if (versionNumber <= 26) {
- offset = 1;
- } else {
- offset = 2;
- }
-
- return this.characterCountBitsForVersions[offset];
- }
+ return this.characterCountBitsForVersions[offset];
+ }
- public getValue(): ModeValues/*int*/ {
- return this.value;
- }
+ public getValue(): ModeValues/*int*/ {
+ return this.value;
+ }
- public getBits(): number /*int*/ {
- return this.bits;
- }
+ public getBits(): number /*int*/ {
+ return this.bits;
+ }
- public equals(o: any): boolean {
- if (!(o instanceof Mode)) {
- return false;
- }
- const other = o;
- return this.value === other.value;
+ public equals(o: any): boolean {
+ if (!(o instanceof Mode)) {
+ return false;
}
+ const other = o;
+ return this.value === other.value;
+ }
- public toString(): string {
- return this.stringValue;
- }
+ public toString(): string {
+ return this.stringValue;
+ }
}
diff --git a/src/core/qrcode/decoder/QRCodeDecoderMetaData.ts b/src/core/qrcode/decoder/QRCodeDecoderMetaData.ts
index d64d0be4..d8277f81 100644
--- a/src/core/qrcode/decoder/QRCodeDecoderMetaData.ts
+++ b/src/core/qrcode/decoder/QRCodeDecoderMetaData.ts
@@ -27,28 +27,28 @@ import ResultPoint from '../../ResultPoint';
export default class QRCodeDecoderMetaData {
- public constructor(private mirrored: boolean) { }
-
- /**
- * @return true if the QR Code was mirrored.
- */
- public isMirrored(): boolean {
- return this.mirrored;
- }
-
- /**
- * Apply the result points' order correction due to mirroring.
- *
- * @param points Array of points to apply mirror correction to.
- */
- public applyMirroredCorrection(points: Array): void {
- if (!this.mirrored || points === null || points.length < 3) {
- return;
- }
- const bottomLeft = points[0];
- points[0] = points[2];
- points[2] = bottomLeft;
- // No need to 'fix' top-left and alignment pattern.
+ public constructor(private mirrored: boolean) { }
+
+ /**
+ * @return true if the QR Code was mirrored.
+ */
+ public isMirrored(): boolean {
+ return this.mirrored;
+ }
+
+ /**
+ * Apply the result points' order correction due to mirroring.
+ *
+ * @param points Array of points to apply mirror correction to.
+ */
+ public applyMirroredCorrection(points: Array): void {
+ if (!this.mirrored || points === null || points.length < 3) {
+ return;
}
+ const bottomLeft = points[0];
+ points[0] = points[2];
+ points[2] = bottomLeft;
+ // No need to 'fix' top-left and alignment pattern.
+ }
}
diff --git a/src/core/qrcode/decoder/Version.ts b/src/core/qrcode/decoder/Version.ts
index f765f23e..6515f59d 100644
--- a/src/core/qrcode/decoder/Version.ts
+++ b/src/core/qrcode/decoder/Version.ts
@@ -32,486 +32,486 @@ import IllegalArgumentException from '../../IllegalArgumentException';
*/
export default class Version {
- /**
- * See ISO 18004:2006 Annex D.
- * Element i represents the raw version bits that specify version i + 7
- */
- private static VERSION_DECODE_INFO = Int32Array.from([
- 0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6,
- 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78,
- 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683,
- 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB,
- 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250,
- 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B,
- 0x2542E, 0x26A64, 0x27541, 0x28C69]);
+ /**
+ * See ISO 18004:2006 Annex D.
+ * Element i represents the raw version bits that specify version i + 7
+ */
+ private static VERSION_DECODE_INFO = Int32Array.from([
+ 0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6,
+ 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78,
+ 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683,
+ 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB,
+ 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250,
+ 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B,
+ 0x2542E, 0x26A64, 0x27541, 0x28C69]);
- /**
- * See ISO 18004:2006 6.5.1 Table 9
- */
- private static VERSIONS: Version[] = [
- new Version(1, new Int32Array(0),
- new ECBlocks(7, new ECB(1, 19)),
- new ECBlocks(10, new ECB(1, 16)),
- new ECBlocks(13, new ECB(1, 13)),
- new ECBlocks(17, new ECB(1, 9))),
- new Version(2, Int32Array.from([6, 18]),
- new ECBlocks(10, new ECB(1, 34)),
- new ECBlocks(16, new ECB(1, 28)),
- new ECBlocks(22, new ECB(1, 22)),
- new ECBlocks(28, new ECB(1, 16))),
- new Version(3, Int32Array.from([6, 22]),
- new ECBlocks(15, new ECB(1, 55)),
- new ECBlocks(26, new ECB(1, 44)),
- new ECBlocks(18, new ECB(2, 17)),
- new ECBlocks(22, new ECB(2, 13))),
- new Version(4, Int32Array.from([6, 26]),
- new ECBlocks(20, new ECB(1, 80)),
- new ECBlocks(18, new ECB(2, 32)),
- new ECBlocks(26, new ECB(2, 24)),
- new ECBlocks(16, new ECB(4, 9))),
- new Version(5, Int32Array.from([6, 30]),
- new ECBlocks(26, new ECB(1, 108)),
- new ECBlocks(24, new ECB(2, 43)),
- new ECBlocks(18, new ECB(2, 15),
- new ECB(2, 16)),
- new ECBlocks(22, new ECB(2, 11),
- new ECB(2, 12))),
- new Version(6, Int32Array.from([6, 34]),
- new ECBlocks(18, new ECB(2, 68)),
- new ECBlocks(16, new ECB(4, 27)),
- new ECBlocks(24, new ECB(4, 19)),
- new ECBlocks(28, new ECB(4, 15))),
- new Version(7, Int32Array.from([6, 22, 38]),
- new ECBlocks(20, new ECB(2, 78)),
- new ECBlocks(18, new ECB(4, 31)),
- new ECBlocks(18, new ECB(2, 14),
- new ECB(4, 15)),
- new ECBlocks(26, new ECB(4, 13),
- new ECB(1, 14))),
- new Version(8, Int32Array.from([6, 24, 42]),
- new ECBlocks(24, new ECB(2, 97)),
- new ECBlocks(22, new ECB(2, 38),
- new ECB(2, 39)),
- new ECBlocks(22, new ECB(4, 18),
- new ECB(2, 19)),
- new ECBlocks(26, new ECB(4, 14),
- new ECB(2, 15))),
- new Version(9, Int32Array.from([6, 26, 46]),
- new ECBlocks(30, new ECB(2, 116)),
- new ECBlocks(22, new ECB(3, 36),
- new ECB(2, 37)),
- new ECBlocks(20, new ECB(4, 16),
- new ECB(4, 17)),
- new ECBlocks(24, new ECB(4, 12),
- new ECB(4, 13))),
- new Version(10, Int32Array.from([6, 28, 50]),
- new ECBlocks(18, new ECB(2, 68),
- new ECB(2, 69)),
- new ECBlocks(26, new ECB(4, 43),
- new ECB(1, 44)),
- new ECBlocks(24, new ECB(6, 19),
- new ECB(2, 20)),
- new ECBlocks(28, new ECB(6, 15),
- new ECB(2, 16))),
- new Version(11, Int32Array.from([6, 30, 54]),
- new ECBlocks(20, new ECB(4, 81)),
- new ECBlocks(30, new ECB(1, 50),
- new ECB(4, 51)),
- new ECBlocks(28, new ECB(4, 22),
- new ECB(4, 23)),
- new ECBlocks(24, new ECB(3, 12),
- new ECB(8, 13))),
- new Version(12, Int32Array.from([6, 32, 58]),
- new ECBlocks(24, new ECB(2, 92),
- new ECB(2, 93)),
- new ECBlocks(22, new ECB(6, 36),
- new ECB(2, 37)),
- new ECBlocks(26, new ECB(4, 20),
- new ECB(6, 21)),
- new ECBlocks(28, new ECB(7, 14),
- new ECB(4, 15))),
- new Version(13, Int32Array.from([6, 34, 62]),
- new ECBlocks(26, new ECB(4, 107)),
- new ECBlocks(22, new ECB(8, 37),
- new ECB(1, 38)),
- new ECBlocks(24, new ECB(8, 20),
- new ECB(4, 21)),
- new ECBlocks(22, new ECB(12, 11),
- new ECB(4, 12))),
- new Version(14, Int32Array.from([6, 26, 46, 66]),
- new ECBlocks(30, new ECB(3, 115),
- new ECB(1, 116)),
- new ECBlocks(24, new ECB(4, 40),
- new ECB(5, 41)),
- new ECBlocks(20, new ECB(11, 16),
- new ECB(5, 17)),
- new ECBlocks(24, new ECB(11, 12),
- new ECB(5, 13))),
- new Version(15, Int32Array.from([6, 26, 48, 70]),
- new ECBlocks(22, new ECB(5, 87),
- new ECB(1, 88)),
- new ECBlocks(24, new ECB(5, 41),
- new ECB(5, 42)),
- new ECBlocks(30, new ECB(5, 24),
- new ECB(7, 25)),
- new ECBlocks(24, new ECB(11, 12),
- new ECB(7, 13))),
- new Version(16, Int32Array.from([6, 26, 50, 74]),
- new ECBlocks(24, new ECB(5, 98),
- new ECB(1, 99)),
- new ECBlocks(28, new ECB(7, 45),
- new ECB(3, 46)),
- new ECBlocks(24, new ECB(15, 19),
- new ECB(2, 20)),
- new ECBlocks(30, new ECB(3, 15),
- new ECB(13, 16))),
- new Version(17, Int32Array.from([6, 30, 54, 78]),
- new ECBlocks(28, new ECB(1, 107),
- new ECB(5, 108)),
- new ECBlocks(28, new ECB(10, 46),
- new ECB(1, 47)),
- new ECBlocks(28, new ECB(1, 22),
- new ECB(15, 23)),
- new ECBlocks(28, new ECB(2, 14),
- new ECB(17, 15))),
- new Version(18, Int32Array.from([6, 30, 56, 82]),
- new ECBlocks(30, new ECB(5, 120),
- new ECB(1, 121)),
- new ECBlocks(26, new ECB(9, 43),
- new ECB(4, 44)),
- new ECBlocks(28, new ECB(17, 22),
- new ECB(1, 23)),
- new ECBlocks(28, new ECB(2, 14),
- new ECB(19, 15))),
- new Version(19, Int32Array.from([6, 30, 58, 86]),
- new ECBlocks(28, new ECB(3, 113),
- new ECB(4, 114)),
- new ECBlocks(26, new ECB(3, 44),
- new ECB(11, 45)),
- new ECBlocks(26, new ECB(17, 21),
- new ECB(4, 22)),
- new ECBlocks(26, new ECB(9, 13),
- new ECB(16, 14))),
- new Version(20, Int32Array.from([6, 34, 62, 90]),
- new ECBlocks(28, new ECB(3, 107),
- new ECB(5, 108)),
- new ECBlocks(26, new ECB(3, 41),
- new ECB(13, 42)),
- new ECBlocks(30, new ECB(15, 24),
- new ECB(5, 25)),
- new ECBlocks(28, new ECB(15, 15),
- new ECB(10, 16))),
- new Version(21, Int32Array.from([6, 28, 50, 72, 94]),
- new ECBlocks(28, new ECB(4, 116),
- new ECB(4, 117)),
- new ECBlocks(26, new ECB(17, 42)),
- new ECBlocks(28, new ECB(17, 22),
- new ECB(6, 23)),
- new ECBlocks(30, new ECB(19, 16),
- new ECB(6, 17))),
- new Version(22, Int32Array.from([6, 26, 50, 74, 98]),
- new ECBlocks(28, new ECB(2, 111),
- new ECB(7, 112)),
- new ECBlocks(28, new ECB(17, 46)),
- new ECBlocks(30, new ECB(7, 24),
- new ECB(16, 25)),
- new ECBlocks(24, new ECB(34, 13))),
- new Version(23, Int32Array.from([6, 30, 54, 78, 102]),
- new ECBlocks(30, new ECB(4, 121),
- new ECB(5, 122)),
- new ECBlocks(28, new ECB(4, 47),
- new ECB(14, 48)),
- new ECBlocks(30, new ECB(11, 24),
- new ECB(14, 25)),
- new ECBlocks(30, new ECB(16, 15),
- new ECB(14, 16))),
- new Version(24, Int32Array.from([6, 28, 54, 80, 106]),
- new ECBlocks(30, new ECB(6, 117),
- new ECB(4, 118)),
- new ECBlocks(28, new ECB(6, 45),
- new ECB(14, 46)),
- new ECBlocks(30, new ECB(11, 24),
- new ECB(16, 25)),
- new ECBlocks(30, new ECB(30, 16),
- new ECB(2, 17))),
- new Version(25, Int32Array.from([6, 32, 58, 84, 110]),
- new ECBlocks(26, new ECB(8, 106),
- new ECB(4, 107)),
- new ECBlocks(28, new ECB(8, 47),
- new ECB(13, 48)),
- new ECBlocks(30, new ECB(7, 24),
- new ECB(22, 25)),
- new ECBlocks(30, new ECB(22, 15),
- new ECB(13, 16))),
- new Version(26, Int32Array.from([6, 30, 58, 86, 114]),
- new ECBlocks(28, new ECB(10, 114),
- new ECB(2, 115)),
- new ECBlocks(28, new ECB(19, 46),
- new ECB(4, 47)),
- new ECBlocks(28, new ECB(28, 22),
- new ECB(6, 23)),
- new ECBlocks(30, new ECB(33, 16),
- new ECB(4, 17))),
- new Version(27, Int32Array.from([6, 34, 62, 90, 118]),
- new ECBlocks(30, new ECB(8, 122),
- new ECB(4, 123)),
- new ECBlocks(28, new ECB(22, 45),
- new ECB(3, 46)),
- new ECBlocks(30, new ECB(8, 23),
- new ECB(26, 24)),
- new ECBlocks(30, new ECB(12, 15),
- new ECB(28, 16))),
- new Version(28, Int32Array.from([6, 26, 50, 74, 98, 122]),
- new ECBlocks(30, new ECB(3, 117),
- new ECB(10, 118)),
- new ECBlocks(28, new ECB(3, 45),
- new ECB(23, 46)),
- new ECBlocks(30, new ECB(4, 24),
- new ECB(31, 25)),
- new ECBlocks(30, new ECB(11, 15),
- new ECB(31, 16))),
- new Version(29, Int32Array.from([6, 30, 54, 78, 102, 126]),
- new ECBlocks(30, new ECB(7, 116),
- new ECB(7, 117)),
- new ECBlocks(28, new ECB(21, 45),
- new ECB(7, 46)),
- new ECBlocks(30, new ECB(1, 23),
- new ECB(37, 24)),
- new ECBlocks(30, new ECB(19, 15),
- new ECB(26, 16))),
- new Version(30, Int32Array.from([6, 26, 52, 78, 104, 130]),
- new ECBlocks(30, new ECB(5, 115),
- new ECB(10, 116)),
- new ECBlocks(28, new ECB(19, 47),
- new ECB(10, 48)),
- new ECBlocks(30, new ECB(15, 24),
- new ECB(25, 25)),
- new ECBlocks(30, new ECB(23, 15),
- new ECB(25, 16))),
- new Version(31, Int32Array.from([6, 30, 56, 82, 108, 134]),
- new ECBlocks(30, new ECB(13, 115),
- new ECB(3, 116)),
- new ECBlocks(28, new ECB(2, 46),
- new ECB(29, 47)),
- new ECBlocks(30, new ECB(42, 24),
- new ECB(1, 25)),
- new ECBlocks(30, new ECB(23, 15),
- new ECB(28, 16))),
- new Version(32, Int32Array.from([6, 34, 60, 86, 112, 138]),
- new ECBlocks(30, new ECB(17, 115)),
- new ECBlocks(28, new ECB(10, 46),
- new ECB(23, 47)),
- new ECBlocks(30, new ECB(10, 24),
- new ECB(35, 25)),
- new ECBlocks(30, new ECB(19, 15),
- new ECB(35, 16))),
- new Version(33, Int32Array.from([6, 30, 58, 86, 114, 142]),
- new ECBlocks(30, new ECB(17, 115),
- new ECB(1, 116)),
- new ECBlocks(28, new ECB(14, 46),
- new ECB(21, 47)),
- new ECBlocks(30, new ECB(29, 24),
- new ECB(19, 25)),
- new ECBlocks(30, new ECB(11, 15),
- new ECB(46, 16))),
- new Version(34, Int32Array.from([6, 34, 62, 90, 118, 146]),
- new ECBlocks(30, new ECB(13, 115),
- new ECB(6, 116)),
- new ECBlocks(28, new ECB(14, 46),
- new ECB(23, 47)),
- new ECBlocks(30, new ECB(44, 24),
- new ECB(7, 25)),
- new ECBlocks(30, new ECB(59, 16),
- new ECB(1, 17))),
- new Version(35, Int32Array.from([6, 30, 54, 78, 102, 126, 150]),
- new ECBlocks(30, new ECB(12, 121),
- new ECB(7, 122)),
- new ECBlocks(28, new ECB(12, 47),
- new ECB(26, 48)),
- new ECBlocks(30, new ECB(39, 24),
- new ECB(14, 25)),
- new ECBlocks(30, new ECB(22, 15),
- new ECB(41, 16))),
- new Version(36, Int32Array.from([6, 24, 50, 76, 102, 128, 154]),
- new ECBlocks(30, new ECB(6, 121),
- new ECB(14, 122)),
- new ECBlocks(28, new ECB(6, 47),
- new ECB(34, 48)),
- new ECBlocks(30, new ECB(46, 24),
- new ECB(10, 25)),
- new ECBlocks(30, new ECB(2, 15),
- new ECB(64, 16))),
- new Version(37, Int32Array.from([6, 28, 54, 80, 106, 132, 158]),
- new ECBlocks(30, new ECB(17, 122),
- new ECB(4, 123)),
- new ECBlocks(28, new ECB(29, 46),
- new ECB(14, 47)),
- new ECBlocks(30, new ECB(49, 24),
- new ECB(10, 25)),
- new ECBlocks(30, new ECB(24, 15),
- new ECB(46, 16))),
- new Version(38, Int32Array.from([6, 32, 58, 84, 110, 136, 162]),
- new ECBlocks(30, new ECB(4, 122),
- new ECB(18, 123)),
- new ECBlocks(28, new ECB(13, 46),
- new ECB(32, 47)),
- new ECBlocks(30, new ECB(48, 24),
- new ECB(14, 25)),
- new ECBlocks(30, new ECB(42, 15),
- new ECB(32, 16))),
- new Version(39, Int32Array.from([6, 26, 54, 82, 110, 138, 166]),
- new ECBlocks(30, new ECB(20, 117),
- new ECB(4, 118)),
- new ECBlocks(28, new ECB(40, 47),
- new ECB(7, 48)),
- new ECBlocks(30, new ECB(43, 24),
- new ECB(22, 25)),
- new ECBlocks(30, new ECB(10, 15),
- new ECB(67, 16))),
- new Version(40, Int32Array.from([6, 30, 58, 86, 114, 142, 170]),
- new ECBlocks(30, new ECB(19, 118),
- new ECB(6, 119)),
- new ECBlocks(28, new ECB(18, 47),
- new ECB(31, 48)),
- new ECBlocks(30, new ECB(34, 24),
- new ECB(34, 25)),
- new ECBlocks(30, new ECB(20, 15),
- new ECB(61, 16)))
- ];
+ /**
+ * See ISO 18004:2006 6.5.1 Table 9
+ */
+ private static VERSIONS: Version[] = [
+ new Version(1, new Int32Array(0),
+ new ECBlocks(7, new ECB(1, 19)),
+ new ECBlocks(10, new ECB(1, 16)),
+ new ECBlocks(13, new ECB(1, 13)),
+ new ECBlocks(17, new ECB(1, 9))),
+ new Version(2, Int32Array.from([6, 18]),
+ new ECBlocks(10, new ECB(1, 34)),
+ new ECBlocks(16, new ECB(1, 28)),
+ new ECBlocks(22, new ECB(1, 22)),
+ new ECBlocks(28, new ECB(1, 16))),
+ new Version(3, Int32Array.from([6, 22]),
+ new ECBlocks(15, new ECB(1, 55)),
+ new ECBlocks(26, new ECB(1, 44)),
+ new ECBlocks(18, new ECB(2, 17)),
+ new ECBlocks(22, new ECB(2, 13))),
+ new Version(4, Int32Array.from([6, 26]),
+ new ECBlocks(20, new ECB(1, 80)),
+ new ECBlocks(18, new ECB(2, 32)),
+ new ECBlocks(26, new ECB(2, 24)),
+ new ECBlocks(16, new ECB(4, 9))),
+ new Version(5, Int32Array.from([6, 30]),
+ new ECBlocks(26, new ECB(1, 108)),
+ new ECBlocks(24, new ECB(2, 43)),
+ new ECBlocks(18, new ECB(2, 15),
+ new ECB(2, 16)),
+ new ECBlocks(22, new ECB(2, 11),
+ new ECB(2, 12))),
+ new Version(6, Int32Array.from([6, 34]),
+ new ECBlocks(18, new ECB(2, 68)),
+ new ECBlocks(16, new ECB(4, 27)),
+ new ECBlocks(24, new ECB(4, 19)),
+ new ECBlocks(28, new ECB(4, 15))),
+ new Version(7, Int32Array.from([6, 22, 38]),
+ new ECBlocks(20, new ECB(2, 78)),
+ new ECBlocks(18, new ECB(4, 31)),
+ new ECBlocks(18, new ECB(2, 14),
+ new ECB(4, 15)),
+ new ECBlocks(26, new ECB(4, 13),
+ new ECB(1, 14))),
+ new Version(8, Int32Array.from([6, 24, 42]),
+ new ECBlocks(24, new ECB(2, 97)),
+ new ECBlocks(22, new ECB(2, 38),
+ new ECB(2, 39)),
+ new ECBlocks(22, new ECB(4, 18),
+ new ECB(2, 19)),
+ new ECBlocks(26, new ECB(4, 14),
+ new ECB(2, 15))),
+ new Version(9, Int32Array.from([6, 26, 46]),
+ new ECBlocks(30, new ECB(2, 116)),
+ new ECBlocks(22, new ECB(3, 36),
+ new ECB(2, 37)),
+ new ECBlocks(20, new ECB(4, 16),
+ new ECB(4, 17)),
+ new ECBlocks(24, new ECB(4, 12),
+ new ECB(4, 13))),
+ new Version(10, Int32Array.from([6, 28, 50]),
+ new ECBlocks(18, new ECB(2, 68),
+ new ECB(2, 69)),
+ new ECBlocks(26, new ECB(4, 43),
+ new ECB(1, 44)),
+ new ECBlocks(24, new ECB(6, 19),
+ new ECB(2, 20)),
+ new ECBlocks(28, new ECB(6, 15),
+ new ECB(2, 16))),
+ new Version(11, Int32Array.from([6, 30, 54]),
+ new ECBlocks(20, new ECB(4, 81)),
+ new ECBlocks(30, new ECB(1, 50),
+ new ECB(4, 51)),
+ new ECBlocks(28, new ECB(4, 22),
+ new ECB(4, 23)),
+ new ECBlocks(24, new ECB(3, 12),
+ new ECB(8, 13))),
+ new Version(12, Int32Array.from([6, 32, 58]),
+ new ECBlocks(24, new ECB(2, 92),
+ new ECB(2, 93)),
+ new ECBlocks(22, new ECB(6, 36),
+ new ECB(2, 37)),
+ new ECBlocks(26, new ECB(4, 20),
+ new ECB(6, 21)),
+ new ECBlocks(28, new ECB(7, 14),
+ new ECB(4, 15))),
+ new Version(13, Int32Array.from([6, 34, 62]),
+ new ECBlocks(26, new ECB(4, 107)),
+ new ECBlocks(22, new ECB(8, 37),
+ new ECB(1, 38)),
+ new ECBlocks(24, new ECB(8, 20),
+ new ECB(4, 21)),
+ new ECBlocks(22, new ECB(12, 11),
+ new ECB(4, 12))),
+ new Version(14, Int32Array.from([6, 26, 46, 66]),
+ new ECBlocks(30, new ECB(3, 115),
+ new ECB(1, 116)),
+ new ECBlocks(24, new ECB(4, 40),
+ new ECB(5, 41)),
+ new ECBlocks(20, new ECB(11, 16),
+ new ECB(5, 17)),
+ new ECBlocks(24, new ECB(11, 12),
+ new ECB(5, 13))),
+ new Version(15, Int32Array.from([6, 26, 48, 70]),
+ new ECBlocks(22, new ECB(5, 87),
+ new ECB(1, 88)),
+ new ECBlocks(24, new ECB(5, 41),
+ new ECB(5, 42)),
+ new ECBlocks(30, new ECB(5, 24),
+ new ECB(7, 25)),
+ new ECBlocks(24, new ECB(11, 12),
+ new ECB(7, 13))),
+ new Version(16, Int32Array.from([6, 26, 50, 74]),
+ new ECBlocks(24, new ECB(5, 98),
+ new ECB(1, 99)),
+ new ECBlocks(28, new ECB(7, 45),
+ new ECB(3, 46)),
+ new ECBlocks(24, new ECB(15, 19),
+ new ECB(2, 20)),
+ new ECBlocks(30, new ECB(3, 15),
+ new ECB(13, 16))),
+ new Version(17, Int32Array.from([6, 30, 54, 78]),
+ new ECBlocks(28, new ECB(1, 107),
+ new ECB(5, 108)),
+ new ECBlocks(28, new ECB(10, 46),
+ new ECB(1, 47)),
+ new ECBlocks(28, new ECB(1, 22),
+ new ECB(15, 23)),
+ new ECBlocks(28, new ECB(2, 14),
+ new ECB(17, 15))),
+ new Version(18, Int32Array.from([6, 30, 56, 82]),
+ new ECBlocks(30, new ECB(5, 120),
+ new ECB(1, 121)),
+ new ECBlocks(26, new ECB(9, 43),
+ new ECB(4, 44)),
+ new ECBlocks(28, new ECB(17, 22),
+ new ECB(1, 23)),
+ new ECBlocks(28, new ECB(2, 14),
+ new ECB(19, 15))),
+ new Version(19, Int32Array.from([6, 30, 58, 86]),
+ new ECBlocks(28, new ECB(3, 113),
+ new ECB(4, 114)),
+ new ECBlocks(26, new ECB(3, 44),
+ new ECB(11, 45)),
+ new ECBlocks(26, new ECB(17, 21),
+ new ECB(4, 22)),
+ new ECBlocks(26, new ECB(9, 13),
+ new ECB(16, 14))),
+ new Version(20, Int32Array.from([6, 34, 62, 90]),
+ new ECBlocks(28, new ECB(3, 107),
+ new ECB(5, 108)),
+ new ECBlocks(26, new ECB(3, 41),
+ new ECB(13, 42)),
+ new ECBlocks(30, new ECB(15, 24),
+ new ECB(5, 25)),
+ new ECBlocks(28, new ECB(15, 15),
+ new ECB(10, 16))),
+ new Version(21, Int32Array.from([6, 28, 50, 72, 94]),
+ new ECBlocks(28, new ECB(4, 116),
+ new ECB(4, 117)),
+ new ECBlocks(26, new ECB(17, 42)),
+ new ECBlocks(28, new ECB(17, 22),
+ new ECB(6, 23)),
+ new ECBlocks(30, new ECB(19, 16),
+ new ECB(6, 17))),
+ new Version(22, Int32Array.from([6, 26, 50, 74, 98]),
+ new ECBlocks(28, new ECB(2, 111),
+ new ECB(7, 112)),
+ new ECBlocks(28, new ECB(17, 46)),
+ new ECBlocks(30, new ECB(7, 24),
+ new ECB(16, 25)),
+ new ECBlocks(24, new ECB(34, 13))),
+ new Version(23, Int32Array.from([6, 30, 54, 78, 102]),
+ new ECBlocks(30, new ECB(4, 121),
+ new ECB(5, 122)),
+ new ECBlocks(28, new ECB(4, 47),
+ new ECB(14, 48)),
+ new ECBlocks(30, new ECB(11, 24),
+ new ECB(14, 25)),
+ new ECBlocks(30, new ECB(16, 15),
+ new ECB(14, 16))),
+ new Version(24, Int32Array.from([6, 28, 54, 80, 106]),
+ new ECBlocks(30, new ECB(6, 117),
+ new ECB(4, 118)),
+ new ECBlocks(28, new ECB(6, 45),
+ new ECB(14, 46)),
+ new ECBlocks(30, new ECB(11, 24),
+ new ECB(16, 25)),
+ new ECBlocks(30, new ECB(30, 16),
+ new ECB(2, 17))),
+ new Version(25, Int32Array.from([6, 32, 58, 84, 110]),
+ new ECBlocks(26, new ECB(8, 106),
+ new ECB(4, 107)),
+ new ECBlocks(28, new ECB(8, 47),
+ new ECB(13, 48)),
+ new ECBlocks(30, new ECB(7, 24),
+ new ECB(22, 25)),
+ new ECBlocks(30, new ECB(22, 15),
+ new ECB(13, 16))),
+ new Version(26, Int32Array.from([6, 30, 58, 86, 114]),
+ new ECBlocks(28, new ECB(10, 114),
+ new ECB(2, 115)),
+ new ECBlocks(28, new ECB(19, 46),
+ new ECB(4, 47)),
+ new ECBlocks(28, new ECB(28, 22),
+ new ECB(6, 23)),
+ new ECBlocks(30, new ECB(33, 16),
+ new ECB(4, 17))),
+ new Version(27, Int32Array.from([6, 34, 62, 90, 118]),
+ new ECBlocks(30, new ECB(8, 122),
+ new ECB(4, 123)),
+ new ECBlocks(28, new ECB(22, 45),
+ new ECB(3, 46)),
+ new ECBlocks(30, new ECB(8, 23),
+ new ECB(26, 24)),
+ new ECBlocks(30, new ECB(12, 15),
+ new ECB(28, 16))),
+ new Version(28, Int32Array.from([6, 26, 50, 74, 98, 122]),
+ new ECBlocks(30, new ECB(3, 117),
+ new ECB(10, 118)),
+ new ECBlocks(28, new ECB(3, 45),
+ new ECB(23, 46)),
+ new ECBlocks(30, new ECB(4, 24),
+ new ECB(31, 25)),
+ new ECBlocks(30, new ECB(11, 15),
+ new ECB(31, 16))),
+ new Version(29, Int32Array.from([6, 30, 54, 78, 102, 126]),
+ new ECBlocks(30, new ECB(7, 116),
+ new ECB(7, 117)),
+ new ECBlocks(28, new ECB(21, 45),
+ new ECB(7, 46)),
+ new ECBlocks(30, new ECB(1, 23),
+ new ECB(37, 24)),
+ new ECBlocks(30, new ECB(19, 15),
+ new ECB(26, 16))),
+ new Version(30, Int32Array.from([6, 26, 52, 78, 104, 130]),
+ new ECBlocks(30, new ECB(5, 115),
+ new ECB(10, 116)),
+ new ECBlocks(28, new ECB(19, 47),
+ new ECB(10, 48)),
+ new ECBlocks(30, new ECB(15, 24),
+ new ECB(25, 25)),
+ new ECBlocks(30, new ECB(23, 15),
+ new ECB(25, 16))),
+ new Version(31, Int32Array.from([6, 30, 56, 82, 108, 134]),
+ new ECBlocks(30, new ECB(13, 115),
+ new ECB(3, 116)),
+ new ECBlocks(28, new ECB(2, 46),
+ new ECB(29, 47)),
+ new ECBlocks(30, new ECB(42, 24),
+ new ECB(1, 25)),
+ new ECBlocks(30, new ECB(23, 15),
+ new ECB(28, 16))),
+ new Version(32, Int32Array.from([6, 34, 60, 86, 112, 138]),
+ new ECBlocks(30, new ECB(17, 115)),
+ new ECBlocks(28, new ECB(10, 46),
+ new ECB(23, 47)),
+ new ECBlocks(30, new ECB(10, 24),
+ new ECB(35, 25)),
+ new ECBlocks(30, new ECB(19, 15),
+ new ECB(35, 16))),
+ new Version(33, Int32Array.from([6, 30, 58, 86, 114, 142]),
+ new ECBlocks(30, new ECB(17, 115),
+ new ECB(1, 116)),
+ new ECBlocks(28, new ECB(14, 46),
+ new ECB(21, 47)),
+ new ECBlocks(30, new ECB(29, 24),
+ new ECB(19, 25)),
+ new ECBlocks(30, new ECB(11, 15),
+ new ECB(46, 16))),
+ new Version(34, Int32Array.from([6, 34, 62, 90, 118, 146]),
+ new ECBlocks(30, new ECB(13, 115),
+ new ECB(6, 116)),
+ new ECBlocks(28, new ECB(14, 46),
+ new ECB(23, 47)),
+ new ECBlocks(30, new ECB(44, 24),
+ new ECB(7, 25)),
+ new ECBlocks(30, new ECB(59, 16),
+ new ECB(1, 17))),
+ new Version(35, Int32Array.from([6, 30, 54, 78, 102, 126, 150]),
+ new ECBlocks(30, new ECB(12, 121),
+ new ECB(7, 122)),
+ new ECBlocks(28, new ECB(12, 47),
+ new ECB(26, 48)),
+ new ECBlocks(30, new ECB(39, 24),
+ new ECB(14, 25)),
+ new ECBlocks(30, new ECB(22, 15),
+ new ECB(41, 16))),
+ new Version(36, Int32Array.from([6, 24, 50, 76, 102, 128, 154]),
+ new ECBlocks(30, new ECB(6, 121),
+ new ECB(14, 122)),
+ new ECBlocks(28, new ECB(6, 47),
+ new ECB(34, 48)),
+ new ECBlocks(30, new ECB(46, 24),
+ new ECB(10, 25)),
+ new ECBlocks(30, new ECB(2, 15),
+ new ECB(64, 16))),
+ new Version(37, Int32Array.from([6, 28, 54, 80, 106, 132, 158]),
+ new ECBlocks(30, new ECB(17, 122),
+ new ECB(4, 123)),
+ new ECBlocks(28, new ECB(29, 46),
+ new ECB(14, 47)),
+ new ECBlocks(30, new ECB(49, 24),
+ new ECB(10, 25)),
+ new ECBlocks(30, new ECB(24, 15),
+ new ECB(46, 16))),
+ new Version(38, Int32Array.from([6, 32, 58, 84, 110, 136, 162]),
+ new ECBlocks(30, new ECB(4, 122),
+ new ECB(18, 123)),
+ new ECBlocks(28, new ECB(13, 46),
+ new ECB(32, 47)),
+ new ECBlocks(30, new ECB(48, 24),
+ new ECB(14, 25)),
+ new ECBlocks(30, new ECB(42, 15),
+ new ECB(32, 16))),
+ new Version(39, Int32Array.from([6, 26, 54, 82, 110, 138, 166]),
+ new ECBlocks(30, new ECB(20, 117),
+ new ECB(4, 118)),
+ new ECBlocks(28, new ECB(40, 47),
+ new ECB(7, 48)),
+ new ECBlocks(30, new ECB(43, 24),
+ new ECB(22, 25)),
+ new ECBlocks(30, new ECB(10, 15),
+ new ECB(67, 16))),
+ new Version(40, Int32Array.from([6, 30, 58, 86, 114, 142, 170]),
+ new ECBlocks(30, new ECB(19, 118),
+ new ECB(6, 119)),
+ new ECBlocks(28, new ECB(18, 47),
+ new ECB(31, 48)),
+ new ECBlocks(30, new ECB(34, 24),
+ new ECB(34, 25)),
+ new ECBlocks(30, new ECB(20, 15),
+ new ECB(61, 16)))
+ ];
- private ecBlocks: ECBlocks[];
- private totalCodewords: number; /*int*/
+ private ecBlocks: ECBlocks[];
+ private totalCodewords: number; /*int*/
- private constructor(private versionNumber: number /*int*/,
- private alignmentPatternCenters: Int32Array,
- ...ecBlocks: ECBlocks[]) {
- this.ecBlocks = ecBlocks;
- let total = 0;
- const ecCodewords = ecBlocks[0].getECCodewordsPerBlock();
- const ecbArray: ECB[] = ecBlocks[0].getECBlocks();
- for (const ecBlock of ecbArray) {
- total += ecBlock.getCount() * (ecBlock.getDataCodewords() + ecCodewords);
- }
- this.totalCodewords = total;
+ private constructor(private versionNumber: number /*int*/,
+ private alignmentPatternCenters: Int32Array,
+ ...ecBlocks: ECBlocks[]) {
+ this.ecBlocks = ecBlocks;
+ let total = 0;
+ const ecCodewords = ecBlocks[0].getECCodewordsPerBlock();
+ const ecbArray: ECB[] = ecBlocks[0].getECBlocks();
+ for (const ecBlock of ecbArray) {
+ total += ecBlock.getCount() * (ecBlock.getDataCodewords() + ecCodewords);
}
+ this.totalCodewords = total;
+ }
- public getVersionNumber(): number /*int*/ {
- return this.versionNumber;
- }
+ public getVersionNumber(): number /*int*/ {
+ return this.versionNumber;
+ }
- public getAlignmentPatternCenters(): Int32Array {
- return this.alignmentPatternCenters;
- }
+ public getAlignmentPatternCenters(): Int32Array {
+ return this.alignmentPatternCenters;
+ }
- public getTotalCodewords(): number /*int*/ {
- return this.totalCodewords;
- }
+ public getTotalCodewords(): number /*int*/ {
+ return this.totalCodewords;
+ }
- public getDimensionForVersion(): number /*int*/ {
- return 17 + 4 * this.versionNumber;
- }
+ public getDimensionForVersion(): number /*int*/ {
+ return 17 + 4 * this.versionNumber;
+ }
- public getECBlocksForLevel(ecLevel: ErrorCorrectionLevel): ECBlocks {
- return this.ecBlocks[ecLevel.getValue()];
- // TYPESCRIPTPORT: original was using ordinal, and using the order of levels as defined in ErrorCorrectionLevel enum (LMQH)
- // I will use the direct value from ErrorCorrectionLevelValues enum which in typescript goes to a number
- }
+ public getECBlocksForLevel(ecLevel: ErrorCorrectionLevel): ECBlocks {
+ return this.ecBlocks[ecLevel.getValue()];
+ // TYPESCRIPTPORT: original was using ordinal, and using the order of levels as defined in ErrorCorrectionLevel enum (LMQH)
+ // I will use the direct value from ErrorCorrectionLevelValues enum which in typescript goes to a number
+ }
- /**
- *
Deduces version information purely from QR Code dimensions.
- *
- * @param dimension dimension in modules
- * @return Version for a QR Code of that dimension
- * @throws FormatException if dimension is not 1 mod 4
- */
- public static getProvisionalVersionForDimension(dimension: number /*int*/): Version /*throws FormatException */ {
- if (dimension % 4 !== 1) {
- throw new FormatException();
- }
- try {
- return this.getVersionForNumber((dimension - 17) / 4);
- } catch (ignored/*: IllegalArgumentException*/) {
- throw new FormatException();
- }
+ /**
+ *
Deduces version information purely from QR Code dimensions.
+ *
+ * @param dimension dimension in modules
+ * @return Version for a QR Code of that dimension
+ * @throws FormatException if dimension is not 1 mod 4
+ */
+ public static getProvisionalVersionForDimension(dimension: number /*int*/): Version /*throws FormatException */ {
+ if (dimension % 4 !== 1) {
+ throw new FormatException();
}
+ try {
+ return this.getVersionForNumber((dimension - 17) / 4);
+ } catch (ignored/*: IllegalArgumentException*/) {
+ throw new FormatException();
+ }
+ }
- public static getVersionForNumber(versionNumber: number /*int*/): Version {
- if (versionNumber < 1 || versionNumber > 40) {
- throw new IllegalArgumentException();
- }
- return Version.VERSIONS[versionNumber - 1];
+ public static getVersionForNumber(versionNumber: number /*int*/): Version {
+ if (versionNumber < 1 || versionNumber > 40) {
+ throw new IllegalArgumentException();
}
+ return Version.VERSIONS[versionNumber - 1];
+ }
- public static decodeVersionInformation(versionBits: number /*int*/): Version {
- let bestDifference = Number.MAX_SAFE_INTEGER;
- let bestVersion = 0;
- for (let i = 0; i < Version.VERSION_DECODE_INFO.length; i++) {
- const targetVersion = Version.VERSION_DECODE_INFO[i];
- // Do the version info bits match exactly? done.
- if (targetVersion === versionBits) {
- return Version.getVersionForNumber(i + 7);
- }
- // Otherwise see if this is the closest to a real version info bit string
- // we have seen so far
- const bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion);
- if (bitsDifference < bestDifference) {
- bestVersion = i + 7;
- bestDifference = bitsDifference;
- }
- }
- // We can tolerate up to 3 bits of error since no two version info codewords will
- // differ in less than 8 bits.
- if (bestDifference <= 3) {
- return Version.getVersionForNumber(bestVersion);
- }
- // If we didn't find a close enough match, fail
- return null;
+ public static decodeVersionInformation(versionBits: number /*int*/): Version {
+ let bestDifference = Number.MAX_SAFE_INTEGER;
+ let bestVersion = 0;
+ for (let i = 0; i < Version.VERSION_DECODE_INFO.length; i++) {
+ const targetVersion = Version.VERSION_DECODE_INFO[i];
+ // Do the version info bits match exactly? done.
+ if (targetVersion === versionBits) {
+ return Version.getVersionForNumber(i + 7);
+ }
+ // Otherwise see if this is the closest to a real version info bit string
+ // we have seen so far
+ const bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion);
+ if (bitsDifference < bestDifference) {
+ bestVersion = i + 7;
+ bestDifference = bitsDifference;
+ }
+ }
+ // We can tolerate up to 3 bits of error since no two version info codewords will
+ // differ in less than 8 bits.
+ if (bestDifference <= 3) {
+ return Version.getVersionForNumber(bestVersion);
}
+ // If we didn't find a close enough match, fail
+ return null;
+ }
- /**
- * See ISO 18004:2006 Annex E
- */
- public buildFunctionPattern(): BitMatrix {
- const dimension = this.getDimensionForVersion();
- const bitMatrix = new BitMatrix(dimension);
+ /**
+ * See ISO 18004:2006 Annex E
+ */
+ public buildFunctionPattern(): BitMatrix {
+ const dimension = this.getDimensionForVersion();
+ const bitMatrix = new BitMatrix(dimension);
- // Top left finder pattern + separator + format
- bitMatrix.setRegion(0, 0, 9, 9);
- // Top right finder pattern + separator + format
- bitMatrix.setRegion(dimension - 8, 0, 8, 9);
- // Bottom left finder pattern + separator + format
- bitMatrix.setRegion(0, dimension - 8, 9, 8);
+ // Top left finder pattern + separator + format
+ bitMatrix.setRegion(0, 0, 9, 9);
+ // Top right finder pattern + separator + format
+ bitMatrix.setRegion(dimension - 8, 0, 8, 9);
+ // Bottom left finder pattern + separator + format
+ bitMatrix.setRegion(0, dimension - 8, 9, 8);
- // Alignment patterns
- const max = this.alignmentPatternCenters.length;
- for (let x = 0; x < max; x++) {
- const i = this.alignmentPatternCenters[x] - 2;
- for (let y = 0; y < max; y++) {
- if ((x === 0 && (y === 0 || y === max - 1)) || (x === max - 1 && y === 0)) {
- // No alignment patterns near the three finder patterns
- continue;
- }
- bitMatrix.setRegion(this.alignmentPatternCenters[y] - 2, i, 5, 5);
- }
+ // Alignment patterns
+ const max = this.alignmentPatternCenters.length;
+ for (let x = 0; x < max; x++) {
+ const i = this.alignmentPatternCenters[x] - 2;
+ for (let y = 0; y < max; y++) {
+ if ((x === 0 && (y === 0 || y === max - 1)) || (x === max - 1 && y === 0)) {
+ // No alignment patterns near the three finder patterns
+ continue;
}
+ bitMatrix.setRegion(this.alignmentPatternCenters[y] - 2, i, 5, 5);
+ }
+ }
- // Vertical timing pattern
- bitMatrix.setRegion(6, 9, 1, dimension - 17);
- // Horizontal timing pattern
- bitMatrix.setRegion(9, 6, dimension - 17, 1);
-
- if (this.versionNumber > 6) {
- // Version info, top right
- bitMatrix.setRegion(dimension - 11, 0, 3, 6);
- // Version info, bottom left
- bitMatrix.setRegion(0, dimension - 11, 6, 3);
- }
+ // Vertical timing pattern
+ bitMatrix.setRegion(6, 9, 1, dimension - 17);
+ // Horizontal timing pattern
+ bitMatrix.setRegion(9, 6, dimension - 17, 1);
- return bitMatrix;
+ if (this.versionNumber > 6) {
+ // Version info, top right
+ bitMatrix.setRegion(dimension - 11, 0, 3, 6);
+ // Version info, bottom left
+ bitMatrix.setRegion(0, dimension - 11, 6, 3);
}
- /*@Override*/
- public toString(): string {
- return '' + this.versionNumber;
- }
+ return bitMatrix;
+ }
+
+ /*@Override*/
+ public toString(): string {
+ return '' + this.versionNumber;
+ }
}
diff --git a/src/core/qrcode/detector/AlignmentPattern.ts b/src/core/qrcode/detector/AlignmentPattern.ts
index c3a896e3..4d050bd6 100644
--- a/src/core/qrcode/detector/AlignmentPattern.ts
+++ b/src/core/qrcode/detector/AlignmentPattern.ts
@@ -26,31 +26,31 @@ import ResultPoint from '../../ResultPoint';
*/
export default class AlignmentPattern extends ResultPoint {
- public constructor(posX: number/*float*/, posY: number/*float*/, private estimatedModuleSize: number/*float*/) {
- super(posX, posY);
- }
+ public constructor(posX: number/*float*/, posY: number/*float*/, private estimatedModuleSize: number/*float*/) {
+ super(posX, posY);
+ }
- /**
- *
Determines if this alignment pattern "about equals" an alignment pattern at the stated
- * position and size -- meaning, it is at nearly the same center with nearly the same size.
Determines if this alignment pattern "about equals" an alignment pattern at the stated
+ * position and size -- meaning, it is at nearly the same center with nearly the same size.
+ */
+ public aboutEquals(moduleSize: number/*float*/, i: number/*float*/, j: number/*float*/): boolean {
+ if (Math.abs(i - this.getY()) <= moduleSize && Math.abs(j - this.getX()) <= moduleSize) {
+ const moduleSizeDiff: number /*float*/ = Math.abs(moduleSize - this.estimatedModuleSize);
+ return moduleSizeDiff <= 1.0 || moduleSizeDiff <= this.estimatedModuleSize;
}
+ return false;
+ }
- /**
- * Combines this object's current estimate of a finder pattern position and module size
- * with a new estimate. It returns a new {@code FinderPattern} containing an average of the two.
- */
- public combineEstimate(i: number/*float*/, j: number/*float*/, newModuleSize: number/*float*/): AlignmentPattern {
- const combinedX: number /*float*/ = (this.getX() + j) / 2.0;
- const combinedY: number /*float*/ = (this.getY() + i) / 2.0;
- const combinedModuleSize: number /*float*/ = (this.estimatedModuleSize + newModuleSize) / 2.0;
- return new AlignmentPattern(combinedX, combinedY, combinedModuleSize);
- }
+ /**
+ * Combines this object's current estimate of a finder pattern position and module size
+ * with a new estimate. It returns a new {@code FinderPattern} containing an average of the two.
+ */
+ public combineEstimate(i: number/*float*/, j: number/*float*/, newModuleSize: number/*float*/): AlignmentPattern {
+ const combinedX: number /*float*/ = (this.getX() + j) / 2.0;
+ const combinedY: number /*float*/ = (this.getY() + i) / 2.0;
+ const combinedModuleSize: number /*float*/ = (this.estimatedModuleSize + newModuleSize) / 2.0;
+ return new AlignmentPattern(combinedX, combinedY, combinedModuleSize);
+ }
}
diff --git a/src/core/qrcode/detector/AlignmentPatternFinder.ts b/src/core/qrcode/detector/AlignmentPatternFinder.ts
index 628d0831..71e222ed 100644
--- a/src/core/qrcode/detector/AlignmentPatternFinder.ts
+++ b/src/core/qrcode/detector/AlignmentPatternFinder.ts
@@ -41,230 +41,230 @@ import NotFoundException from '../../NotFoundException';
*/
export default class AlignmentPatternFinder {
- private possibleCenters: AlignmentPattern[];
- private crossCheckStateCount: Int32Array;
+ private possibleCenters: AlignmentPattern[];
+ private crossCheckStateCount: Int32Array;
- /**
- *
Creates a finder that will look in a portion of the whole image.
- *
- * @param image image to search
- * @param startX left column from which to start searching
- * @param startY top row from which to start searching
- * @param width width of region to search
- * @param height height of region to search
- * @param moduleSize estimated module size so far
- */
- public constructor(private image: BitMatrix,
- private startX: number /*int*/,
- private startY: number /*int*/,
- private width: number /*int*/,
- private height: number /*int*/,
- private moduleSize: number/*float*/,
- private resultPointCallback: ResultPointCallback) {
- this.possibleCenters = []; // new Array(5))
- // TYPESCRIPTPORT: array initialization without size as the length is checked below
- this.crossCheckStateCount = new Int32Array(3);
- }
+ /**
+ *
Creates a finder that will look in a portion of the whole image.
+ *
+ * @param image image to search
+ * @param startX left column from which to start searching
+ * @param startY top row from which to start searching
+ * @param width width of region to search
+ * @param height height of region to search
+ * @param moduleSize estimated module size so far
+ */
+ public constructor(private image: BitMatrix,
+ private startX: number /*int*/,
+ private startY: number /*int*/,
+ private width: number /*int*/,
+ private height: number /*int*/,
+ private moduleSize: number/*float*/,
+ private resultPointCallback: ResultPointCallback) {
+ this.possibleCenters = []; // new Array(5))
+ // TYPESCRIPTPORT: array initialization without size as the length is checked below
+ this.crossCheckStateCount = new Int32Array(3);
+ }
- /**
- *
This method attempts to find the bottom-right alignment pattern in the image. It is a bit messy since
- * it's pretty performance-critical and so is written to be fast foremost.
- *
- * @return {@link AlignmentPattern} if found
- * @throws NotFoundException if not found
- */
- public find(): AlignmentPattern /*throws NotFoundException*/ {
- const startX = this.startX;
- const height = this.height;
- const width = this.width;
- const maxJ = startX + width;
- const middleI = this.startY + (height / 2);
- // We are looking for black/white/black modules in 1:1:1 ratio
- // this tracks the number of black/white/black modules seen so far
- const stateCount = new Int32Array(3);
- const image = this.image;
- for (let iGen = 0; iGen < height; iGen++) {
- // Search from middle outwards
- const i = middleI + ((iGen & 0x01) === 0 ? Math.floor((iGen + 1) / 2) : -Math.floor((iGen + 1) / 2));
+ /**
+ *
This method attempts to find the bottom-right alignment pattern in the image. It is a bit messy since
+ * it's pretty performance-critical and so is written to be fast foremost.
+ *
+ * @return {@link AlignmentPattern} if found
+ * @throws NotFoundException if not found
+ */
+ public find(): AlignmentPattern /*throws NotFoundException*/ {
+ const startX = this.startX;
+ const height = this.height;
+ const width = this.width;
+ const maxJ = startX + width;
+ const middleI = this.startY + (height / 2);
+ // We are looking for black/white/black modules in 1:1:1 ratio
+ // this tracks the number of black/white/black modules seen so far
+ const stateCount = new Int32Array(3);
+ const image = this.image;
+ for (let iGen = 0; iGen < height; iGen++) {
+ // Search from middle outwards
+ const i = middleI + ((iGen & 0x01) === 0 ? Math.floor((iGen + 1) / 2) : -Math.floor((iGen + 1) / 2));
- stateCount[0] = 0;
- stateCount[1] = 0;
- stateCount[2] = 0;
+ stateCount[0] = 0;
+ stateCount[1] = 0;
+ stateCount[2] = 0;
- let j = startX;
- // Burn off leading white pixels before anything else; if we start in the middle of
- // a white run, it doesn't make sense to count its length, since we don't know if the
- // white run continued to the left of the start point
- while (j < maxJ && !image.get(j, i)) {
- j++;
- }
- let currentState = 0;
- while (j < maxJ) {
- if (image.get(j, i)) {
- // Black pixel
- if (currentState === 1) { // Counting black pixels
- stateCount[1]++;
- } else { // Counting white pixels
- if (currentState === 2) { // A winner?
- if (this.foundPatternCross(stateCount)) { // Yes
- const confirmed = this.handlePossibleCenter(stateCount, i, j);
- if (confirmed !== null) {
- return confirmed;
- }
- }
- stateCount[0] = stateCount[2];
- stateCount[1] = 1;
- stateCount[2] = 0;
- currentState = 1;
- } else {
- stateCount[++currentState]++;
- }
- }
- } else { // White pixel
- if (currentState === 1) { // Counting black pixels
- currentState++;
- }
- stateCount[currentState]++;
- }
- j++;
- }
- if (this.foundPatternCross(stateCount)) {
- const confirmed = this.handlePossibleCenter(stateCount, i, maxJ);
+ let j = startX;
+ // Burn off leading white pixels before anything else; if we start in the middle of
+ // a white run, it doesn't make sense to count its length, since we don't know if the
+ // white run continued to the left of the start point
+ while (j < maxJ && !image.get(j, i)) {
+ j++;
+ }
+ let currentState = 0;
+ while (j < maxJ) {
+ if (image.get(j, i)) {
+ // Black pixel
+ if (currentState === 1) { // Counting black pixels
+ stateCount[1]++;
+ } else { // Counting white pixels
+ if (currentState === 2) { // A winner?
+ if (this.foundPatternCross(stateCount)) { // Yes
+ const confirmed = this.handlePossibleCenter(stateCount, i, j);
if (confirmed !== null) {
- return confirmed;
+ return confirmed;
}
+ }
+ stateCount[0] = stateCount[2];
+ stateCount[1] = 1;
+ stateCount[2] = 0;
+ currentState = 1;
+ } else {
+ stateCount[++currentState]++;
}
-
+ }
+ } else { // White pixel
+ if (currentState === 1) { // Counting black pixels
+ currentState++;
+ }
+ stateCount[currentState]++;
}
-
- // Hmm, nothing we saw was observed and confirmed twice. If we had
- // any guess at all, return it.
- if (this.possibleCenters.length !== 0) {
- return this.possibleCenters[0];
+ j++;
+ }
+ if (this.foundPatternCross(stateCount)) {
+ const confirmed = this.handlePossibleCenter(stateCount, i, maxJ);
+ if (confirmed !== null) {
+ return confirmed;
}
+ }
- throw new NotFoundException();
}
- /**
- * Given a count of black/white/black pixels just seen and an end position,
- * figures the location of the center of this black/white/black run.
- */
- private static centerFromEnd(stateCount: Int32Array, end: number /*int*/): number/*float*/ {
- return (end - stateCount[2]) - stateCount[1] / 2.0;
+ // Hmm, nothing we saw was observed and confirmed twice. If we had
+ // any guess at all, return it.
+ if (this.possibleCenters.length !== 0) {
+ return this.possibleCenters[0];
}
- /**
- * @param stateCount count of black/white/black pixels just read
- * @return true iff the proportions of the counts is close enough to the 1/1/1 ratios
- * used by alignment patterns to be considered a match
- */
- private foundPatternCross(stateCount: Int32Array): boolean {
- const moduleSize: number /*float*/ = this.moduleSize;
- const maxVariance: number /*float*/ = moduleSize / 2.0;
- for (let i = 0; i < 3; i++) {
- if (Math.abs(moduleSize - stateCount[i]) >= maxVariance) {
- return false;
- }
- }
- return true;
- }
+ throw new NotFoundException();
+ }
- /**
- *
After a horizontal scan finds a potential alignment pattern, this method
- * "cross-checks" by scanning down vertically through the center of the possible
- * alignment pattern to see if the same proportion is detected.
- *
- * @param startI row where an alignment pattern was detected
- * @param centerJ center of the section that appears to cross an alignment pattern
- * @param maxCount maximum reasonable number of modules that should be
- * observed in any reading state, based on the results of the horizontal scan
- * @return vertical center of alignment pattern, or {@link Float#NaN} if not found
- */
- private crossCheckVertical(startI: number /*int*/, centerJ: number /*int*/, maxCount: number /*int*/,
- originalStateCountTotal: number /*int*/): number/*float*/ {
- const image = this.image;
+ /**
+ * Given a count of black/white/black pixels just seen and an end position,
+ * figures the location of the center of this black/white/black run.
+ */
+ private static centerFromEnd(stateCount: Int32Array, end: number /*int*/): number/*float*/ {
+ return (end - stateCount[2]) - stateCount[1] / 2.0;
+ }
- const maxI = image.getHeight();
- const stateCount = this.crossCheckStateCount;
- stateCount[0] = 0;
- stateCount[1] = 0;
- stateCount[2] = 0;
+ /**
+ * @param stateCount count of black/white/black pixels just read
+ * @return true iff the proportions of the counts is close enough to the 1/1/1 ratios
+ * used by alignment patterns to be considered a match
+ */
+ private foundPatternCross(stateCount: Int32Array): boolean {
+ const moduleSize: number /*float*/ = this.moduleSize;
+ const maxVariance: number /*float*/ = moduleSize / 2.0;
+ for (let i = 0; i < 3; i++) {
+ if (Math.abs(moduleSize - stateCount[i]) >= maxVariance) {
+ return false;
+ }
+ }
+ return true;
+ }
- // Start counting up from center
- let i = startI;
- while (i >= 0 && image.get(centerJ, i) && stateCount[1] <= maxCount) {
- stateCount[1]++;
- i--;
- }
- // If already too many modules in this state or ran off the edge:
- if (i < 0 || stateCount[1] > maxCount) {
- return NaN;
- }
- while (i >= 0 && !image.get(centerJ, i) && stateCount[0] <= maxCount) {
- stateCount[0]++;
- i--;
- }
- if (stateCount[0] > maxCount) {
- return NaN;
- }
+ /**
+ *
After a horizontal scan finds a potential alignment pattern, this method
+ * "cross-checks" by scanning down vertically through the center of the possible
+ * alignment pattern to see if the same proportion is detected.
+ *
+ * @param startI row where an alignment pattern was detected
+ * @param centerJ center of the section that appears to cross an alignment pattern
+ * @param maxCount maximum reasonable number of modules that should be
+ * observed in any reading state, based on the results of the horizontal scan
+ * @return vertical center of alignment pattern, or {@link Float#NaN} if not found
+ */
+ private crossCheckVertical(startI: number /*int*/, centerJ: number /*int*/, maxCount: number /*int*/,
+ originalStateCountTotal: number /*int*/): number/*float*/ {
+ const image = this.image;
- // Now also count down from center
- i = startI + 1;
- while (i < maxI && image.get(centerJ, i) && stateCount[1] <= maxCount) {
- stateCount[1]++;
- i++;
- }
- if (i === maxI || stateCount[1] > maxCount) {
- return NaN;
- }
- while (i < maxI && !image.get(centerJ, i) && stateCount[2] <= maxCount) {
- stateCount[2]++;
- i++;
- }
- if (stateCount[2] > maxCount) {
- return NaN;
- }
+ const maxI = image.getHeight();
+ const stateCount = this.crossCheckStateCount;
+ stateCount[0] = 0;
+ stateCount[1] = 0;
+ stateCount[2] = 0;
- const stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];
- if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) {
- return NaN;
- }
+ // Start counting up from center
+ let i = startI;
+ while (i >= 0 && image.get(centerJ, i) && stateCount[1] <= maxCount) {
+ stateCount[1]++;
+ i--;
+ }
+ // If already too many modules in this state or ran off the edge:
+ if (i < 0 || stateCount[1] > maxCount) {
+ return NaN;
+ }
+ while (i >= 0 && !image.get(centerJ, i) && stateCount[0] <= maxCount) {
+ stateCount[0]++;
+ i--;
+ }
+ if (stateCount[0] > maxCount) {
+ return NaN;
+ }
- return this.foundPatternCross(stateCount) ? AlignmentPatternFinder.centerFromEnd(stateCount, i) : NaN;
+ // Now also count down from center
+ i = startI + 1;
+ while (i < maxI && image.get(centerJ, i) && stateCount[1] <= maxCount) {
+ stateCount[1]++;
+ i++;
+ }
+ if (i === maxI || stateCount[1] > maxCount) {
+ return NaN;
+ }
+ while (i < maxI && !image.get(centerJ, i) && stateCount[2] <= maxCount) {
+ stateCount[2]++;
+ i++;
+ }
+ if (stateCount[2] > maxCount) {
+ return NaN;
}
- /**
- *
This is called when a horizontal scan finds a possible alignment pattern. It will
- * cross check with a vertical scan, and if successful, will see if this pattern had been
- * found on a previous horizontal scan. If so, we consider it confirmed and conclude we have
- * found the alignment pattern.
- *
- * @param stateCount reading state module counts from horizontal scan
- * @param i row where alignment pattern may be found
- * @param j end of possible alignment pattern in row
- * @return {@link AlignmentPattern} if we have found the same pattern twice, or null if not
- */
- private handlePossibleCenter(stateCount: Int32Array, i: number /*int*/, j: number /*int*/): AlignmentPattern {
- const stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];
- const centerJ: number /*float*/ = AlignmentPatternFinder.centerFromEnd(stateCount, j);
- const centerI: number /*float*/ = this.crossCheckVertical(i, /*(int) */centerJ, 2 * stateCount[1], stateCountTotal);
- if (!isNaN(centerI)) {
- const estimatedModuleSize: number /*float*/ = (stateCount[0] + stateCount[1] + stateCount[2]) / 3.0;
- for (const center of this.possibleCenters) {
- // Look for about the same center and module size:
- if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) {
- return center.combineEstimate(centerI, centerJ, estimatedModuleSize);
- }
- }
- // Hadn't found this before; save it
- const point = new AlignmentPattern(centerJ, centerI, estimatedModuleSize);
- this.possibleCenters.push(point);
- if (this.resultPointCallback !== null && this.resultPointCallback !== undefined) {
- this.resultPointCallback.foundPossibleResultPoint(point);
- }
+ const stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];
+ if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) {
+ return NaN;
+ }
+
+ return this.foundPatternCross(stateCount) ? AlignmentPatternFinder.centerFromEnd(stateCount, i) : NaN;
+ }
+
+ /**
+ *
This is called when a horizontal scan finds a possible alignment pattern. It will
+ * cross check with a vertical scan, and if successful, will see if this pattern had been
+ * found on a previous horizontal scan. If so, we consider it confirmed and conclude we have
+ * found the alignment pattern.
+ *
+ * @param stateCount reading state module counts from horizontal scan
+ * @param i row where alignment pattern may be found
+ * @param j end of possible alignment pattern in row
+ * @return {@link AlignmentPattern} if we have found the same pattern twice, or null if not
+ */
+ private handlePossibleCenter(stateCount: Int32Array, i: number /*int*/, j: number /*int*/): AlignmentPattern {
+ const stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];
+ const centerJ: number /*float*/ = AlignmentPatternFinder.centerFromEnd(stateCount, j);
+ const centerI: number /*float*/ = this.crossCheckVertical(i, /*(int) */centerJ, 2 * stateCount[1], stateCountTotal);
+ if (!isNaN(centerI)) {
+ const estimatedModuleSize: number /*float*/ = (stateCount[0] + stateCount[1] + stateCount[2]) / 3.0;
+ for (const center of this.possibleCenters) {
+ // Look for about the same center and module size:
+ if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) {
+ return center.combineEstimate(centerI, centerJ, estimatedModuleSize);
}
- return null;
+ }
+ // Hadn't found this before; save it
+ const point = new AlignmentPattern(centerJ, centerI, estimatedModuleSize);
+ this.possibleCenters.push(point);
+ if (this.resultPointCallback !== null && this.resultPointCallback !== undefined) {
+ this.resultPointCallback.foundPossibleResultPoint(point);
+ }
}
+ return null;
+ }
}
diff --git a/src/core/qrcode/detector/FinderPattern.ts b/src/core/qrcode/detector/FinderPattern.ts
index b49bf1e7..7f6aec27 100644
--- a/src/core/qrcode/detector/FinderPattern.ts
+++ b/src/core/qrcode/detector/FinderPattern.ts
@@ -27,54 +27,54 @@ import ResultPoint from '../../ResultPoint';
*/
export default class FinderPattern extends ResultPoint {
- // FinderPattern(posX: number/*float*/, posY: number/*float*/, estimatedModuleSize: number/*float*/) {
- // this(posX, posY, estimatedModuleSize, 1)
- // }
+ // FinderPattern(posX: number/*float*/, posY: number/*float*/, estimatedModuleSize: number/*float*/) {
+ // this(posX, posY, estimatedModuleSize, 1)
+ // }
- public constructor(posX: number/*float*/, posY: number/*float*/, private estimatedModuleSize: number/*float*/, private count?: number /*int*/) {
- super(posX, posY);
- if (undefined === count) {
- this.count = 1;
- }
+ public constructor(posX: number/*float*/, posY: number/*float*/, private estimatedModuleSize: number/*float*/, private count?: number /*int*/) {
+ super(posX, posY);
+ if (undefined === count) {
+ this.count = 1;
}
+ }
- public getEstimatedModuleSize(): number/*float*/ {
- return this.estimatedModuleSize;
- }
+ public getEstimatedModuleSize(): number/*float*/ {
+ return this.estimatedModuleSize;
+ }
- public getCount(): number /*int*/ {
- return this.count;
- }
+ public getCount(): number /*int*/ {
+ return this.count;
+ }
- /*
- void incrementCount() {
- this.count++
- }
- */
+ /*
+ void incrementCount() {
+ this.count++
+ }
+ */
- /**
- *
Determines if this finder pattern "about equals" a finder pattern at the stated
- * position and size -- meaning, it is at nearly the same center with nearly the same size.
Determines if this finder pattern "about equals" a finder pattern at the stated
+ * position and size -- meaning, it is at nearly the same center with nearly the same size.
+ */
+ public aboutEquals(moduleSize: number/*float*/, i: number/*float*/, j: number/*float*/): boolean {
+ if (Math.abs(i - this.getY()) <= moduleSize && Math.abs(j - this.getX()) <= moduleSize) {
+ const moduleSizeDiff: number /*float*/ = Math.abs(moduleSize - this.estimatedModuleSize);
+ return moduleSizeDiff <= 1.0 || moduleSizeDiff <= this.estimatedModuleSize;
}
+ return false;
+ }
- /**
- * Combines this object's current estimate of a finder pattern position and module size
- * with a new estimate. It returns a new {@code FinderPattern} containing a weighted average
- * based on count.
- */
- public combineEstimate(i: number/*float*/, j: number/*float*/, newModuleSize: number/*float*/): FinderPattern {
- const combinedCount = this.count + 1;
- const combinedX: number /*float*/ = (this.count * this.getX() + j) / combinedCount;
- const combinedY: number /*float*/ = (this.count * this.getY() + i) / combinedCount;
- const combinedModuleSize: number /*float*/ = (this.count * this.estimatedModuleSize + newModuleSize) / combinedCount;
- return new FinderPattern(combinedX, combinedY, combinedModuleSize, combinedCount);
- }
+ /**
+ * Combines this object's current estimate of a finder pattern position and module size
+ * with a new estimate. It returns a new {@code FinderPattern} containing a weighted average
+ * based on count.
+ */
+ public combineEstimate(i: number/*float*/, j: number/*float*/, newModuleSize: number/*float*/): FinderPattern {
+ const combinedCount = this.count + 1;
+ const combinedX: number /*float*/ = (this.count * this.getX() + j) / combinedCount;
+ const combinedY: number /*float*/ = (this.count * this.getY() + i) / combinedCount;
+ const combinedModuleSize: number /*float*/ = (this.count * this.estimatedModuleSize + newModuleSize) / combinedCount;
+ return new FinderPattern(combinedX, combinedY, combinedModuleSize, combinedCount);
+ }
}
diff --git a/src/core/qrcode/detector/FinderPatternFinder.ts b/src/core/qrcode/detector/FinderPatternFinder.ts
index 8415b19c..0d92d202 100644
--- a/src/core/qrcode/detector/FinderPatternFinder.ts
+++ b/src/core/qrcode/detector/FinderPatternFinder.ts
@@ -44,629 +44,629 @@ import { float } from '../../../customTypings';
*/
export default class FinderPatternFinder {
- private static CENTER_QUORUM = 2;
- protected static MIN_SKIP = 3; // 1 pixel/module times 3 modules/center
- protected static MAX_MODULES = 57; // support up to version 10 for mobile clients
-
- private possibleCenters: FinderPattern[];
- private hasSkipped: boolean;
- private crossCheckStateCount: Int32Array;
-
- /**
- *
Creates a finder that will search the image for three finder patterns.
- *
- * @param image image to search
- */
- // public constructor(image: BitMatrix) {
- // this(image, null)
- // }
-
- public constructor(private image: BitMatrix, private resultPointCallback: ResultPointCallback) {
- this.possibleCenters = [];
- this.crossCheckStateCount = new Int32Array(5);
- this.resultPointCallback = resultPointCallback;
- }
-
- protected getImage(): BitMatrix {
- return this.image;
- }
-
- protected getPossibleCenters(): FinderPattern[] {
- return this.possibleCenters;
- }
-
- public find(hints: Map): FinderPatternInfo /*throws NotFoundException */ {
- const tryHarder: boolean = (hints !== null && hints !== undefined) && undefined !== hints.get(DecodeHintType.TRY_HARDER);
- const pureBarcode: boolean = (hints !== null && hints !== undefined) && undefined !== hints.get(DecodeHintType.PURE_BARCODE);
- const image = this.image;
- const maxI = image.getHeight();
- const maxJ = image.getWidth();
- // We are looking for black/white/black/white/black modules in
- // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far
-
- // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the
- // image, and then account for the center being 3 modules in size. This gives the smallest
- // number of pixels the center could be, so skip this often. When trying harder, look for all
- // QR versions regardless of how dense they are.
- let iSkip = Math.floor((3 * maxI) / (4 * FinderPatternFinder.MAX_MODULES));
- if (iSkip < FinderPatternFinder.MIN_SKIP || tryHarder) {
- iSkip = FinderPatternFinder.MIN_SKIP;
- }
+ private static CENTER_QUORUM = 2;
+ protected static MIN_SKIP = 3; // 1 pixel/module times 3 modules/center
+ protected static MAX_MODULES = 57; // support up to version 10 for mobile clients
+
+ private possibleCenters: FinderPattern[];
+ private hasSkipped: boolean;
+ private crossCheckStateCount: Int32Array;
+
+ /**
+ *
Creates a finder that will search the image for three finder patterns.
+ *
+ * @param image image to search
+ */
+ // public constructor(image: BitMatrix) {
+ // this(image, null)
+ // }
+
+ public constructor(private image: BitMatrix, private resultPointCallback: ResultPointCallback) {
+ this.possibleCenters = [];
+ this.crossCheckStateCount = new Int32Array(5);
+ this.resultPointCallback = resultPointCallback;
+ }
+
+ protected getImage(): BitMatrix {
+ return this.image;
+ }
+
+ protected getPossibleCenters(): FinderPattern[] {
+ return this.possibleCenters;
+ }
+
+ public find(hints: Map): FinderPatternInfo /*throws NotFoundException */ {
+ const tryHarder: boolean = (hints !== null && hints !== undefined) && undefined !== hints.get(DecodeHintType.TRY_HARDER);
+ const pureBarcode: boolean = (hints !== null && hints !== undefined) && undefined !== hints.get(DecodeHintType.PURE_BARCODE);
+ const image = this.image;
+ const maxI = image.getHeight();
+ const maxJ = image.getWidth();
+ // We are looking for black/white/black/white/black modules in
+ // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far
+
+ // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the
+ // image, and then account for the center being 3 modules in size. This gives the smallest
+ // number of pixels the center could be, so skip this often. When trying harder, look for all
+ // QR versions regardless of how dense they are.
+ let iSkip = Math.floor((3 * maxI) / (4 * FinderPatternFinder.MAX_MODULES));
+ if (iSkip < FinderPatternFinder.MIN_SKIP || tryHarder) {
+ iSkip = FinderPatternFinder.MIN_SKIP;
+ }
- let done: boolean = false;
- const stateCount = new Int32Array(5);
- for (let i = iSkip - 1; i < maxI && !done; i += iSkip) {
- // Get a row of black/white values
- stateCount[0] = 0;
- stateCount[1] = 0;
- stateCount[2] = 0;
- stateCount[3] = 0;
- stateCount[4] = 0;
- let currentState = 0;
- for (let j = 0; j < maxJ; j++) {
- if (image.get(j, i)) {
- // Black pixel
- if ((currentState & 1) === 1) { // Counting white pixels
- currentState++;
- }
- stateCount[currentState]++;
- } else { // White pixel
- if ((currentState & 1) === 0) { // Counting black pixels
- if (currentState === 4) { // A winner?
- if (FinderPatternFinder.foundPatternCross(stateCount)) { // Yes
- const confirmed: boolean = this.handlePossibleCenter(stateCount, i, j, pureBarcode);
- if (confirmed === true) {
- // Start examining every other line. Checking each line turned out to be too
- // expensive and didn't improve performance.
- iSkip = 2;
- if (this.hasSkipped === true) {
- done = this.haveMultiplyConfirmedCenters();
- } else {
- const rowSkip = this.findRowSkip();
- if (rowSkip > stateCount[2]) {
- // Skip rows between row of lower confirmed center
- // and top of presumed third confirmed center
- // but back up a bit to get a full chance of detecting
- // it, entire width of center of finder pattern
-
- // Skip by rowSkip, but back off by stateCount[2] (size of last center
- // of pattern we saw) to be conservative, and also back off by iSkip which
- // is about to be re-added
- i += rowSkip - stateCount[2] - iSkip;
- j = maxJ - 1;
- }
- }
- } else {
- stateCount[0] = stateCount[2];
- stateCount[1] = stateCount[3];
- stateCount[2] = stateCount[4];
- stateCount[3] = 1;
- stateCount[4] = 0;
- currentState = 3;
- continue;
- }
- // Clear state to start looking again
- currentState = 0;
- stateCount[0] = 0;
- stateCount[1] = 0;
- stateCount[2] = 0;
- stateCount[3] = 0;
- stateCount[4] = 0;
- } else { // No, shift counts back by two
- stateCount[0] = stateCount[2];
- stateCount[1] = stateCount[3];
- stateCount[2] = stateCount[4];
- stateCount[3] = 1;
- stateCount[4] = 0;
- currentState = 3;
- }
- } else {
- stateCount[++currentState]++;
- }
- } else { // Counting white pixels
- stateCount[currentState]++;
- }
- }
- }
- if (FinderPatternFinder.foundPatternCross(stateCount)) {
- const confirmed: boolean = this.handlePossibleCenter(stateCount, i, maxJ, pureBarcode);
+ let done: boolean = false;
+ const stateCount = new Int32Array(5);
+ for (let i = iSkip - 1; i < maxI && !done; i += iSkip) {
+ // Get a row of black/white values
+ stateCount[0] = 0;
+ stateCount[1] = 0;
+ stateCount[2] = 0;
+ stateCount[3] = 0;
+ stateCount[4] = 0;
+ let currentState = 0;
+ for (let j = 0; j < maxJ; j++) {
+ if (image.get(j, i)) {
+ // Black pixel
+ if ((currentState & 1) === 1) { // Counting white pixels
+ currentState++;
+ }
+ stateCount[currentState]++;
+ } else { // White pixel
+ if ((currentState & 1) === 0) { // Counting black pixels
+ if (currentState === 4) { // A winner?
+ if (FinderPatternFinder.foundPatternCross(stateCount)) { // Yes
+ const confirmed: boolean = this.handlePossibleCenter(stateCount, i, j, pureBarcode);
if (confirmed === true) {
- iSkip = stateCount[0];
- if (this.hasSkipped) {
- // Found a third one
- done = this.haveMultiplyConfirmedCenters();
+ // Start examining every other line. Checking each line turned out to be too
+ // expensive and didn't improve performance.
+ iSkip = 2;
+ if (this.hasSkipped === true) {
+ done = this.haveMultiplyConfirmedCenters();
+ } else {
+ const rowSkip = this.findRowSkip();
+ if (rowSkip > stateCount[2]) {
+ // Skip rows between row of lower confirmed center
+ // and top of presumed third confirmed center
+ // but back up a bit to get a full chance of detecting
+ // it, entire width of center of finder pattern
+
+ // Skip by rowSkip, but back off by stateCount[2] (size of last center
+ // of pattern we saw) to be conservative, and also back off by iSkip which
+ // is about to be re-added
+ i += rowSkip - stateCount[2] - iSkip;
+ j = maxJ - 1;
}
+ }
+ } else {
+ stateCount[0] = stateCount[2];
+ stateCount[1] = stateCount[3];
+ stateCount[2] = stateCount[4];
+ stateCount[3] = 1;
+ stateCount[4] = 0;
+ currentState = 3;
+ continue;
}
+ // Clear state to start looking again
+ currentState = 0;
+ stateCount[0] = 0;
+ stateCount[1] = 0;
+ stateCount[2] = 0;
+ stateCount[3] = 0;
+ stateCount[4] = 0;
+ } else { // No, shift counts back by two
+ stateCount[0] = stateCount[2];
+ stateCount[1] = stateCount[3];
+ stateCount[2] = stateCount[4];
+ stateCount[3] = 1;
+ stateCount[4] = 0;
+ currentState = 3;
+ }
+ } else {
+ stateCount[++currentState]++;
}
- }
-
- const patternInfo: FinderPattern[] = this.selectBestPatterns();
- ResultPoint.orderBestPatterns(patternInfo);
-
- return new FinderPatternInfo(patternInfo);
+ } else { // Counting white pixels
+ stateCount[currentState]++;
+ }
+ }
+ }
+ if (FinderPatternFinder.foundPatternCross(stateCount)) {
+ const confirmed: boolean = this.handlePossibleCenter(stateCount, i, maxJ, pureBarcode);
+ if (confirmed === true) {
+ iSkip = stateCount[0];
+ if (this.hasSkipped) {
+ // Found a third one
+ done = this.haveMultiplyConfirmedCenters();
+ }
+ }
+ }
}
- /**
- * Given a count of black/white/black/white/black pixels just seen and an end position,
- * figures the location of the center of this run.
- */
- private static centerFromEnd(stateCount: Int32Array, end: number /*int*/): number/*float*/ {
- return (end - stateCount[4] - stateCount[3]) - stateCount[2] / 2.0;
+ const patternInfo: FinderPattern[] = this.selectBestPatterns();
+ ResultPoint.orderBestPatterns(patternInfo);
+
+ return new FinderPatternInfo(patternInfo);
+ }
+
+ /**
+ * Given a count of black/white/black/white/black pixels just seen and an end position,
+ * figures the location of the center of this run.
+ */
+ private static centerFromEnd(stateCount: Int32Array, end: number /*int*/): number/*float*/ {
+ return (end - stateCount[4] - stateCount[3]) - stateCount[2] / 2.0;
+ }
+
+ /**
+ * @param stateCount count of black/white/black/white/black pixels just read
+ * @return true iff the proportions of the counts is close enough to the 1/1/3/1/1 ratios
+ * used by finder patterns to be considered a match
+ */
+ protected static foundPatternCross(stateCount: Int32Array): boolean {
+ let totalModuleSize = 0;
+ for (let i = 0; i < 5; i++) {
+ const count = stateCount[i];
+ if (count === 0) {
+ return false;
+ }
+ totalModuleSize += count;
+ }
+ if (totalModuleSize < 7) {
+ return false;
+ }
+ const moduleSize: number /*float*/ = totalModuleSize / 7.0;
+ const maxVariance: number /*float*/ = moduleSize / 2.0;
+ // Allow less than 50% variance from 1-1-3-1-1 proportions
+ return Math.abs(moduleSize - stateCount[0]) < maxVariance &&
+ Math.abs(moduleSize - stateCount[1]) < maxVariance &&
+ Math.abs(3.0 * moduleSize - stateCount[2]) < 3 * maxVariance &&
+ Math.abs(moduleSize - stateCount[3]) < maxVariance &&
+ Math.abs(moduleSize - stateCount[4]) < maxVariance;
+ }
+
+ private getCrossCheckStateCount(): Int32Array {
+ const crossCheckStateCount = this.crossCheckStateCount;
+ crossCheckStateCount[0] = 0;
+ crossCheckStateCount[1] = 0;
+ crossCheckStateCount[2] = 0;
+ crossCheckStateCount[3] = 0;
+ crossCheckStateCount[4] = 0;
+ return crossCheckStateCount;
+ }
+
+ /**
+ * After a vertical and horizontal scan finds a potential finder pattern, this method
+ * "cross-cross-cross-checks" by scanning down diagonally through the center of the possible
+ * finder pattern to see if the same proportion is detected.
+ *
+ * @param startI row where a finder pattern was detected
+ * @param centerJ center of the section that appears to cross a finder pattern
+ * @param maxCount maximum reasonable number of modules that should be
+ * observed in any reading state, based on the results of the horizontal scan
+ * @param originalStateCountTotal The original state count total.
+ * @return true if proportions are withing expected limits
+ */
+ private crossCheckDiagonal(startI: number /*int*/, centerJ: number /*int*/, maxCount: number /*int*/, originalStateCountTotal: number /*int*/): boolean {
+ const stateCount: Int32Array = this.getCrossCheckStateCount();
+
+ // Start counting up, left from center finding black center mass
+ let i = 0;
+ const image = this.image;
+ while (startI >= i && centerJ >= i && image.get(centerJ - i, startI - i)) {
+ stateCount[2]++;
+ i++;
}
- /**
- * @param stateCount count of black/white/black/white/black pixels just read
- * @return true iff the proportions of the counts is close enough to the 1/1/3/1/1 ratios
- * used by finder patterns to be considered a match
- */
- protected static foundPatternCross(stateCount: Int32Array): boolean {
- let totalModuleSize = 0;
- for (let i = 0; i < 5; i++) {
- const count = stateCount[i];
- if (count === 0) {
- return false;
- }
- totalModuleSize += count;
- }
- if (totalModuleSize < 7) {
- return false;
- }
- const moduleSize: number /*float*/ = totalModuleSize / 7.0;
- const maxVariance: number /*float*/ = moduleSize / 2.0;
- // Allow less than 50% variance from 1-1-3-1-1 proportions
- return Math.abs(moduleSize - stateCount[0]) < maxVariance &&
- Math.abs(moduleSize - stateCount[1]) < maxVariance &&
- Math.abs(3.0 * moduleSize - stateCount[2]) < 3 * maxVariance &&
- Math.abs(moduleSize - stateCount[3]) < maxVariance &&
- Math.abs(moduleSize - stateCount[4]) < maxVariance;
- }
-
- private getCrossCheckStateCount(): Int32Array {
- const crossCheckStateCount = this.crossCheckStateCount;
- crossCheckStateCount[0] = 0;
- crossCheckStateCount[1] = 0;
- crossCheckStateCount[2] = 0;
- crossCheckStateCount[3] = 0;
- crossCheckStateCount[4] = 0;
- return crossCheckStateCount;
- }
-
- /**
- * After a vertical and horizontal scan finds a potential finder pattern, this method
- * "cross-cross-cross-checks" by scanning down diagonally through the center of the possible
- * finder pattern to see if the same proportion is detected.
- *
- * @param startI row where a finder pattern was detected
- * @param centerJ center of the section that appears to cross a finder pattern
- * @param maxCount maximum reasonable number of modules that should be
- * observed in any reading state, based on the results of the horizontal scan
- * @param originalStateCountTotal The original state count total.
- * @return true if proportions are withing expected limits
- */
- private crossCheckDiagonal(startI: number /*int*/, centerJ: number /*int*/, maxCount: number /*int*/, originalStateCountTotal: number /*int*/): boolean {
- const stateCount: Int32Array = this.getCrossCheckStateCount();
-
- // Start counting up, left from center finding black center mass
- let i = 0;
- const image = this.image;
- while (startI >= i && centerJ >= i && image.get(centerJ - i, startI - i)) {
- stateCount[2]++;
- i++;
- }
-
- if (startI < i || centerJ < i) {
- return false;
- }
-
- // Continue up, left finding white space
- while (startI >= i && centerJ >= i && !image.get(centerJ - i, startI - i) &&
- stateCount[1] <= maxCount) {
- stateCount[1]++;
- i++;
- }
-
- // If already too many modules in this state or ran off the edge:
- if (startI < i || centerJ < i || stateCount[1] > maxCount) {
- return false;
- }
-
- // Continue up, left finding black border
- while (startI >= i && centerJ >= i && image.get(centerJ - i, startI - i) &&
- stateCount[0] <= maxCount) {
- stateCount[0]++;
- i++;
- }
- if (stateCount[0] > maxCount) {
- return false;
- }
-
- const maxI = image.getHeight();
- const maxJ = image.getWidth();
-
- // Now also count down, right from center
- i = 1;
- while (startI + i < maxI && centerJ + i < maxJ && image.get(centerJ + i, startI + i)) {
- stateCount[2]++;
- i++;
- }
-
- // Ran off the edge?
- if (startI + i >= maxI || centerJ + i >= maxJ) {
- return false;
- }
-
- while (startI + i < maxI && centerJ + i < maxJ && !image.get(centerJ + i, startI + i) &&
- stateCount[3] < maxCount) {
- stateCount[3]++;
- i++;
- }
+ if (startI < i || centerJ < i) {
+ return false;
+ }
- if (startI + i >= maxI || centerJ + i >= maxJ || stateCount[3] >= maxCount) {
- return false;
- }
+ // Continue up, left finding white space
+ while (startI >= i && centerJ >= i && !image.get(centerJ - i, startI - i) &&
+ stateCount[1] <= maxCount) {
+ stateCount[1]++;
+ i++;
+ }
- while (startI + i < maxI && centerJ + i < maxJ && image.get(centerJ + i, startI + i) &&
- stateCount[4] < maxCount) {
- stateCount[4]++;
- i++;
- }
+ // If already too many modules in this state or ran off the edge:
+ if (startI < i || centerJ < i || stateCount[1] > maxCount) {
+ return false;
+ }
- if (stateCount[4] >= maxCount) {
- return false;
- }
+ // Continue up, left finding black border
+ while (startI >= i && centerJ >= i && image.get(centerJ - i, startI - i) &&
+ stateCount[0] <= maxCount) {
+ stateCount[0]++;
+ i++;
+ }
+ if (stateCount[0] > maxCount) {
+ return false;
+ }
- // If we found a finder-pattern-like section, but its size is more than 100% different than
- // the original, assume it's a false positive
- const stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];
- return Math.abs(stateCountTotal - originalStateCountTotal) < 2 * originalStateCountTotal &&
- FinderPatternFinder.foundPatternCross(stateCount);
- }
-
- /**
- *
After a horizontal scan finds a potential finder pattern, this method
- * "cross-checks" by scanning down vertically through the center of the possible
- * finder pattern to see if the same proportion is detected.
- *
- * @param startI row where a finder pattern was detected
- * @param centerJ center of the section that appears to cross a finder pattern
- * @param maxCount maximum reasonable number of modules that should be
- * observed in any reading state, based on the results of the horizontal scan
- * @return vertical center of finder pattern, or {@link Float#NaN} if not found
- */
- private crossCheckVertical(startI: number /*int*/, centerJ: number /*int*/, maxCount: number /*int*/,
- originalStateCountTotal: number /*int*/): number/*float*/ {
- const image: BitMatrix = this.image;
-
- const maxI = image.getHeight();
- const stateCount: Int32Array = this.getCrossCheckStateCount();
-
- // Start counting up from center
- let i = startI;
- while (i >= 0 && image.get(centerJ, i)) {
- stateCount[2]++;
- i--;
- }
- if (i < 0) {
- return NaN;
- }
- while (i >= 0 && !image.get(centerJ, i) && stateCount[1] <= maxCount) {
- stateCount[1]++;
- i--;
- }
- // If already too many modules in this state or ran off the edge:
- if (i < 0 || stateCount[1] > maxCount) {
- return NaN;
- }
- while (i >= 0 && image.get(centerJ, i) && stateCount[0] <= maxCount) {
- stateCount[0]++;
- i--;
- }
- if (stateCount[0] > maxCount) {
- return NaN;
- }
+ const maxI = image.getHeight();
+ const maxJ = image.getWidth();
- // Now also count down from center
- i = startI + 1;
- while (i < maxI && image.get(centerJ, i)) {
- stateCount[2]++;
- i++;
- }
- if (i === maxI) {
- return NaN;
- }
- while (i < maxI && !image.get(centerJ, i) && stateCount[3] < maxCount) {
- stateCount[3]++;
- i++;
- }
- if (i === maxI || stateCount[3] >= maxCount) {
- return NaN;
- }
- while (i < maxI && image.get(centerJ, i) && stateCount[4] < maxCount) {
- stateCount[4]++;
- i++;
- }
- if (stateCount[4] >= maxCount) {
- return NaN;
- }
+ // Now also count down, right from center
+ i = 1;
+ while (startI + i < maxI && centerJ + i < maxJ && image.get(centerJ + i, startI + i)) {
+ stateCount[2]++;
+ i++;
+ }
- // If we found a finder-pattern-like section, but its size is more than 40% different than
- // the original, assume it's a false positive
- const stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] +
- stateCount[4];
- if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) {
- return NaN;
- }
+ // Ran off the edge?
+ if (startI + i >= maxI || centerJ + i >= maxJ) {
+ return false;
+ }
- return FinderPatternFinder.foundPatternCross(stateCount) ? FinderPatternFinder.centerFromEnd(stateCount, i) : NaN;
+ while (startI + i < maxI && centerJ + i < maxJ && !image.get(centerJ + i, startI + i) &&
+ stateCount[3] < maxCount) {
+ stateCount[3]++;
+ i++;
}
- /**
- *
Like {@link #crossCheckVertical(int, int, int, int)}, and in fact is basically identical,
- * except it reads horizontally instead of vertically. This is used to cross-cross
- * check a vertical cross check and locate the real center of the alignment pattern.
- */
- private crossCheckHorizontal(startJ: number /*int*/, centerI: number /*int*/, maxCount: number /*int*/,
- originalStateCountTotal: number /*int*/): number/*float*/ {
- const image: BitMatrix = this.image;
+ if (startI + i >= maxI || centerJ + i >= maxJ || stateCount[3] >= maxCount) {
+ return false;
+ }
- const maxJ = image.getWidth();
- const stateCount: Int32Array = this.getCrossCheckStateCount();
+ while (startI + i < maxI && centerJ + i < maxJ && image.get(centerJ + i, startI + i) &&
+ stateCount[4] < maxCount) {
+ stateCount[4]++;
+ i++;
+ }
- let j = startJ;
- while (j >= 0 && image.get(j, centerI)) {
- stateCount[2]++;
- j--;
- }
- if (j < 0) {
- return NaN;
- }
- while (j >= 0 && !image.get(j, centerI) && stateCount[1] <= maxCount) {
- stateCount[1]++;
- j--;
- }
- if (j < 0 || stateCount[1] > maxCount) {
- return NaN;
- }
- while (j >= 0 && image.get(j, centerI) && stateCount[0] <= maxCount) {
- stateCount[0]++;
- j--;
- }
- if (stateCount[0] > maxCount) {
- return NaN;
- }
+ if (stateCount[4] >= maxCount) {
+ return false;
+ }
- j = startJ + 1;
- while (j < maxJ && image.get(j, centerI)) {
- stateCount[2]++;
- j++;
- }
- if (j === maxJ) {
- return NaN;
- }
- while (j < maxJ && !image.get(j, centerI) && stateCount[3] < maxCount) {
- stateCount[3]++;
- j++;
- }
- if (j === maxJ || stateCount[3] >= maxCount) {
- return NaN;
- }
- while (j < maxJ && image.get(j, centerI) && stateCount[4] < maxCount) {
- stateCount[4]++;
- j++;
- }
- if (stateCount[4] >= maxCount) {
- return NaN;
- }
+ // If we found a finder-pattern-like section, but its size is more than 100% different than
+ // the original, assume it's a false positive
+ const stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];
+ return Math.abs(stateCountTotal - originalStateCountTotal) < 2 * originalStateCountTotal &&
+ FinderPatternFinder.foundPatternCross(stateCount);
+ }
+
+ /**
+ *
After a horizontal scan finds a potential finder pattern, this method
+ * "cross-checks" by scanning down vertically through the center of the possible
+ * finder pattern to see if the same proportion is detected.
+ *
+ * @param startI row where a finder pattern was detected
+ * @param centerJ center of the section that appears to cross a finder pattern
+ * @param maxCount maximum reasonable number of modules that should be
+ * observed in any reading state, based on the results of the horizontal scan
+ * @return vertical center of finder pattern, or {@link Float#NaN} if not found
+ */
+ private crossCheckVertical(startI: number /*int*/, centerJ: number /*int*/, maxCount: number /*int*/,
+ originalStateCountTotal: number /*int*/): number/*float*/ {
+ const image: BitMatrix = this.image;
+
+ const maxI = image.getHeight();
+ const stateCount: Int32Array = this.getCrossCheckStateCount();
+
+ // Start counting up from center
+ let i = startI;
+ while (i >= 0 && image.get(centerJ, i)) {
+ stateCount[2]++;
+ i--;
+ }
+ if (i < 0) {
+ return NaN;
+ }
+ while (i >= 0 && !image.get(centerJ, i) && stateCount[1] <= maxCount) {
+ stateCount[1]++;
+ i--;
+ }
+ // If already too many modules in this state or ran off the edge:
+ if (i < 0 || stateCount[1] > maxCount) {
+ return NaN;
+ }
+ while (i >= 0 && image.get(centerJ, i) && stateCount[0] <= maxCount) {
+ stateCount[0]++;
+ i--;
+ }
+ if (stateCount[0] > maxCount) {
+ return NaN;
+ }
- // If we found a finder-pattern-like section, but its size is significantly different than
- // the original, assume it's a false positive
- const stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] +
- stateCount[4];
- if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) {
- return NaN;
- }
+ // Now also count down from center
+ i = startI + 1;
+ while (i < maxI && image.get(centerJ, i)) {
+ stateCount[2]++;
+ i++;
+ }
+ if (i === maxI) {
+ return NaN;
+ }
+ while (i < maxI && !image.get(centerJ, i) && stateCount[3] < maxCount) {
+ stateCount[3]++;
+ i++;
+ }
+ if (i === maxI || stateCount[3] >= maxCount) {
+ return NaN;
+ }
+ while (i < maxI && image.get(centerJ, i) && stateCount[4] < maxCount) {
+ stateCount[4]++;
+ i++;
+ }
+ if (stateCount[4] >= maxCount) {
+ return NaN;
+ }
- return FinderPatternFinder.foundPatternCross(stateCount) ? FinderPatternFinder.centerFromEnd(stateCount, j) : NaN;
- }
-
- /**
- *
This is called when a horizontal scan finds a possible alignment pattern. It will
- * cross check with a vertical scan, and if successful, will, ah, cross-cross-check
- * with another horizontal scan. This is needed primarily to locate the real horizontal
- * center of the pattern in cases of extreme skew.
- * And then we cross-cross-cross check with another diagonal scan.
- *
- *
If that succeeds the finder pattern location is added to a list that tracks
- * the number of times each location has been nearly-matched as a finder pattern.
- * Each additional find is more evidence that the location is in fact a finder
- * pattern center
- *
- * @param stateCount reading state module counts from horizontal scan
- * @param i row where finder pattern may be found
- * @param j end of possible finder pattern in row
- * @param pureBarcode true if in "pure barcode" mode
- * @return true if a finder pattern candidate was found this time
- */
- protected handlePossibleCenter(stateCount: Int32Array, i: number /*int*/, j: number /*int*/, pureBarcode: boolean): boolean {
- const stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] +
- stateCount[4];
- let centerJ: number /*float*/ = FinderPatternFinder.centerFromEnd(stateCount, j);
- let centerI: number /*float*/ = this.crossCheckVertical(i, /*(int) */Math.floor(centerJ), stateCount[2], stateCountTotal);
- if (!isNaN(centerI)) {
- // Re-cross check
- centerJ = this.crossCheckHorizontal(/*(int) */Math.floor(centerJ), /*(int) */Math.floor(centerI), stateCount[2], stateCountTotal);
- if (!isNaN(centerJ) &&
- (!pureBarcode || this.crossCheckDiagonal(/*(int) */Math.floor(centerI), /*(int) */Math.floor(centerJ), stateCount[2], stateCountTotal))) {
- const estimatedModuleSize: number /*float*/ = stateCountTotal / 7.0;
- let found: boolean = false;
- const possibleCenters = this.possibleCenters;
- for (let index = 0, length = possibleCenters.length; index < length; index++) {
- const center: FinderPattern = possibleCenters[index];
- // Look for about the same center and module size:
- if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) {
- possibleCenters[index] = center.combineEstimate(centerI, centerJ, estimatedModuleSize);
- found = true;
- break;
- }
- }
- if (!found) {
- const point: FinderPattern = new FinderPattern(centerJ, centerI, estimatedModuleSize);
- possibleCenters.push(point);
- if (this.resultPointCallback !== null && this.resultPointCallback !== undefined) {
- this.resultPointCallback.foundPossibleResultPoint(point);
- }
- }
- return true;
- }
- }
- return false;
+ // If we found a finder-pattern-like section, but its size is more than 40% different than
+ // the original, assume it's a false positive
+ const stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] +
+ stateCount[4];
+ if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) {
+ return NaN;
}
- /**
- * @return number of rows we could safely skip during scanning, based on the first
- * two finder patterns that have been located. In some cases their position will
- * allow us to infer that the third pattern must lie below a certain point farther
- * down in the image.
- */
- private findRowSkip(): number /*int*/ {
- const max = this.possibleCenters.length;
- if (max <= 1) {
- return 0;
- }
- let firstConfirmedCenter: ResultPoint = null;
- for (const center of this.possibleCenters) {
- if (center.getCount() >= FinderPatternFinder.CENTER_QUORUM) {
- if (firstConfirmedCenter == null) {
- firstConfirmedCenter = center;
- } else {
- // We have two confirmed centers
- // How far down can we skip before resuming looking for the next
- // pattern? In the worst case, only the difference between the
- // difference in the x / y coordinates of the two centers.
- // This is the case where you find top left last.
- this.hasSkipped = true;
- return /*(int) */Math.floor((Math.abs(firstConfirmedCenter.getX() - center.getX()) -
- Math.abs(firstConfirmedCenter.getY() - center.getY())) / 2);
- }
- }
- }
- return 0;
- }
-
- /**
- * @return true iff we have found at least 3 finder patterns that have been detected
- * at least {@link #CENTER_QUORUM} times each, and, the estimated module size of the
- * candidates is "pretty similar"
- */
- private haveMultiplyConfirmedCenters(): boolean {
- let confirmedCount = 0;
- let totalModuleSize: number /*float*/ = 0.0;
- const max = this.possibleCenters.length;
- for (const pattern of this.possibleCenters) {
- if (pattern.getCount() >= FinderPatternFinder.CENTER_QUORUM) {
- confirmedCount++;
- totalModuleSize += pattern.getEstimatedModuleSize();
- }
- }
- if (confirmedCount < 3) {
- return false;
- }
- // OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive"
- // and that we need to keep looking. We detect this by asking if the estimated module sizes
- // vary too much. We arbitrarily say that when the total deviation from average exceeds
- // 5% of the total module size estimates, it's too much.
- const average: number /*float*/ = totalModuleSize / max;
- let totalDeviation: number /*float*/ = 0.0;
- for (const pattern of this.possibleCenters) {
- totalDeviation += Math.abs(pattern.getEstimatedModuleSize() - average);
- }
- return totalDeviation <= 0.05 * totalModuleSize;
+ return FinderPatternFinder.foundPatternCross(stateCount) ? FinderPatternFinder.centerFromEnd(stateCount, i) : NaN;
+ }
+
+ /**
+ *
Like {@link #crossCheckVertical(int, int, int, int)}, and in fact is basically identical,
+ * except it reads horizontally instead of vertically. This is used to cross-cross
+ * check a vertical cross check and locate the real center of the alignment pattern.
+ */
+ private crossCheckHorizontal(startJ: number /*int*/, centerI: number /*int*/, maxCount: number /*int*/,
+ originalStateCountTotal: number /*int*/): number/*float*/ {
+ const image: BitMatrix = this.image;
+
+ const maxJ = image.getWidth();
+ const stateCount: Int32Array = this.getCrossCheckStateCount();
+
+ let j = startJ;
+ while (j >= 0 && image.get(j, centerI)) {
+ stateCount[2]++;
+ j--;
+ }
+ if (j < 0) {
+ return NaN;
+ }
+ while (j >= 0 && !image.get(j, centerI) && stateCount[1] <= maxCount) {
+ stateCount[1]++;
+ j--;
+ }
+ if (j < 0 || stateCount[1] > maxCount) {
+ return NaN;
+ }
+ while (j >= 0 && image.get(j, centerI) && stateCount[0] <= maxCount) {
+ stateCount[0]++;
+ j--;
+ }
+ if (stateCount[0] > maxCount) {
+ return NaN;
}
- /**
- * @return the 3 best {@link FinderPattern}s from our list of candidates. The "best" are
- * those that have been detected at least {@link #CENTER_QUORUM} times, and whose module
- * size differs from the average among those patterns the least
- * @throws NotFoundException if 3 such finder patterns do not exist
- */
- private selectBestPatterns(): FinderPattern[] /*throws NotFoundException */ {
+ j = startJ + 1;
+ while (j < maxJ && image.get(j, centerI)) {
+ stateCount[2]++;
+ j++;
+ }
+ if (j === maxJ) {
+ return NaN;
+ }
+ while (j < maxJ && !image.get(j, centerI) && stateCount[3] < maxCount) {
+ stateCount[3]++;
+ j++;
+ }
+ if (j === maxJ || stateCount[3] >= maxCount) {
+ return NaN;
+ }
+ while (j < maxJ && image.get(j, centerI) && stateCount[4] < maxCount) {
+ stateCount[4]++;
+ j++;
+ }
+ if (stateCount[4] >= maxCount) {
+ return NaN;
+ }
- const startSize = this.possibleCenters.length;
- if (startSize < 3) {
- // Couldn't find enough finder patterns
- throw new NotFoundException();
- }
+ // If we found a finder-pattern-like section, but its size is significantly different than
+ // the original, assume it's a false positive
+ const stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] +
+ stateCount[4];
+ if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) {
+ return NaN;
+ }
+ return FinderPatternFinder.foundPatternCross(stateCount) ? FinderPatternFinder.centerFromEnd(stateCount, j) : NaN;
+ }
+
+ /**
+ *
This is called when a horizontal scan finds a possible alignment pattern. It will
+ * cross check with a vertical scan, and if successful, will, ah, cross-cross-check
+ * with another horizontal scan. This is needed primarily to locate the real horizontal
+ * center of the pattern in cases of extreme skew.
+ * And then we cross-cross-cross check with another diagonal scan.
+ *
+ *
If that succeeds the finder pattern location is added to a list that tracks
+ * the number of times each location has been nearly-matched as a finder pattern.
+ * Each additional find is more evidence that the location is in fact a finder
+ * pattern center
+ *
+ * @param stateCount reading state module counts from horizontal scan
+ * @param i row where finder pattern may be found
+ * @param j end of possible finder pattern in row
+ * @param pureBarcode true if in "pure barcode" mode
+ * @return true if a finder pattern candidate was found this time
+ */
+ protected handlePossibleCenter(stateCount: Int32Array, i: number /*int*/, j: number /*int*/, pureBarcode: boolean): boolean {
+ const stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] +
+ stateCount[4];
+ let centerJ: number /*float*/ = FinderPatternFinder.centerFromEnd(stateCount, j);
+ let centerI: number /*float*/ = this.crossCheckVertical(i, /*(int) */Math.floor(centerJ), stateCount[2], stateCountTotal);
+ if (!isNaN(centerI)) {
+ // Re-cross check
+ centerJ = this.crossCheckHorizontal(/*(int) */Math.floor(centerJ), /*(int) */Math.floor(centerI), stateCount[2], stateCountTotal);
+ if (!isNaN(centerJ) &&
+ (!pureBarcode || this.crossCheckDiagonal(/*(int) */Math.floor(centerI), /*(int) */Math.floor(centerJ), stateCount[2], stateCountTotal))) {
+ const estimatedModuleSize: number /*float*/ = stateCountTotal / 7.0;
+ let found: boolean = false;
const possibleCenters = this.possibleCenters;
+ for (let index = 0, length = possibleCenters.length; index < length; index++) {
+ const center: FinderPattern = possibleCenters[index];
+ // Look for about the same center and module size:
+ if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) {
+ possibleCenters[index] = center.combineEstimate(centerI, centerJ, estimatedModuleSize);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ const point: FinderPattern = new FinderPattern(centerJ, centerI, estimatedModuleSize);
+ possibleCenters.push(point);
+ if (this.resultPointCallback !== null && this.resultPointCallback !== undefined) {
+ this.resultPointCallback.foundPossibleResultPoint(point);
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return number of rows we could safely skip during scanning, based on the first
+ * two finder patterns that have been located. In some cases their position will
+ * allow us to infer that the third pattern must lie below a certain point farther
+ * down in the image.
+ */
+ private findRowSkip(): number /*int*/ {
+ const max = this.possibleCenters.length;
+ if (max <= 1) {
+ return 0;
+ }
+ let firstConfirmedCenter: ResultPoint = null;
+ for (const center of this.possibleCenters) {
+ if (center.getCount() >= FinderPatternFinder.CENTER_QUORUM) {
+ if (firstConfirmedCenter == null) {
+ firstConfirmedCenter = center;
+ } else {
+ // We have two confirmed centers
+ // How far down can we skip before resuming looking for the next
+ // pattern? In the worst case, only the difference between the
+ // difference in the x / y coordinates of the two centers.
+ // This is the case where you find top left last.
+ this.hasSkipped = true;
+ return /*(int) */Math.floor((Math.abs(firstConfirmedCenter.getX() - center.getX()) -
+ Math.abs(firstConfirmedCenter.getY() - center.getY())) / 2);
+ }
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * @return true iff we have found at least 3 finder patterns that have been detected
+ * at least {@link #CENTER_QUORUM} times each, and, the estimated module size of the
+ * candidates is "pretty similar"
+ */
+ private haveMultiplyConfirmedCenters(): boolean {
+ let confirmedCount = 0;
+ let totalModuleSize: number /*float*/ = 0.0;
+ const max = this.possibleCenters.length;
+ for (const pattern of this.possibleCenters) {
+ if (pattern.getCount() >= FinderPatternFinder.CENTER_QUORUM) {
+ confirmedCount++;
+ totalModuleSize += pattern.getEstimatedModuleSize();
+ }
+ }
+ if (confirmedCount < 3) {
+ return false;
+ }
+ // OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive"
+ // and that we need to keep looking. We detect this by asking if the estimated module sizes
+ // vary too much. We arbitrarily say that when the total deviation from average exceeds
+ // 5% of the total module size estimates, it's too much.
+ const average: number /*float*/ = totalModuleSize / max;
+ let totalDeviation: number /*float*/ = 0.0;
+ for (const pattern of this.possibleCenters) {
+ totalDeviation += Math.abs(pattern.getEstimatedModuleSize() - average);
+ }
+ return totalDeviation <= 0.05 * totalModuleSize;
+ }
+
+ /**
+ * @return the 3 best {@link FinderPattern}s from our list of candidates. The "best" are
+ * those that have been detected at least {@link #CENTER_QUORUM} times, and whose module
+ * size differs from the average among those patterns the least
+ * @throws NotFoundException if 3 such finder patterns do not exist
+ */
+ private selectBestPatterns(): FinderPattern[] /*throws NotFoundException */ {
+
+ const startSize = this.possibleCenters.length;
+ if (startSize < 3) {
+ // Couldn't find enough finder patterns
+ throw new NotFoundException();
+ }
- let average: float;
- // Filter outlier possibilities whose module size is too different
- if (startSize > 3) {
- // But we can only afford to do so if we have at least 4 possibilities to choose from
- let totalModuleSize: float = 0.0;
- let square: float = 0.0;
- for (const center of this.possibleCenters) {
- const size: float = center.getEstimatedModuleSize();
- totalModuleSize += size;
- square += size * size;
- }
- average = totalModuleSize / startSize;
- let stdDev: float = Math.sqrt(square / startSize - average * average);
-
- possibleCenters.sort(
- /**
- *
Orders by furthest from average
- */
- // FurthestFromAverageComparator implements Comparator
- (center1: FinderPattern, center2: FinderPattern) => {
- const dA: float = Math.abs(center2.getEstimatedModuleSize() - average);
- const dB: float = Math.abs(center1.getEstimatedModuleSize() - average);
- return dA < dB ? -1 : dA > dB ? 1 : 0;
- });
-
- const limit: float = Math.max(0.2 * average, stdDev);
-
- for (let i = 0; i < possibleCenters.length && possibleCenters.length > 3; i++) {
- const pattern: FinderPattern = possibleCenters[i];
- if (Math.abs(pattern.getEstimatedModuleSize() - average) > limit) {
- possibleCenters.splice(i, 1);
- i--;
- }
- }
- }
-
- if (possibleCenters.length > 3) {
- // Throw away all but those first size candidate points we found.
-
- let totalModuleSize: float = 0.0;
- for (const possibleCenter of possibleCenters) {
- totalModuleSize += possibleCenter.getEstimatedModuleSize();
- }
-
- average = totalModuleSize / possibleCenters.length;
-
- possibleCenters.sort(
- /**
- *
Orders by {@link FinderPattern#getCount()}, descending.
- */
- // CenterComparator implements Comparator
- (center1: FinderPattern, center2: FinderPattern) => {
- if (center2.getCount() === center1.getCount()) {
- const dA: float = Math.abs(center2.getEstimatedModuleSize() - average);
- const dB: float = Math.abs(center1.getEstimatedModuleSize() - average);
- return dA < dB ? 1 : dA > dB ? -1 : 0;
- } else {
- return center2.getCount() - center1.getCount();
- }
- });
-
- possibleCenters.splice(3); // this is not realy necessary as we only return first 3 anyway
- }
+ const possibleCenters = this.possibleCenters;
+
+ let average: float;
+ // Filter outlier possibilities whose module size is too different
+ if (startSize > 3) {
+ // But we can only afford to do so if we have at least 4 possibilities to choose from
+ let totalModuleSize: float = 0.0;
+ let square: float = 0.0;
+ for (const center of this.possibleCenters) {
+ const size: float = center.getEstimatedModuleSize();
+ totalModuleSize += size;
+ square += size * size;
+ }
+ average = totalModuleSize / startSize;
+ let stdDev: float = Math.sqrt(square / startSize - average * average);
+
+ possibleCenters.sort(
+ /**
+ *
Orders by furthest from average
+ */
+ // FurthestFromAverageComparator implements Comparator
+ (center1: FinderPattern, center2: FinderPattern) => {
+ const dA: float = Math.abs(center2.getEstimatedModuleSize() - average);
+ const dB: float = Math.abs(center1.getEstimatedModuleSize() - average);
+ return dA < dB ? -1 : dA > dB ? 1 : 0;
+ });
+
+ const limit: float = Math.max(0.2 * average, stdDev);
+
+ for (let i = 0; i < possibleCenters.length && possibleCenters.length > 3; i++) {
+ const pattern: FinderPattern = possibleCenters[i];
+ if (Math.abs(pattern.getEstimatedModuleSize() - average) > limit) {
+ possibleCenters.splice(i, 1);
+ i--;
+ }
+ }
+ }
- return [
- possibleCenters[0],
- possibleCenters[1],
- possibleCenters[2]
- ];
+ if (possibleCenters.length > 3) {
+ // Throw away all but those first size candidate points we found.
+
+ let totalModuleSize: float = 0.0;
+ for (const possibleCenter of possibleCenters) {
+ totalModuleSize += possibleCenter.getEstimatedModuleSize();
+ }
+
+ average = totalModuleSize / possibleCenters.length;
+
+ possibleCenters.sort(
+ /**
+ *
Orders by {@link FinderPattern#getCount()}, descending.
+ */
+ // CenterComparator implements Comparator
+ (center1: FinderPattern, center2: FinderPattern) => {
+ if (center2.getCount() === center1.getCount()) {
+ const dA: float = Math.abs(center2.getEstimatedModuleSize() - average);
+ const dB: float = Math.abs(center1.getEstimatedModuleSize() - average);
+ return dA < dB ? 1 : dA > dB ? -1 : 0;
+ } else {
+ return center2.getCount() - center1.getCount();
+ }
+ });
+
+ possibleCenters.splice(3); // this is not realy necessary as we only return first 3 anyway
}
+
+ return [
+ possibleCenters[0],
+ possibleCenters[1],
+ possibleCenters[2]
+ ];
+ }
}
diff --git a/src/core/qrcode/detector/FinderPatternInfo.ts b/src/core/qrcode/detector/FinderPatternInfo.ts
index 520cbaa5..8af3f1ee 100644
--- a/src/core/qrcode/detector/FinderPatternInfo.ts
+++ b/src/core/qrcode/detector/FinderPatternInfo.ts
@@ -26,26 +26,26 @@ import FinderPattern from './FinderPattern';
*/
export default class FinderPatternInfo {
- private bottomLeft: FinderPattern;
- private topLeft: FinderPattern;
- private topRight: FinderPattern;
-
- public constructor(patternCenters: FinderPattern[]) {
- this.bottomLeft = patternCenters[0];
- this.topLeft = patternCenters[1];
- this.topRight = patternCenters[2];
- }
-
- public getBottomLeft(): FinderPattern {
- return this.bottomLeft;
- }
-
- public getTopLeft(): FinderPattern {
- return this.topLeft;
- }
-
- public getTopRight(): FinderPattern {
- return this.topRight;
- }
+ private bottomLeft: FinderPattern;
+ private topLeft: FinderPattern;
+ private topRight: FinderPattern;
+
+ public constructor(patternCenters: FinderPattern[]) {
+ this.bottomLeft = patternCenters[0];
+ this.topLeft = patternCenters[1];
+ this.topRight = patternCenters[2];
+ }
+
+ public getBottomLeft(): FinderPattern {
+ return this.bottomLeft;
+ }
+
+ public getTopLeft(): FinderPattern {
+ return this.topLeft;
+ }
+
+ public getTopRight(): FinderPattern {
+ return this.topRight;
+ }
}
diff --git a/src/core/qrcode/encoder/BlockPair.ts b/src/core/qrcode/encoder/BlockPair.ts
index cc346a22..5f950cb7 100644
--- a/src/core/qrcode/encoder/BlockPair.ts
+++ b/src/core/qrcode/encoder/BlockPair.ts
@@ -18,14 +18,14 @@
export default class BlockPair {
- public constructor(private dataBytes: Uint8Array, private errorCorrectionBytes: Uint8Array) { }
+ public constructor(private dataBytes: Uint8Array, private errorCorrectionBytes: Uint8Array) { }
- public getDataBytes(): Uint8Array {
- return this.dataBytes;
- }
+ public getDataBytes(): Uint8Array {
+ return this.dataBytes;
+ }
- public getErrorCorrectionBytes(): Uint8Array {
- return this.errorCorrectionBytes;
- }
+ public getErrorCorrectionBytes(): Uint8Array {
+ return this.errorCorrectionBytes;
+ }
}
diff --git a/src/core/qrcode/encoder/ByteMatrix.ts b/src/core/qrcode/encoder/ByteMatrix.ts
index 0fe3a401..14616cd3 100644
--- a/src/core/qrcode/encoder/ByteMatrix.ts
+++ b/src/core/qrcode/encoder/ByteMatrix.ts
@@ -29,98 +29,98 @@ import StringBuilder from '../../util/StringBuilder';
*/
export default class ByteMatrix {
- private bytes: Array;
+ private bytes: Array;
- public constructor(private width: number /*int*/, private height: number /*int*/) {
- const bytes = new Array(height); // [height][width]
- for (let i = 0; i !== height; i++) {
- bytes[i] = new Uint8Array(width);
- }
- this.bytes = bytes;
+ public constructor(private width: number /*int*/, private height: number /*int*/) {
+ const bytes = new Array(height); // [height][width]
+ for (let i = 0; i !== height; i++) {
+ bytes[i] = new Uint8Array(width);
}
-
- public getHeight(): number /*int*/ {
- return this.height;
+ this.bytes = bytes;
+ }
+
+ public getHeight(): number /*int*/ {
+ return this.height;
+ }
+
+ public getWidth(): number /*int*/ {
+ return this.width;
+ }
+
+ public get(x: number /*int*/, y: number /*int*/): number/*byte*/ {
+ return this.bytes[y][x];
+ }
+
+ /**
+ * @return an internal representation as bytes, in row-major order. array[y][x] represents point (x,y)
+ */
+ public getArray(): Array {
+ return this.bytes;
+ }
+
+ // TYPESCRIPTPORT: preffer to let two methods instead of override to avoid type comparison inside
+ public setNumber(x: number /*int*/, y: number /*int*/, value: number/*byte|int*/): void {
+ this.bytes[y][x] = value;
+ }
+
+ // public set(x: number /*int*/, y: number /*int*/, value: number /*int*/): void {
+ // bytes[y][x] = (byte) value
+ // }
+
+ public setBoolean(x: number /*int*/, y: number /*int*/, value: boolean): void {
+ this.bytes[y][x] = /*(byte) */(value ? 1 : 0);
+ }
+
+ public clear(value: number/*byte*/): void {
+ for (const aByte of this.bytes) {
+ Arrays.fill(aByte, value);
}
+ }
- public getWidth(): number /*int*/ {
- return this.width;
+ public equals(o: any) {
+ if (!(o instanceof ByteMatrix)) {
+ return false;
}
-
- public get(x: number /*int*/, y: number /*int*/): number/*byte*/ {
- return this.bytes[y][x];
- }
-
- /**
- * @return an internal representation as bytes, in row-major order. array[y][x] represents point (x,y)
- */
- public getArray(): Array {
- return this.bytes;
+ const other = o;
+ if (this.width !== other.width) {
+ return false;
}
-
- // TYPESCRIPTPORT: preffer to let two methods instead of override to avoid type comparison inside
- public setNumber(x: number /*int*/, y: number /*int*/, value: number/*byte|int*/): void {
- this.bytes[y][x] = value;
- }
-
- // public set(x: number /*int*/, y: number /*int*/, value: number /*int*/): void {
- // bytes[y][x] = (byte) value
- // }
-
- public setBoolean(x: number /*int*/, y: number /*int*/, value: boolean): void {
- this.bytes[y][x] = /*(byte) */(value ? 1 : 0);
+ if (this.height !== other.height) {
+ return false;
}
-
- public clear(value: number/*byte*/): void {
- for (const aByte of this.bytes) {
- Arrays.fill(aByte, value);
- }
- }
-
- public equals(o: any) {
- if (!(o instanceof ByteMatrix)) {
- return false;
+ for (let y = 0, height = this.height; y < height; ++y) {
+ const bytesY = this.bytes[y];
+ const otherBytesY = other.bytes[y];
+ for (let x = 0, width = this.width; x < width; ++x) {
+ if (bytesY[x] !== otherBytesY[x]) {
+ return false;
}
- const other = o;
- if (this.width !== other.width) {
- return false;
- }
- if (this.height !== other.height) {
- return false;
- }
- for (let y = 0, height = this.height; y < height; ++y) {
- const bytesY = this.bytes[y];
- const otherBytesY = other.bytes[y];
- for (let x = 0, width = this.width; x < width; ++x) {
- if (bytesY[x] !== otherBytesY[x]) {
- return false;
- }
- }
- }
- return true;
+ }
}
-
- /*@Override*/
- public toString(): string {
- const result = new StringBuilder(); // (2 * width * height + 2)
- for (let y = 0, height = this.height; y < height; ++y) {
- const bytesY = this.bytes[y];
- for (let x = 0, width = this.width; x < width; ++x) {
- switch (bytesY[x]) {
- case 0:
- result.append(' 0');
- break;
- case 1:
- result.append(' 1');
- break;
- default:
- result.append(' ');
- break;
- }
- }
- result.append('\n');
+ return true;
+ }
+
+ /*@Override*/
+ public toString(): string {
+ const result = new StringBuilder(); // (2 * width * height + 2)
+ for (let y = 0, height = this.height; y < height; ++y) {
+ const bytesY = this.bytes[y];
+ for (let x = 0, width = this.width; x < width; ++x) {
+ switch (bytesY[x]) {
+ case 0:
+ result.append(' 0');
+ break;
+ case 1:
+ result.append(' 1');
+ break;
+ default:
+ result.append(' ');
+ break;
}
- return result.toString();
+ }
+ result.append('\n');
}
+ return result.toString();
+ }
}
diff --git a/src/core/qrcode/encoder/Encoder.ts b/src/core/qrcode/encoder/Encoder.ts
index d7529a5f..2f4c9fd6 100644
--- a/src/core/qrcode/encoder/Encoder.ts
+++ b/src/core/qrcode/encoder/Encoder.ts
@@ -45,595 +45,595 @@ import WriterException from '../../WriterException';
*/
export default class Encoder {
- // The original table is defined in the table 5 of JISX0510:2004 (p.19).
- private static ALPHANUMERIC_TABLE = Int32Array.from([
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00-0x0f
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10-0x1f
- 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // 0x20-0x2f
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, // 0x30-0x3f
- -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f
- 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 0x50-0x5f
- ]);
-
- public static DEFAULT_BYTE_MODE_ENCODING = CharacterSetECI.UTF8.getName(); // "ISO-8859-1"
- // TYPESCRIPTPORT: changed to UTF8, the default for js
-
- private constructor() { }
-
- // The mask penalty calculation is complicated. See Table 21 of JISX0510:2004 (p.45) for details.
- // Basically it applies four rules and summate all penalties.
- private static calculateMaskPenalty(matrix: ByteMatrix): number /*int*/ {
- return MaskUtil.applyMaskPenaltyRule1(matrix)
- + MaskUtil.applyMaskPenaltyRule2(matrix)
- + MaskUtil.applyMaskPenaltyRule3(matrix)
- + MaskUtil.applyMaskPenaltyRule4(matrix);
- }
-
- /**
- * @param content text to encode
- * @param ecLevel error correction level to use
- * @return {@link QRCode} representing the encoded QR code
- * @throws WriterException if encoding can't succeed, because of for example invalid content
- * or configuration
- */
- // public static encode(content: string, ecLevel: ErrorCorrectionLevel): QRCode /*throws WriterException*/ {
- // return encode(content, ecLevel, null)
- // }
-
- public static encode(content: string,
- ecLevel: ErrorCorrectionLevel,
- hints: Map = null): QRCode /*throws WriterException*/ {
-
- // Determine what character encoding has been specified by the caller, if any
- let encoding: string = Encoder.DEFAULT_BYTE_MODE_ENCODING;
- const hasEncodingHint: boolean = hints !== null && undefined !== hints.get(EncodeHintType.CHARACTER_SET);
- if (hasEncodingHint) {
- encoding = hints.get(EncodeHintType.CHARACTER_SET).toString();
- }
-
- // Pick an encoding mode appropriate for the content. Note that this will not attempt to use
- // multiple modes / segments even if that were more efficient. Twould be nice.
- const mode: Mode = this.chooseMode(content, encoding);
-
- // This will store the header information, like mode and
- // length, as well as "header" segments like an ECI segment.
- const headerBits = new BitArray();
+ // The original table is defined in the table 5 of JISX0510:2004 (p.19).
+ private static ALPHANUMERIC_TABLE = Int32Array.from([
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00-0x0f
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10-0x1f
+ 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // 0x20-0x2f
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, // 0x30-0x3f
+ -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 0x50-0x5f
+ ]);
+
+ public static DEFAULT_BYTE_MODE_ENCODING = CharacterSetECI.UTF8.getName(); // "ISO-8859-1"
+ // TYPESCRIPTPORT: changed to UTF8, the default for js
+
+ private constructor() { }
+
+ // The mask penalty calculation is complicated. See Table 21 of JISX0510:2004 (p.45) for details.
+ // Basically it applies four rules and summate all penalties.
+ private static calculateMaskPenalty(matrix: ByteMatrix): number /*int*/ {
+ return MaskUtil.applyMaskPenaltyRule1(matrix)
+ + MaskUtil.applyMaskPenaltyRule2(matrix)
+ + MaskUtil.applyMaskPenaltyRule3(matrix)
+ + MaskUtil.applyMaskPenaltyRule4(matrix);
+ }
+
+ /**
+ * @param content text to encode
+ * @param ecLevel error correction level to use
+ * @return {@link QRCode} representing the encoded QR code
+ * @throws WriterException if encoding can't succeed, because of for example invalid content
+ * or configuration
+ */
+ // public static encode(content: string, ecLevel: ErrorCorrectionLevel): QRCode /*throws WriterException*/ {
+ // return encode(content, ecLevel, null)
+ // }
+
+ public static encode(content: string,
+ ecLevel: ErrorCorrectionLevel,
+ hints: Map = null): QRCode /*throws WriterException*/ {
+
+ // Determine what character encoding has been specified by the caller, if any
+ let encoding: string = Encoder.DEFAULT_BYTE_MODE_ENCODING;
+ const hasEncodingHint: boolean = hints !== null && undefined !== hints.get(EncodeHintType.CHARACTER_SET);
+ if (hasEncodingHint) {
+ encoding = hints.get(EncodeHintType.CHARACTER_SET).toString();
+ }
- // Append ECI segment if applicable
- if (mode === Mode.BYTE && (hasEncodingHint || Encoder.DEFAULT_BYTE_MODE_ENCODING !== encoding)) {
- const eci = CharacterSetECI.getCharacterSetECIByName(encoding);
- if (eci !== undefined) {
- this.appendECI(eci, headerBits);
- }
- }
+ // Pick an encoding mode appropriate for the content. Note that this will not attempt to use
+ // multiple modes / segments even if that were more efficient. Twould be nice.
+ const mode: Mode = this.chooseMode(content, encoding);
- // (With ECI in place,) Write the mode marker
- this.appendModeInfo(mode, headerBits);
-
- // Collect data within the main segment, separately, to count its size if needed. Don't add it to
- // main payload yet.
- const dataBits = new BitArray();
- this.appendBytes(content, mode, dataBits, encoding);
-
- let version: Version;
- if (hints !== null && undefined !== hints.get(EncodeHintType.QR_VERSION)) {
- const versionNumber = Number.parseInt(hints.get(EncodeHintType.QR_VERSION).toString(), 10);
- version = Version.getVersionForNumber(versionNumber);
- const bitsNeeded = this.calculateBitsNeeded(mode, headerBits, dataBits, version);
- if (!this.willFit(bitsNeeded, version, ecLevel)) {
- throw new WriterException('Data too big for requested version');
- }
- } else {
- version = this.recommendVersion(ecLevel, mode, headerBits, dataBits);
- }
+ // This will store the header information, like mode and
+ // length, as well as "header" segments like an ECI segment.
+ const headerBits = new BitArray();
- const headerAndDataBits = new BitArray();
- headerAndDataBits.appendBitArray(headerBits);
- // Find "length" of main segment and write it
- const numLetters = mode === Mode.BYTE ? dataBits.getSizeInBytes() : content.length;
- this.appendLengthInfo(numLetters, version, mode, headerAndDataBits);
- // Put data together into the overall payload
- headerAndDataBits.appendBitArray(dataBits);
-
- const ecBlocks: ECBlocks = version.getECBlocksForLevel(ecLevel);
- const numDataBytes = version.getTotalCodewords() - ecBlocks.getTotalECCodewords();
-
- // Terminate the bits properly.
- this.terminateBits(numDataBytes, headerAndDataBits);
-
- // Interleave data bits with error correction code.
- const finalBits: BitArray = this.interleaveWithECBytes(headerAndDataBits,
- version.getTotalCodewords(),
- numDataBytes,
- ecBlocks.getNumBlocks());
-
- const qrCode = new QRCode();
-
- qrCode.setECLevel(ecLevel);
- qrCode.setMode(mode);
- qrCode.setVersion(version);
-
- // Choose the mask pattern and set to "qrCode".
- const dimension = version.getDimensionForVersion();
- const matrix: ByteMatrix = new ByteMatrix(dimension, dimension);
- const maskPattern = this.chooseMaskPattern(finalBits, ecLevel, version, matrix);
- qrCode.setMaskPattern(maskPattern);
-
- // Build the matrix and set it to "qrCode".
- MatrixUtil.buildMatrix(finalBits, ecLevel, version, maskPattern, matrix);
- qrCode.setMatrix(matrix);
-
- return qrCode;
- }
-
- /**
- * Decides the smallest version of QR code that will contain all of the provided data.
- *
- * @throws WriterException if the data cannot fit in any version
- */
- private static recommendVersion(ecLevel: ErrorCorrectionLevel,
- mode: Mode,
- headerBits: BitArray,
- dataBits: BitArray): Version /*throws WriterException*/ {
- // Hard part: need to know version to know how many bits length takes. But need to know how many
- // bits it takes to know version. First we take a guess at version by assuming version will be
- // the minimum, 1:
- const provisionalBitsNeeded = this.calculateBitsNeeded(mode, headerBits, dataBits, Version.getVersionForNumber(1));
- const provisionalVersion = this.chooseVersion(provisionalBitsNeeded, ecLevel);
-
- // Use that guess to calculate the right version. I am still not sure this works in 100% of cases.
- const bitsNeeded = this.calculateBitsNeeded(mode, headerBits, dataBits, provisionalVersion);
- return this.chooseVersion(bitsNeeded, ecLevel);
- }
-
- private static calculateBitsNeeded(mode: Mode,
- headerBits: BitArray,
- dataBits: BitArray,
- version: Version): number /*int*/ {
- return headerBits.getSize() + mode.getCharacterCountBits(version) + dataBits.getSize();
- }
-
- /**
- * @return the code point of the table used in alphanumeric mode or
- * -1 if there is no corresponding code in the table.
- */
- public static getAlphanumericCode(code: number /*int*/): number /*int*/ {
- if (code < Encoder.ALPHANUMERIC_TABLE.length) {
- return Encoder.ALPHANUMERIC_TABLE[code];
- }
- return -1;
+ // Append ECI segment if applicable
+ if (mode === Mode.BYTE && (hasEncodingHint || Encoder.DEFAULT_BYTE_MODE_ENCODING !== encoding)) {
+ const eci = CharacterSetECI.getCharacterSetECIByName(encoding);
+ if (eci !== undefined) {
+ this.appendECI(eci, headerBits);
+ }
}
- // public static chooseMode(content: string): Mode {
- // return chooseMode(content, null);
- // }
+ // (With ECI in place,) Write the mode marker
+ this.appendModeInfo(mode, headerBits);
+
+ // Collect data within the main segment, separately, to count its size if needed. Don't add it to
+ // main payload yet.
+ const dataBits = new BitArray();
+ this.appendBytes(content, mode, dataBits, encoding);
+
+ let version: Version;
+ if (hints !== null && undefined !== hints.get(EncodeHintType.QR_VERSION)) {
+ const versionNumber = Number.parseInt(hints.get(EncodeHintType.QR_VERSION).toString(), 10);
+ version = Version.getVersionForNumber(versionNumber);
+ const bitsNeeded = this.calculateBitsNeeded(mode, headerBits, dataBits, version);
+ if (!this.willFit(bitsNeeded, version, ecLevel)) {
+ throw new WriterException('Data too big for requested version');
+ }
+ } else {
+ version = this.recommendVersion(ecLevel, mode, headerBits, dataBits);
+ }
- /**
- * Choose the best mode by examining the content. Note that 'encoding' is used as a hint;
- * if it is Shift_JIS, and the input is only double-byte Kanji, then we return {@link Mode#KANJI}.
- */
- public static chooseMode(content: string, encoding: string = null): Mode {
- if (CharacterSetECI.SJIS.getName() === encoding && this.isOnlyDoubleByteKanji(content)) {
- // Choose Kanji mode if all input are double-byte characters
- return Mode.KANJI;
- }
- let hasNumeric: boolean = false;
- let hasAlphanumeric: boolean = false;
- for (let i = 0, length = content.length; i < length; ++i) {
- const c: string = content.charAt(i);
- if (Encoder.isDigit(c)) {
- hasNumeric = true;
- } else if (this.getAlphanumericCode(c.charCodeAt(0)) !== -1) {
- hasAlphanumeric = true;
- } else {
- return Mode.BYTE;
- }
- }
- if (hasAlphanumeric) {
- return Mode.ALPHANUMERIC;
- }
- if (hasNumeric) {
- return Mode.NUMERIC;
- }
+ const headerAndDataBits = new BitArray();
+ headerAndDataBits.appendBitArray(headerBits);
+ // Find "length" of main segment and write it
+ const numLetters = mode === Mode.BYTE ? dataBits.getSizeInBytes() : content.length;
+ this.appendLengthInfo(numLetters, version, mode, headerAndDataBits);
+ // Put data together into the overall payload
+ headerAndDataBits.appendBitArray(dataBits);
+
+ const ecBlocks: ECBlocks = version.getECBlocksForLevel(ecLevel);
+ const numDataBytes = version.getTotalCodewords() - ecBlocks.getTotalECCodewords();
+
+ // Terminate the bits properly.
+ this.terminateBits(numDataBytes, headerAndDataBits);
+
+ // Interleave data bits with error correction code.
+ const finalBits: BitArray = this.interleaveWithECBytes(headerAndDataBits,
+ version.getTotalCodewords(),
+ numDataBytes,
+ ecBlocks.getNumBlocks());
+
+ const qrCode = new QRCode();
+
+ qrCode.setECLevel(ecLevel);
+ qrCode.setMode(mode);
+ qrCode.setVersion(version);
+
+ // Choose the mask pattern and set to "qrCode".
+ const dimension = version.getDimensionForVersion();
+ const matrix: ByteMatrix = new ByteMatrix(dimension, dimension);
+ const maskPattern = this.chooseMaskPattern(finalBits, ecLevel, version, matrix);
+ qrCode.setMaskPattern(maskPattern);
+
+ // Build the matrix and set it to "qrCode".
+ MatrixUtil.buildMatrix(finalBits, ecLevel, version, maskPattern, matrix);
+ qrCode.setMatrix(matrix);
+
+ return qrCode;
+ }
+
+ /**
+ * Decides the smallest version of QR code that will contain all of the provided data.
+ *
+ * @throws WriterException if the data cannot fit in any version
+ */
+ private static recommendVersion(ecLevel: ErrorCorrectionLevel,
+ mode: Mode,
+ headerBits: BitArray,
+ dataBits: BitArray): Version /*throws WriterException*/ {
+ // Hard part: need to know version to know how many bits length takes. But need to know how many
+ // bits it takes to know version. First we take a guess at version by assuming version will be
+ // the minimum, 1:
+ const provisionalBitsNeeded = this.calculateBitsNeeded(mode, headerBits, dataBits, Version.getVersionForNumber(1));
+ const provisionalVersion = this.chooseVersion(provisionalBitsNeeded, ecLevel);
+
+ // Use that guess to calculate the right version. I am still not sure this works in 100% of cases.
+ const bitsNeeded = this.calculateBitsNeeded(mode, headerBits, dataBits, provisionalVersion);
+ return this.chooseVersion(bitsNeeded, ecLevel);
+ }
+
+ private static calculateBitsNeeded(mode: Mode,
+ headerBits: BitArray,
+ dataBits: BitArray,
+ version: Version): number /*int*/ {
+ return headerBits.getSize() + mode.getCharacterCountBits(version) + dataBits.getSize();
+ }
+
+ /**
+ * @return the code point of the table used in alphanumeric mode or
+ * -1 if there is no corresponding code in the table.
+ */
+ public static getAlphanumericCode(code: number /*int*/): number /*int*/ {
+ if (code < Encoder.ALPHANUMERIC_TABLE.length) {
+ return Encoder.ALPHANUMERIC_TABLE[code];
+ }
+ return -1;
+ }
+
+ // public static chooseMode(content: string): Mode {
+ // return chooseMode(content, null);
+ // }
+
+ /**
+ * Choose the best mode by examining the content. Note that 'encoding' is used as a hint;
+ * if it is Shift_JIS, and the input is only double-byte Kanji, then we return {@link Mode#KANJI}.
+ */
+ public static chooseMode(content: string, encoding: string = null): Mode {
+ if (CharacterSetECI.SJIS.getName() === encoding && this.isOnlyDoubleByteKanji(content)) {
+ // Choose Kanji mode if all input are double-byte characters
+ return Mode.KANJI;
+ }
+ let hasNumeric: boolean = false;
+ let hasAlphanumeric: boolean = false;
+ for (let i = 0, length = content.length; i < length; ++i) {
+ const c: string = content.charAt(i);
+ if (Encoder.isDigit(c)) {
+ hasNumeric = true;
+ } else if (this.getAlphanumericCode(c.charCodeAt(0)) !== -1) {
+ hasAlphanumeric = true;
+ } else {
return Mode.BYTE;
+ }
}
-
- private static isOnlyDoubleByteKanji(content: string): boolean {
- let bytes: Uint8Array;
- try {
- bytes = StringEncoding.encode(content, CharacterSetECI.SJIS); // content.getBytes("Shift_JIS"))
- } catch (ignored/*: UnsupportedEncodingException*/) {
- return false;
- }
- const length = bytes.length;
- if (length % 2 !== 0) {
- return false;
- }
- for (let i = 0; i < length; i += 2) {
- const byte1 = bytes[i] & 0xFF;
- if ((byte1 < 0x81 || byte1 > 0x9F) && (byte1 < 0xE0 || byte1 > 0xEB)) {
- return false;
- }
- }
- return true;
- }
-
- private static chooseMaskPattern(bits: BitArray,
- ecLevel: ErrorCorrectionLevel,
- version: Version,
- matrix: ByteMatrix): number /*int*/ /*throws WriterException*/ {
-
- let minPenalty = Number.MAX_SAFE_INTEGER; // Lower penalty is better.
- let bestMaskPattern = -1;
- // We try all mask patterns to choose the best one.
- for (let maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) {
- MatrixUtil.buildMatrix(bits, ecLevel, version, maskPattern, matrix);
- let penalty = this.calculateMaskPenalty(matrix);
- if (penalty < minPenalty) {
- minPenalty = penalty;
- bestMaskPattern = maskPattern;
- }
- }
- return bestMaskPattern;
+ if (hasAlphanumeric) {
+ return Mode.ALPHANUMERIC;
}
-
- private static chooseVersion(numInputBits: number /*int*/, ecLevel: ErrorCorrectionLevel): Version /*throws WriterException*/ {
- for (let versionNum = 1; versionNum <= 40; versionNum++) {
- const version = Version.getVersionForNumber(versionNum);
- if (Encoder.willFit(numInputBits, version, ecLevel)) {
- return version;
- }
- }
- throw new WriterException('Data too big');
- }
-
- /**
- * @return true if the number of input bits will fit in a code with the specified version and
- * error correction level.
- */
- private static willFit(numInputBits: number /*int*/, version: Version, ecLevel: ErrorCorrectionLevel): boolean {
- // In the following comments, we use numbers of Version 7-H.
- // numBytes = 196
- const numBytes = version.getTotalCodewords();
- // getNumECBytes = 130
- const ecBlocks = version.getECBlocksForLevel(ecLevel);
- const numEcBytes = ecBlocks.getTotalECCodewords();
- // getNumDataBytes = 196 - 130 = 66
- const numDataBytes = numBytes - numEcBytes;
- const totalInputBytes = (numInputBits + 7) / 8;
- return numDataBytes >= totalInputBytes;
- }
-
- /**
- * Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24).
- */
- public static terminateBits(numDataBytes: number /*int*/, bits: BitArray): void /*throws WriterException*/ {
- const capacity = numDataBytes * 8;
- if (bits.getSize() > capacity) {
- throw new WriterException('data bits cannot fit in the QR Code' + bits.getSize() + ' > ' +
- capacity);
- }
- for (let i = 0; i < 4 && bits.getSize() < capacity; ++i) {
- bits.appendBit(false);
- }
- // Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details.
- // If the last byte isn't 8-bit aligned, we'll add padding bits.
- const numBitsInLastByte = bits.getSize() & 0x07;
- if (numBitsInLastByte > 0) {
- for (let i = numBitsInLastByte; i < 8; i++) {
- bits.appendBit(false);
- }
- }
- // If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24).
- const numPaddingBytes = numDataBytes - bits.getSizeInBytes();
- for (let i = 0; i < numPaddingBytes; ++i) {
- bits.appendBits((i & 0x01) === 0 ? 0xEC : 0x11, 8);
- }
- if (bits.getSize() !== capacity) {
- throw new WriterException('Bits size does not equal capacity');
- }
+ if (hasNumeric) {
+ return Mode.NUMERIC;
}
-
- /**
- * Get number of data bytes and number of error correction bytes for block id "blockID". Store
- * the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of
- * JISX0510:2004 (p.30)
- */
- public static getNumDataBytesAndNumECBytesForBlockID(numTotalBytes: number /*int*/,
- numDataBytes: number /*int*/,
- numRSBlocks: number /*int*/,
- blockID: number /*int*/,
- numDataBytesInBlock: Int32Array,
- numECBytesInBlock: Int32Array): void /*throws WriterException*/ {
- if (blockID >= numRSBlocks) {
- throw new WriterException('Block ID too large');
- }
- // numRsBlocksInGroup2 = 196 % 5 = 1
- const numRsBlocksInGroup2 = numTotalBytes % numRSBlocks;
- // numRsBlocksInGroup1 = 5 - 1 = 4
- const numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2;
- // numTotalBytesInGroup1 = 196 / 5 = 39
- const numTotalBytesInGroup1 = Math.floor(numTotalBytes / numRSBlocks);
- // numTotalBytesInGroup2 = 39 + 1 = 40
- const numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1;
- // numDataBytesInGroup1 = 66 / 5 = 13
- const numDataBytesInGroup1 = Math.floor(numDataBytes / numRSBlocks);
- // numDataBytesInGroup2 = 13 + 1 = 14
- const numDataBytesInGroup2 = numDataBytesInGroup1 + 1;
- // numEcBytesInGroup1 = 39 - 13 = 26
- const numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1;
- // numEcBytesInGroup2 = 40 - 14 = 26
- const numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2;
- // Sanity checks.
- // 26 = 26
- if (numEcBytesInGroup1 !== numEcBytesInGroup2) {
- throw new WriterException('EC bytes mismatch');
- }
- // 5 = 4 + 1.
- if (numRSBlocks !== numRsBlocksInGroup1 + numRsBlocksInGroup2) {
- throw new WriterException('RS blocks mismatch');
- }
- // 196 = (13 + 26) * 4 + (14 + 26) * 1
- if (numTotalBytes !==
- ((numDataBytesInGroup1 + numEcBytesInGroup1) *
- numRsBlocksInGroup1) +
- ((numDataBytesInGroup2 + numEcBytesInGroup2) *
- numRsBlocksInGroup2)) {
- throw new WriterException('Total bytes mismatch');
- }
-
- if (blockID < numRsBlocksInGroup1) {
- numDataBytesInBlock[0] = numDataBytesInGroup1;
- numECBytesInBlock[0] = numEcBytesInGroup1;
- } else {
- numDataBytesInBlock[0] = numDataBytesInGroup2;
- numECBytesInBlock[0] = numEcBytesInGroup2;
- }
+ return Mode.BYTE;
+ }
+
+ private static isOnlyDoubleByteKanji(content: string): boolean {
+ let bytes: Uint8Array;
+ try {
+ bytes = StringEncoding.encode(content, CharacterSetECI.SJIS); // content.getBytes("Shift_JIS"))
+ } catch (ignored/*: UnsupportedEncodingException*/) {
+ return false;
+ }
+ const length = bytes.length;
+ if (length % 2 !== 0) {
+ return false;
+ }
+ for (let i = 0; i < length; i += 2) {
+ const byte1 = bytes[i] & 0xFF;
+ if ((byte1 < 0x81 || byte1 > 0x9F) && (byte1 < 0xE0 || byte1 > 0xEB)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static chooseMaskPattern(bits: BitArray,
+ ecLevel: ErrorCorrectionLevel,
+ version: Version,
+ matrix: ByteMatrix): number /*int*/ /*throws WriterException*/ {
+
+ let minPenalty = Number.MAX_SAFE_INTEGER; // Lower penalty is better.
+ let bestMaskPattern = -1;
+ // We try all mask patterns to choose the best one.
+ for (let maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) {
+ MatrixUtil.buildMatrix(bits, ecLevel, version, maskPattern, matrix);
+ let penalty = this.calculateMaskPenalty(matrix);
+ if (penalty < minPenalty) {
+ minPenalty = penalty;
+ bestMaskPattern = maskPattern;
+ }
+ }
+ return bestMaskPattern;
+ }
+
+ private static chooseVersion(numInputBits: number /*int*/, ecLevel: ErrorCorrectionLevel): Version /*throws WriterException*/ {
+ for (let versionNum = 1; versionNum <= 40; versionNum++) {
+ const version = Version.getVersionForNumber(versionNum);
+ if (Encoder.willFit(numInputBits, version, ecLevel)) {
+ return version;
+ }
+ }
+ throw new WriterException('Data too big');
+ }
+
+ /**
+ * @return true if the number of input bits will fit in a code with the specified version and
+ * error correction level.
+ */
+ private static willFit(numInputBits: number /*int*/, version: Version, ecLevel: ErrorCorrectionLevel): boolean {
+ // In the following comments, we use numbers of Version 7-H.
+ // numBytes = 196
+ const numBytes = version.getTotalCodewords();
+ // getNumECBytes = 130
+ const ecBlocks = version.getECBlocksForLevel(ecLevel);
+ const numEcBytes = ecBlocks.getTotalECCodewords();
+ // getNumDataBytes = 196 - 130 = 66
+ const numDataBytes = numBytes - numEcBytes;
+ const totalInputBytes = (numInputBits + 7) / 8;
+ return numDataBytes >= totalInputBytes;
+ }
+
+ /**
+ * Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24).
+ */
+ public static terminateBits(numDataBytes: number /*int*/, bits: BitArray): void /*throws WriterException*/ {
+ const capacity = numDataBytes * 8;
+ if (bits.getSize() > capacity) {
+ throw new WriterException('data bits cannot fit in the QR Code' + bits.getSize() + ' > ' +
+ capacity);
+ }
+ for (let i = 0; i < 4 && bits.getSize() < capacity; ++i) {
+ bits.appendBit(false);
+ }
+ // Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details.
+ // If the last byte isn't 8-bit aligned, we'll add padding bits.
+ const numBitsInLastByte = bits.getSize() & 0x07;
+ if (numBitsInLastByte > 0) {
+ for (let i = numBitsInLastByte; i < 8; i++) {
+ bits.appendBit(false);
+ }
+ }
+ // If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24).
+ const numPaddingBytes = numDataBytes - bits.getSizeInBytes();
+ for (let i = 0; i < numPaddingBytes; ++i) {
+ bits.appendBits((i & 0x01) === 0 ? 0xEC : 0x11, 8);
+ }
+ if (bits.getSize() !== capacity) {
+ throw new WriterException('Bits size does not equal capacity');
+ }
+ }
+
+ /**
+ * Get number of data bytes and number of error correction bytes for block id "blockID". Store
+ * the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of
+ * JISX0510:2004 (p.30)
+ */
+ public static getNumDataBytesAndNumECBytesForBlockID(numTotalBytes: number /*int*/,
+ numDataBytes: number /*int*/,
+ numRSBlocks: number /*int*/,
+ blockID: number /*int*/,
+ numDataBytesInBlock: Int32Array,
+ numECBytesInBlock: Int32Array): void /*throws WriterException*/ {
+ if (blockID >= numRSBlocks) {
+ throw new WriterException('Block ID too large');
+ }
+ // numRsBlocksInGroup2 = 196 % 5 = 1
+ const numRsBlocksInGroup2 = numTotalBytes % numRSBlocks;
+ // numRsBlocksInGroup1 = 5 - 1 = 4
+ const numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2;
+ // numTotalBytesInGroup1 = 196 / 5 = 39
+ const numTotalBytesInGroup1 = Math.floor(numTotalBytes / numRSBlocks);
+ // numTotalBytesInGroup2 = 39 + 1 = 40
+ const numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1;
+ // numDataBytesInGroup1 = 66 / 5 = 13
+ const numDataBytesInGroup1 = Math.floor(numDataBytes / numRSBlocks);
+ // numDataBytesInGroup2 = 13 + 1 = 14
+ const numDataBytesInGroup2 = numDataBytesInGroup1 + 1;
+ // numEcBytesInGroup1 = 39 - 13 = 26
+ const numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1;
+ // numEcBytesInGroup2 = 40 - 14 = 26
+ const numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2;
+ // Sanity checks.
+ // 26 = 26
+ if (numEcBytesInGroup1 !== numEcBytesInGroup2) {
+ throw new WriterException('EC bytes mismatch');
+ }
+ // 5 = 4 + 1.
+ if (numRSBlocks !== numRsBlocksInGroup1 + numRsBlocksInGroup2) {
+ throw new WriterException('RS blocks mismatch');
+ }
+ // 196 = (13 + 26) * 4 + (14 + 26) * 1
+ if (numTotalBytes !==
+ ((numDataBytesInGroup1 + numEcBytesInGroup1) *
+ numRsBlocksInGroup1) +
+ ((numDataBytesInGroup2 + numEcBytesInGroup2) *
+ numRsBlocksInGroup2)) {
+ throw new WriterException('Total bytes mismatch');
}
- /**
- * Interleave "bits" with corresponding error correction bytes. On success, store the result in
- * "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details.
- */
- public static interleaveWithECBytes(bits: BitArray,
- numTotalBytes: number /*int*/,
- numDataBytes: number /*int*/,
- numRSBlocks: number /*int*/): BitArray /*throws WriterException*/ {
-
- // "bits" must have "getNumDataBytes" bytes of data.
- if (bits.getSizeInBytes() !== numDataBytes) {
- throw new WriterException('Number of bits and data bytes does not match');
- }
-
- // Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll
- // store the divided data bytes blocks and error correction bytes blocks into "blocks".
- let dataBytesOffset = 0;
- let maxNumDataBytes = 0;
- let maxNumEcBytes = 0;
-
- // Since, we know the number of reedsolmon blocks, we can initialize the vector with the number.
- const blocks = new Array(); // new Array(numRSBlocks)
-
- for (let i = 0; i < numRSBlocks; ++i) {
- const numDataBytesInBlock: Int32Array = new Int32Array(1);
- const numEcBytesInBlock: Int32Array = new Int32Array(1);
- Encoder.getNumDataBytesAndNumECBytesForBlockID(
- numTotalBytes, numDataBytes, numRSBlocks, i,
- numDataBytesInBlock, numEcBytesInBlock);
-
- const size = numDataBytesInBlock[0];
- const dataBytes = new Uint8Array(size);
- bits.toBytes(8 * dataBytesOffset, dataBytes, 0, size);
- const ecBytes: Uint8Array = Encoder.generateECBytes(dataBytes, numEcBytesInBlock[0]);
- blocks.push(new BlockPair(dataBytes, ecBytes));
-
- maxNumDataBytes = Math.max(maxNumDataBytes, size);
- maxNumEcBytes = Math.max(maxNumEcBytes, ecBytes.length);
- dataBytesOffset += numDataBytesInBlock[0];
- }
- if (numDataBytes !== dataBytesOffset) {
- throw new WriterException('Data bytes does not match offset');
- }
-
- const result = new BitArray();
-
- // First, place data blocks.
- for (let i = 0; i < maxNumDataBytes; ++i) {
- for (const block of blocks) {
- const dataBytes = block.getDataBytes();
- if (i < dataBytes.length) {
- result.appendBits(dataBytes[i], 8);
- }
- }
- }
- // Then, place error correction blocks.
- for (let i = 0; i < maxNumEcBytes; ++i) {
- for (const block of blocks) {
- const ecBytes = block.getErrorCorrectionBytes();
- if (i < ecBytes.length) {
- result.appendBits(ecBytes[i], 8);
- }
- }
- }
- if (numTotalBytes !== result.getSizeInBytes()) { // Should be same.
- throw new WriterException('Interleaving error: ' + numTotalBytes + ' and ' +
- result.getSizeInBytes() + ' differ.');
- }
+ if (blockID < numRsBlocksInGroup1) {
+ numDataBytesInBlock[0] = numDataBytesInGroup1;
+ numECBytesInBlock[0] = numEcBytesInGroup1;
+ } else {
+ numDataBytesInBlock[0] = numDataBytesInGroup2;
+ numECBytesInBlock[0] = numEcBytesInGroup2;
+ }
+ }
+
+ /**
+ * Interleave "bits" with corresponding error correction bytes. On success, store the result in
+ * "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details.
+ */
+ public static interleaveWithECBytes(bits: BitArray,
+ numTotalBytes: number /*int*/,
+ numDataBytes: number /*int*/,
+ numRSBlocks: number /*int*/): BitArray /*throws WriterException*/ {
+
+ // "bits" must have "getNumDataBytes" bytes of data.
+ if (bits.getSizeInBytes() !== numDataBytes) {
+ throw new WriterException('Number of bits and data bytes does not match');
+ }
- return result;
+ // Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll
+ // store the divided data bytes blocks and error correction bytes blocks into "blocks".
+ let dataBytesOffset = 0;
+ let maxNumDataBytes = 0;
+ let maxNumEcBytes = 0;
+
+ // Since, we know the number of reedsolmon blocks, we can initialize the vector with the number.
+ const blocks = new Array(); // new Array(numRSBlocks)
+
+ for (let i = 0; i < numRSBlocks; ++i) {
+ const numDataBytesInBlock: Int32Array = new Int32Array(1);
+ const numEcBytesInBlock: Int32Array = new Int32Array(1);
+ Encoder.getNumDataBytesAndNumECBytesForBlockID(
+ numTotalBytes, numDataBytes, numRSBlocks, i,
+ numDataBytesInBlock, numEcBytesInBlock);
+
+ const size = numDataBytesInBlock[0];
+ const dataBytes = new Uint8Array(size);
+ bits.toBytes(8 * dataBytesOffset, dataBytes, 0, size);
+ const ecBytes: Uint8Array = Encoder.generateECBytes(dataBytes, numEcBytesInBlock[0]);
+ blocks.push(new BlockPair(dataBytes, ecBytes));
+
+ maxNumDataBytes = Math.max(maxNumDataBytes, size);
+ maxNumEcBytes = Math.max(maxNumEcBytes, ecBytes.length);
+ dataBytesOffset += numDataBytesInBlock[0];
+ }
+ if (numDataBytes !== dataBytesOffset) {
+ throw new WriterException('Data bytes does not match offset');
}
- public static generateECBytes(dataBytes: Uint8Array, numEcBytesInBlock: number /*int*/): Uint8Array {
- const numDataBytes = dataBytes.length;
- const toEncode: Int32Array = new Int32Array(numDataBytes + numEcBytesInBlock); // int[numDataBytes + numEcBytesInBlock]
- for (let i = 0; i < numDataBytes; i++) {
- toEncode[i] = dataBytes[i] & 0xFF;
- }
- new ReedSolomonEncoder(GenericGF.QR_CODE_FIELD_256).encode(toEncode, numEcBytesInBlock);
+ const result = new BitArray();
- const ecBytes = new Uint8Array(numEcBytesInBlock);
- for (let i = 0; i < numEcBytesInBlock; i++) {
- ecBytes[i] = /*(byte) */toEncode[numDataBytes + i];
+ // First, place data blocks.
+ for (let i = 0; i < maxNumDataBytes; ++i) {
+ for (const block of blocks) {
+ const dataBytes = block.getDataBytes();
+ if (i < dataBytes.length) {
+ result.appendBits(dataBytes[i], 8);
}
- return ecBytes;
+ }
}
-
- /**
- * Append mode info. On success, store the result in "bits".
- */
- public static appendModeInfo(mode: Mode, bits: BitArray): void {
- bits.appendBits(mode.getBits(), 4);
+ // Then, place error correction blocks.
+ for (let i = 0; i < maxNumEcBytes; ++i) {
+ for (const block of blocks) {
+ const ecBytes = block.getErrorCorrectionBytes();
+ if (i < ecBytes.length) {
+ result.appendBits(ecBytes[i], 8);
+ }
+ }
+ }
+ if (numTotalBytes !== result.getSizeInBytes()) { // Should be same.
+ throw new WriterException('Interleaving error: ' + numTotalBytes + ' and ' +
+ result.getSizeInBytes() + ' differ.');
}
+ return result;
+ }
- /**
- * Append length info. On success, store the result in "bits".
- */
- public static appendLengthInfo(numLetters: number /*int*/, version: Version, mode: Mode, bits: BitArray): void /*throws WriterException*/ {
- const numBits = mode.getCharacterCountBits(version);
- if (numLetters >= (1 << numBits)) {
- throw new WriterException(numLetters + ' is bigger than ' + ((1 << numBits) - 1));
- }
- bits.appendBits(numLetters, numBits);
- }
-
- /**
- * Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits".
- */
- public static appendBytes(content: string,
- mode: Mode,
- bits: BitArray,
- encoding: string): void /*throws WriterException*/ {
- switch (mode) {
- case Mode.NUMERIC:
- Encoder.appendNumericBytes(content, bits);
- break;
- case Mode.ALPHANUMERIC:
- Encoder.appendAlphanumericBytes(content, bits);
- break;
- case Mode.BYTE:
- Encoder.append8BitBytes(content, bits, encoding);
- break;
- case Mode.KANJI:
- Encoder.appendKanjiBytes(content, bits);
- break;
- default:
- throw new WriterException('Invalid mode: ' + mode);
- }
+ public static generateECBytes(dataBytes: Uint8Array, numEcBytesInBlock: number /*int*/): Uint8Array {
+ const numDataBytes = dataBytes.length;
+ const toEncode: Int32Array = new Int32Array(numDataBytes + numEcBytesInBlock); // int[numDataBytes + numEcBytesInBlock]
+ for (let i = 0; i < numDataBytes; i++) {
+ toEncode[i] = dataBytes[i] & 0xFF;
}
+ new ReedSolomonEncoder(GenericGF.QR_CODE_FIELD_256).encode(toEncode, numEcBytesInBlock);
- private static getDigit(singleCharacter: string): number {
- return singleCharacter.charCodeAt(0) - 48;
- }
-
- private static isDigit(singleCharacter: string): boolean {
- const cn = Encoder.getDigit(singleCharacter);
- return cn >= 0 && cn <= 9;
- }
-
- public static appendNumericBytes(content: string, bits: BitArray): void {
- const length = content.length;
- let i = 0;
- while (i < length) {
- const num1 = Encoder.getDigit(content.charAt(i));
- if (i + 2 < length) {
- // Encode three numeric letters in ten bits.
- const num2 = Encoder.getDigit(content.charAt(i + 1));
- const num3 = Encoder.getDigit(content.charAt(i + 2));
- bits.appendBits(num1 * 100 + num2 * 10 + num3, 10);
- i += 3;
- } else if (i + 1 < length) {
- // Encode two numeric letters in seven bits.
- const num2 = Encoder.getDigit(content.charAt(i + 1));
- bits.appendBits(num1 * 10 + num2, 7);
- i += 2;
- } else {
- // Encode one numeric letter in four bits.
- bits.appendBits(num1, 4);
- i++;
- }
- }
+ const ecBytes = new Uint8Array(numEcBytesInBlock);
+ for (let i = 0; i < numEcBytesInBlock; i++) {
+ ecBytes[i] = /*(byte) */toEncode[numDataBytes + i];
}
-
- public static appendAlphanumericBytes(content: string, bits: BitArray): void /*throws WriterException*/ {
- const length = content.length;
- let i = 0;
- while (i < length) {
- const code1 = Encoder.getAlphanumericCode(content.charCodeAt(i));
- if (code1 === -1) {
- throw new WriterException();
- }
- if (i + 1 < length) {
- const code2 = Encoder.getAlphanumericCode(content.charCodeAt(i + 1));
- if (code2 === -1) {
- throw new WriterException();
- }
- // Encode two alphanumeric letters in 11 bits.
- bits.appendBits(code1 * 45 + code2, 11);
- i += 2;
- } else {
- // Encode one alphanumeric letter in six bits.
- bits.appendBits(code1, 6);
- i++;
- }
- }
+ return ecBytes;
+ }
+
+ /**
+ * Append mode info. On success, store the result in "bits".
+ */
+ public static appendModeInfo(mode: Mode, bits: BitArray): void {
+ bits.appendBits(mode.getBits(), 4);
+ }
+
+
+ /**
+ * Append length info. On success, store the result in "bits".
+ */
+ public static appendLengthInfo(numLetters: number /*int*/, version: Version, mode: Mode, bits: BitArray): void /*throws WriterException*/ {
+ const numBits = mode.getCharacterCountBits(version);
+ if (numLetters >= (1 << numBits)) {
+ throw new WriterException(numLetters + ' is bigger than ' + ((1 << numBits) - 1));
}
-
- public static append8BitBytes(content: string, bits: BitArray, encoding: string): void {
- let bytes: Uint8Array;
- try {
- bytes = StringEncoding.encode(content, encoding);
- } catch (uee/*: UnsupportedEncodingException*/) {
- throw new WriterException(uee);
- }
- for (let i = 0, length = bytes.length; i !== length; i++) {
- const b = bytes[i];
- bits.appendBits(b, 8);
- }
+ bits.appendBits(numLetters, numBits);
+ }
+
+ /**
+ * Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits".
+ */
+ public static appendBytes(content: string,
+ mode: Mode,
+ bits: BitArray,
+ encoding: string): void /*throws WriterException*/ {
+ switch (mode) {
+ case Mode.NUMERIC:
+ Encoder.appendNumericBytes(content, bits);
+ break;
+ case Mode.ALPHANUMERIC:
+ Encoder.appendAlphanumericBytes(content, bits);
+ break;
+ case Mode.BYTE:
+ Encoder.append8BitBytes(content, bits, encoding);
+ break;
+ case Mode.KANJI:
+ Encoder.appendKanjiBytes(content, bits);
+ break;
+ default:
+ throw new WriterException('Invalid mode: ' + mode);
+ }
+ }
+
+ private static getDigit(singleCharacter: string): number {
+ return singleCharacter.charCodeAt(0) - 48;
+ }
+
+ private static isDigit(singleCharacter: string): boolean {
+ const cn = Encoder.getDigit(singleCharacter);
+ return cn >= 0 && cn <= 9;
+ }
+
+ public static appendNumericBytes(content: string, bits: BitArray): void {
+ const length = content.length;
+ let i = 0;
+ while (i < length) {
+ const num1 = Encoder.getDigit(content.charAt(i));
+ if (i + 2 < length) {
+ // Encode three numeric letters in ten bits.
+ const num2 = Encoder.getDigit(content.charAt(i + 1));
+ const num3 = Encoder.getDigit(content.charAt(i + 2));
+ bits.appendBits(num1 * 100 + num2 * 10 + num3, 10);
+ i += 3;
+ } else if (i + 1 < length) {
+ // Encode two numeric letters in seven bits.
+ const num2 = Encoder.getDigit(content.charAt(i + 1));
+ bits.appendBits(num1 * 10 + num2, 7);
+ i += 2;
+ } else {
+ // Encode one numeric letter in four bits.
+ bits.appendBits(num1, 4);
+ i++;
+ }
+ }
+ }
+
+ public static appendAlphanumericBytes(content: string, bits: BitArray): void /*throws WriterException*/ {
+ const length = content.length;
+ let i = 0;
+ while (i < length) {
+ const code1 = Encoder.getAlphanumericCode(content.charCodeAt(i));
+ if (code1 === -1) {
+ throw new WriterException();
+ }
+ if (i + 1 < length) {
+ const code2 = Encoder.getAlphanumericCode(content.charCodeAt(i + 1));
+ if (code2 === -1) {
+ throw new WriterException();
+ }
+ // Encode two alphanumeric letters in 11 bits.
+ bits.appendBits(code1 * 45 + code2, 11);
+ i += 2;
+ } else {
+ // Encode one alphanumeric letter in six bits.
+ bits.appendBits(code1, 6);
+ i++;
+ }
+ }
+ }
+
+ public static append8BitBytes(content: string, bits: BitArray, encoding: string): void {
+ let bytes: Uint8Array;
+ try {
+ bytes = StringEncoding.encode(content, encoding);
+ } catch (uee/*: UnsupportedEncodingException*/) {
+ throw new WriterException(uee);
+ }
+ for (let i = 0, length = bytes.length; i !== length; i++) {
+ const b = bytes[i];
+ bits.appendBits(b, 8);
}
+ }
- /**
- * @throws WriterException
- */
- public static appendKanjiBytes(content: string, bits: BitArray): void /*throws */ {
+ /**
+ * @throws WriterException
+ */
+ public static appendKanjiBytes(content: string, bits: BitArray): void /*throws */ {
- let bytes: Uint8Array;
+ let bytes: Uint8Array;
- try {
- bytes = StringEncoding.encode(content, CharacterSetECI.SJIS);
- } catch (uee/*: UnsupportedEncodingException*/) {
- throw new WriterException(uee);
- }
+ try {
+ bytes = StringEncoding.encode(content, CharacterSetECI.SJIS);
+ } catch (uee/*: UnsupportedEncodingException*/) {
+ throw new WriterException(uee);
+ }
- const length = bytes.length;
+ const length = bytes.length;
- for (let i = 0; i < length; i += 2) {
+ for (let i = 0; i < length; i += 2) {
- const byte1 = bytes[i] & 0xFF;
- const byte2 = bytes[i + 1] & 0xFF;
- const code = ((byte1 << 8) & 0xFFFFFFFF) | byte2;
- let subtracted = -1;
+ const byte1 = bytes[i] & 0xFF;
+ const byte2 = bytes[i + 1] & 0xFF;
+ const code = ((byte1 << 8) & 0xFFFFFFFF) | byte2;
+ let subtracted = -1;
- if (code >= 0x8140 && code <= 0x9ffc) {
- subtracted = code - 0x8140;
- } else if (code >= 0xe040 && code <= 0xebbf) {
- subtracted = code - 0xc140;
- }
+ if (code >= 0x8140 && code <= 0x9ffc) {
+ subtracted = code - 0x8140;
+ } else if (code >= 0xe040 && code <= 0xebbf) {
+ subtracted = code - 0xc140;
+ }
- if (subtracted === -1) {
- throw new WriterException('Invalid byte sequence');
- }
+ if (subtracted === -1) {
+ throw new WriterException('Invalid byte sequence');
+ }
- const encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff);
+ const encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff);
- bits.appendBits(encoded, 13);
- }
+ bits.appendBits(encoded, 13);
}
+ }
- private static appendECI(eci: CharacterSetECI, bits: BitArray): void {
- bits.appendBits(Mode.ECI.getBits(), 4);
- // This is correct for values up to 127, which is all we need now.
- bits.appendBits(eci.getValue(), 8);
- }
+ private static appendECI(eci: CharacterSetECI, bits: BitArray): void {
+ bits.appendBits(Mode.ECI.getBits(), 4);
+ // This is correct for values up to 127, which is all we need now.
+ bits.appendBits(eci.getValue(), 8);
+ }
}
diff --git a/src/core/qrcode/encoder/MaskUtil.ts b/src/core/qrcode/encoder/MaskUtil.ts
index 6e9415d6..e5842196 100644
--- a/src/core/qrcode/encoder/MaskUtil.ts
+++ b/src/core/qrcode/encoder/MaskUtil.ts
@@ -27,200 +27,200 @@ import IllegalArgumentException from '../../IllegalArgumentException';
*/
export default class MaskUtil {
- // Penalty weights from section 6.8.2.1
- private static N1 = 3;
- private static N2 = 3;
- private static N3 = 40;
- private static N4 = 10;
+ // Penalty weights from section 6.8.2.1
+ private static N1 = 3;
+ private static N2 = 3;
+ private static N3 = 40;
+ private static N4 = 10;
- private constructor() {
- // do nothing
- }
+ private constructor() {
+ // do nothing
+ }
- /**
- * Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and
- * give penalty to them. Example: 00000 or 11111.
- */
- public static applyMaskPenaltyRule1(matrix: ByteMatrix): number /*int*/ {
- return MaskUtil.applyMaskPenaltyRule1Internal(matrix, true) + MaskUtil.applyMaskPenaltyRule1Internal(matrix, false);
- }
+ /**
+ * Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and
+ * give penalty to them. Example: 00000 or 11111.
+ */
+ public static applyMaskPenaltyRule1(matrix: ByteMatrix): number /*int*/ {
+ return MaskUtil.applyMaskPenaltyRule1Internal(matrix, true) + MaskUtil.applyMaskPenaltyRule1Internal(matrix, false);
+ }
- /**
- * Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give
- * penalty to them. This is actually equivalent to the spec's rule, which is to find MxN blocks and give a
- * penalty proportional to (M-1)x(N-1), because this is the number of 2x2 blocks inside such a block.
- */
- public static applyMaskPenaltyRule2(matrix: ByteMatrix): number /*int*/ {
- let penalty = 0;
- const array: Array = matrix.getArray();
- const width: number /*int*/ = matrix.getWidth();
- const height: number /*int*/ = matrix.getHeight();
- for (let y = 0; y < height - 1; y++) {
- const arrayY = array[y];
- for (let x = 0; x < width - 1; x++) {
- const value = arrayY[x];
- if (value === arrayY[x + 1] && value === array[y + 1][x] && value === array[y + 1][x + 1]) {
- penalty++;
- }
- }
+ /**
+ * Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give
+ * penalty to them. This is actually equivalent to the spec's rule, which is to find MxN blocks and give a
+ * penalty proportional to (M-1)x(N-1), because this is the number of 2x2 blocks inside such a block.
+ */
+ public static applyMaskPenaltyRule2(matrix: ByteMatrix): number /*int*/ {
+ let penalty = 0;
+ const array: Array = matrix.getArray();
+ const width: number /*int*/ = matrix.getWidth();
+ const height: number /*int*/ = matrix.getHeight();
+ for (let y = 0; y < height - 1; y++) {
+ const arrayY = array[y];
+ for (let x = 0; x < width - 1; x++) {
+ const value = arrayY[x];
+ if (value === arrayY[x + 1] && value === array[y + 1][x] && value === array[y + 1][x + 1]) {
+ penalty++;
}
- return MaskUtil.N2 * penalty;
+ }
}
+ return MaskUtil.N2 * penalty;
+ }
- /**
- * Apply mask penalty rule 3 and return the penalty. Find consecutive runs of 1:1:3:1:1:4
- * starting with black, or 4:1:1:3:1:1 starting with white, and give penalty to them. If we
- * find patterns like 000010111010000, we give penalty once.
- */
- public static applyMaskPenaltyRule3(matrix: ByteMatrix): number /*int*/ {
- let numPenalties = 0;
- const array: Array = matrix.getArray();
- const width: number /*int*/ = matrix.getWidth();
- const height: number /*int*/ = matrix.getHeight();
- for (let y = 0; y < height; y++) {
- for (let x = 0; x < width; x++) {
- const arrayY: Uint8Array = array[y]; // We can at least optimize this access
- if (x + 6 < width &&
- arrayY[x] === 1 &&
- arrayY[x + 1] === 0 &&
- arrayY[x + 2] === 1 &&
- arrayY[x + 3] === 1 &&
- arrayY[x + 4] === 1 &&
- arrayY[x + 5] === 0 &&
- arrayY[x + 6] === 1 &&
- (MaskUtil.isWhiteHorizontal(arrayY, x - 4, x) || MaskUtil.isWhiteHorizontal(arrayY, x + 7, x + 11))) {
- numPenalties++;
- }
- if (y + 6 < height &&
- array[y][x] === 1 &&
- array[y + 1][x] === 0 &&
- array[y + 2][x] === 1 &&
- array[y + 3][x] === 1 &&
- array[y + 4][x] === 1 &&
- array[y + 5][x] === 0 &&
- array[y + 6][x] === 1 &&
- (MaskUtil.isWhiteVertical(array, x, y - 4, y) || MaskUtil.isWhiteVertical(array, x, y + 7, y + 11))) {
- numPenalties++;
- }
- }
+ /**
+ * Apply mask penalty rule 3 and return the penalty. Find consecutive runs of 1:1:3:1:1:4
+ * starting with black, or 4:1:1:3:1:1 starting with white, and give penalty to them. If we
+ * find patterns like 000010111010000, we give penalty once.
+ */
+ public static applyMaskPenaltyRule3(matrix: ByteMatrix): number /*int*/ {
+ let numPenalties = 0;
+ const array: Array = matrix.getArray();
+ const width: number /*int*/ = matrix.getWidth();
+ const height: number /*int*/ = matrix.getHeight();
+ for (let y = 0; y < height; y++) {
+ for (let x = 0; x < width; x++) {
+ const arrayY: Uint8Array = array[y]; // We can at least optimize this access
+ if (x + 6 < width &&
+ arrayY[x] === 1 &&
+ arrayY[x + 1] === 0 &&
+ arrayY[x + 2] === 1 &&
+ arrayY[x + 3] === 1 &&
+ arrayY[x + 4] === 1 &&
+ arrayY[x + 5] === 0 &&
+ arrayY[x + 6] === 1 &&
+ (MaskUtil.isWhiteHorizontal(arrayY, x - 4, x) || MaskUtil.isWhiteHorizontal(arrayY, x + 7, x + 11))) {
+ numPenalties++;
+ }
+ if (y + 6 < height &&
+ array[y][x] === 1 &&
+ array[y + 1][x] === 0 &&
+ array[y + 2][x] === 1 &&
+ array[y + 3][x] === 1 &&
+ array[y + 4][x] === 1 &&
+ array[y + 5][x] === 0 &&
+ array[y + 6][x] === 1 &&
+ (MaskUtil.isWhiteVertical(array, x, y - 4, y) || MaskUtil.isWhiteVertical(array, x, y + 7, y + 11))) {
+ numPenalties++;
}
- return numPenalties * MaskUtil.N3;
+ }
}
+ return numPenalties * MaskUtil.N3;
+ }
- private static isWhiteHorizontal(rowArray: Uint8Array, from: number /*int*/, to: number /*int*/): boolean {
- from = Math.max(from, 0);
- to = Math.min(to, rowArray.length);
- for (let i = from; i < to; i++) {
- if (rowArray[i] === 1) {
- return false;
- }
- }
- return true;
+ private static isWhiteHorizontal(rowArray: Uint8Array, from: number /*int*/, to: number /*int*/): boolean {
+ from = Math.max(from, 0);
+ to = Math.min(to, rowArray.length);
+ for (let i = from; i < to; i++) {
+ if (rowArray[i] === 1) {
+ return false;
+ }
}
+ return true;
+ }
- private static isWhiteVertical(array: Uint8Array[], col: number /*int*/, from: number /*int*/, to: number /*int*/): boolean {
- from = Math.max(from, 0);
- to = Math.min(to, array.length);
- for (let i = from; i < to; i++) {
- if (array[i][col] === 1) {
- return false;
- }
- }
- return true;
+ private static isWhiteVertical(array: Uint8Array[], col: number /*int*/, from: number /*int*/, to: number /*int*/): boolean {
+ from = Math.max(from, 0);
+ to = Math.min(to, array.length);
+ for (let i = from; i < to; i++) {
+ if (array[i][col] === 1) {
+ return false;
+ }
}
+ return true;
+ }
- /**
- * Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give
- * penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance.
- */
- public static applyMaskPenaltyRule4(matrix: ByteMatrix): number /*int*/ {
- let numDarkCells = 0;
- const array: Array = matrix.getArray();
- const width: number /*int*/ = matrix.getWidth();
- const height: number /*int*/ = matrix.getHeight();
- for (let y = 0; y < height; y++) {
- const arrayY: Uint8Array = array[y];
- for (let x = 0; x < width; x++) {
- if (arrayY[x] === 1) {
- numDarkCells++;
- }
- }
+ /**
+ * Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give
+ * penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance.
+ */
+ public static applyMaskPenaltyRule4(matrix: ByteMatrix): number /*int*/ {
+ let numDarkCells = 0;
+ const array: Array = matrix.getArray();
+ const width: number /*int*/ = matrix.getWidth();
+ const height: number /*int*/ = matrix.getHeight();
+ for (let y = 0; y < height; y++) {
+ const arrayY: Uint8Array = array[y];
+ for (let x = 0; x < width; x++) {
+ if (arrayY[x] === 1) {
+ numDarkCells++;
}
- const numTotalCells = matrix.getHeight() * matrix.getWidth();
- const fivePercentVariances = Math.floor(Math.abs(numDarkCells * 2 - numTotalCells) * 10 / numTotalCells);
- return fivePercentVariances * MaskUtil.N4;
+ }
}
+ const numTotalCells = matrix.getHeight() * matrix.getWidth();
+ const fivePercentVariances = Math.floor(Math.abs(numDarkCells * 2 - numTotalCells) * 10 / numTotalCells);
+ return fivePercentVariances * MaskUtil.N4;
+ }
- /**
- * Return the mask bit for "getMaskPattern" at "x" and "y". See 8.8 of JISX0510:2004 for mask
- * pattern conditions.
- */
- public static getDataMaskBit(maskPattern: number /*int*/, x: number /*int*/, y: number /*int*/): boolean {
- let intermediate: number; /*int*/
- let temp: number; /*int*/
- switch (maskPattern) {
- case 0:
- intermediate = (y + x) & 0x1;
- break;
- case 1:
- intermediate = y & 0x1;
- break;
- case 2:
- intermediate = x % 3;
- break;
- case 3:
- intermediate = (y + x) % 3;
- break;
- case 4:
- intermediate = (Math.floor(y / 2) + Math.floor(x / 3)) & 0x1;
- break;
- case 5:
- temp = y * x;
- intermediate = (temp & 0x1) + (temp % 3);
- break;
- case 6:
- temp = y * x;
- intermediate = ((temp & 0x1) + (temp % 3)) & 0x1;
- break;
- case 7:
- temp = y * x;
- intermediate = ((temp % 3) + ((y + x) & 0x1)) & 0x1;
- break;
- default:
- throw new IllegalArgumentException('Invalid mask pattern: ' + maskPattern);
- }
- return intermediate === 0;
+ /**
+ * Return the mask bit for "getMaskPattern" at "x" and "y". See 8.8 of JISX0510:2004 for mask
+ * pattern conditions.
+ */
+ public static getDataMaskBit(maskPattern: number /*int*/, x: number /*int*/, y: number /*int*/): boolean {
+ let intermediate: number; /*int*/
+ let temp: number; /*int*/
+ switch (maskPattern) {
+ case 0:
+ intermediate = (y + x) & 0x1;
+ break;
+ case 1:
+ intermediate = y & 0x1;
+ break;
+ case 2:
+ intermediate = x % 3;
+ break;
+ case 3:
+ intermediate = (y + x) % 3;
+ break;
+ case 4:
+ intermediate = (Math.floor(y / 2) + Math.floor(x / 3)) & 0x1;
+ break;
+ case 5:
+ temp = y * x;
+ intermediate = (temp & 0x1) + (temp % 3);
+ break;
+ case 6:
+ temp = y * x;
+ intermediate = ((temp & 0x1) + (temp % 3)) & 0x1;
+ break;
+ case 7:
+ temp = y * x;
+ intermediate = ((temp % 3) + ((y + x) & 0x1)) & 0x1;
+ break;
+ default:
+ throw new IllegalArgumentException('Invalid mask pattern: ' + maskPattern);
}
+ return intermediate === 0;
+ }
- /**
- * Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both
- * vertical and horizontal orders respectively.
- */
- private static applyMaskPenaltyRule1Internal(matrix: ByteMatrix, isHorizontal: boolean): number /*int*/ {
- let penalty = 0;
- const iLimit = isHorizontal ? matrix.getHeight() : matrix.getWidth();
- const jLimit = isHorizontal ? matrix.getWidth() : matrix.getHeight();
- const array: Array = matrix.getArray();
- for (let i = 0; i < iLimit; i++) {
- let numSameBitCells = 0;
- let prevBit = -1;
- for (let j = 0; j < jLimit; j++) {
- const bit = isHorizontal ? array[i][j] : array[j][i];
- if (bit === prevBit) {
- numSameBitCells++;
- } else {
- if (numSameBitCells >= 5) {
- penalty += MaskUtil.N1 + (numSameBitCells - 5);
- }
- numSameBitCells = 1; // Include the cell itself.
- prevBit = bit;
- }
- }
- if (numSameBitCells >= 5) {
- penalty += MaskUtil.N1 + (numSameBitCells - 5);
- }
+ /**
+ * Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both
+ * vertical and horizontal orders respectively.
+ */
+ private static applyMaskPenaltyRule1Internal(matrix: ByteMatrix, isHorizontal: boolean): number /*int*/ {
+ let penalty = 0;
+ const iLimit = isHorizontal ? matrix.getHeight() : matrix.getWidth();
+ const jLimit = isHorizontal ? matrix.getWidth() : matrix.getHeight();
+ const array: Array = matrix.getArray();
+ for (let i = 0; i < iLimit; i++) {
+ let numSameBitCells = 0;
+ let prevBit = -1;
+ for (let j = 0; j < jLimit; j++) {
+ const bit = isHorizontal ? array[i][j] : array[j][i];
+ if (bit === prevBit) {
+ numSameBitCells++;
+ } else {
+ if (numSameBitCells >= 5) {
+ penalty += MaskUtil.N1 + (numSameBitCells - 5);
+ }
+ numSameBitCells = 1; // Include the cell itself.
+ prevBit = bit;
}
- return penalty;
+ }
+ if (numSameBitCells >= 5) {
+ penalty += MaskUtil.N1 + (numSameBitCells - 5);
+ }
}
+ return penalty;
+ }
}
diff --git a/src/core/qrcode/encoder/MatrixUtil.ts b/src/core/qrcode/encoder/MatrixUtil.ts
index 55be9f25..841ee769 100644
--- a/src/core/qrcode/encoder/MatrixUtil.ts
+++ b/src/core/qrcode/encoder/MatrixUtil.ts
@@ -33,450 +33,450 @@ import IllegalArgumentException from '../../IllegalArgumentException';
*/
export default class MatrixUtil {
- private constructor() {
- // do nothing
- }
-
- private static POSITION_DETECTION_PATTERN: Array = Array.from([
- Int32Array.from([1, 1, 1, 1, 1, 1, 1]),
- Int32Array.from([1, 0, 0, 0, 0, 0, 1]),
- Int32Array.from([1, 0, 1, 1, 1, 0, 1]),
- Int32Array.from([1, 0, 1, 1, 1, 0, 1]),
- Int32Array.from([1, 0, 1, 1, 1, 0, 1]),
- Int32Array.from([1, 0, 0, 0, 0, 0, 1]),
- Int32Array.from([1, 1, 1, 1, 1, 1, 1]),
- ]);
-
- private static POSITION_ADJUSTMENT_PATTERN: Array = Array.from([
- Int32Array.from([1, 1, 1, 1, 1]),
- Int32Array.from([1, 0, 0, 0, 1]),
- Int32Array.from([1, 0, 1, 0, 1]),
- Int32Array.from([1, 0, 0, 0, 1]),
- Int32Array.from([1, 1, 1, 1, 1]),
- ]);
-
- // From Appendix E. Table 1, JIS0510X:2004 (71: p). The table was double-checked by komatsu.
- private static POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE: Array = Array.from([
- Int32Array.from([-1, -1, -1, -1, -1, -1, -1]), // Version 1
- Int32Array.from([6, 18, -1, -1, -1, -1, -1]), // Version 2
- Int32Array.from([6, 22, -1, -1, -1, -1, -1]), // Version 3
- Int32Array.from([6, 26, -1, -1, -1, -1, -1]), // Version 4
- Int32Array.from([6, 30, -1, -1, -1, -1, -1]), // Version 5
- Int32Array.from([6, 34, -1, -1, -1, -1, -1]), // Version 6
- Int32Array.from([6, 22, 38, -1, -1, -1, -1]), // Version 7
- Int32Array.from([6, 24, 42, -1, -1, -1, -1]), // Version 8
- Int32Array.from([6, 26, 46, -1, -1, -1, -1]), // Version 9
- Int32Array.from([6, 28, 50, -1, -1, -1, -1]), // Version 10
- Int32Array.from([6, 30, 54, -1, -1, -1, -1]), // Version 11
- Int32Array.from([6, 32, 58, -1, -1, -1, -1]), // Version 12
- Int32Array.from([6, 34, 62, -1, -1, -1, -1]), // Version 13
- Int32Array.from([6, 26, 46, 66, -1, -1, -1]), // Version 14
- Int32Array.from([6, 26, 48, 70, -1, -1, -1]), // Version 15
- Int32Array.from([6, 26, 50, 74, -1, -1, -1]), // Version 16
- Int32Array.from([6, 30, 54, 78, -1, -1, -1]), // Version 17
- Int32Array.from([6, 30, 56, 82, -1, -1, -1]), // Version 18
- Int32Array.from([6, 30, 58, 86, -1, -1, -1]), // Version 19
- Int32Array.from([6, 34, 62, 90, -1, -1, -1]), // Version 20
- Int32Array.from([6, 28, 50, 72, 94, -1, -1]), // Version 21
- Int32Array.from([6, 26, 50, 74, 98, -1, -1]), // Version 22
- Int32Array.from([6, 30, 54, 78, 102, -1, -1]), // Version 23
- Int32Array.from([6, 28, 54, 80, 106, -1, -1]), // Version 24
- Int32Array.from([6, 32, 58, 84, 110, -1, -1]), // Version 25
- Int32Array.from([6, 30, 58, 86, 114, -1, -1]), // Version 26
- Int32Array.from([6, 34, 62, 90, 118, -1, -1]), // Version 27
- Int32Array.from([6, 26, 50, 74, 98, 122, -1]), // Version 28
- Int32Array.from([6, 30, 54, 78, 102, 126, -1]), // Version 29
- Int32Array.from([6, 26, 52, 78, 104, 130, -1]), // Version 30
- Int32Array.from([6, 30, 56, 82, 108, 134, -1]), // Version 31
- Int32Array.from([6, 34, 60, 86, 112, 138, -1]), // Version 32
- Int32Array.from([6, 30, 58, 86, 114, 142, -1]), // Version 33
- Int32Array.from([6, 34, 62, 90, 118, 146, -1]), // Version 34
- Int32Array.from([6, 30, 54, 78, 102, 126, 150]), // Version 35
- Int32Array.from([6, 24, 50, 76, 102, 128, 154]), // Version 36
- Int32Array.from([6, 28, 54, 80, 106, 132, 158]), // Version 37
- Int32Array.from([6, 32, 58, 84, 110, 136, 162]), // Version 38
- Int32Array.from([6, 26, 54, 82, 110, 138, 166]), // Version 39
- Int32Array.from([6, 30, 58, 86, 114, 142, 170]), // Version 40
- ]);
-
- // Type info cells at the left top corner.
- private static TYPE_INFO_COORDINATES: Array = Array.from([
- Int32Array.from([8, 0]),
- Int32Array.from([8, 1]),
- Int32Array.from([8, 2]),
- Int32Array.from([8, 3]),
- Int32Array.from([8, 4]),
- Int32Array.from([8, 5]),
- Int32Array.from([8, 7]),
- Int32Array.from([8, 8]),
- Int32Array.from([7, 8]),
- Int32Array.from([5, 8]),
- Int32Array.from([4, 8]),
- Int32Array.from([3, 8]),
- Int32Array.from([2, 8]),
- Int32Array.from([1, 8]),
- Int32Array.from([0, 8]),
- ]);
-
- // From Appendix D in JISX0510:2004 (p. 67)
- private static VERSION_INFO_POLY = 0x1f25; // 1 1111 0010 0101
-
- // From Appendix C in JISX0510:2004 (p.65).
- private static TYPE_INFO_POLY = 0x537;
- private static TYPE_INFO_MASK_PATTERN = 0x5412;
-
- // Set all cells to -1 (TYPESCRIPTPORT: 255). -1 (TYPESCRIPTPORT: 255) means that the cell is empty (not set yet).
- //
- // JAVAPORT: We shouldn't need to do this at all. The code should be rewritten to begin encoding
- // with the ByteMatrix initialized all to zero.
- public static clearMatrix(matrix: ByteMatrix): void {
- // TYPESCRIPTPORT: we use UintArray se changed here from -1 to 255
- matrix.clear(/*(byte) *//*-1*/255);
+ private constructor() {
+ // do nothing
+ }
+
+ private static POSITION_DETECTION_PATTERN: Array = Array.from([
+ Int32Array.from([1, 1, 1, 1, 1, 1, 1]),
+ Int32Array.from([1, 0, 0, 0, 0, 0, 1]),
+ Int32Array.from([1, 0, 1, 1, 1, 0, 1]),
+ Int32Array.from([1, 0, 1, 1, 1, 0, 1]),
+ Int32Array.from([1, 0, 1, 1, 1, 0, 1]),
+ Int32Array.from([1, 0, 0, 0, 0, 0, 1]),
+ Int32Array.from([1, 1, 1, 1, 1, 1, 1]),
+ ]);
+
+ private static POSITION_ADJUSTMENT_PATTERN: Array = Array.from([
+ Int32Array.from([1, 1, 1, 1, 1]),
+ Int32Array.from([1, 0, 0, 0, 1]),
+ Int32Array.from([1, 0, 1, 0, 1]),
+ Int32Array.from([1, 0, 0, 0, 1]),
+ Int32Array.from([1, 1, 1, 1, 1]),
+ ]);
+
+ // From Appendix E. Table 1, JIS0510X:2004 (71: p). The table was double-checked by komatsu.
+ private static POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE: Array = Array.from([
+ Int32Array.from([-1, -1, -1, -1, -1, -1, -1]), // Version 1
+ Int32Array.from([6, 18, -1, -1, -1, -1, -1]), // Version 2
+ Int32Array.from([6, 22, -1, -1, -1, -1, -1]), // Version 3
+ Int32Array.from([6, 26, -1, -1, -1, -1, -1]), // Version 4
+ Int32Array.from([6, 30, -1, -1, -1, -1, -1]), // Version 5
+ Int32Array.from([6, 34, -1, -1, -1, -1, -1]), // Version 6
+ Int32Array.from([6, 22, 38, -1, -1, -1, -1]), // Version 7
+ Int32Array.from([6, 24, 42, -1, -1, -1, -1]), // Version 8
+ Int32Array.from([6, 26, 46, -1, -1, -1, -1]), // Version 9
+ Int32Array.from([6, 28, 50, -1, -1, -1, -1]), // Version 10
+ Int32Array.from([6, 30, 54, -1, -1, -1, -1]), // Version 11
+ Int32Array.from([6, 32, 58, -1, -1, -1, -1]), // Version 12
+ Int32Array.from([6, 34, 62, -1, -1, -1, -1]), // Version 13
+ Int32Array.from([6, 26, 46, 66, -1, -1, -1]), // Version 14
+ Int32Array.from([6, 26, 48, 70, -1, -1, -1]), // Version 15
+ Int32Array.from([6, 26, 50, 74, -1, -1, -1]), // Version 16
+ Int32Array.from([6, 30, 54, 78, -1, -1, -1]), // Version 17
+ Int32Array.from([6, 30, 56, 82, -1, -1, -1]), // Version 18
+ Int32Array.from([6, 30, 58, 86, -1, -1, -1]), // Version 19
+ Int32Array.from([6, 34, 62, 90, -1, -1, -1]), // Version 20
+ Int32Array.from([6, 28, 50, 72, 94, -1, -1]), // Version 21
+ Int32Array.from([6, 26, 50, 74, 98, -1, -1]), // Version 22
+ Int32Array.from([6, 30, 54, 78, 102, -1, -1]), // Version 23
+ Int32Array.from([6, 28, 54, 80, 106, -1, -1]), // Version 24
+ Int32Array.from([6, 32, 58, 84, 110, -1, -1]), // Version 25
+ Int32Array.from([6, 30, 58, 86, 114, -1, -1]), // Version 26
+ Int32Array.from([6, 34, 62, 90, 118, -1, -1]), // Version 27
+ Int32Array.from([6, 26, 50, 74, 98, 122, -1]), // Version 28
+ Int32Array.from([6, 30, 54, 78, 102, 126, -1]), // Version 29
+ Int32Array.from([6, 26, 52, 78, 104, 130, -1]), // Version 30
+ Int32Array.from([6, 30, 56, 82, 108, 134, -1]), // Version 31
+ Int32Array.from([6, 34, 60, 86, 112, 138, -1]), // Version 32
+ Int32Array.from([6, 30, 58, 86, 114, 142, -1]), // Version 33
+ Int32Array.from([6, 34, 62, 90, 118, 146, -1]), // Version 34
+ Int32Array.from([6, 30, 54, 78, 102, 126, 150]), // Version 35
+ Int32Array.from([6, 24, 50, 76, 102, 128, 154]), // Version 36
+ Int32Array.from([6, 28, 54, 80, 106, 132, 158]), // Version 37
+ Int32Array.from([6, 32, 58, 84, 110, 136, 162]), // Version 38
+ Int32Array.from([6, 26, 54, 82, 110, 138, 166]), // Version 39
+ Int32Array.from([6, 30, 58, 86, 114, 142, 170]), // Version 40
+ ]);
+
+ // Type info cells at the left top corner.
+ private static TYPE_INFO_COORDINATES: Array = Array.from([
+ Int32Array.from([8, 0]),
+ Int32Array.from([8, 1]),
+ Int32Array.from([8, 2]),
+ Int32Array.from([8, 3]),
+ Int32Array.from([8, 4]),
+ Int32Array.from([8, 5]),
+ Int32Array.from([8, 7]),
+ Int32Array.from([8, 8]),
+ Int32Array.from([7, 8]),
+ Int32Array.from([5, 8]),
+ Int32Array.from([4, 8]),
+ Int32Array.from([3, 8]),
+ Int32Array.from([2, 8]),
+ Int32Array.from([1, 8]),
+ Int32Array.from([0, 8]),
+ ]);
+
+ // From Appendix D in JISX0510:2004 (p. 67)
+ private static VERSION_INFO_POLY = 0x1f25; // 1 1111 0010 0101
+
+ // From Appendix C in JISX0510:2004 (p.65).
+ private static TYPE_INFO_POLY = 0x537;
+ private static TYPE_INFO_MASK_PATTERN = 0x5412;
+
+ // Set all cells to -1 (TYPESCRIPTPORT: 255). -1 (TYPESCRIPTPORT: 255) means that the cell is empty (not set yet).
+ //
+ // JAVAPORT: We shouldn't need to do this at all. The code should be rewritten to begin encoding
+ // with the ByteMatrix initialized all to zero.
+ public static clearMatrix(matrix: ByteMatrix): void {
+ // TYPESCRIPTPORT: we use UintArray se changed here from -1 to 255
+ matrix.clear(/*(byte) *//*-1*/255);
+ }
+
+ // Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On
+ // success, store the result in "matrix" and return true.
+ public static buildMatrix(dataBits: BitArray,
+ ecLevel: ErrorCorrectionLevel,
+ version: Version,
+ maskPattern: number /*int*/,
+ matrix: ByteMatrix): void /*throws WriterException*/ {
+ MatrixUtil.clearMatrix(matrix);
+ MatrixUtil.embedBasicPatterns(version, matrix);
+ // Type information appear with any version.
+ MatrixUtil.embedTypeInfo(ecLevel, maskPattern, matrix);
+ // Version info appear if version >= 7.
+ MatrixUtil.maybeEmbedVersionInfo(version, matrix);
+ // Data should be embedded at end.
+ MatrixUtil.embedDataBits(dataBits, maskPattern, matrix);
+ }
+
+ // Embed basic patterns. On success, modify the matrix and return true.
+ // The basic patterns are:
+ // - Position detection patterns
+ // - Timing patterns
+ // - Dark dot at the left bottom corner
+ // - Position adjustment patterns, if need be
+ public static embedBasicPatterns(version: Version, matrix: ByteMatrix): void /*throws WriterException*/ {
+ // Let's get started with embedding big squares at corners.
+ MatrixUtil.embedPositionDetectionPatternsAndSeparators(matrix);
+ // Then, embed the dark dot at the left bottom corner.
+ MatrixUtil.embedDarkDotAtLeftBottomCorner(matrix);
+
+ // Position adjustment patterns appear if version >= 2.
+ MatrixUtil.maybeEmbedPositionAdjustmentPatterns(version, matrix);
+ // Timing patterns should be embedded after position adj. patterns.
+ MatrixUtil.embedTimingPatterns(matrix);
+ }
+
+ // Embed type information. On success, modify the matrix.
+ public static embedTypeInfo(ecLevel: ErrorCorrectionLevel, maskPattern: number /*int*/, matrix: ByteMatrix): void {
+ const typeInfoBits: BitArray = new BitArray();
+ MatrixUtil.makeTypeInfoBits(ecLevel, maskPattern, typeInfoBits);
+
+ for (let i = 0, size = typeInfoBits.getSize(); i < size; ++i) {
+ // Place bits in LSB to MSB order. LSB (least significant bit) is the last value in
+ // "typeInfoBits".
+ const bit: boolean = typeInfoBits.get(typeInfoBits.getSize() - 1 - i);
+
+ // Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46).
+ const coordinates: Int32Array = MatrixUtil.TYPE_INFO_COORDINATES[i];
+ const x1 = coordinates[0];
+ const y1 = coordinates[1];
+ matrix.setBoolean(x1, y1, bit);
+
+ if (i < 8) {
+ // Right top corner.
+ const x2 = matrix.getWidth() - i - 1;
+ const y2 = 8;
+ matrix.setBoolean(x2, y2, bit);
+ } else {
+ // Left bottom corner.
+ const x2 = 8;
+ const y2 = matrix.getHeight() - 7 + (i - 8);
+ matrix.setBoolean(x2, y2, bit);
+ }
}
+ }
- // Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On
- // success, store the result in "matrix" and return true.
- public static buildMatrix(dataBits: BitArray,
- ecLevel: ErrorCorrectionLevel,
- version: Version,
- maskPattern: number /*int*/,
- matrix: ByteMatrix): void /*throws WriterException*/ {
- MatrixUtil.clearMatrix(matrix);
- MatrixUtil.embedBasicPatterns(version, matrix);
- // Type information appear with any version.
- MatrixUtil.embedTypeInfo(ecLevel, maskPattern, matrix);
- // Version info appear if version >= 7.
- MatrixUtil.maybeEmbedVersionInfo(version, matrix);
- // Data should be embedded at end.
- MatrixUtil.embedDataBits(dataBits, maskPattern, matrix);
+ // Embed version information if need be. On success, modify the matrix and return true.
+ // See 8.10 of JISX0510:2004 (p.47) for how to embed version information.
+ public static maybeEmbedVersionInfo(version: Version, matrix: ByteMatrix): void /*throws WriterException*/ {
+ if (version.getVersionNumber() < 7) { // Version info is necessary if version >= 7.
+ return; // Don't need version info.
}
-
- // Embed basic patterns. On success, modify the matrix and return true.
- // The basic patterns are:
- // - Position detection patterns
- // - Timing patterns
- // - Dark dot at the left bottom corner
- // - Position adjustment patterns, if need be
- public static embedBasicPatterns(version: Version, matrix: ByteMatrix): void /*throws WriterException*/ {
- // Let's get started with embedding big squares at corners.
- MatrixUtil.embedPositionDetectionPatternsAndSeparators(matrix);
- // Then, embed the dark dot at the left bottom corner.
- MatrixUtil.embedDarkDotAtLeftBottomCorner(matrix);
-
- // Position adjustment patterns appear if version >= 2.
- MatrixUtil.maybeEmbedPositionAdjustmentPatterns(version, matrix);
- // Timing patterns should be embedded after position adj. patterns.
- MatrixUtil.embedTimingPatterns(matrix);
+ const versionInfoBits = new BitArray();
+ MatrixUtil.makeVersionInfoBits(version, versionInfoBits);
+
+ let bitIndex = 6 * 3 - 1; // It will decrease from 17 to 0.
+ for (let i = 0; i < 6; ++i) {
+ for (let j = 0; j < 3; ++j) {
+ // Place bits in LSB (least significant bit) to MSB order.
+ const bit: boolean = versionInfoBits.get(bitIndex);
+ bitIndex--;
+ // Left bottom corner.
+ matrix.setBoolean(i, matrix.getHeight() - 11 + j, bit);
+ // Right bottom corner.
+ matrix.setBoolean(matrix.getHeight() - 11 + j, i, bit);
+ }
}
-
- // Embed type information. On success, modify the matrix.
- public static embedTypeInfo(ecLevel: ErrorCorrectionLevel, maskPattern: number /*int*/, matrix: ByteMatrix): void {
- const typeInfoBits: BitArray = new BitArray();
- MatrixUtil.makeTypeInfoBits(ecLevel, maskPattern, typeInfoBits);
-
- for (let i = 0, size = typeInfoBits.getSize(); i < size; ++i) {
- // Place bits in LSB to MSB order. LSB (least significant bit) is the last value in
- // "typeInfoBits".
- const bit: boolean = typeInfoBits.get(typeInfoBits.getSize() - 1 - i);
-
- // Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46).
- const coordinates: Int32Array = MatrixUtil.TYPE_INFO_COORDINATES[i];
- const x1 = coordinates[0];
- const y1 = coordinates[1];
- matrix.setBoolean(x1, y1, bit);
-
- if (i < 8) {
- // Right top corner.
- const x2 = matrix.getWidth() - i - 1;
- const y2 = 8;
- matrix.setBoolean(x2, y2, bit);
- } else {
- // Left bottom corner.
- const x2 = 8;
- const y2 = matrix.getHeight() - 7 + (i - 8);
- matrix.setBoolean(x2, y2, bit);
- }
+ }
+
+ // Embed "dataBits" using "getMaskPattern". On success, modify the matrix and return true.
+ // For debugging purposes, it skips masking process if "getMaskPattern" is -1(TYPESCRIPTPORT: 255).
+ // See 8.7 of JISX0510:2004 (p.38) for how to embed data bits.
+ public static embedDataBits(dataBits: BitArray, maskPattern: number /*int*/, matrix: ByteMatrix): void {
+ let bitIndex = 0;
+ let direction = -1;
+ // Start from the right bottom cell.
+ let x = matrix.getWidth() - 1;
+ let y = matrix.getHeight() - 1;
+ while (x > 0) {
+ // Skip the vertical timing pattern.
+ if (x === 6) {
+ x -= 1;
+ }
+ while (y >= 0 && y < matrix.getHeight()) {
+ for (let i = 0; i < 2; ++i) {
+ const xx = x - i;
+ // Skip the cell if it's not empty.
+ if (!MatrixUtil.isEmpty(matrix.get(xx, y))) {
+ continue;
+ }
+ let bit: boolean;
+ if (bitIndex < dataBits.getSize()) {
+ bit = dataBits.get(bitIndex);
+ ++bitIndex;
+ } else {
+ // Padding bit. If there is no bit left, we'll fill the left cells with 0, as described
+ // in 8.4.9 of JISX0510:2004 (p. 24).
+ bit = false;
+ }
+
+ // Skip masking if mask_pattern is -1 (TYPESCRIPTPORT: 255).
+ if (maskPattern !== 255 && MaskUtil.getDataMaskBit(maskPattern, xx, y)) {
+ bit = !bit;
+ }
+ matrix.setBoolean(xx, y, bit);
}
+ y += direction;
+ }
+ direction = -direction; // Reverse the direction.
+ y += direction;
+ x -= 2; // Move to the left.
}
-
- // Embed version information if need be. On success, modify the matrix and return true.
- // See 8.10 of JISX0510:2004 (p.47) for how to embed version information.
- public static maybeEmbedVersionInfo(version: Version, matrix: ByteMatrix): void /*throws WriterException*/ {
- if (version.getVersionNumber() < 7) { // Version info is necessary if version >= 7.
- return; // Don't need version info.
- }
- const versionInfoBits = new BitArray();
- MatrixUtil.makeVersionInfoBits(version, versionInfoBits);
-
- let bitIndex = 6 * 3 - 1; // It will decrease from 17 to 0.
- for (let i = 0; i < 6; ++i) {
- for (let j = 0; j < 3; ++j) {
- // Place bits in LSB (least significant bit) to MSB order.
- const bit: boolean = versionInfoBits.get(bitIndex);
- bitIndex--;
- // Left bottom corner.
- matrix.setBoolean(i, matrix.getHeight() - 11 + j, bit);
- // Right bottom corner.
- matrix.setBoolean(matrix.getHeight() - 11 + j, i, bit);
- }
- }
+ // All bits should be consumed.
+ if (bitIndex !== dataBits.getSize()) {
+ throw new WriterException('Not all bits consumed: ' + bitIndex + '/' + dataBits.getSize());
}
-
- // Embed "dataBits" using "getMaskPattern". On success, modify the matrix and return true.
- // For debugging purposes, it skips masking process if "getMaskPattern" is -1(TYPESCRIPTPORT: 255).
- // See 8.7 of JISX0510:2004 (p.38) for how to embed data bits.
- public static embedDataBits(dataBits: BitArray, maskPattern: number /*int*/, matrix: ByteMatrix): void {
- let bitIndex = 0;
- let direction = -1;
- // Start from the right bottom cell.
- let x = matrix.getWidth() - 1;
- let y = matrix.getHeight() - 1;
- while (x > 0) {
- // Skip the vertical timing pattern.
- if (x === 6) {
- x -= 1;
- }
- while (y >= 0 && y < matrix.getHeight()) {
- for (let i = 0; i < 2; ++i) {
- const xx = x - i;
- // Skip the cell if it's not empty.
- if (!MatrixUtil.isEmpty(matrix.get(xx, y))) {
- continue;
- }
- let bit: boolean;
- if (bitIndex < dataBits.getSize()) {
- bit = dataBits.get(bitIndex);
- ++bitIndex;
- } else {
- // Padding bit. If there is no bit left, we'll fill the left cells with 0, as described
- // in 8.4.9 of JISX0510:2004 (p. 24).
- bit = false;
- }
-
- // Skip masking if mask_pattern is -1 (TYPESCRIPTPORT: 255).
- if (maskPattern !== 255 && MaskUtil.getDataMaskBit(maskPattern, xx, y)) {
- bit = !bit;
- }
- matrix.setBoolean(xx, y, bit);
- }
- y += direction;
- }
- direction = -direction; // Reverse the direction.
- y += direction;
- x -= 2; // Move to the left.
- }
- // All bits should be consumed.
- if (bitIndex !== dataBits.getSize()) {
- throw new WriterException('Not all bits consumed: ' + bitIndex + '/' + dataBits.getSize());
- }
+ }
+
+ // Return the position of the most significant bit set (one: to) in the "value". The most
+ // significant bit is position 32. If there is no bit set, return 0. Examples:
+ // - findMSBSet(0) => 0
+ // - findMSBSet(1) => 1
+ // - findMSBSet(255) => 8
+ public static findMSBSet(value: number /*int*/): number /*int*/ {
+ return 32 - Integer.numberOfLeadingZeros(value);
+ }
+
+ // Calculate BCH (Bose-Chaudhuri-Hocquenghem) code for "value" using polynomial "poly". The BCH
+ // code is used for encoding type information and version information.
+ // Example: Calculation of version information of 7.
+ // f(x) is created from 7.
+ // - 7 = 000111 in 6 bits
+ // - f(x) = x^2 + x^1 + x^0
+ // g(x) is given by the standard (p. 67)
+ // - g(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1
+ // Multiply f(x) by x^(18 - 6)
+ // - f'(x) = f(x) * x^(18 - 6)
+ // - f'(x) = x^14 + x^13 + x^12
+ // Calculate the remainder of f'(x) / g(x)
+ // x^2
+ // __________________________________________________
+ // g(x) )x^14 + x^13 + x^12
+ // x^14 + x^13 + x^12 + x^11 + x^10 + x^7 + x^4 + x^2
+ // --------------------------------------------------
+ // x^11 + x^10 + x^7 + x^4 + x^2
+ //
+ // The remainder is x^11 + x^10 + x^7 + x^4 + x^2
+ // Encode it in binary: 110010010100
+ // The return value is 0xc94 (1100 1001 0100)
+ //
+ // Since all coefficients in the polynomials are 1 or 0, we can do the calculation by bit
+ // operations. We don't care if coefficients are positive or negative.
+ public static calculateBCHCode(value: number /*int*/, poly: number /*int*/): number /*int*/ {
+ if (poly === 0) {
+ throw new IllegalArgumentException('0 polynomial');
}
-
- // Return the position of the most significant bit set (one: to) in the "value". The most
- // significant bit is position 32. If there is no bit set, return 0. Examples:
- // - findMSBSet(0) => 0
- // - findMSBSet(1) => 1
- // - findMSBSet(255) => 8
- public static findMSBSet(value: number /*int*/): number /*int*/ {
- return 32 - Integer.numberOfLeadingZeros(value);
+ // If poly is "1 1111 0010 0101" (version info poly), msbSetInPoly is 13. We'll subtract 1
+ // from 13 to make it 12.
+ const msbSetInPoly = MatrixUtil.findMSBSet(poly);
+ value <<= msbSetInPoly - 1;
+ // Do the division business using exclusive-or operations.
+ while (MatrixUtil.findMSBSet(value) >= msbSetInPoly) {
+ value ^= poly << (MatrixUtil.findMSBSet(value) - msbSetInPoly);
}
-
- // Calculate BCH (Bose-Chaudhuri-Hocquenghem) code for "value" using polynomial "poly". The BCH
- // code is used for encoding type information and version information.
- // Example: Calculation of version information of 7.
- // f(x) is created from 7.
- // - 7 = 000111 in 6 bits
- // - f(x) = x^2 + x^1 + x^0
- // g(x) is given by the standard (p. 67)
- // - g(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1
- // Multiply f(x) by x^(18 - 6)
- // - f'(x) = f(x) * x^(18 - 6)
- // - f'(x) = x^14 + x^13 + x^12
- // Calculate the remainder of f'(x) / g(x)
- // x^2
- // __________________________________________________
- // g(x) )x^14 + x^13 + x^12
- // x^14 + x^13 + x^12 + x^11 + x^10 + x^7 + x^4 + x^2
- // --------------------------------------------------
- // x^11 + x^10 + x^7 + x^4 + x^2
- //
- // The remainder is x^11 + x^10 + x^7 + x^4 + x^2
- // Encode it in binary: 110010010100
- // The return value is 0xc94 (1100 1001 0100)
- //
- // Since all coefficients in the polynomials are 1 or 0, we can do the calculation by bit
- // operations. We don't care if coefficients are positive or negative.
- public static calculateBCHCode(value: number /*int*/, poly: number /*int*/): number /*int*/ {
- if (poly === 0) {
- throw new IllegalArgumentException('0 polynomial');
- }
- // If poly is "1 1111 0010 0101" (version info poly), msbSetInPoly is 13. We'll subtract 1
- // from 13 to make it 12.
- const msbSetInPoly = MatrixUtil.findMSBSet(poly);
- value <<= msbSetInPoly - 1;
- // Do the division business using exclusive-or operations.
- while (MatrixUtil.findMSBSet(value) >= msbSetInPoly) {
- value ^= poly << (MatrixUtil.findMSBSet(value) - msbSetInPoly);
- }
- // Now the "value" is the remainder (i.e. the BCH code)
- return value;
+ // Now the "value" is the remainder (i.e. the BCH code)
+ return value;
+ }
+
+ // Make bit vector of type information. On success, store the result in "bits" and return true.
+ // Encode error correction level and mask pattern. See 8.9 of
+ // JISX0510:2004 (p.45) for details.
+ public static makeTypeInfoBits(ecLevel: ErrorCorrectionLevel, maskPattern: number /*int*/, bits: BitArray): void {
+ if (!QRCode.isValidMaskPattern(maskPattern)) {
+ throw new WriterException('Invalid mask pattern');
}
+ const typeInfo = (ecLevel.getBits() << 3) | maskPattern;
+ bits.appendBits(typeInfo, 5);
- // Make bit vector of type information. On success, store the result in "bits" and return true.
- // Encode error correction level and mask pattern. See 8.9 of
- // JISX0510:2004 (p.45) for details.
- public static makeTypeInfoBits(ecLevel: ErrorCorrectionLevel, maskPattern: number /*int*/, bits: BitArray): void {
- if (!QRCode.isValidMaskPattern(maskPattern)) {
- throw new WriterException('Invalid mask pattern');
- }
- const typeInfo = (ecLevel.getBits() << 3) | maskPattern;
- bits.appendBits(typeInfo, 5);
+ const bchCode = MatrixUtil.calculateBCHCode(typeInfo, MatrixUtil.TYPE_INFO_POLY);
+ bits.appendBits(bchCode, 10);
- const bchCode = MatrixUtil.calculateBCHCode(typeInfo, MatrixUtil.TYPE_INFO_POLY);
- bits.appendBits(bchCode, 10);
+ const maskBits = new BitArray();
+ maskBits.appendBits(MatrixUtil.TYPE_INFO_MASK_PATTERN, 15);
+ bits.xor(maskBits);
- const maskBits = new BitArray();
- maskBits.appendBits(MatrixUtil.TYPE_INFO_MASK_PATTERN, 15);
- bits.xor(maskBits);
-
- if (bits.getSize() !== 15) { // Just in case.
- throw new WriterException('should not happen but we got: ' + bits.getSize());
- }
+ if (bits.getSize() !== 15) { // Just in case.
+ throw new WriterException('should not happen but we got: ' + bits.getSize());
}
+ }
- // Make bit vector of version information. On success, store the result in "bits" and return true.
- // See 8.10 of JISX0510:2004 (p.45) for details.
- public static makeVersionInfoBits(version: Version, bits: BitArray): void /*throws WriterException*/ {
- bits.appendBits(version.getVersionNumber(), 6);
- const bchCode = MatrixUtil.calculateBCHCode(version.getVersionNumber(), MatrixUtil.VERSION_INFO_POLY);
- bits.appendBits(bchCode, 12);
+ // Make bit vector of version information. On success, store the result in "bits" and return true.
+ // See 8.10 of JISX0510:2004 (p.45) for details.
+ public static makeVersionInfoBits(version: Version, bits: BitArray): void /*throws WriterException*/ {
+ bits.appendBits(version.getVersionNumber(), 6);
+ const bchCode = MatrixUtil.calculateBCHCode(version.getVersionNumber(), MatrixUtil.VERSION_INFO_POLY);
+ bits.appendBits(bchCode, 12);
- if (bits.getSize() !== 18) { // Just in case.
- throw new WriterException('should not happen but we got: ' + bits.getSize());
- }
+ if (bits.getSize() !== 18) { // Just in case.
+ throw new WriterException('should not happen but we got: ' + bits.getSize());
}
-
- // Check if "value" is empty.
- private static isEmpty(value: number /*int*/): boolean {
- return value === 255; // -1
+ }
+
+ // Check if "value" is empty.
+ private static isEmpty(value: number /*int*/): boolean {
+ return value === 255; // -1
+ }
+
+ private static embedTimingPatterns(matrix: ByteMatrix): void {
+ // -8 is for skipping position detection patterns (7: size), and two horizontal/vertical
+ // separation patterns (1: size). Thus, 8 = 7 + 1.
+ for (let i = 8; i < matrix.getWidth() - 8; ++i) {
+ const bit = (i + 1) % 2;
+ // Horizontal line.
+ if (MatrixUtil.isEmpty(matrix.get(i, 6))) {
+ matrix.setNumber(i, 6, bit);
+ }
+ // Vertical line.
+ if (MatrixUtil.isEmpty(matrix.get(6, i))) {
+ matrix.setNumber(6, i, bit);
+ }
}
+ }
- private static embedTimingPatterns(matrix: ByteMatrix): void {
- // -8 is for skipping position detection patterns (7: size), and two horizontal/vertical
- // separation patterns (1: size). Thus, 8 = 7 + 1.
- for (let i = 8; i < matrix.getWidth() - 8; ++i) {
- const bit = (i + 1) % 2;
- // Horizontal line.
- if (MatrixUtil.isEmpty(matrix.get(i, 6))) {
- matrix.setNumber(i, 6, bit);
- }
- // Vertical line.
- if (MatrixUtil.isEmpty(matrix.get(6, i))) {
- matrix.setNumber(6, i, bit);
- }
- }
+ // Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46)
+ private static embedDarkDotAtLeftBottomCorner(matrix: ByteMatrix): void /*throws WriterException*/ {
+ if (matrix.get(8, matrix.getHeight() - 8) === 0) {
+ throw new WriterException();
}
-
- // Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46)
- private static embedDarkDotAtLeftBottomCorner(matrix: ByteMatrix): void /*throws WriterException*/ {
- if (matrix.get(8, matrix.getHeight() - 8) === 0) {
- throw new WriterException();
- }
- matrix.setNumber(8, matrix.getHeight() - 8, 1);
+ matrix.setNumber(8, matrix.getHeight() - 8, 1);
+ }
+
+ private static embedHorizontalSeparationPattern(xStart: number /*int*/,
+ yStart: number /*int*/,
+ matrix: ByteMatrix): void /*throws WriterException*/ {
+ for (let x = 0; x < 8; ++x) {
+ if (!MatrixUtil.isEmpty(matrix.get(xStart + x, yStart))) {
+ throw new WriterException();
+ }
+ matrix.setNumber(xStart + x, yStart, 0);
}
-
- private static embedHorizontalSeparationPattern(xStart: number /*int*/,
- yStart: number /*int*/,
- matrix: ByteMatrix): void /*throws WriterException*/ {
- for (let x = 0; x < 8; ++x) {
- if (!MatrixUtil.isEmpty(matrix.get(xStart + x, yStart))) {
- throw new WriterException();
- }
- matrix.setNumber(xStart + x, yStart, 0);
- }
+ }
+
+ private static embedVerticalSeparationPattern(xStart: number /*int*/,
+ yStart: number /*int*/,
+ matrix: ByteMatrix): void /*throws WriterException*/ {
+ for (let y = 0; y < 7; ++y) {
+ if (!MatrixUtil.isEmpty(matrix.get(xStart, yStart + y))) {
+ throw new WriterException();
+ }
+ matrix.setNumber(xStart, yStart + y, 0);
}
-
- private static embedVerticalSeparationPattern(xStart: number /*int*/,
- yStart: number /*int*/,
- matrix: ByteMatrix): void /*throws WriterException*/ {
- for (let y = 0; y < 7; ++y) {
- if (!MatrixUtil.isEmpty(matrix.get(xStart, yStart + y))) {
- throw new WriterException();
- }
- matrix.setNumber(xStart, yStart + y, 0);
- }
+ }
+
+ private static embedPositionAdjustmentPattern(xStart: number /*int*/, yStart: number /*int*/, matrix: ByteMatrix): void {
+ for (let y = 0; y < 5; ++y) {
+ const patternY: Int32Array = MatrixUtil.POSITION_ADJUSTMENT_PATTERN[y];
+ for (let x = 0; x < 5; ++x) {
+ matrix.setNumber(xStart + x, yStart + y, patternY[x]);
+ }
}
-
- private static embedPositionAdjustmentPattern(xStart: number /*int*/, yStart: number /*int*/, matrix: ByteMatrix): void {
- for (let y = 0; y < 5; ++y) {
- const patternY: Int32Array = MatrixUtil.POSITION_ADJUSTMENT_PATTERN[y];
- for (let x = 0; x < 5; ++x) {
- matrix.setNumber(xStart + x, yStart + y, patternY[x]);
- }
- }
- }
-
- private static embedPositionDetectionPattern(xStart: number /*int*/, yStart: number /*int*/, matrix: ByteMatrix): void {
- for (let y = 0; y < 7; ++y) {
- const patternY: Int32Array = MatrixUtil.POSITION_DETECTION_PATTERN[y];
- for (let x = 0; x < 7; ++x) {
- matrix.setNumber(xStart + x, yStart + y, patternY[x]);
- }
- }
+ }
+
+ private static embedPositionDetectionPattern(xStart: number /*int*/, yStart: number /*int*/, matrix: ByteMatrix): void {
+ for (let y = 0; y < 7; ++y) {
+ const patternY: Int32Array = MatrixUtil.POSITION_DETECTION_PATTERN[y];
+ for (let x = 0; x < 7; ++x) {
+ matrix.setNumber(xStart + x, yStart + y, patternY[x]);
+ }
}
-
- // Embed position detection patterns and surrounding vertical/horizontal separators.
- private static embedPositionDetectionPatternsAndSeparators(matrix: ByteMatrix): void /*throws WriterException*/ {
- // Embed three big squares at corners.
- const pdpWidth = MatrixUtil.POSITION_DETECTION_PATTERN[0].length;
- // Left top corner.
- MatrixUtil.embedPositionDetectionPattern(0, 0, matrix);
- // Right top corner.
- MatrixUtil.embedPositionDetectionPattern(matrix.getWidth() - pdpWidth, 0, matrix);
- // Left bottom corner.
- MatrixUtil.embedPositionDetectionPattern(0, matrix.getWidth() - pdpWidth, matrix);
-
- // Embed horizontal separation patterns around the squares.
- const hspWidth = 8;
- // Left top corner.
- MatrixUtil.embedHorizontalSeparationPattern(0, hspWidth - 1, matrix);
- // Right top corner.
- MatrixUtil.embedHorizontalSeparationPattern(matrix.getWidth() - hspWidth,
- hspWidth - 1, matrix);
- // Left bottom corner.
- MatrixUtil.embedHorizontalSeparationPattern(0, matrix.getWidth() - hspWidth, matrix);
-
- // Embed vertical separation patterns around the squares.
- const vspSize = 7;
- // Left top corner.
- MatrixUtil.embedVerticalSeparationPattern(vspSize, 0, matrix);
- // Right top corner.
- MatrixUtil.embedVerticalSeparationPattern(matrix.getHeight() - vspSize - 1, 0, matrix);
- // Left bottom corner.
- MatrixUtil.embedVerticalSeparationPattern(vspSize, matrix.getHeight() - vspSize,
- matrix);
+ }
+
+ // Embed position detection patterns and surrounding vertical/horizontal separators.
+ private static embedPositionDetectionPatternsAndSeparators(matrix: ByteMatrix): void /*throws WriterException*/ {
+ // Embed three big squares at corners.
+ const pdpWidth = MatrixUtil.POSITION_DETECTION_PATTERN[0].length;
+ // Left top corner.
+ MatrixUtil.embedPositionDetectionPattern(0, 0, matrix);
+ // Right top corner.
+ MatrixUtil.embedPositionDetectionPattern(matrix.getWidth() - pdpWidth, 0, matrix);
+ // Left bottom corner.
+ MatrixUtil.embedPositionDetectionPattern(0, matrix.getWidth() - pdpWidth, matrix);
+
+ // Embed horizontal separation patterns around the squares.
+ const hspWidth = 8;
+ // Left top corner.
+ MatrixUtil.embedHorizontalSeparationPattern(0, hspWidth - 1, matrix);
+ // Right top corner.
+ MatrixUtil.embedHorizontalSeparationPattern(matrix.getWidth() - hspWidth,
+ hspWidth - 1, matrix);
+ // Left bottom corner.
+ MatrixUtil.embedHorizontalSeparationPattern(0, matrix.getWidth() - hspWidth, matrix);
+
+ // Embed vertical separation patterns around the squares.
+ const vspSize = 7;
+ // Left top corner.
+ MatrixUtil.embedVerticalSeparationPattern(vspSize, 0, matrix);
+ // Right top corner.
+ MatrixUtil.embedVerticalSeparationPattern(matrix.getHeight() - vspSize - 1, 0, matrix);
+ // Left bottom corner.
+ MatrixUtil.embedVerticalSeparationPattern(vspSize, matrix.getHeight() - vspSize,
+ matrix);
+ }
+
+ // Embed position adjustment patterns if need be.
+ private static maybeEmbedPositionAdjustmentPatterns(version: Version, matrix: ByteMatrix): void {
+ if (version.getVersionNumber() < 2) { // The patterns appear if version >= 2
+ return;
}
-
- // Embed position adjustment patterns if need be.
- private static maybeEmbedPositionAdjustmentPatterns(version: Version, matrix: ByteMatrix): void {
- if (version.getVersionNumber() < 2) { // The patterns appear if version >= 2
- return;
- }
- const index = version.getVersionNumber() - 1;
- const coordinates: Int32Array = MatrixUtil.POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index];
- for (let i = 0, length = coordinates.length; i !== length; i++) {
- const y = coordinates[i];
- if (y >= 0) {
- for (let j = 0; j !== length; j++) {
- const x = coordinates[j];
- if (x >= 0 && MatrixUtil.isEmpty(matrix.get(x, y))) {
- // If the cell is unset, we embed the position adjustment pattern here.
- // -2 is necessary since the x/y coordinates point to the center of the pattern, not the
- // left top corner.
- MatrixUtil.embedPositionAdjustmentPattern(x - 2, y - 2, matrix);
- }
- }
- }
+ const index = version.getVersionNumber() - 1;
+ const coordinates: Int32Array = MatrixUtil.POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index];
+ for (let i = 0, length = coordinates.length; i !== length; i++) {
+ const y = coordinates[i];
+ if (y >= 0) {
+ for (let j = 0; j !== length; j++) {
+ const x = coordinates[j];
+ if (x >= 0 && MatrixUtil.isEmpty(matrix.get(x, y))) {
+ // If the cell is unset, we embed the position adjustment pattern here.
+ // -2 is necessary since the x/y coordinates point to the center of the pattern, not the
+ // left top corner.
+ MatrixUtil.embedPositionAdjustmentPattern(x - 2, y - 2, matrix);
+ }
}
+ }
}
+ }
}
diff --git a/src/core/qrcode/encoder/QRCode.ts b/src/core/qrcode/encoder/QRCode.ts
index 64968ae2..874bdbf8 100644
--- a/src/core/qrcode/encoder/QRCode.ts
+++ b/src/core/qrcode/encoder/QRCode.ts
@@ -28,83 +28,83 @@ import ByteMatrix from './ByteMatrix';
*/
export default class QRCode {
- public static NUM_MASK_PATTERNS = 8;
-
- private mode: Mode;
- private ecLevel: ErrorCorrectionLevel;
- private version: Version;
- private maskPattern: number; /*int*/
- private matrix: ByteMatrix;
-
- public constructor() {
- this.maskPattern = -1;
- }
-
- public getMode(): Mode {
- return this.mode;
- }
-
- public getECLevel(): ErrorCorrectionLevel {
- return this.ecLevel;
- }
-
- public getVersion(): Version {
- return this.version;
- }
-
- public getMaskPattern(): number /*int*/ {
- return this.maskPattern;
- }
-
- public getMatrix(): ByteMatrix {
- return this.matrix;
- }
-
- /*@Override*/
- public toString(): string {
- const result = new StringBuilder(); // (200)
- result.append('<<\n');
- result.append(' mode: ');
- result.append(this.mode ? this.mode.toString() : 'null');
- result.append('\n ecLevel: ');
- result.append(this.ecLevel ? this.ecLevel.toString() : 'null');
- result.append('\n version: ');
- result.append(this.version ? this.version.toString() : 'null');
- result.append('\n maskPattern: ');
- result.append(this.maskPattern.toString());
- if (this.matrix) {
- result.append('\n matrix:\n');
- result.append(this.matrix.toString());
- } else {
- result.append('\n matrix: null\n');
- }
- result.append('>>\n');
- return result.toString();
- }
-
- public setMode(value: Mode): void {
- this.mode = value;
- }
-
- public setECLevel(value: ErrorCorrectionLevel): void {
- this.ecLevel = value;
- }
-
- public setVersion(version: Version): void {
- this.version = version;
- }
-
- public setMaskPattern(value: number /*int*/): void {
- this.maskPattern = value;
- }
-
- public setMatrix(value: ByteMatrix): void {
- this.matrix = value;
- }
-
- // Check if "mask_pattern" is valid.
- public static isValidMaskPattern(maskPattern: number /*int*/): boolean {
- return maskPattern >= 0 && maskPattern < QRCode.NUM_MASK_PATTERNS;
+ public static NUM_MASK_PATTERNS = 8;
+
+ private mode: Mode;
+ private ecLevel: ErrorCorrectionLevel;
+ private version: Version;
+ private maskPattern: number; /*int*/
+ private matrix: ByteMatrix;
+
+ public constructor() {
+ this.maskPattern = -1;
+ }
+
+ public getMode(): Mode {
+ return this.mode;
+ }
+
+ public getECLevel(): ErrorCorrectionLevel {
+ return this.ecLevel;
+ }
+
+ public getVersion(): Version {
+ return this.version;
+ }
+
+ public getMaskPattern(): number /*int*/ {
+ return this.maskPattern;
+ }
+
+ public getMatrix(): ByteMatrix {
+ return this.matrix;
+ }
+
+ /*@Override*/
+ public toString(): string {
+ const result = new StringBuilder(); // (200)
+ result.append('<<\n');
+ result.append(' mode: ');
+ result.append(this.mode ? this.mode.toString() : 'null');
+ result.append('\n ecLevel: ');
+ result.append(this.ecLevel ? this.ecLevel.toString() : 'null');
+ result.append('\n version: ');
+ result.append(this.version ? this.version.toString() : 'null');
+ result.append('\n maskPattern: ');
+ result.append(this.maskPattern.toString());
+ if (this.matrix) {
+ result.append('\n matrix:\n');
+ result.append(this.matrix.toString());
+ } else {
+ result.append('\n matrix: null\n');
}
+ result.append('>>\n');
+ return result.toString();
+ }
+
+ public setMode(value: Mode): void {
+ this.mode = value;
+ }
+
+ public setECLevel(value: ErrorCorrectionLevel): void {
+ this.ecLevel = value;
+ }
+
+ public setVersion(version: Version): void {
+ this.version = version;
+ }
+
+ public setMaskPattern(value: number /*int*/): void {
+ this.maskPattern = value;
+ }
+
+ public setMatrix(value: ByteMatrix): void {
+ this.matrix = value;
+ }
+
+ // Check if "mask_pattern" is valid.
+ public static isValidMaskPattern(maskPattern: number /*int*/): boolean {
+ return maskPattern >= 0 && maskPattern < QRCode.NUM_MASK_PATTERNS;
+ }
}
diff --git a/src/core/util/System.ts b/src/core/util/System.ts
index ff8586d3..e3998b42 100644
--- a/src/core/util/System.ts
+++ b/src/core/util/System.ts
@@ -1,20 +1,20 @@
export default class System {
- // public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
- /**
- * Makes a copy of a array.
- */
- public static arraycopy(src: any, srcPos: number, dest: any, destPos: number, length: number): void {
- // TODO: better use split or set?
- while (length--) {
- dest[destPos++] = src[srcPos++];
- }
+ // public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
+ /**
+ * Makes a copy of a array.
+ */
+ public static arraycopy(src: any, srcPos: number, dest: any, destPos: number, length: number): void {
+ // TODO: better use split or set?
+ while (length--) {
+ dest[destPos++] = src[srcPos++];
}
+ }
- /**
- * Returns the current time in milliseconds.
- */
- public static currentTimeMillis(): number {
- return Date.now();
- }
+ /**
+ * Returns the current time in milliseconds.
+ */
+ public static currentTimeMillis(): number {
+ return Date.now();
+ }
}
diff --git a/src/test/core/PlanarYUVLuminanceSource.spec.ts b/src/test/core/PlanarYUVLuminanceSource.spec.ts
index e40bc02a..fa717263 100644
--- a/src/test/core/PlanarYUVLuminanceSource.spec.ts
+++ b/src/test/core/PlanarYUVLuminanceSource.spec.ts
@@ -23,56 +23,56 @@ import { ZXingSystem } from '@zxing/library';
describe('PlanarYUVLuminanceSource', () => {
- const YUV: Uint8ClampedArray = Uint8ClampedArray.from([
- 0, 1, 1, 2, 3, 5,
- 8, 13, 21, 34, 55, 89,
- 0, -1, -1, -2, -3, -5,
- -8, -13, -21, -34, -55, -89,
- 127, 127, 127, 127, 127, 127,
- 127, 127, 127, 127, 127, 127,
- ]);
+ const YUV: Uint8ClampedArray = Uint8ClampedArray.from([
+ 0, 1, 1, 2, 3, 5,
+ 8, 13, 21, 34, 55, 89,
+ 0, -1, -1, -2, -3, -5,
+ -8, -13, -21, -34, -55, -89,
+ 127, 127, 127, 127, 127, 127,
+ 127, 127, 127, 127, 127, 127,
+ ]);
- const COLS: number /*int*/ = 6;
- const ROWS: number /*int*/ = 4;
- const Y = new Uint8ClampedArray(COLS * ROWS);
+ const COLS: number /*int*/ = 6;
+ const ROWS: number /*int*/ = 4;
+ const Y = new Uint8ClampedArray(COLS * ROWS);
- ZXingSystem.arraycopy(YUV, 0, Y, 0, Y.length);
+ ZXingSystem.arraycopy(YUV, 0, Y, 0, Y.length);
- it('testNoCrop', () => {
- const source = new PlanarYUVLuminanceSource(YUV, COLS, ROWS, 0, 0, COLS, ROWS, false);
- assertTypedArrayEquals(Y, 0, source.getMatrix(), 0, Y.length);
- for (let r: number /*int*/ = 0; r < ROWS; r++) {
- assertTypedArrayEquals(Y, r * COLS, source.getRow(r, null), 0, COLS);
- }
- });
+ it('testNoCrop', () => {
+ const source = new PlanarYUVLuminanceSource(YUV, COLS, ROWS, 0, 0, COLS, ROWS, false);
+ assertTypedArrayEquals(Y, 0, source.getMatrix(), 0, Y.length);
+ for (let r: number /*int*/ = 0; r < ROWS; r++) {
+ assertTypedArrayEquals(Y, r * COLS, source.getRow(r, null), 0, COLS);
+ }
+ });
- it('testCrop', () => {
- const source =
- new PlanarYUVLuminanceSource(YUV, COLS, ROWS, 1, 1, COLS - 2, ROWS - 2, false);
- assert.strictEqual(source.isCropSupported(), true);
- const cropMatrix: Uint8ClampedArray = source.getMatrix();
- for (let r: number /*int*/ = 0; r < ROWS - 2; r++) {
- assertTypedArrayEquals(Y, (r + 1) * COLS + 1, cropMatrix, r * (COLS - 2), COLS - 2);
- }
- for (let r: number /*int*/ = 0; r < ROWS - 2; r++) {
- assertTypedArrayEquals(Y, (r + 1) * COLS + 1, source.getRow(r, null), 0, COLS - 2);
- }
- });
+ it('testCrop', () => {
+ const source =
+ new PlanarYUVLuminanceSource(YUV, COLS, ROWS, 1, 1, COLS - 2, ROWS - 2, false);
+ assert.strictEqual(source.isCropSupported(), true);
+ const cropMatrix: Uint8ClampedArray = source.getMatrix();
+ for (let r: number /*int*/ = 0; r < ROWS - 2; r++) {
+ assertTypedArrayEquals(Y, (r + 1) * COLS + 1, cropMatrix, r * (COLS - 2), COLS - 2);
+ }
+ for (let r: number /*int*/ = 0; r < ROWS - 2; r++) {
+ assertTypedArrayEquals(Y, (r + 1) * COLS + 1, source.getRow(r, null), 0, COLS - 2);
+ }
+ });
- it('testThumbnail', () => {
- const source =
- new PlanarYUVLuminanceSource(YUV, COLS, ROWS, 0, 0, COLS, ROWS, false);
- AssertUtils.typedArraysAreEqual(
- Int32Array.from([0xFF000000, 0xFF010101, 0xFF030303, 0xFF000000, 0xFFFFFFFF, 0xFFFDFDFD]),
- source.renderThumbnail());
- });
+ it('testThumbnail', () => {
+ const source =
+ new PlanarYUVLuminanceSource(YUV, COLS, ROWS, 0, 0, COLS, ROWS, false);
+ AssertUtils.typedArraysAreEqual(
+ Int32Array.from([0xFF000000, 0xFF010101, 0xFF030303, 0xFF000000, 0xFFFFFFFF, 0xFFFDFDFD]),
+ source.renderThumbnail());
+ });
- function assertTypedArrayEquals(expected: Uint8ClampedArray, expectedFrom: number /*int*/,
- actual: Uint8ClampedArray, actualFrom: number /*int*/,
- length: number /*int*/) {
- for (let i: number /*int*/ = 0; i < length; i++) {
- assert.strictEqual(actual[actualFrom + i], expected[expectedFrom + i]);
- }
+ function assertTypedArrayEquals(expected: Uint8ClampedArray, expectedFrom: number /*int*/,
+ actual: Uint8ClampedArray, actualFrom: number /*int*/,
+ length: number /*int*/) {
+ for (let i: number /*int*/ = 0; i < length; i++) {
+ assert.strictEqual(actual[actualFrom + i], expected[expectedFrom + i]);
}
+ }
});
diff --git a/src/test/core/RGBLuminanceSource.spec.ts b/src/test/core/RGBLuminanceSource.spec.ts
index d9f05e54..70b11afb 100644
--- a/src/test/core/RGBLuminanceSource.spec.ts
+++ b/src/test/core/RGBLuminanceSource.spec.ts
@@ -23,36 +23,36 @@ import { RGBLuminanceSource } from '@zxing/library';
describe('RGBLuminanceSource', () => {
- const SOURCE = new RGBLuminanceSource(Int32Array.from([
- 0x000000, 0x7F7F7F, 0xFFFFFF,
- 0xFF0000, 0x00FF00, 0x0000FF,
- 0x0000FF, 0x00FF00, 0xFF0000]), 3, 3);
-
- it('testCrop', () => {
- assert.strictEqual(SOURCE.isCropSupported(), true);
- const cropped: LuminanceSource = SOURCE.crop(1, 1, 1, 1);
- assert.strictEqual(cropped.getHeight(), 1);
- assert.strictEqual(cropped.getWidth(), 1);
- assert.strictEqual(AssertUtils.typedArraysAreEqual(Uint8ClampedArray.from([0x7F]), cropped.getRow(0, null)), true);
- });
-
- it('testMatrix', () => {
- assert.strictEqual(AssertUtils.typedArraysAreEqual(Uint8ClampedArray.from([0x00, 0x7F, 0xFF, 0x3F, 0x7F, 0x3F, 0x3F, 0x7F, 0x3F]),
- SOURCE.getMatrix()), true);
- const croppedFullWidth: LuminanceSource = SOURCE.crop(0, 1, 3, 2);
- assert.strictEqual(AssertUtils.typedArraysAreEqual(Uint8ClampedArray.from([0x3F, 0x7F, 0x3F, 0x3F, 0x7F, 0x3F]),
- croppedFullWidth.getMatrix()), true);
- const croppedCorner: LuminanceSource = SOURCE.crop(1, 1, 2, 2);
- assert.strictEqual(AssertUtils.typedArraysAreEqual(Uint8ClampedArray.from([0x7F, 0x3F, 0x7F, 0x3F]),
- croppedCorner.getMatrix()), true);
- });
-
- it('testGetRow', () => {
- assert.strictEqual(AssertUtils.typedArraysAreEqual(Uint8ClampedArray.from([0x3F, 0x7F, 0x3F]), SOURCE.getRow(2, new Uint8ClampedArray(3))), true);
- });
-
- it('testToString', () => {
- assert.strictEqual(SOURCE.toString(), '#+ \n#+#\n#+#\n');
- });
+ const SOURCE = new RGBLuminanceSource(Int32Array.from([
+ 0x000000, 0x7F7F7F, 0xFFFFFF,
+ 0xFF0000, 0x00FF00, 0x0000FF,
+ 0x0000FF, 0x00FF00, 0xFF0000]), 3, 3);
+
+ it('testCrop', () => {
+ assert.strictEqual(SOURCE.isCropSupported(), true);
+ const cropped: LuminanceSource = SOURCE.crop(1, 1, 1, 1);
+ assert.strictEqual(cropped.getHeight(), 1);
+ assert.strictEqual(cropped.getWidth(), 1);
+ assert.strictEqual(AssertUtils.typedArraysAreEqual(Uint8ClampedArray.from([0x7F]), cropped.getRow(0, null)), true);
+ });
+
+ it('testMatrix', () => {
+ assert.strictEqual(AssertUtils.typedArraysAreEqual(Uint8ClampedArray.from([0x00, 0x7F, 0xFF, 0x3F, 0x7F, 0x3F, 0x3F, 0x7F, 0x3F]),
+ SOURCE.getMatrix()), true);
+ const croppedFullWidth: LuminanceSource = SOURCE.crop(0, 1, 3, 2);
+ assert.strictEqual(AssertUtils.typedArraysAreEqual(Uint8ClampedArray.from([0x3F, 0x7F, 0x3F, 0x3F, 0x7F, 0x3F]),
+ croppedFullWidth.getMatrix()), true);
+ const croppedCorner: LuminanceSource = SOURCE.crop(1, 1, 2, 2);
+ assert.strictEqual(AssertUtils.typedArraysAreEqual(Uint8ClampedArray.from([0x7F, 0x3F, 0x7F, 0x3F]),
+ croppedCorner.getMatrix()), true);
+ });
+
+ it('testGetRow', () => {
+ assert.strictEqual(AssertUtils.typedArraysAreEqual(Uint8ClampedArray.from([0x3F, 0x7F, 0x3F]), SOURCE.getRow(2, new Uint8ClampedArray(3))), true);
+ });
+
+ it('testToString', () => {
+ assert.strictEqual(SOURCE.toString(), '#+ \n#+#\n#+#\n');
+ });
});
diff --git a/src/test/core/aztec/AztecBlackBox1.spec.ts b/src/test/core/aztec/AztecBlackBox1.spec.ts
index b4c5bb98..fe2a7ad6 100644
--- a/src/test/core/aztec/AztecBlackBox1.spec.ts
+++ b/src/test/core/aztec/AztecBlackBox1.spec.ts
@@ -39,8 +39,8 @@ export /*public final*/ class AztecBlackBox1TestCase extends AbstractBlackBoxSpe
}
describe('AztecBlackBox.1', () => {
- it('testBlackBox', async () => {
- const test = new AztecBlackBox1TestCase();
- await test.testBlackBox();
- });
+ it('testBlackBox', async () => {
+ const test = new AztecBlackBox1TestCase();
+ await test.testBlackBox();
+ });
});
diff --git a/src/test/core/aztec/AztecBlackBox2.spec.ts b/src/test/core/aztec/AztecBlackBox2.spec.ts
index a650ef24..24e08c5b 100644
--- a/src/test/core/aztec/AztecBlackBox2.spec.ts
+++ b/src/test/core/aztec/AztecBlackBox2.spec.ts
@@ -41,8 +41,8 @@ export /*public final*/ class AztecBlackBox2TestCase extends AbstractBlackBoxSpe
}
describe('AztecBlackBox.2', () => {
- it('testBlackBox', async () => {
- const test = new AztecBlackBox2TestCase();
- await test.testBlackBox();
- });
+ it('testBlackBox', async () => {
+ const test = new AztecBlackBox2TestCase();
+ await test.testBlackBox();
+ });
});
diff --git a/src/test/core/aztec/decoder/Decoder.spec.ts b/src/test/core/aztec/decoder/Decoder.spec.ts
index 415d8ce7..9f5ed48f 100644
--- a/src/test/core/aztec/decoder/Decoder.spec.ts
+++ b/src/test/core/aztec/decoder/Decoder.spec.ts
@@ -35,152 +35,152 @@ import { FormatException } from '@zxing/library';
*/
describe('DecoderTest', () => {
- const NO_POINTS: ResultPoint[] = [];
+ const NO_POINTS: ResultPoint[] = [];
- /**
- * @Test
- * @throws FormatException
- */
- it('testAztecResult', () => {
- const matrix = BitMatrix.parseFromString(
- 'X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X \n' +
- ' X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X \n',
- 'X ', ' ');
- const r = new AztecDetectorResult(matrix, NO_POINTS, false, 30, 2);
- const result = new AztecDecoder().decode(r);
- assertEquals('88888TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT', result.getText());
- assertArrayEquals(
- new Uint8Array([- 11, 85, 85, 117, 107, 90, -42, -75, -83, 107,
- 90, -42, -75, -83, 107, 90, -42, -75, -83, 107,
- 90, -42, -80]),
- result.getRawBytes());
- assertEquals(180, result.getNumBits());
- });
+ /**
+ * @Test
+ * @throws FormatException
+ */
+ it('testAztecResult', () => {
+ const matrix = BitMatrix.parseFromString(
+ 'X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X \n' +
+ ' X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X \n',
+ 'X ', ' ');
+ const r = new AztecDetectorResult(matrix, NO_POINTS, false, 30, 2);
+ const result = new AztecDecoder().decode(r);
+ assertEquals('88888TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT', result.getText());
+ assertArrayEquals(
+ new Uint8Array([- 11, 85, 85, 117, 107, 90, -42, -75, -83, 107,
+ 90, -42, -75, -83, 107, 90, -42, -75, -83, 107,
+ 90, -42, -80]),
+ result.getRawBytes());
+ assertEquals(180, result.getNumBits());
+ });
- /**
- * @Test(expected = FormatException.class)
- * throws FormatException
- */
- it('testDecodeTooManyErrors', () => {
- const matrix = BitMatrix.parseFromString(''
- + 'X X . X . . . X X . . . X . . X X X . X . X X X X X . \n'
- + 'X X . . X X . . . . . X X . . . X X . . . X . X . . X \n'
- + 'X . . . X X . . X X X . X X . X X X X . X X . . X . . \n'
- + '. . . . X . X X . . X X . X X . X . X X X X . X . . X \n'
- + 'X X X . . X X X X X . . . . . X X . . . X . X . X . X \n'
- + 'X X . . . . . . . . X . . . X . X X X . X . . X . . . \n'
- + 'X X . . X . . . . . X X . . . . . X . . . . X . . X X \n'
- + '. . . X . X . X . . . . . X X X X X X . . . . . . X X \n'
- + 'X . . . X . X X X X X X . . X X X . X . X X X X X X . \n'
- + 'X . . X X X . X X X X X X X X X X X X X . . . X . X X \n'
- + '. . . . X X . . . X . . . . . . . X X . . . X X . X . \n'
- + '. . . X X X . . X X . X X X X X . X . . X . . . . . . \n'
- + 'X . . . . X . X . X . X . . . X . X . X X . X X . X X \n'
- + 'X . X . . X . X . X . X . X . X . X . . . . . X . X X \n'
- + 'X . X X X . . X . X . X . . . X . X . X X X . . . X X \n'
- + 'X X X X X X X X . X . X X X X X . X . X . X . X X X . \n'
- + '. . . . . . . X . X . . . . . . . X X X X . . . X X X \n'
- + 'X X . . X . . X . X X X X X X X X X X X X X . . X . X \n'
- + 'X X X . X X X X . . X X X X . . X . . . . X . . X X X \n'
- + '. . . . X . X X X . . . . X X X X . . X X X X . . . . \n'
- + '. . X . . X . X . . . X . X X . X X . X . . . X . X . \n'
- + 'X X . . X . . X X X X X X X . . X . X X X X X X X . . \n'
- + 'X . X X . . X X . . . . . X . . . . . . X X . X X X . \n'
- + 'X . . X X . . X X . X . X . . . . X . X . . X . . X . \n'
- + 'X . X . X . . X . X X X X X X X X . X X X X . . X X . \n'
- + 'X X X X . . . X . . X X X . X X . . X . . . . X X X . \n'
- + 'X X . X . X . . . X . X . . . . X X . X . . X X . . . \n',
- 'X ', '. ');
- const r = new AztecDetectorResult(matrix, NO_POINTS, true, 16, 4);
- assertThrow(() => new AztecDecoder().decode(r), FormatException);
- });
+ /**
+ * @Test(expected = FormatException.class)
+ * throws FormatException
+ */
+ it('testDecodeTooManyErrors', () => {
+ const matrix = BitMatrix.parseFromString(''
+ + 'X X . X . . . X X . . . X . . X X X . X . X X X X X . \n'
+ + 'X X . . X X . . . . . X X . . . X X . . . X . X . . X \n'
+ + 'X . . . X X . . X X X . X X . X X X X . X X . . X . . \n'
+ + '. . . . X . X X . . X X . X X . X . X X X X . X . . X \n'
+ + 'X X X . . X X X X X . . . . . X X . . . X . X . X . X \n'
+ + 'X X . . . . . . . . X . . . X . X X X . X . . X . . . \n'
+ + 'X X . . X . . . . . X X . . . . . X . . . . X . . X X \n'
+ + '. . . X . X . X . . . . . X X X X X X . . . . . . X X \n'
+ + 'X . . . X . X X X X X X . . X X X . X . X X X X X X . \n'
+ + 'X . . X X X . X X X X X X X X X X X X X . . . X . X X \n'
+ + '. . . . X X . . . X . . . . . . . X X . . . X X . X . \n'
+ + '. . . X X X . . X X . X X X X X . X . . X . . . . . . \n'
+ + 'X . . . . X . X . X . X . . . X . X . X X . X X . X X \n'
+ + 'X . X . . X . X . X . X . X . X . X . . . . . X . X X \n'
+ + 'X . X X X . . X . X . X . . . X . X . X X X . . . X X \n'
+ + 'X X X X X X X X . X . X X X X X . X . X . X . X X X . \n'
+ + '. . . . . . . X . X . . . . . . . X X X X . . . X X X \n'
+ + 'X X . . X . . X . X X X X X X X X X X X X X . . X . X \n'
+ + 'X X X . X X X X . . X X X X . . X . . . . X . . X X X \n'
+ + '. . . . X . X X X . . . . X X X X . . X X X X . . . . \n'
+ + '. . X . . X . X . . . X . X X . X X . X . . . X . X . \n'
+ + 'X X . . X . . X X X X X X X . . X . X X X X X X X . . \n'
+ + 'X . X X . . X X . . . . . X . . . . . . X X . X X X . \n'
+ + 'X . . X X . . X X . X . X . . . . X . X . . X . . X . \n'
+ + 'X . X . X . . X . X X X X X X X X . X X X X . . X X . \n'
+ + 'X X X X . . . X . . X X X . X X . . X . . . . X X X . \n'
+ + 'X X . X . X . . . X . X . . . . X X . X . . X X . . . \n',
+ 'X ', '. ');
+ const r = new AztecDetectorResult(matrix, NO_POINTS, true, 16, 4);
+ assertThrow(() => new AztecDecoder().decode(r), FormatException);
+ });
- /**
- *
- * @Test(expected = FormatException.class)
- * @throws FormatException
- */
- it('testDecodeTooManyErrors2', () => {
- const matrix = BitMatrix.parseFromString(''
- + '. X X . . X . X X . . . X . . X X X . . . X X . X X . \n'
- + 'X X . X X . . X . . . X X . . . X X . X X X . X . X X \n'
- + '. . . . X . . . X X X . X X . X X X X . X X . . X . . \n'
- + 'X . X X . . X . . . X X . X X . X . X X . . . . . X . \n'
- + 'X X . X . . X . X X . . . . . X X . . . . . X . . . X \n'
- + 'X . . X . . . . . . X . . . X . X X X X X X X . . . X \n'
- + 'X . . X X . . X . . X X . . . . . X . . . . . X X X . \n'
- + '. . X X X X . X . . . . . X X X X X X . . . . . . X X \n'
- + 'X . . . X . X X X X X X . . X X X . X . X X X X X X . \n'
- + 'X . . X X X . X X X X X X X X X X X X X . . . X . X X \n'
- + '. . . . X X . . . X . . . . . . . X X . . . X X . X . \n'
- + '. . . X X X . . X X . X X X X X . X . . X . . . . . . \n'
- + 'X . . . . X . X . X . X . . . X . X . X X . X X . X X \n'
- + 'X . X . . X . X . X . X . X . X . X . . . . . X . X X \n'
- + 'X . X X X . . X . X . X . . . X . X . X X X . . . X X \n'
- + 'X X X X X X X X . X . X X X X X . X . X . X . X X X . \n'
- + '. . . . . . . X . X . . . . . . . X X X X . . . X X X \n'
- + 'X X . . X . . X . X X X X X X X X X X X X X . . X . X \n'
- + 'X X X . X X X X . . X X X X . . X . . . . X . . X X X \n'
- + '. . X X X X X . X . . . . X X X X . . X X X . X . X . \n'
- + '. . X X . X . X . . . X . X X . X X . . . . X X . . . \n'
- + 'X . . . X . X . X X X X X X . . X . X X X X X . X . . \n'
- + '. X . . . X X X . . . . . X . . . . . X X X X X . X . \n'
- + 'X . . X . X X X X . X . X . . . . X . X X . X . . X . \n'
- + 'X . . . X X . X . X X X X X X X X . X X X X . . X X . \n'
- + '. X X X X . . X . . X X X . X X . . X . . . . X X X . \n'
- + 'X X . . . X X . . X . X . . . . X X . X . . X . X . X \n',
- 'X ', '. ');
- const r = new AztecDetectorResult(matrix, NO_POINTS, true, 16, 4);
- assertThrow(() => new AztecDecoder().decode(r), FormatException);
- });
+ /**
+ *
+ * @Test(expected = FormatException.class)
+ * @throws FormatException
+ */
+ it('testDecodeTooManyErrors2', () => {
+ const matrix = BitMatrix.parseFromString(''
+ + '. X X . . X . X X . . . X . . X X X . . . X X . X X . \n'
+ + 'X X . X X . . X . . . X X . . . X X . X X X . X . X X \n'
+ + '. . . . X . . . X X X . X X . X X X X . X X . . X . . \n'
+ + 'X . X X . . X . . . X X . X X . X . X X . . . . . X . \n'
+ + 'X X . X . . X . X X . . . . . X X . . . . . X . . . X \n'
+ + 'X . . X . . . . . . X . . . X . X X X X X X X . . . X \n'
+ + 'X . . X X . . X . . X X . . . . . X . . . . . X X X . \n'
+ + '. . X X X X . X . . . . . X X X X X X . . . . . . X X \n'
+ + 'X . . . X . X X X X X X . . X X X . X . X X X X X X . \n'
+ + 'X . . X X X . X X X X X X X X X X X X X . . . X . X X \n'
+ + '. . . . X X . . . X . . . . . . . X X . . . X X . X . \n'
+ + '. . . X X X . . X X . X X X X X . X . . X . . . . . . \n'
+ + 'X . . . . X . X . X . X . . . X . X . X X . X X . X X \n'
+ + 'X . X . . X . X . X . X . X . X . X . . . . . X . X X \n'
+ + 'X . X X X . . X . X . X . . . X . X . X X X . . . X X \n'
+ + 'X X X X X X X X . X . X X X X X . X . X . X . X X X . \n'
+ + '. . . . . . . X . X . . . . . . . X X X X . . . X X X \n'
+ + 'X X . . X . . X . X X X X X X X X X X X X X . . X . X \n'
+ + 'X X X . X X X X . . X X X X . . X . . . . X . . X X X \n'
+ + '. . X X X X X . X . . . . X X X X . . X X X . X . X . \n'
+ + '. . X X . X . X . . . X . X X . X X . . . . X X . . . \n'
+ + 'X . . . X . X . X X X X X X . . X . X X X X X . X . . \n'
+ + '. X . . . X X X . . . . . X . . . . . X X X X X . X . \n'
+ + 'X . . X . X X X X . X . X . . . . X . X X . X . . X . \n'
+ + 'X . . . X X . X . X X X X X X X X . X X X X . . X X . \n'
+ + '. X X X X . . X . . X X X . X X . . X . . . . X X X . \n'
+ + 'X X . . . X X . . X . X . . . . X X . X . . X . X . X \n',
+ 'X ', '. ');
+ const r = new AztecDetectorResult(matrix, NO_POINTS, true, 16, 4);
+ assertThrow(() => new AztecDecoder().decode(r), FormatException);
+ });
- /**
- * @Test
- */
- it('testRawBytes', () => {
- let bool0: boolean[] = [];
- let bool1: boolean[] = [true];
- let bool7: boolean[] = [true, false, true, false, true, false, true];
- let bool8: boolean[] = [true, false, true, false, true, false, true, false];
- let bool9: boolean[] = [
- true, false, true, false, true, false, true, false,
- true];
- let bool16: boolean[] = [
- false, true, true, false, false, false, true, true,
- true, true, false, false, false, false, false, true];
- let byte0: /*byte[]*/Uint8Array = new Uint8Array([]);
- let byte1: /*byte[]*/Uint8Array = new Uint8Array([-128]);
- let byte7: /*byte[]*/ Uint8Array = new Uint8Array([- 86]);
- let byte8: /*byte[]*/ Uint8Array = new Uint8Array([- 86]);
- let byte9: /*byte[]*/ Uint8Array = new Uint8Array([- 86, -128]);
- let byte16: /*byte[]*/ Uint8Array = new Uint8Array([99, - 63]);
+ /**
+ * @Test
+ */
+ it('testRawBytes', () => {
+ let bool0: boolean[] = [];
+ let bool1: boolean[] = [true];
+ let bool7: boolean[] = [true, false, true, false, true, false, true];
+ let bool8: boolean[] = [true, false, true, false, true, false, true, false];
+ let bool9: boolean[] = [
+ true, false, true, false, true, false, true, false,
+ true];
+ let bool16: boolean[] = [
+ false, true, true, false, false, false, true, true,
+ true, true, false, false, false, false, false, true];
+ let byte0: /*byte[]*/Uint8Array = new Uint8Array([]);
+ let byte1: /*byte[]*/Uint8Array = new Uint8Array([-128]);
+ let byte7: /*byte[]*/ Uint8Array = new Uint8Array([- 86]);
+ let byte8: /*byte[]*/ Uint8Array = new Uint8Array([- 86]);
+ let byte9: /*byte[]*/ Uint8Array = new Uint8Array([- 86, -128]);
+ let byte16: /*byte[]*/ Uint8Array = new Uint8Array([99, - 63]);
- assertArrayEquals(byte0, AztecDecoder.convertBoolArrayToByteArray(bool0));
- assertArrayEquals(byte1, AztecDecoder.convertBoolArrayToByteArray(bool1));
- assertArrayEquals(byte7, AztecDecoder.convertBoolArrayToByteArray(bool7));
- assertArrayEquals(byte8, AztecDecoder.convertBoolArrayToByteArray(bool8));
- assertArrayEquals(byte9, AztecDecoder.convertBoolArrayToByteArray(bool9));
- assertArrayEquals(byte16, AztecDecoder.convertBoolArrayToByteArray(bool16));
- });
+ assertArrayEquals(byte0, AztecDecoder.convertBoolArrayToByteArray(bool0));
+ assertArrayEquals(byte1, AztecDecoder.convertBoolArrayToByteArray(bool1));
+ assertArrayEquals(byte7, AztecDecoder.convertBoolArrayToByteArray(bool7));
+ assertArrayEquals(byte8, AztecDecoder.convertBoolArrayToByteArray(bool8));
+ assertArrayEquals(byte9, AztecDecoder.convertBoolArrayToByteArray(bool9));
+ assertArrayEquals(byte16, AztecDecoder.convertBoolArrayToByteArray(bool16));
+ });
});
diff --git a/src/test/core/aztec/detector/Detector.spec.ts b/src/test/core/aztec/detector/Detector.spec.ts
index ffddf653..6d2cd707 100644
--- a/src/test/core/aztec/detector/Detector.spec.ts
+++ b/src/test/core/aztec/detector/Detector.spec.ts
@@ -60,166 +60,166 @@ import { ZXingInteger } from '@zxing/library';
describe('DetectorTest', () => {
- /**
- * @Test
- * @throws Exception
- */
- // public void testErrorInParameterLocatorZeroZero() throws Exception {
- it('testErrorInParameterLocatorZeroZero', () => {
- // Layers=1, CodeWords=1. So the parameter info and its Reed-Solomon info
- // will be completely zero!
- testErrorInParameterLocator('X');
- });
-
- /**
- * @Test
- * @throws Exception
- */
- // public void testErrorInParameterLocatorCompact() throws Exception {
- it('testErrorInParameterLocatorCompact', () => {
- testErrorInParameterLocator('This is an example Aztec symbol for Wikipedia.');
- });
-
- /**
- * @Test
- */
- // public void testErrorInParameterLocatorNotCompact() throws Exception {
- it('testErrorInParameterLocatorNotCompact', () => {
- const alphabet: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxyz';
- testErrorInParameterLocator(alphabet + alphabet + alphabet);
- });
-
- /**
- * @throws Exception
- */
- // Test that we can tolerate errors in the parameter locator bits
- function testErrorInParameterLocator(data: string): void {
- let aztec: AztecCode = AztecEncoder.encode(StringUtils.getBytes(data, ZXingStandardCharsets.ISO_8859_1), 25, AztecEncoder.DEFAULT_AZTEC_LAYERS);
- let random: Random = new Random(aztec.getMatrix().hashCode().toString()); // pseudo-random, but deterministic
- let layers: /*int*/ number = aztec.getLayers();
- let compact: boolean = aztec.isCompact();
- let orientationPoints: AztecPoint[] = getOrientationPoints(aztec);
- for (const isMirror of [false, true]) {
- for (const matrix of getRotations(aztec.getMatrix())) {
- // Systematically try every possible 1- and 2-bit error.
- for (let error1 = 0; error1 < orientationPoints.length; error1++) {
- for (let error2 = error1; error2 < orientationPoints.length; error2++) {
- let copy: BitMatrix = isMirror ? transpose(matrix) : clone(matrix);
- copy.flip(orientationPoints[error1].getX(), orientationPoints[error1].getY());
- if (error2 > error1) {
- // if error2 == error1, we only test a single error
- copy.flip(orientationPoints[error2].getX(), orientationPoints[error2].getY());
- }
- // The detector doesn't seem to work when matrix bits are only 1x1. So magnify.
- let r: AztecDetectorResult = new AztecDetector(makeLarger(copy, 3)).detectMirror(isMirror);
- assertNotNull(r);
- assertEquals(r.getNbLayers(), layers);
- assertEquals(r.isCompact(), compact);
- let res: DecoderResult = new AztecDecoder().decode(r);
- assertEquals(data, res.getText());
- }
- }
- // Try a few random three-bit errors;
- for (let i = 0; i < 5; i++) {
- let copy: BitMatrix = clone(matrix);
- let errors: /* Collection */ Set = /* new TreeSet<>() */ new Set();
- while (errors.size < 3) {
- // Quick and dirty way of getting three distinct integers between 1 and n.
- errors.add(random.nextInt(orientationPoints.length));
- }
- for (const error of errors) {
- copy.flip(orientationPoints[error].getX(), orientationPoints[error].getY());
- }
- try {
- new AztecDetector(makeLarger(copy, 3)).detectMirror(false);
- fail('Should not reach here');
- } catch (expected) {
- // continue
- if (!(expected instanceof NotFoundException)) {
- throw expected;
- }
- }
- }
+ /**
+ * @Test
+ * @throws Exception
+ */
+ // public void testErrorInParameterLocatorZeroZero() throws Exception {
+ it('testErrorInParameterLocatorZeroZero', () => {
+ // Layers=1, CodeWords=1. So the parameter info and its Reed-Solomon info
+ // will be completely zero!
+ testErrorInParameterLocator('X');
+ });
+
+ /**
+ * @Test
+ * @throws Exception
+ */
+ // public void testErrorInParameterLocatorCompact() throws Exception {
+ it('testErrorInParameterLocatorCompact', () => {
+ testErrorInParameterLocator('This is an example Aztec symbol for Wikipedia.');
+ });
+
+ /**
+ * @Test
+ */
+ // public void testErrorInParameterLocatorNotCompact() throws Exception {
+ it('testErrorInParameterLocatorNotCompact', () => {
+ const alphabet: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxyz';
+ testErrorInParameterLocator(alphabet + alphabet + alphabet);
+ });
+
+ /**
+ * @throws Exception
+ */
+ // Test that we can tolerate errors in the parameter locator bits
+ function testErrorInParameterLocator(data: string): void {
+ let aztec: AztecCode = AztecEncoder.encode(StringUtils.getBytes(data, ZXingStandardCharsets.ISO_8859_1), 25, AztecEncoder.DEFAULT_AZTEC_LAYERS);
+ let random: Random = new Random(aztec.getMatrix().hashCode().toString()); // pseudo-random, but deterministic
+ let layers: /*int*/ number = aztec.getLayers();
+ let compact: boolean = aztec.isCompact();
+ let orientationPoints: AztecPoint[] = getOrientationPoints(aztec);
+ for (const isMirror of [false, true]) {
+ for (const matrix of getRotations(aztec.getMatrix())) {
+ // Systematically try every possible 1- and 2-bit error.
+ for (let error1 = 0; error1 < orientationPoints.length; error1++) {
+ for (let error2 = error1; error2 < orientationPoints.length; error2++) {
+ let copy: BitMatrix = isMirror ? transpose(matrix) : clone(matrix);
+ copy.flip(orientationPoints[error1].getX(), orientationPoints[error1].getY());
+ if (error2 > error1) {
+ // if error2 == error1, we only test a single error
+ copy.flip(orientationPoints[error2].getX(), orientationPoints[error2].getY());
}
+ // The detector doesn't seem to work when matrix bits are only 1x1. So magnify.
+ let r: AztecDetectorResult = new AztecDetector(makeLarger(copy, 3)).detectMirror(isMirror);
+ assertNotNull(r);
+ assertEquals(r.getNbLayers(), layers);
+ assertEquals(r.isCompact(), compact);
+ let res: DecoderResult = new AztecDecoder().decode(r);
+ assertEquals(data, res.getText());
+ }
}
- }
-
- // Zooms a bit matrix so that each bit is factor x factor
- function makeLarger(input: BitMatrix, factor: /*int*/ number): BitMatrix {
- let width: number = input.getWidth();
- let output: BitMatrix = new BitMatrix(width * factor);
- for (let inputY: number = 0; inputY < width; inputY++) {
- for (let inputX: number = 0; inputX < width; inputX++) {
- if (input.get(inputX, inputY)) {
- output.setRegion(inputX * factor, inputY * factor, factor, factor);
- }
+ // Try a few random three-bit errors;
+ for (let i = 0; i < 5; i++) {
+ let copy: BitMatrix = clone(matrix);
+ let errors: /* Collection */ Set = /* new TreeSet<>() */ new Set();
+ while (errors.size < 3) {
+ // Quick and dirty way of getting three distinct integers between 1 and n.
+ errors.add(random.nextInt(orientationPoints.length));
+ }
+ for (const error of errors) {
+ copy.flip(orientationPoints[error].getX(), orientationPoints[error].getY());
+ }
+ try {
+ new AztecDetector(makeLarger(copy, 3)).detectMirror(false);
+ fail('Should not reach here');
+ } catch (expected) {
+ // continue
+ if (!(expected instanceof NotFoundException)) {
+ throw expected;
}
+ }
}
- return output;
- }
-
- // Returns a list of the four rotations of the BitMatrix.
- function getRotations(matrix0: BitMatrix): BitMatrix[] {
- let matrix90: BitMatrix = rotateRight(matrix0);
- let matrix180: BitMatrix = rotateRight(matrix90);
- let matrix270: BitMatrix = rotateRight(matrix180);
- return ZXingArrays.asList(matrix0, matrix90, matrix180, matrix270);
+ }
}
-
- // Rotates a square BitMatrix to the right by 90 degrees
- function rotateRight(input: BitMatrix): BitMatrix {
- let width: number = input.getWidth();
- let result: BitMatrix = new BitMatrix(width);
- for (let x /*int*/ = 0; x < width; x++) {
- for (let y /*int*/ = 0; y < width; y++) {
- if (input.get(x, y)) {
- result.set(y, width - x - 1);
- }
- }
+ }
+
+ // Zooms a bit matrix so that each bit is factor x factor
+ function makeLarger(input: BitMatrix, factor: /*int*/ number): BitMatrix {
+ let width: number = input.getWidth();
+ let output: BitMatrix = new BitMatrix(width * factor);
+ for (let inputY: number = 0; inputY < width; inputY++) {
+ for (let inputX: number = 0; inputX < width; inputX++) {
+ if (input.get(inputX, inputY)) {
+ output.setRegion(inputX * factor, inputY * factor, factor, factor);
}
- return result;
+ }
}
-
- // Returns the transpose of a bit matrix, which is equivalent to rotating the
- // matrix to the right, and then flipping it left-to-right
- function transpose(input: BitMatrix): BitMatrix {
- let width: number = input.getWidth();
- let result: BitMatrix = new BitMatrix(width);
- for (let x: number = 0; x < width; x++) {
- for (let y: number = 0; y < width; y++) {
- if (input.get(x, y)) {
- result.set(y, x);
- }
- }
+ return output;
+ }
+
+ // Returns a list of the four rotations of the BitMatrix.
+ function getRotations(matrix0: BitMatrix): BitMatrix[] {
+ let matrix90: BitMatrix = rotateRight(matrix0);
+ let matrix180: BitMatrix = rotateRight(matrix90);
+ let matrix270: BitMatrix = rotateRight(matrix180);
+ return ZXingArrays.asList(matrix0, matrix90, matrix180, matrix270);
+ }
+
+ // Rotates a square BitMatrix to the right by 90 degrees
+ function rotateRight(input: BitMatrix): BitMatrix {
+ let width: number = input.getWidth();
+ let result: BitMatrix = new BitMatrix(width);
+ for (let x /*int*/ = 0; x < width; x++) {
+ for (let y /*int*/ = 0; y < width; y++) {
+ if (input.get(x, y)) {
+ result.set(y, width - x - 1);
}
- return result;
+ }
}
-
- function clone(input: BitMatrix): BitMatrix {
- let width: number = input.getWidth();
- let result: BitMatrix = new BitMatrix(width);
- for (let x: number = 0; x < width; x++) {
- for (let y: number = 0; y < width; y++) {
- if (input.get(x, y)) {
- result.set(x, y);
- }
- }
+ return result;
+ }
+
+ // Returns the transpose of a bit matrix, which is equivalent to rotating the
+ // matrix to the right, and then flipping it left-to-right
+ function transpose(input: BitMatrix): BitMatrix {
+ let width: number = input.getWidth();
+ let result: BitMatrix = new BitMatrix(width);
+ for (let x: number = 0; x < width; x++) {
+ for (let y: number = 0; y < width; y++) {
+ if (input.get(x, y)) {
+ result.set(y, x);
}
- return result;
+ }
}
-
- function getOrientationPoints(code: AztecCode): AztecPoint[] {
- let center: number = ZXingInteger.truncDivision(code.getMatrix().getWidth(), 2);
- let offset: number = code.isCompact() ? 5 : 7;
- let result: AztecPoint[] = [];
- for (let xSign: number = -1; xSign <= 1; xSign += 2) {
- for (let ySign: number = -1; ySign <= 1; ySign += 2) {
- result.push(new AztecPoint(center + xSign * offset, center + ySign * offset));
- result.push(new AztecPoint(center + xSign * (offset - 1), center + ySign * offset));
- result.push(new AztecPoint(center + xSign * offset, center + ySign * (offset - 1)));
- }
+ return result;
+ }
+
+ function clone(input: BitMatrix): BitMatrix {
+ let width: number = input.getWidth();
+ let result: BitMatrix = new BitMatrix(width);
+ for (let x: number = 0; x < width; x++) {
+ for (let y: number = 0; y < width; y++) {
+ if (input.get(x, y)) {
+ result.set(x, y);
}
- return result;
+ }
+ }
+ return result;
+ }
+
+ function getOrientationPoints(code: AztecCode): AztecPoint[] {
+ let center: number = ZXingInteger.truncDivision(code.getMatrix().getWidth(), 2);
+ let offset: number = code.isCompact() ? 5 : 7;
+ let result: AztecPoint[] = [];
+ for (let xSign: number = -1; xSign <= 1; xSign += 2) {
+ for (let ySign: number = -1; ySign <= 1; ySign += 2) {
+ result.push(new AztecPoint(center + xSign * offset, center + ySign * offset));
+ result.push(new AztecPoint(center + xSign * (offset - 1), center + ySign * offset));
+ result.push(new AztecPoint(center + xSign * offset, center + ySign * (offset - 1)));
+ }
}
+ return result;
+ }
});
diff --git a/src/test/core/aztec/encoder/EncoderTest.spec.ts b/src/test/core/aztec/encoder/EncoderTest.spec.ts
index 45d10b1f..59875a28 100644
--- a/src/test/core/aztec/encoder/EncoderTest.spec.ts
+++ b/src/test/core/aztec/encoder/EncoderTest.spec.ts
@@ -65,28 +65,28 @@ describe('EncoderTest', () => {
true,
3,
'X X X X X X X X \n' +
- 'X X X X X X X X X X \n' +
- 'X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X \n' +
- 'X X X X X X X X X X \n' +
- ' X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X \n' +
- ' X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X \n' +
- ' X X X \n' +
- ' X X X X X X X X X X \n' +
- ' X X X X X X X X X X \n'
+ 'X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X \n' +
+ 'X X X X X X X X X X \n' +
+ ' X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X \n' +
+ ' X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X \n' +
+ ' X X X \n' +
+ ' X X X X X X X X X X \n' +
+ ' X X X X X X X X X X \n'
);
});
@@ -95,51 +95,51 @@ describe('EncoderTest', () => {
it('testEncode2', () => {
testEncode(
'Aztec Code is a public domain 2D matrix barcode symbology' +
- ' of nominally square symbols built on a square grid with a ' +
- 'distinctive square bullseye pattern at their center.',
+ ' of nominally square symbols built on a square grid with a ' +
+ 'distinctive square bullseye pattern at their center.',
false,
6,
' X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X X X X X X X X X \n' +
- ' X X X X X X X X X X X X X X X X \n' +
- 'X X X X X X X X X X X X X \n'
+ ' X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X X X X X X X X X \n' +
+ ' X X X X X X X X X X X X X X X X \n' +
+ 'X X X X X X X X X X X X X \n'
);
});
@@ -215,7 +215,7 @@ describe('EncoderTest', () => {
it('testEncodeDecode5', () => {
testEncodeDecode(
'http://test/~!@#*^%&)__ ;:\'"[]{}\\|-+-=`1029384756<>/?abc' +
- 'Four score and seven our forefathers brought forth',
+ 'Four score and seven our forefathers brought forth',
false,
5
);
@@ -226,11 +226,11 @@ describe('EncoderTest', () => {
it('testEncodeDecode10', () => {
testEncodeDecode(
'In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam' +
- ' cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum' +
- ' est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue' +
- ' auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla' +
- ' ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar nisi, id' +
- ' elementum sapien dolor et diam.',
+ ' cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum' +
+ ' est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue' +
+ ' auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla' +
+ ' ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar nisi, id' +
+ ' elementum sapien dolor et diam.',
false,
10
);
@@ -241,27 +241,27 @@ describe('EncoderTest', () => {
it('testEncodeDecode23', () => {
testEncodeDecode(
'In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam' +
- ' cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum' +
- ' est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue' +
- ' auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla' +
- ' ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar nisi, id' +
- ' elementum sapien dolor et diam. Donec ac nunc sodales elit placerat eleifend.' +
- ' Sed ornare luctus ornare. Vestibulum vehicula, massa at pharetra fringilla, risus' +
- ' justo faucibus erat, nec porttitor nibh tellus sed est. Ut justo diam, lobortis eu' +
- ' tristique ac, p.In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus' +
- ' quis diam cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec' +
- ' laoreet rutrum est, nec convallis mauris condimentum sit amet. Phasellus gravida,' +
- ' justo et congue auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec' +
- ' lorem. Nulla ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar' +
- ' nisi, id elementum sapien dolor et diam. Donec ac nunc sodales elit placerat' +
- ' eleifend. Sed ornare luctus ornare. Vestibulum vehicula, massa at pharetra' +
- ' fringilla, risus justo faucibus erat, nec porttitor nibh tellus sed est. Ut justo' +
- ' diam, lobortis eu tristique ac, p. In ut magna vel mauris malesuada dictum. Nulla' +
- ' ullamcorper metus quis diam cursus facilisis. Sed mollis quam id justo rutrum' +
- ' sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum sit amet.' +
- ' Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat, eget hendrerit' +
- ' felis turpis nec lorem. Nulla ultrices, elit pellentesque aliquet laoreet, justo' +
- ' erat pulvinar nisi, id elementum sapien dolor et diam.',
+ ' cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum' +
+ ' est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue' +
+ ' auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla' +
+ ' ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar nisi, id' +
+ ' elementum sapien dolor et diam. Donec ac nunc sodales elit placerat eleifend.' +
+ ' Sed ornare luctus ornare. Vestibulum vehicula, massa at pharetra fringilla, risus' +
+ ' justo faucibus erat, nec porttitor nibh tellus sed est. Ut justo diam, lobortis eu' +
+ ' tristique ac, p.In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus' +
+ ' quis diam cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec' +
+ ' laoreet rutrum est, nec convallis mauris condimentum sit amet. Phasellus gravida,' +
+ ' justo et congue auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec' +
+ ' lorem. Nulla ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar' +
+ ' nisi, id elementum sapien dolor et diam. Donec ac nunc sodales elit placerat' +
+ ' eleifend. Sed ornare luctus ornare. Vestibulum vehicula, massa at pharetra' +
+ ' fringilla, risus justo faucibus erat, nec porttitor nibh tellus sed est. Ut justo' +
+ ' diam, lobortis eu tristique ac, p. In ut magna vel mauris malesuada dictum. Nulla' +
+ ' ullamcorper metus quis diam cursus facilisis. Sed mollis quam id justo rutrum' +
+ ' sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum sit amet.' +
+ ' Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat, eget hendrerit' +
+ ' felis turpis nec lorem. Nulla ultrices, elit pellentesque aliquet laoreet, justo' +
+ ' erat pulvinar nisi, id elementum sapien dolor et diam.',
false,
23
);
@@ -272,42 +272,42 @@ describe('EncoderTest', () => {
it('testEncodeDecode31', () => {
testEncodeDecode(
'In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam' +
- ' cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum' +
- ' est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue' +
- ' auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla' +
- ' ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar nisi, id' +
- ' elementum sapien dolor et diam. Donec ac nunc sodales elit placerat eleifend.' +
- ' Sed ornare luctus ornare. Vestibulum vehicula, massa at pharetra fringilla, risus' +
- ' justo faucibus erat, nec porttitor nibh tellus sed est. Ut justo diam, lobortis eu' +
- ' tristique ac, p.In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus' +
- ' quis diam cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec' +
- ' laoreet rutrum est, nec convallis mauris condimentum sit amet. Phasellus gravida,' +
- ' justo et congue auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec' +
- ' lorem. Nulla ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar' +
- ' nisi, id elementum sapien dolor et diam. Donec ac nunc sodales elit placerat' +
- ' eleifend. Sed ornare luctus ornare. Vestibulum vehicula, massa at pharetra' +
- ' fringilla, risus justo faucibus erat, nec porttitor nibh tellus sed est. Ut justo' +
- ' diam, lobortis eu tristique ac, p. In ut magna vel mauris malesuada dictum. Nulla' +
- ' ullamcorper metus quis diam cursus facilisis. Sed mollis quam id justo rutrum' +
- ' sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum sit amet.' +
- ' Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat, eget hendrerit' +
- ' felis turpis nec lorem. Nulla ultrices, elit pellentesque aliquet laoreet, justo' +
- ' erat pulvinar nisi, id elementum sapien dolor et diam. Donec ac nunc sodales elit' +
- ' placerat eleifend. Sed ornare luctus ornare. Vestibulum vehicula, massa at' +
- ' pharetra fringilla, risus justo faucibus erat, nec porttitor nibh tellus sed est.' +
- ' Ut justo diam, lobortis eu tristique ac, p.In ut magna vel mauris malesuada' +
- ' dictum. Nulla ullamcorper metus quis diam cursus facilisis. Sed mollis quam id' +
- ' justo rutrum sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum' +
- ' sit amet. Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat,' +
- ' eget hendrerit felis turpis nec lorem. Nulla ultrices, elit pellentesque aliquet' +
- ' laoreet, justo erat pulvinar nisi, id elementum sapien dolor et diam. Donec ac' +
- ' nunc sodales elit placerat eleifend. Sed ornare luctus ornare. Vestibulum vehicula,' +
- ' massa at pharetra fringilla, risus justo faucibus erat, nec porttitor nibh tellus' +
- ' sed est. Ut justo diam, lobortis eu tris. In ut magna vel mauris malesuada dictum.' +
- ' Nulla ullamcorper metus quis diam cursus facilisis. Sed mollis quam id justo rutrum' +
- ' sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum sit amet.' +
- ' Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat, eget' +
- ' hendrerit felis turpis nec lorem.',
+ ' cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum' +
+ ' est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue' +
+ ' auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla' +
+ ' ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar nisi, id' +
+ ' elementum sapien dolor et diam. Donec ac nunc sodales elit placerat eleifend.' +
+ ' Sed ornare luctus ornare. Vestibulum vehicula, massa at pharetra fringilla, risus' +
+ ' justo faucibus erat, nec porttitor nibh tellus sed est. Ut justo diam, lobortis eu' +
+ ' tristique ac, p.In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus' +
+ ' quis diam cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec' +
+ ' laoreet rutrum est, nec convallis mauris condimentum sit amet. Phasellus gravida,' +
+ ' justo et congue auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec' +
+ ' lorem. Nulla ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar' +
+ ' nisi, id elementum sapien dolor et diam. Donec ac nunc sodales elit placerat' +
+ ' eleifend. Sed ornare luctus ornare. Vestibulum vehicula, massa at pharetra' +
+ ' fringilla, risus justo faucibus erat, nec porttitor nibh tellus sed est. Ut justo' +
+ ' diam, lobortis eu tristique ac, p. In ut magna vel mauris malesuada dictum. Nulla' +
+ ' ullamcorper metus quis diam cursus facilisis. Sed mollis quam id justo rutrum' +
+ ' sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum sit amet.' +
+ ' Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat, eget hendrerit' +
+ ' felis turpis nec lorem. Nulla ultrices, elit pellentesque aliquet laoreet, justo' +
+ ' erat pulvinar nisi, id elementum sapien dolor et diam. Donec ac nunc sodales elit' +
+ ' placerat eleifend. Sed ornare luctus ornare. Vestibulum vehicula, massa at' +
+ ' pharetra fringilla, risus justo faucibus erat, nec porttitor nibh tellus sed est.' +
+ ' Ut justo diam, lobortis eu tristique ac, p.In ut magna vel mauris malesuada' +
+ ' dictum. Nulla ullamcorper metus quis diam cursus facilisis. Sed mollis quam id' +
+ ' justo rutrum sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum' +
+ ' sit amet. Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat,' +
+ ' eget hendrerit felis turpis nec lorem. Nulla ultrices, elit pellentesque aliquet' +
+ ' laoreet, justo erat pulvinar nisi, id elementum sapien dolor et diam. Donec ac' +
+ ' nunc sodales elit placerat eleifend. Sed ornare luctus ornare. Vestibulum vehicula,' +
+ ' massa at pharetra fringilla, risus justo faucibus erat, nec porttitor nibh tellus' +
+ ' sed est. Ut justo diam, lobortis eu tris. In ut magna vel mauris malesuada dictum.' +
+ ' Nulla ullamcorper metus quis diam cursus facilisis. Sed mollis quam id justo rutrum' +
+ ' sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum sit amet.' +
+ ' Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat, eget' +
+ ' hendrerit felis turpis nec lorem.',
false,
31
);
@@ -399,7 +399,7 @@ describe('EncoderTest', () => {
// Found on an airline boarding pass. Several stretches of Binary shift are
// necessary to keep the bitcount so low.
'09 UAG ^160MEUCIQC0sYS/HpKxnBELR1uB85R20OoqqwFGa0q2uEi' +
- 'Ygh6utAIgLl1aBVM4EOTQtMQQYH9M2Z3Dp4qnA/fwWuQ+M8L3V8U=',
+ 'Ygh6utAIgLl1aBVM4EOTQtMQQYH9M2Z3Dp4qnA/fwWuQ+M8L3V8U=',
823
);
});
diff --git a/src/test/core/common/BitArray.spec.ts b/src/test/core/common/BitArray.spec.ts
index 8323e3d4..1018eee7 100644
--- a/src/test/core/common/BitArray.spec.ts
+++ b/src/test/core/common/BitArray.spec.ts
@@ -27,220 +27,220 @@ import AssertUtils from '../util/AssertUtils';
*/
describe('BitArray', () => {
- it('testGetSet', () => {
- const array = new BitArray(33);
- for (let i = 0; i < 33; i++) {
- assert.strictEqual(array.get(i), false);
- array.set(i);
- assert.strictEqual(array.get(i), true);
- }
- });
+ it('testGetSet', () => {
+ const array = new BitArray(33);
+ for (let i = 0; i < 33; i++) {
+ assert.strictEqual(array.get(i), false);
+ array.set(i);
+ assert.strictEqual(array.get(i), true);
+ }
+ });
- it('testGetNextSet1', () => {
- let array = new BitArray(32);
- for (let i = 0; i < array.getSize(); i++) {
- assert.strictEqual(array.getNextSet(i), 32, '' + i);
- }
- array = new BitArray(33);
- for (let i = 0; i < array.getSize(); i++) {
- assert.strictEqual(array.getNextSet(i), 33, '' + i);
- }
- });
+ it('testGetNextSet1', () => {
+ let array = new BitArray(32);
+ for (let i = 0; i < array.getSize(); i++) {
+ assert.strictEqual(array.getNextSet(i), 32, '' + i);
+ }
+ array = new BitArray(33);
+ for (let i = 0; i < array.getSize(); i++) {
+ assert.strictEqual(array.getNextSet(i), 33, '' + i);
+ }
+ });
- it('testGetNextSet2', () => {
- let array = new BitArray(33);
- array.set(31);
- for (let i = 0; i < array.getSize(); i++) {
- assert.strictEqual(array.getNextSet(i), i <= 31 ? 31 : 33, '' + i);
- }
- array = new BitArray(33);
- array.set(32);
- for (let i = 0; i < array.getSize(); i++) {
- assert.strictEqual(array.getNextSet(i), 32, '' + i);
- }
- });
-
-
- it('testGetNextSet3', () => {
- const array = new BitArray(63);
- array.set(31);
- array.set(32);
- for (let i = 0; i < array.getSize(); i++) {
- let expected;
- if (i <= 31) {
- expected = 31;
- } else if (i === 32) {
- expected = 32;
- } else {
- expected = 63;
- }
- assert.strictEqual(array.getNextSet(i), expected, '' + i);
- }
- });
-
-
- it('testGetNextSet4', () => {
- const array = new BitArray(63);
- array.set(33);
- array.set(40);
- for (let i = 0; i < array.getSize(); i++) {
- let expected;
- if (i <= 33) {
- expected = 33;
- } else if (i <= 40) {
- expected = 40;
- } else {
- expected = 63;
- }
- assert.strictEqual(array.getNextSet(i), expected, '' + i);
- }
- });
-
-
- it('testGetNextSet5', () => {
- const r = new Random('0xDEADBEEF');
- for (let i = 0; i < 10; i++) {
- const array = new BitArray(1 + r.next(100));
- const numSet = r.next(20);
- for (let j = 0; j < numSet; j++) {
- array.set(r.next(array.getSize()));
- }
- const numQueries = r.next(20);
- for (let j = 0; j < numQueries; j++) {
- const query = r.next(array.getSize());
- let expected = query;
- while (expected < array.getSize() && !array.get(expected)) {
- expected++;
- }
- const actual = array.getNextSet(query);
- assert.strictEqual(actual, expected);
- }
- }
- });
+ it('testGetNextSet2', () => {
+ let array = new BitArray(33);
+ array.set(31);
+ for (let i = 0; i < array.getSize(); i++) {
+ assert.strictEqual(array.getNextSet(i), i <= 31 ? 31 : 33, '' + i);
+ }
+ array = new BitArray(33);
+ array.set(32);
+ for (let i = 0; i < array.getSize(); i++) {
+ assert.strictEqual(array.getNextSet(i), 32, '' + i);
+ }
+ });
+
+
+ it('testGetNextSet3', () => {
+ const array = new BitArray(63);
+ array.set(31);
+ array.set(32);
+ for (let i = 0; i < array.getSize(); i++) {
+ let expected;
+ if (i <= 31) {
+ expected = 31;
+ } else if (i === 32) {
+ expected = 32;
+ } else {
+ expected = 63;
+ }
+ assert.strictEqual(array.getNextSet(i), expected, '' + i);
+ }
+ });
+
+
+ it('testGetNextSet4', () => {
+ const array = new BitArray(63);
+ array.set(33);
+ array.set(40);
+ for (let i = 0; i < array.getSize(); i++) {
+ let expected;
+ if (i <= 33) {
+ expected = 33;
+ } else if (i <= 40) {
+ expected = 40;
+ } else {
+ expected = 63;
+ }
+ assert.strictEqual(array.getNextSet(i), expected, '' + i);
+ }
+ });
+
+
+ it('testGetNextSet5', () => {
+ const r = new Random('0xDEADBEEF');
+ for (let i = 0; i < 10; i++) {
+ const array = new BitArray(1 + r.next(100));
+ const numSet = r.next(20);
+ for (let j = 0; j < numSet; j++) {
+ array.set(r.next(array.getSize()));
+ }
+ const numQueries = r.next(20);
+ for (let j = 0; j < numQueries; j++) {
+ const query = r.next(array.getSize());
+ let expected = query;
+ while (expected < array.getSize() && !array.get(expected)) {
+ expected++;
+ }
+ const actual = array.getNextSet(query);
+ assert.strictEqual(actual, expected);
+ }
+ }
+ });
- it('testSetBulk', () => {
- const array = new BitArray(64);
- array.setBulk(32, 0xFFFF0000);
- for (let i = 0; i < 48; i++) {
- assert.strictEqual(array.get(i), false);
- }
- for (let i = 48; i < 64; i++) {
- assert.strictEqual(array.get(i), true);
- }
- });
+ it('testSetBulk', () => {
+ const array = new BitArray(64);
+ array.setBulk(32, 0xFFFF0000);
+ for (let i = 0; i < 48; i++) {
+ assert.strictEqual(array.get(i), false);
+ }
+ for (let i = 48; i < 64; i++) {
+ assert.strictEqual(array.get(i), true);
+ }
+ });
- it('testSetRange', () => {
- const array = new BitArray(64);
- array.setRange(28, 36);
- assert.strictEqual(array.get(27), false);
- for (let i = 28; i < 36; i++) {
- assert.strictEqual(array.get(i), true);
- }
- assert.strictEqual(array.get(36), false);
- });
+ it('testSetRange', () => {
+ const array = new BitArray(64);
+ array.setRange(28, 36);
+ assert.strictEqual(array.get(27), false);
+ for (let i = 28; i < 36; i++) {
+ assert.strictEqual(array.get(i), true);
+ }
+ assert.strictEqual(array.get(36), false);
+ });
- it('testClear', () => {
- const array = new BitArray(32);
- for (let i = 0; i < 32; i++) {
- array.set(i);
- }
- array.clear();
- for (let i = 0; i < 32; i++) {
- assert.strictEqual(array.get(i), false);
- }
- });
-
-
- it('testFlip', () => {
- const array = new BitArray(32);
- assert.strictEqual(array.get(5), false);
- array.flip(5);
- assert.strictEqual(array.get(5), true);
- array.flip(5);
- assert.strictEqual(array.get(5), false);
- });
-
-
- it('testGetArray', () => {
- const array = new BitArray(64);
- array.set(0);
- array.set(63);
- const ints = array.getBitArray();
- assert.strictEqual(ints[0], 1);
- assert.strictEqual(ints[1], ZXingInteger.MIN_VALUE_32_BITS); // Integer.MIN_VALUE)
- });
-
-
- it('testIsRange', () => {
- const array = new BitArray(64);
- assert.strictEqual(array.isRange(0, 64, false), true);
- assert.strictEqual(array.isRange(0, 64, true), false);
- array.set(32);
- assert.strictEqual(array.isRange(32, 33, true), true);
- array.set(31);
- assert.strictEqual(array.isRange(31, 33, true), true);
- array.set(34);
- assert.strictEqual(array.isRange(31, 35, true), false);
- for (let i = 0; i < 31; i++) {
- array.set(i);
- }
- assert.strictEqual(array.isRange(0, 33, true), true);
- for (let i = 33; i < 64; i++) {
- array.set(i);
- }
- assert.strictEqual(array.isRange(0, 64, true), true);
- assert.strictEqual(array.isRange(0, 64, false), false);
- });
-
-
- it('reverseAlgorithmTest', () => {
- const oldBits = Int32Array.from([128, 256, 512, 6453324, 50934953]);
- for (let size = 1; size < 160; size++) {
- const newBitsOriginal = reverseOriginal(oldBits.slice(), size);
- const newBitArray = new BitArray(size, oldBits.slice());
- newBitArray.reverse();
- const newBitsNew = newBitArray.getBitArray();
- assert.strictEqual(AssertUtils.typedArraysAreEqual(newBitsOriginal, newBitsNew, size / 32 + 1), true);
- }
- });
-
-
- it('testClone', () => {
- const array = new BitArray(32);
- array.clone().set(0);
- assert.strictEqual(array.get(0), false);
- });
-
-
- it('testEquals', () => {
- const a = new BitArray(32);
- const b = new BitArray(32);
- assert.strictEqual(a.equals(b), true);
- assert.strictEqual(a.hashCode(), b.hashCode());
- assert.strictEqual(a.equals(new BitArray(31)), false);
- a.set(16);
- assert.strictEqual(a.equals(new BitArray(31)), false);
- assert.notStrictEqual(a.hashCode(), b.hashCode());
- b.set(16);
- assert.strictEqual(a.equals(b), true);
- assert.strictEqual(a.hashCode(), b.hashCode());
- });
-
- function reverseOriginal(oldBits: Int32Array, size: number): Int32Array {
- const newBits = new Int32Array(oldBits.length);
- for (let i = 0; i < size; i++) {
- if (bitSet(oldBits, size - i - 1)) {
- newBits[Math.floor(i / 32)] |= 1 << (i & 0x1F);
- }
- }
- return newBits;
+ it('testClear', () => {
+ const array = new BitArray(32);
+ for (let i = 0; i < 32; i++) {
+ array.set(i);
}
-
- function bitSet(bits: Int32Array, i: number): boolean {
- return (bits[Math.floor(i / 32)] & (1 << (i & 0x1F))) !== 0;
+ array.clear();
+ for (let i = 0; i < 32; i++) {
+ assert.strictEqual(array.get(i), false);
+ }
+ });
+
+
+ it('testFlip', () => {
+ const array = new BitArray(32);
+ assert.strictEqual(array.get(5), false);
+ array.flip(5);
+ assert.strictEqual(array.get(5), true);
+ array.flip(5);
+ assert.strictEqual(array.get(5), false);
+ });
+
+
+ it('testGetArray', () => {
+ const array = new BitArray(64);
+ array.set(0);
+ array.set(63);
+ const ints = array.getBitArray();
+ assert.strictEqual(ints[0], 1);
+ assert.strictEqual(ints[1], ZXingInteger.MIN_VALUE_32_BITS); // Integer.MIN_VALUE)
+ });
+
+
+ it('testIsRange', () => {
+ const array = new BitArray(64);
+ assert.strictEqual(array.isRange(0, 64, false), true);
+ assert.strictEqual(array.isRange(0, 64, true), false);
+ array.set(32);
+ assert.strictEqual(array.isRange(32, 33, true), true);
+ array.set(31);
+ assert.strictEqual(array.isRange(31, 33, true), true);
+ array.set(34);
+ assert.strictEqual(array.isRange(31, 35, true), false);
+ for (let i = 0; i < 31; i++) {
+ array.set(i);
}
+ assert.strictEqual(array.isRange(0, 33, true), true);
+ for (let i = 33; i < 64; i++) {
+ array.set(i);
+ }
+ assert.strictEqual(array.isRange(0, 64, true), true);
+ assert.strictEqual(array.isRange(0, 64, false), false);
+ });
+
+
+ it('reverseAlgorithmTest', () => {
+ const oldBits = Int32Array.from([128, 256, 512, 6453324, 50934953]);
+ for (let size = 1; size < 160; size++) {
+ const newBitsOriginal = reverseOriginal(oldBits.slice(), size);
+ const newBitArray = new BitArray(size, oldBits.slice());
+ newBitArray.reverse();
+ const newBitsNew = newBitArray.getBitArray();
+ assert.strictEqual(AssertUtils.typedArraysAreEqual(newBitsOriginal, newBitsNew, size / 32 + 1), true);
+ }
+ });
+
+
+ it('testClone', () => {
+ const array = new BitArray(32);
+ array.clone().set(0);
+ assert.strictEqual(array.get(0), false);
+ });
+
+
+ it('testEquals', () => {
+ const a = new BitArray(32);
+ const b = new BitArray(32);
+ assert.strictEqual(a.equals(b), true);
+ assert.strictEqual(a.hashCode(), b.hashCode());
+ assert.strictEqual(a.equals(new BitArray(31)), false);
+ a.set(16);
+ assert.strictEqual(a.equals(new BitArray(31)), false);
+ assert.notStrictEqual(a.hashCode(), b.hashCode());
+ b.set(16);
+ assert.strictEqual(a.equals(b), true);
+ assert.strictEqual(a.hashCode(), b.hashCode());
+ });
+
+ function reverseOriginal(oldBits: Int32Array, size: number): Int32Array {
+ const newBits = new Int32Array(oldBits.length);
+ for (let i = 0; i < size; i++) {
+ if (bitSet(oldBits, size - i - 1)) {
+ newBits[Math.floor(i / 32)] |= 1 << (i & 0x1F);
+ }
+ }
+ return newBits;
+ }
+
+ function bitSet(bits: Int32Array, i: number): boolean {
+ return (bits[Math.floor(i / 32)] & (1 << (i & 0x1F))) !== 0;
+ }
});
diff --git a/src/test/core/common/BitSource.spec.ts b/src/test/core/common/BitSource.spec.ts
index 934d3209..590d2604 100644
--- a/src/test/core/common/BitSource.spec.ts
+++ b/src/test/core/common/BitSource.spec.ts
@@ -24,32 +24,32 @@ import { BitSource } from '@zxing/library';
*/
describe('BitSource', () => {
- it('testSource', () => {
- const bytes = Uint8Array.from([
+ it('testSource', () => {
+ const bytes = Uint8Array.from([
/*(byte)*/ 1,
/*(byte)*/ 2,
/*(byte)*/ 3,
/*(byte)*/ 4,
/*(byte)*/ 5
- ]);
+ ]);
- const source = new BitSource(bytes);
+ const source = new BitSource(bytes);
- assert.strictEqual(source.available(), 40);
- assert.strictEqual(source.readBits(1), 0);
- assert.strictEqual(source.available(), 39);
- assert.strictEqual(source.readBits(6), 0);
- assert.strictEqual(source.available(), 33);
- assert.strictEqual(source.readBits(1), 1);
- assert.strictEqual(source.available(), 32);
- assert.strictEqual(source.readBits(8), 2);
- assert.strictEqual(source.available(), 24);
- assert.strictEqual(source.readBits(10), 12);
- assert.strictEqual(source.available(), 14);
- assert.strictEqual(source.readBits(8), 16);
- assert.strictEqual(source.available(), 6);
- assert.strictEqual(source.readBits(6), 5);
- assert.strictEqual(source.available(), 0);
- });
+ assert.strictEqual(source.available(), 40);
+ assert.strictEqual(source.readBits(1), 0);
+ assert.strictEqual(source.available(), 39);
+ assert.strictEqual(source.readBits(6), 0);
+ assert.strictEqual(source.available(), 33);
+ assert.strictEqual(source.readBits(1), 1);
+ assert.strictEqual(source.available(), 32);
+ assert.strictEqual(source.readBits(8), 2);
+ assert.strictEqual(source.available(), 24);
+ assert.strictEqual(source.readBits(10), 12);
+ assert.strictEqual(source.available(), 14);
+ assert.strictEqual(source.readBits(8), 16);
+ assert.strictEqual(source.available(), 6);
+ assert.strictEqual(source.readBits(6), 5);
+ assert.strictEqual(source.available(), 0);
+ });
});
diff --git a/src/test/core/common/BitSourceBuilder.ts b/src/test/core/common/BitSourceBuilder.ts
index 265ed9d1..71542bc9 100644
--- a/src/test/core/common/BitSourceBuilder.ts
+++ b/src/test/core/common/BitSourceBuilder.ts
@@ -25,42 +25,42 @@
*/
export default class BitSourceBuilder {
- private output: Array;
- private nextByte: number; /*int*/
- private bitsLeftInNextByte: number; /*int*/
+ private output: Array;
+ private nextByte: number; /*int*/
+ private bitsLeftInNextByte: number; /*int*/
- public constructor() {
- this.output = new Array();
+ public constructor() {
+ this.output = new Array();
+ this.nextByte = 0;
+ this.bitsLeftInNextByte = 8;
+ }
+
+ public write(value: number /*int*/, numBits: number /*int*/): void {
+ if (numBits <= this.bitsLeftInNextByte) {
+ const nb = (this.nextByte << numBits) & 0xFFFFFFFF;
+ this.nextByte = nb | value;
+ this.bitsLeftInNextByte -= numBits;
+ if (this.bitsLeftInNextByte === 0) {
+ const byte = this.nextByte & 0xFF;
+ this.output.push(byte);
this.nextByte = 0;
this.bitsLeftInNextByte = 8;
+ }
+ } else {
+ const bitsToWriteNow: number /*int*/ = this.bitsLeftInNextByte;
+ const numRestOfBits: number /*int*/ = numBits - bitsToWriteNow;
+ const mask: number /*int*/ = 0xFF >> (8 - bitsToWriteNow);
+ const valueToWriteNow: number /*int*/ = (value >>> numRestOfBits) & mask;
+ this.write(valueToWriteNow, bitsToWriteNow);
+ this.write(value, numRestOfBits);
}
+ }
- public write(value: number /*int*/, numBits: number /*int*/): void {
- if (numBits <= this.bitsLeftInNextByte) {
- const nb = (this.nextByte << numBits) & 0xFFFFFFFF;
- this.nextByte = nb | value;
- this.bitsLeftInNextByte -= numBits;
- if (this.bitsLeftInNextByte === 0) {
- const byte = this.nextByte & 0xFF;
- this.output.push(byte);
- this.nextByte = 0;
- this.bitsLeftInNextByte = 8;
- }
- } else {
- const bitsToWriteNow: number /*int*/ = this.bitsLeftInNextByte;
- const numRestOfBits: number /*int*/ = numBits - bitsToWriteNow;
- const mask: number /*int*/ = 0xFF >> (8 - bitsToWriteNow);
- const valueToWriteNow: number /*int*/ = (value >>> numRestOfBits) & mask;
- this.write(valueToWriteNow, bitsToWriteNow);
- this.write(value, numRestOfBits);
- }
- }
-
- public toByteArray(): Uint8Array {
- if (this.bitsLeftInNextByte < 8) {
- this.write(0, this.bitsLeftInNextByte);
- }
- return Uint8Array.from(this.output);
+ public toByteArray(): Uint8Array {
+ if (this.bitsLeftInNextByte < 8) {
+ this.write(0, this.bitsLeftInNextByte);
}
+ return Uint8Array.from(this.output);
+ }
}
diff --git a/src/test/core/common/PerspectiveTransform.spec.ts b/src/test/core/common/PerspectiveTransform.spec.ts
index 04b4346a..3197234e 100644
--- a/src/test/core/common/PerspectiveTransform.spec.ts
+++ b/src/test/core/common/PerspectiveTransform.spec.ts
@@ -24,39 +24,39 @@ import { PerspectiveTransform } from '@zxing/library';
*/
describe('PerspectiveTransform', () => {
- const EPSILON: number /*float*/ = 1.0E-4;
-
- it('testSquareToQuadrilateral', () => {
- const pt = PerspectiveTransform.squareToQuadrilateral(2.0, 3.0, 10.0, 4.0, 16.0, 15.0, 4.0, 9.0);
- assertPointEquals(2.0, 3.0, 0.0, 0.0, pt);
- assertPointEquals(10.0, 4.0, 1.0, 0.0, pt);
- assertPointEquals(4.0, 9.0, 0.0, 1.0, pt);
- assertPointEquals(16.0, 15.0, 1.0, 1.0, pt);
- assertPointEquals(6.535211, 6.8873234, 0.5, 0.5, pt);
- assertPointEquals(48.0, 42.42857, 1.5, 1.5, pt);
- });
-
- it('testQuadrilateralToQuadrilateral', () => {
- const pt = PerspectiveTransform.quadrilateralToQuadrilateral(
- 2.0, 3.0, 10.0, 4.0, 16.0, 15.0, 4.0, 9.0,
- 103.0, 110.0, 300.0, 120.0, 290.0, 270.0, 150.0, 280.0);
- assertPointEquals(103.0, 110.0, 2.0, 3.0, pt);
- assertPointEquals(300.0, 120.0, 10.0, 4.0, pt);
- assertPointEquals(290.0, 270.0, 16.0, 15.0, pt);
- assertPointEquals(150.0, 280.0, 4.0, 9.0, pt);
- assertPointEquals(7.1516876, -64.60185, 0.5, 0.5, pt);
- assertPointEquals(328.09116, 334.16385, 50.0, 50.0, pt);
- });
-
- function assertPointEquals(expectedX: number/*float*/,
- expectedY: number/*float*/,
- sourceX: number/*float*/,
- sourceY: number/*float*/,
- pt: PerspectiveTransform) {
- const points = Float32Array.from([sourceX, sourceY]);
- pt.transformPoints(points);
- assert.strictEqual(Math.abs(expectedX - points[0]) < EPSILON, true);
- assert.strictEqual(Math.abs(expectedY - points[1]) < EPSILON, true);
- }
+ const EPSILON: number /*float*/ = 1.0E-4;
+
+ it('testSquareToQuadrilateral', () => {
+ const pt = PerspectiveTransform.squareToQuadrilateral(2.0, 3.0, 10.0, 4.0, 16.0, 15.0, 4.0, 9.0);
+ assertPointEquals(2.0, 3.0, 0.0, 0.0, pt);
+ assertPointEquals(10.0, 4.0, 1.0, 0.0, pt);
+ assertPointEquals(4.0, 9.0, 0.0, 1.0, pt);
+ assertPointEquals(16.0, 15.0, 1.0, 1.0, pt);
+ assertPointEquals(6.535211, 6.8873234, 0.5, 0.5, pt);
+ assertPointEquals(48.0, 42.42857, 1.5, 1.5, pt);
+ });
+
+ it('testQuadrilateralToQuadrilateral', () => {
+ const pt = PerspectiveTransform.quadrilateralToQuadrilateral(
+ 2.0, 3.0, 10.0, 4.0, 16.0, 15.0, 4.0, 9.0,
+ 103.0, 110.0, 300.0, 120.0, 290.0, 270.0, 150.0, 280.0);
+ assertPointEquals(103.0, 110.0, 2.0, 3.0, pt);
+ assertPointEquals(300.0, 120.0, 10.0, 4.0, pt);
+ assertPointEquals(290.0, 270.0, 16.0, 15.0, pt);
+ assertPointEquals(150.0, 280.0, 4.0, 9.0, pt);
+ assertPointEquals(7.1516876, -64.60185, 0.5, 0.5, pt);
+ assertPointEquals(328.09116, 334.16385, 50.0, 50.0, pt);
+ });
+
+ function assertPointEquals(expectedX: number/*float*/,
+ expectedY: number/*float*/,
+ sourceX: number/*float*/,
+ sourceY: number/*float*/,
+ pt: PerspectiveTransform) {
+ const points = Float32Array.from([sourceX, sourceY]);
+ pt.transformPoints(points);
+ assert.strictEqual(Math.abs(expectedX - points[0]) < EPSILON, true);
+ assert.strictEqual(Math.abs(expectedY - points[1]) < EPSILON, true);
+ }
});
diff --git a/src/test/core/common/StringUtils.spec.ts b/src/test/core/common/StringUtils.spec.ts
index 52cbb442..e9162291 100644
--- a/src/test/core/common/StringUtils.spec.ts
+++ b/src/test/core/common/StringUtils.spec.ts
@@ -25,50 +25,50 @@ import { CharacterSetECI } from '@zxing/library';
describe('StringUtils', () => {
- it('testShortShiftJIS_1', () => {
- // ΓÑëΓβ ΓΆ
- doTest(Uint8Array.from([/*(byte)*/ 0x8b, /*(byte)*/ 0xe0, /*(byte)*/ 0x8b, /*(byte)*/ 0x9b]), CharacterSetECI.SJIS.getName()/*"SJIS"*/);
- });
+ it('testShortShiftJIS_1', () => {
+ // ΓÑëΓβ ΓΆ
+ doTest(Uint8Array.from([/*(byte)*/ 0x8b, /*(byte)*/ 0xe0, /*(byte)*/ 0x8b, /*(byte)*/ 0x9b]), CharacterSetECI.SJIS.getName()/*"SJIS"*/);
+ });
- it('testShortISO88591_1', () => {
- // bββ’d
- doTest(Uint8Array.from([/*(byte)*/ 0x62, /*(byte)*/ 0xe5, /*(byte)*/ 0x64]), CharacterSetECI.ISO8859_1.getName()/*"ISO-8859-1"*/);
- });
+ it('testShortISO88591_1', () => {
+ // bββ’d
+ doTest(Uint8Array.from([/*(byte)*/ 0x62, /*(byte)*/ 0xe5, /*(byte)*/ 0x64]), CharacterSetECI.ISO8859_1.getName()/*"ISO-8859-1"*/);
+ });
- it('testMixedShiftJIS_1', () => {
- // Hello ΓÑë!
- doTest(Uint8Array.from([/*(byte)*/ 0x48, /*(byte)*/ 0x65, /*(byte)*/ 0x6c, /*(byte)*/ 0x6c, /*(byte)*/ 0x6f,
+ it('testMixedShiftJIS_1', () => {
+ // Hello ΓÑë!
+ doTest(Uint8Array.from([/*(byte)*/ 0x48, /*(byte)*/ 0x65, /*(byte)*/ 0x6c, /*(byte)*/ 0x6c, /*(byte)*/ 0x6f,
/*(byte)*/ 0x20, /*(byte)*/ 0x8b, /*(byte)*/ 0xe0, /*(byte)*/ 0x21]),
- 'SJIS');
- });
+ 'SJIS');
+ });
- function doTest(bytes: Uint8Array, charsetName: string): void {
- // const charset: ZXingCharset = ZXingCharset.forName(charsetName);
- const guessedName: string = StringUtils.guessEncoding(bytes, null);
- // const guessedEncoding: ZXingCharset = ZXingCharset.forName(guessedName);
- // assert.strictEqual(guessedEncoding, charset)
- assert.strictEqual(guessedName, charsetName);
- }
+ function doTest(bytes: Uint8Array, charsetName: string): void {
+ // const charset: ZXingCharset = ZXingCharset.forName(charsetName);
+ const guessedName: string = StringUtils.guessEncoding(bytes, null);
+ // const guessedEncoding: ZXingCharset = ZXingCharset.forName(guessedName);
+ // assert.strictEqual(guessedEncoding, charset)
+ assert.strictEqual(guessedName, charsetName);
+ }
- /**
- * Utility for printing out a string in given encoding as a Java statement, since it's better
- * to write that into the Java source file rather than risk character encoding issues in the
- * source file itself.
- *
- * @param args command line arguments
- */
- // funtion main(String[] args): void {
- // const text: string = args[0]
- // const charset: ZXingCharset = ZXingCharset.forName(args[1]);
- // const declaration = new ZXingStringBuilder()
- // declaration.append("Uint8Array.from([")
- // for (byte b : text.getBytes(charset)) {
- // declaration.append("/*(byte)*/ 0x")
- // declaration.append(Integer.toHexString(b & 0xFF))
- // declaration.append(", ")
- // }
- // declaration.append('}')
- // System.out.println(declaration)
- // }
+ /**
+ * Utility for printing out a string in given encoding as a Java statement, since it's better
+ * to write that into the Java source file rather than risk character encoding issues in the
+ * source file itself.
+ *
+ * @param args command line arguments
+ */
+ // funtion main(String[] args): void {
+ // const text: string = args[0]
+ // const charset: ZXingCharset = ZXingCharset.forName(args[1]);
+ // const declaration = new ZXingStringBuilder()
+ // declaration.append("Uint8Array.from([")
+ // for (byte b : text.getBytes(charset)) {
+ // declaration.append("/*(byte)*/ 0x")
+ // declaration.append(Integer.toHexString(b & 0xFF))
+ // declaration.append(", ")
+ // }
+ // declaration.append('}')
+ // System.out.println(declaration)
+ // }
});
diff --git a/src/test/core/common/TestResult.ts b/src/test/core/common/TestResult.ts
index 6f84ff06..585fb383 100644
--- a/src/test/core/common/TestResult.ts
+++ b/src/test/core/common/TestResult.ts
@@ -18,32 +18,32 @@
export default class TestResult {
- public constructor(
- private mustPassCount: number /*int*/,
- private tryHarderCount: number /*int*/,
- private maxMisreads: number /*int*/,
- private maxTryHarderMisreads: number /*int*/,
- private rotation: number/*float*/) {
- }
-
- public getMustPassCount(): number /*int*/ {
- return this.mustPassCount;
- }
-
- public getTryHarderCount(): number /*int*/ {
- return this.tryHarderCount;
- }
-
- public getMaxMisreads(): number /*int*/ {
- return this.maxMisreads;
- }
-
- public getMaxTryHarderMisreads(): number /*int*/ {
- return this.maxTryHarderMisreads;
- }
-
- public getRotation(): number/*float*/ {
- return this.rotation;
- }
+ public constructor(
+ private mustPassCount: number /*int*/,
+ private tryHarderCount: number /*int*/,
+ private maxMisreads: number /*int*/,
+ private maxTryHarderMisreads: number /*int*/,
+ private rotation: number/*float*/) {
+ }
+
+ public getMustPassCount(): number /*int*/ {
+ return this.mustPassCount;
+ }
+
+ public getTryHarderCount(): number /*int*/ {
+ return this.tryHarderCount;
+ }
+
+ public getMaxMisreads(): number /*int*/ {
+ return this.maxMisreads;
+ }
+
+ public getMaxTryHarderMisreads(): number /*int*/ {
+ return this.maxTryHarderMisreads;
+ }
+
+ public getRotation(): number/*float*/ {
+ return this.rotation;
+ }
}
diff --git a/src/test/core/common/detector/MathUtils.spec.ts b/src/test/core/common/detector/MathUtils.spec.ts
index cb08ce4f..8574ef3a 100644
--- a/src/test/core/common/detector/MathUtils.spec.ts
+++ b/src/test/core/common/detector/MathUtils.spec.ts
@@ -21,45 +21,45 @@ import { MathUtils } from '@zxing/library';
describe('MathUtils', () => {
- const EPSILON: number /*float*/ = 1.0E-8;
+ const EPSILON: number /*float*/ = 1.0E-8;
- it('testRound', () => {
- assert.strictEqual(MathUtils.round(-1.0), -1);
- assert.strictEqual(MathUtils.round(0.0), 0);
- assert.strictEqual(MathUtils.round(1.0), 1);
+ it('testRound', () => {
+ assert.strictEqual(MathUtils.round(-1.0), -1);
+ assert.strictEqual(MathUtils.round(0.0), 0);
+ assert.strictEqual(MathUtils.round(1.0), 1);
- assert.strictEqual(MathUtils.round(1.9), 2);
- assert.strictEqual(MathUtils.round(2.1), 2);
+ assert.strictEqual(MathUtils.round(1.9), 2);
+ assert.strictEqual(MathUtils.round(2.1), 2);
- assert.strictEqual(MathUtils.round(2.5), 3);
+ assert.strictEqual(MathUtils.round(2.5), 3);
- assert.strictEqual(MathUtils.round(-1.9), -2);
- assert.strictEqual(MathUtils.round(-2.1), -2);
+ assert.strictEqual(MathUtils.round(-1.9), -2);
+ assert.strictEqual(MathUtils.round(-2.1), -2);
- assert.strictEqual(MathUtils.round(-2.5), -3); // This differs from Math.round()
+ assert.strictEqual(MathUtils.round(-2.5), -3); // This differs from Math.round()
- assert.strictEqual(MathUtils.round(Number.MAX_SAFE_INTEGER), Number.MAX_SAFE_INTEGER);
- assert.strictEqual(MathUtils.round(Number.MIN_SAFE_INTEGER), Number.MIN_SAFE_INTEGER);
+ assert.strictEqual(MathUtils.round(Number.MAX_SAFE_INTEGER), Number.MAX_SAFE_INTEGER);
+ assert.strictEqual(MathUtils.round(Number.MIN_SAFE_INTEGER), Number.MIN_SAFE_INTEGER);
- assert.strictEqual(MathUtils.round(Number.POSITIVE_INFINITY), Number.MAX_SAFE_INTEGER);
- assert.strictEqual(MathUtils.round(Number.NEGATIVE_INFINITY), Number.MIN_SAFE_INTEGER);
+ assert.strictEqual(MathUtils.round(Number.POSITIVE_INFINITY), Number.MAX_SAFE_INTEGER);
+ assert.strictEqual(MathUtils.round(Number.NEGATIVE_INFINITY), Number.MIN_SAFE_INTEGER);
- assert.strictEqual(MathUtils.round(NaN), 0);
- });
+ assert.strictEqual(MathUtils.round(NaN), 0);
+ });
- it('testDistance', () => {
- assert.strictEqual(Math.abs(MathUtils.distance(1.0, 2.0, 3.0, 4.0) - /*(float) */Math.sqrt(8.0)) < EPSILON, true);
- assert.strictEqual(Math.abs(MathUtils.distance(1.0, 2.0, 1.0, 2.0) - 0.0) < EPSILON, true);
+ it('testDistance', () => {
+ assert.strictEqual(Math.abs(MathUtils.distance(1.0, 2.0, 3.0, 4.0) - /*(float) */Math.sqrt(8.0)) < EPSILON, true);
+ assert.strictEqual(Math.abs(MathUtils.distance(1.0, 2.0, 1.0, 2.0) - 0.0) < EPSILON, true);
- assert.strictEqual(Math.abs(MathUtils.distance(1, 2, 3, 4) - /*(float) */Math.sqrt(8.0)) < EPSILON, true);
- assert.strictEqual(Math.abs(MathUtils.distance(1, 2, 1, 2) - 0.0) < EPSILON, true);
- });
+ assert.strictEqual(Math.abs(MathUtils.distance(1, 2, 3, 4) - /*(float) */Math.sqrt(8.0)) < EPSILON, true);
+ assert.strictEqual(Math.abs(MathUtils.distance(1, 2, 1, 2) - 0.0) < EPSILON, true);
+ });
- it('testSum', () => {
- assert.strictEqual(MathUtils.sum(Int32Array.from([])), 0);
- assert.strictEqual(MathUtils.sum(Int32Array.from([1])), 1);
- assert.strictEqual(MathUtils.sum(Int32Array.from([1, 3])), 4);
- assert.strictEqual(MathUtils.sum(Int32Array.from([-1, 1])), 0);
- });
+ it('testSum', () => {
+ assert.strictEqual(MathUtils.sum(Int32Array.from([])), 0);
+ assert.strictEqual(MathUtils.sum(Int32Array.from([1])), 1);
+ assert.strictEqual(MathUtils.sum(Int32Array.from([1, 3])), 4);
+ assert.strictEqual(MathUtils.sum(Int32Array.from([-1, 1])), 0);
+ });
});
diff --git a/src/test/core/common/reedsolomon/ReedSolomon.spec.ts b/src/test/core/common/reedsolomon/ReedSolomon.spec.ts
index d7d76172..9420cf3b 100644
--- a/src/test/core/common/reedsolomon/ReedSolomon.spec.ts
+++ b/src/test/core/common/reedsolomon/ReedSolomon.spec.ts
@@ -18,7 +18,7 @@
import * as assert from 'assert';
import { ZXingStringBuilder } from '@zxing/library';
-import Random from '../../../core/util/Random';
+import Random from '../../../core/util/Random';
import { ZXingSystem } from '@zxing/library';
import { GenericGF } from '@zxing/library';
import { ReedSolomonEncoder } from '@zxing/library';
@@ -33,470 +33,470 @@ import { corrupt } from './ReedSolomonCorrupt';
*/
describe('ReedSolomonSpec', () => {
- it('testDataMatrix 1 - real life test case', () => {
- testEncodeDecode(
- GenericGF.DATA_MATRIX_FIELD_256,
- Int32Array.from([142, 164, 186]),
- Int32Array.from([114, 25, 5, 88, 102])
- );
- });
-
- it('testDataMatrix 2 - real life test case', () => {
- testEncodeDecode(
- GenericGF.DATA_MATRIX_FIELD_256,
- Int32Array.from([
- 0x69, 0x75, 0x75, 0x71, 0x3B, 0x30, 0x30, 0x64,
- 0x70, 0x65, 0x66, 0x2F, 0x68, 0x70, 0x70, 0x68,
- 0x6D, 0x66, 0x2F, 0x64, 0x70, 0x6E, 0x30, 0x71,
- 0x30, 0x7B, 0x79, 0x6A, 0x6F, 0x68, 0x30, 0x81,
- 0xF0, 0x88, 0x1F, 0xB5
- ]),
- Int32Array.from([
- 0x1C, 0x64, 0xEE, 0xEB, 0xD0, 0x1D, 0x00, 0x03,
- 0xF0, 0x1C, 0xF1, 0xD0, 0x6D, 0x00, 0x98, 0xDA,
- 0x80, 0x88, 0xBE, 0xFF, 0xB7, 0xFA, 0xA9, 0x95
- ])
- );
- });
-
- it('testDataMatrix 3.1 - synthetic test cases', () => {
- testEncodeDecodeRandom(GenericGF.DATA_MATRIX_FIELD_256, 10, 240);
- });
-
- it('testDataMatrix 3.2 - synthetic test cases', () => {
- testEncodeDecodeRandom(GenericGF.DATA_MATRIX_FIELD_256, 128, 127);
- });
-
- it('testDataMatrix 3.3 - synthetic test cases', () => {
- testEncodeDecodeRandom(GenericGF.DATA_MATRIX_FIELD_256, 220, 35);
- });
-
- it('testQRCode 1 - from example given in ISO 18004, Annex I', () => {
-
- // Test case from example given in ISO 18004, Annex I
- testEncodeDecode(
- GenericGF.QR_CODE_FIELD_256,
- Int32Array.from([
- 0x10, 0x20, 0x0C, 0x56, 0x61, 0x80, 0xEC, 0x11,
- 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11
- ]),
- Int32Array.from([
- 0xA5, 0x24, 0xD4, 0xC1, 0xED, 0x36, 0xC7, 0x87,
- 0x2C, 0x55
- ])
- );
-
- });
-
- it('testQRCode 2 - real life test case', () => {
- testEncodeDecode(
- GenericGF.QR_CODE_FIELD_256,
- Int32Array.from([
- 0x72, 0x67, 0x2F, 0x77, 0x69, 0x6B, 0x69, 0x2F,
- 0x4D, 0x61, 0x69, 0x6E, 0x5F, 0x50, 0x61, 0x67,
- 0x65, 0x3B, 0x3B, 0x00, 0xEC, 0x11, 0xEC, 0x11,
- 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11
- ]),
- Int32Array.from([
- 0xD8, 0xB8, 0xEF, 0x14, 0xEC, 0xD0, 0xCC, 0x85,
- 0x73, 0x40, 0x0B, 0xB5, 0x5A, 0xB8, 0x8B, 0x2E,
- 0x08, 0x62
- ])
- );
- });
-
- it('testQRCode 3.1 - synthetic test cases', () => {
- testEncodeDecodeRandom(GenericGF.QR_CODE_FIELD_256, 10, 240);
- });
-
- it('testQRCode 3.2 - synthetic test cases', () => {
- testEncodeDecodeRandom(GenericGF.QR_CODE_FIELD_256, 128, 127);
- });
-
- it('testQRCode 3.3 - synthetic test cases', () => {
- testEncodeDecodeRandom(GenericGF.QR_CODE_FIELD_256, 220, 35);
- });
-
- it('testAztec 1 - real life test case', () => {
- testEncodeDecode(
- GenericGF.AZTEC_PARAM,
- Int32Array.from([0x5, 0x6]),
- Int32Array.from([0x3, 0x2, 0xB, 0xB, 0x7])
- );
- });
-
- it('testAztec 2 - real life test case', () => {
- testEncodeDecode(
- GenericGF.AZTEC_PARAM,
- Int32Array.from([0x0, 0x0, 0x0, 0x9]),
- Int32Array.from([0xA, 0xD, 0x8, 0x6, 0x5, 0x6])
- );
- });
-
- it('testAztec 3 - real life test case', () => {
- testEncodeDecode(
- GenericGF.AZTEC_PARAM,
- Int32Array.from([0x2, 0x8, 0x8, 0x7]),
- Int32Array.from([0xE, 0xC, 0xA, 0x9, 0x6, 0x8])
- );
- });
-
- it('testAztec 4 - real life test case', () => {
- testEncodeDecode(
- GenericGF.AZTEC_DATA_6,
- Int32Array.from([0x9, 0x32, 0x1, 0x29, 0x2F, 0x2, 0x27, 0x25, 0x1, 0x1B]),
- Int32Array.from([0x2C, 0x2, 0xD, 0xD, 0xA, 0x16, 0x28, 0x9, 0x22, 0xA, 0x14])
- );
- });
-
- it('testAztec 5 - real life test case', () => {
- testEncodeDecode(
- GenericGF.AZTEC_DATA_8,
- Int32Array.from([
- 0xE0, 0x86, 0x42, 0x98, 0xE8, 0x4A, 0x96, 0xC6,
- 0xB9, 0xF0, 0x8C, 0xA7, 0x4A, 0xDA, 0xF8, 0xCE,
- 0xB7, 0xDE, 0x88, 0x64, 0x29, 0x8E, 0x84, 0xA9,
- 0x6C, 0x6B, 0x9F, 0x08, 0xCA, 0x74, 0xAD, 0xAF,
- 0x8C, 0xEB, 0x7C, 0x10, 0xC8, 0x53, 0x1D, 0x09,
- 0x52, 0xD8, 0xD7, 0x3E, 0x11, 0x94, 0xE9, 0x5B,
- 0x5F, 0x19, 0xD6, 0xFB, 0xD1, 0x0C, 0x85, 0x31,
- 0xD0, 0x95, 0x2D, 0x8D, 0x73, 0xE1, 0x19, 0x4E,
- 0x95, 0xB5, 0xF1, 0x9D, 0x6F]),
- Int32Array.from([
- 0x31, 0xD7, 0x04, 0x46, 0xB2, 0xC1, 0x06, 0x94,
- 0x17, 0xE5, 0x0C, 0x2B, 0xA3, 0x99, 0x15, 0x7F,
- 0x16, 0x3C, 0x66, 0xBA, 0x33, 0xD9, 0xE8, 0x87,
- 0x86, 0xBB, 0x4B, 0x15, 0x4E, 0x4A, 0xDE, 0xD4,
- 0xED, 0xA1, 0xF8, 0x47, 0x2A, 0x50, 0xA6, 0xBC,
- 0x53, 0x7D, 0x29, 0xFE, 0x06, 0x49, 0xF3, 0x73,
- 0x9F, 0xC1, 0x75])
- );
- });
-
- it('testAztec 6 - real life test case', () => {
- testEncodeDecode(
- GenericGF.AZTEC_DATA_10,
- Int32Array.from([
- 0x15C, 0x1E1, 0x2D5, 0x02E, 0x048, 0x1E2, 0x037, 0x0CD,
- 0x02E, 0x056, 0x26A, 0x281, 0x1C2, 0x1A6, 0x296, 0x045,
- 0x041, 0x0AA, 0x095, 0x2CE, 0x003, 0x38F, 0x2CD, 0x1A2,
- 0x036, 0x1AD, 0x04E, 0x090, 0x271, 0x0D3, 0x02E, 0x0D5,
- 0x2D4, 0x032, 0x2CA, 0x281, 0x0AA, 0x04E, 0x024, 0x2D3,
- 0x296, 0x281, 0x0E2, 0x08A, 0x1AA, 0x28A, 0x280, 0x07C,
- 0x286, 0x0A1, 0x1D0, 0x1AD, 0x154, 0x032, 0x2C2, 0x1C1,
- 0x145, 0x02B, 0x2D4, 0x2B0, 0x033, 0x2D5, 0x276, 0x1C1,
- 0x282, 0x10A, 0x2B5, 0x154, 0x003, 0x385, 0x20F, 0x0C4,
- 0x02D, 0x050, 0x266, 0x0D5, 0x033, 0x2D5, 0x276, 0x1C1,
- 0x0D4, 0x2A0, 0x08F, 0x0C4, 0x024, 0x20F, 0x2E2, 0x1AD,
- 0x154, 0x02E, 0x056, 0x26A, 0x281, 0x090, 0x1E5, 0x14E,
- 0x0CF, 0x2B6, 0x1C1, 0x28A, 0x2A1, 0x04E, 0x0D5, 0x003,
- 0x391, 0x122, 0x286, 0x1AD, 0x2D4, 0x028, 0x262, 0x2EA,
- 0x0A2, 0x004, 0x176, 0x295, 0x201, 0x0D5, 0x024, 0x20F,
- 0x116, 0x0C1, 0x056, 0x095, 0x213, 0x004, 0x1EA, 0x28A,
- 0x02A, 0x234, 0x2CE, 0x037, 0x157, 0x0D3, 0x262, 0x026,
- 0x262, 0x2A0, 0x086, 0x106, 0x2A1, 0x126, 0x1E5, 0x266,
- 0x26A, 0x2A1, 0x0E6, 0x1AA, 0x281, 0x2B6, 0x271, 0x154,
- 0x02F, 0x0C4, 0x02D, 0x213, 0x0CE, 0x003, 0x38F, 0x2CD,
- 0x1A2, 0x036, 0x1B5, 0x26A, 0x086, 0x280, 0x086, 0x1AA,
- 0x2A1, 0x226, 0x1AD, 0x0CF, 0x2A6, 0x292, 0x2C6, 0x022,
- 0x1AA, 0x256, 0x0D5, 0x02D, 0x050, 0x266, 0x0D5, 0x004,
- 0x176, 0x295, 0x201, 0x0D3, 0x055, 0x031, 0x2CD, 0x2EA,
- 0x1E2, 0x261, 0x1EA, 0x28A, 0x004, 0x145, 0x026, 0x1A6,
- 0x1C6, 0x1F5, 0x2CE, 0x034, 0x051, 0x146, 0x1E1, 0x0B0,
- 0x1B0, 0x261, 0x0D5, 0x025, 0x142, 0x1C0, 0x07C, 0x0B0,
- 0x1E6, 0x081, 0x044, 0x02F, 0x2CF, 0x081, 0x290, 0x0A2,
- 0x1A6, 0x281, 0x0CD, 0x155, 0x031, 0x1A2, 0x086, 0x262,
- 0x2A1, 0x0CD, 0x0CA, 0x0E6, 0x1E5, 0x003, 0x394, 0x0C5,
- 0x030, 0x26F, 0x053, 0x0C1, 0x1B6, 0x095, 0x2D4, 0x030,
- 0x26F, 0x053, 0x0C0, 0x07C, 0x2E6, 0x295, 0x143, 0x2CD,
- 0x2CE, 0x037, 0x0C9, 0x144, 0x2CD, 0x040, 0x08E, 0x054,
- 0x282, 0x022, 0x2A1, 0x229, 0x053, 0x0D5, 0x262, 0x027,
- 0x26A, 0x1E8, 0x14D, 0x1A2, 0x004, 0x26A, 0x296, 0x281,
- 0x176, 0x295, 0x201, 0x0E2, 0x2C4, 0x143, 0x2D4, 0x026,
- 0x262, 0x2A0, 0x08F, 0x0C4, 0x031, 0x213, 0x2B5, 0x155,
- 0x213, 0x02F, 0x143, 0x121, 0x2A6, 0x1AD, 0x2D4, 0x034,
- 0x0C5, 0x026, 0x295, 0x003, 0x396, 0x2A1, 0x176, 0x295,
- 0x201, 0x0AA, 0x04E, 0x004, 0x1B0, 0x070, 0x275, 0x154,
- 0x026, 0x2C1, 0x2B3, 0x154, 0x2AA, 0x256, 0x0C1, 0x044,
- 0x004, 0x23F
- ]),
- Int32Array.from([
- 0x379, 0x099, 0x348, 0x010, 0x090, 0x196, 0x09C, 0x1FF,
- 0x1B0, 0x32D, 0x244, 0x0DE, 0x201, 0x386, 0x163, 0x11F,
- 0x39B, 0x344, 0x3FE, 0x02F, 0x188, 0x113, 0x3D9, 0x102,
- 0x04A, 0x2E1, 0x1D1, 0x18E, 0x077, 0x262, 0x241, 0x20D,
- 0x1B8, 0x11D, 0x0D0, 0x0A5, 0x29C, 0x24D, 0x3E7, 0x006,
- 0x2D0, 0x1B7, 0x337, 0x178, 0x0F1, 0x1E0, 0x00B, 0x01E,
- 0x0DA, 0x1C6, 0x2D9, 0x00D, 0x28B, 0x34A, 0x252, 0x27A,
- 0x057, 0x0CA, 0x2C2, 0x2E4, 0x3A6, 0x0E3, 0x22B, 0x307,
- 0x174, 0x292, 0x10C, 0x1ED, 0x2FD, 0x2D4, 0x0A7, 0x051,
- 0x34F, 0x07A, 0x1D5, 0x01D, 0x22E, 0x2C2, 0x1DF, 0x08F,
- 0x105, 0x3FE, 0x286, 0x2A2, 0x3B1, 0x131, 0x285, 0x362,
- 0x315, 0x13C, 0x0F9, 0x1A2, 0x28D, 0x246, 0x1B3, 0x12C,
- 0x2AD, 0x0F8, 0x222, 0x0EC, 0x39F, 0x358, 0x014, 0x229,
- 0x0C8, 0x360, 0x1C2, 0x031, 0x098, 0x041, 0x3E4, 0x046,
- 0x332, 0x318, 0x2E3, 0x24E, 0x3E2, 0x1E1, 0x0BE, 0x239,
- 0x306, 0x3A5, 0x352, 0x351, 0x275, 0x0ED, 0x045, 0x229,
- 0x0BF, 0x05D, 0x253, 0x1BE, 0x02E, 0x35A, 0x0E4, 0x2E9,
- 0x17A, 0x166, 0x03C, 0x007
- ])
- );
- });
-
- it('testAztec 7 - real life test case', () => {
- testEncodeDecode(
- GenericGF.AZTEC_DATA_12,
- Int32Array.from([
- 0x571, 0xE1B, 0x542, 0xE12, 0x1E2, 0x0DC, 0xCD0, 0xB85,
- 0x69A, 0xA81, 0x709, 0xA6A, 0x584, 0x510, 0x4AA, 0x256,
- 0xCE0, 0x0F8, 0xFB3, 0x5A2, 0x0D9, 0xAD1, 0x389, 0x09C,
- 0x4D3, 0x0B8, 0xD5B, 0x503, 0x2B2, 0xA81, 0x2A8, 0x4E0,
- 0x92D, 0x3A5, 0xA81, 0x388, 0x8A6, 0xAA8, 0xAA0, 0x07C,
- 0xA18, 0xA17, 0x41A, 0xD55, 0x032, 0xB09, 0xC15, 0x142,
- 0xBB5, 0x2B0, 0x0CE, 0xD59, 0xD9C, 0x1A0, 0x90A, 0xAD5,
- 0x540, 0x0F8, 0x583, 0xCC4, 0x0B4, 0x509, 0x98D, 0x50C,
- 0xED5, 0x9D9, 0xC13, 0x52A, 0x023, 0xCC4, 0x092, 0x0FB,
- 0x89A, 0xD55, 0x02E, 0x15A, 0x6AA, 0x049, 0x079, 0x54E,
- 0x33E, 0xB67, 0x068, 0xAA8, 0x44E, 0x354, 0x03E, 0x452,
- 0x2A1, 0x9AD, 0xB50, 0x289, 0x8AE, 0xA28, 0x804, 0x5DA,
- 0x958, 0x04D, 0x509, 0x20F, 0x458, 0xC11, 0x589, 0x584,
- 0xC04, 0x7AA, 0x8A0, 0xAA3, 0x4B3, 0x837, 0x55C, 0xD39,
- 0x882, 0x698, 0xAA0, 0x219, 0x06A, 0x852, 0x679, 0x666,
- 0x9AA, 0xA13, 0x99A, 0xAA0, 0x6B6, 0x9C5, 0x540, 0xBCC,
- 0x40B, 0x613, 0x338, 0x03E, 0x3EC, 0xD68, 0x836, 0x6D6,
- 0x6A2, 0x1A8, 0x021, 0x9AA, 0xA86, 0x266, 0xB4C, 0xFA9,
- 0xA92, 0xB18, 0x226, 0xAA5, 0x635, 0x42D, 0x142, 0x663,
- 0x540, 0x45D, 0xA95, 0x804, 0xD31, 0x543, 0x1B3, 0x6EA,
- 0x78A, 0x617, 0xAA8, 0xA01, 0x145, 0x099, 0xA67, 0x19F,
- 0x5B3, 0x834, 0x145, 0x467, 0x84B, 0x06C, 0x261, 0x354,
- 0x255, 0x09C, 0x01F, 0x0B0, 0x798, 0x811, 0x102, 0xFB3,
- 0xC81, 0xA40, 0xA26, 0x9A8, 0x133, 0x555, 0x0C5, 0xA22,
- 0x1A6, 0x2A8, 0x4CD, 0x328, 0xE67, 0x940, 0x3E5, 0x0C5,
- 0x0C2, 0x6F1, 0x4CC, 0x16D, 0x895, 0xB50, 0x309, 0xBC5,
- 0x330, 0x07C, 0xB9A, 0x955, 0x0EC, 0xDB3, 0x837, 0x325,
- 0x44B, 0x344, 0x023, 0x854, 0xA08, 0x22A, 0x862, 0x914,
- 0xCD5, 0x988, 0x279, 0xA9E, 0x853, 0x5A2, 0x012, 0x6AA,
- 0x5A8, 0x15D, 0xA95, 0x804, 0xE2B, 0x114, 0x3B5, 0x026,
- 0x98A, 0xA02, 0x3CC, 0x40C, 0x613, 0xAD5, 0x558, 0x4C2,
- 0xF50, 0xD21, 0xA99, 0xADB, 0x503, 0x431, 0x426, 0xA54,
- 0x03E, 0x5AA, 0x15D, 0xA95, 0x804, 0xAA1, 0x380, 0x46C,
- 0x070, 0x9D5, 0x540, 0x9AC, 0x1AC, 0xD54, 0xAAA, 0x563,
- 0x044, 0x401, 0x220, 0x9F1, 0x4F0, 0xDAA, 0x170, 0x90F,
- 0x106, 0xE66, 0x85C, 0x2B4, 0xD54, 0x0B8, 0x4D3, 0x52C,
- 0x228, 0x825, 0x512, 0xB67, 0x007, 0xC7D, 0x9AD, 0x106,
- 0xCD6, 0x89C, 0x484, 0xE26, 0x985, 0xC6A, 0xDA8, 0x195,
- 0x954, 0x095, 0x427, 0x049, 0x69D, 0x2D4, 0x09C, 0x445,
- 0x355, 0x455, 0x003, 0xE50, 0xC50, 0xBA0, 0xD6A, 0xA81,
- 0x958, 0x4E0, 0xA8A, 0x15D, 0xA95, 0x806, 0x76A, 0xCEC,
- 0xE0D, 0x048, 0x556, 0xAAA, 0x007, 0xC2C, 0x1E6, 0x205,
- 0xA28, 0x4CC, 0x6A8, 0x676, 0xACE, 0xCE0, 0x9A9, 0x501,
- 0x1E6, 0x204, 0x907, 0xDC4, 0xD6A, 0xA81, 0x70A, 0xD35,
- 0x502, 0x483, 0xCAA, 0x719, 0xF5B, 0x383, 0x455, 0x422,
- 0x71A, 0xA01, 0xF22, 0x915, 0x0CD, 0x6DA, 0x814, 0x4C5,
- 0x751, 0x440, 0x22E, 0xD4A, 0xC02, 0x6A8, 0x490, 0x7A2,
- 0xC60, 0x8AC, 0x4AC, 0x260, 0x23D, 0x545, 0x055, 0x1A5,
- 0x9C1, 0xBAA, 0xE69, 0xCC4, 0x134, 0xC55, 0x010, 0xC83,
- 0x542, 0x933, 0xCB3, 0x34D, 0x550, 0x9CC, 0xD55, 0x035,
- 0xB4E, 0x2AA, 0x05E, 0x620, 0x5B0, 0x999, 0xC01, 0xF1F,
- 0x66B, 0x441, 0xB36, 0xB35, 0x10D, 0x401, 0x0CD, 0x554,
- 0x313, 0x35A, 0x67D, 0x4D4, 0x958, 0xC11, 0x355, 0x2B1,
- 0xAA1, 0x68A, 0x133, 0x1AA, 0x022, 0xED4, 0xAC0, 0x269,
- 0x8AA, 0x18D, 0x9B7, 0x53C, 0x530, 0xBD5, 0x450, 0x08A,
- 0x284, 0xCD3, 0x38C, 0xFAD, 0x9C1, 0xA0A, 0x2A3, 0x3C2,
- 0x583, 0x613, 0x09A, 0xA12, 0xA84, 0xE00, 0xF85, 0x83C,
- 0xC40, 0x888, 0x17D, 0x9E4, 0x0D2, 0x051, 0x34D, 0x409,
- 0x9AA, 0xA86, 0x2D1, 0x10D, 0x315, 0x426, 0x699, 0x473,
- 0x3CA, 0x01F, 0x286, 0x286, 0x137, 0x8A6, 0x60B, 0x6C4,
- 0xADA, 0x818, 0x4DE, 0x299, 0x803, 0xE5C, 0xD4A, 0xA87,
- 0x66D, 0x9C1, 0xB99, 0x2A2, 0x59A, 0x201, 0x1C2, 0xA50,
- 0x411, 0x543, 0x148, 0xA66, 0xACC, 0x413, 0xCD4, 0xF42,
- 0x9AD, 0x100, 0x935, 0x52D, 0x40A, 0xED4, 0xAC0, 0x271,
- 0x588, 0xA1D, 0xA81, 0x34C, 0x550, 0x11E, 0x620, 0x630,
- 0x9D6, 0xAAA, 0xC26, 0x17A, 0x869, 0x0D4, 0xCD6, 0xDA8,
- 0x1A1, 0x8A1, 0x352, 0xA01, 0xF2D, 0x50A, 0xED4, 0xAC0,
- 0x255, 0x09C, 0x023, 0x603, 0x84E, 0xAAA, 0x04D, 0x60D,
- 0x66A, 0xA55, 0x52B, 0x182, 0x220, 0x091, 0x00F, 0x8A7,
- 0x86D, 0x50B, 0x848, 0x788, 0x373, 0x342, 0xE15, 0xA6A,
- 0xA05, 0xC26, 0x9A9, 0x611, 0x441, 0x2A8, 0x95B, 0x380,
- 0x3E3, 0xECD, 0x688, 0x366, 0xB44, 0xE24, 0x271, 0x34C,
- 0x2E3, 0x56D, 0x40C, 0xACA, 0xA04, 0xAA1, 0x382, 0x4B4,
- 0xE96, 0xA04, 0xE22, 0x29A, 0xAA2, 0xA80, 0x1F2, 0x862,
- 0x85D, 0x06B, 0x554, 0x0CA, 0xC27, 0x054, 0x50A, 0xED4,
- 0xAC0, 0x33B, 0x567, 0x670, 0x682, 0x42A, 0xB55, 0x500,
- 0x3E1, 0x60F, 0x310, 0x2D1, 0x426, 0x635, 0x433, 0xB56,
- 0x767, 0x04D, 0x4A8, 0x08F, 0x310, 0x248, 0x3EE, 0x26B,
- 0x554, 0x0B8, 0x569, 0xAA8, 0x124, 0x1E5, 0x538, 0xCFA,
- 0xD9C, 0x1A2, 0xAA1, 0x138, 0xD50, 0x0F9, 0x148, 0xA86,
- 0x6B6, 0xD40, 0xA26, 0x2BA, 0x8A2, 0x011, 0x76A, 0x560,
- 0x135, 0x424, 0x83D, 0x163, 0x045, 0x625, 0x613, 0x011,
- 0xEAA, 0x282, 0xA8D, 0x2CE, 0x0DD, 0x573, 0x4E6, 0x209,
- 0xA62, 0xA80, 0x864, 0x1AA, 0x149, 0x9E5, 0x99A, 0x6AA,
- 0x84E, 0x66A, 0xA81, 0xADA, 0x715, 0x502, 0xF31, 0x02D,
- 0x84C, 0xCE0, 0x0F8, 0xFB3, 0x5A2, 0x0D9, 0xB59, 0xA88,
- 0x6A0, 0x086, 0x6AA, 0xA18, 0x99A, 0xD33, 0xEA6, 0xA4A,
- 0xC60, 0x89A, 0xA95, 0x8D5, 0x0B4, 0x509, 0x98D, 0x501,
- 0x176, 0xA56, 0x013, 0x4C5, 0x50C, 0x6CD, 0xBA9, 0xE29,
- 0x85E, 0xAA2, 0x804, 0x514, 0x266, 0x99C, 0x67D, 0x6CE,
- 0x0D0, 0x515, 0x19E, 0x12C, 0x1B0, 0x984, 0xD50, 0x954,
- 0x270, 0x07C, 0x2C1, 0xE62, 0x044, 0x40B, 0xECF, 0x206,
- 0x902, 0x89A, 0x6A0, 0x4CD, 0x554, 0x316, 0x888, 0x698,
- 0xAA1, 0x334, 0xCA3, 0x99E, 0x500, 0xF94, 0x314, 0x309,
- 0xBC5, 0x330, 0x5B6, 0x256, 0xD40, 0xC26, 0xF14, 0xCC0,
- 0x1F2, 0xE6A, 0x554, 0x3B3, 0x6CE, 0x0DC, 0xC95, 0x12C,
- 0xD10, 0x08E, 0x152, 0x820, 0x8AA, 0x18A, 0x453, 0x356,
- 0x620, 0x9E6, 0xA7A, 0x14D, 0x688, 0x049, 0xAA9, 0x6A0,
- 0x576, 0xA56, 0x013, 0x8AC, 0x450, 0xED4, 0x09A, 0x62A,
- 0x808, 0xF31, 0x031, 0x84E, 0xB55, 0x561, 0x30B, 0xD43,
- 0x486, 0xA66, 0xB6D, 0x40D, 0x0C5, 0x09A, 0x950, 0x0F9,
- 0x6A8, 0x576, 0xA56, 0x012, 0xA84, 0xE01, 0x1B0, 0x1C2,
- 0x755, 0x502, 0x6B0, 0x6B3, 0x552, 0xAA9, 0x58C, 0x111,
- 0x004, 0x882, 0x7C5, 0x3C3, 0x6A8, 0x5C2, 0x43C, 0x41B,
- 0x99A, 0x170, 0xAD3, 0x550, 0x2E1, 0x34D, 0x4B0, 0x8A2,
- 0x095, 0x44A, 0xD9C, 0x01F, 0x1F6, 0x6B4, 0x41B, 0x35A,
- 0x271, 0x213, 0x89A, 0x617, 0x1AB, 0x6A0, 0x656, 0x550,
- 0x255, 0x09C, 0x125, 0xA74, 0xB50, 0x271, 0x114, 0xD55,
- 0x154, 0x00F, 0x943, 0x142, 0xE83, 0x5AA, 0xA06, 0x561,
- 0x382, 0xA28, 0x576, 0xA56, 0x019, 0xDAB, 0x3B3, 0x834,
- 0x121, 0x55A, 0xAA8, 0x01F, 0x0B0, 0x798, 0x816, 0x8A1,
- 0x331, 0xAA1, 0x9DA, 0xB3B, 0x382, 0x6A5, 0x404, 0x798,
- 0x812, 0x41F, 0x713, 0x5AA, 0xA05, 0xC2B, 0x4D5, 0x409,
- 0x20F, 0x2A9, 0xC67, 0xD6C, 0xE0D, 0x155, 0x089, 0xC6A,
- 0x807, 0xC8A, 0x454, 0x335, 0xB6A, 0x051, 0x315, 0xD45,
- 0x100, 0x8BB, 0x52B, 0x009, 0xAA1, 0x241, 0xE8B, 0x182,
- 0x2B1, 0x2B0, 0x980, 0x8F5, 0x514, 0x154, 0x696, 0x706,
- 0xEAB, 0x9A7, 0x310, 0x4D3, 0x154, 0x043, 0x20D, 0x50A,
- 0x4CF, 0x2CC, 0xD35, 0x542, 0x733, 0x554, 0x0D6, 0xD38,
- 0xAA8, 0x179, 0x881, 0x6C2, 0x667, 0x007, 0xC7D, 0x9AD,
- 0x106, 0xCDA, 0xCD4, 0x435, 0x004, 0x335, 0x550, 0xC4C,
- 0xD69, 0x9F5, 0x352, 0x563, 0x044, 0xD54, 0xAC6, 0xA85,
- 0xA28, 0x4CC, 0x6A8, 0x08B, 0xB52, 0xB00, 0x9A6, 0x2A8,
- 0x636, 0x6DD, 0x4F1, 0x4C2, 0xF55, 0x140, 0x228, 0xA13,
- 0x34C, 0xE33, 0xEB6, 0x706, 0x828, 0xA8C, 0xF09, 0x60D,
- 0x84C, 0x26A, 0x84A, 0xA13, 0x803, 0xE16, 0x0F3, 0x102,
- 0x220, 0x5F6, 0x790, 0x348, 0x144, 0xD35, 0x026, 0x6AA,
- 0xA18, 0xB44, 0x434, 0xC55, 0x099, 0xA65, 0x1CC, 0xF28,
- 0x07C, 0xA18, 0xA18, 0x4DE, 0x299, 0x82D, 0xB12, 0xB6A,
- 0x061, 0x378, 0xA66, 0x00F, 0x973, 0x52A, 0xA1D, 0x9B6,
- 0x706, 0xE64, 0xA89, 0x668, 0x804, 0x70A, 0x941, 0x045,
- 0x50C, 0x522, 0x99A, 0xB31, 0x04F, 0x353, 0xD0A, 0x6B4,
- 0x402, 0x4D5, 0x4B5, 0x02B, 0xB52, 0xB00, 0x9C5, 0x622,
- 0x876, 0xA04, 0xD31, 0x540, 0x479, 0x881, 0x8C2, 0x75A,
- 0xAAB, 0x098, 0x5EA, 0x1A4, 0x353, 0x35B, 0x6A0, 0x686,
- 0x284, 0xD4A, 0x807, 0xCB5, 0x42B, 0xB52, 0xB00, 0x954,
- 0x270, 0x08D, 0x80E, 0x13A, 0xAA8, 0x135, 0x835, 0x9AA,
- 0x801, 0xF14, 0xF0D, 0xAA1, 0x709, 0x0F1, 0x06E, 0x668,
- 0x5C2, 0xB4D, 0x540, 0xB84, 0xD35, 0x2C2, 0x288, 0x255,
- 0x12B, 0x670, 0x07C, 0x7D9, 0xAD1, 0x06C, 0xD68, 0x9C4,
- 0x84E, 0x269, 0x85C, 0x6AD, 0xA81, 0x959, 0x540, 0x954,
- 0x270, 0x496, 0x9D2, 0xD40, 0x9C4, 0x453, 0x554, 0x550,
- 0x03E, 0x50C, 0x50B, 0xA0D, 0x6AA, 0x819, 0x584, 0xE0A,
- 0x8A1, 0x5DA, 0x958, 0x067, 0x6AC, 0xECE, 0x0D0, 0x485,
- 0x56A, 0xAA0, 0x07C, 0x2C1, 0xE62, 0x05A, 0x284, 0xCC6,
- 0xA86, 0x76A, 0xCEC, 0xE09, 0xA95, 0x011, 0xE62, 0x049,
- 0x07D, 0xC4D, 0x6AA, 0x817, 0x0AD, 0x355, 0x024, 0x83C,
- 0xAA7, 0x19F, 0x5B3, 0x834, 0x554, 0x227, 0x1AA, 0x01F,
- 0x229, 0x150, 0xCD6, 0xDA8, 0x144, 0xC57, 0x514, 0x402,
- 0x2ED, 0x4AC, 0x026, 0xA84, 0x907, 0xA2C, 0x608, 0xAC4,
- 0xAC2, 0x602, 0x3D5, 0x450, 0x551, 0xA59, 0xC1B, 0xAAE,
- 0x69C, 0xC41, 0x34C, 0x550, 0x10C, 0x835, 0x429, 0x33C,
- 0xB33, 0x4D5, 0x509, 0xCCD, 0x550, 0x35B, 0x4E2, 0xAA0,
- 0x5E6, 0x205, 0xB09, 0x99C, 0x09F
- ]),
- Int32Array.from([
- 0xD54, 0x221, 0x154, 0x7CD, 0xBF3, 0x112, 0x89B, 0xC5E,
- 0x9CD, 0x07E, 0xFB6, 0x78F, 0x7FA, 0x16F, 0x377, 0x4B4,
- 0x62D, 0x475, 0xBC2, 0x861, 0xB72, 0x9D0, 0x76A, 0x5A1,
- 0x22A, 0xF74, 0xDBA, 0x8B1, 0x139, 0xDCD, 0x012, 0x293,
- 0x705, 0xA34, 0xDD5, 0x3D2, 0x7F8, 0x0A6, 0x89A, 0x346,
- 0xCE0, 0x690, 0x40E, 0xFF3, 0xC4D, 0x97F, 0x9C9, 0x016,
- 0x73A, 0x923, 0xBCE, 0xFA9, 0xE6A, 0xB92, 0x02A, 0x07C,
- 0x04B, 0x8D5, 0x753, 0x42E, 0x67E, 0x87C, 0xEE6, 0xD7D,
- 0x2BF, 0xFB2, 0xFF8, 0x42F, 0x4CB, 0x214, 0x779, 0x02D,
- 0x606, 0xA02, 0x08A, 0xD4F, 0xB87, 0xDDF, 0xC49, 0xB51,
- 0x0E9, 0xF89, 0xAEF, 0xC92, 0x383, 0x98D, 0x367, 0xBD3,
- 0xA55, 0x148, 0x9DB, 0x913, 0xC79, 0x6FF, 0x387, 0x6EA,
- 0x7FA, 0xC1B, 0x12D, 0x303, 0xBCA, 0x503, 0x0FB, 0xB14,
- 0x0D4, 0xAD1, 0xAFC, 0x9DD, 0x404, 0x145, 0x6E5, 0x8ED,
- 0xF94, 0xD72, 0x645, 0xA21, 0x1A8, 0xABF, 0xC03, 0x91E,
- 0xD53, 0x48C, 0x471, 0x4E4, 0x408, 0x33C, 0x5DF, 0x73D,
- 0xA2A, 0x454, 0xD77, 0xC48, 0x2F5, 0x96A, 0x9CF, 0x047,
- 0x611, 0xE92, 0xC2F, 0xA98, 0x56D, 0x919, 0x615, 0x535,
- 0x67A, 0x8C1, 0x2E2, 0xBC4, 0xBE8, 0x328, 0x04F, 0x257,
- 0x3F9, 0xFA5, 0x477, 0x12E, 0x94B, 0x116, 0xEF7, 0x65F,
- 0x6B3, 0x915, 0xC64, 0x9AF, 0xB6C, 0x6A2, 0x50D, 0xEA3,
- 0x26E, 0xC23, 0x817, 0xA42, 0x71A, 0x9DD, 0xDA8, 0x84D,
- 0x3F3, 0x85B, 0xB00, 0x1FC, 0xB0A, 0xC2F, 0x00C, 0x095,
- 0xC58, 0x0E3, 0x807, 0x962, 0xC4B, 0x29A, 0x6FC, 0x958,
- 0xD29, 0x59E, 0xB14, 0x95A, 0xEDE, 0xF3D, 0xFB8, 0x0E5,
- 0x348, 0x2E7, 0x38E, 0x56A, 0x410, 0x3B1, 0x4B0, 0x793,
- 0xAB7, 0x0BC, 0x648, 0x719, 0xE3E, 0xFB4, 0x3B4, 0xE5C,
- 0x950, 0xD2A, 0x50B, 0x76F, 0x8D2, 0x3C7, 0xECC, 0x87C,
- 0x53A, 0xBA7, 0x4C3, 0x148, 0x437, 0x820, 0xECD, 0x660,
- 0x095, 0x2F4, 0x661, 0x6A4, 0xB74, 0x5F3, 0x1D2, 0x7EC,
- 0x8E2, 0xA40, 0xA6F, 0xFC3, 0x3BE, 0x1E9, 0x52C, 0x233,
- 0x173, 0x4EF, 0xA7C, 0x40B, 0x14C, 0x88D, 0xF30, 0x8D9,
- 0xBDB, 0x0A6, 0x940, 0xD46, 0xB2B, 0x03E, 0x46A, 0x641,
- 0xF08, 0xAFF, 0x496, 0x68A, 0x7A4, 0x0BA, 0xD43, 0x515,
- 0xB26, 0xD8F, 0x05C, 0xD6E, 0xA2C, 0xF25, 0x628, 0x4E5,
- 0x81D, 0xA2A, 0x1FF, 0x302, 0xFBD, 0x6D9, 0x711, 0xD8B,
- 0xE5C, 0x5CF, 0x42E, 0x008, 0x863, 0xB6F, 0x1E1, 0x3DA,
- 0xACE, 0x82B, 0x2DB, 0x7EB, 0xC15, 0x79F, 0xA79, 0xDAF,
- 0x00D, 0x2F6, 0x0CE, 0x370, 0x7E8, 0x9E6, 0x89F, 0xAE9,
- 0x175, 0xA95, 0x06B, 0x9DF, 0xAFF, 0x45B, 0x823, 0xAA4,
- 0xC79, 0x773, 0x886, 0x854, 0x0A5, 0x6D1, 0xE55, 0xEBB,
- 0x518, 0xE50, 0xF8F, 0x8CC, 0x834, 0x388, 0xCD2, 0xFC1,
- 0xA55, 0x1F8, 0xD1F, 0xE08, 0xF93, 0x362, 0xA22, 0x9FA,
- 0xCE5, 0x3C3, 0xDD4, 0xC53, 0xB94, 0xAD0, 0x6EB, 0x68D,
- 0x660, 0x8FC, 0xBCD, 0x914, 0x16F, 0x4C0, 0x134, 0xE1A,
- 0x76F, 0x9CB, 0x660, 0xEA0, 0x320, 0x15A, 0xCE3, 0x7E8,
- 0x03E, 0xB9A, 0xC90, 0xA14, 0x256, 0x1A8, 0x639, 0x7C6,
- 0xA59, 0xA65, 0x956, 0x9E4, 0x592, 0x6A9, 0xCFF, 0x4DC,
- 0xAA3, 0xD2A, 0xFDE, 0xA87, 0xBF5, 0x9F0, 0xC32, 0x94F,
- 0x675, 0x9A6, 0x369, 0x648, 0x289, 0x823, 0x498, 0x574,
- 0x8D1, 0xA13, 0xD1A, 0xBB5, 0xA19, 0x7F7, 0x775, 0x138,
- 0x949, 0xA4C, 0xE36, 0x126, 0xC85, 0xE05, 0xFEE, 0x962,
- 0x36D, 0x08D, 0xC76, 0x1E1, 0x1EC, 0x8D7, 0x231, 0xB68,
- 0x03C, 0x1DE, 0x7DF, 0x2B1, 0x09D, 0xC81, 0xDA4, 0x8F7,
- 0x6B9, 0x947, 0x9B0
- ])
- );
- });
-
- it('testAztec 8.1 - synthetic test cases (compact mode message)', () => {
- testEncodeDecodeRandom(GenericGF.AZTEC_PARAM, 2, 5);
- });
-
- it('testAztec 8.2 - synthetic test cases (full mode message)', () => {
- testEncodeDecodeRandom(GenericGF.AZTEC_PARAM, 4, 6);
- });
-
- it('testAztec 8.3 - synthetic test cases', () => {
- testEncodeDecodeRandom(GenericGF.AZTEC_DATA_6, 10, 7);
- });
-
- it('testAztec 8.4 - synthetic test cases', () => {
- testEncodeDecodeRandom(GenericGF.AZTEC_DATA_6, 20, 12);
- });
-
- it('testAztec 8.5 - synthetic test cases', () => {
- testEncodeDecodeRandom(GenericGF.AZTEC_DATA_8, 20, 11);
- });
-
- it('testAztec 8.6 - synthetic test cases', () => {
- testEncodeDecodeRandom(GenericGF.AZTEC_DATA_8, 128, 127);
- });
-
- it('testAztec 8.7 - synthetic test cases', () => {
- testEncodeDecodeRandom(GenericGF.AZTEC_DATA_10, 128, 128);
- });
-
- it('testAztec 8.8 - synthetic test cases', () => {
- testEncodeDecodeRandom(GenericGF.AZTEC_DATA_10, 768, 255);
- });
-
- it('testAztec 8.9 - synthetic test cases', () => {
- testEncodeDecodeRandom(GenericGF.AZTEC_DATA_12, 3072, 1023);
- });
+ it('testDataMatrix 1 - real life test case', () => {
+ testEncodeDecode(
+ GenericGF.DATA_MATRIX_FIELD_256,
+ Int32Array.from([142, 164, 186]),
+ Int32Array.from([114, 25, 5, 88, 102])
+ );
+ });
+
+ it('testDataMatrix 2 - real life test case', () => {
+ testEncodeDecode(
+ GenericGF.DATA_MATRIX_FIELD_256,
+ Int32Array.from([
+ 0x69, 0x75, 0x75, 0x71, 0x3B, 0x30, 0x30, 0x64,
+ 0x70, 0x65, 0x66, 0x2F, 0x68, 0x70, 0x70, 0x68,
+ 0x6D, 0x66, 0x2F, 0x64, 0x70, 0x6E, 0x30, 0x71,
+ 0x30, 0x7B, 0x79, 0x6A, 0x6F, 0x68, 0x30, 0x81,
+ 0xF0, 0x88, 0x1F, 0xB5
+ ]),
+ Int32Array.from([
+ 0x1C, 0x64, 0xEE, 0xEB, 0xD0, 0x1D, 0x00, 0x03,
+ 0xF0, 0x1C, 0xF1, 0xD0, 0x6D, 0x00, 0x98, 0xDA,
+ 0x80, 0x88, 0xBE, 0xFF, 0xB7, 0xFA, 0xA9, 0x95
+ ])
+ );
+ });
+
+ it('testDataMatrix 3.1 - synthetic test cases', () => {
+ testEncodeDecodeRandom(GenericGF.DATA_MATRIX_FIELD_256, 10, 240);
+ });
+
+ it('testDataMatrix 3.2 - synthetic test cases', () => {
+ testEncodeDecodeRandom(GenericGF.DATA_MATRIX_FIELD_256, 128, 127);
+ });
+
+ it('testDataMatrix 3.3 - synthetic test cases', () => {
+ testEncodeDecodeRandom(GenericGF.DATA_MATRIX_FIELD_256, 220, 35);
+ });
+
+ it('testQRCode 1 - from example given in ISO 18004, Annex I', () => {
+
+ // Test case from example given in ISO 18004, Annex I
+ testEncodeDecode(
+ GenericGF.QR_CODE_FIELD_256,
+ Int32Array.from([
+ 0x10, 0x20, 0x0C, 0x56, 0x61, 0x80, 0xEC, 0x11,
+ 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11
+ ]),
+ Int32Array.from([
+ 0xA5, 0x24, 0xD4, 0xC1, 0xED, 0x36, 0xC7, 0x87,
+ 0x2C, 0x55
+ ])
+ );
+
+ });
+
+ it('testQRCode 2 - real life test case', () => {
+ testEncodeDecode(
+ GenericGF.QR_CODE_FIELD_256,
+ Int32Array.from([
+ 0x72, 0x67, 0x2F, 0x77, 0x69, 0x6B, 0x69, 0x2F,
+ 0x4D, 0x61, 0x69, 0x6E, 0x5F, 0x50, 0x61, 0x67,
+ 0x65, 0x3B, 0x3B, 0x00, 0xEC, 0x11, 0xEC, 0x11,
+ 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11
+ ]),
+ Int32Array.from([
+ 0xD8, 0xB8, 0xEF, 0x14, 0xEC, 0xD0, 0xCC, 0x85,
+ 0x73, 0x40, 0x0B, 0xB5, 0x5A, 0xB8, 0x8B, 0x2E,
+ 0x08, 0x62
+ ])
+ );
+ });
+
+ it('testQRCode 3.1 - synthetic test cases', () => {
+ testEncodeDecodeRandom(GenericGF.QR_CODE_FIELD_256, 10, 240);
+ });
+
+ it('testQRCode 3.2 - synthetic test cases', () => {
+ testEncodeDecodeRandom(GenericGF.QR_CODE_FIELD_256, 128, 127);
+ });
+
+ it('testQRCode 3.3 - synthetic test cases', () => {
+ testEncodeDecodeRandom(GenericGF.QR_CODE_FIELD_256, 220, 35);
+ });
+
+ it('testAztec 1 - real life test case', () => {
+ testEncodeDecode(
+ GenericGF.AZTEC_PARAM,
+ Int32Array.from([0x5, 0x6]),
+ Int32Array.from([0x3, 0x2, 0xB, 0xB, 0x7])
+ );
+ });
+
+ it('testAztec 2 - real life test case', () => {
+ testEncodeDecode(
+ GenericGF.AZTEC_PARAM,
+ Int32Array.from([0x0, 0x0, 0x0, 0x9]),
+ Int32Array.from([0xA, 0xD, 0x8, 0x6, 0x5, 0x6])
+ );
+ });
+
+ it('testAztec 3 - real life test case', () => {
+ testEncodeDecode(
+ GenericGF.AZTEC_PARAM,
+ Int32Array.from([0x2, 0x8, 0x8, 0x7]),
+ Int32Array.from([0xE, 0xC, 0xA, 0x9, 0x6, 0x8])
+ );
+ });
+
+ it('testAztec 4 - real life test case', () => {
+ testEncodeDecode(
+ GenericGF.AZTEC_DATA_6,
+ Int32Array.from([0x9, 0x32, 0x1, 0x29, 0x2F, 0x2, 0x27, 0x25, 0x1, 0x1B]),
+ Int32Array.from([0x2C, 0x2, 0xD, 0xD, 0xA, 0x16, 0x28, 0x9, 0x22, 0xA, 0x14])
+ );
+ });
+
+ it('testAztec 5 - real life test case', () => {
+ testEncodeDecode(
+ GenericGF.AZTEC_DATA_8,
+ Int32Array.from([
+ 0xE0, 0x86, 0x42, 0x98, 0xE8, 0x4A, 0x96, 0xC6,
+ 0xB9, 0xF0, 0x8C, 0xA7, 0x4A, 0xDA, 0xF8, 0xCE,
+ 0xB7, 0xDE, 0x88, 0x64, 0x29, 0x8E, 0x84, 0xA9,
+ 0x6C, 0x6B, 0x9F, 0x08, 0xCA, 0x74, 0xAD, 0xAF,
+ 0x8C, 0xEB, 0x7C, 0x10, 0xC8, 0x53, 0x1D, 0x09,
+ 0x52, 0xD8, 0xD7, 0x3E, 0x11, 0x94, 0xE9, 0x5B,
+ 0x5F, 0x19, 0xD6, 0xFB, 0xD1, 0x0C, 0x85, 0x31,
+ 0xD0, 0x95, 0x2D, 0x8D, 0x73, 0xE1, 0x19, 0x4E,
+ 0x95, 0xB5, 0xF1, 0x9D, 0x6F]),
+ Int32Array.from([
+ 0x31, 0xD7, 0x04, 0x46, 0xB2, 0xC1, 0x06, 0x94,
+ 0x17, 0xE5, 0x0C, 0x2B, 0xA3, 0x99, 0x15, 0x7F,
+ 0x16, 0x3C, 0x66, 0xBA, 0x33, 0xD9, 0xE8, 0x87,
+ 0x86, 0xBB, 0x4B, 0x15, 0x4E, 0x4A, 0xDE, 0xD4,
+ 0xED, 0xA1, 0xF8, 0x47, 0x2A, 0x50, 0xA6, 0xBC,
+ 0x53, 0x7D, 0x29, 0xFE, 0x06, 0x49, 0xF3, 0x73,
+ 0x9F, 0xC1, 0x75])
+ );
+ });
+
+ it('testAztec 6 - real life test case', () => {
+ testEncodeDecode(
+ GenericGF.AZTEC_DATA_10,
+ Int32Array.from([
+ 0x15C, 0x1E1, 0x2D5, 0x02E, 0x048, 0x1E2, 0x037, 0x0CD,
+ 0x02E, 0x056, 0x26A, 0x281, 0x1C2, 0x1A6, 0x296, 0x045,
+ 0x041, 0x0AA, 0x095, 0x2CE, 0x003, 0x38F, 0x2CD, 0x1A2,
+ 0x036, 0x1AD, 0x04E, 0x090, 0x271, 0x0D3, 0x02E, 0x0D5,
+ 0x2D4, 0x032, 0x2CA, 0x281, 0x0AA, 0x04E, 0x024, 0x2D3,
+ 0x296, 0x281, 0x0E2, 0x08A, 0x1AA, 0x28A, 0x280, 0x07C,
+ 0x286, 0x0A1, 0x1D0, 0x1AD, 0x154, 0x032, 0x2C2, 0x1C1,
+ 0x145, 0x02B, 0x2D4, 0x2B0, 0x033, 0x2D5, 0x276, 0x1C1,
+ 0x282, 0x10A, 0x2B5, 0x154, 0x003, 0x385, 0x20F, 0x0C4,
+ 0x02D, 0x050, 0x266, 0x0D5, 0x033, 0x2D5, 0x276, 0x1C1,
+ 0x0D4, 0x2A0, 0x08F, 0x0C4, 0x024, 0x20F, 0x2E2, 0x1AD,
+ 0x154, 0x02E, 0x056, 0x26A, 0x281, 0x090, 0x1E5, 0x14E,
+ 0x0CF, 0x2B6, 0x1C1, 0x28A, 0x2A1, 0x04E, 0x0D5, 0x003,
+ 0x391, 0x122, 0x286, 0x1AD, 0x2D4, 0x028, 0x262, 0x2EA,
+ 0x0A2, 0x004, 0x176, 0x295, 0x201, 0x0D5, 0x024, 0x20F,
+ 0x116, 0x0C1, 0x056, 0x095, 0x213, 0x004, 0x1EA, 0x28A,
+ 0x02A, 0x234, 0x2CE, 0x037, 0x157, 0x0D3, 0x262, 0x026,
+ 0x262, 0x2A0, 0x086, 0x106, 0x2A1, 0x126, 0x1E5, 0x266,
+ 0x26A, 0x2A1, 0x0E6, 0x1AA, 0x281, 0x2B6, 0x271, 0x154,
+ 0x02F, 0x0C4, 0x02D, 0x213, 0x0CE, 0x003, 0x38F, 0x2CD,
+ 0x1A2, 0x036, 0x1B5, 0x26A, 0x086, 0x280, 0x086, 0x1AA,
+ 0x2A1, 0x226, 0x1AD, 0x0CF, 0x2A6, 0x292, 0x2C6, 0x022,
+ 0x1AA, 0x256, 0x0D5, 0x02D, 0x050, 0x266, 0x0D5, 0x004,
+ 0x176, 0x295, 0x201, 0x0D3, 0x055, 0x031, 0x2CD, 0x2EA,
+ 0x1E2, 0x261, 0x1EA, 0x28A, 0x004, 0x145, 0x026, 0x1A6,
+ 0x1C6, 0x1F5, 0x2CE, 0x034, 0x051, 0x146, 0x1E1, 0x0B0,
+ 0x1B0, 0x261, 0x0D5, 0x025, 0x142, 0x1C0, 0x07C, 0x0B0,
+ 0x1E6, 0x081, 0x044, 0x02F, 0x2CF, 0x081, 0x290, 0x0A2,
+ 0x1A6, 0x281, 0x0CD, 0x155, 0x031, 0x1A2, 0x086, 0x262,
+ 0x2A1, 0x0CD, 0x0CA, 0x0E6, 0x1E5, 0x003, 0x394, 0x0C5,
+ 0x030, 0x26F, 0x053, 0x0C1, 0x1B6, 0x095, 0x2D4, 0x030,
+ 0x26F, 0x053, 0x0C0, 0x07C, 0x2E6, 0x295, 0x143, 0x2CD,
+ 0x2CE, 0x037, 0x0C9, 0x144, 0x2CD, 0x040, 0x08E, 0x054,
+ 0x282, 0x022, 0x2A1, 0x229, 0x053, 0x0D5, 0x262, 0x027,
+ 0x26A, 0x1E8, 0x14D, 0x1A2, 0x004, 0x26A, 0x296, 0x281,
+ 0x176, 0x295, 0x201, 0x0E2, 0x2C4, 0x143, 0x2D4, 0x026,
+ 0x262, 0x2A0, 0x08F, 0x0C4, 0x031, 0x213, 0x2B5, 0x155,
+ 0x213, 0x02F, 0x143, 0x121, 0x2A6, 0x1AD, 0x2D4, 0x034,
+ 0x0C5, 0x026, 0x295, 0x003, 0x396, 0x2A1, 0x176, 0x295,
+ 0x201, 0x0AA, 0x04E, 0x004, 0x1B0, 0x070, 0x275, 0x154,
+ 0x026, 0x2C1, 0x2B3, 0x154, 0x2AA, 0x256, 0x0C1, 0x044,
+ 0x004, 0x23F
+ ]),
+ Int32Array.from([
+ 0x379, 0x099, 0x348, 0x010, 0x090, 0x196, 0x09C, 0x1FF,
+ 0x1B0, 0x32D, 0x244, 0x0DE, 0x201, 0x386, 0x163, 0x11F,
+ 0x39B, 0x344, 0x3FE, 0x02F, 0x188, 0x113, 0x3D9, 0x102,
+ 0x04A, 0x2E1, 0x1D1, 0x18E, 0x077, 0x262, 0x241, 0x20D,
+ 0x1B8, 0x11D, 0x0D0, 0x0A5, 0x29C, 0x24D, 0x3E7, 0x006,
+ 0x2D0, 0x1B7, 0x337, 0x178, 0x0F1, 0x1E0, 0x00B, 0x01E,
+ 0x0DA, 0x1C6, 0x2D9, 0x00D, 0x28B, 0x34A, 0x252, 0x27A,
+ 0x057, 0x0CA, 0x2C2, 0x2E4, 0x3A6, 0x0E3, 0x22B, 0x307,
+ 0x174, 0x292, 0x10C, 0x1ED, 0x2FD, 0x2D4, 0x0A7, 0x051,
+ 0x34F, 0x07A, 0x1D5, 0x01D, 0x22E, 0x2C2, 0x1DF, 0x08F,
+ 0x105, 0x3FE, 0x286, 0x2A2, 0x3B1, 0x131, 0x285, 0x362,
+ 0x315, 0x13C, 0x0F9, 0x1A2, 0x28D, 0x246, 0x1B3, 0x12C,
+ 0x2AD, 0x0F8, 0x222, 0x0EC, 0x39F, 0x358, 0x014, 0x229,
+ 0x0C8, 0x360, 0x1C2, 0x031, 0x098, 0x041, 0x3E4, 0x046,
+ 0x332, 0x318, 0x2E3, 0x24E, 0x3E2, 0x1E1, 0x0BE, 0x239,
+ 0x306, 0x3A5, 0x352, 0x351, 0x275, 0x0ED, 0x045, 0x229,
+ 0x0BF, 0x05D, 0x253, 0x1BE, 0x02E, 0x35A, 0x0E4, 0x2E9,
+ 0x17A, 0x166, 0x03C, 0x007
+ ])
+ );
+ });
+
+ it('testAztec 7 - real life test case', () => {
+ testEncodeDecode(
+ GenericGF.AZTEC_DATA_12,
+ Int32Array.from([
+ 0x571, 0xE1B, 0x542, 0xE12, 0x1E2, 0x0DC, 0xCD0, 0xB85,
+ 0x69A, 0xA81, 0x709, 0xA6A, 0x584, 0x510, 0x4AA, 0x256,
+ 0xCE0, 0x0F8, 0xFB3, 0x5A2, 0x0D9, 0xAD1, 0x389, 0x09C,
+ 0x4D3, 0x0B8, 0xD5B, 0x503, 0x2B2, 0xA81, 0x2A8, 0x4E0,
+ 0x92D, 0x3A5, 0xA81, 0x388, 0x8A6, 0xAA8, 0xAA0, 0x07C,
+ 0xA18, 0xA17, 0x41A, 0xD55, 0x032, 0xB09, 0xC15, 0x142,
+ 0xBB5, 0x2B0, 0x0CE, 0xD59, 0xD9C, 0x1A0, 0x90A, 0xAD5,
+ 0x540, 0x0F8, 0x583, 0xCC4, 0x0B4, 0x509, 0x98D, 0x50C,
+ 0xED5, 0x9D9, 0xC13, 0x52A, 0x023, 0xCC4, 0x092, 0x0FB,
+ 0x89A, 0xD55, 0x02E, 0x15A, 0x6AA, 0x049, 0x079, 0x54E,
+ 0x33E, 0xB67, 0x068, 0xAA8, 0x44E, 0x354, 0x03E, 0x452,
+ 0x2A1, 0x9AD, 0xB50, 0x289, 0x8AE, 0xA28, 0x804, 0x5DA,
+ 0x958, 0x04D, 0x509, 0x20F, 0x458, 0xC11, 0x589, 0x584,
+ 0xC04, 0x7AA, 0x8A0, 0xAA3, 0x4B3, 0x837, 0x55C, 0xD39,
+ 0x882, 0x698, 0xAA0, 0x219, 0x06A, 0x852, 0x679, 0x666,
+ 0x9AA, 0xA13, 0x99A, 0xAA0, 0x6B6, 0x9C5, 0x540, 0xBCC,
+ 0x40B, 0x613, 0x338, 0x03E, 0x3EC, 0xD68, 0x836, 0x6D6,
+ 0x6A2, 0x1A8, 0x021, 0x9AA, 0xA86, 0x266, 0xB4C, 0xFA9,
+ 0xA92, 0xB18, 0x226, 0xAA5, 0x635, 0x42D, 0x142, 0x663,
+ 0x540, 0x45D, 0xA95, 0x804, 0xD31, 0x543, 0x1B3, 0x6EA,
+ 0x78A, 0x617, 0xAA8, 0xA01, 0x145, 0x099, 0xA67, 0x19F,
+ 0x5B3, 0x834, 0x145, 0x467, 0x84B, 0x06C, 0x261, 0x354,
+ 0x255, 0x09C, 0x01F, 0x0B0, 0x798, 0x811, 0x102, 0xFB3,
+ 0xC81, 0xA40, 0xA26, 0x9A8, 0x133, 0x555, 0x0C5, 0xA22,
+ 0x1A6, 0x2A8, 0x4CD, 0x328, 0xE67, 0x940, 0x3E5, 0x0C5,
+ 0x0C2, 0x6F1, 0x4CC, 0x16D, 0x895, 0xB50, 0x309, 0xBC5,
+ 0x330, 0x07C, 0xB9A, 0x955, 0x0EC, 0xDB3, 0x837, 0x325,
+ 0x44B, 0x344, 0x023, 0x854, 0xA08, 0x22A, 0x862, 0x914,
+ 0xCD5, 0x988, 0x279, 0xA9E, 0x853, 0x5A2, 0x012, 0x6AA,
+ 0x5A8, 0x15D, 0xA95, 0x804, 0xE2B, 0x114, 0x3B5, 0x026,
+ 0x98A, 0xA02, 0x3CC, 0x40C, 0x613, 0xAD5, 0x558, 0x4C2,
+ 0xF50, 0xD21, 0xA99, 0xADB, 0x503, 0x431, 0x426, 0xA54,
+ 0x03E, 0x5AA, 0x15D, 0xA95, 0x804, 0xAA1, 0x380, 0x46C,
+ 0x070, 0x9D5, 0x540, 0x9AC, 0x1AC, 0xD54, 0xAAA, 0x563,
+ 0x044, 0x401, 0x220, 0x9F1, 0x4F0, 0xDAA, 0x170, 0x90F,
+ 0x106, 0xE66, 0x85C, 0x2B4, 0xD54, 0x0B8, 0x4D3, 0x52C,
+ 0x228, 0x825, 0x512, 0xB67, 0x007, 0xC7D, 0x9AD, 0x106,
+ 0xCD6, 0x89C, 0x484, 0xE26, 0x985, 0xC6A, 0xDA8, 0x195,
+ 0x954, 0x095, 0x427, 0x049, 0x69D, 0x2D4, 0x09C, 0x445,
+ 0x355, 0x455, 0x003, 0xE50, 0xC50, 0xBA0, 0xD6A, 0xA81,
+ 0x958, 0x4E0, 0xA8A, 0x15D, 0xA95, 0x806, 0x76A, 0xCEC,
+ 0xE0D, 0x048, 0x556, 0xAAA, 0x007, 0xC2C, 0x1E6, 0x205,
+ 0xA28, 0x4CC, 0x6A8, 0x676, 0xACE, 0xCE0, 0x9A9, 0x501,
+ 0x1E6, 0x204, 0x907, 0xDC4, 0xD6A, 0xA81, 0x70A, 0xD35,
+ 0x502, 0x483, 0xCAA, 0x719, 0xF5B, 0x383, 0x455, 0x422,
+ 0x71A, 0xA01, 0xF22, 0x915, 0x0CD, 0x6DA, 0x814, 0x4C5,
+ 0x751, 0x440, 0x22E, 0xD4A, 0xC02, 0x6A8, 0x490, 0x7A2,
+ 0xC60, 0x8AC, 0x4AC, 0x260, 0x23D, 0x545, 0x055, 0x1A5,
+ 0x9C1, 0xBAA, 0xE69, 0xCC4, 0x134, 0xC55, 0x010, 0xC83,
+ 0x542, 0x933, 0xCB3, 0x34D, 0x550, 0x9CC, 0xD55, 0x035,
+ 0xB4E, 0x2AA, 0x05E, 0x620, 0x5B0, 0x999, 0xC01, 0xF1F,
+ 0x66B, 0x441, 0xB36, 0xB35, 0x10D, 0x401, 0x0CD, 0x554,
+ 0x313, 0x35A, 0x67D, 0x4D4, 0x958, 0xC11, 0x355, 0x2B1,
+ 0xAA1, 0x68A, 0x133, 0x1AA, 0x022, 0xED4, 0xAC0, 0x269,
+ 0x8AA, 0x18D, 0x9B7, 0x53C, 0x530, 0xBD5, 0x450, 0x08A,
+ 0x284, 0xCD3, 0x38C, 0xFAD, 0x9C1, 0xA0A, 0x2A3, 0x3C2,
+ 0x583, 0x613, 0x09A, 0xA12, 0xA84, 0xE00, 0xF85, 0x83C,
+ 0xC40, 0x888, 0x17D, 0x9E4, 0x0D2, 0x051, 0x34D, 0x409,
+ 0x9AA, 0xA86, 0x2D1, 0x10D, 0x315, 0x426, 0x699, 0x473,
+ 0x3CA, 0x01F, 0x286, 0x286, 0x137, 0x8A6, 0x60B, 0x6C4,
+ 0xADA, 0x818, 0x4DE, 0x299, 0x803, 0xE5C, 0xD4A, 0xA87,
+ 0x66D, 0x9C1, 0xB99, 0x2A2, 0x59A, 0x201, 0x1C2, 0xA50,
+ 0x411, 0x543, 0x148, 0xA66, 0xACC, 0x413, 0xCD4, 0xF42,
+ 0x9AD, 0x100, 0x935, 0x52D, 0x40A, 0xED4, 0xAC0, 0x271,
+ 0x588, 0xA1D, 0xA81, 0x34C, 0x550, 0x11E, 0x620, 0x630,
+ 0x9D6, 0xAAA, 0xC26, 0x17A, 0x869, 0x0D4, 0xCD6, 0xDA8,
+ 0x1A1, 0x8A1, 0x352, 0xA01, 0xF2D, 0x50A, 0xED4, 0xAC0,
+ 0x255, 0x09C, 0x023, 0x603, 0x84E, 0xAAA, 0x04D, 0x60D,
+ 0x66A, 0xA55, 0x52B, 0x182, 0x220, 0x091, 0x00F, 0x8A7,
+ 0x86D, 0x50B, 0x848, 0x788, 0x373, 0x342, 0xE15, 0xA6A,
+ 0xA05, 0xC26, 0x9A9, 0x611, 0x441, 0x2A8, 0x95B, 0x380,
+ 0x3E3, 0xECD, 0x688, 0x366, 0xB44, 0xE24, 0x271, 0x34C,
+ 0x2E3, 0x56D, 0x40C, 0xACA, 0xA04, 0xAA1, 0x382, 0x4B4,
+ 0xE96, 0xA04, 0xE22, 0x29A, 0xAA2, 0xA80, 0x1F2, 0x862,
+ 0x85D, 0x06B, 0x554, 0x0CA, 0xC27, 0x054, 0x50A, 0xED4,
+ 0xAC0, 0x33B, 0x567, 0x670, 0x682, 0x42A, 0xB55, 0x500,
+ 0x3E1, 0x60F, 0x310, 0x2D1, 0x426, 0x635, 0x433, 0xB56,
+ 0x767, 0x04D, 0x4A8, 0x08F, 0x310, 0x248, 0x3EE, 0x26B,
+ 0x554, 0x0B8, 0x569, 0xAA8, 0x124, 0x1E5, 0x538, 0xCFA,
+ 0xD9C, 0x1A2, 0xAA1, 0x138, 0xD50, 0x0F9, 0x148, 0xA86,
+ 0x6B6, 0xD40, 0xA26, 0x2BA, 0x8A2, 0x011, 0x76A, 0x560,
+ 0x135, 0x424, 0x83D, 0x163, 0x045, 0x625, 0x613, 0x011,
+ 0xEAA, 0x282, 0xA8D, 0x2CE, 0x0DD, 0x573, 0x4E6, 0x209,
+ 0xA62, 0xA80, 0x864, 0x1AA, 0x149, 0x9E5, 0x99A, 0x6AA,
+ 0x84E, 0x66A, 0xA81, 0xADA, 0x715, 0x502, 0xF31, 0x02D,
+ 0x84C, 0xCE0, 0x0F8, 0xFB3, 0x5A2, 0x0D9, 0xB59, 0xA88,
+ 0x6A0, 0x086, 0x6AA, 0xA18, 0x99A, 0xD33, 0xEA6, 0xA4A,
+ 0xC60, 0x89A, 0xA95, 0x8D5, 0x0B4, 0x509, 0x98D, 0x501,
+ 0x176, 0xA56, 0x013, 0x4C5, 0x50C, 0x6CD, 0xBA9, 0xE29,
+ 0x85E, 0xAA2, 0x804, 0x514, 0x266, 0x99C, 0x67D, 0x6CE,
+ 0x0D0, 0x515, 0x19E, 0x12C, 0x1B0, 0x984, 0xD50, 0x954,
+ 0x270, 0x07C, 0x2C1, 0xE62, 0x044, 0x40B, 0xECF, 0x206,
+ 0x902, 0x89A, 0x6A0, 0x4CD, 0x554, 0x316, 0x888, 0x698,
+ 0xAA1, 0x334, 0xCA3, 0x99E, 0x500, 0xF94, 0x314, 0x309,
+ 0xBC5, 0x330, 0x5B6, 0x256, 0xD40, 0xC26, 0xF14, 0xCC0,
+ 0x1F2, 0xE6A, 0x554, 0x3B3, 0x6CE, 0x0DC, 0xC95, 0x12C,
+ 0xD10, 0x08E, 0x152, 0x820, 0x8AA, 0x18A, 0x453, 0x356,
+ 0x620, 0x9E6, 0xA7A, 0x14D, 0x688, 0x049, 0xAA9, 0x6A0,
+ 0x576, 0xA56, 0x013, 0x8AC, 0x450, 0xED4, 0x09A, 0x62A,
+ 0x808, 0xF31, 0x031, 0x84E, 0xB55, 0x561, 0x30B, 0xD43,
+ 0x486, 0xA66, 0xB6D, 0x40D, 0x0C5, 0x09A, 0x950, 0x0F9,
+ 0x6A8, 0x576, 0xA56, 0x012, 0xA84, 0xE01, 0x1B0, 0x1C2,
+ 0x755, 0x502, 0x6B0, 0x6B3, 0x552, 0xAA9, 0x58C, 0x111,
+ 0x004, 0x882, 0x7C5, 0x3C3, 0x6A8, 0x5C2, 0x43C, 0x41B,
+ 0x99A, 0x170, 0xAD3, 0x550, 0x2E1, 0x34D, 0x4B0, 0x8A2,
+ 0x095, 0x44A, 0xD9C, 0x01F, 0x1F6, 0x6B4, 0x41B, 0x35A,
+ 0x271, 0x213, 0x89A, 0x617, 0x1AB, 0x6A0, 0x656, 0x550,
+ 0x255, 0x09C, 0x125, 0xA74, 0xB50, 0x271, 0x114, 0xD55,
+ 0x154, 0x00F, 0x943, 0x142, 0xE83, 0x5AA, 0xA06, 0x561,
+ 0x382, 0xA28, 0x576, 0xA56, 0x019, 0xDAB, 0x3B3, 0x834,
+ 0x121, 0x55A, 0xAA8, 0x01F, 0x0B0, 0x798, 0x816, 0x8A1,
+ 0x331, 0xAA1, 0x9DA, 0xB3B, 0x382, 0x6A5, 0x404, 0x798,
+ 0x812, 0x41F, 0x713, 0x5AA, 0xA05, 0xC2B, 0x4D5, 0x409,
+ 0x20F, 0x2A9, 0xC67, 0xD6C, 0xE0D, 0x155, 0x089, 0xC6A,
+ 0x807, 0xC8A, 0x454, 0x335, 0xB6A, 0x051, 0x315, 0xD45,
+ 0x100, 0x8BB, 0x52B, 0x009, 0xAA1, 0x241, 0xE8B, 0x182,
+ 0x2B1, 0x2B0, 0x980, 0x8F5, 0x514, 0x154, 0x696, 0x706,
+ 0xEAB, 0x9A7, 0x310, 0x4D3, 0x154, 0x043, 0x20D, 0x50A,
+ 0x4CF, 0x2CC, 0xD35, 0x542, 0x733, 0x554, 0x0D6, 0xD38,
+ 0xAA8, 0x179, 0x881, 0x6C2, 0x667, 0x007, 0xC7D, 0x9AD,
+ 0x106, 0xCDA, 0xCD4, 0x435, 0x004, 0x335, 0x550, 0xC4C,
+ 0xD69, 0x9F5, 0x352, 0x563, 0x044, 0xD54, 0xAC6, 0xA85,
+ 0xA28, 0x4CC, 0x6A8, 0x08B, 0xB52, 0xB00, 0x9A6, 0x2A8,
+ 0x636, 0x6DD, 0x4F1, 0x4C2, 0xF55, 0x140, 0x228, 0xA13,
+ 0x34C, 0xE33, 0xEB6, 0x706, 0x828, 0xA8C, 0xF09, 0x60D,
+ 0x84C, 0x26A, 0x84A, 0xA13, 0x803, 0xE16, 0x0F3, 0x102,
+ 0x220, 0x5F6, 0x790, 0x348, 0x144, 0xD35, 0x026, 0x6AA,
+ 0xA18, 0xB44, 0x434, 0xC55, 0x099, 0xA65, 0x1CC, 0xF28,
+ 0x07C, 0xA18, 0xA18, 0x4DE, 0x299, 0x82D, 0xB12, 0xB6A,
+ 0x061, 0x378, 0xA66, 0x00F, 0x973, 0x52A, 0xA1D, 0x9B6,
+ 0x706, 0xE64, 0xA89, 0x668, 0x804, 0x70A, 0x941, 0x045,
+ 0x50C, 0x522, 0x99A, 0xB31, 0x04F, 0x353, 0xD0A, 0x6B4,
+ 0x402, 0x4D5, 0x4B5, 0x02B, 0xB52, 0xB00, 0x9C5, 0x622,
+ 0x876, 0xA04, 0xD31, 0x540, 0x479, 0x881, 0x8C2, 0x75A,
+ 0xAAB, 0x098, 0x5EA, 0x1A4, 0x353, 0x35B, 0x6A0, 0x686,
+ 0x284, 0xD4A, 0x807, 0xCB5, 0x42B, 0xB52, 0xB00, 0x954,
+ 0x270, 0x08D, 0x80E, 0x13A, 0xAA8, 0x135, 0x835, 0x9AA,
+ 0x801, 0xF14, 0xF0D, 0xAA1, 0x709, 0x0F1, 0x06E, 0x668,
+ 0x5C2, 0xB4D, 0x540, 0xB84, 0xD35, 0x2C2, 0x288, 0x255,
+ 0x12B, 0x670, 0x07C, 0x7D9, 0xAD1, 0x06C, 0xD68, 0x9C4,
+ 0x84E, 0x269, 0x85C, 0x6AD, 0xA81, 0x959, 0x540, 0x954,
+ 0x270, 0x496, 0x9D2, 0xD40, 0x9C4, 0x453, 0x554, 0x550,
+ 0x03E, 0x50C, 0x50B, 0xA0D, 0x6AA, 0x819, 0x584, 0xE0A,
+ 0x8A1, 0x5DA, 0x958, 0x067, 0x6AC, 0xECE, 0x0D0, 0x485,
+ 0x56A, 0xAA0, 0x07C, 0x2C1, 0xE62, 0x05A, 0x284, 0xCC6,
+ 0xA86, 0x76A, 0xCEC, 0xE09, 0xA95, 0x011, 0xE62, 0x049,
+ 0x07D, 0xC4D, 0x6AA, 0x817, 0x0AD, 0x355, 0x024, 0x83C,
+ 0xAA7, 0x19F, 0x5B3, 0x834, 0x554, 0x227, 0x1AA, 0x01F,
+ 0x229, 0x150, 0xCD6, 0xDA8, 0x144, 0xC57, 0x514, 0x402,
+ 0x2ED, 0x4AC, 0x026, 0xA84, 0x907, 0xA2C, 0x608, 0xAC4,
+ 0xAC2, 0x602, 0x3D5, 0x450, 0x551, 0xA59, 0xC1B, 0xAAE,
+ 0x69C, 0xC41, 0x34C, 0x550, 0x10C, 0x835, 0x429, 0x33C,
+ 0xB33, 0x4D5, 0x509, 0xCCD, 0x550, 0x35B, 0x4E2, 0xAA0,
+ 0x5E6, 0x205, 0xB09, 0x99C, 0x09F
+ ]),
+ Int32Array.from([
+ 0xD54, 0x221, 0x154, 0x7CD, 0xBF3, 0x112, 0x89B, 0xC5E,
+ 0x9CD, 0x07E, 0xFB6, 0x78F, 0x7FA, 0x16F, 0x377, 0x4B4,
+ 0x62D, 0x475, 0xBC2, 0x861, 0xB72, 0x9D0, 0x76A, 0x5A1,
+ 0x22A, 0xF74, 0xDBA, 0x8B1, 0x139, 0xDCD, 0x012, 0x293,
+ 0x705, 0xA34, 0xDD5, 0x3D2, 0x7F8, 0x0A6, 0x89A, 0x346,
+ 0xCE0, 0x690, 0x40E, 0xFF3, 0xC4D, 0x97F, 0x9C9, 0x016,
+ 0x73A, 0x923, 0xBCE, 0xFA9, 0xE6A, 0xB92, 0x02A, 0x07C,
+ 0x04B, 0x8D5, 0x753, 0x42E, 0x67E, 0x87C, 0xEE6, 0xD7D,
+ 0x2BF, 0xFB2, 0xFF8, 0x42F, 0x4CB, 0x214, 0x779, 0x02D,
+ 0x606, 0xA02, 0x08A, 0xD4F, 0xB87, 0xDDF, 0xC49, 0xB51,
+ 0x0E9, 0xF89, 0xAEF, 0xC92, 0x383, 0x98D, 0x367, 0xBD3,
+ 0xA55, 0x148, 0x9DB, 0x913, 0xC79, 0x6FF, 0x387, 0x6EA,
+ 0x7FA, 0xC1B, 0x12D, 0x303, 0xBCA, 0x503, 0x0FB, 0xB14,
+ 0x0D4, 0xAD1, 0xAFC, 0x9DD, 0x404, 0x145, 0x6E5, 0x8ED,
+ 0xF94, 0xD72, 0x645, 0xA21, 0x1A8, 0xABF, 0xC03, 0x91E,
+ 0xD53, 0x48C, 0x471, 0x4E4, 0x408, 0x33C, 0x5DF, 0x73D,
+ 0xA2A, 0x454, 0xD77, 0xC48, 0x2F5, 0x96A, 0x9CF, 0x047,
+ 0x611, 0xE92, 0xC2F, 0xA98, 0x56D, 0x919, 0x615, 0x535,
+ 0x67A, 0x8C1, 0x2E2, 0xBC4, 0xBE8, 0x328, 0x04F, 0x257,
+ 0x3F9, 0xFA5, 0x477, 0x12E, 0x94B, 0x116, 0xEF7, 0x65F,
+ 0x6B3, 0x915, 0xC64, 0x9AF, 0xB6C, 0x6A2, 0x50D, 0xEA3,
+ 0x26E, 0xC23, 0x817, 0xA42, 0x71A, 0x9DD, 0xDA8, 0x84D,
+ 0x3F3, 0x85B, 0xB00, 0x1FC, 0xB0A, 0xC2F, 0x00C, 0x095,
+ 0xC58, 0x0E3, 0x807, 0x962, 0xC4B, 0x29A, 0x6FC, 0x958,
+ 0xD29, 0x59E, 0xB14, 0x95A, 0xEDE, 0xF3D, 0xFB8, 0x0E5,
+ 0x348, 0x2E7, 0x38E, 0x56A, 0x410, 0x3B1, 0x4B0, 0x793,
+ 0xAB7, 0x0BC, 0x648, 0x719, 0xE3E, 0xFB4, 0x3B4, 0xE5C,
+ 0x950, 0xD2A, 0x50B, 0x76F, 0x8D2, 0x3C7, 0xECC, 0x87C,
+ 0x53A, 0xBA7, 0x4C3, 0x148, 0x437, 0x820, 0xECD, 0x660,
+ 0x095, 0x2F4, 0x661, 0x6A4, 0xB74, 0x5F3, 0x1D2, 0x7EC,
+ 0x8E2, 0xA40, 0xA6F, 0xFC3, 0x3BE, 0x1E9, 0x52C, 0x233,
+ 0x173, 0x4EF, 0xA7C, 0x40B, 0x14C, 0x88D, 0xF30, 0x8D9,
+ 0xBDB, 0x0A6, 0x940, 0xD46, 0xB2B, 0x03E, 0x46A, 0x641,
+ 0xF08, 0xAFF, 0x496, 0x68A, 0x7A4, 0x0BA, 0xD43, 0x515,
+ 0xB26, 0xD8F, 0x05C, 0xD6E, 0xA2C, 0xF25, 0x628, 0x4E5,
+ 0x81D, 0xA2A, 0x1FF, 0x302, 0xFBD, 0x6D9, 0x711, 0xD8B,
+ 0xE5C, 0x5CF, 0x42E, 0x008, 0x863, 0xB6F, 0x1E1, 0x3DA,
+ 0xACE, 0x82B, 0x2DB, 0x7EB, 0xC15, 0x79F, 0xA79, 0xDAF,
+ 0x00D, 0x2F6, 0x0CE, 0x370, 0x7E8, 0x9E6, 0x89F, 0xAE9,
+ 0x175, 0xA95, 0x06B, 0x9DF, 0xAFF, 0x45B, 0x823, 0xAA4,
+ 0xC79, 0x773, 0x886, 0x854, 0x0A5, 0x6D1, 0xE55, 0xEBB,
+ 0x518, 0xE50, 0xF8F, 0x8CC, 0x834, 0x388, 0xCD2, 0xFC1,
+ 0xA55, 0x1F8, 0xD1F, 0xE08, 0xF93, 0x362, 0xA22, 0x9FA,
+ 0xCE5, 0x3C3, 0xDD4, 0xC53, 0xB94, 0xAD0, 0x6EB, 0x68D,
+ 0x660, 0x8FC, 0xBCD, 0x914, 0x16F, 0x4C0, 0x134, 0xE1A,
+ 0x76F, 0x9CB, 0x660, 0xEA0, 0x320, 0x15A, 0xCE3, 0x7E8,
+ 0x03E, 0xB9A, 0xC90, 0xA14, 0x256, 0x1A8, 0x639, 0x7C6,
+ 0xA59, 0xA65, 0x956, 0x9E4, 0x592, 0x6A9, 0xCFF, 0x4DC,
+ 0xAA3, 0xD2A, 0xFDE, 0xA87, 0xBF5, 0x9F0, 0xC32, 0x94F,
+ 0x675, 0x9A6, 0x369, 0x648, 0x289, 0x823, 0x498, 0x574,
+ 0x8D1, 0xA13, 0xD1A, 0xBB5, 0xA19, 0x7F7, 0x775, 0x138,
+ 0x949, 0xA4C, 0xE36, 0x126, 0xC85, 0xE05, 0xFEE, 0x962,
+ 0x36D, 0x08D, 0xC76, 0x1E1, 0x1EC, 0x8D7, 0x231, 0xB68,
+ 0x03C, 0x1DE, 0x7DF, 0x2B1, 0x09D, 0xC81, 0xDA4, 0x8F7,
+ 0x6B9, 0x947, 0x9B0
+ ])
+ );
+ });
+
+ it('testAztec 8.1 - synthetic test cases (compact mode message)', () => {
+ testEncodeDecodeRandom(GenericGF.AZTEC_PARAM, 2, 5);
+ });
+
+ it('testAztec 8.2 - synthetic test cases (full mode message)', () => {
+ testEncodeDecodeRandom(GenericGF.AZTEC_PARAM, 4, 6);
+ });
+
+ it('testAztec 8.3 - synthetic test cases', () => {
+ testEncodeDecodeRandom(GenericGF.AZTEC_DATA_6, 10, 7);
+ });
+
+ it('testAztec 8.4 - synthetic test cases', () => {
+ testEncodeDecodeRandom(GenericGF.AZTEC_DATA_6, 20, 12);
+ });
+
+ it('testAztec 8.5 - synthetic test cases', () => {
+ testEncodeDecodeRandom(GenericGF.AZTEC_DATA_8, 20, 11);
+ });
+
+ it('testAztec 8.6 - synthetic test cases', () => {
+ testEncodeDecodeRandom(GenericGF.AZTEC_DATA_8, 128, 127);
+ });
+
+ it('testAztec 8.7 - synthetic test cases', () => {
+ testEncodeDecodeRandom(GenericGF.AZTEC_DATA_10, 128, 128);
+ });
+
+ it('testAztec 8.8 - synthetic test cases', () => {
+ testEncodeDecodeRandom(GenericGF.AZTEC_DATA_10, 768, 255);
+ });
+
+ it('testAztec 8.9 - synthetic test cases', () => {
+ testEncodeDecodeRandom(GenericGF.AZTEC_DATA_12, 3072, 1023);
+ });
});
@@ -505,117 +505,117 @@ const DECODER_TEST_ITERATIONS: number /*int*/ = 10;
function testEncodeDecodeRandom(field: GenericGF, dataSize: number /*int*/, ecSize: number /*int*/): void {
- assert.strictEqual(dataSize > 0 && dataSize <= field.getSize() - 3, true, 'Invalid data size for ' + field);
- assert.strictEqual(ecSize > 0 && ecSize + dataSize <= field.getSize(), true, 'Invalid ECC size for ' + field);
-
- const encoder = new ReedSolomonEncoder(field);
- const message = new Int32Array(dataSize + ecSize);
- const dataWords = new Int32Array(dataSize); /*Int32Array(dataSize)*/
- const ecWords = new Int32Array(ecSize); /*Int32Array(ecSize)*/
- const random: Random = getPseudoRandom();
- const iterations: number /*int*/ = field.getSize() > 256 ? 1 : DECODER_RANDOM_TEST_ITERATIONS;
-
- for (let i: number /*int*/ = 0; i < iterations; i++) {
- // generate random data
- for (let k: number /*int*/ = 0; k < dataSize; k++) {
- dataWords[k] = random.next(field.getSize());
- }
- // generate ECC words
- ZXingSystem.arraycopy(dataWords, 0, message, 0, dataWords.length);
- encoder.encode(message, ecWords.length);
- ZXingSystem.arraycopy(message, dataSize, ecWords, 0, ecSize);
- // check to see if Decoder can fix up to ecWords/2 random errors
- testDecoder(field, dataWords, ecWords);
+ assert.strictEqual(dataSize > 0 && dataSize <= field.getSize() - 3, true, 'Invalid data size for ' + field);
+ assert.strictEqual(ecSize > 0 && ecSize + dataSize <= field.getSize(), true, 'Invalid ECC size for ' + field);
+
+ const encoder = new ReedSolomonEncoder(field);
+ const message = new Int32Array(dataSize + ecSize);
+ const dataWords = new Int32Array(dataSize); /*Int32Array(dataSize)*/
+ const ecWords = new Int32Array(ecSize); /*Int32Array(ecSize)*/
+ const random: Random = getPseudoRandom();
+ const iterations: number /*int*/ = field.getSize() > 256 ? 1 : DECODER_RANDOM_TEST_ITERATIONS;
+
+ for (let i: number /*int*/ = 0; i < iterations; i++) {
+ // generate random data
+ for (let k: number /*int*/ = 0; k < dataSize; k++) {
+ dataWords[k] = random.next(field.getSize());
}
+ // generate ECC words
+ ZXingSystem.arraycopy(dataWords, 0, message, 0, dataWords.length);
+ encoder.encode(message, ecWords.length);
+ ZXingSystem.arraycopy(message, dataSize, ecWords, 0, ecSize);
+ // check to see if Decoder can fix up to ecWords/2 random errors
+ testDecoder(field, dataWords, ecWords);
+ }
}
function testEncodeDecode(field: GenericGF, dataWords: Int32Array, ecWords: Int32Array): void {
- testEncoder(field, dataWords, ecWords);
- testDecoder(field, dataWords, ecWords);
+ testEncoder(field, dataWords, ecWords);
+ testDecoder(field, dataWords, ecWords);
}
function testEncoder(field: GenericGF, dataWords: Int32Array, ecWords: Int32Array): void {
- const encoder = new ReedSolomonEncoder(field);
- const messageExpected = new Int32Array(dataWords.length + ecWords.length);
- const message = new Int32Array(dataWords.length + ecWords.length);
+ const encoder = new ReedSolomonEncoder(field);
+ const messageExpected = new Int32Array(dataWords.length + ecWords.length);
+ const message = new Int32Array(dataWords.length + ecWords.length);
- ZXingSystem.arraycopy(dataWords, 0, messageExpected, 0, dataWords.length);
- ZXingSystem.arraycopy(ecWords, 0, messageExpected, dataWords.length, ecWords.length);
- ZXingSystem.arraycopy(dataWords, 0, message, 0, dataWords.length);
+ ZXingSystem.arraycopy(dataWords, 0, messageExpected, 0, dataWords.length);
+ ZXingSystem.arraycopy(ecWords, 0, messageExpected, dataWords.length, ecWords.length);
+ ZXingSystem.arraycopy(dataWords, 0, message, 0, dataWords.length);
- encoder.encode(message, ecWords.length);
+ encoder.encode(message, ecWords.length);
- assertDataEquals(message, messageExpected, 'Encode in ' + field + ' (' + dataWords.length + ',' + ecWords.length + ') failed');
+ assertDataEquals(message, messageExpected, 'Encode in ' + field + ' (' + dataWords.length + ',' + ecWords.length + ') failed');
}
function testDecoder(field: GenericGF, dataWords: Int32Array, ecWords: Int32Array): void {
- const decoder = new ReedSolomonDecoder(field);
- const message = new Int32Array(dataWords.length + ecWords.length);
- const maxErrors: number /*int*/ = Math.floor(ecWords.length / 2);
- const random: Random = getPseudoRandom();
- const iterations: number /*int*/ = field.getSize() > 256 ? 1 : DECODER_TEST_ITERATIONS;
-
- for (let j: number /*int*/ = 0; j < iterations; j++) {
- for (let i: number /*int*/ = 0; i < ecWords.length; i++) {
-
- if (i > 10 && i < Math.floor(ecWords.length / 2) - 10) {
- // performance improvement - skip intermediate cases in long-running tests
- i += Math.floor(ecWords.length / 10);
- }
-
- ZXingSystem.arraycopy(dataWords, 0, message, 0, dataWords.length);
- ZXingSystem.arraycopy(ecWords, 0, message, dataWords.length, ecWords.length);
-
- corrupt(message, i, random, field.getSize());
-
- try {
- decoder.decode(message, ecWords.length);
- } catch (e/*ReedSolomonException e*/) {
- // fail only if maxErrors exceeded
- assert.strictEqual(i > maxErrors, true,
- 'Decode in ' + field + ' (' + dataWords.length + ',' + ecWords.length + ') failed at ' + i + ' errors: ' + e);
- // else stop
- break;
- }
-
- if (i < maxErrors) {
- assertDataEquals(message,
- dataWords,
- 'Decode in ' + field + ' (' + dataWords.length + ',' + ecWords.length + ') failed at ' + i + ' errors');
- }
- }
+ const decoder = new ReedSolomonDecoder(field);
+ const message = new Int32Array(dataWords.length + ecWords.length);
+ const maxErrors: number /*int*/ = Math.floor(ecWords.length / 2);
+ const random: Random = getPseudoRandom();
+ const iterations: number /*int*/ = field.getSize() > 256 ? 1 : DECODER_TEST_ITERATIONS;
+
+ for (let j: number /*int*/ = 0; j < iterations; j++) {
+ for (let i: number /*int*/ = 0; i < ecWords.length; i++) {
+
+ if (i > 10 && i < Math.floor(ecWords.length / 2) - 10) {
+ // performance improvement - skip intermediate cases in long-running tests
+ i += Math.floor(ecWords.length / 10);
+ }
+
+ ZXingSystem.arraycopy(dataWords, 0, message, 0, dataWords.length);
+ ZXingSystem.arraycopy(ecWords, 0, message, dataWords.length, ecWords.length);
+
+ corrupt(message, i, random, field.getSize());
+
+ try {
+ decoder.decode(message, ecWords.length);
+ } catch (e/*ReedSolomonException e*/) {
+ // fail only if maxErrors exceeded
+ assert.strictEqual(i > maxErrors, true,
+ 'Decode in ' + field + ' (' + dataWords.length + ',' + ecWords.length + ') failed at ' + i + ' errors: ' + e);
+ // else stop
+ break;
+ }
+
+ if (i < maxErrors) {
+ assertDataEquals(message,
+ dataWords,
+ 'Decode in ' + field + ' (' + dataWords.length + ',' + ecWords.length + ') failed at ' + i + ' errors');
+ }
}
+ }
}
function assertDataEquals(received: Int32Array, expected: Int32Array, message: string): void {
- for (let i: number /*int*/ = 0; i < expected.length; i++) {
- if (expected[i] !== received[i]) {
+ for (let i: number /*int*/ = 0; i < expected.length; i++) {
+ if (expected[i] !== received[i]) {
- const receivedToString = arrayToString(Int32Array.from(received.subarray(0, expected.length)));
+ const receivedToString = arrayToString(Int32Array.from(received.subarray(0, expected.length)));
- assert.ok(false, `${message}. Mismatch at ${i}. Expected ${arrayToString(expected)}, got ${receivedToString}`);
- }
+ assert.ok(false, `${message}. Mismatch at ${i}. Expected ${arrayToString(expected)}, got ${receivedToString}`);
}
+ }
}
function arrayToString(data: Int32Array): String {
- const sb = new ZXingStringBuilder();
+ const sb = new ZXingStringBuilder();
- sb.append('{');
+ sb.append('{');
- for (let i: number /*int*/ = 0; i < data.length; i++) {
- if (i > 0) {
- sb.append(',');
- }
- sb.append(data[i].toString(16));
+ for (let i: number /*int*/ = 0; i < data.length; i++) {
+ if (i > 0) {
+ sb.append(',');
}
+ sb.append(data[i].toString(16));
+ }
- return sb.append('}').toString();
+ return sb.append('}').toString();
}
function getPseudoRandom(): Random {
- return new Random('0xDEADBEEF');
+ return new Random('0xDEADBEEF');
}
diff --git a/src/test/core/datamatrix/DataMatrixBlackBox.1.spec.ts b/src/test/core/datamatrix/DataMatrixBlackBox.1.spec.ts
index 7210f2ae..dbe63501 100644
--- a/src/test/core/datamatrix/DataMatrixBlackBox.1.spec.ts
+++ b/src/test/core/datamatrix/DataMatrixBlackBox.1.spec.ts
@@ -25,19 +25,19 @@ import AbstractBlackBoxSpec from '../common/AbstractBlackBox';
*/
class DataMatrixBlackBox1Spec extends AbstractBlackBoxSpec {
- public constructor() {
- super('src/test/resources/blackbox/datamatrix-1', new MultiFormatReader(), BarcodeFormat.DATA_MATRIX);
- this.addTest(21, 21, 0.0);
- this.addTest(21, 21, 90.0);
- this.addTest(21, 21, 180.0);
- this.addTest(21, 21, 270.0);
- }
+ public constructor() {
+ super('src/test/resources/blackbox/datamatrix-1', new MultiFormatReader(), BarcodeFormat.DATA_MATRIX);
+ this.addTest(21, 21, 0.0);
+ this.addTest(21, 21, 90.0);
+ this.addTest(21, 21, 180.0);
+ this.addTest(21, 21, 270.0);
+ }
}
describe('DataMatrixBlackBox.1', () => {
- it('testBlackBox', async () => {
- const test = new DataMatrixBlackBox1Spec();
- await test.testBlackBox();
- });
+ it('testBlackBox', async () => {
+ const test = new DataMatrixBlackBox1Spec();
+ await test.testBlackBox();
+ });
});
diff --git a/src/test/core/datamatrix/decoder/DecodedBitStreamParser.spec.ts b/src/test/core/datamatrix/decoder/DecodedBitStreamParser.spec.ts
index e7a09385..87ae2502 100644
--- a/src/test/core/datamatrix/decoder/DecodedBitStreamParser.spec.ts
+++ b/src/test/core/datamatrix/decoder/DecodedBitStreamParser.spec.ts
@@ -3,27 +3,27 @@ import { DataMatrixDecodedBitStreamParser } from '@zxing/library';
describe('QRCodeDecodedBitStreamParser', () => {
- it('testAsciiStandardDecode', () => {
+ it('testAsciiStandardDecode', () => {
// ASCII characters 0-127 are encoded as the value + 1
- const bytes: Uint8Array = new Uint8Array(6);
- bytes[0] = 'a'.charCodeAt(0) + 1;
- bytes[1] = 'b'.charCodeAt(0) + 1;
- bytes[2] = 'c'.charCodeAt(0) + 1;
- bytes[3] = 'A'.charCodeAt(0) + 1;
- bytes[4] = 'B'.charCodeAt(0) + 1;
- bytes[5] = 'C'.charCodeAt(0) + 1;
- const decodedString = DataMatrixDecodedBitStreamParser.decode(bytes).getText();
- assert.strictEqual(decodedString, 'abcABC');
- });
+ const bytes: Uint8Array = new Uint8Array(6);
+ bytes[0] = 'a'.charCodeAt(0) + 1;
+ bytes[1] = 'b'.charCodeAt(0) + 1;
+ bytes[2] = 'c'.charCodeAt(0) + 1;
+ bytes[3] = 'A'.charCodeAt(0) + 1;
+ bytes[4] = 'B'.charCodeAt(0) + 1;
+ bytes[5] = 'C'.charCodeAt(0) + 1;
+ const decodedString = DataMatrixDecodedBitStreamParser.decode(bytes).getText();
+ assert.strictEqual(decodedString, 'abcABC');
+ });
- it('testAsciiDoubleDigitDecode', () => {
- const bytes: Uint8Array = new Uint8Array(4);
- bytes[0] = 130;
- bytes[1] = 1 + 130;
- bytes[2] = 98 + 130;
- bytes[3] = 99 + 130;
- const decodedString = DataMatrixDecodedBitStreamParser.decode(bytes).getText();
- assert.strictEqual(decodedString, '00019899');
- });
+ it('testAsciiDoubleDigitDecode', () => {
+ const bytes: Uint8Array = new Uint8Array(4);
+ bytes[0] = 130;
+ bytes[1] = 1 + 130;
+ bytes[2] = 98 + 130;
+ bytes[3] = 99 + 130;
+ const decodedString = DataMatrixDecodedBitStreamParser.decode(bytes).getText();
+ assert.strictEqual(decodedString, '00019899');
+ });
});
diff --git a/src/test/core/oned/Code128BlackBox1.spec.ts b/src/test/core/oned/Code128BlackBox1.spec.ts
index 85d7da2c..2b7bcafb 100644
--- a/src/test/core/oned/Code128BlackBox1.spec.ts
+++ b/src/test/core/oned/Code128BlackBox1.spec.ts
@@ -25,16 +25,16 @@ import AbstractBlackBoxSpec from '../common/AbstractBlackBox';
* @author Sean Owen
*/
class Code128BlackBox1Spec extends AbstractBlackBoxSpec {
- public constructor() {
- super('src/test/resources/blackbox/code128-1', new MultiFormatReader(), BarcodeFormat.CODE_128);
- this.addTest(6, 6, 0.0);
- this.addTest(6, 6, 180.0);
- }
+ public constructor() {
+ super('src/test/resources/blackbox/code128-1', new MultiFormatReader(), BarcodeFormat.CODE_128);
+ this.addTest(6, 6, 0.0);
+ this.addTest(6, 6, 180.0);
+ }
}
describe('Code128BlackBox.1', () => {
- it('testBlackBox', async () => {
- const test = new Code128BlackBox1Spec();
- await test.testBlackBox();
- });
+ it('testBlackBox', async () => {
+ const test = new Code128BlackBox1Spec();
+ await test.testBlackBox();
+ });
});
diff --git a/src/test/core/oned/Code39BlackBox1.spec.ts b/src/test/core/oned/Code39BlackBox1.spec.ts
index 1d04426a..dcb0e6bf 100644
--- a/src/test/core/oned/Code39BlackBox1.spec.ts
+++ b/src/test/core/oned/Code39BlackBox1.spec.ts
@@ -25,16 +25,16 @@ import AbstractBlackBoxSpec from './../common/AbstractBlackBox';
* @author Sean Owen
*/
class Code39BlackBox1Spec extends AbstractBlackBoxSpec {
- public constructor() {
- super('src/test/resources/blackbox/code39-1', new MultiFormatReader(), BarcodeFormat.CODE_39);
- this.addTest(4, 4, 0.0);
- this.addTest(4, 4, 180.0);
- }
+ public constructor() {
+ super('src/test/resources/blackbox/code39-1', new MultiFormatReader(), BarcodeFormat.CODE_39);
+ this.addTest(4, 4, 0.0);
+ this.addTest(4, 4, 180.0);
+ }
}
describe('Code39BlackBox.1', () => {
- it('testBlackBox', async () => {
- const test = new Code39BlackBox1Spec();
- await test.testBlackBox();
- });
+ it('testBlackBox', async () => {
+ const test = new Code39BlackBox1Spec();
+ await test.testBlackBox();
+ });
});
diff --git a/src/test/core/oned/Code39BlackBox3.spec.ts b/src/test/core/oned/Code39BlackBox3.spec.ts
index c13898bf..066780d9 100644
--- a/src/test/core/oned/Code39BlackBox3.spec.ts
+++ b/src/test/core/oned/Code39BlackBox3.spec.ts
@@ -25,16 +25,16 @@ import AbstractBlackBoxSpec from './../common/AbstractBlackBox';
* @author Sean Owen
*/
class Code39BlackBox3Spec extends AbstractBlackBoxSpec {
- public constructor() {
- super('src/test/resources/blackbox/code39-3', new MultiFormatReader(), BarcodeFormat.CODE_39);
- this.addTest(17, 17, 0.0);
- this.addTest(17, 17, 180.0);
- }
+ public constructor() {
+ super('src/test/resources/blackbox/code39-3', new MultiFormatReader(), BarcodeFormat.CODE_39);
+ this.addTest(17, 17, 0.0);
+ this.addTest(17, 17, 180.0);
+ }
}
describe('Code39BlackBox.3', () => {
- it('testBlackBox', async () => {
- const test = new Code39BlackBox3Spec();
- await test.testBlackBox();
- });
+ it('testBlackBox', async () => {
+ const test = new Code39BlackBox3Spec();
+ await test.testBlackBox();
+ });
});
diff --git a/src/test/core/oned/Code39ExtendedBlackBox2.spec.ts b/src/test/core/oned/Code39ExtendedBlackBox2.spec.ts
index f681c687..f1fcbc28 100644
--- a/src/test/core/oned/Code39ExtendedBlackBox2.spec.ts
+++ b/src/test/core/oned/Code39ExtendedBlackBox2.spec.ts
@@ -25,16 +25,16 @@ import { Code39Reader } from '@zxing/library';
* @author Sean Owen
*/
class Code39ExtendedBlackBox2Spec extends AbstractBlackBoxSpec {
- public constructor() {
- super('src/test/resources/blackbox/code39-2', new Code39Reader(false, true), BarcodeFormat.CODE_39);
- this.addTest(2, 2, 0.0);
- this.addTest(2, 2, 180.0);
- }
+ public constructor() {
+ super('src/test/resources/blackbox/code39-2', new Code39Reader(false, true), BarcodeFormat.CODE_39);
+ this.addTest(2, 2, 0.0);
+ this.addTest(2, 2, 180.0);
+ }
}
describe('Code39ExtendedBlackBox.2', () => {
- it('testBlackBox', async () => {
- const test = new Code39ExtendedBlackBox2Spec();
- await test.testBlackBox();
- });
+ it('testBlackBox', async () => {
+ const test = new Code39ExtendedBlackBox2Spec();
+ await test.testBlackBox();
+ });
});
diff --git a/src/test/core/oned/Code39ExtendedMode.spec.ts b/src/test/core/oned/Code39ExtendedMode.spec.ts
index 71c57253..519a93c3 100644
--- a/src/test/core/oned/Code39ExtendedMode.spec.ts
+++ b/src/test/core/oned/Code39ExtendedMode.spec.ts
@@ -23,29 +23,29 @@ import { BitMatrix } from '@zxing/library';
import { BitArray } from '@zxing/library';
function doTest(expectedResult: string, encodedResult: string): void {
- const sut = new Code39Reader(false, true);
- const matrix = BitMatrix.parseFromString(encodedResult, '1', '0');
- const row = new BitArray(matrix.getWidth());
- matrix.getRow(0, row);
- const result = sut.decodeRow(0, row, null);
- assert.strictEqual(expectedResult, result.getText());
- }
+ const sut = new Code39Reader(false, true);
+ const matrix = BitMatrix.parseFromString(encodedResult, '1', '0');
+ const row = new BitArray(matrix.getWidth());
+ matrix.getRow(0, row);
+ const result = sut.decodeRow(0, row, null);
+ assert.strictEqual(expectedResult, result.getText());
+}
describe('Code39ExtendedMode', () => {
- it('test 1', () => {
- doTest('\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f',
- '000001001011011010101001001001011001010101101001001001010110101001011010010010010101011010010110100100100101011011010010101001001001010101011001011010010010010101101011001010100100100101010110110010101001001001010101010011011010010010010101101010011010100100100101010110100110101001001001010101011001101010010010010101101010100110100100100101010110101001101001001001010110110101001010010010010101010110100110100100100101011010110100101001001001010101101101001010010010010101010101100110100100100101011010101100101001001001010101101011001010010010010101010110110010100100100101011001010101101001001001010100110101011010010010010101100110101010100100100101010010110101101001001001010110010110101010010010010101001101101010101001001001011010100101101010010010010101101001011010100100100101101101001010101001001001010101100101101010010010010110101100101010010110110100000');
- });
- it('test 2', () => {
- doTest(' !"#$%&\'()*+,-./0123456789:;<=>?',
- '00000100101101101010011010110101001001010010110101001011010010010100101011010010110100100101001011011010010101001001010010101011001011010010010100101101011001010100100101001010110110010101001001010010101010011011010010010100101101010011010100100101001010110100110101001001010010101011001101010010010100101101010100110100100101001010110101001101001010110110110010101101010010010100101101011010010101001101101011010010101101011001010110110110010101010100110101101101001101010101100110101010100101101101101001011010101100101101010010010100101001101101010101001001001010110110010101010010010010101010011011010100100100101101010011010101001001001010110100110101010010010010101011001101010010110110100000');
- });
- it('test 3', () => {
- doTest('@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_',
- '000010010110110101010010010010100110101011011010100101101011010010110110110100101010101100101101101011001010101101100101010101001101101101010011010101101001101010101100110101101010100110101101010011011011010100101010110100110110101101001010110110100101010101100110110101011001010110101100101010110110010110010101011010011010101101100110101010100101101011011001011010101001101101010101001001001011010101001101010010010010101101010011010100100100101101101010010101001001001010101101001101010010010010110101101001010010110110100000');
- });
- it('test 4', () => {
- doTest('`abcdefghijklmnopqrstuvwxyz{|}~',
- '000001001011011010101001001001011001101010101001010010010110101001011010010100100101011010010110100101001001011011010010101001010010010101011001011010010100100101101011001010100101001001010110110010101001010010010101010011011010010100100101101010011010100101001001010110100110101001010010010101011001101010010100100101101010100110100101001001010110101001101001010010010110110101001010010100100101010110100110100101001001011010110100101001010010010101101101001010010100100101010101100110100101001001011010101100101001010010010101101011001010010100100101010110110010100101001001011001010101101001010010010100110101011010010100100101100110101010100101001001010010110101101001010010010110010110101010010100100101001101101010101001001001010110110100101010010010010101010110011010100100100101101010110010101001001001010110101100101010010010010101011011001010010110110100000');
- });
+ it('test 1', () => {
+ doTest('\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f',
+ '000001001011011010101001001001011001010101101001001001010110101001011010010010010101011010010110100100100101011011010010101001001001010101011001011010010010010101101011001010100100100101010110110010101001001001010101010011011010010010010101101010011010100100100101010110100110101001001001010101011001101010010010010101101010100110100100100101010110101001101001001001010110110101001010010010010101010110100110100100100101011010110100101001001001010101101101001010010010010101010101100110100100100101011010101100101001001001010101101011001010010010010101010110110010100100100101011001010101101001001001010100110101011010010010010101100110101010100100100101010010110101101001001001010110010110101010010010010101001101101010101001001001011010100101101010010010010101101001011010100100100101101101001010101001001001010101100101101010010010010110101100101010010110110100000');
+ });
+ it('test 2', () => {
+ doTest(' !"#$%&\'()*+,-./0123456789:;<=>?',
+ '00000100101101101010011010110101001001010010110101001011010010010100101011010010110100100101001011011010010101001001010010101011001011010010010100101101011001010100100101001010110110010101001001010010101010011011010010010100101101010011010100100101001010110100110101001001010010101011001101010010010100101101010100110100100101001010110101001101001010110110110010101101010010010100101101011010010101001101101011010010101101011001010110110110010101010100110101101101001101010101100110101010100101101101101001011010101100101101010010010100101001101101010101001001001010110110010101010010010010101010011011010100100100101101010011010101001001001010110100110101010010010010101011001101010010110110100000');
+ });
+ it('test 3', () => {
+ doTest('@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_',
+ '000010010110110101010010010010100110101011011010100101101011010010110110110100101010101100101101101011001010101101100101010101001101101101010011010101101001101010101100110101101010100110101101010011011011010100101010110100110110101101001010110110100101010101100110110101011001010110101100101010110110010110010101011010011010101101100110101010100101101011011001011010101001101101010101001001001011010101001101010010010010101101010011010100100100101101101010010101001001001010101101001101010010010010110101101001010010110110100000');
+ });
+ it('test 4', () => {
+ doTest('`abcdefghijklmnopqrstuvwxyz{|}~',
+ '000001001011011010101001001001011001101010101001010010010110101001011010010100100101011010010110100101001001011011010010101001010010010101011001011010010100100101101011001010100101001001010110110010101001010010010101010011011010010100100101101010011010100101001001010110100110101001010010010101011001101010010100100101101010100110100101001001010110101001101001010010010110110101001010010100100101010110100110100101001001011010110100101001010010010101101101001010010100100101010101100110100101001001011010101100101001010010010101101011001010010100100101010110110010100101001001011001010101101001010010010100110101011010010100100101100110101010100101001001010010110101101001010010010110010110101010010100100101001101101010101001001001010110110100101010010010010101010110011010100100100101101010110010101001001001010110101100101010010010010101011011001010010110110100000');
+ });
});
diff --git a/src/test/core/oned/Ean13BlackBox1.spec.ts b/src/test/core/oned/Ean13BlackBox1.spec.ts
index cd57f3e9..540b4609 100644
--- a/src/test/core/oned/Ean13BlackBox1.spec.ts
+++ b/src/test/core/oned/Ean13BlackBox1.spec.ts
@@ -23,16 +23,16 @@ import AbstractBlackBoxSpec from '../common/AbstractBlackBox';
*/
class Ean13BlackBox1Spec extends AbstractBlackBoxSpec {
- public constructor() {
- super('src/test/resources/blackbox/ean13-1', new MultiFormatReader(), BarcodeFormat.EAN_13);
- this.addTest(30, 31, 0.0);
- this.addTest(27, 31, 180.0);
- }
+ public constructor() {
+ super('src/test/resources/blackbox/ean13-1', new MultiFormatReader(), BarcodeFormat.EAN_13);
+ this.addTest(30, 31, 0.0);
+ this.addTest(27, 31, 180.0);
+ }
}
describe('Ean13BlackBox1Spec.1', () => {
- it('testBlackBox', async () => {
- const test = new Ean13BlackBox1Spec();
- await test.testBlackBox();
- });
+ it('testBlackBox', async () => {
+ const test = new Ean13BlackBox1Spec();
+ await test.testBlackBox();
+ });
});
diff --git a/src/test/core/oned/Ean8BlackBox1.spec.ts b/src/test/core/oned/Ean8BlackBox1.spec.ts
index 85aa324c..6e7f0521 100644
--- a/src/test/core/oned/Ean8BlackBox1.spec.ts
+++ b/src/test/core/oned/Ean8BlackBox1.spec.ts
@@ -23,16 +23,16 @@ import AbstractBlackBoxSpec from '../common/AbstractBlackBox';
*/
class Ean8BlackBox1Spec extends AbstractBlackBoxSpec {
- public constructor() {
- super('src/test/resources/blackbox/ean8-1', new MultiFormatReader(), BarcodeFormat.EAN_8);
- this.addTest(8, 8, 0.0);
- this.addTest(8, 8, 180.0);
- }
+ public constructor() {
+ super('src/test/resources/blackbox/ean8-1', new MultiFormatReader(), BarcodeFormat.EAN_8);
+ this.addTest(8, 8, 0.0);
+ this.addTest(8, 8, 180.0);
+ }
}
describe('Ean8BlackBox1Spec.1', () => {
- it('testBlackBox', async () => {
- const test = new Ean8BlackBox1Spec();
- await test.testBlackBox();
- });
+ it('testBlackBox', async () => {
+ const test = new Ean8BlackBox1Spec();
+ await test.testBlackBox();
+ });
});
diff --git a/src/test/core/oned/ITFBlackBox.spec.ts b/src/test/core/oned/ITFBlackBox.spec.ts
index b7ae37b7..168bedfb 100644
--- a/src/test/core/oned/ITFBlackBox.spec.ts
+++ b/src/test/core/oned/ITFBlackBox.spec.ts
@@ -27,17 +27,17 @@ import AbstractBlackBoxSpec from '../common/AbstractBlackBox';
class ITFBlackBoxSpec extends AbstractBlackBoxSpec {
- public constructor() {
- super('src/test/resources/blackbox/itf', new MultiFormatReader(), BarcodeFormat.ITF);
- this.addTest(1, 1, 0.0);
- this.addTest(1, 1, 180.0);
- }
+ public constructor() {
+ super('src/test/resources/blackbox/itf', new MultiFormatReader(), BarcodeFormat.ITF);
+ this.addTest(1, 1, 0.0);
+ this.addTest(1, 1, 180.0);
+ }
}
describe('ITFBlackBox', () => {
- it('testBlackBox', async () => {
- const test = new ITFBlackBoxSpec();
- await test.testBlackBox();
- });
+ it('testBlackBox', async () => {
+ const test = new ITFBlackBoxSpec();
+ await test.testBlackBox();
+ });
});
diff --git a/src/test/core/oned/rss/RSS14BlackBox1.spec.ts b/src/test/core/oned/rss/RSS14BlackBox1.spec.ts
index 8e31d0dc..11d48d19 100644
--- a/src/test/core/oned/rss/RSS14BlackBox1.spec.ts
+++ b/src/test/core/oned/rss/RSS14BlackBox1.spec.ts
@@ -27,17 +27,17 @@ import AbstractBlackBoxSpec from '../../common/AbstractBlackBox';
class RSS14BlackBox1Spec extends AbstractBlackBoxSpec {
- public constructor() {
- super('src/test/resources/blackbox/rss14-1', new MultiFormatReader(), BarcodeFormat.RSS_14);
- this.addTest(6, 6, 0.0);
- this.addTest(6, 6, 180.0);
- }
+ public constructor() {
+ super('src/test/resources/blackbox/rss14-1', new MultiFormatReader(), BarcodeFormat.RSS_14);
+ this.addTest(6, 6, 0.0);
+ this.addTest(6, 6, 180.0);
+ }
}
describe('RSS14BlackBox.1', () => {
- it('testBlackBox', async () => {
- const test = new RSS14BlackBox1Spec();
- await test.testBlackBox();
- });
+ it('testBlackBox', async () => {
+ const test = new RSS14BlackBox1Spec();
+ await test.testBlackBox();
+ });
});
diff --git a/src/test/core/oned/rss/RSS14BlackBox2.spec.ts b/src/test/core/oned/rss/RSS14BlackBox2.spec.ts
index e837a056..9b8519e2 100644
--- a/src/test/core/oned/rss/RSS14BlackBox2.spec.ts
+++ b/src/test/core/oned/rss/RSS14BlackBox2.spec.ts
@@ -27,17 +27,17 @@ import AbstractBlackBoxSpec from '../../common/AbstractBlackBox';
class RSS14BlackBox2Spec extends AbstractBlackBoxSpec {
- public constructor() {
- super('src/test/resources/blackbox/rss14-2', new MultiFormatReader(), BarcodeFormat.RSS_14);
- this.addTestWithMax(4, 8, 1, 1, 0.0);
- this.addTestWithMax(2, 8, 0, 1, 180.0);
- }
+ public constructor() {
+ super('src/test/resources/blackbox/rss14-2', new MultiFormatReader(), BarcodeFormat.RSS_14);
+ this.addTestWithMax(4, 8, 1, 1, 0.0);
+ this.addTestWithMax(2, 8, 0, 1, 180.0);
+ }
}
describe('RSS14BlackBox.2', () => {
- it('testBlackBox', async () => {
- const test = new RSS14BlackBox2Spec();
- await test.testBlackBox();
- });
+ it('testBlackBox', async () => {
+ const test = new RSS14BlackBox2Spec();
+ await test.testBlackBox();
+ });
});
diff --git a/src/test/core/oned/rss/expanded/decoders/AI013103DecoderTest.java b/src/test/core/oned/rss/expanded/decoders/AI013103DecoderTest.java
index 28e3c30f..03ca1419 100644
--- a/src/test/core/oned/rss/expanded/decoders/AI013103DecoderTest.java
+++ b/src/test/core/oned/rss/expanded/decoders/AI013103DecoderTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-/*
+/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
diff --git a/src/test/core/oned/rss/expanded/decoders/AnyAIDecoderTest.java b/src/test/core/oned/rss/expanded/decoders/AnyAIDecoderTest.java
index 1036c692..ea7e7ab9 100644
--- a/src/test/core/oned/rss/expanded/decoders/AnyAIDecoderTest.java
+++ b/src/test/core/oned/rss/expanded/decoders/AnyAIDecoderTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-/*
+/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
diff --git a/src/test/core/oned/rss/expanded/expanded/RSSExpandedBlackBox3TestCase.java b/src/test/core/oned/rss/expanded/expanded/RSSExpandedBlackBox3TestCase.java
index 002ce697..0e573721 100644
--- a/src/test/core/oned/rss/expanded/expanded/RSSExpandedBlackBox3TestCase.java
+++ b/src/test/core/oned/rss/expanded/expanded/RSSExpandedBlackBox3TestCase.java
@@ -34,11 +34,11 @@
* A test of {@link RSSExpandedReader} against a fixed test set of images.
*/
public final class RSSExpandedBlackBox3TestCase extends AbstractBlackBoxTestCase {
-
+
public RSSExpandedBlackBox3TestCase() {
super("src/test/resources/blackbox/rssexpanded-3", new MultiFormatReader(), BarcodeFormat.RSS_EXPANDED);
addTest(117, 117, 0.0f);
addTest(117, 117, 180.0f);
}
}
-
+
diff --git a/src/test/core/oned/rss/expanded/expanded/RSSExpandedStackedBlackBox1TestCase.java b/src/test/core/oned/rss/expanded/expanded/RSSExpandedStackedBlackBox1TestCase.java
index dabe8b13..aa261c49 100644
--- a/src/test/core/oned/rss/expanded/expanded/RSSExpandedStackedBlackBox1TestCase.java
+++ b/src/test/core/oned/rss/expanded/expanded/RSSExpandedStackedBlackBox1TestCase.java
@@ -35,7 +35,7 @@
* stacked RSS barcodes.
*/
public final class RSSExpandedStackedBlackBox1TestCase extends AbstractBlackBoxTestCase {
-
+
public RSSExpandedStackedBlackBox1TestCase() {
super("src/test/resources/blackbox/rssexpandedstacked-1", new MultiFormatReader(), BarcodeFormat.RSS_EXPANDED);
addTest(59, 64, 0.0f);
@@ -43,4 +43,4 @@ public RSSExpandedStackedBlackBox1TestCase() {
}
}
-
+
diff --git a/src/test/core/oned/rss/expanded/expanded/RSSExpandedStackedBlackBox2TestCase.java b/src/test/core/oned/rss/expanded/expanded/RSSExpandedStackedBlackBox2TestCase.java
index ee0e008c..9f0bf7c6 100644
--- a/src/test/core/oned/rss/expanded/expanded/RSSExpandedStackedBlackBox2TestCase.java
+++ b/src/test/core/oned/rss/expanded/expanded/RSSExpandedStackedBlackBox2TestCase.java
@@ -35,7 +35,7 @@
* stacked RSS barcodes.
*/
public final class RSSExpandedStackedBlackBox2TestCase extends AbstractBlackBoxTestCase {
-
+
public RSSExpandedStackedBlackBox2TestCase() {
super("src/test/resources/blackbox/rssexpandedstacked-2", new MultiFormatReader(), BarcodeFormat.RSS_EXPANDED);
addTest(2, 7, 0.0f);
@@ -43,4 +43,4 @@ public RSSExpandedStackedBlackBox2TestCase() {
}
}
-
+
diff --git a/src/test/core/oned/rss/expanded/expanded/decoders/AI013103DecoderTest.java b/src/test/core/oned/rss/expanded/expanded/decoders/AI013103DecoderTest.java
index 28e3c30f..03ca1419 100644
--- a/src/test/core/oned/rss/expanded/expanded/decoders/AI013103DecoderTest.java
+++ b/src/test/core/oned/rss/expanded/expanded/decoders/AI013103DecoderTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-/*
+/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
diff --git a/src/test/core/oned/rss/expanded/expanded/decoders/AnyAIDecoderTest.java b/src/test/core/oned/rss/expanded/expanded/decoders/AnyAIDecoderTest.java
index 1036c692..ea7e7ab9 100644
--- a/src/test/core/oned/rss/expanded/expanded/decoders/AnyAIDecoderTest.java
+++ b/src/test/core/oned/rss/expanded/expanded/decoders/AnyAIDecoderTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-/*
+/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
diff --git a/src/test/core/pdf417/decoder/ec/AbstractErrorCorrection.spec.ts b/src/test/core/pdf417/decoder/ec/AbstractErrorCorrection.spec.ts
index cd8268f3..4e47153e 100644
--- a/src/test/core/pdf417/decoder/ec/AbstractErrorCorrection.spec.ts
+++ b/src/test/core/pdf417/decoder/ec/AbstractErrorCorrection.spec.ts
@@ -29,31 +29,31 @@ import { corrupt } from '../../../common/reedsolomon/ReedSolomonCorrupt';
*/
export default abstract class AbstractErrorCorrectionSpec {
- static corrupt(received: Int32Array, howMany: /*int*/number, random: Random): void {
- corrupt(received, howMany, random, 929);
+ static corrupt(received: Int32Array, howMany: /*int*/number, random: Random): void {
+ corrupt(received, howMany, random, 929);
+ }
+
+ static erase(received: Int32Array, howMany: /*int*/number, random: Random): Int32Array {
+ const erased: BitSet = new Map(/*received.length*/);
+ const erasures = new Int32Array(howMany);
+
+ let erasureOffset = 0;
+
+ for (let j = 0; j < howMany; j++) {
+ const location = random.next(received.length);
+ if (erased.get(location)) {
+ j--;
+ } else {
+ erased.set(location, true);
+ received[location] = 0;
+ erasures[erasureOffset++] = location;
+ }
}
+ return erasures;
+ }
- static erase(received: Int32Array, howMany: /*int*/number, random: Random): Int32Array {
- const erased: BitSet = new Map(/*received.length*/);
- const erasures = new Int32Array(howMany);
-
- let erasureOffset = 0;
-
- for (let j = 0; j < howMany; j++) {
- const location = random.next(received.length);
- if (erased.get(location)) {
- j--;
- } else {
- erased.set(location, true);
- received[location] = 0;
- erasures[erasureOffset++] = location;
- }
- }
- return erasures;
- }
-
- static getRandom(): Random {
- return new Random('0xDEADBEEF');
- }
+ static getRandom(): Random {
+ return new Random('0xDEADBEEF');
+ }
}
diff --git a/src/test/core/pdf417/decoder/ec/ErrorCorrection.spec.ts b/src/test/core/pdf417/decoder/ec/ErrorCorrection.spec.ts
index 8c9de10e..996ea595 100644
--- a/src/test/core/pdf417/decoder/ec/ErrorCorrection.spec.ts
+++ b/src/test/core/pdf417/decoder/ec/ErrorCorrection.spec.ts
@@ -37,115 +37,115 @@ import AbstractErrorCorrectionSpec from './AbstractErrorCorrection.spec';
// class ErrorCorrectionTestCase extends AbstractErrorCorrectionSpec {
describe('ErrorCorrectionTestCase', () => {
- // @Test
- // public void testNoError() throws ChecksumException {
- it('testNoError', () => {
-
- const received = Int32Array.from(PDF417_TEST_WITH_EC);
- // no errors
- checkDecode(received);
- });
- // }
-
- // @Test
- // public void testOneError() throws ChecksumException {
- it('testOneError', () => {
-
- const random = AbstractErrorCorrectionSpec.getRandom();
- for (let i: number /*int*/ = 0; i < PDF417_TEST_WITH_EC.length; i++) {
- const received: Int32Array = Int32Array.from(PDF417_TEST_WITH_EC);
- received[i] = random.nextInt(256);
- checkDecode(received);
- }
- });
- // }
-
- // @Test
- // public void testMaxErrors() throws ChecksumException {
- it('testMaxErrors', () => {
-
- const random: Random = AbstractErrorCorrectionSpec.getRandom();
-
- for (let testIterations /*int*/ = 0; testIterations < 100; testIterations++) { // # iterations is kind of arbitrary
- const received: Int32Array = Int32Array.from(PDF417_TEST_WITH_EC);
- AbstractErrorCorrectionSpec.corrupt(received, MAX_ERRORS, random);
- checkDecode(received);
- }
- });
- // }
-
- // @Test
- // public void testTooManyErrors() {
- it('testTooManyErrors', () => {
-
- const received: Int32Array = Int32Array.from(PDF417_TEST_WITH_EC);
- const random: Random = AbstractErrorCorrectionSpec.getRandom();
- AbstractErrorCorrectionSpec.corrupt(received, MAX_ERRORS + 1, random);
- try {
- checkDecode(received);
- assert.fail('Should not have decoded');
- } catch (ce) {
- if (ce instanceof ChecksumException) {
- // good
- return;
- }
- throw ce;
- }
- });
- // }
-
- // @Ignore("Erasures not implemented yet")
- // @Test
- // public void testMaxErasures() throws ChecksumException {
- it('testMaxErasures', () => {
-
- // ignored as Java version
- return;
+ // @Test
+ // public void testNoError() throws ChecksumException {
+ it('testNoError', () => {
+
+ const received = Int32Array.from(PDF417_TEST_WITH_EC);
+ // no errors
+ checkDecode(received);
+ });
+ // }
+
+ // @Test
+ // public void testOneError() throws ChecksumException {
+ it('testOneError', () => {
+
+ const random = AbstractErrorCorrectionSpec.getRandom();
+ for (let i: number /*int*/ = 0; i < PDF417_TEST_WITH_EC.length; i++) {
+ const received: Int32Array = Int32Array.from(PDF417_TEST_WITH_EC);
+ received[i] = random.nextInt(256);
+ checkDecode(received);
+ }
+ });
+ // }
+
+ // @Test
+ // public void testMaxErrors() throws ChecksumException {
+ it('testMaxErrors', () => {
- const random: Random = AbstractErrorCorrectionSpec.getRandom();
- for (const test /*int*/ of PDF417_TEST) { // # iterations is kind of arbitrary
- const received = Int32Array.from(PDF417_TEST_WITH_EC);
- const erasures = AbstractErrorCorrectionSpec.erase(received, MAX_ERASURES, random);
- checkDecode(received, erasures);
- }
- });
- // }
-
- // @Ignore("Erasures not implemented yet")
- // @Test
- // public void testTooManyErasures() {
- it('testTooManyErasures', () => {
-
- const random: Random = AbstractErrorCorrectionSpec.getRandom();
- const received: Int32Array = Int32Array.from(PDF417_TEST_WITH_EC);
- const erasures: Int32Array = AbstractErrorCorrectionSpec.erase(received, MAX_ERASURES + 1, random);
- try {
- checkDecode(received, erasures);
- assert.fail('Should not have decoded');
- } catch (ce) {
- if (ce instanceof ChecksumException) {
- // good
- return;
- }
- throw ce;
- }
- });
- // }
+ const random: Random = AbstractErrorCorrectionSpec.getRandom();
+
+ for (let testIterations /*int*/ = 0; testIterations < 100; testIterations++) { // # iterations is kind of arbitrary
+ const received: Int32Array = Int32Array.from(PDF417_TEST_WITH_EC);
+ AbstractErrorCorrectionSpec.corrupt(received, MAX_ERRORS, random);
+ checkDecode(received);
+ }
+ });
+ // }
+
+ // @Test
+ // public void testTooManyErrors() {
+ it('testTooManyErrors', () => {
+
+ const received: Int32Array = Int32Array.from(PDF417_TEST_WITH_EC);
+ const random: Random = AbstractErrorCorrectionSpec.getRandom();
+ AbstractErrorCorrectionSpec.corrupt(received, MAX_ERRORS + 1, random);
+ try {
+ checkDecode(received);
+ assert.fail('Should not have decoded');
+ } catch (ce) {
+ if (ce instanceof ChecksumException) {
+ // good
+ return;
+ }
+ throw ce;
+ }
+ });
+ // }
+
+ // @Ignore("Erasures not implemented yet")
+ // @Test
+ // public void testMaxErasures() throws ChecksumException {
+ it('testMaxErasures', () => {
+
+ // ignored as Java version
+ return;
+
+ const random: Random = AbstractErrorCorrectionSpec.getRandom();
+ for (const test /*int*/ of PDF417_TEST) { // # iterations is kind of arbitrary
+ const received = Int32Array.from(PDF417_TEST_WITH_EC);
+ const erasures = AbstractErrorCorrectionSpec.erase(received, MAX_ERASURES, random);
+ checkDecode(received, erasures);
+ }
+ });
+ // }
+
+ // @Ignore("Erasures not implemented yet")
+ // @Test
+ // public void testTooManyErasures() {
+ it('testTooManyErasures', () => {
+
+ const random: Random = AbstractErrorCorrectionSpec.getRandom();
+ const received: Int32Array = Int32Array.from(PDF417_TEST_WITH_EC);
+ const erasures: Int32Array = AbstractErrorCorrectionSpec.erase(received, MAX_ERASURES + 1, random);
+ try {
+ checkDecode(received, erasures);
+ assert.fail('Should not have decoded');
+ } catch (ce) {
+ if (ce instanceof ChecksumException) {
+ // good
+ return;
+ }
+ throw ce;
+ }
+ });
+ // }
});
const /*private static final int[]*/ PDF417_TEST = Int32Array.from([
- 48, 901, 56, 141, 627, 856, 330, 69, 244, 900, 852, 169, 843, 895, 852, 895, 913, 154, 845, 778, 387, 89, 869,
- 901, 219, 474, 543, 650, 169, 201, 9, 160, 35, 70, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900,
- 900, 900
+ 48, 901, 56, 141, 627, 856, 330, 69, 244, 900, 852, 169, 843, 895, 852, 895, 913, 154, 845, 778, 387, 89, 869,
+ 901, 219, 474, 543, 650, 169, 201, 9, 160, 35, 70, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900,
+ 900, 900
]);
const /*private static final int[]*/ PDF417_TEST_WITH_EC = Int32Array.from([
- 48, 901, 56, 141, 627, 856, 330, 69, 244, 900, 852, 169, 843, 895, 852, 895, 913, 154, 845, 778, 387, 89, 869,
- 901, 219, 474, 543, 650, 169, 201, 9, 160, 35, 70, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900,
- 900, 900, 769, 843, 591, 910, 605, 206, 706, 917, 371, 469, 79, 718, 47, 777, 249, 262, 193, 620, 597, 477, 450,
- 806, 908, 309, 153, 871, 686, 838, 185, 674, 68, 679, 691, 794, 497, 479, 234, 250, 496, 43, 347, 582, 882, 536,
- 322, 317, 273, 194, 917, 237, 420, 859, 340, 115, 222, 808, 866, 836, 417, 121, 833, 459, 64, 159
+ 48, 901, 56, 141, 627, 856, 330, 69, 244, 900, 852, 169, 843, 895, 852, 895, 913, 154, 845, 778, 387, 89, 869,
+ 901, 219, 474, 543, 650, 169, 201, 9, 160, 35, 70, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900,
+ 900, 900, 769, 843, 591, 910, 605, 206, 706, 917, 371, 469, 79, 718, 47, 777, 249, 262, 193, 620, 597, 477, 450,
+ 806, 908, 309, 153, 871, 686, 838, 185, 674, 68, 679, 691, 794, 497, 479, 234, 250, 496, 43, 347, 582, 882, 536,
+ 322, 317, 273, 194, 917, 237, 420, 859, 340, 115, 222, 808, 866, 836, 417, 121, 833, 459, 64, 159
]);
const /*private static final int*/ ECC_BYTES: number = PDF417_TEST_WITH_EC.length - PDF417_TEST.length;
@@ -160,8 +160,8 @@ const /*private final ErrorCorrection*/ ec = new PDF417DecoderErrorCorrection();
* @throws ChecksumException
*/
function /*private void*/ checkDecode(received: Int32Array, erasures?: Int32Array) {
- ec.decode(received, ECC_BYTES, erasures || Int32Array.from([0]));
- for (let /*int*/ i = 0; i < PDF417_TEST.length; i++) {
- assert.strictEqual(received[i], PDF417_TEST[i]);
- }
+ ec.decode(received, ECC_BYTES, erasures || Int32Array.from([0]));
+ for (let /*int*/ i = 0; i < PDF417_TEST.length; i++) {
+ assert.strictEqual(received[i], PDF417_TEST[i]);
+ }
}
diff --git a/src/test/core/qrcode/HybridBinarizer.spec.ts b/src/test/core/qrcode/HybridBinarizer.spec.ts
index 9adca8e9..ce736bac 100644
--- a/src/test/core/qrcode/HybridBinarizer.spec.ts
+++ b/src/test/core/qrcode/HybridBinarizer.spec.ts
@@ -6,17 +6,17 @@ import SharpImage from '../util/SharpImage';
const path = require('path');
describe('HybridBinarizer', () => {
- it('testHybridBinarizer', async () => {
+ it('testHybridBinarizer', async () => {
- const pathString = path.resolve('src/test/resources/blackbox/common/simple.png');
+ const pathString = path.resolve('src/test/resources/blackbox/common/simple.png');
- const image = await SharpImage.loadWithRotation(pathString, 0);
+ const image = await SharpImage.loadWithRotation(pathString, 0);
- const source = new SharpImageLuminanceSource(image);
- const test = new HybridBinarizer(source);
- const matrix = test.getBlackMatrix();
+ const source = new SharpImageLuminanceSource(image);
+ const test = new HybridBinarizer(source);
+ const matrix = test.getBlackMatrix();
- assert.equal(0, matrix.get(13, 12));
- assert.equal(1, matrix.get(13, 13));
- });
+ assert.equal(0, matrix.get(13, 12));
+ assert.equal(1, matrix.get(13, 13));
+ });
});
diff --git a/src/test/core/qrcode/QRCodeBlackBox.1.spec.ts b/src/test/core/qrcode/QRCodeBlackBox.1.spec.ts
index 52f0b7cd..ce0deb3e 100644
--- a/src/test/core/qrcode/QRCodeBlackBox.1.spec.ts
+++ b/src/test/core/qrcode/QRCodeBlackBox.1.spec.ts
@@ -25,19 +25,19 @@ import AbstractBlackBoxSpec from '../common/AbstractBlackBox';
*/
class QRCodeBlackBox1Spec extends AbstractBlackBoxSpec {
- public constructor() {
- super('src/test/resources/blackbox/qrcode-1', new MultiFormatReader(), BarcodeFormat.QR_CODE);
- this.addTest(17, 17, 0.0);
- this.addTest(14, 14, 90.0);
- this.addTest(17, 17, 180.0);
- this.addTest(14, 14, 270.0);
- }
+ public constructor() {
+ super('src/test/resources/blackbox/qrcode-1', new MultiFormatReader(), BarcodeFormat.QR_CODE);
+ this.addTest(17, 17, 0.0);
+ this.addTest(14, 14, 90.0);
+ this.addTest(17, 17, 180.0);
+ this.addTest(14, 14, 270.0);
+ }
}
describe('QRCodeBlackBox.1', () => {
- it('testBlackBox', async () => {
- const test = new QRCodeBlackBox1Spec();
- await test.testBlackBox();
- });
+ it('testBlackBox', async () => {
+ const test = new QRCodeBlackBox1Spec();
+ await test.testBlackBox();
+ });
});
diff --git a/src/test/core/qrcode/QRCodeBlackBox.2.spec.ts b/src/test/core/qrcode/QRCodeBlackBox.2.spec.ts
index 8a0f2586..a38c8ce4 100644
--- a/src/test/core/qrcode/QRCodeBlackBox.2.spec.ts
+++ b/src/test/core/qrcode/QRCodeBlackBox.2.spec.ts
@@ -30,20 +30,20 @@ ZXingStringEncoding.customEncoder = (b, e) => new TextEncoder(e, { NONSTANDARD_a
*/
export default class QRCodeBlackBox2Spec extends AbstractBlackBoxSpec {
- public constructor() {
- super('src/test/resources/blackbox/qrcode-2', new MultiFormatReader(), BarcodeFormat.QR_CODE);
- this.addTest(31, 31, 0.0);
- this.addTest(29, 29, 90.0);
- this.addTest(30, 30, 180.0);
- this.addTest(29, 29, 270.0);
- }
+ public constructor() {
+ super('src/test/resources/blackbox/qrcode-2', new MultiFormatReader(), BarcodeFormat.QR_CODE);
+ this.addTest(31, 31, 0.0);
+ this.addTest(29, 29, 90.0);
+ this.addTest(30, 30, 180.0);
+ this.addTest(29, 29, 270.0);
+ }
}
describe('QRCodeBlackBox.2', () => {
- it.skip('testBlackBox', async () => {
- const test = new QRCodeBlackBox2Spec();
- await test.testBlackBox();
- });
+ it.skip('testBlackBox', async () => {
+ const test = new QRCodeBlackBox2Spec();
+ await test.testBlackBox();
+ });
});
diff --git a/src/test/core/qrcode/QRCodeBlackBox.3.spec.ts b/src/test/core/qrcode/QRCodeBlackBox.3.spec.ts
index 4dac318a..6f857f5f 100644
--- a/src/test/core/qrcode/QRCodeBlackBox.3.spec.ts
+++ b/src/test/core/qrcode/QRCodeBlackBox.3.spec.ts
@@ -25,19 +25,19 @@ import AbstractBlackBoxSpec from '../common/AbstractBlackBox';
*/
export default class QRCodeBlackBox3Spec extends AbstractBlackBoxSpec {
- public constructor() {
- super('src/test/resources/blackbox/qrcode-3', new MultiFormatReader(), BarcodeFormat.QR_CODE);
- this.addTest(38, 38, 0.0);
- this.addTest(38, 38, 90.0);
- this.addTest(36, 36, 180.0);
- this.addTest(39, 39, 270.0);
- }
+ public constructor() {
+ super('src/test/resources/blackbox/qrcode-3', new MultiFormatReader(), BarcodeFormat.QR_CODE);
+ this.addTest(38, 38, 0.0);
+ this.addTest(38, 38, 90.0);
+ this.addTest(36, 36, 180.0);
+ this.addTest(39, 39, 270.0);
+ }
}
describe('QRCodeBlackBox.3', () => {
- it('testBlackBox', async () => {
- const test = new QRCodeBlackBox3Spec();
- await test.testBlackBox();
- });
+ it('testBlackBox', async () => {
+ const test = new QRCodeBlackBox3Spec();
+ await test.testBlackBox();
+ });
});
diff --git a/src/test/core/qrcode/QRCodeBlackBox.4.spec.ts b/src/test/core/qrcode/QRCodeBlackBox.4.spec.ts
index 4f03358d..2f51eee4 100644
--- a/src/test/core/qrcode/QRCodeBlackBox.4.spec.ts
+++ b/src/test/core/qrcode/QRCodeBlackBox.4.spec.ts
@@ -27,19 +27,19 @@ import AbstractBlackBoxSpec from '../common/AbstractBlackBox';
*/
export default class QRCodeBlackBox4Spec extends AbstractBlackBoxSpec {
- public constructor() {
- super('src/test/resources/blackbox/qrcode-4', new MultiFormatReader(), BarcodeFormat.QR_CODE);
- this.addTest(36, 36, 0.0);
- this.addTest(35, 35, 90.0);
- this.addTest(35, 35, 180.0);
- this.addTest(35, 35, 270.0);
- }
+ public constructor() {
+ super('src/test/resources/blackbox/qrcode-4', new MultiFormatReader(), BarcodeFormat.QR_CODE);
+ this.addTest(36, 36, 0.0);
+ this.addTest(35, 35, 90.0);
+ this.addTest(35, 35, 180.0);
+ this.addTest(35, 35, 270.0);
+ }
}
describe('QRCodeBlackBox.4', () => {
- it('testBlackBox', async () => {
- const test = new QRCodeBlackBox4Spec();
- await test.testBlackBox();
- });
+ it('testBlackBox', async () => {
+ const test = new QRCodeBlackBox4Spec();
+ await test.testBlackBox();
+ });
});
diff --git a/src/test/core/qrcode/QRCodeBlackBox.5.spec.ts b/src/test/core/qrcode/QRCodeBlackBox.5.spec.ts
index d57b2447..850aedfa 100644
--- a/src/test/core/qrcode/QRCodeBlackBox.5.spec.ts
+++ b/src/test/core/qrcode/QRCodeBlackBox.5.spec.ts
@@ -29,19 +29,19 @@ import AbstractBlackBoxSpec from '../common/AbstractBlackBox';
*/
export default class QRCodeBlackBox5Spec extends AbstractBlackBoxSpec {
- public constructor() {
- super('src/test/resources/blackbox/qrcode-5', new MultiFormatReader(), BarcodeFormat.QR_CODE);
- this.addTest(19, 19, 0.0);
- this.addTest(19, 19, 90.0);
- this.addTest(19, 19, 180.0);
- this.addTest(18, 18, 270.0);
- }
+ public constructor() {
+ super('src/test/resources/blackbox/qrcode-5', new MultiFormatReader(), BarcodeFormat.QR_CODE);
+ this.addTest(19, 19, 0.0);
+ this.addTest(19, 19, 90.0);
+ this.addTest(19, 19, 180.0);
+ this.addTest(18, 18, 270.0);
+ }
}
describe('QRCodeBlackBox.5', () => {
- it('testBlackBox', async () => {
- const test = new QRCodeBlackBox5Spec();
- await test.testBlackBox();
- });
+ it('testBlackBox', async () => {
+ const test = new QRCodeBlackBox5Spec();
+ await test.testBlackBox();
+ });
});
diff --git a/src/test/core/qrcode/QRCodeBlackBox.6.spec.ts b/src/test/core/qrcode/QRCodeBlackBox.6.spec.ts
index 9e81f1e9..5b14b7a6 100644
--- a/src/test/core/qrcode/QRCodeBlackBox.6.spec.ts
+++ b/src/test/core/qrcode/QRCodeBlackBox.6.spec.ts
@@ -26,19 +26,19 @@ import AbstractBlackBoxSpec from '../common/AbstractBlackBox';
*/
export default class QRCodeBlackBox6Spec extends AbstractBlackBoxSpec {
- public constructor() {
- super('src/test/resources/blackbox/qrcode-6', new MultiFormatReader(), BarcodeFormat.QR_CODE);
- this.addTest(15, 15, 0.0);
- this.addTest(14, 14, 90.0);
- this.addTest(12, 13, 180.0);
- this.addTest(14, 14, 270.0);
- }
+ public constructor() {
+ super('src/test/resources/blackbox/qrcode-6', new MultiFormatReader(), BarcodeFormat.QR_CODE);
+ this.addTest(15, 15, 0.0);
+ this.addTest(14, 14, 90.0);
+ this.addTest(12, 13, 180.0);
+ this.addTest(14, 14, 270.0);
+ }
}
describe('QRCodeBlackBox.6', () => {
- it('testBlackBox', async () => {
- const test = new QRCodeBlackBox6Spec();
- await test.testBlackBox();
- });
+ it('testBlackBox', async () => {
+ const test = new QRCodeBlackBox6Spec();
+ await test.testBlackBox();
+ });
});
diff --git a/src/test/core/qrcode/QRCodeBlackBox.7.spec.ts b/src/test/core/qrcode/QRCodeBlackBox.7.spec.ts
index 7a67a7d5..fe76f6ea 100644
--- a/src/test/core/qrcode/QRCodeBlackBox.7.spec.ts
+++ b/src/test/core/qrcode/QRCodeBlackBox.7.spec.ts
@@ -26,19 +26,19 @@ import AbstractBlackBoxSpec from '../common/AbstractBlackBox';
*/
export default class QRCodeBlackBox7Spec extends AbstractBlackBoxSpec {
- public constructor() {
- super('src/test/resources/blackbox/qrcode-7', new MultiFormatReader(), BarcodeFormat.QR_CODE);
- this.addTest(4, 4, 0.0);
- this.addTest(4, 4, 90.0);
- this.addTest(4, 4, 180.0);
- this.addTest(4, 4, 270.0);
- }
+ public constructor() {
+ super('src/test/resources/blackbox/qrcode-7', new MultiFormatReader(), BarcodeFormat.QR_CODE);
+ this.addTest(4, 4, 0.0);
+ this.addTest(4, 4, 90.0);
+ this.addTest(4, 4, 180.0);
+ this.addTest(4, 4, 270.0);
+ }
}
describe('QRCodeBlackBox.7', () => {
- it('testBlackBox', async () => {
- const test = new QRCodeBlackBox7Spec();
- await test.testBlackBox();
- });
+ it('testBlackBox', async () => {
+ const test = new QRCodeBlackBox7Spec();
+ await test.testBlackBox();
+ });
});
diff --git a/src/test/core/qrcode/QRCodeWriter.spec.ts b/src/test/core/qrcode/QRCodeWriter.spec.ts
index 183b56e0..73615d85 100644
--- a/src/test/core/qrcode/QRCodeWriter.spec.ts
+++ b/src/test/core/qrcode/QRCodeWriter.spec.ts
@@ -44,96 +44,96 @@ const path = require('path');
* @author dswitkin@google.com (Daniel Switkin) - ported and expanded from C++
*/
describe('QRCodeWriter', () => {
- ZXingStringEncoding.customEncoder = (b, e) => createCustomEncoder(e).encode(b);
-
- const BASE_IMAGE_PATH = 'src/test/resources/golden/qrcode/';
-
- it('testQRCodeWriter', () => {
- // The QR should be multiplied up to fit, with extra padding if necessary
- const bigEnough: number /*int*/ = 256;
- const writer: Writer = new QRCodeWriter();
- let matrix: BitMatrix = writer.encode(
- 'http://www.google.com/',
- BarcodeFormat.QR_CODE,
- bigEnough,
- bigEnough,
- null
- );
- assert.strictEqual(matrix !== null, true);
- assert.strictEqual(matrix.getWidth(), bigEnough);
- assert.strictEqual(matrix.getHeight(), bigEnough);
-
- // The QR will not fit in this size, so the matrix should come back bigger
- const tooSmall: number /* int */ = 20;
- matrix = writer.encode(
- 'http://www.google.com/',
- BarcodeFormat.QR_CODE,
- tooSmall,
- tooSmall,
- null
- );
- assert.strictEqual(matrix !== null, true);
- assert.strictEqual(tooSmall < matrix.getWidth(), true);
- assert.strictEqual(tooSmall < matrix.getHeight(), true);
-
- // We should also be able to handle non-square requests by padding them
- const strangeWidth: number /*int*/ = 500;
- const strangeHeight: number /*int*/ = 100;
- matrix = writer.encode(
- 'http://www.google.com/',
- BarcodeFormat.QR_CODE,
- strangeWidth,
- strangeHeight,
- null
- );
- assert.strictEqual(matrix !== null, true);
- assert.strictEqual(matrix.getWidth(), strangeWidth);
- assert.strictEqual(matrix.getHeight(), strangeHeight);
- });
-
- async function compareToGoldenFile(
- contents: string,
- ecLevel: QRCodeDecoderErrorCorrectionLevel,
- resolution: number /*int*/,
- fileName: string
- ): Promise {
-
- const filePath = path.resolve(BASE_IMAGE_PATH, fileName);
-
- let goldenResult: BitMatrix;
-
- try {
- goldenResult = await SharpImage.loadAsBitMatrix(filePath);
- } catch (err) {
- assert.ok(false, err);
- }
-
- const hints = new Map();
- hints.set(EncodeHintType.ERROR_CORRECTION, ecLevel);
- const writer: Writer = new QRCodeWriter();
- const generatedResult: BitMatrix = writer.encode(
- contents,
- BarcodeFormat.QR_CODE,
- resolution,
- resolution,
- hints
- );
-
- assert.strictEqual(generatedResult.getWidth(), resolution);
- assert.strictEqual(generatedResult.getHeight(), resolution);
- assert.strictEqual(generatedResult.equals(goldenResult), true);
+ ZXingStringEncoding.customEncoder = (b, e) => createCustomEncoder(e).encode(b);
+
+ const BASE_IMAGE_PATH = 'src/test/resources/golden/qrcode/';
+
+ it('testQRCodeWriter', () => {
+ // The QR should be multiplied up to fit, with extra padding if necessary
+ const bigEnough: number /*int*/ = 256;
+ const writer: Writer = new QRCodeWriter();
+ let matrix: BitMatrix = writer.encode(
+ 'http://www.google.com/',
+ BarcodeFormat.QR_CODE,
+ bigEnough,
+ bigEnough,
+ null
+ );
+ assert.strictEqual(matrix !== null, true);
+ assert.strictEqual(matrix.getWidth(), bigEnough);
+ assert.strictEqual(matrix.getHeight(), bigEnough);
+
+ // The QR will not fit in this size, so the matrix should come back bigger
+ const tooSmall: number /* int */ = 20;
+ matrix = writer.encode(
+ 'http://www.google.com/',
+ BarcodeFormat.QR_CODE,
+ tooSmall,
+ tooSmall,
+ null
+ );
+ assert.strictEqual(matrix !== null, true);
+ assert.strictEqual(tooSmall < matrix.getWidth(), true);
+ assert.strictEqual(tooSmall < matrix.getHeight(), true);
+
+ // We should also be able to handle non-square requests by padding them
+ const strangeWidth: number /*int*/ = 500;
+ const strangeHeight: number /*int*/ = 100;
+ matrix = writer.encode(
+ 'http://www.google.com/',
+ BarcodeFormat.QR_CODE,
+ strangeWidth,
+ strangeHeight,
+ null
+ );
+ assert.strictEqual(matrix !== null, true);
+ assert.strictEqual(matrix.getWidth(), strangeWidth);
+ assert.strictEqual(matrix.getHeight(), strangeHeight);
+ });
+
+ async function compareToGoldenFile(
+ contents: string,
+ ecLevel: QRCodeDecoderErrorCorrectionLevel,
+ resolution: number /*int*/,
+ fileName: string
+ ): Promise {
+
+ const filePath = path.resolve(BASE_IMAGE_PATH, fileName);
+
+ let goldenResult: BitMatrix;
+
+ try {
+ goldenResult = await SharpImage.loadAsBitMatrix(filePath);
+ } catch (err) {
+ assert.ok(false, err);
}
- // Golden images are generated with "qrcode_sample.cc". The images are checked with both eye balls
- // and cell phones. We expect pixel-perfect results, because the error correction level is known,
- // and the pixel dimensions matches exactly.
- it('testRegressionTest', () => {
- compareToGoldenFile(
- 'http://www.google.com/',
- QRCodeDecoderErrorCorrectionLevel.M,
- 99,
- 'renderer-test-01.png'
- );
- });
+ const hints = new Map();
+ hints.set(EncodeHintType.ERROR_CORRECTION, ecLevel);
+ const writer: Writer = new QRCodeWriter();
+ const generatedResult: BitMatrix = writer.encode(
+ contents,
+ BarcodeFormat.QR_CODE,
+ resolution,
+ resolution,
+ hints
+ );
+
+ assert.strictEqual(generatedResult.getWidth(), resolution);
+ assert.strictEqual(generatedResult.getHeight(), resolution);
+ assert.strictEqual(generatedResult.equals(goldenResult), true);
+ }
+
+ // Golden images are generated with "qrcode_sample.cc". The images are checked with both eye balls
+ // and cell phones. We expect pixel-perfect results, because the error correction level is known,
+ // and the pixel dimensions matches exactly.
+ it('testRegressionTest', () => {
+ compareToGoldenFile(
+ 'http://www.google.com/',
+ QRCodeDecoderErrorCorrectionLevel.M,
+ 99,
+ 'renderer-test-01.png'
+ );
+ });
});
diff --git a/src/test/core/qrcode/decoder/DataMask.spec.ts b/src/test/core/qrcode/decoder/DataMask.spec.ts
index 294510ce..da29ed95 100644
--- a/src/test/core/qrcode/decoder/DataMask.spec.ts
+++ b/src/test/core/qrcode/decoder/DataMask.spec.ts
@@ -21,7 +21,7 @@ import { BitMatrix } from '@zxing/library';
import { QRCodeDataMask } from '@zxing/library';
interface MaskCondition {
- isMasked(i: number /*int*/, j: number /*int*/): boolean;
+ isMasked(i: number /*int*/, j: number /*int*/): boolean;
}
/**
@@ -29,89 +29,89 @@ interface MaskCondition {
*/
describe('DataMask', () => {
- it('testMask0', () => {
- testMaskAcrossDimensions(0, {
- isMasked(i: number /*int*/, j: number /*int*/): boolean {
- return (i + j) % 2 === 0;
- }
- });
+ it('testMask0', () => {
+ testMaskAcrossDimensions(0, {
+ isMasked(i: number /*int*/, j: number /*int*/): boolean {
+ return (i + j) % 2 === 0;
+ }
});
+ });
- it('testMask1', () => {
- testMaskAcrossDimensions(1, {
- isMasked(i: number /*int*/, j: number /*int*/): boolean {
- return i % 2 === 0;
- }
- });
+ it('testMask1', () => {
+ testMaskAcrossDimensions(1, {
+ isMasked(i: number /*int*/, j: number /*int*/): boolean {
+ return i % 2 === 0;
+ }
});
+ });
- it('testMask2', () => {
- testMaskAcrossDimensions(2, {
- isMasked(i: number /*int*/, j: number /*int*/): boolean {
- return j % 3 === 0;
- }
- });
+ it('testMask2', () => {
+ testMaskAcrossDimensions(2, {
+ isMasked(i: number /*int*/, j: number /*int*/): boolean {
+ return j % 3 === 0;
+ }
});
+ });
- it('testMask3', () => {
- testMaskAcrossDimensions(3, {
- isMasked(i: number /*int*/, j: number /*int*/): boolean {
- return (i + j) % 3 === 0;
- }
- });
+ it('testMask3', () => {
+ testMaskAcrossDimensions(3, {
+ isMasked(i: number /*int*/, j: number /*int*/): boolean {
+ return (i + j) % 3 === 0;
+ }
});
+ });
- it('testMask4', () => {
- testMaskAcrossDimensions(4, {
- isMasked(i: number /*int*/, j: number /*int*/): boolean {
- return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 === 0;
- }
- });
+ it('testMask4', () => {
+ testMaskAcrossDimensions(4, {
+ isMasked(i: number /*int*/, j: number /*int*/): boolean {
+ return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 === 0;
+ }
});
+ });
- it('testMask5', () => {
- testMaskAcrossDimensions(5, {
- isMasked(i: number /*int*/, j: number /*int*/): boolean {
- return (i * j) % 2 + (i * j) % 3 === 0;
- }
- });
+ it('testMask5', () => {
+ testMaskAcrossDimensions(5, {
+ isMasked(i: number /*int*/, j: number /*int*/): boolean {
+ return (i * j) % 2 + (i * j) % 3 === 0;
+ }
});
+ });
- it('testMask6', () => {
- testMaskAcrossDimensions(6, {
- isMasked(i: number /*int*/, j: number /*int*/): boolean {
- return ((i * j) % 2 + (i * j) % 3) % 2 === 0;
- }
- });
+ it('testMask6', () => {
+ testMaskAcrossDimensions(6, {
+ isMasked(i: number /*int*/, j: number /*int*/): boolean {
+ return ((i * j) % 2 + (i * j) % 3) % 2 === 0;
+ }
});
+ });
- it('testMask7', () => {
- testMaskAcrossDimensions(7, {
- isMasked(i: number /*int*/, j: number /*int*/): boolean {
- return ((i + j) % 2 + (i * j) % 3) % 2 === 0;
- }
- });
+ it('testMask7', () => {
+ testMaskAcrossDimensions(7, {
+ isMasked(i: number /*int*/, j: number /*int*/): boolean {
+ return ((i + j) % 2 + (i * j) % 3) % 2 === 0;
+ }
});
+ });
- function testMaskAcrossDimensions(reference: number /*int*/, condition: MaskCondition): void {
- const mask = QRCodeDataMask.values.get(reference);
- for (let version: number /*int*/ = 1; version <= 40; version++) {
- const dimension: number /*int*/ = 17 + 4 * version;
- testMask(mask, dimension, condition);
- }
+ function testMaskAcrossDimensions(reference: number /*int*/, condition: MaskCondition): void {
+ const mask = QRCodeDataMask.values.get(reference);
+ for (let version: number /*int*/ = 1; version <= 40; version++) {
+ const dimension: number /*int*/ = 17 + 4 * version;
+ testMask(mask, dimension, condition);
}
+ }
- function testMask(mask: QRCodeDataMask, dimension: number /*int*/, condition: MaskCondition): void {
- const bits = new BitMatrix(dimension);
- mask.unmaskBitMatrix(bits, dimension);
- for (let i: number /*int*/ = 0; i < dimension; i++) {
- for (let j: number /*int*/ = 0; j < dimension; j++) {
- assert.strictEqual(
- bits.get(j, i),
- condition.isMasked(i, j),
- '(' + i + ',' + j + ')');
- }
- }
+ function testMask(mask: QRCodeDataMask, dimension: number /*int*/, condition: MaskCondition): void {
+ const bits = new BitMatrix(dimension);
+ mask.unmaskBitMatrix(bits, dimension);
+ for (let i: number /*int*/ = 0; i < dimension; i++) {
+ for (let j: number /*int*/ = 0; j < dimension; j++) {
+ assert.strictEqual(
+ bits.get(j, i),
+ condition.isMasked(i, j),
+ '(' + i + ',' + j + ')');
+ }
}
+ }
});
diff --git a/src/test/core/qrcode/decoder/DecodedBitStreamParser.spec.ts b/src/test/core/qrcode/decoder/DecodedBitStreamParser.spec.ts
index a412fcf9..dc77b377 100644
--- a/src/test/core/qrcode/decoder/DecodedBitStreamParser.spec.ts
+++ b/src/test/core/qrcode/decoder/DecodedBitStreamParser.spec.ts
@@ -33,144 +33,144 @@ ZXingStringEncoding.customDecoder = (b, e) => new TextDecoder(e).decode(b);
*/
describe('QRCodeDecodedBitStreamParser', () => {
- it('testSimpleByteMode', () => {/*throws Exception*/
- const builder = new BitSourceBuilder();
- builder.write(0x04, 4); // Byte mode
- builder.write(0x03, 8); // 3 bytes
- builder.write(0xF1, 8);
- builder.write(0xF2, 8);
- builder.write(0xF3, 8);
- const result: string = QRCodeDecodedBitStreamParser.decode(builder.toByteArray(),
- QRCodeVersion.getVersionForNumber(1), null, null).getText();
- assert.strictEqual(result, '\u00f1\u00f2\u00f3');
- });
+ it('testSimpleByteMode', () => {/*throws Exception*/
+ const builder = new BitSourceBuilder();
+ builder.write(0x04, 4); // Byte mode
+ builder.write(0x03, 8); // 3 bytes
+ builder.write(0xF1, 8);
+ builder.write(0xF2, 8);
+ builder.write(0xF3, 8);
+ const result: string = QRCodeDecodedBitStreamParser.decode(builder.toByteArray(),
+ QRCodeVersion.getVersionForNumber(1), null, null).getText();
+ assert.strictEqual(result, '\u00f1\u00f2\u00f3');
+ });
- it('testSimpleSJIS', () => {/*throws Exception*/
- const builder = new BitSourceBuilder();
- builder.write(0x04, 4); // Byte mode
- builder.write(0x04, 8); // 4 bytes
- builder.write(0xA1, 8);
- builder.write(0xA2, 8);
- builder.write(0xA3, 8);
- builder.write(0xD0, 8);
- const result: string = QRCodeDecodedBitStreamParser.decode(builder.toByteArray(),
- QRCodeVersion.getVersionForNumber(1), null, null).getText();
- assert.strictEqual(result, '\uff61\uff62\uff63\uff90');
- });
+ it('testSimpleSJIS', () => {/*throws Exception*/
+ const builder = new BitSourceBuilder();
+ builder.write(0x04, 4); // Byte mode
+ builder.write(0x04, 8); // 4 bytes
+ builder.write(0xA1, 8);
+ builder.write(0xA2, 8);
+ builder.write(0xA3, 8);
+ builder.write(0xD0, 8);
+ const result: string = QRCodeDecodedBitStreamParser.decode(builder.toByteArray(),
+ QRCodeVersion.getVersionForNumber(1), null, null).getText();
+ assert.strictEqual(result, '\uff61\uff62\uff63\uff90');
+ });
- // TYPESCRIPTPORT: CP437 not supported by TextEncoding. TODO: search for an alternative
- // See here for a possibility: https://github.com/SheetJS/js-codepage
- it.skip('testECI', () => {/*throws Exception*/
- const builder = new BitSourceBuilder();
- builder.write(0x07, 4); // ECI mode
- builder.write(0x02, 8); // ECI 2 = CP437 encoding
- builder.write(0x04, 4); // Byte mode
- builder.write(0x03, 8); // 3 bytes
- builder.write(0xA1, 8);
- builder.write(0xA2, 8);
- builder.write(0xA3, 8);
- const byteArray = builder.toByteArray();
- const result: string = QRCodeDecodedBitStreamParser.decode(byteArray,
- QRCodeVersion.getVersionForNumber(1), null, null).getText();
- assert.strictEqual(result, '\u00ed\u00f3\u00fa');
- });
+ // TYPESCRIPTPORT: CP437 not supported by TextEncoding. TODO: search for an alternative
+ // See here for a possibility: https://github.com/SheetJS/js-codepage
+ it.skip('testECI', () => {/*throws Exception*/
+ const builder = new BitSourceBuilder();
+ builder.write(0x07, 4); // ECI mode
+ builder.write(0x02, 8); // ECI 2 = CP437 encoding
+ builder.write(0x04, 4); // Byte mode
+ builder.write(0x03, 8); // 3 bytes
+ builder.write(0xA1, 8);
+ builder.write(0xA2, 8);
+ builder.write(0xA3, 8);
+ const byteArray = builder.toByteArray();
+ const result: string = QRCodeDecodedBitStreamParser.decode(byteArray,
+ QRCodeVersion.getVersionForNumber(1), null, null).getText();
+ assert.strictEqual(result, '\u00ed\u00f3\u00fa');
+ });
- const eciTestData = [
- // label, eciBits, byte1, byte2, byte3, expected
- ['ISO8859_1', 0x03, 0xA1, 0xA2, 0xA3, '\u00A1\u00A2\u00A3'],
- ['ISO8859_2', 0x04, 0xA1, 0xA2, 0xA3, '\u0104\u02D8\u0141'],
- ['ISO8859_3', 0x05, 0xA1, 0xA2, 0xA3, '\u0126\u02D8\u00A3'],
- ['ISO8859_4', 0x06, 0xA1, 0xA2, 0xA3, '\u0104\u0138\u0156'],
- ['ISO8859_5', 0x07, 0xA1, 0xA2, 0xA3, '\u0401\u0402\u0403'],
- ['ISO8859_6', 0x08, 0xE1, 0xE2, 0xE3, '\u0641\u0642\u0643'],
- ['ISO8859_7', 0x09, 0xA1, 0xA2, 0xA3, '\u2018\u2019\u00A3'],
- ['ISO8859_8', 0x0A, 0xE1, 0xE2, 0xE3, '\u05D1\u05D2\u05D3'],
- ['ISO8859_9', 0x0B, 0xD0, 0xDD, 0xDE, '\u011E\u0130\u015E'],
- ['ISO8859_10', 0x0C, 0xA1, 0xA2, 0xA3, '\u0104\u0112\u0122'],
- ['ISO8859_11', 0x0D, 0xA1, 0xA2, 0xA3, '\u0E01\u0E02\u0E03'],
- ['ISO8859_13', 0x0F, 0xD1, 0xD2, 0xD3, '\u0143\u0145\u00D3'],
- ['ISO8859_14', 0x10, 0xA1, 0xA2, 0xA3, '\u1E02\u1E03\u00A3'],
- ['ISO8859_15', 0x11, 0xBC, 0xBD, 0xBE, '\u0152\u0153\u0178'],
- ['ISO8859_16', 0x12, 0xA1, 0xA2, 0xA3, '\u0104\u0105\u0141'],
- ['windows-1250', 0x15, 0xA1, 0xA2, 0xA3, '\u02C7\u02D8\u0141'],
- ['windows-1251', 0x16, 0xA1, 0xA2, 0xA3, '\u040E\u045E\u0408'],
- ['windows-1252', 0x17, 0x91, 0x92, 0x93, '\u2018\u2019\u201C'],
- ['windows-1256', 0x18, 0xE1, 0xE2, 0xE3, '\u0644\u00E2\u0645'],
- ];
+ const eciTestData = [
+ // label, eciBits, byte1, byte2, byte3, expected
+ ['ISO8859_1', 0x03, 0xA1, 0xA2, 0xA3, '\u00A1\u00A2\u00A3'],
+ ['ISO8859_2', 0x04, 0xA1, 0xA2, 0xA3, '\u0104\u02D8\u0141'],
+ ['ISO8859_3', 0x05, 0xA1, 0xA2, 0xA3, '\u0126\u02D8\u00A3'],
+ ['ISO8859_4', 0x06, 0xA1, 0xA2, 0xA3, '\u0104\u0138\u0156'],
+ ['ISO8859_5', 0x07, 0xA1, 0xA2, 0xA3, '\u0401\u0402\u0403'],
+ ['ISO8859_6', 0x08, 0xE1, 0xE2, 0xE3, '\u0641\u0642\u0643'],
+ ['ISO8859_7', 0x09, 0xA1, 0xA2, 0xA3, '\u2018\u2019\u00A3'],
+ ['ISO8859_8', 0x0A, 0xE1, 0xE2, 0xE3, '\u05D1\u05D2\u05D3'],
+ ['ISO8859_9', 0x0B, 0xD0, 0xDD, 0xDE, '\u011E\u0130\u015E'],
+ ['ISO8859_10', 0x0C, 0xA1, 0xA2, 0xA3, '\u0104\u0112\u0122'],
+ ['ISO8859_11', 0x0D, 0xA1, 0xA2, 0xA3, '\u0E01\u0E02\u0E03'],
+ ['ISO8859_13', 0x0F, 0xD1, 0xD2, 0xD3, '\u0143\u0145\u00D3'],
+ ['ISO8859_14', 0x10, 0xA1, 0xA2, 0xA3, '\u1E02\u1E03\u00A3'],
+ ['ISO8859_15', 0x11, 0xBC, 0xBD, 0xBE, '\u0152\u0153\u0178'],
+ ['ISO8859_16', 0x12, 0xA1, 0xA2, 0xA3, '\u0104\u0105\u0141'],
+ ['windows-1250', 0x15, 0xA1, 0xA2, 0xA3, '\u02C7\u02D8\u0141'],
+ ['windows-1251', 0x16, 0xA1, 0xA2, 0xA3, '\u040E\u045E\u0408'],
+ ['windows-1252', 0x17, 0x91, 0x92, 0x93, '\u2018\u2019\u201C'],
+ ['windows-1256', 0x18, 0xE1, 0xE2, 0xE3, '\u0644\u00E2\u0645'],
+ ];
- describe('testECIISOEach', () => {
- for (const d of eciTestData) {
- it('testECIISOEach ' + d[0], () => {
- testEciOneEncoding(d[0], d[1], d[2], d[3], d[4], d[5]);
- });
- }
- });
-
- function testEciOneEncoding(encodingLabel: string, eciBits: number, b1: number, b2: number, b3: number, expected: string) {
- const builder = new BitSourceBuilder();
- builder.write(0x07, 4); // ECI mode
- builder.write(eciBits, 8); // ECI bits
- builder.write(0x04, 4); // Byte mode
- builder.write(0x03, 8); // 3 bytes
- builder.write(b1, 8);
- builder.write(b2, 8);
- builder.write(b3, 8);
- const byteArray = builder.toByteArray();
- const result: string = QRCodeDecodedBitStreamParser.decode(byteArray,
- QRCodeVersion.getVersionForNumber(1), null, null).getText();
- assert.strictEqual(result, expected, encodingLabel);
+ describe('testECIISOEach', () => {
+ for (const d of eciTestData) {
+ it('testECIISOEach ' + d[0], () => {
+ testEciOneEncoding(d[0], d[1], d[2], d[3], d[4], d[5]);
+ });
}
+ });
- describe('testECIISOCombine', () => {
- const r = new Random('ECIISO');
- for (let i = 0; i !== 10; i++) {
- let id1 = r.next(eciTestData.length);
- let id2 = r.next(eciTestData.length);
- let d1 = eciTestData[id1];
- let d2 = eciTestData[id2];
- it('testECIISOCombine ' + d1[0] + ' & ' + d2[0], () => {
- testEciComboned(
- d1[0], d1[1], d1[2], d1[3], d1[4], d1[5],
- d2[0], d2[1], d2[2], d2[3], d2[4], d2[5]);
- });
- }
- });
+ function testEciOneEncoding(encodingLabel: string, eciBits: number, b1: number, b2: number, b3: number, expected: string) {
+ const builder = new BitSourceBuilder();
+ builder.write(0x07, 4); // ECI mode
+ builder.write(eciBits, 8); // ECI bits
+ builder.write(0x04, 4); // Byte mode
+ builder.write(0x03, 8); // 3 bytes
+ builder.write(b1, 8);
+ builder.write(b2, 8);
+ builder.write(b3, 8);
+ const byteArray = builder.toByteArray();
+ const result: string = QRCodeDecodedBitStreamParser.decode(byteArray,
+ QRCodeVersion.getVersionForNumber(1), null, null).getText();
+ assert.strictEqual(result, expected, encodingLabel);
+ }
- function testEciComboned(
- encodingLabel1: string, eciBits1: number, b1: number, b2: number, b3: number, expected1: string,
- encodingLabel2: string, eciBits2: number, b4: number, b5: number, b6: number, expected2: string) {
- const builder = new BitSourceBuilder();
- builder.write(0x07, 4); // ECI mode
- builder.write(eciBits1, 8); // ECI bits
- builder.write(0x04, 4); // Byte mode
- builder.write(0x03, 8); // 3 bytes
- builder.write(b1, 8);
- builder.write(b2, 8);
- builder.write(b3, 8);
- builder.write(0x07, 4); // ECI mode
- builder.write(eciBits2, 8); // ECI bits
- builder.write(0x04, 4); // Byte mode
- builder.write(0x03, 8); // 3 bytes
- builder.write(b4, 8);
- builder.write(b5, 8);
- builder.write(b6, 8);
- const byteArray = builder.toByteArray();
- const result: string = QRCodeDecodedBitStreamParser.decode(byteArray,
- QRCodeVersion.getVersionForNumber(1), null, null).getText();
- assert.strictEqual(result, expected1 + expected2, encodingLabel1 + ' & ' + encodingLabel2);
+ describe('testECIISOCombine', () => {
+ const r = new Random('ECIISO');
+ for (let i = 0; i !== 10; i++) {
+ let id1 = r.next(eciTestData.length);
+ let id2 = r.next(eciTestData.length);
+ let d1 = eciTestData[id1];
+ let d2 = eciTestData[id2];
+ it('testECIISOCombine ' + d1[0] + ' & ' + d2[0], () => {
+ testEciComboned(
+ d1[0], d1[1], d1[2], d1[3], d1[4], d1[5],
+ d2[0], d2[1], d2[2], d2[3], d2[4], d2[5]);
+ });
}
+ });
+
+ function testEciComboned(
+ encodingLabel1: string, eciBits1: number, b1: number, b2: number, b3: number, expected1: string,
+ encodingLabel2: string, eciBits2: number, b4: number, b5: number, b6: number, expected2: string) {
+ const builder = new BitSourceBuilder();
+ builder.write(0x07, 4); // ECI mode
+ builder.write(eciBits1, 8); // ECI bits
+ builder.write(0x04, 4); // Byte mode
+ builder.write(0x03, 8); // 3 bytes
+ builder.write(b1, 8);
+ builder.write(b2, 8);
+ builder.write(b3, 8);
+ builder.write(0x07, 4); // ECI mode
+ builder.write(eciBits2, 8); // ECI bits
+ builder.write(0x04, 4); // Byte mode
+ builder.write(0x03, 8); // 3 bytes
+ builder.write(b4, 8);
+ builder.write(b5, 8);
+ builder.write(b6, 8);
+ const byteArray = builder.toByteArray();
+ const result: string = QRCodeDecodedBitStreamParser.decode(byteArray,
+ QRCodeVersion.getVersionForNumber(1), null, null).getText();
+ assert.strictEqual(result, expected1 + expected2, encodingLabel1 + ' & ' + encodingLabel2);
+ }
- it('testHanzi', () => {/*throws Exception*/
- const builder = new BitSourceBuilder();
- builder.write(0x0D, 4); // Hanzi mode
- builder.write(0x01, 4); // Subset 1 = GB2312 encoding
- builder.write(0x01, 8); // 1 characters
- builder.write(0x03C1, 13);
- const result: string = QRCodeDecodedBitStreamParser.decode(builder.toByteArray(),
- QRCodeVersion.getVersionForNumber(1), null, null).getText();
- assert.strictEqual(result, '\u963f');
- });
+ it('testHanzi', () => {/*throws Exception*/
+ const builder = new BitSourceBuilder();
+ builder.write(0x0D, 4); // Hanzi mode
+ builder.write(0x01, 4); // Subset 1 = GB2312 encoding
+ builder.write(0x01, 8); // 1 characters
+ builder.write(0x03C1, 13);
+ const result: string = QRCodeDecodedBitStreamParser.decode(builder.toByteArray(),
+ QRCodeVersion.getVersionForNumber(1), null, null).getText();
+ assert.strictEqual(result, '\u963f');
+ });
- // TODO definitely need more tests here
+ // TODO definitely need more tests here
});
diff --git a/src/test/core/qrcode/decoder/ErrorCorrectionLevel.spec.ts b/src/test/core/qrcode/decoder/ErrorCorrectionLevel.spec.ts
index ca5ca5fb..ac2c14c8 100644
--- a/src/test/core/qrcode/decoder/ErrorCorrectionLevel.spec.ts
+++ b/src/test/core/qrcode/decoder/ErrorCorrectionLevel.spec.ts
@@ -25,18 +25,18 @@ import { QRCodeDecoderErrorCorrectionLevel } from '@zxing/library';
*/
describe('QRCodeDecoderErrorCorrectionLevel', () => {
- it('testForBits', () => {
- assert.strictEqual(QRCodeDecoderErrorCorrectionLevel.M.equals(QRCodeDecoderErrorCorrectionLevel.forBits(0)), true);
- assert.strictEqual(QRCodeDecoderErrorCorrectionLevel.L.equals(QRCodeDecoderErrorCorrectionLevel.forBits(1)), true);
- assert.strictEqual(QRCodeDecoderErrorCorrectionLevel.H.equals(QRCodeDecoderErrorCorrectionLevel.forBits(2)), true);
- assert.strictEqual(QRCodeDecoderErrorCorrectionLevel.Q.equals(QRCodeDecoderErrorCorrectionLevel.forBits(3)), true);
- try {
- QRCodeDecoderErrorCorrectionLevel.forBits(4);
- assert.ok(false, 'Should have thrown an exception');
- } catch (ex) {
- // good for IllegalArgumentException
- }
- });
+ it('testForBits', () => {
+ assert.strictEqual(QRCodeDecoderErrorCorrectionLevel.M.equals(QRCodeDecoderErrorCorrectionLevel.forBits(0)), true);
+ assert.strictEqual(QRCodeDecoderErrorCorrectionLevel.L.equals(QRCodeDecoderErrorCorrectionLevel.forBits(1)), true);
+ assert.strictEqual(QRCodeDecoderErrorCorrectionLevel.H.equals(QRCodeDecoderErrorCorrectionLevel.forBits(2)), true);
+ assert.strictEqual(QRCodeDecoderErrorCorrectionLevel.Q.equals(QRCodeDecoderErrorCorrectionLevel.forBits(3)), true);
+ try {
+ QRCodeDecoderErrorCorrectionLevel.forBits(4);
+ assert.ok(false, 'Should have thrown an exception');
+ } catch (ex) {
+ // good for IllegalArgumentException
+ }
+ });
});
diff --git a/src/test/core/qrcode/decoder/FormatInformation.spec.ts b/src/test/core/qrcode/decoder/FormatInformation.spec.ts
index c856603d..6e7a62c8 100644
--- a/src/test/core/qrcode/decoder/FormatInformation.spec.ts
+++ b/src/test/core/qrcode/decoder/FormatInformation.spec.ts
@@ -26,46 +26,46 @@ import { QRCodeDecoderFormatInformation } from '@zxing/library';
*/
describe('QRCodeDecoderFormatInformation', () => {
- const MASKED_TEST_FORMAT_INFO: number /*int*/ = 0x2BED;
- const UNMASKED_TEST_FORMAT_INFO: number /*int*/ = MASKED_TEST_FORMAT_INFO ^ 0x5412;
+ const MASKED_TEST_FORMAT_INFO: number /*int*/ = 0x2BED;
+ const UNMASKED_TEST_FORMAT_INFO: number /*int*/ = MASKED_TEST_FORMAT_INFO ^ 0x5412;
- it('testBitsDiffering', () => {
- assert.strictEqual(QRCodeDecoderFormatInformation.numBitsDiffering(1, 1), 0);
- assert.strictEqual(QRCodeDecoderFormatInformation.numBitsDiffering(0, 2), 1);
- assert.strictEqual(QRCodeDecoderFormatInformation.numBitsDiffering(1, 2), 2);
- assert.strictEqual(QRCodeDecoderFormatInformation.numBitsDiffering(-1, 0), 32);
- });
+ it('testBitsDiffering', () => {
+ assert.strictEqual(QRCodeDecoderFormatInformation.numBitsDiffering(1, 1), 0);
+ assert.strictEqual(QRCodeDecoderFormatInformation.numBitsDiffering(0, 2), 1);
+ assert.strictEqual(QRCodeDecoderFormatInformation.numBitsDiffering(1, 2), 2);
+ assert.strictEqual(QRCodeDecoderFormatInformation.numBitsDiffering(-1, 0), 32);
+ });
- it('testDecode', () => {
- // Normal case
- const expected =
- QRCodeDecoderFormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO);
- assert.strictEqual(null !== expected, true);
- assert.strictEqual(expected.getDataMask(), /*(byte)*/ 0x07);
- assert.strictEqual(QRCodeDecoderErrorCorrectionLevel.Q.equals(expected.getErrorCorrectionLevel()), true);
- // where the code forgot the mask!
- assert.strictEqual(QRCodeDecoderFormatInformation.decodeFormatInformation(UNMASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO).equals(expected), true);
- });
+ it('testDecode', () => {
+ // Normal case
+ const expected =
+ QRCodeDecoderFormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO);
+ assert.strictEqual(null !== expected, true);
+ assert.strictEqual(expected.getDataMask(), /*(byte)*/ 0x07);
+ assert.strictEqual(QRCodeDecoderErrorCorrectionLevel.Q.equals(expected.getErrorCorrectionLevel()), true);
+ // where the code forgot the mask!
+ assert.strictEqual(QRCodeDecoderFormatInformation.decodeFormatInformation(UNMASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO).equals(expected), true);
+ });
- it('testDecodeWithBitDifference', () => {
- const expected =
- QRCodeDecoderFormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO);
- // 1,2,3,4 bits difference
- assert.strictEqual(QRCodeDecoderFormatInformation.decodeFormatInformation(
- MASKED_TEST_FORMAT_INFO ^ 0x01, MASKED_TEST_FORMAT_INFO ^ 0x01).equals(expected), true);
- assert.strictEqual(QRCodeDecoderFormatInformation.decodeFormatInformation(
- MASKED_TEST_FORMAT_INFO ^ 0x03, MASKED_TEST_FORMAT_INFO ^ 0x03).equals(expected), true);
- assert.strictEqual(QRCodeDecoderFormatInformation.decodeFormatInformation(
- MASKED_TEST_FORMAT_INFO ^ 0x07, MASKED_TEST_FORMAT_INFO ^ 0x07).equals(expected), true);
- assert.strictEqual(null === QRCodeDecoderFormatInformation.decodeFormatInformation(
- MASKED_TEST_FORMAT_INFO ^ 0x0F, MASKED_TEST_FORMAT_INFO ^ 0x0F), true);
- });
+ it('testDecodeWithBitDifference', () => {
+ const expected =
+ QRCodeDecoderFormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO);
+ // 1,2,3,4 bits difference
+ assert.strictEqual(QRCodeDecoderFormatInformation.decodeFormatInformation(
+ MASKED_TEST_FORMAT_INFO ^ 0x01, MASKED_TEST_FORMAT_INFO ^ 0x01).equals(expected), true);
+ assert.strictEqual(QRCodeDecoderFormatInformation.decodeFormatInformation(
+ MASKED_TEST_FORMAT_INFO ^ 0x03, MASKED_TEST_FORMAT_INFO ^ 0x03).equals(expected), true);
+ assert.strictEqual(QRCodeDecoderFormatInformation.decodeFormatInformation(
+ MASKED_TEST_FORMAT_INFO ^ 0x07, MASKED_TEST_FORMAT_INFO ^ 0x07).equals(expected), true);
+ assert.strictEqual(null === QRCodeDecoderFormatInformation.decodeFormatInformation(
+ MASKED_TEST_FORMAT_INFO ^ 0x0F, MASKED_TEST_FORMAT_INFO ^ 0x0F), true);
+ });
- it('testDecodeWithMisread', () => {
- const expected =
- QRCodeDecoderFormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO);
- assert.strictEqual(QRCodeDecoderFormatInformation.decodeFormatInformation(
- MASKED_TEST_FORMAT_INFO ^ 0x03, MASKED_TEST_FORMAT_INFO ^ 0x0F).equals(expected), true);
- });
+ it('testDecodeWithMisread', () => {
+ const expected =
+ QRCodeDecoderFormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO);
+ assert.strictEqual(QRCodeDecoderFormatInformation.decodeFormatInformation(
+ MASKED_TEST_FORMAT_INFO ^ 0x03, MASKED_TEST_FORMAT_INFO ^ 0x0F).equals(expected), true);
+ });
});
diff --git a/src/test/core/qrcode/decoder/Mode.spec.ts b/src/test/core/qrcode/decoder/Mode.spec.ts
index 05c14953..bcfc16e3 100644
--- a/src/test/core/qrcode/decoder/Mode.spec.ts
+++ b/src/test/core/qrcode/decoder/Mode.spec.ts
@@ -26,28 +26,28 @@ import { QRCodeMode } from '@zxing/library';
*/
describe('Mode', () => {
- it('testForBits', () => {
- assert.strictEqual(QRCodeMode.TERMINATOR.equals(QRCodeMode.forBits(0x00)), true);
- assert.strictEqual(QRCodeMode.NUMERIC.equals(QRCodeMode.forBits(0x01)), true);
- assert.strictEqual(QRCodeMode.ALPHANUMERIC.equals(QRCodeMode.forBits(0x02)), true);
- assert.strictEqual(QRCodeMode.BYTE.equals(QRCodeMode.forBits(0x04)), true);
- assert.strictEqual(QRCodeMode.KANJI.equals(QRCodeMode.forBits(0x08)), true);
- try {
- QRCodeMode.forBits(0x10);
- assert.ok(false, 'Should have thrown an exception');
- } catch (ex) {
- // good for InvalidArgumentException
- }
- });
+ it('testForBits', () => {
+ assert.strictEqual(QRCodeMode.TERMINATOR.equals(QRCodeMode.forBits(0x00)), true);
+ assert.strictEqual(QRCodeMode.NUMERIC.equals(QRCodeMode.forBits(0x01)), true);
+ assert.strictEqual(QRCodeMode.ALPHANUMERIC.equals(QRCodeMode.forBits(0x02)), true);
+ assert.strictEqual(QRCodeMode.BYTE.equals(QRCodeMode.forBits(0x04)), true);
+ assert.strictEqual(QRCodeMode.KANJI.equals(QRCodeMode.forBits(0x08)), true);
+ try {
+ QRCodeMode.forBits(0x10);
+ assert.ok(false, 'Should have thrown an exception');
+ } catch (ex) {
+ // good for InvalidArgumentException
+ }
+ });
- it('testCharacterCount', () => {
- // Spot check a few values
- assert.strictEqual(QRCodeMode.NUMERIC.getCharacterCountBits(QRCodeVersion.getVersionForNumber(5)), 10);
- assert.strictEqual(QRCodeMode.NUMERIC.getCharacterCountBits(QRCodeVersion.getVersionForNumber(26)), 12);
- assert.strictEqual(QRCodeMode.NUMERIC.getCharacterCountBits(QRCodeVersion.getVersionForNumber(40)), 14);
- assert.strictEqual(QRCodeMode.ALPHANUMERIC.getCharacterCountBits(QRCodeVersion.getVersionForNumber(6)), 9);
- assert.strictEqual(QRCodeMode.BYTE.getCharacterCountBits(QRCodeVersion.getVersionForNumber(7)), 8);
- assert.strictEqual(QRCodeMode.KANJI.getCharacterCountBits(QRCodeVersion.getVersionForNumber(8)), 8);
- });
+ it('testCharacterCount', () => {
+ // Spot check a few values
+ assert.strictEqual(QRCodeMode.NUMERIC.getCharacterCountBits(QRCodeVersion.getVersionForNumber(5)), 10);
+ assert.strictEqual(QRCodeMode.NUMERIC.getCharacterCountBits(QRCodeVersion.getVersionForNumber(26)), 12);
+ assert.strictEqual(QRCodeMode.NUMERIC.getCharacterCountBits(QRCodeVersion.getVersionForNumber(40)), 14);
+ assert.strictEqual(QRCodeMode.ALPHANUMERIC.getCharacterCountBits(QRCodeVersion.getVersionForNumber(6)), 9);
+ assert.strictEqual(QRCodeMode.BYTE.getCharacterCountBits(QRCodeVersion.getVersionForNumber(7)), 8);
+ assert.strictEqual(QRCodeMode.KANJI.getCharacterCountBits(QRCodeVersion.getVersionForNumber(8)), 8);
+ });
});
diff --git a/src/test/core/qrcode/decoder/Version.spec.ts b/src/test/core/qrcode/decoder/Version.spec.ts
index 8411a636..7322efd8 100644
--- a/src/test/core/qrcode/decoder/Version.spec.ts
+++ b/src/test/core/qrcode/decoder/Version.spec.ts
@@ -26,56 +26,56 @@ import { QRCodeVersion } from '@zxing/library';
*/
describe('Version', () => {
- it('testVersionForNumber', () => {
- try {
- QRCodeVersion.getVersionForNumber(0);
- assert.ok(false, 'Should have thrown an exception');
- } catch (ex) {
- // good for IllegalArgumentException
- }
- for (let i: number /*int*/ = 1; i <= 40; i++) {
- checkVersion(QRCodeVersion.getVersionForNumber(i), i, 4 * i + 17);
- }
- });
-
- function checkVersion(version: QRCodeVersion, versionNumber: number /*int*/, dimension: number /*int*/): void {
+ it('testVersionForNumber', () => {
+ try {
+ QRCodeVersion.getVersionForNumber(0);
+ assert.ok(false, 'Should have thrown an exception');
+ } catch (ex) {
+ // good for IllegalArgumentException
+ }
+ for (let i: number /*int*/ = 1; i <= 40; i++) {
+ checkVersion(QRCodeVersion.getVersionForNumber(i), i, 4 * i + 17);
+ }
+ });
- assert.strictEqual(null !== version, true);
- assert.strictEqual(version.getVersionNumber(), versionNumber);
- assert.strictEqual(null !== version.getAlignmentPatternCenters(), true);
+ function checkVersion(version: QRCodeVersion, versionNumber: number /*int*/, dimension: number /*int*/): void {
- if (versionNumber > 1) {
- assert.strictEqual(version.getAlignmentPatternCenters().length > 0, true);
- }
+ assert.strictEqual(null !== version, true);
+ assert.strictEqual(version.getVersionNumber(), versionNumber);
+ assert.strictEqual(null !== version.getAlignmentPatternCenters(), true);
- assert.strictEqual(version.getDimensionForVersion(), dimension);
- assert.strictEqual(null !== version.getECBlocksForLevel(QRCodeDecoderErrorCorrectionLevel.H), true);
- assert.strictEqual(null !== version.getECBlocksForLevel(QRCodeDecoderErrorCorrectionLevel.L), true);
- assert.strictEqual(null !== version.getECBlocksForLevel(QRCodeDecoderErrorCorrectionLevel.M), true);
- assert.strictEqual(null !== version.getECBlocksForLevel(QRCodeDecoderErrorCorrectionLevel.Q), true);
- assert.strictEqual(null !== version.buildFunctionPattern(), true);
+ if (versionNumber > 1) {
+ assert.strictEqual(version.getAlignmentPatternCenters().length > 0, true);
}
- it('testGetProvisionalVersionForDimension', () => {
- for (let i: number /*int*/ = 1; i <= 40; i++) {
- assert.strictEqual(QRCodeVersion.getProvisionalVersionForDimension(4 * i + 17).getVersionNumber(), i);
- }
- });
+ assert.strictEqual(version.getDimensionForVersion(), dimension);
+ assert.strictEqual(null !== version.getECBlocksForLevel(QRCodeDecoderErrorCorrectionLevel.H), true);
+ assert.strictEqual(null !== version.getECBlocksForLevel(QRCodeDecoderErrorCorrectionLevel.L), true);
+ assert.strictEqual(null !== version.getECBlocksForLevel(QRCodeDecoderErrorCorrectionLevel.M), true);
+ assert.strictEqual(null !== version.getECBlocksForLevel(QRCodeDecoderErrorCorrectionLevel.Q), true);
+ assert.strictEqual(null !== version.buildFunctionPattern(), true);
+ }
- it('testDecodeVersionInformation', () => {
- // Spot check
- doTestVersion(7, 0x07C94);
- doTestVersion(12, 0x0C762);
- doTestVersion(17, 0x1145D);
- doTestVersion(22, 0x168C9);
- doTestVersion(27, 0x1B08E);
- doTestVersion(32, 0x209D5);
- });
-
- function doTestVersion(expectedVersion: number /*int*/, mask: number /*int*/): void {
- const version: QRCodeVersion = QRCodeVersion.decodeVersionInformation(mask);
- assert.strictEqual(null !== version, true);
- assert.strictEqual(version.getVersionNumber(), expectedVersion);
+ it('testGetProvisionalVersionForDimension', () => {
+ for (let i: number /*int*/ = 1; i <= 40; i++) {
+ assert.strictEqual(QRCodeVersion.getProvisionalVersionForDimension(4 * i + 17).getVersionNumber(), i);
}
+ });
+
+ it('testDecodeVersionInformation', () => {
+ // Spot check
+ doTestVersion(7, 0x07C94);
+ doTestVersion(12, 0x0C762);
+ doTestVersion(17, 0x1145D);
+ doTestVersion(22, 0x168C9);
+ doTestVersion(27, 0x1B08E);
+ doTestVersion(32, 0x209D5);
+ });
+
+ function doTestVersion(expectedVersion: number /*int*/, mask: number /*int*/): void {
+ const version: QRCodeVersion = QRCodeVersion.decodeVersionInformation(mask);
+ assert.strictEqual(null !== version, true);
+ assert.strictEqual(version.getVersionNumber(), expectedVersion);
+ }
});
diff --git a/src/test/core/qrcode/encoder/BitVector.spec.ts b/src/test/core/qrcode/encoder/BitVector.spec.ts
index 9acd32f9..c1e26b47 100644
--- a/src/test/core/qrcode/encoder/BitVector.spec.ts
+++ b/src/test/core/qrcode/encoder/BitVector.spec.ts
@@ -25,155 +25,155 @@ import { BitArray } from '@zxing/library';
*/
describe('BitVector', () => {
- // TYPESCRIPTPORT: cannot use long (64 bits) as we only have 53 bits in number so I will just use a string for testing purposes
- // function getUnsignedInt(v: BitArray, index: number /*int*/): number/*long*/ {
- // let result: number = 0
- // for (let i: number /*int*/ = 0, offset = index * 8; i < 32; i++) {
- // if (v.get(offset + i)) {
- // result |= 1 << (31 - i)
- // }
- // }
- // return result
- // }
- function getUnsignedIntAsString(v: BitArray, index: number /*int*/): string/*long*/ {
- let result = '';
- for (let i: number /*int*/ = 0, offset = index * 8; i < 32; i++) {
- result = result + (v.get(offset + i) ? '1' : '0');
- }
- return ('00000000000000000000000000000000' + result).substring(result.length);
+ // TYPESCRIPTPORT: cannot use long (64 bits) as we only have 53 bits in number so I will just use a string for testing purposes
+ // function getUnsignedInt(v: BitArray, index: number /*int*/): number/*long*/ {
+ // let result: number = 0
+ // for (let i: number /*int*/ = 0, offset = index * 8; i < 32; i++) {
+ // if (v.get(offset + i)) {
+ // result |= 1 << (31 - i)
+ // }
+ // }
+ // return result
+ // }
+ function getUnsignedIntAsString(v: BitArray, index: number /*int*/): string/*long*/ {
+ let result = '';
+ for (let i: number /*int*/ = 0, offset = index * 8; i < 32; i++) {
+ result = result + (v.get(offset + i) ? '1' : '0');
}
-
- it('testAppendBit', () => {
- const v = new BitArray();
- assert.strictEqual(v.getSizeInBytes(), 0);
- // 1
- v.appendBit(true);
- assert.strictEqual(v.getSize(), 1);
- assert.strictEqual(getUnsignedIntAsString(v, 0), 0x80000000.toString(2));
- // 10
- v.appendBit(false);
- assert.strictEqual(v.getSize(), 2);
- assert.strictEqual(getUnsignedIntAsString(v, 0), 0x80000000.toString(2));
- // 101
- v.appendBit(true);
- assert.strictEqual(v.getSize(), 3);
- assert.strictEqual(getUnsignedIntAsString(v, 0), 0xa0000000.toString(2));
- // 1010
- v.appendBit(false);
- assert.strictEqual(v.getSize(), 4);
- assert.strictEqual(getUnsignedIntAsString(v, 0), 0xa0000000.toString(2));
- // 10101
- v.appendBit(true);
- assert.strictEqual(v.getSize(), 5);
- assert.strictEqual(getUnsignedIntAsString(v, 0), 0xa8000000.toString(2));
- // 101010
- v.appendBit(false);
- assert.strictEqual(v.getSize(), 6);
- assert.strictEqual(getUnsignedIntAsString(v, 0), 0xa8000000.toString(2));
- // 1010101
- v.appendBit(true);
- assert.strictEqual(v.getSize(), 7);
- assert.strictEqual(getUnsignedIntAsString(v, 0), 0xaa000000.toString(2));
- // 10101010
- v.appendBit(false);
- assert.strictEqual(v.getSize(), 8);
- assert.strictEqual(getUnsignedIntAsString(v, 0), 0xaa000000.toString(2));
- // 10101010 1
- v.appendBit(true);
- assert.strictEqual(v.getSize(), 9);
- assert.strictEqual(getUnsignedIntAsString(v, 0), 0xaa800000.toString(2));
- // 10101010 10
- v.appendBit(false);
- assert.strictEqual(v.getSize(), 10);
- assert.strictEqual(getUnsignedIntAsString(v, 0), 0xaa800000.toString(2));
- });
-
- it('testAppendBits', () => {
- let v = new BitArray();
- v.appendBits(0x1, 1);
- assert.strictEqual(v.getSize(), 1);
- assert.strictEqual(getUnsignedIntAsString(v, 0), 0x80000000.toString(2));
- v = new BitArray();
- v.appendBits(0xff, 8);
- assert.strictEqual(v.getSize(), 8);
- assert.strictEqual(getUnsignedIntAsString(v, 0), 0xff000000.toString(2));
- v = new BitArray();
- v.appendBits(0xff7, 12);
- assert.strictEqual(v.getSize(), 12);
- assert.strictEqual(getUnsignedIntAsString(v, 0), 0xff700000.toString(2));
- });
-
- it('testNumBytes', () => {
- const v = new BitArray();
- assert.strictEqual(v.getSizeInBytes(), 0);
- v.appendBit(false);
- // 1 bit was added in the vector, so 1 byte should be consumed.
- assert.strictEqual(v.getSizeInBytes(), 1);
- v.appendBits(0, 7);
- assert.strictEqual(v.getSizeInBytes(), 1);
- v.appendBits(0, 8);
- assert.strictEqual(v.getSizeInBytes(), 2);
- v.appendBits(0, 1);
- // We now have 17 bits, so 3 bytes should be consumed.
- assert.strictEqual(v.getSizeInBytes(), 3);
- });
-
- it('testAppendBitVector', () => {
- const v1 = new BitArray();
- v1.appendBits(0xbe, 8);
- const v2 = new BitArray();
- v2.appendBits(0xef, 8);
- v1.appendBitArray(v2);
- // beef = 1011 1110 1110 1111
- assert.strictEqual(v1.toString(), ' X.XXXXX. XXX.XXXX');
- });
-
- it('testXOR', () => {
- const v1 = new BitArray();
- v1.appendBits(0x5555aaaa, 32);
- const v2 = new BitArray();
- v2.appendBits(0xaaaa5555, 32);
- v1.xor(v2);
- assert.strictEqual(getUnsignedIntAsString(v1, 0), 0xffffffff.toString(2));
- });
-
- it('testXOR2', () => {
- const v1 = new BitArray();
- v1.appendBits(0x2a, 7); // 010 1010
- const v2 = new BitArray();
- v2.appendBits(0x55, 7); // 101 0101
- v1.xor(v2);
- assert.strictEqual(getUnsignedIntAsString(v1, 0), 0xfe000000.toString(2)); // 1111 1110
- });
-
- it('testAt', () => {
- const v = new BitArray();
- v.appendBits(0xdead, 16); // 1101 1110 1010 1101
- assert.strictEqual(v.get(0), true);
- assert.strictEqual(v.get(1), true);
- assert.strictEqual(v.get(2), false);
- assert.strictEqual(v.get(3), true);
-
- assert.strictEqual(v.get(4), true);
- assert.strictEqual(v.get(5), true);
- assert.strictEqual(v.get(6), true);
- assert.strictEqual(v.get(7), false);
-
- assert.strictEqual(v.get(8), true);
- assert.strictEqual(v.get(9), false);
- assert.strictEqual(v.get(10), true);
- assert.strictEqual(v.get(11), false);
-
- assert.strictEqual(v.get(12), true);
- assert.strictEqual(v.get(13), true);
- assert.strictEqual(v.get(14), false);
- assert.strictEqual(v.get(15), true);
- });
-
- it('testToString', () => {
- const v = new BitArray();
- v.appendBits(0xdead, 16); // 1101 1110 1010 1101
- assert.strictEqual(v.toString(), ' XX.XXXX. X.X.XX.X');
- });
+ return ('00000000000000000000000000000000' + result).substring(result.length);
+ }
+
+ it('testAppendBit', () => {
+ const v = new BitArray();
+ assert.strictEqual(v.getSizeInBytes(), 0);
+ // 1
+ v.appendBit(true);
+ assert.strictEqual(v.getSize(), 1);
+ assert.strictEqual(getUnsignedIntAsString(v, 0), 0x80000000.toString(2));
+ // 10
+ v.appendBit(false);
+ assert.strictEqual(v.getSize(), 2);
+ assert.strictEqual(getUnsignedIntAsString(v, 0), 0x80000000.toString(2));
+ // 101
+ v.appendBit(true);
+ assert.strictEqual(v.getSize(), 3);
+ assert.strictEqual(getUnsignedIntAsString(v, 0), 0xa0000000.toString(2));
+ // 1010
+ v.appendBit(false);
+ assert.strictEqual(v.getSize(), 4);
+ assert.strictEqual(getUnsignedIntAsString(v, 0), 0xa0000000.toString(2));
+ // 10101
+ v.appendBit(true);
+ assert.strictEqual(v.getSize(), 5);
+ assert.strictEqual(getUnsignedIntAsString(v, 0), 0xa8000000.toString(2));
+ // 101010
+ v.appendBit(false);
+ assert.strictEqual(v.getSize(), 6);
+ assert.strictEqual(getUnsignedIntAsString(v, 0), 0xa8000000.toString(2));
+ // 1010101
+ v.appendBit(true);
+ assert.strictEqual(v.getSize(), 7);
+ assert.strictEqual(getUnsignedIntAsString(v, 0), 0xaa000000.toString(2));
+ // 10101010
+ v.appendBit(false);
+ assert.strictEqual(v.getSize(), 8);
+ assert.strictEqual(getUnsignedIntAsString(v, 0), 0xaa000000.toString(2));
+ // 10101010 1
+ v.appendBit(true);
+ assert.strictEqual(v.getSize(), 9);
+ assert.strictEqual(getUnsignedIntAsString(v, 0), 0xaa800000.toString(2));
+ // 10101010 10
+ v.appendBit(false);
+ assert.strictEqual(v.getSize(), 10);
+ assert.strictEqual(getUnsignedIntAsString(v, 0), 0xaa800000.toString(2));
+ });
+
+ it('testAppendBits', () => {
+ let v = new BitArray();
+ v.appendBits(0x1, 1);
+ assert.strictEqual(v.getSize(), 1);
+ assert.strictEqual(getUnsignedIntAsString(v, 0), 0x80000000.toString(2));
+ v = new BitArray();
+ v.appendBits(0xff, 8);
+ assert.strictEqual(v.getSize(), 8);
+ assert.strictEqual(getUnsignedIntAsString(v, 0), 0xff000000.toString(2));
+ v = new BitArray();
+ v.appendBits(0xff7, 12);
+ assert.strictEqual(v.getSize(), 12);
+ assert.strictEqual(getUnsignedIntAsString(v, 0), 0xff700000.toString(2));
+ });
+
+ it('testNumBytes', () => {
+ const v = new BitArray();
+ assert.strictEqual(v.getSizeInBytes(), 0);
+ v.appendBit(false);
+ // 1 bit was added in the vector, so 1 byte should be consumed.
+ assert.strictEqual(v.getSizeInBytes(), 1);
+ v.appendBits(0, 7);
+ assert.strictEqual(v.getSizeInBytes(), 1);
+ v.appendBits(0, 8);
+ assert.strictEqual(v.getSizeInBytes(), 2);
+ v.appendBits(0, 1);
+ // We now have 17 bits, so 3 bytes should be consumed.
+ assert.strictEqual(v.getSizeInBytes(), 3);
+ });
+
+ it('testAppendBitVector', () => {
+ const v1 = new BitArray();
+ v1.appendBits(0xbe, 8);
+ const v2 = new BitArray();
+ v2.appendBits(0xef, 8);
+ v1.appendBitArray(v2);
+ // beef = 1011 1110 1110 1111
+ assert.strictEqual(v1.toString(), ' X.XXXXX. XXX.XXXX');
+ });
+
+ it('testXOR', () => {
+ const v1 = new BitArray();
+ v1.appendBits(0x5555aaaa, 32);
+ const v2 = new BitArray();
+ v2.appendBits(0xaaaa5555, 32);
+ v1.xor(v2);
+ assert.strictEqual(getUnsignedIntAsString(v1, 0), 0xffffffff.toString(2));
+ });
+
+ it('testXOR2', () => {
+ const v1 = new BitArray();
+ v1.appendBits(0x2a, 7); // 010 1010
+ const v2 = new BitArray();
+ v2.appendBits(0x55, 7); // 101 0101
+ v1.xor(v2);
+ assert.strictEqual(getUnsignedIntAsString(v1, 0), 0xfe000000.toString(2)); // 1111 1110
+ });
+
+ it('testAt', () => {
+ const v = new BitArray();
+ v.appendBits(0xdead, 16); // 1101 1110 1010 1101
+ assert.strictEqual(v.get(0), true);
+ assert.strictEqual(v.get(1), true);
+ assert.strictEqual(v.get(2), false);
+ assert.strictEqual(v.get(3), true);
+
+ assert.strictEqual(v.get(4), true);
+ assert.strictEqual(v.get(5), true);
+ assert.strictEqual(v.get(6), true);
+ assert.strictEqual(v.get(7), false);
+
+ assert.strictEqual(v.get(8), true);
+ assert.strictEqual(v.get(9), false);
+ assert.strictEqual(v.get(10), true);
+ assert.strictEqual(v.get(11), false);
+
+ assert.strictEqual(v.get(12), true);
+ assert.strictEqual(v.get(13), true);
+ assert.strictEqual(v.get(14), false);
+ assert.strictEqual(v.get(15), true);
+ });
+
+ it('testToString', () => {
+ const v = new BitArray();
+ v.appendBits(0xdead, 16); // 1101 1110 1010 1101
+ assert.strictEqual(v.toString(), ' XX.XXXX. X.X.XX.X');
+ });
});
diff --git a/src/test/core/qrcode/encoder/Encoder.spec.ts b/src/test/core/qrcode/encoder/Encoder.spec.ts
index 497e8247..3ba0ccab 100644
--- a/src/test/core/qrcode/encoder/Encoder.spec.ts
+++ b/src/test/core/qrcode/encoder/Encoder.spec.ts
@@ -37,585 +37,585 @@ import { createCustomEncoder, createCustomDecoder } from '../../util/textEncodin
*/
describe('QRCodeEncoder', () => {
- it('testGetAlphanumericCode', () => {
- // The first ten code points are numbers.
- for (let i: number /*int*/ = 0; i < 10; ++i) {
- assert.strictEqual(QRCodeEncoder.getAlphanumericCode('0'.charCodeAt(0) + i), i);
- }
-
- // The next 26 code points are capital alphabet letters.
- for (let i: number /*int*/ = 10; i < 36; ++i) {
- assert.strictEqual(QRCodeEncoder.getAlphanumericCode('A'.charCodeAt(0) + i - 10), i);
- }
-
- // Others are symbol letters
- assert.strictEqual(QRCodeEncoder.getAlphanumericCode(' '.charCodeAt(0)), 36);
- assert.strictEqual(QRCodeEncoder.getAlphanumericCode('$'.charCodeAt(0)), 37);
- assert.strictEqual(QRCodeEncoder.getAlphanumericCode('%'.charCodeAt(0)), 38);
- assert.strictEqual(QRCodeEncoder.getAlphanumericCode('*'.charCodeAt(0)), 39);
- assert.strictEqual(QRCodeEncoder.getAlphanumericCode('+'.charCodeAt(0)), 40);
- assert.strictEqual(QRCodeEncoder.getAlphanumericCode('-'.charCodeAt(0)), 41);
- assert.strictEqual(QRCodeEncoder.getAlphanumericCode('.'.charCodeAt(0)), 42);
- assert.strictEqual(QRCodeEncoder.getAlphanumericCode('/'.charCodeAt(0)), 43);
- assert.strictEqual(QRCodeEncoder.getAlphanumericCode(':'.charCodeAt(0)), 44);
-
- // Should return -1 for other letters;
- assert.strictEqual(QRCodeEncoder.getAlphanumericCode('a'.charCodeAt(0)), -1);
- assert.strictEqual(QRCodeEncoder.getAlphanumericCode('#'.charCodeAt(0)), -1);
- assert.strictEqual(QRCodeEncoder.getAlphanumericCode('\0'.charCodeAt(0)), -1);
- });
-
- it('testChooseMode', () => {
-
- ZXingStringEncoding.customDecoder = (b, e) => createCustomDecoder(e).decode(b);
-
- // Numeric mode.
- assert.strictEqual(QRCodeMode.NUMERIC.equals(QRCodeEncoder.chooseMode('0')), true);
- assert.strictEqual(QRCodeMode.NUMERIC.equals(QRCodeEncoder.chooseMode('0123456789')), true);
- // Alphanumeric mode.
- assert.strictEqual(QRCodeMode.ALPHANUMERIC.equals(QRCodeEncoder.chooseMode('A')), true);
- assert.strictEqual(QRCodeMode.ALPHANUMERIC.equals(QRCodeEncoder.chooseMode('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:')), true);
- // 8-bit byte mode.
- assert.strictEqual(QRCodeMode.BYTE.equals(QRCodeEncoder.chooseMode('a')), true);
- assert.strictEqual(QRCodeMode.BYTE.equals(QRCodeEncoder.chooseMode('#')), true);
- assert.strictEqual(QRCodeMode.BYTE.equals(QRCodeEncoder.chooseMode('')), true);
- // Kanji mode. We used to use MODE_KANJI for these, but we stopped
- // doing that as we cannot distinguish Shift_JIS from other encodings
- // from data bytes alone. See also comments in qrcode_encoder.h.
-
- // AIUE in Hiragana in Shift_JIS
- assert.strictEqual(QRCodeMode.BYTE.equals(QRCodeEncoder.chooseMode(shiftJISString(Uint8Array.from([0x8, 0xa, 0x8, 0xa, 0x8, 0xa, 0x8, 0xa6])))), true);
-
- // Nihon in Kanji in Shift_JIS.
- assert.strictEqual(QRCodeMode.BYTE.equals(QRCodeEncoder.chooseMode(shiftJISString(Uint8Array.from([0x9, 0xf, 0x9, 0x7b])))), true);
-
- // Sou-Utsu-Byou in Kanji in Shift_JIS.
- assert.strictEqual(QRCodeMode.BYTE.equals(QRCodeEncoder.chooseMode(shiftJISString(Uint8Array.from([0xe, 0x4, 0x9, 0x5, 0x9, 0x61])))), true);
-
- ZXingStringEncoding.customDecoder = undefined;
- });
-
- it('testEncode', () => {
- const qrCode: QRCodeEncoderQRCode = QRCodeEncoder.encode('ABCDEF', QRCodeDecoderErrorCorrectionLevel.H);
- const expected: string =
- '<<\n' +
- ' mode: ALPHANUMERIC\n' +
- ' ecLevel: H\n' +
- ' version: 1\n' +
- ' maskPattern: 4\n' +
- ' matrix:\n' +
- ' 1 1 1 1 1 1 1 0 0 1 0 1 0 0 1 1 1 1 1 1 1\n' +
- ' 1 0 0 0 0 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 1\n' +
- ' 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n' +
- ' 1 0 1 1 1 0 1 0 0 1 0 0 1 0 1 0 1 1 1 0 1\n' +
- ' 1 0 1 1 1 0 1 0 0 1 0 1 0 0 1 0 1 1 1 0 1\n' +
- ' 1 0 0 0 0 0 1 0 1 0 0 1 1 0 1 0 0 0 0 0 1\n' +
- ' 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n' +
- ' 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0\n' +
- ' 0 0 0 0 1 1 1 1 0 1 1 0 1 0 1 1 0 0 0 1 0\n' +
- ' 0 0 0 0 1 1 0 1 1 1 0 0 1 1 1 1 0 1 1 0 1\n' +
- ' 1 0 0 0 0 1 1 0 0 1 0 1 0 0 0 1 1 1 0 1 1\n' +
- ' 1 0 0 1 1 1 0 0 1 1 1 1 0 0 0 0 1 0 0 0 0\n' +
- ' 0 1 1 1 1 1 1 0 1 0 1 0 1 1 1 0 0 1 1 0 0\n' +
- ' 0 0 0 0 0 0 0 0 1 1 0 0 0 1 1 0 0 0 1 0 1\n' +
- ' 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 0 0 1 1 0 0\n' +
- ' 1 0 0 0 0 0 1 0 1 1 0 1 0 0 0 1 0 1 1 1 1\n' +
- ' 1 0 1 1 1 0 1 0 1 0 0 1 0 0 0 1 1 0 0 1 1\n' +
- ' 1 0 1 1 1 0 1 0 0 0 1 1 0 1 0 0 0 0 1 1 1\n' +
- ' 1 0 1 1 1 0 1 0 0 1 0 1 0 0 0 1 1 0 0 0 0\n' +
- ' 1 0 0 0 0 0 1 0 0 1 0 0 1 0 0 1 1 0 0 0 1\n' +
- ' 1 1 1 1 1 1 1 0 0 0 1 0 0 1 0 0 0 0 1 1 1\n' +
- '>>\n';
- assert.strictEqual(qrCode.toString(), expected);
- });
-
- it('testEncodeWithVersion', () => {
- const hints = new Map(); // EncodeHintType.class)
- hints.set(EncodeHintType.QR_VERSION, 7);
- const qrCode: QRCodeEncoderQRCode = QRCodeEncoder.encode('ABCDEF', QRCodeDecoderErrorCorrectionLevel.H, hints);
- assert.strictEqual(qrCode.toString().indexOf(' version: 7\n') !== -1, true);
- });
-
- // @Test(expected = WriterException.class)
- it('testEncodeWithVersionTooSmall', () => {
- assert.throws(
- () => {
- const hints = new Map(); // EncodeHintType.class)
- hints.set(EncodeHintType.QR_VERSION, 3);
- QRCodeEncoder.encode('THISMESSAGEISTOOLONGFORAQRCODEVERSION3', QRCodeDecoderErrorCorrectionLevel.H, hints);
- },
- WriterException,
- 'unexpected exception thrown'
- );
- });
-
- it('testSimpleUTF8ECI', () => {
- const hints = new Map(); // EncodeHintType.class)
- hints.set(EncodeHintType.CHARACTER_SET, 'UTF8');
- const qrCode: QRCodeEncoderQRCode = QRCodeEncoder.encode('hello', QRCodeDecoderErrorCorrectionLevel.H, hints);
- const expected: string =
- '<<\n' +
- ' mode: BYTE\n' +
- ' ecLevel: H\n' +
- ' version: 1\n' +
- ' maskPattern: 6\n' +
- ' matrix:\n' +
- ' 1 1 1 1 1 1 1 0 0 0 1 1 0 0 1 1 1 1 1 1 1\n' +
- ' 1 0 0 0 0 0 1 0 0 0 1 1 0 0 1 0 0 0 0 0 1\n' +
- ' 1 0 1 1 1 0 1 0 1 0 0 1 1 0 1 0 1 1 1 0 1\n' +
- ' 1 0 1 1 1 0 1 0 1 0 0 0 1 0 1 0 1 1 1 0 1\n' +
- ' 1 0 1 1 1 0 1 0 0 1 1 0 0 0 1 0 1 1 1 0 1\n' +
- ' 1 0 0 0 0 0 1 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n' +
- ' 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n' +
- ' 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0\n' +
- ' 0 0 0 1 1 0 1 1 0 0 0 0 1 0 0 0 0 1 1 0 0\n' +
- ' 0 0 0 0 0 0 0 0 1 1 0 1 0 0 1 0 1 1 1 1 1\n' +
- ' 1 1 0 0 0 1 1 1 0 0 0 1 1 0 0 1 0 1 0 1 1\n' +
- ' 0 0 0 0 1 1 0 0 1 0 0 0 0 0 1 0 1 1 0 0 0\n' +
- ' 0 1 1 0 0 1 1 0 0 1 1 1 0 1 1 1 1 1 1 1 1\n' +
- ' 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 1 1 1 1 1\n' +
- ' 1 1 1 1 1 1 1 0 1 0 1 0 0 0 1 0 0 0 0 0 0\n' +
- ' 1 0 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 1 0 0\n' +
- ' 1 0 1 1 1 0 1 0 1 0 0 0 1 0 1 0 0 0 1 0 0\n' +
- ' 1 0 1 1 1 0 1 0 1 1 1 1 0 1 0 0 1 0 1 1 0\n' +
- ' 1 0 1 1 1 0 1 0 0 1 1 1 0 0 1 0 0 1 0 1 1\n' +
- ' 1 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 1 1 0 0 0\n' +
- ' 1 1 1 1 1 1 1 0 0 0 0 1 0 1 0 0 1 0 1 0 0\n' +
- '>>\n';
- assert.strictEqual(qrCode.toString(), expected);
- });
-
- it('testEncodeKanjiMode', () => {
-
- ZXingStringEncoding.customEncoder = (b, e) => createCustomEncoder(e).encode(b);
+ it('testGetAlphanumericCode', () => {
+ // The first ten code points are numbers.
+ for (let i: number /*int*/ = 0; i < 10; ++i) {
+ assert.strictEqual(QRCodeEncoder.getAlphanumericCode('0'.charCodeAt(0) + i), i);
+ }
+ // The next 26 code points are capital alphabet letters.
+ for (let i: number /*int*/ = 10; i < 36; ++i) {
+ assert.strictEqual(QRCodeEncoder.getAlphanumericCode('A'.charCodeAt(0) + i - 10), i);
+ }
+
+ // Others are symbol letters
+ assert.strictEqual(QRCodeEncoder.getAlphanumericCode(' '.charCodeAt(0)), 36);
+ assert.strictEqual(QRCodeEncoder.getAlphanumericCode('$'.charCodeAt(0)), 37);
+ assert.strictEqual(QRCodeEncoder.getAlphanumericCode('%'.charCodeAt(0)), 38);
+ assert.strictEqual(QRCodeEncoder.getAlphanumericCode('*'.charCodeAt(0)), 39);
+ assert.strictEqual(QRCodeEncoder.getAlphanumericCode('+'.charCodeAt(0)), 40);
+ assert.strictEqual(QRCodeEncoder.getAlphanumericCode('-'.charCodeAt(0)), 41);
+ assert.strictEqual(QRCodeEncoder.getAlphanumericCode('.'.charCodeAt(0)), 42);
+ assert.strictEqual(QRCodeEncoder.getAlphanumericCode('/'.charCodeAt(0)), 43);
+ assert.strictEqual(QRCodeEncoder.getAlphanumericCode(':'.charCodeAt(0)), 44);
+
+ // Should return -1 for other letters;
+ assert.strictEqual(QRCodeEncoder.getAlphanumericCode('a'.charCodeAt(0)), -1);
+ assert.strictEqual(QRCodeEncoder.getAlphanumericCode('#'.charCodeAt(0)), -1);
+ assert.strictEqual(QRCodeEncoder.getAlphanumericCode('\0'.charCodeAt(0)), -1);
+ });
+
+ it('testChooseMode', () => {
+
+ ZXingStringEncoding.customDecoder = (b, e) => createCustomDecoder(e).decode(b);
+
+ // Numeric mode.
+ assert.strictEqual(QRCodeMode.NUMERIC.equals(QRCodeEncoder.chooseMode('0')), true);
+ assert.strictEqual(QRCodeMode.NUMERIC.equals(QRCodeEncoder.chooseMode('0123456789')), true);
+ // Alphanumeric mode.
+ assert.strictEqual(QRCodeMode.ALPHANUMERIC.equals(QRCodeEncoder.chooseMode('A')), true);
+ assert.strictEqual(QRCodeMode.ALPHANUMERIC.equals(QRCodeEncoder.chooseMode('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:')), true);
+ // 8-bit byte mode.
+ assert.strictEqual(QRCodeMode.BYTE.equals(QRCodeEncoder.chooseMode('a')), true);
+ assert.strictEqual(QRCodeMode.BYTE.equals(QRCodeEncoder.chooseMode('#')), true);
+ assert.strictEqual(QRCodeMode.BYTE.equals(QRCodeEncoder.chooseMode('')), true);
+ // Kanji mode. We used to use MODE_KANJI for these, but we stopped
+ // doing that as we cannot distinguish Shift_JIS from other encodings
+ // from data bytes alone. See also comments in qrcode_encoder.h.
+
+ // AIUE in Hiragana in Shift_JIS
+ assert.strictEqual(QRCodeMode.BYTE.equals(QRCodeEncoder.chooseMode(shiftJISString(Uint8Array.from([0x8, 0xa, 0x8, 0xa, 0x8, 0xa, 0x8, 0xa6])))), true);
+
+ // Nihon in Kanji in Shift_JIS.
+ assert.strictEqual(QRCodeMode.BYTE.equals(QRCodeEncoder.chooseMode(shiftJISString(Uint8Array.from([0x9, 0xf, 0x9, 0x7b])))), true);
+
+ // Sou-Utsu-Byou in Kanji in Shift_JIS.
+ assert.strictEqual(QRCodeMode.BYTE.equals(QRCodeEncoder.chooseMode(shiftJISString(Uint8Array.from([0xe, 0x4, 0x9, 0x5, 0x9, 0x61])))), true);
+
+ ZXingStringEncoding.customDecoder = undefined;
+ });
+
+ it('testEncode', () => {
+ const qrCode: QRCodeEncoderQRCode = QRCodeEncoder.encode('ABCDEF', QRCodeDecoderErrorCorrectionLevel.H);
+ const expected: string =
+ '<<\n' +
+ ' mode: ALPHANUMERIC\n' +
+ ' ecLevel: H\n' +
+ ' version: 1\n' +
+ ' maskPattern: 4\n' +
+ ' matrix:\n' +
+ ' 1 1 1 1 1 1 1 0 0 1 0 1 0 0 1 1 1 1 1 1 1\n' +
+ ' 1 0 0 0 0 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 0 1 0 0 1 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 0 1 0 1 0 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 0 0 0 0 1 0 1 0 0 1 1 0 1 0 0 0 0 0 1\n' +
+ ' 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n' +
+ ' 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0\n' +
+ ' 0 0 0 0 1 1 1 1 0 1 1 0 1 0 1 1 0 0 0 1 0\n' +
+ ' 0 0 0 0 1 1 0 1 1 1 0 0 1 1 1 1 0 1 1 0 1\n' +
+ ' 1 0 0 0 0 1 1 0 0 1 0 1 0 0 0 1 1 1 0 1 1\n' +
+ ' 1 0 0 1 1 1 0 0 1 1 1 1 0 0 0 0 1 0 0 0 0\n' +
+ ' 0 1 1 1 1 1 1 0 1 0 1 0 1 1 1 0 0 1 1 0 0\n' +
+ ' 0 0 0 0 0 0 0 0 1 1 0 0 0 1 1 0 0 0 1 0 1\n' +
+ ' 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 0 0 1 1 0 0\n' +
+ ' 1 0 0 0 0 0 1 0 1 1 0 1 0 0 0 1 0 1 1 1 1\n' +
+ ' 1 0 1 1 1 0 1 0 1 0 0 1 0 0 0 1 1 0 0 1 1\n' +
+ ' 1 0 1 1 1 0 1 0 0 0 1 1 0 1 0 0 0 0 1 1 1\n' +
+ ' 1 0 1 1 1 0 1 0 0 1 0 1 0 0 0 1 1 0 0 0 0\n' +
+ ' 1 0 0 0 0 0 1 0 0 1 0 0 1 0 0 1 1 0 0 0 1\n' +
+ ' 1 1 1 1 1 1 1 0 0 0 1 0 0 1 0 0 0 0 1 1 1\n' +
+ '>>\n';
+ assert.strictEqual(qrCode.toString(), expected);
+ });
+
+ it('testEncodeWithVersion', () => {
+ const hints = new Map(); // EncodeHintType.class)
+ hints.set(EncodeHintType.QR_VERSION, 7);
+ const qrCode: QRCodeEncoderQRCode = QRCodeEncoder.encode('ABCDEF', QRCodeDecoderErrorCorrectionLevel.H, hints);
+ assert.strictEqual(qrCode.toString().indexOf(' version: 7\n') !== -1, true);
+ });
+
+ // @Test(expected = WriterException.class)
+ it('testEncodeWithVersionTooSmall', () => {
+ assert.throws(
+ () => {
const hints = new Map(); // EncodeHintType.class)
- hints.set(EncodeHintType.CHARACTER_SET, CharacterSetECI.SJIS.getName());
- // Nihon in Kanji
- const qrCode: QRCodeEncoderQRCode = QRCodeEncoder.encode('\u65e5\u672c', QRCodeDecoderErrorCorrectionLevel.M, hints);
- const expected: string =
- '<<\n' +
- ' mode: KANJI\n' +
- ' ecLevel: M\n' +
- ' version: 1\n' +
- ' maskPattern: 0\n' +
- ' matrix:\n' +
- ' 1 1 1 1 1 1 1 0 0 1 0 1 0 0 1 1 1 1 1 1 1\n' +
- ' 1 0 0 0 0 0 1 0 1 1 0 0 0 0 1 0 0 0 0 0 1\n' +
- ' 1 0 1 1 1 0 1 0 0 1 1 1 1 0 1 0 1 1 1 0 1\n' +
- ' 1 0 1 1 1 0 1 0 0 0 0 0 1 0 1 0 1 1 1 0 1\n' +
- ' 1 0 1 1 1 0 1 0 1 1 1 1 1 0 1 0 1 1 1 0 1\n' +
- ' 1 0 0 0 0 0 1 0 0 1 1 1 0 0 1 0 0 0 0 0 1\n' +
- ' 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n' +
- ' 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0\n' +
- ' 1 0 1 0 1 0 1 0 0 0 1 0 1 0 0 0 1 0 0 1 0\n' +
- ' 1 1 0 1 0 0 0 1 0 1 1 1 0 1 0 1 0 1 0 0 0\n' +
- ' 0 1 0 0 0 0 1 1 1 1 1 1 0 1 1 1 0 1 0 1 0\n' +
- ' 1 1 1 0 0 1 0 1 0 0 0 1 1 1 0 1 1 0 1 0 0\n' +
- ' 0 1 1 0 0 1 1 0 1 1 0 1 0 1 1 1 0 1 0 0 1\n' +
- ' 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 1 0 1\n' +
- ' 1 1 1 1 1 1 1 0 0 0 0 0 1 0 0 0 1 0 0 1 1\n' +
- ' 1 0 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 1 1\n' +
- ' 1 0 1 1 1 0 1 0 1 0 0 0 1 0 1 0 1 0 1 0 1\n' +
- ' 1 0 1 1 1 0 1 0 0 0 0 1 0 1 0 1 0 1 0 1 0\n' +
- ' 1 0 1 1 1 0 1 0 1 0 1 1 0 1 1 1 0 0 1 0 1\n' +
- ' 1 0 0 0 0 0 1 0 0 0 0 1 1 1 0 1 1 1 0 1 0\n' +
- ' 1 1 1 1 1 1 1 0 1 1 0 1 0 1 1 1 0 0 1 0 0\n' +
- '>>\n';
- assert.strictEqual(qrCode.toString(), expected);
-
- ZXingStringEncoding.customEncoder = undefined;
- });
-
- it('testEncodeShiftjisNumeric', () => {
- const hints = new Map(); // EncodeHintType.class)
- hints.set(EncodeHintType.CHARACTER_SET, CharacterSetECI.SJIS.getName());
- const qrCode: QRCodeEncoderQRCode = QRCodeEncoder.encode('0123', QRCodeDecoderErrorCorrectionLevel.M, hints);
- const expected: string =
- '<<\n' +
- ' mode: NUMERIC\n' +
- ' ecLevel: M\n' +
- ' version: 1\n' +
- ' maskPattern: 2\n' +
- ' matrix:\n' +
- ' 1 1 1 1 1 1 1 0 0 1 1 0 1 0 1 1 1 1 1 1 1\n' +
- ' 1 0 0 0 0 0 1 0 0 1 0 0 1 0 1 0 0 0 0 0 1\n' +
- ' 1 0 1 1 1 0 1 0 1 0 0 0 0 0 1 0 1 1 1 0 1\n' +
- ' 1 0 1 1 1 0 1 0 1 0 1 1 1 0 1 0 1 1 1 0 1\n' +
- ' 1 0 1 1 1 0 1 0 1 1 0 1 1 0 1 0 1 1 1 0 1\n' +
- ' 1 0 0 0 0 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0 1\n' +
- ' 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n' +
- ' 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0\n' +
- ' 1 0 1 1 1 1 1 0 0 1 1 0 1 0 1 1 1 1 1 0 0\n' +
- ' 1 1 0 0 0 1 0 0 1 0 1 0 1 0 0 1 0 0 1 0 0\n' +
- ' 0 1 1 0 1 1 1 1 0 1 1 1 0 1 0 0 1 1 0 1 1\n' +
- ' 1 0 1 1 0 1 0 1 0 0 1 0 0 0 0 1 1 0 1 0 0\n' +
- ' 0 0 1 0 0 1 1 1 0 0 0 1 0 1 0 0 1 0 1 0 0\n' +
- ' 0 0 0 0 0 0 0 0 1 1 0 1 1 1 1 0 0 1 0 0 0\n' +
- ' 1 1 1 1 1 1 1 0 0 0 1 0 1 0 1 1 0 0 0 0 0\n' +
- ' 1 0 0 0 0 0 1 0 1 1 0 1 1 1 1 0 0 1 0 1 0\n' +
- ' 1 0 1 1 1 0 1 0 1 0 1 0 1 0 0 1 0 0 1 0 0\n' +
- ' 1 0 1 1 1 0 1 0 1 1 1 0 1 0 0 1 0 0 1 0 0\n' +
- ' 1 0 1 1 1 0 1 0 1 1 0 1 0 1 0 0 1 1 1 0 0\n' +
- ' 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 1 0 1 1 0\n' +
- ' 1 1 1 1 1 1 1 0 1 1 0 1 0 1 0 0 1 1 1 0 0\n' +
- '>>\n';
- assert.strictEqual(qrCode.toString(), expected);
- });
-
- it('testAppendModeInfo', () => {
- const bits = new BitArray();
- QRCodeEncoder.appendModeInfo(QRCodeMode.NUMERIC, bits);
- assert.strictEqual(bits.toString(), ' ...X');
- });
-
- it('testAppendLengthInfo', () => {
- let bits = new BitArray();
- QRCodeEncoder.appendLengthInfo(1, // 1 letter (1/1).
- QRCodeVersion.getVersionForNumber(1),
- QRCodeMode.NUMERIC,
- bits);
- assert.strictEqual(bits.toString(), ' ........ .X'); // 10 bits.
- bits = new BitArray();
- QRCodeEncoder.appendLengthInfo(2, // 2 letters (2/1).
- QRCodeVersion.getVersionForNumber(10),
- QRCodeMode.ALPHANUMERIC,
- bits);
- assert.strictEqual(bits.toString(), ' ........ .X.'); // 11 bits.
- bits = new BitArray();
- QRCodeEncoder.appendLengthInfo(255, // 255 letter (255/1).
- QRCodeVersion.getVersionForNumber(27),
- QRCodeMode.BYTE,
- bits);
- assert.strictEqual(bits.toString(), ' ........ XXXXXXXX'); // 16 bits.
- bits = new BitArray();
- QRCodeEncoder.appendLengthInfo(512, // 512 letters (1024/2).
- QRCodeVersion.getVersionForNumber(40),
- QRCodeMode.KANJI,
- bits);
- assert.strictEqual(bits.toString(), ' ..X..... ....'); // 12 bits.
- });
-
- it('testAppendBytes', () => {
- ZXingStringEncoding.customEncoder = (b, e) => createCustomEncoder(e).encode(b);
- ZXingStringEncoding.customDecoder = (b, e) => createCustomDecoder(e).decode(b);
-
- // Should use appendNumericBytes.
- // 1 = 01 = 0001 in 4 bits.
- let bits = new BitArray();
- QRCodeEncoder.appendBytes('1', QRCodeMode.NUMERIC, bits, QRCodeEncoder.DEFAULT_BYTE_MODE_ENCODING);
- assert.strictEqual(bits.toString(), ' ...X');
- // Should use appendAlphanumericBytes.
- // A = 10 = 0xa = 001010 in 6 bits
- bits = new BitArray();
- QRCodeEncoder.appendBytes('A', QRCodeMode.ALPHANUMERIC, bits, QRCodeEncoder.DEFAULT_BYTE_MODE_ENCODING);
- assert.strictEqual(bits.toString(), ' ..X.X.');
- // Lower letters such as 'a' cannot be encoded in MODE_ALPHANUMERIC.
- try {
- QRCodeEncoder.appendBytes('a', QRCodeMode.ALPHANUMERIC, bits, QRCodeEncoder.DEFAULT_BYTE_MODE_ENCODING);
- } catch (we/*WriterException*/) {
- if (we instanceof WriterException) {
- // good
- } else {
- throw we;
- }
- }
- // Should use append8BitBytes.
- // 0x61, 0x62, 0x63
- bits = new BitArray();
- QRCodeEncoder.appendBytes('abc', QRCodeMode.BYTE, bits, QRCodeEncoder.DEFAULT_BYTE_MODE_ENCODING);
- assert.strictEqual(bits.toString(), ' .XX....X .XX...X. .XX...XX');
- // Anything can be encoded in QRCodeEncoderQRCode.MODE_8BIT_BYTE.
- // TYPESCRIPTPORT: this seems to be unused: QRCodeEncoder.appendBytes("\0", QRCodeMode.BYTE, bits, QRCodeEncoder.DEFAULT_BYTE_MODE_ENCODING)
-
- // Should use appendKanjiBytes.
- // 0x93, 0x5f
- bits = new BitArray();
- QRCodeEncoder.appendBytes(shiftJISString(Uint8Array.from([0x93, 0x5f])), QRCodeMode.KANJI, bits, QRCodeEncoder.DEFAULT_BYTE_MODE_ENCODING);
- assert.strictEqual(bits.toString(), ' .XX.XX.. XXXXX');
-
- ZXingStringEncoding.customEncoder = undefined;
- ZXingStringEncoding.customDecoder = undefined;
- });
-
- it('testTerminateBits', () => {
- let v = new BitArray();
- QRCodeEncoder.terminateBits(0, v);
- assert.strictEqual(v.toString(), '');
- v = new BitArray();
- QRCodeEncoder.terminateBits(1, v);
- assert.strictEqual(v.toString(), ' ........');
- v = new BitArray();
- v.appendBits(0, 3); // Append 000
- QRCodeEncoder.terminateBits(1, v);
- assert.strictEqual(v.toString(), ' ........');
- v = new BitArray();
- v.appendBits(0, 5); // Append 00000
- QRCodeEncoder.terminateBits(1, v);
- assert.strictEqual(v.toString(), ' ........');
- v = new BitArray();
- v.appendBits(0, 8); // Append 00000000
- QRCodeEncoder.terminateBits(1, v);
- assert.strictEqual(v.toString(), ' ........');
- v = new BitArray();
- QRCodeEncoder.terminateBits(2, v);
- assert.strictEqual(v.toString(), ' ........ XXX.XX..');
- v = new BitArray();
- v.appendBits(0, 1); // Append 0
- QRCodeEncoder.terminateBits(3, v);
- assert.strictEqual(v.toString(), ' ........ XXX.XX.. ...X...X');
- });
-
- it('testGetNumDataBytesAndNumECBytesForBlockID', () => {
- const numDataBytes = new Int32Array(1); /*Int32Array(1)*/
- const numEcBytes = new Int32Array(1); /*Int32Array(1)*/
- // Version 1-H.
- QRCodeEncoder.getNumDataBytesAndNumECBytesForBlockID(26, 9, 1, 0, numDataBytes, numEcBytes);
- assert.strictEqual(numDataBytes[0], 9);
- assert.strictEqual(numEcBytes[0], 17);
-
- // Version 3-H. 2 blocks.
- QRCodeEncoder.getNumDataBytesAndNumECBytesForBlockID(70, 26, 2, 0, numDataBytes, numEcBytes);
- assert.strictEqual(numDataBytes[0], 13);
- assert.strictEqual(numEcBytes[0], 22);
- QRCodeEncoder.getNumDataBytesAndNumECBytesForBlockID(70, 26, 2, 1, numDataBytes, numEcBytes);
- assert.strictEqual(numDataBytes[0], 13);
- assert.strictEqual(numEcBytes[0], 22);
-
- // Version 7-H. (4 + 1) blocks.
- QRCodeEncoder.getNumDataBytesAndNumECBytesForBlockID(196, 66, 5, 0, numDataBytes, numEcBytes);
- assert.strictEqual(numDataBytes[0], 13);
- assert.strictEqual(numEcBytes[0], 26);
- QRCodeEncoder.getNumDataBytesAndNumECBytesForBlockID(196, 66, 5, 4, numDataBytes, numEcBytes);
- assert.strictEqual(numDataBytes[0], 14);
- assert.strictEqual(numEcBytes[0], 26);
-
- // Version 40-H. (20 + 61) blocks.
- QRCodeEncoder.getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 0, numDataBytes, numEcBytes);
- assert.strictEqual(numDataBytes[0], 15);
- assert.strictEqual(numEcBytes[0], 30);
- QRCodeEncoder.getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 20, numDataBytes, numEcBytes);
- assert.strictEqual(numDataBytes[0], 16);
- assert.strictEqual(numEcBytes[0], 30);
- QRCodeEncoder.getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 80, numDataBytes, numEcBytes);
- assert.strictEqual(numDataBytes[0], 16);
- assert.strictEqual(numEcBytes[0], 30);
- });
-
- it('testInterleaveWithECBytes', () => {
- let dataBytes = Uint8Array.from([32, 65, 205, 69, 41, 220, 46, 128, 236]);
- let input = new BitArray();
- for (let i = 0, length = dataBytes.length; i !== length; i++) {
- const dataByte = dataBytes[i];
- input.appendBits(dataByte, 8);
- }
- let out: BitArray = QRCodeEncoder.interleaveWithECBytes(input, 26, 9, 1);
- let expected = Uint8Array.from([
- // Data bytes.
- 32, 65, 205, 69, 41, 220, 46, 128, 236,
- // Error correction bytes.
- 42, 159, 74, 221, 244, 169, 239, 150, 138, 70,
- 237, 85, 224, 96, 74, 219, 61,
- ]);
- assert.strictEqual(out.getSizeInBytes(), expected.length);
- let outArray = new Uint8Array(expected.length);
- out.toBytes(0, outArray, 0, expected.length);
- // Can't use ZXingArrays.equals(), because outArray may be longer than out.sizeInBytes()
- for (let x: number /*int*/ = 0; x < expected.length; x++) {
- assert.strictEqual(outArray[x], expected[x]);
- }
- // Numbers are from http://www.swetake.com/qr/qr8.html
- dataBytes = Uint8Array.from([
- 67, 70, 22, 38, 54, 70, 86, 102, 118, 134, 150, 166, 182,
- 198, 214, 230, 247, 7, 23, 39, 55, 71, 87, 103, 119, 135,
- 151, 166, 22, 38, 54, 70, 86, 102, 118, 134, 150, 166,
- 182, 198, 214, 230, 247, 7, 23, 39, 55, 71, 87, 103, 119,
- 135, 151, 160, 236, 17, 236, 17, 236, 17, 236,
- 17
- ]);
- input = new BitArray();
- for (let i = 0, length = dataBytes.length; i !== length; i++) {
- const dataByte = dataBytes[i];
- input.appendBits(dataByte, 8);
- }
-
- out = QRCodeEncoder.interleaveWithECBytes(input, 134, 62, 4);
- expected = Uint8Array.from([
- // Data bytes.
- 67, 230, 54, 55, 70, 247, 70, 71, 22, 7, 86, 87, 38, 23, 102, 103, 54, 39,
- 118, 119, 70, 55, 134, 135, 86, 71, 150, 151, 102, 87, 166,
- 160, 118, 103, 182, 236, 134, 119, 198, 17, 150,
- 135, 214, 236, 166, 151, 230, 17, 182,
- 166, 247, 236, 198, 22, 7, 17, 214, 38, 23, 236, 39,
- 17,
- // Error correction bytes.
- 175, 155, 245, 236, 80, 146, 56, 74, 155, 165,
- 133, 142, 64, 183, 132, 13, 178, 54, 132, 108, 45,
- 113, 53, 50, 214, 98, 193, 152, 233, 147, 50, 71, 65,
- 190, 82, 51, 209, 199, 171, 54, 12, 112, 57, 113, 155, 117,
- 211, 164, 117, 30, 158, 225, 31, 190, 242, 38,
- 140, 61, 179, 154, 214, 138, 147, 87, 27, 96, 77, 47,
- 187, 49, 156, 214,
- ]);
- assert.strictEqual(out.getSizeInBytes(), expected.length);
- outArray = new Uint8Array(expected.length);
- out.toBytes(0, outArray, 0, expected.length);
- for (let x: number /*int*/ = 0; x < expected.length; x++) {
- assert.strictEqual(outArray[x], expected[x]);
- }
- });
-
- it('testAppendNumericBytes', () => {
- // 1 = 01 = 0001 in 4 bits.
- let bits = new BitArray();
- QRCodeEncoder.appendNumericBytes('1', bits);
- assert.strictEqual(bits.toString(), ' ...X');
- // 12 = 0xc = 0001100 in 7 bits.
- bits = new BitArray();
- QRCodeEncoder.appendNumericBytes('12', bits);
- assert.strictEqual(bits.toString(), ' ...XX..');
- // 123 = 0x7b = 0001111011 in 10 bits.
- bits = new BitArray();
- QRCodeEncoder.appendNumericBytes('123', bits);
- assert.strictEqual(bits.toString(), ' ...XXXX. XX');
- // 1234 = "123" + "4" = 0001111011 + 0100
- bits = new BitArray();
- QRCodeEncoder.appendNumericBytes('1234', bits);
- assert.strictEqual(bits.toString(), ' ...XXXX. XX.X..');
- // Empty.
- bits = new BitArray();
- QRCodeEncoder.appendNumericBytes('', bits);
- assert.strictEqual(bits.toString(), '');
- });
-
- it('testAppendAlphanumericBytes', () => {
- // A = 10 = 0xa = 001010 in 6 bits
- let bits = new BitArray();
- QRCodeEncoder.appendAlphanumericBytes('A', bits);
- assert.strictEqual(bits.toString(), ' ..X.X.');
- // AB = 10 * 45 + 11 = 461 = 0x1cd = 00111001101 in 11 bits
- bits = new BitArray();
- QRCodeEncoder.appendAlphanumericBytes('AB', bits);
- assert.strictEqual(bits.toString(), ' ..XXX..X X.X');
- // ABC = "AB" + "C" = 00111001101 + 001100
- bits = new BitArray();
- QRCodeEncoder.appendAlphanumericBytes('ABC', bits);
- assert.strictEqual(bits.toString(), ' ..XXX..X X.X..XX. .');
- // Empty.
- bits = new BitArray();
- QRCodeEncoder.appendAlphanumericBytes('', bits);
- assert.strictEqual(bits.toString(), '');
- // Invalid data.
- try {
- QRCodeEncoder.appendAlphanumericBytes('abc', new BitArray());
- } catch (we/*WriterException*/) {
- // good
- }
- });
-
- it('testAppend8BitBytes', () => {
- ZXingStringEncoding.customEncoder = (b, e) => createCustomEncoder(e).encode(b);
- // 0x61, 0x62, 0x63
- let bits = new BitArray();
- QRCodeEncoder.append8BitBytes('abc', bits, QRCodeEncoder.DEFAULT_BYTE_MODE_ENCODING);
- assert.strictEqual(bits.toString(), ' .XX....X .XX...X. .XX...XX');
- // Empty.
- bits = new BitArray();
- QRCodeEncoder.append8BitBytes('', bits, QRCodeEncoder.DEFAULT_BYTE_MODE_ENCODING);
- assert.strictEqual(bits.toString(), '');
- });
-
- // Numbers are from page 21 of JISX0510:2004
- it('testAppendKanjiBytes', () => {
- ZXingStringEncoding.customEncoder = (b, e) => createCustomEncoder(e).encode(b);
- ZXingStringEncoding.customDecoder = (b, e) => createCustomDecoder(e).decode(b);
-
- const bits = new BitArray();
- QRCodeEncoder.appendKanjiBytes(shiftJISString(Uint8Array.from([0x93, 0x5f])), bits);
- assert.strictEqual(bits.toString(), ' .XX.XX.. XXXXX');
- QRCodeEncoder.appendKanjiBytes(shiftJISString(Uint8Array.from([0xe4, 0xaa])), bits);
- assert.strictEqual(bits.toString(), ' .XX.XX.. XXXXXXX. X.X.X.X. X.');
-
- ZXingStringEncoding.customEncoder = undefined;
- ZXingStringEncoding.customDecoder = undefined;
- });
-
- // Numbers are from http://www.swetake.com/qr/qr3.html and
- // http://www.swetake.com/qr/qr9.html
- it('testGenerateECBytes', () => {
- let dataBytes = Uint8Array.from([32, 65, 205, 69, 41, 220, 46, 128, 236]);
- let ecBytes: Uint8Array = QRCodeEncoder.generateECBytes(dataBytes, 17);
- let expected = Int32Array.from([
- 42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61
- ]);
- assert.strictEqual(ecBytes.length, expected.length);
- for (let x: number /*int*/ = 0; x < expected.length; x++) {
- assert.strictEqual(ecBytes[x] & 0xFF, expected[x]);
- }
- dataBytes = Uint8Array.from([67, 70, 22, 38, 54, 70, 86, 102, 118,
- 134, 150, 166, 182, 198, 214]);
- ecBytes = QRCodeEncoder.generateECBytes(dataBytes, 18);
- expected = Int32Array.from([
- 175, 80, 155, 64, 178, 45, 214, 233, 65, 209, 12, 155, 117, 31, 140, 214, 27, 187
- ]);
- assert.strictEqual(ecBytes.length, expected.length);
- for (let x: number /*int*/ = 0; x < expected.length; x++) {
- assert.strictEqual(ecBytes[x] & 0xFF, expected[x]);
- }
- // High-order zero coefficient case.
- dataBytes = Uint8Array.from([32, 49, 205, 69, 42, 20, 0, 236, 17]);
- ecBytes = QRCodeEncoder.generateECBytes(dataBytes, 17);
- expected = Int32Array.from([
- 0, 3, 130, 179, 194, 0, 55, 211, 110, 79, 98, 72, 170, 96, 211, 137, 213
- ]);
- assert.strictEqual(ecBytes.length, expected.length);
- for (let x: number /*int*/ = 0; x < expected.length; x++) {
- assert.strictEqual(ecBytes[x] & 0xFF, expected[x]);
- }
- });
-
- it('testBugInBitVectorNumBytes', () => {
- // There was a bug in BitVector.sizeInBytes() that caused it to return a
- // smaller-by-one value (ex. 1465 instead of 1466) if the number of bits
- // in the vector is not 8-bit aligned. In QRCodeEncoder::InitQRCode(),
- // BitVector::sizeInBytes() is used for finding the smallest QR Code
- // version that can fit the given data. Hence there were corner cases
- // where we chose a wrong QR Code version that cannot fit the given
- // data. Note that the issue did not occur with MODE_8BIT_BYTE, as the
- // bits in the bit vector are always 8-bit aligned.
- //
- // Before the bug was fixed, the following test didn't pass, because:
- //
- // - MODE_NUMERIC is chosen as all bytes in the data are '0'
- // - The 3518-byte numeric data needs 1466 bytes
- // - 3518 / 3 * 10 + 7 = 11727 bits = 1465.875 bytes
- // - 3 numeric bytes are encoded in 10 bits, hence the first
- // 3516 bytes are encoded in 3516 / 3 * 10 = 11720 bits.
- // - 2 numeric bytes can be encoded in 7 bits, hence the last
- // 2 bytes are encoded in 7 bits.
- // - The version 27 QR Code with the EC level L has 1468 bytes for data.
- // - 1828 - 360 = 1468
- // - In InitQRCode(), 3 bytes are reserved for a header. Hence 1465 bytes
- // (1468 -3) are left for data.
- // - Because of the bug in BitVector::sizeInBytes(), InitQRCode() determines
- // the given data can fit in 1465 bytes, despite it needs 1466 bytes.
- // - Hence QRCodeEncoder.encode() failed and returned false.
- // - To be precise, it needs 11727 + 4 (getMode info) + 14 (length info) =
- // 11745 bits = 1468.125 bytes are needed (i.e. cannot fit in 1468
- // bytes).
- const builder = new ZXingStringBuilder(); // 3518)
- for (let x: number /*int*/ = 0; x < 3518; x++) {
- builder.append('0');
- }
- QRCodeEncoder.encode(builder.toString(), QRCodeDecoderErrorCorrectionLevel.L);
- });
-
- function shiftJISString(bytes: Uint8Array): string {
- try {
- return ZXingStringEncoding.decode(bytes, CharacterSetECI.SJIS.getName());
- } catch (uee/*UnsupportedEncodingException*/) {
- throw new WriterException(uee.toString());
- }
+ hints.set(EncodeHintType.QR_VERSION, 3);
+ QRCodeEncoder.encode('THISMESSAGEISTOOLONGFORAQRCODEVERSION3', QRCodeDecoderErrorCorrectionLevel.H, hints);
+ },
+ WriterException,
+ 'unexpected exception thrown'
+ );
+ });
+
+ it('testSimpleUTF8ECI', () => {
+ const hints = new Map(); // EncodeHintType.class)
+ hints.set(EncodeHintType.CHARACTER_SET, 'UTF8');
+ const qrCode: QRCodeEncoderQRCode = QRCodeEncoder.encode('hello', QRCodeDecoderErrorCorrectionLevel.H, hints);
+ const expected: string =
+ '<<\n' +
+ ' mode: BYTE\n' +
+ ' ecLevel: H\n' +
+ ' version: 1\n' +
+ ' maskPattern: 6\n' +
+ ' matrix:\n' +
+ ' 1 1 1 1 1 1 1 0 0 0 1 1 0 0 1 1 1 1 1 1 1\n' +
+ ' 1 0 0 0 0 0 1 0 0 0 1 1 0 0 1 0 0 0 0 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 1 0 0 1 1 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 1 0 0 0 1 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 0 1 1 0 0 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 0 0 0 0 1 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n' +
+ ' 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n' +
+ ' 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0\n' +
+ ' 0 0 0 1 1 0 1 1 0 0 0 0 1 0 0 0 0 1 1 0 0\n' +
+ ' 0 0 0 0 0 0 0 0 1 1 0 1 0 0 1 0 1 1 1 1 1\n' +
+ ' 1 1 0 0 0 1 1 1 0 0 0 1 1 0 0 1 0 1 0 1 1\n' +
+ ' 0 0 0 0 1 1 0 0 1 0 0 0 0 0 1 0 1 1 0 0 0\n' +
+ ' 0 1 1 0 0 1 1 0 0 1 1 1 0 1 1 1 1 1 1 1 1\n' +
+ ' 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 1 1 1 1 1\n' +
+ ' 1 1 1 1 1 1 1 0 1 0 1 0 0 0 1 0 0 0 0 0 0\n' +
+ ' 1 0 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 1 0 0\n' +
+ ' 1 0 1 1 1 0 1 0 1 0 0 0 1 0 1 0 0 0 1 0 0\n' +
+ ' 1 0 1 1 1 0 1 0 1 1 1 1 0 1 0 0 1 0 1 1 0\n' +
+ ' 1 0 1 1 1 0 1 0 0 1 1 1 0 0 1 0 0 1 0 1 1\n' +
+ ' 1 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 1 1 0 0 0\n' +
+ ' 1 1 1 1 1 1 1 0 0 0 0 1 0 1 0 0 1 0 1 0 0\n' +
+ '>>\n';
+ assert.strictEqual(qrCode.toString(), expected);
+ });
+
+ it('testEncodeKanjiMode', () => {
+
+ ZXingStringEncoding.customEncoder = (b, e) => createCustomEncoder(e).encode(b);
+
+ const hints = new Map(); // EncodeHintType.class)
+ hints.set(EncodeHintType.CHARACTER_SET, CharacterSetECI.SJIS.getName());
+ // Nihon in Kanji
+ const qrCode: QRCodeEncoderQRCode = QRCodeEncoder.encode('\u65e5\u672c', QRCodeDecoderErrorCorrectionLevel.M, hints);
+ const expected: string =
+ '<<\n' +
+ ' mode: KANJI\n' +
+ ' ecLevel: M\n' +
+ ' version: 1\n' +
+ ' maskPattern: 0\n' +
+ ' matrix:\n' +
+ ' 1 1 1 1 1 1 1 0 0 1 0 1 0 0 1 1 1 1 1 1 1\n' +
+ ' 1 0 0 0 0 0 1 0 1 1 0 0 0 0 1 0 0 0 0 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 0 1 1 1 1 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 0 0 0 0 1 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 1 1 1 1 1 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 0 0 0 0 1 0 0 1 1 1 0 0 1 0 0 0 0 0 1\n' +
+ ' 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n' +
+ ' 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0\n' +
+ ' 1 0 1 0 1 0 1 0 0 0 1 0 1 0 0 0 1 0 0 1 0\n' +
+ ' 1 1 0 1 0 0 0 1 0 1 1 1 0 1 0 1 0 1 0 0 0\n' +
+ ' 0 1 0 0 0 0 1 1 1 1 1 1 0 1 1 1 0 1 0 1 0\n' +
+ ' 1 1 1 0 0 1 0 1 0 0 0 1 1 1 0 1 1 0 1 0 0\n' +
+ ' 0 1 1 0 0 1 1 0 1 1 0 1 0 1 1 1 0 1 0 0 1\n' +
+ ' 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 1 0 1\n' +
+ ' 1 1 1 1 1 1 1 0 0 0 0 0 1 0 0 0 1 0 0 1 1\n' +
+ ' 1 0 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 1 1\n' +
+ ' 1 0 1 1 1 0 1 0 1 0 0 0 1 0 1 0 1 0 1 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 0 0 0 1 0 1 0 1 0 1 0 1 0\n' +
+ ' 1 0 1 1 1 0 1 0 1 0 1 1 0 1 1 1 0 0 1 0 1\n' +
+ ' 1 0 0 0 0 0 1 0 0 0 0 1 1 1 0 1 1 1 0 1 0\n' +
+ ' 1 1 1 1 1 1 1 0 1 1 0 1 0 1 1 1 0 0 1 0 0\n' +
+ '>>\n';
+ assert.strictEqual(qrCode.toString(), expected);
+
+ ZXingStringEncoding.customEncoder = undefined;
+ });
+
+ it('testEncodeShiftjisNumeric', () => {
+ const hints = new Map(); // EncodeHintType.class)
+ hints.set(EncodeHintType.CHARACTER_SET, CharacterSetECI.SJIS.getName());
+ const qrCode: QRCodeEncoderQRCode = QRCodeEncoder.encode('0123', QRCodeDecoderErrorCorrectionLevel.M, hints);
+ const expected: string =
+ '<<\n' +
+ ' mode: NUMERIC\n' +
+ ' ecLevel: M\n' +
+ ' version: 1\n' +
+ ' maskPattern: 2\n' +
+ ' matrix:\n' +
+ ' 1 1 1 1 1 1 1 0 0 1 1 0 1 0 1 1 1 1 1 1 1\n' +
+ ' 1 0 0 0 0 0 1 0 0 1 0 0 1 0 1 0 0 0 0 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 1 0 0 0 0 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 1 0 1 1 1 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 1 1 0 1 1 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 0 0 0 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0 1\n' +
+ ' 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n' +
+ ' 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0\n' +
+ ' 1 0 1 1 1 1 1 0 0 1 1 0 1 0 1 1 1 1 1 0 0\n' +
+ ' 1 1 0 0 0 1 0 0 1 0 1 0 1 0 0 1 0 0 1 0 0\n' +
+ ' 0 1 1 0 1 1 1 1 0 1 1 1 0 1 0 0 1 1 0 1 1\n' +
+ ' 1 0 1 1 0 1 0 1 0 0 1 0 0 0 0 1 1 0 1 0 0\n' +
+ ' 0 0 1 0 0 1 1 1 0 0 0 1 0 1 0 0 1 0 1 0 0\n' +
+ ' 0 0 0 0 0 0 0 0 1 1 0 1 1 1 1 0 0 1 0 0 0\n' +
+ ' 1 1 1 1 1 1 1 0 0 0 1 0 1 0 1 1 0 0 0 0 0\n' +
+ ' 1 0 0 0 0 0 1 0 1 1 0 1 1 1 1 0 0 1 0 1 0\n' +
+ ' 1 0 1 1 1 0 1 0 1 0 1 0 1 0 0 1 0 0 1 0 0\n' +
+ ' 1 0 1 1 1 0 1 0 1 1 1 0 1 0 0 1 0 0 1 0 0\n' +
+ ' 1 0 1 1 1 0 1 0 1 1 0 1 0 1 0 0 1 1 1 0 0\n' +
+ ' 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 1 0 1 1 0\n' +
+ ' 1 1 1 1 1 1 1 0 1 1 0 1 0 1 0 0 1 1 1 0 0\n' +
+ '>>\n';
+ assert.strictEqual(qrCode.toString(), expected);
+ });
+
+ it('testAppendModeInfo', () => {
+ const bits = new BitArray();
+ QRCodeEncoder.appendModeInfo(QRCodeMode.NUMERIC, bits);
+ assert.strictEqual(bits.toString(), ' ...X');
+ });
+
+ it('testAppendLengthInfo', () => {
+ let bits = new BitArray();
+ QRCodeEncoder.appendLengthInfo(1, // 1 letter (1/1).
+ QRCodeVersion.getVersionForNumber(1),
+ QRCodeMode.NUMERIC,
+ bits);
+ assert.strictEqual(bits.toString(), ' ........ .X'); // 10 bits.
+ bits = new BitArray();
+ QRCodeEncoder.appendLengthInfo(2, // 2 letters (2/1).
+ QRCodeVersion.getVersionForNumber(10),
+ QRCodeMode.ALPHANUMERIC,
+ bits);
+ assert.strictEqual(bits.toString(), ' ........ .X.'); // 11 bits.
+ bits = new BitArray();
+ QRCodeEncoder.appendLengthInfo(255, // 255 letter (255/1).
+ QRCodeVersion.getVersionForNumber(27),
+ QRCodeMode.BYTE,
+ bits);
+ assert.strictEqual(bits.toString(), ' ........ XXXXXXXX'); // 16 bits.
+ bits = new BitArray();
+ QRCodeEncoder.appendLengthInfo(512, // 512 letters (1024/2).
+ QRCodeVersion.getVersionForNumber(40),
+ QRCodeMode.KANJI,
+ bits);
+ assert.strictEqual(bits.toString(), ' ..X..... ....'); // 12 bits.
+ });
+
+ it('testAppendBytes', () => {
+ ZXingStringEncoding.customEncoder = (b, e) => createCustomEncoder(e).encode(b);
+ ZXingStringEncoding.customDecoder = (b, e) => createCustomDecoder(e).decode(b);
+
+ // Should use appendNumericBytes.
+ // 1 = 01 = 0001 in 4 bits.
+ let bits = new BitArray();
+ QRCodeEncoder.appendBytes('1', QRCodeMode.NUMERIC, bits, QRCodeEncoder.DEFAULT_BYTE_MODE_ENCODING);
+ assert.strictEqual(bits.toString(), ' ...X');
+ // Should use appendAlphanumericBytes.
+ // A = 10 = 0xa = 001010 in 6 bits
+ bits = new BitArray();
+ QRCodeEncoder.appendBytes('A', QRCodeMode.ALPHANUMERIC, bits, QRCodeEncoder.DEFAULT_BYTE_MODE_ENCODING);
+ assert.strictEqual(bits.toString(), ' ..X.X.');
+ // Lower letters such as 'a' cannot be encoded in MODE_ALPHANUMERIC.
+ try {
+ QRCodeEncoder.appendBytes('a', QRCodeMode.ALPHANUMERIC, bits, QRCodeEncoder.DEFAULT_BYTE_MODE_ENCODING);
+ } catch (we/*WriterException*/) {
+ if (we instanceof WriterException) {
+ // good
+ } else {
+ throw we;
+ }
+ }
+ // Should use append8BitBytes.
+ // 0x61, 0x62, 0x63
+ bits = new BitArray();
+ QRCodeEncoder.appendBytes('abc', QRCodeMode.BYTE, bits, QRCodeEncoder.DEFAULT_BYTE_MODE_ENCODING);
+ assert.strictEqual(bits.toString(), ' .XX....X .XX...X. .XX...XX');
+ // Anything can be encoded in QRCodeEncoderQRCode.MODE_8BIT_BYTE.
+ // TYPESCRIPTPORT: this seems to be unused: QRCodeEncoder.appendBytes("\0", QRCodeMode.BYTE, bits, QRCodeEncoder.DEFAULT_BYTE_MODE_ENCODING)
+
+ // Should use appendKanjiBytes.
+ // 0x93, 0x5f
+ bits = new BitArray();
+ QRCodeEncoder.appendBytes(shiftJISString(Uint8Array.from([0x93, 0x5f])), QRCodeMode.KANJI, bits, QRCodeEncoder.DEFAULT_BYTE_MODE_ENCODING);
+ assert.strictEqual(bits.toString(), ' .XX.XX.. XXXXX');
+
+ ZXingStringEncoding.customEncoder = undefined;
+ ZXingStringEncoding.customDecoder = undefined;
+ });
+
+ it('testTerminateBits', () => {
+ let v = new BitArray();
+ QRCodeEncoder.terminateBits(0, v);
+ assert.strictEqual(v.toString(), '');
+ v = new BitArray();
+ QRCodeEncoder.terminateBits(1, v);
+ assert.strictEqual(v.toString(), ' ........');
+ v = new BitArray();
+ v.appendBits(0, 3); // Append 000
+ QRCodeEncoder.terminateBits(1, v);
+ assert.strictEqual(v.toString(), ' ........');
+ v = new BitArray();
+ v.appendBits(0, 5); // Append 00000
+ QRCodeEncoder.terminateBits(1, v);
+ assert.strictEqual(v.toString(), ' ........');
+ v = new BitArray();
+ v.appendBits(0, 8); // Append 00000000
+ QRCodeEncoder.terminateBits(1, v);
+ assert.strictEqual(v.toString(), ' ........');
+ v = new BitArray();
+ QRCodeEncoder.terminateBits(2, v);
+ assert.strictEqual(v.toString(), ' ........ XXX.XX..');
+ v = new BitArray();
+ v.appendBits(0, 1); // Append 0
+ QRCodeEncoder.terminateBits(3, v);
+ assert.strictEqual(v.toString(), ' ........ XXX.XX.. ...X...X');
+ });
+
+ it('testGetNumDataBytesAndNumECBytesForBlockID', () => {
+ const numDataBytes = new Int32Array(1); /*Int32Array(1)*/
+ const numEcBytes = new Int32Array(1); /*Int32Array(1)*/
+ // Version 1-H.
+ QRCodeEncoder.getNumDataBytesAndNumECBytesForBlockID(26, 9, 1, 0, numDataBytes, numEcBytes);
+ assert.strictEqual(numDataBytes[0], 9);
+ assert.strictEqual(numEcBytes[0], 17);
+
+ // Version 3-H. 2 blocks.
+ QRCodeEncoder.getNumDataBytesAndNumECBytesForBlockID(70, 26, 2, 0, numDataBytes, numEcBytes);
+ assert.strictEqual(numDataBytes[0], 13);
+ assert.strictEqual(numEcBytes[0], 22);
+ QRCodeEncoder.getNumDataBytesAndNumECBytesForBlockID(70, 26, 2, 1, numDataBytes, numEcBytes);
+ assert.strictEqual(numDataBytes[0], 13);
+ assert.strictEqual(numEcBytes[0], 22);
+
+ // Version 7-H. (4 + 1) blocks.
+ QRCodeEncoder.getNumDataBytesAndNumECBytesForBlockID(196, 66, 5, 0, numDataBytes, numEcBytes);
+ assert.strictEqual(numDataBytes[0], 13);
+ assert.strictEqual(numEcBytes[0], 26);
+ QRCodeEncoder.getNumDataBytesAndNumECBytesForBlockID(196, 66, 5, 4, numDataBytes, numEcBytes);
+ assert.strictEqual(numDataBytes[0], 14);
+ assert.strictEqual(numEcBytes[0], 26);
+
+ // Version 40-H. (20 + 61) blocks.
+ QRCodeEncoder.getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 0, numDataBytes, numEcBytes);
+ assert.strictEqual(numDataBytes[0], 15);
+ assert.strictEqual(numEcBytes[0], 30);
+ QRCodeEncoder.getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 20, numDataBytes, numEcBytes);
+ assert.strictEqual(numDataBytes[0], 16);
+ assert.strictEqual(numEcBytes[0], 30);
+ QRCodeEncoder.getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 80, numDataBytes, numEcBytes);
+ assert.strictEqual(numDataBytes[0], 16);
+ assert.strictEqual(numEcBytes[0], 30);
+ });
+
+ it('testInterleaveWithECBytes', () => {
+ let dataBytes = Uint8Array.from([32, 65, 205, 69, 41, 220, 46, 128, 236]);
+ let input = new BitArray();
+ for (let i = 0, length = dataBytes.length; i !== length; i++) {
+ const dataByte = dataBytes[i];
+ input.appendBits(dataByte, 8);
+ }
+ let out: BitArray = QRCodeEncoder.interleaveWithECBytes(input, 26, 9, 1);
+ let expected = Uint8Array.from([
+ // Data bytes.
+ 32, 65, 205, 69, 41, 220, 46, 128, 236,
+ // Error correction bytes.
+ 42, 159, 74, 221, 244, 169, 239, 150, 138, 70,
+ 237, 85, 224, 96, 74, 219, 61,
+ ]);
+ assert.strictEqual(out.getSizeInBytes(), expected.length);
+ let outArray = new Uint8Array(expected.length);
+ out.toBytes(0, outArray, 0, expected.length);
+ // Can't use ZXingArrays.equals(), because outArray may be longer than out.sizeInBytes()
+ for (let x: number /*int*/ = 0; x < expected.length; x++) {
+ assert.strictEqual(outArray[x], expected[x]);
+ }
+ // Numbers are from http://www.swetake.com/qr/qr8.html
+ dataBytes = Uint8Array.from([
+ 67, 70, 22, 38, 54, 70, 86, 102, 118, 134, 150, 166, 182,
+ 198, 214, 230, 247, 7, 23, 39, 55, 71, 87, 103, 119, 135,
+ 151, 166, 22, 38, 54, 70, 86, 102, 118, 134, 150, 166,
+ 182, 198, 214, 230, 247, 7, 23, 39, 55, 71, 87, 103, 119,
+ 135, 151, 160, 236, 17, 236, 17, 236, 17, 236,
+ 17
+ ]);
+ input = new BitArray();
+ for (let i = 0, length = dataBytes.length; i !== length; i++) {
+ const dataByte = dataBytes[i];
+ input.appendBits(dataByte, 8);
+ }
+
+ out = QRCodeEncoder.interleaveWithECBytes(input, 134, 62, 4);
+ expected = Uint8Array.from([
+ // Data bytes.
+ 67, 230, 54, 55, 70, 247, 70, 71, 22, 7, 86, 87, 38, 23, 102, 103, 54, 39,
+ 118, 119, 70, 55, 134, 135, 86, 71, 150, 151, 102, 87, 166,
+ 160, 118, 103, 182, 236, 134, 119, 198, 17, 150,
+ 135, 214, 236, 166, 151, 230, 17, 182,
+ 166, 247, 236, 198, 22, 7, 17, 214, 38, 23, 236, 39,
+ 17,
+ // Error correction bytes.
+ 175, 155, 245, 236, 80, 146, 56, 74, 155, 165,
+ 133, 142, 64, 183, 132, 13, 178, 54, 132, 108, 45,
+ 113, 53, 50, 214, 98, 193, 152, 233, 147, 50, 71, 65,
+ 190, 82, 51, 209, 199, 171, 54, 12, 112, 57, 113, 155, 117,
+ 211, 164, 117, 30, 158, 225, 31, 190, 242, 38,
+ 140, 61, 179, 154, 214, 138, 147, 87, 27, 96, 77, 47,
+ 187, 49, 156, 214,
+ ]);
+ assert.strictEqual(out.getSizeInBytes(), expected.length);
+ outArray = new Uint8Array(expected.length);
+ out.toBytes(0, outArray, 0, expected.length);
+ for (let x: number /*int*/ = 0; x < expected.length; x++) {
+ assert.strictEqual(outArray[x], expected[x]);
+ }
+ });
+
+ it('testAppendNumericBytes', () => {
+ // 1 = 01 = 0001 in 4 bits.
+ let bits = new BitArray();
+ QRCodeEncoder.appendNumericBytes('1', bits);
+ assert.strictEqual(bits.toString(), ' ...X');
+ // 12 = 0xc = 0001100 in 7 bits.
+ bits = new BitArray();
+ QRCodeEncoder.appendNumericBytes('12', bits);
+ assert.strictEqual(bits.toString(), ' ...XX..');
+ // 123 = 0x7b = 0001111011 in 10 bits.
+ bits = new BitArray();
+ QRCodeEncoder.appendNumericBytes('123', bits);
+ assert.strictEqual(bits.toString(), ' ...XXXX. XX');
+ // 1234 = "123" + "4" = 0001111011 + 0100
+ bits = new BitArray();
+ QRCodeEncoder.appendNumericBytes('1234', bits);
+ assert.strictEqual(bits.toString(), ' ...XXXX. XX.X..');
+ // Empty.
+ bits = new BitArray();
+ QRCodeEncoder.appendNumericBytes('', bits);
+ assert.strictEqual(bits.toString(), '');
+ });
+
+ it('testAppendAlphanumericBytes', () => {
+ // A = 10 = 0xa = 001010 in 6 bits
+ let bits = new BitArray();
+ QRCodeEncoder.appendAlphanumericBytes('A', bits);
+ assert.strictEqual(bits.toString(), ' ..X.X.');
+ // AB = 10 * 45 + 11 = 461 = 0x1cd = 00111001101 in 11 bits
+ bits = new BitArray();
+ QRCodeEncoder.appendAlphanumericBytes('AB', bits);
+ assert.strictEqual(bits.toString(), ' ..XXX..X X.X');
+ // ABC = "AB" + "C" = 00111001101 + 001100
+ bits = new BitArray();
+ QRCodeEncoder.appendAlphanumericBytes('ABC', bits);
+ assert.strictEqual(bits.toString(), ' ..XXX..X X.X..XX. .');
+ // Empty.
+ bits = new BitArray();
+ QRCodeEncoder.appendAlphanumericBytes('', bits);
+ assert.strictEqual(bits.toString(), '');
+ // Invalid data.
+ try {
+ QRCodeEncoder.appendAlphanumericBytes('abc', new BitArray());
+ } catch (we/*WriterException*/) {
+ // good
+ }
+ });
+
+ it('testAppend8BitBytes', () => {
+ ZXingStringEncoding.customEncoder = (b, e) => createCustomEncoder(e).encode(b);
+ // 0x61, 0x62, 0x63
+ let bits = new BitArray();
+ QRCodeEncoder.append8BitBytes('abc', bits, QRCodeEncoder.DEFAULT_BYTE_MODE_ENCODING);
+ assert.strictEqual(bits.toString(), ' .XX....X .XX...X. .XX...XX');
+ // Empty.
+ bits = new BitArray();
+ QRCodeEncoder.append8BitBytes('', bits, QRCodeEncoder.DEFAULT_BYTE_MODE_ENCODING);
+ assert.strictEqual(bits.toString(), '');
+ });
+
+ // Numbers are from page 21 of JISX0510:2004
+ it('testAppendKanjiBytes', () => {
+ ZXingStringEncoding.customEncoder = (b, e) => createCustomEncoder(e).encode(b);
+ ZXingStringEncoding.customDecoder = (b, e) => createCustomDecoder(e).decode(b);
+
+ const bits = new BitArray();
+ QRCodeEncoder.appendKanjiBytes(shiftJISString(Uint8Array.from([0x93, 0x5f])), bits);
+ assert.strictEqual(bits.toString(), ' .XX.XX.. XXXXX');
+ QRCodeEncoder.appendKanjiBytes(shiftJISString(Uint8Array.from([0xe4, 0xaa])), bits);
+ assert.strictEqual(bits.toString(), ' .XX.XX.. XXXXXXX. X.X.X.X. X.');
+
+ ZXingStringEncoding.customEncoder = undefined;
+ ZXingStringEncoding.customDecoder = undefined;
+ });
+
+ // Numbers are from http://www.swetake.com/qr/qr3.html and
+ // http://www.swetake.com/qr/qr9.html
+ it('testGenerateECBytes', () => {
+ let dataBytes = Uint8Array.from([32, 65, 205, 69, 41, 220, 46, 128, 236]);
+ let ecBytes: Uint8Array = QRCodeEncoder.generateECBytes(dataBytes, 17);
+ let expected = Int32Array.from([
+ 42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61
+ ]);
+ assert.strictEqual(ecBytes.length, expected.length);
+ for (let x: number /*int*/ = 0; x < expected.length; x++) {
+ assert.strictEqual(ecBytes[x] & 0xFF, expected[x]);
+ }
+ dataBytes = Uint8Array.from([67, 70, 22, 38, 54, 70, 86, 102, 118,
+ 134, 150, 166, 182, 198, 214]);
+ ecBytes = QRCodeEncoder.generateECBytes(dataBytes, 18);
+ expected = Int32Array.from([
+ 175, 80, 155, 64, 178, 45, 214, 233, 65, 209, 12, 155, 117, 31, 140, 214, 27, 187
+ ]);
+ assert.strictEqual(ecBytes.length, expected.length);
+ for (let x: number /*int*/ = 0; x < expected.length; x++) {
+ assert.strictEqual(ecBytes[x] & 0xFF, expected[x]);
+ }
+ // High-order zero coefficient case.
+ dataBytes = Uint8Array.from([32, 49, 205, 69, 42, 20, 0, 236, 17]);
+ ecBytes = QRCodeEncoder.generateECBytes(dataBytes, 17);
+ expected = Int32Array.from([
+ 0, 3, 130, 179, 194, 0, 55, 211, 110, 79, 98, 72, 170, 96, 211, 137, 213
+ ]);
+ assert.strictEqual(ecBytes.length, expected.length);
+ for (let x: number /*int*/ = 0; x < expected.length; x++) {
+ assert.strictEqual(ecBytes[x] & 0xFF, expected[x]);
+ }
+ });
+
+ it('testBugInBitVectorNumBytes', () => {
+ // There was a bug in BitVector.sizeInBytes() that caused it to return a
+ // smaller-by-one value (ex. 1465 instead of 1466) if the number of bits
+ // in the vector is not 8-bit aligned. In QRCodeEncoder::InitQRCode(),
+ // BitVector::sizeInBytes() is used for finding the smallest QR Code
+ // version that can fit the given data. Hence there were corner cases
+ // where we chose a wrong QR Code version that cannot fit the given
+ // data. Note that the issue did not occur with MODE_8BIT_BYTE, as the
+ // bits in the bit vector are always 8-bit aligned.
+ //
+ // Before the bug was fixed, the following test didn't pass, because:
+ //
+ // - MODE_NUMERIC is chosen as all bytes in the data are '0'
+ // - The 3518-byte numeric data needs 1466 bytes
+ // - 3518 / 3 * 10 + 7 = 11727 bits = 1465.875 bytes
+ // - 3 numeric bytes are encoded in 10 bits, hence the first
+ // 3516 bytes are encoded in 3516 / 3 * 10 = 11720 bits.
+ // - 2 numeric bytes can be encoded in 7 bits, hence the last
+ // 2 bytes are encoded in 7 bits.
+ // - The version 27 QR Code with the EC level L has 1468 bytes for data.
+ // - 1828 - 360 = 1468
+ // - In InitQRCode(), 3 bytes are reserved for a header. Hence 1465 bytes
+ // (1468 -3) are left for data.
+ // - Because of the bug in BitVector::sizeInBytes(), InitQRCode() determines
+ // the given data can fit in 1465 bytes, despite it needs 1466 bytes.
+ // - Hence QRCodeEncoder.encode() failed and returned false.
+ // - To be precise, it needs 11727 + 4 (getMode info) + 14 (length info) =
+ // 11745 bits = 1468.125 bytes are needed (i.e. cannot fit in 1468
+ // bytes).
+ const builder = new ZXingStringBuilder(); // 3518)
+ for (let x: number /*int*/ = 0; x < 3518; x++) {
+ builder.append('0');
+ }
+ QRCodeEncoder.encode(builder.toString(), QRCodeDecoderErrorCorrectionLevel.L);
+ });
+
+ function shiftJISString(bytes: Uint8Array): string {
+ try {
+ return ZXingStringEncoding.decode(bytes, CharacterSetECI.SJIS.getName());
+ } catch (uee/*UnsupportedEncodingException*/) {
+ throw new WriterException(uee.toString());
}
+ }
});
diff --git a/src/test/core/qrcode/encoder/MaskUtil.spec.ts b/src/test/core/qrcode/encoder/MaskUtil.spec.ts
index f360207b..a1a0f4b5 100644
--- a/src/test/core/qrcode/encoder/MaskUtil.spec.ts
+++ b/src/test/core/qrcode/encoder/MaskUtil.spec.ts
@@ -26,231 +26,231 @@ import { QRCodeMaskUtil } from '@zxing/library';
*/
describe('QRCodeMaskUtil', () => {
- it('testApplyMaskPenaltyRule1', () => {
- let matrix = new QRCodeByteMatrix(4, 1);
- matrix.setNumber(0, 0, 0);
- matrix.setNumber(1, 0, 0);
- matrix.setNumber(2, 0, 0);
- matrix.setNumber(3, 0, 0);
- assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule1(matrix), 0);
- // Horizontal.
- matrix = new QRCodeByteMatrix(6, 1);
- matrix.setNumber(0, 0, 0);
- matrix.setNumber(1, 0, 0);
- matrix.setNumber(2, 0, 0);
- matrix.setNumber(3, 0, 0);
- matrix.setNumber(4, 0, 0);
- matrix.setNumber(5, 0, 1);
- assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule1(matrix), 3);
- matrix.setNumber(5, 0, 0);
- assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule1(matrix), 4);
- // Vertical.
- matrix = new QRCodeByteMatrix(1, 6);
- matrix.setNumber(0, 0, 0);
- matrix.setNumber(0, 1, 0);
- matrix.setNumber(0, 2, 0);
- matrix.setNumber(0, 3, 0);
- matrix.setNumber(0, 4, 0);
- matrix.setNumber(0, 5, 1);
- assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule1(matrix), 3);
- matrix.setNumber(0, 5, 0);
- assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule1(matrix), 4);
- });
+ it('testApplyMaskPenaltyRule1', () => {
+ let matrix = new QRCodeByteMatrix(4, 1);
+ matrix.setNumber(0, 0, 0);
+ matrix.setNumber(1, 0, 0);
+ matrix.setNumber(2, 0, 0);
+ matrix.setNumber(3, 0, 0);
+ assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule1(matrix), 0);
+ // Horizontal.
+ matrix = new QRCodeByteMatrix(6, 1);
+ matrix.setNumber(0, 0, 0);
+ matrix.setNumber(1, 0, 0);
+ matrix.setNumber(2, 0, 0);
+ matrix.setNumber(3, 0, 0);
+ matrix.setNumber(4, 0, 0);
+ matrix.setNumber(5, 0, 1);
+ assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule1(matrix), 3);
+ matrix.setNumber(5, 0, 0);
+ assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule1(matrix), 4);
+ // Vertical.
+ matrix = new QRCodeByteMatrix(1, 6);
+ matrix.setNumber(0, 0, 0);
+ matrix.setNumber(0, 1, 0);
+ matrix.setNumber(0, 2, 0);
+ matrix.setNumber(0, 3, 0);
+ matrix.setNumber(0, 4, 0);
+ matrix.setNumber(0, 5, 1);
+ assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule1(matrix), 3);
+ matrix.setNumber(0, 5, 0);
+ assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule1(matrix), 4);
+ });
- it('testApplyMaskPenaltyRule2', () => {
- let matrix = new QRCodeByteMatrix(1, 1);
- matrix.setNumber(0, 0, 0);
- assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule2(matrix), 0);
- matrix = new QRCodeByteMatrix(2, 2);
- matrix.setNumber(0, 0, 0);
- matrix.setNumber(1, 0, 0);
- matrix.setNumber(0, 1, 0);
- matrix.setNumber(1, 1, 1);
- assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule2(matrix), 0);
- matrix = new QRCodeByteMatrix(2, 2);
- matrix.setNumber(0, 0, 0);
- matrix.setNumber(1, 0, 0);
- matrix.setNumber(0, 1, 0);
- matrix.setNumber(1, 1, 0);
- assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule2(matrix), 3);
- matrix = new QRCodeByteMatrix(3, 3);
- matrix.setNumber(0, 0, 0);
- matrix.setNumber(1, 0, 0);
- matrix.setNumber(2, 0, 0);
- matrix.setNumber(0, 1, 0);
- matrix.setNumber(1, 1, 0);
- matrix.setNumber(2, 1, 0);
- matrix.setNumber(0, 2, 0);
- matrix.setNumber(1, 2, 0);
- matrix.setNumber(2, 2, 0);
- // Four instances of 2x2 blocks.
- assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule2(matrix), 3 * 4);
- });
+ it('testApplyMaskPenaltyRule2', () => {
+ let matrix = new QRCodeByteMatrix(1, 1);
+ matrix.setNumber(0, 0, 0);
+ assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule2(matrix), 0);
+ matrix = new QRCodeByteMatrix(2, 2);
+ matrix.setNumber(0, 0, 0);
+ matrix.setNumber(1, 0, 0);
+ matrix.setNumber(0, 1, 0);
+ matrix.setNumber(1, 1, 1);
+ assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule2(matrix), 0);
+ matrix = new QRCodeByteMatrix(2, 2);
+ matrix.setNumber(0, 0, 0);
+ matrix.setNumber(1, 0, 0);
+ matrix.setNumber(0, 1, 0);
+ matrix.setNumber(1, 1, 0);
+ assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule2(matrix), 3);
+ matrix = new QRCodeByteMatrix(3, 3);
+ matrix.setNumber(0, 0, 0);
+ matrix.setNumber(1, 0, 0);
+ matrix.setNumber(2, 0, 0);
+ matrix.setNumber(0, 1, 0);
+ matrix.setNumber(1, 1, 0);
+ matrix.setNumber(2, 1, 0);
+ matrix.setNumber(0, 2, 0);
+ matrix.setNumber(1, 2, 0);
+ matrix.setNumber(2, 2, 0);
+ // Four instances of 2x2 blocks.
+ assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule2(matrix), 3 * 4);
+ });
- it('testApplyMaskPenaltyRule3', () => {
- // Horizontal 00001011101.
- let matrix = new QRCodeByteMatrix(11, 1);
- matrix.setNumber(0, 0, 0);
- matrix.setNumber(1, 0, 0);
- matrix.setNumber(2, 0, 0);
- matrix.setNumber(3, 0, 0);
- matrix.setNumber(4, 0, 1);
- matrix.setNumber(5, 0, 0);
- matrix.setNumber(6, 0, 1);
- matrix.setNumber(7, 0, 1);
- matrix.setNumber(8, 0, 1);
- matrix.setNumber(9, 0, 0);
- matrix.setNumber(10, 0, 1);
- assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule3(matrix), 40);
- // Horizontal 10111010000.
- matrix = new QRCodeByteMatrix(11, 1);
- matrix.setNumber(0, 0, 1);
- matrix.setNumber(1, 0, 0);
- matrix.setNumber(2, 0, 1);
- matrix.setNumber(3, 0, 1);
- matrix.setNumber(4, 0, 1);
- matrix.setNumber(5, 0, 0);
- matrix.setNumber(6, 0, 1);
- matrix.setNumber(7, 0, 0);
- matrix.setNumber(8, 0, 0);
- matrix.setNumber(9, 0, 0);
- matrix.setNumber(10, 0, 0);
- assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule3(matrix), 40);
- // Vertical 00001011101.
- matrix = new QRCodeByteMatrix(1, 11);
- matrix.setNumber(0, 0, 0);
- matrix.setNumber(0, 1, 0);
- matrix.setNumber(0, 2, 0);
- matrix.setNumber(0, 3, 0);
- matrix.setNumber(0, 4, 1);
- matrix.setNumber(0, 5, 0);
- matrix.setNumber(0, 6, 1);
- matrix.setNumber(0, 7, 1);
- matrix.setNumber(0, 8, 1);
- matrix.setNumber(0, 9, 0);
- matrix.setNumber(0, 10, 1);
- assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule3(matrix), 40);
- // Vertical 10111010000.
- matrix = new QRCodeByteMatrix(1, 11);
- matrix.setNumber(0, 0, 1);
- matrix.setNumber(0, 1, 0);
- matrix.setNumber(0, 2, 1);
- matrix.setNumber(0, 3, 1);
- matrix.setNumber(0, 4, 1);
- matrix.setNumber(0, 5, 0);
- matrix.setNumber(0, 6, 1);
- matrix.setNumber(0, 7, 0);
- matrix.setNumber(0, 8, 0);
- matrix.setNumber(0, 9, 0);
- matrix.setNumber(0, 10, 0);
- assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule3(matrix), 40);
- });
+ it('testApplyMaskPenaltyRule3', () => {
+ // Horizontal 00001011101.
+ let matrix = new QRCodeByteMatrix(11, 1);
+ matrix.setNumber(0, 0, 0);
+ matrix.setNumber(1, 0, 0);
+ matrix.setNumber(2, 0, 0);
+ matrix.setNumber(3, 0, 0);
+ matrix.setNumber(4, 0, 1);
+ matrix.setNumber(5, 0, 0);
+ matrix.setNumber(6, 0, 1);
+ matrix.setNumber(7, 0, 1);
+ matrix.setNumber(8, 0, 1);
+ matrix.setNumber(9, 0, 0);
+ matrix.setNumber(10, 0, 1);
+ assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule3(matrix), 40);
+ // Horizontal 10111010000.
+ matrix = new QRCodeByteMatrix(11, 1);
+ matrix.setNumber(0, 0, 1);
+ matrix.setNumber(1, 0, 0);
+ matrix.setNumber(2, 0, 1);
+ matrix.setNumber(3, 0, 1);
+ matrix.setNumber(4, 0, 1);
+ matrix.setNumber(5, 0, 0);
+ matrix.setNumber(6, 0, 1);
+ matrix.setNumber(7, 0, 0);
+ matrix.setNumber(8, 0, 0);
+ matrix.setNumber(9, 0, 0);
+ matrix.setNumber(10, 0, 0);
+ assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule3(matrix), 40);
+ // Vertical 00001011101.
+ matrix = new QRCodeByteMatrix(1, 11);
+ matrix.setNumber(0, 0, 0);
+ matrix.setNumber(0, 1, 0);
+ matrix.setNumber(0, 2, 0);
+ matrix.setNumber(0, 3, 0);
+ matrix.setNumber(0, 4, 1);
+ matrix.setNumber(0, 5, 0);
+ matrix.setNumber(0, 6, 1);
+ matrix.setNumber(0, 7, 1);
+ matrix.setNumber(0, 8, 1);
+ matrix.setNumber(0, 9, 0);
+ matrix.setNumber(0, 10, 1);
+ assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule3(matrix), 40);
+ // Vertical 10111010000.
+ matrix = new QRCodeByteMatrix(1, 11);
+ matrix.setNumber(0, 0, 1);
+ matrix.setNumber(0, 1, 0);
+ matrix.setNumber(0, 2, 1);
+ matrix.setNumber(0, 3, 1);
+ matrix.setNumber(0, 4, 1);
+ matrix.setNumber(0, 5, 0);
+ matrix.setNumber(0, 6, 1);
+ matrix.setNumber(0, 7, 0);
+ matrix.setNumber(0, 8, 0);
+ matrix.setNumber(0, 9, 0);
+ matrix.setNumber(0, 10, 0);
+ assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule3(matrix), 40);
+ });
- it('testApplyMaskPenaltyRule4', () => {
- // Dark cell ratio = 0%
- let matrix = new QRCodeByteMatrix(1, 1);
- matrix.setNumber(0, 0, 0);
- assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule4(matrix), 100);
- // Dark cell ratio = 5%
- matrix = new QRCodeByteMatrix(2, 1);
- matrix.setNumber(0, 0, 0);
- matrix.setNumber(0, 0, 1);
- assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule4(matrix), 0);
- // Dark cell ratio = 66.67%
- matrix = new QRCodeByteMatrix(6, 1);
- matrix.setNumber(0, 0, 0);
- matrix.setNumber(1, 0, 1);
- matrix.setNumber(2, 0, 1);
- matrix.setNumber(3, 0, 1);
- matrix.setNumber(4, 0, 1);
- matrix.setNumber(5, 0, 0);
- assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule4(matrix), 30);
- });
+ it('testApplyMaskPenaltyRule4', () => {
+ // Dark cell ratio = 0%
+ let matrix = new QRCodeByteMatrix(1, 1);
+ matrix.setNumber(0, 0, 0);
+ assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule4(matrix), 100);
+ // Dark cell ratio = 5%
+ matrix = new QRCodeByteMatrix(2, 1);
+ matrix.setNumber(0, 0, 0);
+ matrix.setNumber(0, 0, 1);
+ assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule4(matrix), 0);
+ // Dark cell ratio = 66.67%
+ matrix = new QRCodeByteMatrix(6, 1);
+ matrix.setNumber(0, 0, 0);
+ matrix.setNumber(1, 0, 1);
+ matrix.setNumber(2, 0, 1);
+ matrix.setNumber(3, 0, 1);
+ matrix.setNumber(4, 0, 1);
+ matrix.setNumber(5, 0, 0);
+ assert.strictEqual(QRCodeMaskUtil.applyMaskPenaltyRule4(matrix), 30);
+ });
- function TestGetDataMaskBitInternal(maskPattern: number /*int*/, expected: Array): boolean {
- for (let x: number /*int*/ = 0; x < 6; ++x) {
- for (let y: number /*int*/ = 0; y < 6; ++y) {
- if ((expected[y][x] === 1) !== QRCodeMaskUtil.getDataMaskBit(maskPattern, x, y)) {
- return false;
- }
- }
+ function TestGetDataMaskBitInternal(maskPattern: number /*int*/, expected: Array): boolean {
+ for (let x: number /*int*/ = 0; x < 6; ++x) {
+ for (let y: number /*int*/ = 0; y < 6; ++y) {
+ if ((expected[y][x] === 1) !== QRCodeMaskUtil.getDataMaskBit(maskPattern, x, y)) {
+ return false;
}
- return true;
+ }
}
+ return true;
+ }
- // See mask patterns on the page 43 of JISX0510:2004.
- it('testGetDataMaskBit', () => {
- const mask0 = [
- Int32Array.from([1, 0, 1, 0, 1, 0]),
- Int32Array.from([0, 1, 0, 1, 0, 1]),
- Int32Array.from([1, 0, 1, 0, 1, 0]),
- Int32Array.from([0, 1, 0, 1, 0, 1]),
- Int32Array.from([1, 0, 1, 0, 1, 0]),
- Int32Array.from([0, 1, 0, 1, 0, 1])
- ];
- assert.strictEqual(TestGetDataMaskBitInternal(0, mask0), true);
- const mask1 = [
- Int32Array.from([1, 1, 1, 1, 1, 1]),
- Int32Array.from([0, 0, 0, 0, 0, 0]),
- Int32Array.from([1, 1, 1, 1, 1, 1]),
- Int32Array.from([0, 0, 0, 0, 0, 0]),
- Int32Array.from([1, 1, 1, 1, 1, 1]),
- Int32Array.from([0, 0, 0, 0, 0, 0]),
- ];
- assert.strictEqual(TestGetDataMaskBitInternal(1, mask1), true);
- const mask2 = [
- Int32Array.from([1, 0, 0, 1, 0, 0]),
- Int32Array.from([1, 0, 0, 1, 0, 0]),
- Int32Array.from([1, 0, 0, 1, 0, 0]),
- Int32Array.from([1, 0, 0, 1, 0, 0]),
- Int32Array.from([1, 0, 0, 1, 0, 0]),
- Int32Array.from([1, 0, 0, 1, 0, 0]),
- ];
- assert.strictEqual(TestGetDataMaskBitInternal(2, mask2), true);
- const mask3 = [
- Int32Array.from([1, 0, 0, 1, 0, 0]),
- Int32Array.from([0, 0, 1, 0, 0, 1]),
- Int32Array.from([0, 1, 0, 0, 1, 0]),
- Int32Array.from([1, 0, 0, 1, 0, 0]),
- Int32Array.from([0, 0, 1, 0, 0, 1]),
- Int32Array.from([0, 1, 0, 0, 1, 0]),
- ];
- assert.strictEqual(TestGetDataMaskBitInternal(3, mask3), true);
- const mask4 = [
- Int32Array.from([1, 1, 1, 0, 0, 0]),
- Int32Array.from([1, 1, 1, 0, 0, 0]),
- Int32Array.from([0, 0, 0, 1, 1, 1]),
- Int32Array.from([0, 0, 0, 1, 1, 1]),
- Int32Array.from([1, 1, 1, 0, 0, 0]),
- Int32Array.from([1, 1, 1, 0, 0, 0]),
- ];
- assert.strictEqual(TestGetDataMaskBitInternal(4, mask4), true);
- const mask5 = [
- Int32Array.from([1, 1, 1, 1, 1, 1]),
- Int32Array.from([1, 0, 0, 0, 0, 0]),
- Int32Array.from([1, 0, 0, 1, 0, 0]),
- Int32Array.from([1, 0, 1, 0, 1, 0]),
- Int32Array.from([1, 0, 0, 1, 0, 0]),
- Int32Array.from([1, 0, 0, 0, 0, 0]),
- ];
- assert.strictEqual(TestGetDataMaskBitInternal(5, mask5), true);
- const mask6 = [
- Int32Array.from([1, 1, 1, 1, 1, 1]),
- Int32Array.from([1, 1, 1, 0, 0, 0]),
- Int32Array.from([1, 1, 0, 1, 1, 0]),
- Int32Array.from([1, 0, 1, 0, 1, 0]),
- Int32Array.from([1, 0, 1, 1, 0, 1]),
- Int32Array.from([1, 0, 0, 0, 1, 1]),
- ];
- assert.strictEqual(TestGetDataMaskBitInternal(6, mask6), true);
- const mask7 = [
- Int32Array.from([1, 0, 1, 0, 1, 0]),
- Int32Array.from([0, 0, 0, 1, 1, 1]),
- Int32Array.from([1, 0, 0, 0, 1, 1]),
- Int32Array.from([0, 1, 0, 1, 0, 1]),
- Int32Array.from([1, 1, 1, 0, 0, 0]),
- Int32Array.from([0, 1, 1, 1, 0, 0]),
- ];
- assert.strictEqual(TestGetDataMaskBitInternal(7, mask7), true);
- });
+ // See mask patterns on the page 43 of JISX0510:2004.
+ it('testGetDataMaskBit', () => {
+ const mask0 = [
+ Int32Array.from([1, 0, 1, 0, 1, 0]),
+ Int32Array.from([0, 1, 0, 1, 0, 1]),
+ Int32Array.from([1, 0, 1, 0, 1, 0]),
+ Int32Array.from([0, 1, 0, 1, 0, 1]),
+ Int32Array.from([1, 0, 1, 0, 1, 0]),
+ Int32Array.from([0, 1, 0, 1, 0, 1])
+ ];
+ assert.strictEqual(TestGetDataMaskBitInternal(0, mask0), true);
+ const mask1 = [
+ Int32Array.from([1, 1, 1, 1, 1, 1]),
+ Int32Array.from([0, 0, 0, 0, 0, 0]),
+ Int32Array.from([1, 1, 1, 1, 1, 1]),
+ Int32Array.from([0, 0, 0, 0, 0, 0]),
+ Int32Array.from([1, 1, 1, 1, 1, 1]),
+ Int32Array.from([0, 0, 0, 0, 0, 0]),
+ ];
+ assert.strictEqual(TestGetDataMaskBitInternal(1, mask1), true);
+ const mask2 = [
+ Int32Array.from([1, 0, 0, 1, 0, 0]),
+ Int32Array.from([1, 0, 0, 1, 0, 0]),
+ Int32Array.from([1, 0, 0, 1, 0, 0]),
+ Int32Array.from([1, 0, 0, 1, 0, 0]),
+ Int32Array.from([1, 0, 0, 1, 0, 0]),
+ Int32Array.from([1, 0, 0, 1, 0, 0]),
+ ];
+ assert.strictEqual(TestGetDataMaskBitInternal(2, mask2), true);
+ const mask3 = [
+ Int32Array.from([1, 0, 0, 1, 0, 0]),
+ Int32Array.from([0, 0, 1, 0, 0, 1]),
+ Int32Array.from([0, 1, 0, 0, 1, 0]),
+ Int32Array.from([1, 0, 0, 1, 0, 0]),
+ Int32Array.from([0, 0, 1, 0, 0, 1]),
+ Int32Array.from([0, 1, 0, 0, 1, 0]),
+ ];
+ assert.strictEqual(TestGetDataMaskBitInternal(3, mask3), true);
+ const mask4 = [
+ Int32Array.from([1, 1, 1, 0, 0, 0]),
+ Int32Array.from([1, 1, 1, 0, 0, 0]),
+ Int32Array.from([0, 0, 0, 1, 1, 1]),
+ Int32Array.from([0, 0, 0, 1, 1, 1]),
+ Int32Array.from([1, 1, 1, 0, 0, 0]),
+ Int32Array.from([1, 1, 1, 0, 0, 0]),
+ ];
+ assert.strictEqual(TestGetDataMaskBitInternal(4, mask4), true);
+ const mask5 = [
+ Int32Array.from([1, 1, 1, 1, 1, 1]),
+ Int32Array.from([1, 0, 0, 0, 0, 0]),
+ Int32Array.from([1, 0, 0, 1, 0, 0]),
+ Int32Array.from([1, 0, 1, 0, 1, 0]),
+ Int32Array.from([1, 0, 0, 1, 0, 0]),
+ Int32Array.from([1, 0, 0, 0, 0, 0]),
+ ];
+ assert.strictEqual(TestGetDataMaskBitInternal(5, mask5), true);
+ const mask6 = [
+ Int32Array.from([1, 1, 1, 1, 1, 1]),
+ Int32Array.from([1, 1, 1, 0, 0, 0]),
+ Int32Array.from([1, 1, 0, 1, 1, 0]),
+ Int32Array.from([1, 0, 1, 0, 1, 0]),
+ Int32Array.from([1, 0, 1, 1, 0, 1]),
+ Int32Array.from([1, 0, 0, 0, 1, 1]),
+ ];
+ assert.strictEqual(TestGetDataMaskBitInternal(6, mask6), true);
+ const mask7 = [
+ Int32Array.from([1, 0, 1, 0, 1, 0]),
+ Int32Array.from([0, 0, 0, 1, 1, 1]),
+ Int32Array.from([1, 0, 0, 0, 1, 1]),
+ Int32Array.from([0, 1, 0, 1, 0, 1]),
+ Int32Array.from([1, 1, 1, 0, 0, 0]),
+ Int32Array.from([0, 1, 1, 1, 0, 0]),
+ ];
+ assert.strictEqual(TestGetDataMaskBitInternal(7, mask7), true);
+ });
});
diff --git a/src/test/core/qrcode/encoder/MatrixUtil.spec.ts b/src/test/core/qrcode/encoder/MatrixUtil.spec.ts
index 613becd9..9f50fdc0 100644
--- a/src/test/core/qrcode/encoder/MatrixUtil.spec.ts
+++ b/src/test/core/qrcode/encoder/MatrixUtil.spec.ts
@@ -29,274 +29,274 @@ import { QRCodeVersion } from '@zxing/library';
*/
describe('QRCodeMatrixUtil', () => {
- it('testToString', () => {
- const array = new QRCodeByteMatrix(3, 3);
- array.setNumber(0, 0, 0);
- array.setNumber(1, 0, 1);
- array.setNumber(2, 0, 0);
- array.setNumber(0, 1, 1);
- array.setNumber(1, 1, 0);
- array.setNumber(2, 1, 1);
- array.setNumber(0, 2, -1);
- array.setNumber(1, 2, -1);
- array.setNumber(2, 2, -1);
- const expected: string = ' 0 1 0\n' + ' 1 0 1\n' + ' \n';
- assert.strictEqual(array.toString(), expected);
- });
+ it('testToString', () => {
+ const array = new QRCodeByteMatrix(3, 3);
+ array.setNumber(0, 0, 0);
+ array.setNumber(1, 0, 1);
+ array.setNumber(2, 0, 0);
+ array.setNumber(0, 1, 1);
+ array.setNumber(1, 1, 0);
+ array.setNumber(2, 1, 1);
+ array.setNumber(0, 2, -1);
+ array.setNumber(1, 2, -1);
+ array.setNumber(2, 2, -1);
+ const expected: string = ' 0 1 0\n' + ' 1 0 1\n' + ' \n';
+ assert.strictEqual(array.toString(), expected);
+ });
- it('testClearMatrix', () => {
- const matrix = new QRCodeByteMatrix(2, 2);
- QRCodeMatrixUtil.clearMatrix(matrix);
- // TYPESCRIPTPORT: we use UintArray se changed here from -1 to 255
- assert.strictEqual(matrix.get(0, 0), 255);
- assert.strictEqual(matrix.get(1, 0), 255);
- assert.strictEqual(matrix.get(0, 1), 255);
- assert.strictEqual(matrix.get(1, 1), 255);
- });
+ it('testClearMatrix', () => {
+ const matrix = new QRCodeByteMatrix(2, 2);
+ QRCodeMatrixUtil.clearMatrix(matrix);
+ // TYPESCRIPTPORT: we use UintArray se changed here from -1 to 255
+ assert.strictEqual(matrix.get(0, 0), 255);
+ assert.strictEqual(matrix.get(1, 0), 255);
+ assert.strictEqual(matrix.get(0, 1), 255);
+ assert.strictEqual(matrix.get(1, 1), 255);
+ });
- it('testEmbedBasicPatterns1', () => {
- // QRCodeVersion 1.
- const matrix = new QRCodeByteMatrix(21, 21);
- QRCodeMatrixUtil.clearMatrix(matrix);
- QRCodeMatrixUtil.embedBasicPatterns(QRCodeVersion.getVersionForNumber(1), matrix);
- const expected: string =
- ' 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1\n' +
- ' 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n' +
- ' 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n' +
- ' 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n' +
- ' 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n' +
- ' 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n' +
- ' 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n' +
- ' 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
- ' 1 \n' +
- ' 0 \n' +
- ' 1 \n' +
- ' 0 \n' +
- ' 1 \n' +
- ' 0 0 0 0 0 0 0 0 1 \n' +
- ' 1 1 1 1 1 1 1 0 \n' +
- ' 1 0 0 0 0 0 1 0 \n' +
- ' 1 0 1 1 1 0 1 0 \n' +
- ' 1 0 1 1 1 0 1 0 \n' +
- ' 1 0 1 1 1 0 1 0 \n' +
- ' 1 0 0 0 0 0 1 0 \n' +
- ' 1 1 1 1 1 1 1 0 \n';
- assert.strictEqual(matrix.toString(), expected);
- });
+ it('testEmbedBasicPatterns1', () => {
+ // QRCodeVersion 1.
+ const matrix = new QRCodeByteMatrix(21, 21);
+ QRCodeMatrixUtil.clearMatrix(matrix);
+ QRCodeMatrixUtil.embedBasicPatterns(QRCodeVersion.getVersionForNumber(1), matrix);
+ const expected: string =
+ ' 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1\n' +
+ ' 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n' +
+ ' 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n' +
+ ' 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
+ ' 1 \n' +
+ ' 0 \n' +
+ ' 1 \n' +
+ ' 0 \n' +
+ ' 1 \n' +
+ ' 0 0 0 0 0 0 0 0 1 \n' +
+ ' 1 1 1 1 1 1 1 0 \n' +
+ ' 1 0 0 0 0 0 1 0 \n' +
+ ' 1 0 1 1 1 0 1 0 \n' +
+ ' 1 0 1 1 1 0 1 0 \n' +
+ ' 1 0 1 1 1 0 1 0 \n' +
+ ' 1 0 0 0 0 0 1 0 \n' +
+ ' 1 1 1 1 1 1 1 0 \n';
+ assert.strictEqual(matrix.toString(), expected);
+ });
- it('testEmbedBasicPatterns2', () => {
- // QRCodeVersion 2. Position adjustment pattern should apppear at right
- // bottom corner.
- const matrix = new QRCodeByteMatrix(25, 25);
- QRCodeMatrixUtil.clearMatrix(matrix);
- QRCodeMatrixUtil.embedBasicPatterns(QRCodeVersion.getVersionForNumber(2), matrix);
- const expected: string =
- ' 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1\n' +
- ' 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n' +
- ' 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n' +
- ' 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n' +
- ' 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n' +
- ' 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n' +
- ' 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n' +
- ' 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
- ' 1 \n' +
- ' 0 \n' +
- ' 1 \n' +
- ' 0 \n' +
- ' 1 \n' +
- ' 0 \n' +
- ' 1 \n' +
- ' 0 \n' +
- ' 1 1 1 1 1 1 \n' +
- ' 0 0 0 0 0 0 0 0 1 1 0 0 0 1 \n' +
- ' 1 1 1 1 1 1 1 0 1 0 1 0 1 \n' +
- ' 1 0 0 0 0 0 1 0 1 0 0 0 1 \n' +
- ' 1 0 1 1 1 0 1 0 1 1 1 1 1 \n' +
- ' 1 0 1 1 1 0 1 0 \n' +
- ' 1 0 1 1 1 0 1 0 \n' +
- ' 1 0 0 0 0 0 1 0 \n' +
- ' 1 1 1 1 1 1 1 0 \n';
- assert.strictEqual(matrix.toString(), expected);
- });
+ it('testEmbedBasicPatterns2', () => {
+ // QRCodeVersion 2. Position adjustment pattern should apppear at right
+ // bottom corner.
+ const matrix = new QRCodeByteMatrix(25, 25);
+ QRCodeMatrixUtil.clearMatrix(matrix);
+ QRCodeMatrixUtil.embedBasicPatterns(QRCodeVersion.getVersionForNumber(2), matrix);
+ const expected: string =
+ ' 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1\n' +
+ ' 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n' +
+ ' 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n' +
+ ' 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
+ ' 1 \n' +
+ ' 0 \n' +
+ ' 1 \n' +
+ ' 0 \n' +
+ ' 1 \n' +
+ ' 0 \n' +
+ ' 1 \n' +
+ ' 0 \n' +
+ ' 1 1 1 1 1 1 \n' +
+ ' 0 0 0 0 0 0 0 0 1 1 0 0 0 1 \n' +
+ ' 1 1 1 1 1 1 1 0 1 0 1 0 1 \n' +
+ ' 1 0 0 0 0 0 1 0 1 0 0 0 1 \n' +
+ ' 1 0 1 1 1 0 1 0 1 1 1 1 1 \n' +
+ ' 1 0 1 1 1 0 1 0 \n' +
+ ' 1 0 1 1 1 0 1 0 \n' +
+ ' 1 0 0 0 0 0 1 0 \n' +
+ ' 1 1 1 1 1 1 1 0 \n';
+ assert.strictEqual(matrix.toString(), expected);
+ });
- it('testEmbedTypeInfo', () => {
- // Type info bits = 100000011001110.
- const matrix = new QRCodeByteMatrix(21, 21);
- QRCodeMatrixUtil.clearMatrix(matrix);
- QRCodeMatrixUtil.embedTypeInfo(QRCodeDecoderErrorCorrectionLevel.M, 5, matrix);
- const expected: string =
- ' 0 \n' +
- ' 1 \n' +
- ' 1 \n' +
- ' 1 \n' +
- ' 0 \n' +
- ' 0 \n' +
- ' \n' +
- ' 1 \n' +
- ' 1 0 0 0 0 0 0 1 1 1 0 0 1 1 1 0\n' +
- ' \n' +
- ' \n' +
- ' \n' +
- ' \n' +
- ' \n' +
- ' 0 \n' +
- ' 0 \n' +
- ' 0 \n' +
- ' 0 \n' +
- ' 0 \n' +
- ' 0 \n' +
- ' 1 \n';
- assert.strictEqual(matrix.toString(), expected);
- });
+ it('testEmbedTypeInfo', () => {
+ // Type info bits = 100000011001110.
+ const matrix = new QRCodeByteMatrix(21, 21);
+ QRCodeMatrixUtil.clearMatrix(matrix);
+ QRCodeMatrixUtil.embedTypeInfo(QRCodeDecoderErrorCorrectionLevel.M, 5, matrix);
+ const expected: string =
+ ' 0 \n' +
+ ' 1 \n' +
+ ' 1 \n' +
+ ' 1 \n' +
+ ' 0 \n' +
+ ' 0 \n' +
+ ' \n' +
+ ' 1 \n' +
+ ' 1 0 0 0 0 0 0 1 1 1 0 0 1 1 1 0\n' +
+ ' \n' +
+ ' \n' +
+ ' \n' +
+ ' \n' +
+ ' \n' +
+ ' 0 \n' +
+ ' 0 \n' +
+ ' 0 \n' +
+ ' 0 \n' +
+ ' 0 \n' +
+ ' 0 \n' +
+ ' 1 \n';
+ assert.strictEqual(matrix.toString(), expected);
+ });
- it('testEmbedVersionInfo', () => {
- // QRCodeVersion info bits = 000111 110010 010100
- // Actually, version 7 QR Code has 45x45 matrix but we use 21x21 here
- // since 45x45 matrix is too big to depict.
- const matrix = new QRCodeByteMatrix(21, 21);
- QRCodeMatrixUtil.clearMatrix(matrix);
- QRCodeMatrixUtil.maybeEmbedVersionInfo(QRCodeVersion.getVersionForNumber(7), matrix);
- const expected: string =
- ' 0 0 1 \n' +
- ' 0 1 0 \n' +
- ' 0 1 0 \n' +
- ' 0 1 1 \n' +
- ' 1 1 1 \n' +
- ' 0 0 0 \n' +
- ' \n' +
- ' \n' +
- ' \n' +
- ' \n' +
- ' 0 0 0 0 1 0 \n' +
- ' 0 1 1 1 1 0 \n' +
- ' 1 0 0 1 1 0 \n' +
- ' \n' +
- ' \n' +
- ' \n' +
- ' \n' +
- ' \n' +
- ' \n' +
- ' \n' +
- ' \n';
- assert.strictEqual(matrix.toString(), expected);
- });
+ it('testEmbedVersionInfo', () => {
+ // QRCodeVersion info bits = 000111 110010 010100
+ // Actually, version 7 QR Code has 45x45 matrix but we use 21x21 here
+ // since 45x45 matrix is too big to depict.
+ const matrix = new QRCodeByteMatrix(21, 21);
+ QRCodeMatrixUtil.clearMatrix(matrix);
+ QRCodeMatrixUtil.maybeEmbedVersionInfo(QRCodeVersion.getVersionForNumber(7), matrix);
+ const expected: string =
+ ' 0 0 1 \n' +
+ ' 0 1 0 \n' +
+ ' 0 1 0 \n' +
+ ' 0 1 1 \n' +
+ ' 1 1 1 \n' +
+ ' 0 0 0 \n' +
+ ' \n' +
+ ' \n' +
+ ' \n' +
+ ' \n' +
+ ' 0 0 0 0 1 0 \n' +
+ ' 0 1 1 1 1 0 \n' +
+ ' 1 0 0 1 1 0 \n' +
+ ' \n' +
+ ' \n' +
+ ' \n' +
+ ' \n' +
+ ' \n' +
+ ' \n' +
+ ' \n' +
+ ' \n';
+ assert.strictEqual(matrix.toString(), expected);
+ });
- it('testEmbedDataBits', () => {
- // Cells other than basic patterns should be filled with zero.
- const matrix = new QRCodeByteMatrix(21, 21);
- QRCodeMatrixUtil.clearMatrix(matrix);
- QRCodeMatrixUtil.embedBasicPatterns(QRCodeVersion.getVersionForNumber(1), matrix);
- const bits = new BitArray();
- QRCodeMatrixUtil.embedDataBits(bits, 255, matrix);
- const expected: string =
- ' 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1\n' +
- ' 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n' +
- ' 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n' +
- ' 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n' +
- ' 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n' +
- ' 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n' +
- ' 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n' +
- ' 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
- ' 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
- ' 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
- ' 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
- ' 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
- ' 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
- ' 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0\n' +
- ' 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
- ' 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
- ' 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
- ' 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
- ' 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
- ' 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
- ' 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n';
- assert.strictEqual(matrix.toString(), expected);
- });
+ it('testEmbedDataBits', () => {
+ // Cells other than basic patterns should be filled with zero.
+ const matrix = new QRCodeByteMatrix(21, 21);
+ QRCodeMatrixUtil.clearMatrix(matrix);
+ QRCodeMatrixUtil.embedBasicPatterns(QRCodeVersion.getVersionForNumber(1), matrix);
+ const bits = new BitArray();
+ QRCodeMatrixUtil.embedDataBits(bits, 255, matrix);
+ const expected: string =
+ ' 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1\n' +
+ ' 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n' +
+ ' 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n' +
+ ' 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
+ ' 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
+ ' 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
+ ' 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
+ ' 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
+ ' 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
+ ' 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0\n' +
+ ' 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
+ ' 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
+ ' 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
+ ' 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
+ ' 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
+ ' 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n' +
+ ' 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n';
+ assert.strictEqual(matrix.toString(), expected);
+ });
- it('testBuildMatrix', () => {
- // From http://www.swetake.com/qr/qr7.html
- const bytes = Uint16Array.from([32, 65, 205, 69, 41, 220, 46, 128, 236,
- 42, 159, 74, 221, 244, 169, 239, 150, 138,
- 70, 237, 85, 224, 96, 74, 219, 61]);
- const bits = new BitArray();
- for (let i = 0, length = bytes.length; i !== length; i++) {
- const c = bytes[i];
- bits.appendBits(c, 8);
- }
- const matrix = new QRCodeByteMatrix(21, 21);
- QRCodeMatrixUtil.buildMatrix(bits,
- QRCodeDecoderErrorCorrectionLevel.H,
- QRCodeVersion.getVersionForNumber(1), // QRCodeVersion 1
- 3, // Mask pattern 3
- matrix);
- const expected: string =
- ' 1 1 1 1 1 1 1 0 0 1 1 0 0 0 1 1 1 1 1 1 1\n' +
- ' 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n' +
- ' 1 0 1 1 1 0 1 0 0 0 0 1 0 0 1 0 1 1 1 0 1\n' +
- ' 1 0 1 1 1 0 1 0 0 1 1 0 0 0 1 0 1 1 1 0 1\n' +
- ' 1 0 1 1 1 0 1 0 1 1 0 0 1 0 1 0 1 1 1 0 1\n' +
- ' 1 0 0 0 0 0 1 0 0 0 1 1 1 0 1 0 0 0 0 0 1\n' +
- ' 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n' +
- ' 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0\n' +
- ' 0 0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1 0 0 0 0\n' +
- ' 1 0 1 0 1 0 0 0 0 0 1 1 1 0 0 1 0 1 1 1 0\n' +
- ' 1 1 1 1 0 1 1 0 1 0 1 1 1 0 0 1 1 1 0 1 0\n' +
- ' 1 0 1 0 1 1 0 1 1 1 0 0 1 1 1 0 0 1 0 1 0\n' +
- ' 0 0 1 0 0 1 1 1 0 0 0 0 0 0 1 0 1 1 1 1 1\n' +
- ' 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 1 0 1 1\n' +
- ' 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 0 1 0 1 1 0\n' +
- ' 1 0 0 0 0 0 1 0 0 0 0 1 0 1 1 1 0 0 0 0 0\n' +
- ' 1 0 1 1 1 0 1 0 0 1 0 0 1 1 0 0 1 0 0 1 1\n' +
- ' 1 0 1 1 1 0 1 0 1 1 0 1 0 0 0 0 0 1 1 1 0\n' +
- ' 1 0 1 1 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 0 0\n' +
- ' 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0\n' +
- ' 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 0 1 0 0 1 0\n';
- assert.strictEqual(matrix.toString(), expected);
- });
+ it('testBuildMatrix', () => {
+ // From http://www.swetake.com/qr/qr7.html
+ const bytes = Uint16Array.from([32, 65, 205, 69, 41, 220, 46, 128, 236,
+ 42, 159, 74, 221, 244, 169, 239, 150, 138,
+ 70, 237, 85, 224, 96, 74, 219, 61]);
+ const bits = new BitArray();
+ for (let i = 0, length = bytes.length; i !== length; i++) {
+ const c = bytes[i];
+ bits.appendBits(c, 8);
+ }
+ const matrix = new QRCodeByteMatrix(21, 21);
+ QRCodeMatrixUtil.buildMatrix(bits,
+ QRCodeDecoderErrorCorrectionLevel.H,
+ QRCodeVersion.getVersionForNumber(1), // QRCodeVersion 1
+ 3, // Mask pattern 3
+ matrix);
+ const expected: string =
+ ' 1 1 1 1 1 1 1 0 0 1 1 0 0 0 1 1 1 1 1 1 1\n' +
+ ' 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 0 0 0 1 0 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 0 1 1 0 0 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 1 1 1 0 1 0 1 1 0 0 1 0 1 0 1 1 1 0 1\n' +
+ ' 1 0 0 0 0 0 1 0 0 0 1 1 1 0 1 0 0 0 0 0 1\n' +
+ ' 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n' +
+ ' 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0\n' +
+ ' 0 0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1 0 0 0 0\n' +
+ ' 1 0 1 0 1 0 0 0 0 0 1 1 1 0 0 1 0 1 1 1 0\n' +
+ ' 1 1 1 1 0 1 1 0 1 0 1 1 1 0 0 1 1 1 0 1 0\n' +
+ ' 1 0 1 0 1 1 0 1 1 1 0 0 1 1 1 0 0 1 0 1 0\n' +
+ ' 0 0 1 0 0 1 1 1 0 0 0 0 0 0 1 0 1 1 1 1 1\n' +
+ ' 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 1 0 1 1\n' +
+ ' 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 0 1 0 1 1 0\n' +
+ ' 1 0 0 0 0 0 1 0 0 0 0 1 0 1 1 1 0 0 0 0 0\n' +
+ ' 1 0 1 1 1 0 1 0 0 1 0 0 1 1 0 0 1 0 0 1 1\n' +
+ ' 1 0 1 1 1 0 1 0 1 1 0 1 0 0 0 0 0 1 1 1 0\n' +
+ ' 1 0 1 1 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 0 0\n' +
+ ' 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0\n' +
+ ' 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 0 1 0 0 1 0\n';
+ assert.strictEqual(matrix.toString(), expected);
+ });
- it('testFindMSBSet', () => {
- assert.strictEqual(QRCodeMatrixUtil.findMSBSet(0), 0);
- assert.strictEqual(QRCodeMatrixUtil.findMSBSet(1), 1);
- assert.strictEqual(QRCodeMatrixUtil.findMSBSet(0x80), 8);
- assert.strictEqual(QRCodeMatrixUtil.findMSBSet(0x80000000), 32);
- });
+ it('testFindMSBSet', () => {
+ assert.strictEqual(QRCodeMatrixUtil.findMSBSet(0), 0);
+ assert.strictEqual(QRCodeMatrixUtil.findMSBSet(1), 1);
+ assert.strictEqual(QRCodeMatrixUtil.findMSBSet(0x80), 8);
+ assert.strictEqual(QRCodeMatrixUtil.findMSBSet(0x80000000), 32);
+ });
- it('testCalculateBCHCode', () => {
- // Encoding of type information.
- // From Appendix C in JISX0510:2004 (p 65)
- assert.strictEqual(QRCodeMatrixUtil.calculateBCHCode(5, 0x537), 0xdc);
- // From http://www.swetake.com/qr/qr6.html
- assert.strictEqual(QRCodeMatrixUtil.calculateBCHCode(0x13, 0x537), 0x1c2);
- // From http://www.swetake.com/qr/qr11.html
- assert.strictEqual(QRCodeMatrixUtil.calculateBCHCode(0x1b, 0x537), 0x214);
+ it('testCalculateBCHCode', () => {
+ // Encoding of type information.
+ // From Appendix C in JISX0510:2004 (p 65)
+ assert.strictEqual(QRCodeMatrixUtil.calculateBCHCode(5, 0x537), 0xdc);
+ // From http://www.swetake.com/qr/qr6.html
+ assert.strictEqual(QRCodeMatrixUtil.calculateBCHCode(0x13, 0x537), 0x1c2);
+ // From http://www.swetake.com/qr/qr11.html
+ assert.strictEqual(QRCodeMatrixUtil.calculateBCHCode(0x1b, 0x537), 0x214);
- // Encoding of version information.
- // From Appendix D in JISX0510:2004 (p 68)
- assert.strictEqual(QRCodeMatrixUtil.calculateBCHCode(7, 0x1f25), 0xc94);
- assert.strictEqual(QRCodeMatrixUtil.calculateBCHCode(8, 0x1f25), 0x5bc);
- assert.strictEqual(QRCodeMatrixUtil.calculateBCHCode(9, 0x1f25), 0xa99);
- assert.strictEqual(QRCodeMatrixUtil.calculateBCHCode(10, 0x1f25), 0x4d3);
- assert.strictEqual(QRCodeMatrixUtil.calculateBCHCode(20, 0x1f25), 0x9a6);
- assert.strictEqual(QRCodeMatrixUtil.calculateBCHCode(30, 0x1f25), 0xd75);
- assert.strictEqual(QRCodeMatrixUtil.calculateBCHCode(40, 0x1f25), 0xc69);
- });
+ // Encoding of version information.
+ // From Appendix D in JISX0510:2004 (p 68)
+ assert.strictEqual(QRCodeMatrixUtil.calculateBCHCode(7, 0x1f25), 0xc94);
+ assert.strictEqual(QRCodeMatrixUtil.calculateBCHCode(8, 0x1f25), 0x5bc);
+ assert.strictEqual(QRCodeMatrixUtil.calculateBCHCode(9, 0x1f25), 0xa99);
+ assert.strictEqual(QRCodeMatrixUtil.calculateBCHCode(10, 0x1f25), 0x4d3);
+ assert.strictEqual(QRCodeMatrixUtil.calculateBCHCode(20, 0x1f25), 0x9a6);
+ assert.strictEqual(QRCodeMatrixUtil.calculateBCHCode(30, 0x1f25), 0xd75);
+ assert.strictEqual(QRCodeMatrixUtil.calculateBCHCode(40, 0x1f25), 0xc69);
+ });
- // We don't test a lot of cases in this function since we've already
- // tested them in TEST(calculateBCHCode).
- it('testMakeVersionInfoBits', () => {
- // From Appendix D in JISX0510:2004 (p 68)
- const bits = new BitArray();
- QRCodeMatrixUtil.makeVersionInfoBits(QRCodeVersion.getVersionForNumber(7), bits);
- assert.strictEqual(bits.toString(), ' ...XXXXX ..X..X.X ..');
- });
+ // We don't test a lot of cases in this function since we've already
+ // tested them in TEST(calculateBCHCode).
+ it('testMakeVersionInfoBits', () => {
+ // From Appendix D in JISX0510:2004 (p 68)
+ const bits = new BitArray();
+ QRCodeMatrixUtil.makeVersionInfoBits(QRCodeVersion.getVersionForNumber(7), bits);
+ assert.strictEqual(bits.toString(), ' ...XXXXX ..X..X.X ..');
+ });
- // We don't test a lot of cases in this function since we've already
- // tested them in TEST(calculateBCHCode).
- it('testMakeTypeInfoInfoBits', () => {
- // From Appendix C in JISX0510:2004 (p 65)
- const bits = new BitArray();
- QRCodeMatrixUtil.makeTypeInfoBits(QRCodeDecoderErrorCorrectionLevel.M, 5, bits);
- assert.strictEqual(bits.toString(), ' X......X X..XXX.');
- });
+ // We don't test a lot of cases in this function since we've already
+ // tested them in TEST(calculateBCHCode).
+ it('testMakeTypeInfoInfoBits', () => {
+ // From Appendix C in JISX0510:2004 (p 65)
+ const bits = new BitArray();
+ QRCodeMatrixUtil.makeTypeInfoBits(QRCodeDecoderErrorCorrectionLevel.M, 5, bits);
+ assert.strictEqual(bits.toString(), ' X......X X..XXX.');
+ });
});
diff --git a/src/test/core/qrcode/encoder/QRCode.spec.ts b/src/test/core/qrcode/encoder/QRCode.spec.ts
index 06c10617..dc823f84 100644
--- a/src/test/core/qrcode/encoder/QRCode.spec.ts
+++ b/src/test/core/qrcode/encoder/QRCode.spec.ts
@@ -29,97 +29,97 @@ import { QRCodeByteMatrix } from '@zxing/library';
*/
describe('QRCodeEncoderQRCode', () => {
- it('test', () => {
- const qrCode = new QRCodeEncoderQRCode();
+ it('test', () => {
+ const qrCode = new QRCodeEncoderQRCode();
- // First, test simple setters and getters.
- // We use numbers of version 7-H.
- qrCode.setMode(QRCodeMode.BYTE);
- qrCode.setECLevel(QRCodeDecoderErrorCorrectionLevel.H);
- qrCode.setVersion(QRCodeVersion.getVersionForNumber(7));
- qrCode.setMaskPattern(3);
+ // First, test simple setters and getters.
+ // We use numbers of version 7-H.
+ qrCode.setMode(QRCodeMode.BYTE);
+ qrCode.setECLevel(QRCodeDecoderErrorCorrectionLevel.H);
+ qrCode.setVersion(QRCodeVersion.getVersionForNumber(7));
+ qrCode.setMaskPattern(3);
- assert.strictEqual(QRCodeMode.BYTE.equals(qrCode.getMode()), true);
- assert.strictEqual(QRCodeDecoderErrorCorrectionLevel.H.equals(qrCode.getECLevel()), true);
- assert.strictEqual(qrCode.getVersion().getVersionNumber(), 7);
- assert.strictEqual(qrCode.getMaskPattern(), 3);
+ assert.strictEqual(QRCodeMode.BYTE.equals(qrCode.getMode()), true);
+ assert.strictEqual(QRCodeDecoderErrorCorrectionLevel.H.equals(qrCode.getECLevel()), true);
+ assert.strictEqual(qrCode.getVersion().getVersionNumber(), 7);
+ assert.strictEqual(qrCode.getMaskPattern(), 3);
- // Prepare the matrix.
- const matrix = new QRCodeByteMatrix(45, 45);
- // Just set bogus zero/one values.
- for (let y: number /*int*/ = 0; y < 45; ++y) {
- for (let x: number /*int*/ = 0; x < 45; ++x) {
- matrix.setNumber(x, y, (y + x) % 2);
- }
- }
+ // Prepare the matrix.
+ const matrix = new QRCodeByteMatrix(45, 45);
+ // Just set bogus zero/one values.
+ for (let y: number /*int*/ = 0; y < 45; ++y) {
+ for (let x: number /*int*/ = 0; x < 45; ++x) {
+ matrix.setNumber(x, y, (y + x) % 2);
+ }
+ }
- // Set the matrix.
- qrCode.setMatrix(matrix);
- assert.strictEqual(matrix.equals(qrCode.getMatrix()), true);
- });
+ // Set the matrix.
+ qrCode.setMatrix(matrix);
+ assert.strictEqual(matrix.equals(qrCode.getMatrix()), true);
+ });
- it('testToString1', () => {
- const qrCode = new QRCodeEncoderQRCode();
- const expected: string =
- '<<\n' +
- ' mode: null\n' +
- ' ecLevel: null\n' +
- ' version: null\n' +
- ' maskPattern: -1\n' +
- ' matrix: null\n' +
- '>>\n';
- assert.strictEqual(qrCode.toString(), expected);
- });
+ it('testToString1', () => {
+ const qrCode = new QRCodeEncoderQRCode();
+ const expected: string =
+ '<<\n' +
+ ' mode: null\n' +
+ ' ecLevel: null\n' +
+ ' version: null\n' +
+ ' maskPattern: -1\n' +
+ ' matrix: null\n' +
+ '>>\n';
+ assert.strictEqual(qrCode.toString(), expected);
+ });
- it('testToString2', () => {
- const qrCode = new QRCodeEncoderQRCode();
- qrCode.setMode(QRCodeMode.BYTE);
- qrCode.setECLevel(QRCodeDecoderErrorCorrectionLevel.H);
- qrCode.setVersion(QRCodeVersion.getVersionForNumber(1));
- qrCode.setMaskPattern(3);
- const matrix = new QRCodeByteMatrix(21, 21);
- for (let y: number /*int*/ = 0; y < 21; ++y) {
- for (let x: number /*int*/ = 0; x < 21; ++x) {
- matrix.setNumber(x, y, (y + x) % 2);
- }
- }
- qrCode.setMatrix(matrix);
- const expected: string = '<<\n' +
- ' mode: BYTE\n' +
- ' ecLevel: H\n' +
- ' version: 1\n' +
- ' maskPattern: 3\n' +
- ' matrix:\n' +
- ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
- ' 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n' +
- ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
- ' 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n' +
- ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
- ' 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n' +
- ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
- ' 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n' +
- ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
- ' 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n' +
- ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
- ' 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n' +
- ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
- ' 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n' +
- ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
- ' 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n' +
- ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
- ' 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n' +
- ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
- ' 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n' +
- ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
- '>>\n';
- assert.strictEqual(qrCode.toString(), expected);
- });
+ it('testToString2', () => {
+ const qrCode = new QRCodeEncoderQRCode();
+ qrCode.setMode(QRCodeMode.BYTE);
+ qrCode.setECLevel(QRCodeDecoderErrorCorrectionLevel.H);
+ qrCode.setVersion(QRCodeVersion.getVersionForNumber(1));
+ qrCode.setMaskPattern(3);
+ const matrix = new QRCodeByteMatrix(21, 21);
+ for (let y: number /*int*/ = 0; y < 21; ++y) {
+ for (let x: number /*int*/ = 0; x < 21; ++x) {
+ matrix.setNumber(x, y, (y + x) % 2);
+ }
+ }
+ qrCode.setMatrix(matrix);
+ const expected: string = '<<\n' +
+ ' mode: BYTE\n' +
+ ' ecLevel: H\n' +
+ ' version: 1\n' +
+ ' maskPattern: 3\n' +
+ ' matrix:\n' +
+ ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
+ ' 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n' +
+ ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
+ ' 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n' +
+ ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
+ ' 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n' +
+ ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
+ ' 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n' +
+ ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
+ ' 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n' +
+ ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
+ ' 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n' +
+ ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
+ ' 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n' +
+ ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
+ ' 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n' +
+ ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
+ ' 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n' +
+ ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
+ ' 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n' +
+ ' 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n' +
+ '>>\n';
+ assert.strictEqual(qrCode.toString(), expected);
+ });
- it('testIsValidMaskPattern', () => {
- assert.strictEqual(QRCodeEncoderQRCode.isValidMaskPattern(-1), false);
- assert.strictEqual(QRCodeEncoderQRCode.isValidMaskPattern(0), true);
- assert.strictEqual(QRCodeEncoderQRCode.isValidMaskPattern(7), true);
- assert.strictEqual(QRCodeEncoderQRCode.isValidMaskPattern(8), false);
- });
+ it('testIsValidMaskPattern', () => {
+ assert.strictEqual(QRCodeEncoderQRCode.isValidMaskPattern(-1), false);
+ assert.strictEqual(QRCodeEncoderQRCode.isValidMaskPattern(0), true);
+ assert.strictEqual(QRCodeEncoderQRCode.isValidMaskPattern(7), true);
+ assert.strictEqual(QRCodeEncoderQRCode.isValidMaskPattern(8), false);
+ });
});
diff --git a/src/test/core/util/Pattern.ts b/src/test/core/util/Pattern.ts
index a2e66ac2..cafaa5a1 100644
--- a/src/test/core/util/Pattern.ts
+++ b/src/test/core/util/Pattern.ts
@@ -3,8 +3,8 @@
*/
export class Pattern extends RegExp {
- static compile(regexp: string): Pattern {
- throw new Pattern(regexp);
- }
+ static compile(regexp: string): Pattern {
+ throw new Pattern(regexp);
+ }
}
diff --git a/src/test/core/util/textEncodingFactory.ts b/src/test/core/util/textEncodingFactory.ts
index 9d206834..42aedcc3 100644
--- a/src/test/core/util/textEncodingFactory.ts
+++ b/src/test/core/util/textEncodingFactory.ts
@@ -1,4 +1,4 @@
-import { TextEncoder, TextDecoder } from '@zxing/text-encoding';
+import { TextEncoder, TextDecoder } from '@zxing/text-encoding';
export function createCustomEncoder(e: string) {
return new TextEncoder(e, { NONSTANDARD_allowLegacyEncoding: true });
diff --git a/src/test/resources/blackbox/code39-1/2.txt b/src/test/resources/blackbox/code39-1/2.txt
index 4ed0aa93..81201959 100644
--- a/src/test/resources/blackbox/code39-1/2.txt
+++ b/src/test/resources/blackbox/code39-1/2.txt
@@ -1 +1 @@
- WWW.CITRONSOFT.COM
\ No newline at end of file
+ WWW.CITRONSOFT.COM
\ No newline at end of file
diff --git a/src/test/resources/blackbox/qrcode-2/16.txt b/src/test/resources/blackbox/qrcode-2/16.txt
index dbc55c97..987e5285 100644
--- a/src/test/resources/blackbox/qrcode-2/16.txt
+++ b/src/test/resources/blackbox/qrcode-2/16.txt
@@ -1,4 +1,4 @@
[ε€ε΄QRγ³γΌγ]
-
+
*οΎοΎοΎοΎοΎQR*
http://d-qr.net/ex/
\ No newline at end of file
diff --git a/src/test/resources/blackbox/qrcode-2/18.txt b/src/test/resources/blackbox/qrcode-2/18.txt
index cf5ad11a..f7e21bc3 100644
--- a/src/test/resources/blackbox/qrcode-2/18.txt
+++ b/src/test/resources/blackbox/qrcode-2/18.txt
@@ -1,2 +1,2 @@
-*οΎοΎο½»οΎο½²οΎQR*
-http://d-qr.net/ex/
\ No newline at end of file
+*οΎοΎο½»οΎο½²οΎQR*
+http://d-qr.net/ex/
\ No newline at end of file
diff --git a/src/test/resources/blackbox/qrcode-2/19.txt b/src/test/resources/blackbox/qrcode-2/19.txt
index 77fa955b..f7e21bc3 100644
--- a/src/test/resources/blackbox/qrcode-2/19.txt
+++ b/src/test/resources/blackbox/qrcode-2/19.txt
@@ -1,2 +1,2 @@
-*οΎοΎο½»οΎο½²οΎQR*
-http://d-qr.net/ex/
\ No newline at end of file
+*οΎοΎο½»οΎο½²οΎQR*
+http://d-qr.net/ex/
\ No newline at end of file
diff --git a/src/test/resources/blackbox/qrcode-2/20.txt b/src/test/resources/blackbox/qrcode-2/20.txt
index 89924f15..f7e21bc3 100644
--- a/src/test/resources/blackbox/qrcode-2/20.txt
+++ b/src/test/resources/blackbox/qrcode-2/20.txt
@@ -1,2 +1,2 @@
*οΎοΎο½»οΎο½²οΎQR*
-http://d-qr.net/ex/
\ No newline at end of file
+http://d-qr.net/ex/
\ No newline at end of file
diff --git a/src/test/resources/blackbox/qrcode-2/21.txt b/src/test/resources/blackbox/qrcode-2/21.txt
index cde88706..f7e21bc3 100644
--- a/src/test/resources/blackbox/qrcode-2/21.txt
+++ b/src/test/resources/blackbox/qrcode-2/21.txt
@@ -1,2 +1,2 @@
-*οΎοΎο½»οΎο½²οΎQR*
-http://d-qr.net/ex/
\ No newline at end of file
+*οΎοΎο½»οΎο½²οΎQR*
+http://d-qr.net/ex/
\ No newline at end of file
diff --git a/src/test/resources/blackbox/qrcode-2/23.txt b/src/test/resources/blackbox/qrcode-2/23.txt
index c7cd5be8..24a2d6fc 100644
--- a/src/test/resources/blackbox/qrcode-2/23.txt
+++ b/src/test/resources/blackbox/qrcode-2/23.txt
@@ -1 +1 @@
-http://aniful.jp/pr/
\ No newline at end of file
+http://aniful.jp/pr/
\ No newline at end of file
diff --git a/src/test/resources/blackbox/qrcode-2/24.txt b/src/test/resources/blackbox/qrcode-2/24.txt
index 831780b0..f7e21bc3 100644
--- a/src/test/resources/blackbox/qrcode-2/24.txt
+++ b/src/test/resources/blackbox/qrcode-2/24.txt
@@ -1,2 +1,2 @@
-*οΎοΎο½»οΎο½²οΎQR*
-http://d-qr.net/ex/
\ No newline at end of file
+*οΎοΎο½»οΎο½²οΎQR*
+http://d-qr.net/ex/
\ No newline at end of file
diff --git a/src/test/resources/blackbox/qrcode-2/26.txt b/src/test/resources/blackbox/qrcode-2/26.txt
index d7833014..9c7d7640 100644
--- a/src/test/resources/blackbox/qrcode-2/26.txt
+++ b/src/test/resources/blackbox/qrcode-2/26.txt
@@ -1,3 +1,3 @@
-<οΎοΎο½»οΎο½²οΎQR>
+<οΎοΎο½»οΎο½²οΎQR>
ο½²οΎο½½οΎε ₯γο½ΆοΎο½°QRο½Ίο½°οΎοΎ
-http://d-qr.net/ex/
\ No newline at end of file
+http://d-qr.net/ex/
\ No newline at end of file
diff --git a/src/test/resources/blackbox/qrcode-2/27.txt b/src/test/resources/blackbox/qrcode-2/27.txt
index a73039ab..f7e21bc3 100644
--- a/src/test/resources/blackbox/qrcode-2/27.txt
+++ b/src/test/resources/blackbox/qrcode-2/27.txt
@@ -1,2 +1,2 @@
-*οΎοΎο½»οΎο½²οΎQR*
-http://d-qr.net/ex/
\ No newline at end of file
+*οΎοΎο½»οΎο½²οΎQR*
+http://d-qr.net/ex/
\ No newline at end of file
diff --git a/src/test/resources/blackbox/qrcode-2/29.txt b/src/test/resources/blackbox/qrcode-2/29.txt
index 1c875b59..c978cbcb 100644
--- a/src/test/resources/blackbox/qrcode-2/29.txt
+++ b/src/test/resources/blackbox/qrcode-2/29.txt
@@ -1,3 +1,3 @@
-http://live.fdgm.jp/u/event/hype/hype_top.html
+http://live.fdgm.jp/u/event/hype/hype_top.html
MEBKM:TITLE:hypeγ’γγ€γ«;URL:http\://live.fdgm.jp/u/event/hype/hype_top.html;;
\ No newline at end of file
diff --git a/src/test/resources/blackbox/qrcode-3/18.txt b/src/test/resources/blackbox/qrcode-3/18.txt
index 16ac1fdd..f65710f7 100644
--- a/src/test/resources/blackbox/qrcode-3/18.txt
+++ b/src/test/resources/blackbox/qrcode-3/18.txt
@@ -1,2 +1,2 @@
UI office hours signup
-http://www.corp.google.com/sparrow/ui_office_hours/
+http://www.corp.google.com/sparrow/ui_office_hours/
diff --git a/src/test/resources/blackbox/qrcode-3/19.txt b/src/test/resources/blackbox/qrcode-3/19.txt
index 16ac1fdd..f65710f7 100644
--- a/src/test/resources/blackbox/qrcode-3/19.txt
+++ b/src/test/resources/blackbox/qrcode-3/19.txt
@@ -1,2 +1,2 @@
UI office hours signup
-http://www.corp.google.com/sparrow/ui_office_hours/
+http://www.corp.google.com/sparrow/ui_office_hours/
diff --git a/src/test/resources/blackbox/qrcode-3/20.txt b/src/test/resources/blackbox/qrcode-3/20.txt
index 16ac1fdd..f65710f7 100644
--- a/src/test/resources/blackbox/qrcode-3/20.txt
+++ b/src/test/resources/blackbox/qrcode-3/20.txt
@@ -1,2 +1,2 @@
UI office hours signup
-http://www.corp.google.com/sparrow/ui_office_hours/
+http://www.corp.google.com/sparrow/ui_office_hours/
diff --git a/src/test/resources/blackbox/qrcode-3/21.txt b/src/test/resources/blackbox/qrcode-3/21.txt
index 16ac1fdd..f65710f7 100644
--- a/src/test/resources/blackbox/qrcode-3/21.txt
+++ b/src/test/resources/blackbox/qrcode-3/21.txt
@@ -1,2 +1,2 @@
UI office hours signup
-http://www.corp.google.com/sparrow/ui_office_hours/
+http://www.corp.google.com/sparrow/ui_office_hours/
diff --git a/src/test/resources/blackbox/qrcode-3/22.txt b/src/test/resources/blackbox/qrcode-3/22.txt
index 16ac1fdd..f65710f7 100644
--- a/src/test/resources/blackbox/qrcode-3/22.txt
+++ b/src/test/resources/blackbox/qrcode-3/22.txt
@@ -1,2 +1,2 @@
UI office hours signup
-http://www.corp.google.com/sparrow/ui_office_hours/
+http://www.corp.google.com/sparrow/ui_office_hours/
diff --git a/src/test/resources/blackbox/qrcode-3/23.txt b/src/test/resources/blackbox/qrcode-3/23.txt
index 16ac1fdd..f65710f7 100644
--- a/src/test/resources/blackbox/qrcode-3/23.txt
+++ b/src/test/resources/blackbox/qrcode-3/23.txt
@@ -1,2 +1,2 @@
UI office hours signup
-http://www.corp.google.com/sparrow/ui_office_hours/
+http://www.corp.google.com/sparrow/ui_office_hours/
diff --git a/src/test/resources/blackbox/qrcode-3/24.txt b/src/test/resources/blackbox/qrcode-3/24.txt
index 16ac1fdd..f65710f7 100644
--- a/src/test/resources/blackbox/qrcode-3/24.txt
+++ b/src/test/resources/blackbox/qrcode-3/24.txt
@@ -1,2 +1,2 @@
UI office hours signup
-http://www.corp.google.com/sparrow/ui_office_hours/
+http://www.corp.google.com/sparrow/ui_office_hours/
diff --git a/src/test/resources/blackbox/qrcode-3/25.txt b/src/test/resources/blackbox/qrcode-3/25.txt
index 16ac1fdd..f65710f7 100644
--- a/src/test/resources/blackbox/qrcode-3/25.txt
+++ b/src/test/resources/blackbox/qrcode-3/25.txt
@@ -1,2 +1,2 @@
UI office hours signup
-http://www.corp.google.com/sparrow/ui_office_hours/
+http://www.corp.google.com/sparrow/ui_office_hours/
diff --git a/src/test/resources/blackbox/qrcode-5/17.txt b/src/test/resources/blackbox/qrcode-5/17.txt
index 967a10ba..b43b710a 100644
--- a/src/test/resources/blackbox/qrcode-5/17.txt
+++ b/src/test/resources/blackbox/qrcode-5/17.txt
@@ -43,4 +43,4 @@ might.
'Do you know what to-morrow is, Kitty?' Alice began. 'You'd have guessed
if you'd been up in the window with me--only Dinah was making you tidy,
so you couldn't. I was watching the boys getting in sticks for the
-bonfire--and it wants plenty of sticks, Kitty! Only it
+bonfire--and it wants plenty of sticks, Kitty! Only it
From 6a59476aa7e19f8bbde4cc2b0029540d1a38cb6a Mon Sep 17 00:00:00 2001
From: Erik Hughes
Date: Sun, 15 Nov 2020 11:58:42 +0100
Subject: [PATCH 05/53] refactor: migrated docs to browser package
---
docs/examples/aztec-camera/index.html | 116 ------------
docs/examples/barcode-camera/index.html | 115 ------------
docs/examples/barcode-image/index.html | 138 --------------
docs/examples/datamatrix-image/index.html | 125 -------------
docs/examples/multi-camera/index.html | 121 -------------
docs/examples/multi-image/index.html | 81 ---------
docs/examples/pdf417-image/index.html | 127 -------------
docs/examples/qr-camera/index.html | 169 ------------------
docs/examples/qr-image/index.html | 81 ---------
docs/examples/qr-svg-writer/index.html | 84 ---------
docs/examples/qr-video/index.html | 97 ----------
docs/index.html | 104 -----------
docs/resources/blackbox/code128-1/1.png | Bin 466484 -> 0 bytes
.../blackbox/datamatrix/0123456789.png | Bin 483 -> 0 bytes
docs/resources/blackbox/datamatrix/17.png | Bin 29985 -> 0 bytes
.../blackbox/datamatrix/abcdefg-64x64.png | Bin 1065 -> 0 bytes
docs/resources/blackbox/ean13-1/1.png | Bin 466484 -> 0 bytes
docs/resources/blackbox/itf/1.png | Bin 542 -> 0 bytes
docs/resources/blackbox/pdf417-2/05.png | Bin 45233 -> 0 bytes
docs/resources/blackbox/pdf417-2/15.png | Bin 47543 -> 0 bytes
docs/resources/blackbox/pdf417-3/08.png | Bin 143122 -> 0 bytes
docs/resources/blackbox/qrcode-3/01.png | Bin 43446 -> 0 bytes
docs/resources/qrcode-video.mp4 | Bin 1947520 -> 0 bytes
23 files changed, 1358 deletions(-)
delete mode 100644 docs/examples/aztec-camera/index.html
delete mode 100644 docs/examples/barcode-camera/index.html
delete mode 100644 docs/examples/barcode-image/index.html
delete mode 100644 docs/examples/datamatrix-image/index.html
delete mode 100644 docs/examples/multi-camera/index.html
delete mode 100644 docs/examples/multi-image/index.html
delete mode 100644 docs/examples/pdf417-image/index.html
delete mode 100644 docs/examples/qr-camera/index.html
delete mode 100644 docs/examples/qr-image/index.html
delete mode 100644 docs/examples/qr-svg-writer/index.html
delete mode 100644 docs/examples/qr-video/index.html
delete mode 100644 docs/index.html
delete mode 100644 docs/resources/blackbox/code128-1/1.png
delete mode 100644 docs/resources/blackbox/datamatrix/0123456789.png
delete mode 100644 docs/resources/blackbox/datamatrix/17.png
delete mode 100644 docs/resources/blackbox/datamatrix/abcdefg-64x64.png
delete mode 100644 docs/resources/blackbox/ean13-1/1.png
delete mode 100644 docs/resources/blackbox/itf/1.png
delete mode 100644 docs/resources/blackbox/pdf417-2/05.png
delete mode 100644 docs/resources/blackbox/pdf417-2/15.png
delete mode 100644 docs/resources/blackbox/pdf417-3/08.png
delete mode 100644 docs/resources/blackbox/qrcode-3/01.png
delete mode 100644 docs/resources/qrcode-video.mp4
diff --git a/docs/examples/aztec-camera/index.html b/docs/examples/aztec-camera/index.html
deleted file mode 100644
index 858ef9fc..00000000
--- a/docs/examples/aztec-camera/index.html
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
-
-
-
- ZXing TypeScript | Decoding from camera stream
-
-
-
-
-
-
-
-
-
-
-
-
This example shows how to scan an Aztec code with ZXing javascript library from the device video camera. If more
- than one video input devices are available (for example front and back camera) the example shows how to read
- them and use a select to change the input device.
- This example shows how to scan a barcode with ZXing javascript library from the device video camera. If more
- than one video input devices are available (for example front and back camera) the example shows how to read
- them and use a select to change the input device.
-
- These examples show how to scan a barcode with ZXing javascript library from an image. The examples decode from
- the
- src in
- img tag, however is also possible to decode directly from an url without an
- img tag.
-
- This example shows how to scan a Data Matrix with ZXing javascript library from an image.
- The example decodes from the
- src in
- img tag, however is also possible to decode directly from an url without an
- img tag.
-
This example shows how to scan any supported 1D/2D code with ZXing javascript library from the device video
- camera. If more
- than one video input devices are available (for example front and back camera) the example shows how to read
- them and use a select to change the input device.
- This example shows how to scan any supported 1D/2D code with ZXing javascript library from an image.
- The example decodes from the
- src in
- img tag, however is also possible to decode directly from an url without an
- img tag.
-
- This example shows how to scan a PDF 417 with ZXing javascript library from an image.
- The example decodes from the
- src in
- img tag, however is also possible to decode directly from an url without an
- img tag.
-
This example shows how to scan a QR code with ZXing javascript library from the device video camera. If more
- than one video input devices are available (for example front and back camera) the example shows how to read
- them and use a select to change the input device.
- This example shows how to scan a QR code with ZXing javascript library from an image.
- The example decodes from the
- src in
- img tag, however is also possible to decode directly from an url without an
- img tag.
-
- This example shows how to scan a QR code with ZXing javascript library from a video file. The example decodes
- from an url and shows the video while decoding, however is also possbile to decode without showing the video.
-