@zxing/library
Version:
TypeScript port of ZXing multi-format 1D/2D barcode image processing library.
1,254 lines (1,224 loc) • 1.22 MB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ZXing = {}));
})(this, (function (exports) { 'use strict';
function fixProto(target, prototype) {
var setPrototypeOf = Object.setPrototypeOf;
setPrototypeOf ? setPrototypeOf(target, prototype) : target.__proto__ = prototype;
}
function fixStack(target, fn) {
if (fn === void 0) {
fn = target.constructor;
}
var captureStackTrace = Error.captureStackTrace;
captureStackTrace && captureStackTrace(target, fn);
}
var __extends = function () {
var _extendStatics = function extendStatics(d, b) {
_extendStatics = Object.setPrototypeOf || {
__proto__: []
} instanceof Array && function (d, b) {
d.__proto__ = b;
} || function (d, b) {
for (var p in b) {
if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p];
}
};
return _extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
_extendStatics(d, b);
function __() {
this.constructor = d;
}
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
}();
var CustomError = function (_super) {
__extends(CustomError, _super);
function CustomError(message, options) {
var _newTarget = this.constructor;
var _this = _super.call(this, message, options) || this;
Object.defineProperty(_this, 'name', {
value: _newTarget.name,
enumerable: false,
configurable: true
});
fixProto(_this, _newTarget.prototype);
fixStack(_this);
return _this;
}
return CustomError;
}(Error);
/**
* Custom Error class of type Exception.
*/
class Exception extends CustomError {
/**
* Allows Exception to be constructed directly
* with some message and prototype definition.
*/
constructor(message = undefined) {
super(message);
this.message = message;
}
getKind() {
const ex = this.constructor;
return ex.kind;
}
}
/**
* It's typed as string so it can be extended and overriden.
*/
Exception.kind = 'Exception';
/**
* Custom Error class of type Exception.
*/
class ArgumentException extends Exception {
}
ArgumentException.kind = 'ArgumentException';
/**
* Custom Error class of type Exception.
*/
class IllegalArgumentException extends Exception {
}
IllegalArgumentException.kind = 'IllegalArgumentException';
/*
* Copyright 2009 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class BinaryBitmap {
constructor(binarizer) {
this.binarizer = binarizer;
if (binarizer === null) {
throw new IllegalArgumentException('Binarizer must be non-null.');
}
}
/**
* @return The width of the bitmap.
*/
getWidth() {
return this.binarizer.getWidth();
}
/**
* @return The height of the bitmap.
*/
getHeight() {
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
*/
getBlackRow(y /*int*/, row) {
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
*/
getBlackMatrix() {
// 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.
*/
isCropSupported() {
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.
*/
crop(left /*int*/, top /*int*/, width /*int*/, height /*int*/) {
const newSource = this.binarizer.getLuminanceSource().crop(left, top, width, height);
return new BinaryBitmap(this.binarizer.createBinarizer(newSource));
}
/**
* @return Whether this bitmap supports counter-clockwise rotation.
*/
isRotateSupported() {
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.
*/
rotateCounterClockwise() {
const newSource = 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.
*/
rotateCounterClockwise45() {
const newSource = this.binarizer.getLuminanceSource().rotateCounterClockwise45();
return new BinaryBitmap(this.binarizer.createBinarizer(newSource));
}
/*@Override*/
toString() {
try {
return this.getBlackMatrix().toString();
}
catch (e /*: NotFoundException*/) {
return '';
}
}
}
/**
* Custom Error class of type Exception.
*/
class ChecksumException extends Exception {
static getChecksumInstance() {
return new ChecksumException();
}
}
ChecksumException.kind = 'ChecksumException';
/*
* Copyright 2009 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* This class hierarchy provides a set of methods to convert luminance data to 1 bit data.
* It allows the algorithm to vary polymorphically, for example allowing a very expensive
* thresholding technique for servers and a fast one for mobile. It also permits the implementation
* to vary, e.g. a JNI version for Android and a Java fallback version for other platforms.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
class Binarizer {
constructor(source) {
this.source = source;
}
getLuminanceSource() {
return this.source;
}
getWidth() {
return this.source.getWidth();
}
getHeight() {
return this.source.getHeight();
}
}
class System {
// public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
/**
* Makes a copy of a array.
*/
static arraycopy(src, srcPos, dest, destPos, length) {
// TODO: better use split or set?
while (length--) {
dest[destPos++] = src[srcPos++];
}
}
/**
* Returns the current time in milliseconds.
*/
static currentTimeMillis() {
return Date.now();
}
}
/**
* Custom Error class of type Exception.
*/
class IndexOutOfBoundsException extends Exception {
}
IndexOutOfBoundsException.kind = 'IndexOutOfBoundsException';
/**
* Custom Error class of type Exception.
*/
class ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException {
constructor(index = undefined, message = undefined) {
super(message);
this.index = index;
this.message = message;
}
}
ArrayIndexOutOfBoundsException.kind = 'ArrayIndexOutOfBoundsException';
class Arrays {
/**
* Assigns the specified int value to each element of the specified array
* of ints.
*
* @param a the array to be filled
* @param val the value to be stored in all elements of the array
*/
static fill(a, val) {
for (let i = 0, len = a.length; i < len; i++)
a[i] = val;
}
/**
* Assigns the specified int value to each element of the specified
* range of the specified array of ints. The range to be filled
* extends from index {@code fromIndex}, inclusive, to index
* {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the
* range to be filled is empty.)
*
* @param a the array to be filled
* @param fromIndex the index of the first element (inclusive) to be
* filled with the specified value
* @param toIndex the index of the last element (exclusive) to be
* filled with the specified value
* @param val the value to be stored in all elements of the array
* @throws IllegalArgumentException if {@code fromIndex > toIndex}
* @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
* {@code toIndex > a.length}
*/
static fillWithin(a, fromIndex, toIndex, val) {
Arrays.rangeCheck(a.length, fromIndex, toIndex);
for (let i = fromIndex; i < toIndex; i++)
a[i] = val;
}
/**
* Checks that {@code fromIndex} and {@code toIndex} are in
* the range and throws an exception if they aren't.
*/
static rangeCheck(arrayLength, fromIndex, toIndex) {
if (fromIndex > toIndex) {
throw new IllegalArgumentException('fromIndex(' + fromIndex + ') > toIndex(' + toIndex + ')');
}
if (fromIndex < 0) {
throw new ArrayIndexOutOfBoundsException(fromIndex);
}
if (toIndex > arrayLength) {
throw new ArrayIndexOutOfBoundsException(toIndex);
}
}
static asList(...args) {
return args;
}
static create(rows, cols, value) {
let arr = Array.from({ length: rows });
return arr.map(x => Array.from({ length: cols }).fill(value));
}
static createInt32Array(rows, cols, value) {
let arr = Array.from({ length: rows });
return arr.map(x => Int32Array.from({ length: cols }).fill(value));
}
static equals(first, second) {
if (!first) {
return false;
}
if (!second) {
return false;
}
if (!first.length) {
return false;
}
if (!second.length) {
return false;
}
if (first.length !== second.length) {
return false;
}
for (let i = 0, length = first.length; i < length; i++) {
if (first[i] !== second[i]) {
return false;
}
}
return true;
}
static hashCode(a) {
if (a === null) {
return 0;
}
let result = 1;
for (const element of a) {
result = 31 * result + element;
}
return result;
}
static fillUint8Array(a, value) {
for (let i = 0; i !== a.length; i++) {
a[i] = value;
}
}
static copyOf(original, newLength) {
return original.slice(0, newLength);
}
static copyOfUint8Array(original, newLength) {
if (original.length <= newLength) {
const newArray = new Uint8Array(newLength);
newArray.set(original);
return newArray;
}
return original.slice(0, newLength);
}
static copyOfRange(original, from, to) {
const newLength = to - from;
const copy = new Int32Array(newLength);
System.arraycopy(original, from, copy, 0, newLength);
return copy;
}
/*
* Returns the index of of the element in a sorted array or (-n-1) where n is the insertion point
* for the new element.
* Parameters:
* ar - A sorted array
* el - An element to search for
* comparator - A comparator function. The function takes two arguments: (a, b) and returns:
* a negative number if a is less than b;
* 0 if a is equal to b;
* a positive number of a is greater than b.
* The array may contain duplicate elements. If there are more than one equal elements in the array,
* the returned value can be the index of any one of the equal elements.
*
* http://jsfiddle.net/aryzhov/pkfst550/
*/
static binarySearch(ar, el, comparator) {
if (undefined === comparator) {
comparator = Arrays.numberComparator;
}
let m = 0;
let n = ar.length - 1;
while (m <= n) {
const k = (n + m) >> 1;
const cmp = comparator(el, ar[k]);
if (cmp > 0) {
m = k + 1;
}
else if (cmp < 0) {
n = k - 1;
}
else {
return k;
}
}
return -m - 1;
}
static numberComparator(a, b) {
return a - b;
}
}
/**
* Ponyfill for Java's Integer class.
*/
class Integer {
static numberOfTrailingZeros(i) {
let y;
if (i === 0)
return 32;
let n = 31;
y = i << 16;
if (y !== 0) {
n -= 16;
i = y;
}
y = i << 8;
if (y !== 0) {
n -= 8;
i = y;
}
y = i << 4;
if (y !== 0) {
n -= 4;
i = y;
}
y = i << 2;
if (y !== 0) {
n -= 2;
i = y;
}
return n - ((i << 1) >>> 31);
}
static numberOfLeadingZeros(i) {
// HD, Figure 5-6
if (i === 0) {
return 32;
}
let n = 1;
if (i >>> 16 === 0) {
n += 16;
i <<= 16;
}
if (i >>> 24 === 0) {
n += 8;
i <<= 8;
}
if (i >>> 28 === 0) {
n += 4;
i <<= 4;
}
if (i >>> 30 === 0) {
n += 2;
i <<= 2;
}
n -= i >>> 31;
return n;
}
static toHexString(i) {
return i.toString(16);
}
static toBinaryString(intNumber) {
return String(parseInt(String(intNumber), 2));
}
// Returns the number of one-bits in the two's complement binary representation of the specified int value. This function is sometimes referred to as the population count.
// Returns:
// the number of one-bits in the two's complement binary representation of the specified int value.
static bitCount(i) {
// HD, Figure 5-2
i = i - ((i >>> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
i = (i + (i >>> 4)) & 0x0f0f0f0f;
i = i + (i >>> 8);
i = i + (i >>> 16);
return i & 0x3f;
}
static truncDivision(dividend, divisor) {
return Math.trunc(dividend / divisor);
}
/**
* Converts A string to an integer.
* @param s A string to convert into a number.
* @param radix A value between 2 and 36 that specifies the base of the number in numString. If this argument is not supplied, strings with a prefix of '0x' are considered hexadecimal. All other strings are considered decimal.
*/
static parseInt(num, radix = undefined) {
return parseInt(num, radix);
}
}
Integer.MIN_VALUE_32_BITS = -2147483648;
Integer.MAX_VALUE = Number.MAX_SAFE_INTEGER;
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* <p>A simple, fast array of bits, represented compactly by an array of ints internally.</p>
*
* @author Sean Owen
*/
class BitArray /*implements Cloneable*/ {
// public constructor() {
// this.size = 0
// this.bits = new Int32Array(1)
// }
// public constructor(size?: number /*int*/) {
// if (undefined === size) {
// this.size = 0
// } else {
// this.size = size
// }
// this.bits = this.makeArray(size)
// }
// For testing only
constructor(size /*int*/, bits) {
if (undefined === size) {
this.size = 0;
this.bits = new Int32Array(1);
}
else {
this.size = size;
if (undefined === bits || null === bits) {
this.bits = BitArray.makeArray(size);
}
else {
this.bits = bits;
}
}
}
getSize() {
return this.size;
}
getSizeInBytes() {
return Math.floor((this.size + 7) / 8);
}
ensureCapacity(size /*int*/) {
if (size > this.bits.length * 32) {
const newBits = BitArray.makeArray(size);
System.arraycopy(this.bits, 0, newBits, 0, this.bits.length);
this.bits = newBits;
}
}
/**
* @param i bit to get
* @return true iff bit i is set
*/
get(i /*int*/) {
return (this.bits[Math.floor(i / 32)] & (1 << (i & 0x1F))) !== 0;
}
/**
* Sets bit i.
*
* @param i bit to set
*/
set(i /*int*/) {
this.bits[Math.floor(i / 32)] |= 1 << (i & 0x1F);
}
/**
* Flips bit i.
*
* @param i bit to set
*/
flip(i /*int*/) {
this.bits[Math.floor(i / 32)] ^= 1 << (i & 0x1F);
}
/**
* @param from first bit to check
* @return index of first bit that is set, starting from the given index, or size if none are set
* at or beyond this given index
* @see #getNextUnset(int)
*/
getNextSet(from /*int*/) {
const size = this.size;
if (from >= size) {
return size;
}
const bits = this.bits;
let bitsOffset = Math.floor(from / 32);
let currentBits = bits[bitsOffset];
// mask off lesser bits first
currentBits &= ~((1 << (from & 0x1F)) - 1);
const length = bits.length;
while (currentBits === 0) {
if (++bitsOffset === length) {
return size;
}
currentBits = bits[bitsOffset];
}
const result = (bitsOffset * 32) + Integer.numberOfTrailingZeros(currentBits);
return result > size ? size : result;
}
/**
* @param from index to start looking for unset bit
* @return index of next unset bit, or {@code size} if none are unset until the end
* @see #getNextSet(int)
*/
getNextUnset(from /*int*/) {
const size = this.size;
if (from >= size) {
return size;
}
const bits = this.bits;
let bitsOffset = Math.floor(from / 32);
let currentBits = ~bits[bitsOffset];
// mask off lesser bits first
currentBits &= ~((1 << (from & 0x1F)) - 1);
const length = bits.length;
while (currentBits === 0) {
if (++bitsOffset === length) {
return size;
}
currentBits = ~bits[bitsOffset];
}
const result = (bitsOffset * 32) + Integer.numberOfTrailingZeros(currentBits);
return result > size ? size : result;
}
/**
* Sets a block of 32 bits, starting at bit i.
*
* @param i first bit to set
* @param newBits the new value of the next 32 bits. Note again that the least-significant bit
* corresponds to bit i, the next-least-significant to i+1, and so on.
*/
setBulk(i /*int*/, newBits /*int*/) {
this.bits[Math.floor(i / 32)] = newBits;
}
/**
* Sets a range of bits.
*
* @param start start of range, inclusive.
* @param end end of range, exclusive
*/
setRange(start /*int*/, end /*int*/) {
if (end < start || start < 0 || end > this.size) {
throw new IllegalArgumentException();
}
if (end === start) {
return;
}
end--; // will be easier to treat this as the last actually set bit -- inclusive
const firstInt = Math.floor(start / 32);
const lastInt = Math.floor(end / 32);
const bits = this.bits;
for (let i = firstInt; i <= lastInt; i++) {
const firstBit = i > firstInt ? 0 : start & 0x1F;
const lastBit = i < lastInt ? 31 : end & 0x1F;
// Ones from firstBit to lastBit, inclusive
const mask = (2 << lastBit) - (1 << firstBit);
bits[i] |= mask;
}
}
/**
* Clears all bits (sets to false).
*/
clear() {
const max = this.bits.length;
const bits = this.bits;
for (let i = 0; i < max; i++) {
bits[i] = 0;
}
}
/**
* Efficient method to check if a range of bits is set, or not set.
*
* @param start start of range, inclusive.
* @param end end of range, exclusive
* @param value if true, checks that bits in range are set, otherwise checks that they are not set
* @return true iff all bits are set or not set in range, according to value argument
* @throws IllegalArgumentException if end is less than start or the range is not contained in the array
*/
isRange(start /*int*/, end /*int*/, value) {
if (end < start || start < 0 || end > this.size) {
throw new IllegalArgumentException();
}
if (end === start) {
return true; // empty range matches
}
end--; // will be easier to treat this as the last actually set bit -- inclusive
const firstInt = Math.floor(start / 32);
const lastInt = Math.floor(end / 32);
const bits = this.bits;
for (let i = firstInt; i <= lastInt; i++) {
const firstBit = i > firstInt ? 0 : start & 0x1F;
const lastBit = i < lastInt ? 31 : end & 0x1F;
// Ones from firstBit to lastBit, inclusive
const mask = (2 << lastBit) - (1 << firstBit) & 0xFFFFFFFF;
// TYPESCRIPTPORT: & 0xFFFFFFFF added to discard anything after 32 bits, as ES has 53 bits
// Return false if we're looking for 1s and the masked bits[i] isn't all 1s (is: that,
// equals the mask, or we're looking for 0s and the masked portion is not all 0s
if ((bits[i] & mask) !== (value ? mask : 0)) {
return false;
}
}
return true;
}
appendBit(bit) {
this.ensureCapacity(this.size + 1);
if (bit) {
this.bits[Math.floor(this.size / 32)] |= 1 << (this.size & 0x1F);
}
this.size++;
}
/**
* Appends the least-significant bits, from value, in order from most-significant to
* least-significant. For example, appending 6 bits from 0x000001E will append the bits
* 0, 1, 1, 1, 1, 0 in that order.
*
* @param value {@code int} containing bits to append
* @param numBits bits from value to append
*/
appendBits(value /*int*/, numBits /*int*/) {
if (numBits < 0 || numBits > 32) {
throw new IllegalArgumentException('Num bits must be between 0 and 32');
}
this.ensureCapacity(this.size + numBits);
// const appendBit = this.appendBit;
for (let numBitsLeft = numBits; numBitsLeft > 0; numBitsLeft--) {
this.appendBit(((value >> (numBitsLeft - 1)) & 0x01) === 1);
}
}
appendBitArray(other) {
const otherSize = other.size;
this.ensureCapacity(this.size + otherSize);
// const appendBit = this.appendBit;
for (let i = 0; i < otherSize; i++) {
this.appendBit(other.get(i));
}
}
xor(other) {
if (this.size !== other.size) {
throw new IllegalArgumentException('Sizes don\'t match');
}
const bits = this.bits;
for (let i = 0, length = bits.length; i < length; i++) {
// The last int could be incomplete (i.e. not have 32 bits in
// it) but there is no problem since 0 XOR 0 == 0.
bits[i] ^= other.bits[i];
}
}
/**
*
* @param bitOffset first bit to start writing
* @param array array to write into. Bytes are written most-significant byte first. This is the opposite
* of the internal representation, which is exposed by {@link #getBitArray()}
* @param offset position in array to start writing
* @param numBytes how many bytes to write
*/
toBytes(bitOffset /*int*/, array, offset /*int*/, numBytes /*int*/) {
for (let i = 0; i < numBytes; i++) {
let theByte = 0;
for (let j = 0; j < 8; j++) {
if (this.get(bitOffset)) {
theByte |= 1 << (7 - j);
}
bitOffset++;
}
array[offset + i] = /*(byte)*/ theByte;
}
}
/**
* @return underlying array of ints. The first element holds the first 32 bits, and the least
* significant bit is bit 0.
*/
getBitArray() {
return this.bits;
}
/**
* Reverses all bits in the array.
*/
reverse() {
const newBits = new Int32Array(this.bits.length);
// reverse all int's first
const len = Math.floor((this.size - 1) / 32);
const oldBitsLen = len + 1;
const bits = this.bits;
for (let i = 0; i < oldBitsLen; i++) {
let x = bits[i];
x = ((x >> 1) & 0x55555555) | ((x & 0x55555555) << 1);
x = ((x >> 2) & 0x33333333) | ((x & 0x33333333) << 2);
x = ((x >> 4) & 0x0f0f0f0f) | ((x & 0x0f0f0f0f) << 4);
x = ((x >> 8) & 0x00ff00ff) | ((x & 0x00ff00ff) << 8);
x = ((x >> 16) & 0x0000ffff) | ((x & 0x0000ffff) << 16);
newBits[len - i] = /*(int)*/ x;
}
// now correct the int's if the bit size isn't a multiple of 32
if (this.size !== oldBitsLen * 32) {
const leftOffset = oldBitsLen * 32 - this.size;
let currentInt = newBits[0] >>> leftOffset;
for (let i = 1; i < oldBitsLen; i++) {
const nextInt = newBits[i];
currentInt |= nextInt << (32 - leftOffset);
newBits[i - 1] = currentInt;
currentInt = nextInt >>> leftOffset;
}
newBits[oldBitsLen - 1] = currentInt;
}
this.bits = newBits;
}
static makeArray(size /*int*/) {
return new Int32Array(Math.floor((size + 31) / 32));
}
/*@Override*/
equals(o) {
if (!(o instanceof BitArray)) {
return false;
}
const other = o;
return this.size === other.size && Arrays.equals(this.bits, other.bits);
}
/*@Override*/
hashCode() {
return 31 * this.size + Arrays.hashCode(this.bits);
}
/*@Override*/
toString() {
let result = '';
for (let i = 0, size = this.size; i < size; i++) {
if ((i & 0x07) === 0) {
result += ' ';
}
result += this.get(i) ? 'X' : '.';
}
return result;
}
/*@Override*/
clone() {
return new BitArray(this.size, this.bits.slice());
}
/**
* converts to boolean array.
*/
toArray() {
let result = [];
for (let i = 0, size = this.size; i < size; i++) {
result.push(this.get(i));
}
return result;
}
}
/*
* Copyright 2009 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*namespace com.google.zxing {*/
/**
* Encapsulates a type of hint that a caller may pass to a barcode reader to help it
* more quickly or accurately decode it. It is up to implementations to decide what,
* if anything, to do with the information that is supplied.
*
* @author Sean Owen
* @author dswitkin@google.com (Daniel Switkin)
* @see Reader#decode(BinaryBitmap,java.util.Map)
*/
var DecodeHintType;
(function (DecodeHintType) {
/**
* Unspecified, application-specific hint. Maps to an unspecified {@link Object}.
*/
DecodeHintType[DecodeHintType["OTHER"] = 0] = "OTHER"; /*(Object.class)*/
/**
* Image is a pure monochrome image of a barcode. Doesn't matter what it maps to;
* use {@link Boolean#TRUE}.
*/
DecodeHintType[DecodeHintType["PURE_BARCODE"] = 1] = "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.
*/
DecodeHintType[DecodeHintType["POSSIBLE_FORMATS"] = 2] = "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}.
*/
DecodeHintType[DecodeHintType["TRY_HARDER"] = 3] = "TRY_HARDER"; /*(Void.class)*/
/**
* Specifies what character encoding to use when decoding, where applicable (type String)
*/
DecodeHintType[DecodeHintType["CHARACTER_SET"] = 4] = "CHARACTER_SET"; /*(String.class)*/
/**
* Allowed lengths of encoded data -- reject anything else. Maps to an {@code Int32Array}.
*/
DecodeHintType[DecodeHintType["ALLOWED_LENGTHS"] = 5] = "ALLOWED_LENGTHS"; /*(Int32Array.class)*/
/**
* Assume Code 39 codes employ a check digit. Doesn't matter what it maps to;
* use {@link Boolean#TRUE}.
*/
DecodeHintType[DecodeHintType["ASSUME_CODE_39_CHECK_DIGIT"] = 6] = "ASSUME_CODE_39_CHECK_DIGIT"; /*(Void.class)*/
/**
* Enable extended mode for Code 39 codes. Doesn't matter what it maps to;
* use {@link Boolean#TRUE}.
*/
DecodeHintType[DecodeHintType["ENABLE_CODE_39_EXTENDED_MODE"] = 7] = "ENABLE_CODE_39_EXTENDED_MODE"; /*(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}.
*/
DecodeHintType[DecodeHintType["ASSUME_GS1"] = 8] = "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}.
*/
DecodeHintType[DecodeHintType["RETURN_CODABAR_START_END"] = 9] = "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}.
*/
DecodeHintType[DecodeHintType["NEED_RESULT_POINT_CALLBACK"] = 10] = "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.
*/
DecodeHintType[DecodeHintType["ALLOWED_EAN_EXTENSIONS"] = 11] = "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
// }
})(DecodeHintType || (DecodeHintType = {}));
var DecodeHintType$1 = DecodeHintType;
/**
* Custom Error class of type Exception.
*/
class FormatException extends Exception {
static getFormatInstance() {
return new FormatException();
}
}
FormatException.kind = 'FormatException';
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*import java.util.HashMap;*/
/*import java.util.Map;*/
var CharacterSetValueIdentifiers;
(function (CharacterSetValueIdentifiers) {
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["Cp437"] = 0] = "Cp437";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_1"] = 1] = "ISO8859_1";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_2"] = 2] = "ISO8859_2";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_3"] = 3] = "ISO8859_3";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_4"] = 4] = "ISO8859_4";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_5"] = 5] = "ISO8859_5";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_6"] = 6] = "ISO8859_6";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_7"] = 7] = "ISO8859_7";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_8"] = 8] = "ISO8859_8";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_9"] = 9] = "ISO8859_9";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_10"] = 10] = "ISO8859_10";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_11"] = 11] = "ISO8859_11";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_13"] = 12] = "ISO8859_13";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_14"] = 13] = "ISO8859_14";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_15"] = 14] = "ISO8859_15";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_16"] = 15] = "ISO8859_16";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["SJIS"] = 16] = "SJIS";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["Cp1250"] = 17] = "Cp1250";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["Cp1251"] = 18] = "Cp1251";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["Cp1252"] = 19] = "Cp1252";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["Cp1256"] = 20] = "Cp1256";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["UnicodeBigUnmarked"] = 21] = "UnicodeBigUnmarked";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["UTF8"] = 22] = "UTF8";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ASCII"] = 23] = "ASCII";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["Big5"] = 24] = "Big5";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["GB18030"] = 25] = "GB18030";
CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["EUC_KR"] = 26] = "EUC_KR";
})(CharacterSetValueIdentifiers || (CharacterSetValueIdentifiers = {}));
/**
* Encapsulates a Character Set ECI, according to "Extended Channel Interpretations" 5.3.1.1
* of ISO 18004.
*
* @author Sean Owen
*/
class CharacterSetECI {
constructor(valueIdentifier, valuesParam, name, ...otherEncodingNames) {
this.valueIdentifier = valueIdentifier;
this.name = name;
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);
}
}
// 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
// }
getValueIdentifier() {
return this.valueIdentifier;
}
getName() {
return this.name;
}
getValue() {
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
*/
static getCharacterSetECIByValue(value /*int*/) {
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;
}
/**
* @param name character set ECI encoding name
* @return CharacterSetECI representing ECI for character encoding, or null if it is legal
* but unsupported
*/
static getCharacterSetECIByName(name) {
const characterSet = CharacterSetECI.NAME_TO_ECI.get(name);
if (undefined === characterSet) {
throw new FormatException('incorect value');
}
return characterSet;
}
equals(o) {
if (!(o instanceof CharacterSetECI)) {
return false;
}
const other = o;
return this.getName() === other.getName();
}
}
CharacterSetECI.VALUE_IDENTIFIER_TO_ECI = new Map();
CharacterSetECI.VALUES_TO_ECI = new Map();
CharacterSetECI.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
CharacterSetECI.Cp437 = new CharacterSetECI(CharacterSetValueIdentifiers.Cp437, Int32Array.from([0, 2]), 'Cp437');
CharacterSetECI.ISO8859_1 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_1, Int32Array.from([1, 3]), 'ISO-8859-1', 'ISO88591', 'ISO8859_1');
CharacterSetECI.ISO8859_2 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_2, 4, 'ISO-8859-2', 'ISO88592', 'ISO8859_2');
CharacterSetECI.ISO8859_3 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_3, 5, 'ISO-8859-3', 'ISO88593', 'ISO8859_3');
CharacterSetECI.ISO8859_4 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_4, 6, 'ISO-8859-4', 'ISO88594', 'ISO8859_4');
CharacterSetECI.ISO8859_5 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_5, 7, 'ISO-8859-5', 'ISO88595', 'ISO8859_5');
CharacterSetECI.ISO8859_6 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_6, 8, 'ISO-8859-6', 'ISO88596', 'ISO8859_6');
CharacterSetECI.ISO8859_7 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_7, 9, 'ISO-8859-7', 'ISO88597', 'ISO8859_7');
CharacterSetECI.ISO8859_8 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_8, 10, 'ISO-8859-8', 'ISO88598', 'ISO8859_8');
CharacterSetECI.ISO8859_9 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_9, 11, 'ISO-8859-9', 'ISO88599', 'ISO8859_9');
CharacterSetECI.ISO8859_10 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_10, 12, 'ISO-8859-10', 'ISO885910', 'ISO8859_10');
CharacterSetECI.ISO8859_11 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_11, 13, 'ISO-8859-11', 'ISO885911', 'ISO8859_11');
CharacterSetECI.ISO8859_13 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_13, 15, 'ISO-8859-13', 'ISO885913', 'ISO8859_13');
CharacterSetECI.ISO8859_14 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_14, 16, 'ISO-8859-14', 'ISO885914', 'ISO8859_14');
CharacterSetECI.ISO8859_15 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_15, 17, 'ISO-8859-15', 'ISO885915', 'ISO8859_15');
CharacterSetECI.ISO8859_16 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_16, 18, 'ISO-8859-16', 'ISO885916', 'ISO8859_16');
CharacterSetECI.SJIS = new CharacterSetECI(CharacterSetValueIdentifiers.SJIS, 20, 'SJIS', 'Shift_JIS');
CharacterSetECI.Cp1250 = new CharacterSetECI(CharacterSetValueIdentifiers.Cp1250, 21, 'Cp1250', 'windows-1250');
CharacterSetECI.Cp1251 = new CharacterSetECI(CharacterSetValueIdentifiers.Cp1251, 22, 'Cp1251', 'windows-1251');
CharacterSetECI.Cp1252 = new CharacterSetECI(CharacterSetValueIdentifiers.Cp1252, 23, 'Cp1252', 'windows-1252');
CharacterSetECI.Cp1256 = new CharacterSetECI(CharacterSetValueIdentifiers.Cp1256, 24, 'Cp1256', 'windows-1256');
CharacterSetECI.UnicodeBigUnmarked = new CharacterSetECI(CharacterSetValueIdentifiers.UnicodeBigUnmarked, 25, 'UnicodeBigUnmarked', 'UTF-16BE', 'UnicodeBig');
CharacterSetECI.UTF8 = new CharacterSetECI(CharacterSetValueIdentifiers.UTF8, 26, 'UTF8', 'UTF-8');
CharacterSetECI.ASCII = new CharacterSetECI(CharacterSetValueIdentifiers.ASCII, Int32Array.from([27, 170]), 'ASCII', 'US-ASCII');
CharacterSetECI.Big5 = new CharacterSetECI(CharacterSetValueIdentifiers.Big5, 28, 'Big5');
CharacterSetECI.GB18030 = new CharacterSetECI(CharacterSetValueIdentifiers.GB18030, 29, 'GB18030', 'GB2312', 'EUC_CN', 'GBK');
CharacterSetECI.EUC_KR = new CharacterSetECI(CharacterSetValueIdentifiers.EUC_KR, 30, 'EUC_KR', 'EUC-KR');
/**
* Custom Error class of type Exception.
*/
class UnsupportedOperationException extends Exception {
}
UnsupportedOperationException.kind = 'UnsupportedOperationException';
/**
* Responsible for en/decoding strings.
*/
class StringEncoding {
/**
* Decodes some Uint8Array to a string format.
*/
static decode(bytes, encoding) {
const encodingName = this.encodingName(encoding);
if (this.customDecoder) {
return this.customDecoder(bytes, encodingName);
}
// Increases browser support.
if (typeof TextDecoder === 'undefined' || this.shouldDecodeOnFallback(encodingName)) {
return this.decodeFallback(bytes, encodingName);
}
return new TextDecoder(encodingName).decode(bytes);
}
/**
* Checks if the decoding method should use the fallback for decoding
* once Node TextDecoder doesn't support all encoding formats.
*
* @param encodingName
*/
static shouldDecodeOnFallback(encodingName) {
return !StringEncoding.isBrowser() && encodingName === 'ISO-8859-1';
}
/**
* Encodes some string into a Uint8Array.
*/
static encode(s, encoding) {
const encodingName = this.encodingName(encoding);
if (this.customEncoder) {
return this.customEncoder(s, encodingName);
}
// Increases browser support.
if (typeof TextEncoder === 'undefined') {
return this.encodeFallback(s);
}
// TextEncoder only encodes to UTF8 by default as specified by encoding.spec.whatwg.org
return new TextEncoder().encode(s);
}
static