UNPKG

@zxing/library

Version:

TypeScript port of ZXing multi-format 1D/2D barcode image processing library.

1,254 lines (1,224 loc) 1.22 MB
(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