vendor: 10,116 bytes, lines 1-284
1(function (global, factory) { 2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : 3 typeof define === 'function' && define.amd ? define(['exports'], factory) : 4 (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ZXing = {})); 5})(this, (function (exports) { 'use strict'; 6 7 function fixProto(target, prototype) { 8 var setPrototypeOf = Object.setPrototypeOf; 9 setPrototypeOf ? setPrototypeOf(target, prototype) : target.__proto__ = prototype; 10 } 11 function fixStack(target, fn) { 12 if (fn === void 0) { 13 fn = target.constructor; 14 } 15 16 var captureStackTrace = Error.captureStackTrace; 17 captureStackTrace && captureStackTrace(target, fn); 18 } 19 20 var __extends = function () { 21 var _extendStatics = function extendStatics(d, b) { 22 _extendStatics = Object.setPrototypeOf || { 23 __proto__: [] 24 } instanceof Array && function (d, b) { 25 d.__proto__ = b; 26 } || function (d, b) { 27 for (var p in b) { 28 if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; 29 } 30 }; 31 32 return _extendStatics(d, b); 33 }; 34 35 return function (d, b) { 36 if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); 37 38 _extendStatics(d, b); 39 40 function __() { 41 this.constructor = d; 42 } 43 44 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 45 }; 46 }(); 47 48 var CustomError = function (_super) { 49 __extends(CustomError, _super); 50 51 function CustomError(message, options) { 52 var _newTarget = this.constructor; 53 54 var _this = _super.call(this, message, options) || this; 55 56 Object.defineProperty(_this, 'name', { 57 value: _newTarget.name, 58 enumerable: false, 59 configurable: true 60 }); 61 fixProto(_this, _newTarget.prototype); 62 fixStack(_this); 63 return _this; 64 } 65 66 return CustomError; 67 }(Error); 68 69 /** 70 * Custom Error class of type Exception. 71 */ 72 class Exception extends CustomError { 73 /** 74 * Allows Exception to be constructed directly 75 * with some message and prototype definition. 76 */ 77 constructor(message = undefined) { 78 super(message); 79 this.message = message; 80 } 81 getKind() { 82 const ex = this.constructor; 83 return ex.kind; 84 } 85 } 86 /** 87 * It's typed as string so it can be extended and overriden. 88 */ 89 Exception.kind = 'Exception'; 90 91 /** 92 * Custom Error class of type Exception. 93 */ 94 class ArgumentException extends Exception { 95 } 96 ArgumentException.kind = 'ArgumentException'; 97 98 /** 99 * Custom Error class of type Exception. 100 */ 101 class IllegalArgumentException extends Exception { 102 } 103 IllegalArgumentException.kind = 'IllegalArgumentException'; 104 105 /* 106 * Copyright 2009 ZXing authors 107 * 108 * Licensed under the Apache License, Version 2.0 (the "License"); 109 * you may not use this file except in compliance with the License. 110 * You may obtain a copy of the License at 111 * 112 * http://www.apache.org/licenses/LICENSE-2.0 113 * 114 * Unless required by applicable law or agreed to in writing, software 115 * distributed under the License is distributed on an "AS IS" BASIS, 116 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 117 * See the License for the specific language governing permissions and 118 * limitations under the License. 119 */ 120 class BinaryBitmap { 121 constructor(binarizer) { 122 this.binarizer = binarizer; 123 if (binarizer === null) { 124 throw new IllegalArgumentException('Binarizer must be non-null.'); 125 } 126 } 127 /** 128 * @return The width of the bitmap. 129 */ 130 getWidth() { 131 return this.binarizer.getWidth(); 132 } 133 /** 134 * @return The height of the bitmap. 135 */ 136 getHeight() { 137 return this.binarizer.getHeight(); 138 } 139 /** 140 * Converts one row of luminance data to 1 bit data. May actually do the conversion, or return 141 * cached data. Callers should assume this method is expensive and call it as seldom as possible. 142 * This method is intended for decoding 1D barcodes and may choose to apply sharpening. 143 * 144 * @param y The row to fetch, which must be in [0, bitmap height) 145 * @param row An optional preallocated array. If null or too small, it will be ignored. 146 * If used, the Binarizer will call BitArray.clear(). Always use the returned object. 147 * @return The array of bits for this row (true means black). 148 * @throws NotFoundException if row can't be binarized 149 */ 150 getBlackRow(y /*int*/, row) { 151 return this.binarizer.getBlackRow(y, row); 152 } 153 /** 154 * Converts a 2D array of luminance data to 1 bit. As above, assume this method is expensive 155 * and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or 156 * may not apply sharpening. Therefore, a row from this matrix may not be identical to one 157 * fetched using getBlackRow(), so don't mix and match between them. 158 * 159 * @return The 2D array of bits for the image (true means black). 160 * @throws NotFoundException if image can't be binarized to make a matrix 161 */ 162 getBlackMatrix() { 163 // The matrix is created on demand the first time it is requested, then cached. There are two 164 // reasons for this: 165 // 1. This work will never be done if the caller only installs 1D Reader objects, or if a 166 // 1D Reader finds a barcode before the 2D Readers run. 167 // 2. This work will only be done once even if the caller installs multiple 2D Readers. 168 if (this.matrix === null || this.matrix === undefined) { 169 this.matrix = this.binarizer.getBlackMatrix(); 170 } 171 return this.matrix; 172 } 173 /** 174 * @return Whether this bitmap can be cropped. 175 */ 176 isCropSupported() { 177 return this.binarizer.getLuminanceSource().isCropSupported(); 178 } 179 /** 180 * Returns a new object with cropped image data. Implementations may keep a reference to the 181 * original data rather than a copy. Only callable if isCropSupported() is true. 182 * 183 * @param left The left coordinate, which must be in [0,getWidth()) 184 * @param top The top coordinate, which must be in [0,getHeight()) 185 * @param width The width of the rectangle to crop. 186 * @param height The height of the rectangle to crop. 187 * @return A cropped version of this object. 188 */ 189 crop(left /*int*/, top /*int*/, width /*int*/, height /*int*/) { 190 const newSource = this.binarizer.getLuminanceSource().crop(left, top, width, height); 191 return new BinaryBitmap(this.binarizer.createBinarizer(newSource)); 192 } 193 /** 194 * @return Whether this bitmap supports counter-clockwise rotation. 195 */ 196 isRotateSupported() { 197 return this.binarizer.getLuminanceSource().isRotateSupported(); 198 } 199 /** 200 * Returns a new object with rotated image data by 90 degrees counterclockwise. 201 * Only callable if {@link #isRotateSupported()} is true. 202 * 203 * @return A rotated version of this object. 204 */ 205 rotateCounterClockwise() { 206 const newSource = this.binarizer.getLuminanceSource().rotateCounterClockwise(); 207 return new BinaryBitmap(this.binarizer.createBinarizer(newSource)); 208 } 209 /** 210 * Returns a new object with rotated image data by 45 degrees counterclockwise. 211 * Only callable if {@link #isRotateSupported()} is true. 212 * 213 * @return A rotated version of this object. 214 */ 215 rotateCounterClockwise45() { 216 const newSource = this.binarizer.getLuminanceSource().rotateCounterClockwise45(); 217 return new BinaryBitmap(this.binarizer.createBinarizer(newSource)); 218 } 219 /*@Override*/ 220 toString() { 221 try { 222 return this.getBlackMatrix().toString(); 223 } 224 catch (e /*: NotFoundException*/) { 225 return ''; 226 } 227 } 228 } 229 230 /** 231 * Custom Error class of type Exception. 232 */ 233 class ChecksumException extends Exception { 234 static getChecksumInstance() { 235 return new ChecksumException(); 236 } 237 } 238 ChecksumException.kind = 'ChecksumException'; 239 240 /* 241 * Copyright 2009 ZXing authors 242 * 243 * Licensed under the Apache License, Version 2.0 (the "License"); 244 * you may not use this file except in compliance with the License. 245 * You may obtain a copy of the License at 246 * 247 * http://www.apache.org/licenses/LICENSE-2.0 248 * 249 * Unless required by applicable law or agreed to in writing, software 250 * distributed under the License is distributed on an "AS IS" BASIS, 251 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 252 * See the License for the specific language governing permissions and 253 * limitations under the License. 254 */ 255 /** 256 * This class hierarchy provides a set of methods to convert luminance data to 1 bit data. 257 * It allows the algorithm to vary polymorphically, for example allowing a very expensive 258 * thresholding technique for servers and a fast one for mobile. It also permits the implementation 259 * to vary, e.g. a JNI version for Android and a Java fallback version for other platforms. 260 * 261 * @author [email protected] (Daniel Switkin) 262 */ 263 class Binarizer { 264 constructor(source) { 265 this.source = source; 266 } 267 getLuminanceSource() { 268 return this.source; 269 } 270 getWidth() { 271 return this.source.getWidth(); 272 } 273 getHeight() { 274 return this.source.getHeight(); 275 } 276 } 277 278 class System { 279 // public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) 280 /** 281 * Makes a copy of a array. 282 */ 283 static arraycopy(src, srcPos, dest, destPos, length) { 284
284// TODO: better use split or set? 285 while (length--) { 286 dest[destPos++] = src[srcPos++];
vendor: 38,936 bytes, lines 286-1231
286 287 } 288 } 289 /** 290 * Returns the current time in milliseconds. 291 */ 292 static currentTimeMillis() { 293 return Date.now(); 294 } 295 } 296 297 /** 298 * Custom Error class of type Exception. 299 */ 300 class IndexOutOfBoundsException extends Exception { 301 } 302 IndexOutOfBoundsException.kind = 'IndexOutOfBoundsException'; 303 304 /** 305 * Custom Error class of type Exception. 306 */ 307 class ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException { 308 constructor(index = undefined, message = undefined) { 309 super(message); 310 this.index = index; 311 this.message = message; 312 } 313 } 314 ArrayIndexOutOfBoundsException.kind = 'ArrayIndexOutOfBoundsException'; 315 316 class Arrays { 317 /** 318 * Assigns the specified int value to each element of the specified array 319 * of ints. 320 * 321 * @param a the array to be filled 322 * @param val the value to be stored in all elements of the array 323 */ 324 static fill(a, val) { 325 for (let i = 0, len = a.length; i < len; i++) 326 a[i] = val; 327 } 328 /** 329 * Assigns the specified int value to each element of the specified 330 * range of the specified array of ints. The range to be filled 331 * extends from index {@code fromIndex}, inclusive, to index 332 * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the 333 * range to be filled is empty.) 334 * 335 * @param a the array to be filled 336 * @param fromIndex the index of the first element (inclusive) to be 337 * filled with the specified value 338 * @param toIndex the index of the last element (exclusive) to be 339 * filled with the specified value 340 * @param val the value to be stored in all elements of the array 341 * @throws IllegalArgumentException if {@code fromIndex > toIndex} 342 * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or 343 * {@code toIndex > a.length} 344 */ 345 static fillWithin(a, fromIndex, toIndex, val) { 346 Arrays.rangeCheck(a.length, fromIndex, toIndex); 347 for (let i = fromIndex; i < toIndex; i++) 348 a[i] = val; 349 } 350 /** 351 * Checks that {@code fromIndex} and {@code toIndex} are in 352 * the range and throws an exception if they aren't. 353 */ 354 static rangeCheck(arrayLength, fromIndex, toIndex) { 355 if (fromIndex > toIndex) { 356 throw new IllegalArgumentException('fromIndex(' + fromIndex + ') > toIndex(' + toIndex + ')'); 357 } 358 if (fromIndex < 0) { 359 throw new ArrayIndexOutOfBoundsException(fromIndex); 360 } 361 if (toIndex > arrayLength) { 362 throw new ArrayIndexOutOfBoundsException(toIndex); 363 } 364 } 365 static asList(...args) { 366 return args; 367 } 368 static create(rows, cols, value) { 369 let arr = Array.from({ length: rows }); 370 return arr.map(x => Array.from({ length: cols }).fill(value)); 371 } 372 static createInt32Array(rows, cols, value) { 373 let arr = Array.from({ length: rows }); 374 return arr.map(x => Int32Array.from({ length: cols }).fill(value)); 375 } 376 static equals(first, second) { 377 if (!first) { 378 return false; 379 } 380 if (!second) { 381 return false; 382 } 383 if (!first.length) { 384 return false; 385 } 386 if (!second.length) { 387 return false; 388 } 389 if (first.length !== second.length) { 390 return false; 391 } 392 for (let i = 0, length = first.length; i < length; i++) { 393 if (first[i] !== second[i]) { 394 return false; 395 } 396 } 397 return true; 398 } 399 static hashCode(a) { 400 if (a === null) { 401 return 0; 402 } 403 let result = 1; 404 for (const element of a) { 405 result = 31 * result + element; 406 } 407 return result; 408 } 409 static fillUint8Array(a, value) { 410 for (let i = 0; i !== a.length; i++) { 411 a[i] = value; 412 } 413 } 414 static copyOf(original, newLength) { 415 return original.slice(0, newLength); 416 } 417 static copyOfUint8Array(original, newLength) { 418 if (original.length <= newLength) { 419 const newArray = new Uint8Array(newLength); 420 newArray.set(original); 421 return newArray; 422 } 423 return original.slice(0, newLength); 424 } 425 static copyOfRange(original, from, to) { 426 const newLength = to - from; 427 const copy = new Int32Array(newLength); 428 System.arraycopy(original, from, copy, 0, newLength); 429 return copy; 430 } 431 /* 432 * Returns the index of of the element in a sorted array or (-n-1) where n is the insertion point 433 * for the new element. 434 * Parameters: 435 * ar - A sorted array 436 * el - An element to search for 437 * comparator - A comparator function. The function takes two arguments: (a, b) and returns: 438 * a negative number if a is less than b; 439 * 0 if a is equal to b; 440 * a positive number of a is greater than b. 441 * The array may contain duplicate elements. If there are more than one equal elements in the array, 442 * the returned value can be the index of any one of the equal elements. 443 * 444 * http://jsfiddle.net/aryzhov/pkfst550/ 445 */ 446 static binarySearch(ar, el, comparator) { 447 if (undefined === comparator) { 448 comparator = Arrays.numberComparator; 449 } 450 let m = 0; 451 let n = ar.length - 1; 452 while (m <= n) { 453 const k = (n + m) >> 1; 454 const cmp = comparator(el, ar[k]); 455 if (cmp > 0) { 456 m = k + 1; 457 } 458 else if (cmp < 0) { 459 n = k - 1; 460 } 461 else { 462 return k; 463 } 464 } 465 return -m - 1; 466 } 467 static numberComparator(a, b) { 468 return a - b; 469 } 470 } 471 472 /** 473 * Ponyfill for Java's Integer class. 474 */ 475 class Integer { 476 static numberOfTrailingZeros(i) { 477 let y; 478 if (i === 0) 479 return 32; 480 let n = 31; 481 y = i << 16; 482 if (y !== 0) { 483 n -= 16; 484 i = y; 485 } 486 y = i << 8; 487 if (y !== 0) { 488 n -= 8; 489 i = y; 490 } 491 y = i << 4; 492 if (y !== 0) { 493 n -= 4; 494 i = y; 495 } 496 y = i << 2; 497 if (y !== 0) { 498 n -= 2; 499 i = y; 500 } 501 return n - ((i << 1) >>> 31); 502 } 503 static numberOfLeadingZeros(i) { 504 // HD, Figure 5-6 505 if (i === 0) { 506 return 32; 507 } 508 let n = 1; 509 if (i >>> 16 === 0) { 510 n += 16; 511 i <<= 16; 512 } 513 if (i >>> 24 === 0) { 514 n += 8; 515 i <<= 8; 516 } 517 if (i >>> 28 === 0) { 518 n += 4; 519 i <<= 4; 520 } 521 if (i >>> 30 === 0) { 522 n += 2; 523 i <<= 2; 524 } 525 n -= i >>> 31; 526 return n; 527 } 528 static toHexString(i) { 529 return i.toString(16); 530 } 531 static toBinaryString(intNumber) { 532 return String(parseInt(String(intNumber), 2)); 533 } 534 // 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. 535 // Returns: 536 // the number of one-bits in the two's complement binary representation of the specified int value. 537 static bitCount(i) { 538 // HD, Figure 5-2 539 i = i - ((i >>> 1) & 0x55555555); 540 i = (i & 0x33333333) + ((i >>> 2) & 0x33333333); 541 i = (i + (i >>> 4)) & 0x0f0f0f0f; 542 i = i + (i >>> 8); 543 i = i + (i >>> 16); 544 return i & 0x3f; 545 } 546 static truncDivision(dividend, divisor) { 547 return Math.trunc(dividend / divisor); 548 } 549 /** 550 * Converts A string to an integer. 551 * @param s A string to convert into a number. 552 * @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. 553 */ 554 static parseInt(num, radix = undefined) { 555 return parseInt(num, radix); 556 } 557 } 558 Integer.MIN_VALUE_32_BITS = -2147483648; 559 Integer.MAX_VALUE = Number.MAX_SAFE_INTEGER; 560 561 /* 562 * Copyright 2007 ZXing authors 563 * 564 * Licensed under the Apache License, Version 2.0 (the "License"); 565 * you may not use this file except in compliance with the License. 566 * You may obtain a copy of the License at 567 * 568 * http://www.apache.org/licenses/LICENSE-2.0 569 * 570 * Unless required by applicable law or agreed to in writing, software 571 * distributed under the License is distributed on an "AS IS" BASIS, 572 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 573 * See the License for the specific language governing permissions and 574 * limitations under the License. 575 */ 576 /** 577 * <p>A simple, fast array of bits, represented compactly by an array of ints internally.</p> 578 * 579 * @author Sean Owen 580 */ 581 class BitArray /*implements Cloneable*/ { 582 // public constructor() { 583 // this.size = 0 584 // this.bits = new Int32Array(1) 585 // } 586 // public constructor(size?: number /*int*/) { 587 // if (undefined === size) { 588 // this.size = 0 589 // } else { 590 // this.size = size 591 // } 592 // this.bits = this.makeArray(size) 593 // } 594 // For testing only 595 constructor(size /*int*/, bits) { 596 if (undefined === size) { 597 this.size = 0; 598 this.bits = new Int32Array(1); 599 } 600 else { 601 this.size = size; 602 if (undefined === bits || null === bits) { 603 this.bits = BitArray.makeArray(size); 604 } 605 else { 606 this.bits = bits; 607 } 608 } 609 } 610 getSize() { 611 return this.size; 612 } 613 getSizeInBytes() { 614 return Math.floor((this.size + 7) / 8); 615 } 616 ensureCapacity(size /*int*/) { 617 if (size > this.bits.length * 32) { 618 const newBits = BitArray.makeArray(size); 619 System.arraycopy(this.bits, 0, newBits, 0, this.bits.length); 620 this.bits = newBits; 621 } 622 } 623 /** 624 * @param i bit to get 625 * @return true iff bit i is set 626 */ 627 get(i /*int*/) { 628 return (this.bits[Math.floor(i / 32)] & (1 << (i & 0x1F))) !== 0; 629 } 630 /** 631 * Sets bit i. 632 * 633 * @param i bit to set 634 */ 635 set(i /*int*/) { 636 this.bits[Math.floor(i / 32)] |= 1 << (i & 0x1F); 637 } 638 /** 639 * Flips bit i. 640 * 641 * @param i bit to set 642 */ 643 flip(i /*int*/) { 644 this.bits[Math.floor(i / 32)] ^= 1 << (i & 0x1F); 645 } 646 /** 647 * @param from first bit to check 648 * @return index of first bit that is set, starting from the given index, or size if none are set 649 * at or beyond this given index 650 * @see #getNextUnset(int) 651 */ 652 getNextSet(from /*int*/) { 653 const size = this.size; 654 if (from >= size) { 655 return size; 656 } 657 const bits = this.bits; 658 let bitsOffset = Math.floor(from / 32); 659 let currentBits = bits[bitsOffset]; 660 // mask off lesser bits first 661 currentBits &= ~((1 << (from & 0x1F)) - 1); 662 const length = bits.length; 663 while (currentBits === 0) { 664 if (++bitsOffset === length) { 665 return size; 666 } 667 currentBits = bits[bitsOffset]; 668 } 669 const result = (bitsOffset * 32) + Integer.numberOfTrailingZeros(currentBits); 670 return result > size ? size : result; 671 } 672 /** 673 * @param from index to start looking for unset bit 674 * @return index of next unset bit, or {@code size} if none are unset until the end 675 * @see #getNextSet(int) 676 */ 677 getNextUnset(from /*int*/) { 678 const size = this.size; 679 if (from >= size) { 680 return size; 681 } 682 const bits = this.bits; 683 let bitsOffset = Math.floor(from / 32); 684 let currentBits = ~bits[bitsOffset]; 685 // mask off lesser bits first 686 currentBits &= ~((1 << (from & 0x1F)) - 1); 687 const length = bits.length; 688 while (currentBits === 0) { 689 if (++bitsOffset === length) { 690 return size; 691 } 692 currentBits = ~bits[bitsOffset]; 693 } 694 const result = (bitsOffset * 32) + Integer.numberOfTrailingZeros(currentBits); 695 return result > size ? size : result; 696 } 697 /** 698 * Sets a block of 32 bits, starting at bit i. 699 * 700 * @param i first bit to set 701 * @param newBits the new value of the next 32 bits. Note again that the least-significant bit 702 * corresponds to bit i, the next-least-significant to i+1, and so on. 703 */ 704 setBulk(i /*int*/, newBits /*int*/) { 705 this.bits[Math.floor(i / 32)] = newBits; 706 } 707 /** 708 * Sets a range of bits. 709 * 710 * @param start start of range, inclusive. 711 * @param end end of range, exclusive 712 */ 713 setRange(start /*int*/, end /*int*/) { 714 if (end < start || start < 0 || end > this.size) { 715 throw new IllegalArgumentException(); 716 } 717 if (end === start) { 718 return; 719 } 720 end--; // will be easier to treat this as the last actually set bit -- inclusive 721 const firstInt = Math.floor(start / 32); 722 const lastInt = Math.floor(end / 32); 723 const bits = this.bits; 724 for (let i = firstInt; i <= lastInt; i++) { 725 const firstBit = i > firstInt ? 0 : start & 0x1F; 726 const lastBit = i < lastInt ? 31 : end & 0x1F; 727 // Ones from firstBit to lastBit, inclusive 728 const mask = (2 << lastBit) - (1 << firstBit); 729 bits[i] |= mask; 730 } 731 } 732 /** 733 * Clears all bits (sets to false). 734 */ 735 clear() { 736 const max = this.bits.length; 737 const bits = this.bits; 738 for (let i = 0; i < max; i++) { 739 bits[i] = 0; 740 } 741 } 742 /** 743 * Efficient method to check if a range of bits is set, or not set. 744 * 745 * @param start start of range, inclusive. 746 * @param end end of range, exclusive 747 * @param value if true, checks that bits in range are set, otherwise checks that they are not set 748 * @return true iff all bits are set or not set in range, according to value argument 749 * @throws IllegalArgumentException if end is less than start or the range is not contained in the array 750 */ 751 isRange(start /*int*/, end /*int*/, value) { 752 if (end < start || start < 0 || end > this.size) { 753 throw new IllegalArgumentException(); 754 } 755 if (end === start) { 756 return true; // empty range matches 757 } 758 end--; // will be easier to treat this as the last actually set bit -- inclusive 759 const firstInt = Math.floor(start / 32); 760 const lastInt = Math.floor(end / 32); 761 const bits = this.bits; 762 for (let i = firstInt; i <= lastInt; i++) { 763 const firstBit = i > firstInt ? 0 : start & 0x1F; 764 const lastBit = i < lastInt ? 31 : end & 0x1F; 765 // Ones from firstBit to lastBit, inclusive 766 const mask = (2 << lastBit) - (1 << firstBit) & 0xFFFFFFFF; 767 // TYPESCRIPTPORT: & 0xFFFFFFFF added to discard anything after 32 bits, as ES has 53 bits 768 // Return false if we're looking for 1s and the masked bits[i] isn't all 1s (is: that, 769 // equals the mask, or we're looking for 0s and the masked portion is not all 0s 770 if ((bits[i] & mask) !== (value ? mask : 0)) { 771 return false; 772 } 773 } 774 return true; 775 } 776 appendBit(bit) { 777 this.ensureCapacity(this.size + 1); 778 if (bit) { 779 this.bits[Math.floor(this.size / 32)] |= 1 << (this.size & 0x1F); 780 } 781 this.size++; 782 } 783 /** 784 * Appends the least-significant bits, from value, in order from most-significant to 785 * least-significant. For example, appending 6 bits from 0x000001E will append the bits 786 * 0, 1, 1, 1, 1, 0 in that order. 787 * 788 * @param value {@code int} containing bits to append 789 * @param numBits bits from value to append 790 */ 791 appendBits(value /*int*/, numBits /*int*/) { 792 if (numBits < 0 || numBits > 32) { 793 throw new IllegalArgumentException('Num bits must be between 0 and 32'); 794 } 795 this.ensureCapacity(this.size + numBits); 796 // const appendBit = this.appendBit; 797 for (let numBitsLeft = numBits; numBitsLeft > 0; numBitsLeft--) { 798 this.appendBit(((value >> (numBitsLeft - 1)) & 0x01) === 1); 799 } 800 } 801 appendBitArray(other) { 802 const otherSize = other.size; 803 this.ensureCapacity(this.size + otherSize); 804 // const appendBit = this.appendBit; 805 for (let i = 0; i < otherSize; i++) { 806 this.appendBit(other.get(i)); 807 } 808 } 809 xor(other) { 810 if (this.size !== other.size) { 811 throw new IllegalArgumentException('Sizes don\'t match'); 812 } 813 const bits = this.bits; 814 for (let i = 0, length = bits.length; i < length; i++) { 815 // The last int could be incomplete (i.e. not have 32 bits in 816 // it) but there is no problem since 0 XOR 0 == 0. 817 bits[i] ^= other.bits[i]; 818 } 819 } 820 /** 821 * 822 * @param bitOffset first bit to start writing 823 * @param array array to write into. Bytes are written most-significant byte first. This is the opposite 824 * of the internal representation, which is exposed by {@link #getBitArray()} 825 * @param offset position in array to start writing 826 * @param numBytes how many bytes to write 827 */ 828 toBytes(bitOffset /*int*/, array, offset /*int*/, numBytes /*int*/) { 829 for (let i = 0; i < numBytes; i++) { 830 let theByte = 0; 831 for (let j = 0; j < 8; j++) { 832 if (this.get(bitOffset)) { 833 theByte |= 1 << (7 - j); 834 } 835 bitOffset++; 836 } 837 array[offset + i] = /*(byte)*/ theByte; 838 } 839 } 840 /** 841 * @return underlying array of ints. The first element holds the first 32 bits, and the least 842 * significant bit is bit 0. 843 */ 844 getBitArray() { 845 return this.bits; 846 } 847 /** 848 * Reverses all bits in the array. 849 */ 850 reverse() { 851 const newBits = new Int32Array(this.bits.length); 852 // reverse all int's first 853 const len = Math.floor((this.size - 1) / 32); 854 const oldBitsLen = len + 1; 855 const bits = this.bits; 856 for (let i = 0; i < oldBitsLen; i++) { 857 let x = bits[i]; 858 x = ((x >> 1) & 0x55555555) | ((x & 0x55555555) << 1); 859 x = ((x >> 2) & 0x33333333) | ((x & 0x33333333) << 2); 860 x = ((x >> 4) & 0x0f0f0f0f) | ((x & 0x0f0f0f0f) << 4); 861 x = ((x >> 8) & 0x00ff00ff) | ((x & 0x00ff00ff) << 8); 862 x = ((x >> 16) & 0x0000ffff) | ((x & 0x0000ffff) << 16); 863 newBits[len - i] = /*(int)*/ x; 864 } 865 // now correct the int's if the bit size isn't a multiple of 32 866 if (this.size !== oldBitsLen * 32) { 867 const leftOffset = oldBitsLen * 32 - this.size; 868 let currentInt = newBits[0] >>> leftOffset; 869 for (let i = 1; i < oldBitsLen; i++) { 870 const nextInt = newBits[i]; 871 currentInt |= nextInt << (32 - leftOffset); 872 newBits[i - 1] = currentInt; 873 currentInt = nextInt >>> leftOffset; 874 } 875 newBits[oldBitsLen - 1] = currentInt; 876 } 877 this.bits = newBits; 878 } 879 static makeArray(size /*int*/) { 880 return new Int32Array(Math.floor((size + 31) / 32)); 881 } 882 /*@Override*/ 883 equals(o) { 884 if (!(o instanceof BitArray)) { 885 return false; 886 } 887 const other = o; 888 return this.size === other.size && Arrays.equals(this.bits, other.bits); 889 } 890 /*@Override*/ 891 hashCode() { 892 return 31 * this.size + Arrays.hashCode(this.bits); 893 } 894 /*@Override*/ 895 toString() { 896 let result = ''; 897 for (let i = 0, size = this.size; i < size; i++) { 898 if ((i & 0x07) === 0) { 899 result += ' '; 900 } 901 result += this.get(i) ? 'X' : '.'; 902 } 903 return result; 904 } 905 /*@Override*/ 906 clone() { 907 return new BitArray(this.size, this.bits.slice()); 908 } 909 /** 910 * converts to boolean array. 911 */ 912 toArray() { 913 let result = []; 914 for (let i = 0, size = this.size; i < size; i++) { 915 result.push(this.get(i)); 916 } 917 return result; 918 } 919 } 920 921 /* 922 * Copyright 2009 ZXing authors 923 * 924 * Licensed under the Apache License, Version 2.0 (the "License"); 925 * you may not use this file except in compliance with the License. 926 * You may obtain a copy of the License at 927 * 928 * http://www.apache.org/licenses/LICENSE-2.0 929 * 930 * Unless required by applicable law or agreed to in writing, software 931 * distributed under the License is distributed on an "AS IS" BASIS, 932 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 933 * See the License for the specific language governing permissions and 934 * limitations under the License. 935 */ 936 /*namespace com.google.zxing {*/ 937 /** 938 * Encapsulates a type of hint that a caller may pass to a barcode reader to help it 939 * more quickly or accurately decode it. It is up to implementations to decide what, 940 * if anything, to do with the information that is supplied. 941 * 942 * @author Sean Owen 943 * @author [email protected] (Daniel Switkin) 944 * @see Reader#decode(BinaryBitmap,java.util.Map) 945 */ 946 var DecodeHintType; 947 (function (DecodeHintType) { 948 /** 949 * Unspecified, application-specific hint. Maps to an unspecified {@link Object}. 950 */ 951 DecodeHintType[DecodeHintType["OTHER"] = 0] = "OTHER"; /*(Object.class)*/ 952 /** 953 * Image is a pure monochrome image of a barcode. Doesn't matter what it maps to; 954 * use {@link Boolean#TRUE}. 955 */ 956 DecodeHintType[DecodeHintType["PURE_BARCODE"] = 1] = "PURE_BARCODE"; /*(Void.class)*/ 957 /** 958 * Image is known to be of one of a few possible formats. 959 * Maps to a {@link List} of {@link BarcodeFormat}s. 960 */ 961 DecodeHintType[DecodeHintType["POSSIBLE_FORMATS"] = 2] = "POSSIBLE_FORMATS"; /*(List.class)*/ 962 /** 963 * Spend more time to try to find a barcode; optimize for accuracy, not speed. 964 * Doesn't matter what it maps to; use {@link Boolean#TRUE}. 965 */ 966 DecodeHintType[DecodeHintType["TRY_HARDER"] = 3] = "TRY_HARDER"; /*(Void.class)*/ 967 /** 968 * Specifies what character encoding to use when decoding, where applicable (type String) 969 */ 970 DecodeHintType[DecodeHintType["CHARACTER_SET"] = 4] = "CHARACTER_SET"; /*(String.class)*/ 971 /** 972 * Allowed lengths of encoded data -- reject anything else. Maps to an {@code Int32Array}. 973 */ 974 DecodeHintType[DecodeHintType["ALLOWED_LENGTHS"] = 5] = "ALLOWED_LENGTHS"; /*(Int32Array.class)*/ 975 /** 976 * Assume Code 39 codes employ a check digit. Doesn't matter what it maps to; 977 * use {@link Boolean#TRUE}. 978 */ 979 DecodeHintType[DecodeHintType["ASSUME_CODE_39_CHECK_DIGIT"] = 6] = "ASSUME_CODE_39_CHECK_DIGIT"; /*(Void.class)*/ 980 /** 981 * Enable extended mode for Code 39 codes. Doesn't matter what it maps to; 982 * use {@link Boolean#TRUE}. 983 */ 984 DecodeHintType[DecodeHintType["ENABLE_CODE_39_EXTENDED_MODE"] = 7] = "ENABLE_CODE_39_EXTENDED_MODE"; /*(Void.class)*/ 985 /** 986 * Assume the barcode is being processed as a GS1 barcode, and modify behavior as needed. 987 * For example this affects FNC1 handling for Code 128 (aka GS1-128). Doesn't matter what it maps to; 988 * use {@link Boolean#TRUE}. 989 */ 990 DecodeHintType[DecodeHintType["ASSUME_GS1"] = 8] = "ASSUME_GS1"; /*(Void.class)*/ 991 /** 992 * If true, return the start and end digits in a Codabar barcode instead of stripping them. They 993 * are alpha, whereas the rest are numeric. By default, they are stripped, but this causes them 994 * to not be. Doesn't matter what it maps to; use {@link Boolean#TRUE}. 995 */ 996 DecodeHintType[DecodeHintType["RETURN_CODABAR_START_END"] = 9] = "RETURN_CODABAR_START_END"; /*(Void.class)*/ 997 /** 998 * The caller needs to be notified via callback when a possible {@link ResultPoint} 999 * is found. Maps to a {@link ResultPointCallback}. 1000 */ 1001 DecodeHintType[DecodeHintType["NEED_RESULT_POINT_CALLBACK"] = 10] = "NEED_RESULT_POINT_CALLBACK"; /*(ResultPointCallback.class)*/ 1002 /** 1003 * Allowed extension lengths for EAN or UPC barcodes. Other formats will ignore this. 1004 * Maps to an {@code Int32Array} of the allowed extension lengths, for example [2], [5], or [2, 5]. 1005 * If it is optional to have an extension, do not set this hint. If this is set, 1006 * and a UPC or EAN barcode is found but an extension is not, then no result will be returned 1007 * at all. 1008 */ 1009 DecodeHintType[DecodeHintType["ALLOWED_EAN_EXTENSIONS"] = 11] = "ALLOWED_EAN_EXTENSIONS"; /*(Int32Array.class)*/ 1010 // End of enumeration values. 1011 /** 1012 * Data type the hint is expecting. 1013 * Among the possible values the {@link Void} stands out as being used for 1014 * hints that do not expect a value to be supplied (flag hints). Such hints 1015 * will possibly have their value ignored, or replaced by a 1016 * {@link Boolean#TRUE}. Hint suppliers should probably use 1017 * {@link Boolean#TRUE} as directed by the actual hint documentation. 1018 */ 1019 // private valueType: Class<?> 1020 // DecodeHintType(valueType: Class<?>) { 1021 // this.valueType = valueType 1022 // } 1023 // public getValueType(): Class<?> { 1024 // return valueType 1025 // } 1026 })(DecodeHintType || (DecodeHintType = {})); 1027 var DecodeHintType$1 = DecodeHintType; 1028 1029 /** 1030 * Custom Error class of type Exception. 1031 */ 1032 class FormatException extends Exception { 1033 static getFormatInstance() { 1034 return new FormatException(); 1035 } 1036 } 1037 FormatException.kind = 'FormatException'; 1038 1039 /* 1040 * Copyright 2008 ZXing authors 1041 * 1042 * Licensed under the Apache License, Version 2.0 (the "License"); 1043 * you may not use this file except in compliance with the License. 1044 * You may obtain a copy of the License at 1045 * 1046 * http://www.apache.org/licenses/LICENSE-2.0 1047 * 1048 * Unless required by applicable law or agreed to in writing, software 1049 * distributed under the License is distributed on an "AS IS" BASIS, 1050 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1051 * See the License for the specific language governing permissions and 1052 * limitations under the License. 1053 */ 1054 /*import java.util.HashMap;*/ 1055 /*import java.util.Map;*/ 1056 var CharacterSetValueIdentifiers; 1057 (function (CharacterSetValueIdentifiers) { 1058 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["Cp437"] = 0] = "Cp437"; 1059 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_1"] = 1] = "ISO8859_1"; 1060 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_2"] = 2] = "ISO8859_2"; 1061 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_3"] = 3] = "ISO8859_3"; 1062 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_4"] = 4] = "ISO8859_4"; 1063 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_5"] = 5] = "ISO8859_5"; 1064 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_6"] = 6] = "ISO8859_6"; 1065 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_7"] = 7] = "ISO8859_7"; 1066 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_8"] = 8] = "ISO8859_8"; 1067 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_9"] = 9] = "ISO8859_9"; 1068 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_10"] = 10] = "ISO8859_10"; 1069 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_11"] = 11] = "ISO8859_11"; 1070 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_13"] = 12] = "ISO8859_13"; 1071 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_14"] = 13] = "ISO8859_14"; 1072 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_15"] = 14] = "ISO8859_15"; 1073 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ISO8859_16"] = 15] = "ISO8859_16"; 1074 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["SJIS"] = 16] = "SJIS"; 1075 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["Cp1250"] = 17] = "Cp1250"; 1076 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["Cp1251"] = 18] = "Cp1251"; 1077 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["Cp1252"] = 19] = "Cp1252"; 1078 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["Cp1256"] = 20] = "Cp1256"; 1079 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["UnicodeBigUnmarked"] = 21] = "UnicodeBigUnmarked"; 1080 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["UTF8"] = 22] = "UTF8"; 1081 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["ASCII"] = 23] = "ASCII"; 1082 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["Big5"] = 24] = "Big5"; 1083 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["GB18030"] = 25] = "GB18030"; 1084 CharacterSetValueIdentifiers[CharacterSetValueIdentifiers["EUC_KR"] = 26] = "EUC_KR"; 1085 })(CharacterSetValueIdentifiers || (CharacterSetValueIdentifiers = {})); 1086 /** 1087 * Encapsulates a Character Set ECI, according to "Extended Channel Interpretations" 5.3.1.1 1088 * of ISO 18004. 1089 * 1090 * @author Sean Owen 1091 */ 1092 class CharacterSetECI { 1093 constructor(valueIdentifier, valuesParam, name, ...otherEncodingNames) { 1094 this.valueIdentifier = valueIdentifier; 1095 this.name = name; 1096 if (typeof valuesParam === 'number') { 1097 this.values = Int32Array.from([valuesParam]); 1098 } 1099 else { 1100 this.values = valuesParam; 1101 } 1102 this.otherEncodingNames = otherEncodingNames; 1103 CharacterSetECI.VALUE_IDENTIFIER_TO_ECI.set(valueIdentifier, this); 1104 CharacterSetECI.NAME_TO_ECI.set(name, this); 1105 const values = this.values; 1106 for (let i = 0, length = values.length; i !== length; i++) { 1107 const v = values[i]; 1108 CharacterSetECI.VALUES_TO_ECI.set(v, this); 1109 } 1110 for (const otherName of otherEncodingNames) { 1111 CharacterSetECI.NAME_TO_ECI.set(otherName, this); 1112 } 1113 } 1114 // CharacterSetECI(value: number /*int*/) { 1115 // this(new Int32Array {value}) 1116 // } 1117 // CharacterSetECI(value: number /*int*/, String... otherEncodingNames) { 1118 // this.values = new Int32Array {value} 1119 // this.otherEncodingNames = otherEncodingNames 1120 // } 1121 // CharacterSetECI(values: Int32Array, String... otherEncodingNames) { 1122 // this.values = values 1123 // this.otherEncodingNames = otherEncodingNames 1124 // } 1125 getValueIdentifier() { 1126 return this.valueIdentifier; 1127 } 1128 getName() { 1129 return this.name; 1130 } 1131 getValue() { 1132 return this.values[0]; 1133 } 1134 /** 1135 * @param value character set ECI value 1136 * @return {@code CharacterSetECI} representing ECI of given value, or null if it is legal but 1137 * unsupported 1138 * @throws FormatException if ECI value is invalid 1139 */ 1140 static getCharacterSetECIByValue(value /*int*/) { 1141 if (value < 0 || value >= 900) { 1142 throw new FormatException('incorect value'); 1143 } 1144 const characterSet = CharacterSetECI.VALUES_TO_ECI.get(value); 1145 if (undefined === characterSet) { 1146 throw new FormatException('incorect value'); 1147 } 1148 return characterSet; 1149 } 1150 /** 1151 * @param name character set ECI encoding name 1152 * @return CharacterSetECI representing ECI for character encoding, or null if it is legal 1153 * but unsupported 1154 */ 1155 static getCharacterSetECIByName(name) { 1156 const characterSet = CharacterSetECI.NAME_TO_ECI.get(name); 1157 if (undefined === characterSet) { 1158 throw new FormatException('incorect value'); 1159 } 1160 return characterSet; 1161 } 1162 equals(o) { 1163 if (!(o instanceof CharacterSetECI)) { 1164 return false; 1165 } 1166 const other = o; 1167 return this.getName() === other.getName(); 1168 } 1169 } 1170 CharacterSetECI.VALUE_IDENTIFIER_TO_ECI = new Map(); 1171 CharacterSetECI.VALUES_TO_ECI = new Map(); 1172 CharacterSetECI.NAME_TO_ECI = new Map(); 1173 // Enum name is a Java encoding valid for java.lang and java.io 1174 // TYPESCRIPTPORT: changed the main label for ISO as the TextEncoder did not recognized them in the form from java 1175 // (eg ISO8859_1 must be ISO88591 or ISO8859-1 or ISO-8859-1) 1176 // later on: well, except 16 wich does not work with ISO885916 so used ISO-8859-1 form for default 1177 CharacterSetECI.Cp437 = new CharacterSetECI(CharacterSetValueIdentifiers.Cp437, Int32Array.from([0, 2]), 'Cp437'); 1178 CharacterSetECI.ISO8859_1 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_1, Int32Array.from([1, 3]), 'ISO-8859-1', 'ISO88591', 'ISO8859_1'); 1179 CharacterSetECI.ISO8859_2 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_2, 4, 'ISO-8859-2', 'ISO88592', 'ISO8859_2'); 1180 CharacterSetECI.ISO8859_3 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_3, 5, 'ISO-8859-3', 'ISO88593', 'ISO8859_3'); 1181 CharacterSetECI.ISO8859_4 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_4, 6, 'ISO-8859-4', 'ISO88594', 'ISO8859_4'); 1182 CharacterSetECI.ISO8859_5 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_5, 7, 'ISO-8859-5', 'ISO88595', 'ISO8859_5'); 1183 CharacterSetECI.ISO8859_6 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_6, 8, 'ISO-8859-6', 'ISO88596', 'ISO8859_6'); 1184 CharacterSetECI.ISO8859_7 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_7, 9, 'ISO-8859-7', 'ISO88597', 'ISO8859_7'); 1185 CharacterSetECI.ISO8859_8 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_8, 10, 'ISO-8859-8', 'ISO88598', 'ISO8859_8'); 1186 CharacterSetECI.ISO8859_9 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_9, 11, 'ISO-8859-9', 'ISO88599', 'ISO8859_9'); 1187 CharacterSetECI.ISO8859_10 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_10, 12, 'ISO-8859-10', 'ISO885910', 'ISO8859_10'); 1188 CharacterSetECI.ISO8859_11 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_11, 13, 'ISO-8859-11', 'ISO885911', 'ISO8859_11'); 1189 CharacterSetECI.ISO8859_13 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_13, 15, 'ISO-8859-13', 'ISO885913', 'ISO8859_13'); 1190 CharacterSetECI.ISO8859_14 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_14, 16, 'ISO-8859-14', 'ISO885914', 'ISO8859_14'); 1191 CharacterSetECI.ISO8859_15 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_15, 17, 'ISO-8859-15', 'ISO885915', 'ISO8859_15'); 1192 CharacterSetECI.ISO8859_16 = new CharacterSetECI(CharacterSetValueIdentifiers.ISO8859_16, 18, 'ISO-8859-16', 'ISO885916', 'ISO8859_16'); 1193 CharacterSetECI.SJIS = new CharacterSetECI(CharacterSetValueIdentifiers.SJIS, 20, 'SJIS', 'Shift_JIS'); 1194 CharacterSetECI.Cp1250 = new CharacterSetECI(CharacterSetValueIdentifiers.Cp1250, 21, 'Cp1250', 'windows-1250'); 1195 CharacterSetECI.Cp1251 = new CharacterSetECI(CharacterSetValueIdentifiers.Cp1251, 22, 'Cp1251', 'windows-1251'); 1196 CharacterSetECI.Cp1252 = new CharacterSetECI(CharacterSetValueIdentifiers.Cp1252, 23, 'Cp1252', 'windows-1252'); 1197 CharacterSetECI.Cp1256 = new CharacterSetECI(CharacterSetValueIdentifiers.Cp1256, 24, 'Cp1256', 'windows-1256'); 1198 CharacterSetECI.UnicodeBigUnmarked = new CharacterSetECI(CharacterSetValueIdentifiers.UnicodeBigUnmarked, 25, 'UnicodeBigUnmarked', 'UTF-16BE', 'UnicodeBig'); 1199 CharacterSetECI.UTF8 = new CharacterSetECI(CharacterSetValueIdentifiers.UTF8, 26, 'UTF8', 'UTF-8'); 1200 CharacterSetECI.ASCII = new CharacterSetECI(CharacterSetValueIdentifiers.ASCII, Int32Array.from([27, 170]), 'ASCII', 'US-ASCII'); 1201 CharacterSetECI.Big5 = new CharacterSetECI(CharacterSetValueIdentifiers.Big5, 28, 'Big5'); 1202 CharacterSetECI.GB18030 = new CharacterSetECI(CharacterSetValueIdentifiers.GB18030, 29, 'GB18030', 'GB2312', 'EUC_CN', 'GBK'); 1203 CharacterSetECI.EUC_KR = new CharacterSetECI(CharacterSetValueIdentifiers.EUC_KR, 30, 'EUC_KR', 'EUC-KR'); 1204 1205 /** 1206 * Custom Error class of type Exception. 1207 */ 1208 class UnsupportedOperationException extends Exception { 1209 } 1210 UnsupportedOperationException.kind = 'UnsupportedOperationException'; 1211 1212 /** 1213 * Responsible for en/decoding strings. 1214 */ 1215 class StringEncoding { 1216 /** 1217 * Decodes some Uint8Array to a string format. 1218 */ 1219 static decode(bytes, encoding) { 1220 const encodingName = this.encodingName(encoding); 1221 if (this.customDecoder) { 1222 return this.customDecoder(bytes, encodingName); 1223 } 1224 // Increases browser support. 1225 if (typeof TextDecoder === 'undefined' || this.shouldDecodeOnFallback(encodingName)) { 1226 return this.decodeFallback(bytes, encodingName); 1227 } 1228 return new TextDecoder(encodingName).decode(bytes); 1229 } 1230 /** 1231 * Checks if the decoding method should use the fallback for decoding
1231 1232 * once Node TextDecoder doesn't support all encoding formats. 1233 * 1234 * @param encodingName 1235 */ 1236 static shouldDecodeOnFallback(encodingName) { 1237 return !StringEncoding.isBrowser() && encodingName === 'ISO-8859-1'; 1238 } 1239 /** 1240 * Encodes some string into a Uint8Array. 1241 */ 1242 static encode(s, encoding) { 1243 const encodingName = this.encodingName(encoding); 1244 if (this.customEncoder) { 1245 return this.customEncoder(s, encodingName); 1246 } 1247 // Increases browser support. 1248 if (typeof TextEncoder === 'undefined') { 1249 return this.encodeFallback(s); 1250 } 1251 // TextEncoder only encodes to UTF8 by default as specified by encoding.spec.whatwg.org 1252 return new TextEncoder().encode(s); 1253 } 1254 static isBrowser() { 1255 return (typeof window !== 'undefined' && {}.toString.call(window) === '[object Window]'); 1256 } 1257 /** 1258 * Returns the string value from some encoding character set. 1259 */ 1260 static encodingName(encoding) { 1261 return typeof encoding === 'string' 1262 ? encoding 1263 : encoding.getName(); 1264 } 1265 /** 1266 * Returns character set from some encoding character set. 1267 */ 1268 static encodingCharacterSet(encoding) { 1269 if (encoding instanceof CharacterSetECI) { 1270 return encoding; 1271 } 1272 return CharacterSetECI.getCharacterSetECIByName(encoding); 1273 } 1274 /** 1275 * Runs a fallback for the native decoding funcion. 1276 */ 1277 static decodeFallback(bytes, encoding) { 1278 const characterSet = this.encodingCharacterSet(encoding); 1279 if (StringEncoding.isDecodeFallbackSupported(characterSet)) { 1280 let s = ''; 1281 for (let i = 0, length = bytes.length; i < length; i++) { 1282 let h = bytes[i].toString(16); 1283 if (h.length < 2) { 1284 h = '0' + h; 1285 } 1286 s += '%' + h; 1287 } 1288 return decodeURIComponent(s); 1289 } 1290 if (characterSet.equals(CharacterSetECI.UnicodeBigUnmarked)) { 1291 return String.fromCharCode.apply(null, new Uint16Array(bytes.buffer)); 1292 } 1293 throw new UnsupportedOperationException(`Encoding ${this.encodingName(encoding)} not supported by fallback.`); 1294 } 1295 static isDecodeFallbackSupported(characterSet) { 1296 return characterSet.equals(CharacterSetECI.UTF8) || 1297 characterSet.equals(CharacterSetECI.ISO8859_1) || 1298 characterSet.equals(CharacterSetECI.ASCII); 1299 } 1300 /** 1301 * Runs a fallback for the native encoding funcion. 1302 * 1303 * @see https://stackoverflow.com/a/17192845/4367683 1304 */ 1305 static encodeFallback(s) { 1306 const encodedURIstring = btoa(unescape(encodeURIComponent(s))); 1307 const charList = encodedURIstring.split(''); 1308 const uintArray = []; 1309 for (let i = 0; i < charList.length; i++) { 1310 uintArray.push(charList[i].charCodeAt(0)); 1311 } 1312 return new Uint8Array(uintArray); 1313 } 1314 } 1315 1316 /* 1317 * Copyright (C) 2010 ZXing authors 1318 * 1319 * Licensed under the Apache License, Version 2.0 (the "License");
1320 * you may not use this file except in compliance with the License. 1321 * You may obtain a copy of the License at 1322 * 1323 * http://www.apache.org/licenses/LICENSE-2.0 1324 * 1325 * Unless required by applicable law or agreed to in writing, software 1326 * distributed under the License is distributed on an "AS IS" BASIS, 1327 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1328 * See the License for the specific language governing permissions and 1329 * limitations under the License. 1330
vendor: 13,197 bytes, lines 1330-1662
1330*/ 1331 /** 1332 * Common string-related functions. 1333 * 1334 * @author Sean Owen 1335 * @author Alex Dupre 1336 */ 1337 class StringUtils { 1338 // SHIFT_JIS.equalsIgnoreCase(PLATFORM_DEFAULT_ENCODING) || 1339 // EUC_JP.equalsIgnoreCase(PLATFORM_DEFAULT_ENCODING); 1340 static castAsNonUtf8Char(code, encoding = null) { 1341 // ISO 8859-1 is the Java default as UTF-8 is JavaScripts 1342 // you can see this method as a Java version of String.fromCharCode 1343 const e = encoding ? encoding.getName() : this.ISO88591; 1344 // use passed format (fromCharCode will return UTF8 encoding) 1345 return StringEncoding.decode(new Uint8Array([code]), e); 1346 } 1347 /** 1348 * @param bytes bytes encoding a string, whose encoding should be guessed 1349 * @param hints decode hints if applicable 1350 * @return name of guessed encoding; at the moment will only guess one of: 1351 * {@link #SHIFT_JIS}, {@link #UTF8}, {@link #ISO88591}, or the platform 1352 * default encoding if none of these can possibly be correct 1353 */ 1354 static guessEncoding(bytes, hints) { 1355 if (hints !== null && hints !== undefined && undefined !== hints.get(DecodeHintType$1.CHARACTER_SET)) { 1356 return hints.get(DecodeHintType$1.CHARACTER_SET).toString(); 1357 } 1358 // For now, merely tries to distinguish ISO-8859-1, UTF-8 and Shift_JIS, 1359 // which should be by far the most common encodings. 1360 const length = bytes.length; 1361 let canBeISO88591 = true; 1362 let canBeShiftJIS = true; 1363 let canBeUTF8 = true; 1364 let utf8BytesLeft = 0; 1365 // int utf8LowChars = 0 1366 let utf2BytesChars = 0; 1367 let utf3BytesChars = 0; 1368 let utf4BytesChars = 0; 1369 let sjisBytesLeft = 0; 1370 // int sjisLowChars = 0 1371 let sjisKatakanaChars = 0; 1372 // int sjisDoubleBytesChars = 0 1373 let sjisCurKatakanaWordLength = 0; 1374 let sjisCurDoubleBytesWordLength = 0; 1375 let sjisMaxKatakanaWordLength = 0; 1376 let sjisMaxDoubleBytesWordLength = 0; 1377 // int isoLowChars = 0 1378 // int isoHighChars = 0 1379 let isoHighOther = 0; 1380 const utf8bom = bytes.length > 3 && 1381 bytes[0] === /*(byte) */ 0xEF && 1382 bytes[1] === /*(byte) */ 0xBB && 1383 bytes[2] === /*(byte) */ 0xBF; 1384 for (let i = 0; i < length && (canBeISO88591 || canBeShiftJIS || canBeUTF8); i++) { 1385 const value = bytes[i] & 0xFF; 1386 // UTF-8 stuff 1387 if (canBeUTF8) { 1388 if (utf8BytesLeft > 0) { 1389 if ((value & 0x80) === 0) { 1390 canBeUTF8 = false; 1391 } 1392 else { 1393 utf8BytesLeft--; 1394 } 1395 } 1396 else if ((value & 0x80) !== 0) { 1397 if ((value & 0x40) === 0) { 1398 canBeUTF8 = false; 1399 } 1400 else { 1401 utf8BytesLeft++; 1402 if ((value & 0x20) === 0) { 1403 utf2BytesChars++; 1404 } 1405 else { 1406 utf8BytesLeft++; 1407 if ((value & 0x10) === 0) { 1408 utf3BytesChars++; 1409 } 1410 else { 1411 utf8BytesLeft++; 1412 if ((value & 0x08) === 0) { 1413 utf4BytesChars++; 1414 } 1415 else { 1416 canBeUTF8 = false; 1417 } 1418 } 1419 } 1420 } 1421 } // else { 1422 // utf8LowChars++ 1423 // } 1424 } 1425 // ISO-8859-1 stuff 1426 if (canBeISO88591) { 1427 if (value > 0x7F && value < 0xA0) { 1428 canBeISO88591 = false; 1429 } 1430 else if (value > 0x9F) { 1431 if (value < 0xC0 || value === 0xD7 || value === 0xF7) { 1432 isoHighOther++; 1433 } // else { 1434 // isoHighChars++ 1435 // } 1436 } // else { 1437 // isoLowChars++ 1438 // } 1439 } 1440 // Shift_JIS stuff 1441 if (canBeShiftJIS) { 1442 if (sjisBytesLeft > 0) { 1443 if (value < 0x40 || value === 0x7F || value > 0xFC) { 1444 canBeShiftJIS = false; 1445 } 1446 else { 1447 sjisBytesLeft--; 1448 } 1449 } 1450 else if (value === 0x80 || value === 0xA0 || value > 0xEF) { 1451 canBeShiftJIS = false; 1452 } 1453 else if (value > 0xA0 && value < 0xE0) { 1454 sjisKatakanaChars++; 1455 sjisCurDoubleBytesWordLength = 0; 1456 sjisCurKatakanaWordLength++; 1457 if (sjisCurKatakanaWordLength > sjisMaxKatakanaWordLength) { 1458 sjisMaxKatakanaWordLength = sjisCurKatakanaWordLength; 1459 } 1460 } 1461 else if (value > 0x7F) { 1462 sjisBytesLeft++; 1463 // sjisDoubleBytesChars++ 1464 sjisCurKatakanaWordLength = 0; 1465 sjisCurDoubleBytesWordLength++; 1466 if (sjisCurDoubleBytesWordLength > sjisMaxDoubleBytesWordLength) { 1467 sjisMaxDoubleBytesWordLength = sjisCurDoubleBytesWordLength; 1468 } 1469 } 1470 else { 1471 // sjisLowChars++ 1472 sjisCurKatakanaWordLength = 0; 1473 sjisCurDoubleBytesWordLength = 0; 1474 } 1475 } 1476 } 1477 if (canBeUTF8 && utf8BytesLeft > 0) { 1478 canBeUTF8 = false; 1479 } 1480 if (canBeShiftJIS && sjisBytesLeft > 0) { 1481 canBeShiftJIS = false; 1482 } 1483 // Easy -- if there is BOM or at least 1 valid not-single byte character (and no evidence it can't be UTF-8), done 1484 if (canBeUTF8 && (utf8bom || utf2BytesChars + utf3BytesChars + utf4BytesChars > 0)) { 1485 return StringUtils.UTF8; 1486 } 1487 // Easy -- if assuming Shift_JIS or at least 3 valid consecutive not-ascii characters (and no evidence it can't be), done 1488 if (canBeShiftJIS && (StringUtils.ASSUME_SHIFT_JIS || sjisMaxKatakanaWordLength >= 3 || sjisMaxDoubleBytesWordLength >= 3)) { 1489 return StringUtils.SHIFT_JIS; 1490 } 1491 // Distinguishing Shift_JIS and ISO-8859-1 can be a little tough for short words. The crude heuristic is: 1492 // - If we saw 1493 // - only two consecutive katakana chars in the whole text, or 1494 // - at least 10% of bytes that could be "upper" not-alphanumeric Latin1, 1495 // - then we conclude Shift_JIS, else ISO-8859-1 1496 if (canBeISO88591 && canBeShiftJIS) { 1497 return (sjisMaxKatakanaWordLength === 2 && sjisKatakanaChars === 2) || isoHighOther * 10 >= length 1498 ? StringUtils.SHIFT_JIS : StringUtils.ISO88591; 1499 } 1500 // Otherwise, try in order ISO-8859-1, Shift JIS, UTF-8 and fall back to default platform encoding 1501 if (canBeISO88591) { 1502 return StringUtils.ISO88591; 1503 } 1504 if (canBeShiftJIS) { 1505 return StringUtils.SHIFT_JIS; 1506 } 1507 if (canBeUTF8) { 1508 return StringUtils.UTF8; 1509 } 1510 // Otherwise, we take a wild guess with platform encoding 1511 return StringUtils.PLATFORM_DEFAULT_ENCODING; 1512 } 1513 /** 1514 * 1515 * @see https://stackoverflow.com/a/13439711/4367683 1516 * 1517 * @param append The new string to append. 1518 * @param args Argumets values to be formated. 1519 */ 1520 static format(append, ...args) { 1521 let i = -1; 1522 function callback(exp, p0, p1, p2, p3, p4) { 1523 if (exp === '%%') 1524 return '%'; 1525 if (args[++i] === undefined) 1526 return undefined; 1527 exp = p2 ? parseInt(p2.substr(1)) : undefined; 1528 let base = p3 ? parseInt(p3.substr(1)) : undefined; 1529 let val; 1530 switch (p4) { 1531 case 's': 1532 val = args[i]; 1533 break; 1534 case 'c': 1535 val = args[i][0]; 1536 break; 1537 case 'f': 1538 val = parseFloat(args[i]).toFixed(exp); 1539 break; 1540 case 'p': 1541 val = parseFloat(args[i]).toPrecision(exp); 1542 break; 1543 case 'e': 1544 val = parseFloat(args[i]).toExponential(exp); 1545 break; 1546 case 'x': 1547 val = parseInt(args[i]).toString(base ? base : 16); 1548 break; 1549 case 'd': 1550 val = parseFloat(parseInt(args[i], base ? base : 10).toPrecision(exp)).toFixed(0); 1551 break; 1552 } 1553 val = typeof val === 'object' ? JSON.stringify(val) : (+val).toString(base); 1554 let size = parseInt(p1); /* padding size */ 1555 let ch = p1 && (p1[0] + '') === '0' ? '0' : ' '; /* isnull? */ 1556 while (val.length < size) 1557 val = p0 !== undefined ? val + ch : ch + val; /* isminus? */ 1558 return val; 1559 } 1560 let regex = /%(-)?(0?[0-9]+)?([.][0-9]+)?([#][0-9]+)?([scfpexd%])/g; 1561 return append.replace(regex, callback); 1562 } 1563 /** 1564 * 1565 */ 1566 static getBytes(str, encoding) { 1567 return StringEncoding.encode(str, encoding); 1568 } 1569 /** 1570 * Returns the charcode at the specified index or at index zero. 1571 */ 1572 static getCharCode(str, index = 0) { 1573 return str.charCodeAt(index); 1574 } 1575 /** 1576 * Returns char for given charcode 1577 */ 1578 static getCharAt(charCode) { 1579 return String.fromCharCode(charCode); 1580 } 1581 } 1582 StringUtils.SHIFT_JIS = CharacterSetECI.SJIS.getName(); // "SJIS" 1583 StringUtils.GB2312 = 'GB2312'; 1584 StringUtils.ISO88591 = CharacterSetECI.ISO8859_1.getName(); // "ISO8859_1" 1585 StringUtils.EUC_JP = 'EUC_JP'; 1586 StringUtils.UTF8 = CharacterSetECI.UTF8.getName(); // "UTF8" 1587 StringUtils.PLATFORM_DEFAULT_ENCODING = StringUtils.UTF8; // "UTF8"//Charset.defaultCharset().name() 1588 StringUtils.ASSUME_SHIFT_JIS = false; 1589 1590 class StringBuilder { 1591 constructor(value = '') { 1592 this.value = value; 1593 } 1594 enableDecoding(encoding) { 1595 this.encoding = encoding; 1596 return this; 1597 } 1598 append(s) { 1599 if (typeof s === 'string') { 1600 this.value += s.toString(); 1601 } 1602 else if (this.encoding) { 1603 // use passed format (fromCharCode will return UTF8 encoding) 1604 this.value += StringUtils.castAsNonUtf8Char(s, this.encoding); 1605 } 1606 else { 1607 // correctly converts from UTF-8, but not other encodings 1608 this.value += String.fromCharCode(s); 1609 } 1610 return this; 1611 } 1612 appendChars(str, offset, len) { 1613 for (let i = offset; offset < offset + len; i++) { 1614 this.append(str[i]); 1615 } 1616 return this; 1617 } 1618 length() { 1619 return this.value.length; 1620 } 1621 charAt(n) { 1622 return this.value.charAt(n); 1623 } 1624 deleteCharAt(n) { 1625 this.value = this.value.substr(0, n) + this.value.substring(n + 1); 1626 } 1627 setCharAt(n, c) { 1628 this.value = this.value.substr(0, n) + c + this.value.substr(n + 1); 1629 } 1630 substring(start, end) { 1631 return this.value.substring(start, end); 1632 } 1633 /** 1634 * @note helper method for RSS Expanded 1635 */ 1636 setLengthToZero() { 1637 this.value = ''; 1638 } 1639 toString() { 1640 return this.value; 1641 } 1642 insert(n, c) { 1643 this.value = this.value.substring(0, n) + c + this.value.substring(n); 1644 } 1645 } 1646 1647 /* 1648 * Copyright 2007 ZXing authors 1649 * 1650 * Licensed under the Apache License, Version 2.0 (the "License"); 1651 * you may not use this file except in compliance with the License. 1652 * You may obtain a copy of the License at 1653 * 1654 * http://www.apache.org/licenses/LICENSE-2.0 1655 * 1656 * Unless required by applicable law or agreed to in writing, software 1657 * distributed under the License is distributed on an "AS IS" BASIS, 1658 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1659 * See the License for the specific language governing permissions and 1660 * limitations under the License. 1661 */ 1662 /*
1662* 1663 * <p>Represents a 2D matrix of bits. In function arguments below, and throughout the common 1664 * module, x is the column position, and y is the row position. The ordering is always x, y. 1665 * The origin is at the top-left.</p> 1666 * 1667 * <p>Internally the bits are represented in a 1-D array of 32-bit ints. However, each row begins 1668 * with a new int. This is done intentionally so that we can copy out a row into a BitArray very 1669 * efficiently.</p> 1670 * 1671 * <p>The ordering of bits is row-major. Within each int, the least significant bits are used first, 1672 * meaning they represent lower x values. This is compatible with BitArray's implementation.</p> 1673 * 1674 * @author Sean Owen 1675 * @author [email protected] (Daniel Switkin) 1676 */ 1677 class BitMatrix /*implements Cloneable*/ { 1678 /** 1679 * Creates an empty square {@link BitMatrix}. 1680 * 1681 * @param dimension height and width 1682 */ 1683 // public constructor(dimension: number /*int*/) { 1684 // this(dimension, dimension) 1685 // } 1686 /** 1687 * Creates an empty {@link BitMatrix}. 1688 * 1689 * @param width bit matrix width 1690 * @param height bit matrix height 1691 */ 1692 // public constructor(width: number /*int*/, height: number /*int*/) { 1693 // if (width < 1 || height < 1) { 1694 // throw new IllegalArgumentException("Both dimensions must be greater than 0") 1695 // } 1696 // this.width = width 1697 // this.height = height 1698 // this.rowSize = (width + 31) / 32 1699 // bits = new int[rowSize * height]; 1700 // } 1701 constructor(width /*int*/, height /*int*/, rowSize /*int*/, bits) { 1702 this.width = width; 1703 this.height = height; 1704 this.rowSize = rowSize; 1705 this.bits = bits; 1706 if (undefined === height || null === height) { 1707 height = width; 1708 } 1709 this.height = height; 1710 if (width < 1 || height < 1) { 1711 throw new IllegalArgumentException('Both dimensions must be greater than 0'); 1712 } 1713 if (undefined === rowSize || null === rowSize) { 1714 rowSize = Math.floor((width + 31) / 32); 1715 } 1716 this.rowSize = rowSize; 1717 if (undefined === bits || null === bits) { 1718 this.bits = new Int32Array(this.rowSize * this.height); 1719 } 1720 } 1721 /** 1722 * Interprets a 2D array of booleans as a {@link BitMatrix}, where "true" means an "on" bit. 1723 * 1724 * @function parse 1725 * @param image bits of the image, as a row-major 2D array. Elements are arrays representing rows 1726 * @return {@link BitMatrix} representation of image 1727 */ 1728 static parseFromBooleanArray(image) { 1729 const height = image.length; 1730 const width = image[0].length; 1731 const bits = new BitMatrix(width, height); 1732 for (let i = 0; i < height; i++) { 1733 const imageI = image[i]; 1734 for (let j = 0; j < width; j++) { 1735 if (imageI[j]) { 1736 bits.set(j, i); 1737 } 1738 } 1739 } 1740 return bits; 1741 } 1742 /** 1743 * 1744 * @function parse 1745 * @param stringRepresentation 1746 * @param setString 1747 * @param unsetString 1748 */ 1749 static parseFromString(stringRepresentation, setString, unsetString) { 1750 if (stringRepresentation === null) {
vendor: 5,891 bytes, lines 1751-1898
1751 throw new IllegalArgumentException('stringRepresentation cannot be null'); 1752 } 1753 const bits = new Array(stringRepresentation.length); 1754 let bitsPos = 0; 1755 let rowStartPos = 0; 1756 let rowLength = -1; 1757 let nRows = 0; 1758 let pos = 0; 1759 while (pos < stringRepresentation.length) { 1760 if (stringRepresentation.charAt(pos) === '\n' || 1761 stringRepresentation.charAt(pos) === '\r') { 1762 if (bitsPos > rowStartPos) { 1763 if (rowLength === -1) { 1764 rowLength = bitsPos - rowStartPos; 1765 } 1766 else if (bitsPos - rowStartPos !== rowLength) { 1767 throw new IllegalArgumentException('row lengths do not match'); 1768 } 1769 rowStartPos = bitsPos; 1770 nRows++; 1771 } 1772 pos++; 1773 } 1774 else if (stringRepresentation.substring(pos, pos + setString.length) === setString) { 1775 pos += setString.length; 1776 bits[bitsPos] = true; 1777 bitsPos++; 1778 } 1779 else if (stringRepresentation.substring(pos, pos + unsetString.length) === unsetString) { 1780 pos += unsetString.length; 1781 bits[bitsPos] = false; 1782 bitsPos++; 1783 } 1784 else { 1785 throw new IllegalArgumentException('illegal character encountered: ' + stringRepresentation.substring(pos)); 1786 } 1787 } 1788 // no EOL at end? 1789 if (bitsPos > rowStartPos) { 1790 if (rowLength === -1) { 1791 rowLength = bitsPos - rowStartPos; 1792 } 1793 else if (bitsPos - rowStartPos !== rowLength) { 1794 throw new IllegalArgumentException('row lengths do not match'); 1795 } 1796 nRows++; 1797 } 1798 const matrix = new BitMatrix(rowLength, nRows); 1799 for (let i = 0; i < bitsPos; i++) { 1800 if (bits[i]) { 1801 matrix.set(Math.floor(i % rowLength), Math.floor(i / rowLength)); 1802 } 1803 } 1804 return matrix; 1805 } 1806 /** 1807 * <p>Gets the requested bit, where true means black.</p> 1808 * 1809 * @param x The horizontal component (i.e. which column) 1810 * @param y The vertical component (i.e. which row) 1811 * @return value of given bit in matrix 1812 */ 1813 get(x /*int*/, y /*int*/) { 1814 const offset = y * this.rowSize + Math.floor(x / 32); 1815 return ((this.bits[offset] >>> (x & 0x1f)) & 1) !== 0; 1816 } 1817 /** 1818 * <p>Sets the given bit to true.</p> 1819 * 1820 * @param x The horizontal component (i.e. which column) 1821 * @param y The vertical component (i.e. which row) 1822 */ 1823 set(x /*int*/, y /*int*/) { 1824 const offset = y * this.rowSize + Math.floor(x / 32); 1825 this.bits[offset] |= (1 << (x & 0x1f)) & 0xFFFFFFFF; 1826 } 1827 unset(x /*int*/, y /*int*/) { 1828 const offset = y * this.rowSize + Math.floor(x / 32); 1829 this.bits[offset] &= ~((1 << (x & 0x1f)) & 0xFFFFFFFF); 1830 } 1831 /** 1832 * <p>Flips the given bit.</p> 1833 * 1834 * @param x The horizontal component (i.e. which column) 1835 * @param y The vertical component (i.e. which row) 1836 */ 1837 flip(x /*int*/, y /*int*/) { 1838 const offset = y * this.rowSize + Math.floor(x / 32); 1839 this.bits[offset] ^= ((1 << (x & 0x1f)) & 0xFFFFFFFF); 1840 } 1841 /** 1842 * Exclusive-or (XOR): Flip the bit in this {@code BitMatrix} if the corresponding 1843 * mask bit is set. 1844 * 1845 * @param mask XOR mask 1846 */ 1847 xor(mask) { 1848 if (this.width !== mask.getWidth() || this.height !== mask.getHeight() 1849 || this.rowSize !== mask.getRowSize()) { 1850 throw new IllegalArgumentException('input matrix dimensions do not match'); 1851 } 1852 const rowArray = new BitArray(Math.floor(this.width / 32) + 1); 1853 const rowSize = this.rowSize; 1854 const bits = this.bits; 1855 for (let y = 0, height = this.height; y < height; y++) { 1856 const offset = y * rowSize; 1857 const row = mask.getRow(y, rowArray).getBitArray(); 1858 for (let x = 0; x < rowSize; x++) { 1859 bits[offset + x] ^= row[x]; 1860 } 1861 } 1862 } 1863 /** 1864 * Clears all bits (sets to false). 1865 */ 1866 clear() { 1867 const bits = this.bits; 1868 const max = bits.length; 1869 for (let i = 0; i < max; i++) { 1870 bits[i] = 0; 1871 } 1872 } 1873 /** 1874 * <p>Sets a square region of the bit matrix to true.</p> 1875 * 1876 * @param left The horizontal position to begin at (inclusive) 1877 * @param top The vertical position to begin at (inclusive) 1878 * @param width The width of the region 1879 * @param height The height of the region 1880 */ 1881 setRegion(left /*int*/, top /*int*/, width /*int*/, height /*int*/) { 1882 if (top < 0 || left < 0) { 1883 throw new IllegalArgumentException('Left and top must be nonnegative'); 1884 } 1885 if (height < 1 || width < 1) { 1886 throw new IllegalArgumentException('Height and width must be at least 1'); 1887 } 1888 const right = left + width; 1889 const bottom = top + height; 1890 if (bottom > this.height || right > this.width) { 1891 throw new IllegalArgumentException('The region must fit inside the matrix'); 1892 } 1893 const rowSize = this.rowSize; 1894 const bits = this.bits; 1895 for (let y = top; y < bottom; y++) { 1896 const offset = y * rowSize; 1897 for (let x = left; x < right; x++) { 1898 bits[offset + Math.floor(x / 32
vendor: 8,852 bytes, lines 1898-2148
1898)] |= ((1 << (x & 0x1f)) & 0xFFFFFFFF); 1899 } 1900 } 1901 } 1902 /** 1903 * A fast method to retrieve one row of data from the matrix as a BitArray. 1904 * 1905 * @param y The row to retrieve 1906 * @param row An optional caller-allocated BitArray, will be allocated if null or too small 1907 * @return The resulting BitArray - this reference should always be used even when passing 1908 * your own row 1909 */ 1910 getRow(y /*int*/, row) { 1911 if (row === null || row === undefined || row.getSize() < this.width) { 1912 row = new BitArray(this.width); 1913 } 1914 else { 1915 row.clear(); 1916 } 1917 const rowSize = this.rowSize; 1918 const bits = this.bits; 1919 const offset = y * rowSize; 1920 for (let x = 0; x < rowSize; x++) { 1921 row.setBulk(x * 32, bits[offset + x]); 1922 } 1923 return row; 1924 } 1925 /** 1926 * @param y row to set 1927 * @param row {@link BitArray} to copy from 1928 */ 1929 setRow(y /*int*/, row) { 1930 System.arraycopy(row.getBitArray(), 0, this.bits, y * this.rowSize, this.rowSize); 1931 } 1932 /** 1933 * Modifies this {@code BitMatrix} to represent the same but rotated 180 degrees 1934 */ 1935 rotate180() { 1936 const width = this.getWidth(); 1937 const height = this.getHeight(); 1938 let topRow = new BitArray(width); 1939 let bottomRow = new BitArray(width); 1940 for (let i = 0, length = Math.floor((height + 1) / 2); i < length; i++) { 1941 topRow = this.getRow(i, topRow); 1942 bottomRow = this.getRow(height - 1 - i, bottomRow); 1943 topRow.reverse(); 1944 bottomRow.reverse(); 1945 this.setRow(i, bottomRow); 1946 this.setRow(height - 1 - i, topRow); 1947 } 1948 } 1949 /** 1950 * This is useful in detecting the enclosing rectangle of a 'pure' barcode. 1951 * 1952 * @return {@code left,top,width,height} enclosing rectangle of all 1 bits, or null if it is all white 1953 */ 1954 getEnclosingRectangle() { 1955 const width = this.width; 1956 const height = this.height; 1957 const rowSize = this.rowSize; 1958 const bits = this.bits; 1959 let left = width; 1960 let top = height; 1961 let right = -1; 1962 let bottom = -1; 1963 for (let y = 0; y < height; y++) { 1964 for (let x32 = 0; x32 < rowSize; x32++) { 1965 const theBits = bits[y * rowSize + x32]; 1966 if (theBits !== 0) { 1967 if (y < top) { 1968 top = y; 1969 } 1970 if (y > bottom) { 1971 bottom = y; 1972 } 1973 if (x32 * 32 < left) { 1974 let bit = 0; 1975 while (((theBits << (31 - bit)) & 0xFFFFFFFF) === 0) { 1976 bit++; 1977 } 1978 if ((x32 * 32 + bit) < left) { 1979 left = x32 * 32 + bit; 1980 } 1981 } 1982 if (x32 * 32 + 31 > right) { 1983 let bit = 31; 1984 while ((theBits >>> bit) === 0) { 1985 bit--; 1986 } 1987 if ((x32 * 32 + bit) > right) { 1988 right = x32 * 32 + bit; 1989 } 1990 } 1991 } 1992 } 1993 } 1994 if (right < left || bottom < top) { 1995 return null; 1996 } 1997 return Int32Array.from([left, top, right - left + 1, bottom - top + 1]); 1998 } 1999 /** 2000 * This is useful in detecting a corner of a 'pure' barcode. 2001 * 2002 * @return {@code x,y} coordinate of top-left-most 1 bit, or null if it is all white 2003 */ 2004 getTopLeftOnBit() { 2005 const rowSize = this.rowSize; 2006 const bits = this.bits; 2007 let bitsOffset = 0; 2008 while (bitsOffset < bits.length && bits[bitsOffset] === 0) { 2009 bitsOffset++; 2010 } 2011 if (bitsOffset === bits.length) { 2012 return null; 2013 } 2014 const y = bitsOffset / rowSize; 2015 let x = (bitsOffset % rowSize) * 32; 2016 const theBits = bits[bitsOffset]; 2017 let bit = 0; 2018 while (((theBits << (31 - bit)) & 0xFFFFFFFF) === 0) { 2019 bit++; 2020 } 2021 x += bit; 2022 return Int32Array.from([x, y]); 2023 } 2024 getBottomRightOnBit() { 2025 const rowSize = this.rowSize; 2026 const bits = this.bits; 2027 let bitsOffset = bits.length - 1; 2028 while (bitsOffset >= 0 && bits[bitsOffset] === 0) { 2029 bitsOffset--; 2030 } 2031 if (bitsOffset < 0) { 2032 return null; 2033 } 2034 const y = Math.floor(bitsOffset / rowSize); 2035 let x = Math.floor(bitsOffset % rowSize) * 32; 2036 const theBits = bits[bitsOffset]; 2037 let bit = 31; 2038 while ((theBits >>> bit) === 0) { 2039 bit--; 2040 } 2041 x += bit; 2042 return Int32Array.from([x, y]); 2043 } 2044 /** 2045 * @return The width of the matrix 2046 */ 2047 getWidth() { 2048 return this.width; 2049 } 2050 /** 2051 * @return The height of the matrix 2052 */ 2053 getHeight() { 2054 return this.height; 2055 } 2056 /** 2057 * @return The row size of the matrix 2058 */ 2059 getRowSize() { 2060 return this.rowSize; 2061 } 2062 /*@Override*/ 2063 equals(o) { 2064 if (!(o instanceof BitMatrix)) { 2065 return false; 2066 } 2067 const other = o; 2068 return this.width === other.width && this.height === other.height && this.rowSize === other.rowSize && 2069 Arrays.equals(this.bits, other.bits); 2070 } 2071 /*@Override*/ 2072 hashCode() { 2073 let hash = this.width; 2074 hash = 31 * hash + this.width; 2075 hash = 31 * hash + this.height; 2076 hash = 31 * hash + this.rowSize; 2077 hash = 31 * hash + Arrays.hashCode(this.bits); 2078 return hash; 2079 } 2080 /** 2081 * @return string representation using "X" for set and " " for unset bits 2082 */ 2083 /*@Override*/ 2084 // public toString(): string { 2085 // return toString(": "X, " ") 2086 // } 2087 /** 2088 * @param setString representation of a set bit 2089 * @param unsetString representation of an unset bit 2090 * @return string representation of entire matrix utilizing given strings 2091 */ 2092 // public toString(setString: string = "X ", unsetString: string = " "): string { 2093 // return this.buildToString(setString, unsetString, "\n") 2094 // } 2095 /** 2096 * @param setString representation of a set bit 2097 * @param unsetString representation of an unset bit 2098 * @param lineSeparator newline character in string representation 2099 * @return string representation of entire matrix utilizing given strings and line separator 2100 * @deprecated call {@link #toString(String,String)} only, which uses \n line separator always 2101 */ 2102 // @Deprecated 2103 toString(setString = 'X ', unsetString = ' ', lineSeparator = '\n') { 2104 return this.buildToString(setString, unsetString, lineSeparator); 2105 } 2106 buildToString(setString, unsetString, lineSeparator) { 2107 let result = new StringBuilder(); 2108 // result.append(lineSeparator); 2109 for (let y = 0, height = this.height; y < height; y++) { 2110 for (let x = 0, width = this.width; x < width; x++) { 2111 result.append(this.get(x, y) ? setString : unsetString); 2112 } 2113 result.append(lineSeparator); 2114 } 2115 return result.toString(); 2116 } 2117 /*@Override*/ 2118 clone() { 2119 return new BitMatrix(this.width, this.height, this.rowSize, this.bits.slice()); 2120 } 2121 } 2122 2123 /** 2124 * Custom Error class of type Exception. 2125 */ 2126 class NotFoundException extends Exception { 2127 static getNotFoundInstance() { 2128 return new NotFoundException(); 2129 } 2130 } 2131 NotFoundException.kind = 'NotFoundException'; 2132 2133 /* 2134 * Copyright 2009 ZXing authors 2135 * 2136 * Licensed under the Apache License, Version 2.0 (the "License"); 2137 * you may not use this file except in compliance with the License. 2138 * You may obtain a copy of the License at 2139 * 2140 * http://www.apache.org/licenses/LICENSE-2.0 2141 * 2142 * Unless required by applicable law or agreed to in writing, software 2143 * distributed under the License is distributed on an "AS IS" BASIS, 2144 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2145 * See the License for the specific language governing permissions and 2146 * limitations under the License. 2147 */ 2148 /*
2148* 2149 * This Binarizer implementation uses the old ZXing global histogram approach. It is suitable 2150 * for low-end mobile devices which don't have enough CPU or memory to use a local thresholding 2151 * algorithm. However, because it picks a global black point, it cannot handle difficult shadows 2152 * and gradients. 2153 * 2154 * Faster mobile devices and all desktop applications should probably use HybridBinarizer instead. 2155 * 2156 * @author [email protected] (Daniel Switkin) 2157 * @author Sean Owen 2158 */ 2159 class GlobalHistogramBinarizer extends Binarizer { 2160 constructor(source) { 2161 super(source); 2162 this.luminances = GlobalHistogramBinarizer.EMPTY; 2163 this.buckets = new Int32Array(GlobalHistogramBinarizer.LUMINANCE_BUCKETS); 2164 } 2165 // Applies simple sharpening to the row data to improve performance of the 1D Readers. 2166 /*@Override*/ 2167 getBlackRow(y /*int*/, row) { 2168 const source = this.getLuminanceSource(); 2169 const width = source.getWidth(); 2170 if (row === undefined || row === null || row.getSize() < width) { 2171 row = new BitArray(width); 2172 } 2173 else { 2174 row.clear(); 2175 } 2176 this.initArrays(width); 2177 const localLuminances = source.getRow(y, this.luminances); 2178 const localBuckets = this.buckets; 2179 for (let x = 0; x < width; x++) { 2180 localBuckets[(localLuminances[x] & 0xff) >> GlobalHistogramBinarizer.LUMINANCE_SHIFT]++; 2181 } 2182 const blackPoint = GlobalHistogramBinarizer.estimateBlackPoint(localBuckets); 2183 if (width < 3) { 2184 // Special case for very small images 2185 for (let x = 0; x < width; x++) { 2186 if ((localLuminances[x] & 0xff) < blackPoint) { 2187 row.set(x); 2188 } 2189 } 2190 } 2191 else { 2192 let left = localLuminances[0] & 0xff; 2193 let center = localLuminances[1] & 0xff; 2194 for (let x = 1; x < width - 1; x++) { 2195 const right = localLuminances[x + 1] & 0xff; 2196 // A simple -1 4 -1 box filter with a weight of 2. 2197 if (((center * 4) - left - right) / 2 < blackPoint) { 2198 row.set(x); 2199 } 2200 left = center; 2201 center = right; 2202 } 2203 } 2204 return row; 2205 } 2206 // Does not sharpen the data, as this call is intended to only be used by 2D Readers. 2207 /*@Override*/ 2208 getBlackMatrix() { 2209 const source = this.getLuminanceSource(); 2210 const width = source.getWidth(); 2211 const height = source.getHeight(); 2212 const matrix = new BitMatrix(width, height); 2213 // Quickly calculates the histogram by sampling four rows from the image. This proved to be 2214 // more robust on the blackbox tests than sampling a diagonal as we used to do. 2215 this.initArrays(width); 2216 const localBuckets = this.buckets; 2217 for (let y = 1; y < 5; y++) { 2218 const row = Math.floor((height * y) / 5); 2219 const localLuminances = source.getRow(row, this.luminances); 2220 const right = Math.floor((width * 4) / 5); 2221 for (let x = Math.floor(width / 5); x < right; x++) { 2222 const pixel = localLuminances[x] & 0xff;
vendor: 1,342 bytes, lines 2223-2253
2223 localBuckets[pixel >> GlobalHistogramBinarizer.LUMINANCE_SHIFT]++; 2224 } 2225 } 2226 const blackPoint = GlobalHistogramBinarizer.estimateBlackPoint(localBuckets); 2227 // We delay reading the entire image luminance until the black point estimation succeeds. 2228 // Although we end up reading four rows twice, it is consistent with our motto of 2229 // "fail quickly" which is necessary for continuous scanning. 2230 const localLuminances = source.getMatrix(); 2231 for (let y = 0; y < height; y++) { 2232 const offset = y * width; 2233 for (let x = 0; x < width; x++) { 2234 const pixel = localLuminances[offset + x] & 0xff; 2235 if (pixel < blackPoint) { 2236 matrix.set(x, y); 2237 } 2238 } 2239 } 2240 return matrix; 2241 } 2242 /*@Override*/ 2243 createBinarizer(source) { 2244 return new GlobalHistogramBinarizer(source); 2245 } 2246 initArrays(luminanceSize /*int*/) { 2247 if (this.luminances.length < luminanceSize) { 2248 this.luminances = new Uint8ClampedArray(luminanceSize); 2249 } 2250 const buckets = this.buckets; 2251 for (let x = 0; x < GlobalHistogramBinarizer.LUMINANCE_BUCKETS; x++) { 2252 buckets[x] = 0; 2253 }
vendor: 18,979 bytes, lines 2253-2660
2253 2254 } 2255 static estimateBlackPoint(buckets) { 2256 // Find the tallest peak in the histogram. 2257 const numBuckets = buckets.length; 2258 let maxBucketCount = 0; 2259 let firstPeak = 0; 2260 let firstPeakSize = 0; 2261 for (let x = 0; x < numBuckets; x++) { 2262 if (buckets[x] > firstPeakSize) { 2263 firstPeak = x; 2264 firstPeakSize = buckets[x]; 2265 } 2266 if (buckets[x] > maxBucketCount) { 2267 maxBucketCount = buckets[x]; 2268 } 2269 } 2270 // Find the second-tallest peak which is somewhat far from the tallest peak. 2271 let secondPeak = 0; 2272 let secondPeakScore = 0; 2273 for (let x = 0; x < numBuckets; x++) { 2274 const distanceToBiggest = x - firstPeak; 2275 // Encourage more distant second peaks by multiplying by square of distance. 2276 const score = buckets[x] * distanceToBiggest * distanceToBiggest; 2277 if (score > secondPeakScore) { 2278 secondPeak = x; 2279 secondPeakScore = score; 2280 } 2281 } 2282 // Make sure firstPeak corresponds to the black peak. 2283 if (firstPeak > secondPeak) { 2284 const temp = firstPeak; 2285 firstPeak = secondPeak; 2286 secondPeak = temp; 2287 } 2288 // If there is too little contrast in the image to pick a meaningful black point, throw rather 2289 // than waste time trying to decode the image, and risk false positives. 2290 if (secondPeak - firstPeak <= numBuckets / 16) { 2291 throw new NotFoundException(); 2292 } 2293 // Find a valley between them that is low and closer to the white peak. 2294 let bestValley = secondPeak - 1; 2295 let bestValleyScore = -1; 2296 for (let x = secondPeak - 1; x > firstPeak; x--) { 2297 const fromFirst = x - firstPeak; 2298 const score = fromFirst * fromFirst * (secondPeak - x) * (maxBucketCount - buckets[x]); 2299 if (score > bestValleyScore) { 2300 bestValley = x; 2301 bestValleyScore = score; 2302 } 2303 } 2304 return bestValley << GlobalHistogramBinarizer.LUMINANCE_SHIFT; 2305 } 2306 } 2307 GlobalHistogramBinarizer.LUMINANCE_BITS = 5; 2308 GlobalHistogramBinarizer.LUMINANCE_SHIFT = 8 - GlobalHistogramBinarizer.LUMINANCE_BITS; 2309 GlobalHistogramBinarizer.LUMINANCE_BUCKETS = 1 << GlobalHistogramBinarizer.LUMINANCE_BITS; 2310 GlobalHistogramBinarizer.EMPTY = Uint8ClampedArray.from([0]); 2311 2312 /* 2313 * Copyright 2009 ZXing authors 2314 * 2315 * Licensed under the Apache License, Version 2.0 (the "License"); 2316 * you may not use this file except in compliance with the License. 2317 * You may obtain a copy of the License at 2318 * 2319 * http://www.apache.org/licenses/LICENSE-2.0 2320 * 2321 * Unless required by applicable law or agreed to in writing, software 2322 * distributed under the License is distributed on an "AS IS" BASIS, 2323 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2324 * See the License for the specific language governing permissions and 2325 * limitations under the License. 2326 */ 2327 /** 2328 * This class implements a local thresholding algorithm, which while slower than the 2329 * GlobalHistogramBinarizer, is fairly efficient for what it does. It is designed for 2330 * high frequency images of barcodes with black data on white backgrounds. For this application, 2331 * it does a much better job than a global blackpoint with severe shadows and gradients. 2332 * However it tends to produce artifacts on lower frequency images and is therefore not 2333 * a good general purpose binarizer for uses outside ZXing. 2334 * 2335 * This class extends GlobalHistogramBinarizer, using the older histogram approach for 1D readers, 2336 * and the newer local approach for 2D readers. 1D decoding using a per-row histogram is already 2337 * inherently local, and only fails for horizontal gradients. We can revisit that problem later, 2338 * but for now it was not a win to use local blocks for 1D. 2339 * 2340 * This Binarizer is the default for the unit tests and the recommended class for library users. 2341 * 2342 * @author [email protected] (Daniel Switkin) 2343 */ 2344 class HybridBinarizer extends GlobalHistogramBinarizer { 2345 constructor(source) { 2346 super(source); 2347 this.matrix = null; 2348 } 2349 /** 2350 * Calculates the final BitMatrix once for all requests. This could be called once from the 2351 * constructor instead, but there are some advantages to doing it lazily, such as making 2352 * profiling easier, and not doing heavy lifting when callers don't expect it. 2353 */ 2354 /*@Override*/ 2355 getBlackMatrix() { 2356 if (this.matrix !== null) { 2357 return this.matrix; 2358 } 2359 const source = this.getLuminanceSource(); 2360 const width = source.getWidth(); 2361 const height = source.getHeight(); 2362 if (width >= HybridBinarizer.MINIMUM_DIMENSION && height >= HybridBinarizer.MINIMUM_DIMENSION) { 2363 const luminances = source.getMatrix(); 2364 let subWidth = width >> HybridBinarizer.BLOCK_SIZE_POWER; 2365 if ((width & HybridBinarizer.BLOCK_SIZE_MASK) !== 0) { 2366 subWidth++; 2367 } 2368 let subHeight = height >> HybridBinarizer.BLOCK_SIZE_POWER; 2369 if ((height & HybridBinarizer.BLOCK_SIZE_MASK) !== 0) { 2370 subHeight++; 2371 } 2372 const blackPoints = HybridBinarizer.calculateBlackPoints(luminances, subWidth, subHeight, width, height); 2373 const newMatrix = new BitMatrix(width, height); 2374 HybridBinarizer.calculateThresholdForBlock(luminances, subWidth, subHeight, width, height, blackPoints, newMatrix); 2375 this.matrix = newMatrix; 2376 } 2377 else { 2378 // If the image is too small, fall back to the global histogram approach. 2379 this.matrix = super.getBlackMatrix(); 2380 } 2381 return this.matrix; 2382 } 2383 /*@Override*/ 2384 createBinarizer(source) { 2385 return new HybridBinarizer(source); 2386 } 2387 /** 2388 * For each block in the image, calculate the average black point using a 5x5 grid 2389 * of the blocks around it. Also handles the corner cases (fractional blocks are computed based 2390 * on the last pixels in the row/column which are also used in the previous block). 2391 */ 2392 static calculateThresholdForBlock(luminances, subWidth /*int*/, subHeight /*int*/, width /*int*/, height /*int*/, blackPoints, matrix) { 2393 const maxYOffset = height - HybridBinarizer.BLOCK_SIZE; 2394 const maxXOffset = width - HybridBinarizer.BLOCK_SIZE; 2395 for (let y = 0; y < subHeight; y++) { 2396 let yoffset = y << HybridBinarizer.BLOCK_SIZE_POWER; 2397 if (yoffset > maxYOffset) { 2398 yoffset = maxYOffset; 2399 } 2400 const top = HybridBinarizer.cap(y, 2, subHeight - 3); 2401 for (let x = 0; x < subWidth; x++) { 2402 let xoffset = x << HybridBinarizer.BLOCK_SIZE_POWER; 2403 if (xoffset > maxXOffset) { 2404 xoffset = maxXOffset; 2405 } 2406 const left = HybridBinarizer.cap(x, 2, subWidth - 3); 2407 let sum = 0; 2408 for (let z = -2; z <= 2; z++) { 2409 const blackRow = blackPoints[top + z]; 2410 sum += blackRow[left - 2] + blackRow[left - 1] + blackRow[left] + blackRow[left + 1] + blackRow[left + 2]; 2411 } 2412 const average = sum / 25; 2413 HybridBinarizer.thresholdBlock(luminances, xoffset, yoffset, average, width, matrix); 2414 } 2415 } 2416 } 2417 static cap(value /*int*/, min /*int*/, max /*int*/) { 2418 return value < min ? min : value > max ? max : value; 2419 } 2420 /** 2421 * Applies a single threshold to a block of pixels. 2422 */ 2423 static thresholdBlock(luminances, xoffset /*int*/, yoffset /*int*/, threshold /*int*/, stride /*int*/, matrix) { 2424 for (let y = 0, offset = yoffset * stride + xoffset; y < HybridBinarizer.BLOCK_SIZE; y++, offset += stride) { 2425 for (let x = 0; x < HybridBinarizer.BLOCK_SIZE; x++) { 2426 // Comparison needs to be <= so that black == 0 pixels are black even if the threshold is 0. 2427 if ((luminances[offset + x] & 0xFF) <= threshold) { 2428 matrix.set(xoffset + x, yoffset + y); 2429 } 2430 } 2431 } 2432 } 2433 /** 2434 * Calculates a single black point for each block of pixels and saves it away. 2435 * See the following thread for a discussion of this algorithm: 2436 * http://groups.google.com/group/zxing/browse_thread/thread/d06efa2c35a7ddc0 2437 */ 2438 static calculateBlackPoints(luminances, subWidth /*int*/, subHeight /*int*/, width /*int*/, height /*int*/) { 2439 const maxYOffset = height - HybridBinarizer.BLOCK_SIZE; 2440 const maxXOffset = width - HybridBinarizer.BLOCK_SIZE; 2441 // tslint:disable-next-line:whitespace 2442 const blackPoints = new Array(subHeight); // subWidth 2443 for (let y = 0; y < subHeight; y++) { 2444 blackPoints[y] = new Int32Array(subWidth); 2445 let yoffset = y << HybridBinarizer.BLOCK_SIZE_POWER; 2446 if (yoffset > maxYOffset) { 2447 yoffset = maxYOffset; 2448 } 2449 for (let x = 0; x < subWidth; x++) { 2450 let xoffset = x << HybridBinarizer.BLOCK_SIZE_POWER; 2451 if (xoffset > maxXOffset) { 2452 xoffset = maxXOffset; 2453 } 2454 let sum = 0; 2455 let min = 0xFF; 2456 let max = 0; 2457 for (let yy = 0, offset = yoffset * width + xoffset; yy < HybridBinarizer.BLOCK_SIZE; yy++, offset += width) { 2458 for (let xx = 0; xx < HybridBinarizer.BLOCK_SIZE; xx++) { 2459 const pixel = luminances[offset + xx] & 0xFF; 2460 sum += pixel; 2461 // still looking for good contrast 2462 if (pixel < min) { 2463 min = pixel; 2464 } 2465 if (pixel > max) { 2466 max = pixel; 2467 } 2468 } 2469 // short-circuit min/max tests once dynamic range is met 2470 if (max - min > HybridBinarizer.MIN_DYNAMIC_RANGE) { 2471 // finish the rest of the rows quickly 2472 for (yy++, offset += width; yy < HybridBinarizer.BLOCK_SIZE; yy++, offset += width) { 2473 for (let xx = 0; xx < HybridBinarizer.BLOCK_SIZE; xx++) { 2474 sum += luminances[offset + xx] & 0xFF; 2475 } 2476 } 2477 } 2478 } 2479 // The default estimate is the average of the values in the block. 2480 let average = sum >> (HybridBinarizer.BLOCK_SIZE_POWER * 2); 2481 if (max - min <= HybridBinarizer.MIN_DYNAMIC_RANGE) { 2482 // If variation within the block is low, assume this is a block with only light or only 2483 // dark pixels. In that case we do not want to use the average, as it would divide this 2484 // low contrast area into black and white pixels, essentially creating data out of noise. 2485 // 2486 // The default assumption is that the block is light/background. Since no estimate for 2487 // the level of dark pixels exists locally, use half the min for the block. 2488 average = min / 2; 2489 if (y > 0 && x > 0) { 2490 // Correct the "white background" assumption for blocks that have neighbors by comparing 2491 // the pixels in this block to the previously calculated black points. This is based on 2492 // the fact that dark barcode symbology is always surrounded by some amount of light 2493 // background for which reasonable black point estimates were made. The bp estimated at 2494 // the boundaries is used for the interior. 2495 // The (min < bp) is arbitrary but works better than other heuristics that were tried. 2496 const averageNeighborBlackPoint = (blackPoints[y - 1][x] + (2 * blackPoints[y][x - 1]) + blackPoints[y - 1][x - 1]) / 4; 2497 if (min < averageNeighborBlackPoint) { 2498 average = averageNeighborBlackPoint; 2499 } 2500 } 2501 } 2502 blackPoints[y][x] = average; 2503 } 2504 } 2505 return blackPoints; 2506 } 2507 } 2508 // This class uses 5x5 blocks to compute local luminance, where each block is 8x8 pixels. 2509 // So this is the smallest dimension in each axis we can accept. 2510 HybridBinarizer.BLOCK_SIZE_POWER = 3; 2511 HybridBinarizer.BLOCK_SIZE = 1 << HybridBinarizer.BLOCK_SIZE_POWER; // ...0100...00 2512 HybridBinarizer.BLOCK_SIZE_MASK = HybridBinarizer.BLOCK_SIZE - 1; // ...0011...11 2513 HybridBinarizer.MINIMUM_DIMENSION = HybridBinarizer.BLOCK_SIZE * 5; 2514 HybridBinarizer.MIN_DYNAMIC_RANGE = 24; 2515 2516 /* 2517 * Copyright 2009 ZXing authors 2518 * 2519 * Licensed under the Apache License, Version 2.0 (the "License"); 2520 * you may not use this file except in compliance with the License. 2521 * You may obtain a copy of the License at 2522 * 2523 * http://www.apache.org/licenses/LICENSE-2.0 2524 * 2525 * Unless required by applicable law or agreed to in writing, software 2526 * distributed under the License is distributed on an "AS IS" BASIS, 2527 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2528 * See the License for the specific language governing permissions and 2529 * limitations under the License. 2530 */ 2531 /*namespace com.google.zxing {*/ 2532 /** 2533 * The purpose of this class hierarchy is to abstract different bitmap implementations across 2534 * platforms into a standard interface for requesting greyscale luminance values. The interface 2535 * only provides immutable methods; therefore crop and rotation create copies. This is to ensure 2536 * that one Reader does not modify the original luminance source and leave it in an unknown state 2537 * for other Readers in the chain. 2538 * 2539 * @author [email protected] (Daniel Switkin) 2540 */ 2541 class LuminanceSource { 2542 constructor(width /*int*/, height /*int*/) { 2543 this.width = width; 2544 this.height = height; 2545 } 2546 /** 2547 * @return The width of the bitmap. 2548 */ 2549 getWidth() { 2550 return this.width; 2551 } 2552 /** 2553 * @return The height of the bitmap. 2554 */ 2555 getHeight() { 2556 return this.height; 2557 } 2558 /** 2559 * @return Whether this subclass supports cropping. 2560 */ 2561 isCropSupported() { 2562 return false; 2563 } 2564 /** 2565 * Returns a new object with cropped image data. Implementations may keep a reference to the 2566 * original data rather than a copy. Only callable if isCropSupported() is true. 2567 * 2568 * @param left The left coordinate, which must be in [0,getWidth()) 2569 * @param top The top coordinate, which must be in [0,getHeight()) 2570 * @param width The width of the rectangle to crop. 2571 * @param height The height of the rectangle to crop. 2572 * @return A cropped version of this object. 2573 */ 2574 crop(left /*int*/, top /*int*/, width /*int*/, height /*int*/) { 2575 throw new UnsupportedOperationException('This luminance source does not support cropping.'); 2576 } 2577 /** 2578 * @return Whether this subclass supports counter-clockwise rotation. 2579 */ 2580 isRotateSupported() { 2581 return false; 2582 } 2583 /** 2584 * Returns a new object with rotated image data by 90 degrees counterclockwise. 2585 * Only callable if {@link #isRotateSupported()} is true. 2586 * 2587 * @return A rotated version of this object. 2588 */ 2589 rotateCounterClockwise() { 2590 throw new UnsupportedOperationException('This luminance source does not support rotation by 90 degrees.'); 2591 } 2592 /** 2593 * Returns a new object with rotated image data by 45 degrees counterclockwise. 2594 * Only callable if {@link #isRotateSupported()} is true. 2595 * 2596 * @return A rotated version of this object. 2597 */ 2598 rotateCounterClockwise45() { 2599 throw new UnsupportedOperationException('This luminance source does not support rotation by 45 degrees.'); 2600 } 2601 /*@Override*/ 2602 toString() { 2603 const row = new Uint8ClampedArray(this.width); 2604 let result = new StringBuilder(); 2605 for (let y = 0; y < this.height; y++) { 2606 const sourceRow = this.getRow(y, row); 2607 for (let x = 0; x < this.width; x++) { 2608 const luminance = sourceRow[x] & 0xFF; 2609 let c; 2610 if (luminance < 0x40) { 2611 c = '#'; 2612 } 2613 else if (luminance < 0x80) { 2614 c = '+'; 2615 } 2616 else if (luminance < 0xC0) { 2617 c = '.'; 2618 } 2619 else { 2620 c = ' '; 2621 } 2622 result.append(c); 2623 } 2624 result.append('\n'); 2625 } 2626 return result.toString(); 2627 } 2628 } 2629 2630 /* 2631 * Copyright 2009 ZXing authors 2632 * 2633 * Licensed under the Apache License, Version 2.0 (the "License"); 2634 * you may not use this file except in compliance with the License. 2635 * You may obtain a copy of the License at 2636 * 2637 * http://www.apache.org/licenses/LICENSE-2.0 2638 * 2639 * Unless required by applicable law or agreed to in writing, software 2640 * distributed under the License is distributed on an "AS IS" BASIS, 2641 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2642 * See the License for the specific language governing permissions and 2643 * limitations under the License. 2644 */ 2645 /*namespace com.google.zxing {*/ 2646 /** 2647 * A wrapper implementation of {@link LuminanceSource} which inverts the luminances it returns -- black becomes 2648 * white and vice versa, and each value becomes (255-value). 2649 * 2650 * @author Sean Owen 2651 */ 2652 class InvertedLuminanceSource extends LuminanceSource { 2653 constructor(delegate) { 2654 super(delegate.getWidth(), delegate.getHeight()); 2655 this.delegate = delegate; 2656 } 2657 /*@Override*/ 2658 getRow(y /*int*/, row) { 2659 const sourceRow = this.delegate.getRow(y, row); 2660 const width
2660= this.getWidth(); 2661 for (let i = 0; i < width; i++) { 2662 sourceRow[i] = /*(byte)*/ (255 - (sourceRow[i] & 0xFF)); 2663 } 2664 return sourceRow; 2665 } 2666 /*@Override*/ 2667 getMatrix() { 2668 const matrix = this.delegate.getMatrix(); 2669 const length = this.getWidth() * this.getHeight(); 2670 const invertedMatrix = new Uint8ClampedArray(length); 2671 for (let i = 0; i < length; i++) { 2672 invertedMatrix[i] = /*(byte)*/ (255 - (matrix[i] & 0xFF)); 2673 } 2674 return invertedMatrix; 2675 } 2676 /*@Override*/ 2677 isCropSupported() { 2678 return this.delegate.isCropSupported(); 2679 } 2680 /*@Override*/ 2681 crop(left /*int*/, top /*int*/, width /*int*/, height /*int*/) { 2682 return new InvertedLuminanceSource(this.delegate.crop(left, top, width, height)); 2683 } 2684 /*@Override*/ 2685 isRotateSupported() { 2686 return this.delegate.isRotateSupported(); 2687 } 2688 /** 2689 * @return original delegate {@link LuminanceSource} since invert undoes itself 2690 */ 2691 /*@Override*/ 2692 invert() { 2693 return this.delegate; 2694 } 2695 /*@Override*/ 2696 rotateCounterClockwise() { 2697 return new InvertedLuminanceSource(this.delegate.rotateCounterClockwise()); 2698 } 2699 /*@Override*/ 2700 rotateCounterClockwise45() { 2701 return new InvertedLuminanceSource(this.delegate.rotateCounterClockwise45()); 2702 } 2703 } 2704 2705 /** 2706 * @deprecated Moving to @zxing/browser 2707 */ 2708 class HTMLCanvasElementLuminanceSource extends LuminanceSource { 2709 constructor(canvas, doAutoInvert = false) { 2710 super(canvas.width, canvas.height); 2711 this.canvas = canvas; 2712 this.tempCanvasElement = null; 2713 this.buffer = HTMLCanvasElementLuminanceSource.makeBufferFromCanvasImageData(canvas, doAutoInvert); 2714 } 2715 static makeBufferFromCanvasImageData(canvas, doAutoInvert = false) { 2716 const imageData = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height); 2717 return HTMLCanvasElementLuminanceSource.toGrayscaleBuffer(imageData.data, canvas.width, canvas.height, doAutoInvert); 2718 } 2719 static toGrayscaleBuffer(imageBuffer, width, height, doAutoInvert = false) { 2720 const grayscaleBuffer = new Uint8ClampedArray(width * height); 2721 HTMLCanvasElementLuminanceSource.FRAME_INDEX = !HTMLCanvasElementLuminanceSource.FRAME_INDEX; 2722 if (HTMLCanvasElementLuminanceSource.FRAME_INDEX || !doAutoInvert) { 2723 for (let i = 0, j = 0, length = imageBuffer.length; i < length; i += 4, j++) { 2724 let gray; 2725 const alpha = imageBuffer[i + 3]; 2726 // The color of fully-transparent pixels is irrelevant. They are often, technically, fully-transparent 2727 // black (0 alpha, and then 0 RGB). They are often used, of course as the "white" area in a 2728 // barcode image. Force any such pixel to be white: 2729 if (alpha === 0) { 2730 gray = 0xFF; 2731 } 2732 else { 2733 const pixelR = imageBuffer[i]; 2734 const pixelG = imageBuffer[i + 1]; 2735 const pixelB = imageBuffer[i + 2]; 2736 // .299R + 0.587G + 0.114B (YUV/YIQ for PAL and NTSC), 2737 // (306*R) >> 10 is approximately equal to R*0.299, and so on. 2738 // 0x200 >> 10 is 0.5, it implements rounding. 2739 gray = (306 * pixelR + 2740 601 * pixelG + 2741 117 * pixelB + 2742 0x200) >> 10; 2743 } 2744 grayscaleBuffer[j] = gray; 2745 } 2746 } 2747 else { 2748 for (let i = 0, j = 0, length = imageBuffer.length; i < length; i += 4, j++) { 2749 let gray;
vendor: 6,662 bytes, lines 2750-2912
2750 const alpha = imageBuffer[i + 3]; 2751 // The color of fully-transparent pixels is irrelevant. They are often, technically, fully-transparent 2752 // black (0 alpha, and then 0 RGB). They are often used, of course as the "white" area in a 2753 // barcode image. Force any such pixel to be white: 2754 if (alpha === 0) { 2755 gray = 0xFF; 2756 } 2757 else { 2758 const pixelR = imageBuffer[i]; 2759 const pixelG = imageBuffer[i + 1]; 2760 const pixelB = imageBuffer[i + 2]; 2761 // .299R + 0.587G + 0.114B (YUV/YIQ for PAL and NTSC), 2762 // (306*R) >> 10 is approximately equal to R*0.299, and so on. 2763 // 0x200 >> 10 is 0.5, it implements rounding. 2764 gray = (306 * pixelR + 2765 601 * pixelG + 2766 117 * pixelB + 2767 0x200) >> 10; 2768 } 2769 grayscaleBuffer[j] = 0xFF - gray; 2770 } 2771 } 2772 return grayscaleBuffer; 2773 } 2774 getRow(y /*int*/, row) { 2775 if (y < 0 || y >= this.getHeight()) { 2776 throw new IllegalArgumentException('Requested row is outside the image: ' + y); 2777 } 2778 const width = this.getWidth(); 2779 const start = y * width; 2780 if (row === null) { 2781 row = this.buffer.slice(start, start + width); 2782 } 2783 else { 2784 if (row.length < width) { 2785 row = new Uint8ClampedArray(width); 2786 } 2787 // The underlying raster of image consists of bytes with the luminance values 2788 // TODO: can avoid set/slice? 2789 row.set(this.buffer.slice(start, start + width)); 2790 } 2791 return row; 2792 } 2793 getMatrix() { 2794 return this.buffer; 2795 } 2796 isCropSupported() { 2797 return true; 2798 } 2799 crop(left /*int*/, top /*int*/, width /*int*/, height /*int*/) { 2800 super.crop(left, top, width, height); 2801 return this; 2802 } 2803 /** 2804 * This is always true, since the image is a gray-scale image. 2805 * 2806 * @return true 2807 */ 2808 isRotateSupported() { 2809 return true; 2810 } 2811 rotateCounterClockwise() { 2812 this.rotate(-90); 2813 return this; 2814 } 2815 rotateCounterClockwise45() { 2816 this.rotate(-45); 2817 return this; 2818 } 2819 getTempCanvasElement() { 2820 if (null === this.tempCanvasElement) { 2821 const tempCanvasElement = this.canvas.ownerDocument.createElement('canvas'); 2822 tempCanvasElement.width = this.canvas.width; 2823 tempCanvasElement.height = this.canvas.height; 2824 this.tempCanvasElement = tempCanvasElement; 2825 } 2826 return this.tempCanvasElement; 2827 } 2828 rotate(angle) { 2829 const tempCanvasElement = this.getTempCanvasElement(); 2830 const tempContext = tempCanvasElement.getContext('2d'); 2831 const angleRadians = angle * HTMLCanvasElementLuminanceSource.DEGREE_TO_RADIANS; 2832 // Calculate and set new dimensions for temp canvas 2833 const width = this.canvas.width; 2834 const height = this.canvas.height; 2835 const newWidth = Math.ceil(Math.abs(Math.cos(angleRadians)) * width + Math.abs(Math.sin(angleRadians)) * height); 2836 const newHeight = Math.ceil(Math.abs(Math.sin(angleRadians)) * width + Math.abs(Math.cos(angleRadians)) * height); 2837 tempCanvasElement.width = newWidth; 2838 tempCanvasElement.height = newHeight; 2839 // Draw at center of temp canvas to prevent clipping of image data 2840 tempContext.translate(newWidth / 2, newHeight / 2); 2841 tempContext.rotate(angleRadians); 2842 tempContext.drawImage(this.canvas, width / -2, height / -2); 2843 this.buffer = HTMLCanvasElementLuminanceSource.makeBufferFromCanvasImageData(tempCanvasElement); 2844 return this; 2845 } 2846 invert() { 2847 return new InvertedLuminanceSource(this); 2848 } 2849 } 2850 HTMLCanvasElementLuminanceSource.DEGREE_TO_RADIANS = Math.PI / 180; 2851 HTMLCanvasElementLuminanceSource.FRAME_INDEX = true; 2852 2853 /** 2854 * @deprecated Moving to @zxing/browser 2855 * 2856 * Video input device metadata containing the id and label of the device if available. 2857 */ 2858 class VideoInputDevice { 2859 /** 2860 * Creates an instance of VideoInputDevice. 2861 * 2862 * @param {string} deviceId the video input device id 2863 * @param {string} label the label of the device if available 2864 */ 2865 constructor(deviceId, label, groupId) { 2866 this.deviceId = deviceId; 2867 this.label = label; 2868 /** @inheritdoc */ 2869 this.kind = 'videoinput'; 2870 this.groupId = groupId || undefined; 2871 } 2872 /** @inheritdoc */ 2873 toJSON() { 2874 return { 2875 kind: this.kind, 2876 groupId: this.groupId, 2877 deviceId: this.deviceId, 2878 label: this.label, 2879 }; 2880 } 2881 } 2882 2883 var __awaiter = ((globalThis || global || self || window || undefined) && (globalThis || global || self || window || undefined).__awaiter) || function (thisArg, _arguments, P, generator) { 2884 function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 2885 return new (P || (P = Promise))(function (resolve, reject) { 2886 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 2887 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 2888 function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 2889 step((generator = generator.apply(thisArg, _arguments || [])).next()); 2890 }); 2891 }; 2892 /** 2893 * @deprecated Moving to @zxing/browser 2894 * 2895 * Base class for browser code reader. 2896 */ 2897 class BrowserCodeReader { 2898 /** 2899 * Creates an instance of BrowserCodeReader. 2900 * @param {Reader} reader The reader instance to decode the barcode 2901 * @param {number} [timeBetweenScansMillis=500] the time delay between subsequent successful decode tries 2902 * 2903 * @memberOf BrowserCodeReader 2904 */ 2905 constructor(reader, timeBetweenScansMillis = 500, _hints) { 2906 this.reader = reader; 2907 this.timeBetweenScansMillis = timeBetweenScansMillis; 2908 this._hints = _hints; 2909 /** 2910 * This will break the loop. 2911 */ 2912 this._stopContinuousDecode = false;
2913 /** 2914 * This will break the loop. 2915 */ 2916 this._stopAsyncDecode = false; 2917 /** 2918 * Delay time between decode attempts made by the scanner. 2919 */ 2920 this._timeBetweenDecodingAttempts = 0; 2921 } 2922 /** 2923 * If navigator is present. 2924 */ 2925 get hasNavigator() { 2926 return typeof navigator !== 'undefined'; 2927 } 2928 /** 2929 * If mediaDevices under navigator is supported. 2930 */ 2931 get isMediaDevicesSuported() { 2932 return this.hasNavigator && !!navigator.mediaDevices; 2933 } 2934 /** 2935 * If enumerateDevices under navigator is supported. 2936 */ 2937 get canEnumerateDevices() { 2938 return !!(this.isMediaDevicesSuported && navigator.mediaDevices.enumerateDevices); 2939 } 2940 /** Time between two decoding tries in milli seconds. */ 2941 get timeBetweenDecodingAttempts() { 2942 return this._timeBetweenDecodingAttempts; 2943 } 2944 /** 2945 * Change the time span the decoder waits between two decoding tries. 2946 * 2947 * @param {number} millis Time between two decoding tries in milli seconds. 2948 */ 2949 set timeBetweenDecodingAttempts(millis) { 2950 this._timeBetweenDecodingAttempts = millis < 0 ? 0 : millis; 2951 } 2952 /** 2953 * Sets the hints. 2954 */ 2955 set hints(hints) { 2956 this._hints = hints || null; 2957 } 2958 /** 2959 * Sets the hints. 2960 */ 2961 get hints() { 2962 return this._hints
vendor: 24,925 bytes, lines 2962-3524
2962; 2963 } 2964 /** 2965 * Lists all the available video input devices. 2966 */ 2967 listVideoInputDevices() { 2968 return __awaiter(this, void 0, void 0, function* () { 2969 if (!this.hasNavigator) { 2970 throw new Error("Can't enumerate devices, navigator is not present."); 2971 } 2972 if (!this.canEnumerateDevices) { 2973 throw new Error("Can't enumerate devices, method not supported."); 2974 } 2975 const devices = yield navigator.mediaDevices.enumerateDevices(); 2976 const videoDevices = []; 2977 for (const device of devices) { 2978 const kind = device.kind === 'video' ? 'videoinput' : device.kind; 2979 if (kind !== 'videoinput') { 2980 continue; 2981 } 2982 const deviceId = device.deviceId || device.id; 2983 const label = device.label || `Video device ${videoDevices.length + 1}`; 2984 const groupId = device.groupId; 2985 const videoDevice = { deviceId, label, kind, groupId }; 2986 videoDevices.push(videoDevice); 2987 } 2988 return videoDevices; 2989 }); 2990 } 2991 /** 2992 * Obtain the list of available devices with type 'videoinput'. 2993 * 2994 * @returns {Promise<VideoInputDevice[]>} an array of available video input devices 2995 * 2996 * @memberOf BrowserCodeReader 2997 * 2998 * @deprecated Use `listVideoInputDevices` instead. 2999 */ 3000 getVideoInputDevices() { 3001 return __awaiter(this, void 0, void 0, function* () { 3002 const devices = yield this.listVideoInputDevices(); 3003 return devices.map(d => new VideoInputDevice(d.deviceId, d.label)); 3004 }); 3005 } 3006 /** 3007 * Let's you find a device using it's Id. 3008 */ 3009 findDeviceById(deviceId) { 3010 return __awaiter(this, void 0, void 0, function* () { 3011 const devices = yield this.listVideoInputDevices(); 3012 if (!devices) { 3013 return null; 3014 } 3015 return devices.find(x => x.deviceId === deviceId); 3016 }); 3017 } 3018 /** 3019 * Decodes the barcode from the device specified by deviceId while showing the video in the specified video element. 3020 * 3021 * @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. 3022 * @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. 3023 * @returns The decoding result. 3024 * 3025 * @memberOf BrowserCodeReader 3026 * 3027 * @deprecated Use `decodeOnceFromVideoDevice` instead. 3028 */ 3029 decodeFromInputVideoDevice(deviceId, videoSource) { 3030 return __awaiter(this, void 0, void 0, function* () { 3031 return yield this.decodeOnceFromVideoDevice(deviceId, videoSource); 3032 }); 3033 } 3034 /** 3035 * In one attempt, tries to decode the barcode from the device specified by deviceId while showing the video in the specified video element. 3036 * 3037 * @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. 3038 * @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. 3039 * @returns The decoding result. 3040 * 3041 * @memberOf BrowserCodeReader 3042 */ 3043 decodeOnceFromVideoDevice(deviceId, videoSource) { 3044 return __awaiter(this, void 0, void 0, function* () { 3045 this.reset(); 3046 let videoConstraints; 3047 if (!deviceId) { 3048 videoConstraints = { facingMode: 'environment' }; 3049 } 3050 else { 3051 videoConstraints = { deviceId: { exact: deviceId } }; 3052 } 3053 const constraints = { video: videoConstraints }; 3054 return yield this.decodeOnceFromConstraints(constraints, videoSource); 3055 }); 3056 } 3057 /** 3058 * 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. 3059 * 3060 * @param constraints the media stream constraints to get s valid media stream to decode from 3061 * @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. 3062 * @returns The decoding result. 3063 * 3064 * @memberOf BrowserCodeReader 3065 */ 3066 decodeOnceFromConstraints(constraints, videoSource) { 3067 return __awaiter(this, void 0, void 0, function* () { 3068 const stream = yield navigator.mediaDevices.getUserMedia(constraints); 3069 return yield this.decodeOnceFromStream(stream, videoSource); 3070 }); 3071 } 3072 /** 3073 * 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. 3074 * 3075 * @param {MediaStream} [constraints] the media stream constraints to get s valid media stream to decode from 3076 * @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. 3077 * @returns {Promise<Result>} The decoding result. 3078 * 3079 * @memberOf BrowserCodeReader 3080 */ 3081 decodeOnceFromStream(stream, videoSource) { 3082 return __awaiter(this, void 0, void 0, function* () { 3083 this.reset(); 3084 const video = yield this.attachStreamToVideo(stream, videoSource); 3085 const result = yield this.decodeOnce(video); 3086 return result; 3087 }); 3088 } 3089 /** 3090 * Continuously decodes the barcode from the device specified by device while showing the video in the specified video element. 3091 * 3092 * @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. 3093 * @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. 3094 * @returns {Promise<void>} 3095 * 3096 * @memberOf BrowserCodeReader 3097 * 3098 * @deprecated Use `decodeFromVideoDevice` instead. 3099 */ 3100 decodeFromInputVideoDeviceContinuously(deviceId, videoSource, callbackFn) { 3101 return __awaiter(this, void 0, void 0, function* () { 3102 return yield this.decodeFromVideoDevice(deviceId, videoSource, callbackFn); 3103 }); 3104 } 3105 /** 3106 * Continuously tries to decode the barcode from the device specified by device while showing the video in the specified video element. 3107 * 3108 * @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. 3109 * @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. 3110 * @returns {Promise<void>} 3111 * 3112 * @memberOf BrowserCodeReader 3113 */ 3114 decodeFromVideoDevice(deviceId, videoSource, callbackFn) { 3115 return __awaiter(this, void 0, void 0, function* () { 3116 let videoConstraints; 3117 if (!deviceId) { 3118 videoConstraints = { facingMode: 'environment' }; 3119 } 3120 else { 3121 videoConstraints = { deviceId: { exact: deviceId } }; 3122 } 3123 const constraints = { video: videoConstraints }; 3124 return yield this.decodeFromConstraints(constraints, videoSource, callbackFn); 3125 }); 3126 } 3127 /** 3128 * Continuously tries to decode the barcode from a stream obtained from the given constraints while showing the video in the specified video element. 3129 * 3130 * @param {MediaStream} [constraints] the media stream constraints to get s valid media stream to decode from 3131 * @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. 3132 * @returns {Promise<Result>} The decoding result. 3133 * 3134 * @memberOf BrowserCodeReader 3135 */ 3136 decodeFromConstraints(constraints, videoSource, callbackFn) { 3137 return __awaiter(this, void 0, void 0, function* () { 3138 const stream = yield navigator.mediaDevices.getUserMedia(constraints); 3139 return yield this.decodeFromStream(stream, videoSource, callbackFn); 3140 }); 3141 } 3142 /** 3143 * 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. 3144 * 3145 * @param {MediaStream} [constraints] the media stream constraints to get s valid media stream to decode from 3146 * @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. 3147 * @returns {Promise<Result>} The decoding result. 3148 * 3149 * @memberOf BrowserCodeReader 3150 */ 3151 decodeFromStream(stream, videoSource, callbackFn) { 3152 return __awaiter(this, void 0, void 0, function* () { 3153 this.reset(); 3154 const video = yield this.attachStreamToVideo(stream, videoSource); 3155 return yield this.decodeContinuously(video, callbackFn); 3156 }); 3157 } 3158 /** 3159 * Breaks the decoding loop. 3160 */ 3161 stopAsyncDecode() { 3162 this._stopAsyncDecode = true; 3163 } 3164 /** 3165 * Breaks the decoding loop. 3166 */ 3167 stopContinuousDecode() { 3168 this._stopContinuousDecode = true; 3169 } 3170 /** 3171 * Sets the new stream and request a new decoding-with-delay. 3172 * 3173 * @param stream The stream to be shown in the video element. 3174 * @param decodeFn A callback for the decode method. 3175 */ 3176 attachStreamToVideo(stream, videoSource) { 3177 return __awaiter(this, void 0, void 0, function* () { 3178 const videoElement = this.prepareVideoElement(videoSource); 3179 this.addVideoSource(videoElement, stream); 3180 this.videoElement = videoElement; 3181 this.stream = stream; 3182 yield this.playVideoOnLoadAsync(videoElement); 3183 return videoElement; 3184 }); 3185 } 3186 /** 3187 * 3188 * @param videoElement 3189 */ 3190 playVideoOnLoadAsync(videoElement) { 3191 return new Promise((resolve, reject) => this.playVideoOnLoad(videoElement, () => resolve())); 3192 } 3193 /** 3194 * Binds listeners and callbacks to the videoElement. 3195 * 3196 * @param element 3197 * @param callbackFn 3198 */ 3199 playVideoOnLoad(element, callbackFn) { 3200 this.videoEndedListener = () => this.stopStreams(); 3201 this.videoCanPlayListener = () => this.tryPlayVideo(element); 3202 element.addEventListener('ended', this.videoEndedListener); 3203 element.addEventListener('canplay', this.videoCanPlayListener); 3204 element.addEventListener('playing', callbackFn); 3205 // if canplay was already fired, we won't know when to play, so just give it a try 3206 this.tryPlayVideo(element); 3207 } 3208 /** 3209 * Checks if the given video element is currently playing. 3210 */ 3211 isVideoPlaying(video) { 3212 return (video.currentTime > 0 && 3213 !video.paused && 3214 !video.ended && 3215 video.readyState > 2); 3216 } 3217 /** 3218 * Just tries to play the video and logs any errors. 3219 * The play call is only made is the video is not already playing. 3220 */ 3221 tryPlayVideo(videoElement) { 3222 return __awaiter(this, void 0, void 0, function* () { 3223 if (this.isVideoPlaying(videoElement)) { 3224 console.warn('Trying to play video that is already playing.'); 3225 return; 3226 } 3227 try { 3228 yield videoElement.play(); 3229 } 3230 catch (_a) { 3231 console.warn('It was not possible to play the video.'); 3232 } 3233 }); 3234 } 3235 /** 3236 * Searches and validates a media element. 3237 */ 3238 getMediaElement(mediaElementId, type) { 3239 const mediaElement = document.getElementById(mediaElementId); 3240 if (!mediaElement) { 3241 throw new ArgumentException(`element with id '${mediaElementId}' not found`); 3242 } 3243 if (mediaElement.nodeName.toLowerCase() !== type.toLowerCase()) { 3244 throw new ArgumentException(`element with id '${mediaElementId}' must be an ${type} element`); 3245 } 3246 return mediaElement; 3247 } 3248 /** 3249 * Decodes the barcode from an image. 3250 * 3251 * @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. 3252 * @param {string} [url] 3253 * @returns {Promise<Result>} The decoding result. 3254 * 3255 * @memberOf BrowserCodeReader 3256 */ 3257 decodeFromImage(source, url) { 3258 if (!source && !url) { 3259 throw new ArgumentException('either imageElement with a src set or an url must be provided'); 3260 } 3261 if (url && !source) { 3262 return this.decodeFromImageUrl(url); 3263 } 3264 return this.decodeFromImageElement(source); 3265 } 3266 /** 3267 * Decodes the barcode from a video. 3268 * 3269 * @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. 3270 * @param {string} [url] 3271 * @returns {Promise<Result>} The decoding result. 3272 * 3273 * @memberOf BrowserCodeReader 3274 */ 3275 decodeFromVideo(source, url) { 3276 if (!source && !url) { 3277 throw new ArgumentException('Either an element with a src set or an URL must be provided'); 3278 } 3279 if (url && !source) { 3280 return this.decodeFromVideoUrl(url); 3281 } 3282 return this.decodeFromVideoElement(source); 3283 } 3284 /** 3285 * Decodes continuously the barcode from a video. 3286 * 3287 * @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. 3288 * @param {string} [url] 3289 * @returns {Promise<Result>} The decoding result. 3290 * 3291 * @memberOf BrowserCodeReader 3292 * 3293 * @experimental 3294 */ 3295 decodeFromVideoContinuously(source, url, callbackFn) { 3296 if (undefined === source && undefined === url) { 3297 throw new ArgumentException('Either an element with a src set or an URL must be provided'); 3298 } 3299 if (url && !source) { 3300 return this.decodeFromVideoUrlContinuously(url, callbackFn); 3301 } 3302 return this.decodeFromVideoElementContinuously(source, callbackFn); 3303 } 3304 /** 3305 * Decodes something from an image HTML element. 3306 */ 3307 decodeFromImageElement(source) { 3308 if (!source) { 3309 throw new ArgumentException('An image element must be provided.'); 3310 } 3311 this.reset(); 3312 const element = this.prepareImageElement(source); 3313 this.imageElement = element; 3314 let task; 3315 if (this.isImageLoaded(element)) { 3316 task = this.decodeOnce(element, false, true); 3317 } 3318 else { 3319 task = this._decodeOnLoadImage(element); 3320 } 3321 return task; 3322 } 3323 /** 3324 * Decodes something from an image HTML element. 3325 */ 3326 decodeFromVideoElement(source) { 3327 const element = this._decodeFromVideoElementSetup(source); 3328 return this._decodeOnLoadVideo(element); 3329 } 3330 /** 3331 * Decodes something from an image HTML element. 3332 */ 3333 decodeFromVideoElementContinuously(source, callbackFn) { 3334 const element = this._decodeFromVideoElementSetup(source); 3335 return this._decodeOnLoadVideoContinuously(element, callbackFn); 3336 } 3337 /** 3338 * Sets up the video source so it can be decoded when loaded. 3339 * 3340 * @param source The video source element. 3341 */ 3342 _decodeFromVideoElementSetup(source) { 3343 if (!source) { 3344 throw new ArgumentException('A video element must be provided.'); 3345 } 3346 this.reset(); 3347 const element = this.prepareVideoElement(source); 3348 // defines the video element before starts decoding 3349 this.videoElement = element; 3350 return element; 3351 } 3352 /** 3353 * Decodes an image from a URL. 3354 */ 3355 decodeFromImageUrl(url) { 3356 if (!url) { 3357 throw new ArgumentException('An URL must be provided.'); 3358 } 3359 this.reset(); 3360 const element = this.prepareImageElement(); 3361 this.imageElement = element; 3362 const decodeTask = this._decodeOnLoadImage(element); 3363 element.src = url; 3364 return decodeTask; 3365 } 3366 /** 3367 * Decodes an image from a URL. 3368 */ 3369 decodeFromVideoUrl(url) { 3370 if (!url) { 3371 throw new ArgumentException('An URL must be provided.'); 3372 } 3373 this.reset(); 3374 // creates a new element 3375 const element = this.prepareVideoElement(); 3376 const decodeTask = this.decodeFromVideoElement(element); 3377 element.src = url; 3378 return decodeTask; 3379 } 3380 /** 3381 * Decodes an image from a URL. 3382 * 3383 * @experimental 3384 */ 3385 decodeFromVideoUrlContinuously(url, callbackFn) { 3386 if (!url) { 3387 throw new ArgumentException('An URL must be provided.'); 3388 } 3389 this.reset(); 3390 // creates a new element 3391 const element = this.prepareVideoElement(); 3392 const decodeTask = this.decodeFromVideoElementContinuously(element, callbackFn); 3393 element.src = url; 3394 return decodeTask; 3395 } 3396 _decodeOnLoadImage(element) { 3397 return new Promise((resolve, reject) => { 3398 this.imageLoadedListener = () => this.decodeOnce(element, false, true).then(resolve, reject); 3399 element.addEventListener('load', this.imageLoadedListener); 3400 }); 3401 } 3402 _decodeOnLoadVideo(videoElement) { 3403 return __awaiter(this, void 0, void 0, function* () { 3404 // plays the video 3405 yield this.playVideoOnLoadAsync(videoElement); 3406 // starts decoding after played the video 3407 return yield this.decodeOnce(videoElement); 3408 }); 3409 } 3410 _decodeOnLoadVideoContinuously(videoElement, callbackFn) { 3411 return __awaiter(this, void 0, void 0, function* () { 3412 // plays the video 3413 yield this.playVideoOnLoadAsync(videoElement); 3414 // starts decoding after played the video 3415 this.decodeContinuously(videoElement, callbackFn); 3416 }); 3417 } 3418 isImageLoaded(img) { 3419 // During the onload event, IE correctly identifies any images that 3420 // weren’t downloaded as not complete. Others should too. Gecko-based 3421 // browsers act like NS4 in that they report this incorrectly. 3422 if (!img.complete) { 3423 return false; 3424 } 3425 // However, they do have two very useful properties: naturalWidth and 3426 // naturalHeight. These give the true size of the image. If it failed 3427 // to load, either of these should be zero. 3428 if (img.naturalWidth === 0) { 3429 return false; 3430 } 3431 // No other way of checking: assume it’s ok. 3432 return true; 3433 } 3434 prepareImageElement(imageSource) { 3435 let imageElement; 3436 if (typeof imageSource === 'undefined') { 3437 imageElement = document.createElement('img'); 3438 imageElement.width = 200; 3439 imageElement.height = 200; 3440 } 3441 if (typeof imageSource === 'string') { 3442 imageElement = this.getMediaElement(imageSource, 'img'); 3443 } 3444 if (imageSource instanceof HTMLImageElement) { 3445 imageElement = imageSource; 3446 } 3447 return imageElement; 3448 } 3449 /** 3450 * Sets a HTMLVideoElement for scanning or creates a new one. 3451 * 3452 * @param videoSource The HTMLVideoElement to be set. 3453 */ 3454 prepareVideoElement(videoSource) { 3455 let videoElement; 3456 if (!videoSource && typeof document !== 'undefined') { 3457 videoElement = document.createElement('video'); 3458 videoElement.width = 200; 3459 videoElement.height = 200; 3460 } 3461 if (typeof videoSource === 'string') { 3462 videoElement = (this.getMediaElement(videoSource, 'video')); 3463 } 3464 if (videoSource instanceof HTMLVideoElement) { 3465 videoElement = videoSource; 3466 } 3467 // Needed for iOS 11 3468 videoElement.setAttribute('autoplay', 'true'); 3469 videoElement.setAttribute('muted', 'true'); 3470 videoElement.setAttribute('playsinline', 'true'); 3471 return videoElement; 3472 } 3473 /** 3474 * Tries to decode from the video input until it finds some value. 3475 */ 3476 decodeOnce(element, retryIfNotFound = true, retryIfChecksumOrFormatError = true) { 3477 this._stopAsyncDecode = false; 3478 const loop = (resolve, reject) => { 3479 if (this._stopAsyncDecode) { 3480 reject(new NotFoundException('Video stream has ended before any code could be detected.')); 3481 this._stopAsyncDecode = undefined; 3482 return; 3483 } 3484 try { 3485 const result = this.decode(element); 3486 resolve(result); 3487 } 3488 catch (e) { 3489 const ifNotFound = retryIfNotFound && e instanceof NotFoundException; 3490 const isChecksumOrFormatError = e instanceof ChecksumException || e instanceof FormatException; 3491 const ifChecksumOrFormat = isChecksumOrFormatError && retryIfChecksumOrFormatError; 3492 if (ifNotFound || ifChecksumOrFormat) { 3493 // trying again 3494 return setTimeout(loop, this._timeBetweenDecodingAttempts, resolve, reject); 3495 } 3496 reject(e); 3497 } 3498 }; 3499 return new Promise((resolve, reject) => loop(resolve, reject)); 3500 } 3501 /** 3502 * Continuously decodes from video input. 3503 */ 3504 decodeContinuously(element, callbackFn) { 3505 this._stopContinuousDecode = false; 3506 const loop = () => { 3507 if (this._stopContinuousDecode) { 3508 this._stopContinuousDecode = undefined; 3509 return; 3510 } 3511 try { 3512 const result = this.decode(element); 3513 callbackFn(result, null); 3514 setTimeout(loop, this.timeBetweenScansMillis); 3515 } 3516 catch (e) { 3517 callbackFn(null, e); 3518 const isChecksumOrFormatError = e instanceof ChecksumException || e instanceof FormatException; 3519 const isNotFound = e instanceof NotFoundException; 3520 if (isChecksumOrFormatError || isNotFound) { 3521 // trying again 3522 setTimeout(loop, this._timeBetweenDecodingAttempts); 3523 } 3524
vendor: 13,183 bytes, lines 3524-3892
3524} 3525 }; 3526 loop(); 3527 } 3528 /** 3529 * Gets the BinaryBitmap for ya! (and decodes it) 3530 */ 3531 decode(element) { 3532 // get binary bitmap for decode function 3533 const binaryBitmap = this.createBinaryBitmap(element); 3534 return this.decodeBitmap(binaryBitmap); 3535 } 3536 /** 3537 * Creates a binaryBitmap based in some image source. 3538 * 3539 * @param mediaElement HTML element containing drawable image source. 3540 */ 3541 createBinaryBitmap(mediaElement) { 3542 this.getCaptureCanvasContext(mediaElement); 3543 // doing a scan with inverted colors on the second scan should only happen for video elements 3544 let doAutoInvert = false; 3545 if (mediaElement instanceof HTMLVideoElement) { 3546 this.drawFrameOnCanvas(mediaElement); 3547 doAutoInvert = true; 3548 } 3549 else { 3550 this.drawImageOnCanvas(mediaElement); 3551 } 3552 const canvas = this.getCaptureCanvas(mediaElement); 3553 const luminanceSource = new HTMLCanvasElementLuminanceSource(canvas, doAutoInvert); 3554 const hybridBinarizer = new HybridBinarizer(luminanceSource); 3555 return new BinaryBitmap(hybridBinarizer); 3556 } 3557 /** 3558 * 3559 */ 3560 getCaptureCanvasContext(mediaElement) { 3561 if (!this.captureCanvasContext) { 3562 const elem = this.getCaptureCanvas(mediaElement); 3563 let ctx; 3564 try { 3565 ctx = elem.getContext('2d', { willReadFrequently: true }); 3566 } 3567 catch (e) { 3568 ctx = elem.getContext('2d'); 3569 } 3570 this.captureCanvasContext = ctx; 3571 } 3572 return this.captureCanvasContext; 3573 } 3574 /** 3575 * 3576 */ 3577 getCaptureCanvas(mediaElement) { 3578 if (!this.captureCanvas) { 3579 const elem = this.createCaptureCanvas(mediaElement); 3580 this.captureCanvas = elem; 3581 } 3582 return this.captureCanvas; 3583 } 3584 /** 3585 * Overwriting this allows you to manipulate the next frame in anyway you want before decode. 3586 */ 3587 drawFrameOnCanvas(srcElement, dimensions = { 3588 sx: 0, 3589 sy: 0, 3590 sWidth: srcElement.videoWidth, 3591 sHeight: srcElement.videoHeight, 3592 dx: 0, 3593 dy: 0, 3594 dWidth: srcElement.videoWidth, 3595 dHeight: srcElement.videoHeight, 3596 }, canvasElementContext = this.captureCanvasContext) { 3597 canvasElementContext.drawImage(srcElement, dimensions.sx, dimensions.sy, dimensions.sWidth, dimensions.sHeight, dimensions.dx, dimensions.dy, dimensions.dWidth, dimensions.dHeight); 3598 } 3599 /** 3600 * Ovewriting this allows you to manipulate the snapshot image in anyway you want before decode. 3601 */ 3602 drawImageOnCanvas(srcElement, dimensions = { 3603 sx: 0, 3604 sy: 0, 3605 sWidth: srcElement.naturalWidth, 3606 sHeight: srcElement.naturalHeight, 3607 dx: 0, 3608 dy: 0, 3609 dWidth: srcElement.naturalWidth, 3610 dHeight: srcElement.naturalHeight, 3611 }, canvasElementContext = this.captureCanvasContext) { 3612 canvasElementContext.drawImage(srcElement, dimensions.sx, dimensions.sy, dimensions.sWidth, dimensions.sHeight, dimensions.dx, dimensions.dy, dimensions.dWidth, dimensions.dHeight); 3613 } 3614 /** 3615 * Call the encapsulated readers decode 3616 */ 3617 decodeBitmap(binaryBitmap) { 3618 return this.reader.decode(binaryBitmap, this._hints); 3619 } 3620 /** 3621 * 🖌 Prepares the canvas for capture and scan frames. 3622 */ 3623 createCaptureCanvas(mediaElement) { 3624 if (typeof document === 'undefined') { 3625 this._destroyCaptureCanvas(); 3626 return null; 3627 } 3628 const canvasElement = document.createElement('canvas'); 3629 let width; 3630 let height; 3631 if (typeof mediaElement !== 'undefined') { 3632 if (mediaElement instanceof HTMLVideoElement) { 3633 width = mediaElement.videoWidth; 3634 height = mediaElement.videoHeight; 3635 } 3636 else if (mediaElement instanceof HTMLImageElement) { 3637 width = mediaElement.naturalWidth || mediaElement.width; 3638 height = mediaElement.naturalHeight || mediaElement.height; 3639 } 3640 } 3641 canvasElement.style.width = width + 'px'; 3642 canvasElement.style.height = height + 'px'; 3643 canvasElement.width = width; 3644 canvasElement.height = height; 3645 return canvasElement; 3646 } 3647 /** 3648 * Stops the continuous scan and cleans the stream. 3649 */ 3650 stopStreams() { 3651 if (this.stream) { 3652 this.stream.getVideoTracks().forEach(t => t.stop()); 3653 this.stream = undefined; 3654 } 3655 if (this._stopAsyncDecode === false) { 3656 this.stopAsyncDecode(); 3657 } 3658 if (this._stopContinuousDecode === false) { 3659 this.stopContinuousDecode(); 3660 } 3661 } 3662 /** 3663 * Resets the code reader to the initial state. Cancels any ongoing barcode scanning from video or camera. 3664 * 3665 * @memberOf BrowserCodeReader 3666 */ 3667 reset() { 3668 // stops the camera, preview and scan 🔴 3669 this.stopStreams(); 3670 // clean and forget about HTML elements 3671 this._destroyVideoElement(); 3672 this._destroyImageElement(); 3673 this._destroyCaptureCanvas(); 3674 } 3675 _destroyVideoElement() { 3676 if (!this.videoElement) { 3677 return; 3678 } 3679 // first gives freedon to the element 🕊 3680 if (typeof this.videoEndedListener !== 'undefined') { 3681 this.videoElement.removeEventListener('ended', this.videoEndedListener); 3682 } 3683 if (typeof this.videoPlayingEventListener !== 'undefined') { 3684 this.videoElement.removeEventListener('playing', this.videoPlayingEventListener); 3685 } 3686 if (typeof this.videoCanPlayListener !== 'undefined') { 3687 this.videoElement.removeEventListener('loadedmetadata', this.videoCanPlayListener); 3688 } 3689 // then forgets about that element 😢 3690 this.cleanVideoSource(this.videoElement); 3691 this.videoElement = undefined; 3692 } 3693 _destroyImageElement() { 3694 if (!this.imageElement) { 3695 return; 3696 } 3697 // first gives freedon to the element 🕊 3698 if (undefined !== this.imageLoadedListener) { 3699 this.imageElement.removeEventListener('load', this.imageLoadedListener); 3700 } 3701 // then forget about that element 😢 3702 this.imageElement.src = undefined; 3703 this.imageElement.removeAttribute('src'); 3704 this.imageElement = undefined; 3705 } 3706 /** 3707 * Cleans canvas references 🖌 3708 */ 3709 _destroyCaptureCanvas() { 3710 // then forget about that element 😢 3711 this.captureCanvasContext = undefined; 3712 this.captureCanvas = undefined; 3713 } 3714 /** 3715 * Defines what the videoElement src will be. 3716 * 3717 * @param videoElement 3718 * @param stream 3719 */ 3720 addVideoSource(videoElement, stream) { 3721 // Older browsers may not have `srcObject` 3722 try { 3723 // @note Throws Exception if interrupted by a new loaded request 3724 videoElement.srcObject = stream; 3725 } 3726 catch (err) { 3727 // @note Avoid using this in new browsers, as it is going away. 3728 // @ts-ignore 3729 videoElement.src = URL.createObjectURL(stream); 3730 } 3731 } 3732 /** 3733 * Unbinds a HTML video src property. 3734 * 3735 * @param videoElement 3736 */ 3737 cleanVideoSource(videoElement) { 3738 try { 3739 videoElement.srcObject = null; 3740 } 3741 catch (err) { 3742 videoElement.src = ''; 3743 } 3744 this.videoElement.removeAttribute('src'); 3745 } 3746 } 3747 3748 /* 3749 * Copyright 2007 ZXing authors 3750 * 3751 * Licensed under the Apache License, Version 2.0 (the "License"); 3752 * you may not use this file except in compliance with the License. 3753 * You may obtain a copy of the License at 3754 * 3755 * http://www.apache.org/licenses/LICENSE-2.0 3756 * 3757 * Unless required by applicable law or agreed to in writing, software 3758 * distributed under the License is distributed on an "AS IS" BASIS, 3759 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 3760 * See the License for the specific language governing permissions and 3761 * limitations under the License. 3762 */ 3763 /** 3764 * <p>Encapsulates the result of decoding a barcode within an image.</p> 3765 * 3766 * @author Sean Owen 3767 */ 3768 class Result$1 { 3769 // public constructor(private text: string, 3770 // Uint8Array rawBytes, 3771 // ResultPoconst resultPoints: Int32Array, 3772 // BarcodeFormat format) { 3773 // this(text, rawBytes, resultPoints, format, System.currentTimeMillis()) 3774 // } 3775 // public constructor(text: string, 3776 // Uint8Array rawBytes, 3777 // ResultPoconst resultPoints: Int32Array, 3778 // BarcodeFormat format, 3779 // long timestamp) { 3780 // this(text, rawBytes, rawBytes == null ? 0 : 8 * rawBytes.length, 3781 // resultPoints, format, timestamp) 3782 // } 3783 constructor(text, rawBytes, numBits = rawBytes == null ? 0 : 8 * rawBytes.length, resultPoints, format, timestamp = System.currentTimeMillis()) { 3784 this.text = text; 3785 this.rawBytes = rawBytes; 3786 this.numBits = numBits; 3787 this.resultPoints = resultPoints; 3788 this.format = format; 3789 this.timestamp = timestamp; 3790 this.text = text; 3791 this.rawBytes = rawBytes; 3792 if (undefined === numBits || null === numBits) { 3793 this.numBits = (rawBytes === null || rawBytes === undefined) ? 0 : 8 * rawBytes.length; 3794 } 3795 else { 3796 this.numBits = numBits; 3797 } 3798 this.resultPoints = resultPoints; 3799 this.format = format; 3800 this.resultMetadata = null; 3801 if (undefined === timestamp || null === timestamp) { 3802 this.timestamp = System.currentTimeMillis(); 3803 } 3804 else { 3805 this.timestamp = timestamp; 3806 } 3807 } 3808 /** 3809 * @return raw text encoded by the barcode 3810 */ 3811 getText() { 3812 return this.text; 3813 } 3814 /** 3815 * @return raw bytes encoded by the barcode, if applicable, otherwise {@code null} 3816 */ 3817 getRawBytes() { 3818 return this.rawBytes; 3819 } 3820 /** 3821 * @return how many bits of {@link #getRawBytes()} are valid; typically 8 times its length 3822 * @since 3.3.0 3823 */ 3824 getNumBits() { 3825 return this.numBits; 3826 } 3827 /** 3828 * @return points related to the barcode in the image. These are typically points 3829 * identifying finder patterns or the corners of the barcode. The exact meaning is 3830 * specific to the type of barcode that was decoded. 3831 */ 3832 getResultPoints() { 3833 return this.resultPoints; 3834 } 3835 /** 3836 * @return {@link BarcodeFormat} representing the format of the barcode that was decoded 3837 */ 3838 getBarcodeFormat() { 3839 return this.format; 3840 } 3841 /** 3842 * @return {@link Map} mapping {@link ResultMetadataType} keys to values. May be 3843 * {@code null}. This contains optional metadata about what was detected about the barcode, 3844 * like orientation. 3845 */ 3846 getResultMetadata() { 3847 return this.resultMetadata; 3848 } 3849 putMetadata(type, value) { 3850 if (this.resultMetadata === null) { 3851 this.resultMetadata = new Map(); 3852 } 3853 this.resultMetadata.set(type, value); 3854 } 3855 putAllMetadata(metadata) { 3856 if (metadata !== null) { 3857 if (this.resultMetadata === null) { 3858 this.resultMetadata = metadata; 3859 } 3860 else { 3861 this.resultMetadata = new Map(metadata); 3862 } 3863 } 3864 } 3865 addResultPoints(newPoints) { 3866 const oldPoints = this.resultPoints; 3867 if (oldPoints === null) { 3868 this.resultPoints = newPoints; 3869 } 3870 else if (newPoints !== null && newPoints.length > 0) { 3871 const allPoints = new Array(oldPoints.length + newPoints.length); 3872 System.arraycopy(oldPoints, 0, allPoints, 0, oldPoints.length); 3873 System.arraycopy(newPoints, 0, allPoints, oldPoints.length, newPoints.length); 3874 this.resultPoints = allPoints; 3875 } 3876 } 3877 getTimestamp() { 3878 return this.timestamp; 3879 } 3880 /*@Override*/ 3881 toString() { 3882 return this.text; 3883 } 3884 } 3885 3886 /* 3887 * Direct port to TypeScript of ZXing by Adrian Toșcă 3888 */ 3889 /* 3890 * Copyright 2009 ZXing authors 3891 * 3892 * Licensed under the Apache License, Version 2.0 (the "License");
3893 * you may not use this file except in compliance with the License. 3894 * You may obtain a copy of the License at 3895 * 3896 * http://www.apache.org/licenses/LICENSE-2.0 3897 * 3898 * Unless required by applicable law or agreed to in writing, software 3899 * distributed under the License is distributed on an "AS IS" BASIS, 3900 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 3901 * See the License for the specific language governing permissions and 3902 * limitations under the License. 3903 */ 3904 /*namespace com.google.zxing {*/ 3905 /** 3906 * Enumerates barcode formats known to this package. Please keep alphabetized. 3907 * 3908 * @author Sean Owen 3909 */ 3910 var BarcodeFormat; 3911 (function (BarcodeFormat) { 3912 /** Aztec 2D barcode format. */ 3913 BarcodeFormat[BarcodeFormat["AZTEC"] = 0] = "AZTEC"; 3914 /** CODABAR 1D format. */ 3915 BarcodeFormat[BarcodeFormat["CODABAR"] = 1] = "CODABAR"; 3916 /** Code 39 1D format. */ 3917 BarcodeFormat[BarcodeFormat["CODE_39"] = 2] = "CODE_39"; 3918 /** Code 93 1D format. */ 3919 BarcodeFormat[BarcodeFormat["CODE_93"] = 3] = "CODE_93"; 3920 /** Code 128 1D format. */ 3921 BarcodeFormat[BarcodeFormat["CODE_128"] = 4] = "CODE_128"; 3922 /** Data Matrix 2D barcode format. */ 3923 BarcodeFormat[BarcodeFormat["DATA_MATRIX"] = 5] = "DATA_MATRIX"; 3924 /** EAN-8 1D format. */ 3925 BarcodeFormat[BarcodeFormat["EAN_8"] = 6] = "EAN_8"; 3926 /** EAN-13 1D format. */ 3927 BarcodeFormat[BarcodeFormat["EAN_13"] = 7] = "EAN_13"; 3928 /** ITF (Interleaved Two of Five) 1D format. */ 3929 BarcodeFormat[BarcodeFormat["ITF"] = 8] = "ITF"; 3930 /** MaxiCode 2D barcode format. */ 3931 BarcodeFormat[BarcodeFormat["MAXICODE"] = 9] = "MAXICODE"; 3932 /** PDF417 format. */ 3933 BarcodeFormat[BarcodeFormat["PDF_417"] = 10] = "PDF_417"; 3934 /** QR Code 2D barcode format. */ 3935 BarcodeFormat[BarcodeFormat["QR_CODE"] = 11] = "QR_CODE"; 3936 /** RSS 14 */ 3937 BarcodeFormat[BarcodeFormat["RSS_14"] = 12] = "RSS_14"; 3938 /** RSS EXPANDED */ 3939 BarcodeFormat[BarcodeFormat["RSS_EXPANDED"] = 13] = "RSS_EXPANDED"; 3940 /** UPC-A 1D format. */ 3941 BarcodeFormat[BarcodeFormat["UPC_A"] = 14] = "UPC_A"; 3942 /** UPC-E 1D format. */ 3943 BarcodeFormat[BarcodeFormat["UPC_E"] = 15] = "UPC_E"; 3944 /** UPC/EAN extension format. Not a stand-alone format. */ 3945 BarcodeFormat[BarcodeFormat["UPC_EAN_EXTENSION"] = 16] = "UPC_EAN_EXTENSION"; 3946 })(BarcodeFormat || (BarcodeFormat = {})); 3947 var BarcodeFormat$1 = BarcodeFormat; 3948 3949 /* 3950 * Copyright 2008 ZXing authors 3951 * 3952 * Licensed under the Apache License, Version 2.0 (the "License"); 3953 * you may not use this file except in compliance with the License. 3954 * You may obtain a copy of the License at 3955 * 3956 * http://www.apache.org/licenses/LICENSE-2.0 3957 * 3958 * Unless required by applicable law or agreed to in writing, software 3959 * distributed under the License is distributed on an "AS IS" BASIS, 3960 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 3961 * See the License for the specific language governing permissions and 3962 * limitations under the License. 3963 */ 3964 /*namespace com.google.zxing {*/ 3965 /** 3966 * Represents some type of metadata about the result of the decoding that the decoder 3967 * wishes to communicate back to the caller. 3968 * 3969 * @author Sean Owen 3970 */ 3971 var ResultMetadataType; 3972 (function (ResultMetadataType) { 3973 /** 3974 * Unspecified, application-specific metadata. Maps to an unspecified {@link Object}. 3975 */ 3976 ResultMetadataType[ResultMetadataType["OTHER"] = 0] = "OTHER"; 3977 /** 3978 * Denotes the likely approximate orientation of the barcode in the image. This value 3979 * is given as degrees rotated clockwise from the normal, upright orientation. 3980 * For example a 1D barcode which was found by reading top-to-bottom would be 3981 * said to have orientation "90". This key maps to an {@link Integer} whose 3982 * value is in the range [0,360). 3983 */ 3984 ResultMetadataType[ResultMetadataType["ORIENTATION"] = 1] = "ORIENTATION"; 3985 /** 3986 * <p>2D barcode formats typically encode text, but allow for a sort of 'byte mode' 3987 * which is sometimes used to encode binary data. While {@link Result} makes available 3988 * the complete raw bytes in the barcode for these formats, it does not offer the bytes 3989 * from the byte segments alone.</p> 3990 * 3991 * <p>This maps to a {@link java.util.List} of byte arrays corresponding to the 3992 * raw bytes in the byte segments in the barcode, in order.</p> 3993 */
3994 ResultMetadataType[ResultMetadataType["BYTE_SEGMENTS"] = 2] = "BYTE_SEGMENTS"; 3995 /** 3996 * Error correction level used, if applicable. The value type depends on the 3997 * format, but is typically a String. 3998 */ 3999 ResultMetadataType[ResultMetadataType["ERROR_CORRECTION_LEVEL"] = 3] = "ERROR_CORRECTION_LEVEL"; 4000 /** 4001 * For some periodicals, indicates the issue number as an {@link Integer}. 4002 */ 4003 ResultMetadataType[ResultMetadataType["ISSUE_NUMBER"] = 4] = "ISSUE_NUMBER"; 4004 /** 4005 * For some products, indicates the suggested retail price in the barcode as a 4006 * formatted {@link String}. 4007 */ 4008 ResultMetadataType[ResultMetadataType["SUGGESTED_PRICE"] = 5] = "SUGGESTED_PRICE"; 4009 /** 4010 * For some products, the possible country of manufacture as a {@link String} denoting the 4011 * ISO country code. Some map to multiple possible countries, like "US/CA". 4012 */ 4013 ResultMetadataType[ResultMetadataType["POSSIBLE_COUNTRY"] = 6] = "POSSIBLE_COUNTRY"; 4014 /** 4015 * For some products, the extension text 4016 */ 4017 ResultMetadataType[ResultMetadataType["UPC_EAN_EXTENSION"] = 7] = "UPC_EAN_EXTENSION"; 4018 /** 4019 * PDF417-specific metadata 4020 */ 4021 ResultMetadataType[ResultMetadataType["PDF417_EXTRA_METADATA"] = 8] = "PDF417_EXTRA_METADATA"; 4022 /** 4023 * If the code format supports structured append and the current scanned code is part of one then the 4024 * sequence number is given with it. 4025 */ 4026 ResultMetadataType[ResultMetadataType["STRUCTURED_APPEND_SEQUENCE"] = 9] = "STRUCTURED_APPEND_SEQUENCE"; 4027 /** 4028 * If the code format supports structured append and the current scanned code is part of one then the 4029 * parity is given with it. 4030 */ 4031 ResultMetadataType[ResultMetadataType["STRUCTURED_APPEND_PARITY"] = 10] = "STRUCTURED_APPEND_PARITY"; 4032 })(ResultMetadataType || (ResultMetadataType = {})); 4033 var ResultMetadataType$1 = ResultMetadataType; 4034 4035 /* 4036 * Copyright 2007 ZXing authors 4037 * 4038 * Licensed under the Apache License, Version 2.0 (the "License"); 4039 * you may not use this file except in compliance with the License. 4040 * You may obtain a copy of the License at 4041 * 4042 * http://www.apache.org/licenses/LICENSE-2.0 4043 * 4044 * Unless required by applicable law or agreed to in writing, software 4045 * distributed under the License is distributed on an "AS IS" BASIS, 4046 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 4047 * See the License for the specific language governing permissions and 4048 * limitations under the License. 4049 */ 4050 /*namespace com.google.zxing.common {*/ 4051 /*import java.util.List;*/ 4052 /** 4053 * <p>Encapsulates the result of decoding a matrix of bits. This typically 4054 * applies to 2D barcode formats. For now it contains the raw bytes obtained, 4055 * as well as a String interpretation of those bytes, if applicable.</p> 4056 * 4057 * @author Sean Owen 4058 */ 4059 class DecoderResult { 4060 // public constructor(rawBytes: Uint8Array, 4061 // text: string, 4062 // List<Uint8Array> byteSegments, 4063 // String ecLevel) { 4064 // this(rawBytes, text, byteSegments, ecLevel, -1, -1) 4065 // } 4066 constructor(rawBytes, text, byteSegments, ecLevel, structuredAppendSequenceNumber = -1, structuredAppendParity = -1) { 4067 this.rawBytes = rawBytes; 4068 this.text = text; 4069 this.byteSegments = byteSegments; 4070 this.ecLevel = ecLevel; 4071 this.structuredAppendSequenceNumber = structuredAppendSequenceNumber; 4072 this.structuredAppendParity = structuredAppendParity; 4073 this.numBits = (rawBytes === undefined || rawBytes === null) ? 0 : 8 * rawBytes.length; 4074 } 4075 /** 4076 * @return raw bytes representing the result, or {@code null} if not applicable 4077 */ 4078 getRawBytes() { 4079 return this.rawBytes; 4080 } 4081 /** 4082 * @return how many bits of {@link #getRawBytes()} are valid; typically 8 times its length 4083 * @since 3.3.0 4084 */ 4085 getNumBits() { 4086 return this.numBits; 4087 } 4088 /** 4089 * @param numBits overrides the number of bits that are valid in {@link #getRawBytes()} 4090 * @since 3.3.0 4091 */ 4092 setNumBits(numBits /*int*/) { 4093 this.numBits = numBits; 4094 } 4095 /** 4096 * @return text representation of the result 4097 */ 4098 getText() { 4099 return this.text; 4100 } 4101 /**
vendor: 3,670 bytes, lines 4102-4217
4102 * @return list of byte segments in the result, or {@code null} if not applicable 4103 */ 4104 getByteSegments() { 4105 return this.byteSegments; 4106 } 4107 /** 4108 * @return name of error correction level used, or {@code null} if not applicable 4109 */ 4110 getECLevel() { 4111 return this.ecLevel; 4112 } 4113 /** 4114 * @return number of errors corrected, or {@code null} if not applicable 4115 */ 4116 getErrorsCorrected() { 4117 return this.errorsCorrected; 4118 } 4119 setErrorsCorrected(errorsCorrected /*Integer*/) { 4120 this.errorsCorrected = errorsCorrected; 4121 } 4122 /** 4123 * @return number of erasures corrected, or {@code null} if not applicable 4124 */ 4125 getErasures() { 4126 return this.erasures; 4127 } 4128 setErasures(erasures /*Integer*/) { 4129 this.erasures = erasures; 4130 } 4131 /** 4132 * @return arbitrary additional metadata 4133 */ 4134 getOther() { 4135 return this.other; 4136 } 4137 setOther(other) { 4138 this.other = other; 4139 } 4140 hasStructuredAppend() { 4141 return this.structuredAppendParity >= 0 && this.structuredAppendSequenceNumber >= 0; 4142 } 4143 getStructuredAppendParity() { 4144 return this.structuredAppendParity; 4145 } 4146 getStructuredAppendSequenceNumber() { 4147 return this.structuredAppendSequenceNumber; 4148 } 4149 } 4150 4151 /* 4152 * Copyright 2007 ZXing authors 4153 * 4154 * Licensed under the Apache License, Version 2.0 (the "License"); 4155 * you may not use this file except in compliance with the License. 4156 * You may obtain a copy of the License at 4157 * 4158 * http://www.apache.org/licenses/LICENSE-2.0 4159 * 4160 * Unless required by applicable law or agreed to in writing, software 4161 * distributed under the License is distributed on an "AS IS" BASIS, 4162 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 4163 * See the License for the specific language governing permissions and 4164 * limitations under the License. 4165 */ 4166 /** 4167 * <p>This class contains utility methods for performing mathematical operations over 4168 * the Galois Fields. Operations use a given primitive polynomial in calculations.</p> 4169 * 4170 * <p>Throughout this package, elements of the GF are represented as an {@code int} 4171 * for convenience and speed (but at the cost of memory). 4172 * </p> 4173 * 4174 * @author Sean Owen 4175 * @author David Olivier 4176 */ 4177 class AbstractGenericGF { 4178 /** 4179 * @return 2 to the power of a in GF(size) 4180 */ 4181 exp(a) { 4182 return this.expTable[a]; 4183 } 4184 /** 4185 * @return base 2 log of a in GF(size) 4186 */ 4187 log(a /*int*/) { 4188 if (a === 0) { 4189 throw new IllegalArgumentException(); 4190 } 4191 return this.logTable[a]; 4192 } 4193 /** 4194 * Implements both addition and subtraction -- they are the same in GF(size). 4195 * 4196 * @return sum/difference of a and b 4197 */ 4198 static addOrSubtract(a /*int*/, b /*int*/) { 4199 return a ^ b; 4200 } 4201 } 4202 4203 /* 4204 * Copyright 2007 ZXing authors 4205 * 4206 * Licensed under the Apache License, Version 2.0 (the "License"); 4207 * you may not use this file except in compliance with the License. 4208 * You may obtain a copy of the License at 4209 * 4210 * http://www.apache.org/licenses/LICENSE-2.0 4211 * 4212 * Unless required by applicable law or agreed to in writing, software 4213 * distributed under the License is distributed on an "AS IS" BASIS, 4214 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 4215 * See the License for the specific language governing permissions and 4216 * limitations under the License. 4217
vendor: 10,283 bytes, lines 4217-4475
4217*/ 4218 /** 4219 * <p>Represents a polynomial whose coefficients are elements of a GF. 4220 * Instances of this class are immutable.</p> 4221 * 4222 * <p>Much credit is due to William Rucklidge since portions of this code are an indirect 4223 * port of his C++ Reed-Solomon implementation.</p> 4224 * 4225 * @author Sean Owen 4226 */ 4227 class GenericGFPoly { 4228 /** 4229 * @param field the {@link GenericGF} instance representing the field to use 4230 * to perform computations 4231 * @param coefficients coefficients as ints representing elements of GF(size), arranged 4232 * from most significant (highest-power term) coefficient to least significant 4233 * @throws IllegalArgumentException if argument is null or empty, 4234 * or if leading coefficient is 0 and this is not a 4235 * constant polynomial (that is, it is not the monomial "0") 4236 */ 4237 constructor(field, coefficients) { 4238 if (coefficients.length === 0) { 4239 throw new IllegalArgumentException(); 4240 } 4241 this.field = field; 4242 const coefficientsLength = coefficients.length; 4243 if (coefficientsLength > 1 && coefficients[0] === 0) { 4244 // Leading term must be non-zero for anything except the constant polynomial "0" 4245 let firstNonZero = 1; 4246 while (firstNonZero < coefficientsLength && coefficients[firstNonZero] === 0) { 4247 firstNonZero++; 4248 } 4249 if (firstNonZero === coefficientsLength) { 4250 this.coefficients = Int32Array.from([0]); 4251 } 4252 else { 4253 this.coefficients = new Int32Array(coefficientsLength - firstNonZero); 4254 System.arraycopy(coefficients, firstNonZero, this.coefficients, 0, this.coefficients.length); 4255 } 4256 } 4257 else { 4258 this.coefficients = coefficients; 4259 } 4260 } 4261 getCoefficients() { 4262 return this.coefficients; 4263 } 4264 /** 4265 * @return degree of this polynomial 4266 */ 4267 getDegree() { 4268 return this.coefficients.length - 1; 4269 } 4270 /** 4271 * @return true iff this polynomial is the monomial "0" 4272 */ 4273 isZero() { 4274 return this.coefficients[0] === 0; 4275 } 4276 /** 4277 * @return coefficient of x^degree term in this polynomial 4278 */ 4279 getCoefficient(degree /*int*/) { 4280 return this.coefficients[this.coefficients.length - 1 - degree]; 4281 } 4282 /** 4283 * @return evaluation of this polynomial at a given point 4284 */ 4285 evaluateAt(a /*int*/) { 4286 if (a === 0) { 4287 // Just return the x^0 coefficient 4288 return this.getCoefficient(0); 4289 } 4290 const coefficients = this.coefficients; 4291 let result; 4292 if (a === 1) { 4293 // Just the sum of the coefficients 4294 result = 0; 4295 for (let i = 0, length = coefficients.length; i !== length; i++) { 4296 const coefficient = coefficients[i]; 4297 result = AbstractGenericGF.addOrSubtract(result, coefficient); 4298 } 4299 return result; 4300 } 4301 result = coefficients[0]; 4302 const size = coefficients.length; 4303 const field = this.field; 4304 for (let i = 1; i < size; i++) { 4305 result = AbstractGenericGF.addOrSubtract(field.multiply(a, result), coefficients[i]); 4306 } 4307 return result; 4308 } 4309 addOrSubtract(other) { 4310 if (!this.field.equals(other.field)) { 4311 throw new IllegalArgumentException('GenericGFPolys do not have same GenericGF field'); 4312 } 4313 if (this.isZero()) { 4314 return other; 4315 } 4316 if (other.isZero()) { 4317 return this; 4318 } 4319 let smallerCoefficients = this.coefficients; 4320 let largerCoefficients = other.coefficients; 4321 if (smallerCoefficients.length > largerCoefficients.length) { 4322 const temp = smallerCoefficients; 4323 smallerCoefficients = largerCoefficients; 4324 largerCoefficients = temp; 4325 } 4326 let sumDiff = new Int32Array(largerCoefficients.length); 4327 const lengthDiff = largerCoefficients.length - smallerCoefficients.length; 4328 // Copy high-order terms only found in higher-degree polynomial's coefficients 4329 System.arraycopy(largerCoefficients, 0, sumDiff, 0, lengthDiff); 4330 for (let i = lengthDiff; i < largerCoefficients.length; i++) { 4331 sumDiff[i] = AbstractGenericGF.addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]); 4332 } 4333 return new GenericGFPoly(this.field, sumDiff); 4334 } 4335 multiply(other) { 4336 if (!this.field.equals(other.field)) { 4337 throw new IllegalArgumentException('GenericGFPolys do not have same GenericGF field'); 4338 } 4339 if (this.isZero() || other.isZero()) { 4340 return this.field.getZero(); 4341 } 4342 const aCoefficients = this.coefficients; 4343 const aLength = aCoefficients.length; 4344 const bCoefficients = other.coefficients; 4345 const bLength = bCoefficients.length; 4346 const product = new Int32Array(aLength + bLength - 1); 4347 const field = this.field; 4348 for (let i = 0; i < aLength; i++) { 4349 const aCoeff = aCoefficients[i]; 4350 for (let j = 0; j < bLength; j++) { 4351 product[i + j] = AbstractGenericGF.addOrSubtract(product[i + j], field.multiply(aCoeff, bCoefficients[j])); 4352 } 4353 } 4354 return new GenericGFPoly(field, product); 4355 } 4356 multiplyScalar(scalar /*int*/) { 4357 if (scalar === 0) { 4358 return this.field.getZero(); 4359 } 4360 if (scalar === 1) { 4361 return this; 4362 } 4363 const size = this.coefficients.length; 4364 const field = this.field; 4365 const product = new Int32Array(size); 4366 const coefficients = this.coefficients; 4367 for (let i = 0; i < size; i++) { 4368 product[i] = field.multiply(coefficients[i], scalar); 4369 } 4370 return new GenericGFPoly(field, product); 4371 } 4372 multiplyByMonomial(degree /*int*/, coefficient /*int*/) { 4373 if (degree < 0) { 4374 throw new IllegalArgumentException(); 4375 } 4376 if (coefficient === 0) { 4377 return this.field.getZero(); 4378 } 4379 const coefficients = this.coefficients; 4380 const size = coefficients.length; 4381 const product = new Int32Array(size + degree); 4382 const field = this.field; 4383 for (let i = 0; i < size; i++) { 4384 product[i] = field.multiply(coefficients[i], coefficient); 4385 } 4386 return new GenericGFPoly(field, product); 4387 } 4388 divide(other) { 4389 if (!this.field.equals(other.field)) { 4390 throw new IllegalArgumentException('GenericGFPolys do not have same GenericGF field'); 4391 } 4392 if (other.isZero()) { 4393 throw new IllegalArgumentException('Divide by 0'); 4394 } 4395 const field = this.field; 4396 let quotient = field.getZero(); 4397 let remainder = this; 4398 const denominatorLeadingTerm = other.getCoefficient(other.getDegree()); 4399 const inverseDenominatorLeadingTerm = field.inverse(denominatorLeadingTerm); 4400 while (remainder.getDegree() >= other.getDegree() && !remainder.isZero()) { 4401 const degreeDifference = remainder.getDegree() - other.getDegree(); 4402 const scale = field.multiply(remainder.getCoefficient(remainder.getDegree()), inverseDenominatorLeadingTerm); 4403 const term = other.multiplyByMonomial(degreeDifference, scale); 4404 const iterationQuotient = field.buildMonomial(degreeDifference, scale); 4405 quotient = quotient.addOrSubtract(iterationQuotient); 4406 remainder = remainder.addOrSubtract(term); 4407 } 4408 return [quotient, remainder]; 4409 } 4410 /*@Override*/ 4411 toString() { 4412 let result = ''; 4413 for (let degree = this.getDegree(); degree >= 0; degree--) { 4414 let coefficient = this.getCoefficient(degree); 4415 if (coefficient !== 0) { 4416 if (coefficient < 0) { 4417 result += ' - '; 4418 coefficient = -coefficient; 4419 } 4420 else { 4421 if (result.length > 0) { 4422 result += ' + '; 4423 } 4424 } 4425 if (degree === 0 || coefficient !== 1) { 4426 const alphaPower = this.field.log(coefficient); 4427 if (alphaPower === 0) { 4428 result += '1'; 4429 } 4430 else if (alphaPower === 1) { 4431 result += 'a'; 4432 } 4433 else { 4434 result += 'a^'; 4435 result += alphaPower; 4436 } 4437 } 4438 if (degree !== 0) { 4439 if (degree === 1) { 4440 result += 'x'; 4441 } 4442 else { 4443 result += 'x^'; 4444 result += degree; 4445 } 4446 } 4447 } 4448 } 4449 return result; 4450 } 4451 } 4452 4453 /** 4454 * Custom Error class of type Exception. 4455 */ 4456 class ArithmeticException extends Exception { 4457 } 4458 ArithmeticException.kind = 'ArithmeticException'; 4459 4460 /* 4461 * Copyright 2007 ZXing authors 4462 * 4463 * Licensed under the Apache License, Version 2.0 (the "License"); 4464 * you may not use this file except in compliance with the License. 4465 * You may obtain a copy of the License at 4466 * 4467 * http://www.apache.org/licenses/LICENSE-2.0 4468 * 4469 * Unless required by applicable law or agreed to in writing, software 4470 * distributed under the License is distributed on an "AS IS" BASIS, 4471 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 4472 * See the License for the specific language governing permissions and 4473 * limitations under the License. 4474 */ 4475 /*
4475* 4476 * <p>This class contains utility methods for performing mathematical operations over 4477 * the Galois Fields. Operations use a given primitive polynomial in calculations.</p> 4478 * 4479 * <p>Throughout this package, elements of the GF are represented as an {@code int} 4480 * for convenience and speed (but at the cost of memory). 4481 * </p> 4482 * 4483 * @author Sean Owen 4484 * @author David Olivier 4485 */ 4486 class GenericGF extends AbstractGenericGF { 4487 /** 4488 * Create a representation of GF(size) using the given primitive polynomial. 4489 * 4490 * @param primitive irreducible polynomial whose coefficients are represented by 4491 * the bits of an int, where the least-significant bit represents the constant 4492 * coefficient 4493 * @param size the size of the field 4494 * @param b the factor b in the generator polynomial can be 0- or 1-based 4495 * (g(x) = (x+a^b)(x+a^(b+1))...(x+a^(b+2t-1))). 4496 * In most cases it should be 1, but for QR code it is 0. 4497 */ 4498 constructor(primitive /*int*/, size /*int*/, generatorBase /*int*/) { 4499 super(); 4500 this.primitive = primitive; 4501 this.size = size; 4502 this.generatorBase = generatorBase; 4503 const expTable = new Int32Array(size); 4504 let x = 1; 4505 for (let i = 0; i < size; i++) { 4506 expTable[i] = x; 4507 x *= 2; // we're assuming the generator alpha is 2 4508 if (x >= size) { 4509 x ^= primitive; 4510 x &= size - 1; 4511 } 4512 } 4513 this.expTable = expTable; 4514 const logTable = new Int32Array(size); 4515 for (let i = 0; i < size - 1; i++) { 4516 logTable[expTable[i]] = i; 4517 } 4518 this.logTable = logTable; 4519 // logTable[0] == 0 but this should never be used 4520 this.zero = new GenericGFPoly(this, Int32Array.from([0])); 4521 this.one = new GenericGFPoly(this, Int32Array.from([1])); 4522 } 4523 getZero() { 4524 return this.zero; 4525 } 4526 getOne() { 4527 return this.one; 4528 } 4529 /** 4530 * @return the monomial representing coefficient * x^degree 4531 */ 4532 buildMonomial(degree /*int*/, coefficient /*int*/) { 4533 if (degree < 0) { 4534 throw new IllegalArgumentException(); 4535 } 4536 if (coefficient === 0) { 4537 return this.zero; 4538 } 4539 const coefficients = new Int32Array(degree + 1); 4540 coefficients[0] = coefficient; 4541 return new GenericGFPoly(this, coefficients); 4542 } 4543 /** 4544 * @return multiplicative inverse of a 4545 */ 4546 inverse(a /*int*/) { 4547 if (a === 0) { 4548 throw new ArithmeticException(); 4549 } 4550 return this.expTable[this.size - this.logTable[a] - 1]; 4551 } 4552 /** 4553 * @return product of a and b in GF(size) 4554 */ 4555 multiply(a /*int*/, b /*int*/) { 4556 if (a === 0 || b === 0) { 4557 return 0; 4558 } 4559 return this.expTable[(this.logTable[a] + this.logTable[b]) % (this.size - 1)]; 4560 } 4561 getSize() { 4562 return this.size; 4563 } 4564 getGeneratorBase() { 4565 return this.generatorBase; 4566 } 4567 /*@Override*/ 4568 toString() { 4569 return ('GF(0x' + Integer.toHexString(this.primitive) + ',' + this.size + ')'); 4570 } 4571 equals(o) { 4572 return o === this; 4573 } 4574 } 4575 GenericGF.AZTEC_DATA_12 = new GenericGF(0x1069, 4096, 1); // x^12 + x^6 + x^5 + x^3 + 1 4576 GenericGF.AZTEC_DATA_10 = new GenericGF(0x409, 1024, 1); // x^10 + x^3 + 1 4577 GenericGF.AZTEC_DATA_6 = new GenericGF(0x43, 64, 1); // x^6 + x + 1 4578 GenericGF.AZTEC_PARAM = new GenericGF(0x13, 16, 1); // x^4 + x + 1 4579 GenericGF.QR_CODE_FIELD_256 = new GenericGF(0x011d, 256, 0); // x^8 + x^4 + x^3 + x^2 + 1 4580 GenericGF.DATA_MATRIX_FIELD_256 = new GenericGF(0x012d, 256, 1); // x^8 + x^5 + x^3 + x^2 + 1 4581 GenericGF.AZTEC_DATA_8 = GenericGF.DATA_MATRIX_FIELD_256; 4582 GenericGF.MAXICODE_FIELD_64 = GenericGF.AZTEC_DATA_6; 4583 4584 /** 4585 * Custom Error class of type Exception. 4586 */
vendor: 22,439 bytes, lines 4587-5116
4587 class ReedSolomonException extends Exception { 4588 } 4589 ReedSolomonException.kind = 'ReedSolomonException'; 4590 4591 /** 4592 * Custom Error class of type Exception. 4593 */ 4594 class IllegalStateException extends Exception { 4595 } 4596 IllegalStateException.kind = 'IllegalStateException'; 4597 4598 /* 4599 * Copyright 2007 ZXing authors 4600 * 4601 * Licensed under the Apache License, Version 2.0 (the "License"); 4602 * you may not use this file except in compliance with the License. 4603 * You may obtain a copy of the License at 4604 * 4605 * http://www.apache.org/licenses/LICENSE-2.0 4606 * 4607 * Unless required by applicable law or agreed to in writing, software 4608 * distributed under the License is distributed on an "AS IS" BASIS, 4609 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 4610 * See the License for the specific language governing permissions and 4611 * limitations under the License. 4612 */ 4613 /** 4614 * <p>Implements Reed-Solomon decoding, as the name implies.</p> 4615 * 4616 * <p>The algorithm will not be explained here, but the following references were helpful 4617 * in creating this implementation:</p> 4618 * 4619 * <ul> 4620 * <li>Bruce Maggs. 4621 * <a href="http://www.cs.cmu.edu/afs/cs.cmu.edu/project/pscico-guyb/realworld/www/rs_decode.ps"> 4622 * "Decoding Reed-Solomon Codes"</a> (see discussion of Forney's Formula)</li> 4623 * <li>J.I. Hall. <a href="www.mth.msu.edu/~jhall/classes/codenotes/GRS.pdf"> 4624 * "Chapter 5. Generalized Reed-Solomon Codes"</a> 4625 * (see discussion of Euclidean algorithm)</li> 4626 * </ul> 4627 * 4628 * <p>Much credit is due to William Rucklidge since portions of this code are an indirect 4629 * port of his C++ Reed-Solomon implementation.</p> 4630 * 4631 * @author Sean Owen 4632 * @author William Rucklidge 4633 * @author sanfordsquires 4634 */ 4635 class ReedSolomonDecoder { 4636 constructor(field) { 4637 this.field = field; 4638 } 4639 /** 4640 * <p>Decodes given set of received codewords, which include both data and error-correction 4641 * codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place, 4642 * in the input.</p> 4643 * 4644 * @param received data and error-correction codewords 4645 * @param twoS number of error-correction codewords available 4646 * @throws ReedSolomonException if decoding fails for any reason 4647 */ 4648 decode(received, twoS /*int*/) { 4649 const field = this.field; 4650 const poly = new GenericGFPoly(field, received); 4651 const syndromeCoefficients = new Int32Array(twoS); 4652 let noError = true; 4653 for (let i = 0; i < twoS; i++) { 4654 const evalResult = poly.evaluateAt(field.exp(i + field.getGeneratorBase())); 4655 syndromeCoefficients[syndromeCoefficients.length - 1 - i] = evalResult; 4656 if (evalResult !== 0) { 4657 noError = false; 4658 } 4659 } 4660 if (noError) { 4661 return; 4662 } 4663 const syndrome = new GenericGFPoly(field, syndromeCoefficients); 4664 const sigmaOmega = this.runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS); 4665 const sigma = sigmaOmega[0]; 4666 const omega = sigmaOmega[1]; 4667 const errorLocations = this.findErrorLocations(sigma); 4668 const errorMagnitudes = this.findErrorMagnitudes(omega, errorLocations); 4669 for (let i = 0; i < errorLocations.length; i++) { 4670 const position = received.length - 1 - field.log(errorLocations[i]); 4671 if (position < 0) { 4672 throw new ReedSolomonException('Bad error location'); 4673 } 4674 received[position] = GenericGF.addOrSubtract(received[position], errorMagnitudes[i]); 4675 } 4676 } 4677 runEuclideanAlgorithm(a, b, R /*int*/) { 4678 // Assume a's degree is >= b's 4679 if (a.getDegree() < b.getDegree()) { 4680 const temp = a; 4681 a = b; 4682 b = temp; 4683 } 4684 const field = this.field; 4685 let rLast = a; 4686 let r = b; 4687 let tLast = field.getZero(); 4688 let t = field.getOne(); 4689 // Run Euclidean algorithm until r's degree is less than R/2 4690 while (r.getDegree() >= (R / 2 | 0)) { 4691 let rLastLast = rLast; 4692 let tLastLast = tLast; 4693 rLast = r; 4694 tLast = t; 4695 // Divide rLastLast by rLast, with quotient in q and remainder in r 4696 if (rLast.isZero()) { 4697 // Oops, Euclidean algorithm already terminated? 4698 throw new ReedSolomonException('r_{i-1} was zero'); 4699 } 4700 r = rLastLast; 4701 let q = field.getZero(); 4702 const denominatorLeadingTerm = rLast.getCoefficient(rLast.getDegree()); 4703 const dltInverse = field.inverse(denominatorLeadingTerm); 4704 while (r.getDegree() >= rLast.getDegree() && !r.isZero()) { 4705 const degreeDiff = r.getDegree() - rLast.getDegree(); 4706 const scale = field.multiply(r.getCoefficient(r.getDegree()), dltInverse); 4707 q = q.addOrSubtract(field.buildMonomial(degreeDiff, scale)); 4708 r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale)); 4709 } 4710 t = q.multiply(tLast).addOrSubtract(tLastLast); 4711 if (r.getDegree() >= rLast.getDegree()) { 4712 throw new IllegalStateException('Division algorithm failed to reduce polynomial?'); 4713 } 4714 } 4715 const sigmaTildeAtZero = t.getCoefficient(0); 4716 if (sigmaTildeAtZero === 0) { 4717 throw new ReedSolomonException('sigmaTilde(0) was zero'); 4718 } 4719 const inverse = field.inverse(sigmaTildeAtZero); 4720 const sigma = t.multiplyScalar(inverse); 4721 const omega = r.multiplyScalar(inverse); 4722 return [sigma, omega]; 4723 } 4724 findErrorLocations(errorLocator) { 4725 // This is a direct application of Chien's search 4726 const numErrors = errorLocator.getDegree(); 4727 if (numErrors === 1) { // shortcut 4728 return Int32Array.from([errorLocator.getCoefficient(1)]); 4729 } 4730 const result = new Int32Array(numErrors); 4731 let e = 0; 4732 const field = this.field; 4733 for (let i = 1; i < field.getSize() && e < numErrors; i++) { 4734 if (errorLocator.evaluateAt(i) === 0) { 4735 result[e] = field.inverse(i); 4736 e++; 4737 } 4738 } 4739 if (e !== numErrors) { 4740 throw new ReedSolomonException('Error locator degree does not match number of roots'); 4741 } 4742 return result; 4743 } 4744 findErrorMagnitudes(errorEvaluator, errorLocations) { 4745 // This is directly applying Forney's Formula 4746 const s = errorLocations.length; 4747 const result = new Int32Array(s); 4748 const field = this.field; 4749 for (let i = 0; i < s; i++) { 4750 const xiInverse = field.inverse(errorLocations[i]); 4751 let denominator = 1; 4752 for (let j = 0; j < s; j++) { 4753 if (i !== j) { 4754 // denominator = field.multiply(denominator, 4755 // GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse))) 4756 // Above should work but fails on some Apple and Linux JDKs due to a Hotspot bug. 4757 // Below is a funny-looking workaround from Steven Parkes 4758 const term = field.multiply(errorLocations[j], xiInverse); 4759 const termPlus1 = (term & 0x1) === 0 ? term | 1 : term & ~1; 4760 denominator = field.multiply(denominator, termPlus1); 4761 } 4762 } 4763 result[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse), field.inverse(denominator)); 4764 if (field.getGeneratorBase() !== 0) { 4765 result[i] = field.multiply(result[i], xiInverse); 4766 } 4767 } 4768 return result; 4769 } 4770 } 4771 4772 /* 4773 * Copyright 2010 ZXing authors 4774 * 4775 * Licensed under the Apache License, Version 2.0 (the "License"); 4776 * you may not use this file except in compliance with the License. 4777 * You may obtain a copy of the License at 4778 * 4779 * http://www.apache.org/licenses/LICENSE-2.0 4780 * 4781 * Unless required by applicable law or agreed to in writing, software 4782 * distributed under the License is distributed on an "AS IS" BASIS, 4783 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 4784 * See the License for the specific language governing permissions and 4785 * limitations under the License. 4786 */ 4787 // import java.util.Arrays; 4788 var Table; 4789 (function (Table) { 4790 Table[Table["UPPER"] = 0] = "UPPER"; 4791 Table[Table["LOWER"] = 1] = "LOWER"; 4792 Table[Table["MIXED"] = 2] = "MIXED"; 4793 Table[Table["DIGIT"] = 3] = "DIGIT"; 4794 Table[Table["PUNCT"] = 4] = "PUNCT"; 4795 Table[Table["BINARY"] = 5] = "BINARY"; 4796 })(Table || (Table = {})); 4797 /** 4798 * <p>The main class which implements Aztec Code decoding -- as opposed to locating and extracting 4799 * the Aztec Code from an image.</p> 4800 * 4801 * @author David Olivier 4802 */ 4803 class Decoder$2 { 4804 decode(detectorResult) { 4805 this.ddata = detectorResult; 4806 let matrix = detectorResult.getBits(); 4807 let rawbits = this.extractBits(matrix); 4808 let correctedBits = this.correctBits(rawbits); 4809 let rawBytes = Decoder$2.convertBoolArrayToByteArray(correctedBits); 4810 let result = Decoder$2.getEncodedData(correctedBits); 4811 let decoderResult = new DecoderResult(rawBytes, result, null, null); 4812 decoderResult.setNumBits(correctedBits.length); 4813 return decoderResult; 4814 } 4815 // This method is used for testing the high-level encoder 4816 static highLevelDecode(correctedBits) { 4817 return this.getEncodedData(correctedBits); 4818 } 4819 /** 4820 * Gets the string encoded in the aztec code bits 4821 * 4822 * @return the decoded string 4823 */ 4824 static getEncodedData(correctedBits) { 4825 let endIndex = correctedBits.length; 4826 let latchTable = Table.UPPER; // table most recently latched to 4827 let shiftTable = Table.UPPER; // table to use for the next read 4828 let result = ''; 4829 let index = 0; 4830 while (index < endIndex) { 4831 if (shiftTable === Table.BINARY) { 4832 if (endIndex - index < 5) { 4833 break; 4834 } 4835 let length = Decoder$2.readCode(correctedBits, index, 5); 4836 index += 5; 4837 if (length === 0) { 4838 if (endIndex - index < 11) { 4839 break; 4840 } 4841 length = Decoder$2.readCode(correctedBits, index, 11) + 31; 4842 index += 11; 4843 } 4844 for (let charCount = 0; charCount < length; charCount++) { 4845 if (endIndex - index < 8) { 4846 index = endIndex; // Force outer loop to exit 4847 break; 4848 } 4849 const code = Decoder$2.readCode(correctedBits, index, 8); 4850 result += /*(char)*/ StringUtils.castAsNonUtf8Char(code); 4851 index += 8; 4852 } 4853 // Go back to whatever mode we had been in 4854 shiftTable = latchTable; 4855 } 4856 else { 4857 let size = shiftTable === Table.DIGIT ? 4 : 5; 4858 if (endIndex - index < size) { 4859 break; 4860 } 4861 let code = Decoder$2.readCode(correctedBits, index, size); 4862 index += size; 4863 let str = Decoder$2.getCharacter(shiftTable, code); 4864 if (str.startsWith('CTRL_')) { 4865 // Table changes 4866 // ISO/IEC 24778:2008 prescribes ending a shift sequence in the mode from which it was invoked. 4867 // That's including when that mode is a shift. 4868 // Our test case dlusbs.png for issue #642 exercises that. 4869 latchTable = shiftTable; // Latch the current mode, so as to return to Upper after U/S B/S 4870 shiftTable = Decoder$2.getTable(str.charAt(5)); 4871 if (str.charAt(6) === 'L') { 4872 latchTable = shiftTable; 4873 } 4874 } 4875 else { 4876 result += str; 4877 // Go back to whatever mode we had been in 4878 shiftTable = latchTable; 4879 } 4880 } 4881 } 4882 return result; 4883 } 4884 /** 4885 * gets the table corresponding to the char passed 4886 */ 4887 static getTable(t) { 4888 switch (t) { 4889 case 'L': 4890 return Table.LOWER; 4891 case 'P': 4892 return Table.PUNCT; 4893 case 'M': 4894 return Table.MIXED; 4895 case 'D': 4896 return Table.DIGIT; 4897 case 'B': 4898 return Table.BINARY; 4899 case 'U': 4900 default: 4901 return Table.UPPER; 4902 } 4903 } 4904 /** 4905 * Gets the character (or string) corresponding to the passed code in the given table 4906 * 4907 * @param table the table used 4908 * @param code the code of the character 4909 */ 4910 static getCharacter(table, code) { 4911 switch (table) { 4912 case Table.UPPER: 4913 return Decoder$2.UPPER_TABLE[code]; 4914 case Table.LOWER: 4915 return Decoder$2.LOWER_TABLE[code]; 4916 case Table.MIXED: 4917 return Decoder$2.MIXED_TABLE[code]; 4918 case Table.PUNCT: 4919 return Decoder$2.PUNCT_TABLE[code]; 4920 case Table.DIGIT: 4921 return Decoder$2.DIGIT_TABLE[code]; 4922 default: 4923 // Should not reach here. 4924 throw new IllegalStateException('Bad table'); 4925 } 4926 } 4927 /** 4928 * <p>Performs RS error correction on an array of bits.</p> 4929 * 4930 * @return the corrected array 4931 * @throws FormatException if the input contains too many errors 4932 */ 4933 correctBits(rawbits) { 4934 let gf; 4935 let codewordSize; 4936 if (this.ddata.getNbLayers() <= 2) { 4937 codewordSize = 6; 4938 gf = GenericGF.AZTEC_DATA_6; 4939 } 4940 else if (this.ddata.getNbLayers() <= 8) { 4941 codewordSize = 8; 4942 gf = GenericGF.AZTEC_DATA_8; 4943 } 4944 else if (this.ddata.getNbLayers() <= 22) { 4945 codewordSize = 10; 4946 gf = GenericGF.AZTEC_DATA_10; 4947 } 4948 else { 4949 codewordSize = 12; 4950 gf = GenericGF.AZTEC_DATA_12; 4951 } 4952 let numDataCodewords = this.ddata.getNbDatablocks(); 4953 let numCodewords = rawbits.length / codewordSize; 4954 if (numCodewords < numDataCodewords) { 4955 throw new FormatException(); 4956 } 4957 let offset = rawbits.length % codewordSize; 4958 let dataWords = new Int32Array(numCodewords); 4959 for (let i = 0; i < numCodewords; i++, offset += codewordSize) { 4960 dataWords[i] = Decoder$2.readCode(rawbits, offset, codewordSize); 4961 } 4962 try { 4963 let rsDecoder = new ReedSolomonDecoder(gf); 4964 rsDecoder.decode(dataWords, numCodewords - numDataCodewords); 4965 } 4966 catch (ex) { 4967 throw new FormatException(ex); 4968 } 4969 // Now perform the unstuffing operation. 4970 // First, count how many bits are going to be thrown out as stuffing 4971 let mask = (1 << codewordSize) - 1; 4972 let stuffedBits = 0; 4973 for (let i = 0; i < numDataCodewords; i++) { 4974 let dataWord = dataWords[i]; 4975 if (dataWord === 0 || dataWord === mask) { 4976 throw new FormatException(); 4977 } 4978 else if (dataWord === 1 || dataWord === mask - 1) { 4979 stuffedBits++; 4980 } 4981 } 4982 // Now, actually unpack the bits and remove the stuffing 4983 let correctedBits = new Array(numDataCodewords * codewordSize - stuffedBits); 4984 let index = 0; 4985 for (let i = 0; i < numDataCodewords; i++) { 4986 let dataWord = dataWords[i]; 4987 if (dataWord === 1 || dataWord === mask - 1) { 4988 // next codewordSize-1 bits are all zeros or all ones 4989 correctedBits.fill(dataWord > 1, index, index + codewordSize - 1); 4990 // Arrays.fill(correctedBits, index, index + codewordSize - 1, dataWord > 1); 4991 index += codewordSize - 1; 4992 } 4993 else { 4994 for (let bit = codewordSize - 1; bit >= 0; --bit) { 4995 correctedBits[index++] = (dataWord & (1 << bit)) !== 0; 4996 } 4997 } 4998 } 4999 return correctedBits; 5000 } 5001 /** 5002 * Gets the array of bits from an Aztec Code matrix 5003 * 5004 * @return the array of bits 5005 */ 5006 extractBits(matrix) { 5007 let compact = this.ddata.isCompact(); 5008 let layers = this.ddata.getNbLayers(); 5009 let baseMatrixSize = (compact ? 11 : 14) + layers * 4; // not including alignment lines 5010 let alignmentMap = new Int32Array(baseMatrixSize); 5011 let rawbits = new Array(this.totalBitsInLayer(layers, compact)); 5012 if (compact) { 5013 for (let i = 0; i < alignmentMap.length; i++) { 5014 alignmentMap[i] = i; 5015 } 5016 } 5017 else { 5018 let matrixSize = baseMatrixSize + 1 + 2 * Integer.truncDivision((Integer.truncDivision(baseMatrixSize, 2) - 1), 15); 5019 let origCenter = baseMatrixSize / 2; 5020 let center = Integer.truncDivision(matrixSize, 2); 5021 for (let i = 0; i < origCenter; i++) { 5022 let newOffset = i + Integer.truncDivision(i, 15); 5023 alignmentMap[origCenter - i - 1] = center - newOffset - 1; 5024 alignmentMap[origCenter + i] = center + newOffset + 1; 5025 } 5026 } 5027 for (let i = 0, rowOffset = 0; i < layers; i++) { 5028 let rowSize = (layers - i) * 4 + (compact ? 9 : 12); 5029 // The top-left most point of this layer is <low, low> (not including alignment lines) 5030 let low = i * 2; 5031 // The bottom-right most point of this layer is <high, high> (not including alignment lines) 5032 let high = baseMatrixSize - 1 - low; 5033 // We pull bits from the two 2 x rowSize columns and two rowSize x 2 rows 5034 for (let j = 0; j < rowSize; j++) { 5035 let columnOffset = j * 2; 5036 for (let k = 0; k < 2; k++) { 5037 // left column 5038 rawbits[rowOffset + columnOffset + k] = 5039 matrix.get(alignmentMap[low + k], alignmentMap[low + j]); 5040 // bottom row 5041 rawbits[rowOffset + 2 * rowSize + columnOffset + k] = 5042 matrix.get(alignmentMap[low + j], alignmentMap[high - k]); 5043 // right column 5044 rawbits[rowOffset + 4 * rowSize + columnOffset + k] = 5045 matrix.get(alignmentMap[high - k], alignmentMap[high - j]); 5046 // top row 5047 rawbits[rowOffset + 6 * rowSize + columnOffset + k] = 5048 matrix.get(alignmentMap[high - j], alignmentMap[low + k]); 5049 } 5050 } 5051 rowOffset += rowSize * 8; 5052 } 5053 return rawbits; 5054 } 5055 /** 5056 * Reads a code of given length and at given index in an array of bits 5057 */ 5058 static readCode(rawbits, startIndex, length) { 5059 let res = 0; 5060 for (let i = startIndex; i < startIndex + length; i++) { 5061 res <<= 1; 5062 if (rawbits[i]) { 5063 res |= 0x01; 5064 } 5065 } 5066 return res; 5067 } 5068 /** 5069 * Reads a code of length 8 in an array of bits, padding with zeros 5070 */ 5071 static readByte(rawbits, startIndex) { 5072 let n = rawbits.length - startIndex; 5073 if (n >= 8) { 5074 return Decoder$2.readCode(rawbits, startIndex, 8); 5075 } 5076 return Decoder$2.readCode(rawbits, startIndex, n) << (8 - n); 5077 } 5078 /** 5079 * Packs a bit array into bytes, most significant bit first 5080 */ 5081 static convertBoolArrayToByteArray(boolArr) { 5082 let byteArr = new Uint8Array((boolArr.length + 7) / 8); 5083 for (let i = 0; i < byteArr.length; i++) { 5084 byteArr[i] = Decoder$2.readByte(boolArr, 8 * i); 5085 } 5086 return byteArr; 5087 } 5088 totalBitsInLayer(layers, compact) { 5089 return ((compact ? 88 : 112) + 16 * layers) * layers; 5090 } 5091 } 5092 Decoder$2.UPPER_TABLE = [ 5093 'CTRL_PS', ' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 5094 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'CTRL_LL', 'CTRL_ML', 'CTRL_DL', 'CTRL_BS' 5095 ]; 5096 Decoder$2.LOWER_TABLE = [ 5097 'CTRL_PS', ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 5098 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'CTRL_US', 'CTRL_ML', 'CTRL_DL', 'CTRL_BS' 5099 ]; 5100 Decoder$2.MIXED_TABLE = [ 5101 'CTRL_PS', ' ', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\b', '\t', '\n', 5102 '\x0b', '\f', '\r', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', '@', '\\', '^', '_', 5103 '`', '|', '~', '\x7f', 'CTRL_LL', 'CTRL_UL', 'CTRL_PL', 'CTRL_BS' 5104 ]; 5105 Decoder$2.PUNCT_TABLE = [ 5106 '', '\r', '\r\n', '. ', ', ', ': ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', 5107 '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', ']', '{', '}', 'CTRL_UL' 5108 ]; 5109 Decoder$2.DIGIT_TABLE = [ 5110 'CTRL_PS', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ',', '.', 'CTRL_UL', 'CTRL_US' 5111 ]; 5112 5113 /* 5114 * Copyright 2012 ZXing authors 5115 * 5116 * Licensed under the Apache License, Version 2.0 (the "License");
5117 * you may not use this file except in compliance with the License. 5118 * You may obtain a copy of the License at 5119 * 5120 * http://www.apache.org/licenses/LICENSE-2.0 5121 * 5122 * Unless required by applicable law or agreed to in writing, software 5123 * distributed under the License is distributed on an "AS IS" BASIS, 5124 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5125 * See the License for the specific language governing permissions and 5126 * limitations under the License. 5127 */ 5128 /*namespace com.google.zxing.common.detector {*/ 5129 /** 5130 * General math-related and numeric utility functions. 5131 */ 5132 class MathUtils { 5133 constructor() { } 5134 /** 5135 * Ends up being a bit faster than {@link Math#round(float)}. This merely rounds its 5136 * argument to the nearest int, where x.5 rounds up to x+1. Semantics of this shortcut 5137 * differ slightly from {@link Math#round(float)} in that half rounds down for negative 5138 * values. -2.5 rounds to -3, not -2. For purposes here it makes no difference. 5139 * 5140 * @param d real value to round 5141 * @return nearest {@code int} 5142 */ 5143 static round(d /*float*/) { 5144 if (isNaN(d)) 5145 return 0; 5146 if (d <= Number.MIN_SAFE_INTEGER) 5147 return Number.MIN_SAFE_INTEGER; 5148 if (d >= Number.MAX_SAFE_INTEGER) 5149 return Number.MAX_SAFE_INTEGER; 5150 return /*(int) */ (d + (d < 0.0 ? -0.5 : 0.5)) | 0; 5151 } 5152 // TYPESCRIPTPORT: maybe remove round method and call directly Math.round, it looks like it doesn't make sense for js 5153 /** 5154 * @param aX point A x coordinate 5155 * @param aY point A y coordinate 5156 * @param bX point B x coordinate 5157 * @param bY point B y coordinate 5158 * @return Euclidean distance between points A and B 5159 */ 5160 static distance(aX /*float|int*/, aY /*float|int*/, bX /*float|int*/, bY /*float|int*/) { 5161 const xDiff = aX - bX; 5162 const yDiff = aY - bY; 5163 return /*(float) */ Math.sqrt(xDiff * xDiff + yDiff * yDiff); 5164 } 5165 /** 5166 * @param aX point A x coordinate 5167 * @param aY point A y coordinate 5168 * @param bX point B x coordinate 5169 * @param bY point B y coordinate 5170 * @return Euclidean distance between points A and B 5171 */ 5172 // public static distance(aX: number /*int*/, aY: number /*int*/, bX: number /*int*/, bY: number /*int*/): float { 5173 // const xDiff = aX - bX 5174 // const yDiff = aY - bY 5175 // return (float) Math.sqrt(xDiff * xDiff + yDiff * yDiff); 5176 // } 5177 /** 5178 * @param array values to sum 5179 * @return sum of values in array 5180 */ 5181 static sum(array) { 5182 let count = 0; 5183 for (let i = 0, length = array.length; i !== length; i++) { 5184 const a = array[i]; 5185 count += a; 5186 } 5187 return count; 5188 } 5189 } 5190 5191 /** 5192 * Ponyfill for Java's Float class. 5193 */ 5194 class Float { 5195 /** 5196 * SincTS has no difference between int and float, there's all numbers, 5197 * this is used only to polyfill Java code. 5198 */ 5199 static floatToIntBits(f) { 5200 return f; 5201 } 5202 } 5203 /** 5204 * The float max value in JS is the number max value. 5205 */ 5206 Float.MAX_VALUE = Number.MAX_SAFE_INTEGER; 5207 5208 /* 5209 * Copyright 2007 ZXing authors 5210 * 5211 * Licensed under the Apache License, Version 2.0 (the "License"); 5212 * you may not use this file except in compliance with the License. 5213 * You may obtain a copy of the License at 5214 * 5215 * http://www.apache.org/licenses/LICENSE-2.0 5216 * 5217 * Unless required by applicable law or agreed to in writing, software 5218 * distributed under the License is distributed on an "AS IS" BASIS, 5219 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5220 * See the License for the specific language governing permissions and 5221 * limitations under the License. 5222
vendor: 6,514 bytes, lines 5222-5406
5222*/ 5223 /** 5224 * <p>Encapsulates a point of interest in an image containing a barcode. Typically, this 5225 * would be the location of a finder pattern or the corner of the barcode, for example.</p> 5226 * 5227 * @author Sean Owen 5228 */ 5229 class ResultPoint { 5230 constructor(x, y) { 5231 this.x = x; 5232 this.y = y; 5233 } 5234 getX() { 5235 return this.x; 5236 } 5237 getY() { 5238 return this.y; 5239 } 5240 /*@Override*/ 5241 equals(other) { 5242 if (other instanceof ResultPoint) { 5243 const otherPoint = other; 5244 return this.x === otherPoint.x && this.y === otherPoint.y; 5245 } 5246 return false; 5247 } 5248 /*@Override*/ 5249 hashCode() { 5250 return 31 * Float.floatToIntBits(this.x) + Float.floatToIntBits(this.y); 5251 } 5252 /*@Override*/ 5253 toString() { 5254 return '(' + this.x + ',' + this.y + ')'; 5255 } 5256 /** 5257 * Orders an array of three ResultPoints in an order [A,B,C] such that AB is less than AC 5258 * and BC is less than AC, and the angle between BC and BA is less than 180 degrees. 5259 * 5260 * @param patterns array of three {@code ResultPoint} to order 5261 */ 5262 static orderBestPatterns(patterns) { 5263 // Find distances between pattern centers 5264 const zeroOneDistance = this.distance(patterns[0], patterns[1]); 5265 const oneTwoDistance = this.distance(patterns[1], patterns[2]); 5266 const zeroTwoDistance = this.distance(patterns[0], patterns[2]); 5267 let pointA; 5268 let pointB; 5269 let pointC; 5270 // Assume one closest to other two is B; A and C will just be guesses at first 5271 if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance) { 5272 pointB = patterns[0]; 5273 pointA = patterns[1]; 5274 pointC = patterns[2]; 5275 } 5276 else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance) { 5277 pointB = patterns[1]; 5278 pointA = patterns[0]; 5279 pointC = patterns[2]; 5280 } 5281 else { 5282 pointB = patterns[2]; 5283 pointA = patterns[0]; 5284 pointC = patterns[1]; 5285 } 5286 // Use cross product to figure out whether A and C are correct or flipped. 5287 // This asks whether BC x BA has a positive z component, which is the arrangement 5288 // we want for A, B, C. If it's negative, then we've got it flipped around and 5289 // should swap A and C. 5290 if (this.crossProductZ(pointA, pointB, pointC) < 0.0) { 5291 const temp = pointA; 5292 pointA = pointC; 5293 pointC = temp; 5294 } 5295 patterns[0] = pointA; 5296 patterns[1] = pointB; 5297 patterns[2] = pointC; 5298 } 5299 /** 5300 * @param pattern1 first pattern 5301 * @param pattern2 second pattern 5302 * @return distance between two points 5303 */ 5304 static distance(pattern1, pattern2) { 5305 return MathUtils.distance(pattern1.x, pattern1.y, pattern2.x, pattern2.y); 5306 } 5307 /** 5308 * Returns the z component of the cross product between vectors BC and BA. 5309 */ 5310 static crossProductZ(pointA, pointB, pointC) { 5311 const bX = pointB.x; 5312 const bY = pointB.y; 5313 return ((pointC.x - bX) * (pointA.y - bY)) - ((pointC.y - bY) * (pointA.x - bX)); 5314 } 5315 } 5316 5317 /* 5318 * Copyright 2007 ZXing authors 5319 * 5320 * Licensed under the Apache License, Version 2.0 (the "License"); 5321 * you may not use this file except in compliance with the License. 5322 * You may obtain a copy of the License at 5323 * 5324 * http://www.apache.org/licenses/LICENSE-2.0 5325 * 5326 * Unless required by applicable law or agreed to in writing, software 5327 * distributed under the License is distributed on an "AS IS" BASIS, 5328 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5329 * See the License for the specific language governing permissions and 5330 * limitations under the License. 5331 */ 5332 /** 5333 * <p>Encapsulates the result of detecting a barcode in an image. This includes the raw 5334 * matrix of black/white pixels corresponding to the barcode, and possibly points of interest 5335 * in the image, like the location of finder patterns or corners of the barcode in the image.</p> 5336 * 5337 * @author Sean Owen 5338 */ 5339 class DetectorResult { 5340 constructor(bits, points) { 5341 this.bits = bits; 5342 this.points = points; 5343 } 5344 getBits() { 5345 return this.bits; 5346 } 5347 getPoints() { 5348 return this.points; 5349 } 5350 } 5351 5352 /* 5353 * Copyright 2010 ZXing authors 5354 * 5355 * Licensed under the Apache License, Version 2.0 (the "License"); 5356 * you may not use this file except in compliance with the License. 5357 * You may obtain a copy of the License at 5358 * 5359 * http://www.apache.org/licenses/LICENSE-2.0 5360 * 5361 * Unless required by applicable law or agreed to in writing, software 5362 * distributed under the License is distributed on an "AS IS" BASIS, 5363 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5364 * See the License for the specific language governing permissions and 5365 * limitations under the License. 5366 */ 5367 /** 5368 * <p>Extends {@link DetectorResult} with more information specific to the Aztec format, 5369 * like the number of layers and whether it's compact.</p> 5370 * 5371 * @author Sean Owen 5372 */ 5373 class AztecDetectorResult extends DetectorResult { 5374 constructor(bits, points, compact, nbDatablocks, nbLayers) { 5375 super(bits, points); 5376 this.compact = compact; 5377 this.nbDatablocks = nbDatablocks; 5378 this.nbLayers = nbLayers; 5379 } 5380 getNbLayers() { 5381 return this.nbLayers; 5382 } 5383 getNbDatablocks() { 5384 return this.nbDatablocks; 5385 } 5386 isCompact() { 5387 return this.compact; 5388 } 5389 } 5390 5391 /* 5392 * Copyright 2010 ZXing authors 5393 * 5394 * Licensed under the Apache License, Version 2.0 (the "License"); 5395 * you may not use this file except in compliance with the License. 5396 * You may obtain a copy of the License at 5397 * 5398 * http://www.apache.org/licenses/LICENSE-2.0 5399 * 5400 * Unless required by applicable law or agreed to in writing, software 5401 * distributed under the License is distributed on an "AS IS" BASIS, 5402 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5403 * See the License for the specific language governing permissions and 5404 * limitations under the License. 5405 */ 5406 /*
5406* 5407 * <p> 5408 * Detects a candidate barcode-like rectangular region within an image. It 5409 * starts around the center of the image, increases the size of the candidate 5410 * region until it finds a white rectangular region. By keeping track of the 5411 * last black points it encountered, it determines the corners of the barcode. 5412 * </p> 5413 * 5414 * @author David Olivier 5415 */ 5416 class WhiteRectangleDetector { 5417 // public constructor(private image: BitMatrix) /*throws NotFoundException*/ { 5418 // this(image, INIT_SIZE, image.getWidth() / 2, image.getHeight() / 2) 5419 // } 5420 /** 5421 * @param image barcode image to find a rectangle in 5422 * @param initSize initial size of search area around center 5423 * @param x x position of search center 5424 * @param y y position of search center 5425 * @throws NotFoundException if image is too small to accommodate {@code initSize} 5426 */ 5427 constructor(image, initSize /*int*/, x /*int*/, y /*int*/) { 5428 this.image = image; 5429 this.height = image.getHeight(); 5430 this.width = image.getWidth(); 5431 if (undefined === initSize || null === initSize) { 5432 initSize = WhiteRectangleDetector.INIT_SIZE; 5433 } 5434 if (undefined === x || null === x) { 5435 x = image.getWidth() / 2 | 0; 5436 } 5437 if (undefined === y || null === y) { 5438 y = image.getHeight() / 2 | 0; 5439 } 5440 const halfsize = initSize / 2 | 0; 5441 this.leftInit = x - halfsize; 5442 this.rightInit = x + halfsize; 5443 this.upInit = y - halfsize; 5444 this.downInit = y + halfsize; 5445 if (this.upInit < 0 || this.leftInit < 0 || this.downInit >= this.height || this.rightInit >= this.width) { 5446 throw new NotFoundException(); 5447 } 5448 } 5449 /** 5450 * <p> 5451 * Detects a candidate barcode-like rectangular region within an image. It 5452 * starts around the center of the image, increases the size of the candidate 5453 * region until it finds a white rectangular region. 5454 * </p> 5455 * 5456 * @return {@link ResultPoint}[] describing the corners of the rectangular 5457 * region. The first and last points are opposed on the diagonal, as 5458 * are the second and third. The first point will be the topmost 5459 * point and the last, the bottommost. The second point will be 5460 * leftmost and the third, the rightmost 5461 * @throws NotFoundException if no Data Matrix Code can be found 5462 */ 5463 detect() { 5464 let left = this.leftInit; 5465 let right = this.rightInit; 5466 let up = this.upInit; 5467 let down = this.downInit; 5468 let sizeExceeded = false;
vendor: 8,399 bytes, lines 5469-5683
5469 let aBlackPointFoundOnBorder = true; 5470 let atLeastOneBlackPointFoundOnBorder = false; 5471 let atLeastOneBlackPointFoundOnRight = false; 5472 let atLeastOneBlackPointFoundOnBottom = false; 5473 let atLeastOneBlackPointFoundOnLeft = false; 5474 let atLeastOneBlackPointFoundOnTop = false; 5475 const width = this.width; 5476 const height = this.height; 5477 while (aBlackPointFoundOnBorder) { 5478 aBlackPointFoundOnBorder = false; 5479 // ..... 5480 // . | 5481 // ..... 5482 let rightBorderNotWhite = true; 5483 while ((rightBorderNotWhite || !atLeastOneBlackPointFoundOnRight) && right < width) { 5484 rightBorderNotWhite = this.containsBlackPoint(up, down, right, false); 5485 if (rightBorderNotWhite) { 5486 right++; 5487 aBlackPointFoundOnBorder = true; 5488 atLeastOneBlackPointFoundOnRight = true; 5489 } 5490 else if (!atLeastOneBlackPointFoundOnRight) { 5491 right++; 5492 } 5493 } 5494 if (right >= width) { 5495 sizeExceeded = true; 5496 break; 5497 } 5498 // ..... 5499 // . . 5500 // .___. 5501 let bottomBorderNotWhite = true; 5502 while ((bottomBorderNotWhite || !atLeastOneBlackPointFoundOnBottom) && down < height) { 5503 bottomBorderNotWhite = this.containsBlackPoint(left, right, down, true); 5504 if (bottomBorderNotWhite) { 5505 down++; 5506 aBlackPointFoundOnBorder = true; 5507 atLeastOneBlackPointFoundOnBottom = true; 5508 } 5509 else if (!atLeastOneBlackPointFoundOnBottom) { 5510 down++; 5511 } 5512 } 5513 if (down >= height) { 5514 sizeExceeded = true; 5515 break; 5516 } 5517 // ..... 5518 // | . 5519 // ..... 5520 let leftBorderNotWhite = true; 5521 while ((leftBorderNotWhite || !atLeastOneBlackPointFoundOnLeft) && left >= 0) { 5522 leftBorderNotWhite = this.containsBlackPoint(up, down, left, false); 5523 if (leftBorderNotWhite) { 5524 left--; 5525 aBlackPointFoundOnBorder = true; 5526 atLeastOneBlackPointFoundOnLeft = true; 5527 } 5528 else if (!atLeastOneBlackPointFoundOnLeft) { 5529 left--; 5530 } 5531 } 5532 if (left < 0) { 5533 sizeExceeded = true; 5534 break; 5535 } 5536 // .___. 5537 // . . 5538 // ..... 5539 let topBorderNotWhite = true; 5540 while ((topBorderNotWhite || !atLeastOneBlackPointFoundOnTop) && up >= 0) { 5541 topBorderNotWhite = this.containsBlackPoint(left, right, up, true); 5542 if (topBorderNotWhite) { 5543 up--; 5544 aBlackPointFoundOnBorder = true; 5545 atLeastOneBlackPointFoundOnTop = true; 5546 } 5547 else if (!atLeastOneBlackPointFoundOnTop) { 5548 up--; 5549 } 5550 } 5551 if (up < 0) { 5552 sizeExceeded = true; 5553 break; 5554 } 5555 if (aBlackPointFoundOnBorder) { 5556 atLeastOneBlackPointFoundOnBorder = true; 5557 } 5558 } 5559 if (!sizeExceeded && atLeastOneBlackPointFoundOnBorder) { 5560 const maxSize = right - left; 5561 let z = null; 5562 for (let i = 1; z === null && i < maxSize; i++) { 5563 z = this.getBlackPointOnSegment(left, down - i, left + i, down); 5564 } 5565 if (z == null) { 5566 throw new NotFoundException(); 5567 } 5568 let t = null; 5569 // go down right 5570 for (let i = 1; t === null && i < maxSize; i++) { 5571 t = this.getBlackPointOnSegment(left, up + i, left + i, up); 5572 } 5573 if (t == null) { 5574 throw new NotFoundException(); 5575 } 5576 let x = null; 5577 // go down left 5578 for (let i = 1; x === null && i < maxSize; i++) { 5579 x = this.getBlackPointOnSegment(right, up + i, right - i, up); 5580 } 5581 if (x == null) { 5582 throw new NotFoundException(); 5583 } 5584 let y = null; 5585 // go up left 5586 for (let i = 1; y === null && i < maxSize; i++) { 5587 y = this.getBlackPointOnSegment(right, down - i, right - i, down); 5588 } 5589 if (y == null) { 5590 throw new NotFoundException(); 5591 } 5592 return this.centerEdges(y, z, x, t); 5593 } 5594 else { 5595 throw new NotFoundException(); 5596 } 5597 } 5598 getBlackPointOnSegment(aX /*float*/, aY /*float*/, bX /*float*/, bY /*float*/) { 5599 const dist = MathUtils.round(MathUtils.distance(aX, aY, bX, bY)); 5600 const xStep = (bX - aX) / dist; 5601 const yStep = (bY - aY) / dist; 5602 const image = this.image; 5603 for (let i = 0; i < dist; i++) { 5604 const x = MathUtils.round(aX + i * xStep); 5605 const y = MathUtils.round(aY + i * yStep); 5606 if (image.get(x, y)) { 5607 return new ResultPoint(x, y); 5608 } 5609 } 5610 return null; 5611 } 5612 /** 5613 * recenters the points of a constant distance towards the center 5614 * 5615 * @param y bottom most point 5616 * @param z left most point 5617 * @param x right most point 5618 * @param t top most point 5619 * @return {@link ResultPoint}[] describing the corners of the rectangular 5620 * region. The first and last points are opposed on the diagonal, as 5621 * are the second and third. The first point will be the topmost 5622 * point and the last, the bottommost. The second point will be 5623 * leftmost and the third, the rightmost 5624 */ 5625 centerEdges(y, z, x, t) { 5626 // 5627 // t t 5628 // z x 5629 // x OR z 5630 // y y 5631 // 5632 const yi = y.getX(); 5633 const yj = y.getY(); 5634 const zi = z.getX(); 5635 const zj = z.getY(); 5636 const xi = x.getX(); 5637 const xj = x.getY(); 5638 const ti = t.getX(); 5639 const tj = t.getY(); 5640 const CORR = WhiteRectangleDetector.CORR; 5641 if (yi < this.width / 2.0) { 5642 return [ 5643 new ResultPoint(ti - CORR, tj + CORR), 5644 new ResultPoint(zi + CORR, zj + CORR), 5645 new ResultPoint(xi - CORR, xj - CORR), 5646 new ResultPoint(yi + CORR, yj - CORR) 5647 ]; 5648 } 5649 else { 5650 return [ 5651 new ResultPoint(ti + CORR, tj + CORR), 5652 new ResultPoint(zi + CORR, zj - CORR), 5653 new ResultPoint(xi - CORR, xj + CORR), 5654 new ResultPoint(yi - CORR, yj - CORR) 5655 ]; 5656 } 5657 } 5658 /** 5659 * Determines whether a segment contains a black point 5660 * 5661 * @param a min value of the scanned coordinate 5662 * @param b max value of the scanned coordinate 5663 * @param fixed value of fixed coordinate 5664 * @param horizontal set to true if scan must be horizontal, false if vertical 5665 * @return true if a black point has been found, else false. 5666 */ 5667 containsBlackPoint(a /*int*/, b /*int*/, fixed /*int*/, horizontal) { 5668 const image = this.image; 5669 if (horizontal) { 5670 for (let x = a; x <= b; x++) { 5671 if (image.get(x, fixed)) { 5672 return true; 5673 } 5674 } 5675 } 5676 else { 5677 for (let y = a; y <= b; y++) { 5678 if (image.get(fixed, y)) { 5679 return true; 5680 } 5681 } 5682 } 5683 return false;
5684 } 5685 } 5686 WhiteRectangleDetector.INIT_SIZE = 10; 5687 WhiteRectangleDetector.CORR = 1; 5688 5689 /* 5690 * Copyright 2007 ZXing authors 5691 * 5692 * Licensed under the Apache License, Version 2.0 (the "License"); 5693 * you may not use this file except in compliance with the License. 5694 * You may obtain a copy of the License at 5695 * 5696 * http://www.apache.org/licenses/LICENSE-2.0 5697 * 5698 * Unless required by applicable law or agreed to in writing, software 5699 * distributed under the License is distributed on an "AS IS" BASIS, 5700 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5701 * See the License for the specific language governing permissions and 5702 * limitations under the License. 5703 */ 5704 /** 5705 * Implementations of this class can, given locations of finder patterns for a QR code in an 5706 * image, sample the right points in the image to reconstruct the QR code, accounting for 5707 * perspective distortion. It is abstracted since it is relatively expensive and should be allowed 5708 * to take advantage of platform-specific optimized implementations, like Sun's Java Advanced 5709 * Imaging library, but which may not be available in other environments such as J2ME, and vice 5710 * versa. 5711 * 5712 * The implementation used can be controlled by calling {@link #setGridSampler(GridSampler)} 5713 * with an instance of a class which implements this interface. 5714 * 5715 * @author Sean Owen 5716 */ 5717 class GridSampler { 5718 /** 5719 * <p>Checks a set of points that have been transformed to sample points on an image against 5720 * the image's dimensions to see if the point are even within the image.</p> 5721 * 5722 * <p>This method will actually "nudge" the endpoints back onto the image if they are found to be 5723 * barely (less than 1 pixel) off the image. This accounts for imperfect detection of finder 5724 * patterns in an image where the QR Code runs all the way to the image border.</p> 5725 * 5726 * <p>For efficiency, the method will check points from either end of the line until one is found 5727 * to be within the image. Because the set of points are assumed to be linear, this is valid.</p> 5728 * 5729 * @param image image into which the points should map 5730 * @param points actual points in x1,y1,...,xn,yn form 5731 * @throws NotFoundException if an endpoint is lies outside the image boundaries 5732 */ 5733 static checkAndNudgePoints(image, points) { 5734 const width = image.getWidth(); 5735 const height
vendor: 8,418 bytes, lines 5735-5915
5735 = image.getHeight(); 5736 // Check and nudge points from start until we see some that are OK: 5737 let nudged = true; 5738 for (let offset = 0; offset < points.length && nudged; offset += 2) { 5739 const x = Math.floor(points[offset]); 5740 const y = Math.floor(points[offset + 1]); 5741 if (x < -1 || x > width || y < -1 || y > height) { 5742 throw new NotFoundException(); 5743 } 5744 nudged = false; 5745 if (x === -1) { 5746 points[offset] = 0.0; 5747 nudged = true; 5748 } 5749 else if (x === width) { 5750 points[offset] = width - 1; 5751 nudged = true; 5752 } 5753 if (y === -1) { 5754 points[offset + 1] = 0.0; 5755 nudged = true; 5756 } 5757 else if (y === height) { 5758 points[offset + 1] = height - 1; 5759 nudged = true; 5760 } 5761 } 5762 // Check and nudge points from end: 5763 nudged = true; 5764 for (let offset = points.length - 2; offset >= 0 && nudged; offset -= 2) { 5765 const x = Math.floor(points[offset]); 5766 const y = Math.floor(points[offset + 1]); 5767 if (x < -1 || x > width || y < -1 || y > height) { 5768 throw new NotFoundException(); 5769 } 5770 nudged = false; 5771 if (x === -1) { 5772 points[offset] = 0.0; 5773 nudged = true; 5774 } 5775 else if (x === width) { 5776 points[offset] = width - 1; 5777 nudged = true; 5778 } 5779 if (y === -1) { 5780 points[offset + 1] = 0.0; 5781 nudged = true; 5782 } 5783 else if (y === height) { 5784 points[offset + 1] = height - 1; 5785 nudged = true; 5786 } 5787 } 5788 } 5789 } 5790 5791 /* 5792 * Copyright 2007 ZXing authors 5793 * 5794 * Licensed under the Apache License, Version 2.0 (the "License"); 5795 * you may not use this file except in compliance with the License. 5796 * You may obtain a copy of the License at 5797 * 5798 * http://www.apache.org/licenses/LICENSE-2.0 5799 * 5800 * Unless required by applicable law or agreed to in writing, software 5801 * distributed under the License is distributed on an "AS IS" BASIS, 5802 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5803 * See the License for the specific language governing permissions and 5804 * limitations under the License. 5805 */ 5806 /*namespace com.google.zxing.common {*/ 5807 /** 5808 * <p>This class implements a perspective transform in two dimensions. Given four source and four 5809 * destination points, it will compute the transformation implied between them. The code is based 5810 * directly upon section 3.4.2 of George Wolberg's "Digital Image Warping"; see pages 54-56.</p> 5811 * 5812 * @author Sean Owen 5813 */ 5814 class PerspectiveTransform { 5815 constructor(a11 /*float*/, a21 /*float*/, a31 /*float*/, a12 /*float*/, a22 /*float*/, a32 /*float*/, a13 /*float*/, a23 /*float*/, a33 /*float*/) { 5816 this.a11 = a11; 5817 this.a21 = a21; 5818 this.a31 = a31; 5819 this.a12 = a12; 5820 this.a22 = a22; 5821 this.a32 = a32; 5822 this.a13 = a13; 5823 this.a23 = a23; 5824 this.a33 = a33; 5825 } 5826 static quadrilateralToQuadrilateral(x0 /*float*/, y0 /*float*/, x1 /*float*/, y1 /*float*/, x2 /*float*/, y2 /*float*/, x3 /*float*/, y3 /*float*/, x0p /*float*/, y0p /*float*/, x1p /*float*/, y1p /*float*/, x2p /*float*/, y2p /*float*/, x3p /*float*/, y3p /*float*/) { 5827 const qToS = PerspectiveTransform.quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3); 5828 const sToQ = PerspectiveTransform.squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p); 5829 return sToQ.times(qToS); 5830 } 5831 transformPoints(points) { 5832 const max = points.length; 5833 const a11 = this.a11; 5834 const a12 = this.a12; 5835 const a13 = this.a13; 5836 const a21 = this.a21; 5837 const a22 = this.a22; 5838 const a23 = this.a23; 5839 const a31 = this.a31; 5840 const a32 = this.a32; 5841 const a33 = this.a33; 5842 for (let i = 0; i < max; i += 2) { 5843 const x = points[i]; 5844 const y = points[i + 1]; 5845 const denominator = a13 * x + a23 * y + a33; 5846 points[i] = (a11 * x + a21 * y + a31) / denominator; 5847 points[i + 1] = (a12 * x + a22 * y + a32) / denominator; 5848 } 5849 } 5850 transformPointsWithValues(xValues, yValues) { 5851 const a11 = this.a11; 5852 const a12 = this.a12; 5853 const a13 = this.a13; 5854 const a21 = this.a21; 5855 const a22 = this.a22; 5856 const a23 = this.a23; 5857 const a31 = this.a31; 5858 const a32 = this.a32; 5859 const a33 = this.a33; 5860 const n = xValues.length; 5861 for (let i = 0; i < n; i++) { 5862 const x = xValues[i]; 5863 const y = yValues[i]; 5864 const denominator = a13 * x + a23 * y + a33; 5865 xValues[i] = (a11 * x + a21 * y + a31) / denominator; 5866 yValues[i] = (a12 * x + a22 * y + a32) / denominator; 5867 } 5868 } 5869 static squareToQuadrilateral(x0 /*float*/, y0 /*float*/, x1 /*float*/, y1 /*float*/, x2 /*float*/, y2 /*float*/, x3 /*float*/, y3 /*float*/) { 5870 const dx3 = x0 - x1 + x2 - x3; 5871 const dy3 = y0 - y1 + y2 - y3; 5872 if (dx3 === 0.0 && dy3 === 0.0) { 5873 // Affine 5874 return new PerspectiveTransform(x1 - x0, x2 - x1, x0, y1 - y0, y2 - y1, y0, 0.0, 0.0, 1.0); 5875 } 5876 else { 5877 const dx1 = x1 - x2; 5878 const dx2 = x3 - x2; 5879 const dy1 = y1 - y2; 5880 const dy2 = y3 - y2; 5881 const denominator = dx1 * dy2 - dx2 * dy1; 5882 const a13 = (dx3 * dy2 - dx2 * dy3) / denominator; 5883 const a23 = (dx1 * dy3 - dx3 * dy1) / denominator; 5884 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); 5885 } 5886 } 5887 static quadrilateralToSquare(x0 /*float*/, y0 /*float*/, x1 /*float*/, y1 /*float*/, x2 /*float*/, y2 /*float*/, x3 /*float*/, y3 /*float*/) { 5888 // Here, the adjoint serves as the inverse: 5889 return PerspectiveTransform.squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3).buildAdjoint(); 5890 } 5891 buildAdjoint() { 5892 // Adjoint is the transpose of the cofactor matrix: 5893 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); 5894 } 5895 times(other) { 5896 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); 5897 } 5898 } 5899 5900 /* 5901 * Copyright 2007 ZXing authors 5902 * 5903 * Licensed under the Apache License, Version 2.0 (the "License"); 5904 * you may not use this file except in compliance with the License. 5905 * You may obtain a copy of the License at 5906 * 5907 * http://www.apache.org/licenses/LICENSE-2.0 5908 * 5909 * Unless required by applicable law or agreed to in writing, software 5910 * distributed under the License is distributed on an "AS IS" BASIS, 5911 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5912 * See the License for the specific language governing permissions and 5913 * limitations under the License. 5914 */ 5915 /*
vendor: 2,942 bytes, lines 5915-5967
5915* 5916 * @author Sean Owen 5917 */ 5918 class DefaultGridSampler extends GridSampler { 5919 /*@Override*/ 5920 sampleGrid(image, dimensionX /*int*/, dimensionY /*int*/, p1ToX /*float*/, p1ToY /*float*/, p2ToX /*float*/, p2ToY /*float*/, p3ToX /*float*/, p3ToY /*float*/, p4ToX /*float*/, p4ToY /*float*/, p1FromX /*float*/, p1FromY /*float*/, p2FromX /*float*/, p2FromY /*float*/, p3FromX /*float*/, p3FromY /*float*/, p4FromX /*float*/, p4FromY /*float*/) { 5921 const transform = PerspectiveTransform.quadrilateralToQuadrilateral(p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY); 5922 return this.sampleGridWithTransform(image, dimensionX, dimensionY, transform); 5923 } 5924 /*@Override*/ 5925 sampleGridWithTransform(image, dimensionX /*int*/, dimensionY /*int*/, transform) { 5926 if (dimensionX <= 0 || dimensionY <= 0) { 5927 throw new NotFoundException(); 5928 } 5929 const bits = new BitMatrix(dimensionX, dimensionY); 5930 const points = new Float32Array(2 * dimensionX); 5931 for (let y = 0; y < dimensionY; y++) { 5932 const max = points.length; 5933 const iValue = y + 0.5; 5934 for (let x = 0; x < max; x += 2) { 5935 points[x] = (x / 2) + 0.5; 5936 points[x + 1] = iValue; 5937 } 5938 transform.transformPoints(points); 5939 // Quick check to see if points transformed to something inside the image 5940 // sufficient to check the endpoints 5941 GridSampler.checkAndNudgePoints(image, points); 5942 try { 5943 for (let x = 0; x < max; x += 2) { 5944 if (image.get(Math.floor(points[x]), Math.floor(points[x + 1]))) { 5945 // Black(-ish) pixel 5946 bits.set(x / 2, y); 5947 } 5948 } 5949 } 5950 catch (aioobe /*: ArrayIndexOutOfBoundsException*/) { 5951 // This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting 5952 // transform gets "twisted" such that it maps a straight line of points to a set of points 5953 // whose endpoints are in bounds, but others are not. There is probably some mathematical 5954 // way to detect this about the transformation that I don't know yet. 5955 // This results in an ugly runtime exception despite our clever checks above -- can't have 5956 // that. We could check each point's coordinates but that feels duplicative. We settle for 5957 // catching and wrapping ArrayIndexOutOfBoundsException. 5958 throw new NotFoundException(); 5959 } 5960 } 5961 return bits; 5962 } 5963 } 5964 5965 class GridSamplerInstance { 5966 /** 5967 * Sets the implementation of GridSampler used by the library. O
5967ne global 5968 * instance is stored, which may sound problematic. But, the implementation provided 5969 * ought to be appropriate for the entire platform, and all uses of this library 5970 * in the whole lifetime of the JVM. For instance, an Android activity can swap in 5971 * an implementation that takes advantage of native platform libraries. 5972 * 5973 * @param newGridSampler The platform-specific object to install. 5974 */ 5975 static setGridSampler(newGridSampler) { 5976 GridSamplerInstance.gridSampler = newGridSampler; 5977 } 5978 /** 5979 * @return the current implementation of GridSampler 5980 */ 5981 static getInstance() { 5982 return GridSamplerInstance.gridSampler; 5983 } 5984 } 5985 GridSamplerInstance.gridSampler = new DefaultGridSampler(); 5986 5987 /* 5988 * Copyright 2010 ZXing authors 5989 * 5990 * Licensed under the Apache License, Version 2.0 (the "License"); 5991 * you may not use this file except in compliance with the License. 5992 * You may obtain a copy of the License at 5993 * 5994 * http://www.apache.org/licenses/LICENSE-2.0 5995 * 5996 * Unless required by applicable law or agreed to in writing, software 5997 * distributed under the License is distributed on an "AS IS" BASIS, 5998 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5999 * See the License for the specific language governing permissions and 6000 * limitations under the License. 6001 */ 6002 class Point { 6003 constructor(x, y) { 6004 this.x = x; 6005 this.y = y; 6006 } 6007 toResultPoint() { 6008 return new ResultPoint(this.getX(), this.getY()); 6009 } 6010 getX() { 6011 return this.x; 6012 } 6013 getY() { 6014 return this.y; 6015 } 6016 } 6017 /** 6018 * Encapsulates logic that can detect an Aztec Code in an image, even if the Aztec Code 6019 * is rotated or skewed, or partially obscured. 6020 * 6021 * @author David Olivier 6022 * @author Frank Yellin 6023 */ 6024 class Detector$3 { 6025 constructor(image) { 6026 this.EXPECTED_CORNER_BITS = new Int32Array([ 6027 0xee0, 6028 0x1dc, 6029 0x83b, 6030 0x707, 6031 ]); 6032 this.image = image; 6033 } 6034 detect() { 6035 return this.detectMirror(false); 6036 } 6037 /** 6038 * Detects an Aztec Code in an image. 6039 * 6040 * @param isMirror if true, image is a mirror-image of original 6041 * @return {@link AztecDetectorResult} encapsulating results of detecting an Aztec Code 6042 * @throws NotFoundException if no Aztec Code can be found 6043 */ 6044 detectMirror(isMirror) { 6045 // 1. Get the center of the aztec matrix 6046 let pCenter = this.getMatrixCenter(); 6047 // 2. Get the center points of the four diagonal points just outside the bull's eye 6048 // [topRight, bottomRight, bottomLeft, topLeft] 6049 let bullsEyeCorners = this.getBullsEyeCorners(pCenter); 6050 if (isMirror) { 6051 let temp = bullsEyeCorners[0]; 6052 bullsEyeCorners[0] = bullsEyeCorners[2]; 6053 bullsEyeCorners[2] = temp; 6054 } 6055 // 3. Get the size of the matrix and other parameters from the bull's eye 6056 this.extractParameters(bullsEyeCorners); 6057 // 4. Sample the grid 6058 let bits = this.sampleGrid(this.image, bullsEyeCorners[this.shift % 4], bullsEyeCorners[(this.shift + 1) % 4], bullsEyeCorners[(this.shift + 2) % 4], bullsEyeCorners[(this.shift + 3) % 4]); 6059 // 5. Get the corners of the matrix. 6060 let corners = this.getMatrixCornerPoints(bullsEyeCorners); 6061 return new AztecDetectorResult(bits, corners, this.compact, this.nbDataBlocks, this.nbLayers); 6062 } 6063 /** 6064 * Extracts the number of data layers and data blocks from the layer around the bull's eye. 6065 * 6066 * @param bullsEyeCorners the array of bull's eye corners 6067 * @throws NotFoundException in case of too many errors or invalid parameters 6068 */ 6069 extractParameters(bullsEyeCorners) { 6070 if (!this.isValidPoint(bullsEyeCorners[0]) || !this.isValidPoint(bullsEyeCorners[1]) || 6071 !this.isValidPoint(bullsEyeCorners[2]) || !this.isValidPoint(bullsEyeCorners[3])) { 6072 throw new NotFoundException(); 6073 } 6074 let length = 2 * this.nbCenterLayers; 6075 // Get the bits around the bull's eye 6076 let sides = new Int32Array([ 6077 this.sampleLine(bullsEyeCorners[0], bullsEyeCorners[1], length), 6078 this.sampleLine(bullsEyeCorners[1], bullsEyeCorners[2], length), 6079 this.sampleLine(bullsEyeCorners[2], bullsEyeCorners[3], length),
vendor: 17,313 bytes, lines 6079-6462
6079 6080 this.sampleLine(bullsEyeCorners[3], bullsEyeCorners[0], length) // Top 6081 ]); 6082 // bullsEyeCorners[shift] is the corner of the bulls'eye that has three 6083 // orientation marks. 6084 // sides[shift] is the row/column that goes from the corner with three 6085 // orientation marks to the corner with two. 6086 this.shift = this.getRotation(sides, length); 6087 // Flatten the parameter bits into a single 28- or 40-bit long 6088 let parameterData = 0; 6089 for (let i = 0; i < 4; i++) { 6090 let side = sides[(this.shift + i) % 4]; 6091 if (this.compact) { 6092 // Each side of the form ..XXXXXXX. where Xs are parameter data 6093 parameterData <<= 7; 6094 parameterData += (side >> 1) & 0x7F; 6095 } 6096 else { 6097 // Each side of the form ..XXXXX.XXXXX. where Xs are parameter data 6098 parameterData <<= 10; 6099 parameterData += ((side >> 2) & (0x1f << 5)) + ((side >> 1) & 0x1F); 6100 } 6101 } 6102 // Corrects parameter data using RS. Returns just the data portion 6103 // without the error correction. 6104 let correctedData = this.getCorrectedParameterData(parameterData, this.compact); 6105 if (this.compact) { 6106 // 8 bits: 2 bits layers and 6 bits data blocks 6107 this.nbLayers = (correctedData >> 6) + 1; 6108 this.nbDataBlocks = (correctedData & 0x3F) + 1; 6109 } 6110 else { 6111 // 16 bits: 5 bits layers and 11 bits data blocks 6112 this.nbLayers = (correctedData >> 11) + 1; 6113 this.nbDataBlocks = (correctedData & 0x7FF) + 1; 6114 } 6115 } 6116 getRotation(sides, length) { 6117 // In a normal pattern, we expect to See 6118 // ** .* D A 6119 // * * 6120 // 6121 // . * 6122 // .. .. C B 6123 // 6124 // Grab the 3 bits from each of the sides the form the locator pattern and concatenate 6125 // into a 12-bit integer. Start with the bit at A 6126 let cornerBits = 0; 6127 sides.forEach((side, idx, arr) => { 6128 // XX......X where X's are orientation marks 6129 let t = ((side >> (length - 2)) << 1) + (side & 1); 6130 cornerBits = (cornerBits << 3) + t; 6131 }); 6132 // for (var side in sides) { 6133 // // XX......X where X's are orientation marks 6134 // var t = ((side >> (length - 2)) << 1) + (side & 1); 6135 // cornerBits = (cornerBits << 3) + t; 6136 // } 6137 // Mov the bottom bit to the top, so that the three bits of the locator pattern at A are 6138 // together. cornerBits is now: 6139 // 3 orientation bits at A || 3 orientation bits at B || ... || 3 orientation bits at D 6140 cornerBits = ((cornerBits & 1) << 11) + (cornerBits >> 1); 6141 // The result shift indicates which element of BullsEyeCorners[] goes into the top-left 6142 // corner. Since the four rotation values have a Hamming distance of 8, we 6143 // can easily tolerate two errors. 6144 for (let shift = 0; shift < 4; shift++) { 6145 if (Integer.bitCount(cornerBits ^ this.EXPECTED_CORNER_BITS[shift]) <= 2) { 6146 return shift; 6147 } 6148 } 6149 throw new NotFoundException(); 6150 } 6151 /** 6152 * Corrects the parameter bits using Reed-Solomon algorithm. 6153 * 6154 * @param parameterData parameter bits 6155 * @param compact true if this is a compact Aztec code 6156 * @throws NotFoundException if the array contains too many errors 6157 */ 6158 getCorrectedParameterData(parameterData, compact) { 6159 let numCodewords; 6160 let numDataCodewords; 6161 if (compact) { 6162 numCodewords = 7; 6163 numDataCodewords = 2; 6164 } 6165 else { 6166 numCodewords = 10; 6167 numDataCodewords = 4; 6168 } 6169 let numECCodewords = numCodewords - numDataCodewords; 6170 let parameterWords = new Int32Array(numCodewords); 6171 for (let i = numCodewords - 1; i >= 0; --i) { 6172 parameterWords[i] = parameterData & 0xF; 6173 parameterData >>= 4; 6174 } 6175 try { 6176 let rsDecoder = new ReedSolomonDecoder(GenericGF.AZTEC_PARAM); 6177 rsDecoder.decode(parameterWords, numECCodewords); 6178 } 6179 catch (ignored) { 6180 throw new NotFoundException(); 6181 } 6182 // Toss the error correction. Just return the data as an integer 6183 let result = 0; 6184 for (let i = 0; i < numDataCodewords; i++) { 6185 result = (result << 4) + parameterWords[i]; 6186 } 6187 return result; 6188 } 6189 /** 6190 * Finds the corners of a bull-eye centered on the passed point. 6191 * This returns the centers of the diagonal points just outside the bull's eye 6192 * Returns [topRight, bottomRight, bottomLeft, topLeft] 6193 * 6194 * @param pCenter Center point 6195 * @return The corners of the bull-eye 6196 * @throws NotFoundException If no valid bull-eye can be found 6197 */ 6198 getBullsEyeCorners(pCenter) { 6199 let pina = pCenter; 6200 let pinb = pCenter; 6201 let pinc = pCenter; 6202 let pind = pCenter; 6203 let color = true; 6204 for (this.nbCenterLayers = 1; this.nbCenterLayers < 9; this.nbCenterLayers++) { 6205 let pouta = this.getFirstDifferent(pina, color, 1, -1); 6206 let poutb = this.getFirstDifferent(pinb, color, 1, 1); 6207 let poutc = this.getFirstDifferent(pinc, color, -1, 1); 6208 let poutd = this.getFirstDifferent(pind, color, -1, -1); 6209 // d a 6210 // 6211 // c b 6212 if (this.nbCenterLayers > 2) { 6213 let q = (this.distancePoint(poutd, pouta) * this.nbCenterLayers) / (this.distancePoint(pind, pina) * (this.nbCenterLayers + 2)); 6214 if (q < 0.75 || q > 1.25 || !this.isWhiteOrBlackRectangle(pouta, poutb, poutc, poutd)) { 6215 break; 6216 } 6217 } 6218 pina = pouta; 6219 pinb = poutb; 6220 pinc = poutc; 6221 pind = poutd; 6222 color = !color; 6223 } 6224 if (this.nbCenterLayers !== 5 && this.nbCenterLayers !== 7) { 6225 throw new NotFoundException(); 6226 } 6227 this.compact = this.nbCenterLayers === 5; 6228 // Expand the square by .5 pixel in each direction so that we're on the border 6229 // between the white square and the black square 6230 let pinax = new ResultPoint(pina.getX() + 0.5, pina.getY() - 0.5); 6231 let pinbx = new ResultPoint(pinb.getX() + 0.5, pinb.getY() + 0.5); 6232 let pincx = new ResultPoint(pinc.getX() - 0.5, pinc.getY() + 0.5); 6233 let pindx = new ResultPoint(pind.getX() - 0.5, pind.getY() - 0.5); 6234 // Expand the square so that its corners are the centers of the points 6235 // just outside the bull's eye. 6236 return this.expandSquare([pinax, pinbx, pincx, pindx], 2 * this.nbCenterLayers - 3, 2 * this.nbCenterLayers); 6237 } 6238 /** 6239 * Finds a candidate center point of an Aztec code from an image 6240 * 6241 * @return the center point 6242 */ 6243 getMatrixCenter() { 6244 let pointA; 6245 let pointB; 6246 let pointC; 6247 let pointD; 6248 // Get a white rectangle that can be the border of the matrix in center bull's eye or 6249 try { 6250 let cornerPoints = new WhiteRectangleDetector(this.image).detect(); 6251 pointA = cornerPoints[0]; 6252 pointB = cornerPoints[1]; 6253 pointC = cornerPoints[2]; 6254 pointD = cornerPoints[3]; 6255 } 6256 catch (e) { 6257 // This exception can be in case the initial rectangle is white 6258 // In that case, surely in the bull's eye, we try to expand the rectangle. 6259 let cx = this.image.getWidth() / 2; 6260 let cy = this.image.getHeight() / 2; 6261 pointA = this.getFirstDifferent(new Point(cx + 7, cy - 7), false, 1, -1).toResultPoint(); 6262 pointB = this.getFirstDifferent(new Point(cx + 7, cy + 7), false, 1, 1).toResultPoint(); 6263 pointC = this.getFirstDifferent(new Point(cx - 7, cy + 7), false, -1, 1).toResultPoint(); 6264 pointD = this.getFirstDifferent(new Point(cx - 7, cy - 7), false, -1, -1).toResultPoint(); 6265 } 6266 // Compute the center of the rectangle 6267 let cx = MathUtils.round((pointA.getX() + pointD.getX() + pointB.getX() + pointC.getX()) / 4.0); 6268 let cy = MathUtils.round((pointA.getY() + pointD.getY() + pointB.getY() + pointC.getY()) / 4.0); 6269 // Redetermine the white rectangle starting from previously computed center. 6270 // This will ensure that we end up with a white rectangle in center bull's eye 6271 // in order to compute a more accurate center. 6272 try { 6273 let cornerPoints = new WhiteRectangleDetector(this.image, 15, cx, cy).detect(); 6274 pointA = cornerPoints[0]; 6275 pointB = cornerPoints[1]; 6276 pointC = cornerPoints[2]; 6277 pointD = cornerPoints[3]; 6278 } 6279 catch (e) { 6280 // This exception can be in case the initial rectangle is white 6281 // In that case we try to expand the rectangle. 6282 pointA = this.getFirstDifferent(new Point(cx + 7, cy - 7), false, 1, -1).toResultPoint(); 6283 pointB = this.getFirstDifferent(new Point(cx + 7, cy + 7), false, 1, 1).toResultPoint(); 6284 pointC = this.getFirstDifferent(new Point(cx - 7, cy + 7), false, -1, 1).toResultPoint(); 6285 pointD = this.getFirstDifferent(new Point(cx - 7, cy - 7), false, -1, -1).toResultPoint(); 6286 } 6287 // Recompute the center of the rectangle 6288 cx = MathUtils.round((pointA.getX() + pointD.getX() + pointB.getX() + pointC.getX()) / 4.0); 6289 cy = MathUtils.round((pointA.getY() + pointD.getY() + pointB.getY() + pointC.getY()) / 4.0); 6290 return new Point(cx, cy); 6291 } 6292 /** 6293 * Gets the Aztec code corners from the bull's eye corners and the parameters. 6294 * 6295 * @param bullsEyeCorners the array of bull's eye corners 6296 * @return the array of aztec code corners 6297 */ 6298 getMatrixCornerPoints(bullsEyeCorners) { 6299 return this.expandSquare(bullsEyeCorners, 2 * this.nbCenterLayers, this.getDimension()); 6300 } 6301 /** 6302 * Creates a BitMatrix by sampling the provided image. 6303 * topLeft, topRight, bottomRight, and bottomLeft are the centers of the squares on the 6304 * diagonal just outside the bull's eye. 6305 */ 6306 sampleGrid(image, topLeft, topRight, bottomRight, bottomLeft) { 6307 let sampler = GridSamplerInstance.getInstance(); 6308 let dimension = this.getDimension(); 6309 let low = dimension / 2 - this.nbCenterLayers; 6310 let high = dimension / 2 + this.nbCenterLayers; 6311 return sampler.sampleGrid(image, dimension, dimension, low, low, // topleft 6312 high, low, // topright 6313 high, high, // bottomright 6314 low, high, // bottomleft 6315 topLeft.getX(), topLeft.getY(), topRight.getX(), topRight.getY(), bottomRight.getX(), bottomRight.getY(), bottomLeft.getX(), bottomLeft.getY()); 6316 } 6317 /** 6318 * Samples a line. 6319 * 6320 * @param p1 start point (inclusive) 6321 * @param p2 end point (exclusive) 6322 * @param size number of bits 6323 * @return the array of bits as an int (first bit is high-order bit of result) 6324 */ 6325 sampleLine(p1, p2, size) { 6326 let result = 0; 6327 let d = this.distanceResultPoint(p1, p2); 6328 let moduleSize = d / size; 6329 let px = p1.getX(); 6330 let py = p1.getY(); 6331 let dx = moduleSize * (p2.getX() - p1.getX()) / d; 6332 let dy = moduleSize * (p2.getY() - p1.getY()) / d; 6333 for (let i = 0; i < size; i++) { 6334 if (this.image.get(MathUtils.round(px + i * dx), MathUtils.round(py + i * dy))) { 6335 result |= 1 << (size - i - 1); 6336 } 6337 } 6338 return result; 6339 } 6340 /** 6341 * @return true if the border of the rectangle passed in parameter is compound of white points only 6342 * or black points only 6343 */ 6344 isWhiteOrBlackRectangle(p1, p2, p3, p4) { 6345 let corr = 3; 6346 p1 = new Point(p1.getX() - corr, p1.getY() + corr); 6347 p2 = new Point(p2.getX() - corr, p2.getY() - corr); 6348 p3 = new Point(p3.getX() + corr, p3.getY() - corr); 6349 p4 = new Point(p4.getX() + corr, p4.getY() + corr); 6350 let cInit = this.getColor(p4, p1); 6351 if (cInit === 0) { 6352 return false; 6353 } 6354 let c = this.getColor(p1, p2); 6355 if (c !== cInit) { 6356 return false; 6357 } 6358 c = this.getColor(p2, p3); 6359 if (c !== cInit) { 6360 return false; 6361 } 6362 c = this.getColor(p3, p4); 6363 return c === cInit; 6364 } 6365 /** 6366 * Gets the color of a segment 6367 * 6368 * @return 1 if segment more than 90% black, -1 if segment is more than 90% white, 0 else 6369 */ 6370 getColor(p1, p2) { 6371 let d = this.distancePoint(p1, p2); 6372 let dx = (p2.getX() - p1.getX()) / d; 6373 let dy = (p2.getY() - p1.getY()) / d; 6374 let error = 0; 6375 let px = p1.getX(); 6376 let py = p1.getY(); 6377 let colorModel = this.image.get(p1.getX(), p1.getY()); 6378 let iMax = Math.ceil(d); 6379 for (let i = 0; i < iMax; i++) { 6380 px += dx; 6381 py += dy; 6382 if (this.image.get(MathUtils.round(px), MathUtils.round(py)) !== colorModel) { 6383 error++; 6384 } 6385 } 6386 let errRatio = error / d; 6387 if (errRatio > 0.1 && errRatio < 0.9) { 6388 return 0; 6389 } 6390 return (errRatio <= 0.1) === colorModel ? 1 : -1; 6391 } 6392 /** 6393 * Gets the coordinate of the first point with a different color in the given direction 6394 */ 6395 getFirstDifferent(init, color, dx, dy) { 6396 let x = init.getX() + dx; 6397 let y = init.getY() + dy; 6398 while (this.isValid(x, y) && this.image.get(x, y) === color) { 6399 x += dx; 6400 y += dy; 6401 } 6402 x -= dx; 6403 y -= dy; 6404 while (this.isValid(x, y) && this.image.get(x, y) === color) { 6405 x += dx; 6406 } 6407 x -= dx; 6408 while (this.isValid(x, y) && this.image.get(x, y) === color) { 6409 y += dy; 6410 } 6411 y -= dy; 6412 return new Point(x, y); 6413 } 6414 /** 6415 * Expand the square represented by the corner points by pushing out equally in all directions 6416 * 6417 * @param cornerPoints the corners of the square, which has the bull's eye at its center 6418 * @param oldSide the original length of the side of the square in the target bit matrix 6419 * @param newSide the new length of the size of the square in the target bit matrix 6420 * @return the corners of the expanded square 6421 */ 6422 expandSquare(cornerPoints, oldSide, newSide) { 6423 let ratio = newSide / (2.0 * oldSide); 6424 let dx = cornerPoints[0].getX() - cornerPoints[2].getX(); 6425 let dy = cornerPoints[0].getY() - cornerPoints[2].getY(); 6426 let centerx = (cornerPoints[0].getX() + cornerPoints[2].getX()) / 2.0; 6427 let centery = (cornerPoints[0].getY() + cornerPoints[2].getY()) / 2.0; 6428 let result0 = new ResultPoint(centerx + ratio * dx, centery + ratio * dy); 6429 let result2 = new ResultPoint(centerx - ratio * dx, centery - ratio * dy); 6430 dx = cornerPoints[1].getX() - cornerPoints[3].getX(); 6431 dy = cornerPoints[1].getY() - cornerPoints[3].getY(); 6432 centerx = (cornerPoints[1].getX() + cornerPoints[3].getX()) / 2.0; 6433 centery = (cornerPoints[1].getY() + cornerPoints[3].getY()) / 2.0; 6434 let result1 = new ResultPoint(centerx + ratio * dx, centery + ratio * dy); 6435 let result3 = new ResultPoint(centerx - ratio * dx, centery - ratio * dy); 6436 let results = [result0, result1, result2, result3]; 6437 return results; 6438 } 6439 isValid(x, y) { 6440 return x >= 0 && x < this.image.getWidth() && y > 0 && y < this.image.getHeight(); 6441 } 6442 isValidPoint(point) { 6443 let x = MathUtils.round(point.getX()); 6444 let y = MathUtils.round(point.getY()); 6445 return this.isValid(x, y); 6446 } 6447 distancePoint(a, b) { 6448 return MathUtils.distance(a.getX(), a.getY(), b.getX(), b.getY()); 6449 } 6450 distanceResultPoint(a, b) { 6451 return MathUtils.distance(a.getX(), a.getY(), b.getX(), b.getY()); 6452 } 6453 getDimension() { 6454 if (this.compact) { 6455 return 4 * this.nbLayers + 11; 6456 } 6457 if (this.nbLayers <= 4) { 6458 return 4 * this.nbLayers + 15; 6459 } 6460 return 4 * this.nbLayers + 2 * (Integer.truncDivision((this.nbLayers - 4), 8) + 1) + 15; 6461 } 6462 }
6462 6463 6464 /* 6465 * Copyright 2010 ZXing authors 6466 * 6467 * Licensed under the Apache License, Version 2.0 (the "License");
vendor: 7,877 bytes, lines 6468-6659
6468 * you may not use this file except in compliance with the License. 6469 * You may obtain a copy of the License at 6470 * 6471 * http://www.apache.org/licenses/LICENSE-2.0 6472 * 6473 * Unless required by applicable law or agreed to in writing, software 6474 * distributed under the License is distributed on an "AS IS" BASIS, 6475 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 6476 * See the License for the specific language governing permissions and 6477 * limitations under the License. 6478 */ 6479 // import java.util.List; 6480 // import java.util.Map; 6481 /** 6482 * This implementation can detect and decode Aztec codes in an image. 6483 * 6484 * @author David Olivier 6485 */ 6486 class AztecReader { 6487 /** 6488 * Locates and decodes a Data Matrix code in an image. 6489 * 6490 * @return a String representing the content encoded by the Data Matrix code 6491 * @throws NotFoundException if a Data Matrix code cannot be found 6492 * @throws FormatException if a Data Matrix code cannot be decoded 6493 */ 6494 decode(image, hints = null) { 6495 let exception = null; 6496 let detector = new Detector$3(image.getBlackMatrix()); 6497 let points = null; 6498 let decoderResult = null; 6499 try { 6500 let detectorResult = detector.detectMirror(false); 6501 points = detectorResult.getPoints(); 6502 this.reportFoundResultPoints(hints, points); 6503 decoderResult = new Decoder$2().decode(detectorResult); 6504 } 6505 catch (e) { 6506 exception = e; 6507 } 6508 if (decoderResult == null) { 6509 try { 6510 let detectorResult = detector.detectMirror(true); 6511 points = detectorResult.getPoints(); 6512 this.reportFoundResultPoints(hints, points); 6513 decoderResult = new Decoder$2().decode(detectorResult); 6514 } 6515 catch (e) { 6516 if (exception != null) { 6517 throw exception; 6518 } 6519 throw e; 6520 } 6521 } 6522 let result = new Result$1(decoderResult.getText(), decoderResult.getRawBytes(), decoderResult.getNumBits(), points, BarcodeFormat$1.AZTEC, System.currentTimeMillis()); 6523 let byteSegments = decoderResult.getByteSegments(); 6524 if (byteSegments != null) { 6525 result.putMetadata(ResultMetadataType$1.BYTE_SEGMENTS, byteSegments); 6526 } 6527 let ecLevel = decoderResult.getECLevel(); 6528 if (ecLevel != null) { 6529 result.putMetadata(ResultMetadataType$1.ERROR_CORRECTION_LEVEL, ecLevel); 6530 } 6531 return result; 6532 } 6533 reportFoundResultPoints(hints, points) { 6534 if (hints != null) { 6535 let rpcb = hints.get(DecodeHintType$1.NEED_RESULT_POINT_CALLBACK); 6536 if (rpcb != null) { 6537 points.forEach((point, idx, arr) => { 6538 rpcb.foundPossibleResultPoint(point); 6539 }); 6540 } 6541 } 6542 } 6543 // @Override 6544 reset() { 6545 // do nothing 6546 } 6547 } 6548 6549 /** 6550 * Aztec Code reader to use from browser. 6551 * 6552 * @class BrowserAztecCodeReader 6553 * @extends {BrowserCodeReader} 6554 */ 6555 class BrowserAztecCodeReader extends BrowserCodeReader { 6556 /** 6557 * Creates an instance of BrowserAztecCodeReader. 6558 * @param {number} [timeBetweenScansMillis=500] the time delay between subsequent decode tries 6559 * 6560 * @memberOf BrowserAztecCodeReader 6561 */ 6562 constructor(timeBetweenScansMillis = 500) { 6563 super(new AztecReader(), timeBetweenScansMillis); 6564 } 6565 } 6566 6567 /* 6568 * Copyright 2008 ZXing authors 6569 * 6570 * Licensed under the Apache License, Version 2.0 (the "License"); 6571 * you may not use this file except in compliance with the License. 6572 * You may obtain a copy of the License at 6573 * 6574 * http://www.apache.org/licenses/LICENSE-2.0 6575 * 6576 * Unless required by applicable law or agreed to in writing, software 6577 * distributed under the License is distributed on an "AS IS" BASIS, 6578 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 6579 * See the License for the specific language governing permissions and 6580 * limitations under the License. 6581 */ 6582 /** 6583 * Encapsulates functionality and implementation that is common to all families 6584 * of one-dimensional barcodes. 6585 * 6586 * @author [email protected] (Daniel Switkin) 6587 * @author Sean Owen 6588 */ 6589 class OneDReader { 6590 /* 6591 @Override 6592 public Result decode(BinaryBitmap image) throws NotFoundException, FormatException { 6593 return decode(image, null); 6594 } 6595 */ 6596 // Note that we don't try rotation without the try harder flag, even if rotation was supported. 6597 // @Override 6598 decode(image, hints) { 6599 try { 6600 return this.doDecode(image, hints); 6601 } 6602 catch (nfe) { 6603 const tryHarder = hints && (hints.get(DecodeHintType$1.TRY_HARDER) === true); 6604 if (tryHarder && image.isRotateSupported()) { 6605 const rotatedImage = image.rotateCounterClockwise(); 6606 const result = this.doDecode(rotatedImage, hints); 6607 // Record that we found it rotated 90 degrees CCW / 270 degrees CW 6608 const metadata = result.getResultMetadata(); 6609 let orientation = 270; 6610 if (metadata !== null && (metadata.get(ResultMetadataType$1.ORIENTATION) === true)) { 6611 // But if we found it reversed in doDecode(), add in that result here: 6612 orientation = (orientation + metadata.get(ResultMetadataType$1.ORIENTATION) % 360); 6613 } 6614 result.putMetadata(ResultMetadataType$1.ORIENTATION, orientation); 6615 // Update result points 6616 const points = result.getResultPoints(); 6617 if (points !== null) { 6618 const height = rotatedImage.getHeight(); 6619 for (let i = 0; i < points.length; i++) { 6620 points[i] = new ResultPoint(height - points[i].getY() - 1, points[i].getX()); 6621 } 6622 } 6623 return result; 6624 } 6625 else { 6626 throw new NotFoundException(); 6627 } 6628 } 6629 } 6630 // @Override 6631 reset() { 6632 // do nothing 6633 } 6634 /** 6635 * We're going to examine rows from the middle outward, searching alternately above and below the 6636 * middle, and farther out each time. rowStep is the number of rows between each successive 6637 * attempt above and below the middle. So we'd scan row middle, then middle - rowStep, then 6638 * middle + rowStep, then middle - (2 * rowStep), etc. 6639 * rowStep is bigger as the image is taller, but is always at least 1. We've somewhat arbitrarily 6640 * decided that moving up and down by about 1/16 of the image is pretty good; we try more of the 6641 * image if "trying harder". 6642 * 6643 * @param image The image to decode 6644 * @param hints Any hints that were requested 6645 * @return The contents of the decoded barcode 6646 * @throws NotFoundException Any spontaneous errors which occur 6647 */ 6648 doDecode(image, hints) { 6649 const width = image.getWidth(); 6650 const height = image.getHeight(); 6651 let row = new BitArray(width); 6652 const tryHarder = hints && (hints.get(DecodeHintType$1.TRY_HARDER) === true); 6653 const rowStep = Math.max(1, height >> (tryHarder ? 8 : 5)); 6654 let maxLines; 6655 if (tryHarder) { 6656 maxLines = height; // Look at the whole image, not just the center 6657 } 6658 else { 6659 maxLines = 15; // 15 rows spaced 1/32 apart is roughly the middle half of the image
vendor: 8,080 bytes, lines 6659-6831
6659 6660 } 6661 const middle = Math.trunc(height / 2); 6662 for (let x = 0; x < maxLines; x++) { 6663 // Scanning from the middle out. Determine which row we're looking at next: 6664 const rowStepsAboveOrBelow = Math.trunc((x + 1) / 2); 6665 const isAbove = (x & 0x01) === 0; // i.e. is x even? 6666 const rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow); 6667 if (rowNumber < 0 || rowNumber >= height) { 6668 // Oops, if we run off the top or bottom, stop 6669 break; 6670 } 6671 // Estimate black point for this row and load it: 6672 try { 6673 row = image.getBlackRow(rowNumber, row); 6674 } 6675 catch (ignored) { 6676 continue; 6677 } 6678 // While we have the image data in a BitArray, it's fairly cheap to reverse it in place to 6679 // handle decoding upside down barcodes. 6680 for (let attempt = 0; attempt < 2; attempt++) { 6681 if (attempt === 1) { // trying again? 6682 row.reverse(); // reverse the row and continue 6683 // This means we will only ever draw result points *once* in the life of this method 6684 // since we want to avoid drawing the wrong points after flipping the row, and, 6685 // don't want to clutter with noise from every single row scan -- just the scans 6686 // that start on the center line. 6687 if (hints && (hints.get(DecodeHintType$1.NEED_RESULT_POINT_CALLBACK) === true)) { 6688 const newHints = new Map(); 6689 hints.forEach((hint, key) => newHints.set(key, hint)); 6690 newHints.delete(DecodeHintType$1.NEED_RESULT_POINT_CALLBACK); 6691 hints = newHints; 6692 } 6693 } 6694 try { 6695 // Look for a barcode 6696 const result = this.decodeRow(rowNumber, row, hints); 6697 // We found our barcode 6698 if (attempt === 1) { 6699 // But it was upside down, so note that 6700 result.putMetadata(ResultMetadataType$1.ORIENTATION, 180); 6701 // And remember to flip the result points horizontally. 6702 const points = result.getResultPoints(); 6703 if (points !== null) { 6704 points[0] = new ResultPoint(width - points[0].getX() - 1, points[0].getY()); 6705 points[1] = new ResultPoint(width - points[1].getX() - 1, points[1].getY()); 6706 } 6707 } 6708 return result; 6709 } 6710 catch (re) { 6711 // continue -- just couldn't decode this row 6712 } 6713 } 6714 } 6715 throw new NotFoundException(); 6716 } 6717 /** 6718 * Records the size of successive runs of white and black pixels in a row, starting at a given point. 6719 * The values are recorded in the given array, and the number of runs recorded is equal to the size 6720 * of the array. If the row starts on a white pixel at the given start point, then the first count 6721 * recorded is the run of white pixels starting from that point; likewise it is the count of a run 6722 * of black pixels if the row begin on a black pixels at that point. 6723 * 6724 * @param row row to count from 6725 * @param start offset into row to start at 6726 * @param counters array into which to record counts 6727 * @throws NotFoundException if counters cannot be filled entirely from row before running out 6728 * of pixels 6729 */ 6730 static recordPattern(row, start, counters) { 6731 const numCounters = counters.length; 6732 for (let index = 0; index < numCounters; index++) 6733 counters[index] = 0; 6734 const end = row.getSize(); 6735 if (start >= end) { 6736 throw new NotFoundException(); 6737 } 6738 let isWhite = !row.get(start); 6739 let counterPosition = 0; 6740 let i = start; 6741 while (i < end) { 6742 if (row.get(i) !== isWhite) { 6743 counters[counterPosition]++; 6744 } 6745 else { 6746 if (++counterPosition === numCounters) { 6747 break; 6748 } 6749 else { 6750 counters[counterPosition] = 1; 6751 isWhite = !isWhite; 6752 } 6753 } 6754 i++; 6755 } 6756 // If we read fully the last section of pixels and filled up our counters -- or filled 6757 // the last counter but ran off the side of the image, OK. Otherwise, a problem. 6758 if (!(counterPosition === numCounters || (counterPosition === numCounters - 1 && i === end))) { 6759 throw new NotFoundException(); 6760 } 6761 } 6762 static recordPatternInReverse(row, start, counters) { 6763 // This could be more efficient I guess 6764 let numTransitionsLeft = counters.length; 6765 let last = row.get(start); 6766 while (start > 0 && numTransitionsLeft >= 0) { 6767 if (row.get(--start) !== last) { 6768 numTransitionsLeft--; 6769 last = !last; 6770 } 6771 } 6772 if (numTransitionsLeft >= 0) { 6773 throw new NotFoundException(); 6774 } 6775 OneDReader.recordPattern(row, start + 1, counters); 6776 } 6777 /** 6778 * Determines how closely a set of observed counts of runs of black/white values matches a given 6779 * target pattern. This is reported as the ratio of the total variance from the expected pattern 6780 * proportions across all pattern elements, to the length of the pattern. 6781 * 6782 * @param counters observed counters 6783 * @param pattern expected pattern 6784 * @param maxIndividualVariance The most any counter can differ before we give up 6785 * @return ratio of total variance between counters and pattern compared to total pattern size 6786 */ 6787 static patternMatchVariance(counters, pattern, maxIndividualVariance) { 6788 const numCounters = counters.length; 6789 let total = 0; 6790 let patternLength = 0; 6791 for (let i = 0; i < numCounters; i++) { 6792 total += counters[i]; 6793 patternLength += pattern[i]; 6794 } 6795 if (total < patternLength) { 6796 // If we don't even have one pixel per unit of bar width, assume this is too small 6797 // to reliably match, so fail: 6798 return Number.POSITIVE_INFINITY; 6799 } 6800 const unitBarWidth = total / patternLength; 6801 maxIndividualVariance *= unitBarWidth; 6802 let totalVariance = 0.0; 6803 for (let x = 0; x < numCounters; x++) { 6804 const counter = counters[x]; 6805 const scaledPattern = pattern[x] * unitBarWidth; 6806 const variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter; 6807 if (variance > maxIndividualVariance) { 6808 return Number.POSITIVE_INFINITY; 6809 } 6810 totalVariance += variance; 6811 } 6812 return totalVariance / total; 6813 } 6814 } 6815 6816 /* 6817 * Copyright 2008 ZXing authors 6818 * 6819 * Licensed under the Apache License, Version 2.0 (the "License"); 6820 * you may not use this file except in compliance with the License. 6821 * You may obtain a copy of the License at 6822 * 6823 * http://www.apache.org/licenses/LICENSE-2.0 6824 * 6825 * Unless required by applicable law or agreed to in writing, software 6826 * distributed under the License is distributed on an "AS IS" BASIS, 6827 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 6828 * See the License for the specific language governing permissions and 6829 * limitations under the License. 6830 */ 6831 /*
vendor: 22,113 bytes, lines 6831-7288
6831* 6832 * <p>Decodes Code 128 barcodes.</p> 6833 * 6834 * @author Sean Owen 6835 */ 6836 class Code128Reader extends OneDReader { 6837 static findStartPattern(row) { 6838 const width = row.getSize(); 6839 const rowOffset = row.getNextSet(0); 6840 let counterPosition = 0; 6841 let counters = Int32Array.from([0, 0, 0, 0, 0, 0]); 6842 let patternStart = rowOffset; 6843 let isWhite = false; 6844 const patternLength = 6; 6845 for (let i = rowOffset; i < width; i++) { 6846 if (row.get(i) !== isWhite) { 6847 counters[counterPosition]++; 6848 } 6849 else { 6850 if (counterPosition === (patternLength - 1)) { 6851 let bestVariance = Code128Reader.MAX_AVG_VARIANCE; 6852 let bestMatch = -1; 6853 for (let startCode = Code128Reader.CODE_START_A; startCode <= Code128Reader.CODE_START_C; startCode++) { 6854 const variance = OneDReader.patternMatchVariance(counters, Code128Reader.CODE_PATTERNS[startCode], Code128Reader.MAX_INDIVIDUAL_VARIANCE); 6855 if (variance < bestVariance) { 6856 bestVariance = variance; 6857 bestMatch = startCode; 6858 } 6859 } 6860 // Look for whitespace before start pattern, >= 50% of width of start pattern 6861 if (bestMatch >= 0 && 6862 row.isRange(Math.max(0, patternStart - (i - patternStart) / 2), patternStart, false)) { 6863 return Int32Array.from([patternStart, i, bestMatch]); 6864 } 6865 patternStart += counters[0] + counters[1]; 6866 counters = counters.slice(2, counters.length); 6867 counters[counterPosition - 1] = 0; 6868 counters[counterPosition] = 0; 6869 counterPosition--; 6870 } 6871 else { 6872 counterPosition++; 6873 } 6874 counters[counterPosition] = 1; 6875 isWhite = !isWhite; 6876 } 6877 } 6878 throw new NotFoundException(); 6879 } 6880 static decodeCode(row, counters, rowOffset) { 6881 OneDReader.recordPattern(row, rowOffset, counters); 6882 let bestVariance = Code128Reader.MAX_AVG_VARIANCE; // worst variance we'll accept 6883 let bestMatch = -1; 6884 for (let d = 0; d < Code128Reader.CODE_PATTERNS.length; d++) { 6885 const pattern = Code128Reader.CODE_PATTERNS[d]; 6886 const variance = this.patternMatchVariance(counters, pattern, Code128Reader.MAX_INDIVIDUAL_VARIANCE); 6887 if (variance < bestVariance) { 6888 bestVariance = variance; 6889 bestMatch = d; 6890 } 6891 } 6892 // TODO We're overlooking the fact that the STOP pattern has 7 values, not 6. 6893 if (bestMatch >= 0) { 6894 return bestMatch; 6895 } 6896 else { 6897 throw new NotFoundException(); 6898 } 6899 } 6900 decodeRow(rowNumber, row, hints) { 6901 const convertFNC1 = hints && (hints.get(DecodeHintType$1.ASSUME_GS1) === true); 6902 const startPatternInfo = Code128Reader.findStartPattern(row); 6903 const startCode = startPatternInfo[2]; 6904 let currentRawCodesIndex = 0; 6905 const rawCodes = new Uint8Array(20); 6906 rawCodes[currentRawCodesIndex++] = startCode; 6907 let codeSet; 6908 switch (startCode) { 6909 case Code128Reader.CODE_START_A: 6910 codeSet = Code128Reader.CODE_CODE_A; 6911 break; 6912 case Code128Reader.CODE_START_B: 6913 codeSet = Code128Reader.CODE_CODE_B; 6914 break; 6915 case Code128Reader.CODE_START_C: 6916 codeSet = Code128Reader.CODE_CODE_C; 6917 break; 6918 default: 6919 throw new FormatException(); 6920 } 6921 let done = false; 6922 let isNextShifted = false; 6923 let result = ''; 6924 let lastStart = startPatternInfo[0]; 6925 let nextStart = startPatternInfo[1]; 6926 const counters = Int32Array.from([0, 0, 0, 0, 0, 0]); 6927 let lastCode = 0; 6928 let code = 0; 6929 let checksumTotal = startCode; 6930 let multiplier = 0; 6931 let lastCharacterWasPrintable = true; 6932 let upperMode = false; 6933 let shiftUpperMode = false; 6934 while (!done) { 6935 const unshift = isNextShifted; 6936 isNextShifted = false; 6937 // Save off last code 6938 lastCode = code; 6939 // Decode another code from image 6940 code = Code128Reader.decodeCode(row, counters, nextStart); 6941 rawCodes[currentRawCodesIndex++] = code; 6942 // Remember whether the last code was printable or not (excluding CODE_STOP) 6943 if (code !== Code128Reader.CODE_STOP) { 6944 lastCharacterWasPrintable = true; 6945 } 6946 // Add to checksum computation (if not CODE_STOP of course) 6947 if (code !== Code128Reader.CODE_STOP) { 6948 multiplier++; 6949 checksumTotal += multiplier * code; 6950 } 6951 // Advance to where the next code will to start 6952 lastStart = nextStart; 6953 nextStart += counters.reduce((previous, current) => previous + current, 0); 6954 // Take care of illegal start codes 6955 switch (code) { 6956 case Code128Reader.CODE_START_A: 6957 case Code128Reader.CODE_START_B: 6958 case Code128Reader.CODE_START_C: 6959 throw new FormatException(); 6960 } 6961 switch (codeSet) { 6962 case Code128Reader.CODE_CODE_A: 6963 if (code < 64) { 6964 if (shiftUpperMode === upperMode) { 6965 result += String.fromCharCode((' '.charCodeAt(0) + code)); 6966 } 6967 else { 6968 result += String.fromCharCode((' '.charCodeAt(0) + code + 128)); 6969 } 6970 shiftUpperMode = false; 6971 } 6972 else if (code < 96) { 6973 if (shiftUpperMode === upperMode) { 6974 result += String.fromCharCode((code - 64)); 6975 } 6976 else { 6977 result += String.fromCharCode((code + 64)); 6978 } 6979 shiftUpperMode = false; 6980 } 6981 else { 6982 // Don't let CODE_STOP, which always appears, affect whether whether we think the last 6983 // code was printable or not. 6984 if (code !== Code128Reader.CODE_STOP) { 6985 lastCharacterWasPrintable = false; 6986 } 6987 switch (code) { 6988 case Code128Reader.CODE_FNC_1: 6989 if (convertFNC1) { 6990 if (result.length === 0) { 6991 // GS1 specification 5.4.3.7. and 5.4.6.4. If the first char after the start code 6992 // is FNC1 then this is GS1-128. We add the symbology identifier. 6993 result += ']C1'; 6994 } 6995 else { 6996 // GS1 specification 5.4.7.5. Every subsequent FNC1 is returned as ASCII 29 (GS) 6997 result += String.fromCharCode(29); 6998 } 6999 } 7000 break; 7001 case Code128Reader.CODE_FNC_2: 7002 case Code128Reader.CODE_FNC_3: 7003 // do nothing? 7004 break; 7005 case Code128Reader.CODE_FNC_4_A: 7006 if (!upperMode && shiftUpperMode) { 7007 upperMode = true; 7008 shiftUpperMode = false; 7009 } 7010 else if (upperMode && shiftUpperMode) { 7011 upperMode = false; 7012 shiftUpperMode = false; 7013 } 7014 else { 7015 shiftUpperMode = true; 7016 } 7017 break; 7018 case Code128Reader.CODE_SHIFT: 7019 isNextShifted = true; 7020 codeSet = Code128Reader.CODE_CODE_B; 7021 break; 7022 case Code128Reader.CODE_CODE_B: 7023 codeSet = Code128Reader.CODE_CODE_B; 7024 break; 7025 case Code128Reader.CODE_CODE_C: 7026 codeSet = Code128Reader.CODE_CODE_C; 7027 break; 7028 case Code128Reader.CODE_STOP: 7029 done = true; 7030 break; 7031 } 7032 } 7033 break; 7034 case Code128Reader.CODE_CODE_B: 7035 if (code < 96) { 7036 if (shiftUpperMode === upperMode) { 7037 result += String.fromCharCode((' '.charCodeAt(0) + code)); 7038 } 7039 else { 7040 result += String.fromCharCode((' '.charCodeAt(0) + code + 128)); 7041 } 7042 shiftUpperMode = false; 7043 } 7044 else { 7045 if (code !== Code128Reader.CODE_STOP) { 7046 lastCharacterWasPrintable = false; 7047 } 7048 switch (code) { 7049 case Code128Reader.CODE_FNC_1: 7050 if (convertFNC1) { 7051 if (result.length === 0) { 7052 // GS1 specification 5.4.3.7. and 5.4.6.4. If the first char after the start code 7053 // is FNC1 then this is GS1-128. We add the symbology identifier. 7054 result += ']C1'; 7055 } 7056 else { 7057 // GS1 specification 5.4.7.5. Every subsequent FNC1 is returned as ASCII 29 (GS) 7058 result += String.fromCharCode(29); 7059 } 7060 } 7061 break; 7062 case Code128Reader.CODE_FNC_2: 7063 case Code128Reader.CODE_FNC_3: 7064 // do nothing? 7065 break; 7066 case Code128Reader.CODE_FNC_4_B: 7067 if (!upperMode && shiftUpperMode) { 7068 upperMode = true; 7069 shiftUpperMode = false; 7070 } 7071 else if (upperMode && shiftUpperMode) { 7072 upperMode = false; 7073 shiftUpperMode = false; 7074 } 7075 else { 7076 shiftUpperMode = true; 7077 } 7078 break; 7079 case Code128Reader.CODE_SHIFT: 7080 isNextShifted = true; 7081 codeSet = Code128Reader.CODE_CODE_A; 7082 break; 7083 case Code128Reader.CODE_CODE_A: 7084 codeSet = Code128Reader.CODE_CODE_A; 7085 break; 7086 case Code128Reader.CODE_CODE_C: 7087 codeSet = Code128Reader.CODE_CODE_C; 7088 break; 7089 case Code128Reader.CODE_STOP: 7090 done = true; 7091 break; 7092 } 7093 } 7094 break; 7095 case Code128Reader.CODE_CODE_C: 7096 if (code < 100) { 7097 if (code < 10) { 7098 result += '0'; 7099 } 7100 result += code; 7101 } 7102 else { 7103 if (code !== Code128Reader.CODE_STOP) { 7104 lastCharacterWasPrintable = false; 7105 } 7106 switch (code) { 7107 case Code128Reader.CODE_FNC_1: 7108 if (convertFNC1) { 7109 if (result.length === 0) { 7110 // GS1 specification 5.4.3.7. and 5.4.6.4. If the first char after the start code 7111 // is FNC1 then this is GS1-128. We add the symbology identifier. 7112 result += ']C1'; 7113 } 7114 else { 7115 // GS1 specification 5.4.7.5. Every subsequent FNC1 is returned as ASCII 29 (GS) 7116 result += String.fromCharCode(29); 7117 } 7118 } 7119 break; 7120 case Code128Reader.CODE_CODE_A: 7121 codeSet = Code128Reader.CODE_CODE_A; 7122 break; 7123 case Code128Reader.CODE_CODE_B: 7124 codeSet = Code128Reader.CODE_CODE_B; 7125 break; 7126 case Code128Reader.CODE_STOP: 7127 done = true; 7128 break; 7129 } 7130 } 7131 break; 7132 } 7133 // Unshift back to another code set if we were shifted 7134 if (unshift) { 7135 codeSet = codeSet === Code128Reader.CODE_CODE_A ? Code128Reader.CODE_CODE_B : Code128Reader.CODE_CODE_A; 7136 } 7137 } 7138 const lastPatternSize = nextStart - lastStart; 7139 // Check for ample whitespace following pattern, but, to do this we first need to remember that 7140 // we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left 7141 // to read off. Would be slightly better to properly read. Here we just skip it: 7142 nextStart = row.getNextUnset(nextStart); 7143 if (!row.isRange(nextStart, Math.min(row.getSize(), nextStart + (nextStart - lastStart) / 2), false)) { 7144 throw new NotFoundException(); 7145 } 7146 // Pull out from sum the value of the penultimate check code 7147 checksumTotal -= multiplier * lastCode; 7148 // lastCode is the checksum then: 7149 if (checksumTotal % 103 !== lastCode) { 7150 throw new ChecksumException(); 7151 } 7152 // Need to pull out the check digits from string 7153 const resultLength = result.length; 7154 if (resultLength === 0) { 7155 // false positive 7156 throw new NotFoundException(); 7157 } 7158 // Only bother if the result had at least one character, and if the checksum digit happened to 7159 // be a printable character. If it was just interpreted as a control code, nothing to remove. 7160 if (resultLength > 0 && lastCharacterWasPrintable) { 7161 if (codeSet === Code128Reader.CODE_CODE_C) { 7162 result = result.substring(0, resultLength - 2); 7163 } 7164 else { 7165 result = result.substring(0, resultLength - 1); 7166 } 7167 } 7168 const left = (startPatternInfo[1] + startPatternInfo[0]) / 2.0; 7169 const right = lastStart + lastPatternSize / 2.0; 7170 const rawCodesSize = rawCodes.length; 7171 const rawBytes = new Uint8Array(rawCodesSize); 7172 for (let i = 0; i < rawCodesSize; i++) { 7173 rawBytes[i] = rawCodes[i]; 7174 } 7175 const points = [new ResultPoint(left, rowNumber), new ResultPoint(right, rowNumber)]; 7176 return new Result$1(result, rawBytes, 0, points, BarcodeFormat$1.CODE_128, new Date().getTime()); 7177 } 7178 } 7179 Code128Reader.CODE_PATTERNS = [ 7180 Int32Array.from([2, 1, 2, 2, 2, 2]), 7181 Int32Array.from([2, 2, 2, 1, 2, 2]), 7182 Int32Array.from([2, 2, 2, 2, 2, 1]), 7183 Int32Array.from([1, 2, 1, 2, 2, 3]), 7184 Int32Array.from([1, 2, 1, 3, 2, 2]), 7185 Int32Array.from([1, 3, 1, 2, 2, 2]), 7186 Int32Array.from([1, 2, 2, 2, 1, 3]), 7187 Int32Array.from([1, 2, 2, 3, 1, 2]), 7188 Int32Array.from([1, 3, 2, 2, 1, 2]), 7189 Int32Array.from([2, 2, 1, 2, 1, 3]), 7190 Int32Array.from([2, 2, 1, 3, 1, 2]), 7191 Int32Array.from([2, 3, 1, 2, 1, 2]), 7192 Int32Array.from([1, 1, 2, 2, 3, 2]), 7193 Int32Array.from([1, 2, 2, 1, 3, 2]), 7194 Int32Array.from([1, 2, 2, 2, 3, 1]), 7195 Int32Array.from([1, 1, 3, 2, 2, 2]), 7196 Int32Array.from([1, 2, 3, 1, 2, 2]), 7197 Int32Array.from([1, 2, 3, 2, 2, 1]), 7198 Int32Array.from([2, 2, 3, 2, 1, 1]), 7199 Int32Array.from([2, 2, 1, 1, 3, 2]), 7200 Int32Array.from([2, 2, 1, 2, 3, 1]), 7201 Int32Array.from([2, 1, 3, 2, 1, 2]), 7202 Int32Array.from([2, 2, 3, 1, 1, 2]), 7203 Int32Array.from([3, 1, 2, 1, 3, 1]), 7204 Int32Array.from([3, 1, 1, 2, 2, 2]), 7205 Int32Array.from([3, 2, 1, 1, 2, 2]), 7206 Int32Array.from([3, 2, 1, 2, 2, 1]), 7207 Int32Array.from([3, 1, 2, 2, 1, 2]), 7208 Int32Array.from([3, 2, 2, 1, 1, 2]), 7209 Int32Array.from([3, 2, 2, 2, 1, 1]), 7210 Int32Array.from([2, 1, 2, 1, 2, 3]), 7211 Int32Array.from([2, 1, 2, 3, 2, 1]), 7212 Int32Array.from([2, 3, 2, 1, 2, 1]), 7213 Int32Array.from([1, 1, 1, 3, 2, 3]), 7214 Int32Array.from([1, 3, 1, 1, 2, 3]), 7215 Int32Array.from([1, 3, 1, 3, 2, 1]), 7216 Int32Array.from([1, 1, 2, 3, 1, 3]), 7217 Int32Array.from([1, 3, 2, 1, 1, 3]), 7218 Int32Array.from([1, 3, 2, 3, 1, 1]), 7219 Int32Array.from([2, 1, 1, 3, 1, 3]), 7220 Int32Array.from([2, 3, 1, 1, 1, 3]), 7221 Int32Array.from([2, 3, 1, 3, 1, 1]), 7222 Int32Array.from([1, 1, 2, 1, 3, 3]), 7223 Int32Array.from([1, 1, 2, 3, 3, 1]), 7224 Int32Array.from([1, 3, 2, 1, 3, 1]), 7225 Int32Array.from([1, 1, 3, 1, 2, 3]), 7226 Int32Array.from([1, 1, 3, 3, 2, 1]), 7227 Int32Array.from([1, 3, 3, 1, 2, 1]), 7228 Int32Array.from([3, 1, 3, 1, 2, 1]), 7229 Int32Array.from([2, 1, 1, 3, 3, 1]), 7230 Int32Array.from([2, 3, 1, 1, 3, 1]), 7231 Int32Array.from([2, 1, 3, 1, 1, 3]), 7232 Int32Array.from([2, 1, 3, 3, 1, 1]), 7233 Int32Array.from([2, 1, 3, 1, 3, 1]), 7234 Int32Array.from([3, 1, 1, 1, 2, 3]), 7235 Int32Array.from([3, 1, 1, 3, 2, 1]), 7236 Int32Array.from([3, 3, 1, 1, 2, 1]), 7237 Int32Array.from([3, 1, 2, 1, 1, 3]), 7238 Int32Array.from([3, 1, 2, 3, 1, 1]), 7239 Int32Array.from([3, 3, 2, 1, 1, 1]), 7240 Int32Array.from([3, 1, 4, 1, 1, 1]), 7241 Int32Array.from([2, 2, 1, 4, 1, 1]), 7242 Int32Array.from([4, 3, 1, 1, 1, 1]), 7243 Int32Array.from([1, 1, 1, 2, 2, 4]), 7244 Int32Array.from([1, 1, 1, 4, 2, 2]), 7245 Int32Array.from([1, 2, 1, 1, 2, 4]), 7246 Int32Array.from([1, 2, 1, 4, 2, 1]), 7247 Int32Array.from([1, 4, 1, 1, 2, 2]), 7248 Int32Array.from([1, 4, 1, 2, 2, 1]), 7249 Int32Array.from([1, 1, 2, 2, 1, 4]), 7250 Int32Array.from([1, 1, 2, 4, 1, 2]), 7251 Int32Array.from([1, 2, 2, 1, 1, 4]), 7252 Int32Array.from([1, 2, 2, 4, 1, 1]), 7253 Int32Array.from([1, 4, 2, 1, 1, 2]), 7254 Int32Array.from([1, 4, 2, 2, 1, 1]), 7255 Int32Array.from([2, 4, 1, 2, 1, 1]), 7256 Int32Array.from([2, 2, 1, 1, 1, 4]), 7257 Int32Array.from([4, 1, 3, 1, 1, 1]), 7258 Int32Array.from([2, 4, 1, 1, 1, 2]), 7259 Int32Array.from([1, 3, 4, 1, 1, 1]), 7260 Int32Array.from([1, 1, 1, 2, 4, 2]), 7261 Int32Array.from([1, 2, 1, 1, 4, 2]), 7262 Int32Array.from([1, 2, 1, 2, 4, 1]), 7263 Int32Array.from([1, 1, 4, 2, 1, 2]), 7264 Int32Array.from([1, 2, 4, 1, 1, 2]), 7265 Int32Array.from([1, 2, 4, 2, 1, 1]), 7266 Int32Array.from([4, 1, 1, 2, 1, 2]), 7267 Int32Array.from([4, 2, 1, 1, 1, 2]), 7268 Int32Array.from([4, 2, 1, 2, 1, 1]), 7269 Int32Array.from([2, 1, 2, 1, 4, 1]), 7270 Int32Array.from([2, 1, 4, 1, 2, 1]), 7271 Int32Array.from([4, 1, 2, 1, 2, 1]), 7272 Int32Array.from([1, 1, 1, 1, 4, 3]), 7273 Int32Array.from([1, 1, 1, 3, 4, 1]), 7274 Int32Array.from([1, 3, 1, 1, 4, 1]), 7275 Int32Array.from([1, 1, 4, 1, 1, 3]), 7276 Int32Array.from([1, 1, 4, 3, 1, 1]), 7277 Int32Array.from([4, 1, 1, 1, 1, 3]), 7278 Int32Array.from([4, 1, 1, 3, 1, 1]), 7279 Int32Array.from([1, 1, 3, 1, 4, 1]), 7280 Int32Array.from([1, 1, 4, 1, 3, 1]), 7281 Int32Array.from([3, 1, 1, 1, 4, 1]), 7282 Int32Array.from([4, 1, 1, 1, 3, 1]), 7283 Int32Array.from([2, 1, 1, 4, 1, 2]), 7284 Int32Array.from([2, 1, 1, 2, 1, 4]), 7285 Int32Array.from([2, 1, 1, 2, 3, 2]), 7286 Int32Array.from([2, 3, 3, 1, 1, 1, 2]), 7287 ]; 7288 Code128Reader.MAX_AVG_VARIANCE = 0.25;
7289 Code128Reader.MAX_INDIVIDUAL_VARIANCE = 0.7; 7290 Code128Reader.CODE_SHIFT = 98; 7291 Code128Reader.CODE_CODE_C = 99; 7292 Code128Reader.CODE_CODE_B = 100; 7293 Code128Reader.CODE_CODE_A = 101; 7294 Code128Reader.CODE_FNC_1 = 102; 7295 Code128Reader.CODE_FNC_2 = 97; 7296 Code128Reader.CODE_FNC_3 = 96; 7297 Code128Reader.CODE_FNC_4_A = 101; 7298 Code128Reader.CODE_FNC_4_B = 100; 7299 Code128Reader.CODE_START_A = 103; 7300 Code128Reader.CODE_START_B = 104; 7301 Code128Reader.CODE_START_C = 105; 7302 Code128Reader.CODE_STOP = 106; 7303 7304 /* 7305 * Copyright 2008 ZXing authors 7306 * 7307 * Licensed under the Apache License, Version 2.0 (the "License"); 7308 * you may not use this file except in compliance with the License. 7309 * You may obtain a copy of the License at 7310 * 7311 * http://www.apache.org/licenses/LICENSE-2.0 7312 * 7313 * Unless required by applicable law or agreed to in writing, software 7314 * distributed under the License is distributed on an "AS IS" BASIS, 7315 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 7316 * See the License for the specific language governing permissions and 7317 * limitations under the License. 7318
vendor: 12,585 bytes, lines 7318-7599
7318*/ 7319 /** 7320 * <p>Decodes Code 39 barcodes. Supports "Full ASCII Code 39" if USE_CODE_39_EXTENDED_MODE is set.</p> 7321 * 7322 * @author Sean Owen 7323 * @see Code93Reader 7324 */ 7325 class Code39Reader extends OneDReader { 7326 /** 7327 * Creates a reader that assumes all encoded data is data, and does not treat the final 7328 * character as a check digit. It will not decoded "extended Code 39" sequences. 7329 */ 7330 // public Code39Reader() { 7331 // this(false); 7332 // } 7333 /** 7334 * Creates a reader that can be configured to check the last character as a check digit. 7335 * It will not decoded "extended Code 39" sequences. 7336 * 7337 * @param usingCheckDigit if true, treat the last data character as a check digit, not 7338 * data, and verify that the checksum passes. 7339 */ 7340 // public Code39Reader(boolean usingCheckDigit) { 7341 // this(usingCheckDigit, false); 7342 // } 7343 /** 7344 * Creates a reader that can be configured to check the last character as a check digit, 7345 * or optionally attempt to decode "extended Code 39" sequences that are used to encode 7346 * the full ASCII character set. 7347 * 7348 * @param usingCheckDigit if true, treat the last data character as a check digit, not 7349 * data, and verify that the checksum passes. 7350 * @param extendedMode if true, will attempt to decode extended Code 39 sequences in the 7351 * text. 7352 */ 7353 constructor(usingCheckDigit = false, extendedMode = false) { 7354 super(); 7355 this.usingCheckDigit = usingCheckDigit; 7356 this.extendedMode = extendedMode; 7357 this.decodeRowResult = ''; 7358 this.counters = new Int32Array(9); 7359 } 7360 decodeRow(rowNumber, row, hints) { 7361 let theCounters = this.counters; 7362 theCounters.fill(0); 7363 this.decodeRowResult = ''; 7364 let start = Code39Reader.findAsteriskPattern(row, theCounters); 7365 // Read off white space 7366 let nextStart = row.getNextSet(start[1]); 7367 let end = row.getSize(); 7368 let decodedChar; 7369 let lastStart; 7370 do { 7371 Code39Reader.recordPattern(row, nextStart, theCounters); 7372 let pattern = Code39Reader.toNarrowWidePattern(theCounters); 7373 if (pattern < 0) { 7374 throw new NotFoundException(); 7375 } 7376 decodedChar = Code39Reader.patternToChar(pattern); 7377 this.decodeRowResult += decodedChar; 7378 lastStart = nextStart; 7379 for (let counter of theCounters) { 7380 nextStart += counter; 7381 } 7382 // Read off white space 7383 nextStart = row.getNextSet(nextStart); 7384 } while (decodedChar !== '*'); 7385 this.decodeRowResult = this.decodeRowResult.substring(0, this.decodeRowResult.length - 1); // remove asterisk 7386 // Look for whitespace after pattern: 7387 let lastPatternSize = 0; 7388 for (let counter of theCounters) { 7389 lastPatternSize += counter; 7390 } 7391 let whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize; 7392 // If 50% of last pattern size, following last pattern, is not whitespace, fail 7393 // (but if it's whitespace to the very end of the image, that's OK) 7394 if (nextStart !== end && (whiteSpaceAfterEnd * 2) < lastPatternSize) { 7395 throw new NotFoundException(); 7396 } 7397 if (this.usingCheckDigit) { 7398 let max = this.decodeRowResult.length - 1; 7399 let total = 0; 7400 for (let i = 0; i < max; i++) { 7401 total += Code39Reader.ALPHABET_STRING.indexOf(this.decodeRowResult.charAt(i)); 7402 } 7403 if (this.decodeRowResult.charAt(max) !== Code39Reader.ALPHABET_STRING.charAt(total % 43)) { 7404 throw new ChecksumException(); 7405 } 7406 this.decodeRowResult = this.decodeRowResult.substring(0, max); 7407 } 7408 if (this.decodeRowResult.length === 0) { 7409 // false positive 7410 throw new NotFoundException(); 7411 } 7412 let resultString; 7413 if (this.extendedMode) { 7414 resultString = Code39Reader.decodeExtended(this.decodeRowResult); 7415 } 7416 else { 7417 resultString = this.decodeRowResult; 7418 } 7419 let left = (start[1] + start[0]) / 2.0; 7420 let right = lastStart + lastPatternSize / 2.0; 7421 return new Result$1(resultString, null, 0, [new ResultPoint(left, rowNumber), new ResultPoint(right, rowNumber)], BarcodeFormat$1.CODE_39, new Date().getTime()); 7422 } 7423 static findAsteriskPattern(row, counters) { 7424 let width = row.getSize(); 7425 let rowOffset = row.getNextSet(0); 7426 let counterPosition = 0; 7427 let patternStart = rowOffset; 7428 let isWhite = false; 7429 let patternLength = counters.length; 7430 for (let i = rowOffset; i < width; i++) { 7431 if (row.get(i) !== isWhite) { 7432 counters[counterPosition]++; 7433 } 7434 else { 7435 if (counterPosition === patternLength - 1) { 7436 // Look for whitespace before start pattern, >= 50% of width of start pattern 7437 if (this.toNarrowWidePattern(counters) === Code39Reader.ASTERISK_ENCODING && 7438 row.isRange(Math.max(0, patternStart - Math.floor((i - patternStart) / 2)), patternStart, false)) { 7439 return [patternStart, i]; 7440 } 7441 patternStart += counters[0] + counters[1]; 7442 counters.copyWithin(0, 2, 2 + counterPosition - 1); 7443 counters[counterPosition - 1] = 0; 7444 counters[counterPosition] = 0; 7445 counterPosition--; 7446 } 7447 else { 7448 counterPosition++; 7449 } 7450 counters[counterPosition] = 1; 7451 isWhite = !isWhite; 7452 } 7453 } 7454 throw new NotFoundException(); 7455 } 7456 // For efficiency, returns -1 on failure. Not throwing here saved as many as 700 exceptions 7457 // per image when using some of our blackbox images. 7458 static toNarrowWidePattern(counters) { 7459 let numCounters = counters.length; 7460 let maxNarrowCounter = 0; 7461 let wideCounters; 7462 do { 7463 let minCounter = 0x7fffffff; 7464 for (let counter of counters) { 7465 if (counter < minCounter && counter > maxNarrowCounter) { 7466 minCounter = counter; 7467 } 7468 } 7469 maxNarrowCounter = minCounter; 7470 wideCounters = 0; 7471 let totalWideCountersWidth = 0; 7472 let pattern = 0; 7473 for (let i = 0; i < numCounters; i++) { 7474 let counter = counters[i]; 7475 if (counter > maxNarrowCounter) { 7476 pattern |= 1 << (numCounters - 1 - i); 7477 wideCounters++; 7478 totalWideCountersWidth += counter; 7479 } 7480 } 7481 if (wideCounters === 3) { 7482 // Found 3 wide counters, but are they close enough in width? 7483 // We can perform a cheap, conservative check to see if any individual 7484 // counter is more than 1.5 times the average: 7485 for (let i = 0; i < numCounters && wideCounters > 0; i++) { 7486 let counter = counters[i]; 7487 if (counter > maxNarrowCounter) { 7488 wideCounters--; 7489 // totalWideCountersWidth = 3 * average, so this checks if counter >= 3/2 * average 7490 if ((counter * 2) >= totalWideCountersWidth) { 7491 return -1; 7492 } 7493 } 7494 } 7495 return pattern; 7496 } 7497 } while (wideCounters > 3); 7498 return -1; 7499 } 7500 static patternToChar(pattern) { 7501 for (let i = 0; i < Code39Reader.CHARACTER_ENCODINGS.length; i++) { 7502 if (Code39Reader.CHARACTER_ENCODINGS[i] === pattern) { 7503 return Code39Reader.ALPHABET_STRING.charAt(i); 7504 } 7505 } 7506 if (pattern === Code39Reader.ASTERISK_ENCODING) { 7507 return '*'; 7508 } 7509 throw new NotFoundException(); 7510 } 7511 static decodeExtended(encoded) { 7512 let length = encoded.length; 7513 let decoded = ''; 7514 for (let i = 0; i < length; i++) { 7515 let c = encoded.charAt(i); 7516 if (c === '+' || c === '$' || c === '%' || c === '/') { 7517 let next = encoded.charAt(i + 1); 7518 let decodedChar = '\0'; 7519 switch (c) { 7520 case '+': 7521 // +A to +Z map to a to z 7522 if (next >= 'A' && next <= 'Z') { 7523 decodedChar = String.fromCharCode(next.charCodeAt(0) + 32); 7524 } 7525 else { 7526 throw new FormatException(); 7527 } 7528 break; 7529 case '$': 7530 // $A to $Z map to control codes SH to SB 7531 if (next >= 'A' && next <= 'Z') { 7532 decodedChar = String.fromCharCode(next.charCodeAt(0) - 64); 7533 } 7534 else { 7535 throw new FormatException(); 7536 } 7537 break; 7538 case '%': 7539 // %A to %E map to control codes ESC to US 7540 if (next >= 'A' && next <= 'E') { 7541 decodedChar = String.fromCharCode(next.charCodeAt(0) - 38); 7542 } 7543 else if (next >= 'F' && next <= 'J') { 7544 decodedChar = String.fromCharCode(next.charCodeAt(0) - 11); 7545 } 7546 else if (next >= 'K' && next <= 'O') { 7547 decodedChar = String.fromCharCode(next.charCodeAt(0) + 16); 7548 } 7549 else if (next >= 'P' && next <= 'T') { 7550 decodedChar = String.fromCharCode(next.charCodeAt(0) + 43); 7551 } 7552 else if (next === 'U') { 7553 decodedChar = '\0'; 7554 } 7555 else if (next === 'V') { 7556 decodedChar = '@'; 7557 } 7558 else if (next === 'W') { 7559 decodedChar = '`'; 7560 } 7561 else if (next === 'X' || next === 'Y' || next === 'Z') { 7562 decodedChar = '\x7f'; 7563 } 7564 else { 7565 throw new FormatException(); 7566 } 7567 break; 7568 case '/': 7569 // /A to /O map to ! to , and /Z maps to : 7570 if (next >= 'A' && next <= 'O') { 7571 decodedChar = String.fromCharCode(next.charCodeAt(0) - 32); 7572 } 7573 else if (next === 'Z') { 7574 decodedChar = ':'; 7575 } 7576 else { 7577 throw new FormatException(); 7578 } 7579 break; 7580 } 7581 decoded += decodedChar; 7582 // bump up i again since we read two characters 7583 i++; 7584 } 7585 else { 7586 decoded += c; 7587 } 7588 } 7589 return decoded; 7590 } 7591 } 7592 Code39Reader.ALPHABET_STRING = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%'; 7593 /** 7594 * These represent the encodings of characters, as patterns of wide and narrow bars. 7595 * The 9 least-significant bits of each int correspond to the pattern of wide and narrow, 7596 * with 1s representing "wide" and 0s representing narrow. 7597 */ 7598 Code39Reader.CHARACTER_ENCODINGS = [ 7599 0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064,
7599 7600 0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, 7601 0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, 7602 0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0, 0x085, 0x184, 0x0C4, 0x0A8, 7603 0x0A2, 0x08A, 0x02A // /-% 7604 ]; 7605 Code39Reader.ASTERISK_ENCODING = 0x094; 7606 7607 /* 7608 * Copyright 2010 ZXing authors 7609 * 7610 * Licensed under the Apache License, Version 2.0 (the "License"); 7611 * you may not use this file except in compliance with the License. 7612 * You may obtain a copy of the License at 7613 * 7614 * http://www.apache.org/licenses/LICENSE-2.0 7615 * 7616 * Unless required by applicable law or agreed to in writing, softw
vendor: 10,679 bytes, lines 7616-7868
7616are 7617 * distributed under the License is distributed on an "AS IS" BASIS, 7618 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 7619 * See the License for the specific language governing permissions and 7620 * limitations under the License. 7621 */ 7622 /** 7623 * <p>Decodes Code 93 barcodes.</p> 7624 * 7625 * @author Sean Owen 7626 * @see Code39Reader 7627 */ 7628 class Code93Reader extends OneDReader { 7629 //public Code93Reader() { 7630 // decodeRowResult = new StringBuilder(20); 7631 // counters = new int[6]; 7632 //} 7633 constructor() { 7634 super(); 7635 this.decodeRowResult = ''; 7636 this.counters = new Int32Array(6); 7637 } 7638 decodeRow(rowNumber, row, hints) { 7639 let start = this.findAsteriskPattern(row); 7640 // Read off white space 7641 let nextStart = row.getNextSet(start[1]); 7642 let end = row.getSize(); 7643 let theCounters = this.counters; 7644 theCounters.fill(0); 7645 this.decodeRowResult = ''; 7646 let decodedChar; 7647 let lastStart; 7648 do { 7649 Code93Reader.recordPattern(row, nextStart, theCounters); 7650 let pattern = this.toPattern(theCounters); 7651 if (pattern < 0) { 7652 throw new NotFoundException(); 7653 } 7654 decodedChar = this.patternToChar(pattern); 7655 this.decodeRowResult += decodedChar; 7656 lastStart = nextStart; 7657 for (let counter of theCounters) { 7658 nextStart += counter; 7659 } 7660 // Read off white space 7661 nextStart = row.getNextSet(nextStart); 7662 } while (decodedChar !== '*'); 7663 this.decodeRowResult = this.decodeRowResult.substring(0, this.decodeRowResult.length - 1); // remove asterisk 7664 let lastPatternSize = 0; 7665 for (let counter of theCounters) { 7666 lastPatternSize += counter; 7667 } 7668 // Should be at least one more black module 7669 if (nextStart === end || !row.get(nextStart)) { 7670 throw new NotFoundException(); 7671 } 7672 if (this.decodeRowResult.length < 2) { 7673 // false positive -- need at least 2 checksum digits 7674 throw new NotFoundException(); 7675 } 7676 this.checkChecksums(this.decodeRowResult); 7677 // Remove checksum digits 7678 this.decodeRowResult = this.decodeRowResult.substring(0, this.decodeRowResult.length - 2); 7679 let resultString = this.decodeExtended(this.decodeRowResult); 7680 let left = (start[1] + start[0]) / 2.0; 7681 let right = lastStart + lastPatternSize / 2.0; 7682 return new Result$1(resultString, null, 0, [new ResultPoint(left, rowNumber), new ResultPoint(right, rowNumber)], BarcodeFormat$1.CODE_93, new Date().getTime()); 7683 } 7684 findAsteriskPattern(row) { 7685 let width = row.getSize(); 7686 let rowOffset = row.getNextSet(0); 7687 this.counters.fill(0); 7688 let theCounters = this.counters; 7689 let patternStart = rowOffset; 7690 let isWhite = false; 7691 let patternLength = theCounters.length; 7692 let counterPosition = 0; 7693 for (let i = rowOffset; i < width; i++) { 7694 if (row.get(i) !== isWhite) { 7695 theCounters[counterPosition]++; 7696 } 7697 else { 7698 if (counterPosition === patternLength - 1) { 7699 if (this.toPattern(theCounters) === Code93Reader.ASTERISK_ENCODING) { 7700 return new Int32Array([patternStart, i]); 7701 } 7702 patternStart += theCounters[0] + theCounters[1]; 7703 theCounters.copyWithin(0, 2, 2 + counterPosition - 1); 7704 theCounters[counterPosition - 1] = 0; 7705 theCounters[counterPosition] = 0; 7706 counterPosition--; 7707 } 7708 else { 7709 counterPosition++; 7710 } 7711 theCounters[counterPosition] = 1; 7712 isWhite = !isWhite; 7713 } 7714 } 7715 throw new NotFoundException; 7716 } 7717 toPattern(counters) { 7718 let sum = 0; 7719 for (const counter of counters) { 7720 sum += counter; 7721 } 7722 let pattern = 0; 7723 let max = counters.length; 7724 for (let i = 0; i < max; i++) { 7725 let scaled = Math.round(counters[i] * 9.0 / sum); 7726 if (scaled < 1 || scaled > 4) { 7727 return -1; 7728 } 7729 if ((i & 0x01) === 0) { 7730 for (let j = 0; j < scaled; j++) { 7731 pattern = (pattern << 1) | 0x01; 7732 } 7733 } 7734 else { 7735 pattern <<= scaled; 7736 } 7737 } 7738 return pattern; 7739 } 7740 patternToChar(pattern) { 7741 for (let i = 0; i < Code93Reader.CHARACTER_ENCODINGS.length; i++) { 7742 if (Code93Reader.CHARACTER_ENCODINGS[i] === pattern) { 7743 return Code93Reader.ALPHABET_STRING.charAt(i); 7744 } 7745 } 7746 throw new NotFoundException(); 7747 } 7748 decodeExtended(encoded) { 7749 let length = encoded.length; 7750 let decoded = ''; 7751 for (let i = 0; i < length; i++) { 7752 let c = encoded.charAt(i); 7753 if (c >= 'a' && c <= 'd') { 7754 if (i >= length - 1) { 7755 throw new FormatException(); 7756 } 7757 let next = encoded.charAt(i + 1); 7758 let decodedChar = '\0'; 7759 switch (c) { 7760 case 'd': 7761 // +A to +Z map to a to z 7762 if (next >= 'A' && next <= 'Z') { 7763 decodedChar = String.fromCharCode(next.charCodeAt(0) + 32); 7764 } 7765 else { 7766 throw new FormatException(); 7767 } 7768 break; 7769 case 'a': 7770 // $A to $Z map to control codes SH to SB 7771 if (next >= 'A' && next <= 'Z') { 7772 decodedChar = String.fromCharCode(next.charCodeAt(0) - 64); 7773 } 7774 else { 7775 throw new FormatException(); 7776 } 7777 break; 7778 case 'b': 7779 if (next >= 'A' && next <= 'E') { 7780 // %A to %E map to control codes ESC to USep 7781 decodedChar = String.fromCharCode(next.charCodeAt(0) - 38); 7782 } 7783 else if (next >= 'F' && next <= 'J') { 7784 // %F to %J map to ; < = > ? 7785 decodedChar = String.fromCharCode(next.charCodeAt(0) - 11); 7786 } 7787 else if (next >= 'K' && next <= 'O') { 7788 // %K to %O map to [ \ ] ^ _ 7789 decodedChar = String.fromCharCode(next.charCodeAt(0) + 16); 7790 } 7791 else if (next >= 'P' && next <= 'T') { 7792 // %P to %T map to { | } ~ DEL 7793 decodedChar = String.fromCharCode(next.charCodeAt(0) + 43); 7794 } 7795 else if (next === 'U') { 7796 // %U map to NUL 7797 decodedChar = '\0'; 7798 } 7799 else if (next === 'V') { 7800 // %V map to @ 7801 decodedChar = '@'; 7802 } 7803 else if (next === 'W') { 7804 // %W map to ` 7805 decodedChar = '`'; 7806 } 7807 else if (next >= 'X' && next <= 'Z') { 7808 // %X to %Z all map to DEL (127) 7809 decodedChar = String.fromCharCode(127); 7810 } 7811 else { 7812 throw new FormatException(); 7813 } 7814 break; 7815 case 'c': 7816 // /A to /O map to ! to , and /Z maps to : 7817 if (next >= 'A' && next <= 'O') { 7818 decodedChar = String.fromCharCode(next.charCodeAt(0) - 32); 7819 } 7820 else if (next === 'Z') { 7821 decodedChar = ':'; 7822 } 7823 else { 7824 throw new FormatException(); 7825 } 7826 break; 7827 } 7828 decoded += decodedChar; 7829 // bump up i again since we read two characters 7830 i++; 7831 } 7832 else { 7833 decoded += c; 7834 } 7835 } 7836 return decoded; 7837 } 7838 checkChecksums(result) { 7839 let length = result.length; 7840 this.checkOneChecksum(result, length - 2, 20); 7841 this.checkOneChecksum(result, length - 1, 15); 7842 } 7843 checkOneChecksum(result, checkPosition, weightMax) { 7844 let weight = 1; 7845 let total = 0; 7846 for (let i = checkPosition - 1; i >= 0; i--) { 7847 total += weight * Code93Reader.ALPHABET_STRING.indexOf(result.charAt(i)); 7848 if (++weight > weightMax) { 7849 weight = 1; 7850 } 7851 } 7852 if (result.charAt(checkPosition) !== Code93Reader.ALPHABET_STRING[total % 47]) { 7853 throw new ChecksumException; 7854 } 7855 } 7856 } 7857 // Note that 'abcd' are dummy characters in place of control characters. 7858 Code93Reader.ALPHABET_STRING = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%abcd*"; 7859 /** 7860 * These represent the encodings of characters, as patterns of wide and narrow bars. 7861 * The 9 least-significant bits of each int correspond to the pattern of wide and narrow. 7862 */ 7863 Code93Reader.CHARACTER_ENCODINGS = [ 7864 0x114, 0x148, 0x144, 0x142, 0x128, 0x124, 0x122, 0x150, 0x112, 0x10A, 7865 0x1A8, 0x1A4, 0x1A2, 0x194, 0x192, 0x18A, 0x168, 0x164, 0x162, 0x134, 7866 0x11A, 0x158, 0x14C, 0x146, 0x12C, 0x116, 0x1B4, 0x1B2, 0x1AC, 0x1A6, 7867 0x196, 0x19A, 0x16C, 0x166, 0x136, 0x13A, 7868 0x12E, 0x1D4, 0x1D2, 0x1CA, 0x16E, 0x176, 0x1AE,
7869 0x126, 0x1DA, 0x1D6, 0x132, 0x15E, 7870 ]; 7871 Code93Reader.ASTERISK_ENCODING = Code93Reader.CHARACTER_ENCODINGS[47]; 7872 7873 /* 7874 * Copyright 2008 ZXing authors 7875 * 7876 * Licensed under the Apache License, Version 2.0 (the "License"); 7877 * you may not use this file except in compliance with the License. 7878 * You may obtain a copy of the License at 7879 * 7880 * http://www.apache.org/licenses/LICENSE-2.0 7881 * 7882 * Unless required by applicable law or agreed to in writing, software 7883 * distributed under the License is distributed on an "AS IS" BASIS, 7884 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 7885 * See the License for the specific language governing permissions and 7886 * limitations under the License. 7887
vendor: 11,661 bytes, lines 7887-8162
7887*/ 7888 /** 7889 * <p>Decodes ITF barcodes.</p> 7890 * 7891 * @author Tjieco 7892 */ 7893 class ITFReader extends OneDReader { 7894 constructor() { 7895 // private static W = 3; // Pixel width of a 3x wide line 7896 // private static w = 2; // Pixel width of a 2x wide line 7897 // private static N = 1; // Pixed width of a narrow line 7898 super(...arguments); 7899 // Stores the actual narrow line width of the image being decoded. 7900 this.narrowLineWidth = -1; 7901 } 7902 // See ITFWriter.PATTERNS 7903 /* 7904 7905 /!** 7906 * Patterns of Wide / Narrow lines to indicate each digit 7907 *!/ 7908 */ 7909 decodeRow(rowNumber, row, hints) { 7910 // Find out where the Middle section (payload) starts & ends 7911 let startRange = this.decodeStart(row); 7912 let endRange = this.decodeEnd(row); 7913 let result = new StringBuilder(); 7914 ITFReader.decodeMiddle(row, startRange[1], endRange[0], result); 7915 let resultString = result.toString(); 7916 let allowedLengths = null; 7917 if (hints != null) { 7918 allowedLengths = hints.get(DecodeHintType$1.ALLOWED_LENGTHS); 7919 } 7920 if (allowedLengths == null) { 7921 allowedLengths = ITFReader.DEFAULT_ALLOWED_LENGTHS; 7922 } 7923 // To avoid false positives with 2D barcodes (and other patterns), make 7924 // an assumption that the decoded string must be a 'standard' length if it's short 7925 let length = resultString.length; 7926 let lengthOK = false; 7927 let maxAllowedLength = 0; 7928 for (let value of allowedLengths) { 7929 if (length === value) { 7930 lengthOK = true; 7931 break; 7932 } 7933 if (value > maxAllowedLength) { 7934 maxAllowedLength = value; 7935 } 7936 } 7937 if (!lengthOK && length > maxAllowedLength) { 7938 lengthOK = true; 7939 } 7940 if (!lengthOK) { 7941 throw new FormatException(); 7942 } 7943 const points = [new ResultPoint(startRange[1], rowNumber), new ResultPoint(endRange[0], rowNumber)]; 7944 let resultReturn = new Result$1(resultString, null, // no natural byte representation for these barcodes 7945 0, points, BarcodeFormat$1.ITF, new Date().getTime()); 7946 return resultReturn; 7947 } 7948 /* 7949 /!** 7950 * @param row row of black/white values to search 7951 * @param payloadStart offset of start pattern 7952 * @param resultString {@link StringBuilder} to append decoded chars to 7953 * @throws NotFoundException if decoding could not complete successfully 7954 *!/*/ 7955 static decodeMiddle(row, payloadStart, payloadEnd, resultString) { 7956 // Digits are interleaved in pairs - 5 black lines for one digit, and the 7957 // 5 7958 // interleaved white lines for the second digit. 7959 // Therefore, need to scan 10 lines and then 7960 // split these into two arrays 7961 let counterDigitPair = new Int32Array(10); // 10 7962 let counterBlack = new Int32Array(5); // 5 7963 let counterWhite = new Int32Array(5); // 5 7964 counterDigitPair.fill(0); 7965 counterBlack.fill(0); 7966 counterWhite.fill(0); 7967 while (payloadStart < payloadEnd) { 7968 // Get 10 runs of black/white. 7969 OneDReader.recordPattern(row, payloadStart, counterDigitPair); 7970 // Split them into each array 7971 for (let k = 0; k < 5; k++) { 7972 let twoK = 2 * k; 7973 counterBlack[k] = counterDigitPair[twoK]; 7974 counterWhite[k] = counterDigitPair[twoK + 1]; 7975 } 7976 let bestMatch = ITFReader.decodeDigit(counterBlack); 7977 resultString.append(bestMatch.toString()); 7978 bestMatch = this.decodeDigit(counterWhite); 7979 resultString.append(bestMatch.toString()); 7980 counterDigitPair.forEach(function (counterDigit) { 7981 payloadStart += counterDigit; 7982 }); 7983 } 7984 } 7985 /*/!** 7986 * Identify where the start of the middle / payload section starts. 7987 * 7988 * @param row row of black/white values to search 7989 * @return Array, containing index of start of 'start block' and end of 7990 * 'start block' 7991 *!/*/ 7992 decodeStart(row) { 7993 let endStart = ITFReader.skipWhiteSpace(row); 7994 let startPattern = ITFReader.findGuardPattern(row, endStart, ITFReader.START_PATTERN); 7995 // Determine the width of a narrow line in pixels. We can do this by 7996 // getting the width of the start pattern and dividing by 4 because its 7997 // made up of 4 narrow lines. 7998 this.narrowLineWidth = (startPattern[1] - startPattern[0]) / 4; 7999 this.validateQuietZone(row, startPattern[0]); 8000 return startPattern; 8001 } 8002 /*/!** 8003 * The start & end patterns must be pre/post fixed by a quiet zone. This 8004 * zone must be at least 10 times the width of a narrow line. Scan back until 8005 * we either get to the start of the barcode or match the necessary number of 8006 * quiet zone pixels. 8007 * 8008 * Note: Its assumed the row is reversed when using this method to find 8009 * quiet zone after the end pattern. 8010 * 8011 * ref: http://www.barcode-1.net/i25code.html 8012 * 8013 * @param row bit array representing the scanned barcode. 8014 * @param startPattern index into row of the start or end pattern. 8015 * @throws NotFoundException if the quiet zone cannot be found 8016 *!/*/ 8017 validateQuietZone(row, startPattern) { 8018 let quietCount = this.narrowLineWidth * 10; // expect to find this many pixels of quiet zone 8019 // if there are not so many pixel at all let's try as many as possible 8020 quietCount = quietCount < startPattern ? quietCount : startPattern; 8021 for (let i = startPattern - 1; quietCount > 0 && i >= 0; i--) { 8022 if (row.get(i)) { 8023 break; 8024 } 8025 quietCount--; 8026 } 8027 if (quietCount !== 0) { 8028 // Unable to find the necessary number of quiet zone pixels. 8029 throw new NotFoundException(); 8030 } 8031 } 8032 /* 8033 /!** 8034 * Skip all whitespace until we get to the first black line. 8035 * 8036 * @param row row of black/white values to search 8037 * @return index of the first black line. 8038 * @throws NotFoundException Throws exception if no black lines are found in the row 8039 *!/*/ 8040 static skipWhiteSpace(row) { 8041 const width = row.getSize(); 8042 const endStart = row.getNextSet(0); 8043 if (endStart === width) { 8044 throw new NotFoundException(); 8045 } 8046 return endStart; 8047 } 8048 /*/!** 8049 * Identify where the end of the middle / payload section ends. 8050 * 8051 * @param row row of black/white values to search 8052 * @return Array, containing index of start of 'end block' and end of 'end 8053 * block' 8054 *!/*/ 8055 decodeEnd(row) { 8056 // For convenience, reverse the row and then 8057 // search from 'the start' for the end block 8058 row.reverse(); 8059 try { 8060 let endStart = ITFReader.skipWhiteSpace(row); 8061 let endPattern; 8062 try { 8063 endPattern = ITFReader.findGuardPattern(row, endStart, ITFReader.END_PATTERN_REVERSED[0]); 8064 } 8065 catch (error) { 8066 if (error instanceof NotFoundException) { 8067 endPattern = ITFReader.findGuardPattern(row, endStart, ITFReader.END_PATTERN_REVERSED[1]); 8068 } 8069 } 8070 // The start & end patterns must be pre/post fixed by a quiet zone. This 8071 // zone must be at least 10 times the width of a narrow line. 8072 // ref: http://www.barcode-1.net/i25code.html 8073 this.validateQuietZone(row, endPattern[0]); 8074 // Now recalculate the indices of where the 'endblock' starts & stops to 8075 // accommodate 8076 // the reversed nature of the search 8077 let temp = endPattern[0]; 8078 endPattern[0] = row.getSize() - endPattern[1]; 8079 endPattern[1] = row.getSize() - temp; 8080 return endPattern; 8081 } 8082 finally { 8083 // Put the row back the right way. 8084 row.reverse(); 8085 } 8086 } 8087 /* 8088 /!** 8089 * @param row row of black/white values to search 8090 * @param rowOffset position to start search 8091 * @param pattern pattern of counts of number of black and white pixels that are 8092 * being searched for as a pattern 8093 * @return start/end horizontal offset of guard pattern, as an array of two 8094 * ints 8095 * @throws NotFoundException if pattern is not found 8096 *!/*/ 8097 static findGuardPattern(row, rowOffset, pattern) { 8098 let patternLength = pattern.length; 8099 let counters = new Int32Array(patternLength); 8100 let width = row.getSize(); 8101 let isWhite = false; 8102 let counterPosition = 0; 8103 let patternStart = rowOffset; 8104 counters.fill(0); 8105 for (let x = rowOffset; x < width; x++) { 8106 if (row.get(x) !== isWhite) { 8107 counters[counterPosition]++; 8108 } 8109 else { 8110 if (counterPosition === patternLength - 1) { 8111 if (OneDReader.patternMatchVariance(counters, pattern, ITFReader.MAX_INDIVIDUAL_VARIANCE) < ITFReader.MAX_AVG_VARIANCE) { 8112 return [patternStart, x]; 8113 } 8114 patternStart += counters[0] + counters[1]; 8115 System.arraycopy(counters, 2, counters, 0, counterPosition - 1); 8116 counters[counterPosition - 1] = 0; 8117 counters[counterPosition] = 0; 8118 counterPosition--; 8119 } 8120 else { 8121 counterPosition++; 8122 } 8123 counters[counterPosition] = 1; 8124 isWhite = !isWhite; 8125 } 8126 } 8127 throw new NotFoundException(); 8128 } 8129 /*/!** 8130 * Attempts to decode a sequence of ITF black/white lines into single 8131 * digit. 8132 * 8133 * @param counters the counts of runs of observed black/white/black/... values 8134 * @return The decoded digit 8135 * @throws NotFoundException if digit cannot be decoded 8136 *!/*/ 8137 static decodeDigit(counters) { 8138 let bestVariance = ITFReader.MAX_AVG_VARIANCE; // worst variance we'll accept 8139 let bestMatch = -1; 8140 let max = ITFReader.PATTERNS.length; 8141 for (let i = 0; i < max; i++) { 8142 let pattern = ITFReader.PATTERNS[i]; 8143 let variance = OneDReader.patternMatchVariance(counters, pattern, ITFReader.MAX_INDIVIDUAL_VARIANCE); 8144 if (variance < bestVariance) { 8145 bestVariance = variance; 8146 bestMatch = i; 8147 } 8148 else if (variance === bestVariance) { 8149 // if we find a second 'best match' with the same variance, we can not reliably report to have a suitable match 8150 bestMatch = -1; 8151 } 8152 } 8153 if (bestMatch >= 0) { 8154 return bestMatch % 10; 8155 } 8156 else { 8157 throw new NotFoundException(); 8158 } 8159 } 8160 } 8161 ITFReader.PATTERNS = [ 8162 Int32Array.from([1, 1, 2, 2, 1]),
8162 8163 Int32Array.from([2, 1, 1, 1, 2]), 8164 Int32Array.from([1, 2, 1, 1, 2]), 8165 Int32Array.from([2, 2, 1, 1, 1]), 8166 Int32Array.from([1, 1, 2, 1, 2]), 8167 Int32Array.from([2, 1, 2, 1, 1]), 8168 Int32Array.from([1, 2, 2, 1, 1]), 8169 Int32Array.from([1, 1, 1, 2, 2]), 8170 Int32Array.from([2, 1, 1, 2, 1]), 8171 Int32Array.from([1, 2, 1, 2, 1]), 8172 Int32Array.from([1, 1, 3, 3, 1]), 8173 Int32Array.from([3, 1, 1, 1, 3]), 8174 Int32Array.from([1, 3, 1, 1, 3]), 8175 Int32Array.from([3, 3, 1, 1, 1]), 8176 Int32Array.from([1, 1, 3, 1, 3]), 8177 Int32Array.from([3, 1, 3, 1, 1]), 8178 Int32Array.from([1, 3, 3, 1, 1]), 8179 Int32Array.from([1, 1, 1, 3, 3]), 8180 Int32Array.from([3, 1, 1, 3, 1]), 8181 Int32Array.from([1, 3, 1, 3, 1]) // 9 8182 ]; 8183 ITFReader.MAX_AVG_VARIANCE = 0.38; 8184 ITFReader.MAX_INDIVIDUAL_VARIANCE = 0.5; 8185 /* /!** Valid ITF lengths. Anything longer than the largest value is also allowed. *!/*/ 8186 ITFReader.DEFAULT_ALLOWED_LENGTHS = [6, 8, 10, 12, 14]; 8187 /*/!** 8188 * Start/end guard pattern. 8189 * 8190 * Note: The end pattern is reversed because the row is reversed before 8191 * searching for the END_PATTERN 8192 *!/*/ 8193 ITFReader.START_PATTERN = Int32Array.from([1, 1, 1, 1]); 8194 ITFReader.END_PATTERN_REVERSED = [ 8195 Int32Array.from([1, 1, 2]),
vendor: 7,622 bytes, lines 8195-8379
8195 8196 Int32Array.from([1, 1, 3]) // 3x 8197 ]; 8198 8199 /* 8200 * Copyright 2008 ZXing authors 8201 * 8202 * Licensed under the Apache License, Version 2.0 (the "License"); 8203 * you may not use this file except in compliance with the License. 8204 * You may obtain a copy of the License at 8205 * 8206 * http://www.apache.org/licenses/LICENSE-2.0 8207 * 8208 * Unless required by applicable law or agreed to in writing, software 8209 * distributed under the License is distributed on an "AS IS" BASIS, 8210 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8211 * See the License for the specific language governing permissions and 8212 * limitations under the License. 8213 */ 8214 /** 8215 * <p>Encapsulates functionality and implementation that is common to UPC and EAN families 8216 * of one-dimensional barcodes.</p> 8217 * 8218 * @author [email protected] (Daniel Switkin) 8219 * @author Sean Owen 8220 * @author [email protected] (Alasdair Mackintosh) 8221 */ 8222 class AbstractUPCEANReader extends OneDReader { 8223 constructor() { 8224 super(...arguments); 8225 this.decodeRowStringBuffer = ''; 8226 } 8227 // private final UPCEANExtensionSupport extensionReader; 8228 // private final EANManufacturerOrgSupport eanManSupport; 8229 /* 8230 protected UPCEANReader() { 8231 decodeRowStringBuffer = new StringBuilder(20); 8232 extensionReader = new UPCEANExtensionSupport(); 8233 eanManSupport = new EANManufacturerOrgSupport(); 8234 } 8235 */ 8236 static findStartGuardPattern(row) { 8237 let foundStart = false; 8238 let startRange; 8239 let nextStart = 0; 8240 let counters = Int32Array.from([0, 0, 0]); 8241 while (!foundStart) { 8242 counters = Int32Array.from([0, 0, 0]); 8243 startRange = AbstractUPCEANReader.findGuardPattern(row, nextStart, false, this.START_END_PATTERN, counters); 8244 let start = startRange[0]; 8245 nextStart = startRange[1]; 8246 let quietStart = start - (nextStart - start); 8247 if (quietStart >= 0) { 8248 foundStart = row.isRange(quietStart, start, false); 8249 } 8250 } 8251 return startRange; 8252 } 8253 static checkChecksum(s) { 8254 return AbstractUPCEANReader.checkStandardUPCEANChecksum(s); 8255 } 8256 static checkStandardUPCEANChecksum(s) { 8257 let length = s.length; 8258 if (length === 0) 8259 return false; 8260 let check = parseInt(s.charAt(length - 1), 10); 8261 return AbstractUPCEANReader.getStandardUPCEANChecksum(s.substring(0, length - 1)) === check; 8262 } 8263 static getStandardUPCEANChecksum(s) { 8264 let length = s.length; 8265 let sum = 0; 8266 for (let i = length - 1; i >= 0; i -= 2) { 8267 let digit = s.charAt(i).charCodeAt(0) - '0'.charCodeAt(0); 8268 if (digit < 0 || digit > 9) { 8269 throw new FormatException(); 8270 } 8271 sum += digit; 8272 } 8273 sum *= 3; 8274 for (let i = length - 2; i >= 0; i -= 2) { 8275 let digit = s.charAt(i).charCodeAt(0) - '0'.charCodeAt(0); 8276 if (digit < 0 || digit > 9) { 8277 throw new FormatException(); 8278 } 8279 sum += digit; 8280 } 8281 return (1000 - sum) % 10; 8282 } 8283 static decodeEnd(row, endStart) { 8284 return AbstractUPCEANReader.findGuardPattern(row, endStart, false, AbstractUPCEANReader.START_END_PATTERN, new Int32Array(AbstractUPCEANReader.START_END_PATTERN.length).fill(0)); 8285 } 8286 /** 8287 * @throws NotFoundException 8288 */ 8289 static findGuardPatternWithoutCounters(row, rowOffset, whiteFirst, pattern) { 8290 return this.findGuardPattern(row, rowOffset, whiteFirst, pattern, new Int32Array(pattern.length)); 8291 } 8292 /** 8293 * @param row row of black/white values to search 8294 * @param rowOffset position to start search 8295 * @param whiteFirst if true, indicates that the pattern specifies white/black/white/... 8296 * pixel counts, otherwise, it is interpreted as black/white/black/... 8297 * @param pattern pattern of counts of number of black and white pixels that are being 8298 * searched for as a pattern 8299 * @param counters array of counters, as long as pattern, to re-use 8300 * @return start/end horizontal offset of guard pattern, as an array of two ints 8301 * @throws NotFoundException if pattern is not found 8302 */ 8303 static findGuardPattern(row, rowOffset, whiteFirst, pattern, counters) { 8304 let width = row.getSize(); 8305 rowOffset = whiteFirst ? row.getNextUnset(rowOffset) : row.getNextSet(rowOffset); 8306 let counterPosition = 0; 8307 let patternStart = rowOffset; 8308 let patternLength = pattern.length; 8309 let isWhite = whiteFirst; 8310 for (let x = rowOffset; x < width; x++) { 8311 if (row.get(x) !== isWhite) { 8312 counters[counterPosition]++; 8313 } 8314 else { 8315 if (counterPosition === patternLength - 1) { 8316 if (OneDReader.patternMatchVariance(counters, pattern, AbstractUPCEANReader.MAX_INDIVIDUAL_VARIANCE) < AbstractUPCEANReader.MAX_AVG_VARIANCE) { 8317 return Int32Array.from([patternStart, x]); 8318 } 8319 patternStart += counters[0] + counters[1]; 8320 let slice = counters.slice(2, counters.length); 8321 for (let i = 0; i < counterPosition - 1; i++) { 8322 counters[i] = slice[i]; 8323 } 8324 counters[counterPosition - 1] = 0; 8325 counters[counterPosition] = 0; 8326 counterPosition--; 8327 } 8328 else { 8329 counterPosition++; 8330 } 8331 counters[counterPosition] = 1; 8332 isWhite = !isWhite; 8333 } 8334 } 8335 throw new NotFoundException(); 8336 } 8337 static decodeDigit(row, counters, rowOffset, patterns) { 8338 this.recordPattern(row, rowOffset, counters); 8339 let bestVariance = this.MAX_AVG_VARIANCE; 8340 let bestMatch = -1; 8341 let max = patterns.length; 8342 for (let i = 0; i < max; i++) { 8343 let pattern = patterns[i]; 8344 let variance = OneDReader.patternMatchVariance(counters, pattern, AbstractUPCEANReader.MAX_INDIVIDUAL_VARIANCE); 8345 if (variance < bestVariance) { 8346 bestVariance = variance; 8347 bestMatch = i; 8348 } 8349 } 8350 if (bestMatch >= 0) { 8351 return bestMatch; 8352 } 8353 else { 8354 throw new NotFoundException(); 8355 } 8356 } 8357 } 8358 // These two values are critical for determining how permissive the decoding will be. 8359 // We've arrived at these values through a lot of trial and error. Setting them any higher 8360 // lets false positives creep in quickly. 8361 AbstractUPCEANReader.MAX_AVG_VARIANCE = 0.48; 8362 AbstractUPCEANReader.MAX_INDIVIDUAL_VARIANCE = 0.7; 8363 /** 8364 * Start/end guard pattern. 8365 */ 8366 AbstractUPCEANReader.START_END_PATTERN = Int32Array.from([1, 1, 1]); 8367 /** 8368 * Pattern marking the middle of a UPC/EAN pattern, separating the two halves. 8369 */ 8370 AbstractUPCEANReader.MIDDLE_PATTERN = Int32Array.from([1, 1, 1, 1, 1]); 8371 /** 8372 * end guard pattern. 8373 */ 8374 AbstractUPCEANReader.END_PATTERN = Int32Array.from([1, 1, 1, 1, 1, 1]); 8375 /** 8376 * "Odd", or "L" patterns used to encode UPC/EAN digits. 8377 */ 8378 AbstractUPCEANReader.L_PATTERNS = [ 8379 Int32Array.from([3, 2, 1, 1]),
8379 8380 Int32Array.from([2, 2, 2, 1]), 8381 Int32Array.from([2, 1, 2, 2]), 8382 Int32Array.from([1, 4, 1, 1]), 8383 Int32Array.from([1, 1, 3, 2]), 8384 Int32Array.from([1, 2, 3, 1]), 8385 Int32Array.from([1, 1, 1, 4]), 8386 Int32Array.from([1, 3, 1, 2]), 8387 Int32Array.from([1, 2, 1, 3]), 8388 Int32Array.from([3, 1, 1, 2]),
vendor: 22,263 bytes, lines 8388-8921
8388 8389 ]; 8390 8391 /* 8392 * Copyright (C) 2010 ZXing authors 8393 * 8394 * Licensed under the Apache License, Version 2.0 (the "License"); 8395 * you may not use this file except in compliance with the License. 8396 * You may obtain a copy of the License at 8397 * 8398 * http://www.apache.org/licenses/LICENSE-2.0 8399 * 8400 * Unless required by applicable law or agreed to in writing, software 8401 * distributed under the License is distributed on an "AS IS" BASIS, 8402 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8403 * See the License for the specific language governing permissions and 8404 * limitations under the License. 8405 */ 8406 /** 8407 * @see UPCEANExtension2Support 8408 */ 8409 class UPCEANExtension5Support { 8410 constructor() { 8411 this.CHECK_DIGIT_ENCODINGS = [0x18, 0x14, 0x12, 0x11, 0x0C, 0x06, 0x03, 0x0A, 0x09, 0x05]; 8412 this.decodeMiddleCounters = Int32Array.from([0, 0, 0, 0]); 8413 this.decodeRowStringBuffer = ''; 8414 } 8415 decodeRow(rowNumber, row, extensionStartRange) { 8416 let result = this.decodeRowStringBuffer; 8417 let end = this.decodeMiddle(row, extensionStartRange, result); 8418 let resultString = result.toString(); 8419 let extensionData = UPCEANExtension5Support.parseExtensionString(resultString); 8420 let resultPoints = [ 8421 new ResultPoint((extensionStartRange[0] + extensionStartRange[1]) / 2.0, rowNumber), 8422 new ResultPoint(end, rowNumber) 8423 ]; 8424 let extensionResult = new Result$1(resultString, null, 0, resultPoints, BarcodeFormat$1.UPC_EAN_EXTENSION, new Date().getTime()); 8425 if (extensionData != null) { 8426 extensionResult.putAllMetadata(extensionData); 8427 } 8428 return extensionResult; 8429 } 8430 decodeMiddle(row, startRange, resultString) { 8431 let counters = this.decodeMiddleCounters; 8432 counters[0] = 0; 8433 counters[1] = 0; 8434 counters[2] = 0; 8435 counters[3] = 0; 8436 let end = row.getSize(); 8437 let rowOffset = startRange[1]; 8438 let lgPatternFound = 0; 8439 for (let x = 0; x < 5 && rowOffset < end; x++) { 8440 let bestMatch = AbstractUPCEANReader.decodeDigit(row, counters, rowOffset, AbstractUPCEANReader.L_AND_G_PATTERNS); 8441 resultString += String.fromCharCode(('0'.charCodeAt(0) + bestMatch % 10)); 8442 for (let counter of counters) { 8443 rowOffset += counter; 8444 } 8445 if (bestMatch >= 10) { 8446 lgPatternFound |= 1 << (4 - x); 8447 } 8448 if (x !== 4) { 8449 // Read off separator if not last 8450 rowOffset = row.getNextSet(rowOffset); 8451 rowOffset = row.getNextUnset(rowOffset); 8452 } 8453 } 8454 if (resultString.length !== 5) { 8455 throw new NotFoundException(); 8456 } 8457 let checkDigit = this.determineCheckDigit(lgPatternFound); 8458 if (UPCEANExtension5Support.extensionChecksum(resultString.toString()) !== checkDigit) { 8459 throw new NotFoundException(); 8460 } 8461 return rowOffset; 8462 } 8463 static extensionChecksum(s) { 8464 let length = s.length; 8465 let sum = 0; 8466 for (let i = length - 2; i >= 0; i -= 2) { 8467 sum += s.charAt(i).charCodeAt(0) - '0'.charCodeAt(0); 8468 } 8469 sum *= 3; 8470 for (let i = length - 1; i >= 0; i -= 2) { 8471 sum += s.charAt(i).charCodeAt(0) - '0'.charCodeAt(0); 8472 } 8473 sum *= 3; 8474 return sum % 10; 8475 } 8476 determineCheckDigit(lgPatternFound) { 8477 for (let d = 0; d < 10; d++) { 8478 if (lgPatternFound === this.CHECK_DIGIT_ENCODINGS[d]) { 8479 return d; 8480 } 8481 } 8482 throw new NotFoundException(); 8483 } 8484 static parseExtensionString(raw) { 8485 if (raw.length !== 5) { 8486 return null; 8487 } 8488 let value = UPCEANExtension5Support.parseExtension5String(raw); 8489 if (value == null) { 8490 return null; 8491 } 8492 return new Map([[ResultMetadataType$1.SUGGESTED_PRICE, value]]); 8493 } 8494 static parseExtension5String(raw) { 8495 let currency; 8496 switch (raw.charAt(0)) { 8497 case '0': 8498 currency = '£'; 8499 break; 8500 case '5': 8501 currency = '$'; 8502 break; 8503 case '9': 8504 // Reference: http://www.jollytech.com 8505 switch (raw) { 8506 case '90000': 8507 // No suggested retail price 8508 return null; 8509 case '99991': 8510 // Complementary 8511 return '0.00'; 8512 case '99990': 8513 return 'Used'; 8514 } 8515 // Otherwise... unknown currency? 8516 currency = ''; 8517 break; 8518 default: 8519 currency = ''; 8520 break; 8521 } 8522 let rawAmount = parseInt(raw.substring(1)); 8523 let unitsString = (rawAmount / 100).toString(); 8524 let hundredths = rawAmount % 100; 8525 let hundredthsString = hundredths < 10 ? '0' + hundredths : hundredths.toString(); // fixme 8526 return currency + unitsString + '.' + hundredthsString; 8527 } 8528 } 8529 8530 /* 8531 * Copyright (C) 2012 ZXing authors 8532 * 8533 * Licensed under the Apache License, Version 2.0 (the "License"); 8534 * you may not use this file except in compliance with the License. 8535 * You may obtain a copy of the License at 8536 * 8537 * http://www.apache.org/licenses/LICENSE-2.0 8538 * 8539 * Unless required by applicable law or agreed to in writing, software 8540 * distributed under the License is distributed on an "AS IS" BASIS, 8541 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8542 * See the License for the specific language governing permissions and 8543 * limitations under the License. 8544 */ 8545 /** 8546 * @see UPCEANExtension5Support 8547 */ 8548 class UPCEANExtension2Support { 8549 constructor() { 8550 this.decodeMiddleCounters = Int32Array.from([0, 0, 0, 0]); 8551 this.decodeRowStringBuffer = ''; 8552 } 8553 decodeRow(rowNumber, row, extensionStartRange) { 8554 let result = this.decodeRowStringBuffer; 8555 let end = this.decodeMiddle(row, extensionStartRange, result); 8556 let resultString = result.toString(); 8557 let extensionData = UPCEANExtension2Support.parseExtensionString(resultString); 8558 let resultPoints = [ 8559 new ResultPoint((extensionStartRange[0] + extensionStartRange[1]) / 2.0, rowNumber), 8560 new ResultPoint(end, rowNumber) 8561 ]; 8562 let extensionResult = new Result$1(resultString, null, 0, resultPoints, BarcodeFormat$1.UPC_EAN_EXTENSION, new Date().getTime()); 8563 if (extensionData != null) { 8564 extensionResult.putAllMetadata(extensionData); 8565 } 8566 return extensionResult; 8567 } 8568 decodeMiddle(row, startRange, resultString) { 8569 let counters = this.decodeMiddleCounters; 8570 counters[0] = 0; 8571 counters[1] = 0; 8572 counters[2] = 0; 8573 counters[3] = 0; 8574 let end = row.getSize(); 8575 let rowOffset = startRange[1]; 8576 let checkParity = 0; 8577 for (let x = 0; x < 2 && rowOffset < end; x++) { 8578 let bestMatch = AbstractUPCEANReader.decodeDigit(row, counters, rowOffset, AbstractUPCEANReader.L_AND_G_PATTERNS); 8579 resultString += String.fromCharCode(('0'.charCodeAt(0) + bestMatch % 10)); 8580 for (let counter of counters) { 8581 rowOffset += counter; 8582 } 8583 if (bestMatch >= 10) { 8584 checkParity |= 1 << (1 - x); 8585 } 8586 if (x !== 1) { 8587 // Read off separator if not last 8588 rowOffset = row.getNextSet(rowOffset); 8589 rowOffset = row.getNextUnset(rowOffset); 8590 } 8591 } 8592 if (resultString.length !== 2) { 8593 throw new NotFoundException(); 8594 } 8595 if (parseInt(resultString.toString()) % 4 !== checkParity) { 8596 throw new NotFoundException(); 8597 } 8598 return rowOffset; 8599 } 8600 static parseExtensionString(raw) { 8601 if (raw.length !== 2) { 8602 return null; 8603 } 8604 return new Map([[ResultMetadataType$1.ISSUE_NUMBER, parseInt(raw)]]); 8605 } 8606 } 8607 8608 /* 8609 * Copyright (C) 2010 ZXing authors 8610 * 8611 * Licensed under the Apache License, Version 2.0 (the "License"); 8612 * you may not use this file except in compliance with the License. 8613 * You may obtain a copy of the License at 8614 * 8615 * http://www.apache.org/licenses/LICENSE-2.0 8616 * 8617 * Unless required by applicable law or agreed to in writing, software 8618 * distributed under the License is distributed on an "AS IS" BASIS, 8619 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8620 * See the License for the specific language governing permissions and 8621 * limitations under the License. 8622 */ 8623 class UPCEANExtensionSupport { 8624 static decodeRow(rowNumber, row, rowOffset) { 8625 let extensionStartRange = AbstractUPCEANReader.findGuardPattern(row, rowOffset, false, this.EXTENSION_START_PATTERN, new Int32Array(this.EXTENSION_START_PATTERN.length).fill(0)); 8626 try { 8627 // return null; 8628 let fiveSupport = new UPCEANExtension5Support(); 8629 return fiveSupport.decodeRow(rowNumber, row, extensionStartRange); 8630 } 8631 catch (err) { 8632 // return null; 8633 let twoSupport = new UPCEANExtension2Support(); 8634 return twoSupport.decodeRow(rowNumber, row, extensionStartRange); 8635 } 8636 } 8637 } 8638 UPCEANExtensionSupport.EXTENSION_START_PATTERN = Int32Array.from([1, 1, 2]); 8639 8640 /* 8641 * Copyright 2008 ZXing authors 8642 * 8643 * Licensed under the Apache License, Version 2.0 (the "License"); 8644 * you may not use this file except in compliance with the License. 8645 * You may obtain a copy of the License at 8646 * 8647 * http://www.apache.org/licenses/LICENSE-2.0 8648 * 8649 * Unless required by applicable law or agreed to in writing, software 8650 * distributed under the License is distributed on an "AS IS" BASIS, 8651 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8652 * See the License for the specific language governing permissions and 8653 * limitations under the License. 8654 */ 8655 /** 8656 * <p>Encapsulates functionality and implementation that is common to UPC and EAN families 8657 * of one-dimensional barcodes.</p> 8658 * 8659 * @author [email protected] (Daniel Switkin) 8660 * @author Sean Owen 8661 * @author [email protected] (Alasdair Mackintosh) 8662 */ 8663 class UPCEANReader extends AbstractUPCEANReader { 8664 constructor() { 8665 super(); 8666 this.decodeRowStringBuffer = ''; 8667 UPCEANReader.L_AND_G_PATTERNS = UPCEANReader.L_PATTERNS.map(arr => Int32Array.from(arr)); 8668 for (let i = 10; i < 20; i++) { 8669 let widths = UPCEANReader.L_PATTERNS[i - 10]; 8670 let reversedWidths = new Int32Array(widths.length); 8671 for (let j = 0; j < widths.length; j++) { 8672 reversedWidths[j] = widths[widths.length - j - 1]; 8673 } 8674 UPCEANReader.L_AND_G_PATTERNS[i] = reversedWidths; 8675 } 8676 } 8677 decodeRow(rowNumber, row, hints) { 8678 let startGuardRange = UPCEANReader.findStartGuardPattern(row); 8679 let resultPointCallback = hints == null ? null : hints.get(DecodeHintType$1.NEED_RESULT_POINT_CALLBACK); 8680 if (resultPointCallback != null) { 8681 const resultPoint = new ResultPoint((startGuardRange[0] + startGuardRange[1]) / 2.0, rowNumber); 8682 resultPointCallback.foundPossibleResultPoint(resultPoint); 8683 } 8684 let budello = this.decodeMiddle(row, startGuardRange, this.decodeRowStringBuffer); 8685 let endStart = budello.rowOffset; 8686 let result = budello.resultString; 8687 if (resultPointCallback != null) { 8688 const resultPoint = new ResultPoint(endStart, rowNumber); 8689 resultPointCallback.foundPossibleResultPoint(resultPoint); 8690 } 8691 let endRange = UPCEANReader.decodeEnd(row, endStart); 8692 if (resultPointCallback != null) { 8693 const resultPoint = new ResultPoint((endRange[0] + endRange[1]) / 2.0, rowNumber); 8694 resultPointCallback.foundPossibleResultPoint(resultPoint); 8695 } 8696 // Make sure there is a quiet zone at least as big as the end pattern after the barcode. The 8697 // spec might want more whitespace, but in practice this is the maximum we can count on. 8698 let end = endRange[1]; 8699 let quietEnd = end + (end - endRange[0]); 8700 if (quietEnd >= row.getSize() || !row.isRange(end, quietEnd, false)) { 8701 throw new NotFoundException(); 8702 } 8703 let resultString = result.toString(); 8704 // UPC/EAN should never be less than 8 chars anyway 8705 if (resultString.length < 8) { 8706 throw new FormatException(); 8707 } 8708 if (!UPCEANReader.checkChecksum(resultString)) { 8709 throw new ChecksumException(); 8710 } 8711 let left = (startGuardRange[1] + startGuardRange[0]) / 2.0; 8712 let right = (endRange[1] + endRange[0]) / 2.0; 8713 let format = this.getBarcodeFormat(); 8714 let resultPoint = [new ResultPoint(left, rowNumber), new ResultPoint(right, rowNumber)]; 8715 let decodeResult = new Result$1(resultString, null, 0, resultPoint, format, new Date().getTime()); 8716 let extensionLength = 0; 8717 try { 8718 let extensionResult = UPCEANExtensionSupport.decodeRow(rowNumber, row, endRange[1]); 8719 decodeResult.putMetadata(ResultMetadataType$1.UPC_EAN_EXTENSION, extensionResult.getText()); 8720 decodeResult.putAllMetadata(extensionResult.getResultMetadata()); 8721 decodeResult.addResultPoints(extensionResult.getResultPoints()); 8722 extensionLength = extensionResult.getText().length; 8723 } 8724 catch (err) { 8725 } 8726 let allowedExtensions = hints == null ? null : hints.get(DecodeHintType$1.ALLOWED_EAN_EXTENSIONS); 8727 if (allowedExtensions != null) { 8728 let valid = false; 8729 for (let length in allowedExtensions) { 8730 if (extensionLength.toString() === length) { // check me 8731 valid = true; 8732 break; 8733 } 8734 } 8735 if (!valid) { 8736 throw new NotFoundException(); 8737 } 8738 } 8739 if (format === BarcodeFormat$1.EAN_13 || format === BarcodeFormat$1.UPC_A) ; 8740 return decodeResult; 8741 } 8742 static checkChecksum(s) { 8743 return UPCEANReader.checkStandardUPCEANChecksum(s); 8744 } 8745 static checkStandardUPCEANChecksum(s) { 8746 let length = s.length; 8747 if (length === 0) 8748 return false; 8749 let check = parseInt(s.charAt(length - 1), 10); 8750 return UPCEANReader.getStandardUPCEANChecksum(s.substring(0, length - 1)) === check; 8751 } 8752 static getStandardUPCEANChecksum(s) { 8753 let length = s.length; 8754 let sum = 0; 8755 for (let i = length - 1; i >= 0; i -= 2) { 8756 let digit = s.charAt(i).charCodeAt(0) - '0'.charCodeAt(0); 8757 if (digit < 0 || digit > 9) { 8758 throw new FormatException(); 8759 } 8760 sum += digit; 8761 } 8762 sum *= 3; 8763 for (let i = length - 2; i >= 0; i -= 2) { 8764 let digit = s.charAt(i).charCodeAt(0) - '0'.charCodeAt(0); 8765 if (digit < 0 || digit > 9) { 8766 throw new FormatException(); 8767 } 8768 sum += digit; 8769 } 8770 return (1000 - sum) % 10; 8771 } 8772 static decodeEnd(row, endStart) { 8773 return UPCEANReader.findGuardPattern(row, endStart, false, UPCEANReader.START_END_PATTERN, new Int32Array(UPCEANReader.START_END_PATTERN.length).fill(0)); 8774 } 8775 } 8776 8777 /* 8778 * Copyright 2008 ZXing authors 8779 * 8780 * Licensed under the Apache License, Version 2.0 (the "License"); 8781 * you may not use this file except in compliance with the License. 8782 * You may obtain a copy of the License at 8783 * 8784 * http://www.apache.org/licenses/LICENSE-2.0 8785 * 8786 * Unless required by applicable law or agreed to in writing, software 8787 * distributed under the License is distributed on an "AS IS" BASIS, 8788 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8789 * See the License for the specific language governing permissions and 8790 * limitations under the License. 8791 */ 8792 /** 8793 * <p>Implements decoding of the EAN-13 format.</p> 8794 * 8795 * @author [email protected] (Daniel Switkin) 8796 * @author Sean Owen 8797 * @author [email protected] (Alasdair Mackintosh) 8798 */ 8799 class EAN13Reader extends UPCEANReader { 8800 constructor() { 8801 super(); 8802 this.decodeMiddleCounters = Int32Array.from([0, 0, 0, 0]); 8803 } 8804 decodeMiddle(row, startRange, resultString) { 8805 let counters = this.decodeMiddleCounters; 8806 counters[0] = 0; 8807 counters[1] = 0; 8808 counters[2] = 0; 8809 counters[3] = 0; 8810 let end = row.getSize(); 8811 let rowOffset = startRange[1]; 8812 let lgPatternFound = 0; 8813 for (let x = 0; x < 6 && rowOffset < end; x++) { 8814 let bestMatch = UPCEANReader.decodeDigit(row, counters, rowOffset, UPCEANReader.L_AND_G_PATTERNS); 8815 resultString += String.fromCharCode(('0'.charCodeAt(0) + bestMatch % 10)); 8816 for (let counter of counters) { 8817 rowOffset += counter; 8818 } 8819 if (bestMatch >= 10) { 8820 lgPatternFound |= 1 << (5 - x); 8821 } 8822 } 8823 resultString = EAN13Reader.determineFirstDigit(resultString, lgPatternFound); 8824 let middleRange = UPCEANReader.findGuardPattern(row, rowOffset, true, UPCEANReader.MIDDLE_PATTERN, new Int32Array(UPCEANReader.MIDDLE_PATTERN.length).fill(0)); 8825 rowOffset = middleRange[1]; 8826 for (let x = 0; x < 6 && rowOffset < end; x++) { 8827 let bestMatch = UPCEANReader.decodeDigit(row, counters, rowOffset, UPCEANReader.L_PATTERNS); 8828 resultString += String.fromCharCode(('0'.charCodeAt(0) + bestMatch)); 8829 for (let counter of counters) { 8830 rowOffset += counter; 8831 } 8832 } 8833 return { rowOffset, resultString }; 8834 } 8835 getBarcodeFormat() { 8836 return BarcodeFormat$1.EAN_13; 8837 } 8838 static determineFirstDigit(resultString, lgPatternFound) { 8839 for (let d = 0; d < 10; d++) { 8840 if (lgPatternFound === this.FIRST_DIGIT_ENCODINGS[d]) { 8841 resultString = String.fromCharCode(('0'.charCodeAt(0) + d)) + resultString; 8842 return resultString; 8843 } 8844 } 8845 throw new NotFoundException(); 8846 } 8847 } 8848 EAN13Reader.FIRST_DIGIT_ENCODINGS = [0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A]; 8849 8850 /* 8851 * Copyright 2008 ZXing authors 8852 * 8853 * Licensed under the Apache License, Version 2.0 (the "License"); 8854 * you may not use this file except in compliance with the License. 8855 * You may obtain a copy of the License at 8856 * 8857 * http://www.apache.org/licenses/LICENSE-2.0 8858 * 8859 * Unless required by applicable law or agreed to in writing, software 8860 * distributed under the License is distributed on an "AS IS" BASIS, 8861 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8862 * See the License for the specific language governing permissions and 8863 * limitations under the License. 8864 */ 8865 /** 8866 * <p>Implements decoding of the EAN-8 format.</p> 8867 * 8868 * @author Sean Owen 8869 */ 8870 class EAN8Reader extends UPCEANReader { 8871 constructor() { 8872 super(); 8873 this.decodeMiddleCounters = Int32Array.from([0, 0, 0, 0]); 8874 } 8875 decodeMiddle(row, startRange, resultString) { 8876 const counters = this.decodeMiddleCounters; 8877 counters[0] = 0; 8878 counters[1] = 0; 8879 counters[2] = 0; 8880 counters[3] = 0; 8881 let end = row.getSize(); 8882 let rowOffset = startRange[1]; 8883 for (let x = 0; x < 4 && rowOffset < end; x++) { 8884 let bestMatch = UPCEANReader.decodeDigit(row, counters, rowOffset, UPCEANReader.L_PATTERNS); 8885 resultString += String.fromCharCode(('0'.charCodeAt(0) + bestMatch)); 8886 for (let counter of counters) { 8887 rowOffset += counter; 8888 } 8889 } 8890 let middleRange = UPCEANReader.findGuardPattern(row, rowOffset, true, UPCEANReader.MIDDLE_PATTERN, new Int32Array(UPCEANReader.MIDDLE_PATTERN.length).fill(0)); 8891 rowOffset = middleRange[1]; 8892 for (let x = 0; x < 4 && rowOffset < end; x++) { 8893 let bestMatch = UPCEANReader.decodeDigit(row, counters, rowOffset, UPCEANReader.L_PATTERNS); 8894 resultString += String.fromCharCode(('0'.charCodeAt(0) + bestMatch)); 8895 for (let counter of counters) { 8896 rowOffset += counter; 8897 } 8898 } 8899 return { rowOffset, resultString }; 8900 } 8901 getBarcodeFormat() { 8902 return BarcodeFormat$1.EAN_8; 8903 } 8904 } 8905 8906 /* 8907 * Copyright 2008 ZXing authors 8908 * 8909 * Licensed under the Apache License, Version 2.0 (the "License"); 8910 * you may not use this file except in compliance with the License. 8911 * You may obtain a copy of the License at 8912 * 8913 * http://www.apache.org/licenses/LICENSE-2.0 8914 * 8915 * Unless required by applicable law or agreed to in writing, software 8916 * distributed under the License is distributed on an "AS IS" BASIS, 8917 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8918 * See the License for the specific language governing permissions and 8919 * limitations under the License. 8920 */ 8921 /*
8921* 8922 * Encapsulates functionality and implementation that is common to all families 8923 * of one-dimensional barcodes. 8924 * 8925 * @author [email protected] (Daniel Switkin) 8926 * @author Sean Owen 8927 * @author sam2332 (Sam Rudloff) 8928 * 8929 * @source https://github.com/zxing/zxing/blob/3c96923276dd5785d58eb970b6ba3f80d36a9505/core/src/main/java/com/google/zxing/oned/UPCAReader.java 8930 * 8931 * @experimental 8932 */ 8933 class UPCAReader extends UPCEANReader { 8934 constructor() { 8935 super(...arguments); 8936 this.ean13Reader = new EAN13Reader(); 8937 } 8938 // @Override 8939 getBarcodeFormat() { 8940 return BarcodeFormat$1.UPC_A; 8941 } 8942 // Note that we don't try rotation without the try harder flag, even if rotation was supported. 8943 // @Override 8944 decode(image, hints) { 8945 return this.maybeReturnResult(this.ean13Reader.decode(image)); 8946 } 8947 // @Override 8948 decodeRow(rowNumber, row, hints) { 8949 return this.maybeReturnResult(this.ean13Reader.decodeRow(rowNumber, row, hints)); 8950 } 8951 // @Override 8952 decodeMiddle(row, startRange, resultString) { 8953 return this.ean13Reader.decodeMiddle(row, startRange, resultString); 8954 } 8955 maybeReturnResult(result) { 8956 let text = result.getText(); 8957 if (text.charAt(0) === '0') { 8958 let upcaResult = new Result$1(text.substring(1), null, null, result.getResultPoints(), BarcodeFormat$1.UPC_A); 8959 if (result.getResultMetadata() != null) { 8960 upcaResult.putAllMetadata(result.getResultMetadata()); 8961 } 8962 return upcaResult; 8963 } 8964 else { 8965 throw new NotFoundException(); 8966 } 8967 } 8968 reset() { 8969 this.ean13Reader.reset(); 8970 } 8971 } 8972 8973 /* 8974 * Copyright 2008 ZXing authors 8975 * 8976 * Licensed under the Apache License, Version 2.0 (the "License");
8977 * you may not use this file except in compliance with the License. 8978 * You may obtain a copy of the License at 8979 * 8980 * http://www.apache.org/licenses/LICENSE-2.0 8981 * 8982 * Unless required by applicable law or agreed to in writing, software 8983 * distributed under the License is distributed on an "AS IS" BASIS, 8984 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8985 * See the License for the specific language governing permissions and 8986 * limitations under the License. 8987 */ 8988 // package com.google.zxing.oned; 8989 // import com.google.zxing.BarcodeFormat; 8990 // import com.google.zxing.FormatException; 8991 // import com.google.zxing.NotFoundException; 8992 // import com.google.zxing.common.BitArray; 8993 /** 8994 * <p>Implements decoding of the UPC-E format.</p> 8995 * <p><a href="http://www.barcodeisland.com/upce.phtml">This</a> is a great reference for 8996 * UPC-E information.</p> 8997 * 8998 * @author Sean Owen 8999 * 9000 * @source https://github.com/zxing/zxing/blob/3c96923276dd5785d58eb970b6ba3f80d36a9505/core/src/main/java/com/google/zxing/oned/UPCEReader.java 9001 * 9002 * @experimental 9003 */ 9004 /* final */
vendor: 10,636 bytes, lines 9004-9258
9004 class UPCEReader extends UPCEANReader { 9005 constructor() { 9006 super(); 9007 this.decodeMiddleCounters = new Int32Array(4); 9008 } 9009 /** 9010 * @throws NotFoundException 9011 */ 9012 // @Override 9013 decodeMiddle(row, startRange, result) { 9014 const counters = this.decodeMiddleCounters.map(x => x); 9015 counters[0] = 0; 9016 counters[1] = 0; 9017 counters[2] = 0; 9018 counters[3] = 0; 9019 const end = row.getSize(); 9020 let rowOffset = startRange[1]; 9021 let lgPatternFound = 0; 9022 for (let x = 0; x < 6 && rowOffset < end; x++) { 9023 const bestMatch = UPCEReader.decodeDigit(row, counters, rowOffset, UPCEReader.L_AND_G_PATTERNS); 9024 result += String.fromCharCode(('0'.charCodeAt(0) + bestMatch % 10)); 9025 for (let counter of counters) { 9026 rowOffset += counter; 9027 } 9028 if (bestMatch >= 10) { 9029 lgPatternFound |= 1 << (5 - x); 9030 } 9031 } 9032 UPCEReader.determineNumSysAndCheckDigit(new StringBuilder(result), lgPatternFound); 9033 return rowOffset; 9034 } 9035 /** 9036 * @throws NotFoundException 9037 */ 9038 // @Override 9039 decodeEnd(row, endStart) { 9040 return UPCEReader.findGuardPatternWithoutCounters(row, endStart, true, UPCEReader.MIDDLE_END_PATTERN); 9041 } 9042 /** 9043 * @throws FormatException 9044 */ 9045 // @Override 9046 checkChecksum(s) { 9047 return UPCEANReader.checkChecksum(UPCEReader.convertUPCEtoUPCA(s)); 9048 } 9049 /** 9050 * @throws NotFoundException 9051 */ 9052 static determineNumSysAndCheckDigit(resultString, lgPatternFound) { 9053 for (let numSys = 0; numSys <= 1; numSys++) { 9054 for (let d = 0; d < 10; d++) { 9055 if (lgPatternFound === this.NUMSYS_AND_CHECK_DIGIT_PATTERNS[numSys][d]) { 9056 resultString.insert(0, /*(char)*/ ('0' + numSys)); 9057 resultString.append(/*(char)*/ ('0' + d)); 9058 return; 9059 } 9060 } 9061 } 9062 throw NotFoundException.getNotFoundInstance(); 9063 } 9064 // @Override 9065 getBarcodeFormat() { 9066 return BarcodeFormat$1.UPC_E; 9067 } 9068 /** 9069 * Expands a UPC-E value back into its full, equivalent UPC-A code value. 9070 * 9071 * @param upce UPC-E code as string of digits 9072 * @return equivalent UPC-A code as string of digits 9073 */ 9074 static convertUPCEtoUPCA(upce) { 9075 // the following line is equivalent to upce.getChars(1, 7, upceChars, 0); 9076 const upceChars = upce.slice(1, 7).split('').map(x => x.charCodeAt(0)); 9077 const result = new StringBuilder( /*12*/); 9078 result.append(upce.charAt(0)); 9079 let lastChar = upceChars[5]; 9080 switch (lastChar) { 9081 case 0: 9082 case 1: 9083 case 2: 9084 result.appendChars(upceChars, 0, 2); 9085 result.append(lastChar); 9086 result.append('0000'); 9087 result.appendChars(upceChars, 2, 3); 9088 break; 9089 case 3: 9090 result.appendChars(upceChars, 0, 3); 9091 result.append('00000'); 9092 result.appendChars(upceChars, 3, 2); 9093 break; 9094 case 4: 9095 result.appendChars(upceChars, 0, 4); 9096 result.append('00000'); 9097 result.append(upceChars[4]); 9098 break; 9099 default: 9100 result.appendChars(upceChars, 0, 5); 9101 result.append('0000'); 9102 result.append(lastChar); 9103 break; 9104 } 9105 // Only append check digit in conversion if supplied 9106 if (upce.length >= 8) { 9107 result.append(upce.charAt(7)); 9108 } 9109 return result.toString(); 9110 } 9111 } 9112 /** 9113 * The pattern that marks the middle, and end, of a UPC-E pattern. 9114 * There is no "second half" to a UPC-E barcode. 9115 */ 9116 UPCEReader.MIDDLE_END_PATTERN = Int32Array.from([1, 1, 1, 1, 1, 1]); 9117 // For an UPC-E barcode, the final digit is represented by the parities used 9118 // to encode the middle six digits, according to the table below. 9119 // 9120 // Parity of next 6 digits 9121 // Digit 0 1 2 3 4 5 9122 // 0 Even Even Even Odd Odd Odd 9123 // 1 Even Even Odd Even Odd Odd 9124 // 2 Even Even Odd Odd Even Odd 9125 // 3 Even Even Odd Odd Odd Even 9126 // 4 Even Odd Even Even Odd Odd 9127 // 5 Even Odd Odd Even Even Odd 9128 // 6 Even Odd Odd Odd Even Even 9129 // 7 Even Odd Even Odd Even Odd 9130 // 8 Even Odd Even Odd Odd Even 9131 // 9 Even Odd Odd Even Odd Even 9132 // 9133 // The encoding is represented by the following array, which is a bit pattern 9134 // using Odd = 0 and Even = 1. For example, 5 is represented by: 9135 // 9136 // Odd Even Even Odd Odd Even 9137 // in binary: 9138 // 0 1 1 0 0 1 == 0x19 9139 // 9140 /** 9141 * See {@link #L_AND_G_PATTERNS}; these values similarly represent patterns of 9142 * even-odd parity encodings of digits that imply both the number system (0 or 1) 9143 * used, and the check digit. 9144 */ 9145 UPCEReader.NUMSYS_AND_CHECK_DIGIT_PATTERNS = [ 9146 Int32Array.from([0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25]), 9147 Int32Array.from([0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1]), 9148 ]; 9149 9150 /* 9151 * Copyright 2008 ZXing authors 9152 * 9153 * Licensed under the Apache License, Version 2.0 (the "License"); 9154 * you may not use this file except in compliance with the License. 9155 * You may obtain a copy of the License at 9156 * 9157 * http://www.apache.org/licenses/LICENSE-2.0 9158 * 9159 * Unless required by applicable law or agreed to in writing, software 9160 * distributed under the License is distributed on an "AS IS" BASIS, 9161 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9162 * See the License for the specific language governing permissions and 9163 * limitations under the License. 9164 */ 9165 /** 9166 * <p>A reader that can read all available UPC/EAN formats. If a caller wants to try to 9167 * read all such formats, it is most efficient to use this implementation rather than invoke 9168 * individual readers.</p> 9169 * 9170 * @author Sean Owen 9171 */ 9172 class MultiFormatUPCEANReader extends OneDReader { 9173 constructor(hints) { 9174 super(); 9175 let possibleFormats = hints == null ? null : hints.get(DecodeHintType$1.POSSIBLE_FORMATS); 9176 let readers = []; 9177 if (possibleFormats != null) { 9178 if (possibleFormats.indexOf(BarcodeFormat$1.EAN_13) > -1) { 9179 readers.push(new EAN13Reader()); 9180 } 9181 if (possibleFormats.indexOf(BarcodeFormat$1.UPC_A) > -1) { 9182 readers.push(new UPCAReader()); 9183 } 9184 if (possibleFormats.indexOf(BarcodeFormat$1.EAN_8) > -1) { 9185 readers.push(new EAN8Reader()); 9186 } 9187 if (possibleFormats.indexOf(BarcodeFormat$1.UPC_E) > -1) { 9188 readers.push(new UPCEReader()); 9189 } 9190 } 9191 if (readers.length === 0) { 9192 readers.push(new EAN13Reader()); 9193 readers.push(new UPCAReader()); 9194 readers.push(new EAN8Reader()); 9195 readers.push(new UPCEReader()); 9196 } 9197 this.readers = readers; 9198 } 9199 decodeRow(rowNumber, row, hints) { 9200 for (let reader of this.readers) { 9201 try { 9202 // const result: Result = reader.decodeRow(rowNumber, row, startGuardPattern, hints); 9203 const result = reader.decodeRow(rowNumber, row, hints); 9204 // Special case: a 12-digit code encoded in UPC-A is identical to a "0" 9205 // followed by those 12 digits encoded as EAN-13. Each will recognize such a code, 9206 // UPC-A as a 12-digit string and EAN-13 as a 13-digit string starting with "0". 9207 // Individually these are correct and their readers will both read such a code 9208 // and correctly call it EAN-13, or UPC-A, respectively. 9209 // 9210 // In this case, if we've been looking for both types, we'd like to call it 9211 // a UPC-A code. But for efficiency we only run the EAN-13 decoder to also read 9212 // UPC-A. So we special case it here, and convert an EAN-13 result to a UPC-A 9213 // result if appropriate. 9214 // 9215 // But, don't return UPC-A if UPC-A was not a requested format! 9216 const ean13MayBeUPCA = result.getBarcodeFormat() === BarcodeFormat$1.EAN_13 && 9217 result.getText().charAt(0) === '0'; 9218 // @SuppressWarnings("unchecked") 9219 const possibleFormats = hints == null ? null : hints.get(DecodeHintType$1.POSSIBLE_FORMATS); 9220 const canReturnUPCA = possibleFormats == null || possibleFormats.includes(BarcodeFormat$1.UPC_A); 9221 if (ean13MayBeUPCA && canReturnUPCA) { 9222 const rawBytes = result.getRawBytes(); 9223 // Transfer the metadata across 9224 const resultUPCA = new Result$1(result.getText().substring(1), rawBytes, (rawBytes ? rawBytes.length : null), result.getResultPoints(), BarcodeFormat$1.UPC_A); 9225 resultUPCA.putAllMetadata(result.getResultMetadata()); 9226 return resultUPCA; 9227 } 9228 return result; 9229 } 9230 catch (err) { 9231 // continue; 9232 } 9233 } 9234 throw new NotFoundException(); 9235 } 9236 reset() { 9237 for (let reader of this.readers) { 9238 reader.reset(); 9239 } 9240 } 9241 } 9242 9243 /* 9244 * Copyright 2008 ZXing authors 9245 * 9246 * Licensed under the Apache License, Version 2.0 (the "License"); 9247 * you may not use this file except in compliance with the License. 9248 * You may obtain a copy of the License at 9249 * 9250 * http://www.apache.org/licenses/LICENSE-2.0 9251 * 9252 * Unless required by applicable law or agreed to in writing, software 9253 * distributed under the License is distributed on an "AS IS" BASIS, 9254 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9255 * See the License for the specific language governing permissions and 9256 * limitations under the License. 9257 */ 9258 /*
vendor: 9,412 bytes, lines 9258-9533
9258* 9259 * <p>Decodes CodaBar barcodes. </p> 9260 * 9261 * @author Evan @dodobelieve 9262 * @see CodaBarReader 9263 */ 9264 class CodaBarReader extends OneDReader { 9265 constructor() { 9266 super(...arguments); 9267 this.CODA_BAR_CHAR_SET = { 9268 nnnnnww: '0', 9269 nnnnwwn: '1', 9270 nnnwnnw: '2', 9271 wwnnnnn: '3', 9272 nnwnnwn: '4', 9273 wnnnnwn: '5', 9274 nwnnnnw: '6', 9275 nwnnwnn: '7', 9276 nwwnnnn: '8', 9277 wnnwnnn: '9', 9278 nnnwwnn: '-', 9279 nnwwnnn: '$', 9280 wnnnwnw: ':', 9281 wnwnnnw: '/', 9282 wnwnwnn: '.', 9283 nnwwwww: '+', 9284 nnwwnwn: 'A', 9285 nwnwnnw: 'B', 9286 nnnwnww: 'C', 9287 nnnwwwn: 'D' 9288 }; 9289 } 9290 decodeRow(rowNumber, row, hints) { 9291 let validRowData = this.getValidRowData(row); 9292 if (!validRowData) 9293 throw new NotFoundException(); 9294 let retStr = this.codaBarDecodeRow(validRowData.row); 9295 if (!retStr) 9296 throw new NotFoundException(); 9297 return new Result$1(retStr, null, 0, [new ResultPoint(validRowData.left, rowNumber), new ResultPoint(validRowData.right, rowNumber)], BarcodeFormat$1.CODABAR, new Date().getTime()); 9298 } 9299 /** 9300 * converts bit array to valid data array(lengths of black bits and white bits) 9301 * @param row bit array to convert 9302 */ 9303 getValidRowData(row) { 9304 let booleanArr = row.toArray(); 9305 let startIndex = booleanArr.indexOf(true); 9306 if (startIndex === -1) 9307 return null; 9308 let lastIndex = booleanArr.lastIndexOf(true); 9309 if (lastIndex <= startIndex) 9310 return null; 9311 booleanArr = booleanArr.slice(startIndex, lastIndex + 1); 9312 let result = []; 9313 let lastBit = booleanArr[0]; 9314 let bitLength = 1; 9315 for (let i = 1; i < booleanArr.length; i++) { 9316 if (booleanArr[i] === lastBit) { 9317 bitLength++; 9318 } 9319 else { 9320 lastBit = booleanArr[i]; 9321 result.push(bitLength); 9322 bitLength = 1; 9323 } 9324 } 9325 result.push(bitLength); 9326 // CodaBar code data valid 9327 if (result.length < 23 && (result.length + 1) % 8 !== 0) 9328 return null; 9329 return { row: result, left: startIndex, right: lastIndex }; 9330 } 9331 /** 9332 * decode codabar code 9333 * @param row row to cecode 9334 */ 9335 codaBarDecodeRow(row) { 9336 const code = []; 9337 const barThreshold = Math.ceil(row.reduce((pre, item) => (pre + item) / 2, 0)); 9338 // Read one encoded character at a time. 9339 while (row.length > 0) { 9340 const seg = row.splice(0, 8).splice(0, 7); 9341 const key = seg.map(len => (len < barThreshold ? 'n' : 'w')).join(''); 9342 if (this.CODA_BAR_CHAR_SET[key] === undefined) 9343 return null; 9344 code.push(this.CODA_BAR_CHAR_SET[key]); 9345 } 9346 let strCode = code.join(''); 9347 if (this.validCodaBarString(strCode)) 9348 return strCode; 9349 return null; 9350 } 9351 /** 9352 * check if the string is a CodaBar string 9353 * @param src string to determine 9354 */ 9355 validCodaBarString(src) { 9356 let reg = /^[A-D].{1,}[A-D]$/; 9357 return reg.test(src); 9358 } 9359 } 9360 9361 // import Integer from '../../util/Integer'; 9362 // import Float from '../../util/Float'; 9363 class AbstractRSSReader extends OneDReader { 9364 constructor() { 9365 super(); 9366 this.decodeFinderCounters = new Int32Array(4); 9367 this.dataCharacterCounters = new Int32Array(8); 9368 this.oddRoundingErrors = new Array(4); 9369 this.evenRoundingErrors = new Array(4); 9370 this.oddCounts = new Array(this.dataCharacterCounters.length / 2); 9371 this.evenCounts = new Array(this.dataCharacterCounters.length / 2); 9372 } 9373 getDecodeFinderCounters() { 9374 return this.decodeFinderCounters; 9375 } 9376 getDataCharacterCounters() { 9377 return this.dataCharacterCounters; 9378 } 9379 getOddRoundingErrors() { 9380 return this.oddRoundingErrors; 9381 } 9382 getEvenRoundingErrors() { 9383 return this.evenRoundingErrors; 9384 } 9385 getOddCounts() { 9386 return this.oddCounts; 9387 } 9388 getEvenCounts() { 9389 return this.evenCounts; 9390 } 9391 parseFinderValue(counters, finderPatterns) { 9392 for (let value = 0; value < finderPatterns.length; value++) { 9393 if (OneDReader.patternMatchVariance(counters, finderPatterns[value], AbstractRSSReader.MAX_INDIVIDUAL_VARIANCE) < AbstractRSSReader.MAX_AVG_VARIANCE) { 9394 return value; 9395 } 9396 } 9397 throw new NotFoundException(); 9398 } 9399 /** 9400 * @param array values to sum 9401 * @return sum of values 9402 * @deprecated call {@link MathUtils#sum(int[])} 9403 */ 9404 static count(array) { 9405 return MathUtils.sum(new Int32Array(array)); 9406 } 9407 static increment(array, errors) { 9408 let index = 0; 9409 let biggestError = errors[0]; 9410 for (let i = 1; i < array.length; i++) { 9411 if (errors[i] > biggestError) { 9412 biggestError = errors[i]; 9413 index = i; 9414 } 9415 } 9416 array[index]++; 9417 } 9418 static decrement(array, errors) { 9419 let index = 0; 9420 let biggestError = errors[0]; 9421 for (let i = 1; i < array.length; i++) { 9422 if (errors[i] < biggestError) { 9423 biggestError = errors[i]; 9424 index = i; 9425 } 9426 } 9427 array[index]--; 9428 } 9429 static isFinderPattern(counters) { 9430 let firstTwoSum = counters[0] + counters[1]; 9431 let sum = firstTwoSum + counters[2] + counters[3]; 9432 let ratio = firstTwoSum / sum; 9433 if (ratio >= AbstractRSSReader.MIN_FINDER_PATTERN_RATIO && ratio <= AbstractRSSReader.MAX_FINDER_PATTERN_RATIO) { 9434 // passes ratio test in spec, but see if the counts are unreasonable 9435 let minCounter = Number.MAX_SAFE_INTEGER; 9436 let maxCounter = Number.MIN_SAFE_INTEGER; 9437 for (let counter of counters) { 9438 if (counter > maxCounter) { 9439 maxCounter = counter; 9440 } 9441 if (counter < minCounter) { 9442 minCounter = counter; 9443 } 9444 } 9445 return maxCounter < 10 * minCounter; 9446 } 9447 return false; 9448 } 9449 } 9450 AbstractRSSReader.MAX_AVG_VARIANCE = 0.2; 9451 AbstractRSSReader.MAX_INDIVIDUAL_VARIANCE = 0.45; 9452 AbstractRSSReader.MIN_FINDER_PATTERN_RATIO = 9.5 / 12.0; 9453 AbstractRSSReader.MAX_FINDER_PATTERN_RATIO = 12.5 / 14.0; 9454 9455 class DataCharacter { 9456 constructor(value, checksumPortion) { 9457 this.value = value; 9458 this.checksumPortion = checksumPortion; 9459 } 9460 getValue() { 9461 return this.value; 9462 } 9463 getChecksumPortion() { 9464 return this.checksumPortion; 9465 } 9466 toString() { 9467 return this.value + '(' + this.checksumPortion + ')'; 9468 } 9469 equals(o) { 9470 if (!(o instanceof DataCharacter)) { 9471 return false; 9472 } 9473 const that = o; 9474 return this.value === that.value && this.checksumPortion === that.checksumPortion; 9475 } 9476 hashCode() { 9477 return this.value ^ this.checksumPortion; 9478 } 9479 } 9480 9481 class FinderPattern$1 { 9482 constructor(value, startEnd, start, end, rowNumber) { 9483 this.value = value; 9484 this.startEnd = startEnd; 9485 this.value = value; 9486 this.startEnd = startEnd; 9487 this.resultPoints = new Array(); 9488 this.resultPoints.push(new ResultPoint(start, rowNumber)); 9489 this.resultPoints.push(new ResultPoint(end, rowNumber)); 9490 } 9491 getValue() { 9492 return this.value; 9493 } 9494 getStartEnd() { 9495 return this.startEnd; 9496 } 9497 getResultPoints() { 9498 return this.resultPoints; 9499 } 9500 equals(o) { 9501 if (!(o instanceof FinderPattern$1)) { 9502 return false; 9503 } 9504 const that = o; 9505 return this.value === that.value; 9506 } 9507 hashCode() { 9508 return this.value; 9509 } 9510 } 9511 9512 /** 9513 * RSS util functions. 9514 */ 9515 class RSSUtils { 9516 constructor() { } 9517 static getRSSvalue(widths, maxWidth, noNarrow) { 9518 let n = 0; 9519 for (let width of widths) { 9520 n += width; 9521 } 9522 let val = 0; 9523 let narrowMask = 0; 9524 let elements = widths.length; 9525 for (let bar = 0; bar < elements - 1; bar++) { 9526 let elmWidth; 9527 for (elmWidth = 1, narrowMask |= 1 << bar; elmWidth < widths[bar]; elmWidth++, narrowMask &= ~(1 << bar)) { 9528 let subVal = RSSUtils.combins(n - elmWidth - 1, elements - bar - 2); 9529 if (noNarrow && (narrowMask === 0) && (n - elmWidth - (elements - bar - 1) >= elements - bar - 1)) { 9530 subVal -= RSSUtils.combins(n - elmWidth - (elements - bar), elements - bar - 2); 9531 } 9532 if (elements - bar - 1 > 1) { 9533 let lessVal = 0;
9534 for (let mxwElement = n - elmWidth - (elements - bar - 2); mxwElement > maxWidth; mxwElement--) { 9535 lessVal += RSSUtils.combins(n - elmWidth - mxwElement - 1, elements - bar - 3); 9536 } 9537 subVal -= lessVal * (elements - 1 - bar); 9538 } 9539 else if (n - elmWidth > maxWidth) { 9540 subVal--; 9541 } 9542 val += subVal; 9543 } 9544 n -= elmWidth; 9545 } 9546 return val; 9547 } 9548 static combins(n, r) { 9549 let maxDenom; 9550 let minDenom; 9551 if (n - r > r) { 9552 minDenom = r; 9553 maxDenom = n - r; 9554 } 9555 else { 9556 minDenom = n - r; 9557 maxDenom = r; 9558 } 9559 let val = 1; 9560 let j = 1; 9561 for (let i = n; i > maxDenom; i--) { 9562 val *= i; 9563 if (j <= minDenom) { 9564 val /= j; 9565 j++; 9566 } 9567 } 9568 while ((j <= minDenom)) { 9569 val /= j; 9570 j++; 9571 } 9572 return val; 9573 } 9574 } 9575 9576 class BitArrayBuilder { 9577 static buildBitArray(pairs) { 9578 let charNumber = pairs.length * 2 - 1; 9579 if (pairs[pairs.length - 1].getRightChar() == null) { 9580 charNumber -= 1; 9581 } 9582 let size = 12 * charNumber; 9583 let binary = new BitArray(size); 9584 let accPos = 0; 9585 let firstPair = pairs[0]; 9586 let firstValue = firstPair.getRightChar().getValue(); 9587 for (let i = 11; i >= 0; --i) { 9588 if ((firstValue & (1 << i)) !== 0) { 9589 binary.set(accPos); 9590 } 9591 accPos++; 9592 } 9593 for (let i = 1; i < pairs.length; ++i) { 9594 let currentPair = pairs[i]; 9595 let leftValue = currentPair.getLeftChar().getValue(); 9596 for (let j = 11; j >= 0; --j) { 9597 if ((leftValue & (1 << j)) !== 0) { 9598 binary.set(accPos); 9599 } 9600 accPos++; 9601 } 9602 if (currentPair.getRightChar() !== null) { 9603 let rightValue = currentPair.getRightChar().getValue(); 9604 for (let j = 11; j >= 0; --j) { 9605 if ((rightValue & (1 << j)) !== 0) { 9606 binary.set(accPos); 9607 } 9608 accPos++; 9609 } 9610 } 9611 } 9612 return binary; 9613 } 9614 } 9615 9616 class BlockParsedResult { 9617 constructor(finished, decodedInformation) { 9618 if (decodedInformation) { 9619 this.decodedInformation = null; 9620 } 9621 else { 9622 this.finished = finished; 9623 this.decodedInformation = decodedInformation; 9624 } 9625 } 9626 getDecodedInformation() { 9627 return this.decodedInformation; 9628 } 9629 isFinished() { 9630 return this.finished; 9631 } 9632 } 9633 9634 class DecodedObject { 9635 constructor(newPosition) { 9636 this.newPosition = newPosition; 9637 } 9638 getNewPosition() { 9639 return this.newPosition; 9640 } 9641 } 9642 9643 class DecodedChar extends DecodedObject { 9644 constructor(newPosition, value) { 9645 super(newPosition); 9646 this.value = value; 9647 } 9648 getValue() { 9649 return this.value; 9650 } 9651 isFNC1() { 9652 return this.value === DecodedChar.FNC1; 9653 } 9654 } 9655 DecodedChar.FNC1 = '$'; 9656 9657 class DecodedInformation extends DecodedObject { 9658 constructor(newPosition, newString, remainingValue) { 9659 super(newPosition); 9660 if (remainingValue) { 9661 this.remaining = true; 9662 this.remainingValue = this.remainingValue; 9663 } 9664 else { 9665 this.remaining = false; 9666 this.remainingValue = 0; 9667 } 9668 this.newString = newString; 9669 } 9670 getNewString() { 9671 return this.newString; 9672 } 9673 isRemaining() { 9674 return this.remaining; 9675 } 9676 getRemainingValue() { 9677 return this.remainingValue; 9678 } 9679 } 9680 9681 class DecodedNumeric extends DecodedObject { 9682 constructor(newPosition, firstDigit, secondDigit) { 9683 super(newPosition); 9684 if (firstDigit < 0 || firstDigit > 10 || secondDigit < 0 || secondDigit > 10) { 9685 throw new FormatException(); 9686 } 9687 this.firstDigit = firstDigit; 9688 this.secondDigit = secondDigit; 9689 } 9690 getFirstDigit() { 9691 return this.firstDigit; 9692 } 9693 getSecondDigit() { 9694 return this.secondDigit; 9695 } 9696 getValue() { 9697 return this.firstDigit * 10 + this.secondDigit; 9698 } 9699 isFirstDigitFNC1() { 9700 return this.firstDigit === DecodedNumeric.FNC1; 9701 } 9702 isSecondDigitFNC1() { 9703 return this.secondDigit === DecodedNumeric.FNC1; 9704 } 9705 isAnyFNC1() { 9706 return this.firstDigit === DecodedNumeric.FNC1 || this.secondDigit === DecodedNumeric.FNC1; 9707 } 9708 } 9709 DecodedNumeric.FNC1 = 10; 9710 9711 class FieldParser { 9712 constructor() { 9713 } 9714 static parseFieldsInGeneralPurpose(rawInformation) { 9715 if (!rawInformation) { 9716 return null; 9717 } 9718 // Processing 2-digit AIs 9719 if (rawInformation.length < 2) { 9720 throw new NotFoundException(); 9721 } 9722 let firstTwoDigits = rawInformation.substring(0, 2); 9723 for (let dataLength of FieldParser.TWO_DIGIT_DATA_LENGTH) { 9724 if (dataLength[0] === firstTwoDigits) { 9725 if (dataLength[1] === FieldParser.VARIABLE_LENGTH) { 9726 return FieldParser.processVariableAI(2, dataLength[2], rawInformation); 9727 }
9728 return FieldParser.processFixedAI(2, dataLength[1], rawInformation); 9729 } 9730 } 9731 if (rawInformation.length < 3) { 9732 throw new NotFoundException(); 9733 } 9734 let firstThreeDigits = rawInformation.substring(0, 3); 9735 for (let dataLength of FieldParser.THREE_DIGIT_DATA_LENGTH) { 9736 if (dataLength[0] === firstThreeDigits) { 9737 if (dataLength[1] === FieldParser.VARIABLE_LENGTH) { 9738 return FieldParser.processVariableAI(3, dataLength[2], rawInformation); 9739 } 9740 return FieldParser.processFixedAI(3, dataLength[1], rawInformation); 9741 } 9742 } 9743 for (let dataLength of FieldParser.THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH) { 9744 if (dataLength[0] === firstThreeDigits) { 9745 if (dataLength[1] === FieldParser.VARIABLE_LENGTH) { 9746 return FieldParser.processVariableAI(4, dataLength[2], rawInformation); 9747 } 9748 return FieldParser.processFixedAI(4, dataLength[1], rawInformation); 9749 } 9750 } 9751 if (rawInformation.length < 4) { 9752 throw new NotFoundException(); 9753 } 9754 let firstFourDigits = rawInformation.substring(0, 4); 9755 for (let dataLength of FieldParser.FOUR_DIGIT_DATA_LENGTH) { 9756 if (dataLength[0] === firstFourDigits) { 9757 if (dataLength[1] === FieldParser.VARIABLE_LENGTH) { 9758 return FieldParser.processVariableAI(4, dataLength[2], rawInformation); 9759 } 9760 return FieldParser.processFixedAI(4, dataLength[1], rawInformation); 9761 } 9762 } 9763 throw new NotFoundException(); 9764 }
9765 static processFixedAI(aiSize, fieldSize, rawInformation) { 9766 if (rawInformation.length < aiSize) { 9767 throw new NotFoundException(); 9768 } 9769 let ai = rawInformation.substring(0, aiSize); 9770 if (rawInformation.length < aiSize + fieldSize) { 9771 throw new NotFoundException(); 9772 } 9773 let field = rawInformation.substring(aiSize, aiSize + fieldSize); 9774 let remaining = rawInformation.substring(aiSize + fieldSize); 9775 let result = '(' + ai + ')' + field; 9776 let parsedAI = FieldParser.parseFieldsInGeneralPurpose(remaining); 9777 return parsedAI == null ? result : result + parsedAI; 9778 } 9779 static processVariableAI(aiSize, variableFieldSize, rawInformation) { 9780 let ai = rawInformation.substring(0, aiSize); 9781 let maxSize; 9782 if (rawInformation.length < aiSize + variableFieldSize) { 9783 maxSize = rawInformation.length; 9784 } 9785 else { 9786 maxSize = aiSize + variableFieldSize; 9787 } 9788 let field = rawInformation.substring(aiSize, maxSize); 9789 let remaining = rawInformation.substring(maxSize); 9790 let result = '(' + ai + ')' + field; 9791 let parsedAI = FieldParser.parseFieldsInGeneralPurpose(remaining); 9792 return parsedAI == null ? result : result + parsedAI; 9793 } 9794 } 9795 FieldParser.VARIABLE_LENGTH = []; 9796 FieldParser.TWO_DIGIT_DATA_LENGTH = [ 9797 ['00', 18], 9798 ['01', 14], 9799 ['02', 14], 9800 ['10', FieldParser.VARIABLE_LENGTH, 20], 9801 ['11', 6], 9802 ['12', 6], 9803 ['13', 6], 9804 ['15', 6], 9805 ['17', 6], 9806 ['20', 2], 9807 ['21', FieldParser.VARIABLE_LENGTH, 20], 9808 ['22', FieldParser.VARIABLE_LENGTH, 29], 9809 ['30', FieldParser.VARIABLE_LENGTH, 8], 9810 ['37', FieldParser.VARIABLE_LENGTH, 8], 9811 // internal company codes 9812 ['90', FieldParser.VARIABLE_LENGTH, 30], 9813 ['91', FieldParser.VARIABLE_LENGTH, 30], 9814 ['92', FieldParser.VARIABLE_LENGTH, 30], 9815 ['93', FieldParser.VARIABLE_LENGTH, 30], 9816 ['94', FieldParser.VARIABLE_LENGTH, 30], 9817 ['95', FieldParser.VARIABLE_LENGTH, 30], 9818 ['96', FieldParser.VARIABLE_LENGTH, 30], 9819 ['97', FieldParser.VARIABLE_LENGTH, 3], 9820 ['98', FieldParser.VARIABLE_LENGTH, 30], 9821 ['99', FieldParser.VARIABLE_LENGTH, 30], 9822 ]; 9823 FieldParser.THREE_DIGIT_DATA_LENGTH = [ 9824 // Same format as above 9825 ['240', FieldParser.VARIABLE_LENGTH, 30], 9826 ['241', FieldParser.VARIABLE_LENGTH, 30], 9827 ['242', FieldParser.VARIABLE_LENGTH, 6], 9828 ['250', FieldParser.VARIABLE_LENGTH, 30], 9829 ['251', FieldParser.VARIABLE_LENGTH, 30], 9830 ['253', FieldParser.VARIABLE_LENGTH, 17], 9831 ['254', FieldParser.VARIABLE_LENGTH, 20], 9832 ['400', FieldParser.VARIABLE_LENGTH, 30], 9833 ['401', FieldParser.VARIABLE_LENGTH, 30], 9834 ['402', 17], 9835 ['403', FieldParser.VARIABLE_LENGTH, 30], 9836 ['410', 13], 9837 ['411', 13], 9838 ['412', 13], 9839 ['413', 13], 9840 ['414', 13], 9841 ['420', FieldParser.VARIABLE_LENGTH, 20], 9842 ['421', FieldParser.VARIABLE_LENGTH, 15], 9843 ['422', 3], 9844 ['423', FieldParser.VARIABLE_LENGTH, 15], 9845 ['424', 3], 9846 ['425', 3], 9847 ['426', 3], 9848 ]; 9849 FieldParser.THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH = [ 9850 // Same format as above 9851 ['310', 6], 9852 ['311', 6], 9853 ['312', 6], 9854 ['313', 6], 9855 ['314', 6], 9856 ['315', 6], 9857 ['316', 6], 9858 ['320', 6], 9859 ['321', 6], 9860 ['322', 6], 9861 ['323', 6], 9862 ['324', 6], 9863 ['325', 6], 9864 ['326', 6], 9865 ['327', 6], 9866 ['328', 6], 9867 ['329', 6], 9868 ['330', 6], 9869 ['331', 6], 9870 ['332', 6], 9871 ['333', 6], 9872 ['334', 6], 9873 ['335', 6], 9874 ['336', 6], 9875 ['340', 6], 9876 ['341', 6], 9877 ['342', 6], 9878 ['343', 6], 9879 ['344', 6], 9880 ['345', 6], 9881 ['346', 6], 9882 ['347', 6], 9883 ['348', 6], 9884 ['349', 6], 9885 ['350', 6], 9886 ['351', 6], 9887 ['352', 6], 9888 ['353', 6], 9889 ['354', 6], 9890 ['355', 6], 9891 ['356', 6], 9892 ['357', 6], 9893 ['360', 6], 9894 ['361', 6], 9895 ['362', 6], 9896 ['363', 6], 9897 ['364', 6], 9898 ['365', 6], 9899 ['366', 6], 9900 ['367', 6], 9901 ['368', 6], 9902 ['369', 6], 9903 ['390', FieldParser.VARIABLE_LENGTH, 15], 9904 ['391', FieldParser.VARIABLE_LENGTH, 18], 9905 ['392', FieldParser.VARIABLE_LENGTH, 15], 9906 ['393', FieldParser.VARIABLE_LENGTH, 18], 9907 ['703', FieldParser.VARIABLE_LENGTH, 30], 9908 ]; 9909 FieldParser.FOUR_DIGIT_DATA_LENGTH = [ 9910 // Same format as above 9911 ['7001', 13], 9912 ['7002', FieldParser.VARIABLE_LENGTH, 30], 9913 ['7003', 10], 9914 ['8001', 14], 9915 ['8002', FieldParser.VARIABLE_LENGTH, 20], 9916 ['8003', FieldParser.VARIABLE_LENGTH, 30], 9917 ['8004', FieldParser.VARIABLE_LENGTH, 30], 9918 ['8005', 6], 9919 ['8006', 18], 9920 ['8007', FieldParser.VARIABLE_LENGTH, 30], 9921 ['8008', FieldParser.VARIABLE_LENGTH, 12], 9922 ['8018', 18], 9923 ['8020', FieldParser.VARIABLE_LENGTH, 25], 9924 ['8100', 6], 9925 ['8101', 10], 9926 ['8102', 2], 9927 ['8110', FieldParser.VARIABLE_LENGTH, 70], 9928 ['8200', FieldParser.VARIABLE_LENGTH, 70], 9929 ]; 9930 9931 class GeneralAppIdDecoder { 9932 constructor(information) { 9933 this.buffer = new StringBuilder(); 9934 this.information = information; 9935 } 9936 decodeAllCodes(buff, initialPosition) { 9937 let currentPosition = initialPosition; 9938 let remaining = null; 9939 do { 9940 let info = this.decodeGeneralPurposeField(currentPosition, remaining); 9941 let parsedFields = FieldParser.parseFieldsInGeneralPurpose(info.getNewString()); 9942 if (parsedFields != null) { 9943 buff.append(parsedFields); 9944 } 9945 if (info.isRemaining()) { 9946 remaining = '' + info.getRemainingValue(); 9947 } 9948 else { 9949 remaining = null; 9950 } 9951 if (currentPosition === info.getNewPosition()) { // No step forward! 9952 break; 9953 } 9954 currentPosition = info.getNewPosition(); 9955 } while (true); 9956 return buff.toString(); 9957 } 9958 isStillNumeric(pos) { 9959 // It's numeric if it still has 7 positions 9960 // and one of the first 4 bits is "1". 9961 if (pos + 7 > this.information.getSize()) { 9962 return pos + 4 <= this.information.getSize(); 9963 } 9964 for (let i = pos; i < pos + 3; ++i) { 9965 if (this.information.get(i)) { 9966 return true; 9967 } 9968 } 9969 return this.information.get(pos + 3); 9970 } 9971 decodeNumeric(pos) { 9972 if (pos + 7 > this.information.getSize()) { 9973 let numeric = this.extractNumericValueFromBitArray(pos, 4); 9974 if (numeric === 0) { 9975 return new DecodedNumeric(this.information.getSize(), DecodedNumeric.FNC1, DecodedNumeric.FNC1); 9976 } 9977 return new DecodedNumeric(this.information.getSize(), numeric - 1, DecodedNumeric.FNC1); 9978 } 9979 let numeric = this.extractNumericValueFromBitArray(pos, 7); 9980 let digit1 = (numeric - 8) / 11; 9981 let digit2 = (numeric - 8) % 11; 9982 return new DecodedNumeric(pos + 7, digit1, digit2); 9983 } 9984 extractNumericValueFromBitArray(pos, bits) { 9985 return GeneralAppIdDecoder.extractNumericValueFromBitArray(this.information, pos, bits); 9986 } 9987 static extractNumericValueFromBitArray(information, pos, bits) { 9988 let value = 0; 9989 for (let i = 0; i < bits; ++i) { 9990 if (information.get(pos + i)) { 9991 value |= 1 << (bits - i - 1); 9992 } 9993 } 9994 return value; 9995 } 9996 decodeGeneralPurposeField(pos, remaining) { 9997 // this.buffer.setLength(0); 9998 this.buffer.setLengthToZero(); 9999 if (remaining != null) { 10000 this.buffer.append(remaining); 10001 } 10002 this.current.setPosition(pos); 10003 let lastDecoded = this.parseBlocks(); 10004 if (lastDecoded != null && lastDecoded.isRemaining()) { 10005 return new DecodedInformation(this.current.getPosition(), this.buffer.toString(), lastDecoded.getRemainingValue()); 10006 } 10007 return new DecodedInformation(this.current.getPosition(), this.buffer.toString()); 10008 } 10009 parseBlocks() { 10010 let isFinished; 10011 let result; 10012 do { 10013 let initialPosition = this.current.getPosition(); 10014 if (this.current.isAlpha()) { 10015 result = this.parseAlphaBlock(); 10016 isFinished = result.isFinished(); 10017 } 10018 else if (this.current.isIsoIec646()) { 10019 result = this.parseIsoIec646Block(); 10020 isFinished = result.isFinished(); 10021 } 10022 else { // it must be numeric 10023 result = this.parseNumericBlock(); 10024 isFinished = result.isFinished(); 10025 } 10026 let positionChanged = initialPosition !== this.current.getPosition(); 10027 if (!positionChanged && !isFinished) { 10028 break; 10029 } 10030 } while (!isFinished); 10031 return result.getDecodedInformation(); 10032 } 10033 parseNumericBlock() { 10034 while (this.isStillNumeric(this.current.getPosition())) { 10035 let numeric = this.decodeNumeric(this.current.getPosition()); 10036 this.current.setPosition(numeric.getNewPosition()); 10037 if (numeric.isFirstDigitFNC1()) { 10038 let information; 10039 if (numeric.isSecondDigitFNC1()) { 10040 information = new DecodedInformation(this.current.getPosition(), this.buffer.toString()); 10041 } 10042 else { 10043 information = new DecodedInformation(this.current.getPosition(), this.buffer.toString(), numeric.get
10043SecondDigit()); 10044 } 10045 return new BlockParsedResult(true, information); 10046 } 10047 this.buffer.append(numeric.getFirstDigit()); 10048 if (numeric.isSecondDigitFNC1()) { 10049 let information = new DecodedInformation(this.current.getPosition(), this.buffer.toString()); 10050 return new BlockParsedResult(true, information); 10051 } 10052 this.buffer.append(numeric.getSecondDigit()); 10053 } 10054 if (this.isNumericToAlphaNumericLatch(this.current.getPosition())) { 10055 this.current.setAlpha(); 10056 this.current.incrementPosition(4); 10057 } 10058 return new BlockParsedResult(false); 10059 } 10060 parseIsoIec646Block() { 10061 while (this.isStillIsoIec646(this.current.getPosition())) { 10062 let iso = this.decodeIsoIec646(this.current.getPosition()); 10063 this.current.setPosition(iso.getNewPosition()); 10064 if (iso.isFNC1()) { 10065 let information = new DecodedInformation(this.current.getPosition(), this.buffer.toString()); 10066 return new BlockParsedResult(true, information); 10067 } 10068 this.buffer.append(iso.getValue()); 10069 } 10070 if (this.isAlphaOr646ToNumericLatch(this.current.getPosition())) { 10071 this.current.incrementPosition(3); 10072 this.current.setNumeric(); 10073 } 10074 else if (this.isAlphaTo646ToAlphaLatch(this.current.getPosition())) { 10075 if (this.current.getPosition() + 5 < this.information.getSize()) { 10076 this.current.incrementPosition(5); 10077 } 10078 else { 10079 this.current.setPosition(this.information.getSize()); 10080 } 10081 this.current.setAlpha(); 10082 } 10083 return new BlockParsedResult(false); 10084 } 10085 parseAlphaBlock() { 10086 while (this.isStillAlpha(this.current.getPosition())) { 10087 let alpha = this.decodeAlphanumeric(this.current.getPosition()); 10088 this.current.setPosition(alpha.getNewPosition()); 10089 if (alpha.isFNC1()) { 10090 let information = new DecodedInformation(this.current.getPosition(), this.buffer.toString()); 10091 return new BlockParsedResult(true, information); // end of the char block 10092 } 10093 this.buffer.append(alpha.getValue()); 10094 } 10095 if (this.isAlphaOr646ToNumericLatch(this.current.getPosition())) { 10096 this.current.incrementPosition(3); 10097 this.current.setNumeric(); 10098 } 10099 else if (this.isAlphaTo646ToAlphaLatch(this.current.getPosition())) { 10100 if (this.current.getPosition() + 5 < this.information.getSize()) { 10101 this.current.incrementPosition(5); 10102 } 10103 else { 10104 this.current.setPosition(this.information.getSize()); 10105 } 10106 this.current.setIsoIec646(); 10107 } 10108 return new BlockParsedResult(false); 10109 } 10110 isStillIsoIec646(pos) { 10111 if (pos + 5 > this.information.getSize()) { 10112 return false; 10113 } 10114 let fiveBitValue = this.extractNumericValueFromBitArray(pos, 5); 10115 if (fiveBitValue >= 5 && fiveBitValue < 16) { 10116 return true; 10117 } 10118 if (pos + 7 > this.information.getSize()) { 10119 return false; 10120 } 10121 let sevenBitValue = this.extractNumericValueFromBitArray(pos, 7); 10122 if (sevenBitValue >= 64 && sevenBitValue < 116) { 10123 return true; 10124 } 10125 if (pos + 8 > this.information.getSize()) { 10126 return false; 10127 } 10128 let eightBitValue = this.extractNumericValueFromBitArray(pos, 8); 10129 return eightBitValue >= 232 && eightBitValue < 253; 10130 } 10131 decodeIsoIec646(pos) { 10132 let fiveBitValue = this.extractNumericValueFromBitArray(pos, 5); 10133 if (fiveBitValue === 15) { 10134 return new DecodedChar(pos + 5, DecodedChar.FNC1); 10135 } 10136 if (fiveBitValue >= 5 && fiveBitValue < 15) { 10137 return new DecodedChar(pos + 5, ('0' + (fiveBitValue - 5))); 10138 } 10139 let sevenBitValue = this.extractNumericValueFromBitArray(pos, 7); 10140 if (sevenBitValue >= 64 && sevenBitValue < 90) { 10141 return new DecodedChar(pos + 7, ('' + (sevenBitValue + 1))); 10142 } 10143 if (sevenBitValue >= 90 && sevenBitValue < 116) { 10144 return new DecodedChar(pos + 7, ('' + (sevenBitValue + 7))); 10145 } 10146 let eightBitValue = this.extractNumericValueFromBitArray(pos, 8); 10147 let c; 10148 switch (eightBitValue) { 10149 case 232: 10150 c = '!'; 10151 break; 10152 case 233: 10153 c = '"'; 10154 break; 10155 case 234: 10156 c = '%'; 10157 break; 10158 case 235: 10159 c = '&'; 10160 break; 10161 case 236: 10162 c = '\''; 10163 break; 10164 case 237: 10165 c = '('; 10166 break; 10167 case 238: 10168 c = ')'; 10169 break; 10170 case 239: 10171 c = '*'; 10172 break; 10173 case 240: 10174 c = '+'; 10175 break; 10176 case 241: 10177 c = ','; 10178 break; 10179 case 242: 10180 c = '-'; 10181 break; 10182 case 243: 10183 c = '.'; 10184 break; 10185 case 244: 10186 c = '/'; 10187 break; 10188 case 245:
10189 c = ':'; 10190 break; 10191 case 246: 10192 c = ';'; 10193 break; 10194 case 247: 10195 c = '<'; 10196 break; 10197 case 248: 10198 c = '='; 10199 break; 10200 case 249: 10201 c = '>'; 10202 break; 10203 case 250: 10204 c = '?'; 10205 break; 10206 case 251: 10207 c = '_'; 10208 break; 10209 case 252: 10210 c = ' '; 10211 break; 10212 default: 10213 throw new FormatException(); 10214 } 10215 return new DecodedChar(pos + 8, c); 10216 } 10217 isStillAlpha(pos) { 10218 if (pos + 5 > this.information.getSize()) { 10219 return false; 10220 } 10221 // We now check if it's a valid 5-bit value (0..9 and FNC1) 10222 let fiveBitValue = this.extractNumericValueFromBitArray(pos, 5); 10223 if (fiveBitValue >= 5 && fiveBitValue < 16) { 10224 return true; 10225 } 10226 if (pos + 6 > this.information.getSize()) { 10227 return false; 10228 } 10229 let sixBitValue = this.extractNumericValueFromBitArray(pos, 6); 10230 return sixBitValue >= 16 && sixBitValue < 63; // 63 not included 10231 } 10232 decodeAlphanumeric(pos) { 10233 let fiveBitValue = this.extractNumericValueFromBitArray(pos, 5); 10234 if (fiveBitValue === 15) { 10235 return new DecodedChar(pos + 5, DecodedChar.FNC1); 10236 } 10237 if (fiveBitValue >= 5 && fiveBitValue < 15) { 10238 return new DecodedChar(pos + 5, ('0' + (fiveBitValue - 5))); 10239 } 10240 let sixBitValue = this.extractNumericValueFromBitArray(pos, 6); 10241 if (sixBitValue >= 32 && sixBitValue < 58) { 10242 return new DecodedChar(pos + 6, ('' + (sixBitValue + 33))); 10243 } 10244 let c; 10245 switch (sixBitValue) { 10246 case 58: 10247 c = '*'; 10248 break; 10249 case 59: 10250 c = ','; 10251 break; 10252 case 60: 10253 c = '-'; 10254 break; 10255 case 61: 10256 c = '.'; 10257 break; 10258 case 62: 10259 c = '/'; 10260 break; 10261 default: 10262 throw new IllegalStateException('Decoding invalid alphanumeric value: ' + sixBitValue); 10263 } 10264 return new DecodedChar(pos + 6, c); 10265 } 10266 isAlphaTo646ToAlphaLatch(pos) { 10267 if (pos + 1 > this.information.getSize()) { 10268 return false; 10269 } 10270 for (let i = 0; i < 5 && i + pos < this.information.getSize(); ++i) { 10271 if (i === 2) { 10272 if (!this.information.get(pos + 2)) { 10273 return false; 10274 } 10275 } 10276 else if (this.information.get(pos + i)) { 10277 return false; 10278 } 10279 } 10280 return true; 10281 } 10282 isAlphaOr646ToNumericLatch(pos) { 10283 // Next is alphanumeric if there are 3 positions and they are all zeros 10284 if (pos + 3 > this.information.getSize()) { 10285 return false; 10286 } 10287 for (let i = pos; i < pos + 3; ++i) { 10288 if (this.information.get(i)) { 10289 return false; 10290 } 10291 } 10292 return true; 10293 } 10294 isNumericToAlphaNumericLatch(pos) { 10295 // Next is alphanumeric if there are 4 positions and they are all zeros, or 10296 // if there is a subset of this just before the end of the symbol 10297 if (pos + 1 > this.information.getSize()) { 10298 return false; 10299 } 10300 for (let i = 0; i < 4 && i + pos < this.information.getSize(); ++i) { 10301 if (this.information.get(pos + i)) { 10302 return false; 10303 } 10304 } 10305 return true; 10306 } 10307 } 10308 10309 class AbstractExpandedDecoder { 10310 constructor(information) { 10311 this.information = information; 10312 this.generalDecoder = new GeneralAppIdDecoder(information); 10313 } 10314 getInformation() { 10315 return this.information; 10316 } 10317 getGeneralDecoder() { 10318 return this.generalDecoder; 10319 } 10320 } 10321 10322 class AI01decoder extends AbstractExpandedDecoder { 10323 constructor(information) { 10324 super(information); 10325 } 10326 encodeCompressedGtin(buf, currentPos) { 10327 buf.append('(01)'); 10328 let initialPosition = buf.length(); 10329 buf.append('9'); 10330 this.encodeCompressedGtinWithoutAI(buf, currentPos, initialPosition); 10331 } 10332 encodeCompressedGtinWithoutAI(buf, currentPos, initialBufferPosition) { 10333 for (let i = 0; i < 4; ++i) { 10334 let currentBlock = this.getGeneralDecoder().extractNumericValueFromBitArray(currentPos + 10 * i, 10); 10335 if (currentBlock / 100 === 0) { 10336 buf.append('0'); 10337 } 10338 if (currentBlock / 10 === 0) { 10339 buf.append('0'); 10340 } 10341 buf.append(currentBlock); 10342 } 10343 AI01decoder.appendCheckDigit(buf, initialBufferPosition); 10344 } 10345 static appendCheckDigit(buf, currentPos) { 10346 let checkDigit = 0; 10347 for (let i = 0; i < 13; i++) { 10348 // let digit = buf.charAt(i + currentPos) - '0'; 10349 // To be checked
10350 let digit = buf.charAt(i + currentPos).charCodeAt(0) - '0'.charCodeAt(0); 10351 checkDigit += (i & 0x01) === 0 ? 3 * digit : digit; 10352 } 10353 checkDigit = 10 - (checkDigit % 10); 10354 if (checkDigit === 10) { 10355 checkDigit = 0; 10356 } 10357 buf.append(checkDigit); 10358 } 10359 } 10360 AI01decoder.GTIN_SIZE = 40; 10361 10362 class AI01AndOtherAIs extends AI01decoder { 10363 // the second one is the encodation method, and the other two are for the variable length 10364 constructor(information) { 10365 super(information); 10366 } 10367 parseInformation() { 10368 let buff = new StringBuilder(); 10369 buff.append('(01)'); 10370 let initialGtinPosition = buff.length(); 10371 let firstGtinDigit = this.getGeneralDecoder().extractNumericValueFromBitArray(AI01AndOtherAIs.HEADER_SIZE, 4); 10372 buff.append(firstGtinDigit); 10373 this.encodeCompressedGtinWithoutAI(buff, AI01AndOtherAIs.HEADER_SIZE + 4, initialGtinPosition); 10374 return this.getGeneralDecoder().decodeAllCodes(buff, AI01AndOtherAIs.HEADER_SIZE + 44); 10375 } 10376 } 10377 AI01AndOtherAIs.HEADER_SIZE = 1 + 1 + 2; // first bit encodes the linkage flag, 10378 10379 class AnyAIDecoder extends AbstractExpandedDecoder { 10380 constructor(information) { 10381 super(information); 10382 } 10383 parseInformation() { 10384 let buf = new StringBuilder(); 10385 return this.getGeneralDecoder().decodeAllCodes(buf, AnyAIDecoder.HEADER_SIZE); 10386 } 10387 } 10388 AnyAIDecoder.HEADER_SIZE = 2 + 1 + 2; 10389 10390 class AI01weightDecoder extends AI01decoder { 10391 constructor(information) { 10392 super(information); 10393 } 10394 encodeCompressedWeight(buf, currentPos, weightSize) { 10395 let originalWeightNumeric = this.getGeneralDecoder().extractNumericValueFromBitArray(currentPos, weightSize); 10396 this.addWeightCode(buf, originalWeightNumeric); 10397 let weightNumeric = this.checkWeight(originalWeightNumeric); 10398 let currentDivisor = 100000; 10399 for (let i = 0; i < 5; ++i) { 10400 if (weightNumeric / currentDivisor === 0) { 10401 buf.append('0'); 10402 } 10403 currentDivisor /= 10; 10404 } 10405 buf.append(weightNumeric); 10406 } 10407 } 10408 10409 class AI013x0xDecoder extends AI01weightDecoder { 10410 constructor(information) { 10411 super(information); 10412 } 10413 parseInformation() { 10414 if (this.getInformation().getSize() !== 10415 AI013x0xDecoder.HEADER_SIZE + 10416 AI01weightDecoder.GTIN_SIZE + 10417 AI013x0xDecoder.WEIGHT_SIZE) { 10418 throw new NotFoundException(); 10419 } 10420 let buf = new StringBuilder(); 10421 this.encodeCompressedGtin(buf, AI013x0xDecoder.HEADER_SIZE); 10422 this.encodeCompressedWeight(buf, AI013x0xDecoder.HEADER_SIZE + AI01weightDecoder.GTIN_SIZE, AI013x0xDecoder.WEIGHT_SIZE); 10423 return buf.toString(); 10424 } 10425 } 10426 AI013x0xDecoder.HEADER_SIZE = 4 + 1; 10427 AI013x0xDecoder.WEIGHT_SIZE = 15; 10428 10429 class AI013103decoder extends AI013x0xDecoder { 10430 constructor(information) { 10431 super(information); 10432 } 10433 addWeightCode(buf, weight) { 10434 buf.append('(3103)'); 10435 } 10436 checkWeight(weight) { 10437 return weight; 10438 } 10439 } 10440 10441 class AI01320xDecoder extends AI013x0xDecoder { 10442 constructor(information) { 10443 super(information); 10444 } 10445 addWeightCode(buf, weight) { 10446 if (weight < 10000) { 10447 buf.append('(3202)'); 10448 } 10449 else { 10450 buf.append('(3203)'); 10451 } 10452 } 10453 checkWeight(weight) { 10454 if (weight < 10000) { 10455 return weight; 10456 } 10457 return weight - 10000; 10458 } 10459 } 10460 10461 class AI01392xDecoder extends AI01decoder { 10462 constructor(information) { 10463 super(information); 10464 } 10465 parseInformation() { 10466 if (this.getInformation().getSize() < AI01392xDecoder.HEADER_SIZE + AI01decoder.GTIN_SIZE) { 10467 throw new NotFoundException(); 10468 } 10469 let buf = new StringBuilder(); 10470 this.encodeCompressedGtin(buf, AI01392xDecoder.HEADER_SIZE); 10471 let lastAIdigit = this.getGeneralDecoder().extractNumericValueFromBitArray(AI01392xDecoder.HEADER_SIZE + AI01decoder.GTIN_SIZE, AI01392xDecoder.LAST_DIGIT_SIZE); 10472 buf.append('(392'); 10473 buf.append(lastAIdigit); 10474 buf.append(')'); 10475 let decodedInformation = this.getGeneralDecoder().decodeGeneralPurposeField(AI01392xDecoder.HEADER_SIZE + AI01decoder.GTIN_SIZE + AI01392xDecoder.LAST_DIGIT_SIZE, null); 10476 buf.append(decodedInformation.getNewString()); 10477 return buf.toString(); 10478 } 10479 } 10480 AI01392xDecoder.HEADER_SIZE = 5 + 1 + 2; 10481 AI01392xDecoder.LAST_DIGIT_SIZE = 2; 10482 10483 class AI01393xDecoder extends AI01decoder { 10484 constructor(information) { 10485 super(information); 10486 } 10487 parseInformation() { 10488 if (this.getInformation().getSize() < 10489 AI01393xDecoder.HEADER_SIZE + AI01decoder.GTIN_SIZE) { 10490 throw new NotFoundException(); 10491 } 10492 let buf = new StringBuilder(); 10493 this.encodeCompressedGtin(buf, AI01393xDecoder.HEADER_SIZE); 10494 let lastAIdigit = this.getGeneralDecoder().extractNumericValueFromBitArray(AI01393xDecoder.HEADER_SIZE + AI01decoder.GTIN_SIZE, AI01393xDecoder.LAST_DIGIT_SIZE); 10495 buf.append('(393'); 10496 buf.append(lastAIdigit); 10497 buf.append(')'); 10498 let firstThreeDigits = this.getGeneralDecoder().extractNumericValueFromBitArray(AI01393xDecoder.HEADER_SIZE + 10499 AI01decoder.GTIN_SIZE + 10500 AI01393xDecoder.LAST_DIGIT_SIZE, AI01393xDecoder.FIRST_THREE_DIGITS_SIZE); 10501 if (firstThreeDigits / 100 === 0) { 10502 buf.append('0'); 10503 } 10504 if (firstThreeDigits / 10 === 0) { 10505 buf.append('0'); 10506 } 10507 buf.append(firstThreeDigits); 10508 let generalInformation = this.getGeneralDecoder().decodeGeneralPurposeField(AI01393xDecoder.HEADER_SIZE + 10509 AI01decoder.GTIN_SIZE + 10510 AI01393xDecoder.LAST_DIGIT_SIZE + 10511 AI01393xDecoder.FIRST_THREE_DIGITS_SIZE, null); 10512 buf.append(generalInformation.getNewString()); 10513 return buf.toString(); 10514 } 10515 } 10516 AI01393xDecoder.HEADER_SIZE = 5 + 1 + 2; 10517 AI01393xDecoder.LAST_DIGIT_SIZE = 2; 10518 AI01393xDecoder.FIRST_THREE_DIGITS_SIZE = 10; 10519 10520 class AI013x0x1xDecoder extends AI01weightDecoder { 10521 constructor(information, firstAIdigits, dateCode) { 10522 super(information);
10523 this.dateCode = dateCode; 10524 this.firstAIdigits = firstAIdigits; 10525 } 10526 parseInformation() { 10527 if (this.getInformation().getSize() !== 10528 AI013x0x1xDecoder.HEADER_SIZE + 10529 AI013x0x1xDecoder.GTIN_SIZE + 10530 AI013x0x1xDecoder.WEIGHT_SIZE + 10531 AI013x0x1xDecoder.DATE_SIZE) { 10532 throw new NotFoundException(); 10533 } 10534 let buf = new StringBuilder(); 10535 this.encodeCompressedGtin(buf, AI013x0x1xDecoder.HEADER_SIZE); 10536 this.encodeCompressedWeight(buf, AI013x0x1xDecoder.HEADER_SIZE + AI013x0x1xDecoder.GTIN_SIZE, AI013x0x1xDecoder.WEIGHT_SIZE); 10537 this.encodeCompressedDate(buf, AI013x0x1xDecoder.HEADER_SIZE + 10538 AI013x0x1xDecoder.GTIN_SIZE + 10539 AI013x0x1xDecoder.WEIGHT_SIZE); 10540 return buf.toString(); 10541 } 10542 encodeCompressedDate(buf, currentPos) { 10543 let numericDate = this.getGeneralDecoder().extractNumericValueFromBitArray(currentPos, AI013x0x1xDecoder.DATE_SIZE); 10544 if (numericDate === 38400) { 10545 return; 10546 } 10547 buf.append('('); 10548 buf.append(this.dateCode); 10549 buf.append(')'); 10550 let day = numericDate % 32; 10551 numericDate /= 32; 10552 let month = (numericDate % 12) + 1; 10553 numericDate /= 12; 10554 let year = numericDate; 10555 if (year / 10 === 0) { 10556 buf.append('0'); 10557 } 10558 buf.append(year); 10559 if (month / 10 === 0) { 10560 buf.append('0'); 10561 } 10562 buf.append(month); 10563 if (day / 10 === 0) { 10564 buf.append('0'); 10565 } 10566 buf.append(day); 10567 } 10568 addWeightCode(buf, weight) { 10569 buf.append('('); 10570 buf.append(this.firstAIdigits); 10571 buf.append(weight / 100000); 10572 buf.append(')'); 10573 } 10574 checkWeight(weight) { 10575 return weight % 100000; 10576 } 10577 } 10578 AI013x0x1xDecoder.HEADER_SIZE = 7 + 1; 10579 AI013x0x1xDecoder.WEIGHT_SIZE = 20; 10580 AI013x0x1xDecoder.DATE_SIZE = 16; 10581 10582 function createDecoder(information) { 10583 try { 10584 if (information.get(1)) { 10585 return new AI01AndOtherAIs(information); 10586 } 10587 if (!information.get(2)) { 10588 return new AnyAIDecoder(information); 10589 } 10590 let fourBitEncodationMethod = GeneralAppIdDecoder.extractNumericValueFromBitArray(information, 1, 4); 10591 switch (fourBitEncodationMethod) { 10592 case 4: return new AI013103decoder(information); 10593 case 5: return new AI01320xDecoder(information); 10594 } 10595 let fiveBitEncodationMethod = GeneralAppIdDecoder.extractNumericValueFromBitArray(information, 1, 5); 10596 switch (fiveBitEncodationMethod) { 10597 case 12: return new AI01392xDecoder(information); 10598 case 13: return new AI01393xDecoder(information); 10599 } 10600 let sevenBitEncodationMethod = GeneralAppIdDecoder.extractNumericValueFromBitArray(information, 1, 7); 10601 switch (sevenBitEncodationMethod) { 10602 case 56: return new AI013x0x1xDecoder(information, '310', '11'); 10603 case 57: return new AI013x0x1xDecoder(information, '320', '11'); 10604 case 58: return new AI013x0x1xDecoder(information, '310', '13'); 10605 case 59: return new AI013x0x1xDecoder(information, '320', '13'); 10606 case 60: return new AI013x0x1xDecoder(information, '310', '15'); 10607 case 61: return new AI013x0x1xDecoder(information, '320', '15'); 10608 case 62: return new AI013x0x1xDecoder(information, '310', '17'); 10609 case 63: return new AI013x0x1xDecoder(information, '320', '17'); 10610 } 10611 } 10612 catch (e) { 10613 console.log(e); 10614 throw new IllegalStateException('unknown decoder: ' + information); 10615 } 10616 } 10617 10618 class ExpandedPair { 10619 constructor(leftChar, rightChar, finderPatter, mayBeLast) { 10620 this.leftchar = leftChar; 10621 this.rightchar = rightChar; 10622 this.finderpattern = finderPatter; 10623 this.maybeLast = mayBeLast; 10624 } 10625 mayBeLast() { 10626 return this.maybeLast; 10627 } 10628 getLeftChar() { 10629 return this.leftchar; 10630 } 10631 getRightChar() { 10632 return this.rightchar; 10633 } 10634 getFinderPattern() { 10635 return this.finderpattern; 10636 } 10637 mustBeLast() { 10638 return this.rightchar == null; 10639 } 10640 toString() { 10641 return '[ ' + this.leftchar + ', ' + this.rightchar + ' : ' + (this.finderpattern == null ? 'null' : this.finderpattern.getValue()) + ' ]'; 10642 } 10643 static equals(o1, o2) { 10644 if (!(o1 instanceof ExpandedPair)) { 10645 return false;
10646 } 10647 return ExpandedPair.equalsOrNull(o1.leftchar, o2.leftchar) && 10648 ExpandedPair.equalsOrNull(o1.rightchar, o2.rightchar) && 10649 ExpandedPair.equalsOrNull(o1.finderpattern, o2.finderpattern); 10650 } 10651 static equalsOrNull(o1, o2) { 10652 return o1 === null ? o2 === null : ExpandedPair.equals(o1, o2); 10653 } 10654 hashCode() { 10655 // return ExpandedPair.hashNotNull(leftChar) ^ hashNotNull(rightChar) ^ hashNotNull(finderPattern); 10656 let value = this.leftchar.getValue() ^ this.rightchar.getValue() ^ this.finderpattern.getValue(); 10657 return value; 10658 } 10659 } 10660 10661 class ExpandedRow { 10662 constructor(pairs, rowNumber, wasReversed) { 10663 this.pairs = pairs; 10664 this.rowNumber = rowNumber; 10665 this.wasReversed = wasReversed; 10666 } 10667 getPairs() { 10668 return this.pairs; 10669 } 10670 getRowNumber() { 10671 return this.rowNumber; 10672 } 10673 isReversed() { 10674 return this.wasReversed; 10675 } 10676 // check implementation 10677 isEquivalent(otherPairs) { 10678 return this.checkEqualitity(this, otherPairs); 10679 } 10680 // @Override 10681 toString() { 10682 return '{ ' + this.pairs + ' }'; 10683 } 10684 /** 10685 * Two rows are equal if they contain the same pairs in the same order. 10686 */ 10687 // @Override 10688 // check implementation 10689 equals(o1, o2) { 10690 if (!(o1 instanceof ExpandedRow)) { 10691 return false; 10692 } 10693 return this.checkEqualitity(o1, o2) && o1.wasReversed === o2.wasReversed; 10694 } 10695 checkEqualitity(pair1, pair2) { 10696 if (!pair1 || !pair2) 10697 return; 10698 let result; 10699 pair1.forEach((e1, i) => { 10700 pair2.forEach(e2 => { 10701 if (e1.getLeftChar().getValue() === e2.getLeftChar().getValue() && e1.getRightChar().getValue() === e2.getRightChar().getValue() && e1.getFinderPatter().getValue() === e2.getFinderPatter().getValue()) { 10702 result = true; 10703 } 10704 }); 10705 }); 10706 return result; 10707 } 10708 } 10709 10710 // import java.util.ArrayList; 10711 // import java.util.Iterator; 10712 // import java.util.List; 10713 // import java.util.Map; 10714 // import java.util.Collections; 10715 /** @experimental */ 10716 class RSSExpandedReader extends AbstractRSSReader { 10717 constructor() { 10718 super(...arguments); 10719 this.pairs = new Array(RSSExpandedReader.MAX_PAIRS); 10720 this.rows = new Array(); 10721 this.startEnd = [2]; 10722 } 10723 decodeRow(rowNumber, row, hints) { 10724 // Rows can start with even pattern in case in prev rows there where odd number of patters. 10725 // So lets try twice 10726 // this.pairs.clear(); 10727 this.pairs.length = 0; 10728 this.startFromEven = false; 10729 try { 10730 return RSSExpandedReader.constructResult(this.decodeRow2pairs(rowNumber, row)); 10731 } 10732 catch (e) { 10733 // OK 10734 // console.log(e); 10735 } 10736 this.pairs.length = 0; 10737 this.startFromEven = true; 10738 return RSSExpandedReader.constructResult(this.decodeRow2pairs(rowNumber, row)); 10739 } 10740 reset() { 10741 this.pairs.length = 0; 10742 this.rows.length = 0; 10743 } 10744 // Not private for testing 10745 decodeRow2pairs(rowNumber, row) { 10746 let done = false; 10747 while (!done) { 10748 try { 10749 this.pairs.push(this.retrieveNextPair(row, this.pairs, rowNumber)); 10750 } 10751 catch (error) { 10752 if (error instanceof NotFoundException) { 10753 if (!this.pairs.length) { 10754 throw new NotFoundException(); 10755 } 10756 // exit this loop when retrieveNextPair() fails and throws 10757 done = true; 10758 } 10759 } 10760 } 10761 // TODO: verify sequence of finder patterns as in checkPairSequence() 10762 if (this.checkChecksum()) { 10763 return this.pairs; 10764 } 10765 let tryStackedDecode; 10766 if (this.rows.length) { 10767 tryStackedDecode = true; 10768 } 10769 else { 10770 tryStackedDecode = false;
10771 } 10772 // let tryStackedDecode = !this.rows.isEmpty(); 10773 this.storeRow(rowNumber, false); // TODO: deal with reversed rows 10774 if (tryStackedDecode) { 10775 // When the image is 180-rotated, then rows are sorted in wrong direction. 10776 // Try twice with both the directions. 10777 let ps = this.checkRowsBoolean(false); 10778 if (ps != null) { 10779 return ps; 10780 } 10781 ps = this.checkRowsBoolean(true); 10782 if (ps != null) { 10783 return ps; 10784 } 10785 } 10786 throw new NotFoundException(); 10787 } 10788 // Need to Verify 10789 checkRowsBoolean(reverse) { 10790 // Limit number of rows we are checking 10791 // We use recursive algorithm with pure complexity and don't want it to take forever 10792 // Stacked barcode can have up to 11 rows, so 25 seems reasonable enough 10793 if (this.rows.length > 25) { 10794 this.rows.length = 0; // We will never have a chance to get result, so clear it 10795 return null; 10796 } 10797 this.pairs.length = 0; 10798 if (reverse) { 10799 this.rows = this.rows.reverse(); 10800 // Collections.reverse(this.rows); 10801 } 10802 let ps = null; 10803 try { 10804 ps = this.checkRows(new Array(), 0); 10805 } 10806 catch (e) { 10807 // OK 10808 console.log(e); 10809 } 10810 if (reverse) { 10811 this.rows = this.rows.reverse(); 10812 // Collections.reverse(this.rows); 10813 } 10814 return ps; 10815 } 10816 // Try to construct a valid rows sequence 10817 // Recursion is used to implement backtracking 10818 checkRows(collectedRows, currentRow) { 10819 for (let i = currentRow; i < this.rows.length; i++) { 10820 let row = this.rows[i]; 10821 this.pairs.length = 0; 10822 for (let collectedRow of collectedRows) { 10823 this.pairs.push(collectedRow.getPairs()); 10824 } 10825 this.pairs.push(row.getPairs()); 10826 if (!RSSExpandedReader.isValidSequence(this.pairs)) { 10827 continue; 10828 } 10829 if (this.checkChecksum()) { 10830 return this.pairs; 10831 } 10832 let rs = new Array(collectedRows); 10833 rs.push(row); 10834 try { 10835 // Recursion: try to add more rows 10836 return this.checkRows(rs, i + 1); 10837 } 10838 catch (e) { 10839 // We failed, try the next candidate 10840 console.log(e); 10841 } 10842 } 10843 throw new NotFoundException(); 10844 } 10845 // Whether the pairs form a valid find pattern sequence, 10846 // either complete or a prefix 10847 static isValidSequence(pairs) { 10848 for (let sequence of RSSExpandedReader.FINDER_PATTERN_SEQUENCES) { 10849 if (pairs.length > sequence.length) { 10850 continue; 10851 } 10852 let stop = true; 10853 for (let j = 0; j < pairs.length; j++) { 10854 if (pairs[j].getFinderPattern().getValue() !== sequence[j]) { 10855 stop = false; 10856 break; 10857 } 10858 } 10859 if (stop) { 10860 return true; 10861 } 10862 } 10863 return false; 10864 } 10865 storeRow(rowNumber, wasReversed) { 10866 // Discard if duplicate above or below; otherwise insert in order by row number. 10867 let insertPos = 0; 10868 let prevIsSame = false; 10869 let nextIsSame = false; 10870 while (insertPos < this.rows.length) { 10871 let erow = this.rows[insertPos]; 10872 if (erow.getRowNumber() > rowNumber) { 10873 nextIsSame = erow.isEquivalent(this.pairs); 10874 break; 10875 } 10876 prevIsSame = erow.isEquivalent(this.pairs); 10877 insertPos++; 10878 } 10879 if (nextIsSame || prevIsSame) { 10880 return; 10881 } 10882 // When the row was partially decoded (e.g. 2 pairs found instead of 3), 10883 // it will prevent us from detecting the barcode. 10884 // Try to merge partial rows 10885 // Check whether the row is part of an allready detected row 10886 if (RSSExpandedReader.isPartialRow(this.pairs, this.rows)) { 10887 return; 10888 } 10889 this.rows.push(insertPos, new ExpandedRow(this.pairs, rowNumber, wasReversed)); 10890 this.removePartialRows(this.pairs, this.rows); 10891 } 10892 // Remove all the rows that contains only specified pairs 10893 removePartialRows(pairs, rows) { 10894 // for (Iterator<ExpandedRow> iterator = rows.iterator(); iterator.hasNext();) { 10895 // ExpandedRow r = iterator.next(); 10896 // if (r.getPairs().size() == pairs.size()) { 10897 // continue; 10898 // } 10899 // boolean allFound = true;
10900 // for (ExpandedPair p : r.getPairs()) { 10901 // boolean found = false; 10902 // for (ExpandedPair pp : pairs) { 10903 // if (p.equals(pp)) { 10904 // found = true; 10905 // break; 10906 // } 10907 // } 10908 // if (!found) { 10909 // allFound = false; 10910 // break; 10911 // } 10912 // } 10913 // if (allFound) { 10914 // // 'pairs' contains all the pairs from the row 'r' 10915 // iterator.remove(); 10916 // } 10917 // } 10918 for (let row of rows) { 10919 if (row.getPairs().length === pairs.length) { 10920 continue; 10921 } 10922 for (let p of row.getPairs()) { 10923 for (let pp of pairs) { 10924 if (ExpandedPair.equals(p, pp)) { 10925 break; 10926 } 10927 } 10928 } 10929 } 10930 } 10931 // Returns true when one of the rows already contains all the pairs 10932 static isPartialRow(pairs, rows) { 10933 for (let r of rows) { 10934 let allFound = true; 10935 for (let p of pairs) { 10936 let found = false; 10937 for (let pp of r.getPairs()) { 10938 if (p.equals(pp)) { 10939 found = true; 10940 break; 10941 } 10942 } 10943 if (!found) { 10944 allFound = false; 10945 break; 10946 } 10947 } 10948 if (allFound) { 10949 // the row 'r' contain all the pairs from 'pairs' 10950 return true; 10951 } 10952 } 10953 return false; 10954 } 10955 // Only used for unit testing 10956 getRows() { 10957 return this.rows; 10958 } 10959 // Not private for unit testing 10960 static constructResult(pairs) { 10961 let binary = BitArrayBuilder.buildBitArray(pairs); 10962 let decoder = createDecoder(binary); 10963 let resultingString = decoder.parseInformation(); 10964 let firstPoints = pairs[0].getFinderPattern().getResultPoints(); 10965 let lastPoints = pairs[pairs.length - 1] 10966 .getFinderPattern() 10967 .getResultPoints(); 10968 let points = [firstPoints[0], firstPoints[1], lastPoints[0], lastPoints[1]]; 10969 return new Result$1(resultingString, null, null, points, BarcodeFormat$1.RSS_EXPANDED, null); 10970 } 10971 checkChecksum() { 10972 let firstPair = this.pairs.get(0); 10973 let checkCharacter = firstPair.getLeftChar(); 10974 let firstCharacter = firstPair.getRightChar(); 10975 if (firstCharacter === null) { 10976 return false; 10977 } 10978 let checksum = firstCharacter.getChecksumPortion(); 10979 let s = 2; 10980 for (let i = 1; i < this.pairs.size(); ++i) { 10981 let currentPair = this.pairs.get(i); 10982 checksum += currentPair.getLeftChar().getChecksumPortion(); 10983 s++; 10984 let currentRightChar = currentPair.getRightChar(); 10985 if (currentRightChar != null) { 10986 checksum += currentRightChar.getChecksumPortion(); 10987 s++; 10988 } 10989 } 10990 checksum %= 211; 10991 let checkCharacterValue = 211 * (s - 4) + checksum; 10992 return checkCharacterValue === checkCharacter.getValue(); 10993 } 10994 static getNextSecondBar(row, initialPos) { 10995 let currentPos; 10996 if (row.get(initialPos)) { 10997 currentPos = row.getNextUnset(initialPos); 10998 currentPos = row.getNextSet(currentPos); 10999 } 11000 else { 11001 currentPos = row.getNextSet(initialPos); 11002 currentPos = row.getNextUnset(currentPos); 11003 } 11004 return currentPos; 11005 } 11006 // not private for testing 11007 retrieveNextPair(row, previousPairs, rowNumber) { 11008 let isOddPattern = previousPairs.length % 2 === 0; 11009 if (this.startFromEven) { 11010 isOddPattern = !isOddPattern; 11011 } 11012 let pattern; 11013 let keepFinding = true; 11014 let forcedOffset = -1; 11015 do { 11016 this.findNextPair(row, previousPairs, forcedOffset); 11017 pattern = this.parseFoundFinderPattern(row, rowNumber, isOddPattern); 11018 if (pattern === null) { 11019 forcedOffset = RSSExpandedReader.getNextSecondBar(row, this.startEnd[0]); 11020 } 11021 else { 11022 keepFinding = false;
11023 } 11024 } while (keepFinding); 11025 // When stacked symbol is split over multiple rows, there's no way to guess if this pair can be last or not. 11026 // boolean mayBeLast = checkPairSequence(previousPairs, pattern); 11027 let leftChar = this.decodeDataCharacter(row, pattern, isOddPattern, true); 11028 if (!this.isEmptyPair(previousPairs) && 11029 previousPairs[previousPairs.length - 1].mustBeLast()) { 11030 throw new NotFoundException(); 11031 } 11032 let rightChar; 11033 try { 11034 rightChar = this.decodeDataCharacter(row, pattern, isOddPattern, false); 11035 } 11036 catch (e) { 11037 rightChar = null; 11038 console.log(e); 11039 } 11040 return new ExpandedPair(leftChar, rightChar, pattern, true); 11041 } 11042 isEmptyPair(pairs) { 11043 if (pairs.length === 0) { 11044 return true; 11045 } 11046 return false; 11047 } 11048 findNextPair(row, previousPairs, forcedOffset) { 11049 let counters = this.getDecodeFinderCounters(); 11050 counters[0] = 0; 11051 counters[1] = 0; 11052 counters[2] = 0; 11053 counters[3] = 0; 11054 let width = row.getSize(); 11055 let rowOffset; 11056 if (forcedOffset >= 0) { 11057 rowOffset = forcedOffset; 11058 } 11059 else if (this.isEmptyPair(previousPairs)) { 11060 rowOffset = 0; 11061 } 11062 else { 11063 let lastPair = previousPairs[previousPairs.length - 1]; 11064 rowOffset = lastPair.getFinderPattern().getStartEnd()[1]; 11065 } 11066 let searchingEvenPair = previousPairs.length % 2 !== 0; 11067 if (this.startFromEven) { 11068 searchingEvenPair = !searchingEvenPair; 11069 } 11070 let isWhite = false; 11071 while (rowOffset < width) { 11072 isWhite = !row.get(rowOffset); 11073 if (!isWhite) { 11074 break; 11075 } 11076 rowOffset++; 11077 } 11078 let counterPosition = 0; 11079 let patternStart = rowOffset; 11080 for (let x = rowOffset; x < width; x++) { 11081 if (row.get(x) !== isWhite) { 11082 counters[counterPosition]++; 11083 } 11084 else { 11085 if (counterPosition === 3) { 11086 if (searchingEvenPair) { 11087 RSSExpandedReader.reverseCounters(counters); 11088 } 11089 if (RSSExpandedReader.isFinderPattern(counters)) { 11090 this.startEnd[0] = patternStart; 11091 this.startEnd[1] = x; 11092 return; 11093 } 11094 if (searchingEvenPair) { 11095 RSSExpandedReader.reverseCounters(counters); 11096 } 11097 patternStart += counters[0] + counters[1]; 11098 counters[0] = counters[2]; 11099 counters[1] = counters[3]; 11100 counters[2] = 0; 11101 counters[3] = 0; 11102 counterPosition--; 11103 } 11104 else { 11105 counterPosition++; 11106 } 11107 counters[counterPosition] = 1; 11108 isWhite = !isWhite; 11109 } 11110 } 11111 throw new NotFoundException(); 11112 } 11113 static reverseCounters(counters) { 11114 let length = counters.length; 11115 for (let i = 0; i < length / 2; ++i) { 11116 let tmp = counters[i]; 11117 counters[i] = counters[length - i - 1]; 11118 counters[length - i - 1] = tmp; 11119 } 11120 } 11121 parseFoundFinderPattern(row, rowNumber, oddPattern) { 11122 // Actually we found elements 2-5. 11123 let firstCounter; 11124 let start; 11125 let end; 11126 if (oddPattern) { 11127 // If pattern number is odd, we need to locate element 1 *before* the current block. 11128 let firstElementStart = this.startEnd[0] - 1; 11129 // Locate element 1 11130 while (firstElementStart >= 0 && !row.get(firstElementStart)) { 11131 firstElementStart--; 11132 } 11133 firstElementStart++; 11134 firstCounter = this.startEnd[0] - firstElementStart; 11135 start = firstElementStart; 11136 end = this.startEnd[1]; 11137 } 11138 else { 11139 // If pattern number is even, the pattern is reversed, so we need to locate element 1 *after* the current block. 11140 start = this.startEnd[0]; 11141 end = row.getNextUnset(this.startEnd[1] + 1); 11142 firstCounter = end - this.startEnd[1]; 11143 } 11144 // Make 'counters' hold 1-4 11145 let counters = this.getDecodeFinderCounters(); 11146 System.arraycopy(counters, 0, counters, 1, counters.length - 1); 11147 counters[0] = firstCounter; 11148 let value; 11149 try { 11150 value = this.parseFinderValue(counters, RSSExpandedReader.FINDER_PATTERNS); 11151 } 11152 catch (e) { 11153 return null; 11154 } 11155 // return new FinderPattern(value, new int[] { start, end }, start, end, rowNumber}); 11156 return new FinderPattern$1(value, [start, end], start, end, rowNumber); 11157 } 11158 decodeDataCharacter(row, pattern, isOddPattern, leftChar) { 11159 let counters = this.getDataCharacterCounters(); 11160 for (let x = 0; x < counters.length; x++) { 11161 counters[x] = 0; 11162 } 11163 if (leftChar) { 11164 RSSExpandedReader.recordPatternInReverse(row, pattern.getStartEnd()[0], counters); 11165 } 11166 else { 11167 RSSExpandedReader.recordPattern(row, pattern.getStartEnd()[1], counters); 11168 // reverse it 11169 for (let i = 0, j = counters.length - 1; i < j; i++, j--) { 11170 let temp = counters[i]; 11171 counters[i] = counters[j]; 11172 counters[j] = temp; 11173 } 11174 } // counters[] has the pixels of the module 11175 let numModules = 17; // left and right data characters have all the same length 11176 let elementWidth = MathUtils.sum(new Int32Array(counters)) / numModules; 11177 // Sanity check: element width for pattern and the character should match 11178 let expectedElementWidth = (pattern.getStartEnd()[1] - pattern.getStartEnd()[0]) / 15.0; 11179 if (Math.abs(elementWidth - expectedElementWidth) / expectedElementWidth > 11180 0.3) { 11181 throw new NotFoundException(); 11182 } 11183 let oddCounts = this.getOddCounts(); 11184 let evenCounts = this.getEvenCounts(); 11185 let oddRoundingErrors = this.getOddRoundingErrors(); 11186 let evenRoundingErrors = this.getEvenRoundingErrors(); 11187 for (let i = 0; i < counters.length; i++) { 11188 let value = (1.0 * counters[i]) / elementWidth; 11189 let count = value + 0.5; // Round 11190 if (count < 1) { 11191 if (value < 0.3) { 11192 throw new NotFoundException(); 11193 } 11194 count = 1; 11195 } 11196 else if (count > 8) { 11197 if (value > 8.7) { 11198 throw new NotFoundException(); 11199 } 11200 count = 8; 11201 } 11202 let offset = i / 2; 11203 if ((i & 0x01) === 0) { 11204 oddCounts[offset] = count; 11205 oddRoundingErrors[offset] = value - count; 11206 } 11207 else { 11208 evenCounts[offset] = count; 11209 evenRoundingErrors[offset] = value - count; 11210 } 11211 } 11212 this.adjustOddEvenCounts(numModules); 11213 let weightRowNumber = 4 * pattern.getValue() + (isOddPattern ? 0 : 2) + (leftChar ? 0 : 1) - 1; 11214 let oddSum = 0; 11215 let oddChecksumPortion = 0; 11216 for (let i = oddCounts.length - 1; i >= 0; i--) { 11217 if (RSSExpandedReader.isNotA1left(pattern, isOddPattern, leftChar)) { 11218 let weight = RSSExpandedReader.WEIGHTS[weightRowNumber][2 * i]; 11219 oddChecksumPortion += oddCounts[i] * weight; 11220 } 11221 oddSum += oddCounts[i]; 11222 } 11223 let evenChecksumPortion = 0; 11224 // int evenSum = 0; 11225 for (let i = evenCounts.length - 1; i >= 0; i--) { 11226 if (RSSExpandedReader.isNotA1left(pattern, isOddPattern, leftChar)) { 11227 let weight = RSSExpandedReader.WEIGHTS[weightRowNumber][2 * i + 1]; 11228 evenChecksumPortion += evenCounts[i] * weight; 11229 } 11230 // evenSum += evenCounts[i]; 11231 } 11232 let checksumPortion = oddChecksumPortion + evenChecksumPortion; 11233 if ((oddSum & 0x01) !== 0 || oddSum > 13 || oddSum < 4) { 11234 throw new NotFoundException(); 11235 } 11236 let group = (13 - oddSum) / 2; 11237 let oddWidest = RSSExpandedReader.SYMBOL_WIDEST[group]; 11238 let evenWidest = 9 - oddWidest; 11239 let vOdd = RSSUtils.getRSSvalue(oddCounts, oddWidest, true); 11240 let vEven = RSSUtils.getRSSvalue(evenCounts, evenWidest, false); 11241 let tEven = RSSExpandedReader.EVEN_TOTAL_SUBSET[group]; 11242 let gSum = RSSExpandedReader.GSUM[group]; 11243 let value = vOdd * tEven + vEven + gSum; 11244 return new DataCharacter(value, checksumPortion); 11245 } 11246 static isNotA1left(pattern, isOddPattern, leftChar) { 11247 // A1: pattern.getValue is 0 (A), and it's an oddPattern, and it is a left char 11248 return !(pattern.getValue() === 0 && isOddPattern && leftChar); 11249 } 11250 adjustOddEvenCounts(numModules) { 11251 let oddSum = MathUtils.sum(new Int32Array(this.getOddCounts())); 11252 let evenSum = MathUtils.sum(new Int32Array(this.getEvenCounts())); 11253 let incrementOdd = false;
vendor: 9,232 bytes, lines 11254-11518
11254 let decrementOdd = false; 11255 if (oddSum > 13) { 11256 decrementOdd = true; 11257 } 11258 else if (oddSum < 4) { 11259 incrementOdd = true; 11260 } 11261 let incrementEven = false; 11262 let decrementEven = false; 11263 if (evenSum > 13) { 11264 decrementEven = true; 11265 } 11266 else if (evenSum < 4) { 11267 incrementEven = true; 11268 } 11269 let mismatch = oddSum + evenSum - numModules; 11270 let oddParityBad = (oddSum & 0x01) === 1; 11271 let evenParityBad = (evenSum & 0x01) === 0; 11272 if (mismatch === 1) { 11273 if (oddParityBad) { 11274 if (evenParityBad) { 11275 throw new NotFoundException(); 11276 } 11277 decrementOdd = true; 11278 } 11279 else { 11280 if (!evenParityBad) { 11281 throw new NotFoundException(); 11282 } 11283 decrementEven = true; 11284 } 11285 } 11286 else if (mismatch === -1) { 11287 if (oddParityBad) { 11288 if (evenParityBad) { 11289 throw new NotFoundException(); 11290 } 11291 incrementOdd = true; 11292 } 11293 else { 11294 if (!evenParityBad) { 11295 throw new NotFoundException(); 11296 } 11297 incrementEven = true; 11298 } 11299 } 11300 else if (mismatch === 0) { 11301 if (oddParityBad) { 11302 if (!evenParityBad) { 11303 throw new NotFoundException(); 11304 } 11305 // Both bad 11306 if (oddSum < evenSum) { 11307 incrementOdd = true; 11308 decrementEven = true; 11309 } 11310 else { 11311 decrementOdd = true; 11312 incrementEven = true; 11313 } 11314 } 11315 else { 11316 if (evenParityBad) { 11317 throw new NotFoundException(); 11318 } 11319 // Nothing to do! 11320 } 11321 } 11322 else { 11323 throw new NotFoundException(); 11324 } 11325 if (incrementOdd) { 11326 if (decrementOdd) { 11327 throw new NotFoundException(); 11328 } 11329 RSSExpandedReader.increment(this.getOddCounts(), this.getOddRoundingErrors()); 11330 } 11331 if (decrementOdd) { 11332 RSSExpandedReader.decrement(this.getOddCounts(), this.getOddRoundingErrors()); 11333 } 11334 if (incrementEven) { 11335 if (decrementEven) { 11336 throw new NotFoundException(); 11337 } 11338 RSSExpandedReader.increment(this.getEvenCounts(), this.getOddRoundingErrors()); 11339 } 11340 if (decrementEven) { 11341 RSSExpandedReader.decrement(this.getEvenCounts(), this.getEvenRoundingErrors()); 11342 } 11343 } 11344 } 11345 RSSExpandedReader.SYMBOL_WIDEST = [7, 5, 4, 3, 1]; 11346 RSSExpandedReader.EVEN_TOTAL_SUBSET = [4, 20, 52, 104, 204]; 11347 RSSExpandedReader.GSUM = [0, 348, 1388, 2948, 3988]; 11348 RSSExpandedReader.FINDER_PATTERNS = [ 11349 Int32Array.from([1, 8, 4, 1]), 11350 Int32Array.from([3, 6, 4, 1]), 11351 Int32Array.from([3, 4, 6, 1]), 11352 Int32Array.from([3, 2, 8, 1]), 11353 Int32Array.from([2, 6, 5, 1]), 11354 Int32Array.from([2, 2, 9, 1]), 11355 ]; 11356 RSSExpandedReader.WEIGHTS = [ 11357 [1, 3, 9, 27, 81, 32, 96, 77], 11358 [20, 60, 180, 118, 143, 7, 21, 63], 11359 [189, 145, 13, 39, 117, 140, 209, 205], 11360 [193, 157, 49, 147, 19, 57, 171, 91], 11361 [62, 186, 136, 197, 169, 85, 44, 132], 11362 [185, 133, 188, 142, 4, 12, 36, 108], 11363 [113, 128, 173, 97, 80, 29, 87, 50], 11364 [150, 28, 84, 41, 123, 158, 52, 156], 11365 [46, 138, 203, 187, 139, 206, 196, 166], 11366 [76, 17, 51, 153, 37, 111, 122, 155], 11367 [43, 129, 176, 106, 107, 110, 119, 146], 11368 [16, 48, 144, 10, 30, 90, 59, 177], 11369 [109, 116, 137, 200, 178, 112, 125, 164], 11370 [70, 210, 208, 202, 184, 130, 179, 115], 11371 [134, 191, 151, 31, 93, 68, 204, 190], 11372 [148, 22, 66, 198, 172, 94, 71, 2], 11373 [6, 18, 54, 162, 64, 192, 154, 40], 11374 [120, 149, 25, 75, 14, 42, 126, 167], 11375 [79, 26, 78, 23, 69, 207, 199, 175], 11376 [103, 98, 83, 38, 114, 131, 182, 124], 11377 [161, 61, 183, 127, 170, 88, 53, 159], 11378 [55, 165, 73, 8, 24, 72, 5, 15], 11379 [45, 135, 194, 160, 58, 174, 100, 89], 11380 ]; 11381 RSSExpandedReader.FINDER_PAT_A = 0; 11382 RSSExpandedReader.FINDER_PAT_B = 1; 11383 RSSExpandedReader.FINDER_PAT_C = 2; 11384 RSSExpandedReader.FINDER_PAT_D = 3; 11385 RSSExpandedReader.FINDER_PAT_E = 4; 11386 RSSExpandedReader.FINDER_PAT_F = 5; 11387 RSSExpandedReader.FINDER_PATTERN_SEQUENCES = [ 11388 [RSSExpandedReader.FINDER_PAT_A, RSSExpandedReader.FINDER_PAT_A], 11389 [ 11390 RSSExpandedReader.FINDER_PAT_A, 11391 RSSExpandedReader.FINDER_PAT_B, 11392 RSSExpandedReader.FINDER_PAT_B, 11393 ], 11394 [ 11395 RSSExpandedReader.FINDER_PAT_A, 11396 RSSExpandedReader.FINDER_PAT_C, 11397 RSSExpandedReader.FINDER_PAT_B, 11398 RSSExpandedReader.FINDER_PAT_D, 11399 ], 11400 [ 11401 RSSExpandedReader.FINDER_PAT_A, 11402 RSSExpandedReader.FINDER_PAT_E, 11403 RSSExpandedReader.FINDER_PAT_B, 11404 RSSExpandedReader.FINDER_PAT_D, 11405 RSSExpandedReader.FINDER_PAT_C, 11406 ], 11407 [ 11408 RSSExpandedReader.FINDER_PAT_A, 11409 RSSExpandedReader.FINDER_PAT_E, 11410 RSSExpandedReader.FINDER_PAT_B, 11411 RSSExpandedReader.FINDER_PAT_D, 11412 RSSExpandedReader.FINDER_PAT_D, 11413 RSSExpandedReader.FINDER_PAT_F, 11414 ], 11415 [ 11416 RSSExpandedReader.FINDER_PAT_A, 11417 RSSExpandedReader.FINDER_PAT_E, 11418 RSSExpandedReader.FINDER_PAT_B, 11419 RSSExpandedReader.FINDER_PAT_D, 11420 RSSExpandedReader.FINDER_PAT_E, 11421 RSSExpandedReader.FINDER_PAT_F, 11422 RSSExpandedReader.FINDER_PAT_F, 11423 ], 11424 [ 11425 RSSExpandedReader.FINDER_PAT_A, 11426 RSSExpandedReader.FINDER_PAT_A, 11427 RSSExpandedReader.FINDER_PAT_B, 11428 RSSExpandedReader.FINDER_PAT_B, 11429 RSSExpandedReader.FINDER_PAT_C, 11430 RSSExpandedReader.FINDER_PAT_C, 11431 RSSExpandedReader.FINDER_PAT_D, 11432 RSSExpandedReader.FINDER_PAT_D, 11433 ], 11434 [ 11435 RSSExpandedReader.FINDER_PAT_A, 11436 RSSExpandedReader.FINDER_PAT_A, 11437 RSSExpandedReader.FINDER_PAT_B, 11438 RSSExpandedReader.FINDER_PAT_B, 11439 RSSExpandedReader.FINDER_PAT_C, 11440 RSSExpandedReader.FINDER_PAT_C, 11441 RSSExpandedReader.FINDER_PAT_D, 11442 RSSExpandedReader.FINDER_PAT_E, 11443 RSSExpandedReader.FINDER_PAT_E, 11444 ], 11445 [ 11446 RSSExpandedReader.FINDER_PAT_A, 11447 RSSExpandedReader.FINDER_PAT_A, 11448 RSSExpandedReader.FINDER_PAT_B, 11449 RSSExpandedReader.FINDER_PAT_B, 11450 RSSExpandedReader.FINDER_PAT_C, 11451 RSSExpandedReader.FINDER_PAT_C, 11452 RSSExpandedReader.FINDER_PAT_D, 11453 RSSExpandedReader.FINDER_PAT_E, 11454 RSSExpandedReader.FINDER_PAT_F, 11455 RSSExpandedReader.FINDER_PAT_F, 11456 ], 11457 [ 11458 RSSExpandedReader.FINDER_PAT_A, 11459 RSSExpandedReader.FINDER_PAT_A, 11460 RSSExpandedReader.FINDER_PAT_B, 11461 RSSExpandedReader.FINDER_PAT_B, 11462 RSSExpandedReader.FINDER_PAT_C, 11463 RSSExpandedReader.FINDER_PAT_D, 11464 RSSExpandedReader.FINDER_PAT_D, 11465 RSSExpandedReader.FINDER_PAT_E, 11466 RSSExpandedReader.FINDER_PAT_E, 11467 RSSExpandedReader.FINDER_PAT_F, 11468 RSSExpandedReader.FINDER_PAT_F, 11469 ], 11470 ]; 11471 RSSExpandedReader.MAX_PAIRS = 11; 11472 11473 class Pair extends DataCharacter { 11474 constructor(value, checksumPortion, finderPattern) { 11475 super(value, checksumPortion); 11476 this.count = 0; 11477 this.finderPattern = finderPattern; 11478 } 11479 getFinderPattern() { 11480 return this.finderPattern; 11481 } 11482 getCount() { 11483 return this.count; 11484 } 11485 incrementCount() { 11486 this.count++; 11487 } 11488 } 11489 11490 class RSS14Reader extends AbstractRSSReader { 11491 constructor() { 11492 super(...arguments); 11493 this.possibleLeftPairs = []; 11494 this.possibleRightPairs = []; 11495 } 11496 decodeRow(rowNumber, row, hints) { 11497 const leftPair = this.decodePair(row, false, rowNumber, hints); 11498 RSS14Reader.addOrTally(this.possibleLeftPairs, leftPair); 11499 row.reverse(); 11500 let rightPair = this.decodePair(row, true, rowNumber, hints); 11501 RSS14Reader.addOrTally(this.possibleRightPairs, rightPair); 11502 row.reverse(); 11503 for (let left of this.possibleLeftPairs) { 11504 if (left.getCount() > 1) { 11505 for (let right of this.possibleRightPairs) { 11506 if (right.getCount() > 1 && RSS14Reader.checkChecksum(left, right)) { 11507 return RSS14Reader.constructResult(left, right); 11508 } 11509 } 11510 } 11511 } 11512 throw new NotFoundException(); 11513 } 11514 static addOrTally(possiblePairs, pair) { 11515 if (pair == null) { 11516 return; 11517 } 11518 let found = false;
11519 for (let other of possiblePairs) { 11520 if (other.getValue() === pair.getValue()) { 11521 other.incrementCount(); 11522 found = true; 11523 break; 11524 } 11525 } 11526 if (!found) { 11527 possiblePairs.push(pair); 11528 } 11529 } 11530 reset() { 11531 this.possibleLeftPairs.length = 0; 11532 this.possibleRightPairs.length = 0; 11533 } 11534 static constructResult(leftPair, rightPair) { 11535 let symbolValue = 4537077 * leftPair.getValue() + rightPair.getValue(); 11536 let text = new String(symbolValue).toString(); 11537 let buffer = new StringBuilder(); 11538 for (let i = 13 - text.length; i > 0; i--) { 11539 buffer.append('0'); 11540 } 11541 buffer.append(text); 11542 let checkDigit = 0; 11543 for (let i = 0; i < 13; i++) { 11544 let digit = buffer.charAt(i).charCodeAt(0) - '0'.charCodeAt(0); 11545 checkDigit += ((i & 0x01) === 0) ? 3 * digit : digit; 11546 } 11547 checkDigit = 10 - (checkDigit % 10); 11548 if (checkDigit === 10) { 11549 checkDigit = 0; 11550 } 11551 buffer.append(checkDigit.toString()); 11552 let leftPoints = leftPair.getFinderPattern().getResultPoints(); 11553 let rightPoints = rightPair.getFinderPattern().getResultPoints(); 11554 return new Result$1(buffer.toString(), null, 0, [leftPoints[0], leftPoints[1], rightPoints[0], rightPoints[1]], BarcodeFormat$1.RSS_14, new Date().getTime()); 11555 } 11556 static checkChecksum(leftPair, rightPair) { 11557 let checkValue = (leftPair.getChecksumPortion() + 16 * rightPair.getChecksumPortion()) % 79; 11558 let targetCheckValue = 9 * leftPair.getFinderPattern().getValue() + rightPair.getFinderPattern().getValue(); 11559 if (targetCheckValue > 72) { 11560 targetCheckValue--; 11561 } 11562 if (targetCheckValue > 8) { 11563 targetCheckValue--; 11564 } 11565 return checkValue === targetCheckValue; 11566 } 11567 decodePair(row, right, rowNumber, hints) { 11568 try { 11569 let startEnd = this.findFinderPattern(row, right); 11570 let pattern = this.parseFoundFinderPattern(row, rowNumber, right, startEnd); 11571 let resultPointCallback = hints == null ? null : hints.get(DecodeHintType$1.NEED_RESULT_POINT_CALLBACK); 11572 if (resultPointCallback != null) { 11573 let center = (startEnd[0] + startEnd[1]) / 2.0; 11574 if (right) { 11575 // row is actually reversed 11576 center = row.getSize() - 1 - center; 11577 } 11578 resultPointCallback.foundPossibleResultPoint(new ResultPoint(center, rowNumber)); 11579 } 11580 let outside = this.decodeDataCharacter(row, pattern, true); 11581 let inside = this.decodeDataCharacter(row, pattern, false); 11582 return new Pair(1597 * outside.getValue() + inside.getValue(), outside.getChecksumPortion() + 4 * inside.getChecksumPortion(), pattern); 11583 } 11584 catch (err) { 11585 return null; 11586 } 11587 } 11588 decodeDataCharacter(row, pattern, outsideChar) { 11589 let counters = this.getDataCharacterCounters(); 11590 for (let x = 0; x < counters.length; x++) { 11591 counters[x] = 0; 11592 } 11593 if (outsideChar) { 11594 OneDReader.recordPatternInReverse(row, pattern.getStartEnd()[0], counters); 11595 } 11596 else { 11597 OneDReader.recordPattern(row, pattern.getStartEnd()[1] + 1, counters); 11598 // reverse it 11599 for (let i = 0, j = counters.length - 1; i < j; i++, j--) { 11600 let temp = counters[i]; 11601 counters[i] = counters[j]; 11602 counters[j] = temp; 11603 } 11604 } 11605 let numModules = outsideChar ? 16 : 15; 11606 let elementWidth = MathUtils.sum(new Int32Array(counters)) / numModules; 11607 let oddCounts = this.getOddCounts(); 11608 let evenCounts = this.getEvenCounts(); 11609 let oddRoundingErrors = this.getOddRoundingErrors(); 11610 let evenRoundingErrors = this.getEvenRoundingErrors(); 11611 for (let i = 0; i < counters.length; i++) { 11612 let value = counters[i] / elementWidth; 11613 let count = Math.floor(value + 0.5); 11614 if (count < 1) { 11615 count = 1; 11616 } 11617 else if (count > 8) { 11618 count = 8; 11619 } 11620 let offset = Math.floor(i / 2); 11621 if ((i & 0x01) === 0) { 11622 oddCounts[offset] = count; 11623 oddRoundingErrors[offset] = value - count; 11624 } 11625 else { 11626 evenCounts[offset] = count; 11627 evenRoundingErrors[offset] = value - count; 11628 } 11629 } 11630 this.adjustOddEvenCounts(outsideChar, numModules); 11631 let oddSum = 0; 11632 let oddChecksumPortion = 0; 11633 for (let i = oddCounts.length - 1; i >= 0; i--) { 11634 oddChecksumPortion *= 9; 11635 oddChecksumPortion += oddCounts[i]; 11636 oddSum += oddCounts[i]; 11637 } 11638 let evenChecksumPortion = 0; 11639 let evenSum = 0; 11640 for (let i = evenCounts.length - 1; i >= 0; i--) { 11641 evenChecksumPortion *= 9; 11642 evenChecksumPortion += evenCounts[i]; 11643 evenSum += evenCounts[i]; 11644 } 11645 let checksumPortion = oddChecksumPortion + 3 * evenChecksumPortion; 11646 if (outsideChar) { 11647 if ((oddSum & 0x01) !== 0 || oddSum > 12 || oddSum < 4) { 11648 throw new NotFoundException(); 11649 } 11650 let group = (12 - oddSum) / 2; 11651 let oddWidest = RSS14Reader.OUTSIDE_ODD_WIDEST[group]; 11652 let evenWidest = 9 - oddWidest; 11653 let vOdd = RSSUtils.getRSSvalue(oddCounts, oddWidest, false); 11654 let vEven = RSSUtils.getRSSvalue(evenCounts, evenWidest, true); 11655 let tEven = RSS14Reader.OUTSIDE_EVEN_TOTAL_SUBSET[group]; 11656 let gSum = RSS14Reader.OUTSIDE_GSUM[group]; 11657 return new DataCharacter(vOdd * tEven + vEven + gSum, checksumPortion); 11658 } 11659 else { 11660 if ((evenSum & 0x01) !== 0 || evenSum > 10 || evenSum < 4) { 11661 throw new NotFoundException(); 11662 } 11663 let group = (10 - evenSum) / 2; 11664 let oddWidest = RSS14Reader.INSIDE_ODD_WIDEST[group]; 11665 let evenWidest = 9 - oddWidest; 11666 let vOdd = RSSUtils.getRSSvalue(oddCounts, oddWidest, true); 11667 let vEven = RSSUtils.getRSSvalue(evenCounts, evenWidest, false); 11668 let tOdd = RSS14Reader.INSIDE_ODD_TOTAL_SUBSET[group]; 11669 let gSum = RSS14Reader.INSIDE_GSUM[group]; 11670 return new DataCharacter(vEven * tOdd + vOdd + gSum, checksumPortion); 11671 } 11672 } 11673 findFinderPattern(row, rightFinderPattern) { 11674 let counters = this.getDecodeFinderCounters(); 11675 counters[0] = 0; 11676 counters[1] = 0; 11677 counters[2] = 0; 11678 counters[3] = 0; 11679 let width = row.getSize(); 11680 let isWhite = false;
vendor: 18,521 bytes, lines 11681-12134
11681 let rowOffset = 0; 11682 while (rowOffset < width) { 11683 isWhite = !row.get(rowOffset); 11684 if (rightFinderPattern === isWhite) { 11685 // Will encounter white first when searching for right finder pattern 11686 break; 11687 } 11688 rowOffset++; 11689 } 11690 let counterPosition = 0; 11691 let patternStart = rowOffset; 11692 for (let x = rowOffset; x < width; x++) { 11693 if (row.get(x) !== isWhite) { 11694 counters[counterPosition]++; 11695 } 11696 else { 11697 if (counterPosition === 3) { 11698 if (AbstractRSSReader.isFinderPattern(counters)) { 11699 return [patternStart, x]; 11700 } 11701 patternStart += counters[0] + counters[1]; 11702 counters[0] = counters[2]; 11703 counters[1] = counters[3]; 11704 counters[2] = 0; 11705 counters[3] = 0; 11706 counterPosition--; 11707 } 11708 else { 11709 counterPosition++; 11710 } 11711 counters[counterPosition] = 1; 11712 isWhite = !isWhite; 11713 } 11714 } 11715 throw new NotFoundException(); 11716 } 11717 parseFoundFinderPattern(row, rowNumber, right, startEnd) { 11718 // Actually we found elements 2-5 11719 let firstIsBlack = row.get(startEnd[0]); 11720 let firstElementStart = startEnd[0] - 1; 11721 // Locate element 1 11722 while (firstElementStart >= 0 && firstIsBlack !== row.get(firstElementStart)) { 11723 firstElementStart--; 11724 } 11725 firstElementStart++; 11726 const firstCounter = startEnd[0] - firstElementStart; 11727 // Make 'counters' hold 1-4 11728 const counters = this.getDecodeFinderCounters(); 11729 const copy = new Int32Array(counters.length); 11730 System.arraycopy(counters, 0, copy, 1, counters.length - 1); 11731 copy[0] = firstCounter; 11732 const value = this.parseFinderValue(copy, RSS14Reader.FINDER_PATTERNS); 11733 let start = firstElementStart; 11734 let end = startEnd[1]; 11735 if (right) { 11736 // row is actually reversed 11737 start = row.getSize() - 1 - start; 11738 end = row.getSize() - 1 - end; 11739 } 11740 return new FinderPattern$1(value, [firstElementStart, startEnd[1]], start, end, rowNumber); 11741 } 11742 adjustOddEvenCounts(outsideChar, numModules) { 11743 let oddSum = MathUtils.sum(new Int32Array(this.getOddCounts())); 11744 let evenSum = MathUtils.sum(new Int32Array(this.getEvenCounts())); 11745 let incrementOdd = false; 11746 let decrementOdd = false; 11747 let incrementEven = false; 11748 let decrementEven = false; 11749 if (outsideChar) { 11750 if (oddSum > 12) { 11751 decrementOdd = true; 11752 } 11753 else if (oddSum < 4) { 11754 incrementOdd = true; 11755 } 11756 if (evenSum > 12) { 11757 decrementEven = true; 11758 } 11759 else if (evenSum < 4) { 11760 incrementEven = true; 11761 } 11762 } 11763 else { 11764 if (oddSum > 11) { 11765 decrementOdd = true; 11766 } 11767 else if (oddSum < 5) { 11768 incrementOdd = true; 11769 } 11770 if (evenSum > 10) { 11771 decrementEven = true; 11772 } 11773 else if (evenSum < 4) { 11774 incrementEven = true; 11775 } 11776 } 11777 let mismatch = oddSum + evenSum - numModules; 11778 let oddParityBad = (oddSum & 0x01) === (outsideChar ? 1 : 0); 11779 let evenParityBad = (evenSum & 0x01) === 1; 11780 if (mismatch === 1) { 11781 if (oddParityBad) { 11782 if (evenParityBad) { 11783 throw new NotFoundException(); 11784 } 11785 decrementOdd = true; 11786 } 11787 else { 11788 if (!evenParityBad) { 11789 throw new NotFoundException(); 11790 } 11791 decrementEven = true; 11792 } 11793 } 11794 else if (mismatch === -1) { 11795 if (oddParityBad) { 11796 if (evenParityBad) { 11797 throw new NotFoundException(); 11798 } 11799 incrementOdd = true; 11800 } 11801 else { 11802 if (!evenParityBad) { 11803 throw new NotFoundException(); 11804 } 11805 incrementEven = true; 11806 } 11807 } 11808 else if (mismatch === 0) { 11809 if (oddParityBad) { 11810 if (!evenParityBad) { 11811 throw new NotFoundException(); 11812 } 11813 // Both bad 11814 if (oddSum < evenSum) { 11815 incrementOdd = true; 11816 decrementEven = true; 11817 } 11818 else { 11819 decrementOdd = true; 11820 incrementEven = true; 11821 } 11822 } 11823 else { 11824 if (evenParityBad) { 11825 throw new NotFoundException(); 11826 } 11827 // Nothing to do! 11828 } 11829 } 11830 else { 11831 throw new NotFoundException(); 11832 } 11833 if (incrementOdd) { 11834 if (decrementOdd) { 11835 throw new NotFoundException(); 11836 } 11837 AbstractRSSReader.increment(this.getOddCounts(), this.getOddRoundingErrors()); 11838 } 11839 if (decrementOdd) { 11840 AbstractRSSReader.decrement(this.getOddCounts(), this.getOddRoundingErrors()); 11841 } 11842 if (incrementEven) { 11843 if (decrementEven) { 11844 throw new NotFoundException(); 11845 } 11846 AbstractRSSReader.increment(this.getEvenCounts(), this.getOddRoundingErrors()); 11847 } 11848 if (decrementEven) { 11849 AbstractRSSReader.decrement(this.getEvenCounts(), this.getEvenRoundingErrors()); 11850 } 11851 } 11852 } 11853 RSS14Reader.OUTSIDE_EVEN_TOTAL_SUBSET = [1, 10, 34, 70, 126]; 11854 RSS14Reader.INSIDE_ODD_TOTAL_SUBSET = [4, 20, 48, 81]; 11855 RSS14Reader.OUTSIDE_GSUM = [0, 161, 961, 2015, 2715]; 11856 RSS14Reader.INSIDE_GSUM = [0, 336, 1036, 1516]; 11857 RSS14Reader.OUTSIDE_ODD_WIDEST = [8, 6, 4, 3, 1]; 11858 RSS14Reader.INSIDE_ODD_WIDEST = [2, 4, 6, 8]; 11859 RSS14Reader.FINDER_PATTERNS = [ 11860 Int32Array.from([3, 8, 2, 1]), 11861 Int32Array.from([3, 5, 5, 1]), 11862 Int32Array.from([3, 3, 7, 1]), 11863 Int32Array.from([3, 1, 9, 1]), 11864 Int32Array.from([2, 7, 4, 1]), 11865 Int32Array.from([2, 5, 6, 1]), 11866 Int32Array.from([2, 3, 8, 1]), 11867 Int32Array.from([1, 5, 7, 1]), 11868 Int32Array.from([1, 3, 9, 1]), 11869 ]; 11870 11871 /* 11872 * Copyright 2008 ZXing authors 11873 * 11874 * Licensed under the Apache License, Version 2.0 (the "License"); 11875 * you may not use this file except in compliance with the License. 11876 * You may obtain a copy of the License at 11877 * 11878 * http://www.apache.org/licenses/LICENSE-2.0 11879 * 11880 * Unless required by applicable law or agreed to in writing, software 11881 * distributed under the License is distributed on an "AS IS" BASIS, 11882 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11883 * See the License for the specific language governing permissions and 11884 * limitations under the License. 11885 */ 11886 /** 11887 * @author Daniel Switkin <[email protected]> 11888 * @author Sean Owen 11889 */ 11890 class MultiFormatOneDReader extends OneDReader { 11891 constructor(hints) { 11892 super(); 11893 this.readers = []; 11894 const possibleFormats = !hints ? null : hints.get(DecodeHintType$1.POSSIBLE_FORMATS); 11895 const useCode39CheckDigit = hints && hints.get(DecodeHintType$1.ASSUME_CODE_39_CHECK_DIGIT) !== undefined; 11896 const useCode39ExtendedMode = hints && hints.get(DecodeHintType$1.ENABLE_CODE_39_EXTENDED_MODE) !== undefined; 11897 if (possibleFormats) { 11898 if (possibleFormats.includes(BarcodeFormat$1.EAN_13) || 11899 possibleFormats.includes(BarcodeFormat$1.UPC_A) || 11900 possibleFormats.includes(BarcodeFormat$1.EAN_8) || 11901 possibleFormats.includes(BarcodeFormat$1.UPC_E)) { 11902 this.readers.push(new MultiFormatUPCEANReader(hints)); 11903 } 11904 if (possibleFormats.includes(BarcodeFormat$1.CODE_39)) { 11905 this.readers.push(new Code39Reader(useCode39CheckDigit, useCode39ExtendedMode)); 11906 } 11907 if (possibleFormats.includes(BarcodeFormat$1.CODE_93)) { 11908 this.readers.push(new Code93Reader()); 11909 } 11910 if (possibleFormats.includes(BarcodeFormat$1.CODE_128)) { 11911 this.readers.push(new Code128Reader()); 11912 } 11913 if (possibleFormats.includes(BarcodeFormat$1.ITF)) { 11914 this.readers.push(new ITFReader()); 11915 } 11916 if (possibleFormats.includes(BarcodeFormat$1.CODABAR)) { 11917 this.readers.push(new CodaBarReader()); 11918 } 11919 if (possibleFormats.includes(BarcodeFormat$1.RSS_14)) { 11920 this.readers.push(new RSS14Reader()); 11921 } 11922 if (possibleFormats.includes(BarcodeFormat$1.RSS_EXPANDED)) { 11923 console.warn('RSS Expanded reader IS NOT ready for production yet! use at your own risk.'); 11924 this.readers.push(new RSSExpandedReader()); 11925 } 11926 } 11927 if (this.readers.length === 0) { 11928 this.readers.push(new MultiFormatUPCEANReader(hints)); 11929 this.readers.push(new Code39Reader()); 11930 // this.readers.push(new CodaBarReader()); 11931 this.readers.push(new Code93Reader()); 11932 this.readers.push(new MultiFormatUPCEANReader(hints)); 11933 this.readers.push(new Code128Reader()); 11934 this.readers.push(new ITFReader()); 11935 this.readers.push(new RSS14Reader()); 11936 // this.readers.push(new RSSExpandedReader()); 11937 } 11938 } 11939 // @Override 11940 decodeRow(rowNumber, row, hints) { 11941 for (let i = 0; i < this.readers.length; i++) { 11942 try { 11943 return this.readers[i].decodeRow(rowNumber, row, hints); 11944 } 11945 catch (re) { 11946 // continue 11947 } 11948 } 11949 throw new NotFoundException(); 11950 } 11951 // @Override 11952 reset() { 11953 this.readers.forEach(reader => reader.reset()); 11954 } 11955 } 11956 11957 /** 11958 * @deprecated Moving to @zxing/browser 11959 * 11960 * Barcode reader reader to use from browser. 11961 */ 11962 class BrowserBarcodeReader extends BrowserCodeReader { 11963 /** 11964 * Creates an instance of BrowserBarcodeReader. 11965 * @param {number} [timeBetweenScansMillis=500] the time delay between subsequent decode tries 11966 * @param {Map<DecodeHintType, any>} hints 11967 */ 11968 constructor(timeBetweenScansMillis = 500, hints) { 11969 super(new MultiFormatOneDReader(hints), timeBetweenScansMillis, hints); 11970 } 11971 } 11972 11973 /* 11974 * Copyright 2007 ZXing authors 11975 * 11976 * Licensed under the Apache License, Version 2.0 (the "License"); 11977 * you may not use this file except in compliance with the License. 11978 * You may obtain a copy of the License at 11979 * 11980 * http://www.apache.org/licenses/LICENSE-2.0 11981 * 11982 * Unless required by applicable law or agreed to in writing, software 11983 * distributed under the License is distributed on an "AS IS" BASIS, 11984 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11985 * See the License for the specific language governing permissions and 11986 * limitations under the License. 11987 */ 11988 /** 11989 * <p>Encapsulates a set of error-correction blocks in one symbol version. Most versions will 11990 * use blocks of differing sizes within one version, so, this encapsulates the parameters for 11991 * each set of blocks. It also holds the number of error-correction codewords per block since it 11992 * will be the same across all blocks within one version.</p> 11993 */ 11994 class ECBlocks$1 { 11995 constructor(ecCodewords, ecBlocks1, ecBlocks2) { 11996 this.ecCodewords = ecCodewords; 11997 this.ecBlocks = [ecBlocks1]; 11998 ecBlocks2 && this.ecBlocks.push(ecBlocks2); 11999 } 12000 getECCodewords() { 12001 return this.ecCodewords; 12002 } 12003 getECBlocks() { 12004 return this.ecBlocks; 12005 } 12006 } 12007 /** 12008 * <p>Encapsulates the parameters for one error-correction block in one symbol version. 12009 * This includes the number of data codewords, and the number of times a block with these 12010 * parameters is used consecutively in the Data Matrix code version's format.</p> 12011 */ 12012 class ECB$1 { 12013 constructor(count, dataCodewords) { 12014 this.count = count; 12015 this.dataCodewords = dataCodewords; 12016 } 12017 getCount() { 12018 return this.count; 12019 } 12020 getDataCodewords() { 12021 return this.dataCodewords; 12022 } 12023 } 12024 /** 12025 * The Version object encapsulates attributes about a particular 12026 * size Data Matrix Code. 12027 * 12028 * @author [email protected] (Brian Brown) 12029 */ 12030 class Version$1 { 12031 constructor(versionNumber, symbolSizeRows, symbolSizeColumns, dataRegionSizeRows, dataRegionSizeColumns, ecBlocks) { 12032 this.versionNumber = versionNumber; 12033 this.symbolSizeRows = symbolSizeRows; 12034 this.symbolSizeColumns = symbolSizeColumns; 12035 this.dataRegionSizeRows = dataRegionSizeRows; 12036 this.dataRegionSizeColumns = dataRegionSizeColumns; 12037 this.ecBlocks = ecBlocks; 12038 // Calculate the total number of codewords 12039 let total = 0; 12040 const ecCodewords = ecBlocks.getECCodewords(); 12041 const ecbArray = ecBlocks.getECBlocks(); 12042 for (let ecBlock of ecbArray) { 12043 total += ecBlock.getCount() * (ecBlock.getDataCodewords() + ecCodewords); 12044 } 12045 this.totalCodewords = total; 12046 } 12047 getVersionNumber() { 12048 return this.versionNumber; 12049 } 12050 getSymbolSizeRows() { 12051 return this.symbolSizeRows; 12052 } 12053 getSymbolSizeColumns() { 12054 return this.symbolSizeColumns; 12055 } 12056 getDataRegionSizeRows() { 12057 return this.dataRegionSizeRows; 12058 } 12059 getDataRegionSizeColumns() { 12060 return this.dataRegionSizeColumns; 12061 } 12062 getTotalCodewords() { 12063 return this.totalCodewords; 12064 } 12065 getECBlocks() { 12066 return this.ecBlocks; 12067 } 12068 /** 12069 * <p>Deduces version information from Data Matrix dimensions.</p> 12070 * 12071 * @param numRows Number of rows in modules 12072 * @param numColumns Number of columns in modules 12073 * @return Version for a Data Matrix Code of those dimensions 12074 * @throws FormatException if dimensions do correspond to a valid Data Matrix size 12075 */ 12076 static getVersionForDimensions(numRows, numColumns) { 12077 if ((numRows & 0x01) !== 0 || (numColumns & 0x01) !== 0) { 12078 throw new FormatException(); 12079 } 12080 for (let version of Version$1.VERSIONS) { 12081 if (version.symbolSizeRows === numRows && version.symbolSizeColumns === numColumns) { 12082 return version; 12083 } 12084 } 12085 throw new FormatException(); 12086 } 12087 // @Override 12088 toString() { 12089 return '' + this.versionNumber; 12090 } 12091 /** 12092 * See ISO 16022:2006 5.5.1 Table 7 12093 */ 12094 static buildVersions() { 12095 return [ 12096 new Version$1(1, 10, 10, 8, 8, new ECBlocks$1(5, new ECB$1(1, 3))), 12097 new Version$1(2, 12, 12, 10, 10, new ECBlocks$1(7, new ECB$1(1, 5))), 12098 new Version$1(3, 14, 14, 12, 12, new ECBlocks$1(10, new ECB$1(1, 8))), 12099 new Version$1(4, 16, 16, 14, 14, new ECBlocks$1(12, new ECB$1(1, 12))), 12100 new Version$1(5, 18, 18, 16, 16, new ECBlocks$1(14, new ECB$1(1, 18))), 12101 new Version$1(6, 20, 20, 18, 18, new ECBlocks$1(18, new ECB$1(1, 22))), 12102 new Version$1(7, 22, 22, 20, 20, new ECBlocks$1(20, new ECB$1(1, 30))), 12103 new Version$1(8, 24, 24, 22, 22, new ECBlocks$1(24, new ECB$1(1, 36))), 12104 new Version$1(9, 26, 26, 24, 24, new ECBlocks$1(28, new ECB$1(1, 44))), 12105 new Version$1(10, 32, 32, 14, 14, new ECBlocks$1(36, new ECB$1(1, 62))), 12106 new Version$1(11, 36, 36, 16, 16, new ECBlocks$1(42, new ECB$1(1, 86))), 12107 new Version$1(12, 40, 40, 18, 18, new ECBlocks$1(48, new ECB$1(1, 114))), 12108 new Version$1(13, 44, 44, 20, 20, new ECBlocks$1(56, new ECB$1(1, 144))), 12109 new Version$1(14, 48, 48, 22, 22, new ECBlocks$1(68, new ECB$1(1, 174))), 12110 new Version$1(15, 52, 52, 24, 24, new ECBlocks$1(42, new ECB$1(2, 102))), 12111 new Version$1(16, 64, 64, 14, 14, new ECBlocks$1(56, new ECB$1(2, 140))), 12112 new Version$1(17, 72, 72, 16, 16, new ECBlocks$1(36, new ECB$1(4, 92))), 12113 new Version$1(18, 80, 80, 18, 18, new ECBlocks$1(48, new ECB$1(4, 114))), 12114 new Version$1(19, 88, 88, 20, 20, new ECBlocks$1(56, new ECB$1(4, 144))), 12115 new Version$1(20, 96, 96, 22, 22, new ECBlocks$1(68, new ECB$1(4, 174))), 12116 new Version$1(21, 104, 104, 24, 24, new ECBlocks$1(56, new ECB$1(6, 136))), 12117 new Version$1(22, 120, 120, 18, 18, new ECBlocks$1(68, new ECB$1(6, 175))), 12118 new Version$1(23, 132, 132, 20, 20, new ECBlocks$1(62, new ECB$1(8, 163))), 12119 new Version$1(24, 144, 144, 22, 22, new ECBlocks$1(62, new ECB$1(8, 156), new ECB$1(2, 155))), 12120 new Version$1(25, 8, 18, 6, 16, new ECBlocks$1(7, new ECB$1(1, 5))), 12121 new Version$1(26, 8, 32, 6, 14, new ECBlocks$1(11, new ECB$1(1, 10))), 12122 new Version$1(27, 12, 26, 10, 24, new ECBlocks$1(14, new ECB$1(1, 16))), 12123 new Version$1(28, 12, 36, 10, 16, new ECBlocks$1(18, new ECB$1(1, 22))), 12124 new Version$1(29, 16, 36, 14, 16, new ECBlocks$1(24, new ECB$1(1, 32))), 12125 new Version$1(30, 16, 48, 14, 22, new ECBlocks$1(28, new ECB$1(1, 49))) 12126 ]; 12127 } 12128 } 12129 Version$1.VERSIONS = Version$1.buildVersions(); 12130 12131 /* 12132 * Copyright 2007 ZXing authors 12133 * 12134 * Licensed under the Apache License, Version 2.0 (the "License");
12135 * you may not use this file except in compliance with the License. 12136 * You may obtain a copy of the License at 12137 * 12138 * http://www.apache.org/licenses/LICENSE-2.0 12139 * 12140 * Unless required by applicable law or agreed to in writing, software 12141 * distributed under the License is distributed on an "AS IS" BASIS, 12142 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12143 * See the License for the specific language governing permissions and 12144 * limitations under the License. 12145 */ 12146 /** 12147 * @author [email protected] (Brian Brown) 12148 */ 12149 class BitMatrixParser$1 { 12150 /** 12151 * @param bitMatrix {@link BitMatrix} to parse 12152 * @throws FormatException if dimension is < 8 or > 144 or not 0 mod 2 12153 */ 12154 constructor(bitMatrix) { 12155 const dimension = bitMatrix.getHeight(); 12156 if (dimension < 8 || dimension > 144 || (dimension & 0x01) !== 0) { 12157 throw new FormatException(); 12158 } 12159 this.version = BitMatrixParser$1
vendor: 15,862 bytes, lines 12159-12539
12159.readVersion(bitMatrix); 12160 this.mappingBitMatrix = this.extractDataRegion(bitMatrix); 12161 this.readMappingMatrix = new BitMatrix(this.mappingBitMatrix.getWidth(), this.mappingBitMatrix.getHeight()); 12162 } 12163 getVersion() { 12164 return this.version; 12165 } 12166 /** 12167 * <p>Creates the version object based on the dimension of the original bit matrix from 12168 * the datamatrix code.</p> 12169 * 12170 * <p>See ISO 16022:2006 Table 7 - ECC 200 symbol attributes</p> 12171 * 12172 * @param bitMatrix Original {@link BitMatrix} including alignment patterns 12173 * @return {@link Version} encapsulating the Data Matrix Code's "version" 12174 * @throws FormatException if the dimensions of the mapping matrix are not valid 12175 * Data Matrix dimensions. 12176 */ 12177 static readVersion(bitMatrix) { 12178 const numRows = bitMatrix.getHeight(); 12179 const numColumns = bitMatrix.getWidth(); 12180 return Version$1.getVersionForDimensions(numRows, numColumns); 12181 } 12182 /** 12183 * <p>Reads the bits in the {@link BitMatrix} representing the mapping matrix (No alignment patterns) 12184 * in the correct order in order to reconstitute the codewords bytes contained within the 12185 * Data Matrix Code.</p> 12186 * 12187 * @return bytes encoded within the Data Matrix Code 12188 * @throws FormatException if the exact number of bytes expected is not read 12189 */ 12190 readCodewords() { 12191 const result = new Int8Array(this.version.getTotalCodewords()); 12192 let resultOffset = 0; 12193 let row = 4; 12194 let column = 0; 12195 const numRows = this.mappingBitMatrix.getHeight(); 12196 const numColumns = this.mappingBitMatrix.getWidth(); 12197 let corner1Read = false; 12198 let corner2Read = false; 12199 let corner3Read = false; 12200 let corner4Read = false; 12201 // Read all of the codewords 12202 do { 12203 // Check the four corner cases 12204 if ((row === numRows) && (column === 0) && !corner1Read) { 12205 result[resultOffset++] = this.readCorner1(numRows, numColumns) & 0xff; 12206 row -= 2; 12207 column += 2; 12208 corner1Read = true; 12209 } 12210 else if ((row === numRows - 2) && (column === 0) && ((numColumns & 0x03) !== 0) && !corner2Read) { 12211 result[resultOffset++] = this.readCorner2(numRows, numColumns) & 0xff; 12212 row -= 2; 12213 column += 2; 12214 corner2Read = true; 12215 } 12216 else if ((row === numRows + 4) && (column === 2) && ((numColumns & 0x07) === 0) && !corner3Read) { 12217 result[resultOffset++] = this.readCorner3(numRows, numColumns) & 0xff; 12218 row -= 2; 12219 column += 2; 12220 corner3Read = true; 12221 } 12222 else if ((row === numRows - 2) && (column === 0) && ((numColumns & 0x07) === 4) && !corner4Read) { 12223 result[resultOffset++] = this.readCorner4(numRows, numColumns) & 0xff; 12224 row -= 2; 12225 column += 2; 12226 corner4Read = true; 12227 } 12228 else { 12229 // Sweep upward diagonally to the right 12230 do { 12231 if ((row < numRows) && (column >= 0) && !this.readMappingMatrix.get(column, row)) { 12232 result[resultOffset++] = this.readUtah(row, column, numRows, numColumns) & 0xff; 12233 } 12234 row -= 2; 12235 column += 2; 12236 } while ((row >= 0) && (column < numColumns)); 12237 row += 1; 12238 column += 3; 12239 // Sweep downward diagonally to the left 12240 do { 12241 if ((row >= 0) && (column < numColumns) && !this.readMappingMatrix.get(column, row)) { 12242 result[resultOffset++] = this.readUtah(row, column, numRows, numColumns) & 0xff; 12243 } 12244 row += 2; 12245 column -= 2; 12246 } while ((row < numRows) && (column >= 0)); 12247 row += 3; 12248 column += 1; 12249 } 12250 } while ((row < numRows) || (column < numColumns)); 12251 if (resultOffset !== this.version.getTotalCodewords()) { 12252 throw new FormatException(); 12253 } 12254 return result; 12255 } 12256 /** 12257 * <p>Reads a bit of the mapping matrix accounting for boundary wrapping.</p> 12258 * 12259 * @param row Row to read in the mapping matrix 12260 * @param column Column to read in the mapping matrix 12261 * @param numRows Number of rows in the mapping matrix 12262 * @param numColumns Number of columns in the mapping matrix 12263 * @return value of the given bit in the mapping matrix 12264 */ 12265 readModule(row, column, numRows, numColumns) { 12266 // Adjust the row and column indices based on boundary wrapping 12267 if (row < 0) { 12268 row += numRows; 12269 column += 4 - ((numRows + 4) & 0x07); 12270 } 12271 if (column < 0) { 12272 column += numColumns; 12273 row += 4 - ((numColumns + 4) & 0x07); 12274 } 12275 this.readMappingMatrix.set(column, row); 12276 return this.mappingBitMatrix.get(column, row); 12277 } 12278 /** 12279 * <p>Reads the 8 bits of the standard Utah-shaped pattern.</p> 12280 * 12281 * <p>See ISO 16022:2006, 5.8.1 Figure 6</p> 12282 * 12283 * @param row Current row in the mapping matrix, anchored at the 8th bit (LSB) of the pattern 12284 * @param column Current column in the mapping matrix, anchored at the 8th bit (LSB) of the pattern 12285 * @param numRows Number of rows in the mapping matrix 12286 * @param numColumns Number of columns in the mapping matrix 12287 * @return byte from the utah shape 12288 */ 12289 readUtah(row, column, numRows, numColumns) { 12290 let currentByte = 0; 12291 if (this.readModule(row - 2, column - 2, numRows, numColumns)) { 12292 currentByte |= 1; 12293 } 12294 currentByte <<= 1; 12295 if (this.readModule(row - 2, column - 1, numRows, numColumns)) { 12296 currentByte |= 1; 12297 } 12298 currentByte <<= 1; 12299 if (this.readModule(row - 1, column - 2, numRows, numColumns)) { 12300 currentByte |= 1; 12301 } 12302 currentByte <<= 1; 12303 if (this.readModule(row - 1, column - 1, numRows, numColumns)) { 12304 currentByte |= 1; 12305 } 12306 currentByte <<= 1; 12307 if (this.readModule(row - 1, column, numRows, numColumns)) { 12308 currentByte |= 1; 12309 } 12310 currentByte <<= 1; 12311 if (this.readModule(row, column - 2, numRows, numColumns)) { 12312 currentByte |= 1; 12313 } 12314 currentByte <<= 1; 12315 if (this.readModule(row, column - 1, numRows, numColumns)) { 12316 currentByte |= 1; 12317 } 12318 currentByte <<= 1; 12319 if (this.readModule(row, column, numRows, numColumns)) { 12320 currentByte |= 1; 12321 } 12322 return currentByte; 12323 } 12324 /** 12325 * <p>Reads the 8 bits of the special corner condition 1.</p> 12326 * 12327 * <p>See ISO 16022:2006, Figure F.3</p> 12328 * 12329 * @param numRows Number of rows in the mapping matrix 12330 * @param numColumns Number of columns in the mapping matrix 12331 * @return byte from the Corner condition 1 12332 */ 12333 readCorner1(numRows, numColumns) { 12334 let currentByte = 0; 12335 if (this.readModule(numRows - 1, 0, numRows, numColumns)) { 12336 currentByte |= 1; 12337 } 12338 currentByte <<= 1; 12339 if (this.readModule(numRows - 1, 1, numRows, numColumns)) { 12340 currentByte |= 1; 12341 } 12342 currentByte <<= 1; 12343 if (this.readModule(numRows - 1, 2, numRows, numColumns)) { 12344 currentByte |= 1; 12345 } 12346 currentByte <<= 1; 12347 if (this.readModule(0, numColumns - 2, numRows, numColumns)) { 12348 currentByte |= 1; 12349 } 12350 currentByte <<= 1; 12351 if (this.readModule(0, numColumns - 1, numRows, numColumns)) { 12352 currentByte |= 1; 12353 } 12354 currentByte <<= 1; 12355 if (this.readModule(1, numColumns - 1, numRows, numColumns)) { 12356 currentByte |= 1; 12357 } 12358 currentByte <<= 1; 12359 if (this.readModule(2, numColumns - 1, numRows, numColumns)) { 12360 currentByte |= 1; 12361 } 12362 currentByte <<= 1; 12363 if (this.readModule(3, numColumns - 1, numRows, numColumns)) { 12364 currentByte |= 1; 12365 } 12366 return currentByte; 12367 } 12368 /** 12369 * <p>Reads the 8 bits of the special corner condition 2.</p> 12370 * 12371 * <p>See ISO 16022:2006, Figure F.4</p> 12372 * 12373 * @param numRows Number of rows in the mapping matrix 12374 * @param numColumns Number of columns in the mapping matrix 12375 * @return byte from the Corner condition 2 12376 */ 12377 readCorner2(numRows, numColumns) { 12378 let currentByte = 0; 12379 if (this.readModule(numRows - 3, 0, numRows, numColumns)) { 12380 currentByte |= 1; 12381 } 12382 currentByte <<= 1; 12383 if (this.readModule(numRows - 2, 0, numRows, numColumns)) { 12384 currentByte |= 1; 12385 } 12386 currentByte <<= 1; 12387 if (this.readModule(numRows - 1, 0, numRows, numColumns)) { 12388 currentByte |= 1; 12389 } 12390 currentByte <<= 1; 12391 if (this.readModule(0, numColumns - 4, numRows, numColumns)) { 12392 currentByte |= 1; 12393 } 12394 currentByte <<= 1; 12395 if (this.readModule(0, numColumns - 3, numRows, numColumns)) { 12396 currentByte |= 1; 12397 } 12398 currentByte <<= 1; 12399 if (this.readModule(0, numColumns - 2, numRows, numColumns)) { 12400 currentByte |= 1; 12401 } 12402 currentByte <<= 1; 12403 if (this.readModule(0, numColumns - 1, numRows, numColumns)) { 12404 currentByte |= 1; 12405 } 12406 currentByte <<= 1; 12407 if (this.readModule(1, numColumns - 1, numRows, numColumns)) { 12408 currentByte |= 1; 12409 } 12410 return currentByte; 12411 } 12412 /** 12413 * <p>Reads the 8 bits of the special corner condition 3.</p> 12414 * 12415 * <p>See ISO 16022:2006, Figure F.5</p> 12416 * 12417 * @param numRows Number of rows in the mapping matrix 12418 * @param numColumns Number of columns in the mapping matrix 12419 * @return byte from the Corner condition 3 12420 */ 12421 readCorner3(numRows, numColumns) { 12422 let currentByte = 0; 12423 if (this.readModule(numRows - 1, 0, numRows, numColumns)) { 12424 currentByte |= 1; 12425 } 12426 currentByte <<= 1; 12427 if (this.readModule(numRows - 1, numColumns - 1, numRows, numColumns)) { 12428 currentByte |= 1; 12429 } 12430 currentByte <<= 1; 12431 if (this.readModule(0, numColumns - 3, numRows, numColumns)) { 12432 currentByte |= 1; 12433 } 12434 currentByte <<= 1; 12435 if (this.readModule(0, numColumns - 2, numRows, numColumns)) { 12436 currentByte |= 1; 12437 } 12438 currentByte <<= 1; 12439 if (this.readModule(0, numColumns - 1, numRows, numColumns)) { 12440 currentByte |= 1; 12441 } 12442 currentByte <<= 1; 12443 if (this.readModule(1, numColumns - 3, numRows, numColumns)) { 12444 currentByte |= 1; 12445 } 12446 currentByte <<= 1; 12447 if (this.readModule(1, numColumns - 2, numRows, numColumns)) { 12448 currentByte |= 1; 12449 } 12450 currentByte <<= 1; 12451 if (this.readModule(1, numColumns - 1, numRows, numColumns)) { 12452 currentByte |= 1; 12453 } 12454 return currentByte; 12455 } 12456 /** 12457 * <p>Reads the 8 bits of the special corner condition 4.</p> 12458 * 12459 * <p>See ISO 16022:2006, Figure F.6</p> 12460 * 12461 * @param numRows Number of rows in the mapping matrix 12462 * @param numColumns Number of columns in the mapping matrix 12463 * @return byte from the Corner condition 4 12464 */ 12465 readCorner4(numRows, numColumns) { 12466 let currentByte = 0; 12467 if (this.readModule(numRows - 3, 0, numRows, numColumns)) { 12468 currentByte |= 1; 12469 } 12470 currentByte <<= 1; 12471 if (this.readModule(numRows - 2, 0, numRows, numColumns)) { 12472 currentByte |= 1; 12473 } 12474 currentByte <<= 1; 12475 if (this.readModule(numRows - 1, 0, numRows, numColumns)) { 12476 currentByte |= 1; 12477 } 12478 currentByte <<= 1; 12479 if (this.readModule(0, numColumns - 2, numRows, numColumns)) { 12480 currentByte |= 1; 12481 } 12482 currentByte <<= 1; 12483 if (this.readModule(0, numColumns - 1, numRows, numColumns)) { 12484 currentByte |= 1; 12485 } 12486 currentByte <<= 1; 12487 if (this.readModule(1, numColumns - 1, numRows, numColumns)) { 12488 currentByte |= 1; 12489 } 12490 currentByte <<= 1; 12491 if (this.readModule(2, numColumns - 1, numRows, numColumns)) { 12492 currentByte |= 1; 12493 } 12494 currentByte <<= 1; 12495 if (this.readModule(3, numColumns - 1, numRows, numColumns)) { 12496 currentByte |= 1; 12497 } 12498 return currentByte; 12499 } 12500 /** 12501 * <p>Extracts the data region from a {@link BitMatrix} that contains 12502 * alignment patterns.</p> 12503 * 12504 * @param bitMatrix Original {@link BitMatrix} with alignment patterns 12505 * @return BitMatrix that has the alignment patterns removed 12506 */ 12507 extractDataRegion(bitMatrix) { 12508 const symbolSizeRows = this.version.getSymbolSizeRows(); 12509 const symbolSizeColumns = this.version.getSymbolSizeColumns(); 12510 if (bitMatrix.getHeight() !== symbolSizeRows) { 12511 throw new IllegalArgumentException('Dimension of bitMatrix must match the version size'); 12512 } 12513 const dataRegionSizeRows = this.version.getDataRegionSizeRows(); 12514 const dataRegionSizeColumns = this.version.getDataRegionSizeColumns(); 12515 const numDataRegionsRow = symbolSizeRows / dataRegionSizeRows | 0; 12516 const numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns | 0; 12517 const sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows; 12518 const sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns; 12519 const bitMatrixWithoutAlignment = new BitMatrix(sizeDataRegionColumn, sizeDataRegionRow); 12520 for (let dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow) { 12521 const dataRegionRowOffset = dataRegionRow * dataRegionSizeRows; 12522 for (let dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn) { 12523 const dataRegionColumnOffset = dataRegionColumn * dataRegionSizeColumns; 12524 for (let i = 0; i < dataRegionSizeRows; ++i) { 12525 const readRowOffset = dataRegionRow * (dataRegionSizeRows + 2) + 1 + i; 12526 const writeRowOffset = dataRegionRowOffset + i; 12527 for (let j = 0; j < dataRegionSizeColumns; ++j) { 12528 const readColumnOffset = dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j; 12529 if (bitMatrix.get(readColumnOffset, readRowOffset)) { 12530 const writeColumnOffset = dataRegionColumnOffset + j; 12531 bitMatrixWithoutAlignment.set(writeColumnOffset, writeRowOffset); 12532 } 12533 } 12534 } 12535 } 12536 } 12537 return bitMatrixWithoutAlignment; 12538 } 12539 }
vendor: 8,913 bytes, lines 12539-12744
12539 12540 12541 /* 12542 * Copyright 2008 ZXing authors 12543 * 12544 * Licensed under the Apache License, Version 2.0 (the "License"); 12545 * you may not use this file except in compliance with the License. 12546 * You may obtain a copy of the License at 12547 * 12548 * http://www.apache.org/licenses/LICENSE-2.0 12549 * 12550 * Unless required by applicable law or agreed to in writing, software 12551 * distributed under the License is distributed on an "AS IS" BASIS, 12552 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12553 * See the License for the specific language governing permissions and 12554 * limitations under the License. 12555 */ 12556 /** 12557 * <p>Encapsulates a block of data within a Data Matrix Code. Data Matrix Codes may split their data into 12558 * multiple blocks, each of which is a unit of data and error-correction codewords. Each 12559 * is represented by an instance of this class.</p> 12560 * 12561 * @author [email protected] (Brian Brown) 12562 */ 12563 class DataBlock$1 { 12564 constructor(numDataCodewords, codewords) { 12565 this.numDataCodewords = numDataCodewords; 12566 this.codewords = codewords; 12567 } 12568 /** 12569 * <p>When Data Matrix Codes use multiple data blocks, they actually interleave the bytes of each of them. 12570 * That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This 12571 * method will separate the data into original blocks.</p> 12572 * 12573 * @param rawCodewords bytes as read directly from the Data Matrix Code 12574 * @param version version of the Data Matrix Code 12575 * @return DataBlocks containing original bytes, "de-interleaved" from representation in the 12576 * Data Matrix Code 12577 */ 12578 static getDataBlocks(rawCodewords, version) { 12579 // Figure out the number and size of data blocks used by this version 12580 const ecBlocks = version.getECBlocks(); 12581 // First count the total number of data blocks 12582 let totalBlocks = 0; 12583 const ecBlockArray = ecBlocks.getECBlocks(); 12584 for (let ecBlock of ecBlockArray) { 12585 totalBlocks += ecBlock.getCount(); 12586 } 12587 // Now establish DataBlocks of the appropriate size and number of data codewords 12588 const result = new Array(totalBlocks); 12589 let numResultBlocks = 0; 12590 for (let ecBlock of ecBlockArray) { 12591 for (let i = 0; i < ecBlock.getCount(); i++) { 12592 const numDataCodewords = ecBlock.getDataCodewords(); 12593 const numBlockCodewords = ecBlocks.getECCodewords() + numDataCodewords; 12594 result[numResultBlocks++] = new DataBlock$1(numDataCodewords, new Uint8Array(numBlockCodewords)); 12595 } 12596 } 12597 // All blocks have the same amount of data, except that the last n 12598 // (where n may be 0) have 1 less byte. Figure out where these start. 12599 // TODO(bbrown): There is only one case where there is a difference for Data Matrix for size 144 12600 const longerBlocksTotalCodewords = result[0].codewords.length; 12601 // int shorterBlocksTotalCodewords = longerBlocksTotalCodewords - 1; 12602 const longerBlocksNumDataCodewords = longerBlocksTotalCodewords - ecBlocks.getECCodewords(); 12603 const shorterBlocksNumDataCodewords = longerBlocksNumDataCodewords - 1; 12604 // The last elements of result may be 1 element shorter for 144 matrix 12605 // first fill out as many elements as all of them have minus 1 12606 let rawCodewordsOffset = 0; 12607 for (let i = 0; i < shorterBlocksNumDataCodewords; i++) { 12608 for (let j = 0; j < numResultBlocks; j++) { 12609 result[j].codewords[i] = rawCodewords[rawCodewordsOffset++]; 12610 } 12611 } 12612 // Fill out the last data block in the longer ones 12613 const specialVersion = version.getVersionNumber() === 24; 12614 const numLongerBlocks = specialVersion ? 8 : numResultBlocks; 12615 for (let j = 0; j < numLongerBlocks; j++) { 12616 result[j].codewords[longerBlocksNumDataCodewords - 1] = rawCodewords[rawCodewordsOffset++]; 12617 } 12618 // Now add in error correction blocks 12619 const max = result[0].codewords.length; 12620 for (let i = longerBlocksNumDataCodewords; i < max; i++) { 12621 for (let j = 0; j < numResultBlocks; j++) { 12622 const jOffset = specialVersion ? (j + 8) % numResultBlocks : j; 12623 const iOffset = specialVersion && jOffset > 7 ? i - 1 : i; 12624 result[jOffset].codewords[iOffset] = rawCodewords[rawCodewordsOffset++]; 12625 } 12626 } 12627 if (rawCodewordsOffset !== rawCodewords.length) { 12628 throw new IllegalArgumentException(); 12629 } 12630 return result; 12631 } 12632 getNumDataCodewords() { 12633 return this.numDataCodewords; 12634 } 12635 getCodewords() { 12636 return this.codewords; 12637 } 12638 } 12639 12640 /* 12641 * Copyright 2007 ZXing authors 12642 * 12643 * Licensed under the Apache License, Version 2.0 (the "License"); 12644 * you may not use this file except in compliance with the License. 12645 * You may obtain a copy of the License at 12646 * 12647 * http://www.apache.org/licenses/LICENSE-2.0 12648 * 12649 * Unless required by applicable law or agreed to in writing, software 12650 * distributed under the License is distributed on an "AS IS" BASIS, 12651 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12652 * See the License for the specific language governing permissions and 12653 * limitations under the License. 12654 */ 12655 /** 12656 * <p>This provides an easy abstraction to read bits at a time from a sequence of bytes, where the 12657 * number of bits read is not often a multiple of 8.</p> 12658 * 12659 * <p>This class is thread-safe but not reentrant -- unless the caller modifies the bytes array 12660 * it passed in, in which case all bets are off.</p> 12661 * 12662 * @author Sean Owen 12663 */ 12664 class BitSource { 12665 /** 12666 * @param bytes bytes from which this will read bits. Bits will be read from the first byte first. 12667 * Bits are read within a byte from most-significant to least-significant bit. 12668 */ 12669 constructor(bytes) { 12670 this.bytes = bytes; 12671 this.byteOffset = 0; 12672 this.bitOffset = 0; 12673 } 12674 /** 12675 * @return index of next bit in current byte which would be read by the next call to {@link #readBits(int)}. 12676 */ 12677 getBitOffset() { 12678 return this.bitOffset; 12679 } 12680 /** 12681 * @return index of next byte in input byte array which would be read by the next call to {@link #readBits(int)}. 12682 */ 12683 getByteOffset() { 12684 return this.byteOffset; 12685 } 12686 /** 12687 * @param numBits number of bits to read 12688 * @return int representing the bits read. The bits will appear as the least-significant 12689 * bits of the int 12690 * @throws IllegalArgumentException if numBits isn't in [1,32] or more than is available 12691 */ 12692 readBits(numBits /*int*/) { 12693 if (numBits < 1 || numBits > 32 || numBits > this.available()) { 12694 throw new IllegalArgumentException('' + numBits); 12695 } 12696 let result = 0; 12697 let bitOffset = this.bitOffset; 12698 let byteOffset = this.byteOffset; 12699 const bytes = this.bytes; 12700 // First, read remainder from current byte 12701 if (bitOffset > 0) { 12702 const bitsLeft = 8 - bitOffset; 12703 const toRead = numBits < bitsLeft ? numBits : bitsLeft; 12704 const bitsToNotRead = bitsLeft - toRead; 12705 const mask = (0xFF >> (8 - toRead)) << bitsToNotRead; 12706 result = (bytes[byteOffset] & mask) >> bitsToNotRead; 12707 numBits -= toRead; 12708 bitOffset += toRead; 12709 if (bitOffset === 8) { 12710 bitOffset = 0; 12711 byteOffset++; 12712 } 12713 } 12714 // Next read whole bytes 12715 if (numBits > 0) { 12716 while (numBits >= 8) { 12717 result = (result << 8) | (bytes[byteOffset] & 0xFF); 12718 byteOffset++; 12719 numBits -= 8; 12720 } 12721 // Finally read a partial byte 12722 if (numBits > 0) { 12723 const bitsToNotRead = 8 - numBits; 12724 const mask = (0xFF >> bitsToNotRead) << bitsToNotRead; 12725 result = (result << numBits) | ((bytes[byteOffset] & mask) >> bitsToNotRead); 12726 bitOffset += numBits; 12727 } 12728 } 12729 this.bitOffset = bitOffset; 12730 this.byteOffset = byteOffset; 12731 return result; 12732 } 12733 /** 12734 * @return number of bits that can be read successfully 12735 */ 12736 available() { 12737 return 8 * (this.bytes.length - this.byteOffset) - this.bitOffset; 12738 } 12739 } 12740 12741 /* 12742 * Copyright 2008 ZXing authors 12743 * 12744 * Licensed under the Apache License, Version 2.0 (the "License");
12745 * you may not use this file except in compliance with the License. 12746 * You may obtain a copy of the License at 12747 * 12748 * http://www.apache.org/licenses/LICENSE-2.0 12749 * 12750 * Unless required by applicable law or agreed to in writing, software 12751 * distributed under the License is distributed on an "AS IS" BASIS, 12752 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12753 * See the License for the specific language governing permissions and 12754 * limitations under the License. 12755 */ 12756 var Mode$3; 12757 (function (Mode) { 12758 Mode[Mode["PAD_ENCODE"] = 0] = "PAD_ENCODE"; 12759 Mode[Mode["ASCII_ENCODE"] = 1] = "ASCII_ENCODE"; 12760 Mode[Mode["C40_ENCODE"] = 2] = "C40_ENCODE"; 12761 Mode[Mode["TEXT_ENCODE"] = 3] = "TEXT_ENCODE"; 12762 Mode[Mode["ANSIX12_ENCODE"] = 4] = "ANSIX12_ENCODE"; 12763 Mode[Mode["EDIFACT_ENCODE"] = 5] = "EDIFACT_ENCODE"; 12764 Mode[Mode["BASE256_ENCODE"] = 6] = "BASE256_ENCODE"; 12765 })(Mode$3 || (Mode$3 = {})); 12766 /** 12767 * <p>Data Matrix Codes can encode text as bits in one of several modes, and can use multiple modes 12768 * in one Data Matrix Code. This class decodes the bits back into text.</p> 12769 * 12770 * <p>See ISO 16022:2006, 5.2.1 - 5.2.9.2</p> 12771 * 12772 * @author [email protected] (Brian Brown) 12773 * @author Sean Owen 12774 */ 12775 class DecodedBitStreamParser$2
vendor: 19,369 bytes, lines 12775-13210
12775 { 12776 static decode(bytes) { 12777 const bits = new BitSource(bytes); 12778 const result = new StringBuilder(); 12779 const resultTrailer = new StringBuilder(); 12780 const byteSegments = new Array(); 12781 let mode = Mode$3.ASCII_ENCODE; 12782 do { 12783 if (mode === Mode$3.ASCII_ENCODE) { 12784 mode = this.decodeAsciiSegment(bits, result, resultTrailer); 12785 } 12786 else { 12787 switch (mode) { 12788 case Mode$3.C40_ENCODE: 12789 this.decodeC40Segment(bits, result); 12790 break; 12791 case Mode$3.TEXT_ENCODE: 12792 this.decodeTextSegment(bits, result); 12793 break; 12794 case Mode$3.ANSIX12_ENCODE: 12795 this.decodeAnsiX12Segment(bits, result); 12796 break; 12797 case Mode$3.EDIFACT_ENCODE: 12798 this.decodeEdifactSegment(bits, result); 12799 break; 12800 case Mode$3.BASE256_ENCODE: 12801 this.decodeBase256Segment(bits, result, byteSegments); 12802 break; 12803 default: 12804 throw new FormatException(); 12805 } 12806 mode = Mode$3.ASCII_ENCODE; 12807 } 12808 } while (mode !== Mode$3.PAD_ENCODE && bits.available() > 0); 12809 if (resultTrailer.length() > 0) { 12810 result.append(resultTrailer.toString()); 12811 } 12812 return new DecoderResult(bytes, result.toString(), byteSegments.length === 0 ? null : byteSegments, null); 12813 } 12814 /** 12815 * See ISO 16022:2006, 5.2.3 and Annex C, Table C.2 12816 */ 12817 static decodeAsciiSegment(bits, result, resultTrailer) { 12818 let upperShift = false; 12819 do { 12820 let oneByte = bits.readBits(8); 12821 if (oneByte === 0) { 12822 throw new FormatException(); 12823 } 12824 else if (oneByte <= 128) { // ASCII data (ASCII value + 1) 12825 if (upperShift) { 12826 oneByte += 128; 12827 // upperShift = false; 12828 } 12829 result.append(String.fromCharCode(oneByte - 1)); 12830 return Mode$3.ASCII_ENCODE; 12831 } 12832 else if (oneByte === 129) { // Pad 12833 return Mode$3.PAD_ENCODE; 12834 } 12835 else if (oneByte <= 229) { // 2-digit data 00-99 (Numeric Value + 130) 12836 const value = oneByte - 130; 12837 if (value < 10) { // pad with '0' for single digit values 12838 result.append('0'); 12839 } 12840 result.append('' + value); 12841 } 12842 else { 12843 switch (oneByte) { 12844 case 230: // Latch to C40 encodation 12845 return Mode$3.C40_ENCODE; 12846 case 231: // Latch to Base 256 encodation 12847 return Mode$3.BASE256_ENCODE; 12848 case 232: // FNC1 12849 result.append(String.fromCharCode(29)); // translate as ASCII 29 12850 break; 12851 case 233: // Structured Append 12852 case 234: // Reader Programming 12853 // Ignore these symbols for now 12854 // throw ReaderException.getInstance(); 12855 break; 12856 case 235: // Upper Shift (shift to Extended ASCII) 12857 upperShift = true; 12858 break; 12859 case 236: // 05 Macro 12860 result.append('[)>\u001E05\u001D'); 12861 resultTrailer.insert(0, '\u001E\u0004'); 12862 break; 12863 case 237: // 06 Macro 12864 result.append('[)>\u001E06\u001D'); 12865 resultTrailer.insert(0, '\u001E\u0004'); 12866 break; 12867 case 238: // Latch to ANSI X12 encodation 12868 return Mode$3.ANSIX12_ENCODE; 12869 case 239: // Latch to Text encodation 12870 return Mode$3.TEXT_ENCODE; 12871 case 240: // Latch to EDIFACT encodation 12872 return Mode$3.EDIFACT_ENCODE; 12873 case 241: // ECI Character 12874 // TODO(bbrown): I think we need to support ECI 12875 // throw ReaderException.getInstance(); 12876 // Ignore this symbol for now 12877 break; 12878 default: 12879 // Not to be used in ASCII encodation 12880 // but work around encoders that end with 254, latch back to ASCII 12881 if (oneByte !== 254 || bits.available() !== 0) { 12882 throw new FormatException(); 12883 } 12884 break; 12885 } 12886 } 12887 } while (bits.available() > 0); 12888 return Mode$3.ASCII_ENCODE; 12889 } 12890 /** 12891 * See ISO 16022:2006, 5.2.5 and Annex C, Table C.1 12892 */ 12893 static decodeC40Segment(bits, result) { 12894 // Three C40 values are encoded in a 16-bit value as 12895 // (1600 * C1) + (40 * C2) + C3 + 1 12896 // TODO(bbrown): The Upper Shift with C40 doesn't work in the 4 value scenario all the time 12897 let upperShift = false; 12898 const cValues = []; 12899 let shift = 0; 12900 do { 12901 // If there is only one byte left then it will be encoded as ASCII 12902 if (bits.available() === 8) { 12903 return; 12904 } 12905 const firstByte = bits.readBits(8); 12906 if (firstByte === 254) { // Unlatch codeword 12907 return; 12908 } 12909 this.parseTwoBytes(firstByte, bits.readBits(8), cValues); 12910 for (let i = 0; i < 3; i++) { 12911 const cValue = cValues[i]; 12912 switch (shift) { 12913 case 0: 12914 if (cValue < 3) { 12915 shift = cValue + 1; 12916 } 12917 else if (cValue < this.C40_BASIC_SET_CHARS.length) { 12918 const c40char = this.C40_BASIC_SET_CHARS[cValue]; 12919 if (upperShift) { 12920 result.append(String.fromCharCode(c40char.charCodeAt(0) + 128)); 12921 upperShift = false; 12922 } 12923 else { 12924 result.append(c40char); 12925 } 12926 } 12927 else { 12928 throw new FormatException(); 12929 } 12930 break; 12931 case 1: 12932 if (upperShift) { 12933 result.append(String.fromCharCode(cValue + 128)); 12934 upperShift = false; 12935 } 12936 else { 12937 result.append(String.fromCharCode(cValue)); 12938 } 12939 shift = 0; 12940 break; 12941 case 2: 12942 if (cValue < this.C40_SHIFT2_SET_CHARS.length) { 12943 const c40char = this.C40_SHIFT2_SET_CHARS[cValue]; 12944 if (upperShift) { 12945 result.append(String.fromCharCode(c40char.charCodeAt(0) + 128)); 12946 upperShift = false; 12947 } 12948 else { 12949 result.append(c40char); 12950 } 12951 } 12952 else { 12953 switch (cValue) { 12954 case 27: // FNC1 12955 result.append(String.fromCharCode(29)); // translate as ASCII 29 12956 break; 12957 case 30: // Upper Shift 12958 upperShift = true; 12959 break; 12960 default: 12961 throw new FormatException(); 12962 } 12963 } 12964 shift = 0; 12965 break; 12966 case 3: 12967 if (upperShift) { 12968 result.append(String.fromCharCode(cValue + 224)); 12969 upperShift = false; 12970 } 12971 else { 12972 result.append(String.fromCharCode(cValue + 96)); 12973 } 12974 shift = 0; 12975 break; 12976 default: 12977 throw new FormatException(); 12978 } 12979 } 12980 } while (bits.available() > 0); 12981 } 12982 /** 12983 * See ISO 16022:2006, 5.2.6 and Annex C, Table C.2 12984 */ 12985 static decodeTextSegment(bits, result) { 12986 // Three Text values are encoded in a 16-bit value as 12987 // (1600 * C1) + (40 * C2) + C3 + 1 12988 // TODO(bbrown): The Upper Shift with Text doesn't work in the 4 value scenario all the time 12989 let upperShift = false; 12990 let cValues = []; 12991 let shift = 0; 12992 do { 12993 // If there is only one byte left then it will be encoded as ASCII 12994 if (bits.available() === 8) { 12995 return; 12996 } 12997 const firstByte = bits.readBits(8); 12998 if (firstByte === 254) { // Unlatch codeword 12999 return; 13000 } 13001 this.parseTwoBytes(firstByte, bits.readBits(8), cValues); 13002 for (let i = 0; i < 3; i++) { 13003 const cValue = cValues[i]; 13004 switch (shift) { 13005 case 0: 13006 if (cValue < 3) { 13007 shift = cValue + 1; 13008 } 13009 else if (cValue < this.TEXT_BASIC_SET_CHARS.length) { 13010 const textChar = this.TEXT_BASIC_SET_CHARS[cValue]; 13011 if (upperShift) { 13012 result.append(String.fromCharCode(textChar.charCodeAt(0) + 128)); 13013 upperShift = false; 13014 } 13015 else { 13016 result.append(textChar); 13017 } 13018 } 13019 else { 13020 throw new FormatException(); 13021 } 13022 break; 13023 case 1: 13024 if (upperShift) { 13025 result.append(String.fromCharCode(cValue + 128)); 13026 upperShift = false; 13027 } 13028 else { 13029 result.append(String.fromCharCode(cValue)); 13030 } 13031 shift = 0; 13032 break; 13033 case 2: 13034 // Shift 2 for Text is the same encoding as C40 13035 if (cValue < this.TEXT_SHIFT2_SET_CHARS.length) { 13036 const textChar = this.TEXT_SHIFT2_SET_CHARS[cValue]; 13037 if (upperShift) { 13038 result.append(String.fromCharCode(textChar.charCodeAt(0) + 128)); 13039 upperShift = false; 13040 } 13041 else { 13042 result.append(textChar); 13043 } 13044 } 13045 else { 13046 switch (cValue) { 13047 case 27: // FNC1 13048 result.append(String.fromCharCode(29)); // translate as ASCII 29 13049 break; 13050 case 30: // Upper Shift 13051 upperShift = true; 13052 break; 13053 default: 13054 throw new FormatException(); 13055 } 13056 } 13057 shift = 0; 13058 break; 13059 case 3: 13060 if (cValue < this.TEXT_SHIFT3_SET_CHARS.length) { 13061 const textChar = this.TEXT_SHIFT3_SET_CHARS[cValue]; 13062 if (upperShift) { 13063 result.append(String.fromCharCode(textChar.charCodeAt(0) + 128)); 13064 upperShift = false; 13065 } 13066 else { 13067 result.append(textChar); 13068 } 13069 shift = 0; 13070 } 13071 else { 13072 throw new FormatException(); 13073 } 13074 break; 13075 default: 13076 throw new FormatException(); 13077 } 13078 } 13079 } while (bits.available() > 0); 13080 } 13081 /** 13082 * See ISO 16022:2006, 5.2.7 13083 */ 13084 static decodeAnsiX12Segment(bits, result) { 13085 // Three ANSI X12 values are encoded in a 16-bit value as 13086 // (1600 * C1) + (40 * C2) + C3 + 1 13087 const cValues = []; 13088 do { 13089 // If there is only one byte left then it will be encoded as ASCII 13090 if (bits.available() === 8) { 13091 return; 13092 } 13093 const firstByte = bits.readBits(8); 13094 if (firstByte === 254) { // Unlatch codeword 13095 return; 13096 } 13097 this.parseTwoBytes(firstByte, bits.readBits(8), cValues); 13098 for (let i = 0; i < 3; i++) { 13099 const cValue = cValues[i]; 13100 switch (cValue) { 13101 case 0: // X12 segment terminator <CR> 13102 result.append('\r'); 13103 break; 13104 case 1: // X12 segment separator * 13105 result.append('*'); 13106 break; 13107 case 2: // X12 sub-element separator > 13108 result.append('>'); 13109 break; 13110 case 3: // space 13111 result.append(' '); 13112 break; 13113 default: 13114 if (cValue < 14) { // 0 - 9 13115 result.append(String.fromCharCode(cValue + 44)); 13116 } 13117 else if (cValue < 40) { // A - Z 13118 result.append(String.fromCharCode(cValue + 51)); 13119 } 13120 else { 13121 throw new FormatException(); 13122 } 13123 break; 13124 } 13125 } 13126 } while (bits.available() > 0); 13127 } 13128 static parseTwoBytes(firstByte, secondByte, result) { 13129 let fullBitValue = (firstByte << 8) + secondByte - 1; 13130 let temp = Math.floor(fullBitValue / 1600); 13131 result[0] = temp; 13132 fullBitValue -= temp * 1600; 13133 temp = Math.floor(fullBitValue / 40); 13134 result[1] = temp; 13135 result[2] = fullBitValue - temp * 40; 13136 } 13137 /** 13138 * See ISO 16022:2006, 5.2.8 and Annex C Table C.3 13139 */ 13140 static decodeEdifactSegment(bits, result) { 13141 do { 13142 // If there is only two or less bytes left then it will be encoded as ASCII 13143 if (bits.available() <= 16) { 13144 return; 13145 } 13146 for (let i = 0; i < 4; i++) { 13147 let edifactValue = bits.readBits(6); 13148 // Check for the unlatch character 13149 if (edifactValue === 0x1F) { // 011111 13150 // Read rest of byte, which should be 0, and stop 13151 const bitsLeft = 8 - bits.getBitOffset(); 13152 if (bitsLeft !== 8) { 13153 bits.readBits(bitsLeft); 13154 } 13155 return; 13156 } 13157 if ((edifactValue & 0x20) === 0) { // no 1 in the leading (6th) bit 13158 edifactValue |= 0x40; // Add a leading 01 to the 6 bit binary value 13159 } 13160 result.append(String.fromCharCode(edifactValue)); 13161 } 13162 } while (bits.available() > 0); 13163 } 13164 /** 13165 * See ISO 16022:2006, 5.2.9 and Annex B, B.2 13166 */ 13167 static decodeBase256Segment(bits, result, byteSegments) { 13168 // Figure out how long the Base 256 Segment is. 13169 let codewordPosition = 1 + bits.getByteOffset(); // position is 1-indexed 13170 const d1 = this.unrandomize255State(bits.readBits(8), codewordPosition++); 13171 let count; 13172 if (d1 === 0) { // Read the remainder of the symbol 13173 count = bits.available() / 8 | 0; 13174 } 13175 else if (d1 < 250) { 13176 count = d1; 13177 } 13178 else { 13179 count = 250 * (d1 - 249) + this.unrandomize255State(bits.readBits(8), codewordPosition++); 13180 } 13181 // We're seeing NegativeArraySizeException errors from users. 13182 if (count < 0) { 13183 throw new FormatException(); 13184 } 13185 const bytes = new Uint8Array(count); 13186 for (let i = 0; i < count; i++) { 13187 // Have seen this particular error in the wild, such as at 13188 // http://www.bcgen.com/demo/IDAutomationStreamingDataMatrix.aspx?MODE=3&D=Fred&PFMT=3&PT=F&X=0.3&O=0&LM=0.2 13189 if (bits.available() < 8) { 13190 throw new FormatException(); 13191 } 13192 bytes[i] = this.unrandomize255State(bits.readBits(8), codewordPosition++); 13193 } 13194 byteSegments.push(bytes); 13195 try { 13196 result.append(StringEncoding.decode(bytes, StringUtils.ISO88591)); 13197 } 13198 catch (uee) { 13199 throw new IllegalStateException('Platform does not support required encoding: ' + uee.message); 13200 } 13201 } 13202 /** 13203 * See ISO 16022:2006, Annex B, B.2 13204 */ 13205 static unrandomize255State(randomizedBase256Codeword, base256CodewordPosition) { 13206 const pseudoRandomNumber = ((149 * base256CodewordPosition) % 255) + 1; 13207 const tempVariable = randomizedBase256Codeword - pseudoRandomNumber; 13208 return tempVariable >= 0 ? tempVariable : tempVariable + 256; 13209 } 13210 }
13210 13211 /** 13212 * See ISO 16022:2006, Annex C Table C.1 13213 * The C40 Basic Character Set (*'s used for placeholders for the shift values) 13214 */ 13215 DecodedBitStreamParser$2.C40_BASIC_SET_CHARS = [ 13216 '*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 13217 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 13218 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' 13219 ]; 13220 DecodedBitStreamParser$2.C40_SHIFT2_SET_CHARS = [ 13221 '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', 13222 '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_' 13223 ]; 13224 /** 13225 * See ISO 16022:2006, Annex C Table C.2 13226 * The Text Basic Character Set (*'s used for placeholders for the shift values) 13227 */ 13228 DecodedBitStreamParser$2.TEXT_BASIC_SET_CHARS = [ 13229 '*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 13230 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 13231 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' 13232 ]; 13233 // Shift 2 for Text is the same encoding as C40 13234 DecodedBitStreamParser$2.TEXT_SHIFT2_SET_CHARS = DecodedBitStreamParser$2.C40_SHIFT2_SET_CHARS; 13235 DecodedBitStreamParser$2.TEXT_SHIFT3_SET_CHARS = [ 13236 '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 13237 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', String.fromCharCode(127) 13238 ]; 13239 13240 /* 13241 * Copyright 2007 ZXing authors 13242 * 13243 * Licensed under the Apache License, Version 2.0 (the "License"); 13244 * you may not use this file except in compliance with the License. 13245 * You may obtain a copy of the License at 13246 * 13247 * http://www.apache.org/licenses/LICENSE-2.0 13248 * 13249 * Unless required by applicable law or agreed to in writing, software 13250 * distributed under the License is distributed on an "AS IS" BASIS, 13251 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13252 * See the License for the specific language governing permissions and 13253 * limitations under the License. 13254 */ 13255 /** 13256 * <p>The main class which implements Data Matrix Code decoding -- as opposed to locating and extracting 13257 * the Data Matrix Code from an image.</p> 13258 * 13259 * @author [email protected] (Brian Brown) 13260 */ 13261 class Decoder$1 { 13262 constructor() { 13263 this.rsDecoder = new ReedSolomonDecoder(GenericGF.DATA_MATRIX_FIELD_256); 13264 } 13265 /** 13266 * <p>Decodes a Data Matrix Code represented as a {@link BitMatrix}. A 1 or "true" is taken 13267 * to mean a black module.</p> 13268 * 13269 * @param bits booleans representing white/black Data Matrix Code modules 13270 * @return text and bytes encoded within the Data Matrix Code 13271 * @throws FormatException if the Data Matrix Code cannot be decoded 13272 * @throws ChecksumException if error correction fails 13273 */ 13274 decode(bits) { 13275 // Construct a parser and read version, error-correction level 13276 const parser = new BitMatrixParser$1(bits); 13277 const version = parser.getVersion(); 13278 // Read codewords 13279 const codewords = parser.readCodewords(); 13280 // Separate into data blocks 13281 const dataBlocks = DataBlock$1.getDataBlocks(codewords, version); 13282 // Count total number of data bytes 13283 let totalBytes = 0; 13284 for (let db of dataBlocks) { 13285 totalBytes += db.getNumDataCodewords(); 13286 } 13287 const resultBytes = new Uint8Array(totalBytes); 13288 const dataBlocksCount = dataBlocks.length; 13289 // Error-correct and copy data blocks together into a stream of bytes 13290 for (let j = 0; j < dataBlocksCount; j++) { 13291 const dataBlock = dataBlocks[j]; 13292 const codewordBytes = dataBlock.getCodewords(); 13293 const numDataCodewords = dataBlock.getNumDataCodewords(); 13294 this.correctErrors(codewordBytes, numDataCodewords); 13295 for (let i = 0; i < numDataCodewords; i++) { 13296 // De-interlace data blocks. 13297 resultBytes[i * dataBlocksCount + j] = codewordBytes[i]; 13298 } 13299 } 13300 // Decode the contents of that stream of bytes 13301 return DecodedBitStreamParser$2.decode(resultBytes); 13302 } 13303 /** 13304 * <p>
13304Given data and error-correction codewords received, possibly corrupted by errors, attempts to 13305 * correct the errors in-place using Reed-Solomon error correction.</p> 13306 * 13307 * @param codewordBytes data and error correction codewords 13308 * @param numDataCodewords number of codewords that are data bytes 13309 * @throws ChecksumException if error correction fails 13310 */ 13311 correctErrors(codewordBytes, numDataCodewords) { 13312 // const numCodewords = codewordBytes.length; 13313 // First read into an array of ints 13314 const codewordsInts = new Int32Array(codewordBytes); 13315 // for (let i = 0; i < numCodewords; i++) { 13316 // codewordsInts[i] = codewordBytes[i] & 0xFF; 13317 // } 13318 try { 13319 this.rsDecoder.decode(codewordsInts, codewordBytes.length - numDataCodewords); 13320 } 13321 catch (ignored /* ReedSolomonException */) { 13322 throw new ChecksumException(); 13323 } 13324 // Copy back into array of bytes -- only need to worry about the bytes that were data 13325 // We don't care about errors in the error-correction codewords 13326 for (let i = 0; i < numDataCodewords; i++) { 13327 codewordBytes[i] = codewordsInts[i]; 13328 } 13329 } 13330 } 13331 13332 /* 13333 * Copyright 2008 ZXing authors 13334 * 13335 * Licensed under the Apache License, Version 2.0 (the "License"); 13336 * you may not use this file except in compliance with the License. 13337 * You may obtain a copy of the License at 13338 * 13339 * http://www.apache.org/licenses/LICENSE-2.0 13340 * 13341 * Unless required by applicable law or agreed to in writing, software 13342 * distributed under the License is distributed on an "AS IS" BASIS, 13343 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13344 * See the License for the specific language governing permissions and 13345 * limitations under the License. 13346 */ 13347 /** 13348 * <p>Encapsulates logic that can detect a Data Matrix Code in an image, even if the Data Matrix Code 13349 * is rotated or skewed, or partially obscured.</p> 13350 * 13351 * @author Sean Owen 13352 */ 13353 class Detector$2 { 13354 constructor(image) { 13355 this.image = image; 13356 this.rectangleDetector = new WhiteRectangleDetector(this.image); 13357 } 13358 /** 13359 * <p>Detects a Data Matrix Code in an image.</p> 13360 * 13361 * @return {@link DetectorResult} encapsulating results of detecting a Data Matrix Code 13362 * @throws NotFoundException if no Data Matrix Code can be found 13363 */ 13364 detect() { 13365 const cornerPoints = this.rectangleDetector.detect(); 13366 let points = this.detectSolid1(cornerPoints); 13367 points = this.detectSolid2(points); 13368 points[3] = this.correctTopRight(points); 13369 if (!points[3]) { 13370 throw new NotFoundException(); 13371 } 13372 points = this.shiftToModuleCenter(points); 13373 const topLeft = points[0]; 13374 const bottomLeft = points[1]; 13375 const bottomRight = points[2]; 13376 const topRight = points[3]; 13377 let dimensionTop = this.transitionsBetween(topLeft, top
vendor: 27,114 bytes, lines 13377-14055
13377Right) + 1; 13378 let dimensionRight = this.transitionsBetween(bottomRight, topRight) + 1; 13379 if ((dimensionTop & 0x01) === 1) { 13380 dimensionTop += 1; 13381 } 13382 if ((dimensionRight & 0x01) === 1) { 13383 dimensionRight += 1; 13384 } 13385 if (4 * dimensionTop < 7 * dimensionRight && 4 * dimensionRight < 7 * dimensionTop) { 13386 // The matrix is square 13387 dimensionTop = dimensionRight = Math.max(dimensionTop, dimensionRight); 13388 } 13389 let bits = Detector$2.sampleGrid(this.image, topLeft, bottomLeft, bottomRight, topRight, dimensionTop, dimensionRight); 13390 return new DetectorResult(bits, [topLeft, bottomLeft, bottomRight, topRight]); 13391 } 13392 static shiftPoint(point, to, div) { 13393 let x = (to.getX() - point.getX()) / (div + 1); 13394 let y = (to.getY() - point.getY()) / (div + 1); 13395 return new ResultPoint(point.getX() + x, point.getY() + y); 13396 } 13397 static moveAway(point, fromX, fromY) { 13398 let x = point.getX(); 13399 let y = point.getY(); 13400 if (x < fromX) { 13401 x -= 1; 13402 } 13403 else { 13404 x += 1; 13405 } 13406 if (y < fromY) { 13407 y -= 1; 13408 } 13409 else { 13410 y += 1; 13411 } 13412 return new ResultPoint(x, y); 13413 } 13414 /** 13415 * Detect a solid side which has minimum transition. 13416 */ 13417 detectSolid1(cornerPoints) { 13418 // 0 2 13419 // 1 3 13420 let pointA = cornerPoints[0]; 13421 let pointB = cornerPoints[1]; 13422 let pointC = cornerPoints[3]; 13423 let pointD = cornerPoints[2]; 13424 let trAB = this.transitionsBetween(pointA, pointB); 13425 let trBC = this.transitionsBetween(pointB, pointC); 13426 let trCD = this.transitionsBetween(pointC, pointD); 13427 let trDA = this.transitionsBetween(pointD, pointA); 13428 // 0..3 13429 // : : 13430 // 1--2 13431 let min = trAB; 13432 let points = [pointD, pointA, pointB, pointC]; 13433 if (min > trBC) { 13434 min = trBC; 13435 points[0] = pointA; 13436 points[1] = pointB; 13437 points[2] = pointC; 13438 points[3] = pointD; 13439 } 13440 if (min > trCD) { 13441 min = trCD; 13442 points[0] = pointB; 13443 points[1] = pointC; 13444 points[2] = pointD; 13445 points[3] = pointA; 13446 } 13447 if (min > trDA) { 13448 points[0] = pointC; 13449 points[1] = pointD; 13450 points[2] = pointA; 13451 points[3] = pointB; 13452 } 13453 return points; 13454 } 13455 /** 13456 * Detect a second solid side next to first solid side. 13457 */ 13458 detectSolid2(points) { 13459 // A..D 13460 // : : 13461 // B--C 13462 let pointA = points[0]; 13463 let pointB = points[1]; 13464 let pointC = points[2]; 13465 let pointD = points[3]; 13466 // Transition detection on the edge is not stable. 13467 // To safely detect, shift the points to the module center. 13468 let tr = this.transitionsBetween(pointA, pointD); 13469 let pointBs = Detector$2.shiftPoint(pointB, pointC, (tr + 1) * 4); 13470 let pointCs = Detector$2.shiftPoint(pointC, pointB, (tr + 1) * 4); 13471 let trBA = this.transitionsBetween(pointBs, pointA); 13472 let trCD = this.transitionsBetween(pointCs, pointD); 13473 // 0..3 13474 // | : 13475 // 1--2 13476 if (trBA < trCD) { 13477 // solid sides: A-B-C 13478 points[0] = pointA; 13479 points[1] = pointB; 13480 points[2] = pointC; 13481 points[3] = pointD; 13482 } 13483 else { 13484 // solid sides: B-C-D 13485 points[0] = pointB; 13486 points[1] = pointC; 13487 points[2] = pointD; 13488 points[3] = pointA; 13489 } 13490 return points; 13491 } 13492 /** 13493 * Calculates the corner position of the white top right module. 13494 */ 13495 correctTopRight(points) { 13496 // A..D 13497 // | : 13498 // B--C 13499 let pointA = points[0]; 13500 let pointB = points[1]; 13501 let pointC = points[2]; 13502 let pointD = points[3]; 13503 // shift points for safe transition detection. 13504 let trTop = this.transitionsBetween(pointA, pointD); 13505 let trRight = this.transitionsBetween(pointB, pointD); 13506 let pointAs = Detector$2.shiftPoint(pointA, pointB, (trRight + 1) * 4); 13507 let pointCs = Detector$2.shiftPoint(pointC, pointB, (trTop + 1) * 4); 13508 trTop = this.transitionsBetween(pointAs, pointD); 13509 trRight = this.transitionsBetween(pointCs, pointD); 13510 let candidate1 = new ResultPoint(pointD.getX() + (pointC.getX() - pointB.getX()) / (trTop + 1), pointD.getY() + (pointC.getY() - pointB.getY()) / (trTop + 1)); 13511 let candidate2 = new ResultPoint(pointD.getX() + (pointA.getX() - pointB.getX()) / (trRight + 1), pointD.getY() + (pointA.getY() - pointB.getY()) / (trRight + 1)); 13512 if (!this.isValid(candidate1)) { 13513 if (this.isValid(candidate2)) { 13514 return candidate2; 13515 } 13516 return null; 13517 } 13518 if (!this.isValid(candidate2)) { 13519 return candidate1; 13520 } 13521 let sumc1 = this.transitionsBetween(pointAs, candidate1) + this.transitionsBetween(pointCs, candidate1); 13522 let sumc2 = this.transitionsBetween(pointAs, candidate2) + this.transitionsBetween(pointCs, candidate2); 13523 if (sumc1 > sumc2) { 13524 return candidate1; 13525 } 13526 else { 13527 return candidate2; 13528 } 13529 } 13530 /** 13531 * Shift the edge points to the module center. 13532 */ 13533 shiftToModuleCenter(points) { 13534 // A..D 13535 // | : 13536 // B--C 13537 let pointA = points[0]; 13538 let pointB = points[1]; 13539 let pointC = points[2]; 13540 let pointD = points[3]; 13541 // calculate pseudo dimensions 13542 let dimH = this.transitionsBetween(pointA, pointD) + 1; 13543 let dimV = this.transitionsBetween(pointC, pointD) + 1; 13544 // shift points for safe dimension detection 13545 let pointAs = Detector$2.shiftPoint(pointA, pointB, dimV * 4); 13546 let pointCs = Detector$2.shiftPoint(pointC, pointB, dimH * 4); 13547 // calculate more precise dimensions 13548 dimH = this.transitionsBetween(pointAs, pointD) + 1; 13549 dimV = this.transitionsBetween(pointCs, pointD) + 1; 13550 if ((dimH & 0x01) === 1) { 13551 dimH += 1; 13552 } 13553 if ((dimV & 0x01) === 1) { 13554 dimV += 1; 13555 } 13556 // WhiteRectangleDetector returns points inside of the rectangle. 13557 // I want points on the edges. 13558 let centerX = (pointA.getX() + pointB.getX() + pointC.getX() + pointD.getX()) / 4; 13559 let centerY = (pointA.getY() + pointB.getY() + pointC.getY() + pointD.getY()) / 4; 13560 pointA = Detector$2.moveAway(pointA, centerX, centerY); 13561 pointB = Detector$2.moveAway(pointB, centerX, centerY); 13562 pointC = Detector$2.moveAway(pointC, centerX, centerY); 13563 pointD = Detector$2.moveAway(pointD, centerX, centerY); 13564 let pointBs; 13565 let pointDs; 13566 // shift points to the center of each modules 13567 pointAs = Detector$2.shiftPoint(pointA, pointB, dimV * 4); 13568 pointAs = Detector$2.shiftPoint(pointAs, pointD, dimH * 4); 13569 pointBs = Detector$2.shiftPoint(pointB, pointA, dimV * 4); 13570 pointBs = Detector$2.shiftPoint(pointBs, pointC, dimH * 4); 13571 pointCs = Detector$2.shiftPoint(pointC, pointD, dimV * 4); 13572 pointCs = Detector$2.shiftPoint(pointCs, pointB, dimH * 4); 13573 pointDs = Detector$2.shiftPoint(pointD, pointC, dimV * 4); 13574 pointDs = Detector$2.shiftPoint(pointDs, pointA, dimH * 4); 13575 return [pointAs, pointBs, pointCs, pointDs]; 13576 } 13577 isValid(p) { 13578 return p.getX() >= 0 && p.getX() < this.image.getWidth() && p.getY() > 0 && p.getY() < this.image.getHeight(); 13579 } 13580 static sampleGrid(image, topLeft, bottomLeft, bottomRight, topRight, dimensionX, dimensionY) { 13581 const sampler = GridSamplerInstance.getInstance(); 13582 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()); 13583 } 13584 /** 13585 * Counts the number of black/white transitions between two points, using something like Bresenham's algorithm. 13586 */ 13587 transitionsBetween(from, to) { 13588 // See QR Code Detector, sizeOfBlackWhiteBlackRun() 13589 let fromX = Math.trunc(from.getX()); 13590 let fromY = Math.trunc(from.getY()); 13591 let toX = Math.trunc(to.getX()); 13592 let toY = Math.trunc(to.getY()); 13593 let steep = Math.abs(toY - fromY) > Math.abs(toX - fromX); 13594 if (steep) { 13595 let temp = fromX; 13596 fromX = fromY; 13597 fromY = temp; 13598 temp = toX; 13599 toX = toY; 13600 toY = temp; 13601 } 13602 let dx = Math.abs(toX - fromX); 13603 let dy = Math.abs(toY - fromY); 13604 let error = -dx / 2; 13605 let ystep = fromY < toY ? 1 : -1; 13606 let xstep = fromX < toX ? 1 : -1; 13607 let transitions = 0; 13608 let inBlack = this.image.get(steep ? fromY : fromX, steep ? fromX : fromY); 13609 for (let x = fromX, y = fromY; x !== toX; x += xstep) { 13610 let isBlack = this.image.get(steep ? y : x, steep ? x : y); 13611 if (isBlack !== inBlack) { 13612 transitions++; 13613 inBlack = isBlack; 13614 } 13615 error += dy; 13616 if (error > 0) { 13617 if (y === toY) { 13618 break; 13619 } 13620 y += ystep; 13621 error -= dx; 13622 } 13623 } 13624 return transitions; 13625 } 13626 } 13627 13628 /* 13629 * Copyright 2007 ZXing authors 13630 * 13631 * Licensed under the Apache License, Version 2.0 (the "License"); 13632 * you may not use this file except in compliance with the License. 13633 * You may obtain a copy of the License at 13634 * 13635 * http://www.apache.org/licenses/LICENSE-2.0 13636 * 13637 * Unless required by applicable law or agreed to in writing, software 13638 * distributed under the License is distributed on an "AS IS" BASIS, 13639 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13640 * See the License for the specific language governing permissions and 13641 * limitations under the License. 13642 */ 13643 /** 13644 * This implementation can detect and decode Data Matrix codes in an image. 13645 * 13646 * @author [email protected] (Brian Brown) 13647 */ 13648 class DataMatrixReader { 13649 constructor() { 13650 this.decoder = new Decoder$1(); 13651 } 13652 /** 13653 * Locates and decodes a Data Matrix code in an image. 13654 * 13655 * @return a String representing the content encoded by the Data Matrix code 13656 * @throws NotFoundException if a Data Matrix code cannot be found 13657 * @throws FormatException if a Data Matrix code cannot be decoded 13658 * @throws ChecksumException if error correction fails 13659 */ 13660 // @Override 13661 // public Result decode(BinaryBitmap image) throws NotFoundException, ChecksumException, FormatException { 13662 // return decode(image, null); 13663 // } 13664 // @Override 13665 decode(image, hints = null) { 13666 let decoderResult; 13667 let points; 13668 if (hints != null && hints.has(DecodeHintType$1.PURE_BARCODE)) { 13669 const bits = DataMatrixReader.extractPureBits(image.getBlackMatrix()); 13670 decoderResult = this.decoder.decode(bits); 13671 points = DataMatrixReader.NO_POINTS; 13672 } 13673 else { 13674 const detectorResult = new Detector$2(image.getBlackMatrix()).detect(); 13675 decoderResult = this.decoder.decode(detectorResult.getBits()); 13676 points = detectorResult.getPoints(); 13677 } 13678 const rawBytes = decoderResult.getRawBytes(); 13679 const result = new Result$1(decoderResult.getText(), rawBytes, 8 * rawBytes.length, points, BarcodeFormat$1.DATA_MATRIX, System.currentTimeMillis()); 13680 const byteSegments = decoderResult.getByteSegments(); 13681 if (byteSegments != null) { 13682 result.putMetadata(ResultMetadataType$1.BYTE_SEGMENTS, byteSegments); 13683 } 13684 const ecLevel = decoderResult.getECLevel(); 13685 if (ecLevel != null) { 13686 result.putMetadata(ResultMetadataType$1.ERROR_CORRECTION_LEVEL, ecLevel); 13687 } 13688 return result; 13689 } 13690 // @Override 13691 reset() { 13692 // do nothing 13693 } 13694 /** 13695 * This method detects a code in a "pure" image -- that is, pure monochrome image 13696 * which contains only an unrotated, unskewed, image of a code, with some white border 13697 * around it. This is a specialized method that works exceptionally fast in this special 13698 * case. 13699 * 13700 * @see com.google.zxing.qrcode.QRCodeReader#extractPureBits(BitMatrix) 13701 */ 13702 static extractPureBits(image) { 13703 const leftTopBlack = image.getTopLeftOnBit(); 13704 const rightBottomBlack = image.getBottomRightOnBit(); 13705 if (leftTopBlack == null || rightBottomBlack == null) { 13706 throw new NotFoundException(); 13707 } 13708 const moduleSize = this.moduleSize(leftTopBlack, image); 13709 let top = leftTopBlack[1]; 13710 const bottom = rightBottomBlack[1]; 13711 let left = leftTopBlack[0]; 13712 const right = rightBottomBlack[0]; 13713 const matrixWidth = (right - left + 1) / moduleSize; 13714 const matrixHeight = (bottom - top + 1) / moduleSize; 13715 if (matrixWidth <= 0 || matrixHeight <= 0) { 13716 throw new NotFoundException(); 13717 } 13718 // Push in the "border" by half the module width so that we start 13719 // sampling in the middle of the module. Just in case the image is a 13720 // little off, this will help recover. 13721 const nudge = moduleSize / 2; 13722 top += nudge; 13723 left += nudge; 13724 // Now just read off the bits 13725 const bits = new BitMatrix(matrixWidth, matrixHeight); 13726 for (let y = 0; y < matrixHeight; y++) { 13727 const iOffset = top + y * moduleSize; 13728 for (let x = 0; x < matrixWidth; x++) { 13729 if (image.get(left + x * moduleSize, iOffset)) { 13730 bits.set(x, y); 13731 } 13732 } 13733 } 13734 return bits; 13735 } 13736 static moduleSize(leftTopBlack, image) { 13737 const width = image.getWidth(); 13738 let x = leftTopBlack[0]; 13739 const y = leftTopBlack[1]; 13740 while (x < width && image.get(x, y)) { 13741 x++; 13742 } 13743 if (x === width) { 13744 throw new NotFoundException(); 13745 } 13746 const moduleSize = x - leftTopBlack[0]; 13747 if (moduleSize === 0) { 13748 throw new NotFoundException(); 13749 } 13750 return moduleSize; 13751 } 13752 } 13753 DataMatrixReader.NO_POINTS = []; 13754 13755 /** 13756 * @deprecated Moving to @zxing/browser 13757 * 13758 * QR Code reader to use from browser. 13759 */ 13760 class BrowserDatamatrixCodeReader extends BrowserCodeReader { 13761 /** 13762 * Creates an instance of BrowserQRCodeReader. 13763 * @param {number} [timeBetweenScansMillis=500] the time delay between subsequent decode tries 13764 */ 13765 constructor(timeBetweenScansMillis = 500) { 13766 super(new DataMatrixReader(), timeBetweenScansMillis); 13767 } 13768 } 13769 13770 /* 13771 * Copyright 2007 ZXing authors 13772 * 13773 * Licensed under the Apache License, Version 2.0 (the "License"); 13774 * you may not use this file except in compliance with the License. 13775 * You may obtain a copy of the License at 13776 * 13777 * http://www.apache.org/licenses/LICENSE-2.0 13778 * 13779 * Unless required by applicable law or agreed to in writing, software 13780 * distributed under the License is distributed on an "AS IS" BASIS, 13781 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13782 * See the License for the specific language governing permissions and 13783 * limitations under the License. 13784 */ 13785 var ErrorCorrectionLevelValues; 13786 (function (ErrorCorrectionLevelValues) { 13787 ErrorCorrectionLevelValues[ErrorCorrectionLevelValues["L"] = 0] = "L"; 13788 ErrorCorrectionLevelValues[ErrorCorrectionLevelValues["M"] = 1] = "M"; 13789 ErrorCorrectionLevelValues[ErrorCorrectionLevelValues["Q"] = 2] = "Q"; 13790 ErrorCorrectionLevelValues[ErrorCorrectionLevelValues["H"] = 3] = "H"; 13791 })(ErrorCorrectionLevelValues || (ErrorCorrectionLevelValues = {})); 13792 /** 13793 * <p>See ISO 18004:2006, 6.5.1. This enum encapsulates the four error correction levels 13794 * defined by the QR code standard.</p> 13795 * 13796 * @author Sean Owen 13797 */ 13798 class ErrorCorrectionLevel { 13799 constructor(value, stringValue, bits /*int*/) { 13800 this.value = value; 13801 this.stringValue = stringValue; 13802 this.bits = bits; 13803 ErrorCorrectionLevel.FOR_BITS.set(bits, this); 13804 ErrorCorrectionLevel.FOR_VALUE.set(value, this); 13805 } 13806 getValue() { 13807 return this.value; 13808 } 13809 getBits() { 13810 return this.bits; 13811 } 13812 static fromString(s) { 13813 switch (s) { 13814 case 'L': return ErrorCorrectionLevel.L; 13815 case 'M': return ErrorCorrectionLevel.M; 13816 case 'Q': return ErrorCorrectionLevel.Q; 13817 case 'H': return ErrorCorrectionLevel.H; 13818 default: throw new ArgumentException(s + 'not available'); 13819 } 13820 } 13821 toString() { 13822 return this.stringValue; 13823 } 13824 equals(o) { 13825 if (!(o instanceof ErrorCorrectionLevel)) { 13826 return false; 13827 } 13828 const other = o; 13829 return this.value === other.value; 13830 } 13831 /** 13832 * @param bits int containing the two bits encoding a QR Code's error correction level 13833 * @return ErrorCorrectionLevel representing the encoded error correction level 13834 */ 13835 static forBits(bits /*int*/) { 13836 if (bits < 0 || bits >= ErrorCorrectionLevel.FOR_BITS.size) { 13837 throw new IllegalArgumentException(); 13838 } 13839 return ErrorCorrectionLevel.FOR_BITS.get(bits); 13840 } 13841 } 13842 ErrorCorrectionLevel.FOR_BITS = new Map(); 13843 ErrorCorrectionLevel.FOR_VALUE = new Map(); 13844 /** L = ~7% correction */ 13845 ErrorCorrectionLevel.L = new ErrorCorrectionLevel(ErrorCorrectionLevelValues.L, 'L', 0x01); 13846 /** M = ~15% correction */ 13847 ErrorCorrectionLevel.M = new ErrorCorrectionLevel(ErrorCorrectionLevelValues.M, 'M', 0x00); 13848 /** Q = ~25% correction */ 13849 ErrorCorrectionLevel.Q = new ErrorCorrectionLevel(ErrorCorrectionLevelValues.Q, 'Q', 0x03); 13850 /** H = ~30% correction */ 13851 ErrorCorrectionLevel.H = new ErrorCorrectionLevel(ErrorCorrectionLevelValues.H, 'H', 0x02); 13852 13853 /* 13854 * Copyright 2007 ZXing authors 13855 * 13856 * Licensed under the Apache License, Version 2.0 (the "License"); 13857 * you may not use this file except in compliance with the License. 13858 * You may obtain a copy of the License at 13859 * 13860 * http://www.apache.org/licenses/LICENSE-2.0 13861 * 13862 * Unless required by applicable law or agreed to in writing, software 13863 * distributed under the License is distributed on an "AS IS" BASIS, 13864 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13865 * See the License for the specific language governing permissions and 13866 * limitations under the License. 13867 */ 13868 /** 13869 * <p>Encapsulates a QR Code's format information, including the data mask used and 13870 * error correction level.</p> 13871 * 13872 * @author Sean Owen 13873 * @see DataMask 13874 * @see ErrorCorrectionLevel 13875 */ 13876 class FormatInformation { 13877 constructor(formatInfo /*int*/) { 13878 // Bits 3,4 13879 this.errorCorrectionLevel = ErrorCorrectionLevel.forBits((formatInfo >> 3) & 0x03); 13880 // Bottom 3 bits 13881 this.dataMask = /*(byte) */ (formatInfo & 0x07); 13882 } 13883 static numBitsDiffering(a /*int*/, b /*int*/) { 13884 return Integer.bitCount(a ^ b); 13885 } 13886 /** 13887 * @param maskedFormatInfo1 format info indicator, with mask still applied 13888 * @param maskedFormatInfo2 second copy of same info; both are checked at the same time 13889 * to establish best match 13890 * @return information about the format it specifies, or {@code null} 13891 * if doesn't seem to match any known pattern 13892 */ 13893 static decodeFormatInformation(maskedFormatInfo1 /*int*/, maskedFormatInfo2 /*int*/) { 13894 const formatInfo = FormatInformation.doDecodeFormatInformation(maskedFormatInfo1, maskedFormatInfo2); 13895 if (formatInfo !== null) { 13896 return formatInfo; 13897 } 13898 // Should return null, but, some QR codes apparently 13899 // do not mask this info. Try again by actually masking the pattern 13900 // first 13901 return FormatInformation.doDecodeFormatInformation(maskedFormatInfo1 ^ FormatInformation.FORMAT_INFO_MASK_QR, maskedFormatInfo2 ^ FormatInformation.FORMAT_INFO_MASK_QR); 13902 } 13903 static doDecodeFormatInformation(maskedFormatInfo1 /*int*/, maskedFormatInfo2 /*int*/) { 13904 // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing 13905 let bestDifference = Number.MAX_SAFE_INTEGER; 13906 let bestFormatInfo = 0; 13907 for (const decodeInfo of FormatInformation.FORMAT_INFO_DECODE_LOOKUP) { 13908 const targetInfo = decodeInfo[0]; 13909 if (targetInfo === maskedFormatInfo1 || targetInfo === maskedFormatInfo2) { 13910 // Found an exact match 13911 return new FormatInformation(decodeInfo[1]); 13912 } 13913 let bitsDifference = FormatInformation.numBitsDiffering(maskedFormatInfo1, targetInfo); 13914 if (bitsDifference < bestDifference) { 13915 bestFormatInfo = decodeInfo[1]; 13916 bestDifference = bitsDifference; 13917 } 13918 if (maskedFormatInfo1 !== maskedFormatInfo2) { 13919 // also try the other option 13920 bitsDifference = FormatInformation.numBitsDiffering(maskedFormatInfo2, targetInfo); 13921 if (bitsDifference < bestDifference) { 13922 bestFormatInfo = decodeInfo[1]; 13923 bestDifference = bitsDifference; 13924 } 13925 } 13926 } 13927 // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits 13928 // differing means we found a match 13929 if (bestDifference <= 3) { 13930 return new FormatInformation(bestFormatInfo); 13931 } 13932 return null; 13933 } 13934 getErrorCorrectionLevel() { 13935 return this.errorCorrectionLevel; 13936 } 13937 getDataMask() { 13938 return this.dataMask; 13939 } 13940 /*@Override*/ 13941 hashCode() { 13942 return (this.errorCorrectionLevel.getBits() << 3) | this.dataMask; 13943 } 13944 /*@Override*/ 13945 equals(o) { 13946 if (!(o instanceof FormatInformation)) { 13947 return false; 13948 } 13949 const other = o; 13950 return this.errorCorrectionLevel === other.errorCorrectionLevel && 13951 this.dataMask === other.dataMask; 13952 } 13953 } 13954 FormatInformation.FORMAT_INFO_MASK_QR = 0x5412; 13955 /** 13956 * See ISO 18004:2006, Annex C, Table C.1 13957 */ 13958 FormatInformation.FORMAT_INFO_DECODE_LOOKUP = [ 13959 Int32Array.from([0x5412, 0x00]), 13960 Int32Array.from([0x5125, 0x01]), 13961 Int32Array.from([0x5E7C, 0x02]), 13962 Int32Array.from([0x5B4B, 0x03]), 13963 Int32Array.from([0x45F9, 0x04]), 13964 Int32Array.from([0x40CE, 0x05]), 13965 Int32Array.from([0x4F97, 0x06]), 13966 Int32Array.from([0x4AA0, 0x07]), 13967 Int32Array.from([0x77C4, 0x08]), 13968 Int32Array.from([0x72F3, 0x09]), 13969 Int32Array.from([0x7DAA, 0x0A]), 13970 Int32Array.from([0x789D, 0x0B]), 13971 Int32Array.from([0x662F, 0x0C]), 13972 Int32Array.from([0x6318, 0x0D]), 13973 Int32Array.from([0x6C41, 0x0E]), 13974 Int32Array.from([0x6976, 0x0F]), 13975 Int32Array.from([0x1689, 0x10]), 13976 Int32Array.from([0x13BE, 0x11]), 13977 Int32Array.from([0x1CE7, 0x12]), 13978 Int32Array.from([0x19D0, 0x13]), 13979 Int32Array.from([0x0762, 0x14]), 13980 Int32Array.from([0x0255, 0x15]), 13981 Int32Array.from([0x0D0C, 0x16]), 13982 Int32Array.from([0x083B, 0x17]), 13983 Int32Array.from([0x355F, 0x18]), 13984 Int32Array.from([0x3068, 0x19]), 13985 Int32Array.from([0x3F31, 0x1A]), 13986 Int32Array.from([0x3A06, 0x1B]), 13987 Int32Array.from([0x24B4, 0x1C]), 13988 Int32Array.from([0x2183, 0x1D]), 13989 Int32Array.from([0x2EDA, 0x1E]), 13990 Int32Array.from([0x2BED, 0x1F]), 13991 ]; 13992 13993 /** 13994 * <p>Encapsulates a set of error-correction blocks in one symbol version. Most versions will 13995 * use blocks of differing sizes within one version, so, this encapsulates the parameters for 13996 * each set of blocks. It also holds the number of error-correction codewords per block since it 13997 * will be the same across all blocks within one version.</p> 13998 */ 13999 class ECBlocks { 14000 constructor(ecCodewordsPerBlock /*int*/, ...ecBlocks) { 14001 this.ecCodewordsPerBlock = ecCodewordsPerBlock; 14002 this.ecBlocks = ecBlocks; 14003 } 14004 getECCodewordsPerBlock() { 14005 return this.ecCodewordsPerBlock; 14006 } 14007 getNumBlocks() { 14008 let total = 0; 14009 const ecBlocks = this.ecBlocks; 14010 for (const ecBlock of ecBlocks) { 14011 total += ecBlock.getCount(); 14012 } 14013 return total; 14014 } 14015 getTotalECCodewords() { 14016 return this.ecCodewordsPerBlock * this.getNumBlocks(); 14017 } 14018 getECBlocks() { 14019 return this.ecBlocks; 14020 } 14021 } 14022 14023 /** 14024 * <p>Encapsulates the parameters for one error-correction block in one symbol version. 14025 * This includes the number of data codewords, and the number of times a block with these 14026 * parameters is used consecutively in the QR code version's format.</p> 14027 */ 14028 class ECB { 14029 constructor(count /*int*/, dataCodewords /*int*/) { 14030 this.count = count; 14031 this.dataCodewords = dataCodewords; 14032 } 14033 getCount() { 14034 return this.count; 14035 } 14036 getDataCodewords() { 14037 return this.dataCodewords; 14038 } 14039 } 14040 14041 /* 14042 * Copyright 2007 ZXing authors 14043 * 14044 * Licensed under the Apache License, Version 2.0 (the "License"); 14045 * you may not use this file except in compliance with the License. 14046 * You may obtain a copy of the License at 14047 * 14048 * http://www.apache.org/licenses/LICENSE-2.0 14049 * 14050 * Unless required by applicable law or agreed to in writing, software 14051 * distributed under the License is distributed on an "AS IS" BASIS, 14052 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14053 * See the License for the specific language governing permissions and 14054 * limitations under the License. 14055
vendor: 21,154 bytes, lines 14055-14357
14055*/ 14056 /** 14057 * See ISO 18004:2006 Annex D 14058 * 14059 * @author Sean Owen 14060 */ 14061 class Version { 14062 constructor(versionNumber /*int*/, alignmentPatternCenters, ...ecBlocks) { 14063 this.versionNumber = versionNumber; 14064 this.alignmentPatternCenters = alignmentPatternCenters; 14065 this.ecBlocks = ecBlocks; 14066 let total = 0; 14067 const ecCodewords = ecBlocks[0].getECCodewordsPerBlock(); 14068 const ecbArray = ecBlocks[0].getECBlocks(); 14069 for (const ecBlock of ecbArray) { 14070 total += ecBlock.getCount() * (ecBlock.getDataCodewords() + ecCodewords); 14071 } 14072 this.totalCodewords = total; 14073 } 14074 getVersionNumber() { 14075 return this.versionNumber; 14076 } 14077 getAlignmentPatternCenters() { 14078 return this.alignmentPatternCenters; 14079 } 14080 getTotalCodewords() { 14081 return this.totalCodewords; 14082 } 14083 getDimensionForVersion() { 14084 return 17 + 4 * this.versionNumber; 14085 } 14086 getECBlocksForLevel(ecLevel) { 14087 return this.ecBlocks[ecLevel.getValue()]; 14088 // TYPESCRIPTPORT: original was using ordinal, and using the order of levels as defined in ErrorCorrectionLevel enum (LMQH) 14089 // I will use the direct value from ErrorCorrectionLevelValues enum which in typescript goes to a number 14090 } 14091 /** 14092 * <p>Deduces version information purely from QR Code dimensions.</p> 14093 * 14094 * @param dimension dimension in modules 14095 * @return Version for a QR Code of that dimension 14096 * @throws FormatException if dimension is not 1 mod 4 14097 */ 14098 static getProvisionalVersionForDimension(dimension /*int*/) { 14099 if (dimension % 4 !== 1) { 14100 throw new FormatException(); 14101 } 14102 try { 14103 return this.getVersionForNumber((dimension - 17) / 4); 14104 } 14105 catch (ignored /*: IllegalArgumentException*/) { 14106 throw new FormatException(); 14107 } 14108 } 14109 static getVersionForNumber(versionNumber /*int*/) { 14110 if (versionNumber < 1 || versionNumber > 40) { 14111 throw new IllegalArgumentException(); 14112 } 14113 return Version.VERSIONS[versionNumber - 1]; 14114 } 14115 static decodeVersionInformation(versionBits /*int*/) { 14116 let bestDifference = Number.MAX_SAFE_INTEGER; 14117 let bestVersion = 0; 14118 for (let i = 0; i < Version.VERSION_DECODE_INFO.length; i++) { 14119 const targetVersion = Version.VERSION_DECODE_INFO[i]; 14120 // Do the version info bits match exactly? done. 14121 if (targetVersion === versionBits) { 14122 return Version.getVersionForNumber(i + 7); 14123 } 14124 // Otherwise see if this is the closest to a real version info bit string 14125 // we have seen so far 14126 const bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion); 14127 if (bitsDifference < bestDifference) { 14128 bestVersion = i + 7; 14129 bestDifference = bitsDifference; 14130 } 14131 } 14132 // We can tolerate up to 3 bits of error since no two version info codewords will 14133 // differ in less than 8 bits. 14134 if (bestDifference <= 3) { 14135 return Version.getVersionForNumber(bestVersion); 14136 } 14137 // If we didn't find a close enough match, fail 14138 return null; 14139 } 14140 /** 14141 * See ISO 18004:2006 Annex E 14142 */ 14143 buildFunctionPattern() { 14144 const dimension = this.getDimensionForVersion(); 14145 const bitMatrix = new BitMatrix(dimension); 14146 // Top left finder pattern + separator + format 14147 bitMatrix.setRegion(0, 0, 9, 9); 14148 // Top right finder pattern + separator + format 14149 bitMatrix.setRegion(dimension - 8, 0, 8, 9); 14150 // Bottom left finder pattern + separator + format 14151 bitMatrix.setRegion(0, dimension - 8, 9, 8); 14152 // Alignment patterns 14153 const max = this.alignmentPatternCenters.length; 14154 for (let x = 0; x < max; x++) { 14155 const i = this.alignmentPatternCenters[x] - 2; 14156 for (let y = 0; y < max; y++) { 14157 if ((x === 0 && (y === 0 || y === max - 1)) || (x === max - 1 && y === 0)) { 14158 // No alignment patterns near the three finder patterns 14159 continue; 14160 } 14161 bitMatrix.setRegion(this.alignmentPatternCenters[y] - 2, i, 5, 5); 14162 } 14163 } 14164 // Vertical timing pattern 14165 bitMatrix.setRegion(6, 9, 1, dimension - 17); 14166 // Horizontal timing pattern 14167 bitMatrix.setRegion(9, 6, dimension - 17, 1); 14168 if (this.versionNumber > 6) { 14169 // Version info, top right 14170 bitMatrix.setRegion(dimension - 11, 0, 3, 6); 14171 // Version info, bottom left 14172 bitMatrix.setRegion(0, dimension - 11, 6, 3); 14173 } 14174 return bitMatrix; 14175 } 14176 /*@Override*/ 14177 toString() { 14178 return '' + this.versionNumber; 14179 } 14180 } 14181 /** 14182 * See ISO 18004:2006 Annex D. 14183 * Element i represents the raw version bits that specify version i + 7 14184 */ 14185 Version.VERSION_DECODE_INFO = Int32Array.from([ 14186 0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6, 14187 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78, 14188 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683, 14189 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB, 14190 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250, 14191 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B, 14192 0x2542E, 0x26A64, 0x27541, 0x28C69 14193 ]); 14194 /** 14195 * See ISO 18004:2006 6.5.1 Table 9 14196 */ 14197 Version.VERSIONS = [ 14198 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))), 14199 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))), 14200 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))), 14201 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))), 14202 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))), 14203 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))), 14204 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))), 14205 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))), 14206 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))), 14207 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))), 14208 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))), 14209 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))), 14210 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))), 14211 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))), 14212 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))), 14213 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))), 14214 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))), 14215 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))), 14216 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))), 14217 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))), 14218 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))), 14219 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))), 14220 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))), 14221 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))), 14222 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))), 14223 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))), 14224 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))), 14225 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))), 14226 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))), 14227 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))), 14228 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))), 14229 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))), 14230 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))), 14231 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))), 14232 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))), 14233 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))), 14234 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))), 14235 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))), 14236 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))), 14237 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))) 14238 ]; 14239 14240 /* 14241 * Copyright 2007 ZXing authors 14242 * 14243 * Licensed under the Apache License, Version 2.0 (the "License"); 14244 * you may not use this file except in compliance with the License. 14245 * You may obtain a copy of the License at 14246 * 14247 * http://www.apache.org/licenses/LICENSE-2.0 14248 * 14249 * Unless required by applicable law or agreed to in writing, software 14250 * distributed under the License is distributed on an "AS IS" BASIS, 14251 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14252 * See the License for the specific language governing permissions and 14253 * limitations under the License. 14254 */ 14255 var DataMaskValues; 14256 (function (DataMaskValues) { 14257 DataMaskValues[DataMaskValues["DATA_MASK_000"] = 0] = "DATA_MASK_000"; 14258 DataMaskValues[DataMaskValues["DATA_MASK_001"] = 1] = "DATA_MASK_001"; 14259 DataMaskValues[DataMaskValues["DATA_MASK_010"] = 2] = "DATA_MASK_010"; 14260 DataMaskValues[DataMaskValues["DATA_MASK_011"] = 3] = "DATA_MASK_011"; 14261 DataMaskValues[DataMaskValues["DATA_MASK_100"] = 4] = "DATA_MASK_100"; 14262 DataMaskValues[DataMaskValues["DATA_MASK_101"] = 5] = "DATA_MASK_101"; 14263 DataMaskValues[DataMaskValues["DATA_MASK_110"] = 6] = "DATA_MASK_110"; 14264 DataMaskValues[DataMaskValues["DATA_MASK_111"] = 7] = "DATA_MASK_111"; 14265 })(DataMaskValues || (DataMaskValues = {})); 14266 /** 14267 * <p>Encapsulates data masks for the data bits in a QR code, per ISO 18004:2006 6.8. Implementations 14268 * of this class can un-mask a raw BitMatrix. For simplicity, they will unmask the entire BitMatrix, 14269 * including areas used for finder patterns, timing patterns, etc. These areas should be unused 14270 * after the point they are unmasked anyway.</p> 14271 * 14272 * <p>Note that the diagram in section 6.8.1 is misleading since it indicates that i is column position 14273 * and j is row position. In fact, as the text says, i is row position and j is column position.</p> 14274 * 14275 * @author Sean Owen 14276 */ 14277 class DataMask { 14278 // See ISO 18004:2006 6.8.1 14279 constructor(value, isMasked) { 14280 this.value = value; 14281 this.isMasked = isMasked; 14282 } 14283 // End of enum constants. 14284 /** 14285 * <p>Implementations of this method reverse the data masking process applied to a QR Code and 14286 * make its bits ready to read.</p> 14287 * 14288 * @param bits representation of QR Code bits 14289 * @param dimension dimension of QR Code, represented by bits, being unmasked 14290 */ 14291 unmaskBitMatrix(bits, dimension /*int*/) { 14292 for (let i = 0; i < dimension; i++) { 14293 for (let j = 0; j < dimension; j++) { 14294 if (this.isMasked(i, j)) { 14295 bits.flip(j, i); 14296 } 14297 } 14298 } 14299 } 14300 } 14301 DataMask.values = new Map([ 14302 /** 14303 * 000: mask bits for which (x + y) mod 2 == 0 14304 */ 14305 [DataMaskValues.DATA_MASK_000, new DataMask(DataMaskValues.DATA_MASK_000, (i /*int*/, j /*int*/) => { return ((i + j) & 0x01) === 0; })], 14306 /** 14307 * 001: mask bits for which x mod 2 == 0 14308 */ 14309 [DataMaskValues.DATA_MASK_001, new DataMask(DataMaskValues.DATA_MASK_001, (i /*int*/, j /*int*/) => { return (i & 0x01) === 0; })], 14310 /** 14311 * 010: mask bits for which y mod 3 == 0 14312 */ 14313 [DataMaskValues.DATA_MASK_010, new DataMask(DataMaskValues.DATA_MASK_010, (i /*int*/, j /*int*/) => { return j % 3 === 0; })], 14314 /** 14315 * 011: mask bits for which (x + y) mod 3 == 0 14316 */ 14317 [DataMaskValues.DATA_MASK_011, new DataMask(DataMaskValues.DATA_MASK_011, (i /*int*/, j /*int*/) => { return (i + j) % 3 === 0; })], 14318 /** 14319 * 100: mask bits for which (x/2 + y/3) mod 2 == 0 14320 */ 14321 [DataMaskValues.DATA_MASK_100, new DataMask(DataMaskValues.DATA_MASK_100, (i /*int*/, j /*int*/) => { return ((Math.floor(i / 2) + Math.floor(j / 3)) & 0x01) === 0; })], 14322 /** 14323 * 101: mask bits for which xy mod 2 + xy mod 3 == 0 14324 * equivalently, such that xy mod 6 == 0 14325 */ 14326 [DataMaskValues.DATA_MASK_101, new DataMask(DataMaskValues.DATA_MASK_101, (i /*int*/, j /*int*/) => { return (i * j) % 6 === 0; })], 14327 /** 14328 * 110: mask bits for which (xy mod 2 + xy mod 3) mod 2 == 0 14329 * equivalently, such that xy mod 6 < 3 14330 */ 14331 [DataMaskValues.DATA_MASK_110, new DataMask(DataMaskValues.DATA_MASK_110, (i /*int*/, j /*int*/) => { return ((i * j) % 6) < 3; })], 14332 /** 14333 * 111: mask bits for which ((x+y)mod 2 + xy mod 3) mod 2 == 0 14334 * equivalently, such that (x + y + xy mod 3) mod 2 == 0 14335 */ 14336 [DataMaskValues.DATA_MASK_111, new DataMask(DataMaskValues.DATA_MASK_111, (i /*int*/, j /*int*/) => { return ((i + j + ((i * j) % 3)) & 0x01) === 0; })], 14337 ]); 14338 14339 /* 14340 * Copyright 2007 ZXing authors 14341 * 14342 * Licensed under the Apache License, Version 2.0 (the "License"); 14343 * you may not use this file except in compliance with the License. 14344 * You may obtain a copy of the License at 14345 * 14346 * http://www.apache.org/licenses/LICENSE-2.0 14347 * 14348 * Unless required by applicable law or agreed to in writing, software 14349 * distributed under the License is distributed on an "AS IS" BASIS, 14350 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14351 * See the License for the specific language governing permissions and 14352 * limitations under the License. 14353 */ 14354 /** 14355 * @author Sean Owen 14356 */ 14357
vendor: 33,785 bytes, lines 14357-15095
14357class BitMatrixParser { 14358 /** 14359 * @param bitMatrix {@link BitMatrix} to parse 14360 * @throws FormatException if dimension is not >= 21 and 1 mod 4 14361 */ 14362 constructor(bitMatrix) { 14363 const dimension = bitMatrix.getHeight(); 14364 if (dimension < 21 || (dimension & 0x03) !== 1) { 14365 throw new FormatException(); 14366 } 14367 this.bitMatrix = bitMatrix; 14368 } 14369 /** 14370 * <p>Reads format information from one of its two locations within the QR Code.</p> 14371 * 14372 * @return {@link FormatInformation} encapsulating the QR Code's format info 14373 * @throws FormatException if both format information locations cannot be parsed as 14374 * the valid encoding of format information 14375 */ 14376 readFormatInformation() { 14377 if (this.parsedFormatInfo !== null && this.parsedFormatInfo !== undefined) { 14378 return this.parsedFormatInfo; 14379 } 14380 // Read top-left format info bits 14381 let formatInfoBits1 = 0; 14382 for (let i = 0; i < 6; i++) { 14383 formatInfoBits1 = this.copyBit(i, 8, formatInfoBits1); 14384 } 14385 // .. and skip a bit in the timing pattern ... 14386 formatInfoBits1 = this.copyBit(7, 8, formatInfoBits1); 14387 formatInfoBits1 = this.copyBit(8, 8, formatInfoBits1); 14388 formatInfoBits1 = this.copyBit(8, 7, formatInfoBits1); 14389 // .. and skip a bit in the timing pattern ... 14390 for (let j = 5; j >= 0; j--) { 14391 formatInfoBits1 = this.copyBit(8, j, formatInfoBits1); 14392 } 14393 // Read the top-right/bottom-left pattern too 14394 const dimension = this.bitMatrix.getHeight(); 14395 let formatInfoBits2 = 0; 14396 const jMin = dimension - 7; 14397 for (let j = dimension - 1; j >= jMin; j--) { 14398 formatInfoBits2 = this.copyBit(8, j, formatInfoBits2); 14399 } 14400 for (let i = dimension - 8; i < dimension; i++) { 14401 formatInfoBits2 = this.copyBit(i, 8, formatInfoBits2); 14402 } 14403 this.parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits1, formatInfoBits2); 14404 if (this.parsedFormatInfo !== null) { 14405 return this.parsedFormatInfo; 14406 } 14407 throw new FormatException(); 14408 } 14409 /** 14410 * <p>Reads version information from one of its two locations within the QR Code.</p> 14411 * 14412 * @return {@link Version} encapsulating the QR Code's version 14413 * @throws FormatException if both version information locations cannot be parsed as 14414 * the valid encoding of version information 14415 */ 14416 readVersion() { 14417 if (this.parsedVersion !== null && this.parsedVersion !== undefined) { 14418 return this.parsedVersion; 14419 } 14420 const dimension = this.bitMatrix.getHeight(); 14421 const provisionalVersion = Math.floor((dimension - 17) / 4); 14422 if (provisionalVersion <= 6) { 14423 return Version.getVersionForNumber(provisionalVersion); 14424 } 14425 // Read top-right version info: 3 wide by 6 tall 14426 let versionBits = 0; 14427 const ijMin = dimension - 11; 14428 for (let j = 5; j >= 0; j--) { 14429 for (let i = dimension - 9; i >= ijMin; i--) { 14430 versionBits = this.copyBit(i, j, versionBits); 14431 } 14432 } 14433 let theParsedVersion = Version.decodeVersionInformation(versionBits); 14434 if (theParsedVersion !== null && theParsedVersion.getDimensionForVersion() === dimension) { 14435 this.parsedVersion = theParsedVersion; 14436 return theParsedVersion; 14437 } 14438 // Hmm, failed. Try bottom left: 6 wide by 3 tall 14439 versionBits = 0; 14440 for (let i = 5; i >= 0; i--) { 14441 for (let j = dimension - 9; j >= ijMin; j--) { 14442 versionBits = this.copyBit(i, j, versionBits); 14443 } 14444 } 14445 theParsedVersion = Version.decodeVersionInformation(versionBits); 14446 if (theParsedVersion !== null && theParsedVersion.getDimensionForVersion() === dimension) { 14447 this.parsedVersion = theParsedVersion; 14448 return theParsedVersion; 14449 } 14450 throw new FormatException(); 14451 } 14452 copyBit(i /*int*/, j /*int*/, versionBits /*int*/) { 14453 const bit = this.isMirror ? this.bitMatrix.get(j, i) : this.bitMatrix.get(i, j); 14454 return bit ? (versionBits << 1) | 0x1 : versionBits << 1; 14455 } 14456 /** 14457 * <p>Reads the bits in the {@link BitMatrix} representing the finder pattern in the 14458 * correct order in order to reconstruct the codewords bytes contained within the 14459 * QR Code.</p> 14460 * 14461 * @return bytes encoded within the QR Code 14462 * @throws FormatException if the exact number of bytes expected is not read 14463 */ 14464 readCodewords() { 14465 const formatInfo = this.readFormatInformation(); 14466 const version = this.readVersion(); 14467 // Get the data mask for the format used in this QR Code. This will exclude 14468 // some bits from reading as we wind through the bit matrix. 14469 const dataMask = DataMask.values.get(formatInfo.getDataMask()); 14470 const dimension = this.bitMatrix.getHeight(); 14471 dataMask.unmaskBitMatrix(this.bitMatrix, dimension); 14472 const functionPattern = version.buildFunctionPattern(); 14473 let readingUp = true; 14474 const result = new Uint8Array(version.getTotalCodewords()); 14475 let resultOffset = 0; 14476 let currentByte = 0; 14477 let bitsRead = 0; 14478 // Read columns in pairs, from right to left 14479 for (let j = dimension - 1; j > 0; j -= 2) { 14480 if (j === 6) { 14481 // Skip whole column with vertical alignment pattern 14482 // saves time and makes the other code proceed more cleanly 14483 j--; 14484 } 14485 // Read alternatingly from bottom to top then top to bottom 14486 for (let count = 0; count < dimension; count++) { 14487 const i = readingUp ? dimension - 1 - count : count; 14488 for (let col = 0; col < 2; col++) { 14489 // Ignore bits covered by the function pattern 14490 if (!functionPattern.get(j - col, i)) { 14491 // Read a bit 14492 bitsRead++; 14493 currentByte <<= 1; 14494 if (this.bitMatrix.get(j - col, i)) { 14495 currentByte |= 1; 14496 } 14497 // If we've made a whole byte, save it off 14498 if (bitsRead === 8) { 14499 result[resultOffset++] = /*(byte) */ currentByte; 14500 bitsRead = 0; 14501 currentByte = 0; 14502 } 14503 } 14504 } 14505 } 14506 readingUp = !readingUp; // readingUp ^= true; // readingUp = !readingUp; // switch directions 14507 } 14508 if (resultOffset !== version.getTotalCodewords()) { 14509 throw new FormatException(); 14510 } 14511 return result; 14512 } 14513 /** 14514 * Revert the mask removal done while reading the code words. The bit matrix should revert to its original state. 14515 */ 14516 remask() { 14517 if (this.parsedFormatInfo === null) { 14518 return; // We have no format information, and have no data mask 14519 } 14520 const dataMask = DataMask.values.get(this.parsedFormatInfo.getDataMask()); 14521 const dimension = this.bitMatrix.getHeight(); 14522 dataMask.unmaskBitMatrix(this.bitMatrix, dimension); 14523 } 14524 /** 14525 * Prepare the parser for a mirrored operation. 14526 * This flag has effect only on the {@link #readFormatInformation()} and the 14527 * {@link #readVersion()}. Before proceeding with {@link #readCodewords()} the 14528 * {@link #mirror()} method should be called. 14529 * 14530 * @param mirror Whether to read version and format information mirrored. 14531 */ 14532 setMirror(isMirror) { 14533 this.parsedVersion = null; 14534 this.parsedFormatInfo = null; 14535 this.isMirror = isMirror; 14536 } 14537 /** Mirror the bit matrix in order to attempt a second reading. */ 14538 mirror() { 14539 const bitMatrix = this.bitMatrix; 14540 for (let x = 0, width = bitMatrix.getWidth(); x < width; x++) { 14541 for (let y = x + 1, height = bitMatrix.getHeight(); y < height; y++) { 14542 if (bitMatrix.get(x, y) !== bitMatrix.get(y, x)) { 14543 bitMatrix.flip(y, x); 14544 bitMatrix.flip(x, y); 14545 } 14546 } 14547 } 14548 } 14549 } 14550 14551 /* 14552 * Copyright 2007 ZXing authors 14553 * 14554 * Licensed under the Apache License, Version 2.0 (the "License"); 14555 * you may not use this file except in compliance with the License. 14556 * You may obtain a copy of the License at 14557 * 14558 * http://www.apache.org/licenses/LICENSE-2.0 14559 * 14560 * Unless required by applicable law or agreed to in writing, software 14561 * distributed under the License is distributed on an "AS IS" BASIS, 14562 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14563 * See the License for the specific language governing permissions and 14564 * limitations under the License. 14565 */ 14566 /** 14567 * <p>Encapsulates a block of data within a QR Code. QR Codes may split their data into 14568 * multiple blocks, each of which is a unit of data and error-correction codewords. Each 14569 * is represented by an instance of this class.</p> 14570 * 14571 * @author Sean Owen 14572 */ 14573 class DataBlock { 14574 constructor(numDataCodewords /*int*/, codewords) { 14575 this.numDataCodewords = numDataCodewords; 14576 this.codewords = codewords; 14577 } 14578 /** 14579 * <p>When QR Codes use multiple data blocks, they are actually interleaved. 14580 * That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This 14581 * method will separate the data into original blocks.</p> 14582 * 14583 * @param rawCodewords bytes as read directly from the QR Code 14584 * @param version version of the QR Code 14585 * @param ecLevel error-correction level of the QR Code 14586 * @return DataBlocks containing original bytes, "de-interleaved" from representation in the 14587 * QR Code 14588 */ 14589 static getDataBlocks(rawCodewords, version, ecLevel) { 14590 if (rawCodewords.length !== version.getTotalCodewords()) { 14591 throw new IllegalArgumentException(); 14592 } 14593 // Figure out the number and size of data blocks used by this version and 14594 // error correction level 14595 const ecBlocks = version.getECBlocksForLevel(ecLevel); 14596 // First count the total number of data blocks 14597 let totalBlocks = 0; 14598 const ecBlockArray = ecBlocks.getECBlocks(); 14599 for (const ecBlock of ecBlockArray) { 14600 totalBlocks += ecBlock.getCount(); 14601 } 14602 // Now establish DataBlocks of the appropriate size and number of data codewords 14603 const result = new Array(totalBlocks); 14604 let numResultBlocks = 0; 14605 for (const ecBlock of ecBlockArray) { 14606 for (let i = 0; i < ecBlock.getCount(); i++) { 14607 const numDataCodewords = ecBlock.getDataCodewords(); 14608 const numBlockCodewords = ecBlocks.getECCodewordsPerBlock() + numDataCodewords; 14609 result[numResultBlocks++] = new DataBlock(numDataCodewords, new Uint8Array(numBlockCodewords)); 14610 } 14611 } 14612 // All blocks have the same amount of data, except that the last n 14613 // (where n may be 0) have 1 more byte. Figure out where these start. 14614 const shorterBlocksTotalCodewords = result[0].codewords.length; 14615 let longerBlocksStartAt = result.length - 1; 14616 // TYPESCRIPTPORT: check length is correct here 14617 while (longerBlocksStartAt >= 0) { 14618 const numCodewords = result[longerBlocksStartAt].codewords.length; 14619 if (numCodewords === shorterBlocksTotalCodewords) { 14620 break; 14621 } 14622 longerBlocksStartAt--; 14623 } 14624 longerBlocksStartAt++; 14625 const shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewordsPerBlock(); 14626 // The last elements of result may be 1 element longer 14627 // first fill out as many elements as all of them have 14628 let rawCodewordsOffset = 0; 14629 for (let i = 0; i < shorterBlocksNumDataCodewords; i++) { 14630 for (let j = 0; j < numResultBlocks; j++) { 14631 result[j].codewords[i] = rawCodewords[rawCodewordsOffset++]; 14632 } 14633 } 14634 // Fill out the last data block in the longer ones 14635 for (let j = longerBlocksStartAt; j < numResultBlocks; j++) { 14636 result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++]; 14637 } 14638 // Now add in error correction blocks 14639 const max = result[0].codewords.length; 14640 for (let i = shorterBlocksNumDataCodewords; i < max; i++) { 14641 for (let j = 0; j < numResultBlocks; j++) { 14642 const iOffset = j < longerBlocksStartAt ? i : i + 1; 14643 result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++]; 14644 } 14645 } 14646 return result; 14647 } 14648 getNumDataCodewords() { 14649 return this.numDataCodewords; 14650 } 14651 getCodewords() { 14652 return this.codewords; 14653 } 14654 } 14655 14656 /* 14657 * Copyright 2007 ZXing authors 14658 * 14659 * Licensed under the Apache License, Version 2.0 (the "License"); 14660 * you may not use this file except in compliance with the License. 14661 * You may obtain a copy of the License at 14662 * 14663 * http://www.apache.org/licenses/LICENSE-2.0 14664 * 14665 * Unless required by applicable law or agreed to in writing, software 14666 * distributed under the License is distributed on an "AS IS" BASIS, 14667 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14668 * See the License for the specific language governing permissions and 14669 * limitations under the License. 14670 */ 14671 var ModeValues; 14672 (function (ModeValues) { 14673 ModeValues[ModeValues["TERMINATOR"] = 0] = "TERMINATOR"; 14674 ModeValues[ModeValues["NUMERIC"] = 1] = "NUMERIC"; 14675 ModeValues[ModeValues["ALPHANUMERIC"] = 2] = "ALPHANUMERIC"; 14676 ModeValues[ModeValues["STRUCTURED_APPEND"] = 3] = "STRUCTURED_APPEND"; 14677 ModeValues[ModeValues["BYTE"] = 4] = "BYTE"; 14678 ModeValues[ModeValues["ECI"] = 5] = "ECI"; 14679 ModeValues[ModeValues["KANJI"] = 6] = "KANJI"; 14680 ModeValues[ModeValues["FNC1_FIRST_POSITION"] = 7] = "FNC1_FIRST_POSITION"; 14681 ModeValues[ModeValues["FNC1_SECOND_POSITION"] = 8] = "FNC1_SECOND_POSITION"; 14682 /** See GBT 18284-2000; "Hanzi" is a transliteration of this mode name. */ 14683 ModeValues[ModeValues["HANZI"] = 9] = "HANZI"; 14684 })(ModeValues || (ModeValues = {})); 14685 /** 14686 * <p>See ISO 18004:2006, 6.4.1, Tables 2 and 3. This enum encapsulates the various modes in which 14687 * data can be encoded to bits in the QR code standard.</p> 14688 * 14689 * @author Sean Owen 14690 */ 14691 class Mode$2 { 14692 constructor(value, stringValue, characterCountBitsForVersions, bits /*int*/) { 14693 this.value = value; 14694 this.stringValue = stringValue; 14695 this.characterCountBitsForVersions = characterCountBitsForVersions; 14696 this.bits = bits; 14697 Mode$2.FOR_BITS.set(bits, this); 14698 Mode$2.FOR_VALUE.set(value, this); 14699 } 14700 /** 14701 * @param bits four bits encoding a QR Code data mode 14702 * @return Mode encoded by these bits 14703 * @throws IllegalArgumentException if bits do not correspond to a known mode 14704 */ 14705 static forBits(bits /*int*/) { 14706 const mode = Mode$2.FOR_BITS.get(bits); 14707 if (undefined === mode) { 14708 throw new IllegalArgumentException(); 14709 } 14710 return mode; 14711 } 14712 /** 14713 * @param version version in question 14714 * @return number of bits used, in this QR Code symbol {@link Version}, to encode the 14715 * count of characters that will follow encoded in this Mode 14716 */ 14717 getCharacterCountBits(version) { 14718 const versionNumber = version.getVersionNumber(); 14719 let offset; 14720 if (versionNumber <= 9) { 14721 offset = 0; 14722 } 14723 else if (versionNumber <= 26) { 14724 offset = 1; 14725 } 14726 else { 14727 offset = 2; 14728 } 14729 return this.characterCountBitsForVersions[offset]; 14730 } 14731 getValue() { 14732 return this.value; 14733 } 14734 getBits() { 14735 return this.bits; 14736 } 14737 equals(o) { 14738 if (!(o instanceof Mode$2)) { 14739 return false; 14740 } 14741 const other = o; 14742 return this.value === other.value; 14743 } 14744 toString() { 14745 return this.stringValue; 14746 } 14747 } 14748 Mode$2.FOR_BITS = new Map(); 14749 Mode$2.FOR_VALUE = new Map(); 14750 Mode$2.TERMINATOR = new Mode$2(ModeValues.TERMINATOR, 'TERMINATOR', Int32Array.from([0, 0, 0]), 0x00); // Not really a mode... 14751 Mode$2.NUMERIC = new Mode$2(ModeValues.NUMERIC, 'NUMERIC', Int32Array.from([10, 12, 14]), 0x01); 14752 Mode$2.ALPHANUMERIC = new Mode$2(ModeValues.ALPHANUMERIC, 'ALPHANUMERIC', Int32Array.from([9, 11, 13]), 0x02); 14753 Mode$2.STRUCTURED_APPEND = new Mode$2(ModeValues.STRUCTURED_APPEND, 'STRUCTURED_APPEND', Int32Array.from([0, 0, 0]), 0x03); // Not supported 14754 Mode$2.BYTE = new Mode$2(ModeValues.BYTE, 'BYTE', Int32Array.from([8, 16, 16]), 0x04); 14755 Mode$2.ECI = new Mode$2(ModeValues.ECI, 'ECI', Int32Array.from([0, 0, 0]), 0x07); // character counts don't apply 14756 Mode$2.KANJI = new Mode$2(ModeValues.KANJI, 'KANJI', Int32Array.from([8, 10, 12]), 0x08); 14757 Mode$2.FNC1_FIRST_POSITION = new Mode$2(ModeValues.FNC1_FIRST_POSITION, 'FNC1_FIRST_POSITION', Int32Array.from([0, 0, 0]), 0x05); 14758 Mode$2.FNC1_SECOND_POSITION = new Mode$2(ModeValues.FNC1_SECOND_POSITION, 'FNC1_SECOND_POSITION', Int32Array.from([0, 0, 0]), 0x09); 14759 /** See GBT 18284-2000; "Hanzi" is a transliteration of this mode name. */ 14760 Mode$2.HANZI = new Mode$2(ModeValues.HANZI, 'HANZI', Int32Array.from([8, 10, 12]), 0x0D); 14761 14762 /* 14763 * Copyright 2007 ZXing authors 14764 * 14765 * Licensed under the Apache License, Version 2.0 (the "License"); 14766 * you may not use this file except in compliance with the License. 14767 * You may obtain a copy of the License at 14768 * 14769 * http://www.apache.org/licenses/LICENSE-2.0 14770 * 14771 * Unless required by applicable law or agreed to in writing, software 14772 * distributed under the License is distributed on an "AS IS" BASIS, 14773 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14774 * See the License for the specific language governing permissions and 14775 * limitations under the License. 14776 */ 14777 /*import java.io.UnsupportedEncodingException;*/ 14778 /*import java.util.ArrayList;*/ 14779 /*import java.util.Collection;*/ 14780 /*import java.util.List;*/ 14781 /*import java.util.Map;*/ 14782 /** 14783 * <p>QR Codes can encode text as bits in one of several modes, and can use multiple modes 14784 * in one QR Code. This class decodes the bits back into text.</p> 14785 * 14786 * <p>See ISO 18004:2006, 6.4.3 - 6.4.7</p> 14787 * 14788 * @author Sean Owen 14789 */ 14790 class DecodedBitStreamParser$1 { 14791 static decode(bytes, version, ecLevel, hints) { 14792 const bits = new BitSource(bytes); 14793 let result = new StringBuilder(); 14794 const byteSegments = new Array(); // 1 14795 // TYPESCRIPTPORT: I do not use constructor with size 1 as in original Java means capacity and the array length is checked below 14796 let symbolSequence = -1; 14797 let parityData = -1; 14798 try { 14799 let currentCharacterSetECI = null; 14800 let fc1InEffect = false; 14801 let mode; 14802 do { 14803 // While still another segment to read... 14804 if (bits.available() < 4) { 14805 // OK, assume we're done. Really, a TERMINATOR mode should have been recorded here 14806 mode = Mode$2.TERMINATOR; 14807 } 14808 else { 14809 const modeBits = bits.readBits(4); 14810 mode = Mode$2.forBits(modeBits); // mode is encoded by 4 bits 14811 } 14812 switch (mode) { 14813 case Mode$2.TERMINATOR: 14814 break; 14815 case Mode$2.FNC1_FIRST_POSITION: 14816 case Mode$2.FNC1_SECOND_POSITION: 14817 // We do little with FNC1 except alter the parsed result a bit according to the spec 14818 fc1InEffect = true; 14819 break; 14820 case Mode$2.STRUCTURED_APPEND: 14821 if (bits.available() < 16) { 14822 throw new FormatException(); 14823 } 14824 // sequence number and parity is added later to the result metadata 14825 // Read next 8 bits (symbol sequence #) and 8 bits (data: parity), then continue 14826 symbolSequence = bits.readBits(8); 14827 parityData = bits.readBits(8); 14828 break; 14829 case Mode$2.ECI: 14830 // Count doesn't apply to ECI 14831 const value = DecodedBitStreamParser$1.parseECIValue(bits); 14832 currentCharacterSetECI = CharacterSetECI.getCharacterSetECIByValue(value); 14833 if (currentCharacterSetECI === null) { 14834 throw new FormatException(); 14835 } 14836 break; 14837 case Mode$2.HANZI: 14838 // First handle Hanzi mode which does not start with character count 14839 // Chinese mode contains a sub set indicator right after mode indicator 14840 const subset = bits.readBits(4); 14841 const countHanzi = bits.readBits(mode.getCharacterCountBits(version)); 14842 if (subset === DecodedBitStreamParser$1.GB2312_SUBSET) { 14843 DecodedBitStreamParser$1.decodeHanziSegment(bits, result, countHanzi); 14844 } 14845 break; 14846 default: 14847 // "Normal" QR code modes: 14848 // How many characters will follow, encoded in this mode? 14849 const count = bits.readBits(mode.getCharacterCountBits(version)); 14850 switch (mode) { 14851 case Mode$2.NUMERIC: 14852 DecodedBitStreamParser$1.decodeNumericSegment(bits, result, count); 14853 break; 14854 case Mode$2.ALPHANUMERIC: 14855 DecodedBitStreamParser$1.decodeAlphanumericSegment(bits, result, count, fc1InEffect); 14856 break; 14857 case Mode$2.BYTE: 14858 DecodedBitStreamParser$1.decodeByteSegment(bits, result, count, currentCharacterSetECI, byteSegments, hints); 14859 break; 14860 case Mode$2.KANJI: 14861 DecodedBitStreamParser$1.decodeKanjiSegment(bits, result, count); 14862 break; 14863 default: 14864 throw new FormatException(); 14865 } 14866 break; 14867 } 14868 } while (mode !== Mode$2.TERMINATOR); 14869 } 14870 catch (iae /*: IllegalArgumentException*/) { 14871 // from readBits() calls 14872 throw new FormatException(); 14873 } 14874 return new DecoderResult(bytes, result.toString(), byteSegments.length === 0 ? null : byteSegments, ecLevel === null ? null : ecLevel.toString(), symbolSequence, parityData); 14875 } 14876 /** 14877 * See specification GBT 18284-2000 14878 */ 14879 static decodeHanziSegment(bits, result, count /*int*/) { 14880 // Don't crash trying to read more bits than we have available. 14881 if (count * 13 > bits.available()) { 14882 throw new FormatException(); 14883 } 14884 // Each character will require 2 bytes. Read the characters as 2-byte pairs 14885 // and decode as GB2312 afterwards 14886 const buffer = new Uint8Array(2 * count); 14887 let offset = 0; 14888 while (count > 0) { 14889 // Each 13 bits encodes a 2-byte character 14890 const twoBytes = bits.readBits(13); 14891 let assembledTwoBytes = (((twoBytes / 0x060) << 8) & 0xFFFFFFFF) | (twoBytes % 0x060); 14892 if (assembledTwoBytes < 0x003BF) { 14893 // In the 0xA1A1 to 0xAAFE range 14894 assembledTwoBytes += 0x0A1A1; 14895 } 14896 else { 14897 // In the 0xB0A1 to 0xFAFE range 14898 assembledTwoBytes += 0x0A6A1; 14899 } 14900 buffer[offset] = /*(byte) */ ((assembledTwoBytes >> 8) & 0xFF); 14901 buffer[offset + 1] = /*(byte) */ (assembledTwoBytes & 0xFF); 14902 offset += 2; 14903 count--; 14904 } 14905 try { 14906 result.append(StringEncoding.decode(buffer, StringUtils.GB2312)); 14907 // TYPESCRIPTPORT: TODO: implement GB2312 decode. StringView from MDN could be a starting point 14908 } 14909 catch (ignored /*: UnsupportedEncodingException*/) { 14910 throw new FormatException(ignored); 14911 } 14912 } 14913 static decodeKanjiSegment(bits, result, count /*int*/) { 14914 // Don't crash trying to read more bits than we have available. 14915 if (count * 13 > bits.available()) { 14916 throw new FormatException(); 14917 } 14918 // Each character will require 2 bytes. Read the characters as 2-byte pairs 14919 // and decode as Shift_JIS afterwards 14920 const buffer = new Uint8Array(2 * count); 14921 let offset = 0; 14922 while (count > 0) { 14923 // Each 13 bits encodes a 2-byte character 14924 const twoBytes = bits.readBits(13); 14925 let assembledTwoBytes = (((twoBytes / 0x0C0) << 8) & 0xFFFFFFFF) | (twoBytes % 0x0C0); 14926 if (assembledTwoBytes < 0x01F00) { 14927 // In the 0x8140 to 0x9FFC range 14928 assembledTwoBytes += 0x08140; 14929 } 14930 else { 14931 // In the 0xE040 to 0xEBBF range 14932 assembledTwoBytes += 0x0C140; 14933 } 14934 buffer[offset] = /*(byte) */ (assembledTwoBytes >> 8); 14935 buffer[offset + 1] = /*(byte) */ assembledTwoBytes; 14936 offset += 2; 14937 count--; 14938 } 14939 // Shift_JIS may not be supported in some environments: 14940 try { 14941 result.append(StringEncoding.decode(buffer, StringUtils.SHIFT_JIS)); 14942 // TYPESCRIPTPORT: TODO: implement SHIFT_JIS decode. StringView from MDN could be a starting point 14943 } 14944 catch (ignored /*: UnsupportedEncodingException*/) { 14945 throw new FormatException(ignored); 14946 } 14947 } 14948 static decodeByteSegment(bits, result, count /*int*/, currentCharacterSetECI, byteSegments, hints) { 14949 // Don't crash trying to read more bits than we have available. 14950 if (8 * count > bits.available()) { 14951 throw new FormatException(); 14952 } 14953 const readBytes = new Uint8Array(count); 14954 for (let i = 0; i < count; i++) { 14955 readBytes[i] = /*(byte) */ bits.readBits(8); 14956 } 14957 let encoding; 14958 if (currentCharacterSetECI === null) { 14959 // The spec isn't clear on this mode; see 14960 // section 6.4.5: t does not say which encoding to assuming 14961 // upon decoding. I have seen ISO-8859-1 used as well as 14962 // Shift_JIS -- without anything like an ECI designator to 14963 // give a hint. 14964 encoding = StringUtils.guessEncoding(readBytes, hints); 14965 } 14966 else { 14967 encoding = currentCharacterSetECI.getName(); 14968 } 14969 try { 14970 result.append(StringEncoding.decode(readBytes, encoding)); 14971 } 14972 catch (ignored /*: UnsupportedEncodingException*/) { 14973 throw new FormatException(ignored); 14974 } 14975 byteSegments.push(readBytes); 14976 } 14977 static toAlphaNumericChar(value /*int*/) { 14978 if (value >= DecodedBitStreamParser$1.ALPHANUMERIC_CHARS.length) { 14979 throw new FormatException(); 14980 } 14981 return DecodedBitStreamParser$1.ALPHANUMERIC_CHARS[value]; 14982 } 14983 static decodeAlphanumericSegment(bits, result, count /*int*/, fc1InEffect) { 14984 // Read two characters at a time 14985 const start = result.length(); 14986 while (count > 1) { 14987 if (bits.available() < 11) { 14988 throw new FormatException(); 14989 } 14990 const nextTwoCharsBits = bits.readBits(11); 14991 result.append(DecodedBitStreamParser$1.toAlphaNumericChar(Math.floor(nextTwoCharsBits / 45))); 14992 result.append(DecodedBitStreamParser$1.toAlphaNumericChar(nextTwoCharsBits % 45)); 14993 count -= 2; 14994 } 14995 if (count === 1) { 14996 // special case: one character left 14997 if (bits.available() < 6) { 14998 throw new FormatException(); 14999 } 15000 result.append(DecodedBitStreamParser$1.toAlphaNumericChar(bits.readBits(6))); 15001 } 15002 // See section 6.4.8.1, 6.4.8.2 15003 if (fc1InEffect) { 15004 // We need to massage the result a bit if in an FNC1 mode: 15005 for (let i = start; i < result.length(); i++) { 15006 if (result.charAt(i) === '%') { 15007 if (i < result.length() - 1 && result.charAt(i + 1) === '%') { 15008 // %% is rendered as % 15009 result.deleteCharAt(i + 1); 15010 } 15011 else { 15012 // In alpha mode, % should be converted to FNC1 separator 0x1D 15013 result.setCharAt(i, String.fromCharCode(0x1D)); 15014 } 15015 } 15016 } 15017 } 15018 } 15019 static decodeNumericSegment(bits, result, count /*int*/) { 15020 // Read three digits at a time 15021 while (count >= 3) { 15022 // Each 10 bits encodes three digits 15023 if (bits.available() < 10) { 15024 throw new FormatException(); 15025 } 15026 const threeDigitsBits = bits.readBits(10); 15027 if (threeDigitsBits >= 1000) { 15028 throw new FormatException(); 15029 } 15030 result.append(DecodedBitStreamParser$1.toAlphaNumericChar(Math.floor(threeDigitsBits / 100))); 15031 result.append(DecodedBitStreamParser$1.toAlphaNumericChar(Math.floor(threeDigitsBits / 10) % 10)); 15032 result.append(DecodedBitStreamParser$1.toAlphaNumericChar(threeDigitsBits % 10)); 15033 count -= 3; 15034 } 15035 if (count === 2) { 15036 // Two digits left over to read, encoded in 7 bits 15037 if (bits.available() < 7) { 15038 throw new FormatException(); 15039 } 15040 const twoDigitsBits = bits.readBits(7); 15041 if (twoDigitsBits >= 100) { 15042 throw new FormatException(); 15043 } 15044 result.append(DecodedBitStreamParser$1.toAlphaNumericChar(Math.floor(twoDigitsBits / 10))); 15045 result.append(DecodedBitStreamParser$1.toAlphaNumericChar(twoDigitsBits % 10)); 15046 } 15047 else if (count === 1) { 15048 // One digit left over to read 15049 if (bits.available() < 4) { 15050 throw new FormatException(); 15051 } 15052 const digitBits = bits.readBits(4); 15053 if (digitBits >= 10) { 15054 throw new FormatException(); 15055 } 15056 result.append(DecodedBitStreamParser$1.toAlphaNumericChar(digitBits)); 15057 } 15058 } 15059 static parseECIValue(bits) { 15060 const firstByte = bits.readBits(8); 15061 if ((firstByte & 0x80) === 0) { 15062 // just one byte 15063 return firstByte & 0x7F; 15064 } 15065 if ((firstByte & 0xC0) === 0x80) { 15066 // two bytes 15067 const secondByte = bits.readBits(8); 15068 return (((firstByte & 0x3F) << 8) & 0xFFFFFFFF) | secondByte; 15069 } 15070 if ((firstByte & 0xE0) === 0xC0) { 15071 // three bytes 15072 const secondThirdBytes = bits.readBits(16); 15073 return (((firstByte & 0x1F) << 16) & 0xFFFFFFFF) | secondThirdBytes; 15074 } 15075 throw new FormatException(); 15076 } 15077 } 15078 /** 15079 * See ISO 18004:2006, 6.4.4 Table 5 15080 */ 15081 DecodedBitStreamParser$1.ALPHANUMERIC_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:'; 15082 DecodedBitStreamParser$1.GB2312_SUBSET = 1; 15083 // function Uint8ArrayToString(a: Uint8Array): string { 15084 // const CHUNK_SZ = 0x8000; 15085 // const c = new StringBuilder(); 15086 // for (let i = 0, length = a.length; i < length; i += CHUNK_SZ) { 15087 // c.append(String.fromCharCode.apply(null, a.subarray(i, i + CHUNK_SZ))); 15088 // } 15089 // return c.toString(); 15090 // } 15091 15092 /* 15093 * Copyright 2013 ZXing authors 15094 * 15095 * Licensed under the Apache License, Version 2.0 (the "License");
15096 * you may not use this file except in compliance with the License. 15097 * You may obtain a copy of the License at 15098 * 15099 * http://www.apache.org/licenses/LICENSE-2.0 15100 * 15101 * Unless required by applicable law or agreed to in writing, software 15102 * distributed under the License is distributed on an "AS IS" BASIS, 15103 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15104 * See the License for the specific language governing permissions and 15105 * limitations under the License. 15106 */ 15107 /** 15108 * Meta-data container for QR Code decoding. Instances of this class may be used to convey information back to the 15109 * decoding caller. Callers are expected to process this. 15110 * 15111 * @see com.google.zxing.common.DecoderResult#getOther() 15112 */ 15113 class QRCodeDecoderMetaData { 15114 constructor(mirrored) { 15115 this.mirrored = mirrored; 15116 } 15117 /** 15118 * @return true if the QR Code was mirrored. 15119 */ 15120 isMirrored() { 15121 return this.mirrored; 15122 } 15123 /** 15124 * Apply the result points' order correction due to mirroring. 15125 * 15126 * @param points Array of points to apply mirror correction to. 15127 */ 15128 applyMirroredCorrection(points) { 15129 if (!this.mirrored || points === null || points.length < 3) { 15130 return; 15131 } 15132 const bottomLeft = points[0]; 15133 points[0] = points[2]; 15134 points[2] = bottomLeft; 15135 // No need to 'fix' top-left and alignment pattern. 15136 } 15137 } 15138 15139 /* 15140 * Copyright 2007 ZXing authors 15141 * 15142 * Licensed under the Apache License, Version 2.0 (the "License"); 15143 * you may not use this file except in compliance with the License. 15144 * You may obtain a copy of the License at 15145 * 15146 * http://www.apache.org/licenses/LICENSE-2.0 15147 * 15148 * Unless required by applicable law or agreed to in writing, software 15149 * distributed under the License is distributed on an "AS IS" BASIS, 15150 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15151 * See the License for the specific language governing permissions and 15152 * limitations under the License. 15153 */ 15154 /*import java.util.Map;*/ 15155 /** 15156 * <p>The main class which implements QR Code decoding -- as opposed to locating and extracting 15157 * the QR Code from an image.</p> 15158 * 15159 * @author Sean Owen 15160 */ 15161 class Decoder { 15162 constructor() { 15163 this.rsDecoder = new ReedSolomonDecoder(GenericGF.QR_CODE_FIELD_256); 15164 } 15165 // public decode(image: boolean[][]): DecoderResult /*throws ChecksumException, FormatException*/ { 15166 // return decode(image, null) 15167 // } 15168 /** 15169 * <p>Convenience method that can decode a QR Code represented as a 2D array of booleans. 15170 * "true" is taken to mean a black module.</p> 15171 * 15172 * @param image booleans representing white/black QR Code modules 15173 * @param hints decoding hints that should be used to influence decoding 15174 * @return text and bytes encoded within the QR Code 15175 * @throws FormatException if the QR Code cannot be decoded 15176 * @throws ChecksumException if error correction fails 15177 */ 15178 decodeBooleanArray(image, hints) { 15179 return this.decodeBitMatrix(BitMatrix.parseFromBooleanArray(image), hints); 15180 } 15181 // public decodeBitMatrix(bits: BitMatrix): DecoderResult /*throws ChecksumException, FormatException*/ { 15182 // return decode(bits, null) 15183 // } 15184 /** 15185 * <p>Decodes a QR Code represented as a {@link BitMatrix}. A 1 or "true" is taken to mean a black module.</p> 15186 * 15187 * @param bits booleans representing white/black QR Code modules 15188 * @param hints decoding hints that should be used to influence decoding 15189 * @return text and bytes encoded within the QR Code 15190 * @throws FormatException if the QR Code cannot be decoded 15191 * @throws ChecksumException if error correction fails 15192 */ 15193 decodeBitMatrix(bits, hints) { 15194 // Construct a parser and read version, error-correction level 15195 const parser = new BitMatrixParser(bits); 15196 let ex = null; 15197 try { 15198 return this.decodeBitMatrixParser(parser, hints); 15199 } 15200 catch (e /*: FormatException, ChecksumException*/) { 15201 ex = e; 15202 } 15203 try { 15204 // Revert the bit matrix 15205 parser.remask();
vendor: 2,540 bytes, lines 15206-15260
15206 // Will be attempting a mirrored reading of the version and format info. 15207 parser.setMirror(true); 15208 // Preemptively read the version. 15209 parser.readVersion(); 15210 // Preemptively read the format information. 15211 parser.readFormatInformation(); 15212 /* 15213 * Since we're here, this means we have successfully detected some kind 15214 * of version and format information when mirrored. This is a good sign, 15215 * that the QR code may be mirrored, and we should try once more with a 15216 * mirrored content. 15217 */ 15218 // Prepare for a mirrored reading. 15219 parser.mirror(); 15220 const result = this.decodeBitMatrixParser(parser, hints); 15221 // Success! Notify the caller that the code was mirrored. 15222 result.setOther(new QRCodeDecoderMetaData(true)); 15223 return result; 15224 } 15225 catch (e /*FormatException | ChecksumException*/) { 15226 // Throw the exception from the original reading 15227 if (ex !== null) { 15228 throw ex; 15229 } 15230 throw e; 15231 } 15232 } 15233 decodeBitMatrixParser(parser, hints) { 15234 const version = parser.readVersion(); 15235 const ecLevel = parser.readFormatInformation().getErrorCorrectionLevel(); 15236 // Read codewords 15237 const codewords = parser.readCodewords(); 15238 // Separate into data blocks 15239 const dataBlocks = DataBlock.getDataBlocks(codewords, version, ecLevel); 15240 // Count total number of data bytes 15241 let totalBytes = 0; 15242 for (const dataBlock of dataBlocks) { 15243 totalBytes += dataBlock.getNumDataCodewords(); 15244 } 15245 const resultBytes = new Uint8Array(totalBytes); 15246 let resultOffset = 0; 15247 // Error-correct and copy data blocks together into a stream of bytes 15248 for (const dataBlock of dataBlocks) { 15249 const codewordBytes = dataBlock.getCodewords(); 15250 const numDataCodewords = dataBlock.getNumDataCodewords(); 15251 this.correctErrors(codewordBytes, numDataCodewords); 15252 for (let i = 0; i < numDataCodewords; i++) { 15253 resultBytes[resultOffset++] = codewordBytes[i]; 15254 } 15255 } 15256 // Decode the contents of that stream of bytes 15257 return DecodedBitStreamParser$1.decode(resultBytes, version, ecLevel, hints); 15258 } 15259 /** 15260 * <p>
15260Given data and error-correction codewords received, possibly corrupted by errors, attempts to 15261 * correct the errors in-place using Reed-Solomon error correction.</p> 15262 * 15263 * @param codewordBytes data and error correction codewords 15264 * @param numDataCodewords number of codewords that are data bytes 15265 * @throws ChecksumException if error correction fails 15266 */ 15267 correctErrors(codewordBytes, numDataCodewords /*int*/) { 15268 // const numCodewords = codewordBytes.length; 15269 // First read into an array of ints 15270 const codewordsInts = new Int32Array(codewordBytes); 15271 // TYPESCRIPTPORT: not realy necessary to transform to ints? could redesign everything to work with unsigned bytes? 15272 // const codewordsInts = new Int32Array(numCodewords) 15273 // for (let i = 0; i < numCodewords; i++) { 15274 // codewordsInts[i] = codewordBytes[i] & 0xFF 15275 // } 15276 try { 15277 this.rsDecoder.decode(codewordsInts, codewordBytes.length - numDataCodewords); 15278 } 15279 catch (ignored /*: ReedSolomonException*/) { 15280 throw new ChecksumException(); 15281 } 15282 // Copy back into array of bytes -- only need to worry about the bytes that were data 15283 // We don't care about errors in the error-correction codewords 15284 for (let i = 0; i < numDataCodewords; i++) { 15285 codewordBytes[i] = /*(byte) */ codewordsInts[i]; 15286 } 15287 } 15288 } 15289 15290 /* 15291 * Copyright 2007 ZXing authors 15292 * 15293 * Licensed under the Apache License, Version 2.0 (the "License"); 15294 * you may not use this file except in compliance with the License. 15295 * You may obtain a copy of the License at 15296 * 15297 * http://www.apache.org/licenses/LICENSE-2.0 15298 * 15299 * Unless required by applicable law or agreed to in writing, software 15300 * distributed under the License is distributed on an "AS IS" BASIS, 15301 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15302 * See the License for the specific language governing permissions and 15303 * limitations under the License. 15304 */ 15305 /** 15306 * <p>Encapsulates an alignment pattern, which are the smaller square patterns found in 15307 * all but the simplest QR Codes.</p> 15308 * 15309 * @author Sean Owen 15310 */ 15311 class AlignmentPattern extends ResultPoint { 15312 constructor(posX /*float*/, posY /*float*/, estimatedModuleSize /*float*/) { 15313 super(posX, posY); 15314 this.estimatedModuleSize = estimatedModuleSize; 15315 } 15316 /** 15317 * <p>Determines if this alignment pattern "about equals" an alignment pattern at the stated 15318 * position and size -- meaning, it is at nearly the same center with nearly the same size.</p> 15319 */ 15320 aboutEquals(moduleSize /*float*/, i /*float*/, j /*float*/) { 15321 if (Math.abs(i - this.getY()) <= moduleSize && Math.abs(j - this.getX()) <= moduleSize) { 15322 const moduleSizeDiff = Math.abs(moduleSize - this.estimatedModuleSize); 15323 return moduleSizeDiff <= 1.0 || moduleSizeDiff <= this.estimatedModuleSize; 15324 } 15325 return false; 15326 } 15327 /** 15328 * Combines this object's current estimate of a finder pattern position and module size 15329 * with a new estimate. It returns a new {@code FinderPattern} containing an average of the two. 15330 */ 15331 combineEstimate(i /*float*/, j /*float*/, newModuleSize /*float*/) { 15332 const combinedX = (this.getX() + j) / 2.0; 15333 const combinedY = (this.getY() + i) / 2.0; 15334 const combinedModuleSize = (this.estimatedModuleSize + newModuleSize) / 2.0; 15335 return new AlignmentPattern(combinedX, combinedY, combinedModuleSize); 15336 } 15337 } 15338 15339 /* 15340 * Copyright 2007 ZXing authors 15341 * 15342 * Licensed under the Apache License, Version 2.0 (the "License"); 15343 * you may not use this file except in compliance with the License. 15344 * You may obtain a copy of the License at 15345 * 15346 * http://www.apache.org/licenses/LICENSE-2.0 15347 * 15348 * Unless required by applicable law or agreed to in writing, software 15349 * distributed under the License is distributed on an "AS IS" BASIS, 15350 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15351 * See the License for the specific language governing permissions and 15352 * limitations under the License. 15353 */ 15354 /*import java.util.ArrayList;*/ 15355 /*import java.util.List;*/ 15356 /** 15357 * <p>This class attempts to find alignment patterns in a QR Code. Alignment patterns look like finder 15358 * patterns but are smaller and appear at regular intervals throughout the image.</p> 15359 * 15360 * <p>
15360At the moment this only looks for the bottom-right alignment pattern.</p> 15361 * 15362 * <p>This is mostly a simplified copy of {@link FinderPatternFinder}. It is copied, 15363 * pasted and stripped down here for maximum performance but does unfortunately duplicate 15364 * some code.</p> 15365 * 15366 * <p>This class is thread-safe but not reentrant. Each thread must allocate its own object.</p> 15367 * 15368 * @author Sean Owen 15369 */ 15370 class AlignmentPatternFinder { 15371 /** 15372 * <p>Creates a finder that will look in a portion of the whole image.</p> 15373 * 15374 * @param image image to search 15375 * @param startX left column from which to start searching 15376 * @param startY top row from which to start searching 15377 * @param width width of region to search 15378 * @param height height of region to search 15379 * @param moduleSize estimated module size so far 15380 */ 15381 constructor(image, startX /*int*/, startY /*int*/, width /*int*/, height /*int*/, moduleSize /*float*/, resultPointCallback) { 15382 this.image = image; 15383 this.startX = startX; 15384 this.startY = startY; 15385 this.width = width; 15386 this.height = height; 15387 this.moduleSize = moduleSize; 15388 this.resultPointCallback = resultPointCallback; 15389 this.possibleCenters = []; // new Array<any>(5)) 15390 // TYPESCRIPTPORT: array initialization without size as the length is checked below 15391 this.crossCheckStateCount = new Int32Array(3); 15392 } 15393 /** 15394 * <p>This method attempts to find the bottom-right alignment pattern in the image. It is a bit messy since 15395 * it's pretty performance-critical and so is written to be fast foremost.</p> 15396 * 15397 * @return {@link AlignmentPattern} if found 15398 * @throws NotFoundException if not found 15399 */ 15400 find() { 15401 const startX = this.startX; 15402 const height = this.height; 15403 const width = this.width; 15404 const maxJ = startX + width; 15405 const middleI = this.startY + (height / 2); 15406 // We are looking for black/white/black modules in 1:1:1 ratio 15407 // this tracks the number of black/white/black modules seen so far 15408 const stateCount = new Int32Array(3); 15409 const image = this.image; 15410 for (let iGen = 0; iGen < height; iGen++) { 15411 // Search from middle outwards 15412 const i = middleI + ((iGen & 0x01) === 0 ? Math.floor((iGen + 1) / 2) : -Math.floor((iGen + 1) / 2)); 15413 stateCount[0] = 0; 15414 stateCount[1] = 0; 15415 stateCount[2] = 0; 15416 let j = startX; 15417 // Burn off leading white pixels before anything else; if we start in the middle of 15418 // a white run, it doesn't make sense to count its length, since we don't know if the 15419 // white run continued to the left of the start point 15420 while (j < maxJ && !image.get(j, i)) { 15421 j++; 15422 } 15423 let currentState = 0; 15424 while (j < maxJ) { 15425 if (image.get(j, i)) { 15426 // Black pixel 15427 if (currentState === 1) { // Counting black pixels 15428 stateCount[1]++; 15429 } 15430 else { // Counting white pixels 15431 if (currentState === 2) { // A winner?
vendor: 11,165 bytes, lines 15432-15694
15432 if (this.foundPatternCross(stateCount)) { // Yes 15433 const confirmed = this.handlePossibleCenter(stateCount, i, j); 15434 if (confirmed !== null) { 15435 return confirmed; 15436 } 15437 } 15438 stateCount[0] = stateCount[2]; 15439 stateCount[1] = 1; 15440 stateCount[2] = 0; 15441 currentState = 1; 15442 } 15443 else { 15444 stateCount[++currentState]++; 15445 } 15446 } 15447 } 15448 else { // White pixel 15449 if (currentState === 1) { // Counting black pixels 15450 currentState++; 15451 } 15452 stateCount[currentState]++; 15453 } 15454 j++; 15455 } 15456 if (this.foundPatternCross(stateCount)) { 15457 const confirmed = this.handlePossibleCenter(stateCount, i, maxJ); 15458 if (confirmed !== null) { 15459 return confirmed; 15460 } 15461 } 15462 } 15463 // Hmm, nothing we saw was observed and confirmed twice. If we had 15464 // any guess at all, return it. 15465 if (this.possibleCenters.length !== 0) { 15466 return this.possibleCenters[0]; 15467 } 15468 throw new NotFoundException(); 15469 } 15470 /** 15471 * Given a count of black/white/black pixels just seen and an end position, 15472 * figures the location of the center of this black/white/black run. 15473 */ 15474 static centerFromEnd(stateCount, end /*int*/) { 15475 return (end - stateCount[2]) - stateCount[1] / 2.0; 15476 } 15477 /** 15478 * @param stateCount count of black/white/black pixels just read 15479 * @return true iff the proportions of the counts is close enough to the 1/1/1 ratios 15480 * used by alignment patterns to be considered a match 15481 */ 15482 foundPatternCross(stateCount) { 15483 const moduleSize = this.moduleSize; 15484 const maxVariance = moduleSize / 2.0; 15485 for (let i = 0; i < 3; i++) { 15486 if (Math.abs(moduleSize - stateCount[i]) >= maxVariance) { 15487 return false; 15488 } 15489 } 15490 return true; 15491 } 15492 /** 15493 * <p>After a horizontal scan finds a potential alignment pattern, this method 15494 * "cross-checks" by scanning down vertically through the center of the possible 15495 * alignment pattern to see if the same proportion is detected.</p> 15496 * 15497 * @param startI row where an alignment pattern was detected 15498 * @param centerJ center of the section that appears to cross an alignment pattern 15499 * @param maxCount maximum reasonable number of modules that should be 15500 * observed in any reading state, based on the results of the horizontal scan 15501 * @return vertical center of alignment pattern, or {@link Float#NaN} if not found 15502 */ 15503 crossCheckVertical(startI /*int*/, centerJ /*int*/, maxCount /*int*/, originalStateCountTotal /*int*/) { 15504 const image = this.image; 15505 const maxI = image.getHeight(); 15506 const stateCount = this.crossCheckStateCount; 15507 stateCount[0] = 0; 15508 stateCount[1] = 0; 15509 stateCount[2] = 0; 15510 // Start counting up from center 15511 let i = startI; 15512 while (i >= 0 && image.get(centerJ, i) && stateCount[1] <= maxCount) { 15513 stateCount[1]++; 15514 i--; 15515 } 15516 // If already too many modules in this state or ran off the edge: 15517 if (i < 0 || stateCount[1] > maxCount) { 15518 return NaN; 15519 } 15520 while (i >= 0 && !image.get(centerJ, i) && stateCount[0] <= maxCount) { 15521 stateCount[0]++; 15522 i--; 15523 } 15524 if (stateCount[0] > maxCount) { 15525 return NaN; 15526 } 15527 // Now also count down from center 15528 i = startI + 1; 15529 while (i < maxI && image.get(centerJ, i) && stateCount[1] <= maxCount) { 15530 stateCount[1]++; 15531 i++; 15532 } 15533 if (i === maxI || stateCount[1] > maxCount) { 15534 return NaN; 15535 } 15536 while (i < maxI && !image.get(centerJ, i) && stateCount[2] <= maxCount) { 15537 stateCount[2]++; 15538 i++; 15539 } 15540 if (stateCount[2] > maxCount) { 15541 return NaN; 15542 } 15543 const stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; 15544 if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) { 15545 return NaN; 15546 } 15547 return this.foundPatternCross(stateCount) ? AlignmentPatternFinder.centerFromEnd(stateCount, i) : NaN; 15548 } 15549 /** 15550 * <p>This is called when a horizontal scan finds a possible alignment pattern. It will 15551 * cross check with a vertical scan, and if successful, will see if this pattern had been 15552 * found on a previous horizontal scan. If so, we consider it confirmed and conclude we have 15553 * found the alignment pattern.</p> 15554 * 15555 * @param stateCount reading state module counts from horizontal scan 15556 * @param i row where alignment pattern may be found 15557 * @param j end of possible alignment pattern in row 15558 * @return {@link AlignmentPattern} if we have found the same pattern twice, or null if not 15559 */ 15560 handlePossibleCenter(stateCount, i /*int*/, j /*int*/) { 15561 const stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; 15562 const centerJ = AlignmentPatternFinder.centerFromEnd(stateCount, j); 15563 const centerI = this.crossCheckVertical(i, /*(int) */ centerJ, 2 * stateCount[1], stateCountTotal); 15564 if (!isNaN(centerI)) { 15565 const estimatedModuleSize = (stateCount[0] + stateCount[1] + stateCount[2]) / 3.0; 15566 for (const center of this.possibleCenters) { 15567 // Look for about the same center and module size: 15568 if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) { 15569 return center.combineEstimate(centerI, centerJ, estimatedModuleSize); 15570 } 15571 } 15572 // Hadn't found this before; save it 15573 const point = new AlignmentPattern(centerJ, centerI, estimatedModuleSize); 15574 this.possibleCenters.push(point); 15575 if (this.resultPointCallback !== null && this.resultPointCallback !== undefined) { 15576 this.resultPointCallback.foundPossibleResultPoint(point); 15577 } 15578 } 15579 return null; 15580 } 15581 } 15582 15583 /* 15584 * Copyright 2007 ZXing authors 15585 * 15586 * Licensed under the Apache License, Version 2.0 (the "License"); 15587 * you may not use this file except in compliance with the License. 15588 * You may obtain a copy of the License at 15589 * 15590 * http://www.apache.org/licenses/LICENSE-2.0 15591 * 15592 * Unless required by applicable law or agreed to in writing, software 15593 * distributed under the License is distributed on an "AS IS" BASIS, 15594 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15595 * See the License for the specific language governing permissions and 15596 * limitations under the License. 15597 */ 15598 /** 15599 * <p>Encapsulates a finder pattern, which are the three square patterns found in 15600 * the corners of QR Codes. It also encapsulates a count of similar finder patterns, 15601 * as a convenience to the finder's bookkeeping.</p> 15602 * 15603 * @author Sean Owen 15604 */ 15605 class FinderPattern extends ResultPoint { 15606 // FinderPattern(posX: number/*float*/, posY: number/*float*/, estimatedModuleSize: number/*float*/) { 15607 // this(posX, posY, estimatedModuleSize, 1) 15608 // } 15609 constructor(posX /*float*/, posY /*float*/, estimatedModuleSize /*float*/, count /*int*/) { 15610 super(posX, posY); 15611 this.estimatedModuleSize = estimatedModuleSize; 15612 this.count = count; 15613 if (undefined === count) { 15614 this.count = 1; 15615 } 15616 } 15617 getEstimatedModuleSize() { 15618 return this.estimatedModuleSize; 15619 } 15620 getCount() { 15621 return this.count; 15622 } 15623 /* 15624 void incrementCount() { 15625 this.count++ 15626 } 15627 */ 15628 /** 15629 * <p>Determines if this finder pattern "about equals" a finder pattern at the stated 15630 * position and size -- meaning, it is at nearly the same center with nearly the same size.</p> 15631 */ 15632 aboutEquals(moduleSize /*float*/, i /*float*/, j /*float*/) { 15633 if (Math.abs(i - this.getY()) <= moduleSize && Math.abs(j - this.getX()) <= moduleSize) { 15634 const moduleSizeDiff = Math.abs(moduleSize - this.estimatedModuleSize); 15635 return moduleSizeDiff <= 1.0 || moduleSizeDiff <= this.estimatedModuleSize; 15636 } 15637 return false; 15638 } 15639 /** 15640 * Combines this object's current estimate of a finder pattern position and module size 15641 * with a new estimate. It returns a new {@code FinderPattern} containing a weighted average 15642 * based on count. 15643 */ 15644 combineEstimate(i /*float*/, j /*float*/, newModuleSize /*float*/) { 15645 const combinedCount = this.count + 1; 15646 const combinedX = (this.count * this.getX() + j) / combinedCount; 15647 const combinedY = (this.count * this.getY() + i) / combinedCount; 15648 const combinedModuleSize = (this.count * this.estimatedModuleSize + newModuleSize) / combinedCount; 15649 return new FinderPattern(combinedX, combinedY, combinedModuleSize, combinedCount); 15650 } 15651 } 15652 15653 /* 15654 * Copyright 2007 ZXing authors 15655 * 15656 * Licensed under the Apache License, Version 2.0 (the "License"); 15657 * you may not use this file except in compliance with the License. 15658 * You may obtain a copy of the License at 15659 * 15660 * http://www.apache.org/licenses/LICENSE-2.0 15661 * 15662 * Unless required by applicable law or agreed to in writing, software 15663 * distributed under the License is distributed on an "AS IS" BASIS, 15664 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15665 * See the License for the specific language governing permissions and 15666 * limitations under the License. 15667 */ 15668 /** 15669 * <p>Encapsulates information about finder patterns in an image, including the location of 15670 * the three finder patterns, and their estimated module size.</p> 15671 * 15672 * @author Sean Owen 15673 */ 15674 class FinderPatternInfo { 15675 constructor(patternCenters) { 15676 this.bottomLeft = patternCenters[0]; 15677 this.topLeft = patternCenters[1]; 15678 this.topRight = patternCenters[2]; 15679 } 15680 getBottomLeft() { 15681 return this.bottomLeft; 15682 } 15683 getTopLeft() { 15684 return this.topLeft; 15685 } 15686 getTopRight() { 15687 return this.topRight; 15688 } 15689 } 15690 15691 /* 15692 * Copyright 2007 ZXing authors 15693 * 15694 * Licensed under the Apache License, Version 2.0 (the "License");
15695 * you may not use this file except in compliance with the License. 15696 * You may obtain a copy of the License at 15697 * 15698 * http://www.apache.org/licenses/LICENSE-2.0 15699 * 15700 * Unless required by applicable law or agreed to in writing, software 15701 * distributed under the License is distributed on an "AS IS" BASIS, 15702 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15703 * See the License for the specific language governing permissions and 15704 * limitations under the License. 15705 */ 15706 /*import java.io.Serializable;*/ 15707 /*import java.util.ArrayList;*/ 15708 /*import java.util.Collections;*/ 15709 /*import java.util.Comparator;*/ 15710 /*import java.util.List;*/ 15711 /*import java.util.Map;*/ 15712 /** 15713 * <p>This class attempts to find finder patterns in a QR Code. Finder patterns are the square 15714 * markers at three corners of a QR Code.</p> 15715 * 15716 * <p>This class is thread-safe but not reentrant. Each thread must allocate its own object. 15717 * 15718 * @author Sean Owen 15719 */ 15720 class FinderPatternFinder { 15721 /** 15722 * <p>Creates a finder that will search the image for three finder patterns.</p> 15723 * 15724 * @param image image to search 15725 */ 15726 // public constructor(image: BitMatrix) { 15727 // this(image, null) 15728 // } 15729 constructor(image, resultPointCallback) { 15730 this.image = image; 15731 this.resultPointCallback = resultPointCallback; 15732 this.possibleCenters = []; 15733 this.crossCheckStateCount = new Int32Array(5); 15734 this.resultPointCallback = resultPointCallback; 15735 } 15736 getImage() { 15737 return this.image; 15738 } 15739 getPossibleCenters() { 15740 return this.possibleCenters; 15741 } 15742 find(hints) { 15743 const tryHarder = (hints !== null && hints !== undefined) && undefined !== hints.get(DecodeHintType$1.TRY_HARDER); 15744 const pureBarcode = (hints !== null && hints !== undefined) && undefined !== hints.get(DecodeHintType$1.PURE_BARCODE); 15745 const image = this.image; 15746 const maxI = image.getHeight(); 15747 const maxJ = image.getWidth(); 15748 // We are looking for black/white/black/white/black modules in 15749 // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far 15750 // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the 15751 // image, and then account for the center being 3 modules in size. This gives the smallest 15752 // number of pixels the center could be, so skip this often. When trying harder, look for all 15753 // QR versions regardless of how dense they are. 15754 let iSkip = Math.floor((3 * maxI) / (4 * FinderPatternFinder.MAX_MODULES)); 15755 if (iSkip < FinderPatternFinder.MIN_SKIP || tryHarder) { 15756 iSkip = FinderPatternFinder.MIN_SKIP; 15757 } 15758 let done = false; 15759 const stateCount = new Int32Array(5); 15760 for (let i = iSkip - 1; i < maxI && !done; i += iSkip) { 15761 // Get a row of black/white values 15762 stateCount[0] = 0; 15763 stateCount[1] = 0; 15764 stateCount[2] = 0; 15765 stateCount[3] = 0; 15766 stateCount[4] = 0; 15767 let currentState = 0; 15768 for (let j = 0; j < maxJ; j++) { 15769 if (image.get(j, i)) { 15770 // Black pixel 15771 if ((currentState & 1) === 1) { // Counting white pixels 15772 currentState++; 15773 } 15774 stateCount[currentState]++; 15775 } 15776 else { // White pixel 15777 if ((currentState & 1) === 0) { // Counting black pixels 15778 if (currentState === 4) { // A winner?
vendor: 29,339 bytes, lines 15779-16391
15779 if (FinderPatternFinder.foundPatternCross(stateCount)) { // Yes 15780 const confirmed = this.handlePossibleCenter(stateCount, i, j, pureBarcode); 15781 if (confirmed === true) { 15782 // Start examining every other line. Checking each line turned out to be too 15783 // expensive and didn't improve performance. 15784 iSkip = 2; 15785 if (this.hasSkipped === true) { 15786 done = this.haveMultiplyConfirmedCenters(); 15787 } 15788 else { 15789 const rowSkip = this.findRowSkip(); 15790 if (rowSkip > stateCount[2]) { 15791 // Skip rows between row of lower confirmed center 15792 // and top of presumed third confirmed center 15793 // but back up a bit to get a full chance of detecting 15794 // it, entire width of center of finder pattern 15795 // Skip by rowSkip, but back off by stateCount[2] (size of last center 15796 // of pattern we saw) to be conservative, and also back off by iSkip which 15797 // is about to be re-added 15798 i += rowSkip - stateCount[2] - iSkip; 15799 j = maxJ - 1; 15800 } 15801 } 15802 } 15803 else { 15804 stateCount[0] = stateCount[2]; 15805 stateCount[1] = stateCount[3]; 15806 stateCount[2] = stateCount[4]; 15807 stateCount[3] = 1; 15808 stateCount[4] = 0; 15809 currentState = 3; 15810 continue; 15811 } 15812 // Clear state to start looking again 15813 currentState = 0; 15814 stateCount[0] = 0; 15815 stateCount[1] = 0; 15816 stateCount[2] = 0; 15817 stateCount[3] = 0; 15818 stateCount[4] = 0; 15819 } 15820 else { // No, shift counts back by two 15821 stateCount[0] = stateCount[2]; 15822 stateCount[1] = stateCount[3]; 15823 stateCount[2] = stateCount[4]; 15824 stateCount[3] = 1; 15825 stateCount[4] = 0; 15826 currentState = 3; 15827 } 15828 } 15829 else { 15830 stateCount[++currentState]++; 15831 } 15832 } 15833 else { // Counting white pixels 15834 stateCount[currentState]++; 15835 } 15836 } 15837 } 15838 if (FinderPatternFinder.foundPatternCross(stateCount)) { 15839 const confirmed = this.handlePossibleCenter(stateCount, i, maxJ, pureBarcode); 15840 if (confirmed === true) { 15841 iSkip = stateCount[0]; 15842 if (this.hasSkipped) { 15843 // Found a third one 15844 done = this.haveMultiplyConfirmedCenters(); 15845 } 15846 } 15847 } 15848 } 15849 const patternInfo = this.selectBestPatterns(); 15850 ResultPoint.orderBestPatterns(patternInfo); 15851 return new FinderPatternInfo(patternInfo); 15852 } 15853 /** 15854 * Given a count of black/white/black/white/black pixels just seen and an end position, 15855 * figures the location of the center of this run. 15856 */ 15857 static centerFromEnd(stateCount, end /*int*/) { 15858 return (end - stateCount[4] - stateCount[3]) - stateCount[2] / 2.0; 15859 } 15860 /** 15861 * @param stateCount count of black/white/black/white/black pixels just read 15862 * @return true iff the proportions of the counts is close enough to the 1/1/3/1/1 ratios 15863 * used by finder patterns to be considered a match 15864 */ 15865 static foundPatternCross(stateCount) { 15866 let totalModuleSize = 0; 15867 for (let i = 0; i < 5; i++) { 15868 const count = stateCount[i]; 15869 if (count === 0) { 15870 return false; 15871 } 15872 totalModuleSize += count; 15873 } 15874 if (totalModuleSize < 7) { 15875 return false; 15876 } 15877 const moduleSize = totalModuleSize / 7.0; 15878 const maxVariance = moduleSize / 2.0; 15879 // Allow less than 50% variance from 1-1-3-1-1 proportions 15880 return Math.abs(moduleSize - stateCount[0]) < maxVariance && 15881 Math.abs(moduleSize - stateCount[1]) < maxVariance && 15882 Math.abs(3.0 * moduleSize - stateCount[2]) < 3 * maxVariance && 15883 Math.abs(moduleSize - stateCount[3]) < maxVariance && 15884 Math.abs(moduleSize - stateCount[4]) < maxVariance; 15885 } 15886 getCrossCheckStateCount() { 15887 const crossCheckStateCount = this.crossCheckStateCount; 15888 crossCheckStateCount[0] = 0; 15889 crossCheckStateCount[1] = 0; 15890 crossCheckStateCount[2] = 0; 15891 crossCheckStateCount[3] = 0; 15892 crossCheckStateCount[4] = 0; 15893 return crossCheckStateCount; 15894 } 15895 /** 15896 * After a vertical and horizontal scan finds a potential finder pattern, this method 15897 * "cross-cross-cross-checks" by scanning down diagonally through the center of the possible 15898 * finder pattern to see if the same proportion is detected. 15899 * 15900 * @param startI row where a finder pattern was detected 15901 * @param centerJ center of the section that appears to cross a finder pattern 15902 * @param maxCount maximum reasonable number of modules that should be 15903 * observed in any reading state, based on the results of the horizontal scan 15904 * @param originalStateCountTotal The original state count total. 15905 * @return true if proportions are withing expected limits 15906 */ 15907 crossCheckDiagonal(startI /*int*/, centerJ /*int*/, maxCount /*int*/, originalStateCountTotal /*int*/) { 15908 const stateCount = this.getCrossCheckStateCount(); 15909 // Start counting up, left from center finding black center mass 15910 let i = 0; 15911 const image = this.image; 15912 while (startI >= i && centerJ >= i && image.get(centerJ - i, startI - i)) { 15913 stateCount[2]++; 15914 i++; 15915 } 15916 if (startI < i || centerJ < i) { 15917 return false; 15918 } 15919 // Continue up, left finding white space 15920 while (startI >= i && centerJ >= i && !image.get(centerJ - i, startI - i) && 15921 stateCount[1] <= maxCount) { 15922 stateCount[1]++; 15923 i++; 15924 } 15925 // If already too many modules in this state or ran off the edge: 15926 if (startI < i || centerJ < i || stateCount[1] > maxCount) { 15927 return false; 15928 } 15929 // Continue up, left finding black border 15930 while (startI >= i && centerJ >= i && image.get(centerJ - i, startI - i) && 15931 stateCount[0] <= maxCount) { 15932 stateCount[0]++; 15933 i++; 15934 } 15935 if (stateCount[0] > maxCount) { 15936 return false; 15937 } 15938 const maxI = image.getHeight(); 15939 const maxJ = image.getWidth(); 15940 // Now also count down, right from center 15941 i = 1; 15942 while (startI + i < maxI && centerJ + i < maxJ && image.get(centerJ + i, startI + i)) { 15943 stateCount[2]++; 15944 i++; 15945 } 15946 // Ran off the edge? 15947 if (startI + i >= maxI || centerJ + i >= maxJ) { 15948 return false; 15949 } 15950 while (startI + i < maxI && centerJ + i < maxJ && !image.get(centerJ + i, startI + i) && 15951 stateCount[3] < maxCount) { 15952 stateCount[3]++; 15953 i++; 15954 } 15955 if (startI + i >= maxI || centerJ + i >= maxJ || stateCount[3] >= maxCount) { 15956 return false; 15957 } 15958 while (startI + i < maxI && centerJ + i < maxJ && image.get(centerJ + i, startI + i) && 15959 stateCount[4] < maxCount) { 15960 stateCount[4]++; 15961 i++; 15962 } 15963 if (stateCount[4] >= maxCount) { 15964 return false; 15965 } 15966 // If we found a finder-pattern-like section, but its size is more than 100% different than 15967 // the original, assume it's a false positive 15968 const stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; 15969 return Math.abs(stateCountTotal - originalStateCountTotal) < 2 * originalStateCountTotal && 15970 FinderPatternFinder.foundPatternCross(stateCount); 15971 } 15972 /** 15973 * <p>After a horizontal scan finds a potential finder pattern, this method 15974 * "cross-checks" by scanning down vertically through the center of the possible 15975 * finder pattern to see if the same proportion is detected.</p> 15976 * 15977 * @param startI row where a finder pattern was detected 15978 * @param centerJ center of the section that appears to cross a finder pattern 15979 * @param maxCount maximum reasonable number of modules that should be 15980 * observed in any reading state, based on the results of the horizontal scan 15981 * @return vertical center of finder pattern, or {@link Float#NaN} if not found 15982 */ 15983 crossCheckVertical(startI /*int*/, centerJ /*int*/, maxCount /*int*/, originalStateCountTotal /*int*/) { 15984 const image = this.image; 15985 const maxI = image.getHeight(); 15986 const stateCount = this.getCrossCheckStateCount(); 15987 // Start counting up from center 15988 let i = startI; 15989 while (i >= 0 && image.get(centerJ, i)) { 15990 stateCount[2]++; 15991 i--; 15992 } 15993 if (i < 0) { 15994 return NaN; 15995 } 15996 while (i >= 0 && !image.get(centerJ, i) && stateCount[1] <= maxCount) { 15997 stateCount[1]++; 15998 i--; 15999 } 16000 // If already too many modules in this state or ran off the edge: 16001 if (i < 0 || stateCount[1] > maxCount) { 16002 return NaN; 16003 } 16004 while (i >= 0 && image.get(centerJ, i) && stateCount[0] <= maxCount) { 16005 stateCount[0]++; 16006 i--; 16007 } 16008 if (stateCount[0] > maxCount) { 16009 return NaN; 16010 } 16011 // Now also count down from center 16012 i = startI + 1; 16013 while (i < maxI && image.get(centerJ, i)) { 16014 stateCount[2]++; 16015 i++; 16016 } 16017 if (i === maxI) { 16018 return NaN; 16019 } 16020 while (i < maxI && !image.get(centerJ, i) && stateCount[3] < maxCount) { 16021 stateCount[3]++; 16022 i++; 16023 } 16024 if (i === maxI || stateCount[3] >= maxCount) { 16025 return NaN; 16026 } 16027 while (i < maxI && image.get(centerJ, i) && stateCount[4] < maxCount) { 16028 stateCount[4]++; 16029 i++; 16030 } 16031 if (stateCount[4] >= maxCount) { 16032 return NaN; 16033 } 16034 // If we found a finder-pattern-like section, but its size is more than 40% different than 16035 // the original, assume it's a false positive 16036 const stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + 16037 stateCount[4]; 16038 if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) { 16039 return NaN; 16040 } 16041 return FinderPatternFinder.foundPatternCross(stateCount) ? FinderPatternFinder.centerFromEnd(stateCount, i) : NaN; 16042 } 16043 /** 16044 * <p>Like {@link #crossCheckVertical(int, int, int, int)}, and in fact is basically identical, 16045 * except it reads horizontally instead of vertically. This is used to cross-cross 16046 * check a vertical cross check and locate the real center of the alignment pattern.</p> 16047 */ 16048 crossCheckHorizontal(startJ /*int*/, centerI /*int*/, maxCount /*int*/, originalStateCountTotal /*int*/) { 16049 const image = this.image; 16050 const maxJ = image.getWidth(); 16051 const stateCount = this.getCrossCheckStateCount(); 16052 let j = startJ; 16053 while (j >= 0 && image.get(j, centerI)) { 16054 stateCount[2]++; 16055 j--; 16056 } 16057 if (j < 0) { 16058 return NaN; 16059 } 16060 while (j >= 0 && !image.get(j, centerI) && stateCount[1] <= maxCount) { 16061 stateCount[1]++; 16062 j--; 16063 } 16064 if (j < 0 || stateCount[1] > maxCount) { 16065 return NaN; 16066 } 16067 while (j >= 0 && image.get(j, centerI) && stateCount[0] <= maxCount) { 16068 stateCount[0]++; 16069 j--; 16070 } 16071 if (stateCount[0] > maxCount) { 16072 return NaN; 16073 } 16074 j = startJ + 1; 16075 while (j < maxJ && image.get(j, centerI)) { 16076 stateCount[2]++; 16077 j++; 16078 } 16079 if (j === maxJ) { 16080 return NaN; 16081 } 16082 while (j < maxJ && !image.get(j, centerI) && stateCount[3] < maxCount) { 16083 stateCount[3]++; 16084 j++; 16085 } 16086 if (j === maxJ || stateCount[3] >= maxCount) { 16087 return NaN; 16088 } 16089 while (j < maxJ && image.get(j, centerI) && stateCount[4] < maxCount) { 16090 stateCount[4]++; 16091 j++; 16092 } 16093 if (stateCount[4] >= maxCount) { 16094 return NaN; 16095 } 16096 // If we found a finder-pattern-like section, but its size is significantly different than 16097 // the original, assume it's a false positive 16098 const stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + 16099 stateCount[4]; 16100 if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) { 16101 return NaN; 16102 } 16103 return FinderPatternFinder.foundPatternCross(stateCount) ? FinderPatternFinder.centerFromEnd(stateCount, j) : NaN; 16104 } 16105 /** 16106 * <p>This is called when a horizontal scan finds a possible alignment pattern. It will 16107 * cross check with a vertical scan, and if successful, will, ah, cross-cross-check 16108 * with another horizontal scan. This is needed primarily to locate the real horizontal 16109 * center of the pattern in cases of extreme skew. 16110 * And then we cross-cross-cross check with another diagonal scan.</p> 16111 * 16112 * <p>If that succeeds the finder pattern location is added to a list that tracks 16113 * the number of times each location has been nearly-matched as a finder pattern. 16114 * Each additional find is more evidence that the location is in fact a finder 16115 * pattern center 16116 * 16117 * @param stateCount reading state module counts from horizontal scan 16118 * @param i row where finder pattern may be found 16119 * @param j end of possible finder pattern in row 16120 * @param pureBarcode true if in "pure barcode" mode 16121 * @return true if a finder pattern candidate was found this time 16122 */ 16123 handlePossibleCenter(stateCount, i /*int*/, j /*int*/, pureBarcode) { 16124 const stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + 16125 stateCount[4]; 16126 let centerJ = FinderPatternFinder.centerFromEnd(stateCount, j); 16127 let centerI = this.crossCheckVertical(i, /*(int) */ Math.floor(centerJ), stateCount[2], stateCountTotal); 16128 if (!isNaN(centerI)) { 16129 // Re-cross check 16130 centerJ = this.crossCheckHorizontal(/*(int) */ Math.floor(centerJ), /*(int) */ Math.floor(centerI), stateCount[2], stateCountTotal); 16131 if (!isNaN(centerJ) && 16132 (!pureBarcode || this.crossCheckDiagonal(/*(int) */ Math.floor(centerI), /*(int) */ Math.floor(centerJ), stateCount[2], stateCountTotal))) { 16133 const estimatedModuleSize = stateCountTotal / 7.0; 16134 let found = false; 16135 const possibleCenters = this.possibleCenters; 16136 for (let index = 0, length = possibleCenters.length; index < length; index++) { 16137 const center = possibleCenters[index]; 16138 // Look for about the same center and module size: 16139 if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) { 16140 possibleCenters[index] = center.combineEstimate(centerI, centerJ, estimatedModuleSize); 16141 found = true; 16142 break; 16143 } 16144 } 16145 if (!found) { 16146 const point = new FinderPattern(centerJ, centerI, estimatedModuleSize); 16147 possibleCenters.push(point); 16148 if (this.resultPointCallback !== null && this.resultPointCallback !== undefined) { 16149 this.resultPointCallback.foundPossibleResultPoint(point); 16150 } 16151 } 16152 return true; 16153 } 16154 } 16155 return false; 16156 } 16157 /** 16158 * @return number of rows we could safely skip during scanning, based on the first 16159 * two finder patterns that have been located. In some cases their position will 16160 * allow us to infer that the third pattern must lie below a certain point farther 16161 * down in the image. 16162 */ 16163 findRowSkip() { 16164 const max = this.possibleCenters.length; 16165 if (max <= 1) { 16166 return 0; 16167 } 16168 let firstConfirmedCenter = null; 16169 for (const center of this.possibleCenters) { 16170 if (center.getCount() >= FinderPatternFinder.CENTER_QUORUM) { 16171 if (firstConfirmedCenter == null) { 16172 firstConfirmedCenter = center; 16173 } 16174 else { 16175 // We have two confirmed centers 16176 // How far down can we skip before resuming looking for the next 16177 // pattern? In the worst case, only the difference between the 16178 // difference in the x / y coordinates of the two centers. 16179 // This is the case where you find top left last. 16180 this.hasSkipped = true; 16181 return /*(int) */ Math.floor((Math.abs(firstConfirmedCenter.getX() - center.getX()) - 16182 Math.abs(firstConfirmedCenter.getY() - center.getY())) / 2); 16183 } 16184 } 16185 } 16186 return 0; 16187 } 16188 /** 16189 * @return true iff we have found at least 3 finder patterns that have been detected 16190 * at least {@link #CENTER_QUORUM} times each, and, the estimated module size of the 16191 * candidates is "pretty similar" 16192 */ 16193 haveMultiplyConfirmedCenters() { 16194 let confirmedCount = 0; 16195 let totalModuleSize = 0.0; 16196 const max = this.possibleCenters.length; 16197 for (const pattern of this.possibleCenters) { 16198 if (pattern.getCount() >= FinderPatternFinder.CENTER_QUORUM) { 16199 confirmedCount++; 16200 totalModuleSize += pattern.getEstimatedModuleSize(); 16201 } 16202 } 16203 if (confirmedCount < 3) { 16204 return false; 16205 } 16206 // OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive" 16207 // and that we need to keep looking. We detect this by asking if the estimated module sizes 16208 // vary too much. We arbitrarily say that when the total deviation from average exceeds 16209 // 5% of the total module size estimates, it's too much. 16210 const average = totalModuleSize / max; 16211 let totalDeviation = 0.0; 16212 for (const pattern of this.possibleCenters) { 16213 totalDeviation += Math.abs(pattern.getEstimatedModuleSize() - average); 16214 } 16215 return totalDeviation <= 0.05 * totalModuleSize; 16216 } 16217 /** 16218 * @return the 3 best {@link FinderPattern}s from our list of candidates. The "best" are 16219 * those that have been detected at least {@link #CENTER_QUORUM} times, and whose module 16220 * size differs from the average among those patterns the least 16221 * @throws NotFoundException if 3 such finder patterns do not exist 16222 */ 16223 selectBestPatterns() { 16224 const startSize = this.possibleCenters.length; 16225 if (startSize < 3) { 16226 // Couldn't find enough finder patterns 16227 throw new NotFoundException(); 16228 } 16229 const possibleCenters = this.possibleCenters; 16230 let average; 16231 // Filter outlier possibilities whose module size is too different 16232 if (startSize > 3) { 16233 // But we can only afford to do so if we have at least 4 possibilities to choose from 16234 let totalModuleSize = 0.0; 16235 let square = 0.0; 16236 for (const center of this.possibleCenters) { 16237 const size = center.getEstimatedModuleSize(); 16238 totalModuleSize += size; 16239 square += size * size; 16240 } 16241 average = totalModuleSize / startSize; 16242 let stdDev = Math.sqrt(square / startSize - average * average); 16243 possibleCenters.sort( 16244 /** 16245 * <p>Orders by furthest from average</p> 16246 */ 16247 // FurthestFromAverageComparator implements Comparator<FinderPattern> 16248 (center1, center2) => { 16249 const dA = Math.abs(center2.getEstimatedModuleSize() - average); 16250 const dB = Math.abs(center1.getEstimatedModuleSize() - average); 16251 return dA < dB ? -1 : dA > dB ? 1 : 0; 16252 }); 16253 const limit = Math.max(0.2 * average, stdDev); 16254 for (let i = 0; i < possibleCenters.length && possibleCenters.length > 3; i++) { 16255 const pattern = possibleCenters[i]; 16256 if (Math.abs(pattern.getEstimatedModuleSize() - average) > limit) { 16257 possibleCenters.splice(i, 1); 16258 i--; 16259 } 16260 } 16261 } 16262 if (possibleCenters.length > 3) { 16263 // Throw away all but those first size candidate points we found. 16264 let totalModuleSize = 0.0; 16265 for (const possibleCenter of possibleCenters) { 16266 totalModuleSize += possibleCenter.getEstimatedModuleSize(); 16267 } 16268 average = totalModuleSize / possibleCenters.length; 16269 possibleCenters.sort( 16270 /** 16271 * <p>Orders by {@link FinderPattern#getCount()}, descending.</p> 16272 */ 16273 // CenterComparator implements Comparator<FinderPattern> 16274 (center1, center2) => { 16275 if (center2.getCount() === center1.getCount()) { 16276 const dA = Math.abs(center2.getEstimatedModuleSize() - average); 16277 const dB = Math.abs(center1.getEstimatedModuleSize() - average); 16278 return dA < dB ? 1 : dA > dB ? -1 : 0; 16279 } 16280 else { 16281 return center2.getCount() - center1.getCount(); 16282 } 16283 }); 16284 possibleCenters.splice(3); // this is not realy necessary as we only return first 3 anyway 16285 } 16286 return [ 16287 possibleCenters[0], 16288 possibleCenters[1], 16289 possibleCenters[2] 16290 ]; 16291 } 16292 } 16293 FinderPatternFinder.CENTER_QUORUM = 2; 16294 FinderPatternFinder.MIN_SKIP = 3; // 1 pixel/module times 3 modules/center 16295 FinderPatternFinder.MAX_MODULES = 57; // support up to version 10 for mobile clients 16296 16297 /* 16298 * Copyright 2007 ZXing authors 16299 * 16300 * Licensed under the Apache License, Version 2.0 (the "License"); 16301 * you may not use this file except in compliance with the License. 16302 * You may obtain a copy of the License at 16303 * 16304 * http://www.apache.org/licenses/LICENSE-2.0 16305 * 16306 * Unless required by applicable law or agreed to in writing, software 16307 * distributed under the License is distributed on an "AS IS" BASIS, 16308 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16309 * See the License for the specific language governing permissions and 16310 * limitations under the License. 16311 */ 16312 /*import java.util.Map;*/ 16313 /** 16314 * <p>Encapsulates logic that can detect a QR Code in an image, even if the QR Code 16315 * is rotated or skewed, or partially obscured.</p> 16316 * 16317 * @author Sean Owen 16318 */ 16319 class Detector$1 { 16320 constructor(image) { 16321 this.image = image; 16322 } 16323 getImage() { 16324 return this.image; 16325 } 16326 getResultPointCallback() { 16327 return this.resultPointCallback; 16328 } 16329 /** 16330 * <p>Detects a QR Code in an image.</p> 16331 * 16332 * @return {@link DetectorResult} encapsulating results of detecting a QR Code 16333 * @throws NotFoundException if QR Code cannot be found 16334 * @throws FormatException if a QR Code cannot be decoded 16335 */ 16336 // public detect(): DetectorResult /*throws NotFoundException, FormatException*/ { 16337 // return detect(null) 16338 // } 16339 /** 16340 * <p>Detects a QR Code in an image.</p> 16341 * 16342 * @param hints optional hints to detector 16343 * @return {@link DetectorResult} encapsulating results of detecting a QR Code 16344 * @throws NotFoundException if QR Code cannot be found 16345 * @throws FormatException if a QR Code cannot be decoded 16346 */ 16347 detect(hints) { 16348 this.resultPointCallback = (hints === null || hints === undefined) ? null : 16349 /*(ResultPointCallback) */ hints.get(DecodeHintType$1.NEED_RESULT_POINT_CALLBACK); 16350 const finder = new FinderPatternFinder(this.image, this.resultPointCallback); 16351 const info = finder.find(hints); 16352 return this.processFinderPatternInfo(info); 16353 } 16354 processFinderPatternInfo(info) { 16355 const topLeft = info.getTopLeft(); 16356 const topRight = info.getTopRight(); 16357 const bottomLeft = info.getBottomLeft(); 16358 const moduleSize = this.calculateModuleSize(topLeft, topRight, bottomLeft); 16359 if (moduleSize < 1.0) { 16360 throw new NotFoundException('No pattern found in proccess finder.'); 16361 } 16362 const dimension = Detector$1.computeDimension(topLeft, topRight, bottomLeft, moduleSize); 16363 const provisionalVersion = Version.getProvisionalVersionForDimension(dimension); 16364 const modulesBetweenFPCenters = provisionalVersion.getDimensionForVersion() - 7; 16365 let alignmentPattern = null; 16366 // Anything above version 1 has an alignment pattern 16367 if (provisionalVersion.getAlignmentPatternCenters().length > 0) { 16368 // Guess where a "bottom right" finder pattern would have been 16369 const bottomRightX = topRight.getX() - topLeft.getX() + bottomLeft.getX(); 16370 const bottomRightY = topRight.getY() - topLeft.getY() + bottomLeft.getY(); 16371 // Estimate that alignment pattern is closer by 3 modules 16372 // from "bottom right" to known top left location 16373 const correctionToTopLeft = 1.0 - 3.0 / modulesBetweenFPCenters; 16374 const estAlignmentX = /*(int) */ Math.floor(topLeft.getX() + correctionToTopLeft * (bottomRightX - topLeft.getX())); 16375 const estAlignmentY = /*(int) */ Math.floor(topLeft.getY() + correctionToTopLeft * (bottomRightY - topLeft.getY())); 16376 // Kind of arbitrary -- expand search radius before giving up 16377 for (let i = 4; i <= 16; i <<= 1) { 16378 try { 16379 alignmentPattern = this.findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, i); 16380 break; 16381 } 16382 catch (re /*NotFoundException*/) { 16383 if (!(re instanceof NotFoundException)) { 16384 throw re; 16385 } 16386 // try next round 16387 } 16388 } 16389 // If we didn't find alignment pattern... well try anyway without it 16390 } 16391 const transform = Detector$1.createTransform(topLeft, top
16391Right, bottomLeft, alignmentPattern, dimension); 16392 const bits = Detector$1.sampleGrid(this.image, transform, dimension); 16393 let points; 16394 if (alignmentPattern === null) { 16395 points = [bottomLeft, topLeft, topRight]; 16396 } 16397 else { 16398 points = [bottomLeft, topLeft, topRight, alignmentPattern]; 16399 } 16400 return new DetectorResult(bits, points); 16401 } 16402 static createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension /*int*/) { 16403 const dimMinusThree
vendor: 3,328 bytes, lines 16403-16468
16403 = dimension - 3.5; 16404 let bottomRightX; /*float*/ 16405 let bottomRightY; /*float*/ 16406 let sourceBottomRightX; /*float*/ 16407 let sourceBottomRightY; /*float*/ 16408 if (alignmentPattern !== null) { 16409 bottomRightX = alignmentPattern.getX(); 16410 bottomRightY = alignmentPattern.getY(); 16411 sourceBottomRightX = dimMinusThree - 3.0; 16412 sourceBottomRightY = sourceBottomRightX; 16413 } 16414 else { 16415 // Don't have an alignment pattern, just make up the bottom-right point 16416 bottomRightX = (topRight.getX() - topLeft.getX()) + bottomLeft.getX(); 16417 bottomRightY = (topRight.getY() - topLeft.getY()) + bottomLeft.getY(); 16418 sourceBottomRightX = dimMinusThree; 16419 sourceBottomRightY = dimMinusThree; 16420 } 16421 return PerspectiveTransform.quadrilateralToQuadrilateral(3.5, 3.5, dimMinusThree, 3.5, sourceBottomRightX, sourceBottomRightY, 3.5, dimMinusThree, topLeft.getX(), topLeft.getY(), topRight.getX(), topRight.getY(), bottomRightX, bottomRightY, bottomLeft.getX(), bottomLeft.getY()); 16422 } 16423 static sampleGrid(image, transform, dimension /*int*/) { 16424 const sampler = GridSamplerInstance.getInstance(); 16425 return sampler.sampleGridWithTransform(image, dimension, dimension, transform); 16426 } 16427 /** 16428 * <p>Computes the dimension (number of modules on a size) of the QR Code based on the position 16429 * of the finder patterns and estimated module size.</p> 16430 */ 16431 static computeDimension(topLeft, topRight, bottomLeft, moduleSize /*float*/) { 16432 const tltrCentersDimension = MathUtils.round(ResultPoint.distance(topLeft, topRight) / moduleSize); 16433 const tlblCentersDimension = MathUtils.round(ResultPoint.distance(topLeft, bottomLeft) / moduleSize); 16434 let dimension = Math.floor((tltrCentersDimension + tlblCentersDimension) / 2) + 7; 16435 switch (dimension & 0x03) { // mod 4 16436 case 0: 16437 dimension++; 16438 break; 16439 // 1? do nothing 16440 case 2: 16441 dimension--; 16442 break; 16443 case 3: 16444 throw new NotFoundException('Dimensions could be not found.'); 16445 } 16446 return dimension; 16447 } 16448 /** 16449 * <p>Computes an average estimated module size based on estimated derived from the positions 16450 * of the three finder patterns.</p> 16451 * 16452 * @param topLeft detected top-left finder pattern center 16453 * @param topRight detected top-right finder pattern center 16454 * @param bottomLeft detected bottom-left finder pattern center 16455 * @return estimated module size 16456 */ 16457 calculateModuleSize(topLeft, topRight, bottomLeft) { 16458 // Take the average 16459 return (this.calculateModuleSizeOneWay(topLeft, topRight) + 16460 this.calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2.0; 16461 } 16462 /** 16463 * <p>Estimates module size based on two finder patterns -- it uses 16464 * {@link #sizeOfBlackWhiteBlackRunBothWays(int, int, int, int)} to figure the 16465 * width of each, measuring along the axis between their centers.</p> 16466 */ 16467 calculateModuleSizeOneWay(pattern, otherPattern) { 16468 const moduleSizeEst1
vendor: 5,400 bytes, lines 16468-16579
16468= this.sizeOfBlackWhiteBlackRunBothWays(/*(int) */ Math.floor(pattern.getX()), 16469 /*(int) */ Math.floor(pattern.getY()), 16470 /*(int) */ Math.floor(otherPattern.getX()), 16471 /*(int) */ Math.floor(otherPattern.getY())); 16472 const moduleSizeEst2 = this.sizeOfBlackWhiteBlackRunBothWays(/*(int) */ Math.floor(otherPattern.getX()), 16473 /*(int) */ Math.floor(otherPattern.getY()), 16474 /*(int) */ Math.floor(pattern.getX()), 16475 /*(int) */ Math.floor(pattern.getY())); 16476 if (isNaN(moduleSizeEst1)) { 16477 return moduleSizeEst2 / 7.0; 16478 } 16479 if (isNaN(moduleSizeEst2)) { 16480 return moduleSizeEst1 / 7.0; 16481 } 16482 // Average them, and divide by 7 since we've counted the width of 3 black modules, 16483 // and 1 white and 1 black module on either side. Ergo, divide sum by 14. 16484 return (moduleSizeEst1 + moduleSizeEst2) / 14.0; 16485 } 16486 /** 16487 * See {@link #sizeOfBlackWhiteBlackRun(int, int, int, int)}; computes the total width of 16488 * a finder pattern by looking for a black-white-black run from the center in the direction 16489 * of another point (another finder pattern center), and in the opposite direction too. 16490 */ 16491 sizeOfBlackWhiteBlackRunBothWays(fromX /*int*/, fromY /*int*/, toX /*int*/, toY /*int*/) { 16492 let result = this.sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY); 16493 // Now count other way -- don't run off image though of course 16494 let scale = 1.0; 16495 let otherToX = fromX - (toX - fromX); 16496 if (otherToX < 0) { 16497 scale = fromX / /*(float) */ (fromX - otherToX); 16498 otherToX = 0; 16499 } 16500 else if (otherToX >= this.image.getWidth()) { 16501 scale = (this.image.getWidth() - 1 - fromX) / /*(float) */ (otherToX - fromX); 16502 otherToX = this.image.getWidth() - 1; 16503 } 16504 let otherToY = /*(int) */ Math.floor(fromY - (toY - fromY) * scale); 16505 scale = 1.0; 16506 if (otherToY < 0) { 16507 scale = fromY / /*(float) */ (fromY - otherToY); 16508 otherToY = 0; 16509 } 16510 else if (otherToY >= this.image.getHeight()) { 16511 scale = (this.image.getHeight() - 1 - fromY) / /*(float) */ (otherToY - fromY); 16512 otherToY = this.image.getHeight() - 1; 16513 } 16514 otherToX = /*(int) */ Math.floor(fromX + (otherToX - fromX) * scale); 16515 result += this.sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY); 16516 // Middle pixel is double-counted this way; subtract 1 16517 return result - 1.0; 16518 } 16519 /** 16520 * <p>This method traces a line from a point in the image, in the direction towards another point. 16521 * It begins in a black region, and keeps going until it finds white, then black, then white again. 16522 * It reports the distance from the start to this point.</p> 16523 * 16524 * <p>This is used when figuring out how wide a finder pattern is, when the finder pattern 16525 * may be skewed or rotated.</p> 16526 */ 16527 sizeOfBlackWhiteBlackRun(fromX /*int*/, fromY /*int*/, toX /*int*/, toY /*int*/) { 16528 // Mild variant of Bresenham's algorithm 16529 // see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm 16530 const steep = Math.abs(toY - fromY) > Math.abs(toX - fromX); 16531 if (steep) { 16532 let temp = fromX; 16533 fromX = fromY; 16534 fromY = temp; 16535 temp = toX; 16536 toX = toY; 16537 toY = temp; 16538 } 16539 const dx = Math.abs(toX - fromX); 16540 const dy = Math.abs(toY - fromY); 16541 let error = -dx / 2; 16542 const xstep = fromX < toX ? 1 : -1; 16543 const ystep = fromY < toY ? 1 : -1; 16544 // In black pixels, looking for white, first or second time. 16545 let state = 0; 16546 // Loop up until x == toX, but not beyond 16547 const xLimit = toX + xstep; 16548 for (let x = fromX, y = fromY; x !== xLimit; x += xstep) { 16549 const realX = steep ? y : x; 16550 const realY = steep ? x : y; 16551 // Does current pixel mean we have moved white to black or vice versa? 16552 // Scanning black in state 0,2 and white in state 1, so if we find the wrong 16553 // color, advance to next state or end if we are in state 2 already 16554 if ((state === 1) === this.image.get(realX, realY)) { 16555 if (state === 2) { 16556 return MathUtils.distance(x, y, fromX, fromY); 16557 } 16558 state++; 16559 } 16560 error += dy; 16561 if (error > 0) { 16562 if (y === toY) { 16563 break; 16564 } 16565 y += ystep; 16566 error -= dx; 16567 } 16568 } 16569 // Found black-white-black; give the benefit of the doubt that the next pixel outside the image 16570 // is "white" so this last point at (toX+xStep,toY) is the right ending. This is really a 16571 // small approximation; (toX+xStep,toY+yStep) might be really correct. Ignore this. 16572 if (state === 2) { 16573 return MathUtils.distance(toX + xstep, toY, fromX, fromY); 16574 } 16575 // else we didn't find even black-white-black; no estimate is really possible 16576 return NaN; 16577 } 16578 /** 16579 * <p>
16579Attempts to locate an alignment pattern in a limited region of the image, which is 16580 * guessed to contain it. This method uses {@link AlignmentPattern}.</p> 16581 * 16582 * @param overallEstModuleSize estimated module size so far 16583 * @param estAlignmentX x coordinate of center of area probably containing alignment pattern 16584 * @param estAlignmentY y coordinate of above 16585 * @param allowanceFactor number of pixels in all directions to search from the center 16586 * @return {@link AlignmentPattern} if found, or null otherwise 16587 * @throws NotFoundException if an unexpected error occurs during detection 16588 */ 16589 findAlignmentInRegion(overallEstModuleSize /*float*/, estAlignmentX /*int*/, estAlignmentY /*int*/, allowanceFactor /*float*/) { 16590 // Look for an alignment pattern (3 modules in size) around where it 16591 // should be 16592 const allowance = /*(int) */ Math.floor(allowanceFactor * overallEstModuleSize); 16593 const alignmentAreaLeftX = Math.max(0, estAlignmentX - allowance); 16594 const alignmentAreaRightX = Math.min(this.image.getWidth() - 1, estAlignmentX + allowance); 16595 if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) { 16596 throw new NotFoundException('Alignment top exceeds estimated module size.'); 16597 } 16598 const alignmentAreaTopY = Math.max(0, estAlignmentY - allowance); 16599 const alignmentAreaBottomY = Math.min(this.image.getHeight() - 1, estAlignmentY + allowance); 16600 if (alignmentAreaBottomY - alignmentAreaTopY < overallEstModuleSize * 3) { 16601 throw new NotFoundException('Alignment bottom exceeds estimated module size.'); 16602 } 16603 const alignmentFinder = new AlignmentPatternFinder(this.image, alignmentAreaLeftX, alignmentAreaTopY, alignmentAreaRightX - alignmentAreaLeftX, alignmentAreaBottomY - alignmentAreaTopY, overallEstModuleSize, this.resultPointCallback); 16604 return alignmentFinder.find(); 16605 } 16606 } 16607 16608 /* 16609 * Copyright 2007 ZXing authors 16610 * 16611 * Licensed under the Apache License, Version 2.0 (the "License"); 16612 * you may not use this file except in compliance with the License. 16613 * You may obtain a copy of the License at 16614 * 16615 * http://www.apache.org/licenses/LICENSE-2.0 16616 * 16617 * Unless required by applicable law or agreed to in writing, software 16618 * distributed under the License is distributed on an "AS IS" BASIS, 16619 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16620 * See the License for the specific language governing permissions and 16621 * limitations under the License. 16622 */ 16623 /*import java.util.List;*/ 16624 /*import java.util.Map;*/ 16625 /** 16626 * This implementation can detect and decode QR Codes in an image. 16627 * 16628 * @author Sean Owen 16629 */ 16630 class QRCodeReader { 16631 constructor() { 16632 this.decoder = new Decoder(); 16633 } 16634 getDecoder() { 16635 return this.decoder; 16636 } 16637 /** 16638 * Locates and decodes a QR code in an image. 16639 * 16640 * @return a representing: string the content encoded by the QR code 16641 * @throws NotFoundException if a QR code cannot be found 16642 * @throws FormatException if a QR code cannot be decoded 16643 * @throws ChecksumException if error correction fails 16644 */ 16645 /*@Override*/ 16646 // public decode(image: BinaryBitmap): Result /*throws NotFoundException, ChecksumException, FormatException */ { 16647 // return this.decode(image, null) 16648 // } 16649 /*@Override*/ 16650 decode(image, hints) { 16651 let decoderResult; 16652 let points; 16653 if (hints !== undefined && hints !== null && undefined !== hints.get(DecodeHintType$1.PURE_BARCODE)) { 16654 const bits = QRCodeReader.extractPureBits(image.getBlackMatrix()); 16655 decoderResult = this.decoder.decodeBitMatrix(bits, hints); 16656 points = QRCodeReader.NO_POINTS; 16657 } 16658 else { 16659 const detectorResult = new Detector$1(image.getBlackMatrix()).detect(hints); 16660 decoderResult = this.decoder.decodeBitMatrix(detectorResult.getBits(), hints); 16661 points = detectorResult.getPoints(); 16662 } 16663 // If the code was mirrored: swap the bottom-left and the top-right points. 16664 if (decoderResult.getOther() instanceof QRCodeDecoderMetaData) { 16665 decoderResult.getOther().applyMirroredCorrection(points); 16666 } 16667 const result = new Result$1(decoderResult.getText(), decoderResult.getRawBytes(), undefined, points, BarcodeFormat$1.QR_CODE, undefined); 16668 const byteSegments = decoderResult.getByteSegments(); 16669 if (byteSegments !== null) { 16670 result.putMetadata(ResultMetadataType$1.BYTE_SEGMENTS, byteSegments); 16671 } 16672 const ecLevel = decoderResult.getECLevel(); 16673 if (ecLevel !== null) { 16674 result.putMetadata(ResultMetadataType$1.ERROR_CORRECTION_LEVEL, ecLevel); 16675 }
vendor: 5,010 bytes, lines 16676-16793
16676 if (decoderResult.hasStructuredAppend()) { 16677 result.putMetadata(ResultMetadataType$1.STRUCTURED_APPEND_SEQUENCE, decoderResult.getStructuredAppendSequenceNumber()); 16678 result.putMetadata(ResultMetadataType$1.STRUCTURED_APPEND_PARITY, decoderResult.getStructuredAppendParity()); 16679 } 16680 return result; 16681 } 16682 /*@Override*/ 16683 reset() { 16684 // do nothing 16685 } 16686 /** 16687 * This method detects a code in a "pure" image -- that is, pure monochrome image 16688 * which contains only an unrotated, unskewed, image of a code, with some white border 16689 * around it. This is a specialized method that works exceptionally fast in this special 16690 * case. 16691 * 16692 * @see com.google.zxing.datamatrix.DataMatrixReader#extractPureBits(BitMatrix) 16693 */ 16694 static extractPureBits(image) { 16695 const leftTopBlack = image.getTopLeftOnBit(); 16696 const rightBottomBlack = image.getBottomRightOnBit(); 16697 if (leftTopBlack === null || rightBottomBlack === null) { 16698 throw new NotFoundException(); 16699 } 16700 const moduleSize = this.moduleSize(leftTopBlack, image); 16701 let top = leftTopBlack[1]; 16702 let bottom = rightBottomBlack[1]; 16703 let left = leftTopBlack[0]; 16704 let right = rightBottomBlack[0]; 16705 // Sanity check! 16706 if (left >= right || top >= bottom) { 16707 throw new NotFoundException(); 16708 } 16709 if (bottom - top !== right - left) { 16710 // Special case, where bottom-right module wasn't black so we found something else in the last row 16711 // Assume it's a square, so use height as the width 16712 right = left + (bottom - top); 16713 if (right >= image.getWidth()) { 16714 // Abort if that would not make sense -- off image 16715 throw new NotFoundException(); 16716 } 16717 } 16718 const matrixWidth = Math.round((right - left + 1) / moduleSize); 16719 const matrixHeight = Math.round((bottom - top + 1) / moduleSize); 16720 if (matrixWidth <= 0 || matrixHeight <= 0) { 16721 throw new NotFoundException(); 16722 } 16723 if (matrixHeight !== matrixWidth) { 16724 // Only possibly decode square regions 16725 throw new NotFoundException(); 16726 } 16727 // Push in the "border" by half the module width so that we start 16728 // sampling in the middle of the module. Just in case the image is a 16729 // little off, this will help recover. 16730 const nudge = /*(int) */ Math.floor(moduleSize / 2.0); 16731 top += nudge; 16732 left += nudge; 16733 // But careful that this does not sample off the edge 16734 // "right" is the farthest-right valid pixel location -- right+1 is not necessarily 16735 // This is positive by how much the inner x loop below would be too large 16736 const nudgedTooFarRight = left + /*(int) */ Math.floor((matrixWidth - 1) * moduleSize) - right; 16737 if (nudgedTooFarRight > 0) { 16738 if (nudgedTooFarRight > nudge) { 16739 // Neither way fits; abort 16740 throw new NotFoundException(); 16741 } 16742 left -= nudgedTooFarRight; 16743 } 16744 // See logic above 16745 const nudgedTooFarDown = top + /*(int) */ Math.floor((matrixHeight - 1) * moduleSize) - bottom; 16746 if (nudgedTooFarDown > 0) { 16747 if (nudgedTooFarDown > nudge) { 16748 // Neither way fits; abort 16749 throw new NotFoundException(); 16750 } 16751 top -= nudgedTooFarDown; 16752 } 16753 // Now just read off the bits 16754 const bits = new BitMatrix(matrixWidth, matrixHeight); 16755 for (let y = 0; y < matrixHeight; y++) { 16756 const iOffset = top + /*(int) */ Math.floor(y * moduleSize); 16757 for (let x = 0; x < matrixWidth; x++) { 16758 if (image.get(left + /*(int) */ Math.floor(x * moduleSize), iOffset)) { 16759 bits.set(x, y); 16760 } 16761 } 16762 } 16763 return bits; 16764 } 16765 static moduleSize(leftTopBlack, image) { 16766 const height = image.getHeight(); 16767 const width = image.getWidth(); 16768 let x = leftTopBlack[0]; 16769 let y = leftTopBlack[1]; 16770 let inBlack = true; 16771 let transitions = 0; 16772 while (x < width && y < height) { 16773 if (inBlack !== image.get(x, y)) { 16774 if (++transitions === 5) { 16775 break; 16776 } 16777 inBlack = !inBlack; 16778 } 16779 x++; 16780 y++; 16781 } 16782 if (x === width || y === height) { 16783 throw new NotFoundException(); 16784 } 16785 return (x - leftTopBlack[0]) / 7.0; 16786 } 16787 } 16788 QRCodeReader.NO_POINTS = new Array(); 16789 16790 /* 16791 * Copyright 2009 ZXing authors 16792 * 16793 * Licensed under the Apache License, Version 2.0 (the "License");
16794 * you may not use this file except in compliance with the License. 16795 * You may obtain a copy of the License at 16796 * 16797 * http://www.apache.org/licenses/LICENSE-2.0 16798 * 16799 * Unless required by applicable law or agreed to in writing, software 16800 * distributed under the License is distributed on an "AS IS" BASIS, 16801 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16802 * See the License for the specific language governing permissions and 16803 * limitations under the License. 16804 */ 16805 /** 16806 * @author SITA Lab ([email protected]) 16807 * @author Guenther Grau 16808 */ 16809 /*public final*/
vendor: 46,561 bytes, lines 16809-17288
16809 class PDF417Common { 16810 PDF417Common() { 16811 } 16812 /** 16813 * @param moduleBitCount values to sum 16814 * @return sum of values 16815 * @deprecated call {@link MathUtils#sum(int[])} 16816 */ 16817 // @Deprecated 16818 static getBitCountSum(moduleBitCount) { 16819 return MathUtils.sum(moduleBitCount); 16820 } 16821 static toIntArray(list) { 16822 if (list == null || !list.length) { 16823 return PDF417Common.EMPTY_INT_ARRAY; 16824 } 16825 const result = new Int32Array(list.length); 16826 let i = 0; 16827 for (const integer of list) { 16828 result[i++] = integer; 16829 } 16830 return result; 16831 } 16832 /** 16833 * @param symbol encoded symbol to translate to a codeword 16834 * @return the codeword corresponding to the symbol. 16835 */ 16836 static getCodeword(symbol /*int*/) { 16837 const i = Arrays.binarySearch(PDF417Common.SYMBOL_TABLE, symbol & 0x3FFFF); 16838 if (i < 0) { 16839 return -1; 16840 } 16841 return (PDF417Common.CODEWORD_TABLE[i] - 1) % PDF417Common.NUMBER_OF_CODEWORDS; 16842 } 16843 } 16844 PDF417Common.NUMBER_OF_CODEWORDS = 929; 16845 // Maximum Codewords (Data + Error). 16846 PDF417Common.MAX_CODEWORDS_IN_BARCODE = PDF417Common.NUMBER_OF_CODEWORDS - 1; 16847 PDF417Common.MIN_ROWS_IN_BARCODE = 3; 16848 PDF417Common.MAX_ROWS_IN_BARCODE = 90; 16849 // One left row indication column + max 30 data columns + one right row indicator column 16850 // public static /*final*/ MAX_CODEWORDS_IN_ROW: /*int*/ number = 32; 16851 PDF417Common.MODULES_IN_CODEWORD = 17; 16852 PDF417Common.MODULES_IN_STOP_PATTERN = 18; 16853 PDF417Common.BARS_IN_MODULE = 8; 16854 PDF417Common.EMPTY_INT_ARRAY = new Int32Array([]); 16855 /** 16856 * The sorted table of all possible symbols. Extracted from the PDF417 16857 * specification. The index of a symbol in this table corresponds to the 16858 * index into the codeword table. 16859 */ 16860 PDF417Common.SYMBOL_TABLE = Int32Array.from([ 16861 0x1025e, 0x1027a, 0x1029e, 0x102bc, 0x102f2, 0x102f4, 0x1032e, 0x1034e, 0x1035c, 0x10396, 0x103a6, 0x103ac, 16862 0x10422, 0x10428, 0x10436, 0x10442, 0x10444, 0x10448, 0x10450, 0x1045e, 0x10466, 0x1046c, 0x1047a, 0x10482, 16863 0x1049e, 0x104a0, 0x104bc, 0x104c6, 0x104d8, 0x104ee, 0x104f2, 0x104f4, 0x10504, 0x10508, 0x10510, 0x1051e, 16864 0x10520, 0x1053c, 0x10540, 0x10578, 0x10586, 0x1058c, 0x10598, 0x105b0, 0x105be, 0x105ce, 0x105dc, 0x105e2, 16865 0x105e4, 0x105e8, 0x105f6, 0x1062e, 0x1064e, 0x1065c, 0x1068e, 0x1069c, 0x106b8, 0x106de, 0x106fa, 0x10716, 16866 0x10726, 0x1072c, 0x10746, 0x1074c, 0x10758, 0x1076e, 0x10792, 0x10794, 0x107a2, 0x107a4, 0x107a8, 0x107b6, 16867 0x10822, 0x10828, 0x10842, 0x10848, 0x10850, 0x1085e, 0x10866, 0x1086c, 0x1087a, 0x10882, 0x10884, 0x10890, 16868 0x1089e, 0x108a0, 0x108bc, 0x108c6, 0x108cc, 0x108d8, 0x108ee, 0x108f2, 0x108f4, 0x10902, 0x10908, 0x1091e, 16869 0x10920, 0x1093c, 0x10940, 0x10978, 0x10986, 0x10998, 0x109b0, 0x109be, 0x109ce, 0x109dc, 0x109e2, 0x109e4, 16870 0x109e8, 0x109f6, 0x10a08, 0x10a10, 0x10a1e, 0x10a20, 0x10a3c, 0x10a40, 0x10a78, 0x10af0, 0x10b06, 0x10b0c, 16871 0x10b18, 0x10b30, 0x10b3e, 0x10b60, 0x10b7c, 0x10b8e, 0x10b9c, 0x10bb8, 0x10bc2, 0x10bc4, 0x10bc8, 0x10bd0, 16872 0x10bde, 0x10be6, 0x10bec, 0x10c2e, 0x10c4e, 0x10c5c, 0x10c62, 0x10c64, 0x10c68, 0x10c76, 0x10c8e, 0x10c9c, 16873 0x10cb8, 0x10cc2, 0x10cc4, 0x10cc8, 0x10cd0, 0x10cde, 0x10ce6, 0x10cec, 0x10cfa, 0x10d0e, 0x10d1c, 0x10d38, 16874 0x10d70, 0x10d7e, 0x10d82, 0x10d84, 0x10d88, 0x10d90, 0x10d9e, 0x10da0, 0x10dbc, 0x10dc6, 0x10dcc, 0x10dd8, 16875 0x10dee, 0x10df2, 0x10df4, 0x10e16, 0x10e26, 0x10e2c, 0x10e46, 0x10e58, 0x10e6e, 0x10e86, 0x10e8c, 0x10e98, 16876 0x10eb0, 0x10ebe, 0x10ece, 0x10edc, 0x10f0a, 0x10f12, 0x10f14, 0x10f22, 0x10f28, 0x10f36, 0x10f42, 0x10f44, 16877 0x10f48, 0x10f50, 0x10f5e, 0x10f66, 0x10f6c, 0x10fb2, 0x10fb4, 0x11022, 0x11028, 0x11042, 0x11048, 0x11050, 16878 0x1105e, 0x1107a, 0x11082, 0x11084, 0x11090, 0x1109e, 0x110a0, 0x110bc, 0x110c6, 0x110cc, 0x110d8, 0x110ee, 16879 0x110f2, 0x110f4, 0x11102, 0x1111e, 0x11120, 0x1113c, 0x11140, 0x11178, 0x11186, 0x11198, 0x111b0, 0x111be, 16880 0x111ce, 0x111dc, 0x111e2, 0x111e4, 0x111e8, 0x111f6, 0x11208, 0x1121e, 0x11220, 0x11278, 0x112f0, 0x1130c, 16881 0x11330, 0x1133e, 0x11360, 0x1137c, 0x1138e, 0x1139c, 0x113b8, 0x113c2, 0x113c8, 0x113d0, 0x113de, 0x113e6, 16882 0x113ec, 0x11408, 0x11410, 0x1141e, 0x11420, 0x1143c, 0x11440, 0x11478, 0x114f0, 0x115e0, 0x1160c, 0x11618, 16883 0x11630, 0x1163e, 0x11660, 0x1167c, 0x116c0, 0x116f8, 0x1171c, 0x11738, 0x11770, 0x1177e, 0x11782, 0x11784, 16884 0x11788, 0x11790, 0x1179e, 0x117a0, 0x117bc, 0x117c6, 0x117cc, 0x117d8, 0x117ee, 0x1182e, 0x11834, 0x1184e, 16885 0x1185c, 0x11862, 0x11864, 0x11868, 0x11876, 0x1188e, 0x1189c, 0x118b8, 0x118c2, 0x118c8, 0x118d0, 0x118de, 16886 0x118e6, 0x118ec, 0x118fa, 0x1190e, 0x1191c, 0x11938, 0x11970, 0x1197e, 0x11982, 0x11984, 0x11990, 0x1199e, 16887 0x119a0, 0x119bc, 0x119c6, 0x119cc, 0x119d8, 0x119ee, 0x119f2, 0x119f4, 0x11a0e, 0x11a1c, 0x11a38, 0x11a70, 16888 0x11a7e, 0x11ae0, 0x11afc, 0x11b08, 0x11b10, 0x11b1e, 0x11b20, 0x11b3c, 0x11b40, 0x11b78, 0x11b8c, 0x11b98, 16889 0x11bb0, 0x11bbe, 0x11bce, 0x11bdc, 0x11be2, 0x11be4, 0x11be8, 0x11bf6, 0x11c16, 0x11c26, 0x11c2c, 0x11c46, 16890 0x11c4c, 0x11c58, 0x11c6e, 0x11c86, 0x11c98, 0x11cb0, 0x11cbe, 0x11cce, 0x11cdc, 0x11ce2, 0x11ce4, 0x11ce8, 16891 0x11cf6, 0x11d06, 0x11d0c, 0x11d18, 0x11d30, 0x11d3e, 0x11d60, 0x11d7c, 0x11d8e, 0x11d9c, 0x11db8, 0x11dc4, 16892 0x11dc8, 0x11dd0, 0x11dde, 0x11de6, 0x11dec, 0x11dfa, 0x11e0a, 0x11e12, 0x11e14, 0x11e22, 0x11e24, 0x11e28, 16893 0x11e36, 0x11e42, 0x11e44, 0x11e50, 0x11e5e, 0x11e66, 0x11e6c, 0x11e82, 0x11e84, 0x11e88, 0x11e90, 0x11e9e, 16894 0x11ea0, 0x11ebc, 0x11ec6, 0x11ecc, 0x11ed8, 0x11eee, 0x11f1a, 0x11f2e, 0x11f32, 0x11f34, 0x11f4e, 0x11f5c, 16895 0x11f62, 0x11f64, 0x11f68, 0x11f76, 0x12048, 0x1205e, 0x12082, 0x12084, 0x12090, 0x1209e, 0x120a0, 0x120bc, 16896 0x120d8, 0x120f2, 0x120f4, 0x12108, 0x1211e, 0x12120, 0x1213c, 0x12140, 0x12178, 0x12186, 0x12198, 0x121b0, 16897 0x121be, 0x121e2, 0x121e4, 0x121e8, 0x121f6, 0x12204, 0x12210, 0x1221e, 0x12220, 0x12278, 0x122f0, 0x12306, 16898 0x1230c, 0x12330, 0x1233e, 0x12360, 0x1237c, 0x1238e, 0x1239c, 0x123b8, 0x123c2, 0x123c8, 0x123d0, 0x123e6, 16899 0x123ec, 0x1241e, 0x12420, 0x1243c, 0x124f0, 0x125e0, 0x12618, 0x1263e, 0x12660, 0x1267c, 0x126c0, 0x126f8, 16900 0x12738, 0x12770, 0x1277e, 0x12782, 0x12784, 0x12790, 0x1279e, 0x127a0, 0x127bc, 0x127c6, 0x127cc, 0x127d8, 16901 0x127ee, 0x12820, 0x1283c, 0x12840, 0x12878, 0x128f0, 0x129e0, 0x12bc0, 0x12c18, 0x12c30, 0x12c3e, 0x12c60, 16902 0x12c7c, 0x12cc0, 0x12cf8, 0x12df0, 0x12e1c, 0x12e38, 0x12e70, 0x12e7e, 0x12ee0, 0x12efc, 0x12f04, 0x12f08, 16903 0x12f10, 0x12f20, 0x12f3c, 0x12f40, 0x12f78, 0x12f86, 0x12f8c, 0x12f98, 0x12fb0, 0x12fbe, 0x12fce, 0x12fdc, 16904 0x1302e, 0x1304e, 0x1305c, 0x13062, 0x13068, 0x1308e, 0x1309c, 0x130b8, 0x130c2, 0x130c8, 0x130d0, 0x130de, 16905 0x130ec, 0x130fa, 0x1310e, 0x13138, 0x13170, 0x1317e, 0x13182, 0x13184, 0x13190, 0x1319e, 0x131a0, 0x131bc, 16906 0x131c6, 0x131cc, 0x131d8, 0x131f2, 0x131f4, 0x1320e, 0x1321c, 0x13270, 0x1327e, 0x132e0, 0x132fc, 0x13308, 16907 0x1331e, 0x13320, 0x1333c, 0x13340, 0x13378, 0x13386, 0x13398, 0x133b0, 0x133be, 0x133ce, 0x133dc, 0x133e2, 16908 0x133e4, 0x133e8, 0x133f6, 0x1340e, 0x1341c, 0x13438, 0x13470, 0x1347e, 0x134e0, 0x134fc, 0x135c0, 0x135f8, 16909 0x13608, 0x13610, 0x1361e, 0x13620, 0x1363c, 0x13640, 0x13678, 0x136f0, 0x1370c, 0x13718, 0x13730, 0x1373e, 16910 0x13760, 0x1377c, 0x1379c, 0x137b8, 0x137c2, 0x137c4, 0x137c8, 0x137d0, 0x137de, 0x137e6, 0x137ec, 0x13816, 16911 0x13826, 0x1382c, 0x13846, 0x1384c, 0x13858, 0x1386e, 0x13874, 0x13886, 0x13898, 0x138b0, 0x138be, 0x138ce, 16912 0x138dc, 0x138e2, 0x138e4, 0x138e8, 0x13906, 0x1390c, 0x13930, 0x1393e, 0x13960, 0x1397c, 0x1398e, 0x1399c, 16913 0x139b8, 0x139c8, 0x139d0, 0x139de, 0x139e6, 0x139ec, 0x139fa, 0x13a06, 0x13a0c, 0x13a18, 0x13a30, 0x13a3e, 16914 0x13a60, 0x13a7c, 0x13ac0, 0x13af8, 0x13b0e, 0x13b1c, 0x13b38, 0x13b70, 0x13b7e, 0x13b88, 0x13b90, 0x13b9e, 16915 0x13ba0, 0x13bbc, 0x13bcc, 0x13bd8, 0x13bee, 0x13bf2, 0x13bf4, 0x13c12, 0x13c14, 0x13c22, 0x13c24, 0x13c28, 16916 0x13c36, 0x13c42, 0x13c48, 0x13c50, 0x13c5e, 0x13c66, 0x13c6c, 0x13c82, 0x13c84, 0x13c90, 0x13c9e, 0x13ca0, 16917 0x13cbc, 0x13cc6, 0x13ccc, 0x13cd8, 0x13cee, 0x13d02, 0x13d04, 0x13d08, 0x13d10, 0x13d1e, 0x13d20, 0x13d3c, 16918 0x13d40, 0x13d78, 0x13d86, 0x13d8c, 0x13d98, 0x13db0, 0x13dbe, 0x13dce, 0x13ddc, 0x13de4, 0x13de8, 0x13df6, 16919 0x13e1a, 0x13e2e, 0x13e32, 0x13e34, 0x13e4e, 0x13e5c, 0x13e62, 0x13e64, 0x13e68, 0x13e76, 0x13e8e, 0x13e9c, 16920 0x13eb8, 0x13ec2, 0x13ec4, 0x13ec8, 0x13ed0, 0x13ede, 0x13ee6, 0x13eec, 0x13f26, 0x13f2c, 0x13f3a, 0x13f46, 16921 0x13f4c, 0x13f58, 0x13f6e, 0x13f72, 0x13f74, 0x14082, 0x1409e, 0x140a0, 0x140bc, 0x14104, 0x14108, 0x14110, 16922 0x1411e, 0x14120, 0x1413c, 0x14140, 0x14178, 0x1418c, 0x14198, 0x141b0, 0x141be, 0x141e2, 0x141e4, 0x141e8, 16923 0x14208, 0x14210, 0x1421e, 0x14220, 0x1423c, 0x14240, 0x14278, 0x142f0, 0x14306, 0x1430c, 0x14318, 0x14330, 16924 0x1433e, 0x14360, 0x1437c, 0x1438e, 0x143c2, 0x143c4, 0x143c8, 0x143d0, 0x143e6, 0x143ec, 0x14408, 0x14410, 16925 0x1441e, 0x14420, 0x1443c, 0x14440, 0x14478, 0x144f0, 0x145e0, 0x1460c, 0x14618, 0x14630, 0x1463e, 0x14660, 16926 0x1467c, 0x146c0, 0x146f8, 0x1471c, 0x14738, 0x14770, 0x1477e, 0x14782, 0x14784, 0x14788, 0x14790, 0x147a0, 16927 0x147bc, 0x147c6, 0x147cc, 0x147d8, 0x147ee, 0x14810, 0x14820, 0x1483c, 0x14840, 0x14878, 0x148f0, 0x149e0, 16928 0x14bc0, 0x14c30, 0x14c3e, 0x14c60, 0x14c7c, 0x14cc0, 0x14cf8, 0x14df0, 0x14e38, 0x14e70, 0x14e7e, 0x14ee0, 16929 0x14efc, 0x14f04, 0x14f08, 0x14f10, 0x14f1e, 0x14f20, 0x14f3c, 0x14f40, 0x14f78, 0x14f86, 0x14f8c, 0x14f98, 16930 0x14fb0, 0x14fce, 0x14fdc, 0x15020, 0x15040, 0x15078, 0x150f0, 0x151e0, 0x153c0, 0x15860, 0x1587c, 0x158c0, 16931 0x158f8, 0x159f0, 0x15be0, 0x15c70, 0x15c7e, 0x15ce0, 0x15cfc, 0x15dc0, 0x15df8, 0x15e08, 0x15e10, 0x15e20, 16932 0x15e40, 0x15e78, 0x15ef0, 0x15f0c, 0x15f18, 0x15f30, 0x15f60, 0x15f7c, 0x15f8e, 0x15f9c, 0x15fb8, 0x1604e, 16933 0x1605c, 0x1608e, 0x1609c, 0x160b8, 0x160c2, 0x160c4, 0x160c8, 0x160de, 0x1610e, 0x1611c, 0x16138, 0x16170, 16934 0x1617e, 0x16184, 0x16188, 0x16190, 0x1619e, 0x161a0, 0x161bc, 0x161c6, 0x161cc, 0x161d8, 0x161f2, 0x161f4, 16935 0x1620e, 0x1621c, 0x16238, 0x16270, 0x1627e, 0x162e0, 0x162fc, 0x16304, 0x16308, 0x16310, 0x1631e, 0x16320, 16936 0x1633c, 0x16340, 0x16378, 0x16386, 0x1638c, 0x16398, 0x163b0, 0x163be, 0x163ce, 0x163dc, 0x163e2, 0x163e4, 16937 0x163e8, 0x163f6, 0x1640e, 0x1641c, 0x16438, 0x16470, 0x1647e, 0x164e0, 0x164fc, 0x165c0, 0x165f8, 0x16610, 16938 0x1661e, 0x16620, 0x1663c, 0x16640, 0x16678, 0x166f0, 0x16718, 0x16730, 0x1673e, 0x16760, 0x1677c, 0x1678e, 16939 0x1679c, 0x167b8, 0x167c2, 0x167c4, 0x167c8, 0x167d0, 0x167de, 0x167e6, 0x167ec, 0x1681c, 0x16838, 0x16870, 16940 0x168e0, 0x168fc, 0x169c0, 0x169f8, 0x16bf0, 0x16c10, 0x16c1e, 0x16c20, 0x16c3c, 0x16c40, 0x16c78, 0x16cf0, 16941 0x16de0, 0x16e18, 0x16e30, 0x16e3e, 0x16e60, 0x16e7c, 0x16ec0, 0x16ef8, 0x16f1c, 0x16f38, 0x16f70, 0x16f7e, 16942 0x16f84, 0x16f88, 0x16f90, 0x16f9e, 0x16fa0, 0x16fbc, 0x16fc6, 0x16fcc, 0x16fd8, 0x17026, 0x1702c, 0x17046, 16943 0x1704c, 0x17058, 0x1706e, 0x17086, 0x1708c, 0x17098, 0x170b0, 0x170be, 0x170ce, 0x170dc, 0x170e8, 0x17106, 16944 0x1710c, 0x17118, 0x17130, 0x1713e, 0x17160, 0x1717c, 0x1718e, 0x1719c, 0x171b8, 0x171c2, 0x171c4, 0x171c8, 16945 0x171d0, 0x171de, 0x171e6, 0x171ec, 0x171fa, 0x17206, 0x1720c, 0x17218, 0x17230, 0x1723e, 0x17260, 0x1727c, 16946 0x172c0, 0x172f8, 0x1730e, 0x1731c, 0x17338, 0x17370, 0x1737e, 0x17388, 0x17390, 0x1739e, 0x173a0, 0x173bc, 16947 0x173cc, 0x173d8, 0x173ee, 0x173f2, 0x173f4, 0x1740c, 0x17418, 0x17430, 0x1743e, 0x17460, 0x1747c, 0x174c0, 16948 0x174f8, 0x175f0, 0x1760e, 0x1761c, 0x17638, 0x17670, 0x1767e, 0x176e0, 0x176fc, 0x17708, 0x17710, 0x1771e, 16949 0x17720, 0x1773c, 0x17740, 0x17778, 0x17798, 0x177b0, 0x177be, 0x177dc, 0x177e2, 0x177e4, 0x177e8, 0x17822, 16950 0x17824, 0x17828, 0x17836, 0x17842, 0x17844, 0x17848, 0x17850, 0x1785e, 0x17866, 0x1786c, 0x17882, 0x17884, 16951 0x17888, 0x17890, 0x1789e, 0x178a0, 0x178bc, 0x178c6, 0x178cc, 0x178d8, 0x178ee, 0x178f2, 0x178f4, 0x17902, 16952 0x17904, 0x17908, 0x17910, 0x1791e, 0x17920, 0x1793c, 0x17940, 0x17978, 0x17986, 0x1798c, 0x17998, 0x179b0, 16953 0x179be, 0x179ce, 0x179dc, 0x179e2, 0x179e4, 0x179e8, 0x179f6, 0x17a04, 0x17a08, 0x17a10, 0x17a1e, 0x17a20, 16954 0x17a3c, 0x17a40, 0x17a78, 0x17af0, 0x17b06, 0x17b0c, 0x17b18, 0x17b30, 0x17b3e, 0x17b60, 0x17b7c, 0x17b8e, 16955 0x17b9c, 0x17bb8, 0x17bc4, 0x17bc8, 0x17bd0, 0x17bde, 0x17be6, 0x17bec, 0x17c2e, 0x17c32, 0x17c34, 0x17c4e, 16956 0x17c5c, 0x17c62, 0x17c64, 0x17c68, 0x17c76, 0x17c8e, 0x17c9c, 0x17cb8, 0x17cc2, 0x17cc4, 0x17cc8, 0x17cd0, 16957 0x17cde, 0x17ce6, 0x17cec, 0x17d0e, 0x17d1c, 0x17d38, 0x17d70, 0x17d82, 0x17d84, 0x17d88, 0x17d90, 0x17d9e, 16958 0x17da0, 0x17dbc, 0x17dc6, 0x17dcc, 0x17dd8, 0x17dee, 0x17e26, 0x17e2c, 0x17e3a, 0x17e46, 0x17e4c, 0x17e58, 16959 0x17e6e, 0x17e72, 0x17e74, 0x17e86, 0x17e8c, 0x17e98, 0x17eb0, 0x17ece, 0x17edc, 0x17ee2, 0x17ee4, 0x17ee8, 16960 0x17ef6, 0x1813a, 0x18172, 0x18174, 0x18216, 0x18226, 0x1823a, 0x1824c, 0x18258, 0x1826e, 0x18272, 0x18274, 16961 0x18298, 0x182be, 0x182e2, 0x182e4, 0x182e8, 0x182f6, 0x1835e, 0x1837a, 0x183ae, 0x183d6, 0x18416, 0x18426, 16962 0x1842c, 0x1843a, 0x18446, 0x18458, 0x1846e, 0x18472, 0x18474, 0x18486, 0x184b0, 0x184be, 0x184ce, 0x184dc, 16963 0x184e2, 0x184e4, 0x184e8, 0x184f6, 0x18506, 0x1850c, 0x18518, 0x18530, 0x1853e, 0x18560, 0x1857c, 0x1858e, 16964 0x1859c, 0x185b8, 0x185c2, 0x185c4, 0x185c8, 0x185d0, 0x185de, 0x185e6, 0x185ec, 0x185fa, 0x18612, 0x18614, 16965 0x18622, 0x18628, 0x18636, 0x18642, 0x18650, 0x1865e, 0x1867a, 0x18682, 0x18684, 0x18688, 0x18690, 0x1869e, 16966 0x186a0, 0x186bc, 0x186c6, 0x186cc, 0x186d8, 0x186ee, 0x186f2, 0x186f4, 0x1872e, 0x1874e, 0x1875c, 0x18796, 16967 0x187a6, 0x187ac, 0x187d2, 0x187d4, 0x18826, 0x1882c, 0x1883a, 0x18846, 0x1884c, 0x18858, 0x1886e, 0x18872, 16968 0x18874, 0x18886, 0x18898, 0x188b0, 0x188be, 0x188ce, 0x188dc, 0x188e2, 0x188e4, 0x188e8, 0x188f6, 0x1890c, 16969 0x18930, 0x1893e, 0x18960, 0x1897c, 0x1898e, 0x189b8, 0x189c2, 0x189c8, 0x189d0, 0x189de, 0x189e6, 0x189ec, 16970 0x189fa, 0x18a18, 0x18a30, 0x18a3e, 0x18a60, 0x18a7c, 0x18ac0, 0x18af8, 0x18b1c, 0x18b38, 0x18b70, 0x18b7e, 16971 0x18b82, 0x18b84, 0x18b88, 0x18b90, 0x18b9e, 0x18ba0, 0x18bbc, 0x18bc6, 0x18bcc, 0x18bd8, 0x18bee, 0x18bf2, 16972 0x18bf4, 0x18c22, 0x18c24, 0x18c28, 0x18c36, 0x18c42, 0x18c48, 0x18c50, 0x18c5e, 0x18c66, 0x18c7a, 0x18c82, 16973 0x18c84, 0x18c90, 0x18c9e, 0x18ca0, 0x18cbc, 0x18ccc, 0x18cf2, 0x18cf4, 0x18d04, 0x18d08, 0x18d10, 0x18d1e, 16974 0x18d20, 0x18d3c, 0x18d40, 0x18d78, 0x18d86, 0x18d98, 0x18dce, 0x18de2, 0x18de4, 0x18de8, 0x18e2e, 0x18e32, 16975 0x18e34, 0x18e4e, 0x18e5c, 0x18e62, 0x18e64, 0x18e68, 0x18e8e, 0x18e9c, 0x18eb8, 0x18ec2, 0x18ec4, 0x18ec8, 16976 0x18ed0, 0x18efa, 0x18f16, 0x18f26, 0x18f2c, 0x18f46, 0x18f4c, 0x18f58, 0x18f6e, 0x18f8a, 0x18f92, 0x18f94, 16977 0x18fa2, 0x18fa4, 0x18fa8, 0x18fb6, 0x1902c, 0x1903a, 0x19046, 0x1904c, 0x19058, 0x19072, 0x19074, 0x19086, 16978 0x19098, 0x190b0, 0x190be, 0x190ce, 0x190dc, 0x190e2, 0x190e8, 0x190f6, 0x19106, 0x1910c, 0x19130, 0x1913e, 16979 0x19160, 0x1917c, 0x1918e, 0x1919c, 0x191b8, 0x191c2, 0x191c8, 0x191d0, 0x191de, 0x191e6, 0x191ec, 0x191fa, 16980 0x19218, 0x1923e, 0x19260, 0x1927c, 0x192c0, 0x192f8, 0x19338, 0x19370, 0x1937e, 0x19382, 0x19384, 0x19390, 16981 0x1939e, 0x193a0, 0x193bc, 0x193c6, 0x193cc, 0x193d8, 0x193ee, 0x193f2, 0x193f4, 0x19430, 0x1943e, 0x19460, 16982 0x1947c, 0x194c0, 0x194f8, 0x195f0, 0x19638, 0x19670, 0x1967e, 0x196e0, 0x196fc, 0x19702, 0x19704, 0x19708, 16983 0x19710, 0x19720, 0x1973c, 0x19740, 0x19778, 0x19786, 0x1978c, 0x19798, 0x197b0, 0x197be, 0x197ce, 0x197dc, 16984 0x197e2, 0x197e4, 0x197e8, 0x19822, 0x19824, 0x19842, 0x19848, 0x19850, 0x1985e, 0x19866, 0x1987a, 0x19882, 16985 0x19884, 0x19890, 0x1989e, 0x198a0, 0x198bc, 0x198cc, 0x198f2, 0x198f4, 0x19902, 0x19908, 0x1991e, 0x19920, 16986 0x1993c, 0x19940, 0x19978, 0x19986, 0x19998, 0x199ce, 0x199e2, 0x199e4, 0x199e8, 0x19a08, 0x19a10, 0x19a1e, 16987 0x19a20, 0x19a3c, 0x19a40, 0x19a78, 0x19af0, 0x19b18, 0x19b3e, 0x19b60, 0x19b9c, 0x19bc2, 0x19bc4, 0x19bc8, 16988 0x19bd0, 0x19be6, 0x19c2e, 0x19c34, 0x19c4e, 0x19c5c, 0x19c62, 0x19c64, 0x19c68, 0x19c8e, 0x19c9c, 0x19cb8, 16989 0x19cc2, 0x19cc8, 0x19cd0, 0x19ce6, 0x19cfa, 0x19d0e, 0x19d1c, 0x19d38, 0x19d70, 0x19d7e, 0x19d82, 0x19d84, 16990 0x19d88, 0x19d90, 0x19da0, 0x19dcc, 0x19df2, 0x19df4, 0x19e16, 0x19e26, 0x19e2c, 0x19e46, 0x19e4c, 0x19e58, 16991 0x19e74, 0x19e86, 0x19e8c, 0x19e98, 0x19eb0, 0x19ebe, 0x19ece, 0x19ee2, 0x19ee4, 0x19ee8, 0x19f0a, 0x19f12, 16992 0x19f14, 0x19f22, 0x19f24, 0x19f28, 0x19f42, 0x19f44, 0x19f48, 0x19f50, 0x19f5e, 0x19f6c, 0x19f9a, 0x19fae, 16993 0x19fb2, 0x19fb4, 0x1a046, 0x1a04c, 0x1a072, 0x1a074, 0x1a086, 0x1a08c, 0x1a098, 0x1a0b0, 0x1a0be, 0x1a0e2, 16994 0x1a0e4, 0x1a0e8, 0x1a0f6, 0x1a106, 0x1a10c, 0x1a118, 0x1a130, 0x1a13e, 0x1a160, 0x1a17c, 0x1a18e, 0x1a19c, 16995 0x1a1b8, 0x1a1c2, 0x1a1c4, 0x1a1c8, 0x1a1d0, 0x1a1de, 0x1a1e6, 0x1a1ec, 0x1a218, 0x1a230, 0x1a23e, 0x1a260, 16996 0x1a27c, 0x1a2c0, 0x1a2f8, 0x1a31c, 0x1a338, 0x1a370, 0x1a37e, 0x1a382, 0x1a384, 0x1a388, 0x1a390, 0x1a39e, 16997 0x1a3a0, 0x1a3bc, 0x1a3c6, 0x1a3cc, 0x1a3d8, 0x1a3ee, 0x1a3f2, 0x1a3f4, 0x1a418, 0x1a430, 0x1a43e, 0x1a460, 16998 0x1a47c, 0x1a4c0, 0x1a4f8, 0x1a5f0, 0x1a61c, 0x1a638, 0x1a670, 0x1a67e, 0x1a6e0, 0x1a6fc, 0x1a702, 0x1a704, 16999 0x1a708, 0x1a710, 0x1a71e, 0x1a720, 0x1a73c, 0x1a740, 0x1a778, 0x1a786, 0x1a78c, 0x1a798, 0x1a7b0, 0x1a7be, 17000 0x1a7ce, 0x1a7dc, 0x1a7e2, 0x1a7e4, 0x1a7e8, 0x1a830, 0x1a860, 0x1a87c, 0x1a8c0, 0x1a8f8, 0x1a9f0, 0x1abe0, 17001 0x1ac70, 0x1ac7e, 0x1ace0, 0x1acfc, 0x1adc0, 0x1adf8, 0x1ae04, 0x1ae08, 0x1ae10, 0x1ae20, 0x1ae3c, 0x1ae40, 17002 0x1ae78, 0x1aef0, 0x1af06, 0x1af0c, 0x1af18, 0x1af30, 0x1af3e, 0x1af60, 0x1af7c, 0x1af8e, 0x1af9c, 0x1afb8, 17003 0x1afc4, 0x1afc8, 0x1afd0, 0x1afde, 0x1b042, 0x1b05e, 0x1b07a, 0x1b082, 0x1b084, 0x1b088, 0x1b090, 0x1b09e, 17004 0x1b0a0, 0x1b0bc, 0x1b0cc, 0x1b0f2, 0x1b0f4, 0x1b102, 0x1b104, 0x1b108, 0x1b110, 0x1b11e, 0x1b120, 0x1b13c, 17005 0x1b140, 0x1b178, 0x1b186, 0x1b198, 0x1b1ce, 0x1b1e2, 0x1b1e4, 0x1b1e8, 0x1b204, 0x1b208, 0x1b210, 0x1b21e, 17006 0x1b220, 0x1b23c, 0x1b240, 0x1b278, 0x1b2f0, 0x1b30c, 0x1b33e, 0x1b360, 0x1b39c, 0x1b3c2, 0x1b3c4, 0x1b3c8, 17007 0x1b3d0, 0x1b3e6, 0x1b410, 0x1b41e, 0x1b420, 0x1b43c, 0x1b440, 0x1b478, 0x1b4f0, 0x1b5e0, 0x1b618, 0x1b660, 17008 0x1b67c, 0x1b6c0, 0x1b738, 0x1b782, 0x1b784, 0x1b788, 0x1b790, 0x1b79e, 0x1b7a0, 0x1b7cc, 0x1b82e, 0x1b84e, 17009 0x1b85c, 0x1b88e, 0x1b89c, 0x1b8b8, 0x1b8c2, 0x1b8c4, 0x1b8c8, 0x1b8d0, 0x1b8e6, 0x1b8fa, 0x1b90e, 0x1b91c, 17010 0x1b938, 0x1b970, 0x1b97e, 0x1b982, 0x1b984, 0x1b988, 0x1b990, 0x1b99e, 0x1b9a0, 0x1b9cc, 0x1b9f2, 0x1b9f4, 17011 0x1ba0e, 0x1ba1c, 0x1ba38, 0x1ba70, 0x1ba7e, 0x1bae0, 0x1bafc, 0x1bb08, 0x1bb10, 0x1bb20, 0x1bb3c, 0x1bb40, 17012 0x1bb98, 0x1bbce, 0x1bbe2, 0x1bbe4, 0x1bbe8, 0x1bc16, 0x1bc26, 0x1bc2c, 0x1bc46, 0x1bc4c, 0x1bc58, 0x1bc72, 17013 0x1bc74, 0x1bc86, 0x1bc8c, 0x1bc98, 0x1bcb0, 0x1bcbe, 0x1bcce, 0x1bce2, 0x1bce4, 0x1bce8, 0x1bd06, 0x1bd0c, 17014 0x1bd18, 0x1bd30, 0x1bd3e, 0x1bd60, 0x1bd7c, 0x1bd9c, 0x1bdc2, 0x1bdc4, 0x1bdc8, 0x1bdd0, 0x1bde6, 0x1bdfa, 17015 0x1be12, 0x1be14, 0x1be22, 0x1be24, 0x1be28, 0x1be42, 0x1be44, 0x1be48, 0x1be50, 0x1be5e, 0x1be66, 0x1be82, 17016 0x1be84, 0x1be88, 0x1be90, 0x1be9e, 0x1bea0, 0x1bebc, 0x1becc, 0x1bef4, 0x1bf1a, 0x1bf2e, 0x1bf32, 0x1bf34, 17017 0x1bf4e, 0x1bf5c, 0x1bf62, 0x1bf64, 0x1bf68, 0x1c09a, 0x1c0b2, 0x1c0b4, 0x1c11a, 0x1c132, 0x1c134, 0x1c162, 17018 0x1c164, 0x1c168, 0x1c176, 0x1c1ba, 0x1c21a, 0x1c232, 0x1c234, 0x1c24e, 0x1c25c, 0x1c262, 0x1c264, 0x1c268, 17019 0x1c276, 0x1c28e, 0x1c2c2, 0x1c2c4, 0x1c2c8, 0x1c2d0, 0x1c2de, 0x1c2e6, 0x1c2ec, 0x1c2fa, 0x1c316, 0x1c326, 17020 0x1c33a, 0x1c346, 0x1c34c, 0x1c372, 0x1c374, 0x1c41a, 0x1c42e, 0x1c432, 0x1c434, 0x1c44e, 0x1c45c, 0x1c462, 17021 0x1c464, 0x1c468, 0x1c476, 0x1c48e, 0x1c49c, 0x1c4b8, 0x1c4c2, 0x1c4c8, 0x1c4d0, 0x1c4de, 0x1c4e6, 0x1c4ec, 17022 0x1c4fa, 0x1c51c, 0x1c538, 0x1c570, 0x1c57e, 0x1c582, 0x1c584, 0x1c588, 0x1c590, 0x1c59e, 0x1c5a0, 0x1c5bc, 17023 0x1c5c6, 0x1c5cc, 0x1c5d8, 0x1c5ee, 0x1c5f2, 0x1c5f4, 0x1c616, 0x1c626, 0x1c62c, 0x1c63a, 0x1c646, 0x1c64c, 17024 0x1c658, 0x1c66e, 0x1c672, 0x1c674, 0x1c686, 0x1c68c, 0x1c698, 0x1c6b0, 0x1c6be, 0x1c6ce, 0x1c6dc, 0x1c6e2, 17025 0x1c6e4, 0x1c6e8, 0x1c712, 0x1c714, 0x1c722, 0x1c728, 0x1c736, 0x1c742, 0x1c744, 0x1c748, 0x1c750, 0x1c75e, 17026 0x1c766, 0x1c76c, 0x1c77a, 0x1c7ae, 0x1c7d6, 0x1c7ea, 0x1c81a, 0x1c82e, 0x1c832, 0x1c834, 0x1c84e, 0x1c85c, 17027 0x1c862, 0x1c864, 0x1c868, 0x1c876, 0x1c88e, 0x1c89c, 0x1c8b8, 0x1c8c2, 0x1c8c8, 0x1c8d0, 0x1c8de, 0x1c8e6, 17028 0x1c8ec, 0x1c8fa, 0x1c90e, 0x1c938, 0x1c970, 0x1c97e, 0x1c982, 0x1c984, 0x1c990, 0x1c99e, 0x1c9a0, 0x1c9bc, 17029 0x1c9c6, 0x1c9cc, 0x1c9d8, 0x1c9ee, 0x1c9f2, 0x1c9f4, 0x1ca38, 0x1ca70, 0x1ca7e, 0x1cae0, 0x1cafc, 0x1cb02, 17030 0x1cb04, 0x1cb08, 0x1cb10, 0x1cb20, 0x1cb3c, 0x1cb40, 0x1cb78, 0x1cb86, 0x1cb8c, 0x1cb98, 0x1cbb0, 0x1cbbe, 17031 0x1cbce, 0x1cbdc, 0x1cbe2, 0x1cbe4, 0x1cbe8, 0x1cbf6, 0x1cc16, 0x1cc26, 0x1cc2c, 0x1cc3a, 0x1cc46, 0x1cc58, 17032 0x1cc72, 0x1cc74, 0x1cc86, 0x1ccb0, 0x1ccbe, 0x1ccce, 0x1cce2, 0x1cce4, 0x1cce8, 0x1cd06, 0x1cd0c, 0x1cd18, 17033 0x1cd30, 0x1cd3e, 0x1cd60, 0x1cd7c, 0x1cd9c, 0x1cdc2, 0x1cdc4, 0x1cdc8, 0x1cdd0, 0x1cdde, 0x1cde6, 0x1cdfa, 17034 0x1ce22, 0x1ce28, 0x1ce42, 0x1ce50, 0x1ce5e, 0x1ce66, 0x1ce7a, 0x1ce82, 0x1ce84, 0x1ce88, 0x1ce90, 0x1ce9e, 17035 0x1cea0, 0x1cebc, 0x1cecc, 0x1cef2, 0x1cef4, 0x1cf2e, 0x1cf32, 0x1cf34, 0x1cf4e, 0x1cf5c, 0x1cf62, 0x1cf64, 17036 0x1cf68, 0x1cf96, 0x1cfa6, 0x1cfac, 0x1cfca, 0x1cfd2, 0x1cfd4, 0x1d02e, 0x1d032, 0x1d034, 0x1d04e, 0x1d05c, 17037 0x1d062, 0x1d064, 0x1d068, 0x1d076, 0x1d08e, 0x1d09c, 0x1d0b8, 0x1d0c2, 0x1d0c4, 0x1d0c8, 0x1d0d0, 0x1d0de, 17038 0x1d0e6, 0x1d0ec, 0x1d0fa, 0x1d11c, 0x1d138, 0x1d170, 0x1d17e, 0x1d182, 0x1d184, 0x1d188, 0x1d190, 0x1d19e, 17039 0x1d1a0, 0x1d1bc, 0x1d1c6, 0x1d1cc, 0x1d1d8, 0x1d1ee, 0x1d1f2, 0x1d1f4, 0x1d21c, 0x1d238, 0x1d270, 0x1d27e, 17040 0x1d2e0, 0x1d2fc, 0x1d302, 0x1d304, 0x1d308, 0x1d310, 0x1d31e, 0x1d320, 0x1d33c, 0x1d340, 0x1d378, 0x1d386, 17041 0x1d38c, 0x1d398, 0x1d3b0, 0x1d3be, 0x1d3ce, 0x1d3dc, 0x1d3e2, 0x1d3e4, 0x1d3e8, 0x1d3f6, 0x1d470, 0x1d47e, 17042 0x1d4e0, 0x1d4fc, 0x1d5c0, 0x1d5f8, 0x1d604, 0x1d608, 0x1d610, 0x1d620, 0x1d640, 0x1d678, 0x1d6f0, 0x1d706, 17043 0x1d70c, 0x1d718, 0x1d730, 0x1d73e, 0x1d760, 0x1d77c, 0x1d78e, 0x1d79c, 0x1d7b8, 0x1d7c2, 0x1d7c4, 0x1d7c8, 17044 0x1d7d0, 0x1d7de, 0x1d7e6, 0x1d7ec, 0x1d826, 0x1d82c, 0x1d83a, 0x1d846, 0x1d84c, 0x1d858, 0x1d872, 0x1d874, 17045 0x1d886, 0x1d88c, 0x1d898, 0x1d8b0, 0x1d8be, 0x1d8ce, 0x1d8e2, 0x1d8e4, 0x1d8e8, 0x1d8f6, 0x1d90c, 0x1d918, 17046 0x1d930, 0x1d93e, 0x1d960, 0x1d97c, 0x1d99c, 0x1d9c2, 0x1d9c4, 0x1d9c8, 0x1d9d0, 0x1d9e6, 0x1d9fa, 0x1da0c, 17047 0x1da18, 0x1da30, 0x1da3e, 0x1da60, 0x1da7c, 0x1dac0, 0x1daf8, 0x1db38, 0x1db82, 0x1db84, 0x1db88, 0x1db90, 17048 0x1db9e, 0x1dba0, 0x1dbcc, 0x1dbf2, 0x1dbf4, 0x1dc22, 0x1dc42, 0x1dc44, 0x1dc48, 0x1dc50, 0x1dc5e, 0x1dc66, 17049 0x1dc7a, 0x1dc82, 0x1dc84, 0x1dc88, 0x1dc90, 0x1dc9e, 0x1dca0, 0x1dcbc, 0x1dccc, 0x1dcf2, 0x1dcf4, 0x1dd04, 17050 0x1dd08, 0x1dd10, 0x1dd1e, 0x1dd20, 0x1dd3c, 0x1dd40, 0x1dd78, 0x1dd86, 0x1dd98, 0x1ddce, 0x1dde2, 0x1dde4, 17051 0x1dde8, 0x1de2e, 0x1de32, 0x1de34, 0x1de4e, 0x1de5c, 0x1de62, 0x1de64, 0x1de68, 0x1de8e, 0x1de9c, 0x1deb8, 17052 0x1dec2, 0x1dec4, 0x1dec8, 0x1ded0, 0x1dee6, 0x1defa, 0x1df16, 0x1df26, 0x1df2c, 0x1df46, 0x1df4c, 0x1df58, 17053 0x1df72, 0x1df74, 0x1df8a, 0x1df92, 0x1df94, 0x1dfa2, 0x1dfa4, 0x1dfa8, 0x1e08a, 0x1e092, 0x1e094, 0x1e0a2, 17054 0x1e0a4, 0x1e0a8, 0x1e0b6, 0x1e0da, 0x1e10a, 0x1e112, 0x1e114, 0x1e122, 0x1e124, 0x1e128, 0x1e136, 0x1e142, 17055 0x1e144, 0x1e148, 0x1e150, 0x1e166, 0x1e16c, 0x1e17a, 0x1e19a, 0x1e1b2, 0x1e1b4, 0x1e20a, 0x1e212, 0x1e214, 17056 0x1e222, 0x1e224, 0x1e228, 0x1e236, 0x1e242, 0x1e248, 0x1e250, 0x1e25e, 0x1e266, 0x1e26c, 0x1e27a, 0x1e282, 17057 0x1e284, 0x1e288, 0x1e290, 0x1e2a0, 0x1e2bc, 0x1e2c6, 0x1e2cc, 0x1e2d8, 0x1e2ee, 0x1e2f2, 0x1e2f4, 0x1e31a, 17058 0x1e332, 0x1e334, 0x1e35c, 0x1e362, 0x1e364, 0x1e368, 0x1e3ba, 0x1e40a, 0x1e412, 0x1e414, 0x1e422, 0x1e428, 17059 0x1e436, 0x1e442, 0x1e448, 0x1e450, 0x1e45e, 0x1e466, 0x1e46c, 0x1e47a, 0x1e482, 0x1e484, 0x1e490, 0x1e49e, 17060 0x1e4a0, 0x1e4bc, 0x1e4c6, 0x1e4cc, 0x1e4d8, 0x1e4ee, 0x1e4f2, 0x1e4f4, 0x1e502, 0x1e504, 0x1e508, 0x1e510, 17061 0x1e51e, 0x1e520, 0x1e53c, 0x1e540, 0x1e578, 0x1e586, 0x1e58c, 0x1e598, 0x1e5b0, 0x1e5be, 0x1e5ce, 0x1e5dc, 17062 0x1e5e2, 0x1e5e4, 0x1e5e8, 0x1e5f6, 0x1e61a, 0x1e62e, 0x1e632, 0x1e634, 0x1e64e, 0x1e65c, 0x1e662, 0x1e668, 17063 0x1e68e, 0x1e69c, 0x1e6b8, 0x1e6c2, 0x1e6c4, 0x1e6c8, 0x1e6d0, 0x1e6e6, 0x1e6fa, 0x1e716, 0x1e726, 0x1e72c, 17064 0x1e73a, 0x1e746, 0x1e74c, 0x1e758, 0x1e772, 0x1e774, 0x1e792, 0x1e794, 0x1e7a2, 0x1e7a4, 0x1e7a8, 0x1e7b6, 17065 0x1e812, 0x1e814, 0x1e822, 0x1e824, 0x1e828, 0x1e836, 0x1e842, 0x1e844, 0x1e848, 0x1e850, 0x1e85e, 0x1e866, 17066 0x1e86c, 0x1e87a, 0x1e882, 0x1e884, 0x1e888, 0x1e890, 0x1e89e, 0x1e8a0, 0x1e8bc, 0x1e8c6, 0x1e8cc, 0x1e8d8, 17067 0x1e8ee, 0x1e8f2, 0x1e8f4, 0x1e902, 0x1e904, 0x1e908, 0x1e910, 0x1e920, 0x1e93c, 0x1e940, 0x1e978, 0x1e986, 17068 0x1e98c, 0x1e998, 0x1e9b0, 0x1e9be, 0x1e9ce, 0x1e9dc, 0x1e9e2, 0x1e9e4, 0x1e9e8, 0x1e9f6, 0x1ea04, 0x1ea08, 17069 0x1ea10, 0x1ea20, 0x1ea40, 0x1ea78, 0x1eaf0, 0x1eb06, 0x1eb0c, 0x1eb18, 0x1eb30, 0x1eb3e, 0x1eb60, 0x1eb7c, 17070 0x1eb8e, 0x1eb9c, 0x1ebb8, 0x1ebc2, 0x1ebc4, 0x1ebc8, 0x1ebd0, 0x1ebde, 0x1ebe6, 0x1ebec, 0x1ec1a, 0x1ec2e, 17071 0x1ec32, 0x1ec34, 0x1ec4e, 0x1ec5c, 0x1ec62, 0x1ec64, 0x1ec68, 0x1ec8e, 0x1ec9c, 0x1ecb8, 0x1ecc2, 0x1ecc4, 17072 0x1ecc8, 0x1ecd0, 0x1ece6, 0x1ecfa, 0x1ed0e, 0x1ed1c, 0x1ed38, 0x1ed70, 0x1ed7e, 0x1ed82, 0x1ed84, 0x1ed88, 17073 0x1ed90, 0x1ed9e, 0x1eda0, 0x1edcc, 0x1edf2, 0x1edf4, 0x1ee16, 0x1ee26, 0x1ee2c, 0x1ee3a, 0x1ee46, 0x1ee4c, 17074 0x1ee58, 0x1ee6e, 0x1ee72, 0x1ee74, 0x1ee86, 0x1ee8c, 0x1ee98, 0x1eeb0, 0x1eebe, 0x1eece, 0x1eedc, 0x1eee2, 17075 0x1eee4, 0x1eee8, 0x1ef12, 0x1ef22, 0x1ef24, 0x1ef28, 0x1ef36, 0x1ef42, 0x1ef44, 0x1ef48, 0x1ef50, 0x1ef5e, 17076 0x1ef66, 0x1ef6c, 0x1ef7a, 0x1efae, 0x1efb2, 0x1efb4, 0x1efd6, 0x1f096, 0x1f0a6, 0x1f0ac, 0x1f0ba, 0x1f0ca, 17077 0x1f0d2, 0x1f0d4, 0x1f116, 0x1f126, 0x1f12c, 0x1f13a, 0x1f146, 0x1f14c, 0x1f158, 0x1f16e, 0x1f172, 0x1f174, 17078 0x1f18a, 0x1f192, 0x1f194, 0x1f1a2, 0x1f1a4, 0x1f1a8, 0x1f1da, 0x1f216, 0x1f226, 0x1f22c, 0x1f23a, 0x1f246, 17079 0x1f258, 0x1f26e, 0x1f272, 0x1f274, 0x1f286, 0x1f28c, 0x1f298, 0x1f2b0, 0x1f2be, 0x1f2ce, 0x1f2dc, 0x1f2e2, 17080 0x1f2e4, 0x1f2e8, 0x1f2f6, 0x1f30a, 0x1f312, 0x1f314, 0x1f322, 0x1f328, 0x1f342, 0x1f344, 0x1f348, 0x1f350, 17081 0x1f35e, 0x1f366, 0x1f37a, 0x1f39a, 0x1f3ae, 0x1f3b2, 0x1f3b4, 0x1f416, 0x1f426, 0x1f42c, 0x1f43a, 0x1f446, 17082 0x1f44c, 0x1f458, 0x1f46e, 0x1f472, 0x1f474, 0x1f486, 0x1f48c, 0x1f498, 0x1f4b0, 0x1f4be, 0x1f4ce, 0x1f4dc, 17083 0x1f4e2, 0x1f4e4, 0x1f4e8, 0x1f4f6, 0x1f506, 0x1f50c, 0x1f518, 0x1f530, 0x1f53e, 0x1f560, 0x1f57c, 0x1f58e, 17084 0x1f59c, 0x1f5b8, 0x1f5c2, 0x1f5c4, 0x1f5c8, 0x1f5d0, 0x1f5de, 0x1f5e6, 0x1f5ec, 0x1f5fa, 0x1f60a, 0x1f612, 17085 0x1f614, 0x1f622, 0x1f624, 0x1f628, 0x1f636, 0x1f642, 0x1f644, 0x1f648, 0x1f650, 0x1f65e, 0x1f666, 0x1f67a, 17086 0x1f682, 0x1f684, 0x1f688, 0x1f690, 0x1f69e, 0x1f6a0, 0x1f6bc, 0x1f6cc, 0x1f6f2, 0x1f6f4, 0x1f71a, 0x1f72e, 17087 0x1f732, 0x1f734, 0x1f74e, 0x1f75c, 0x1f762, 0x1f764, 0x1f768, 0x1f776, 0x1f796, 0x1f7a6, 0x1f7ac, 0x1f7ba, 17088 0x1f7d2, 0x1f7d4, 0x1f89a, 0x1f8ae, 0x1f8b2, 0x1f8b4, 0x1f8d6, 0x1f8ea, 0x1f91a, 0x1f92e, 0x1f932, 0x1f934, 17089 0x1f94e, 0x1f95c, 0x1f962, 0x1f964, 0x1f968, 0x1f976, 0x1f996, 0x1f9a6, 0x1f9ac, 0x1f9ba, 0x1f9ca, 0x1f9d2, 17090 0x1f9d4, 0x1fa1a, 0x1fa2e, 0x1fa32, 0x1fa34, 0x1fa4e, 0x1fa5c, 0x1fa62, 0x1fa64, 0x1fa68, 0x1fa76, 0x1fa8e, 17091 0x1fa9c, 0x1fab8, 0x1fac2, 0x1fac4, 0x1fac8, 0x1fad0, 0x1fade, 0x1fae6, 0x1faec, 0x1fb16, 0x1fb26, 0x1fb2c, 17092 0x1fb3a, 0x1fb46, 0x1fb4c, 0x1fb58, 0x1fb6e, 0x1fb72, 0x1fb74, 0x1fb8a, 0x1fb92, 0x1fb94, 0x1fba2, 0x1fba4, 17093 0x1fba8, 0x1fbb6, 0x1fbda 17094 ]); 17095 /** 17096 * This table contains to codewords for all symbols. 17097 */ 17098 PDF417Common.CODEWORD_TABLE = Int32Array.from([ 17099 2627, 1819, 2622, 2621, 1813, 1812, 2729, 2724, 2723, 2779, 2774, 2773, 902, 896, 908, 868, 865, 861, 859, 2511, 17100 873, 871, 1780, 835, 2493, 825, 2491, 842, 837, 844, 1764, 1762, 811, 810, 809, 2483, 807, 2482, 806, 2480, 815, 17101 814, 813, 812, 2484, 817, 816, 1745, 1744, 1742, 1746, 2655, 2637, 2635, 2626, 2625, 2623, 2628, 1820, 2752, 17102 2739, 2737, 2728, 2727, 2725, 2730, 2785, 2783, 2778, 2777, 2775, 2780, 787, 781, 747, 739, 736, 2413, 754, 752, 17103 1719, 692, 689, 681, 2371, 678, 2369, 700, 697, 694, 703, 1688, 1686, 642, 638, 2343, 631, 2341, 627, 2338, 651, 17104 646, 643, 2345, 654, 652, 1652, 1650, 1647, 1654, 601, 599, 2322, 596, 2321, 594, 2319, 2317, 611, 610, 608, 606, 17105 2324, 603, 2323, 615, 614, 612, 1617, 1616, 1614, 1612, 616, 1619, 1618, 2575, 2538, 2536, 905, 901, 898, 909, 17106 2509, 2507, 2504, 870, 867, 864, 860, 2512, 875, 872, 1781, 2490, 2489, 2487, 2485, 1748, 836, 834, 832, 830, 17107 2494, 827, 2492, 843, 841, 839, 845, 1765, 1763, 2701, 2676, 2674, 2653, 2648, 2656, 2634, 2633, 2631, 2629, 17108 1821, 2638, 2636, 2770, 2763, 2761, 2750, 2745, 2753, 2736, 2735, 2733, 2731, 1848, 2740, 2738, 2786, 2784, 591, 17109 588, 576, 569, 566, 2296, 1590, 537, 534, 526, 2276, 522, 2274, 545, 542, 539, 548, 1572, 1570, 481, 2245, 466, 17110 2242, 462, 2239, 492, 485, 482, 2249, 496, 494, 1534, 1531, 1528, 1538, 413, 2196, 406, 2191, 2188, 425, 419, 17111 2202, 415, 2199, 432, 430, 427, 1472, 1467, 1464, 433, 1476, 1474, 368, 367, 2160, 365, 2159, 362, 2157, 2155, 17112 2152, 378, 377, 375, 2166, 372, 2165, 369, 2162, 383, 381, 379, 2168, 1419, 1418, 1416, 1414, 385, 1411, 384, 17113 1423, 1422, 1420, 1424, 2461, 802, 2441, 2439, 790, 786, 783, 794, 2409, 2406, 2403, 750, 742, 738, 2414, 756, 17114 753, 1720, 2367, 2365, 2362, 2359, 1663, 693, 691, 684, 2373, 680, 2370, 702, 699, 696, 704, 1690, 1687, 2337, 17115 2336, 2334, 2332, 1624, 2329, 1622, 640, 637, 2344, 634, 2342, 630, 2340, 650, 648, 645, 2346, 655, 653, 1653, 17116 1651, 1649, 1655, 2612, 2597, 2595, 2571, 2568, 2565, 2576, 2534, 2529, 2526, 1787, 2540, 2537, 907, 904, 900, 17117 910, 2503, 2502, 2500, 2498, 1768, 2495, 1767, 2510, 2508, 2506, 869, 866, 863, 2513, 876, 874, 1782, 2720, 2713, 17118 2711, 2697, 2694, 2691, 2702, 2672, 2670, 2664, 1828, 2678, 2675, 2647, 2646, 2644, 2642, 1823, 2639, 1822, 2654, 17119 2652, 2650, 2657, 2771, 1855, 2765, 2762, 1850, 1849, 2751, 2749, 2747, 2754, 353, 2148, 344, 342, 336, 2142, 17120 332, 2140, 345, 1375, 1373, 306, 2130, 299, 2128, 295, 2125, 319, 314, 311, 2132, 1354, 1352, 1349, 1356, 262, 17121 257, 2101, 253, 2096, 2093, 274, 273, 267, 2107, 263, 2104, 280, 278, 275, 1316, 1311, 1308, 1320, 1318, 2052, 17122 202, 2050, 2044, 2040, 219, 2063, 212, 2060, 208, 2055, 224, 221, 2066, 1260, 1258, 1252, 231, 1248, 229, 1266, 17123 1264, 1261, 1268, 155, 1998, 153, 1996, 1994, 1991, 1988, 165, 164, 2007, 162, 2006, 159, 2003, 2000, 172, 171, 17124 169, 2012, 166, 2010, 1186, 1184, 1182, 1179, 175, 1176, 173, 1192, 1191, 1189, 1187, 176, 1194, 1193, 2313, 17125 2307, 2305, 592, 589, 2294, 2292, 2289, 578, 572, 568, 2297, 580, 1591, 2272, 2267, 2264, 1547, 538, 536, 529, 17126 2278, 525, 2275, 547, 544, 541, 1574, 1571, 2237, 2235, 2229, 1493, 2225, 1489, 478, 2247, 470, 2244, 465, 2241, 17127 493, 488, 484, 2250, 498, 495, 1536, 1533, 1530, 1539, 2187, 2186, 2184, 2182, 1432, 2179, 1430, 2176, 1427, 414, 17128 412, 2197, 409, 2195, 405, 2193, 2190, 426, 424, 421, 2203, 418, 2201, 431, 429, 1473, 1471, 1469, 1466, 434, 17129 1477, 1475, 2478, 2472, 2470, 2459, 2457, 2454, 2462, 803, 2437, 2432, 2429, 1726, 2443, 2440, 792, 789, 785, 17130 2401, 2399, 2393, 1702, 2389, 1699, 2411, 2408, 2405, 745, 741, 2415, 758, 755, 1721, 2358, 2357, 2355, 2353, 17131 1661, 2350, 1660, 2347, 1657, 2368, 2366, 2364, 2361, 1666, 690, 687, 2374, 683, 2372, 701, 698, 705, 1691, 1689, 17132 2619, 2617, 2610, 2608, 2605, 2613, 2593, 2588, 2585, 1803, 2599, 2596, 2563, 2561, 2555, 1797, 2551, 1795, 2573, 17133 2570, 2567, 2577, 2525, 2524, 2522, 2520, 1786, 2517, 1785, 2514, 1783, 2535, 2533, 2531, 2528, 1788, 2541, 2539, 17134 906, 903, 911, 2721, 1844, 2715, 2712, 1838, 1836, 2699, 2696, 2693, 2703, 1827, 1826, 1824, 2673, 2671, 2669, 17135 2666, 1829, 2679, 2677, 1858, 1857, 2772, 1854, 1853, 1851, 1856, 2766, 2764, 143, 1987, 139, 1986, 135, 133, 17136 131, 1984, 128, 1983, 125, 1981, 138, 137, 136, 1985, 1133, 1132, 1130, 112, 110, 1974, 107, 1973, 104, 1971, 17137 1969, 122, 121, 119, 117, 1977, 114, 1976, 124, 1115, 1114, 1112, 1110, 1117, 1116, 84, 83, 1953, 81, 1952, 78, 17138 1950, 1948, 1945, 94, 93, 91, 1959, 88, 1958, 85, 1955, 99, 97, 95, 1961, 1086, 1085, 1083, 1081, 1078, 100, 17139 1090, 1089, 1087, 1091, 49, 47, 1917, 44, 1915, 1913, 1910, 1907, 59, 1926, 56, 1925, 53, 1922, 1919, 66, 64, 17140 1931, 61, 1929, 1042, 1040, 1038, 71, 1035, 70, 1032, 68, 1048, 1047, 1045, 1043, 1050, 1049, 12, 10, 1869, 1867, 17141 1864, 1861, 21, 1880, 19, 1877, 1874, 1871, 28, 1888, 25, 1886, 22, 1883, 982, 980, 977, 974, 32, 30, 991, 989, 17142 987, 984, 34, 995, 994, 992, 2151, 2150, 2147, 2146, 2144, 356, 355, 354, 2149, 2139, 2138, 2136, 2134, 1359, 17143 343, 341, 338, 2143, 335, 2141, 348, 347, 346, 1376, 1374, 2124, 2123, 2121, 2119, 1326, 2116, 1324, 310, 308, 17144 305, 2131, 302, 2129, 298, 2127, 320, 318, 316, 313, 2133, 322, 321, 1355, 1353, 1351, 1357, 2092, 2091, 2089, 17145 2087, 1276, 2084, 1274, 2081, 1271, 259, 2102, 256, 2100, 252, 2098, 2095, 272, 269, 2108, 266, 2106, 281, 279, 17146 277, 1317, 1315, 1313, 1310, 282, 1321, 1319, 2039, 2037, 2035, 2032, 1203, 2029, 1200, 1197, 207, 2053, 205, 17147 2051, 201, 2049, 2046, 2043, 220, 218, 2064, 215, 2062, 211, 2059, 228, 226, 223, 2069, 1259, 1257, 1254, 232, 17148 1251, 230, 1267, 1265, 1263, 2316, 2315, 2312, 2311, 2309, 2314, 2304, 2303, 2301, 2299, 1593, 2308, 2306, 590, 17149 2288, 2287, 2285, 2283, 1578, 2280, 1577, 2295, 2293, 2291, 579, 577, 574, 571, 2298, 582, 581, 1592, 2263, 2262, 17150 2260, 2258, 1545, 2255, 1544, 2252, 1541, 2273, 2271, 2269, 2266, 1550, 535, 532, 2279, 528, 2277, 546, 543, 549, 17151 1575, 1573, 2224, 2222, 2220, 1486, 2217, 1485, 2214, 1482, 1479, 2238, 2236, 2234, 2231, 1496, 2228, 1492, 480, 17152 477, 2248, 473, 2246, 469, 2243, 490, 487, 2251, 497, 1537, 1535, 1532, 2477, 2476, 2474, 2479, 2469, 2468, 2466, 17153 2464, 1730, 2473, 2471, 2453, 2452, 2450, 2448, 1729, 2445, 1728, 2460, 2458, 2456, 2463, 805, 804, 2428, 2427, 17154 2425, 2423, 1725, 2420, 1724, 2417, 1722, 2438, 2436, 2434, 2431, 1727, 2444, 2442, 793, 791, 788, 795, 2388, 17155 2386, 2384, 1697, 2381, 1696, 2378, 1694, 1692, 2402, 2400, 2398, 2395, 1703, 2392, 1701, 2412, 2410, 2407, 751, 17156 748, 744, 2416, 759, 757, 1807, 2620, 2618, 1806, 1805, 2611, 2609, 2607, 2614, 1802, 1801, 1799, 2594, 2592, 17157 2590, 2587, 1804, 2600, 2598, 1794, 1793, 1791, 1789, 2564, 2562, 2560, 2557, 1798, 2554, 1796, 2574, 2572, 2569, 17158 2578, 1847, 1846, 2722, 1843, 1842, 1840, 1845, 2716, 2714, 1835, 1834, 1832, 1830, 1839, 1837, 2700, 2698, 2695, 17159 2704, 1817, 1811, 1810, 897, 862, 1777, 829, 826, 838, 1760, 1758, 808, 2481, 1741, 1740, 1738, 1743, 2624, 1818, 17160 2726, 2776, 782, 740, 737, 1715, 686, 679, 695, 1682, 1680, 639, 628, 2339, 647, 644, 1645, 1643, 1640, 1648, 17161 602, 600, 597, 595, 2320, 593, 2318, 609, 607, 604, 1611, 1610, 1608, 1606, 613, 1615, 1613, 2328, 926, 924, 892, 17162 886, 899, 857, 850, 2505, 1778, 824, 823, 821, 819, 2488, 818, 2486, 833, 831, 828, 840, 1761, 1759, 2649, 2632, 17163 2630, 2746, 2734, 2732, 2782, 2781, 570, 567, 1587, 531, 527, 523, 540, 1566, 1564, 476, 467, 463, 2240, 486, 17164 483, 1524, 1521, 1518, 1529, 411, 403, 2192, 399, 2189, 423, 416, 1462, 1457, 1454, 428, 1468, 1465, 2210, 366, 17165 363, 2158, 360, 2156, 357, 2153, 376, 373, 370, 2163, 1410, 1409, 1407, 1405, 382, 1402, 380, 1417, 1415, 1412, 17166 1421, 2175, 2174, 777, 774, 771, 784, 732, 725, 722, 2404, 743, 1716, 676, 674, 668, 2363, 665, 2360, 685, 1684, 17167 1681, 626, 624, 622, 2335, 620, 2333, 617, 2330, 641, 635, 649, 1646, 1644, 1642, 2566, 928, 925, 2530, 2527, 17168 894, 891, 888, 2501, 2499, 2496, 858, 856, 854, 851, 1779, 2692, 2668, 2665, 2645, 2643, 2640, 2651, 2768, 2759, 17169 2757, 2744, 2743, 2741, 2748, 352, 1382, 340, 337, 333, 1371, 1369, 307, 300, 296, 2126, 315, 312, 1347, 1342, 17170 1350, 261, 258, 250, 2097, 246, 2094, 271, 268, 264, 1306, 1301, 1298, 276, 1312, 1309, 2115, 203, 2048, 195, 17171 2045, 191, 2041, 213, 209, 2056, 1246, 1244, 1238, 225, 1234, 222, 1256, 1253, 1249, 1262, 2080, 2079, 154, 1997, 17172 150, 1995, 147, 1992, 1989, 163, 160, 2004, 156, 2001, 1175, 1174, 1172, 1170, 1167, 170, 1164, 167, 1185, 1183, 17173 1180, 1177, 174, 1190, 1188, 2025, 2024, 2022, 587, 586, 564, 559, 556, 2290, 573, 1588, 520, 518, 512, 2268, 17174 508, 2265, 530, 1568, 1565, 461, 457, 2233, 450, 2230, 446, 2226, 479, 471, 489, 1526, 1523, 1520, 397, 395, 17175 2185, 392, 2183, 389, 2180, 2177, 410, 2194, 402, 422, 1463, 1461, 1459, 1456, 1470, 2455, 799, 2433, 2430, 779, 17176 776, 773, 2397, 2394, 2390, 734, 728, 724, 746, 1717, 2356, 2354, 2351, 2348, 1658, 677, 675, 673, 670, 667, 688, 17177 1685, 1683, 2606, 2589, 2586, 2559, 2556, 2552, 927, 2523, 2521, 2518, 2515, 1784, 2532, 895, 893, 890, 2718, 17178 2709, 2707, 2689, 2687, 2684, 2663, 2662, 2660, 2658, 1825, 2667, 2769, 1852, 2760, 2758, 142, 141, 1139, 1138, 17179 134, 132, 129, 126, 1982, 1129, 1128, 1126, 1131, 113, 111, 108, 105, 1972, 101, 1970, 120, 118, 115, 1109, 1108, 17180 1106, 1104, 123, 1113, 1111, 82, 79, 1951, 75, 1949, 72, 1946, 92, 89, 86, 1956, 1077, 1076, 1074, 1072, 98, 17181 1069, 96, 1084, 1082, 1079, 1088, 1968, 1967, 48, 45, 1916, 42, 1914, 39, 1911, 1908, 60, 57, 54, 1923, 50, 1920, 17182 1031, 1030, 1028, 1026, 67, 1023, 65, 1020, 62, 1041, 1039, 1036, 1033, 69, 1046, 1044, 1944, 1943, 1941, 11, 9, 17183 1868, 7, 1865, 1862, 1859, 20, 1878, 16, 1875, 13, 1872, 970, 968, 966, 963, 29, 960, 26, 23, 983, 981, 978, 975, 17184 33, 971, 31, 990, 988, 985, 1906, 1904, 1902, 993, 351, 2145, 1383, 331, 330, 328, 326, 2137, 323, 2135, 339, 17185 1372, 1370, 294, 293, 291, 289, 2122, 286, 2120, 283, 2117, 309, 303, 317, 1348, 1346, 1344, 245, 244, 242, 2090, 17186 239, 2088, 236, 2085, 2082, 260, 2099, 249, 270, 1307, 1305, 1303, 1300, 1314, 189, 2038, 186, 2036, 183, 2033, 17187 2030, 2026, 206, 198, 2047, 194, 216, 1247, 1245, 1243, 1240, 227, 1237, 1255, 2310, 2302, 2300, 2286, 2284, 17188 2281, 565, 563, 561, 558, 575, 1589, 2261, 2259, 2256, 2253, 1542, 521, 519, 517, 514, 2270, 511, 533, 1569, 17189 1567, 2223, 2221, 2218, 2215, 1483, 2211, 1480, 459, 456, 453, 2232, 449, 474, 491, 1527, 1525, 1522, 2475, 2467, 17190 2465, 2451, 2449, 2446, 801, 800, 2426, 2424, 2421, 2418, 1723, 2435, 780, 778, 775, 2387, 2385, 2382, 2379, 17191 1695, 2375, 1693, 2396, 735, 733, 730, 727, 749, 1718, 2616, 2615, 2604, 2603, 2601, 2584, 2583, 2581, 2579, 17192 1800, 2591, 2550, 2549, 2547, 2545, 1792, 2542, 1790, 2558, 929, 2719, 1841, 2710, 2708, 1833, 1831, 2690, 2688, 17193 2686, 1815, 1809, 1808, 1774, 1756, 1754, 1737, 1736, 1734, 1739, 1816, 1711, 1676, 1674, 633, 629, 1638, 1636, 17194 1633, 1641, 598, 1605, 1604, 1602, 1600, 605, 1609, 1607, 2327, 887, 853, 1775, 822, 820, 1757, 1755, 1584, 524, 17195 1560, 1558, 468, 464, 1514, 1511, 1508, 1519, 408, 404, 400, 1452, 1447, 1444, 417, 1458, 1455, 2208, 364, 361, 17196 358, 2154, 1401, 1400, 1398, 1396, 374, 1393, 371, 1408, 1406, 1403, 1413, 2173, 2172, 772, 726, 723, 1712, 672, 17197 669, 666, 682, 1678, 1675, 625, 623, 621, 618, 2331, 636, 632, 1639, 1637, 1635, 920, 918, 884, 880, 889, 849, 17198 848, 847, 846, 2497, 855, 852, 1776, 2641, 2742, 2787, 1380, 334, 1367, 1365, 301, 297, 1340, 1338, 1335, 1343, 17199 255, 251, 247, 1296, 1291, 1288, 265, 1302, 1299, 2113, 204, 196, 192, 2042, 1232, 1230, 1224, 214, 1220, 210, 17200 1242, 1239, 1235, 1250, 2077, 2075, 151, 148, 1993, 144, 1990, 1163, 1162, 1160, 1158, 1155, 161, 1152, 157, 17201 1173, 1171, 1168, 1165, 168, 1181, 1178, 2021, 2020, 2018, 2023, 585, 560, 557, 1585, 516, 509, 1562, 1559, 458, 17202 447, 2227, 472, 1516, 1513, 1510, 398, 396, 393, 390, 2181, 386, 2178, 407, 1453, 1451, 1449, 1446, 420, 1460, 17203 2209, 769, 764, 720, 712, 2391, 729, 1713, 664, 663, 661, 659, 2352, 656, 2349, 671, 1679, 1677, 2553, 922, 919, 17204 2519, 2516, 885, 883, 881, 2685, 2661, 2659, 2767, 2756, 2755, 140, 1137, 1136, 130, 127, 1125, 1124, 1122, 1127, 17205 109, 106, 102, 1103, 1102, 1100, 1098, 116, 1107, 1105, 1980, 80, 76, 73, 1947, 1068, 1067, 1065, 1063, 90, 1060, 17206 87, 1075, 1073, 1070, 1080, 1966, 1965, 46, 43, 40, 1912, 36, 1909, 1019, 1018, 1016, 1014, 58, 1011, 55, 1008, 17207 51, 1029, 1027, 1024, 1021, 63, 1037, 1034, 1940, 1939, 1937, 1942, 8, 1866, 4, 1863, 1, 1860, 956, 954, 952, 17208 949, 946, 17, 14, 969, 967, 964, 961, 27, 957, 24, 979, 976, 972, 1901, 1900, 1898, 1896, 986, 1905, 1903, 350, 17209 349, 1381, 329, 327, 324, 1368, 1366, 292, 290, 287, 284, 2118, 304, 1341, 1339, 1337, 1345, 243, 240, 237, 2086, 17210 233, 2083, 254, 1297, 1295, 1293, 1290, 1304, 2114, 190, 187, 184, 2034, 180, 2031, 177, 2027, 199, 1233, 1231, 17211 1229, 1226, 217, 1223, 1241, 2078, 2076, 584, 555, 554, 552, 550, 2282, 562, 1586, 507, 506, 504, 502, 2257, 499, 17212 2254, 515, 1563, 1561, 445, 443, 441, 2219, 438, 2216, 435, 2212, 460, 454, 475, 1517, 1515, 1512, 2447, 798, 17213 797, 2422, 2419, 770, 768, 766, 2383, 2380, 2376, 721, 719, 717, 714, 731, 1714, 2602, 2582, 2580, 2548, 2546, 17214 2543, 923, 921, 2717, 2706, 2705, 2683, 2682, 2680, 1771, 1752, 1750, 1733, 1732, 1731, 1735, 1814, 1707, 1670, 17215 1668, 1631, 1629, 1626, 1634, 1599, 1598, 1596, 1594, 1603, 1601, 2326, 1772, 1753, 1751, 1581, 1554, 1552, 1504, 17216 1501, 1498, 1509, 1442, 1437, 1434, 401, 1448, 1445, 2206, 1392, 1391, 1389, 1387, 1384, 359, 1399, 1397, 1394, 17217 1404, 2171, 2170, 1708, 1672, 1669, 619, 1632, 1630, 1628, 1773, 1378, 1363, 1361, 1333, 1328, 1336, 1286, 1281, 17218 1278, 248, 1292, 1289, 2111, 1218, 1216, 1210, 197, 1206, 193, 1228, 1225, 1221, 1236, 2073, 2071, 1151, 1150, 17219 1148, 1146, 152, 1143, 149, 1140, 145, 1161, 1159, 1156, 1153, 158, 1169, 1166, 2017, 2016, 2014, 2019, 1582, 17220 510, 1556, 1553, 452, 448, 1506, 1500, 394, 391, 387, 1443, 1441, 1439, 1436, 1450, 2207, 765, 716, 713, 1709, 17221 662, 660, 657, 1673, 1671, 916, 914, 879, 878, 877, 882, 1135, 1134, 1121, 1120, 1118, 1123, 1097, 1096, 1094, 17222 1092, 103, 1101, 1099, 1979, 1059, 1058, 1056, 1054, 77, 1051, 74, 1066, 1064, 1061, 1071, 1964, 1963, 1007, 17223 1006, 1004, 1002, 999, 41, 996, 37, 1017, 1015, 1012, 1009, 52, 1025, 1022, 1936, 1935, 1933, 1938, 942, 940, 17224 938, 935, 932, 5, 2, 955, 953, 950, 947, 18, 943, 15, 965, 962, 958, 1895, 1894, 1892, 1890, 973, 1899, 1897, 17225 1379, 325, 1364, 1362, 288, 285, 1334, 1332, 1330, 241, 238, 234, 1287, 1285, 1283, 1280, 1294, 2112, 188, 185, 17226 181, 178, 2028, 1219, 1217, 1215, 1212, 200, 1209, 1227, 2074, 2072, 583, 553, 551, 1583, 505, 503, 500, 513, 17227 1557, 1555, 444, 442, 439, 436, 2213, 455, 451, 1507, 1505, 1502, 796, 763, 762, 760, 767, 711, 710, 708, 706, 17228 2377, 718, 715, 1710, 2544, 917, 915, 2681, 1627, 1597, 1595, 2325, 1769, 1749, 1747, 1499, 1438, 1435, 2204, 17229 1390, 1388, 1385, 1395, 2169, 2167, 1704, 1665, 1662, 1625, 1623, 1620, 1770, 1329, 1282, 1279, 2109, 1214, 1207, 17230 1222, 2068, 2065, 1149, 1147, 1144, 1141, 146, 1157, 1154, 2013, 2011, 2008, 2015, 1579, 1549, 1546, 1495, 1487, 17231 1433, 1431, 1428, 1425, 388, 1440, 2205, 1705, 658, 1667, 1664, 1119, 1095, 1093, 1978, 1057, 1055, 1052, 1062, 17232 1962, 1960, 1005, 1003, 1000, 997, 38, 1013, 1010, 1932, 1930, 1927, 1934, 941, 939, 936, 933, 6, 930, 3, 951, 17233 948, 944, 1889, 1887, 1884, 1881, 959, 1893, 1891, 35, 1377, 1360, 1358, 1327, 1325, 1322, 1331, 1277, 1275, 17234 1272, 1269, 235, 1284, 2110, 1205, 1204, 1201, 1198, 182, 1195, 179, 1213, 2070, 2067, 1580, 501, 1551, 1548, 17235 440, 437, 1497, 1494, 1490, 1503, 761, 709, 707, 1706, 913, 912, 2198, 1386, 2164, 2161, 1621, 1766, 2103, 1208, 17236 2058, 2054, 1145, 1142, 2005, 2002, 1999, 2009, 1488, 1429, 1426, 2200, 1698, 1659, 1656, 1975, 1053, 1957, 1954, 17237 1001, 998, 1924, 1921, 1918, 1928, 937, 934, 931, 1879, 1876, 1873, 1870, 945, 1885, 1882, 1323, 1273, 1270, 17238 2105, 1202, 1199, 1196, 1211, 2061, 2057, 1576, 1543, 1540, 1484, 1481, 1478, 1491, 1700 17239 ]); 17240 17241 /* 17242 * Copyright 2007 ZXing authors 17243 * 17244 * Licensed under the Apache License, Version 2.0 (the "License"); 17245 * you may not use this file except in compliance with the License. 17246 * You may obtain a copy of the License at 17247 * 17248 * http://www.apache.org/licenses/LICENSE-2.0 17249 * 17250 * Unless required by applicable law or agreed to in writing, software 17251 * distributed under the License is distributed on an "AS IS" BASIS, 17252 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17253 * See the License for the specific language governing permissions and 17254 * limitations under the License. 17255 */ 17256 // import java.util.List; 17257 /** 17258 * @author Guenther Grau 17259 */ 17260 /*public final*/ class PDF417DetectorResult { 17261 constructor(bits, points) { 17262 this.bits = bits; 17263 this.points = points; 17264 } 17265 getBits() { 17266 return this.bits; 17267 } 17268 getPoints() { 17269 return this.points; 17270 } 17271 } 17272 17273 /* 17274 * Copyright 2009 ZXing authors 17275 * 17276 * Licensed under the Apache License, Version 2.0 (the "License"); 17277 * you may not use this file except in compliance with the License. 17278 * You may obtain a copy of the License at 17279 * 17280 * http://www.apache.org/licenses/LICENSE-2.0 17281 * 17282 * Unless required by applicable law or agreed to in writing, software 17283 * distributed under the License is distributed on an "AS IS" BASIS, 17284 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17285 * See the License for the specific language governing permissions and 17286 * limitations under the License. 17287 */ 17288 // import
17288java.util.ArrayList; 17289 // import java.util.Arrays; 17290 // import java.util.List; 17291 // import java.util.Map; 17292 /** 17293 * <p>Encapsulates logic that can detect a PDF417 Code in an image, even if the 17294 * PDF417 Code is rotated or skewed, or partially obscured.</p> 17295 * 17296 * @author SITA Lab ([email protected]) 17297 * @author [email protected] (Daniel Switkin) 17298 * @author Guenther Grau 17299 */ 17300 /*public*/ /*final*/
vendor: 14,616 bytes, lines 17300-17594
17300 class Detector { 17301 /** 17302 * <p>Detects a PDF417 Code in an image. Only checks 0 and 180 degree rotations.</p> 17303 * 17304 * @param image barcode image to decode 17305 * @param hints optional hints to detector 17306 * @param multiple if true, then the image is searched for multiple codes. If false, then at most one code will 17307 * be found and returned 17308 * @return {@link PDF417DetectorResult} encapsulating results of detecting a PDF417 code 17309 * @throws NotFoundException if no PDF417 Code can be found 17310 */ 17311 static detectMultiple(image, hints, multiple) { 17312 // TODO detection improvement, tryHarder could try several different luminance thresholds/blackpoints or even 17313 // different binarizers 17314 // boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER); 17315 let bitMatrix = image.getBlackMatrix(); 17316 let barcodeCoordinates = Detector.detect(multiple, bitMatrix); 17317 if (!barcodeCoordinates.length) { 17318 bitMatrix = bitMatrix.clone(); 17319 bitMatrix.rotate180(); 17320 barcodeCoordinates = Detector.detect(multiple, bitMatrix); 17321 } 17322 return new PDF417DetectorResult(bitMatrix, barcodeCoordinates); 17323 } 17324 /** 17325 * Detects PDF417 codes in an image. Only checks 0 degree rotation 17326 * @param multiple if true, then the image is searched for multiple codes. If false, then at most one code will 17327 * be found and returned 17328 * @param bitMatrix bit matrix to detect barcodes in 17329 * @return List of ResultPoint arrays containing the coordinates of found barcodes 17330 */ 17331 static detect(multiple, bitMatrix) { 17332 const barcodeCoordinates = new Array(); 17333 let row = 0; 17334 let column = 0; 17335 let foundBarcodeInRow = false; 17336 while (row < bitMatrix.getHeight()) { 17337 const vertices = Detector.findVertices(bitMatrix, row, column); 17338 if (vertices[0] == null && vertices[3] == null) { 17339 if (!foundBarcodeInRow) { 17340 // we didn't find any barcode so that's the end of searching 17341 break; 17342 } 17343 // we didn't find a barcode starting at the given column and row. Try again from the first column and slightly 17344 // below the lowest barcode we found so far. 17345 foundBarcodeInRow = false; 17346 column = 0; 17347 for (const barcodeCoordinate of barcodeCoordinates) { 17348 if (barcodeCoordinate[1] != null) { 17349 row = Math.trunc(Math.max(row, barcodeCoordinate[1].getY())); 17350 } 17351 if (barcodeCoordinate[3] != null) { 17352 row = Math.max(row, Math.trunc(barcodeCoordinate[3].getY())); 17353 } 17354 } 17355 row += Detector.ROW_STEP; 17356 continue; 17357 } 17358 foundBarcodeInRow = true; 17359 barcodeCoordinates.push(vertices); 17360 if (!multiple) { 17361 break; 17362 } 17363 // if we didn't find a right row indicator column, then continue the search for the next barcode after the 17364 // start pattern of the barcode just found. 17365 if (vertices[2] != null) { 17366 column = Math.trunc(vertices[2].getX()); 17367 row = Math.trunc(vertices[2].getY()); 17368 } 17369 else { 17370 column = Math.trunc(vertices[4].getX()); 17371 row = Math.trunc(vertices[4].getY()); 17372 } 17373 } 17374 return barcodeCoordinates; 17375 } 17376 /** 17377 * Locate the vertices and the codewords area of a black blob using the Start 17378 * and Stop patterns as locators. 17379 * 17380 * @param matrix the scanned barcode image. 17381 * @return an array containing the vertices: 17382 * vertices[0] x, y top left barcode 17383 * vertices[1] x, y bottom left barcode 17384 * vertices[2] x, y top right barcode 17385 * vertices[3] x, y bottom right barcode 17386 * vertices[4] x, y top left codeword area 17387 * vertices[5] x, y bottom left codeword area 17388 * vertices[6] x, y top right codeword area 17389 * vertices[7] x, y bottom right codeword area 17390 */ 17391 static findVertices(matrix, startRow, startColumn) { 17392 const height = matrix.getHeight(); 17393 const width = matrix.getWidth(); 17394 // const result = new ResultPoint[8]; 17395 const result = new Array(8); 17396 Detector.copyToResult(result, Detector.findRowsWithPattern(matrix, height, width, startRow, startColumn, Detector.START_PATTERN), Detector.INDEXES_START_PATTERN); 17397 if (result[4] != null) { 17398 startColumn = Math.trunc(result[4].getX()); 17399 startRow = Math.trunc(result[4].getY()); 17400 } 17401 Detector.copyToResult(result, Detector.findRowsWithPattern(matrix, height, width, startRow, startColumn, Detector.STOP_PATTERN), Detector.INDEXES_STOP_PATTERN); 17402 return result; 17403 } 17404 static copyToResult(result, tmpResult, destinationIndexes) { 17405 for (let i = 0; i < destinationIndexes.length; i++) { 17406 result[destinationIndexes[i]] = tmpResult[i]; 17407 } 17408 } 17409 static findRowsWithPattern(matrix, height, width, startRow, startColumn, pattern) { 17410 // const result = new ResultPoint[4]; 17411 const result = new Array(4); 17412 let found = false; 17413 const counters = new Int32Array(pattern.length); 17414 for (; startRow < height; startRow += Detector.ROW_STEP) { 17415 let loc = Detector.findGuardPattern(matrix, startColumn, startRow, width, false, pattern, counters); 17416 if (loc != null) { 17417 while (startRow > 0) { 17418 const previousRowLoc = Detector.findGuardPattern(matrix, startColumn, --startRow, width, false, pattern, counters); 17419 if (previousRowLoc != null) { 17420 loc = previousRowLoc; 17421 } 17422 else { 17423 startRow++; 17424 break; 17425 } 17426 } 17427 result[0] = new ResultPoint(loc[0], startRow); 17428 result[1] = new ResultPoint(loc[1], startRow); 17429 found = true; 17430 break; 17431 } 17432 } 17433 let stopRow = startRow + 1; 17434 // Last row of the current symbol that contains pattern 17435 if (found) { 17436 let skippedRowCount = 0; 17437 let previousRowLoc = Int32Array.from([Math.trunc(result[0].getX()), Math.trunc(result[1].getX())]); 17438 for (; stopRow < height; stopRow++) { 17439 const loc = Detector.findGuardPattern(matrix, previousRowLoc[0], stopRow, width, false, pattern, counters); 17440 // a found pattern is only considered to belong to the same barcode if the start and end positions 17441 // don't differ too much. Pattern drift should be not bigger than two for consecutive rows. With 17442 // a higher number of skipped rows drift could be larger. To keep it simple for now, we allow a slightly 17443 // larger drift and don't check for skipped rows. 17444 if (loc != null && 17445 Math.abs(previousRowLoc[0] - loc[0]) < Detector.MAX_PATTERN_DRIFT && 17446 Math.abs(previousRowLoc[1] - loc[1]) < Detector.MAX_PATTERN_DRIFT) { 17447 previousRowLoc = loc; 17448 skippedRowCount = 0; 17449 } 17450 else { 17451 if (skippedRowCount > Detector.SKIPPED_ROW_COUNT_MAX) { 17452 break; 17453 } 17454 else { 17455 skippedRowCount++; 17456 } 17457 } 17458 } 17459 stopRow -= skippedRowCount + 1; 17460 result[2] = new ResultPoint(previousRowLoc[0], stopRow); 17461 result[3] = new ResultPoint(previousRowLoc[1], stopRow); 17462 } 17463 if (stopRow - startRow < Detector.BARCODE_MIN_HEIGHT) { 17464 Arrays.fill(result, null); 17465 } 17466 return result; 17467 } 17468 /** 17469 * @param matrix row of black/white values to search 17470 * @param column x position to start search 17471 * @param row y position to start search 17472 * @param width the number of pixels to search on this row 17473 * @param pattern pattern of counts of number of black and white pixels that are 17474 * being searched for as a pattern 17475 * @param counters array of counters, as long as pattern, to re-use 17476 * @return start/end horizontal offset of guard pattern, as an array of two ints. 17477 */ 17478 static findGuardPattern(matrix, column, row, width, whiteFirst, pattern, counters) { 17479 Arrays.fillWithin(counters, 0, counters.length, 0); 17480 let patternStart = column; 17481 let pixelDrift = 0; 17482 // if there are black pixels left of the current pixel shift to the left, but only for MAX_PIXEL_DRIFT pixels 17483 while (matrix.get(patternStart, row) && patternStart > 0 && pixelDrift++ < Detector.MAX_PIXEL_DRIFT) { 17484 patternStart--; 17485 } 17486 let x = patternStart; 17487 let counterPosition = 0; 17488 let patternLength = pattern.length; 17489 for (let isWhite = whiteFirst; x < width; x++) { 17490 let pixel = matrix.get(x, row); 17491 if (pixel !== isWhite) { 17492 counters[counterPosition]++; 17493 } 17494 else { 17495 if (counterPosition === patternLength - 1) { 17496 if (Detector.patternMatchVariance(counters, pattern, Detector.MAX_INDIVIDUAL_VARIANCE) < Detector.MAX_AVG_VARIANCE) { 17497 return new Int32Array([patternStart, x]); 17498 } 17499 patternStart += counters[0] + counters[1]; 17500 System.arraycopy(counters, 2, counters, 0, counterPosition - 1); 17501 counters[counterPosition - 1] = 0; 17502 counters[counterPosition] = 0; 17503 counterPosition--; 17504 } 17505 else { 17506 counterPosition++; 17507 } 17508 counters[counterPosition] = 1; 17509 isWhite = !isWhite; 17510 } 17511 } 17512 if (counterPosition === patternLength - 1 && 17513 Detector.patternMatchVariance(counters, pattern, Detector.MAX_INDIVIDUAL_VARIANCE) < Detector.MAX_AVG_VARIANCE) { 17514 return new Int32Array([patternStart, x - 1]); 17515 } 17516 return null; 17517 } 17518 /** 17519 * Determines how closely a set of observed counts of runs of black/white 17520 * values matches a given target pattern. This is reported as the ratio of 17521 * the total variance from the expected pattern proportions across all 17522 * pattern elements, to the length of the pattern. 17523 * 17524 * @param counters observed counters 17525 * @param pattern expected pattern 17526 * @param maxIndividualVariance The most any counter can differ before we give up 17527 * @return ratio of total variance between counters and pattern compared to total pattern size 17528 */ 17529 static patternMatchVariance(counters, pattern, maxIndividualVariance) { 17530 let numCounters = counters.length; 17531 let total = 0; 17532 let patternLength = 0; 17533 for (let i = 0; i < numCounters; i++) { 17534 total += counters[i]; 17535 patternLength += pattern[i]; 17536 } 17537 if (total < patternLength) { 17538 // If we don't even have one pixel per unit of bar width, assume this 17539 // is too small to reliably match, so fail: 17540 return /*Float.POSITIVE_INFINITY*/ Infinity; 17541 } 17542 // We're going to fake floating-point math in integers. We just need to use more bits. 17543 // Scale up patternLength so that intermediate values below like scaledCounter will have 17544 // more "significant digits". 17545 let unitBarWidth = total / patternLength; 17546 maxIndividualVariance *= unitBarWidth; 17547 let totalVariance = 0.0; 17548 for (let x = 0; x < numCounters; x++) { 17549 let counter = counters[x]; 17550 let scaledPattern = pattern[x] * unitBarWidth; 17551 let variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter; 17552 if (variance > maxIndividualVariance) { 17553 return /*Float.POSITIVE_INFINITY*/ Infinity; 17554 } 17555 totalVariance += variance; 17556 } 17557 return totalVariance / total; 17558 } 17559 } 17560 Detector.INDEXES_START_PATTERN = Int32Array.from([0, 4, 1, 5]); 17561 Detector.INDEXES_STOP_PATTERN = Int32Array.from([6, 2, 7, 3]); 17562 Detector.MAX_AVG_VARIANCE = 0.42; 17563 Detector.MAX_INDIVIDUAL_VARIANCE = 0.8; 17564 // B S B S B S B S Bar/Space pattern 17565 // 11111111 0 1 0 1 0 1 000 17566 Detector.START_PATTERN = Int32Array.from([8, 1, 1, 1, 1, 1, 1, 3]); 17567 // 1111111 0 1 000 1 0 1 00 1 17568 Detector.STOP_PATTERN = Int32Array.from([7, 1, 1, 3, 1, 1, 1, 2, 1]); 17569 Detector.MAX_PIXEL_DRIFT = 3; 17570 Detector.MAX_PATTERN_DRIFT = 5; 17571 // if we set the value too low, then we don't detect the correct height of the bar if the start patterns are damaged. 17572 // if we set the value too high, then we might detect the start pattern from a neighbor barcode. 17573 Detector.SKIPPED_ROW_COUNT_MAX = 25; 17574 // A PDF471 barcode should have at least 3 rows, with each row being >= 3 times the module width. Therefore it should be at least 17575 // 9 pixels tall. To be conservative, we use about half the size to ensure we don't miss it. 17576 Detector.ROW_STEP = 5; 17577 Detector.BARCODE_MIN_HEIGHT = 10; 17578 17579 /* 17580 * Copyright 2012 ZXing authors 17581 * 17582 * Licensed under the Apache License, Version 2.0 (the "License"); 17583 * you may not use this file except in compliance with the License. 17584 * You may obtain a copy of the License at 17585 * 17586 * http://www.apache.org/licenses/LICENSE-2.0 17587 * 17588 * Unless required by applicable law or agreed to in writing, software 17589 * distributed under the License is distributed on an "AS IS" BASIS, 17590 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17591 * See the License for the specific language governing permissions and 17592 * limitations under the License. 17593 */ 17594 /
vendor: 20,053 bytes, lines 17594-18105
17594** 17595 * @author Sean Owen 17596 * @see com.google.zxing.common.reedsolomon.GenericGFPoly 17597 */ 17598 /*final*/ class ModulusPoly { 17599 constructor(field, coefficients) { 17600 if (coefficients.length === 0) { 17601 throw new IllegalArgumentException(); 17602 } 17603 this.field = field; 17604 let coefficientsLength = /*int*/ coefficients.length; 17605 if (coefficientsLength > 1 && coefficients[0] === 0) { 17606 // Leading term must be non-zero for anything except the constant polynomial "0" 17607 let firstNonZero = /*int*/ 1; 17608 while (firstNonZero < coefficientsLength && coefficients[firstNonZero] === 0) { 17609 firstNonZero++; 17610 } 17611 if (firstNonZero === coefficientsLength) { 17612 this.coefficients = new Int32Array([0]); 17613 } 17614 else { 17615 this.coefficients = new Int32Array(coefficientsLength - firstNonZero); 17616 System.arraycopy(coefficients, firstNonZero, this.coefficients, 0, this.coefficients.length); 17617 } 17618 } 17619 else { 17620 this.coefficients = coefficients; 17621 } 17622 } 17623 getCoefficients() { 17624 return this.coefficients; 17625 } 17626 /** 17627 * @return degree of this polynomial 17628 */ 17629 getDegree() { 17630 return this.coefficients.length - 1; 17631 } 17632 /** 17633 * @return true iff this polynomial is the monomial "0" 17634 */ 17635 isZero() { 17636 return this.coefficients[0] === 0; 17637 } 17638 /** 17639 * @return coefficient of x^degree term in this polynomial 17640 */ 17641 getCoefficient(degree) { 17642 return this.coefficients[this.coefficients.length - 1 - degree]; 17643 } 17644 /** 17645 * @return evaluation of this polynomial at a given point 17646 */ 17647 evaluateAt(a) { 17648 if (a === 0) { 17649 // Just return the x^0 coefficient 17650 return this.getCoefficient(0); 17651 } 17652 if (a === 1) { 17653 // Just the sum of the coefficients 17654 let sum = /*int*/ 0; 17655 for (let coefficient /*int*/ of this.coefficients) { 17656 sum = this.field.add(sum, coefficient); 17657 } 17658 return sum; 17659 } 17660 let result = /*int*/ this.coefficients[0]; 17661 let size = /*int*/ this.coefficients.length; 17662 for (let i /*int*/ = 1; i < size; i++) { 17663 result = this.field.add(this.field.multiply(a, result), this.coefficients[i]); 17664 } 17665 return result; 17666 } 17667 add(other) { 17668 if (!this.field.equals(other.field)) { 17669 throw new IllegalArgumentException('ModulusPolys do not have same ModulusGF field'); 17670 } 17671 if (this.isZero()) { 17672 return other; 17673 } 17674 if (other.isZero()) { 17675 return this; 17676 } 17677 let smallerCoefficients = this.coefficients; 17678 let largerCoefficients = other.coefficients; 17679 if (smallerCoefficients.length > largerCoefficients.length) { 17680 let temp = smallerCoefficients; 17681 smallerCoefficients = largerCoefficients; 17682 largerCoefficients = temp; 17683 } 17684 let sumDiff = new Int32Array(largerCoefficients.length); 17685 let lengthDiff = /*int*/ largerCoefficients.length - smallerCoefficients.length; 17686 // Copy high-order terms only found in higher-degree polynomial's coefficients 17687 System.arraycopy(largerCoefficients, 0, sumDiff, 0, lengthDiff); 17688 for (let i /*int*/ = lengthDiff; i < largerCoefficients.length; i++) { 17689 sumDiff[i] = this.field.add(smallerCoefficients[i - lengthDiff], largerCoefficients[i]); 17690 } 17691 return new ModulusPoly(this.field, sumDiff); 17692 } 17693 subtract(other) { 17694 if (!this.field.equals(other.field)) { 17695 throw new IllegalArgumentException('ModulusPolys do not have same ModulusGF field'); 17696 } 17697 if (other.isZero()) { 17698 return this; 17699 } 17700 return this.add(other.negative()); 17701 } 17702 multiply(other) { 17703 if (other instanceof ModulusPoly) { 17704 return this.multiplyOther(other); 17705 } 17706 return this.multiplyScalar(other); 17707 } 17708 multiplyOther(other) { 17709 if (!this.field.equals(other.field)) { 17710 throw new IllegalArgumentException('ModulusPolys do not have same ModulusGF field'); 17711 } 17712 if (this.isZero() || other.isZero()) { 17713 // return this.field.getZero(); 17714 return new ModulusPoly(this.field, new Int32Array([0])); 17715 } 17716 let aCoefficients = this.coefficients; 17717 let aLength = /*int*/ aCoefficients.length; 17718 let bCoefficients = other.coefficients; 17719 let bLength = /*int*/ bCoefficients.length; 17720 let product = new Int32Array(aLength + bLength - 1); 17721 for (let i /*int*/ = 0; i < aLength; i++) { 17722 let aCoeff = /*int*/ aCoefficients[i]; 17723 for (let j /*int*/ = 0; j < bLength; j++) { 17724 product[i + j] = this.field.add(product[i + j], this.field.multiply(aCoeff, bCoefficients[j])); 17725 } 17726 } 17727 return new ModulusPoly(this.field, product); 17728 } 17729 negative() { 17730 let size = /*int*/ this.coefficients.length; 17731 let negativeCoefficients = new Int32Array(size); 17732 for (let i /*int*/ = 0; i < size; i++) { 17733 negativeCoefficients[i] = this.field.subtract(0, this.coefficients[i]); 17734 } 17735 return new ModulusPoly(this.field, negativeCoefficients); 17736 } 17737 multiplyScalar(scalar) { 17738 if (scalar === 0) { 17739 return new ModulusPoly(this.field, new Int32Array([0])); 17740 } 17741 if (scalar === 1) { 17742 return this; 17743 } 17744 let size = /*int*/ this.coefficients.length; 17745 let product = new Int32Array(size); 17746 for (let i /*int*/ = 0; i < size; i++) { 17747 product[i] = this.field.multiply(this.coefficients[i], scalar); 17748 } 17749 return new ModulusPoly(this.field, product); 17750 } 17751 multiplyByMonomial(degree, coefficient) { 17752 if (degree < 0) { 17753 throw new IllegalArgumentException(); 17754 } 17755 if (coefficient === 0) { 17756 return new ModulusPoly(this.field, new Int32Array([0])); 17757 } 17758 let size = /*int*/ this.coefficients.length; 17759 let product = new Int32Array(size + degree); 17760 for (let i /*int*/ = 0; i < size; i++) { 17761 product[i] = this.field.multiply(this.coefficients[i], coefficient); 17762 } 17763 return new ModulusPoly(this.field, product); 17764 } 17765 /* 17766 ModulusPoly[] divide(other: ModulusPoly) { 17767 if (!field.equals(other.field)) { 17768 throw new IllegalArgumentException("ModulusPolys do not have same ModulusGF field"); 17769 } 17770 if (other.isZero()) { 17771 throw new IllegalArgumentException("Divide by 0"); 17772 } 17773 17774 let quotient: ModulusPoly = field.getZero(); 17775 let remainder: ModulusPoly = this; 17776 17777 let denominatorLeadingTerm: /*int/ number = other.getCoefficient(other.getDegree()); 17778 let inverseDenominatorLeadingTerm: /*int/ number = field.inverse(denominatorLeadingTerm); 17779 17780 while (remainder.getDegree() >= other.getDegree() && !remainder.isZero()) { 17781 let degreeDifference: /*int/ number = remainder.getDegree() - other.getDegree(); 17782 let scale: /*int/ number = field.multiply(remainder.getCoefficient(remainder.getDegree()), inverseDenominatorLeadingTerm); 17783 let term: ModulusPoly = other.multiplyByMonomial(degreeDifference, scale); 17784 let iterationQuotient: ModulusPoly = field.buildMonomial(degreeDifference, scale); 17785 quotient = quotient.add(iterationQuotient); 17786 remainder = remainder.subtract(term); 17787 } 17788 17789 return new ModulusPoly[] { quotient, remainder }; 17790 } 17791 */ 17792 // @Override 17793 toString() { 17794 let result = new StringBuilder( /*8 * this.getDegree()*/); // dynamic string size in JS 17795 for (let degree /*int*/ = this.getDegree(); degree >= 0; degree--) { 17796 let coefficient = /*int*/ this.getCoefficient(degree); 17797 if (coefficient !== 0) { 17798 if (coefficient < 0) { 17799 result.append(' - '); 17800 coefficient = -coefficient; 17801 } 17802 else { 17803 if (result.length() > 0) { 17804 result.append(' + '); 17805 } 17806 } 17807 if (degree === 0 || coefficient !== 1) { 17808 result.append(coefficient); 17809 } 17810 if (degree !== 0) { 17811 if (degree === 1) { 17812 result.append('x'); 17813 } 17814 else { 17815 result.append('x^'); 17816 result.append(degree); 17817 } 17818 } 17819 } 17820 } 17821 return result.toString(); 17822 } 17823 } 17824 17825 class ModulusBase { 17826 add(a, b) { 17827 return (a + b) % this.modulus; 17828 } 17829 subtract(a, b) { 17830 return (this.modulus + a - b) % this.modulus; 17831 } 17832 exp(a) { 17833 return this.expTable[a]; 17834 } 17835 log(a) { 17836 if (a === 0) { 17837 throw new IllegalArgumentException(); 17838 } 17839 return this.logTable[a]; 17840 } 17841 inverse(a) { 17842 if (a === 0) { 17843 throw new ArithmeticException(); 17844 } 17845 return this.expTable[this.modulus - this.logTable[a] - 1]; 17846 } 17847 multiply(a, b) { 17848 if (a === 0 || b === 0) { 17849 return 0; 17850 } 17851 return this.expTable[(this.logTable[a] + this.logTable[b]) % (this.modulus - 1)]; 17852 } 17853 getSize() { 17854 return this.modulus; 17855 } 17856 equals(o) { 17857 return o === this; 17858 } 17859 } 17860 17861 /* 17862 * Copyright 2012 ZXing authors 17863 * 17864 * Licensed under the Apache License, Version 2.0 (the "License"); 17865 * you may not use this file except in compliance with the License. 17866 * You may obtain a copy of the License at 17867 * 17868 * http://www.apache.org/licenses/LICENSE-2.0 17869 * 17870 * Unless required by applicable law or agreed to in writing, software 17871 * distributed under the License is distributed on an "AS IS" BASIS, 17872 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17873 * See the License for the specific language governing permissions and 17874 * limitations under the License. 17875 */ 17876 /** 17877 * <p>A field based on powers of a generator integer, modulo some modulus.</p> 17878 * 17879 * @author Sean Owen 17880 * @see com.google.zxing.common.reedsolomon.GenericGF 17881 */ 17882 /*public final*/ class ModulusGF extends ModulusBase { 17883 // private /*final*/ modulus: /*int*/ number; 17884 constructor(modulus, generator) { 17885 super(); 17886 this.modulus = modulus; 17887 this.expTable = new Int32Array(modulus); 17888 this.logTable = new Int32Array(modulus); 17889 let x = /*int*/ 1; 17890 for (let i /*int*/ = 0; i < modulus; i++) { 17891 this.expTable[i] = x; 17892 x = (x * generator) % modulus; 17893 } 17894 for (let i /*int*/ = 0; i < modulus - 1; i++) { 17895 this.logTable[this.expTable[i]] = i; 17896 } 17897 // logTable[0] == 0 but this should never be used 17898 this.zero = new ModulusPoly(this, new Int32Array([0])); 17899 this.one = new ModulusPoly(this, new Int32Array([1])); 17900 } 17901 getZero() { 17902 return this.zero; 17903 } 17904 getOne() { 17905 return this.one; 17906 } 17907 buildMonomial(degree, coefficient) { 17908 if (degree < 0) { 17909 throw new IllegalArgumentException(); 17910 } 17911 if (coefficient === 0) { 17912 return this.zero; 17913 } 17914 let coefficients = new Int32Array(degree + 1); 17915 coefficients[0] = coefficient; 17916 return new ModulusPoly(this, coefficients); 17917 } 17918 } 17919 ModulusGF.PDF417_GF = new ModulusGF(PDF417Common.NUMBER_OF_CODEWORDS, 3); 17920 17921 /* 17922 * Copyright 2012 ZXing authors 17923 * 17924 * Licensed under the Apache License, Version 2.0 (the "License"); 17925 * you may not use this file except in compliance with the License. 17926 * You may obtain a copy of the License at 17927 * 17928 * http://www.apache.org/licenses/LICENSE-2.0 17929 * 17930 * Unless required by applicable law or agreed to in writing, software 17931 * distributed under the License is distributed on an "AS IS" BASIS, 17932 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17933 * See the License for the specific language governing permissions and 17934 * limitations under the License. 17935 */ 17936 /** 17937 * <p>PDF417 error correction implementation.</p> 17938 * 17939 * <p>This <a href="http://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction#Example">example</a> 17940 * is quite useful in understanding the algorithm.</p> 17941 * 17942 * @author Sean Owen 17943 * @see com.google.zxing.common.reedsolomon.ReedSolomonDecoder 17944 */ 17945 /*public final*/ class ErrorCorrection$1 { 17946 constructor() { 17947 this.field = ModulusGF.PDF417_GF; 17948 } 17949 /** 17950 * @param received received codewords 17951 * @param numECCodewords number of those codewords used for EC 17952 * @param erasures location of erasures 17953 * @return number of errors 17954 * @throws ChecksumException if errors cannot be corrected, maybe because of too many errors 17955 */ 17956 decode(received, numECCodewords, erasures) { 17957 let poly = new ModulusPoly(this.field, received); 17958 let S = new Int32Array(numECCodewords); 17959 let error = false; 17960 for (let i /*int*/ = numECCodewords; i > 0; i--) { 17961 let evaluation = poly.evaluateAt(this.field.exp(i)); 17962 S[numECCodewords - i] = evaluation; 17963 if (evaluation !== 0) { 17964 error = true; 17965 } 17966 } 17967 if (!error) { 17968 return 0; 17969 } 17970 let knownErrors = this.field.getOne(); 17971 if (erasures != null) { 17972 for (const erasure of erasures) { 17973 let b = this.field.exp(received.length - 1 - erasure); 17974 // Add (1 - bx) term: 17975 let term = new ModulusPoly(this.field, new Int32Array([this.field.subtract(0, b), 1])); 17976 knownErrors = knownErrors.multiply(term); 17977 } 17978 } 17979 let syndrome = new ModulusPoly(this.field, S); 17980 // syndrome = syndrome.multiply(knownErrors); 17981 let sigmaOmega = this.runEuclideanAlgorithm(this.field.buildMonomial(numECCodewords, 1), syndrome, numECCodewords); 17982 let sigma = sigmaOmega[0]; 17983 let omega = sigmaOmega[1]; 17984 // sigma = sigma.multiply(knownErrors); 17985 let errorLocations = this.findErrorLocations(sigma); 17986 let errorMagnitudes = this.findErrorMagnitudes(omega, sigma, errorLocations); 17987 for (let i /*int*/ = 0; i < errorLocations.length; i++) { 17988 let position = received.length - 1 - this.field.log(errorLocations[i]); 17989 if (position < 0) { 17990 throw ChecksumException.getChecksumInstance(); 17991 } 17992 received[position] = this.field.subtract(received[position], errorMagnitudes[i]); 17993 } 17994 return errorLocations.length; 17995 } 17996 /** 17997 * 17998 * @param ModulusPoly 17999 * @param a 18000 * @param ModulusPoly 18001 * @param b 18002 * @param int 18003 * @param R 18004 * @throws ChecksumException 18005 */ 18006 runEuclideanAlgorithm(a, b, R) { 18007 // Assume a's degree is >= b's 18008 if (a.getDegree() < b.getDegree()) { 18009 let temp = a; 18010 a = b; 18011 b = temp; 18012 } 18013 let rLast = a; 18014 let r = b; 18015 let tLast = this.field.getZero(); 18016 let t = this.field.getOne(); 18017 // Run Euclidean algorithm until r's degree is less than R/2 18018 while (r.getDegree() >= Math.round(R / 2)) { 18019 let rLastLast = rLast; 18020 let tLastLast = tLast; 18021 rLast = r; 18022 tLast = t; 18023 // Divide rLastLast by rLast, with quotient in q and remainder in r 18024 if (rLast.isZero()) { 18025 // Oops, Euclidean algorithm already terminated? 18026 throw ChecksumException.getChecksumInstance(); 18027 } 18028 r = rLastLast; 18029 let q = this.field.getZero(); 18030 let denominatorLeadingTerm = rLast.getCoefficient(rLast.getDegree()); 18031 let dltInverse = this.field.inverse(denominatorLeadingTerm); 18032 while (r.getDegree() >= rLast.getDegree() && !r.isZero()) { 18033 let degreeDiff = r.getDegree() - rLast.getDegree(); 18034 let scale = this.field.multiply(r.getCoefficient(r.getDegree()), dltInverse); 18035 q = q.add(this.field.buildMonomial(degreeDiff, scale)); 18036 r = r.subtract(rLast.multiplyByMonomial(degreeDiff, scale)); 18037 } 18038 t = q.multiply(tLast).subtract(tLastLast).negative(); 18039 } 18040 let sigmaTildeAtZero = t.getCoefficient(0); 18041 if (sigmaTildeAtZero === 0) { 18042 throw ChecksumException.getChecksumInstance(); 18043 } 18044 let inverse = this.field.inverse(sigmaTildeAtZero); 18045 let sigma = t.multiply(inverse); 18046 let omega = r.multiply(inverse); 18047 return [sigma, omega]; 18048 } 18049 /** 18050 * 18051 * @param errorLocator 18052 * @throws ChecksumException 18053 */ 18054 findErrorLocations(errorLocator) { 18055 // This is a direct application of Chien's search 18056 let numErrors = errorLocator.getDegree(); 18057 let result = new Int32Array(numErrors); 18058 let e = 0; 18059 for (let i /*int*/ = 1; i < this.field.getSize() && e < numErrors; i++) { 18060 if (errorLocator.evaluateAt(i) === 0) { 18061 result[e] = this.field.inverse(i); 18062 e++; 18063 } 18064 } 18065 if (e !== numErrors) { 18066 throw ChecksumException.getChecksumInstance(); 18067 } 18068 return result; 18069 } 18070 findErrorMagnitudes(errorEvaluator, errorLocator, errorLocations) { 18071 let errorLocatorDegree = errorLocator.getDegree(); 18072 let formalDerivativeCoefficients = new Int32Array(errorLocatorDegree); 18073 for (let i /*int*/ = 1; i <= errorLocatorDegree; i++) { 18074 formalDerivativeCoefficients[errorLocatorDegree - i] = 18075 this.field.multiply(i, errorLocator.getCoefficient(i)); 18076 } 18077 let formalDerivative = new ModulusPoly(this.field, formalDerivativeCoefficients); 18078 // This is directly applying Forney's Formula 18079 let s = errorLocations.length; 18080 let result = new Int32Array(s); 18081 for (let i /*int*/ = 0; i < s; i++) { 18082 let xiInverse = this.field.inverse(errorLocations[i]); 18083 let numerator = this.field.subtract(0, errorEvaluator.evaluateAt(xiInverse)); 18084 let denominator = this.field.inverse(formalDerivative.evaluateAt(xiInverse)); 18085 result[i] = this.field.multiply(numerator, denominator); 18086 } 18087 return result; 18088 } 18089 } 18090 18091 /* 18092 * Copyright 2013 ZXing authors 18093 * 18094 * Licensed under the Apache License, Version 2.0 (the "License"); 18095 * you may not use this file except in compliance with the License. 18096 * You may obtain a copy of the License at 18097 * 18098 * http://www.apache.org/licenses/LICENSE-2.0 18099 * 18100 * Unless required by applicable law or agreed to in writing, software 18101 * distributed under the License is distributed on an "AS IS" BASIS, 18102 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18103 * See the License for the specific language governing permissions and 18104 * limitations under the License. 18105 */
vendor: 9,180 bytes, lines 18105-18371
18105 18106 /** 18107 * @author Guenther Grau 18108 */ 18109 /*final*/ class BoundingBox { 18110 constructor(image, topLeft, bottomLeft, topRight, bottomRight) { 18111 if (image instanceof BoundingBox) { 18112 this.constructor_2(image); 18113 } 18114 else { 18115 this.constructor_1(image, topLeft, bottomLeft, topRight, bottomRight); 18116 } 18117 } 18118 /** 18119 * 18120 * @param image 18121 * @param topLeft 18122 * @param bottomLeft 18123 * @param topRight 18124 * @param bottomRight 18125 * 18126 * @throws NotFoundException 18127 */ 18128 constructor_1(image, topLeft, bottomLeft, topRight, bottomRight) { 18129 const leftUnspecified = topLeft == null || bottomLeft == null; 18130 const rightUnspecified = topRight == null || bottomRight == null; 18131 if (leftUnspecified && rightUnspecified) { 18132 throw new NotFoundException(); 18133 } 18134 if (leftUnspecified) { 18135 topLeft = new ResultPoint(0, topRight.getY()); 18136 bottomLeft = new ResultPoint(0, bottomRight.getY()); 18137 } 18138 else if (rightUnspecified) { 18139 topRight = new ResultPoint(image.getWidth() - 1, topLeft.getY()); 18140 bottomRight = new ResultPoint(image.getWidth() - 1, bottomLeft.getY()); 18141 } 18142 this.image = image; 18143 this.topLeft = topLeft; 18144 this.bottomLeft = bottomLeft; 18145 this.topRight = topRight; 18146 this.bottomRight = bottomRight; 18147 this.minX = Math.trunc(Math.min(topLeft.getX(), bottomLeft.getX())); 18148 this.maxX = Math.trunc(Math.max(topRight.getX(), bottomRight.getX())); 18149 this.minY = Math.trunc(Math.min(topLeft.getY(), topRight.getY())); 18150 this.maxY = Math.trunc(Math.max(bottomLeft.getY(), bottomRight.getY())); 18151 } 18152 constructor_2(boundingBox) { 18153 this.image = boundingBox.image; 18154 this.topLeft = boundingBox.getTopLeft(); 18155 this.bottomLeft = boundingBox.getBottomLeft(); 18156 this.topRight = boundingBox.getTopRight(); 18157 this.bottomRight = boundingBox.getBottomRight(); 18158 this.minX = boundingBox.getMinX(); 18159 this.maxX = boundingBox.getMaxX(); 18160 this.minY = boundingBox.getMinY(); 18161 this.maxY = boundingBox.getMaxY(); 18162 } 18163 /** 18164 * @throws NotFoundException 18165 */ 18166 static merge(leftBox, rightBox) { 18167 if (leftBox == null) { 18168 return rightBox; 18169 } 18170 if (rightBox == null) { 18171 return leftBox; 18172 } 18173 return new BoundingBox(leftBox.image, leftBox.topLeft, leftBox.bottomLeft, rightBox.topRight, rightBox.bottomRight); 18174 } 18175 /** 18176 * @throws NotFoundException 18177 */ 18178 addMissingRows(missingStartRows, missingEndRows, isLeft) { 18179 let newTopLeft = this.topLeft; 18180 let newBottomLeft = this.bottomLeft; 18181 let newTopRight = this.topRight; 18182 let newBottomRight = this.bottomRight; 18183 if (missingStartRows > 0) { 18184 let top = isLeft ? this.topLeft : this.topRight; 18185 let newMinY = Math.trunc(top.getY() - missingStartRows); 18186 if (newMinY < 0) { 18187 newMinY = 0; 18188 } 18189 let newTop = new ResultPoint(top.getX(), newMinY); 18190 if (isLeft) { 18191 newTopLeft = newTop; 18192 } 18193 else { 18194 newTopRight = newTop; 18195 } 18196 } 18197 if (missingEndRows > 0) { 18198 let bottom = isLeft ? this.bottomLeft : this.bottomRight; 18199 let newMaxY = Math.trunc(bottom.getY() + missingEndRows); 18200 if (newMaxY >= this.image.getHeight()) { 18201 newMaxY = this.image.getHeight() - 1; 18202 } 18203 let newBottom = new ResultPoint(bottom.getX(), newMaxY); 18204 if (isLeft) { 18205 newBottomLeft = newBottom; 18206 } 18207 else { 18208 newBottomRight = newBottom; 18209 } 18210 } 18211 return new BoundingBox(this.image, newTopLeft, newBottomLeft, newTopRight, newBottomRight); 18212 } 18213 getMinX() { 18214 return this.minX; 18215 } 18216 getMaxX() { 18217 return this.maxX; 18218 } 18219 getMinY() { 18220 return this.minY; 18221 } 18222 getMaxY() { 18223 return this.maxY; 18224 } 18225 getTopLeft() { 18226 return this.topLeft; 18227 } 18228 getTopRight() { 18229 return this.topRight; 18230 } 18231 getBottomLeft() { 18232 return this.bottomLeft; 18233 } 18234 getBottomRight() { 18235 return this.bottomRight; 18236 } 18237 } 18238 18239 /* 18240 * Copyright 2013 ZXing authors 18241 * 18242 * Licensed under the Apache License, Version 2.0 (the "License"); 18243 * you may not use this file except in compliance with the License. 18244 * You may obtain a copy of the License at 18245 * 18246 * http://www.apache.org/licenses/LICENSE-2.0 18247 * 18248 * Unless required by applicable law or agreed to in writing, software 18249 * distributed under the License is distributed on an "AS IS" BASIS, 18250 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18251 * See the License for the specific language governing permissions and 18252 * limitations under the License. 18253 */ 18254 // package com.google.zxing.pdf417.decoder; 18255 /** 18256 * @author Guenther Grau 18257 */ 18258 /*final*/ class BarcodeMetadata { 18259 constructor(columnCount, rowCountUpperPart, rowCountLowerPart, errorCorrectionLevel) { 18260 this.columnCount = columnCount; 18261 this.errorCorrectionLevel = errorCorrectionLevel; 18262 this.rowCountUpperPart = rowCountUpperPart; 18263 this.rowCountLowerPart = rowCountLowerPart; 18264 this.rowCount = rowCountUpperPart + rowCountLowerPart; 18265 } 18266 getColumnCount() { 18267 return this.columnCount; 18268 } 18269 getErrorCorrectionLevel() { 18270 return this.errorCorrectionLevel; 18271 } 18272 getRowCount() { 18273 return this.rowCount; 18274 } 18275 getRowCountUpperPart() { 18276 return this.rowCountUpperPart; 18277 } 18278 getRowCountLowerPart() { 18279 return this.rowCountLowerPart; 18280 } 18281 } 18282 18283 /** 18284 * Java Formatter class polyfill that works in the JS way. 18285 */ 18286 class Formatter { 18287 constructor() { 18288 this.buffer = ''; 18289 } 18290 /** 18291 * 18292 * @see https://stackoverflow.com/a/13439711/4367683 18293 * 18294 * @param str 18295 * @param arr 18296 */ 18297 static form(str, arr) { 18298 let i = -1; 18299 function callback(exp, p0, p1, p2, p3, p4) { 18300 if (exp === '%%') 18301 return '%'; 18302 if (arr[++i] === undefined) 18303 return undefined; 18304 exp = p2 ? parseInt(p2.substr(1)) : undefined; 18305 let base = p3 ? parseInt(p3.substr(1)) : undefined; 18306 let val; 18307 switch (p4) { 18308 case 's': 18309 val = arr[i]; 18310 break; 18311 case 'c': 18312 val = arr[i][0]; 18313 break; 18314 case 'f': 18315 val = parseFloat(arr[i]).toFixed(exp); 18316 break; 18317 case 'p': 18318 val = parseFloat(arr[i]).toPrecision(exp); 18319 break; 18320 case 'e': 18321 val = parseFloat(arr[i]).toExponential(exp); 18322 break; 18323 case 'x': 18324 val = parseInt(arr[i]).toString(base ? base : 16); 18325 break; 18326 case 'd': 18327 val = parseFloat(parseInt(arr[i], base ? base : 10).toPrecision(exp)).toFixed(0); 18328 break; 18329 } 18330 val = typeof val === 'object' ? JSON.stringify(val) : (+val).toString(base); 18331 let size = parseInt(p1); /* padding size */ 18332 let ch = p1 && (p1[0] + '') === '0' ? '0' : ' '; /* isnull? */ 18333 while (val.length < size) 18334 val = p0 !== undefined ? val + ch : ch + val; /* isminus? */ 18335 return val; 18336 } 18337 let regex = /%(-)?(0?[0-9]+)?([.][0-9]+)?([#][0-9]+)?([scfpexd%])/g; 18338 return str.replace(regex, callback); 18339 } 18340 /** 18341 * 18342 * @param append The new string to append. 18343 * @param args Argumets values to be formated. 18344 */ 18345 format(append, ...args) { 18346 this.buffer += Formatter.form(append, args); 18347 } 18348 /** 18349 * Returns the Formatter string value. 18350 */ 18351 toString() { 18352 return this.buffer; 18353 } 18354 } 18355 18356 /* 18357 * Copyright 2013 ZXing authors 18358 * 18359 * Licensed under the Apache License, Version 2.0 (the "License"); 18360 * you may not use this file except in compliance with the License. 18361 * You may obtain a copy of the License at 18362 * 18363 * http://www.apache.org/licenses/LICENSE-2.0 18364 * 18365 * Unless required by applicable law or agreed to in writing, software 18366 * distributed under the License is distributed on an "AS IS" BASIS, 18367 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18368 * See the License for the specific language governing permissions and 18369 * limitations under the License. 18370 */ 18371 /
vendor: 16,950 bytes, lines 18371-18757
18371** 18372 * @author Guenther Grau 18373 */ 18374 class DetectionResultColumn { 18375 constructor(boundingBox) { 18376 this.boundingBox = new BoundingBox(boundingBox); 18377 // this.codewords = new Codeword[boundingBox.getMaxY() - boundingBox.getMinY() + 1]; 18378 this.codewords = new Array(boundingBox.getMaxY() - boundingBox.getMinY() + 1); 18379 } 18380 /*final*/ getCodewordNearby(imageRow) { 18381 let codeword = this.getCodeword(imageRow); 18382 if (codeword != null) { 18383 return codeword; 18384 } 18385 for (let i = 1; i < DetectionResultColumn.MAX_NEARBY_DISTANCE; i++) { 18386 let nearImageRow = this.imageRowToCodewordIndex(imageRow) - i; 18387 if (nearImageRow >= 0) { 18388 codeword = this.codewords[nearImageRow]; 18389 if (codeword != null) { 18390 return codeword; 18391 } 18392 } 18393 nearImageRow = this.imageRowToCodewordIndex(imageRow) + i; 18394 if (nearImageRow < this.codewords.length) { 18395 codeword = this.codewords[nearImageRow]; 18396 if (codeword != null) { 18397 return codeword; 18398 } 18399 } 18400 } 18401 return null; 18402 } 18403 /*final int*/ imageRowToCodewordIndex(imageRow) { 18404 return imageRow - this.boundingBox.getMinY(); 18405 } 18406 /*final void*/ setCodeword(imageRow, codeword) { 18407 this.codewords[this.imageRowToCodewordIndex(imageRow)] = codeword; 18408 } 18409 /*final*/ getCodeword(imageRow) { 18410 return this.codewords[this.imageRowToCodewordIndex(imageRow)]; 18411 } 18412 /*final*/ getBoundingBox() { 18413 return this.boundingBox; 18414 } 18415 /*final*/ getCodewords() { 18416 return this.codewords; 18417 } 18418 // @Override 18419 toString() { 18420 const formatter = new Formatter(); 18421 let row = 0; 18422 for (const codeword of this.codewords) { 18423 if (codeword == null) { 18424 formatter.format('%3d: | %n', row++); 18425 continue; 18426 } 18427 formatter.format('%3d: %3d|%3d%n', row++, codeword.getRowNumber(), codeword.getValue()); 18428 } 18429 return formatter.toString(); 18430 } 18431 } 18432 DetectionResultColumn.MAX_NEARBY_DISTANCE = 5; 18433 18434 /* 18435 * Copyright 2013 ZXing authors 18436 * 18437 * Licensed under the Apache License, Version 2.0 (the "License"); 18438 * you may not use this file except in compliance with the License. 18439 * You may obtain a copy of the License at 18440 * 18441 * http://www.apache.org/licenses/LICENSE-2.0 18442 * 18443 * Unless required by applicable law or agreed to in writing, software 18444 * distributed under the License is distributed on an "AS IS" BASIS, 18445 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18446 * See the License for the specific language governing permissions and 18447 * limitations under the License. 18448 */ 18449 // import java.util.ArrayList; 18450 // import java.util.Collection; 18451 // import java.util.HashMap; 18452 // import java.util.Map; 18453 // import java.util.Map.Entry; 18454 /** 18455 * @author Guenther Grau 18456 */ 18457 /*final*/ class BarcodeValue { 18458 constructor() { 18459 this.values = new Map(); 18460 } 18461 /** 18462 * Add an occurrence of a value 18463 */ 18464 setValue(value) { 18465 value = Math.trunc(value); 18466 let confidence = this.values.get(value); 18467 if (confidence == null) { 18468 confidence = 0; 18469 } 18470 confidence++; 18471 this.values.set(value, confidence); 18472 } 18473 /** 18474 * Determines the maximum occurrence of a set value and returns all values which were set with this occurrence. 18475 * @return an array of int, containing the values with the highest occurrence, or null, if no value was set 18476 */ 18477 getValue() { 18478 let maxConfidence = -1; 18479 let result = new Array(); 18480 for (const [key, value] of this.values.entries()) { 18481 const entry = { 18482 getKey: () => key, 18483 getValue: () => value, 18484 }; 18485 if (entry.getValue() > maxConfidence) { 18486 maxConfidence = entry.getValue(); 18487 result = []; 18488 result.push(entry.getKey()); 18489 } 18490 else if (entry.getValue() === maxConfidence) { 18491 result.push(entry.getKey()); 18492 } 18493 } 18494 return PDF417Common.toIntArray(result); 18495 } 18496 getConfidence(value) { 18497 return this.values.get(value); 18498 } 18499 } 18500 18501 /* 18502 * Copyright 2013 ZXing authors 18503 * 18504 * Licensed under the Apache License, Version 2.0 (the "License"); 18505 * you may not use this file except in compliance with the License. 18506 * You may obtain a copy of the License at 18507 * 18508 * http://www.apache.org/licenses/LICENSE-2.0 18509 * 18510 * Unless required by applicable law or agreed to in writing, software 18511 * distributed under the License is distributed on an "AS IS" BASIS, 18512 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18513 * See the License for the specific language governing permissions and 18514 * limitations under the License. 18515 */ 18516 /** 18517 * @author Guenther Grau 18518 */ 18519 /*final*/ class DetectionResultRowIndicatorColumn extends DetectionResultColumn { 18520 constructor(boundingBox, isLeft) { 18521 super(boundingBox); 18522 this._isLeft = isLeft; 18523 } 18524 setRowNumbers() { 18525 for (let codeword /*Codeword*/ of this.getCodewords()) { 18526 if (codeword != null) { 18527 codeword.setRowNumberAsRowIndicatorColumn(); 18528 } 18529 } 18530 } 18531 // TODO implement properly 18532 // TODO maybe we should add missing codewords to store the correct row number to make 18533 // finding row numbers for other columns easier 18534 // use row height count to make detection of invalid row numbers more reliable 18535 adjustCompleteIndicatorColumnRowNumbers(barcodeMetadata) { 18536 let codewords = this.getCodewords(); 18537 this.setRowNumbers(); 18538 this.removeIncorrectCodewords(codewords, barcodeMetadata); 18539 let boundingBox = this.getBoundingBox(); 18540 let top = this._isLeft ? boundingBox.getTopLeft() : boundingBox.getTopRight(); 18541 let bottom = this._isLeft ? boundingBox.getBottomLeft() : boundingBox.getBottomRight(); 18542 let firstRow = this.imageRowToCodewordIndex(Math.trunc(top.getY())); 18543 let lastRow = this.imageRowToCodewordIndex(Math.trunc(bottom.getY())); 18544 // We need to be careful using the average row height. Barcode could be skewed so that we have smaller and 18545 // taller rows 18546 // float averageRowHeight = (lastRow - firstRow) / /*(float)*/ barcodeMetadata.getRowCount(); 18547 let barcodeRow = -1; 18548 let maxRowHeight = 1; 18549 let currentRowHeight = 0; 18550 for (let codewordsRow /*int*/ = firstRow; codewordsRow < lastRow; codewordsRow++) { 18551 if (codewords[codewordsRow] == null) { 18552 continue; 18553 } 18554 let codeword = codewords[codewordsRow]; 18555 // float expectedRowNumber = (codewordsRow - firstRow) / averageRowHeight; 18556 // if (Math.abs(codeword.getRowNumber() - expectedRowNumber) > 2) { 18557 // SimpleLog.log(LEVEL.WARNING, 18558 // "Removing codeword, rowNumberSkew too high, codeword[" + codewordsRow + "]: Expected Row: " + 18559 // expectedRowNumber + ", RealRow: " + codeword.getRowNumber() + ", value: " + codeword.getValue()); 18560 // codewords[codewordsRow] = null; 18561 // } 18562 let rowDifference = codeword.getRowNumber() - barcodeRow; 18563 // TODO improve handling with case where first row indicator doesn't start with 0 18564 if (rowDifference === 0) { 18565 currentRowHeight++; 18566 } 18567 else if (rowDifference === 1) { 18568 maxRowHeight = Math.max(maxRowHeight, currentRowHeight); 18569 currentRowHeight = 1; 18570 barcodeRow = codeword.getRowNumber(); 18571 } 18572 else if (rowDifference < 0 || 18573 codeword.getRowNumber() >= barcodeMetadata.getRowCount() || 18574 rowDifference > codewordsRow) { 18575 codewords[codewordsRow] = null; 18576 } 18577 else { 18578 let checkedRows; 18579 if (maxRowHeight > 2) { 18580 checkedRows = (maxRowHeight - 2) * rowDifference; 18581 } 18582 else { 18583 checkedRows = rowDifference; 18584 } 18585 let closePreviousCodewordFound = checkedRows >= codewordsRow; 18586 for (let i /*int*/ = 1; i <= checkedRows && !closePreviousCodewordFound; i++) { 18587 // there must be (height * rowDifference) number of codewords missing. For now we assume height = 1. 18588 // This should hopefully get rid of most problems already. 18589 closePreviousCodewordFound = codewords[codewordsRow - i] != null; 18590 } 18591 if (closePreviousCodewordFound) { 18592 codewords[codewordsRow] = null; 18593 } 18594 else { 18595 barcodeRow = codeword.getRowNumber(); 18596 currentRowHeight = 1; 18597 } 18598 } 18599 } 18600 // return (int) (averageRowHeight + 0.5); 18601 } 18602 getRowHeights() { 18603 let barcodeMetadata = this.getBarcodeMetadata(); 18604 if (barcodeMetadata == null) { 18605 return null; 18606 } 18607 this.adjustIncompleteIndicatorColumnRowNumbers(barcodeMetadata); 18608 let result = new Int32Array(barcodeMetadata.getRowCount()); 18609 for (let codeword /*Codeword*/ of this.getCodewords()) { 18610 if (codeword != null) { 18611 let rowNumber = codeword.getRowNumber(); 18612 if (rowNumber >= result.length) { 18613 // We have more rows than the barcode metadata allows for, ignore them. 18614 continue; 18615 } 18616 result[rowNumber]++; 18617 } // else throw exception? 18618 } 18619 return result; 18620 } 18621 // TODO maybe we should add missing codewords to store the correct row number to make 18622 // finding row numbers for other columns easier 18623 // use row height count to make detection of invalid row numbers more reliable 18624 adjustIncompleteIndicatorColumnRowNumbers(barcodeMetadata) { 18625 let boundingBox = this.getBoundingBox(); 18626 let top = this._isLeft ? boundingBox.getTopLeft() : boundingBox.getTopRight(); 18627 let bottom = this._isLeft ? boundingBox.getBottomLeft() : boundingBox.getBottomRight(); 18628 let firstRow = this.imageRowToCodewordIndex(Math.trunc(top.getY())); 18629 let lastRow = this.imageRowToCodewordIndex(Math.trunc(bottom.getY())); 18630 // float averageRowHeight = (lastRow - firstRow) / /*(float)*/ barcodeMetadata.getRowCount(); 18631 let codewords = this.getCodewords(); 18632 let barcodeRow = -1; 18633 for (let codewordsRow /*int*/ = firstRow; codewordsRow < lastRow; codewordsRow++) { 18634 if (codewords[codewordsRow] == null) { 18635 continue; 18636 } 18637 let codeword = codewords[codewordsRow]; 18638 codeword.setRowNumberAsRowIndicatorColumn(); 18639 let rowDifference = codeword.getRowNumber() - barcodeRow; 18640 // TODO improve handling with case where first row indicator doesn't start with 0 18641 if (rowDifference === 0) ; 18642 else if (rowDifference === 1) { 18643 barcodeRow = codeword.getRowNumber(); 18644 } 18645 else if (codeword.getRowNumber() >= barcodeMetadata.getRowCount()) { 18646 codewords[codewordsRow] = null; 18647 } 18648 else { 18649 barcodeRow = codeword.getRowNumber(); 18650 } 18651 } 18652 // return (int) (averageRowHeight + 0.5); 18653 } 18654 getBarcodeMetadata() { 18655 let codewords = this.getCodewords(); 18656 let barcodeColumnCount = new BarcodeValue(); 18657 let barcodeRowCountUpperPart = new BarcodeValue(); 18658 let barcodeRowCountLowerPart = new BarcodeValue(); 18659 let barcodeECLevel = new BarcodeValue(); 18660 for (let codeword /*Codeword*/ of codewords) { 18661 if (codeword == null) { 18662 continue; 18663 } 18664 codeword.setRowNumberAsRowIndicatorColumn(); 18665 let rowIndicatorValue = codeword.getValue() % 30; 18666 let codewordRowNumber = codeword.getRowNumber(); 18667 if (!this._isLeft) { 18668 codewordRowNumber += 2; 18669 } 18670 switch (codewordRowNumber % 3) { 18671 case 0: 18672 barcodeRowCountUpperPart.setValue(rowIndicatorValue * 3 + 1); 18673 break; 18674 case 1: 18675 barcodeECLevel.setValue(rowIndicatorValue / 3); 18676 barcodeRowCountLowerPart.setValue(rowIndicatorValue % 3); 18677 break; 18678 case 2: 18679 barcodeColumnCount.setValue(rowIndicatorValue + 1); 18680 break; 18681 } 18682 } 18683 // Maybe we should check if we have ambiguous values? 18684 if ((barcodeColumnCount.getValue().length === 0) || 18685 (barcodeRowCountUpperPart.getValue().length === 0) || 18686 (barcodeRowCountLowerPart.getValue().length === 0) || 18687 (barcodeECLevel.getValue().length === 0) || 18688 barcodeColumnCount.getValue()[0] < 1 || 18689 barcodeRowCountUpperPart.getValue()[0] + barcodeRowCountLowerPart.getValue()[0] < PDF417Common.MIN_ROWS_IN_BARCODE || 18690 barcodeRowCountUpperPart.getValue()[0] + barcodeRowCountLowerPart.getValue()[0] > PDF417Common.MAX_ROWS_IN_BARCODE) { 18691 return null; 18692 } 18693 let barcodeMetadata = new BarcodeMetadata(barcodeColumnCount.getValue()[0], barcodeRowCountUpperPart.getValue()[0], barcodeRowCountLowerPart.getValue()[0], barcodeECLevel.getValue()[0]); 18694 this.removeIncorrectCodewords(codewords, barcodeMetadata); 18695 return barcodeMetadata; 18696 } 18697 removeIncorrectCodewords(codewords, barcodeMetadata) { 18698 // Remove codewords which do not match the metadata 18699 // TODO Maybe we should keep the incorrect codewords for the start and end positions? 18700 for (let codewordRow /*int*/ = 0; codewordRow < codewords.length; codewordRow++) { 18701 let codeword = codewords[codewordRow]; 18702 if (codewords[codewordRow] == null) { 18703 continue; 18704 } 18705 let rowIndicatorValue = codeword.getValue() % 30; 18706 let codewordRowNumber = codeword.getRowNumber(); 18707 if (codewordRowNumber > barcodeMetadata.getRowCount()) { 18708 codewords[codewordRow] = null; 18709 continue; 18710 } 18711 if (!this._isLeft) { 18712 codewordRowNumber += 2; 18713 } 18714 switch (codewordRowNumber % 3) { 18715 case 0: 18716 if (rowIndicatorValue * 3 + 1 !== barcodeMetadata.getRowCountUpperPart()) { 18717 codewords[codewordRow] = null; 18718 } 18719 break; 18720 case 1: 18721 if (Math.trunc(rowIndicatorValue / 3) !== barcodeMetadata.getErrorCorrectionLevel() || 18722 rowIndicatorValue % 3 !== barcodeMetadata.getRowCountLowerPart()) { 18723 codewords[codewordRow] = null; 18724 } 18725 break; 18726 case 2: 18727 if (rowIndicatorValue + 1 !== barcodeMetadata.getColumnCount()) { 18728 codewords[codewordRow] = null; 18729 } 18730 break; 18731 } 18732 } 18733 } 18734 isLeft() { 18735 return this._isLeft; 18736 } 18737 // @Override 18738 toString() { 18739 return 'IsLeft: ' + this._isLeft + '\n' + super.toString(); 18740 } 18741 } 18742 18743 /* 18744 * Copyright 2013 ZXing authors 18745 * 18746 * Licensed under the Apache License, Version 2.0 (the "License"); 18747 * you may not use this file except in compliance with the License. 18748 * You may obtain a copy of the License at 18749 * 18750 * http://www.apache.org/licenses/LICENSE-2.0 18751 * 18752 * Unless required by applicable law or agreed to in writing, software 18753 * distributed under the License is distributed on an "AS IS" BASIS, 18754 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18755 * See the License for the specific language governing permissions and 18756 * limitations under the License. 18757 */
vendor: 12,980 bytes, lines 18757-19030
18757 18758 /** 18759 * @author Guenther Grau 18760 */ 18761 /*final*/ class DetectionResult { 18762 constructor(barcodeMetadata, boundingBox) { 18763 /*final*/ this.ADJUST_ROW_NUMBER_SKIP = 2; 18764 this.barcodeMetadata = barcodeMetadata; 18765 this.barcodeColumnCount = barcodeMetadata.getColumnCount(); 18766 this.boundingBox = boundingBox; 18767 // this.detectionResultColumns = new DetectionResultColumn[this.barcodeColumnCount + 2]; 18768 this.detectionResultColumns = new Array(this.barcodeColumnCount + 2); 18769 } 18770 getDetectionResultColumns() { 18771 this.adjustIndicatorColumnRowNumbers(this.detectionResultColumns[0]); 18772 this.adjustIndicatorColumnRowNumbers(this.detectionResultColumns[this.barcodeColumnCount + 1]); 18773 let unadjustedCodewordCount = PDF417Common.MAX_CODEWORDS_IN_BARCODE; 18774 let previousUnadjustedCount; 18775 do { 18776 previousUnadjustedCount = unadjustedCodewordCount; 18777 unadjustedCodewordCount = this.adjustRowNumbersAndGetCount(); 18778 } while (unadjustedCodewordCount > 0 && unadjustedCodewordCount < previousUnadjustedCount); 18779 return this.detectionResultColumns; 18780 } 18781 adjustIndicatorColumnRowNumbers(detectionResultColumn) { 18782 if (detectionResultColumn != null) { 18783 detectionResultColumn 18784 .adjustCompleteIndicatorColumnRowNumbers(this.barcodeMetadata); 18785 } 18786 } 18787 // TODO ensure that no detected codewords with unknown row number are left 18788 // we should be able to estimate the row height and use it as a hint for the row number 18789 // we should also fill the rows top to bottom and bottom to top 18790 /** 18791 * @return number of codewords which don't have a valid row number. Note that the count is not accurate as codewords 18792 * will be counted several times. It just serves as an indicator to see when we can stop adjusting row numbers 18793 */ 18794 adjustRowNumbersAndGetCount() { 18795 let unadjustedCount = this.adjustRowNumbersByRow(); 18796 if (unadjustedCount === 0) { 18797 return 0; 18798 } 18799 for (let barcodeColumn /*int*/ = 1; barcodeColumn < this.barcodeColumnCount + 1; barcodeColumn++) { 18800 let codewords = this.detectionResultColumns[barcodeColumn].getCodewords(); 18801 for (let codewordsRow /*int*/ = 0; codewordsRow < codewords.length; codewordsRow++) { 18802 if (codewords[codewordsRow] == null) { 18803 continue; 18804 } 18805 if (!codewords[codewordsRow].hasValidRowNumber()) { 18806 this.adjustRowNumbers(barcodeColumn, codewordsRow, codewords); 18807 } 18808 } 18809 } 18810 return unadjustedCount; 18811 } 18812 adjustRowNumbersByRow() { 18813 this.adjustRowNumbersFromBothRI(); 18814 // TODO we should only do full row adjustments if row numbers of left and right row indicator column match. 18815 // Maybe it's even better to calculated the height (rows: d) and divide it by the number of barcode 18816 // rows. This, together with the LRI and RRI row numbers should allow us to get a good estimate where a row 18817 // number starts and ends. 18818 let unadjustedCount = this.adjustRowNumbersFromLRI(); 18819 return unadjustedCount + this.adjustRowNumbersFromRRI(); 18820 } 18821 adjustRowNumbersFromBothRI() { 18822 if (this.detectionResultColumns[0] == null || this.detectionResultColumns[this.barcodeColumnCount + 1] == null) { 18823 return; 18824 } 18825 let LRIcodewords = this.detectionResultColumns[0].getCodewords(); 18826 let RRIcodewords = this.detectionResultColumns[this.barcodeColumnCount + 1].getCodewords(); 18827 for (let codewordsRow /*int*/ = 0; codewordsRow < LRIcodewords.length; codewordsRow++) { 18828 if (LRIcodewords[codewordsRow] != null && 18829 RRIcodewords[codewordsRow] != null && 18830 LRIcodewords[codewordsRow].getRowNumber() === RRIcodewords[codewordsRow].getRowNumber()) { 18831 for (let barcodeColumn /*int*/ = 1; barcodeColumn <= this.barcodeColumnCount; barcodeColumn++) { 18832 let codeword = this.detectionResultColumns[barcodeColumn].getCodewords()[codewordsRow]; 18833 if (codeword == null) { 18834 continue; 18835 } 18836 codeword.setRowNumber(LRIcodewords[codewordsRow].getRowNumber()); 18837 if (!codeword.hasValidRowNumber()) { 18838 this.detectionResultColumns[barcodeColumn].getCodewords()[codewordsRow] = null; 18839 } 18840 } 18841 } 18842 } 18843 } 18844 adjustRowNumbersFromRRI() { 18845 if (this.detectionResultColumns[this.barcodeColumnCount + 1] == null) { 18846 return 0; 18847 } 18848 let unadjustedCount = 0; 18849 let codewords = this.detectionResultColumns[this.barcodeColumnCount + 1].getCodewords(); 18850 for (let codewordsRow /*int*/ = 0; codewordsRow < codewords.length; codewordsRow++) { 18851 if (codewords[codewordsRow] == null) { 18852 continue; 18853 } 18854 let rowIndicatorRowNumber = codewords[codewordsRow].getRowNumber(); 18855 let invalidRowCounts = 0; 18856 for (let barcodeColumn /*int*/ = this.barcodeColumnCount + 1; barcodeColumn > 0 && invalidRowCounts < this.ADJUST_ROW_NUMBER_SKIP; barcodeColumn--) { 18857 let codeword = this.detectionResultColumns[barcodeColumn].getCodewords()[codewordsRow]; 18858 if (codeword != null) { 18859 invalidRowCounts = DetectionResult.adjustRowNumberIfValid(rowIndicatorRowNumber, invalidRowCounts, codeword); 18860 if (!codeword.hasValidRowNumber()) { 18861 unadjustedCount++; 18862 } 18863 } 18864 } 18865 } 18866 return unadjustedCount; 18867 } 18868 adjustRowNumbersFromLRI() { 18869 if (this.detectionResultColumns[0] == null) { 18870 return 0; 18871 } 18872 let unadjustedCount = 0; 18873 let codewords = this.detectionResultColumns[0].getCodewords(); 18874 for (let codewordsRow /*int*/ = 0; codewordsRow < codewords.length; codewordsRow++) { 18875 if (codewords[codewordsRow] == null) { 18876 continue; 18877 } 18878 let rowIndicatorRowNumber = codewords[codewordsRow].getRowNumber(); 18879 let invalidRowCounts = 0; 18880 for (let barcodeColumn /*int*/ = 1; barcodeColumn < this.barcodeColumnCount + 1 && invalidRowCounts < this.ADJUST_ROW_NUMBER_SKIP; barcodeColumn++) { 18881 let codeword = this.detectionResultColumns[barcodeColumn].getCodewords()[codewordsRow]; 18882 if (codeword != null) { 18883 invalidRowCounts = DetectionResult.adjustRowNumberIfValid(rowIndicatorRowNumber, invalidRowCounts, codeword); 18884 if (!codeword.hasValidRowNumber()) { 18885 unadjustedCount++; 18886 } 18887 } 18888 } 18889 } 18890 return unadjustedCount; 18891 } 18892 static adjustRowNumberIfValid(rowIndicatorRowNumber, invalidRowCounts, codeword) { 18893 if (codeword == null) { 18894 return invalidRowCounts; 18895 } 18896 if (!codeword.hasValidRowNumber()) { 18897 if (codeword.isValidRowNumber(rowIndicatorRowNumber)) { 18898 codeword.setRowNumber(rowIndicatorRowNumber); 18899 invalidRowCounts = 0; 18900 } 18901 else { 18902 ++invalidRowCounts; 18903 } 18904 } 18905 return invalidRowCounts; 18906 } 18907 adjustRowNumbers(barcodeColumn, codewordsRow, codewords) { 18908 if (this.detectionResultColumns[barcodeColumn - 1] == null) { 18909 return; 18910 } 18911 let codeword = codewords[codewordsRow]; 18912 let previousColumnCodewords = this.detectionResultColumns[barcodeColumn - 1].getCodewords(); 18913 let nextColumnCodewords = previousColumnCodewords; 18914 if (this.detectionResultColumns[barcodeColumn + 1] != null) { 18915 nextColumnCodewords = this.detectionResultColumns[barcodeColumn + 1].getCodewords(); 18916 } 18917 // let otherCodewords: Codeword[] = new Codeword[14]; 18918 let otherCodewords = new Array(14); 18919 otherCodewords[2] = previousColumnCodewords[codewordsRow]; 18920 otherCodewords[3] = nextColumnCodewords[codewordsRow]; 18921 if (codewordsRow > 0) { 18922 otherCodewords[0] = codewords[codewordsRow - 1]; 18923 otherCodewords[4] = previousColumnCodewords[codewordsRow - 1]; 18924 otherCodewords[5] = nextColumnCodewords[codewordsRow - 1]; 18925 } 18926 if (codewordsRow > 1) { 18927 otherCodewords[8] = codewords[codewordsRow - 2]; 18928 otherCodewords[10] = previousColumnCodewords[codewordsRow - 2]; 18929 otherCodewords[11] = nextColumnCodewords[codewordsRow - 2]; 18930 } 18931 if (codewordsRow < codewords.length - 1) { 18932 otherCodewords[1] = codewords[codewordsRow + 1]; 18933 otherCodewords[6] = previousColumnCodewords[codewordsRow + 1]; 18934 otherCodewords[7] = nextColumnCodewords[codewordsRow + 1]; 18935 } 18936 if (codewordsRow < codewords.length - 2) { 18937 otherCodewords[9] = codewords[codewordsRow + 2]; 18938 otherCodewords[12] = previousColumnCodewords[codewordsRow + 2]; 18939 otherCodewords[13] = nextColumnCodewords[codewordsRow + 2]; 18940 } 18941 for (let otherCodeword of otherCodewords) { 18942 if (DetectionResult.adjustRowNumber(codeword, otherCodeword)) { 18943 return; 18944 } 18945 } 18946 } 18947 /** 18948 * @return true, if row number was adjusted, false otherwise 18949 */ 18950 static adjustRowNumber(codeword, otherCodeword) { 18951 if (otherCodeword == null) { 18952 return false; 18953 } 18954 if (otherCodeword.hasValidRowNumber() && otherCodeword.getBucket() === codeword.getBucket()) { 18955 codeword.setRowNumber(otherCodeword.getRowNumber()); 18956 return true; 18957 } 18958 return false; 18959 } 18960 getBarcodeColumnCount() { 18961 return this.barcodeColumnCount; 18962 } 18963 getBarcodeRowCount() { 18964 return this.barcodeMetadata.getRowCount(); 18965 } 18966 getBarcodeECLevel() { 18967 return this.barcodeMetadata.getErrorCorrectionLevel(); 18968 } 18969 setBoundingBox(boundingBox) { 18970 this.boundingBox = boundingBox; 18971 } 18972 getBoundingBox() { 18973 return this.boundingBox; 18974 } 18975 setDetectionResultColumn(barcodeColumn, detectionResultColumn) { 18976 this.detectionResultColumns[barcodeColumn] = detectionResultColumn; 18977 } 18978 getDetectionResultColumn(barcodeColumn) { 18979 return this.detectionResultColumns[barcodeColumn]; 18980 } 18981 // @Override 18982 toString() { 18983 let rowIndicatorColumn = this.detectionResultColumns[0]; 18984 if (rowIndicatorColumn == null) { 18985 rowIndicatorColumn = this.detectionResultColumns[this.barcodeColumnCount + 1]; 18986 } 18987 // try ( 18988 let formatter = new Formatter(); 18989 // ) { 18990 for (let codewordsRow /*int*/ = 0; codewordsRow < rowIndicatorColumn.getCodewords().length; codewordsRow++) { 18991 formatter.format('CW %3d:', codewordsRow); 18992 for (let barcodeColumn /*int*/ = 0; barcodeColumn < this.barcodeColumnCount + 2; barcodeColumn++) { 18993 if (this.detectionResultColumns[barcodeColumn] == null) { 18994 formatter.format(' | '); 18995 continue; 18996 } 18997 let codeword = this.detectionResultColumns[barcodeColumn].getCodewords()[codewordsRow]; 18998 if (codeword == null) { 18999 formatter.format(' | '); 19000 continue; 19001 } 19002 formatter.format(' %3d|%3d', codeword.getRowNumber(), codeword.getValue()); 19003 } 19004 formatter.format('%n'); 19005 } 19006 return formatter.toString(); 19007 // } 19008 } 19009 } 19010 19011 /* 19012 * Copyright 2013 ZXing authors 19013 * 19014 * Licensed under the Apache License, Version 2.0 (the "License"); 19015 * you may not use this file except in compliance with the License. 19016 * You may obtain a copy of the License at 19017 * 19018 * http://www.apache.org/licenses/LICENSE-2.0 19019 * 19020 * Unless required by applicable law or agreed to in writing, software 19021 * distributed under the License is distributed on an "AS IS" BASIS, 19022 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19023 * See the License for the specific language governing permissions and 19024 * limitations under the License. 19025 */ 19026 // package com.google.zxing.pdf417.decoder; 19027 /** 19028 * @author Guenther Grau 19029 */ 19030
vendor: 4,643 bytes, lines 19030-19148
19030/*final*/ class Codeword { 19031 constructor(startX, endX, bucket, value) { 19032 this.rowNumber = Codeword.BARCODE_ROW_UNKNOWN; 19033 this.startX = Math.trunc(startX); 19034 this.endX = Math.trunc(endX); 19035 this.bucket = Math.trunc(bucket); 19036 this.value = Math.trunc(value); 19037 } 19038 hasValidRowNumber() { 19039 return this.isValidRowNumber(this.rowNumber); 19040 } 19041 isValidRowNumber(rowNumber) { 19042 return rowNumber !== Codeword.BARCODE_ROW_UNKNOWN && this.bucket === (rowNumber % 3) * 3; 19043 } 19044 setRowNumberAsRowIndicatorColumn() { 19045 this.rowNumber = Math.trunc((Math.trunc(this.value / 30)) * 3 + Math.trunc(this.bucket / 3)); 19046 } 19047 getWidth() { 19048 return this.endX - this.startX; 19049 } 19050 getStartX() { 19051 return this.startX; 19052 } 19053 getEndX() { 19054 return this.endX; 19055 } 19056 getBucket() { 19057 return this.bucket; 19058 } 19059 getValue() { 19060 return this.value; 19061 } 19062 getRowNumber() { 19063 return this.rowNumber; 19064 } 19065 setRowNumber(rowNumber) { 19066 this.rowNumber = rowNumber; 19067 } 19068 // @Override 19069 toString() { 19070 return this.rowNumber + '|' + this.value; 19071 } 19072 } 19073 Codeword.BARCODE_ROW_UNKNOWN = -1; 19074 19075 /* 19076 * Copyright 2013 ZXing authors 19077 * 19078 * Licensed under the Apache License, Version 2.0 (the "License"); 19079 * you may not use this file except in compliance with the License. 19080 * You may obtain a copy of the License at 19081 * 19082 * http://www.apache.org/licenses/LICENSE-2.0 19083 * 19084 * Unless required by applicable law or agreed to in writing, software 19085 * distributed under the License is distributed on an "AS IS" BASIS, 19086 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19087 * See the License for the specific language governing permissions and 19088 * limitations under the License. 19089 */ 19090 /** 19091 * @author Guenther Grau 19092 * @author creatale GmbH ([email protected]) 19093 */ 19094 /*final*/ class PDF417CodewordDecoder { 19095 /* @note 19096 * this action have to be performed before first use of class 19097 * - static constructor 19098 * working with 32bit float (based from Java logic) 19099 */ 19100 static initialize() { 19101 // Pre-computes the symbol ratio table. 19102 for ( /*int*/let i = 0; i < PDF417Common.SYMBOL_TABLE.length; i++) { 19103 let currentSymbol = PDF417Common.SYMBOL_TABLE[i]; 19104 let currentBit = currentSymbol & 0x1; 19105 for ( /*int*/let j = 0; j < PDF417Common.BARS_IN_MODULE; j++) { 19106 let size = 0.0; 19107 while ((currentSymbol & 0x1) === currentBit) { 19108 size += 1.0; 19109 currentSymbol >>= 1; 19110 } 19111 currentBit = currentSymbol & 0x1; 19112 if (!PDF417CodewordDecoder.RATIOS_TABLE[i]) { 19113 PDF417CodewordDecoder.RATIOS_TABLE[i] = new Array(PDF417Common.BARS_IN_MODULE); 19114 } 19115 PDF417CodewordDecoder.RATIOS_TABLE[i][PDF417Common.BARS_IN_MODULE - j - 1] = Math.fround(size / PDF417Common.MODULES_IN_CODEWORD); 19116 } 19117 } 19118 this.bSymbolTableReady = true; 19119 } 19120 static getDecodedValue(moduleBitCount) { 19121 let decodedValue = PDF417CodewordDecoder.getDecodedCodewordValue(PDF417CodewordDecoder.sampleBitCounts(moduleBitCount)); 19122 if (decodedValue !== -1) { 19123 return decodedValue; 19124 } 19125 return PDF417CodewordDecoder.getClosestDecodedValue(moduleBitCount); 19126 } 19127 static sampleBitCounts(moduleBitCount) { 19128 let bitCountSum = MathUtils.sum(moduleBitCount); 19129 let result = new Int32Array(PDF417Common.BARS_IN_MODULE); 19130 let bitCountIndex = 0; 19131 let sumPreviousBits = 0; 19132 for ( /*int*/let i = 0; i < PDF417Common.MODULES_IN_CODEWORD; i++) { 19133 let sampleIndex = bitCountSum / (2 * PDF417Common.MODULES_IN_CODEWORD) + 19134 (i * bitCountSum) / PDF417Common.MODULES_IN_CODEWORD; 19135 if (sumPreviousBits + moduleBitCount[bitCountIndex] <= sampleIndex) { 19136 sumPreviousBits += moduleBitCount[bitCountIndex]; 19137 bitCountIndex++; 19138 } 19139 result[bitCountIndex]++; 19140 } 19141 return result; 19142 } 19143 static getDecodedCodewordValue(moduleBitCount) { 19144 let decodedValue = PDF417CodewordDecoder.getBitValue(moduleBitCount); 19145 return PDF417Common.getCodeword(decodedValue) === -1 ? -1 : decodedValue; 19146 } 19147 static getBitValue(moduleBitCount) { 19148 let result = /*long*/
vendor: 13,445 bytes, lines 19148-19518
19148 0; 19149 for (let /*int*/ i = 0; i < moduleBitCount.length; i++) { 19150 for ( /*int*/let bit = 0; bit < moduleBitCount[i]; bit++) { 19151 result = (result << 1) | (i % 2 === 0 ? 1 : 0); 19152 } 19153 } 19154 return Math.trunc(result); 19155 } 19156 // working with 32bit float (as in Java) 19157 static getClosestDecodedValue(moduleBitCount) { 19158 let bitCountSum = MathUtils.sum(moduleBitCount); 19159 let bitCountRatios = new Array(PDF417Common.BARS_IN_MODULE); 19160 if (bitCountSum > 1) { 19161 for (let /*int*/ i = 0; i < bitCountRatios.length; i++) { 19162 bitCountRatios[i] = Math.fround(moduleBitCount[i] / bitCountSum); 19163 } 19164 } 19165 let bestMatchError = Float.MAX_VALUE; 19166 let bestMatch = -1; 19167 if (!this.bSymbolTableReady) { 19168 PDF417CodewordDecoder.initialize(); 19169 } 19170 for ( /*int*/let j = 0; j < PDF417CodewordDecoder.RATIOS_TABLE.length; j++) { 19171 let error = 0.0; 19172 let ratioTableRow = PDF417CodewordDecoder.RATIOS_TABLE[j]; 19173 for ( /*int*/let k = 0; k < PDF417Common.BARS_IN_MODULE; k++) { 19174 let diff = Math.fround(ratioTableRow[k] - bitCountRatios[k]); 19175 error += Math.fround(diff * diff); 19176 if (error >= bestMatchError) { 19177 break; 19178 } 19179 } 19180 if (error < bestMatchError) { 19181 bestMatchError = error; 19182 bestMatch = PDF417Common.SYMBOL_TABLE[j]; 19183 } 19184 } 19185 return bestMatch; 19186 } 19187 } 19188 // flag that the table is ready for use 19189 PDF417CodewordDecoder.bSymbolTableReady = false; 19190 PDF417CodewordDecoder.RATIOS_TABLE = new Array(PDF417Common.SYMBOL_TABLE.length).map(x => new Array(PDF417Common.BARS_IN_MODULE)); 19191 19192 /* 19193 * Copyright 2013 ZXing authors 19194 * 19195 * Licensed under the Apache License, Version 2.0 (the "License"); 19196 * you may not use this file except in compliance with the License. 19197 * You may obtain a copy of the License at 19198 * 19199 * http://www.apache.org/licenses/LICENSE-2.0 19200 * 19201 * Unless required by applicable law or agreed to in writing, software 19202 * distributed under the License is distributed on an "AS IS" BASIS, 19203 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19204 * See the License for the specific language governing permissions and 19205 * limitations under the License. 19206 */ 19207 // package com.google.zxing.pdf417; 19208 /** 19209 * @author Guenther Grau 19210 */ 19211 /*public final*/ class PDF417ResultMetadata { 19212 constructor() { 19213 this.segmentCount = -1; 19214 this.fileSize = -1; 19215 this.timestamp = -1; 19216 this.checksum = -1; 19217 } 19218 /** 19219 * The Segment ID represents the segment of the whole file distributed over different symbols. 19220 * 19221 * @return File segment index 19222 */ 19223 getSegmentIndex() { 19224 return this.segmentIndex; 19225 } 19226 setSegmentIndex(segmentIndex) { 19227 this.segmentIndex = segmentIndex; 19228 } 19229 /** 19230 * Is the same for each related PDF417 symbol 19231 * 19232 * @return File ID 19233 */ 19234 getFileId() { 19235 return this.fileId; 19236 } 19237 setFileId(fileId) { 19238 this.fileId = fileId; 19239 } 19240 /** 19241 * @return always null 19242 * @deprecated use dedicated already parsed fields 19243 */ 19244 // @Deprecated 19245 getOptionalData() { 19246 return this.optionalData; 19247 } 19248 /** 19249 * @param optionalData old optional data format as int array 19250 * @deprecated parse and use new fields 19251 */ 19252 // @Deprecated 19253 setOptionalData(optionalData) { 19254 this.optionalData = optionalData; 19255 } 19256 /** 19257 * @return true if it is the last segment 19258 */ 19259 isLastSegment() { 19260 return this.lastSegment; 19261 } 19262 setLastSegment(lastSegment) { 19263 this.lastSegment = lastSegment; 19264 } 19265 /** 19266 * @return count of segments, -1 if not set 19267 */ 19268 getSegmentCount() { 19269 return this.segmentCount; 19270 } 19271 setSegmentCount(segmentCount /*int*/) { 19272 this.segmentCount = segmentCount; 19273 } 19274 getSender() { 19275 return this.sender || null; 19276 } 19277 setSender(sender) { 19278 this.sender = sender; 19279 } 19280 getAddressee() { 19281 return this.addressee || null; 19282 } 19283 setAddressee(addressee) { 19284 this.addressee = addressee; 19285 } 19286 /** 19287 * Filename of the encoded file 19288 * 19289 * @return filename 19290 */ 19291 getFileName() { 19292 return this.fileName; 19293 } 19294 setFileName(fileName) { 19295 this.fileName = fileName; 19296 } 19297 /** 19298 * filesize in bytes of the encoded file 19299 * 19300 * @return filesize in bytes, -1 if not set 19301 */ 19302 getFileSize() { 19303 return this.fileSize; 19304 } 19305 setFileSize(fileSize /*long*/) { 19306 this.fileSize = fileSize; 19307 } 19308 /** 19309 * 16-bit CRC checksum using CCITT-16 19310 * 19311 * @return crc checksum, -1 if not set 19312 */ 19313 getChecksum() { 19314 return this.checksum; 19315 } 19316 setChecksum(checksum /*int*/) { 19317 this.checksum = checksum; 19318 } 19319 /** 19320 * unix epock timestamp, elapsed seconds since 1970-01-01 19321 * 19322 * @return elapsed seconds, -1 if not set 19323 */ 19324 getTimestamp() { 19325 return this.timestamp; 19326 } 19327 setTimestamp(timestamp /*long*/) { 19328 this.timestamp = timestamp; 19329 } 19330 } 19331 19332 /** 19333 * Ponyfill for Java's Long class. 19334 */ 19335 class Long { 19336 /** 19337 * Parses a string to a number, since JS has no really Int64. 19338 * 19339 * @param num Numeric string. 19340 * @param radix Destination radix. 19341 */ 19342 static parseLong(num, radix = undefined) { 19343 return parseInt(num, radix); 19344 } 19345 } 19346 19347 /** 19348 * Custom Error class of type Exception. 19349 */ 19350 class NullPointerException extends Exception { 19351 } 19352 NullPointerException.kind = 'NullPointerException'; 19353 19354 /* 19355 * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved. 19356 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 19357 * 19358 * This code is free software; you can redistribute it and/or modify it 19359 * under the terms of the GNU General Public License version 2 only, as 19360 * published by the Free Software Foundation. Oracle designates this 19361 * particular file as subject to the "Classpath" exception as provided 19362 * by Oracle in the LICENSE file that accompanied this code. 19363 * 19364 * This code is distributed in the hope that it will be useful, but WITHOUT 19365 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 19366 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 19367 * version 2 for more details (a copy is included in the LICENSE file that 19368 * accompanied this code). 19369 * 19370 * You should have received a copy of the GNU General Public License version 19371 * 2 along with this work; if not, write to the Free Software Foundation, 19372 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19373 * 19374 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19375 * or visit www.oracle.com if you need additional information or have any 19376 * questions. 19377 */ 19378 // package java.io; 19379 /** 19380 * This abstract class is the superclass of all classes representing 19381 * an output stream of bytes. An output stream accepts output bytes 19382 * and sends them to some sink. 19383 * <p> 19384 * Applications that need to define a subclass of 19385 * <code>OutputStream</code> must always provide at least a method 19386 * that writes one byte of output. 19387 * 19388 * @author Arthur van Hoff 19389 * @see java.io.BufferedOutputStream 19390 * @see java.io.ByteArrayOutputStream 19391 * @see java.io.DataOutputStream 19392 * @see java.io.FilterOutputStream 19393 * @see java.io.InputStream 19394 * @see java.io.OutputStream#write(int) 19395 * @since JDK1.0 19396 */ 19397 /*public*/ class OutputStream /*implements Closeable, Flushable*/ { 19398 /** 19399 * Writes <code>b.length</code> bytes from the specified byte array 19400 * to this output stream. The general contract for <code>write(b)</code> 19401 * is that it should have exactly the same effect as the call 19402 * <code>write(b, 0, b.length)</code>. 19403 * 19404 * @param b the data. 19405 * @exception IOException if an I/O error occurs. 19406 * @see java.io.OutputStream#write(byte[], int, int) 19407 */ 19408 writeBytes(b) { 19409 this.writeBytesOffset(b, 0, b.length); 19410 } 19411 /** 19412 * Writes <code>len</code> bytes from the specified byte array 19413 * starting at offset <code>off</code> to this output stream. 19414 * The general contract for <code>write(b, off, len)</code> is that 19415 * some of the bytes in the array <code>b</code> are written to the 19416 * output stream in order; element <code>b[off]</code> is the first 19417 * byte written and <code>b[off+len-1]</code> is the last byte written 19418 * by this operation. 19419 * <p> 19420 * The <code>write</code> method of <code>OutputStream</code> calls 19421 * the write method of one argument on each of the bytes to be 19422 * written out. Subclasses are encouraged to override this method and 19423 * provide a more efficient implementation. 19424 * <p> 19425 * If <code>b</code> is <code>null</code>, a 19426 * <code>NullPointerException</code> is thrown. 19427 * <p> 19428 * If <code>off</code> is negative, or <code>len</code> is negative, or 19429 * <code>off+len</code> is greater than the length of the array 19430 * <code>b</code>, then an <tt>IndexOutOfBoundsException</tt> is thrown. 19431 * 19432 * @param b the data. 19433 * @param off the start offset in the data. 19434 * @param len the number of bytes to write. 19435 * @exception IOException if an I/O error occurs. In particular, 19436 * an <code>IOException</code> is thrown if the output 19437 * stream is closed. 19438 */ 19439 writeBytesOffset(b, off, len) { 19440 if (b == null) { 19441 throw new NullPointerException(); 19442 } 19443 else if ((off < 0) || (off > b.length) || (len < 0) || 19444 ((off + len) > b.length) || ((off + len) < 0)) { 19445 throw new IndexOutOfBoundsException(); 19446 } 19447 else if (len === 0) { 19448 return; 19449 } 19450 for (let i = 0; i < len; i++) { 19451 this.write(b[off + i]); 19452 } 19453 } 19454 /** 19455 * Flushes this output stream and forces any buffered output bytes 19456 * to be written out. The general contract of <code>flush</code> is 19457 * that calling it is an indication that, if any bytes previously 19458 * written have been buffered by the implementation of the output 19459 * stream, such bytes should immediately be written to their 19460 * intended destination. 19461 * <p> 19462 * If the intended destination of this stream is an abstraction provided by 19463 * the underlying operating system, for example a file, then flushing the 19464 * stream guarantees only that bytes previously written to the stream are 19465 * passed to the operating system for writing; it does not guarantee that 19466 * they are actually written to a physical device such as a disk drive. 19467 * <p> 19468 * The <code>flush</code> method of <code>OutputStream</code> does nothing. 19469 * 19470 * @exception IOException if an I/O error occurs. 19471 */ 19472 flush() { 19473 } 19474 /** 19475 * Closes this output stream and releases any system resources 19476 * associated with this stream. The general contract of <code>close</code> 19477 * is that it closes the output stream. A closed stream cannot perform 19478 * output operations and cannot be reopened. 19479 * <p> 19480 * The <code>close</code> method of <code>OutputStream</code> does nothing. 19481 * 19482 * @exception IOException if an I/O error occurs. 19483 */ 19484 close() { 19485 } 19486 } 19487 19488 /** 19489 * Custom Error class of type Exception. 19490 */ 19491 class OutOfMemoryError extends Exception { 19492 } 19493 19494 /* 19495 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. 19496 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 19497 * 19498 * This code is free software; you can redistribute it and/or modify it 19499 * under the terms of the GNU General Public License version 2 only, as 19500 * published by the Free Software Foundation. Oracle designates this 19501 * particular file as subject to the "Classpath" exception as provided 19502 * by Oracle in the LICENSE file that accompanied this code. 19503 * 19504 * This code is distributed in the hope that it will be useful, but WITHOUT 19505 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 19506 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 19507 * version 2 for more details (a copy is included in the LICENSE file that 19508 * accompanied this code). 19509 * 19510 * You should have received a copy of the GNU General Public License version 19511 * 2 along with this work; if not, write to the Free Software Foundation, 19512 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19513 * 19514 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19515 * or visit www.oracle.com if you need additional information or have any 19516 * questions. 19517 */ 19518 /
19518** 19519 * This class implements an output stream in which the data is 19520 * written into a byte array. The buffer automatically grows as data 19521 * is written to it. 19522 * The data can be retrieved using <code>toByteArray()</code> and 19523 * <code>toString()</code>. 19524 * <p> 19525 * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in 19526 * this class can be called after the stream has been closed without 19527 * generating an <tt>IOException</tt>. 19528 * 19529 * @author Arthur van Hoff 19530 * @since JDK1.0 19531 */ 19532 /*public*/ class ByteArrayOutputStream extends OutputStream { 19533 /** 19534 * Creates a new byte array output stream. The buffer capacity is 19535 * initially 32 bytes, though its size increases if necessary. 19536 */ 19537 // public constructor() { 19538 // this(32); 19539 // } 19540 /** 19541 * Creates a new byte array output stream, with a buffer capacity of 19542 * the specified size, in bytes. 19543 * 19544 * @param size the initial size. 19545 * @exception IllegalArgumentException if size is negative. 19546 */ 19547 constructor(size = 32) { 19548 super(); 19549 /** 19550 * The number of valid bytes in the buffer. 19551 */ 19552 this.count = 0; 19553 if (size < 0) { 19554 throw new IllegalArgumentException('Negative initial size: ' 19555 + size); 19556 } 19557 this.buf = new Uint8Array(size); 19558 } 19559 /** 19560 * Increases the capacity if necessary to ensure that it can hold 19561 * at least the number of elements specified by the minimum 19562 * capacity argument. 19563 * 19564 * @param minCapacity the desired minimum capacity 19565 * @throws OutOfMemoryError if {@code minCapacity < 0}. This is 19566 * interpreted as a request for the unsatisfiably large capacity 19567 * {@code (long) Integer.MAX_VALUE + (minCapacity - Integer.MAX_VALUE)}. 19568 */ 19569 ensureCapacity(minCapacity) { 19570 // overflow-conscious code 19571 if (minCapacity - this.buf.length > 0) 19572 this.grow(minCapacity); 19573 } 19574 /** 19575 * Increases the capacity to ensure that it can hold at least the 19576 * number of elements specified by the minimum capacity argument. 19577 * 19578 * @param minCapacity the desired minimum capacity 19579 */ 19580 grow(minCapacity) { 19581 // overflow-conscious code 19582 let oldCapacity = this.buf.length; 19583 let newCapacity = oldCapacity << 1; 19584 if (newCapacity - minCapacity < 0) 19585 newCapacity = minCapacity; 19586 if (newCapacity < 0) { 19587 if (minCapacity < 0) // overflow 19588 throw new OutOfMemoryError(); 19589 newCapacity = Integer.MAX_VALUE; 19590 } 19591 this.buf = Arrays.copyOfUint8Array(this.buf, newCapacity); 19592 } 19593 /** 19594 * Writes the specified byte to this byte array output stream. 19595 * 19596 * @param b the byte to be written. 19597 */ 19598 write(b) { 19599 this.ensureCapacity(this.count + 1); 19600 this.buf[this.count] = /*(byte)*/ b; 19601 this.count += 1; 19602 } 19603 /** 19604 * Writes <code>len</code> bytes from the specified byte array 19605 * starting at offset <code>off</code> to this byte array output stream. 19606 * 19607 * @param b the data. 19608 * @param off the start offset in the data. 19609 * @param len the number of bytes to write. 19610 */ 19611 writeBytesOffset(b, off, len) { 19612 if ((off < 0) || (off > b.length) || (len < 0) || 19613 ((off + len) - b.length > 0)) { 19614 throw new IndexOutOfBoundsException(); 19615 } 19616 this.ensureCapacity(this.count + len); 19617 System.arraycopy(b, off, this.buf, this.count, len); 19618 this.count += len; 19619 } 19620 /** 19621 * Writes the complete contents of this byte array output stream to 19622 * the specified output stream argument, as if by calling the output 19623 * stream's write method using <code>out.write(buf, 0, count)</code>. 19624 * 19625 * @param out the output stream to which to write the data. 19626 * @exception IOException if an I/O error occurs. 19627 */ 19628 writeTo(out) { 19629 out.writeBytesOffset(this.buf, 0, this.count); 19630 } 19631 /** 19632 * Resets the <code>count</code> field of this byte array output 19633 * stream to zero, so that all currently accumulated output in the 19634 * output stream is discarded. The output stream can be used again, 19635 * reusing the already allocated buffer space. 19636 * 19637 * @see java.io.ByteArrayInputStream#count 19638 */ 19639 reset() { 19640 this.count = 0; 19641 } 19642 /** 19643 * Creates a newly allocated byte array. Its size is the current 19644 * size of this output stream and the valid contents of the buffer 19645 * have been copied into it. 19646 * 19647 * @return the current contents of this output stream, as a byte array. 19648 * @see java.io.ByteArrayOutputStream#size() 19649 */ 19650 toByteArray() { 19651 return Arrays.copyOfUint8Array(this.buf, this.count); 19652 } 19653 /** 19654 * Returns the current size of the buffer. 19655 * 19656 * @return the value of the <code>count</code> field, which is the number 19657 * of valid bytes in this output stream. 19658 * @see java.io.ByteArrayOutputStream#count 19659 */ 19660 size() { 19661 return this.count; 19662 } 19663 toString(param) { 19664 if (!param) { 19665 return this.toString_void(); 19666 } 19667 if (typeof param === 'string') { 19668 return this.toString_string(param); 19669 } 19670 return this.toString_number(param); 19671 } 19672 /** 19673 * Converts the buffer's contents into a string decoding bytes using the 19674 * platform's default character set. The length of the new <tt>String</tt> 19675 * is a function of the character set, and hence may not be equal to the 19676 * size of the buffer. 19677 * 19678 * <p> This method always replaces malformed-input and unmappable-character 19679 * sequences with the default replacement string for the platform's 19680 * default character set. The {@linkplain java.nio.charset.CharsetDecoder} 19681 * class should be used when more control over the decoding process is 19682 * required. 19683 * 19684 * @return String decoded from the buffer's contents. 19685 * @since JDK1.1 19686 */ 19687 toString_void() { 19688 return new String(this.buf /*, 0, this.count*/).toString(); 19689 } 19690 /** 19691 * Converts the buffer's contents into a string by decoding the bytes using 19692 * the specified {@link java.nio.charset.Charset charsetName}. The length of 19693 * the new <tt>String</tt> is a function of the charset, and hence may not be 19694 * equal to the length of the byte array. 19695 * 19696 * <p> This method always replaces malformed-input and unmappable-character 19697 * sequences with this charset's default replacement string. The {@link 19698 * java.nio.charset.CharsetDecoder} class should be used when more control 19699 * over the decoding process is required. 19700 * 19701 * @param charsetName the name of a supported 19702 * {@linkplain java.nio.charset.Charset </code>charset<code>} 19703 * @return String decoded from the buffer's contents. 19704 * @exception UnsupportedEncodingException 19705 * If the named charset is not supported 19706 * @since JDK1.1 19707 */ 19708 toString_string(charsetName) { 19709 return new String(this.buf /*, 0, this.count, charsetName*/).toString(); 19710 } 19711 /** 19712 * Creates a newly allocated string. Its size is the current size of 19713 * the output stream and the valid contents of the buffer have been
19714 * copied into it. Each character <i>c</i> in the resulting string is 19715 * constructed from the corresponding element <i>b</i> in the byte 19716 * array such that: 19717 * <blockquote><pre> 19718 * c == (char)(((hibyte & 0xff) << 8) | (b & 0xff)) 19719 * </pre></blockquote> 19720 * 19721 * @deprecated This method does not properly convert bytes into characters. 19722 * As of JDK 1.1, the preferred way to do this is via the 19723 * <code>toString(String enc)</code> method, which takes an encoding-name 19724 * argument, or the <code>toString()</code> method, which uses the 19725 * platform's default character encoding. 19726 * 19727 * @param hibyte the high byte of each resulting Unicode character. 19728 * @return the current contents of the output stream, as a string. 19729 * @see java.io.ByteArrayOutputStream#size() 19730 * @see java.io.ByteArrayOutputStream#toString(String) 19731 * @see java.io.ByteArrayOutputStream#toString() 19732 */ 19733 // @Deprecated 19734 toString_number(hibyte) { 19735 return new String(this.buf /*, hibyte, 0, this.count*/).toString(); 19736 } 19737 /** 19738 * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in 19739 * this class can be called after the stream has been closed without 19740 * generating an <tt>IOException</tt>. 19741 * <p> 19742 * 19743 * @throws IOException 19744 */ 19745 close() { 19746 } 19747 } 19748 19749 /* 19750 * Copyright 2009 ZXing authors 19751 * 19752 * Licensed under the Apache License, Version 2.0 (the "License"); 19753 * you may not use this file except in compliance with the License. 19754 * You may obtain a copy of the License at 19755 * 19756 * http://www.apache.org/licenses/LICENSE-2.0 19757 * 19758 * Unless required by applicable law or agreed to in writing, software 19759 * distributed under the License is distributed on an "AS IS" BASIS, 19760 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19761 * See the License for the specific language governing permissions and 19762 * limitations under the License. 19763 */ 19764 /*private*/ var Mode$1; 19765 (function (Mode) { 19766 Mode[Mode["ALPHA"] = 0] = "ALPHA"; 19767 Mode[Mode["LOWER"] = 1] = "LOWER"; 19768 Mode[Mode["MIXED"] = 2] = "MIXED"; 19769 Mode[Mode["PUNCT"] = 3] = "PUNCT"; 19770 Mode[Mode["ALPHA_SHIFT"] = 4] = "ALPHA_SHIFT"; 19771 Mode[Mode["PUNCT_SHIFT"] = 5] = "PUNCT_SHIFT"; 19772 })(Mode$1 || (Mode$1 = {})); 19773 /** 19774 * Indirectly access the global BigInt constructor, it 19775 * allows browsers that doesn't support BigInt to run 19776 * the library without breaking due to "undefined BigInt" 19777 * errors. 19778 */ 19779 function getBigIntConstructor() { 19780 if (typeof window !== 'undefined') { 19781 return window['BigInt'] || null; 19782 } 19783 if (typeof global !== 'undefined') { 19784 return global['BigInt'] || null; 19785 } 19786 if (typeof self !== 'undefined') { 19787 return self['BigInt'] || null; 19788 } 19789 throw new Error('Can\'t search globals for BigInt!'); 19790 } 19791 /** 19792 * Used to store the BigInt constructor. 19793 */ 19794 let BigInteger; 19795 /** 19796 * This function creates a bigint value. It allows browsers 19797 * that doesn't support BigInt to run the rest of the library 19798 * by not directly accessing the BigInt constructor. 19799 */ 19800 function createBigInt(num) { 19801 if (typeof BigInteger === 'undefined') { 19802 BigInteger = getBigIntConstructor(); 19803 } 19804 if (BigInteger === null) { 19805 throw new Error('BigInt is not supported!'); 19806 } 19807 return BigInteger(num); 19808 } 19809 function getEXP900() { 19810 // in Java - array with length = 16 19811 let EXP900 = []; 19812 EXP900[0] = createBigInt(1); 19813 let nineHundred = createBigInt(900); 19814 EXP900[1] = nineHundred; 19815 // in Java - array with length = 16 19816 for (let i /*int*/ = 2; i < 16; i++) { 19817 EXP900[i] = EXP900[i - 1] * nineHundred; 19818 } 19819 return EXP900; 19820 } 19821 /** 19822 * <p>This class contains the methods for decoding the PDF417 codewords.</p> 19823 * 19824 * @author SITA Lab ([email protected]) 19825 * @author Guenther Grau 19826 */ 19827 /*final*/
vendor: 14,720 bytes, lines 19827-20086
19827 class DecodedBitStreamParser { 19828 // private DecodedBitStreamParser() { 19829 // } 19830 /** 19831 * 19832 * @param codewords 19833 * @param ecLevel 19834 * 19835 * @throws FormatException 19836 */ 19837 static decode(codewords, ecLevel) { 19838 // pass encoding to result (will be used for decode symbols in byte mode) 19839 let result = new StringBuilder(''); 19840 // let encoding: Charset = StandardCharsets.ISO_8859_1; 19841 let encoding = CharacterSetECI.ISO8859_1; 19842 /** 19843 * @note the next command is specific from this TypeScript library 19844 * because TS can't properly cast some values to char and 19845 * convert it to string later correctly due to encoding 19846 * differences from Java version. As reported here: 19847 * https://github.com/zxing-js/library/pull/264/files#r382831593 19848 */ 19849 result.enableDecoding(encoding); 19850 // Get compaction mode 19851 let codeIndex = 1; 19852 let code = codewords[codeIndex++]; 19853 let resultMetadata = new PDF417ResultMetadata(); 19854 while (codeIndex < codewords[0]) { 19855 switch (code) { 19856 case DecodedBitStreamParser.TEXT_COMPACTION_MODE_LATCH: 19857 codeIndex = DecodedBitStreamParser.textCompaction(codewords, codeIndex, result); 19858 break; 19859 case DecodedBitStreamParser.BYTE_COMPACTION_MODE_LATCH: 19860 case DecodedBitStreamParser.BYTE_COMPACTION_MODE_LATCH_6: 19861 codeIndex = DecodedBitStreamParser.byteCompaction(code, codewords, encoding, codeIndex, result); 19862 break; 19863 case DecodedBitStreamParser.MODE_SHIFT_TO_BYTE_COMPACTION_MODE: 19864 result.append(/*(char)*/ codewords[codeIndex++]); 19865 break; 19866 case DecodedBitStreamParser.NUMERIC_COMPACTION_MODE_LATCH: 19867 codeIndex = DecodedBitStreamParser.numericCompaction(codewords, codeIndex, result); 19868 break; 19869 case DecodedBitStreamParser.ECI_CHARSET: 19870 CharacterSetECI.getCharacterSetECIByValue(codewords[codeIndex++]); 19871 // encoding = Charset.forName(charsetECI.getName()); 19872 break; 19873 case DecodedBitStreamParser.ECI_GENERAL_PURPOSE: 19874 // Can't do anything with generic ECI; skip its 2 characters 19875 codeIndex += 2; 19876 break; 19877 case DecodedBitStreamParser.ECI_USER_DEFINED: 19878 // Can't do anything with user ECI; skip its 1 character 19879 codeIndex++; 19880 break; 19881 case DecodedBitStreamParser.BEGIN_MACRO_PDF417_CONTROL_BLOCK: 19882 codeIndex = DecodedBitStreamParser.decodeMacroBlock(codewords, codeIndex, resultMetadata); 19883 break; 19884 case DecodedBitStreamParser.BEGIN_MACRO_PDF417_OPTIONAL_FIELD: 19885 case DecodedBitStreamParser.MACRO_PDF417_TERMINATOR: 19886 // Should not see these outside a macro block 19887 throw new FormatException(); 19888 default: 19889 // Default to text compaction. During testing numerous barcodes 19890 // appeared to be missing the starting mode. In these cases defaulting 19891 // to text compaction seems to work. 19892 codeIndex--; 19893 codeIndex = DecodedBitStreamParser.textCompaction(codewords, codeIndex, result); 19894 break; 19895 } 19896 if (codeIndex < codewords.length) { 19897 code = codewords[codeIndex++]; 19898 } 19899 else { 19900 throw FormatException.getFormatInstance(); 19901 } 19902 } 19903 if (result.length() === 0) { 19904 throw FormatException.getFormatInstance(); 19905 } 19906 let decoderResult = new DecoderResult(null, result.toString(), null, ecLevel); 19907 decoderResult.setOther(resultMetadata); 19908 return decoderResult; 19909 } 19910 /** 19911 * 19912 * @param int 19913 * @param param1 19914 * @param codewords 19915 * @param int 19916 * @param codeIndex 19917 * @param PDF417ResultMetadata 19918 * @param resultMetadata 19919 * 19920 * @throws FormatException 19921 */ 19922 // @SuppressWarnings("deprecation") 19923 static decodeMacroBlock(codewords, codeIndex, resultMetadata) { 19924 if (codeIndex + DecodedBitStreamParser.NUMBER_OF_SEQUENCE_CODEWORDS > codewords[0]) { 19925 // we must have at least two bytes left for the segment index 19926 throw FormatException.getFormatInstance(); 19927 } 19928 let segmentIndexArray = new Int32Array(DecodedBitStreamParser.NUMBER_OF_SEQUENCE_CODEWORDS); 19929 for (let i /*int*/ = 0; i < DecodedBitStreamParser.NUMBER_OF_SEQUENCE_CODEWORDS; i++, codeIndex++) { 19930 segmentIndexArray[i] = codewords[codeIndex]; 19931 } 19932 resultMetadata.setSegmentIndex(Integer.parseInt(DecodedBitStreamParser.decodeBase900toBase10(segmentIndexArray, DecodedBitStreamParser.NUMBER_OF_SEQUENCE_CODEWORDS))); 19933 let fileId = new StringBuilder(); 19934 codeIndex = DecodedBitStreamParser.textCompaction(codewords, codeIndex, fileId); 19935 resultMetadata.setFileId(fileId.toString()); 19936 let optionalFieldsStart = -1; 19937 if (codewords[codeIndex] === DecodedBitStreamParser.BEGIN_MACRO_PDF417_OPTIONAL_FIELD) { 19938 optionalFieldsStart = codeIndex + 1; 19939 } 19940 while (codeIndex < codewords[0]) { 19941 switch (codewords[codeIndex]) { 19942 case DecodedBitStreamParser.BEGIN_MACRO_PDF417_OPTIONAL_FIELD: 19943 codeIndex++; 19944 switch (codewords[codeIndex]) { 19945 case DecodedBitStreamParser.MACRO_PDF417_OPTIONAL_FIELD_FILE_NAME: 19946 let fileName = new StringBuilder(); 19947 codeIndex = DecodedBitStreamParser.textCompaction(codewords, codeIndex + 1, fileName); 19948 resultMetadata.setFileName(fileName.toString()); 19949 break; 19950 case DecodedBitStreamParser.MACRO_PDF417_OPTIONAL_FIELD_SENDER: 19951 let sender = new StringBuilder(); 19952 codeIndex = DecodedBitStreamParser.textCompaction(codewords, codeIndex + 1, sender); 19953 resultMetadata.setSender(sender.toString()); 19954 break; 19955 case DecodedBitStreamParser.MACRO_PDF417_OPTIONAL_FIELD_ADDRESSEE: 19956 let addressee = new StringBuilder(); 19957 codeIndex = DecodedBitStreamParser.textCompaction(codewords, codeIndex + 1, addressee); 19958 resultMetadata.setAddressee(addressee.toString()); 19959 break; 19960 case DecodedBitStreamParser.MACRO_PDF417_OPTIONAL_FIELD_SEGMENT_COUNT: 19961 let segmentCount = new StringBuilder(); 19962 codeIndex = DecodedBitStreamParser.numericCompaction(codewords, codeIndex + 1, segmentCount); 19963 resultMetadata.setSegmentCount(Integer.parseInt(segmentCount.toString())); 19964 break; 19965 case DecodedBitStreamParser.MACRO_PDF417_OPTIONAL_FIELD_TIME_STAMP: 19966 let timestamp = new StringBuilder(); 19967 codeIndex = DecodedBitStreamParser.numericCompaction(codewords, codeIndex + 1, timestamp); 19968 resultMetadata.setTimestamp(Long.parseLong(timestamp.toString())); 19969 break; 19970 case DecodedBitStreamParser.MACRO_PDF417_OPTIONAL_FIELD_CHECKSUM: 19971 let checksum = new StringBuilder(); 19972 codeIndex = DecodedBitStreamParser.numericCompaction(codewords, codeIndex + 1, checksum); 19973 resultMetadata.setChecksum(Integer.parseInt(checksum.toString())); 19974 break; 19975 case DecodedBitStreamParser.MACRO_PDF417_OPTIONAL_FIELD_FILE_SIZE: 19976 let fileSize = new StringBuilder(); 19977 codeIndex = DecodedBitStreamParser.numericCompaction(codewords, codeIndex + 1, fileSize); 19978 resultMetadata.setFileSize(Long.parseLong(fileSize.toString())); 19979 break; 19980 default: 19981 throw FormatException.getFormatInstance(); 19982 } 19983 break; 19984 case DecodedBitStreamParser.MACRO_PDF417_TERMINATOR: 19985 codeIndex++; 19986 resultMetadata.setLastSegment(true); 19987 break; 19988 default: 19989 throw FormatException.getFormatInstance(); 19990 } 19991 } 19992 // copy optional fields to additional options 19993 if (optionalFieldsStart !== -1) { 19994 let optionalFieldsLength = codeIndex - optionalFieldsStart; 19995 if (resultMetadata.isLastSegment()) { 19996 // do not include terminator 19997 optionalFieldsLength--; 19998 } 19999 resultMetadata.setOptionalData(Arrays.copyOfRange(codewords, optionalFieldsStart, optionalFieldsStart + optionalFieldsLength)); 20000 } 20001 return codeIndex; 20002 } 20003 /** 20004 * Text Compaction mode (see 5.4.1.5) permits all printable ASCII characters to be 20005 * encoded, i.e. values 32 - 126 inclusive in accordance with ISO/IEC 646 (IRV), as 20006 * well as selected control characters. 20007 * 20008 * @param codewords The array of codewords (data + error) 20009 * @param codeIndex The current index into the codeword array. 20010 * @param result The decoded data is appended to the result. 20011 * @return The next index into the codeword array. 20012 */ 20013 static textCompaction(codewords, codeIndex, result) { 20014 // 2 character per codeword 20015 let textCompactionData = new Int32Array((codewords[0] - codeIndex) * 2); 20016 // Used to hold the byte compaction value if there is a mode shift 20017 let byteCompactionData = new Int32Array((codewords[0] - codeIndex) * 2); 20018 let index = 0; 20019 let end = false; 20020 while ((codeIndex < codewords[0]) && !end) { 20021 let code = codewords[codeIndex++]; 20022 if (code < DecodedBitStreamParser.TEXT_COMPACTION_MODE_LATCH) { 20023 textCompactionData[index] = code / 30; 20024 textCompactionData[index + 1] = code % 30; 20025 index += 2; 20026 } 20027 else { 20028 switch (code) { 20029 case DecodedBitStreamParser.TEXT_COMPACTION_MODE_LATCH: 20030 // reinitialize text compaction mode to alpha sub mode 20031 textCompactionData[index++] = DecodedBitStreamParser.TEXT_COMPACTION_MODE_LATCH; 20032 break; 20033 case DecodedBitStreamParser.BYTE_COMPACTION_MODE_LATCH: 20034 case DecodedBitStreamParser.BYTE_COMPACTION_MODE_LATCH_6: 20035 case DecodedBitStreamParser.NUMERIC_COMPACTION_MODE_LATCH: 20036 case DecodedBitStreamParser.BEGIN_MACRO_PDF417_CONTROL_BLOCK: 20037 case DecodedBitStreamParser.BEGIN_MACRO_PDF417_OPTIONAL_FIELD: 20038 case DecodedBitStreamParser.MACRO_PDF417_TERMINATOR: 20039 codeIndex--; 20040 end = true; 20041 break; 20042 case DecodedBitStreamParser.MODE_SHIFT_TO_BYTE_COMPACTION_MODE: 20043 // The Mode Shift codeword 913 shall cause a temporary 20044 // switch from Text Compaction mode to Byte Compaction mode. 20045 // This switch shall be in effect for only the next codeword, 20046 // after which the mode shall revert to the prevailing sub-mode 20047 // of the Text Compaction mode. Codeword 913 is only available 20048 // in Text Compaction mode; its use is described in 5.4.2.4. 20049 textCompactionData[index] = DecodedBitStreamParser.MODE_SHIFT_TO_BYTE_COMPACTION_MODE; 20050 code = codewords[codeIndex++]; 20051 byteCompactionData[index] = code; 20052 index++; 20053 break; 20054 } 20055 } 20056 } 20057 DecodedBitStreamParser.decodeTextCompaction(textCompactionData, byteCompactionData, index, result); 20058 return codeIndex; 20059 } 20060 /** 20061 * The Text Compaction mode includes all the printable ASCII characters 20062 * (i.e. values from 32 to 126) and three ASCII control characters: HT or tab 20063 * (9: e), LF or line feed (10: e), and CR or carriage 20064 * return (13: e). The Text Compaction mode also includes various latch 20065 * and shift characters which are used exclusively within the mode. The Text 20066 * Compaction mode encodes up to 2 characters per codeword. The compaction rules 20067 * for converting data into PDF417 codewords are defined in 5.4.2.2. The sub-mode 20068 * switches are defined in 5.4.2.3. 20069 * 20070 * @param textCompactionData The text compaction data. 20071 * @param byteCompactionData The byte compaction data if there 20072 * was a mode shift. 20073 * @param length The size of the text compaction and byte compaction data. 20074 * @param result The decoded data is appended to the result. 20075 */ 20076 static decodeTextCompaction(textCompactionData, byteCompactionData, length, result) { 20077 // Beginning from an initial state of the Alpha sub-mode 20078 // The default compaction mode for PDF417 in effect at the start of each symbol shall always be Text 20079 // Compaction mode Alpha sub-mode (alphabetic: uppercase). A latch codeword from another mode to the Text 20080 // Compaction mode shall always switch to the Text Compaction Alpha sub-mode. 20081 let subMode = Mode$1.ALPHA; 20082 let priorToShiftMode = Mode$1.ALPHA; 20083 let i = 0; 20084 while (i < length) { 20085 let subModeCh = textCompactionData[i]; 20086 let ch =
20086/*char*/
vendor: 9,215 bytes, lines 20086-20268
20086 ''; 20087 switch (subMode) { 20088 case Mode$1.ALPHA: 20089 // Alpha (alphabetic: uppercase) 20090 if (subModeCh < 26) { 20091 // Upper case Alpha Character 20092 // Note: 65 = 'A' ASCII -> there is byte code of symbol 20093 ch = /*(char)('A' + subModeCh) */ String.fromCharCode(65 + subModeCh); 20094 } 20095 else { 20096 switch (subModeCh) { 20097 case 26: 20098 ch = ' '; 20099 break; 20100 case DecodedBitStreamParser.LL: 20101 subMode = Mode$1.LOWER; 20102 break; 20103 case DecodedBitStreamParser.ML: 20104 subMode = Mode$1.MIXED; 20105 break; 20106 case DecodedBitStreamParser.PS: 20107 // Shift to punctuation 20108 priorToShiftMode = subMode; 20109 subMode = Mode$1.PUNCT_SHIFT; 20110 break; 20111 case DecodedBitStreamParser.MODE_SHIFT_TO_BYTE_COMPACTION_MODE: 20112 result.append(/*(char)*/ byteCompactionData[i]); 20113 break; 20114 case DecodedBitStreamParser.TEXT_COMPACTION_MODE_LATCH: 20115 subMode = Mode$1.ALPHA; 20116 break; 20117 } 20118 } 20119 break; 20120 case Mode$1.LOWER: 20121 // Lower (alphabetic: lowercase) 20122 if (subModeCh < 26) { 20123 ch = /*(char)('a' + subModeCh)*/ String.fromCharCode(97 + subModeCh); 20124 } 20125 else { 20126 switch (subModeCh) { 20127 case 26: 20128 ch = ' '; 20129 break; 20130 case DecodedBitStreamParser.AS: 20131 // Shift to alpha 20132 priorToShiftMode = subMode; 20133 subMode = Mode$1.ALPHA_SHIFT; 20134 break; 20135 case DecodedBitStreamParser.ML: 20136 subMode = Mode$1.MIXED; 20137 break; 20138 case DecodedBitStreamParser.PS: 20139 // Shift to punctuation 20140 priorToShiftMode = subMode; 20141 subMode = Mode$1.PUNCT_SHIFT; 20142 break; 20143 case DecodedBitStreamParser.MODE_SHIFT_TO_BYTE_COMPACTION_MODE: 20144 // TODO Does this need to use the current character encoding? See other occurrences below 20145 result.append(/*(char)*/ byteCompactionData[i]); 20146 break; 20147 case DecodedBitStreamParser.TEXT_COMPACTION_MODE_LATCH: 20148 subMode = Mode$1.ALPHA; 20149 break; 20150 } 20151 } 20152 break; 20153 case Mode$1.MIXED: 20154 // Mixed (punctuation: e) 20155 if (subModeCh < DecodedBitStreamParser.PL) { 20156 ch = DecodedBitStreamParser.MIXED_CHARS[subModeCh]; 20157 } 20158 else { 20159 switch (subModeCh) { 20160 case DecodedBitStreamParser.PL: 20161 subMode = Mode$1.PUNCT; 20162 break; 20163 case 26: 20164 ch = ' '; 20165 break; 20166 case DecodedBitStreamParser.LL: 20167 subMode = Mode$1.LOWER; 20168 break; 20169 case DecodedBitStreamParser.AL: 20170 subMode = Mode$1.ALPHA; 20171 break; 20172 case DecodedBitStreamParser.PS: 20173 // Shift to punctuation 20174 priorToShiftMode = subMode; 20175 subMode = Mode$1.PUNCT_SHIFT; 20176 break; 20177 case DecodedBitStreamParser.MODE_SHIFT_TO_BYTE_COMPACTION_MODE: 20178 result.append(/*(char)*/ byteCompactionData[i]); 20179 break; 20180 case DecodedBitStreamParser.TEXT_COMPACTION_MODE_LATCH: 20181 subMode = Mode$1.ALPHA; 20182 break; 20183 } 20184 } 20185 break; 20186 case Mode$1.PUNCT: 20187 // Punctuation 20188 if (subModeCh < DecodedBitStreamParser.PAL) { 20189 ch = DecodedBitStreamParser.PUNCT_CHARS[subModeCh]; 20190 } 20191 else { 20192 switch (subModeCh) { 20193 case DecodedBitStreamParser.PAL: 20194 subMode = Mode$1.ALPHA; 20195 break; 20196 case DecodedBitStreamParser.MODE_SHIFT_TO_BYTE_COMPACTION_MODE: 20197 result.append(/*(char)*/ byteCompactionData[i]); 20198 break; 20199 case DecodedBitStreamParser.TEXT_COMPACTION_MODE_LATCH: 20200 subMode = Mode$1.ALPHA; 20201 break; 20202 } 20203 } 20204 break; 20205 case Mode$1.ALPHA_SHIFT: 20206 // Restore sub-mode 20207 subMode = priorToShiftMode; 20208 if (subModeCh < 26) { 20209 ch = /*(char)('A' + subModeCh)*/ String.fromCharCode(65 + subModeCh); 20210 } 20211 else { 20212 switch (subModeCh) { 20213 case 26: 20214 ch = ' '; 20215 break; 20216 case DecodedBitStreamParser.TEXT_COMPACTION_MODE_LATCH: 20217 subMode = Mode$1.ALPHA; 20218 break; 20219 } 20220 } 20221 break; 20222 case Mode$1.PUNCT_SHIFT: 20223 // Restore sub-mode 20224 subMode = priorToShiftMode; 20225 if (subModeCh < DecodedBitStreamParser.PAL) { 20226 ch = DecodedBitStreamParser.PUNCT_CHARS[subModeCh]; 20227 } 20228 else { 20229 switch (subModeCh) { 20230 case DecodedBitStreamParser.PAL: 20231 subMode = Mode$1.ALPHA; 20232 break; 20233 case DecodedBitStreamParser.MODE_SHIFT_TO_BYTE_COMPACTION_MODE: 20234 // PS before Shift-to-Byte is used as a padding character, 20235 // see 5.4.2.4 of the specification 20236 result.append(/*(char)*/ byteCompactionData[i]); 20237 break; 20238 case DecodedBitStreamParser.TEXT_COMPACTION_MODE_LATCH: 20239 subMode = Mode$1.ALPHA; 20240 break; 20241 } 20242 } 20243 break; 20244 } 20245 // if (ch !== 0) { 20246 if (ch !== '') { 20247 // Append decoded character to result 20248 result.append(ch); 20249 } 20250 i++; 20251 } 20252 } 20253 /** 20254 * Byte Compaction mode (see 5.4.3) permits all 256 possible 8-bit byte values to be encoded. 20255 * This includes all ASCII characters value 0 to 127 inclusive and provides for international 20256 * character set support. 20257 * 20258 * @param mode The byte compaction mode i.e. 901 or 924 20259 * @param codewords The array of codewords (data + error) 20260 * @param encoding Currently active character encoding 20261 * @param codeIndex The current index into the codeword array. 20262 * @param result The decoded data is appended to the result. 20263 * @return The next index into the codeword array. 20264 */ 20265 static /*int*/ byteCompaction(mode, codewords, encoding, codeIndex, result) { 20266 let decodedBytes = new ByteArrayOutputStream(); 20267 let count = 0; 20268 let value =
20268/*long*/
vendor: 12,490 bytes, lines 20268-20517
20268 0; 20269 let end = false; 20270 switch (mode) { 20271 case DecodedBitStreamParser.BYTE_COMPACTION_MODE_LATCH: 20272 // Total number of Byte Compaction characters to be encoded 20273 // is not a multiple of 6 20274 let byteCompactedCodewords = new Int32Array(6); 20275 let nextCode = codewords[codeIndex++]; 20276 while ((codeIndex < codewords[0]) && !end) { 20277 byteCompactedCodewords[count++] = nextCode; 20278 // Base 900 20279 value = 900 * value + nextCode; 20280 nextCode = codewords[codeIndex++]; 20281 // perhaps it should be ok to check only nextCode >= TEXT_COMPACTION_MODE_LATCH 20282 switch (nextCode) { 20283 case DecodedBitStreamParser.TEXT_COMPACTION_MODE_LATCH: 20284 case DecodedBitStreamParser.BYTE_COMPACTION_MODE_LATCH: 20285 case DecodedBitStreamParser.NUMERIC_COMPACTION_MODE_LATCH: 20286 case DecodedBitStreamParser.BYTE_COMPACTION_MODE_LATCH_6: 20287 case DecodedBitStreamParser.BEGIN_MACRO_PDF417_CONTROL_BLOCK: 20288 case DecodedBitStreamParser.BEGIN_MACRO_PDF417_OPTIONAL_FIELD: 20289 case DecodedBitStreamParser.MACRO_PDF417_TERMINATOR: 20290 codeIndex--; 20291 end = true; 20292 break; 20293 default: 20294 if ((count % 5 === 0) && (count > 0)) { 20295 // Decode every 5 codewords 20296 // Convert to Base 256 20297 for (let j /*int*/ = 0; j < 6; ++j) { 20298 /* @note 20299 * JavaScript stores numbers as 64 bits floating point numbers, but all bitwise operations are performed on 32 bits binary numbers. 20300 * So the next bitwise operation could not be done with simple numbers 20301 */ 20302 decodedBytes.write(/*(byte)*/ Number(createBigInt(value) >> createBigInt(8 * (5 - j)))); 20303 } 20304 value = 0; 20305 count = 0; 20306 } 20307 break; 20308 } 20309 } 20310 // if the end of all codewords is reached the last codeword needs to be added 20311 if (codeIndex === codewords[0] && nextCode < DecodedBitStreamParser.TEXT_COMPACTION_MODE_LATCH) { 20312 byteCompactedCodewords[count++] = nextCode; 20313 } 20314 // If Byte Compaction mode is invoked with codeword 901, 20315 // the last group of codewords is interpreted directly 20316 // as one byte per codeword, without compaction. 20317 for (let i /*int*/ = 0; i < count; i++) { 20318 decodedBytes.write(/*(byte)*/ byteCompactedCodewords[i]); 20319 } 20320 break; 20321 case DecodedBitStreamParser.BYTE_COMPACTION_MODE_LATCH_6: 20322 // Total number of Byte Compaction characters to be encoded 20323 // is an integer multiple of 6 20324 while (codeIndex < codewords[0] && !end) { 20325 let code = codewords[codeIndex++]; 20326 if (code < DecodedBitStreamParser.TEXT_COMPACTION_MODE_LATCH) { 20327 count++; 20328 // Base 900 20329 value = 900 * value + code; 20330 } 20331 else { 20332 switch (code) { 20333 case DecodedBitStreamParser.TEXT_COMPACTION_MODE_LATCH: 20334 case DecodedBitStreamParser.BYTE_COMPACTION_MODE_LATCH: 20335 case DecodedBitStreamParser.NUMERIC_COMPACTION_MODE_LATCH: 20336 case DecodedBitStreamParser.BYTE_COMPACTION_MODE_LATCH_6: 20337 case DecodedBitStreamParser.BEGIN_MACRO_PDF417_CONTROL_BLOCK: 20338 case DecodedBitStreamParser.BEGIN_MACRO_PDF417_OPTIONAL_FIELD: 20339 case DecodedBitStreamParser.MACRO_PDF417_TERMINATOR: 20340 codeIndex--; 20341 end = true; 20342 break; 20343 } 20344 } 20345 if ((count % 5 === 0) && (count > 0)) { 20346 // Decode every 5 codewords 20347 // Convert to Base 256 20348 /* @note 20349 * JavaScript stores numbers as 64 bits floating point numbers, but all bitwise operations are performed on 32 bits binary numbers. 20350 * So the next bitwise operation could not be done with simple numbers 20351 */ 20352 for (let j /*int*/ = 0; j < 6; ++j) { 20353 decodedBytes.write(/*(byte)*/ Number(createBigInt(value) >> createBigInt(8 * (5 - j)))); 20354 } 20355 value = 0; 20356 count = 0; 20357 } 20358 } 20359 break; 20360 } 20361 result.append(StringEncoding.decode(decodedBytes.toByteArray(), encoding)); 20362 return codeIndex; 20363 } 20364 /** 20365 * Numeric Compaction mode (see 5.4.4) permits efficient encoding of numeric data strings. 20366 * 20367 * @param codewords The array of codewords (data + error) 20368 * @param codeIndex The current index into the codeword array. 20369 * @param result The decoded data is appended to the result. 20370 * @return The next index into the codeword array. 20371 * 20372 * @throws FormatException 20373 */ 20374 static numericCompaction(codewords, codeIndex /*int*/, result) { 20375 let count = 0; 20376 let end = false; 20377 let numericCodewords = new Int32Array(DecodedBitStreamParser.MAX_NUMERIC_CODEWORDS); 20378 while (codeIndex < codewords[0] && !end) { 20379 let code = codewords[codeIndex++]; 20380 if (codeIndex === codewords[0]) { 20381 end = true; 20382 } 20383 if (code < DecodedBitStreamParser.TEXT_COMPACTION_MODE_LATCH) { 20384 numericCodewords[count] = code; 20385 count++; 20386 } 20387 else { 20388 switch (code) { 20389 case DecodedBitStreamParser.TEXT_COMPACTION_MODE_LATCH: 20390 case DecodedBitStreamParser.BYTE_COMPACTION_MODE_LATCH: 20391 case DecodedBitStreamParser.BYTE_COMPACTION_MODE_LATCH_6: 20392 case DecodedBitStreamParser.BEGIN_MACRO_PDF417_CONTROL_BLOCK: 20393 case DecodedBitStreamParser.BEGIN_MACRO_PDF417_OPTIONAL_FIELD: 20394 case DecodedBitStreamParser.MACRO_PDF417_TERMINATOR: 20395 codeIndex--; 20396 end = true; 20397 break; 20398 } 20399 } 20400 if ((count % DecodedBitStreamParser.MAX_NUMERIC_CODEWORDS === 0 || code === DecodedBitStreamParser.NUMERIC_COMPACTION_MODE_LATCH || end) && count > 0) { 20401 // Re-invoking Numeric Compaction mode (by using codeword 902 20402 // while in Numeric Compaction mode) serves to terminate the 20403 // current Numeric Compaction mode grouping as described in 5.4.4.2, 20404 // and then to start a new one grouping. 20405 result.append(DecodedBitStreamParser.decodeBase900toBase10(numericCodewords, count)); 20406 count = 0; 20407 } 20408 } 20409 return codeIndex; 20410 } 20411 /** 20412 * Convert a list of Numeric Compacted codewords from Base 900 to Base 10. 20413 * 20414 * @param codewords The array of codewords 20415 * @param count The number of codewords 20416 * @return The decoded string representing the Numeric data. 20417 * 20418 * EXAMPLE 20419 * Encode the fifteen digit numeric string 000213298174000 20420 * Prefix the numeric string with a 1 and set the initial value of 20421 * t = 1 000 213 298 174 000 20422 * Calculate codeword 0 20423 * d0 = 1 000 213 298 174 000 mod 900 = 200 20424 * 20425 * t = 1 000 213 298 174 000 div 900 = 1 111 348 109 082 20426 * Calculate codeword 1 20427 * d1 = 1 111 348 109 082 mod 900 = 282 20428 * 20429 * t = 1 111 348 109 082 div 900 = 1 234 831 232 20430 * Calculate codeword 2 20431 * d2 = 1 234 831 232 mod 900 = 632 20432 * 20433 * t = 1 234 831 232 div 900 = 1 372 034 20434 * Calculate codeword 3 20435 * d3 = 1 372 034 mod 900 = 434 20436 * 20437 * t = 1 372 034 div 900 = 1 524 20438 * Calculate codeword 4 20439 * d4 = 1 524 mod 900 = 624 20440 * 20441 * t = 1 524 div 900 = 1 20442 * Calculate codeword 5 20443 * d5 = 1 mod 900 = 1 20444 * t = 1 div 900 = 0 20445 * Codeword sequence is: 1, 624, 434, 632, 282, 200 20446 * 20447 * Decode the above codewords involves 20448 * 1 x 900 power of 5 + 624 x 900 power of 4 + 434 x 900 power of 3 + 20449 * 632 x 900 power of 2 + 282 x 900 power of 1 + 200 x 900 power of 0 = 1000213298174000 20450 * 20451 * Remove leading 1 => Result is 000213298174000 20452 * 20453 * @throws FormatException 20454 */ 20455 static decodeBase900toBase10(codewords, count) { 20456 let result = createBigInt(0); 20457 for (let i /*int*/ = 0; i < count; i++) { 20458 result += DecodedBitStreamParser.EXP900[count - i - 1] * createBigInt(codewords[i]); 20459 } 20460 let resultString = result.toString(); 20461 if (resultString.charAt(0) !== '1') { 20462 throw new FormatException(); 20463 } 20464 return resultString.substring(1); 20465 } 20466 } 20467 DecodedBitStreamParser.TEXT_COMPACTION_MODE_LATCH = 900; 20468 DecodedBitStreamParser.BYTE_COMPACTION_MODE_LATCH = 901; 20469 DecodedBitStreamParser.NUMERIC_COMPACTION_MODE_LATCH = 902; 20470 DecodedBitStreamParser.BYTE_COMPACTION_MODE_LATCH_6 = 924; 20471 DecodedBitStreamParser.ECI_USER_DEFINED = 925; 20472 DecodedBitStreamParser.ECI_GENERAL_PURPOSE = 926; 20473 DecodedBitStreamParser.ECI_CHARSET = 927; 20474 DecodedBitStreamParser.BEGIN_MACRO_PDF417_CONTROL_BLOCK = 928; 20475 DecodedBitStreamParser.BEGIN_MACRO_PDF417_OPTIONAL_FIELD = 923; 20476 DecodedBitStreamParser.MACRO_PDF417_TERMINATOR = 922; 20477 DecodedBitStreamParser.MODE_SHIFT_TO_BYTE_COMPACTION_MODE = 913; 20478 DecodedBitStreamParser.MAX_NUMERIC_CODEWORDS = 15; 20479 DecodedBitStreamParser.MACRO_PDF417_OPTIONAL_FIELD_FILE_NAME = 0; 20480 DecodedBitStreamParser.MACRO_PDF417_OPTIONAL_FIELD_SEGMENT_COUNT = 1; 20481 DecodedBitStreamParser.MACRO_PDF417_OPTIONAL_FIELD_TIME_STAMP = 2; 20482 DecodedBitStreamParser.MACRO_PDF417_OPTIONAL_FIELD_SENDER = 3; 20483 DecodedBitStreamParser.MACRO_PDF417_OPTIONAL_FIELD_ADDRESSEE = 4; 20484 DecodedBitStreamParser.MACRO_PDF417_OPTIONAL_FIELD_FILE_SIZE = 5; 20485 DecodedBitStreamParser.MACRO_PDF417_OPTIONAL_FIELD_CHECKSUM = 6; 20486 DecodedBitStreamParser.PL = 25; 20487 DecodedBitStreamParser.LL = 27; 20488 DecodedBitStreamParser.AS = 27; 20489 DecodedBitStreamParser.ML = 28; 20490 DecodedBitStreamParser.AL = 28; 20491 DecodedBitStreamParser.PS = 29; 20492 DecodedBitStreamParser.PAL = 29; 20493 DecodedBitStreamParser.PUNCT_CHARS = ';<>@[\\]_`~!\r\t,:\n-.$/"|*()?{}\''; 20494 DecodedBitStreamParser.MIXED_CHARS = '0123456789&\r\t,:#-.$/+%*=^'; 20495 /** 20496 * Table containing values for the exponent of 900. 20497 * This is used in the numeric compaction decode algorithm. 20498 */ 20499 DecodedBitStreamParser.EXP900 = getBigIntConstructor() ? getEXP900() : []; 20500 DecodedBitStreamParser.NUMBER_OF_SEQUENCE_CODEWORDS = 2; 20501 20502 /* 20503 * Copyright 2013 ZXing authors 20504 * 20505 * Licensed under the Apache License, Version 2.0 (the "License"); 20506 * you may not use this file except in compliance with the License. 20507 * You may obtain a copy of the License at 20508 * 20509 * http://www.apache.org/licenses/LICENSE-2.0 20510 * 20511 * Unless required by applicable law or agreed to in writing, software 20512 * distributed under the License is distributed on an "AS IS" BASIS, 20513 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20514 * See the License for the specific language governing permissions and 20515 * limitations under the License. 20516 */ 20517 //
20517import java.util.ArrayList; 20518 // import java.util.Collection; 20519 // import java.util.Formatter; 20520 // import java.util.List; 20521 /** 20522 * @author Guenther Grau 20523 */ 20524 /*public final*/
vendor: 11,722 bytes, lines 20524-20760
20524 class PDF417ScanningDecoder { 20525 constructor() { } 20526 /** 20527 * @TODO don't pass in minCodewordWidth and maxCodewordWidth, pass in barcode columns for start and stop pattern 20528 * 20529 * columns. That way width can be deducted from the pattern column. 20530 * This approach also allows to detect more details about the barcode, e.g. if a bar type (white or black) is wider 20531 * than it should be. This can happen if the scanner used a bad blackpoint. 20532 * 20533 * @param BitMatrix 20534 * @param image 20535 * @param ResultPoint 20536 * @param imageTopLeft 20537 * @param ResultPoint 20538 * @param imageBottomLeft 20539 * @param ResultPoint 20540 * @param imageTopRight 20541 * @param ResultPoint 20542 * @param imageBottomRight 20543 * @param int 20544 * @param minCodewordWidth 20545 * @param int 20546 * @param maxCodewordWidth 20547 * 20548 * @throws NotFoundException 20549 * @throws FormatException 20550 * @throws ChecksumException 20551 */ 20552 static decode(image, imageTopLeft, imageBottomLeft, imageTopRight, imageBottomRight, minCodewordWidth, maxCodewordWidth) { 20553 let boundingBox = new BoundingBox(image, imageTopLeft, imageBottomLeft, imageTopRight, imageBottomRight); 20554 let leftRowIndicatorColumn = null; 20555 let rightRowIndicatorColumn = null; 20556 let detectionResult; 20557 for (let firstPass /*boolean*/ = true;; firstPass = false) { 20558 if (imageTopLeft != null) { 20559 leftRowIndicatorColumn = PDF417ScanningDecoder.getRowIndicatorColumn(image, boundingBox, imageTopLeft, true, minCodewordWidth, maxCodewordWidth); 20560 } 20561 if (imageTopRight != null) { 20562 rightRowIndicatorColumn = PDF417ScanningDecoder.getRowIndicatorColumn(image, boundingBox, imageTopRight, false, minCodewordWidth, maxCodewordWidth); 20563 } 20564 detectionResult = PDF417ScanningDecoder.merge(leftRowIndicatorColumn, rightRowIndicatorColumn); 20565 if (detectionResult == null) { 20566 throw NotFoundException.getNotFoundInstance(); 20567 } 20568 let resultBox = detectionResult.getBoundingBox(); 20569 if (firstPass && resultBox != null && 20570 (resultBox.getMinY() < boundingBox.getMinY() || resultBox.getMaxY() > boundingBox.getMaxY())) { 20571 boundingBox = resultBox; 20572 } 20573 else { 20574 break; 20575 } 20576 } 20577 detectionResult.setBoundingBox(boundingBox); 20578 let maxBarcodeColumn = detectionResult.getBarcodeColumnCount() + 1; 20579 detectionResult.setDetectionResultColumn(0, leftRowIndicatorColumn); 20580 detectionResult.setDetectionResultColumn(maxBarcodeColumn, rightRowIndicatorColumn); 20581 let leftToRight = leftRowIndicatorColumn != null; 20582 for (let barcodeColumnCount /*int*/ = 1; barcodeColumnCount <= maxBarcodeColumn; barcodeColumnCount++) { 20583 let barcodeColumn = leftToRight ? barcodeColumnCount : maxBarcodeColumn - barcodeColumnCount; 20584 if (detectionResult.getDetectionResultColumn(barcodeColumn) !== /* null */ undefined) { 20585 // This will be the case for the opposite row indicator column, which doesn't need to be decoded again. 20586 continue; 20587 } 20588 let detectionResultColumn; 20589 if (barcodeColumn === 0 || barcodeColumn === maxBarcodeColumn) { 20590 detectionResultColumn = new DetectionResultRowIndicatorColumn(boundingBox, barcodeColumn === 0); 20591 } 20592 else { 20593 detectionResultColumn = new DetectionResultColumn(boundingBox); 20594 } 20595 detectionResult.setDetectionResultColumn(barcodeColumn, detectionResultColumn); 20596 let startColumn = -1; 20597 let previousStartColumn = startColumn; 20598 // TODO start at a row for which we know the start position, then detect upwards and downwards from there. 20599 for (let imageRow /*int*/ = boundingBox.getMinY(); imageRow <= boundingBox.getMaxY(); imageRow++) { 20600 startColumn = PDF417ScanningDecoder.getStartColumn(detectionResult, barcodeColumn, imageRow, leftToRight); 20601 if (startColumn < 0 || startColumn > boundingBox.getMaxX()) { 20602 if (previousStartColumn === -1) { 20603 continue; 20604 } 20605 startColumn = previousStartColumn; 20606 } 20607 let codeword = PDF417ScanningDecoder.detectCodeword(image, boundingBox.getMinX(), boundingBox.getMaxX(), leftToRight, startColumn, imageRow, minCodewordWidth, maxCodewordWidth); 20608 if (codeword != null) { 20609 detectionResultColumn.setCodeword(imageRow, codeword); 20610 previousStartColumn = startColumn; 20611 minCodewordWidth = Math.min(minCodewordWidth, codeword.getWidth()); 20612 maxCodewordWidth = Math.max(maxCodewordWidth, codeword.getWidth()); 20613 } 20614 } 20615 } 20616 return PDF417ScanningDecoder.createDecoderResult(detectionResult); 20617 } 20618 /** 20619 * 20620 * @param leftRowIndicatorColumn 20621 * @param rightRowIndicatorColumn 20622 * 20623 * @throws NotFoundException 20624 */ 20625 static merge(leftRowIndicatorColumn, rightRowIndicatorColumn) { 20626 if (leftRowIndicatorColumn == null && rightRowIndicatorColumn == null) { 20627 return null; 20628 } 20629 let barcodeMetadata = PDF417ScanningDecoder.getBarcodeMetadata(leftRowIndicatorColumn, rightRowIndicatorColumn); 20630 if (barcodeMetadata == null) { 20631 return null; 20632 } 20633 let boundingBox = BoundingBox.merge(PDF417ScanningDecoder.adjustBoundingBox(leftRowIndicatorColumn), PDF417ScanningDecoder.adjustBoundingBox(rightRowIndicatorColumn)); 20634 return new DetectionResult(barcodeMetadata, boundingBox); 20635 } 20636 /** 20637 * 20638 * @param rowIndicatorColumn 20639 * 20640 * @throws NotFoundException 20641 */ 20642 static adjustBoundingBox(rowIndicatorColumn) { 20643 if (rowIndicatorColumn == null) { 20644 return null; 20645 } 20646 let rowHeights = rowIndicatorColumn.getRowHeights(); 20647 if (rowHeights == null) { 20648 return null; 20649 } 20650 let maxRowHeight = PDF417ScanningDecoder.getMax(rowHeights); 20651 let missingStartRows = 0; 20652 for (let rowHeight /*int*/ of rowHeights) { 20653 missingStartRows += maxRowHeight - rowHeight; 20654 if (rowHeight > 0) { 20655 break; 20656 } 20657 } 20658 let codewords = rowIndicatorColumn.getCodewords(); 20659 for (let row /*int*/ = 0; missingStartRows > 0 && codewords[row] == null; row++) { 20660 missingStartRows--; 20661 } 20662 let missingEndRows = 0; 20663 for (let row /*int*/ = rowHeights.length - 1; row >= 0; row--) { 20664 missingEndRows += maxRowHeight - rowHeights[row]; 20665 if (rowHeights[row] > 0) { 20666 break; 20667 } 20668 } 20669 for (let row /*int*/ = codewords.length - 1; missingEndRows > 0 && codewords[row] == null; row--) { 20670 missingEndRows--; 20671 } 20672 return rowIndicatorColumn.getBoundingBox().addMissingRows(missingStartRows, missingEndRows, rowIndicatorColumn.isLeft()); 20673 } 20674 static getMax(values) { 20675 let maxValue = -1; 20676 for (let value /*int*/ of values) { 20677 maxValue = Math.max(maxValue, value); 20678 } 20679 return maxValue; 20680 } 20681 static getBarcodeMetadata(leftRowIndicatorColumn, rightRowIndicatorColumn) { 20682 let leftBarcodeMetadata; 20683 if (leftRowIndicatorColumn == null || 20684 (leftBarcodeMetadata = leftRowIndicatorColumn.getBarcodeMetadata()) == null) { 20685 return rightRowIndicatorColumn == null ? null : rightRowIndicatorColumn.getBarcodeMetadata(); 20686 } 20687 let rightBarcodeMetadata; 20688 if (rightRowIndicatorColumn == null || 20689 (rightBarcodeMetadata = rightRowIndicatorColumn.getBarcodeMetadata()) == null) { 20690 return leftBarcodeMetadata; 20691 } 20692 if (leftBarcodeMetadata.getColumnCount() !== rightBarcodeMetadata.getColumnCount() && 20693 leftBarcodeMetadata.getErrorCorrectionLevel() !== rightBarcodeMetadata.getErrorCorrectionLevel() && 20694 leftBarcodeMetadata.getRowCount() !== rightBarcodeMetadata.getRowCount()) { 20695 return null; 20696 } 20697 return leftBarcodeMetadata; 20698 } 20699 static getRowIndicatorColumn(image, boundingBox, startPoint, leftToRight, minCodewordWidth, maxCodewordWidth) { 20700 let rowIndicatorColumn = new DetectionResultRowIndicatorColumn(boundingBox, leftToRight); 20701 for (let i /*int*/ = 0; i < 2; i++) { 20702 let increment = i === 0 ? 1 : -1; 20703 let startColumn = Math.trunc(Math.trunc(startPoint.getX())); 20704 for (let imageRow /*int*/ = Math.trunc(Math.trunc(startPoint.getY())); imageRow <= boundingBox.getMaxY() && 20705 imageRow >= boundingBox.getMinY(); imageRow += increment) { 20706 let codeword = PDF417ScanningDecoder.detectCodeword(image, 0, image.getWidth(), leftToRight, startColumn, imageRow, minCodewordWidth, maxCodewordWidth); 20707 if (codeword != null) { 20708 rowIndicatorColumn.setCodeword(imageRow, codeword); 20709 if (leftToRight) { 20710 startColumn = codeword.getStartX(); 20711 } 20712 else { 20713 startColumn = codeword.getEndX(); 20714 } 20715 } 20716 } 20717 } 20718 return rowIndicatorColumn; 20719 } 20720 /** 20721 * 20722 * @param detectionResult 20723 * @param BarcodeValue 20724 * @param param2 20725 * @param param3 20726 * @param barcodeMatrix 20727 * 20728 * @throws NotFoundException 20729 */ 20730 static adjustCodewordCount(detectionResult, barcodeMatrix) { 20731 let barcodeMatrix01 = barcodeMatrix[0][1]; 20732 let numberOfCodewords = barcodeMatrix01.getValue(); 20733 let calculatedNumberOfCodewords = detectionResult.getBarcodeColumnCount() * 20734 detectionResult.getBarcodeRowCount() - 20735 PDF417ScanningDecoder.getNumberOfECCodeWords(detectionResult.getBarcodeECLevel()); 20736 if (numberOfCodewords.length === 0) { 20737 if (calculatedNumberOfCodewords < 1 || calculatedNumberOfCodewords > PDF417Common.MAX_CODEWORDS_IN_BARCODE) { 20738 throw NotFoundException.getNotFoundInstance(); 20739 } 20740 barcodeMatrix01.setValue(calculatedNumberOfCodewords); 20741 } 20742 else if (numberOfCodewords[0] !== calculatedNumberOfCodewords) { 20743 // The calculated one is more reliable as it is derived from the row indicator columns 20744 barcodeMatrix01.setValue(calculatedNumberOfCodewords); 20745 } 20746 } 20747 /** 20748 * 20749 * @param detectionResult 20750 * 20751 * @throws FormatException 20752 * @throws ChecksumException 20753 * @throws NotFoundException 20754 */ 20755 static createDecoderResult(detectionResult) { 20756 let barcodeMatrix = PDF417ScanningDecoder.createBarcodeMatrix(detectionResult); 20757 PDF417ScanningDecoder.adjustCodewordCount(detectionResult, barcodeMatrix); 20758 let erasures /*Collection<Integer>*/ = new Array(); 20759 let codewords = new Int32Array(detectionResult.getBarcodeRowCount() * detectionResult.getBarcodeColumnCount()); 20760 let ambiguousIndexValuesList =
20760/*List<int[]>*/ []; 20761 let ambiguousIndexesList = /*Collection<Integer>*/
vendor: 25,385 bytes, lines 20761-21284
20761 new Array(); 20762 for (let row /*int*/ = 0; row < detectionResult.getBarcodeRowCount(); row++) { 20763 for (let column /*int*/ = 0; column < detectionResult.getBarcodeColumnCount(); column++) { 20764 let values = barcodeMatrix[row][column + 1].getValue(); 20765 let codewordIndex = row * detectionResult.getBarcodeColumnCount() + column; 20766 if (values.length === 0) { 20767 erasures.push(codewordIndex); 20768 } 20769 else if (values.length === 1) { 20770 codewords[codewordIndex] = values[0]; 20771 } 20772 else { 20773 ambiguousIndexesList.push(codewordIndex); 20774 ambiguousIndexValuesList.push(values); 20775 } 20776 } 20777 } 20778 let ambiguousIndexValues = new Array(ambiguousIndexValuesList.length); 20779 for (let i /*int*/ = 0; i < ambiguousIndexValues.length; i++) { 20780 ambiguousIndexValues[i] = ambiguousIndexValuesList[i]; 20781 } 20782 return PDF417ScanningDecoder.createDecoderResultFromAmbiguousValues(detectionResult.getBarcodeECLevel(), codewords, PDF417Common.toIntArray(erasures), PDF417Common.toIntArray(ambiguousIndexesList), ambiguousIndexValues); 20783 } 20784 /** 20785 * This method deals with the fact, that the decoding process doesn't always yield a single most likely value. The 20786 * current error correction implementation doesn't deal with erasures very well, so it's better to provide a value 20787 * for these ambiguous codewords instead of treating it as an erasure. The problem is that we don't know which of 20788 * the ambiguous values to choose. We try decode using the first value, and if that fails, we use another of the 20789 * ambiguous values and try to decode again. This usually only happens on very hard to read and decode barcodes, 20790 * so decoding the normal barcodes is not affected by this. 20791 * 20792 * @param erasureArray contains the indexes of erasures 20793 * @param ambiguousIndexes array with the indexes that have more than one most likely value 20794 * @param ambiguousIndexValues two dimensional array that contains the ambiguous values. The first dimension must 20795 * be the same length as the ambiguousIndexes array 20796 * 20797 * @throws FormatException 20798 * @throws ChecksumException 20799 */ 20800 static createDecoderResultFromAmbiguousValues(ecLevel, codewords, erasureArray, ambiguousIndexes, ambiguousIndexValues) { 20801 let ambiguousIndexCount = new Int32Array(ambiguousIndexes.length); 20802 let tries = 100; 20803 while (tries-- > 0) { 20804 for (let i /*int*/ = 0; i < ambiguousIndexCount.length; i++) { 20805 codewords[ambiguousIndexes[i]] = ambiguousIndexValues[i][ambiguousIndexCount[i]]; 20806 } 20807 try { 20808 return PDF417ScanningDecoder.decodeCodewords(codewords, ecLevel, erasureArray); 20809 } 20810 catch (err) { 20811 let ignored = err instanceof ChecksumException; 20812 if (!ignored) { 20813 throw err; 20814 } 20815 } 20816 if (ambiguousIndexCount.length === 0) { 20817 throw ChecksumException.getChecksumInstance(); 20818 } 20819 for (let i /*int*/ = 0; i < ambiguousIndexCount.length; i++) { 20820 if (ambiguousIndexCount[i] < ambiguousIndexValues[i].length - 1) { 20821 ambiguousIndexCount[i]++; 20822 break; 20823 } 20824 else { 20825 ambiguousIndexCount[i] = 0; 20826 if (i === ambiguousIndexCount.length - 1) { 20827 throw ChecksumException.getChecksumInstance(); 20828 } 20829 } 20830 } 20831 } 20832 throw ChecksumException.getChecksumInstance(); 20833 } 20834 static createBarcodeMatrix(detectionResult) { 20835 // let barcodeMatrix: BarcodeValue[][] = 20836 // new BarcodeValue[detectionResult.getBarcodeRowCount()][detectionResult.getBarcodeColumnCount() + 2]; 20837 let barcodeMatrix = Array.from({ length: detectionResult.getBarcodeRowCount() }, () => new Array(detectionResult.getBarcodeColumnCount() + 2)); 20838 for (let row /*int*/ = 0; row < barcodeMatrix.length; row++) { 20839 for (let column /*int*/ = 0; column < barcodeMatrix[row].length; column++) { 20840 barcodeMatrix[row][column] = new BarcodeValue(); 20841 } 20842 } 20843 let column = 0; 20844 for (let detectionResultColumn /*DetectionResultColumn*/ of detectionResult.getDetectionResultColumns()) { 20845 if (detectionResultColumn != null) { 20846 for (let codeword /*Codeword*/ of detectionResultColumn.getCodewords()) { 20847 if (codeword != null) { 20848 let rowNumber = codeword.getRowNumber(); 20849 if (rowNumber >= 0) { 20850 if (rowNumber >= barcodeMatrix.length) { 20851 // We have more rows than the barcode metadata allows for, ignore them. 20852 continue; 20853 } 20854 barcodeMatrix[rowNumber][column].setValue(codeword.getValue()); 20855 } 20856 } 20857 } 20858 } 20859 column++; 20860 } 20861 return barcodeMatrix; 20862 } 20863 static isValidBarcodeColumn(detectionResult, barcodeColumn) { 20864 return barcodeColumn >= 0 && barcodeColumn <= detectionResult.getBarcodeColumnCount() + 1; 20865 } 20866 static getStartColumn(detectionResult, barcodeColumn, imageRow, leftToRight) { 20867 let offset = leftToRight ? 1 : -1; 20868 let codeword = null; 20869 if (PDF417ScanningDecoder.isValidBarcodeColumn(detectionResult, barcodeColumn - offset)) { 20870 codeword = detectionResult.getDetectionResultColumn(barcodeColumn - offset).getCodeword(imageRow); 20871 } 20872 if (codeword != null) { 20873 return leftToRight ? codeword.getEndX() : codeword.getStartX(); 20874 } 20875 codeword = detectionResult.getDetectionResultColumn(barcodeColumn).getCodewordNearby(imageRow); 20876 if (codeword != null) { 20877 return leftToRight ? codeword.getStartX() : codeword.getEndX(); 20878 } 20879 if (PDF417ScanningDecoder.isValidBarcodeColumn(detectionResult, barcodeColumn - offset)) { 20880 codeword = detectionResult.getDetectionResultColumn(barcodeColumn - offset).getCodewordNearby(imageRow); 20881 } 20882 if (codeword != null) { 20883 return leftToRight ? codeword.getEndX() : codeword.getStartX(); 20884 } 20885 let skippedColumns = 0; 20886 while (PDF417ScanningDecoder.isValidBarcodeColumn(detectionResult, barcodeColumn - offset)) { 20887 barcodeColumn -= offset; 20888 for (let previousRowCodeword /*Codeword*/ of detectionResult.getDetectionResultColumn(barcodeColumn).getCodewords()) { 20889 if (previousRowCodeword != null) { 20890 return (leftToRight ? previousRowCodeword.getEndX() : previousRowCodeword.getStartX()) + 20891 offset * 20892 skippedColumns * 20893 (previousRowCodeword.getEndX() - previousRowCodeword.getStartX()); 20894 } 20895 } 20896 skippedColumns++; 20897 } 20898 return leftToRight ? detectionResult.getBoundingBox().getMinX() : detectionResult.getBoundingBox().getMaxX(); 20899 } 20900 static detectCodeword(image, minColumn, maxColumn, leftToRight, startColumn, imageRow, minCodewordWidth, maxCodewordWidth) { 20901 startColumn = PDF417ScanningDecoder.adjustCodewordStartColumn(image, minColumn, maxColumn, leftToRight, startColumn, imageRow); 20902 // we usually know fairly exact now how long a codeword is. We should provide minimum and maximum expected length 20903 // and try to adjust the read pixels, e.g. remove single pixel errors or try to cut off exceeding pixels. 20904 // min and maxCodewordWidth should not be used as they are calculated for the whole barcode an can be inaccurate 20905 // for the current position 20906 let moduleBitCount = PDF417ScanningDecoder.getModuleBitCount(image, minColumn, maxColumn, leftToRight, startColumn, imageRow); 20907 if (moduleBitCount == null) { 20908 return null; 20909 } 20910 let endColumn; 20911 let codewordBitCount = MathUtils.sum(moduleBitCount); 20912 if (leftToRight) { 20913 endColumn = startColumn + codewordBitCount; 20914 } 20915 else { 20916 for (let i /*int*/ = 0; i < moduleBitCount.length / 2; i++) { 20917 let tmpCount = moduleBitCount[i]; 20918 moduleBitCount[i] = moduleBitCount[moduleBitCount.length - 1 - i]; 20919 moduleBitCount[moduleBitCount.length - 1 - i] = tmpCount; 20920 } 20921 endColumn = startColumn; 20922 startColumn = endColumn - codewordBitCount; 20923 } 20924 // TODO implement check for width and correction of black and white bars 20925 // use start (and maybe stop pattern) to determine if black bars are wider than white bars. If so, adjust. 20926 // should probably done only for codewords with a lot more than 17 bits. 20927 // The following fixes 10-1.png, which has wide black bars and small white bars 20928 // for (let i /*int*/ = 0; i < moduleBitCount.length; i++) { 20929 // if (i % 2 === 0) { 20930 // moduleBitCount[i]--; 20931 // } else { 20932 // moduleBitCount[i]++; 20933 // } 20934 // } 20935 // We could also use the width of surrounding codewords for more accurate results, but this seems 20936 // sufficient for now 20937 if (!PDF417ScanningDecoder.checkCodewordSkew(codewordBitCount, minCodewordWidth, maxCodewordWidth)) { 20938 // We could try to use the startX and endX position of the codeword in the same column in the previous row, 20939 // create the bit count from it and normalize it to 8. This would help with single pixel errors. 20940 return null; 20941 } 20942 let decodedValue = PDF417CodewordDecoder.getDecodedValue(moduleBitCount); 20943 let codeword = PDF417Common.getCodeword(decodedValue); 20944 if (codeword === -1) { 20945 return null; 20946 } 20947 return new Codeword(startColumn, endColumn, PDF417ScanningDecoder.getCodewordBucketNumber(decodedValue), codeword); 20948 } 20949 static getModuleBitCount(image, minColumn, maxColumn, leftToRight, startColumn, imageRow) { 20950 let imageColumn = startColumn; 20951 let moduleBitCount = new Int32Array(8); 20952 let moduleNumber = 0; 20953 let increment = leftToRight ? 1 : -1; 20954 let previousPixelValue = leftToRight; 20955 while ((leftToRight ? imageColumn < maxColumn : imageColumn >= minColumn) && 20956 moduleNumber < moduleBitCount.length) { 20957 if (image.get(imageColumn, imageRow) === previousPixelValue) { 20958 moduleBitCount[moduleNumber]++; 20959 imageColumn += increment; 20960 } 20961 else { 20962 moduleNumber++; 20963 previousPixelValue = !previousPixelValue; 20964 } 20965 } 20966 if (moduleNumber === moduleBitCount.length || 20967 ((imageColumn === (leftToRight ? maxColumn : minColumn)) && 20968 moduleNumber === moduleBitCount.length - 1)) { 20969 return moduleBitCount; 20970 } 20971 return null; 20972 } 20973 static getNumberOfECCodeWords(barcodeECLevel) { 20974 return 2 << barcodeECLevel; 20975 } 20976 static adjustCodewordStartColumn(image, minColumn, maxColumn, leftToRight, codewordStartColumn, imageRow) { 20977 let correctedStartColumn = codewordStartColumn; 20978 let increment = leftToRight ? -1 : 1; 20979 // there should be no black pixels before the start column. If there are, then we need to start earlier. 20980 for (let i /*int*/ = 0; i < 2; i++) { 20981 while ((leftToRight ? correctedStartColumn >= minColumn : correctedStartColumn < maxColumn) && 20982 leftToRight === image.get(correctedStartColumn, imageRow)) { 20983 if (Math.abs(codewordStartColumn - correctedStartColumn) > PDF417ScanningDecoder.CODEWORD_SKEW_SIZE) { 20984 return codewordStartColumn; 20985 } 20986 correctedStartColumn += increment; 20987 } 20988 increment = -increment; 20989 leftToRight = !leftToRight; 20990 } 20991 return correctedStartColumn; 20992 } 20993 static checkCodewordSkew(codewordSize, minCodewordWidth, maxCodewordWidth) { 20994 return minCodewordWidth - PDF417ScanningDecoder.CODEWORD_SKEW_SIZE <= codewordSize && 20995 codewordSize <= maxCodewordWidth + PDF417ScanningDecoder.CODEWORD_SKEW_SIZE; 20996 } 20997 /** 20998 * @throws FormatException, 20999 * @throws ChecksumException 21000 */ 21001 static decodeCodewords(codewords, ecLevel, erasures) { 21002 if (codewords.length === 0) { 21003 throw FormatException.getFormatInstance(); 21004 } 21005 let numECCodewords = 1 << (ecLevel + 1); 21006 let correctedErrorsCount = PDF417ScanningDecoder.correctErrors(codewords, erasures, numECCodewords); 21007 PDF417ScanningDecoder.verifyCodewordCount(codewords, numECCodewords); 21008 // Decode the codewords 21009 let decoderResult = DecodedBitStreamParser.decode(codewords, '' + ecLevel); 21010 decoderResult.setErrorsCorrected(correctedErrorsCount); 21011 decoderResult.setErasures(erasures.length); 21012 return decoderResult; 21013 } 21014 /** 21015 * <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to 21016 * correct the errors in-place.</p> 21017 * 21018 * @param codewords data and error correction codewords 21019 * @param erasures positions of any known erasures 21020 * @param numECCodewords number of error correction codewords that are available in codewords 21021 * @throws ChecksumException if error correction fails 21022 */ 21023 static correctErrors(codewords, erasures, numECCodewords) { 21024 if (erasures != null && 21025 erasures.length > numECCodewords / 2 + PDF417ScanningDecoder.MAX_ERRORS || 21026 numECCodewords < 0 || 21027 numECCodewords > PDF417ScanningDecoder.MAX_EC_CODEWORDS) { 21028 // Too many errors or EC Codewords is corrupted 21029 throw ChecksumException.getChecksumInstance(); 21030 } 21031 return PDF417ScanningDecoder.errorCorrection.decode(codewords, numECCodewords, erasures); 21032 } 21033 /** 21034 * Verify that all is OK with the codeword array. 21035 * @throws FormatException 21036 */ 21037 static verifyCodewordCount(codewords, numECCodewords) { 21038 if (codewords.length < 4) { 21039 // Codeword array size should be at least 4 allowing for 21040 // Count CW, At least one Data CW, Error Correction CW, Error Correction CW 21041 throw FormatException.getFormatInstance(); 21042 } 21043 // The first codeword, the Symbol Length Descriptor, shall always encode the total number of data 21044 // codewords in the symbol, including the Symbol Length Descriptor itself, data codewords and pad 21045 // codewords, but excluding the number of error correction codewords. 21046 let numberOfCodewords = codewords[0]; 21047 if (numberOfCodewords > codewords.length) { 21048 throw FormatException.getFormatInstance(); 21049 } 21050 if (numberOfCodewords === 0) { 21051 // Reset to the length of the array - 8 (Allow for at least level 3 Error Correction (8 Error Codewords) 21052 if (numECCodewords < codewords.length) { 21053 codewords[0] = codewords.length - numECCodewords; 21054 } 21055 else { 21056 throw FormatException.getFormatInstance(); 21057 } 21058 } 21059 } 21060 static getBitCountForCodeword(codeword) { 21061 let result = new Int32Array(8); 21062 let previousValue = 0; 21063 let i = result.length - 1; 21064 while (true) { 21065 if ((codeword & 0x1) !== previousValue) { 21066 previousValue = codeword & 0x1; 21067 i--; 21068 if (i < 0) { 21069 break; 21070 } 21071 } 21072 result[i]++; 21073 codeword >>= 1; 21074 } 21075 return result; 21076 } 21077 static getCodewordBucketNumber(codeword) { 21078 if (codeword instanceof Int32Array) { 21079 return this.getCodewordBucketNumber_Int32Array(codeword); 21080 } 21081 return this.getCodewordBucketNumber_number(codeword); 21082 } 21083 static getCodewordBucketNumber_number(codeword) { 21084 return PDF417ScanningDecoder.getCodewordBucketNumber(PDF417ScanningDecoder.getBitCountForCodeword(codeword)); 21085 } 21086 static getCodewordBucketNumber_Int32Array(moduleBitCount) { 21087 return (moduleBitCount[0] - moduleBitCount[2] + moduleBitCount[4] - moduleBitCount[6] + 9) % 9; 21088 } 21089 static toString(barcodeMatrix) { 21090 let formatter = new Formatter(); 21091 // try (let formatter = new Formatter()) { 21092 for (let row /*int*/ = 0; row < barcodeMatrix.length; row++) { 21093 formatter.format('Row %2d: ', row); 21094 for (let column /*int*/ = 0; column < barcodeMatrix[row].length; column++) { 21095 let barcodeValue = barcodeMatrix[row][column]; 21096 if (barcodeValue.getValue().length === 0) { 21097 formatter.format(' ', null); 21098 } 21099 else { 21100 formatter.format('%4d(%2d)', barcodeValue.getValue()[0], barcodeValue.getConfidence(barcodeValue.getValue()[0])); 21101 } 21102 } 21103 formatter.format('%n'); 21104 } 21105 return formatter.toString(); 21106 // } 21107 } 21108 } 21109 /*final*/ PDF417ScanningDecoder.CODEWORD_SKEW_SIZE = 2; 21110 /*final*/ PDF417ScanningDecoder.MAX_ERRORS = 3; 21111 /*final*/ PDF417ScanningDecoder.MAX_EC_CODEWORDS = 512; 21112 /*final*/ PDF417ScanningDecoder.errorCorrection = new ErrorCorrection$1(); 21113 21114 /* 21115 * Copyright 2009 ZXing authors 21116 * 21117 * Licensed under the Apache License, Version 2.0 (the "License"); 21118 * you may not use this file except in compliance with the License. 21119 * You may obtain a copy of the License at 21120 * 21121 * http://www.apache.org/licenses/LICENSE-2.0 21122 * 21123 * Unless required by applicable law or agreed to in writing, software 21124 * distributed under the License is distributed on an "AS IS" BASIS, 21125 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21126 * See the License for the specific language governing permissions and 21127 * limitations under the License. 21128 */ 21129 // import java.util.ArrayList; 21130 // import java.util.List; 21131 // import java.util.Map; 21132 /** 21133 * This implementation can detect and decode PDF417 codes in an image. 21134 * 21135 * @author Guenther Grau 21136 */ 21137 /*public final*/ class PDF417Reader { 21138 // private static /*final Result[]*/ EMPTY_RESULT_ARRAY: Result[] = new Result([0]); 21139 /** 21140 * Locates and decodes a PDF417 code in an image. 21141 * 21142 * @return a String representing the content encoded by the PDF417 code 21143 * @throws NotFoundException if a PDF417 code cannot be found, 21144 * @throws FormatException if a PDF417 cannot be decoded 21145 * @throws ChecksumException 21146 */ 21147 // @Override 21148 decode(image, hints = null) { 21149 let result = PDF417Reader.decode(image, hints, false); 21150 if (result == null || result.length === 0 || result[0] == null) { 21151 throw NotFoundException.getNotFoundInstance(); 21152 } 21153 return result[0]; 21154 } 21155 /** 21156 * 21157 * @param BinaryBitmap 21158 * @param image 21159 * @throws NotFoundException 21160 */ 21161 // @Override 21162 decodeMultiple(image, hints = null) { 21163 try { 21164 return PDF417Reader.decode(image, hints, true); 21165 } 21166 catch (ignored) { 21167 if (ignored instanceof FormatException || ignored instanceof ChecksumException) { 21168 throw NotFoundException.getNotFoundInstance(); 21169 } 21170 throw ignored; 21171 } 21172 } 21173 /** 21174 * 21175 * @param image 21176 * @param hints 21177 * @param multiple 21178 * 21179 * @throws NotFoundException 21180 * @throws FormatExceptionß 21181 * @throws ChecksumException 21182 */ 21183 static decode(image, hints, multiple) { 21184 const results = new Array(); 21185 const detectorResult = Detector.detectMultiple(image, hints, multiple); 21186 for (const points of detectorResult.getPoints()) { 21187 const decoderResult = PDF417ScanningDecoder.decode(detectorResult.getBits(), points[4], points[5], points[6], points[7], PDF417Reader.getMinCodewordWidth(points), PDF417Reader.getMaxCodewordWidth(points)); 21188 const result = new Result$1(decoderResult.getText(), decoderResult.getRawBytes(), undefined, points, BarcodeFormat$1.PDF_417); 21189 result.putMetadata(ResultMetadataType$1.ERROR_CORRECTION_LEVEL, decoderResult.getECLevel()); 21190 const pdf417ResultMetadata = decoderResult.getOther(); 21191 if (pdf417ResultMetadata != null) { 21192 result.putMetadata(ResultMetadataType$1.PDF417_EXTRA_METADATA, pdf417ResultMetadata); 21193 } 21194 results.push(result); 21195 } 21196 return results.map(x => x); 21197 } 21198 static getMaxWidth(p1, p2) { 21199 if (p1 == null || p2 == null) { 21200 return 0; 21201 } 21202 return Math.trunc(Math.abs(p1.getX() - p2.getX())); 21203 } 21204 static getMinWidth(p1, p2) { 21205 if (p1 == null || p2 == null) { 21206 return Integer.MAX_VALUE; 21207 } 21208 return Math.trunc(Math.abs(p1.getX() - p2.getX())); 21209 } 21210 static getMaxCodewordWidth(p) { 21211 return Math.floor(Math.max(Math.max(PDF417Reader.getMaxWidth(p[0], p[4]), PDF417Reader.getMaxWidth(p[6], p[2]) * PDF417Common.MODULES_IN_CODEWORD / 21212 PDF417Common.MODULES_IN_STOP_PATTERN), Math.max(PDF417Reader.getMaxWidth(p[1], p[5]), PDF417Reader.getMaxWidth(p[7], p[3]) * PDF417Common.MODULES_IN_CODEWORD / 21213 PDF417Common.MODULES_IN_STOP_PATTERN))); 21214 } 21215 static getMinCodewordWidth(p) { 21216 return Math.floor(Math.min(Math.min(PDF417Reader.getMinWidth(p[0], p[4]), PDF417Reader.getMinWidth(p[6], p[2]) * PDF417Common.MODULES_IN_CODEWORD / 21217 PDF417Common.MODULES_IN_STOP_PATTERN), Math.min(PDF417Reader.getMinWidth(p[1], p[5]), PDF417Reader.getMinWidth(p[7], p[3]) * PDF417Common.MODULES_IN_CODEWORD / 21218 PDF417Common.MODULES_IN_STOP_PATTERN))); 21219 } 21220 // @Override 21221 reset() { 21222 // nothing needs to be reset 21223 } 21224 } 21225 21226 /** 21227 * Custom Error class of type Exception. 21228 */ 21229 class ReaderException extends Exception { 21230 } 21231 ReaderException.kind = 'ReaderException'; 21232 21233 /* 21234 * Copyright 2009 ZXing authors 21235 * 21236 * Licensed under the Apache License, Version 2.0 (the "License"); 21237 * you may not use this file except in compliance with the License. 21238 * You may obtain a copy of the License at 21239 * 21240 * http://www.apache.org/licenses/LICENSE-2.0 21241 * 21242 * Unless required by applicable law or agreed to in writing, software 21243 * distributed under the License is distributed on an "AS IS" BASIS, 21244 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21245 * See the License for the specific language governing permissions and 21246 * limitations under the License. 21247 */ 21248 /*namespace com.google.zxing {*/ 21249 /** 21250 * MultiFormatReader is a convenience class and the main entry point into the library for most uses. 21251 * By default it attempts to decode all barcode formats that the library supports. Optionally, you 21252 * can provide a hints object to request different behavior, for example only decoding QR codes. 21253 * 21254 * @author Sean Owen 21255 * @author [email protected] (Daniel Switkin) 21256 */ 21257 class MultiFormatReader { 21258 /** 21259 * This version of decode honors the intent of Reader.decode(BinaryBitmap) in that it 21260 * passes null as a hint to the decoders. However, that makes it inefficient to call repeatedly. 21261 * Use setHints() followed by decodeWithState() for continuous scan applications. 21262 * 21263 * @param image The pixel data to decode 21264 * @return The contents of the image 21265 * 21266 * @throws NotFoundException Any errors which occurred 21267 */ 21268 /*@Override*/ 21269 // public decode(image: BinaryBitmap): Result { 21270 // setHints(null) 21271 // return decodeInternal(image) 21272 // } 21273 /** 21274 * Decode an image using the hints provided. Does not honor existing state. 21275 * 21276 * @param image The pixel data to decode 21277 * @param hints The hints to use, clearing the previous state. 21278 * @return The contents of the image 21279 * 21280 * @throws NotFoundException Any errors which occurred 21281 */ 21282 /*@Override*/ 21283 decode(image, hints) { 21284
vendor: 5,303 bytes, lines 21284-21410
21284this.setHints(hints); 21285 return this.decodeInternal(image); 21286 } 21287 /** 21288 * Decode an image using the state set up by calling setHints() previously. Continuous scan 21289 * clients will get a <b>large</b> speed increase by using this instead of decode(). 21290 * 21291 * @param image The pixel data to decode 21292 * @return The contents of the image 21293 * 21294 * @throws NotFoundException Any errors which occurred 21295 */ 21296 decodeWithState(image) { 21297 // Make sure to set up the default state so we don't crash 21298 if (this.readers === null || this.readers === undefined) { 21299 this.setHints(null); 21300 } 21301 return this.decodeInternal(image); 21302 } 21303 /** 21304 * This method adds state to the MultiFormatReader. By setting the hints once, subsequent calls 21305 * to decodeWithState(image) can reuse the same set of readers without reallocating memory. This 21306 * is important for performance in continuous scan clients. 21307 * 21308 * @param hints The set of hints to use for subsequent calls to decode(image) 21309 */ 21310 setHints(hints) { 21311 this.hints = hints; 21312 const tryHarder = hints !== null && hints !== undefined && undefined !== hints.get(DecodeHintType$1.TRY_HARDER); 21313 /*@SuppressWarnings("unchecked")*/ 21314 const formats = hints === null || hints === undefined ? null : hints.get(DecodeHintType$1.POSSIBLE_FORMATS); 21315 const readers = new Array(); 21316 if (formats !== null && formats !== undefined) { 21317 const addOneDReader = formats.some(f => f === BarcodeFormat$1.UPC_A || 21318 f === BarcodeFormat$1.UPC_E || 21319 f === BarcodeFormat$1.EAN_13 || 21320 f === BarcodeFormat$1.EAN_8 || 21321 f === BarcodeFormat$1.CODABAR || 21322 f === BarcodeFormat$1.CODE_39 || 21323 f === BarcodeFormat$1.CODE_93 || 21324 f === BarcodeFormat$1.CODE_128 || 21325 f === BarcodeFormat$1.ITF || 21326 f === BarcodeFormat$1.RSS_14 || 21327 f === BarcodeFormat$1.RSS_EXPANDED); 21328 // Put 1D readers upfront in "normal" mode 21329 // TYPESCRIPTPORT: TODO: uncomment below as they are ported 21330 if (addOneDReader && !tryHarder) { 21331 readers.push(new MultiFormatOneDReader(hints)); 21332 } 21333 if (formats.includes(BarcodeFormat$1.QR_CODE)) { 21334 readers.push(new QRCodeReader()); 21335 } 21336 if (formats.includes(BarcodeFormat$1.DATA_MATRIX)) { 21337 readers.push(new DataMatrixReader()); 21338 } 21339 if (formats.includes(BarcodeFormat$1.AZTEC)) { 21340 readers.push(new AztecReader()); 21341 } 21342 if (formats.includes(BarcodeFormat$1.PDF_417)) { 21343 readers.push(new PDF417Reader()); 21344 } 21345 // if (formats.includes(BarcodeFormat.MAXICODE)) { 21346 // readers.push(new MaxiCodeReader()) 21347 // } 21348 // At end in "try harder" mode 21349 if (addOneDReader && tryHarder) { 21350 readers.push(new MultiFormatOneDReader(hints)); 21351 } 21352 } 21353 if (readers.length === 0) { 21354 if (!tryHarder) { 21355 readers.push(new MultiFormatOneDReader(hints)); 21356 } 21357 readers.push(new QRCodeReader()); 21358 readers.push(new DataMatrixReader()); 21359 readers.push(new AztecReader()); 21360 readers.push(new PDF417Reader()); 21361 // readers.push(new MaxiCodeReader()) 21362 if (tryHarder) { 21363 readers.push(new MultiFormatOneDReader(hints)); 21364 } 21365 } 21366 this.readers = readers; // .toArray(new Reader[readers.size()]) 21367 } 21368 /*@Override*/ 21369 reset() { 21370 if (this.readers !== null) { 21371 for (const reader of this.readers) { 21372 reader.reset(); 21373 } 21374 } 21375 } 21376 /** 21377 * @throws NotFoundException 21378 */ 21379 decodeInternal(image) { 21380 if (this.readers === null) { 21381 throw new ReaderException('No readers where selected, nothing can be read.'); 21382 } 21383 for (const reader of this.readers) { 21384 // Trying to decode with ${reader} reader. 21385 try { 21386 return reader.decode(image, this.hints); 21387 } 21388 catch (ex) { 21389 if (ex instanceof ReaderException) { 21390 continue; 21391 } 21392 // Bad Exception. 21393 } 21394 } 21395 throw new NotFoundException('No MultiFormat Readers were able to detect the code.'); 21396 } 21397 } 21398 21399 class BrowserMultiFormatReader extends BrowserCodeReader { 21400 constructor(hints = null, timeBetweenScansMillis = 500) { 21401 const reader = new MultiFormatReader(); 21402 reader.setHints(hints); 21403 super(reader, timeBetweenScansMillis); 21404 } 21405 /** 21406 * Overwrite decodeBitmap to call decodeWithState, which will pay 21407 * attention to the hints set in the constructor function 21408 */ 21409 decodeBitmap(binaryBitmap) { 21410 return this.reader.decodeWithState(binaryBitmap);
vendor: 13,344 bytes, lines 21410-21692
21410 21411 } 21412 } 21413 21414 /** 21415 * @deprecated Moving to @zxing/browser 21416 * 21417 * QR Code reader to use from browser. 21418 */ 21419 class BrowserPDF417Reader extends BrowserCodeReader { 21420 /** 21421 * Creates an instance of BrowserPDF417Reader. 21422 * @param {number} [timeBetweenScansMillis=500] the time delay between subsequent decode tries 21423 */ 21424 constructor(timeBetweenScansMillis = 500) { 21425 super(new PDF417Reader(), timeBetweenScansMillis); 21426 } 21427 } 21428 21429 /** 21430 * @deprecated Moving to @zxing/browser 21431 * 21432 * QR Code reader to use from browser. 21433 */ 21434 class BrowserQRCodeReader extends BrowserCodeReader { 21435 /** 21436 * Creates an instance of BrowserQRCodeReader. 21437 * @param {number} [timeBetweenScansMillis=500] the time delay between subsequent decode tries 21438 */ 21439 constructor(timeBetweenScansMillis = 500) { 21440 super(new QRCodeReader(), timeBetweenScansMillis); 21441 } 21442 } 21443 21444 /* 21445 * Copyright 2009 ZXing authors 21446 * 21447 * Licensed under the Apache License, Version 2.0 (the "License"); 21448 * you may not use this file except in compliance with the License. 21449 * You may obtain a copy of the License at 21450 * 21451 * http://www.apache.org/licenses/LICENSE-2.0 21452 * 21453 * Unless required by applicable law or agreed to in writing, software 21454 * distributed under the License is distributed on an "AS IS" BASIS, 21455 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21456 * See the License for the specific language governing permissions and 21457 * limitations under the License. 21458 */ 21459 /*namespace com.google.zxing {*/ 21460 /** 21461 * These are a set of hints that you may pass to Writers to specify their behavior. 21462 * 21463 * @author [email protected] (Daniel Switkin) 21464 */ 21465 var EncodeHintType; 21466 (function (EncodeHintType) { 21467 /** 21468 * Specifies what degree of error correction to use, for example in QR Codes. 21469 * Type depends on the encoder. For example for QR codes it's type 21470 * {@link com.google.zxing.qrcode.decoder.ErrorCorrectionLevel ErrorCorrectionLevel}. 21471 * For Aztec it is of type {@link Integer}, representing the minimal percentage of error correction words. 21472 * For PDF417 it is of type {@link Integer}, valid values being 0 to 8. 21473 * In all cases, it can also be a {@link String} representation of the desired value as well. 21474 * Note: an Aztec symbol should have a minimum of 25% EC words. 21475 */ 21476 EncodeHintType[EncodeHintType["ERROR_CORRECTION"] = 0] = "ERROR_CORRECTION"; 21477 /** 21478 * Specifies what character encoding to use where applicable (type {@link String}) 21479 */ 21480 EncodeHintType[EncodeHintType["CHARACTER_SET"] = 1] = "CHARACTER_SET"; 21481 /** 21482 * Specifies the matrix shape for Data Matrix (type {@link com.google.zxing.datamatrix.encoder.SymbolShapeHint}) 21483 */ 21484 EncodeHintType[EncodeHintType["DATA_MATRIX_SHAPE"] = 2] = "DATA_MATRIX_SHAPE"; 21485 /** 21486 * Specifies whether to use compact mode for Data Matrix (type {@link Boolean}, or "true" or "false" 21487 * {@link String } value). 21488 * The compact encoding mode also supports the encoding of characters that are not in the ISO-8859-1 21489 * character set via ECIs. 21490 * Please note that in that case, the most compact character encoding is chosen for characters in 21491 * the input that are not in the ISO-8859-1 character set. Based on experience, some scanners do not 21492 * support encodings like cp-1256 (Arabic). In such cases the encoding can be forced to UTF-8 by 21493 * means of the {@link #CHARACTER_SET} encoding hint. 21494 * Compact encoding also provides GS1-FNC1 support when {@link #GS1_FORMAT} is selected. In this case 21495 * group-separator character (ASCII 29 decimal) can be used to encode the positions of FNC1 codewords 21496 * for the purpose of delimiting AIs. 21497 * This option and {@link #FORCE_C40} are mutually exclusive. 21498 */ 21499 EncodeHintType[EncodeHintType["DATA_MATRIX_COMPACT"] = 3] = "DATA_MATRIX_COMPACT"; 21500 /** 21501 * Specifies a minimum barcode size (type {@link Dimension}). Only applicable to Data Matrix now. 21502 * 21503 * @deprecated use width/height params in 21504 * {@link com.google.zxing.datamatrix.DataMatrixWriter#encode(String, BarcodeFormat, int, int)} 21505 */ 21506 /*@Deprecated*/ 21507 EncodeHintType[EncodeHintType["MIN_SIZE"] = 4] = "MIN_SIZE"; 21508 /** 21509 * Specifies a maximum barcode size (type {@link Dimension}). Only applicable to Data Matrix now. 21510 * 21511 * @deprecated without replacement 21512 */ 21513 /*@Deprecated*/ 21514 EncodeHintType[EncodeHintType["MAX_SIZE"] = 5] = "MAX_SIZE"; 21515 /** 21516 * Specifies margin, in pixels, to use when generating the barcode. The meaning can vary 21517 * by format; for example it controls margin before and after the barcode horizontally for 21518 * most 1D formats. (Type {@link Integer}, or {@link String} representation of the integer value). 21519 */ 21520 EncodeHintType[EncodeHintType["MARGIN"] = 6] = "MARGIN"; 21521 /** 21522 * Specifies whether to use compact mode for PDF417 (type {@link Boolean}, or "true" or "false" 21523 * {@link String} value). 21524 */ 21525 EncodeHintType[EncodeHintType["PDF417_COMPACT"] = 7] = "PDF417_COMPACT"; 21526 /** 21527 * Specifies what compaction mode to use for PDF417 (type 21528 * {@link com.google.zxing.pdf417.encoder.Compaction Compaction} or {@link String} value of one of its 21529 * enum values). 21530 */ 21531 EncodeHintType[EncodeHintType["PDF417_COMPACTION"] = 8] = "PDF417_COMPACTION"; 21532 /** 21533 * Specifies the minimum and maximum number of rows and columns for PDF417 (type 21534 * {@link com.google.zxing.pdf417.encoder.Dimensions Dimensions}). 21535 */ 21536 EncodeHintType[EncodeHintType["PDF417_DIMENSIONS"] = 9] = "PDF417_DIMENSIONS"; 21537 /** 21538 * Specifies the required number of layers for an Aztec code. 21539 * A negative number (-1, -2, -3, -4) specifies a compact Aztec code. 21540 * 0 indicates to use the minimum number of layers (the default). 21541 * A positive number (1, 2, .. 32) specifies a normal (non-compact) Aztec code. 21542 * (Type {@link Integer}, or {@link String} representation of the integer value). 21543 */ 21544 EncodeHintType[EncodeHintType["AZTEC_LAYERS"] = 10] = "AZTEC_LAYERS"; 21545 /** 21546 * Specifies the exact version of QR code to be encoded. 21547 * (Type {@link Integer}, or {@link String} representation of the integer value). 21548 */ 21549 EncodeHintType[EncodeHintType["QR_VERSION"] = 11] = "QR_VERSION"; 21550 /** 21551 * Specifies whether the data should be encoded to the GS1 standard (type {@link Boolean}, or "true" or "false" 21552 * {@link String } value). 21553 */ 21554 EncodeHintType[EncodeHintType["GS1_FORMAT"] = 12] = "GS1_FORMAT"; 21555 /** 21556 * Forces C40 encoding for data-matrix (type {@link Boolean}, or "true" or "false") {@link String } value). This 21557 * option and {@link #DATA_MATRIX_COMPACT} are mutually exclusive. 21558 */ 21559 EncodeHintType[EncodeHintType["FORCE_C40"] = 13] = "FORCE_C40"; 21560 })(EncodeHintType || (EncodeHintType = {})); 21561 var EncodeHintType$1 = EncodeHintType; 21562 21563 /* 21564 * Copyright 2008 ZXing authors 21565 * 21566 * Licensed under the Apache License, Version 2.0 (the "License"); 21567 * you may not use this file except in compliance with the License. 21568 * You may obtain a copy of the License at 21569 * 21570 * http://www.apache.org/licenses/LICENSE-2.0 21571 * 21572 * Unless required by applicable law or agreed to in writing, software 21573 * distributed under the License is distributed on an "AS IS" BASIS, 21574 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21575 * See the License for the specific language governing permissions and 21576 * limitations under the License. 21577 */ 21578 /** 21579 * <p>Implements Reed-Solomon encoding, as the name implies.</p> 21580 * 21581 * @author Sean Owen 21582 * @author William Rucklidge 21583 */ 21584 class ReedSolomonEncoder { 21585 /** 21586 * A reed solomon error-correcting encoding constructor is created by 21587 * passing as Galois Field with of size equal to the number of code 21588 * words (symbols) in the alphabet (the number of values in each 21589 * element of arrays that are encoded/decoded). 21590 * @param field A galois field with a number of elements equal to the size 21591 * of the alphabet of symbols to encode. 21592 */ 21593 constructor(field) { 21594 this.field = field; 21595 this.cachedGenerators = []; 21596 this.cachedGenerators.push(new GenericGFPoly(field, Int32Array.from([1]))); 21597 } 21598 buildGenerator(degree /*int*/) { 21599 const cachedGenerators = this.cachedGenerators; 21600 if (degree >= cachedGenerators.length) { 21601 let lastGenerator = cachedGenerators[cachedGenerators.length - 1]; 21602 const field = this.field; 21603 for (let d = cachedGenerators.length; d <= degree; d++) { 21604 const nextGenerator = lastGenerator.multiply(new GenericGFPoly(field, Int32Array.from([1, field.exp(d - 1 + field.getGeneratorBase())]))); 21605 cachedGenerators.push(nextGenerator); 21606 lastGenerator = nextGenerator; 21607 } 21608 } 21609 return cachedGenerators[degree]; 21610 } 21611 /** 21612 * <p>Encode a sequence of code words (symbols) using Reed-Solomon to allow decoders 21613 * to detect and correct errors that may have been introduced when the resulting 21614 * data is stored or transmitted.</p> 21615 * 21616 * @param toEncode array used for both and output. Caller initializes the array with 21617 * the code words (symbols) to be encoded followed by empty elements allocated to make 21618 * space for error-correction code words in the encoded output. The array contains 21619 * the encdoded output when encode returns. Code words are encoded as numbers from 21620 * 0 to n-1, where n is the number of possible code words (symbols), as determined 21621 * by the size of the Galois Field passed in the constructor of this object. 21622 * @param ecBytes the number of elements reserved in the array (first parameter) 21623 * to store error-correction code words. Thus, the number of code words (symbols) 21624 * to encode in the first parameter is thus toEncode.length - ecBytes. 21625 * Note, the use of "bytes" in the name of this parameter is misleading, as there may 21626 * be more or fewer than 256 symbols being encoded, as determined by the number of 21627 * elements in the Galois Field passed as a constructor to this object. 21628 * @throws IllegalArgumentException thrown in response to validation errros. 21629 */ 21630 encode(toEncode, ecBytes /*int*/) { 21631 if (ecBytes === 0) { 21632 throw new IllegalArgumentException('No error correction bytes'); 21633 } 21634 const dataBytes = toEncode.length - ecBytes; 21635 if (dataBytes <= 0) { 21636 throw new IllegalArgumentException('No data bytes provided'); 21637 } 21638 const generator = this.buildGenerator(ecBytes); 21639 const infoCoefficients = new Int32Array(dataBytes); 21640 System.arraycopy(toEncode, 0, infoCoefficients, 0, dataBytes); 21641 let info = new GenericGFPoly(this.field, infoCoefficients); 21642 info = info.multiplyByMonomial(ecBytes, 1); 21643 const remainder = info.divide(generator)[1]; 21644 const coefficients = remainder.getCoefficients(); 21645 const numZeroCoefficients = ecBytes - coefficients.length; 21646 for (let i = 0; i < numZeroCoefficients; i++) { 21647 toEncode[dataBytes + i] = 0; 21648 } 21649 System.arraycopy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.length); 21650 } 21651 } 21652 21653 /* 21654 * Copyright 2008 ZXing authors 21655 * 21656 * Licensed under the Apache License, Version 2.0 (the "License"); 21657 * you may not use this file except in compliance with the License. 21658 * You may obtain a copy of the License at 21659 * 21660 * http://www.apache.org/licenses/LICENSE-2.0 21661 * 21662 * Unless required by applicable law or agreed to in writing, software 21663 * distributed under the License is distributed on an "AS IS" BASIS, 21664 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21665 * See the License for the specific language governing permissions and 21666 * limitations under the License. 21667 */ 21668 /** 21669 * @author Satoru Takabayashi 21670 * @author Daniel Switkin 21671 * @author Sean Owen 21672 */ 21673 class MaskUtil { 21674 constructor() { 21675 // do nothing 21676 } 21677 /** 21678 * Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and 21679 * give penalty to them. Example: 00000 or 11111. 21680 */ 21681 static applyMaskPenaltyRule1(matrix) { 21682 return MaskUtil.applyMaskPenaltyRule1Internal(matrix, true) + MaskUtil.applyMaskPenaltyRule1Internal(matrix, false); 21683 } 21684 /** 21685 * Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give 21686 * penalty to them. This is actually equivalent to the spec's rule, which is to find MxN blocks and give a 21687 * penalty proportional to (M-1)x(N-1), because this is the number of 2x2 blocks inside such a block. 21688 */ 21689 static applyMaskPenaltyRule2(matrix) { 21690 let penalty = 0; 21691 const array = matrix.getArray(); 21692 const width
vendor: 6,851 bytes, lines 21692-21866
21692= matrix.getWidth(); 21693 const height = matrix.getHeight(); 21694 for (let y = 0; y < height - 1; y++) { 21695 const arrayY = array[y]; 21696 for (let x = 0; x < width - 1; x++) { 21697 const value = arrayY[x]; 21698 if (value === arrayY[x + 1] && value === array[y + 1][x] && value === array[y + 1][x + 1]) { 21699 penalty++; 21700 } 21701 } 21702 } 21703 return MaskUtil.N2 * penalty; 21704 } 21705 /** 21706 * Apply mask penalty rule 3 and return the penalty. Find consecutive runs of 1:1:3:1:1:4 21707 * starting with black, or 4:1:1:3:1:1 starting with white, and give penalty to them. If we 21708 * find patterns like 000010111010000, we give penalty once. 21709 */ 21710 static applyMaskPenaltyRule3(matrix) { 21711 let numPenalties = 0; 21712 const array = matrix.getArray(); 21713 const width = matrix.getWidth(); 21714 const height = matrix.getHeight(); 21715 for (let y = 0; y < height; y++) { 21716 for (let x = 0; x < width; x++) { 21717 const arrayY = array[y]; // We can at least optimize this access 21718 if (x + 6 < width && 21719 arrayY[x] === 1 && 21720 arrayY[x + 1] === 0 && 21721 arrayY[x + 2] === 1 && 21722 arrayY[x + 3] === 1 && 21723 arrayY[x + 4] === 1 && 21724 arrayY[x + 5] === 0 && 21725 arrayY[x + 6] === 1 && 21726 (MaskUtil.isWhiteHorizontal(arrayY, x - 4, x) || MaskUtil.isWhiteHorizontal(arrayY, x + 7, x + 11))) { 21727 numPenalties++; 21728 } 21729 if (y + 6 < height && 21730 array[y][x] === 1 && 21731 array[y + 1][x] === 0 && 21732 array[y + 2][x] === 1 && 21733 array[y + 3][x] === 1 && 21734 array[y + 4][x] === 1 && 21735 array[y + 5][x] === 0 && 21736 array[y + 6][x] === 1 && 21737 (MaskUtil.isWhiteVertical(array, x, y - 4, y) || MaskUtil.isWhiteVertical(array, x, y + 7, y + 11))) { 21738 numPenalties++; 21739 } 21740 } 21741 } 21742 return numPenalties * MaskUtil.N3; 21743 } 21744 static isWhiteHorizontal(rowArray, from /*int*/, to /*int*/) { 21745 from = Math.max(from, 0); 21746 to = Math.min(to, rowArray.length); 21747 for (let i = from; i < to; i++) { 21748 if (rowArray[i] === 1) { 21749 return false; 21750 } 21751 } 21752 return true; 21753 } 21754 static isWhiteVertical(array, col /*int*/, from /*int*/, to /*int*/) { 21755 from = Math.max(from, 0); 21756 to = Math.min(to, array.length); 21757 for (let i = from; i < to; i++) { 21758 if (array[i][col] === 1) { 21759 return false; 21760 } 21761 } 21762 return true; 21763 } 21764 /** 21765 * Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give 21766 * penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance. 21767 */ 21768 static applyMaskPenaltyRule4(matrix) { 21769 let numDarkCells = 0; 21770 const array = matrix.getArray(); 21771 const width = matrix.getWidth(); 21772 const height = matrix.getHeight(); 21773 for (let y = 0; y < height; y++) { 21774 const arrayY = array[y]; 21775 for (let x = 0; x < width; x++) { 21776 if (arrayY[x] === 1) { 21777 numDarkCells++; 21778 } 21779 } 21780 } 21781 const numTotalCells = matrix.getHeight() * matrix.getWidth(); 21782 const fivePercentVariances = Math.floor(Math.abs(numDarkCells * 2 - numTotalCells) * 10 / numTotalCells); 21783 return fivePercentVariances * MaskUtil.N4; 21784 } 21785 /** 21786 * Return the mask bit for "getMaskPattern" at "x" and "y". See 8.8 of JISX0510:2004 for mask 21787 * pattern conditions. 21788 */ 21789 static getDataMaskBit(maskPattern /*int*/, x /*int*/, y /*int*/) { 21790 let intermediate; /*int*/ 21791 let temp; /*int*/ 21792 switch (maskPattern) { 21793 case 0: 21794 intermediate = (y + x) & 0x1; 21795 break; 21796 case 1: 21797 intermediate = y & 0x1; 21798 break; 21799 case 2: 21800 intermediate = x % 3; 21801 break; 21802 case 3: 21803 intermediate = (y + x) % 3; 21804 break; 21805 case 4: 21806 intermediate = (Math.floor(y / 2) + Math.floor(x / 3)) & 0x1; 21807 break; 21808 case 5: 21809 temp = y * x; 21810 intermediate = (temp & 0x1) + (temp % 3); 21811 break; 21812 case 6: 21813 temp = y * x; 21814 intermediate = ((temp & 0x1) + (temp % 3)) & 0x1; 21815 break; 21816 case 7: 21817 temp = y * x; 21818 intermediate = ((temp % 3) + ((y + x) & 0x1)) & 0x1; 21819 break; 21820 default: 21821 throw new IllegalArgumentException('Invalid mask pattern: ' + maskPattern); 21822 } 21823 return intermediate === 0; 21824 } 21825 /** 21826 * Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both 21827 * vertical and horizontal orders respectively. 21828 */ 21829 static applyMaskPenaltyRule1Internal(matrix, isHorizontal) { 21830 let penalty = 0; 21831 const iLimit = isHorizontal ? matrix.getHeight() : matrix.getWidth(); 21832 const jLimit = isHorizontal ? matrix.getWidth() : matrix.getHeight(); 21833 const array = matrix.getArray(); 21834 for (let i = 0; i < iLimit; i++) { 21835 let numSameBitCells = 0; 21836 let prevBit = -1; 21837 for (let j = 0; j < jLimit; j++) { 21838 const bit = isHorizontal ? array[i][j] : array[j][i]; 21839 if (bit === prevBit) { 21840 numSameBitCells++; 21841 } 21842 else { 21843 if (numSameBitCells >= 5) { 21844 penalty += MaskUtil.N1 + (numSameBitCells - 5); 21845 } 21846 numSameBitCells = 1; // Include the cell itself. 21847 prevBit = bit; 21848 } 21849 } 21850 if (numSameBitCells >= 5) { 21851 penalty += MaskUtil.N1 + (numSameBitCells - 5); 21852 } 21853 } 21854 return penalty; 21855 } 21856 } 21857 // Penalty weights from section 6.8.2.1 21858 MaskUtil.N1 = 3; 21859 MaskUtil.N2 = 3; 21860 MaskUtil.N3 = 40; 21861 MaskUtil.N4 = 10; 21862 21863 /* 21864 * Copyright 2008 ZXing authors 21865 * 21866 * Licensed under the Apache License, Version 2.0 (the "License");
21867 * you may not use this file except in compliance with the License. 21868 * You may obtain a copy of the License at 21869 * 21870 * http://www.apache.org/licenses/LICENSE-2.0 21871 * 21872 * Unless required by applicable law or agreed to in writing, software 21873 * distributed under the License is distributed on an "AS IS" BASIS, 21874 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21875 * See the License for the specific language governing permissions and 21876 * limitations under the License. 21877 */ 21878 /** 21879 * JAVAPORT: The original code was a 2D array of ints, but since it only ever gets assigned 21880 * -1, 0, and 1, I'm going to use less memory and go with bytes. 21881 * 21882 * @author [email protected] (Daniel Switkin) 21883 */ 21884 class ByteMatrix { 21885 constructor(width /*int*/, height /*int*/) { 21886 this.width = width; 21887 this.height = height; 21888 const bytes = new Array(height); // [height][width] 21889 for (let i = 0; i !== height; i++) { 21890 bytes[i] = new Uint8Array(width); 21891 } 21892 this.bytes = bytes; 21893 } 21894 getHeight() { 21895 return this.height; 21896 } 21897 getWidth() { 21898 return this.width; 21899 } 21900 get(x /*int*/, y /*int*/) { 21901 return this.bytes[y][x]; 21902 } 21903 /** 21904 * @return an internal representation as bytes, in row-major order. array[y][x] represents point (x,y) 21905 */ 21906 getArray() { 21907 return this.bytes; 21908 } 21909 // TYPESCRIPTPORT: preffer to let two methods instead of override to avoid type comparison inside 21910 setNumber(x /*int*/, y /*int*/, value /*byte|int*/) { 21911 this.bytes[y][x] = value; 21912 } 21913 // public set(x: number /*int*/, y: number /*int*/, value: number /*int*/): void { 21914 // bytes[y][x] = (byte) value 21915 // } 21916 setBoolean(x /*int*/, y /*int*/, value) { 21917 this.bytes[y][x] = /*(byte) */ (value ? 1 : 0); 21918 } 21919 clear(value /*byte*/) { 21920 for (const aByte of this.bytes) { 21921 Arrays.fill(aByte, value); 21922 } 21923 } 21924 equals(o) { 21925 if (!(o instanceof ByteMatrix)) { 21926 return false; 21927 } 21928 const other = o; 21929 if (this.width !== other.width) { 21930 return false; 21931 } 21932 if (this.height !== other.height) { 21933 return false; 21934 } 21935 for (let y = 0, height = this.height; y < height; ++y) { 21936 const bytesY = this.bytes[y]; 21937 const otherBytesY = other.bytes[y]; 21938 for (let x = 0, width = this.width; x < width; ++x) { 21939 if (bytesY[x] !== otherBytesY[x]) { 21940 return false; 21941 } 21942 } 21943 } 21944 return true; 21945 } 21946 /*@Override*/ 21947 toString() { 21948 const result = new StringBuilder(); // (2 * width * height + 2) 21949 for (let y = 0, height = this.height; y < height; ++y) { 21950 const bytesY = this.bytes[y]; 21951 for (let x = 0, width = this.width; x < width; ++x) { 21952 switch (bytesY[x]) { 21953 case 0: 21954 result.append(' 0'); 21955 break; 21956 case 1: 21957 result.append(' 1'); 21958 break; 21959 default: 21960 result.append(' '); 21961 break; 21962 } 21963 } 21964 result.append('\n'); 21965 } 21966 return result.toString(); 21967 } 21968 } 21969 21970 /* 21971 * Copyright 2008 ZXing authors 21972 * 21973 * Licensed under the Apache License, Version 2.0 (the "License"); 21974 * you may not use this file except in compliance with the License. 21975 * You may obtain a copy of the License at 21976 * 21977 * http://www.apache.org/licenses/LICENSE-2.0 21978 * 21979 * Unless required by applicable law or agreed to in writing, software 21980 * distributed under the License is distributed on an "AS IS" BASIS, 21981 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21982 * See the License for the specific language governing permissions and 21983 * limitations under the License. 21984 */ 21985 /** 21986 * @author [email protected] (Satoru Takabayashi) - creator 21987 * @author [email protected] (Daniel Switkin) - ported from C++ 21988 */ 21989 class QRCode { 21990 constructor() { 21991 this.maskPattern = -1; 21992 } 21993 getMode() { 21994 return this.mode; 21995 } 21996 getECLevel() { 21997 return this.ecLevel; 21998 } 21999 getVersion() { 22000 return this.version; 22001 } 22002 getMaskPattern() { 22003 return this.maskPattern; 22004 } 22005 getMatrix() { 22006 return this.matrix; 22007 } 22008 /*@Override*/ 22009 toString() { 22010 const result = new StringBuilder(); // (200) 22011 result.append('<<\n'); 22012 result.append(' mode: '); 22013 result.append(this.mode ? this.mode.toString() : 'null'); 22014 result.append('\n ecLevel: '); 22015 result.append(this.ecLevel ? this.ecLevel.toString() : 'null'); 22016 result.append('\n version: '); 22017 result.append(this.version ? this.version.toString() : 'null'); 22018 result.append('\n maskPattern: '); 22019 result.append(this.maskPattern.toString());
22020 if (this.matrix) { 22021 result.append('\n matrix:\n'); 22022 result.append(this.matrix.toString()); 22023 } 22024 else { 22025 result.append('\n matrix: null\n'); 22026 } 22027 result.append('>>\n'); 22028 return result.toString(); 22029 } 22030 setMode(value) { 22031 this.mode = value; 22032 } 22033 setECLevel(value) { 22034 this.ecLevel = value; 22035 } 22036 setVersion(version) { 22037 this.version = version; 22038 } 22039 setMaskPattern(value /*int*/) { 22040 this.maskPattern = value; 22041 } 22042 setMatrix(value) { 22043 this.matrix = value; 22044 } 22045 // Check if "mask_pattern" is valid. 22046 static isValidMaskPattern(maskPattern /*int*/) { 22047 return maskPattern >= 0 && maskPattern < QRCode.NUM_MASK_PATTERNS; 22048 } 22049 } 22050 QRCode.NUM_MASK_PATTERNS = 8; 22051 22052 /** 22053 * Custom Error class of type Exception. 22054 */ 22055 class WriterException extends Exception { 22056 } 22057 WriterException.kind = 'WriterException'; 22058 22059 /* 22060 * Copyright 2008 ZXing authors 22061 * 22062 * Licensed under the Apache License, Version 2.0 (the "License"); 22063 * you may not use this file except in compliance with the License. 22064 * You may obtain a copy of the License at 22065 * 22066 * http://www.apache.org/licenses/LICENSE-2.0 22067 * 22068 * Unless required by applicable law or agreed to in writing, software 22069 * distributed under the License is distributed on an "AS IS" BASIS, 22070 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22071 * See the License for the specific language governing permissions and 22072 * limitations under the License. 22073
vendor: 16,835 bytes, lines 22073-22416
22073*/ 22074 /** 22075 * @author [email protected] (Satoru Takabayashi) - creator 22076 * @author [email protected] (Daniel Switkin) - ported from C++ 22077 */ 22078 class MatrixUtil { 22079 constructor() { 22080 // do nothing 22081 } 22082 // Set all cells to -1 (TYPESCRIPTPORT: 255). -1 (TYPESCRIPTPORT: 255) means that the cell is empty (not set yet). 22083 // 22084 // JAVAPORT: We shouldn't need to do this at all. The code should be rewritten to begin encoding 22085 // with the ByteMatrix initialized all to zero. 22086 static clearMatrix(matrix) { 22087 // TYPESCRIPTPORT: we use UintArray se changed here from -1 to 255 22088 matrix.clear(/*(byte) */ /*-1*/ 255); 22089 } 22090 // Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On 22091 // success, store the result in "matrix" and return true. 22092 static buildMatrix(dataBits, ecLevel, version, maskPattern /*int*/, matrix) { 22093 MatrixUtil.clearMatrix(matrix); 22094 MatrixUtil.embedBasicPatterns(version, matrix); 22095 // Type information appear with any version. 22096 MatrixUtil.embedTypeInfo(ecLevel, maskPattern, matrix); 22097 // Version info appear if version >= 7. 22098 MatrixUtil.maybeEmbedVersionInfo(version, matrix); 22099 // Data should be embedded at end. 22100 MatrixUtil.embedDataBits(dataBits, maskPattern, matrix); 22101 } 22102 // Embed basic patterns. On success, modify the matrix and return true. 22103 // The basic patterns are: 22104 // - Position detection patterns 22105 // - Timing patterns 22106 // - Dark dot at the left bottom corner 22107 // - Position adjustment patterns, if need be 22108 static embedBasicPatterns(version, matrix) { 22109 // Let's get started with embedding big squares at corners. 22110 MatrixUtil.embedPositionDetectionPatternsAndSeparators(matrix); 22111 // Then, embed the dark dot at the left bottom corner. 22112 MatrixUtil.embedDarkDotAtLeftBottomCorner(matrix); 22113 // Position adjustment patterns appear if version >= 2. 22114 MatrixUtil.maybeEmbedPositionAdjustmentPatterns(version, matrix); 22115 // Timing patterns should be embedded after position adj. patterns. 22116 MatrixUtil.embedTimingPatterns(matrix); 22117 } 22118 // Embed type information. On success, modify the matrix. 22119 static embedTypeInfo(ecLevel, maskPattern /*int*/, matrix) { 22120 const typeInfoBits = new BitArray(); 22121 MatrixUtil.makeTypeInfoBits(ecLevel, maskPattern, typeInfoBits); 22122 for (let i = 0, size = typeInfoBits.getSize(); i < size; ++i) { 22123 // Place bits in LSB to MSB order. LSB (least significant bit) is the last value in 22124 // "typeInfoBits". 22125 const bit = typeInfoBits.get(typeInfoBits.getSize() - 1 - i); 22126 // Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46). 22127 const coordinates = MatrixUtil.TYPE_INFO_COORDINATES[i]; 22128 const x1 = coordinates[0]; 22129 const y1 = coordinates[1]; 22130 matrix.setBoolean(x1, y1, bit); 22131 if (i < 8) { 22132 // Right top corner. 22133 const x2 = matrix.getWidth() - i - 1; 22134 const y2 = 8; 22135 matrix.setBoolean(x2, y2, bit); 22136 } 22137 else { 22138 // Left bottom corner. 22139 const x2 = 8; 22140 const y2 = matrix.getHeight() - 7 + (i - 8); 22141 matrix.setBoolean(x2, y2, bit); 22142 } 22143 } 22144 } 22145 // Embed version information if need be. On success, modify the matrix and return true. 22146 // See 8.10 of JISX0510:2004 (p.47) for how to embed version information. 22147 static maybeEmbedVersionInfo(version, matrix) { 22148 if (version.getVersionNumber() < 7) { // Version info is necessary if version >= 7. 22149 return; // Don't need version info. 22150 } 22151 const versionInfoBits = new BitArray(); 22152 MatrixUtil.makeVersionInfoBits(version, versionInfoBits); 22153 let bitIndex = 6 * 3 - 1; // It will decrease from 17 to 0. 22154 for (let i = 0; i < 6; ++i) { 22155 for (let j = 0; j < 3; ++j) { 22156 // Place bits in LSB (least significant bit) to MSB order. 22157 const bit = versionInfoBits.get(bitIndex); 22158 bitIndex--; 22159 // Left bottom corner. 22160 matrix.setBoolean(i, matrix.getHeight() - 11 + j, bit); 22161 // Right bottom corner. 22162 matrix.setBoolean(matrix.getHeight() - 11 + j, i, bit); 22163 } 22164 } 22165 } 22166 // Embed "dataBits" using "getMaskPattern". On success, modify the matrix and return true. 22167 // For debugging purposes, it skips masking process if "getMaskPattern" is -1(TYPESCRIPTPORT: 255). 22168 // See 8.7 of JISX0510:2004 (p.38) for how to embed data bits. 22169 static embedDataBits(dataBits, maskPattern /*int*/, matrix) { 22170 let bitIndex = 0; 22171 let direction = -1; 22172 // Start from the right bottom cell. 22173 let x = matrix.getWidth() - 1; 22174 let y = matrix.getHeight() - 1; 22175 while (x > 0) { 22176 // Skip the vertical timing pattern. 22177 if (x === 6) { 22178 x -= 1; 22179 } 22180 while (y >= 0 && y < matrix.getHeight()) { 22181 for (let i = 0; i < 2; ++i) { 22182 const xx = x - i; 22183 // Skip the cell if it's not empty. 22184 if (!MatrixUtil.isEmpty(matrix.get(xx, y))) { 22185 continue; 22186 } 22187 let bit; 22188 if (bitIndex < dataBits.getSize()) { 22189 bit = dataBits.get(bitIndex); 22190 ++bitIndex; 22191 } 22192 else { 22193 // Padding bit. If there is no bit left, we'll fill the left cells with 0, as described 22194 // in 8.4.9 of JISX0510:2004 (p. 24). 22195 bit = false; 22196 } 22197 // Skip masking if mask_pattern is -1 (TYPESCRIPTPORT: 255). 22198 if (maskPattern !== 255 && MaskUtil.getDataMaskBit(maskPattern, xx, y)) { 22199 bit = !bit; 22200 } 22201 matrix.setBoolean(xx, y, bit); 22202 } 22203 y += direction; 22204 } 22205 direction = -direction; // Reverse the direction. 22206 y += direction; 22207 x -= 2; // Move to the left. 22208 } 22209 // All bits should be consumed. 22210 if (bitIndex !== dataBits.getSize()) { 22211 throw new WriterException('Not all bits consumed: ' + bitIndex + '/' + dataBits.getSize()); 22212 } 22213 } 22214 // Return the position of the most significant bit set (one: to) in the "value". The most 22215 // significant bit is position 32. If there is no bit set, return 0. Examples: 22216 // - findMSBSet(0) => 0 22217 // - findMSBSet(1) => 1 22218 // - findMSBSet(255) => 8 22219 static findMSBSet(value /*int*/) { 22220 return 32 - Integer.numberOfLeadingZeros(value); 22221 } 22222 // Calculate BCH (Bose-Chaudhuri-Hocquenghem) code for "value" using polynomial "poly". The BCH 22223 // code is used for encoding type information and version information. 22224 // Example: Calculation of version information of 7. 22225 // f(x) is created from 7. 22226 // - 7 = 000111 in 6 bits 22227 // - f(x) = x^2 + x^1 + x^0 22228 // g(x) is given by the standard (p. 67) 22229 // - g(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1 22230 // Multiply f(x) by x^(18 - 6) 22231 // - f'(x) = f(x) * x^(18 - 6) 22232 // - f'(x) = x^14 + x^13 + x^12 22233 // Calculate the remainder of f'(x) / g(x) 22234 // x^2 22235 // __________________________________________________ 22236 // g(x) )x^14 + x^13 + x^12 22237 // x^14 + x^13 + x^12 + x^11 + x^10 + x^7 + x^4 + x^2 22238 // -------------------------------------------------- 22239 // x^11 + x^10 + x^7 + x^4 + x^2 22240 // 22241 // The remainder is x^11 + x^10 + x^7 + x^4 + x^2 22242 // Encode it in binary: 110010010100 22243 // The return value is 0xc94 (1100 1001 0100) 22244 // 22245 // Since all coefficients in the polynomials are 1 or 0, we can do the calculation by bit 22246 // operations. We don't care if coefficients are positive or negative. 22247 static calculateBCHCode(value /*int*/, poly /*int*/) { 22248 if (poly === 0) { 22249 throw new IllegalArgumentException('0 polynomial'); 22250 } 22251 // If poly is "1 1111 0010 0101" (version info poly), msbSetInPoly is 13. We'll subtract 1 22252 // from 13 to make it 12. 22253 const msbSetInPoly = MatrixUtil.findMSBSet(poly); 22254 value <<= msbSetInPoly - 1; 22255 // Do the division business using exclusive-or operations. 22256 while (MatrixUtil.findMSBSet(value) >= msbSetInPoly) { 22257 value ^= poly << (MatrixUtil.findMSBSet(value) - msbSetInPoly); 22258 } 22259 // Now the "value" is the remainder (i.e. the BCH code) 22260 return value; 22261 } 22262 // Make bit vector of type information. On success, store the result in "bits" and return true. 22263 // Encode error correction level and mask pattern. See 8.9 of 22264 // JISX0510:2004 (p.45) for details. 22265 static makeTypeInfoBits(ecLevel, maskPattern /*int*/, bits) { 22266 if (!QRCode.isValidMaskPattern(maskPattern)) { 22267 throw new WriterException('Invalid mask pattern'); 22268 } 22269 const typeInfo = (ecLevel.getBits() << 3) | maskPattern; 22270 bits.appendBits(typeInfo, 5); 22271 const bchCode = MatrixUtil.calculateBCHCode(typeInfo, MatrixUtil.TYPE_INFO_POLY); 22272 bits.appendBits(bchCode, 10); 22273 const maskBits = new BitArray(); 22274 maskBits.appendBits(MatrixUtil.TYPE_INFO_MASK_PATTERN, 15); 22275 bits.xor(maskBits); 22276 if (bits.getSize() !== 15) { // Just in case. 22277 throw new WriterException('should not happen but we got: ' + bits.getSize()); 22278 } 22279 } 22280 // Make bit vector of version information. On success, store the result in "bits" and return true. 22281 // See 8.10 of JISX0510:2004 (p.45) for details. 22282 static makeVersionInfoBits(version, bits) { 22283 bits.appendBits(version.getVersionNumber(), 6); 22284 const bchCode = MatrixUtil.calculateBCHCode(version.getVersionNumber(), MatrixUtil.VERSION_INFO_POLY); 22285 bits.appendBits(bchCode, 12); 22286 if (bits.getSize() !== 18) { // Just in case. 22287 throw new WriterException('should not happen but we got: ' + bits.getSize()); 22288 } 22289 } 22290 // Check if "value" is empty. 22291 static isEmpty(value /*int*/) { 22292 return value === 255; // -1 22293 } 22294 static embedTimingPatterns(matrix) { 22295 // -8 is for skipping position detection patterns (7: size), and two horizontal/vertical 22296 // separation patterns (1: size). Thus, 8 = 7 + 1. 22297 for (let i = 8; i < matrix.getWidth() - 8; ++i) { 22298 const bit = (i + 1) % 2; 22299 // Horizontal line. 22300 if (MatrixUtil.isEmpty(matrix.get(i, 6))) { 22301 matrix.setNumber(i, 6, bit); 22302 } 22303 // Vertical line. 22304 if (MatrixUtil.isEmpty(matrix.get(6, i))) { 22305 matrix.setNumber(6, i, bit); 22306 } 22307 } 22308 } 22309 // Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46) 22310 static embedDarkDotAtLeftBottomCorner(matrix) { 22311 if (matrix.get(8, matrix.getHeight() - 8) === 0) { 22312 throw new WriterException(); 22313 } 22314 matrix.setNumber(8, matrix.getHeight() - 8, 1); 22315 } 22316 static embedHorizontalSeparationPattern(xStart /*int*/, yStart /*int*/, matrix) { 22317 for (let x = 0; x < 8; ++x) { 22318 if (!MatrixUtil.isEmpty(matrix.get(xStart + x, yStart))) { 22319 throw new WriterException(); 22320 } 22321 matrix.setNumber(xStart + x, yStart, 0); 22322 } 22323 } 22324 static embedVerticalSeparationPattern(xStart /*int*/, yStart /*int*/, matrix) { 22325 for (let y = 0; y < 7; ++y) { 22326 if (!MatrixUtil.isEmpty(matrix.get(xStart, yStart + y))) { 22327 throw new WriterException(); 22328 } 22329 matrix.setNumber(xStart, yStart + y, 0); 22330 } 22331 } 22332 static embedPositionAdjustmentPattern(xStart /*int*/, yStart /*int*/, matrix) { 22333 for (let y = 0; y < 5; ++y) { 22334 const patternY = MatrixUtil.POSITION_ADJUSTMENT_PATTERN[y]; 22335 for (let x = 0; x < 5; ++x) { 22336 matrix.setNumber(xStart + x, yStart + y, patternY[x]); 22337 } 22338 } 22339 } 22340 static embedPositionDetectionPattern(xStart /*int*/, yStart /*int*/, matrix) { 22341 for (let y = 0; y < 7; ++y) { 22342 const patternY = MatrixUtil.POSITION_DETECTION_PATTERN[y]; 22343 for (let x = 0; x < 7; ++x) { 22344 matrix.setNumber(xStart + x, yStart + y, patternY[x]); 22345 } 22346 } 22347 } 22348 // Embed position detection patterns and surrounding vertical/horizontal separators. 22349 static embedPositionDetectionPatternsAndSeparators(matrix) { 22350 // Embed three big squares at corners. 22351 const pdpWidth = MatrixUtil.POSITION_DETECTION_PATTERN[0].length; 22352 // Left top corner. 22353 MatrixUtil.embedPositionDetectionPattern(0, 0, matrix); 22354 // Right top corner. 22355 MatrixUtil.embedPositionDetectionPattern(matrix.getWidth() - pdpWidth, 0, matrix); 22356 // Left bottom corner. 22357 MatrixUtil.embedPositionDetectionPattern(0, matrix.getWidth() - pdpWidth, matrix); 22358 // Embed horizontal separation patterns around the squares. 22359 const hspWidth = 8; 22360 // Left top corner. 22361 MatrixUtil.embedHorizontalSeparationPattern(0, hspWidth - 1, matrix); 22362 // Right top corner. 22363 MatrixUtil.embedHorizontalSeparationPattern(matrix.getWidth() - hspWidth, hspWidth - 1, matrix); 22364 // Left bottom corner. 22365 MatrixUtil.embedHorizontalSeparationPattern(0, matrix.getWidth() - hspWidth, matrix); 22366 // Embed vertical separation patterns around the squares. 22367 const vspSize = 7; 22368 // Left top corner. 22369 MatrixUtil.embedVerticalSeparationPattern(vspSize, 0, matrix); 22370 // Right top corner. 22371 MatrixUtil.embedVerticalSeparationPattern(matrix.getHeight() - vspSize - 1, 0, matrix); 22372 // Left bottom corner. 22373 MatrixUtil.embedVerticalSeparationPattern(vspSize, matrix.getHeight() - vspSize, matrix); 22374 } 22375 // Embed position adjustment patterns if need be. 22376 static maybeEmbedPositionAdjustmentPatterns(version, matrix) { 22377 if (version.getVersionNumber() < 2) { // The patterns appear if version >= 2 22378 return; 22379 } 22380 const index = version.getVersionNumber() - 1; 22381 const coordinates = MatrixUtil.POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index]; 22382 for (let i = 0, length = coordinates.length; i !== length; i++) { 22383 const y = coordinates[i]; 22384 if (y >= 0) { 22385 for (let j = 0; j !== length; j++) { 22386 const x = coordinates[j]; 22387 if (x >= 0 && MatrixUtil.isEmpty(matrix.get(x, y))) { 22388 // If the cell is unset, we embed the position adjustment pattern here. 22389 // -2 is necessary since the x/y coordinates point to the center of the pattern, not the 22390 // left top corner. 22391 MatrixUtil.embedPositionAdjustmentPattern(x - 2, y - 2, matrix); 22392 } 22393 } 22394 } 22395 } 22396 } 22397 } 22398 MatrixUtil.POSITION_DETECTION_PATTERN = Array.from([ 22399 Int32Array.from([1, 1, 1, 1, 1, 1, 1]), 22400 Int32Array.from([1, 0, 0, 0, 0, 0, 1]), 22401 Int32Array.from([1, 0, 1, 1, 1, 0, 1]), 22402 Int32Array.from([1, 0, 1, 1, 1, 0, 1]), 22403 Int32Array.from([1, 0, 1, 1, 1, 0, 1]), 22404 Int32Array.from([1, 0, 0, 0, 0, 0, 1]), 22405 Int32Array.from([1, 1, 1, 1, 1, 1, 1]), 22406 ]); 22407 MatrixUtil.POSITION_ADJUSTMENT_PATTERN = Array.from([ 22408 Int32Array.from([1, 1, 1, 1, 1]), 22409 Int32Array.from([1, 0, 0, 0, 1]), 22410 Int32Array.from([1, 0, 1, 0, 1]), 22411 Int32Array.from([1, 0, 0, 0, 1]), 22412 Int32Array.from([1, 1, 1, 1, 1]), 22413 ]); 22414 // From Appendix E. Table 1, JIS0510X:2004 (71: p). The table was double-checked by komatsu. 22415 MatrixUtil.POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE = Array.from([ 22416 Int32Array.from([-1, -1, -1, -1, -1, -1, -1]),
vendor: 2,987 bytes, lines 22416-22484
22416 22417 Int32Array.from([6, 18, -1, -1, -1, -1, -1]), 22418 Int32Array.from([6, 22, -1, -1, -1, -1, -1]), 22419 Int32Array.from([6, 26, -1, -1, -1, -1, -1]), 22420 Int32Array.from([6, 30, -1, -1, -1, -1, -1]), 22421 Int32Array.from([6, 34, -1, -1, -1, -1, -1]), 22422 Int32Array.from([6, 22, 38, -1, -1, -1, -1]), 22423 Int32Array.from([6, 24, 42, -1, -1, -1, -1]), 22424 Int32Array.from([6, 26, 46, -1, -1, -1, -1]), 22425 Int32Array.from([6, 28, 50, -1, -1, -1, -1]), 22426 Int32Array.from([6, 30, 54, -1, -1, -1, -1]), 22427 Int32Array.from([6, 32, 58, -1, -1, -1, -1]), 22428 Int32Array.from([6, 34, 62, -1, -1, -1, -1]), 22429 Int32Array.from([6, 26, 46, 66, -1, -1, -1]), 22430 Int32Array.from([6, 26, 48, 70, -1, -1, -1]), 22431 Int32Array.from([6, 26, 50, 74, -1, -1, -1]), 22432 Int32Array.from([6, 30, 54, 78, -1, -1, -1]), 22433 Int32Array.from([6, 30, 56, 82, -1, -1, -1]), 22434 Int32Array.from([6, 30, 58, 86, -1, -1, -1]), 22435 Int32Array.from([6, 34, 62, 90, -1, -1, -1]), 22436 Int32Array.from([6, 28, 50, 72, 94, -1, -1]), 22437 Int32Array.from([6, 26, 50, 74, 98, -1, -1]), 22438 Int32Array.from([6, 30, 54, 78, 102, -1, -1]), 22439 Int32Array.from([6, 28, 54, 80, 106, -1, -1]), 22440 Int32Array.from([6, 32, 58, 84, 110, -1, -1]), 22441 Int32Array.from([6, 30, 58, 86, 114, -1, -1]), 22442 Int32Array.from([6, 34, 62, 90, 118, -1, -1]), 22443 Int32Array.from([6, 26, 50, 74, 98, 122, -1]), 22444 Int32Array.from([6, 30, 54, 78, 102, 126, -1]), 22445 Int32Array.from([6, 26, 52, 78, 104, 130, -1]), 22446 Int32Array.from([6, 30, 56, 82, 108, 134, -1]), 22447 Int32Array.from([6, 34, 60, 86, 112, 138, -1]), 22448 Int32Array.from([6, 30, 58, 86, 114, 142, -1]), 22449 Int32Array.from([6, 34, 62, 90, 118, 146, -1]), 22450 Int32Array.from([6, 30, 54, 78, 102, 126, 150]), 22451 Int32Array.from([6, 24, 50, 76, 102, 128, 154]), 22452 Int32Array.from([6, 28, 54, 80, 106, 132, 158]), 22453 Int32Array.from([6, 32, 58, 84, 110, 136, 162]), 22454 Int32Array.from([6, 26, 54, 82, 110, 138, 166]), 22455 Int32Array.from([6, 30, 58, 86, 114, 142, 170]), 22456 ]); 22457 // Type info cells at the left top corner. 22458 MatrixUtil.TYPE_INFO_COORDINATES = Array.from([ 22459 Int32Array.from([8, 0]), 22460 Int32Array.from([8, 1]), 22461 Int32Array.from([8, 2]), 22462 Int32Array.from([8, 3]), 22463 Int32Array.from([8, 4]), 22464 Int32Array.from([8, 5]), 22465 Int32Array.from([8, 7]), 22466 Int32Array.from([8, 8]), 22467 Int32Array.from([7, 8]), 22468 Int32Array.from([5, 8]), 22469 Int32Array.from([4, 8]), 22470 Int32Array.from([3, 8]), 22471 Int32Array.from([2, 8]), 22472 Int32Array.from([1, 8]), 22473 Int32Array.from([0, 8]), 22474 ]); 22475 // From Appendix D in JISX0510:2004 (p. 67) 22476 MatrixUtil.VERSION_INFO_POLY = 0x1f25; // 1 1111 0010 0101 22477 // From Appendix C in JISX0510:2004 (p.65). 22478 MatrixUtil.TYPE_INFO_POLY = 0x537; 22479 MatrixUtil.TYPE_INFO_MASK_PATTERN = 0x5412; 22480 22481 /* 22482 * Copyright 2008 ZXing authors 22483 * 22484 * Licensed under the Apache License, Version 2.0 (the "License");
22485 * you may not use this file except in compliance with the License. 22486 * You may obtain a copy of the License at 22487 * 22488 * http://www.apache.org/licenses/LICENSE-2.0 22489 * 22490 * Unless required by applicable law or agreed to in writing, software 22491 * distributed under the License is distributed on an "AS IS" BASIS, 22492 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22493 * See the License for the specific language governing permissions and 22494 * limitations under the License. 22495 */ 22496 /*namespace com.google.zxing.qrcode.encoder {*/ 22497 class BlockPair { 22498 constructor(dataBytes, errorCorrectionBytes) { 22499 this.dataBytes = dataBytes; 22500 this.errorCorrectionBytes = errorCorrectionBytes; 22501 } 22502 getDataBytes() { 22503 return this.dataBytes; 22504 } 22505 getErrorCorrectionBytes() { 22506 return this.errorCorrectionBytes; 22507 } 22508 } 22509 22510 /* 22511 * Copyright 2008 ZXing authors 22512 * 22513 * Licensed under the Apache License, Version 2.0 (the "License"); 22514 * you may not use this file except in compliance with the License. 22515 * You may obtain a copy of the License at 22516 * 22517 * http://www.apache.org/licenses/LICENSE-2.0 22518 * 22519 * Unless required by applicable law or agreed to in writing, software 22520 * distributed under the License is distributed on an "AS IS" BASIS, 22521 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22522 * See the License for the specific language governing permissions and 22523 * limitations under the License. 22524 */ 22525 /*import java.io.UnsupportedEncodingException;*/ 22526 /*import java.util.ArrayList;*/ 22527 /*import java.util.Collection;*/ 22528 /*import java.util.Map;*/ 22529 /** 22530 * @author [email protected] (Satoru Takabayashi) - creator 22531 * @author [email protected] (Daniel Switkin) - ported from C++ 22532 */ 22533 class Encoder$1 { 22534 // TYPESCRIPTPORT: changed to UTF8, the default for js 22535 constructor() { } 22536 // The mask penalty calculation is complicated. See Table 21 of JISX0510:2004 (p.45) for details. 22537 // Basically it applies four rules and summate all penalties. 22538 static calculateMaskPenalty(matrix) { 22539 return MaskUtil.applyMaskPenaltyRule1(matrix) 22540 + MaskUtil.applyMaskPenaltyRule2(matrix) 22541 + MaskUtil.applyMaskPenaltyRule3(matrix) 22542 + MaskUtil.applyMaskPenaltyRule4(matrix); 22543 } 22544 /** 22545 * @param content text to encode 22546 * @param ecLevel error correction level to use 22547 * @return {@link QRCode} representing the encoded QR code 22548 * @throws WriterException if encoding can't succeed, because of for example invalid content 22549 * or configuration 22550 */ 22551 // public static encode(content: string, ecLevel: ErrorCorrectionLevel): QRCode /*throws WriterException*/ { 22552 // return encode(content, ecLevel, null) 22553 // } 22554 static encode(content, ecLevel, hints = null) { 22555 // Determine what character encoding has been specified by the caller, if any 22556 let encoding = Encoder$1.DEFAULT_BYTE_MODE_ENCODING; 22557 const hasEncodingHint = hints !== null && undefined !== hints.get(EncodeHintType$1.CHARACTER_SET); 22558 if (hasEncodingHint) { 22559 encoding = hints.get(EncodeHintType$1.CHARACTER_SET).toString(); 22560 } 22561 // Pick an encoding mode appropriate for the content. Note that this will not attempt to use 22562 // multiple modes / segments even if that were more efficient. Twould be nice. 22563 const mode = this.chooseMode(content, encoding); 22564 // This will store the header information, like mode and 22565 // length, as well as "header" segments like an ECI segment. 22566 const headerBits = new BitArray(); 22567 // Append ECI segment if applicable 22568 if (mode === Mode$2.BYTE && (hasEncodingHint || Encoder$1.DEFAULT_BYTE_MODE_ENCODING !== encoding)) { 22569 const eci = CharacterSetECI.getCharacterSetECIByName(encoding); 22570 if (eci !== undefined) { 22571 this.appendECI(eci, headerBits); 22572 } 22573 } 22574 // (With ECI in place,) Write the mode marker 22575 this.appendModeInfo(mode, headerBits); 22576 // Collect data within the main segment, separately, to count its size if needed. Don't add it to 22577 // main payload yet. 22578 const dataBits = new BitArray(); 22579 this.appendBytes(content, mode, dataBits, encoding); 22580 let version; 22581 if (hints !== null && undefined !== hints.get(EncodeHintType$1.QR_VERSION)) { 22582 const versionNumber = Number.parseInt(hints.get(EncodeHintType$1.QR_VERSION).toString(), 10); 22583 version = Version.getVersionForNumber(versionNumber); 22584 const bitsNeeded = this.calculateBitsNeeded(mode, headerBits, dataBits, version); 22585 if (!this.willFit(bitsNeeded, version, ecLevel)) { 22586 throw new WriterException('Data too big for requested version'); 22587 } 22588 } 22589 else { 22590 version = this.recommendVersion(ecLevel, mode, headerBits, dataBits); 22591 }
vendor: 20,568 bytes, lines 22592-23039
22592 const headerAndDataBits = new BitArray(); 22593 headerAndDataBits.appendBitArray(headerBits); 22594 // Find "length" of main segment and write it 22595 const numLetters = mode === Mode$2.BYTE ? dataBits.getSizeInBytes() : content.length; 22596 this.appendLengthInfo(numLetters, version, mode, headerAndDataBits); 22597 // Put data together into the overall payload 22598 headerAndDataBits.appendBitArray(dataBits); 22599 const ecBlocks = version.getECBlocksForLevel(ecLevel); 22600 const numDataBytes = version.getTotalCodewords() - ecBlocks.getTotalECCodewords(); 22601 // Terminate the bits properly. 22602 this.terminateBits(numDataBytes, headerAndDataBits); 22603 // Interleave data bits with error correction code. 22604 const finalBits = this.interleaveWithECBytes(headerAndDataBits, version.getTotalCodewords(), numDataBytes, ecBlocks.getNumBlocks()); 22605 const qrCode = new QRCode(); 22606 qrCode.setECLevel(ecLevel); 22607 qrCode.setMode(mode); 22608 qrCode.setVersion(version); 22609 // Choose the mask pattern and set to "qrCode". 22610 const dimension = version.getDimensionForVersion(); 22611 const matrix = new ByteMatrix(dimension, dimension); 22612 const maskPattern = this.chooseMaskPattern(finalBits, ecLevel, version, matrix); 22613 qrCode.setMaskPattern(maskPattern); 22614 // Build the matrix and set it to "qrCode". 22615 MatrixUtil.buildMatrix(finalBits, ecLevel, version, maskPattern, matrix); 22616 qrCode.setMatrix(matrix); 22617 return qrCode; 22618 } 22619 /** 22620 * Decides the smallest version of QR code that will contain all of the provided data. 22621 * 22622 * @throws WriterException if the data cannot fit in any version 22623 */ 22624 static recommendVersion(ecLevel, mode, headerBits, dataBits) { 22625 // Hard part: need to know version to know how many bits length takes. But need to know how many 22626 // bits it takes to know version. First we take a guess at version by assuming version will be 22627 // the minimum, 1: 22628 const provisionalBitsNeeded = this.calculateBitsNeeded(mode, headerBits, dataBits, Version.getVersionForNumber(1)); 22629 const provisionalVersion = this.chooseVersion(provisionalBitsNeeded, ecLevel); 22630 // Use that guess to calculate the right version. I am still not sure this works in 100% of cases. 22631 const bitsNeeded = this.calculateBitsNeeded(mode, headerBits, dataBits, provisionalVersion); 22632 return this.chooseVersion(bitsNeeded, ecLevel); 22633 } 22634 static calculateBitsNeeded(mode, headerBits, dataBits, version) { 22635 return headerBits.getSize() + mode.getCharacterCountBits(version) + dataBits.getSize(); 22636 } 22637 /** 22638 * @return the code point of the table used in alphanumeric mode or 22639 * -1 if there is no corresponding code in the table. 22640 */ 22641 static getAlphanumericCode(code /*int*/) { 22642 if (code < Encoder$1.ALPHANUMERIC_TABLE.length) { 22643 return Encoder$1.ALPHANUMERIC_TABLE[code]; 22644 } 22645 return -1; 22646 } 22647 // public static chooseMode(content: string): Mode { 22648 // return chooseMode(content, null); 22649 // } 22650 /** 22651 * Choose the best mode by examining the content. Note that 'encoding' is used as a hint; 22652 * if it is Shift_JIS, and the input is only double-byte Kanji, then we return {@link Mode#KANJI}. 22653 */ 22654 static chooseMode(content, encoding = null) { 22655 if (CharacterSetECI.SJIS.getName() === encoding && this.isOnlyDoubleByteKanji(content)) { 22656 // Choose Kanji mode if all input are double-byte characters 22657 return Mode$2.KANJI; 22658 } 22659 let hasNumeric = false; 22660 let hasAlphanumeric = false; 22661 for (let i = 0, length = content.length; i < length; ++i) { 22662 const c = content.charAt(i); 22663 if (Encoder$1.isDigit(c)) { 22664 hasNumeric = true; 22665 } 22666 else if (this.getAlphanumericCode(c.charCodeAt(0)) !== -1) { 22667 hasAlphanumeric = true; 22668 } 22669 else { 22670 return Mode$2.BYTE; 22671 } 22672 } 22673 if (hasAlphanumeric) { 22674 return Mode$2.ALPHANUMERIC; 22675 } 22676 if (hasNumeric) { 22677 return Mode$2.NUMERIC; 22678 } 22679 return Mode$2.BYTE; 22680 } 22681 static isOnlyDoubleByteKanji(content) { 22682 let bytes; 22683 try { 22684 bytes = StringEncoding.encode(content, CharacterSetECI.SJIS); // content.getBytes("Shift_JIS")) 22685 } 22686 catch (ignored /*: UnsupportedEncodingException*/) { 22687 return false; 22688 } 22689 const length = bytes.length; 22690 if (length % 2 !== 0) { 22691 return false; 22692 } 22693 for (let i = 0; i < length; i += 2) { 22694 const byte1 = bytes[i] & 0xFF; 22695 if ((byte1 < 0x81 || byte1 > 0x9F) && (byte1 < 0xE0 || byte1 > 0xEB)) { 22696 return false; 22697 } 22698 } 22699 return true; 22700 } 22701 static chooseMaskPattern(bits, ecLevel, version, matrix) { 22702 let minPenalty = Number.MAX_SAFE_INTEGER; // Lower penalty is better. 22703 let bestMaskPattern = -1; 22704 // We try all mask patterns to choose the best one. 22705 for (let maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) { 22706 MatrixUtil.buildMatrix(bits, ecLevel, version, maskPattern, matrix); 22707 let penalty = this.calculateMaskPenalty(matrix); 22708 if (penalty < minPenalty) { 22709 minPenalty = penalty; 22710 bestMaskPattern = maskPattern; 22711 } 22712 } 22713 return bestMaskPattern; 22714 } 22715 static chooseVersion(numInputBits /*int*/, ecLevel) { 22716 for (let versionNum = 1; versionNum <= 40; versionNum++) { 22717 const version = Version.getVersionForNumber(versionNum); 22718 if (Encoder$1.willFit(numInputBits, version, ecLevel)) { 22719 return version; 22720 } 22721 } 22722 throw new WriterException('Data too big'); 22723 } 22724 /** 22725 * @return true if the number of input bits will fit in a code with the specified version and 22726 * error correction level. 22727 */ 22728 static willFit(numInputBits /*int*/, version, ecLevel) { 22729 // In the following comments, we use numbers of Version 7-H. 22730 // numBytes = 196 22731 const numBytes = version.getTotalCodewords(); 22732 // getNumECBytes = 130 22733 const ecBlocks = version.getECBlocksForLevel(ecLevel); 22734 const numEcBytes = ecBlocks.getTotalECCodewords(); 22735 // getNumDataBytes = 196 - 130 = 66 22736 const numDataBytes = numBytes - numEcBytes; 22737 const totalInputBytes = (numInputBits + 7) / 8; 22738 return numDataBytes >= totalInputBytes; 22739 } 22740 /** 22741 * Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24). 22742 */ 22743 static terminateBits(numDataBytes /*int*/, bits) { 22744 const capacity = numDataBytes * 8; 22745 if (bits.getSize() > capacity) { 22746 throw new WriterException('data bits cannot fit in the QR Code' + bits.getSize() + ' > ' + 22747 capacity); 22748 } 22749 for (let i = 0; i < 4 && bits.getSize() < capacity; ++i) { 22750 bits.appendBit(false); 22751 } 22752 // Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details. 22753 // If the last byte isn't 8-bit aligned, we'll add padding bits. 22754 const numBitsInLastByte = bits.getSize() & 0x07; 22755 if (numBitsInLastByte > 0) { 22756 for (let i = numBitsInLastByte; i < 8; i++) { 22757 bits.appendBit(false); 22758 } 22759 } 22760 // If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24). 22761 const numPaddingBytes = numDataBytes - bits.getSizeInBytes(); 22762 for (let i = 0; i < numPaddingBytes; ++i) { 22763 bits.appendBits((i & 0x01) === 0 ? 0xEC : 0x11, 8); 22764 } 22765 if (bits.getSize() !== capacity) { 22766 throw new WriterException('Bits size does not equal capacity'); 22767 } 22768 } 22769 /** 22770 * Get number of data bytes and number of error correction bytes for block id "blockID". Store 22771 * the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of 22772 * JISX0510:2004 (p.30) 22773 */ 22774 static getNumDataBytesAndNumECBytesForBlockID(numTotalBytes /*int*/, numDataBytes /*int*/, numRSBlocks /*int*/, blockID /*int*/, numDataBytesInBlock, numECBytesInBlock) { 22775 if (blockID >= numRSBlocks) { 22776 throw new WriterException('Block ID too large'); 22777 } 22778 // numRsBlocksInGroup2 = 196 % 5 = 1 22779 const numRsBlocksInGroup2 = numTotalBytes % numRSBlocks; 22780 // numRsBlocksInGroup1 = 5 - 1 = 4 22781 const numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2; 22782 // numTotalBytesInGroup1 = 196 / 5 = 39 22783 const numTotalBytesInGroup1 = Math.floor(numTotalBytes / numRSBlocks); 22784 // numTotalBytesInGroup2 = 39 + 1 = 40 22785 const numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1; 22786 // numDataBytesInGroup1 = 66 / 5 = 13 22787 const numDataBytesInGroup1 = Math.floor(numDataBytes / numRSBlocks); 22788 // numDataBytesInGroup2 = 13 + 1 = 14 22789 const numDataBytesInGroup2 = numDataBytesInGroup1 + 1; 22790 // numEcBytesInGroup1 = 39 - 13 = 26 22791 const numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1; 22792 // numEcBytesInGroup2 = 40 - 14 = 26 22793 const numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2; 22794 // Sanity checks. 22795 // 26 = 26 22796 if (numEcBytesInGroup1 !== numEcBytesInGroup2) { 22797 throw new WriterException('EC bytes mismatch'); 22798 } 22799 // 5 = 4 + 1. 22800 if (numRSBlocks !== numRsBlocksInGroup1 + numRsBlocksInGroup2) { 22801 throw new WriterException('RS blocks mismatch'); 22802 } 22803 // 196 = (13 + 26) * 4 + (14 + 26) * 1 22804 if (numTotalBytes !== 22805 ((numDataBytesInGroup1 + numEcBytesInGroup1) * 22806 numRsBlocksInGroup1) + 22807 ((numDataBytesInGroup2 + numEcBytesInGroup2) * 22808 numRsBlocksInGroup2)) { 22809 throw new WriterException('Total bytes mismatch'); 22810 } 22811 if (blockID < numRsBlocksInGroup1) { 22812 numDataBytesInBlock[0] = numDataBytesInGroup1; 22813 numECBytesInBlock[0] = numEcBytesInGroup1; 22814 } 22815 else { 22816 numDataBytesInBlock[0] = numDataBytesInGroup2; 22817 numECBytesInBlock[0] = numEcBytesInGroup2; 22818 } 22819 } 22820 /** 22821 * Interleave "bits" with corresponding error correction bytes. On success, store the result in 22822 * "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details. 22823 */ 22824 static interleaveWithECBytes(bits, numTotalBytes /*int*/, numDataBytes /*int*/, numRSBlocks /*int*/) { 22825 // "bits" must have "getNumDataBytes" bytes of data. 22826 if (bits.getSizeInBytes() !== numDataBytes) { 22827 throw new WriterException('Number of bits and data bytes does not match'); 22828 } 22829 // Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll 22830 // store the divided data bytes blocks and error correction bytes blocks into "blocks". 22831 let dataBytesOffset = 0; 22832 let maxNumDataBytes = 0; 22833 let maxNumEcBytes = 0; 22834 // Since, we know the number of reedsolmon blocks, we can initialize the vector with the number. 22835 const blocks = new Array(); // new Array<BlockPair>(numRSBlocks) 22836 for (let i = 0; i < numRSBlocks; ++i) { 22837 const numDataBytesInBlock = new Int32Array(1); 22838 const numEcBytesInBlock = new Int32Array(1); 22839 Encoder$1.getNumDataBytesAndNumECBytesForBlockID(numTotalBytes, numDataBytes, numRSBlocks, i, numDataBytesInBlock, numEcBytesInBlock); 22840 const size = numDataBytesInBlock[0]; 22841 const dataBytes = new Uint8Array(size); 22842 bits.toBytes(8 * dataBytesOffset, dataBytes, 0, size); 22843 const ecBytes = Encoder$1.generateECBytes(dataBytes, numEcBytesInBlock[0]); 22844 blocks.push(new BlockPair(dataBytes, ecBytes)); 22845 maxNumDataBytes = Math.max(maxNumDataBytes, size); 22846 maxNumEcBytes = Math.max(maxNumEcBytes, ecBytes.length); 22847 dataBytesOffset += numDataBytesInBlock[0]; 22848 } 22849 if (numDataBytes !== dataBytesOffset) { 22850 throw new WriterException('Data bytes does not match offset'); 22851 } 22852 const result = new BitArray(); 22853 // First, place data blocks. 22854 for (let i = 0; i < maxNumDataBytes; ++i) { 22855 for (const block of blocks) { 22856 const dataBytes = block.getDataBytes(); 22857 if (i < dataBytes.length) { 22858 result.appendBits(dataBytes[i], 8); 22859 } 22860 } 22861 } 22862 // Then, place error correction blocks. 22863 for (let i = 0; i < maxNumEcBytes; ++i) { 22864 for (const block of blocks) { 22865 const ecBytes = block.getErrorCorrectionBytes(); 22866 if (i < ecBytes.length) { 22867 result.appendBits(ecBytes[i], 8); 22868 } 22869 } 22870 } 22871 if (numTotalBytes !== result.getSizeInBytes()) { // Should be same. 22872 throw new WriterException('Interleaving error: ' + numTotalBytes + ' and ' + 22873 result.getSizeInBytes() + ' differ.'); 22874 } 22875 return result; 22876 } 22877 static generateECBytes(dataBytes, numEcBytesInBlock /*int*/) { 22878 const numDataBytes = dataBytes.length; 22879 const toEncode = new Int32Array(numDataBytes + numEcBytesInBlock); // int[numDataBytes + numEcBytesInBlock] 22880 for (let i = 0; i < numDataBytes; i++) { 22881 toEncode[i] = dataBytes[i] & 0xFF; 22882 } 22883 new ReedSolomonEncoder(GenericGF.QR_CODE_FIELD_256).encode(toEncode, numEcBytesInBlock); 22884 const ecBytes = new Uint8Array(numEcBytesInBlock); 22885 for (let i = 0; i < numEcBytesInBlock; i++) { 22886 ecBytes[i] = /*(byte) */ toEncode[numDataBytes + i]; 22887 } 22888 return ecBytes; 22889 } 22890 /** 22891 * Append mode info. On success, store the result in "bits". 22892 */ 22893 static appendModeInfo(mode, bits) { 22894 bits.appendBits(mode.getBits(), 4); 22895 } 22896 /** 22897 * Append length info. On success, store the result in "bits". 22898 */ 22899 static appendLengthInfo(numLetters /*int*/, version, mode, bits) { 22900 const numBits = mode.getCharacterCountBits(version); 22901 if (numLetters >= (1 << numBits)) { 22902 throw new WriterException(numLetters + ' is bigger than ' + ((1 << numBits) - 1)); 22903 } 22904 bits.appendBits(numLetters, numBits); 22905 } 22906 /** 22907 * Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits". 22908 */ 22909 static appendBytes(content, mode, bits, encoding) { 22910 switch (mode) { 22911 case Mode$2.NUMERIC: 22912 Encoder$1.appendNumericBytes(content, bits); 22913 break; 22914 case Mode$2.ALPHANUMERIC: 22915 Encoder$1.appendAlphanumericBytes(content, bits); 22916 break; 22917 case Mode$2.BYTE: 22918 Encoder$1.append8BitBytes(content, bits, encoding); 22919 break; 22920 case Mode$2.KANJI: 22921 Encoder$1.appendKanjiBytes(content, bits); 22922 break; 22923 default: 22924 throw new WriterException('Invalid mode: ' + mode); 22925 } 22926 } 22927 static getDigit(singleCharacter) { 22928 return singleCharacter.charCodeAt(0) - 48; 22929 } 22930 static isDigit(singleCharacter) { 22931 const cn = Encoder$1.getDigit(singleCharacter); 22932 return cn >= 0 && cn <= 9; 22933 } 22934 static appendNumericBytes(content, bits) { 22935 const length = content.length; 22936 let i = 0; 22937 while (i < length) { 22938 const num1 = Encoder$1.getDigit(content.charAt(i)); 22939 if (i + 2 < length) { 22940 // Encode three numeric letters in ten bits. 22941 const num2 = Encoder$1.getDigit(content.charAt(i + 1)); 22942 const num3 = Encoder$1.getDigit(content.charAt(i + 2)); 22943 bits.appendBits(num1 * 100 + num2 * 10 + num3, 10); 22944 i += 3; 22945 } 22946 else if (i + 1 < length) { 22947 // Encode two numeric letters in seven bits. 22948 const num2 = Encoder$1.getDigit(content.charAt(i + 1)); 22949 bits.appendBits(num1 * 10 + num2, 7); 22950 i += 2; 22951 } 22952 else { 22953 // Encode one numeric letter in four bits. 22954 bits.appendBits(num1, 4); 22955 i++; 22956 } 22957 } 22958 } 22959 static appendAlphanumericBytes(content, bits) { 22960 const length = content.length; 22961 let i = 0; 22962 while (i < length) { 22963 const code1 = Encoder$1.getAlphanumericCode(content.charCodeAt(i)); 22964 if (code1 === -1) { 22965 throw new WriterException(); 22966 } 22967 if (i + 1 < length) { 22968 const code2 = Encoder$1.getAlphanumericCode(content.charCodeAt(i + 1)); 22969 if (code2 === -1) { 22970 throw new WriterException(); 22971 } 22972 // Encode two alphanumeric letters in 11 bits. 22973 bits.appendBits(code1 * 45 + code2, 11); 22974 i += 2; 22975 } 22976 else { 22977 // Encode one alphanumeric letter in six bits. 22978 bits.appendBits(code1, 6); 22979 i++; 22980 } 22981 } 22982 } 22983 static append8BitBytes(content, bits, encoding) { 22984 let bytes; 22985 try { 22986 bytes = StringEncoding.encode(content, encoding); 22987 } 22988 catch (uee /*: UnsupportedEncodingException*/) { 22989 throw new WriterException(uee); 22990 } 22991 for (let i = 0, length = bytes.length; i !== length; i++) { 22992 const b = bytes[i]; 22993 bits.appendBits(b, 8); 22994 } 22995 } 22996 /** 22997 * @throws WriterException 22998 */ 22999 static appendKanjiBytes(content, bits) { 23000 let bytes; 23001 try { 23002 bytes = StringEncoding.encode(content, CharacterSetECI.SJIS); 23003 } 23004 catch (uee /*: UnsupportedEncodingException*/) { 23005 throw new WriterException(uee); 23006 } 23007 const length = bytes.length; 23008 for (let i = 0; i < length; i += 2) { 23009 const byte1 = bytes[i] & 0xFF; 23010 const byte2 = bytes[i + 1] & 0xFF; 23011 const code = ((byte1 << 8) & 0xFFFFFFFF) | byte2; 23012 let subtracted = -1; 23013 if (code >= 0x8140 && code <= 0x9ffc) { 23014 subtracted = code - 0x8140; 23015 } 23016 else if (code >= 0xe040 && code <= 0xebbf) { 23017 subtracted = code - 0xc140; 23018 } 23019 if (subtracted === -1) { 23020 throw new WriterException('Invalid byte sequence'); 23021 } 23022 const encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff); 23023 bits.appendBits(encoded, 13); 23024 } 23025 } 23026 static appendECI(eci, bits) { 23027 bits.appendBits(Mode$2.ECI.getBits(), 4); 23028 // This is correct for values up to 127, which is all we need now. 23029 bits.appendBits(eci.getValue(), 8); 23030 } 23031 } 23032 // The original table is defined in the table 5 of JISX0510:2004 (p.19). 23033 Encoder$1.ALPHANUMERIC_TABLE = Int32Array.from([ 23034 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23035 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23036 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, 23037 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, 23038 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 23039 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
vendor: 6,038 bytes, lines 23039-23174
23039 23040 ]); 23041 Encoder$1.DEFAULT_BYTE_MODE_ENCODING = CharacterSetECI.UTF8.getName(); // "ISO-8859-1" 23042 23043 /** 23044 * @deprecated Moving to @zxing/browser 23045 */ 23046 class BrowserQRCodeSvgWriter { 23047 /** 23048 * Writes and renders a QRCode SVG element. 23049 * 23050 * @param contents 23051 * @param width 23052 * @param height 23053 * @param hints 23054 */ 23055 write(contents, width, height, hints = null) { 23056 if (contents.length === 0) { 23057 throw new IllegalArgumentException('Found empty contents'); 23058 } 23059 // if (format != BarcodeFormat.QR_CODE) { 23060 // throw new IllegalArgumentException("Can only encode QR_CODE, but got " + format) 23061 // } 23062 if (width < 0 || height < 0) { 23063 throw new IllegalArgumentException('Requested dimensions are too small: ' + width + 'x' + height); 23064 } 23065 let errorCorrectionLevel = ErrorCorrectionLevel.L; 23066 let quietZone = BrowserQRCodeSvgWriter.QUIET_ZONE_SIZE; 23067 if (hints !== null) { 23068 if (undefined !== hints.get(EncodeHintType$1.ERROR_CORRECTION)) { 23069 errorCorrectionLevel = ErrorCorrectionLevel.fromString(hints.get(EncodeHintType$1.ERROR_CORRECTION).toString()); 23070 } 23071 if (undefined !== hints.get(EncodeHintType$1.MARGIN)) { 23072 quietZone = Number.parseInt(hints.get(EncodeHintType$1.MARGIN).toString(), 10); 23073 } 23074 } 23075 const code = Encoder$1.encode(contents, errorCorrectionLevel, hints); 23076 return this.renderResult(code, width, height, quietZone); 23077 } 23078 /** 23079 * Renders the result and then appends it to the DOM. 23080 */ 23081 writeToDom(containerElement, contents, width, height, hints = null) { 23082 if (typeof containerElement === 'string') { 23083 containerElement = document.querySelector(containerElement); 23084 } 23085 const svgElement = this.write(contents, width, height, hints); 23086 if (containerElement) 23087 containerElement.appendChild(svgElement); 23088 } 23089 /** 23090 * Note that the input matrix uses 0 == white, 1 == black. 23091 * The output matrix uses 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap). 23092 */ 23093 renderResult(code, width /*int*/, height /*int*/, quietZone /*int*/) { 23094 const input = code.getMatrix(); 23095 if (input === null) { 23096 throw new IllegalStateException(); 23097 } 23098 const inputWidth = input.getWidth(); 23099 const inputHeight = input.getHeight(); 23100 const qrWidth = inputWidth + (quietZone * 2); 23101 const qrHeight = inputHeight + (quietZone * 2); 23102 const outputWidth = Math.max(width, qrWidth); 23103 const outputHeight = Math.max(height, qrHeight); 23104 const multiple = Math.min(Math.floor(outputWidth / qrWidth), Math.floor(outputHeight / qrHeight)); 23105 // Padding includes both the quiet zone and the extra white pixels to accommodate the requested 23106 // dimensions. For example, if input is 25x25 the QR will be 33x33 including the quiet zone. 23107 // If the requested size is 200x160, the multiple will be 4, for a QR of 132x132. These will 23108 // handle all the padding from 100x100 (the actual QR) up to 200x160. 23109 const leftPadding = Math.floor((outputWidth - (inputWidth * multiple)) / 2); 23110 const topPadding = Math.floor((outputHeight - (inputHeight * multiple)) / 2); 23111 const svgElement = this.createSVGElement(outputWidth, outputHeight); 23112 for (let inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) { 23113 // Write the contents of this row of the barcode 23114 for (let inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) { 23115 if (input.get(inputX, inputY) === 1) { 23116 const svgRectElement = this.createSvgRectElement(outputX, outputY, multiple, multiple); 23117 svgElement.appendChild(svgRectElement); 23118 } 23119 } 23120 } 23121 return svgElement; 23122 } 23123 /** 23124 * Creates a SVG element. 23125 * 23126 * @param w SVG's width attribute 23127 * @param h SVG's height attribute 23128 */ 23129 createSVGElement(w, h) { 23130 const svgElement = document.createElementNS(BrowserQRCodeSvgWriter.SVG_NS, 'svg'); 23131 svgElement.setAttributeNS(null, 'height', w.toString()); 23132 svgElement.setAttributeNS(null, 'width', h.toString()); 23133 return svgElement; 23134 } 23135 /** 23136 * Creates a SVG rect element. 23137 * 23138 * @param x Element's x coordinate 23139 * @param y Element's y coordinate 23140 * @param w Element's width attribute 23141 * @param h Element's height attribute 23142 */ 23143 createSvgRectElement(x, y, w, h) { 23144 const rect = document.createElementNS(BrowserQRCodeSvgWriter.SVG_NS, 'rect'); 23145 rect.setAttributeNS(null, 'x', x.toString()); 23146 rect.setAttributeNS(null, 'y', y.toString()); 23147 rect.setAttributeNS(null, 'height', w.toString()); 23148 rect.setAttributeNS(null, 'width', h.toString()); 23149 rect.setAttributeNS(null, 'fill', '#000000'); 23150 return rect; 23151 } 23152 } 23153 BrowserQRCodeSvgWriter.QUIET_ZONE_SIZE = 4; 23154 /** 23155 * SVG markup NameSpace 23156 */ 23157 BrowserQRCodeSvgWriter.SVG_NS = 'http://www.w3.org/2000/svg'; 23158 23159 /* 23160 * Copyright 2008 ZXing authors 23161 * 23162 * Licensed under the Apache License, Version 2.0 (the "License"); 23163 * you may not use this file except in compliance with the License. 23164 * You may obtain a copy of the License at 23165 * 23166 * http://www.apache.org/licenses/LICENSE-2.0 23167 * 23168 * Unless required by applicable law or agreed to in writing, software 23169 * distributed under the License is distributed on an "AS IS" BASIS, 23170 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 23171 * See the License for the specific language governing permissions and 23172 * limitations under the License. 23173 */ 23174 /*
vendor: 3,829 bytes, lines 23174-23247
23174import java.util.Map;*/ 23175 /** 23176 * This object renders a QR Code as a BitMatrix 2D array of greyscale values. 23177 * 23178 * @author [email protected] (Daniel Switkin) 23179 */ 23180 class QRCodeWriter { 23181 /*@Override*/ 23182 // public encode(contents: string, format: BarcodeFormat, width: number /*int*/, height: number /*int*/): BitMatrix 23183 // /*throws WriterException */ { 23184 // return encode(contents, format, width, height, null) 23185 // } 23186 /*@Override*/ 23187 encode(contents, format, width /*int*/, height /*int*/, hints) { 23188 if (contents.length === 0) { 23189 throw new IllegalArgumentException('Found empty contents'); 23190 } 23191 if (format !== BarcodeFormat$1.QR_CODE) { 23192 throw new IllegalArgumentException('Can only encode QR_CODE, but got ' + format); 23193 } 23194 if (width < 0 || height < 0) { 23195 throw new IllegalArgumentException(`Requested dimensions are too small: ${width}x${height}`); 23196 } 23197 let errorCorrectionLevel = ErrorCorrectionLevel.L; 23198 let quietZone = QRCodeWriter.QUIET_ZONE_SIZE; 23199 if (hints !== null) { 23200 if (undefined !== hints.get(EncodeHintType$1.ERROR_CORRECTION)) { 23201 errorCorrectionLevel = ErrorCorrectionLevel.fromString(hints.get(EncodeHintType$1.ERROR_CORRECTION).toString()); 23202 } 23203 if (undefined !== hints.get(EncodeHintType$1.MARGIN)) { 23204 quietZone = Number.parseInt(hints.get(EncodeHintType$1.MARGIN).toString(), 10); 23205 } 23206 } 23207 const code = Encoder$1.encode(contents, errorCorrectionLevel, hints); 23208 return QRCodeWriter.renderResult(code, width, height, quietZone); 23209 } 23210 // Note that the input matrix uses 0 == white, 1 == black, while the output matrix uses 23211 // 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap). 23212 static renderResult(code, width /*int*/, height /*int*/, quietZone /*int*/) { 23213 const input = code.getMatrix(); 23214 if (input === null) { 23215 throw new IllegalStateException(); 23216 } 23217 const inputWidth = input.getWidth(); 23218 const inputHeight = input.getHeight(); 23219 const qrWidth = inputWidth + (quietZone * 2); 23220 const qrHeight = inputHeight + (quietZone * 2); 23221 const outputWidth = Math.max(width, qrWidth); 23222 const outputHeight = Math.max(height, qrHeight); 23223 const multiple = Math.min(Math.floor(outputWidth / qrWidth), Math.floor(outputHeight / qrHeight)); 23224 // Padding includes both the quiet zone and the extra white pixels to accommodate the requested 23225 // dimensions. For example, if input is 25x25 the QR will be 33x33 including the quiet zone. 23226 // If the requested size is 200x160, the multiple will be 4, for a QR of 132x132. These will 23227 // handle all the padding from 100x100 (the actual QR) up to 200x160. 23228 const leftPadding = Math.floor((outputWidth - (inputWidth * multiple)) / 2); 23229 const topPadding = Math.floor((outputHeight - (inputHeight * multiple)) / 2); 23230 const output = new BitMatrix(outputWidth, outputHeight); 23231 for (let inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) { 23232 // Write the contents of this row of the barcode 23233 for (let inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) { 23234 if (input.get(inputX, inputY) === 1) { 23235 output.setRegion(outputX, outputY, multiple, multiple); 23236 } 23237 } 23238 } 23239 return output; 23240 } 23241 } 23242 QRCodeWriter.QUIET_ZONE_SIZE = 4; 23243 23244 /* 23245 * Copyright 2008 ZXing authors 23246 * 23247 * Licensed under the Apache License, Version 2.0 (the "License");
23248 * you may not use this file except in compliance with the License. 23249 * You may obtain a copy of the License at 23250 * 23251 * http://www.apache.org/licenses/LICENSE-2.0 23252 * 23253 * Unless required by applicable law or agreed to in writing, software 23254 * distributed under the License is distributed on an "AS IS" BASIS, 23255 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 23256 * See the License for the specific language governing permissions and 23257 * limitations under the License. 23258 */ 23259 /*import java.util.Map;*/ 23260 /** 23261 * This is a factory class which finds the appropriate Writer subclass for the BarcodeFormat 23262 * requested and encodes the barcode with the supplied contents. 23263 * 23264 * @author [email protected] (Daniel Switkin) 23265 */ 23266 class MultiFormatWriter { 23267 /*@Override*/ 23268 // public encode(contents: string, 23269 // format: BarcodeFormat, 23270 // width: number /*int*/, 23271 // height: number /*int*/): BitMatrix /*throws WriterException */ { 23272 // return encode(contents, format, width, height, null) 23273 // } 23274 /*@Override*/ 23275 encode(contents, format, width /*int*/, height /*int*/, hints) { 23276 let writer; 23277 switch (format) { 23278 // case BarcodeFormat.EAN_8: 23279 // writer = new EAN8Writer() 23280 // break 23281 // case BarcodeFormat.UPC_E: 23282 // writer = new UPCEWriter() 23283 // break 23284 // case BarcodeFormat.EAN_13: 23285 // writer = new EAN13Writer() 23286 // break 23287 // case BarcodeFormat.UPC_A: 23288 // writer = new UPCAWriter() 23289 // break 23290 case BarcodeFormat$1.QR_CODE: 23291 writer = new QRCodeWriter(); 23292 break; 23293 // case BarcodeFormat.CODE_39: 23294 // writer = new Code39Writer() 23295 // break 23296 // case BarcodeFormat.CODE_93: 23297 // writer = new Code93Writer() 23298 // break 23299 // case BarcodeFormat.CODE_128: 23300 // writer = new Code128Writer() 23301 // break 23302 // case BarcodeFormat.ITF: 23303 // writer = new ITFWriter() 23304 // break 23305 // case BarcodeFormat.PDF_417: 23306 // writer = new PDF417Writer() 23307 // break 23308 // case BarcodeFormat.CODABAR: 23309 // writer = new CodaBarWriter() 23310 // break 23311 // case BarcodeFormat.DATA_MATRIX: 23312 // writer = new DataMatrixWriter() 23313 // break 23314 // case BarcodeFormat.AZTEC: 23315 // writer = new AztecWriter() 23316 // break 23317 default: 23318 throw new IllegalArgumentException('No encoder available for format ' + format); 23319 } 23320 return writer.encode(contents, format, width, height, hints); 23321 } 23322 } 23323 23324 /* 23325 * Copyright 2009 ZXing authors 23326 * 23327 * Licensed under the Apache License, Version 2.0 (the "License"); 23328 * you may not use this file except in compliance with the License. 23329 * You may obtain a copy of the License at 23330 * 23331 * http://www.apache.org/licenses/LICENSE-2.0 23332 * 23333 * Unless required by applicable law or agreed to in writing, software 23334 * distributed under the License is distributed on an "AS IS" BASIS, 23335 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 23336 * See the License for the specific language governing permissions and 23337 * limitations under the License. 23338 */ 23339 /** 23340 * This object extends LuminanceSource around an array of YUV data returned from the camera driver, 23341 * with the option to crop to a rectangle within the full data. This can be used to exclude 23342 * superfluous pixels around the perimeter and speed up decoding. 23343 * 23344 * It works for any pixel format where the Y channel is planar and appears first, including 23345 * YCbCr_420_SP and YCbCr_422_SP. 23346 * 23347 * @author [email protected] (Daniel Switkin) 23348 */ 23349 class PlanarYUVLuminanceSource extends LuminanceSource { 23350 constructor(yuvData, dataWidth /*int*/, dataHeight /*int*/, left /*int*/, top /*int*/, width /*int*/, height /*int*/, reverseHorizontal) { 23351 super(width, height); 23352 this.yuvData = yuvData; 23353 this.dataWidth = dataWidth; 23354 this.dataHeight = dataHeight; 23355 this.left = left; 23356 this.top = top; 23357 if (left + width > dataWidth || top + height > dataHeight) { 23358 throw new IllegalArgumentException('Crop rectangle does not fit within image data.'); 23359 } 23360 if (reverseHorizontal) { 23361 this.reverseHorizontal(width, height); 23362 } 23363 } 23364 /*@Override*/ 23365 getRow(y /*int*/, row) { 23366 if (y < 0 || y >= this.getHeight()) { 23367 throw new IllegalArgumentException('Requested row is outside the image: ' + y); 23368 } 23369 const width = this.getWidth();
vendor: 4,349 bytes, lines 23370-23469
23370 if (row === null || row === undefined || row.length < width) { 23371 row = new Uint8ClampedArray(width); 23372 } 23373 const offset = (y + this.top) * this.dataWidth + this.left; 23374 System.arraycopy(this.yuvData, offset, row, 0, width); 23375 return row; 23376 } 23377 /*@Override*/ 23378 getMatrix() { 23379 const width = this.getWidth(); 23380 const height = this.getHeight(); 23381 // If the caller asks for the entire underlying image, save the copy and give them the 23382 // original data. The docs specifically warn that result.length must be ignored. 23383 if (width === this.dataWidth && height === this.dataHeight) { 23384 return this.yuvData; 23385 } 23386 const area = width * height; 23387 const matrix = new Uint8ClampedArray(area); 23388 let inputOffset = this.top * this.dataWidth + this.left; 23389 // If the width matches the full width of the underlying data, perform a single copy. 23390 if (width === this.dataWidth) { 23391 System.arraycopy(this.yuvData, inputOffset, matrix, 0, area); 23392 return matrix; 23393 } 23394 // Otherwise copy one cropped row at a time. 23395 for (let y = 0; y < height; y++) { 23396 const outputOffset = y * width; 23397 System.arraycopy(this.yuvData, inputOffset, matrix, outputOffset, width); 23398 inputOffset += this.dataWidth; 23399 } 23400 return matrix; 23401 } 23402 /*@Override*/ 23403 isCropSupported() { 23404 return true; 23405 } 23406 /*@Override*/ 23407 crop(left /*int*/, top /*int*/, width /*int*/, height /*int*/) { 23408 return new PlanarYUVLuminanceSource(this.yuvData, this.dataWidth, this.dataHeight, this.left + left, this.top + top, width, height, false); 23409 } 23410 renderThumbnail() { 23411 const width = this.getWidth() / PlanarYUVLuminanceSource.THUMBNAIL_SCALE_FACTOR; 23412 const height = this.getHeight() / PlanarYUVLuminanceSource.THUMBNAIL_SCALE_FACTOR; 23413 const pixels = new Int32Array(width * height); 23414 const yuv = this.yuvData; 23415 let inputOffset = this.top * this.dataWidth + this.left; 23416 for (let y = 0; y < height; y++) { 23417 const outputOffset = y * width; 23418 for (let x = 0; x < width; x++) { 23419 const grey = yuv[inputOffset + x * PlanarYUVLuminanceSource.THUMBNAIL_SCALE_FACTOR] & 0xff; 23420 pixels[outputOffset + x] = 0xFF000000 | (grey * 0x00010101); 23421 } 23422 inputOffset += this.dataWidth * PlanarYUVLuminanceSource.THUMBNAIL_SCALE_FACTOR; 23423 } 23424 return pixels; 23425 } 23426 /** 23427 * @return width of image from {@link #renderThumbnail()} 23428 */ 23429 getThumbnailWidth() { 23430 return this.getWidth() / PlanarYUVLuminanceSource.THUMBNAIL_SCALE_FACTOR; 23431 } 23432 /** 23433 * @return height of image from {@link #renderThumbnail()} 23434 */ 23435 getThumbnailHeight() { 23436 return this.getHeight() / PlanarYUVLuminanceSource.THUMBNAIL_SCALE_FACTOR; 23437 } 23438 reverseHorizontal(width /*int*/, height /*int*/) { 23439 const yuvData = this.yuvData; 23440 for (let y = 0, rowStart = this.top * this.dataWidth + this.left; y < height; y++, rowStart += this.dataWidth) { 23441 const middle = rowStart + width / 2; 23442 for (let x1 = rowStart, x2 = rowStart + width - 1; x1 < middle; x1++, x2--) { 23443 const temp = yuvData[x1]; 23444 yuvData[x1] = yuvData[x2]; 23445 yuvData[x2] = temp; 23446 } 23447 } 23448 } 23449 invert() { 23450 return new InvertedLuminanceSource(this); 23451 } 23452 } 23453 PlanarYUVLuminanceSource.THUMBNAIL_SCALE_FACTOR = 2; 23454 23455 /* 23456 * Copyright 2009 ZXing authors 23457 * 23458 * Licensed under the Apache License, Version 2.0 (the "License"); 23459 * you may not use this file except in compliance with the License. 23460 * You may obtain a copy of the License at 23461 * 23462 * http://www.apache.org/licenses/LICENSE-2.0 23463 * 23464 * Unless required by applicable law or agreed to in writing, software 23465 * distributed under the License is distributed on an "AS IS" BASIS, 23466 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 23467 * See the License for the specific language governing permissions and 23468 * limitations under the License. 23469
vendor: 37,160 bytes, lines 23469-24435
23469*/ 23470 /** 23471 * This class is used to help decode images from files which arrive as RGB data from 23472 * an ARGB pixel array. It does not support rotation. 23473 * 23474 * @author [email protected] (Daniel Switkin) 23475 * @author Betaminos 23476 */ 23477 class RGBLuminanceSource extends LuminanceSource { 23478 constructor(luminances, width /*int*/, height /*int*/, dataWidth /*int*/, dataHeight /*int*/, left /*int*/, top /*int*/) { 23479 super(width, height); 23480 this.dataWidth = dataWidth; 23481 this.dataHeight = dataHeight; 23482 this.left = left; 23483 this.top = top; 23484 if (luminances.BYTES_PER_ELEMENT === 4) { // Int32Array 23485 const size = width * height; 23486 const luminancesUint8Array = new Uint8ClampedArray(size); 23487 for (let offset = 0; offset < size; offset++) { 23488 const pixel = luminances[offset]; 23489 const r = (pixel >> 16) & 0xff; // red 23490 const g2 = (pixel >> 7) & 0x1fe; // 2 * green 23491 const b = pixel & 0xff; // blue 23492 // Calculate green-favouring average cheaply 23493 luminancesUint8Array[offset] = /*(byte) */ ((r + g2 + b) / 4) & 0xFF; 23494 } 23495 this.luminances = luminancesUint8Array; 23496 } 23497 else { 23498 this.luminances = luminances; 23499 } 23500 if (undefined === dataWidth) { 23501 this.dataWidth = width; 23502 } 23503 if (undefined === dataHeight) { 23504 this.dataHeight = height; 23505 } 23506 if (undefined === left) { 23507 this.left = 0; 23508 } 23509 if (undefined === top) { 23510 this.top = 0; 23511 } 23512 if (this.left + width > this.dataWidth || this.top + height > this.dataHeight) { 23513 throw new IllegalArgumentException('Crop rectangle does not fit within image data.'); 23514 } 23515 } 23516 /*@Override*/ 23517 getRow(y /*int*/, row) { 23518 if (y < 0 || y >= this.getHeight()) { 23519 throw new IllegalArgumentException('Requested row is outside the image: ' + y); 23520 } 23521 const width = this.getWidth(); 23522 if (row === null || row === undefined || row.length < width) { 23523 row = new Uint8ClampedArray(width); 23524 } 23525 const offset = (y + this.top) * this.dataWidth + this.left; 23526 System.arraycopy(this.luminances, offset, row, 0, width); 23527 return row; 23528 } 23529 /*@Override*/ 23530 getMatrix() { 23531 const width = this.getWidth(); 23532 const height = this.getHeight(); 23533 // If the caller asks for the entire underlying image, save the copy and give them the 23534 // original data. The docs specifically warn that result.length must be ignored. 23535 if (width === this.dataWidth && height === this.dataHeight) { 23536 return this.luminances; 23537 } 23538 const area = width * height; 23539 const matrix = new Uint8ClampedArray(area); 23540 let inputOffset = this.top * this.dataWidth + this.left; 23541 // If the width matches the full width of the underlying data, perform a single copy. 23542 if (width === this.dataWidth) { 23543 System.arraycopy(this.luminances, inputOffset, matrix, 0, area); 23544 return matrix; 23545 } 23546 // Otherwise copy one cropped row at a time. 23547 for (let y = 0; y < height; y++) { 23548 const outputOffset = y * width; 23549 System.arraycopy(this.luminances, inputOffset, matrix, outputOffset, width); 23550 inputOffset += this.dataWidth; 23551 } 23552 return matrix; 23553 } 23554 /*@Override*/ 23555 isCropSupported() { 23556 return true; 23557 } 23558 /*@Override*/ 23559 crop(left /*int*/, top /*int*/, width /*int*/, height /*int*/) { 23560 return new RGBLuminanceSource(this.luminances, width, height, this.dataWidth, this.dataHeight, this.left + left, this.top + top); 23561 } 23562 invert() { 23563 return new InvertedLuminanceSource(this); 23564 } 23565 } 23566 23567 /** 23568 * Just to make a shortcut between Java code and TS code. 23569 */ 23570 class Charset extends CharacterSetECI { 23571 static forName(name) { 23572 return this.getCharacterSetECIByName(name); 23573 } 23574 } 23575 23576 /** 23577 * Just to make a shortcut between Java code and TS code. 23578 */ 23579 class StandardCharsets { 23580 } 23581 StandardCharsets.ISO_8859_1 = CharacterSetECI.ISO8859_1; 23582 23583 /** 23584 * Symbol Character Placement Program. Adapted from Annex M.1 in ISO/IEC 16022:2000(E). 23585 */ 23586 class DefaultPlacement { 23587 /** 23588 * Main constructor 23589 * 23590 * @param codewords the codewords to place 23591 * @param numcols the number of columns 23592 * @param numrows the number of rows 23593 */ 23594 constructor(codewords, numcols, numrows) { 23595 this.codewords = codewords; 23596 this.numcols = numcols; 23597 this.numrows = numrows; 23598 this.bits = new Uint8Array(numcols * numrows); 23599 Arrays.fill(this.bits, 2); // Initialize with "not set" value 23600 } 23601 getNumrows() { 23602 return this.numrows; 23603 } 23604 getNumcols() { 23605 return this.numcols; 23606 } 23607 getBits() { 23608 return this.bits; 23609 } 23610 getBit(col, row) { 23611 return this.bits[row * this.numcols + col] === 1; 23612 } 23613 setBit(col, row, bit) { 23614 this.bits[row * this.numcols + col] = bit ? 1 : 0; 23615 } 23616 noBit(col, row) { 23617 return this.bits[row * this.numcols + col] === 2; 23618 } 23619 place() { 23620 let pos = 0; 23621 let row = 4; 23622 let col = 0; 23623 do { 23624 // repeatedly first check for one of the special corner cases, then... 23625 if (row === this.numrows && col === 0) { 23626 this.corner1(pos++); 23627 } 23628 if (row === this.numrows - 2 && col === 0 && this.numcols % 4 !== 0) { 23629 this.corner2(pos++); 23630 } 23631 if (row === this.numrows - 2 && col === 0 && this.numcols % 8 === 4) { 23632 this.corner3(pos++); 23633 } 23634 if (row === this.numrows + 4 && col === 2 && this.numcols % 8 === 0) { 23635 this.corner4(pos++); 23636 } 23637 // sweep upward diagonally, inserting successive characters... 23638 do { 23639 if (row < this.numrows && col >= 0 && this.noBit(col, row)) { 23640 this.utah(row, col, pos++); 23641 } 23642 row -= 2; 23643 col += 2; 23644 } while (row >= 0 && col < this.numcols); 23645 row++; 23646 col += 3; 23647 // and then sweep downward diagonally, inserting successive characters, ... 23648 do { 23649 if (row >= 0 && col < this.numcols && this.noBit(col, row)) { 23650 this.utah(row, col, pos++); 23651 } 23652 row += 2; 23653 col -= 2; 23654 } while (row < this.numrows && col >= 0); 23655 row += 3; 23656 col++; 23657 // ...until the entire array is scanned 23658 } while (row < this.numrows || col < this.numcols); 23659 // Lastly, if the lower right-hand corner is untouched, fill in fixed pattern 23660 if (this.noBit(this.numcols - 1, this.numrows - 1)) { 23661 this.setBit(this.numcols - 1, this.numrows - 1, true); 23662 this.setBit(this.numcols - 2, this.numrows - 2, true); 23663 } 23664 } 23665 module(row, col, pos, bit) { 23666 if (row < 0) { 23667 row += this.numrows; 23668 col += 4 - ((this.numrows + 4) % 8); 23669 } 23670 if (col < 0) { 23671 col += this.numcols; 23672 row += 4 - ((this.numcols + 4) % 8); 23673 } 23674 // Note the conversion: 23675 let v = this.codewords.charCodeAt(pos); 23676 v &= 1 << (8 - bit); 23677 this.setBit(col, row, v !== 0); 23678 } 23679 /** 23680 * Places the 8 bits of a utah-shaped symbol character in ECC200. 23681 * 23682 * @param row the row 23683 * @param col the column 23684 * @param pos character position 23685 */ 23686 utah(row, col, pos) { 23687 this.module(row - 2, col - 2, pos, 1); 23688 this.module(row - 2, col - 1, pos, 2); 23689 this.module(row - 1, col - 2, pos, 3); 23690 this.module(row - 1, col - 1, pos, 4); 23691 this.module(row - 1, col, pos, 5); 23692 this.module(row, col - 2, pos, 6); 23693 this.module(row, col - 1, pos, 7); 23694 this.module(row, col, pos, 8); 23695 } 23696 corner1(pos) { 23697 this.module(this.numrows - 1, 0, pos, 1); 23698 this.module(this.numrows - 1, 1, pos, 2); 23699 this.module(this.numrows - 1, 2, pos, 3); 23700 this.module(0, this.numcols - 2, pos, 4); 23701 this.module(0, this.numcols - 1, pos, 5); 23702 this.module(1, this.numcols - 1, pos, 6); 23703 this.module(2, this.numcols - 1, pos, 7); 23704 this.module(3, this.numcols - 1, pos, 8); 23705 } 23706 corner2(pos) { 23707 this.module(this.numrows - 3, 0, pos, 1); 23708 this.module(this.numrows - 2, 0, pos, 2); 23709 this.module(this.numrows - 1, 0, pos, 3); 23710 this.module(0, this.numcols - 4, pos, 4); 23711 this.module(0, this.numcols - 3, pos, 5); 23712 this.module(0, this.numcols - 2, pos, 6); 23713 this.module(0, this.numcols - 1, pos, 7); 23714 this.module(1, this.numcols - 1, pos, 8); 23715 } 23716 corner3(pos) { 23717 this.module(this.numrows - 3, 0, pos, 1); 23718 this.module(this.numrows - 2, 0, pos, 2); 23719 this.module(this.numrows - 1, 0, pos, 3); 23720 this.module(0, this.numcols - 2, pos, 4); 23721 this.module(0, this.numcols - 1, pos, 5); 23722 this.module(1, this.numcols - 1, pos, 6); 23723 this.module(2, this.numcols - 1, pos, 7); 23724 this.module(3, this.numcols - 1, pos, 8); 23725 } 23726 corner4(pos) { 23727 this.module(this.numrows - 1, 0, pos, 1); 23728 this.module(this.numrows - 1, this.numcols - 1, pos, 2); 23729 this.module(0, this.numcols - 3, pos, 3); 23730 this.module(0, this.numcols - 2, pos, 4); 23731 this.module(0, this.numcols - 1, pos, 5); 23732 this.module(1, this.numcols - 3, pos, 6); 23733 this.module(1, this.numcols - 2, pos, 7); 23734 this.module(1, this.numcols - 1, pos, 8); 23735 } 23736 } 23737 23738 /** 23739 * Lookup table which factors to use for which number of error correction codewords. 23740 * See FACTORS. 23741 */ 23742 const FACTOR_SETS = [ 23743 5, 7, 10, 11, 12, 14, 18, 20, 24, 28, 36, 42, 48, 56, 62, 68, 23744 ]; 23745 /** 23746 * Precomputed polynomial factors for ECC 200. 23747 */ 23748 const FACTORS = [ 23749 [228, 48, 15, 111, 62], 23750 [23, 68, 144, 134, 240, 92, 254], 23751 [28, 24, 185, 166, 223, 248, 116, 255, 110, 61], 23752 [175, 138, 205, 12, 194, 168, 39, 245, 60, 97, 120], 23753 [41, 153, 158, 91, 61, 42, 142, 213, 97, 178, 100, 242], 23754 [156, 97, 192, 252, 95, 9, 157, 119, 138, 45, 18, 186, 83, 185], 23755 [ 23756 83, 195, 100, 39, 188, 75, 66, 61, 241, 213, 109, 129, 94, 254, 225, 48, 90, 23757 188, 23758 ], 23759 [ 23760 15, 195, 244, 9, 233, 71, 168, 2, 188, 160, 153, 145, 253, 79, 108, 82, 27, 23761 174, 186, 172, 23762 ], 23763 [ 23764 52, 190, 88, 205, 109, 39, 176, 21, 155, 197, 251, 223, 155, 21, 5, 172, 23765 254, 124, 12, 181, 184, 96, 50, 193, 23766 ], 23767 [ 23768 211, 231, 43, 97, 71, 96, 103, 174, 37, 151, 170, 53, 75, 34, 249, 121, 17, 23769 138, 110, 213, 141, 136, 120, 151, 233, 168, 93, 255, 23770 ], 23771 [ 23772 245, 127, 242, 218, 130, 250, 162, 181, 102, 120, 84, 179, 220, 251, 80, 23773 182, 229, 18, 2, 4, 68, 33, 101, 137, 95, 119, 115, 44, 175, 184, 59, 25, 23774 225, 98, 81, 112, 23775 ], 23776 [ 23777 77, 193, 137, 31, 19, 38, 22, 153, 247, 105, 122, 2, 245, 133, 242, 8, 175, 23778 95, 100, 9, 167, 105, 214, 111, 57, 121, 21, 1, 253, 57, 54, 101, 248, 202, 23779 69, 50, 150, 177, 226, 5, 9, 5, 23780 ], 23781 [ 23782 245, 132, 172, 223, 96, 32, 117, 22, 238, 133, 238, 231, 205, 188, 237, 87, 23783 191, 106, 16, 147, 118, 23, 37, 90, 170, 205, 131, 88, 120, 100, 66, 138, 23784 186, 240, 82, 44, 176, 87, 187, 147, 160, 175, 69, 213, 92, 253, 225, 19, 23785 ], 23786 [ 23787 175, 9, 223, 238, 12, 17, 220, 208, 100, 29, 175, 170, 230, 192, 215, 235, 23788 150, 159, 36, 223, 38, 200, 132, 54, 228, 146, 218, 234, 117, 203, 29, 232, 23789 144, 238, 22, 150, 201, 117, 62, 207, 164, 13, 137, 245, 127, 67, 247, 28, 23790 155, 43, 203, 107, 233, 53, 143, 46, 23791 ], 23792 [ 23793 242, 93, 169, 50, 144, 210, 39, 118, 202, 188, 201, 189, 143, 108, 196, 37, 23794 185, 112, 134, 230, 245, 63, 197, 190, 250, 106, 185, 221, 175, 64, 114, 71, 23795 161, 44, 147, 6, 27, 218, 51, 63, 87, 10, 40, 130, 188, 17, 163, 31, 176, 23796 170, 4, 107, 232, 7, 94, 166, 224, 124, 86, 47, 11, 204, 23797 ], 23798 [ 23799 220, 228, 173, 89, 251, 149, 159, 56, 89, 33, 147, 244, 154, 36, 73, 127, 23800 213, 136, 248, 180, 234, 197, 158, 177, 68, 122, 93, 213, 15, 160, 227, 236, 23801 66, 139, 153, 185, 202, 167, 179, 25, 220, 232, 96, 210, 231, 136, 223, 239, 23802 181, 241, 59, 52, 172, 25, 49, 232, 211, 189, 64, 54, 108, 153, 132, 63, 96, 23803 103, 82, 186, 23804 ], 23805 ]; 23806 const /*final*/ MODULO_VALUE = 0x12d; 23807 const static_LOG = (LOG, ALOG) => { 23808 let p = 1; 23809 for (let i = 0; i < 255; i++) { 23810 ALOG[i] = p; 23811 LOG[p] = i; 23812 p *= 2; 23813 if (p >= 256) { 23814 p ^= MODULO_VALUE; 23815 } 23816 } 23817 return { 23818 LOG, 23819 ALOG, 23820 }; 23821 }; 23822 const { LOG, ALOG } = static_LOG([], []); 23823 exports.DataMatrixSymbolShapeHint = void 0; 23824 (function (SymbolShapeHint) { 23825 SymbolShapeHint[SymbolShapeHint["FORCE_NONE"] = 0] = "FORCE_NONE"; 23826 SymbolShapeHint[SymbolShapeHint["FORCE_SQUARE"] = 1] = "FORCE_SQUARE"; 23827 SymbolShapeHint[SymbolShapeHint["FORCE_RECTANGLE"] = 2] = "FORCE_RECTANGLE"; 23828 })(exports.DataMatrixSymbolShapeHint || (exports.DataMatrixSymbolShapeHint = {})); 23829 /** 23830 * Padding character 23831 */ 23832 const PAD = 129; 23833 /** 23834 * mode latch to C40 encodation mode 23835 */ 23836 const LATCH_TO_C40 = 230; 23837 /** 23838 * mode latch to Base 256 encodation mode 23839 */ 23840 const LATCH_TO_BASE256 = 231; 23841 /** 23842 * FNC1 Codeword 23843 */ 23844 // private static FNC1 = 232; 23845 /** 23846 * Structured Append Codeword 23847 */ 23848 // private static STRUCTURED_APPEND = 233; 23849 /** 23850 * Reader Programming 23851 */ 23852 // private static READER_PROGRAMMING = 234; 23853 /** 23854 * Upper Shift 23855 */ 23856 const UPPER_SHIFT = 235; 23857 /** 23858 * 05 Macro 23859 */ 23860 const MACRO_05 = 236; 23861 /** 23862 * 06 Macro 23863 */ 23864 const MACRO_06 = 237; 23865 /** 23866 * mode latch to ANSI X.12 encodation mode 23867 */ 23868 const LATCH_TO_ANSIX12 = 238; 23869 /** 23870 * mode latch to Text encodation mode 23871 */ 23872 const LATCH_TO_TEXT = 239; 23873 /** 23874 * mode latch to EDIFACT encodation mode 23875 */ 23876 const LATCH_TO_EDIFACT = 240; 23877 /** 23878 * ECI character (Extended Channel Interpretation) 23879 */ 23880 // private export const ECI = 241; 23881 /** 23882 * Unlatch from C40 encodation 23883 */ 23884 const C40_UNLATCH = 254; 23885 /** 23886 * Unlatch from X12 encodation 23887 */ 23888 const X12_UNLATCH = 254; 23889 /** 23890 * 05 Macro header 23891 */ 23892 const MACRO_05_HEADER = '[)>\u001E05\u001D'; 23893 /** 23894 * 06 Macro header 23895 */ 23896 const MACRO_06_HEADER = '[)>\u001E06\u001D'; 23897 /** 23898 * Macro trailer 23899 */ 23900 const MACRO_TRAILER = '\u001E\u0004'; 23901 const ASCII_ENCODATION = 0; 23902 const C40_ENCODATION = 1; 23903 const TEXT_ENCODATION = 2; 23904 const X12_ENCODATION = 3; 23905 const EDIFACT_ENCODATION = 4; 23906 const BASE256_ENCODATION = 5; 23907 23908 /** 23909 * Error Correction Code for ECC200. 23910 */ 23911 class ErrorCorrection { 23912 /** 23913 * Creates the ECC200 error correction for an encoded message. 23914 * 23915 * @param codewords the codewords 23916 * @param symbolInfo information about the symbol to be encoded 23917 * @return the codewords with interleaved error correction. 23918 */ 23919 static encodeECC200(codewords, symbolInfo) { 23920 if (codewords.length !== symbolInfo.getDataCapacity()) { 23921 throw new Error('The number of codewords does not match the selected symbol'); 23922 } 23923 const sb = new StringBuilder(); 23924 sb.append(codewords); 23925 const blockCount = symbolInfo.getInterleavedBlockCount(); 23926 if (blockCount === 1) { 23927 const ecc = this.createECCBlock(codewords, symbolInfo.getErrorCodewords()); 23928 sb.append(ecc); 23929 } 23930 else { 23931 const errorSizes = []; 23932 for (let i = 0; i < blockCount; i++) { 23933 symbolInfo.getDataLengthForInterleavedBlock(i + 1); 23934 errorSizes[i] = symbolInfo.getErrorLengthForInterleavedBlock(i + 1); 23935 } 23936 for (let block = 0; block < blockCount; block++) { 23937 const temp = new StringBuilder(); 23938 for (let d = block; d < symbolInfo.getDataCapacity(); d += blockCount) { 23939 temp.append(codewords.charAt(d)); 23940 } 23941 const ecc = this.createECCBlock(temp.toString(), errorSizes[block]); 23942 let pos = 0; 23943 for (let e = block; e < errorSizes[block] * blockCount; e += blockCount) { 23944 sb.setCharAt(symbolInfo.getDataCapacity() + e, ecc.charAt(pos++)); 23945 } 23946 } 23947 } 23948 return sb.toString(); 23949 } 23950 static createECCBlock(codewords, numECWords) { 23951 let table = -1; 23952 for (let i = 0; i < FACTOR_SETS.length; i++) { 23953 if (FACTOR_SETS[i] === numECWords) { 23954 table = i; 23955 break; 23956 } 23957 } 23958 if (table < 0) { 23959 throw new Error('Illegal number of error correction codewords specified: ' + numECWords); 23960 } 23961 const poly = FACTORS[table]; 23962 const ecc = []; 23963 for (let i = 0; i < numECWords; i++) { 23964 ecc[i] = 0; 23965 } 23966 for (let i = 0; i < codewords.length; i++) { 23967 let m = ecc[numECWords - 1] ^ codewords.charAt(i).charCodeAt(0); 23968 for (let k = numECWords - 1; k > 0; k--) { 23969 if (m !== 0 && poly[k] !== 0) { 23970 ecc[k] = ecc[k - 1] ^ ALOG[(LOG[m] + LOG[poly[k]]) % 255]; 23971 } 23972 else { 23973 ecc[k] = ecc[k - 1]; 23974 } 23975 } 23976 if (m !== 0 && poly[0] !== 0) { 23977 ecc[0] = ALOG[(LOG[m] + LOG[poly[0]]) % 255]; 23978 } 23979 else { 23980 ecc[0] = 0; 23981 } 23982 } 23983 const eccReversed = []; 23984 for (let i = 0; i < numECWords; i++) { 23985 eccReversed[i] = ecc[numECWords - i - 1]; 23986 } 23987 return eccReversed.map(c => String.fromCharCode(c)).join(''); 23988 } 23989 } 23990 23991 class ASCIIEncoder { 23992 getEncodingMode() { 23993 return ASCII_ENCODATION; 23994 } 23995 encode(context) { 23996 // step B 23997 const n = HighLevelEncoder$1.determineConsecutiveDigitCount(context.getMessage(), context.pos); 23998 if (n >= 2) { 23999 context.writeCodeword(this.encodeASCIIDigits(context.getMessage().charCodeAt(context.pos), context.getMessage().charCodeAt(context.pos + 1))); 24000 context.pos += 2; 24001 } 24002 else { 24003 const c = context.getCurrentChar(); 24004 const newMode = HighLevelEncoder$1.lookAheadTest(context.getMessage(), context.pos, this.getEncodingMode()); 24005 if (newMode !== this.getEncodingMode()) { 24006 switch (newMode) { 24007 case BASE256_ENCODATION: 24008 context.writeCodeword(LATCH_TO_BASE256); 24009 context.signalEncoderChange(BASE256_ENCODATION); 24010 return; 24011 case C40_ENCODATION: 24012 context.writeCodeword(LATCH_TO_C40); 24013 context.signalEncoderChange(C40_ENCODATION); 24014 return; 24015 case X12_ENCODATION: 24016 context.writeCodeword(LATCH_TO_ANSIX12); 24017 context.signalEncoderChange(X12_ENCODATION); 24018 break; 24019 case TEXT_ENCODATION: 24020 context.writeCodeword(LATCH_TO_TEXT); 24021 context.signalEncoderChange(TEXT_ENCODATION); 24022 break; 24023 case EDIFACT_ENCODATION: 24024 context.writeCodeword(LATCH_TO_EDIFACT); 24025 context.signalEncoderChange(EDIFACT_ENCODATION); 24026 break; 24027 default: 24028 throw new Error('Illegal mode: ' + newMode); 24029 } 24030 } 24031 else if (HighLevelEncoder$1.isExtendedASCII(c)) { 24032 context.writeCodeword(UPPER_SHIFT); 24033 context.writeCodeword(c - 128 + 1); 24034 context.pos++; 24035 } 24036 else { 24037 context.writeCodeword(c + 1); 24038 context.pos++; 24039 } 24040 } 24041 } 24042 encodeASCIIDigits(digit1, digit2) { 24043 if (HighLevelEncoder$1.isDigit(digit1) && HighLevelEncoder$1.isDigit(digit2)) { 24044 const num = (digit1 - 48) * 10 + (digit2 - 48); 24045 return num + 130; 24046 } 24047 throw new Error('not digits: ' + digit1 + digit2); 24048 } 24049 } 24050 24051 class Base256Encoder { 24052 getEncodingMode() { 24053 return BASE256_ENCODATION; 24054 } 24055 encode(context) { 24056 const buffer = new StringBuilder(); 24057 buffer.append(0o0); // Initialize length field 24058 while (context.hasMoreCharacters()) { 24059 const c = context.getCurrentChar(); 24060 buffer.append(c); 24061 context.pos++; 24062 const newMode = HighLevelEncoder$1.lookAheadTest(context.getMessage(), context.pos, this.getEncodingMode()); 24063 if (newMode !== this.getEncodingMode()) { 24064 // Return to ASCII encodation, which will actually handle latch to new mode 24065 context.signalEncoderChange(ASCII_ENCODATION); 24066 break; 24067 } 24068 } 24069 const dataCount = buffer.length() - 1; 24070 const lengthFieldSize = 1; 24071 const currentSize = context.getCodewordCount() + dataCount + lengthFieldSize; 24072 context.updateSymbolInfo(currentSize); 24073 const mustPad = context.getSymbolInfo().getDataCapacity() - currentSize > 0; 24074 if (context.hasMoreCharacters() || mustPad) { 24075 if (dataCount <= 249) { 24076 buffer.setCharAt(0, StringUtils.getCharAt(dataCount)); 24077 } 24078 else if (dataCount <= 1555) { 24079 buffer.setCharAt(0, StringUtils.getCharAt(Math.floor(dataCount / 250) + 249)); 24080 buffer.insert(1, StringUtils.getCharAt(dataCount % 250)); 24081 } 24082 else { 24083 throw new Error('Message length not in valid ranges: ' + dataCount); 24084 } 24085 } 24086 for (let i = 0, c = buffer.length(); i < c; i++) { 24087 context.writeCodeword(this.randomize255State(buffer.charAt(i).charCodeAt(0), context.getCodewordCount() + 1)); 24088 } 24089 } 24090 randomize255State(ch, codewordPosition) { 24091 const pseudoRandom = ((149 * codewordPosition) % 255) + 1; 24092 const tempVariable = ch + pseudoRandom; 24093 if (tempVariable <= 255) { 24094 return tempVariable; 24095 } 24096 else { 24097 return tempVariable - 256; 24098 } 24099 } 24100 } 24101 24102 class C40Encoder { 24103 getEncodingMode() { 24104 return C40_ENCODATION; 24105 } 24106 encodeMaximal(context) { 24107 const buffer = new StringBuilder(); 24108 let lastCharSize = 0; 24109 let backtrackStartPosition = context.pos; 24110 let backtrackBufferLength = 0; 24111 while (context.hasMoreCharacters()) { 24112 const c = context.getCurrentChar(); 24113 context.pos++; 24114 lastCharSize = this.encodeChar(c, buffer); 24115 if (buffer.length() % 3 === 0) { 24116 backtrackStartPosition = context.pos; 24117 backtrackBufferLength = buffer.length(); 24118 } 24119 } 24120 if (backtrackBufferLength !== buffer.length()) { 24121 const unwritten = Math.floor((buffer.length() / 3) * 2); 24122 const curCodewordCount = Math.floor(context.getCodewordCount() + unwritten + 1); // +1 for the latch to C40 24123 context.updateSymbolInfo(curCodewordCount); 24124 const available = context.getSymbolInfo().getDataCapacity() - curCodewordCount; 24125 const rest = Math.floor(buffer.length() % 3); 24126 if ((rest === 2 && available !== 2) || 24127 (rest === 1 && (lastCharSize > 3 || available !== 1))) { 24128 // buffer.setLength(backtrackBufferLength); 24129 context.pos = backtrackStartPosition; 24130 } 24131 } 24132 if (buffer.length() > 0) { 24133 context.writeCodeword(LATCH_TO_C40); 24134 } 24135 this.handleEOD(context, buffer); 24136 } 24137 encode(context) { 24138 // step C 24139 const buffer = new StringBuilder(); 24140 while (context.hasMoreCharacters()) { 24141 const c = context.getCurrentChar(); 24142 context.pos++; 24143 let lastCharSize = this.encodeChar(c, buffer); 24144 const unwritten = Math.floor(buffer.length() / 3) * 2; 24145 const curCodewordCount = context.getCodewordCount() + unwritten; 24146 context.updateSymbolInfo(curCodewordCount); 24147 const available = context.getSymbolInfo().getDataCapacity() - curCodewordCount; 24148 if (!context.hasMoreCharacters()) { 24149 // Avoid having a single C40 value in the last triplet 24150 const removed = new StringBuilder(); 24151 if (buffer.length() % 3 === 2 && available !== 2) { 24152 lastCharSize = this.backtrackOneCharacter(context, buffer, removed, lastCharSize); 24153 } 24154 while (buffer.length() % 3 === 1 && 24155 (lastCharSize > 3 || available !== 1)) { 24156 lastCharSize = this.backtrackOneCharacter(context, buffer, removed, lastCharSize); 24157 } 24158 break; 24159 } 24160 const count = buffer.length(); 24161 if (count % 3 === 0) { 24162 const newMode = HighLevelEncoder$1.lookAheadTest(context.getMessage(), context.pos, this.getEncodingMode()); 24163 if (newMode !== this.getEncodingMode()) { 24164 // Return to ASCII encodation, which will actually handle latch to new mode 24165 context.signalEncoderChange(ASCII_ENCODATION); 24166 break; 24167 } 24168 } 24169 } 24170 this.handleEOD(context, buffer); 24171 } 24172 backtrackOneCharacter(context, buffer, removed, lastCharSize) { 24173 const count = buffer.length(); 24174 const test = buffer.toString().substring(0, count - lastCharSize); 24175 buffer.setLengthToZero(); 24176 buffer.append(test); 24177 // buffer.delete(count - lastCharSize, count); 24178 /*for (let i = count - lastCharSize; i < count; i++) { 24179 buffer.deleteCharAt(i); 24180 }*/ 24181 context.pos--; 24182 const c = context.getCurrentChar(); 24183 lastCharSize = this.encodeChar(c, removed); 24184 context.resetSymbolInfo(); // Deal with possible reduction in symbol size 24185 return lastCharSize; 24186 } 24187 writeNextTriplet(context, buffer) { 24188 context.writeCodewords(this.encodeToCodewords(buffer.toString())); 24189 const test = buffer.toString().substring(3); 24190 buffer.setLengthToZero(); 24191 buffer.append(test); 24192 // buffer.delete(0, 3); 24193 /*for (let i = 0; i < 3; i++) { 24194 buffer.deleteCharAt(i); 24195 }*/ 24196 } 24197 /** 24198 * Handle "end of data" situations 24199 * 24200 * @param context the encoder context 24201 * @param buffer the buffer with the remaining encoded characters 24202 */ 24203 handleEOD(context, buffer) { 24204 const unwritten = Math.floor((buffer.length() / 3) * 2); 24205 const rest = buffer.length() % 3; 24206 const curCodewordCount = context.getCodewordCount() + unwritten; 24207 context.updateSymbolInfo(curCodewordCount); 24208 const available = context.getSymbolInfo().getDataCapacity() - curCodewordCount; 24209 if (rest === 2) { 24210 buffer.append('\0'); // Shift 1 24211 while (buffer.length() >= 3) { 24212 this.writeNextTriplet(context, buffer); 24213 } 24214 if (context.hasMoreCharacters()) { 24215 context.writeCodeword(C40_UNLATCH); 24216 } 24217 } 24218 else if (available === 1 && rest === 1) { 24219 while (buffer.length() >= 3) { 24220 this.writeNextTriplet(context, buffer); 24221 } 24222 if (context.hasMoreCharacters()) { 24223 context.writeCodeword(C40_UNLATCH); 24224 } 24225 // else no unlatch 24226 context.pos--; 24227 } 24228 else if (rest === 0) { 24229 while (buffer.length() >= 3) { 24230 this.writeNextTriplet(context, buffer); 24231 } 24232 if (available > 0 || context.hasMoreCharacters()) { 24233 context.writeCodeword(C40_UNLATCH); 24234 } 24235 } 24236 else { 24237 throw new Error('Unexpected case. Please report!'); 24238 } 24239 context.signalEncoderChange(ASCII_ENCODATION); 24240 } 24241 encodeChar(c, sb) { 24242 if (c === ' '.charCodeAt(0)) { 24243 sb.append(0o3); 24244 return 1; 24245 } 24246 if (c >= '0'.charCodeAt(0) && c <= '9'.charCodeAt(0)) { 24247 sb.append(c - 48 + 4); 24248 return 1; 24249 } 24250 if (c >= 'A'.charCodeAt(0) && c <= 'Z'.charCodeAt(0)) { 24251 sb.append(c - 65 + 14); 24252 return 1; 24253 } 24254 if (c < ' '.charCodeAt(0)) { 24255 sb.append(0o0); // Shift 1 Set 24256 sb.append(c); 24257 return 2; 24258 } 24259 if (c <= '/'.charCodeAt(0)) { 24260 sb.append(0o1); // Shift 2 Set 24261 sb.append(c - 33); 24262 return 2; 24263 } 24264 if (c <= '@'.charCodeAt(0)) { 24265 sb.append(0o1); // Shift 2 Set 24266 sb.append(c - 58 + 15); 24267 return 2; 24268 } 24269 if (c <= '_'.charCodeAt(0)) { 24270 sb.append(0o1); // Shift 2 Set 24271 sb.append(c - 91 + 22); 24272 return 2; 24273 } 24274 if (c <= 127) { 24275 sb.append(0o2); // Shift 3 Set 24276 sb.append(c - 96); 24277 return 2; 24278 } 24279 sb.append(`${0o1}\u001e`); // Shift 2, Upper Shift 24280 let len = 2; 24281 len += this.encodeChar(c - 128, sb); 24282 return len; 24283 } 24284 encodeToCodewords(sb) { 24285 const v = 1600 * sb.charCodeAt(0) + 40 * sb.charCodeAt(1) + sb.charCodeAt(2) + 1; 24286 const cw1 = v / 256; 24287 const cw2 = v % 256; 24288 const result = new StringBuilder(); 24289 result.append(cw1); 24290 result.append(cw2); 24291 return result.toString(); 24292 } 24293 } 24294 24295 class EdifactEncoder { 24296 getEncodingMode() { 24297 return EDIFACT_ENCODATION; 24298 } 24299 encode(context) { 24300 // step F 24301 const buffer = new StringBuilder(); 24302 while (context.hasMoreCharacters()) { 24303 const c = context.getCurrentChar(); 24304 this.encodeChar(c, buffer); 24305 context.pos++; 24306 const count = buffer.length(); 24307 if (count >= 4) { 24308 context.writeCodewords(this.encodeToCodewords(buffer.toString())); 24309 const test = buffer.toString().substring(4); 24310 buffer.setLengthToZero(); 24311 buffer.append(test); 24312 // buffer.delete(0, 4); 24313 // for (let i = 0; i < 4; i++) { 24314 // buffer.deleteCharAt(i); 24315 // } 24316 const newMode = HighLevelEncoder$1.lookAheadTest(context.getMessage(), context.pos, this.getEncodingMode()); 24317 if (newMode !== this.getEncodingMode()) { 24318 // Return to ASCII encodation, which will actually handle latch to new mode 24319 context.signalEncoderChange(ASCII_ENCODATION); 24320 break; 24321 } 24322 } 24323 } 24324 buffer.append(StringUtils.getCharAt(31)); // Unlatch 24325 this.handleEOD(context, buffer); 24326 } 24327 /** 24328 * Handle "end of data" situations 24329 * 24330 * @param context the encoder context 24331 * @param buffer the buffer with the remaining encoded characters 24332 */ 24333 handleEOD(context, buffer) { 24334 try { 24335 const count = buffer.length(); 24336 if (count === 0) { 24337 return; // Already finished 24338 } 24339 if (count === 1) { 24340 // Only an unlatch at the end 24341 context.updateSymbolInfo(); 24342 let available = context.getSymbolInfo().getDataCapacity() - 24343 context.getCodewordCount(); 24344 const remaining = context.getRemainingCharacters(); 24345 // The following two lines are a hack inspired by the 'fix' from https://sourceforge.net/p/barcode4j/svn/221/ 24346 if (remaining > available) { 24347 context.updateSymbolInfo(context.getCodewordCount() + 1); 24348 available = 24349 context.getSymbolInfo().getDataCapacity() - 24350 context.getCodewordCount(); 24351 } 24352 if (remaining <= available && available <= 2) { 24353 return; // No unlatch 24354 } 24355 } 24356 if (count > 4) { 24357 throw new Error('Count must not exceed 4'); 24358 } 24359 const restChars = count - 1; 24360 const encoded = this.encodeToCodewords(buffer.toString()); 24361 const endOfSymbolReached = !context.hasMoreCharacters(); 24362 let restInAscii = endOfSymbolReached && restChars <= 2; 24363 if (restChars <= 2) { 24364 context.updateSymbolInfo(context.getCodewordCount() + restChars); 24365 const available = context.getSymbolInfo().getDataCapacity() - 24366 context.getCodewordCount(); 24367 if (available >= 3) { 24368 restInAscii = false; 24369 context.updateSymbolInfo(context.getCodewordCount() + encoded.length); 24370 // available = context.symbolInfo.dataCapacity - context.getCodewordCount(); 24371 } 24372 } 24373 if (restInAscii) { 24374 context.resetSymbolInfo(); 24375 context.pos -= restChars; 24376 } 24377 else { 24378 context.writeCodewords(encoded); 24379 } 24380 } 24381 finally { 24382 context.signalEncoderChange(ASCII_ENCODATION); 24383 } 24384 } 24385 encodeChar(c, sb) { 24386 if (c >= ' '.charCodeAt(0) && c <= '?'.charCodeAt(0)) { 24387 sb.append(c); 24388 } 24389 else if (c >= '@'.charCodeAt(0) && c <= '^'.charCodeAt(0)) { 24390 sb.append(StringUtils.getCharAt(c - 64)); 24391 } 24392 else { 24393 HighLevelEncoder$1.illegalCharacter(StringUtils.getCharAt(c)); 24394 } 24395 } 24396 encodeToCodewords(sb) { 24397 const len = sb.length; 24398 if (len === 0) { 24399 throw new Error('StringBuilder must not be empty'); 24400 } 24401 const c1 = sb.charAt(0).charCodeAt(0); 24402 const c2 = len >= 2 ? sb.charAt(1).charCodeAt(0) : 0; 24403 const c3 = len >= 3 ? sb.charAt(2).charCodeAt(0) : 0; 24404 const c4 = len >= 4 ? sb.charAt(3).charCodeAt(0) : 0; 24405 const v = (c1 << 18) + (c2 << 12) + (c3 << 6) + c4; 24406 const cw1 = (v >> 16) & 255; 24407 const cw2 = (v >> 8) & 255; 24408 const cw3 = v & 255; 24409 const res = new StringBuilder(); 24410 res.append(cw1); 24411 if (len >= 2) { 24412 res.append(cw2); 24413 } 24414 if (len >= 3) { 24415 res.append(cw3); 24416 } 24417 return res.toString(); 24418 } 24419 } 24420 24421 /** 24422 * Symbol info table for DataMatrix. 24423 */ 24424 class SymbolInfo { 24425 constructor(rectangular, dataCapacity, errorCodewords, matrixWidth, matrixHeight, dataRegions, rsBlockData = 0, rsBlockError = 0) { 24426 this.rectangular = rectangular; 24427 this.dataCapacity = dataCapacity; 24428 this.errorCodewords = errorCodewords; 24429 this.matrixWidth = matrixWidth; 24430 this.matrixHeight = matrixHeight; 24431 this.dataRegions = dataRegions; 24432 this.rsBlockData = rsBlockData; 24433 this.rsBlockError = rsBlockError; 24434 } 24435 static lookup(dataCodewords, shape = 0 /*
vendor: 26,262 bytes, lines 24435-25113
24435FORCE_NONE */, minSize = null, maxSize = null, fail = true) { 24436 for (const symbol of PROD_SYMBOLS) { 24437 if (shape === 1 /* FORCE_SQUARE */ && symbol.rectangular) { 24438 continue; 24439 } 24440 if (shape === 2 /* FORCE_RECTANGLE */ && !symbol.rectangular) { 24441 continue; 24442 } 24443 if (minSize != null && 24444 (symbol.getSymbolWidth() < minSize.getWidth() || 24445 symbol.getSymbolHeight() < minSize.getHeight())) { 24446 continue; 24447 } 24448 if (maxSize != null && 24449 (symbol.getSymbolWidth() > maxSize.getWidth() || 24450 symbol.getSymbolHeight() > maxSize.getHeight())) { 24451 continue; 24452 } 24453 if (dataCodewords <= symbol.dataCapacity) { 24454 return symbol; 24455 } 24456 } 24457 if (fail) { 24458 throw new Error("Can't find a symbol arrangement that matches the message. Data codewords: " + 24459 dataCodewords); 24460 } 24461 return null; 24462 } 24463 getHorizontalDataRegions() { 24464 switch (this.dataRegions) { 24465 case 1: 24466 return 1; 24467 case 2: 24468 case 4: 24469 return 2; 24470 case 16: 24471 return 4; 24472 case 36: 24473 return 6; 24474 default: 24475 throw new Error('Cannot handle this number of data regions'); 24476 } 24477 } 24478 getVerticalDataRegions() { 24479 switch (this.dataRegions) { 24480 case 1: 24481 case 2: 24482 return 1; 24483 case 4: 24484 return 2; 24485 case 16: 24486 return 4; 24487 case 36: 24488 return 6; 24489 default: 24490 throw new Error('Cannot handle this number of data regions'); 24491 } 24492 } 24493 getSymbolDataWidth() { 24494 return this.getHorizontalDataRegions() * this.matrixWidth; 24495 } 24496 getSymbolDataHeight() { 24497 return this.getVerticalDataRegions() * this.matrixHeight; 24498 } 24499 getSymbolWidth() { 24500 return this.getSymbolDataWidth() + this.getHorizontalDataRegions() * 2; 24501 } 24502 getSymbolHeight() { 24503 return this.getSymbolDataHeight() + this.getVerticalDataRegions() * 2; 24504 } 24505 getCodewordCount() { 24506 return this.dataCapacity + this.errorCodewords; 24507 } 24508 getInterleavedBlockCount() { 24509 if (!this.rsBlockData) 24510 return 1; 24511 return this.dataCapacity / this.rsBlockData; 24512 } 24513 getDataCapacity() { 24514 return this.dataCapacity; 24515 } 24516 getErrorCodewords() { 24517 return this.errorCodewords; 24518 } 24519 getDataLengthForInterleavedBlock(index) { 24520 return this.rsBlockData; 24521 } 24522 getErrorLengthForInterleavedBlock(index) { 24523 return this.rsBlockError; 24524 } 24525 } 24526 class DataMatrixSymbolInfo144 extends SymbolInfo { 24527 constructor() { 24528 super(false, 1558, 620, 22, 22, 36, -1, 62); 24529 } 24530 getInterleavedBlockCount() { 24531 return 10; 24532 } 24533 getDataLengthForInterleavedBlock(index) { 24534 return index <= 8 ? 156 : 155; 24535 } 24536 } 24537 const PROD_SYMBOLS = [ 24538 new SymbolInfo(false, 3, 5, 8, 8, 1), 24539 new SymbolInfo(false, 5, 7, 10, 10, 1), 24540 /*rect*/ new SymbolInfo(true, 5, 7, 16, 6, 1), 24541 new SymbolInfo(false, 8, 10, 12, 12, 1), 24542 /*rect*/ new SymbolInfo(true, 10, 11, 14, 6, 2), 24543 new SymbolInfo(false, 12, 12, 14, 14, 1), 24544 /*rect*/ new SymbolInfo(true, 16, 14, 24, 10, 1), 24545 new SymbolInfo(false, 18, 14, 16, 16, 1), 24546 new SymbolInfo(false, 22, 18, 18, 18, 1), 24547 /*rect*/ new SymbolInfo(true, 22, 18, 16, 10, 2), 24548 new SymbolInfo(false, 30, 20, 20, 20, 1), 24549 /*rect*/ new SymbolInfo(true, 32, 24, 16, 14, 2), 24550 new SymbolInfo(false, 36, 24, 22, 22, 1), 24551 new SymbolInfo(false, 44, 28, 24, 24, 1), 24552 /*rect*/ new SymbolInfo(true, 49, 28, 22, 14, 2), 24553 new SymbolInfo(false, 62, 36, 14, 14, 4), 24554 new SymbolInfo(false, 86, 42, 16, 16, 4), 24555 new SymbolInfo(false, 114, 48, 18, 18, 4), 24556 new SymbolInfo(false, 144, 56, 20, 20, 4), 24557 new SymbolInfo(false, 174, 68, 22, 22, 4), 24558 new SymbolInfo(false, 204, 84, 24, 24, 4, 102, 42), 24559 new SymbolInfo(false, 280, 112, 14, 14, 16, 140, 56), 24560 new SymbolInfo(false, 368, 144, 16, 16, 16, 92, 36), 24561 new SymbolInfo(false, 456, 192, 18, 18, 16, 114, 48), 24562 new SymbolInfo(false, 576, 224, 20, 20, 16, 144, 56), 24563 new SymbolInfo(false, 696, 272, 22, 22, 16, 174, 68), 24564 new SymbolInfo(false, 816, 336, 24, 24, 16, 136, 56), 24565 new SymbolInfo(false, 1050, 408, 18, 18, 36, 175, 68), 24566 new SymbolInfo(false, 1304, 496, 20, 20, 36, 163, 62), 24567 new DataMatrixSymbolInfo144(), 24568 ]; 24569 24570 class EncoderContext { 24571 constructor(msg) { 24572 this.msg = msg; 24573 this.pos = 0; 24574 this.skipAtEnd = 0; 24575 // From this point on Strings are not Unicode anymore! 24576 const msgBinary = msg.split('').map(c => c.charCodeAt(0)); 24577 const sb = new StringBuilder(); 24578 for (let i = 0, c = msgBinary.length; i < c; i++) { 24579 const ch = String.fromCharCode(msgBinary[i] & 0xff); 24580 if (ch === '?' && msg.charAt(i) !== '?') { 24581 throw new Error('Message contains characters outside ISO-8859-1 encoding.'); 24582 } 24583 sb.append(ch); 24584 } 24585 this.msg = sb.toString(); // Not Unicode here! 24586 this.shape = 0 /* FORCE_NONE */; 24587 this.codewords = new StringBuilder(); 24588 this.newEncoding = -1; 24589 } 24590 setSymbolShape(shape) { 24591 this.shape = shape; 24592 } 24593 setSizeConstraints(minSize, maxSize) { 24594 this.minSize = minSize; 24595 this.maxSize = maxSize; 24596 } 24597 getMessage() { 24598 return this.msg; 24599 } 24600 setSkipAtEnd(count) { 24601 this.skipAtEnd = count; 24602 } 24603 getCurrentChar() { 24604 return this.msg.charCodeAt(this.pos); 24605 } 24606 getCurrent() { 24607 return this.msg.charCodeAt(this.pos); 24608 } 24609 getCodewords() { 24610 return this.codewords; 24611 } 24612 writeCodewords(codewords) { 24613 this.codewords.append(codewords); 24614 } 24615 writeCodeword(codeword) { 24616 this.codewords.append(codeword); 24617 } 24618 getCodewordCount() { 24619 return this.codewords.length(); 24620 } 24621 getNewEncoding() { 24622 return this.newEncoding; 24623 } 24624 signalEncoderChange(encoding) { 24625 this.newEncoding = encoding; 24626 } 24627 resetEncoderSignal() { 24628 this.newEncoding = -1; 24629 } 24630 hasMoreCharacters() { 24631 return this.pos < this.getTotalMessageCharCount(); 24632 } 24633 getTotalMessageCharCount() { 24634 return this.msg.length - this.skipAtEnd; 24635 } 24636 getRemainingCharacters() { 24637 return this.getTotalMessageCharCount() - this.pos; 24638 } 24639 getSymbolInfo() { 24640 return this.symbolInfo; 24641 } 24642 updateSymbolInfo(len = this.getCodewordCount()) { 24643 if (this.symbolInfo == null || len > this.symbolInfo.getDataCapacity()) { 24644 this.symbolInfo = SymbolInfo.lookup(len, this.shape, this.minSize, this.maxSize, true); 24645 } 24646 } 24647 resetSymbolInfo() { 24648 this.symbolInfo = null; 24649 } 24650 } 24651 24652 class X12Encoder extends C40Encoder { 24653 getEncodingMode() { 24654 return X12_ENCODATION; 24655 } 24656 encode(context) { 24657 // step C 24658 const buffer = new StringBuilder(); 24659 while (context.hasMoreCharacters()) { 24660 const c = context.getCurrentChar(); 24661 context.pos++; 24662 this.encodeChar(c, buffer); 24663 const count = buffer.length(); 24664 if (count % 3 === 0) { 24665 this.writeNextTriplet(context, buffer); 24666 const newMode = HighLevelEncoder$1.lookAheadTest(context.getMessage(), context.pos, this.getEncodingMode()); 24667 if (newMode !== this.getEncodingMode()) { 24668 // Return to ASCII encodation, which will actually handle latch to new mode 24669 context.signalEncoderChange(ASCII_ENCODATION); 24670 break; 24671 } 24672 } 24673 } 24674 this.handleEOD(context, buffer); 24675 } 24676 encodeChar(c, sb) { 24677 switch (c) { 24678 case 13: // CR (Carriage return) 24679 sb.append(0o0); 24680 break; 24681 case '*'.charCodeAt(0): 24682 sb.append(0o1); 24683 break; 24684 case '>'.charCodeAt(0): 24685 sb.append(0o2); 24686 break; 24687 case ' '.charCodeAt(0): 24688 sb.append(0o3); 24689 break; 24690 default: 24691 if (c >= '0'.charCodeAt(0) && c <= '9'.charCodeAt(0)) { 24692 sb.append(c - 48 + 4); 24693 } 24694 else if (c >= 'A'.charCodeAt(0) && c <= 'Z'.charCodeAt(0)) { 24695 sb.append(c - 65 + 14); 24696 } 24697 else { 24698 HighLevelEncoder$1.illegalCharacter(StringUtils.getCharAt(c)); 24699 } 24700 break; 24701 } 24702 return 1; 24703 } 24704 handleEOD(context, buffer) { 24705 context.updateSymbolInfo(); 24706 const available = context.getSymbolInfo().getDataCapacity() - context.getCodewordCount(); 24707 const count = buffer.length(); 24708 context.pos -= count; 24709 if (context.getRemainingCharacters() > 1 || 24710 available > 1 || 24711 context.getRemainingCharacters() !== available) { 24712 context.writeCodeword(X12_UNLATCH); 24713 } 24714 if (context.getNewEncoding() < 0) { 24715 context.signalEncoderChange(ASCII_ENCODATION); 24716 } 24717 } 24718 } 24719 24720 class TextEncoder$1 extends C40Encoder { 24721 getEncodingMode() { 24722 return TEXT_ENCODATION; 24723 } 24724 encodeChar(c, sb) { 24725 if (c === ' '.charCodeAt(0)) { 24726 sb.append(0o3); 24727 return 1; 24728 } 24729 if (c >= '0'.charCodeAt(0) && c <= '9'.charCodeAt(0)) { 24730 sb.append(c - 48 + 4); 24731 return 1; 24732 } 24733 if (c >= 'a'.charCodeAt(0) && c <= 'z'.charCodeAt(0)) { 24734 sb.append(c - 97 + 14); 24735 return 1; 24736 } 24737 if (c < ' '.charCodeAt(0)) { 24738 sb.append(0o0); // Shift 1 Set 24739 sb.append(c); 24740 return 2; 24741 } 24742 if (c <= '/'.charCodeAt(0)) { 24743 sb.append(0o1); // Shift 2 Set 24744 sb.append(c - 33); 24745 return 2; 24746 } 24747 if (c <= '@'.charCodeAt(0)) { 24748 sb.append(0o1); // Shift 2 Set 24749 sb.append(c - 58 + 15); 24750 return 2; 24751 } 24752 if (c >= '['.charCodeAt(0) && c <= '_'.charCodeAt(0)) { 24753 sb.append(0o1); // Shift 2 Set 24754 sb.append(c - 91 + 22); 24755 return 2; 24756 } 24757 if (c === '`'.charCodeAt(0)) { 24758 sb.append(0o2); // Shift 3 Set 24759 sb.append(0); // '`' - 96 == 0 24760 return 2; 24761 } 24762 if (c <= 'Z'.charCodeAt(0)) { 24763 sb.append(0o2); // Shift 3 Set 24764 sb.append(c - 65 + 1); 24765 return 2; 24766 } 24767 if (c <= 127) { 24768 sb.append(0o2); // Shift 3 Set 24769 sb.append(c - 123 + 27); 24770 return 2; 24771 } 24772 sb.append(`${0o1}\u001e`); // Shift 2, Upper Shift 24773 let len = 2; 24774 len += this.encodeChar(c - 128, sb); 24775 return len; 24776 } 24777 } 24778 24779 // tslint:disable-next-line:no-circular-imports 24780 /** 24781 * DataMatrix ECC 200 data encoder following the algorithm described in ISO/IEC 16022:200(E) in 24782 * annex S. 24783 */ 24784 class HighLevelEncoder$1 { 24785 static randomize253State(codewordPosition) { 24786 const pseudoRandom = ((149 * codewordPosition) % 253) + 1; 24787 const tempVariable = PAD + pseudoRandom; 24788 return tempVariable <= 254 ? tempVariable : tempVariable - 254; 24789 } 24790 /** 24791 * Performs message encoding of a DataMatrix message using the algorithm described in annex P 24792 * of ISO/IEC 16022:2000(E). 24793 * 24794 * @param msg the message 24795 * @param shape requested shape. May be {@code SymbolShapeHint.FORCE_NONE}, 24796 * {@code SymbolShapeHint.FORCE_SQUARE} or {@code SymbolShapeHint.FORCE_RECTANGLE}. 24797 * @param minSize the minimum symbol size constraint or null for no constraint 24798 * @param maxSize the maximum symbol size constraint or null for no constraint 24799 * @param forceC40 enforce C40 encoding 24800 * @return the encoded message (the char values range from 0 to 255) 24801 */ 24802 static encodeHighLevel(msg, shape = 0 /* FORCE_NONE */, minSize = null, maxSize = null, forceC40 = false) { 24803 // the codewords 0..255 are encoded as Unicode characters 24804 const c40Encoder = new C40Encoder(); 24805 const encoders = [ 24806 new ASCIIEncoder(), 24807 c40Encoder, 24808 new TextEncoder$1(), 24809 new X12Encoder(), 24810 new EdifactEncoder(), 24811 new Base256Encoder(), 24812 ]; 24813 const context = new EncoderContext(msg); 24814 context.setSymbolShape(shape); 24815 context.setSizeConstraints(minSize, maxSize); 24816 if (msg.startsWith(MACRO_05_HEADER) && msg.endsWith(MACRO_TRAILER)) { 24817 context.writeCodeword(MACRO_05); 24818 context.setSkipAtEnd(2); 24819 context.pos += MACRO_05_HEADER.length; 24820 } 24821 else if (msg.startsWith(MACRO_06_HEADER) && msg.endsWith(MACRO_TRAILER)) { 24822 context.writeCodeword(MACRO_06); 24823 context.setSkipAtEnd(2); 24824 context.pos += MACRO_06_HEADER.length; 24825 } 24826 let encodingMode = ASCII_ENCODATION; // Default mode 24827 if (forceC40) { 24828 c40Encoder.encodeMaximal(context); 24829 encodingMode = context.getNewEncoding(); 24830 context.resetEncoderSignal(); 24831 } 24832 while (context.hasMoreCharacters()) { 24833 encoders[encodingMode].encode(context); 24834 if (context.getNewEncoding() >= 0) { 24835 encodingMode = context.getNewEncoding(); 24836 context.resetEncoderSignal(); 24837 } 24838 } 24839 const len = context.getCodewordCount(); 24840 context.updateSymbolInfo(); 24841 const capacity = context.getSymbolInfo().getDataCapacity(); 24842 if (len < capacity && 24843 encodingMode !== ASCII_ENCODATION && 24844 encodingMode !== BASE256_ENCODATION && 24845 encodingMode !== EDIFACT_ENCODATION) { 24846 context.writeCodeword('\u00fe'); // Unlatch (254) 24847 } 24848 // Padding 24849 const codewords = context.getCodewords(); 24850 if (codewords.length() < capacity) { 24851 codewords.append(PAD); 24852 } 24853 while (codewords.length() < capacity) { 24854 codewords.append(this.randomize253State(codewords.length() + 1)); 24855 } 24856 return context.getCodewords().toString(); 24857 } 24858 static lookAheadTest(msg, startpos, currentMode) { 24859 const newMode = this.lookAheadTestIntern(msg, startpos, currentMode); 24860 if (currentMode === X12_ENCODATION && newMode === X12_ENCODATION) { 24861 const endpos = Math.min(startpos + 3, msg.length); 24862 for (let i = startpos; i < endpos; i++) { 24863 if (!this.isNativeX12(msg.charCodeAt(i))) { 24864 return ASCII_ENCODATION; 24865 } 24866 } 24867 } 24868 else if (currentMode === EDIFACT_ENCODATION && 24869 newMode === EDIFACT_ENCODATION) { 24870 const endpos = Math.min(startpos + 4, msg.length); 24871 for (let i = startpos; i < endpos; i++) { 24872 if (!this.isNativeEDIFACT(msg.charCodeAt(i))) { 24873 return ASCII_ENCODATION; 24874 } 24875 } 24876 } 24877 return newMode; 24878 } 24879 static lookAheadTestIntern(msg, startpos, currentMode) { 24880 if (startpos >= msg.length) { 24881 return currentMode; 24882 } 24883 let charCounts; 24884 // step J 24885 if (currentMode === ASCII_ENCODATION) { 24886 charCounts = [0, 1, 1, 1, 1, 1.25]; 24887 } 24888 else { 24889 charCounts = [1, 2, 2, 2, 2, 2.25]; 24890 charCounts[currentMode] = 0; 24891 } 24892 let charsProcessed = 0; 24893 const mins = new Uint8Array(6); 24894 const intCharCounts = []; 24895 while (true) { 24896 // step K 24897 if (startpos + charsProcessed === msg.length) { 24898 Arrays.fill(mins, 0); 24899 Arrays.fill(intCharCounts, 0); 24900 const min = this.findMinimums(charCounts, intCharCounts, Integer.MAX_VALUE, mins); 24901 const minCount = this.getMinimumCount(mins); 24902 if (intCharCounts[ASCII_ENCODATION] === min) { 24903 return ASCII_ENCODATION; 24904 } 24905 if (minCount === 1) { 24906 if (mins[BASE256_ENCODATION] > 0) { 24907 return BASE256_ENCODATION; 24908 } 24909 if (mins[EDIFACT_ENCODATION] > 0) { 24910 return EDIFACT_ENCODATION; 24911 } 24912 if (mins[TEXT_ENCODATION] > 0) { 24913 return TEXT_ENCODATION; 24914 } 24915 if (mins[X12_ENCODATION] > 0) { 24916 return X12_ENCODATION; 24917 } 24918 } 24919 return C40_ENCODATION; 24920 } 24921 const c = msg.charCodeAt(startpos + charsProcessed); 24922 charsProcessed++; 24923 // step L 24924 if (this.isDigit(c)) { 24925 charCounts[ASCII_ENCODATION] += 0.5; 24926 } 24927 else if (this.isExtendedASCII(c)) { 24928 charCounts[ASCII_ENCODATION] = Math.ceil(charCounts[ASCII_ENCODATION]); 24929 charCounts[ASCII_ENCODATION] += 2.0; 24930 } 24931 else { 24932 charCounts[ASCII_ENCODATION] = Math.ceil(charCounts[ASCII_ENCODATION]); 24933 charCounts[ASCII_ENCODATION]++; 24934 } 24935 // step M 24936 if (this.isNativeC40(c)) { 24937 charCounts[C40_ENCODATION] += 2.0 / 3.0; 24938 } 24939 else if (this.isExtendedASCII(c)) { 24940 charCounts[C40_ENCODATION] += 8.0 / 3.0; 24941 } 24942 else { 24943 charCounts[C40_ENCODATION] += 4.0 / 3.0; 24944 } 24945 // step N 24946 if (this.isNativeText(c)) { 24947 charCounts[TEXT_ENCODATION] += 2.0 / 3.0; 24948 } 24949 else if (this.isExtendedASCII(c)) { 24950 charCounts[TEXT_ENCODATION] += 8.0 / 3.0; 24951 } 24952 else { 24953 charCounts[TEXT_ENCODATION] += 4.0 / 3.0; 24954 } 24955 // step O 24956 if (this.isNativeX12(c)) { 24957 charCounts[X12_ENCODATION] += 2.0 / 3.0; 24958 } 24959 else if (this.isExtendedASCII(c)) { 24960 charCounts[X12_ENCODATION] += 13.0 / 3.0; 24961 } 24962 else { 24963 charCounts[X12_ENCODATION] += 10.0 / 3.0; 24964 } 24965 // step P 24966 if (this.isNativeEDIFACT(c)) { 24967 charCounts[EDIFACT_ENCODATION] += 3.0 / 4.0; 24968 } 24969 else if (this.isExtendedASCII(c)) { 24970 charCounts[EDIFACT_ENCODATION] += 17.0 / 4.0; 24971 } 24972 else { 24973 charCounts[EDIFACT_ENCODATION] += 13.0 / 4.0; 24974 } 24975 // step Q 24976 if (this.isSpecialB256(c)) { 24977 charCounts[BASE256_ENCODATION] += 4.0; 24978 } 24979 else { 24980 charCounts[BASE256_ENCODATION]++; 24981 } 24982 // step R 24983 if (charsProcessed >= 4) { 24984 Arrays.fill(mins, 0); 24985 Arrays.fill(intCharCounts, 0); 24986 this.findMinimums(charCounts, intCharCounts, Integer.MAX_VALUE, mins); 24987 if (intCharCounts[ASCII_ENCODATION] < 24988 this.min(intCharCounts[BASE256_ENCODATION], intCharCounts[C40_ENCODATION], intCharCounts[TEXT_ENCODATION], intCharCounts[X12_ENCODATION], intCharCounts[EDIFACT_ENCODATION])) { 24989 return ASCII_ENCODATION; 24990 } 24991 if (intCharCounts[BASE256_ENCODATION] < intCharCounts[ASCII_ENCODATION] || 24992 intCharCounts[BASE256_ENCODATION] + 1 < 24993 this.min(intCharCounts[C40_ENCODATION], intCharCounts[TEXT_ENCODATION], intCharCounts[X12_ENCODATION], intCharCounts[EDIFACT_ENCODATION])) { 24994 return BASE256_ENCODATION; 24995 } 24996 if (intCharCounts[EDIFACT_ENCODATION] + 1 < 24997 this.min(intCharCounts[BASE256_ENCODATION], intCharCounts[C40_ENCODATION], intCharCounts[TEXT_ENCODATION], intCharCounts[X12_ENCODATION], intCharCounts[ASCII_ENCODATION])) { 24998 return EDIFACT_ENCODATION; 24999 } 25000 if (intCharCounts[TEXT_ENCODATION] + 1 < 25001 this.min(intCharCounts[BASE256_ENCODATION], intCharCounts[C40_ENCODATION], intCharCounts[EDIFACT_ENCODATION], intCharCounts[X12_ENCODATION], intCharCounts[ASCII_ENCODATION])) { 25002 return TEXT_ENCODATION; 25003 } 25004 if (intCharCounts[X12_ENCODATION] + 1 < 25005 this.min(intCharCounts[BASE256_ENCODATION], intCharCounts[C40_ENCODATION], intCharCounts[EDIFACT_ENCODATION], intCharCounts[TEXT_ENCODATION], intCharCounts[ASCII_ENCODATION])) { 25006 return X12_ENCODATION; 25007 } 25008 if (intCharCounts[C40_ENCODATION] + 1 < 25009 this.min(intCharCounts[ASCII_ENCODATION], intCharCounts[BASE256_ENCODATION], intCharCounts[EDIFACT_ENCODATION], intCharCounts[TEXT_ENCODATION])) { 25010 if (intCharCounts[C40_ENCODATION] < intCharCounts[X12_ENCODATION]) { 25011 return C40_ENCODATION; 25012 } 25013 if (intCharCounts[C40_ENCODATION] === intCharCounts[X12_ENCODATION]) { 25014 let p = startpos + charsProcessed + 1; 25015 while (p < msg.length) { 25016 const tc = msg.charCodeAt(p); 25017 if (this.isX12TermSep(tc)) { 25018 return X12_ENCODATION; 25019 } 25020 if (!this.isNativeX12(tc)) { 25021 break; 25022 } 25023 p++; 25024 } 25025 return C40_ENCODATION; 25026 } 25027 } 25028 } 25029 } 25030 } 25031 static min(f1, f2, f3, f4, f5) { 25032 const val = Math.min(f1, Math.min(f2, Math.min(f3, f4))); 25033 if (f5 === undefined) { 25034 return val; 25035 } 25036 else { 25037 return Math.min(val, f5); 25038 } 25039 } 25040 static findMinimums(charCounts, intCharCounts, min, mins) { 25041 for (let i = 0; i < 6; i++) { 25042 const current = (intCharCounts[i] = Math.ceil(charCounts[i])); 25043 if (min > current) { 25044 min = current; 25045 Arrays.fill(mins, 0); 25046 } 25047 if (min === current) { 25048 mins[i] = mins[i] + 1; 25049 } 25050 } 25051 return min; 25052 } 25053 static getMinimumCount(mins) { 25054 let minCount = 0; 25055 for (let i = 0; i < 6; i++) { 25056 minCount += mins[i]; 25057 } 25058 return minCount || 0; 25059 } 25060 static isDigit(ch) { 25061 return ch >= '0'.charCodeAt(0) && ch <= '9'.charCodeAt(0); 25062 } 25063 static isExtendedASCII(ch) { 25064 return ch >= 128 && ch <= 255; 25065 } 25066 static isNativeC40(ch) { 25067 return (ch === ' '.charCodeAt(0) || 25068 (ch >= '0'.charCodeAt(0) && ch <= '9'.charCodeAt(0)) || 25069 (ch >= 'A'.charCodeAt(0) && ch <= 'Z'.charCodeAt(0))); 25070 } 25071 static isNativeText(ch) { 25072 return (ch === ' '.charCodeAt(0) || 25073 (ch >= '0'.charCodeAt(0) && ch <= '9'.charCodeAt(0)) || 25074 (ch >= 'a'.charCodeAt(0) && ch <= 'z'.charCodeAt(0))); 25075 } 25076 static isNativeX12(ch) { 25077 return (this.isX12TermSep(ch) || 25078 ch === ' '.charCodeAt(0) || 25079 (ch >= '0'.charCodeAt(0) && ch <= '9'.charCodeAt(0)) || 25080 (ch >= 'A'.charCodeAt(0) && ch <= 'Z'.charCodeAt(0))); 25081 } 25082 static isX12TermSep(ch) { 25083 return (ch === 13 || // CR 25084 ch === '*'.charCodeAt(0) || 25085 ch === '>'.charCodeAt(0)); 25086 } 25087 static isNativeEDIFACT(ch) { 25088 return ch >= ' '.charCodeAt(0) && ch <= '^'.charCodeAt(0); 25089 } 25090 static isSpecialB256(ch) { 25091 return false; // TODO NOT IMPLEMENTED YET!!! 25092 } 25093 /** 25094 * Determines the number of consecutive characters that are encodable using numeric compaction. 25095 * 25096 * @param msg the message 25097 * @param startpos the start position within the message 25098 * @return the requested character count 25099 */ 25100 static determineConsecutiveDigitCount(msg, startpos = 0) { 25101 const len = msg.length; 25102 let idx = startpos; 25103 while (idx < len && this.isDigit(msg.charCodeAt(idx))) { 25104 idx++; 25105 } 25106 return idx - startpos; 25107 } 25108 static illegalCharacter(singleCharacter) { 25109 let hex = Integer.toHexString(singleCharacter.charCodeAt(0)); 25110 hex = '0000'.substring(0, 4 - hex.length) + hex; 25111 throw new Error('Illegal character: ' + singleCharacter + ' (0x' + hex + ')'); 25112 } 25113 }
vendor: 54,800 bytes, lines 25113-26266
25113 25114 25115 /** 25116 * Set of CharsetEncoders for a given input string 25117 * 25118 * Invariants: 25119 * - The list contains only encoders from CharacterSetECI (list is shorter then the list of encoders available on 25120 * the platform for which ECI values are defined). 25121 * - The list contains encoders at least one encoder for every character in the input. 25122 * - The first encoder in the list is always the ISO-8859-1 encoder even of no character in the input can be encoded 25123 * by it. 25124 * - If the input contains a character that is not in ISO-8859-1 then the last two entries in the list will be the 25125 * UTF-8 encoder and the UTF-16BE encoder. 25126 * 25127 * @author Alex Geller 25128 */ 25129 class CharsetEncoder { 25130 constructor(charset) { 25131 this.charset = charset; 25132 this.name = charset.name; 25133 } 25134 canEncode(c) { 25135 try { 25136 return StringEncoding.encode(c, this.charset) != null; 25137 } 25138 catch (ex) { 25139 return false; 25140 } 25141 } 25142 } 25143 class ECIEncoderSet { 25144 /** 25145 * Constructs an encoder set 25146 * 25147 * @param stringToEncode the string that needs to be encoded 25148 * @param priorityCharset The preferred {@link Charset} or null. 25149 * @param fnc1 fnc1 denotes the character in the input that represents the FNC1 character or -1 for a non-GS1 bar 25150 * code. When specified, it is considered an error to pass it as argument to the methods canEncode() or encode(). 25151 */ 25152 constructor(stringToEncode, priorityCharset, fnc1) { 25153 this.ENCODERS = [ 25154 'IBM437', 25155 'ISO-8859-2', 25156 'ISO-8859-3', 25157 'ISO-8859-4', 25158 'ISO-8859-5', 25159 'ISO-8859-6', 25160 'ISO-8859-7', 25161 'ISO-8859-8', 25162 'ISO-8859-9', 25163 'ISO-8859-10', 25164 'ISO-8859-11', 25165 'ISO-8859-13', 25166 'ISO-8859-14', 25167 'ISO-8859-15', 25168 'ISO-8859-16', 25169 'windows-1250', 25170 'windows-1251', 25171 'windows-1252', 25172 'windows-1256', 25173 'Shift_JIS', 25174 ].map(name => new CharsetEncoder(Charset.forName(name))); 25175 this.encoders = []; 25176 const neededEncoders = []; 25177 // we always need the ISO-8859-1 encoder. It is the default encoding 25178 neededEncoders.push(new CharsetEncoder(StandardCharsets.ISO_8859_1)); 25179 let needUnicodeEncoder = priorityCharset != null && priorityCharset.name.startsWith('UTF'); 25180 // Walk over the input string and see if all characters can be encoded with the list of encoders 25181 for (let i = 0; i < stringToEncode.length; i++) { 25182 let canEncode = false; 25183 for (const encoder of neededEncoders) { 25184 const singleCharacter = stringToEncode.charAt(i); 25185 const c = singleCharacter.charCodeAt(0); 25186 if (c === fnc1 || encoder.canEncode(singleCharacter)) { 25187 canEncode = true; 25188 break; 25189 } 25190 } 25191 if (!canEncode) { 25192 // for the character at position i we don't yet have an encoder in the list 25193 for (const encoder of this.ENCODERS) { 25194 if (encoder.canEncode(stringToEncode.charAt(i))) { 25195 // Good, we found an encoder that can encode the character. We add him to the list and continue scanning 25196 // the input 25197 neededEncoders.push(encoder); 25198 canEncode = true; 25199 break; 25200 } 25201 } 25202 } 25203 if (!canEncode) { 25204 // The character is not encodeable by any of the single byte encoders so we remember that we will need a 25205 // Unicode encoder. 25206 needUnicodeEncoder = true; 25207 } 25208 } 25209 if (neededEncoders.length === 1 && !needUnicodeEncoder) { 25210 // the entire input can be encoded by the ISO-8859-1 encoder 25211 this.encoders = [neededEncoders[0]]; 25212 } 25213 else { 25214 // we need more than one single byte encoder or we need a Unicode encoder. 25215 // In this case we append a UTF-8 and UTF-16 encoder to the list 25216 this.encoders = []; 25217 let index = 0; 25218 for (const encoder of neededEncoders) { 25219 this.encoders[index++] = encoder; 25220 } 25221 // this.encoders[index] = new CharsetEncoder(StandardCharsets.UTF_8); 25222 // this.encoders[index + 1] = new CharsetEncoder(StandardCharsets.UTF_16BE); 25223 } 25224 // Compute priorityEncoderIndex by looking up priorityCharset in encoders 25225 let priorityEncoderIndexValue = -1; 25226 if (priorityCharset != null) { 25227 for (let i = 0; i < this.encoders.length; i++) { 25228 if (this.encoders[i] != null && 25229 priorityCharset.name === this.encoders[i].name) { 25230 priorityEncoderIndexValue = i; 25231 break; 25232 } 25233 } 25234 } 25235 this.priorityEncoderIndex = priorityEncoderIndexValue; 25236 // invariants 25237 // if(this?.encoders?.[0].name !== StandardCharsets.ISO_8859_1)){ 25238 // throw new Error("ISO-8859-1 must be the first encoder"); 25239 // } 25240 } 25241 length() { 25242 return this.encoders.length; 25243 } 25244 getCharsetName(index) { 25245 if (!(index < this.length())) { 25246 throw new Error('index must be less than length'); 25247 } 25248 return this.encoders[index].name; 25249 } 25250 getCharset(index) { 25251 if (!(index < this.length())) { 25252 throw new Error('index must be less than length'); 25253 } 25254 return this.encoders[index].charset; 25255 } 25256 getECIValue(encoderIndex) { 25257 return this.encoders[encoderIndex].charset.getValueIdentifier(); 25258 } 25259 /* 25260 * returns -1 if no priority charset was defined 25261 */ 25262 getPriorityEncoderIndex() { 25263 return this.priorityEncoderIndex; 25264 } 25265 canEncode(c, encoderIndex) { 25266 if (!(encoderIndex < this.length())) { 25267 throw new Error('index must be less than length'); 25268 } 25269 return true; 25270 } 25271 encode(c, encoderIndex) { 25272 if (!(encoderIndex < this.length())) { 25273 throw new Error('index must be less than length'); 25274 } 25275 return StringEncoding.encode(StringUtils.getCharAt(c), this.encoders[encoderIndex].name); 25276 } 25277 } 25278 25279 const COST_PER_ECI = 3; // approximated (latch + 2 codewords) 25280 class MinimalECIInput { 25281 /** 25282 * Constructs a minimal input 25283 * 25284 * @param stringToEncode the character string to encode 25285 * @param priorityCharset The preferred {@link Charset}. When the value of the argument is null, the algorithm 25286 * chooses charsets that leads to a minimal representation. Otherwise the algorithm will use the priority 25287 * charset to encode any character in the input that can be encoded by it if the charset is among the 25288 * supported charsets. 25289 * @param fnc1 denotes the character in the input that represents the FNC1 character or -1 if this is not GS1 25290 * input. 25291 */ 25292 constructor(stringToEncode, priorityCharset, fnc1) { 25293 this.fnc1 = fnc1; 25294 const encoderSet = new ECIEncoderSet(stringToEncode, priorityCharset, fnc1); 25295 if (encoderSet.length() === 1) { 25296 // optimization for the case when all can be encoded without ECI in ISO-8859-1 25297 for (let i = 0; i < this.bytes.length; i++) { 25298 const c = stringToEncode.charAt(i).charCodeAt(0); 25299 this.bytes[i] = c === fnc1 ? 1000 : c; 25300 } 25301 } 25302 else { 25303 this.bytes = this.encodeMinimally(stringToEncode, encoderSet, fnc1); 25304 } 25305 } 25306 getFNC1Character() { 25307 return this.fnc1; 25308 } 25309 /** 25310 * Returns the length of this input. The length is the number 25311 * of {@code byte}s, FNC1 characters or ECIs in the sequence. 25312 * 25313 * @return the number of {@code char}s in this sequence 25314 */ 25315 length() { 25316 return this.bytes.length; 25317 } 25318 haveNCharacters(index, n) { 25319 if (index + n - 1 >= this.bytes.length) { 25320 return false; 25321 } 25322 for (let i = 0; i < n; i++) { 25323 if (this.isECI(index + i)) { 25324 return false; 25325 } 25326 } 25327 return true; 25328 } 25329 /** 25330 * Returns the {@code byte} value at the specified index. An index ranges from zero 25331 * to {@code length() - 1}. The first {@code byte} value of the sequence is at 25332 * index zero, the next at index one, and so on, as for array 25333 * indexing. 25334 * 25335 * @param index the index of the {@code byte} value to be returned 25336 * 25337 * @return the specified {@code byte} value as character or the FNC1 character 25338 * 25339 * @throws IndexOutOfBoundsException 25340 * if the {@code index} argument is negative or not less than 25341 * {@code length()} 25342 * @throws IllegalArgumentException 25343 * if the value at the {@code index} argument is an ECI (@see #isECI) 25344 */ 25345 charAt(index) { 25346 if (index < 0 || index >= this.length()) { 25347 throw new Error('' + index); 25348 } 25349 if (this.isECI(index)) { 25350 throw new Error('value at ' + index + ' is not a character but an ECI'); 25351 } 25352 return this.isFNC1(index) ? this.fnc1 : this.bytes[index]; 25353 } 25354 /** 25355 * Returns a {@code CharSequence} that is a subsequence of this sequence. 25356 * The subsequence starts with the {@code char} value at the specified index and 25357 * ends with the {@code char} value at index {@code end - 1}. The length 25358 * (in {@code char}s) of the 25359 * returned sequence is {@code end - start}, so if {@code start == end} 25360 * then an empty sequence is returned. 25361 * 25362 * @param start the start index, inclusive 25363 * @param end the end index, exclusive 25364 * 25365 * @return the specified subsequence 25366 * 25367 * @throws IndexOutOfBoundsException 25368 * if {@code start} or {@code end} are negative, 25369 * if {@code end} is greater than {@code length()}, 25370 * or if {@code start} is greater than {@code end} 25371 * @throws IllegalArgumentException 25372 * if a value in the range {@code start}-{@code end} is an ECI (@see #isECI) 25373 */ 25374 subSequence(start, end) { 25375 if (start < 0 || start > end || end > this.length()) { 25376 throw new Error('' + start); 25377 } 25378 const result = new StringBuilder(); 25379 for (let i = start; i < end; i++) { 25380 if (this.isECI(i)) { 25381 throw new Error('value at ' + i + ' is not a character but an ECI'); 25382 } 25383 result.append(this.charAt(i)); 25384 } 25385 return result.toString(); 25386 } 25387 /** 25388 * Determines if a value is an ECI 25389 * 25390 * @param index the index of the value 25391 * 25392 * @return true if the value at position {@code index} is an ECI 25393 * 25394 * @throws IndexOutOfBoundsException 25395 * if the {@code index} argument is negative or not less than 25396 * {@code length()} 25397 */ 25398 isECI(index) { 25399 if (index < 0 || index >= this.length()) { 25400 throw new Error('' + index); 25401 } 25402 return this.bytes[index] > 255 && this.bytes[index] <= 999; 25403 } 25404 /** 25405 * Determines if a value is the FNC1 character 25406 * 25407 * @param index the index of the value 25408 * 25409 * @return true if the value at position {@code index} is the FNC1 character 25410 * 25411 * @throws IndexOutOfBoundsException 25412 * if the {@code index} argument is negative or not less than 25413 * {@code length()} 25414 */ 25415 isFNC1(index) { 25416 if (index < 0 || index >= this.length()) { 25417 throw new Error('' + index); 25418 } 25419 return this.bytes[index] === 1000; 25420 } 25421 /** 25422 * Returns the {@code int} ECI value at the specified index. An index ranges from zero 25423 * to {@code length() - 1}. The first {@code byte} value of the sequence is at 25424 * index zero, the next at index one, and so on, as for array 25425 * indexing. 25426 * 25427 * @param index the index of the {@code int} value to be returned 25428 * 25429 * @return the specified {@code int} ECI value. 25430 * The ECI specified the encoding of all bytes with a higher index until the 25431 * next ECI or until the end of the input if no other ECI follows. 25432 * 25433 * @throws IndexOutOfBoundsException 25434 * if the {@code index} argument is negative or not less than 25435 * {@code length()} 25436 * @throws IllegalArgumentException 25437 * if the value at the {@code index} argument is not an ECI (@see #isECI) 25438 */ 25439 getECIValue(index) { 25440 if (index < 0 || index >= this.length()) { 25441 throw new Error('' + index); 25442 } 25443 if (!this.isECI(index)) { 25444 throw new Error('value at ' + index + ' is not an ECI but a character'); 25445 } 25446 return this.bytes[index] - 256; 25447 } 25448 addEdge(edges, to, edge) { 25449 if (edges[to][edge.encoderIndex] == null || 25450 edges[to][edge.encoderIndex].cachedTotalSize > edge.cachedTotalSize) { 25451 edges[to][edge.encoderIndex] = edge; 25452 } 25453 } 25454 addEdges(stringToEncode, encoderSet, edges, from, previous, fnc1) { 25455 const ch = stringToEncode.charAt(from).charCodeAt(0); 25456 let start = 0; 25457 let end = encoderSet.length(); 25458 if (encoderSet.getPriorityEncoderIndex() >= 0 && 25459 (ch === fnc1 || 25460 encoderSet.canEncode(ch, encoderSet.getPriorityEncoderIndex()))) { 25461 start = encoderSet.getPriorityEncoderIndex(); 25462 end = start + 1; 25463 } 25464 for (let i = start; i < end; i++) { 25465 if (ch === fnc1 || encoderSet.canEncode(ch, i)) { 25466 this.addEdge(edges, from + 1, new InputEdge(ch, encoderSet, i, previous, fnc1)); 25467 } 25468 } 25469 } 25470 encodeMinimally(stringToEncode, encoderSet, fnc1) { 25471 const inputLength = stringToEncode.length; 25472 // Array that represents vertices. There is a vertex for every character and encoding. 25473 const edges = new InputEdge[inputLength + 1][encoderSet.length()](); 25474 this.addEdges(stringToEncode, encoderSet, edges, 0, null, fnc1); 25475 for (let i = 1; i <= inputLength; i++) { 25476 for (let j = 0; j < encoderSet.length(); j++) { 25477 if (edges[i][j] != null && i < inputLength) { 25478 this.addEdges(stringToEncode, encoderSet, edges, i, edges[i][j], fnc1); 25479 } 25480 } 25481 // optimize memory by removing edges that have been passed. 25482 for (let j = 0; j < encoderSet.length(); j++) { 25483 edges[i - 1][j] = null; 25484 } 25485 } 25486 let minimalJ = -1; 25487 let minimalSize = Integer.MAX_VALUE; 25488 for (let j = 0; j < encoderSet.length(); j++) { 25489 if (edges[inputLength][j] != null) { 25490 const edge = edges[inputLength][j]; 25491 if (edge.cachedTotalSize < minimalSize) { 25492 minimalSize = edge.cachedTotalSize; 25493 minimalJ = j; 25494 } 25495 } 25496 } 25497 if (minimalJ < 0) { 25498 throw new Error('Failed to encode "' + stringToEncode + '"'); 25499 } 25500 const intsAL = []; 25501 let current = edges[inputLength][minimalJ]; 25502 while (current != null) { 25503 if (current.isFNC1()) { 25504 intsAL.unshift(1000); 25505 } 25506 else { 25507 const bytes = encoderSet.encode(current.c, current.encoderIndex); 25508 for (let i = bytes.length - 1; i >= 0; i--) { 25509 intsAL.unshift(bytes[i] & 0xff); 25510 } 25511 } 25512 const previousEncoderIndex = current.previous === null ? 0 : current.previous.encoderIndex; 25513 if (previousEncoderIndex !== current.encoderIndex) { 25514 intsAL.unshift(256 + encoderSet.getECIValue(current.encoderIndex)); 25515 } 25516 current = current.previous; 25517 } 25518 const ints = []; 25519 for (let i = 0; i < ints.length; i++) { 25520 ints[i] = intsAL[i]; 25521 } 25522 return ints; 25523 } 25524 } 25525 class InputEdge { 25526 constructor(c, encoderSet, encoderIndex, previous, fnc1) { 25527 this.c = c; 25528 this.encoderSet = encoderSet; 25529 this.encoderIndex = encoderIndex; 25530 this.previous = previous; 25531 this.fnc1 = fnc1; 25532 this.c = c === fnc1 ? 1000 : c; 25533 let size = this.isFNC1() ? 1 : encoderSet.encode(c, encoderIndex).length; 25534 const previousEncoderIndex = previous === null ? 0 : previous.encoderIndex; 25535 if (previousEncoderIndex !== encoderIndex) { 25536 size += COST_PER_ECI; 25537 } 25538 if (previous != null) { 25539 size += previous.cachedTotalSize; 25540 } 25541 this.cachedTotalSize = size; 25542 } 25543 isFNC1() { 25544 return this.c === 1000; 25545 } 25546 } 25547 25548 var Mode; 25549 (function (Mode) { 25550 Mode[Mode["ASCII"] = 0] = "ASCII"; 25551 Mode[Mode["C40"] = 1] = "C40"; 25552 Mode[Mode["TEXT"] = 2] = "TEXT"; 25553 Mode[Mode["X12"] = 3] = "X12"; 25554 Mode[Mode["EDF"] = 4] = "EDF"; 25555 Mode[Mode["B256"] = 5] = "B256"; 25556 })(Mode || (Mode = {})); 25557 const C40_SHIFT2_CHARS = [ 25558 '!', 25559 '"', 25560 '#', 25561 '$', 25562 '%', 25563 '&', 25564 "'", 25565 '(', 25566 ')', 25567 '*', 25568 '+', 25569 ',', 25570 '-', 25571 '.', 25572 '/', 25573 ':', 25574 ';', 25575 '<', 25576 '=', 25577 '>', 25578 '?', 25579 '@', 25580 '[', 25581 '\\', 25582 ']', 25583 '^', 25584 '_', 25585 ]; 25586 class MinimalEncoder { 25587 static isExtendedASCII(ch, fnc1) { 25588 return ch !== fnc1 && ch >= 128 && ch <= 255; 25589 } 25590 static isInC40Shift1Set(ch) { 25591 return ch <= 31; 25592 } 25593 static isInC40Shift2Set(ch, fnc1) { 25594 for (const c40Shift2Char of C40_SHIFT2_CHARS) { 25595 if (c40Shift2Char.charCodeAt(0) === ch) { 25596 return true; 25597 } 25598 } 25599 return ch === fnc1; 25600 } 25601 static isInTextShift1Set(ch) { 25602 return this.isInC40Shift1Set(ch); 25603 } 25604 static isInTextShift2Set(ch, fnc1) { 25605 return this.isInC40Shift2Set(ch, fnc1); 25606 } 25607 /** 25608 * Performs message encoding of a DataMatrix message 25609 * 25610 * @param msg the message 25611 * @param priorityCharset The preferred {@link Charset}. When the value of the argument is null, the algorithm 25612 * chooses charsets that leads to a minimal representation. Otherwise the algorithm will use the priority 25613 * charset to encode any character in the input that can be encoded by it if the charset is among the 25614 * supported charsets. 25615 * @param fnc1 denotes the character in the input that represents the FNC1 character or -1 if this is not a GS1 25616 * bar code. If the value is not -1 then a FNC1 is also prepended. 25617 * @param shape requested shape. 25618 * @return the encoded message (the char values range from 0 to 255) 25619 */ 25620 static encodeHighLevel(msg, priorityCharset = null, fnc1 = -1, shape = 0 /* FORCE_NONE */) { 25621 let macroId = 0; 25622 if (msg.startsWith(MACRO_05_HEADER) && msg.endsWith(MACRO_TRAILER)) { 25623 macroId = 5; 25624 msg = msg.substring(MACRO_05_HEADER.length, msg.length - 2); 25625 } 25626 else if (msg.startsWith(MACRO_06_HEADER) && msg.endsWith(MACRO_TRAILER)) { 25627 macroId = 6; 25628 msg = msg.substring(MACRO_06_HEADER.length, msg.length - 2); 25629 } 25630 return decodeURIComponent(escape(String.fromCharCode(...this.encode(msg, priorityCharset, fnc1, shape, macroId)))); 25631 } 25632 /** 25633 * Encodes input minimally and returns an array of the codewords 25634 * 25635 * @param input The string to encode 25636 * @param priorityCharset The preferred {@link Charset}. When the value of the argument is null, the algorithm 25637 * chooses charsets that leads to a minimal representation. Otherwise the algorithm will use the priority 25638 * charset to encode any character in the input that can be encoded by it if the charset is among the 25639 * supported charsets. 25640 * @param fnc1 denotes the character in the input that represents the FNC1 character or -1 if this is not a GS1 25641 * bar code. If the value is not -1 then a FNC1 is also prepended. 25642 * @param shape requested shape. 25643 * @param macroId Prepends the specified macro function in case that a value of 5 or 6 is specified. 25644 * @return An array of bytes representing the codewords of a minimal encoding. 25645 */ 25646 static encode(input, priorityCharset, fnc1, shape, macroId) { 25647 return this.encodeMinimally(new Input(input, priorityCharset, fnc1, shape, macroId)).getBytes(); 25648 } 25649 static addEdge(edges, edge) { 25650 const vertexIndex = edge.fromPosition + edge.characterLength; 25651 if (edges[vertexIndex][edge.getEndMode()] === null || 25652 edges[vertexIndex][edge.getEndMode()].cachedTotalSize > 25653 edge.cachedTotalSize) { 25654 edges[vertexIndex][edge.getEndMode()] = edge; 25655 } 25656 } 25657 /** @return the number of words in which the string starting at from can be encoded in c40 or text mode. 25658 * The number of characters encoded is returned in characterLength. 25659 * The number of characters encoded is also minimal in the sense that the algorithm stops as soon 25660 * as a character encoding fills a C40 word competely (three C40 values). An exception is at the 25661 * end of the string where two C40 values are allowed (according to the spec the third c40 value 25662 * is filled with 0 (Shift 1) in this case). 25663 */ 25664 static getNumberOfC40Words(input, from, c40, characterLength) { 25665 let thirdsCount = 0; 25666 for (let i = from; i < input.length(); i++) { 25667 if (input.isECI(i)) { 25668 characterLength[0] = 0; 25669 return 0; 25670 } 25671 const ci = input.charAt(i); 25672 if ((c40 && HighLevelEncoder$1.isNativeC40(ci)) || 25673 (!c40 && HighLevelEncoder$1.isNativeText(ci))) { 25674 thirdsCount++; // native 25675 } 25676 else if (!MinimalEncoder.isExtendedASCII(ci, input.getFNC1Character())) { 25677 thirdsCount += 2; // shift 25678 } 25679 else { 25680 const asciiValue = ci & 0xff; 25681 if (asciiValue >= 128 && 25682 ((c40 && HighLevelEncoder$1.isNativeC40(asciiValue - 128)) || 25683 (!c40 && HighLevelEncoder$1.isNativeText(asciiValue - 128)))) { 25684 thirdsCount += 3; // shift, Upper shift 25685 } 25686 else { 25687 thirdsCount += 4; // shift, Upper shift, shift 25688 } 25689 } 25690 if (thirdsCount % 3 === 0 || 25691 ((thirdsCount - 2) % 3 === 0 && i + 1 === input.length())) { 25692 characterLength[0] = i - from + 1; 25693 return Math.ceil(thirdsCount / 3.0); 25694 } 25695 } 25696 characterLength[0] = 0; 25697 return 0; 25698 } 25699 static addEdges(input, edges, from, previous) { 25700 if (input.isECI(from)) { 25701 this.addEdge(edges, new Edge(input, Mode.ASCII, from, 1, previous)); 25702 return; 25703 } 25704 const ch = input.charAt(from); 25705 if (previous === null || previous.getEndMode() !== Mode.EDF) { 25706 // not possible to unlatch a full EDF edge to something 25707 // else 25708 if (HighLevelEncoder$1.isDigit(ch) && 25709 input.haveNCharacters(from, 2) && 25710 HighLevelEncoder$1.isDigit(input.charAt(from + 1))) { 25711 // two digits ASCII encoded 25712 this.addEdge(edges, new Edge(input, Mode.ASCII, from, 2, previous)); 25713 } 25714 else { 25715 // one ASCII encoded character or an extended character via Upper Shift 25716 this.addEdge(edges, new Edge(input, Mode.ASCII, from, 1, previous)); 25717 } 25718 const modes = [Mode.C40, Mode.TEXT]; 25719 for (const mode of modes) { 25720 const characterLength = []; 25721 if (MinimalEncoder.getNumberOfC40Words(input, from, mode === Mode.C40, characterLength) > 0) { 25722 this.addEdge(edges, new Edge(input, mode, from, characterLength[0], previous)); 25723 } 25724 } 25725 if (input.haveNCharacters(from, 3) && 25726 HighLevelEncoder$1.isNativeX12(input.charAt(from)) && 25727 HighLevelEncoder$1.isNativeX12(input.charAt(from + 1)) && 25728 HighLevelEncoder$1.isNativeX12(input.charAt(from + 2))) { 25729 this.addEdge(edges, new Edge(input, Mode.X12, from, 3, previous)); 25730 } 25731 this.addEdge(edges, new Edge(input, Mode.B256, from, 1, previous)); 25732 } 25733 // We create 4 EDF edges, with 1, 2 3 or 4 characters length. The fourth normally doesn't have a latch to ASCII 25734 // unless it is 2 characters away from the end of the input. 25735 let i; 25736 for (i = 0; i < 3; i++) { 25737 const pos = from + i; 25738 if (input.haveNCharacters(pos, 1) && 25739 HighLevelEncoder$1.isNativeEDIFACT(input.charAt(pos))) { 25740 this.addEdge(edges, new Edge(input, Mode.EDF, from, i + 1, previous)); 25741 } 25742 else { 25743 break; 25744 } 25745 } 25746 if (i === 3 && 25747 input.haveNCharacters(from, 4) && 25748 HighLevelEncoder$1.isNativeEDIFACT(input.charAt(from + 3))) { 25749 this.addEdge(edges, new Edge(input, Mode.EDF, from, 4, previous)); 25750 } 25751 } 25752 static encodeMinimally(input) { 25753 /* The minimal encoding is computed by Dijkstra. The acyclic graph is modeled as follows: 25754 * A vertex represents a combination of a position in the input and an encoding mode where position 0 25755 * denotes the position left of the first character, 1 the position left of the second character and so on. 25756 * Likewise the end vertices are located after the last character at position input.length(). 25757 * For any position there might be up to six vertices, one for each of the encoding types ASCII, C40, TEXT, X12, 25758 * EDF and B256. 25759 * 25760 * As an example consider the input string "ABC123" then at position 0 there is only one vertex with the default 25761 * ASCII encodation. At position 3 there might be vertices for the types ASCII, C40, X12, EDF and B256. 25762 * 25763 * An edge leading to such a vertex encodes one or more of the characters left of the position that the vertex 25764 * represents. It encodes the characters in the encoding mode of the vertex that it ends on. In other words, 25765 * all edges leading to a particular vertex encode the same characters (the length of the suffix can vary) using the same 25766 * encoding mode. 25767 * As an example consider the input string "ABC123" and the vertex (4,EDF). Possible edges leading to this vertex 25768 * are: 25769 * (0,ASCII) --EDF(ABC1)--> (4,EDF) 25770 * (1,ASCII) --EDF(BC1)--> (4,EDF) 25771 * (1,B256) --EDF(BC1)--> (4,EDF) 25772 * (1,EDF) --EDF(BC1)--> (4,EDF) 25773 * (2,ASCII) --EDF(C1)--> (4,EDF) 25774 * (2,B256) --EDF(C1)--> (4,EDF) 25775 * (2,EDF) --EDF(C1)--> (4,EDF) 25776 * (3,ASCII) --EDF(1)--> (4,EDF) 25777 * (3,B256) --EDF(1)--> (4,EDF) 25778 * (3,EDF) --EDF(1)--> (4,EDF) 25779 * (3,C40) --EDF(1)--> (4,EDF) 25780 * (3,X12) --EDF(1)--> (4,EDF) 25781 * 25782 * The edges leading to a vertex are stored in such a way that there is a fast way to enumerate the edges ending 25783 * on a particular vertex. 25784 * 25785 * The algorithm processes the vertices in order of their position thereby performing the following: 25786 * 25787 * For every vertex at position i the algorithm enumerates the edges ending on the vertex and removes all but the 25788 * shortest from that list. 25789 * Then it processes the vertices for the position i+1. If i+1 == input.length() then the algorithm ends 25790 * and chooses the the edge with the smallest size from any of the edges leading to vertices at this position. 25791 * Otherwise the algorithm computes all possible outgoing edges for the vertices at the position i+1 25792 * 25793 * Examples: 25794 * The process is illustrated by showing the graph (edges) after each iteration from left to right over the input: 25795 * An edge is drawn as follows "(" + fromVertex + ") -- " + encodingMode + "(" + encodedInput + ") (" + 25796 * accumulatedSize + ") --> (" + toVertex + ")" 25797 * 25798 * Example 1 encoding the string "ABCDEFG": 25799 * 25800 * 25801 * Situation after adding edges to the start vertex (0,ASCII) 25802 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) 25803 * (0,ASCII) B256(A) (3) --> (1,B256) 25804 * (0,ASCII) EDF(AB) (4) --> (2,EDF) 25805 * (0,ASCII) C40(ABC) (3) --> (3,C40) 25806 * (0,ASCII) TEXT(ABC) (5) --> (3,TEXT) 25807 * (0,ASCII) X12(ABC) (3) --> (3,X12) 25808 * (0,ASCII) EDF(ABC) (4) --> (3,EDF) 25809 * (0,ASCII) EDF(ABCD) (4) --> (4,EDF) 25810 * 25811 * Situation after adding edges to vertices at position 1 25812 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) 25813 * (0,ASCII) B256(A) (3) --> (1,B256) 25814 * (0,ASCII) EDF(AB) (4) --> (2,EDF) 25815 * (0,ASCII) C40(ABC) (3) --> (3,C40) 25816 * (0,ASCII) TEXT(ABC) (5) --> (3,TEXT) 25817 * (0,ASCII) X12(ABC) (3) --> (3,X12) 25818 * (0,ASCII) EDF(ABC) (4) --> (3,EDF) 25819 * (0,ASCII) EDF(ABCD) (4) --> (4,EDF) 25820 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) 25821 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) B256(B) (4) --> (2,B256) 25822 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BC) (5) --> (3,EDF) 25823 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) C40(BCD) (4) --> (4,C40) 25824 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) TEXT(BCD) (6) --> (4,TEXT) 25825 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) X12(BCD) (4) --> (4,X12) 25826 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BCD) (5) --> (4,EDF) 25827 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BCDE) (5) --> (5,EDF) 25828 * (0,ASCII) B256(A) (3) --> (1,B256) ASCII(B) (4) --> (2,ASCII) 25829 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) 25830 * (0,ASCII) B256(A) (3) --> (1,B256) EDF(BC) (6) --> (3,EDF) 25831 * (0,ASCII) B256(A) (3) --> (1,B256) C40(BCD) (5) --> (4,C40) 25832 * (0,ASCII) B256(A) (3) --> (1,B256) TEXT(BCD) (7) --> (4,TEXT) 25833 * (0,ASCII) B256(A) (3) --> (1,B256) X12(BCD) (5) --> (4,X12) 25834 * (0,ASCII) B256(A) (3) --> (1,B256) EDF(BCD) (6) --> (4,EDF) 25835 * (0,ASCII) B256(A) (3) --> (1,B256) EDF(BCDE) (6) --> (5,EDF) 25836 * 25837 * Edge "(1,ASCII) ASCII(B) (2) --> (2,ASCII)" is minimal for the vertex (2,ASCII) so that edge "(1,B256) ASCII(B) (4) --> (2,ASCII)" is removed. 25838 * Edge "(1,B256) B256(B) (3) --> (2,B256)" is minimal for the vertext (2,B256) so that the edge "(1,ASCII) B256(B) (4) --> (2,B256)" is removed. 25839 * 25840 * Situation after adding edges to vertices at position 2 25841 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) 25842 * (0,ASCII) B256(A) (3) --> (1,B256) 25843 * (0,ASCII) EDF(AB) (4) --> (2,EDF) 25844 * (0,ASCII) C40(ABC) (3) --> (3,C40) 25845 * (0,ASCII) TEXT(ABC) (5) --> (3,TEXT) 25846 * (0,ASCII) X12(ABC) (3) --> (3,X12) 25847 * (0,ASCII) EDF(ABC) (4) --> (3,EDF) 25848 * (0,ASCII) EDF(ABCD) (4) --> (4,EDF) 25849 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) 25850 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BC) (5) --> (3,EDF) 25851 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) C40(BCD) (4) --> (4,C40) 25852 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) TEXT(BCD) (6) --> (4,TEXT) 25853 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) X12(BCD) (4) --> (4,X12) 25854 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BCD) (5) --> (4,EDF) 25855 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BCDE) (5) --> (5,EDF) 25856 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) 25857 * (0,ASCII) B256(A) (3) --> (1,B256) EDF(BC) (6) --> (3,EDF) 25858 * (0,ASCII) B256(A) (3) --> (1,B256) C40(BCD) (5) --> (4,C40) 25859 * (0,ASCII) B256(A) (3) --> (1,B256) TEXT(BCD) (7) --> (4,TEXT) 25860 * (0,ASCII) B256(A) (3) --> (1,B256) X12(BCD) (5) --> (4,X12) 25861 * (0,ASCII) B256(A) (3) --> (1,B256) EDF(BCD) (6) --> (4,EDF) 25862 * (0,ASCII) B256(A) (3) --> (1,B256) EDF(BCDE) (6) --> (5,EDF) 25863 * (0,ASCII) EDF(AB) (4) --> (2,EDF) ASCII(C) (5) --> (3,ASCII) 25864 * (0,ASCII) EDF(AB) (4) --> (2,EDF) B256(C) (6) --> (3,B256) 25865 * (0,ASCII) EDF(AB) (4) --> (2,EDF) EDF(CD) (7) --> (4,EDF) 25866 * (0,ASCII) EDF(AB) (4) --> (2,EDF) C40(CDE) (6) --> (5,C40) 25867 * (0,ASCII) EDF(AB) (4) --> (2,EDF) TEXT(CDE) (8) --> (5,TEXT) 25868 * (0,ASCII) EDF(AB) (4) --> (2,EDF) X12(CDE) (6) --> (5,X12) 25869 * (0,ASCII) EDF(AB) (4) --> (2,EDF) EDF(CDE) (7) --> (5,EDF) 25870 * (0,ASCII) EDF(AB) (4) --> (2,EDF) EDF(CDEF) (7) --> (6,EDF) 25871 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) 25872 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) B256(C) (5) --> (3,B256) 25873 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) EDF(CD) (6) --> (4,EDF) 25874 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) C40(CDE) (5) --> (5,C40) 25875 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) TEXT(CDE) (7) --> (5,TEXT) 25876 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) X12(CDE) (5) --> (5,X12) 25877 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) EDF(CDE) (6) --> (5,EDF) 25878 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) EDF(CDEF) (6) --> (6,EDF) 25879 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) ASCII(C) (4) --> (3,ASCII) 25880 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) B256(C) (4) --> (3,B256) 25881 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) EDF(CD) (6) --> (4,EDF) 25882 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) C40(CDE) (5) --> (5,C40) 25883 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) TEXT(CDE) (7) --> (5,TEXT) 25884 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) X12(CDE) (5) --> (5,X12) 25885 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) EDF(CDE) (6) --> (5,EDF) 25886 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) EDF(CDEF) (6) --> (6,EDF) 25887 * 25888 * Edge "(2,ASCII) ASCII(C) (3) --> (3,ASCII)" is minimal for the vertex (3,ASCII) so that edges "(2,EDF) ASCII(C) (5) --> (3,ASCII)" 25889 * and "(2,B256) ASCII(C) (4) --> (3,ASCII)" can be removed. 25890 * Edge "(0,ASCII) EDF(ABC) (4) --> (3,EDF)" is minimal for the vertex (3,EDF) so that edges "(1,ASCII) EDF(BC) (5) --> (3,EDF)" 25891 * and "(1,B256) EDF(BC) (6) --> (3,EDF)" can be removed. 25892 * Edge "(2,B256) B256(C) (4) --> (3,B256)" is minimal for the vertex (3,B256) so that edges "(2,ASCII) B256(C) (5) --> (3,B256)" 25893 * and "(2,EDF) B256(C) (6) --> (3,B256)" can be removed. 25894 * 25895 * This continues for vertices 3 thru 7 25896 * 25897 * Situation after adding edges to vertices at position 7 25898 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) 25899 * (0,ASCII) B256(A) (3) --> (1,B256) 25900 * (0,ASCII) EDF(AB) (4) --> (2,EDF) 25901 * (0,ASCII) C40(ABC) (3) --> (3,C40) 25902 * (0,ASCII) TEXT(ABC) (5) --> (3,TEXT) 25903 * (0,ASCII) X12(ABC) (3) --> (3,X12) 25904 * (0,ASCII) EDF(ABC) (4) --> (3,EDF) 25905 * (0,ASCII) EDF(ABCD) (4) --> (4,EDF) 25906 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) 25907 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) C40(BCD) (4) --> (4,C40) 25908 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) TEXT(BCD) (6) --> (4,TEXT) 25909 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) X12(BCD) (4) --> (4,X12) 25910 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BCDE) (5) --> (5,EDF) 25911 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) 25912 * (0,ASCII) C40(ABC) (3) --> (3,C40) C40(DEF) (5) --> (6,C40) 25913 * (0,ASCII) X12(ABC) (3) --> (3,X12) X12(DEF) (5) --> (6,X12) 25914 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) 25915 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) C40(CDE) (5) --> (5,C40) 25916 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) TEXT(CDE) (7) --> (5,TEXT) 25917 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) X12(CDE) (5) --> (5,X12) 25918 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) EDF(CDEF) (6) --> (6,EDF) 25919 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) C40(BCD) (4) --> (4,C40) C40(EFG) (6) --> (7,C40) //Solution 1 25920 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) X12(BCD) (4) --> (4,X12) X12(EFG) (6) --> (7,X12) //Solution 2 25921 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) B256(C) (4) --> (3,B256) 25922 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) ASCII(D) (4) --> (4,ASCII) 25923 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) TEXT(DEF) (8) --> (6,TEXT) 25924 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) EDF(DEFG) (7) --> (7,EDF) 25925 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) B256(C) (4) --> (3,B256) B256(D) (5) --> (4,B256) 25926 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) ASCII(D) (4) --> (4,ASCII) ASCII(E) (5) --> (5,ASCII) 25927 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) ASCII(D) (4) --> (4,ASCII) TEXT(EFG) (9) --> (7,TEXT) 25928 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) B256(C) (4) --> (3,B256) B256(D) (5) --> (4,B256) B256(E) (6) --> (5,B256) 25929 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) ASCII(D) (4) --> (4,ASCII) ASCII(E) (5) --> (5,ASCII) ASCII(F) (6) --> (6,ASCII) 25930 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) B256(C) (4) --> (3,B256) B256(D) (5) --> (4,B256) B256(E) (6) --> (5,B256) B256(F) (7) --> (6,B256) 25931 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) ASCII(D) (4) --> (4,ASCII) ASCII(E) (5) --> (5,ASCII) ASCII(F) (6) --> (6,ASCII) ASCII(G) (7) --> (7,ASCII) 25932 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) B256(C) (4) --> (3,B256) B256(D) (5) --> (4,B256) B256(E) (6) --> (5,B256) B256(F) (7) --> (6,B256) B256(G) (8) --> (7,B256) 25933 * 25934 * Hence a minimal encoding of "ABCDEFG" is either ASCII(A),C40(BCDEFG) or ASCII(A), X12(BCDEFG) with a size of 5 bytes. 25935 */ 25936 const inputLength = input.length(); 25937 // Array that represents vertices. There is a vertex for every character and mode. 25938 // The last dimension in the array below encodes the 6 modes ASCII, C40, TEXT, X12, EDF and B256 25939 const edges = Array(inputLength + 1) 25940 .fill(null) 25941 .map(() => Array(6).fill(0)); 25942 this.addEdges(input, edges, 0, null); 25943 for (let i = 1; i <= inputLength; i++) { 25944 for (let j = 0; j < 6; j++) { 25945 if (edges[i][j] !== null && i < inputLength) { 25946 this.addEdges(input, edges, i, edges[i][j]); 25947 } 25948 } 25949 // optimize memory by removing edges that have been passed. 25950 for (let j = 0; j < 6; j++) { 25951 edges[i - 1][j] = null; 25952 } 25953 } 25954 let minimalJ = -1; 25955 let minimalSize = Integer.MAX_VALUE; 25956 for (let j = 0; j < 6; j++) { 25957 if (edges[inputLength][j] !== null) { 25958 const edge = edges[inputLength][j]; 25959 const size = j >= 1 && j <= 3 ? edge.cachedTotalSize + 1 : edge.cachedTotalSize; // C40, TEXT and X12 need an 25960 // extra unlatch at the end 25961 if (size < minimalSize) { 25962 minimalSize = size; 25963 minimalJ = j; 25964 } 25965 } 25966 } 25967 if (minimalJ < 0) { 25968 throw new Error('Failed to encode "' + input + '"'); 25969 } 25970 return new Result(edges[inputLength][minimalJ]); 25971 } 25972 } 25973 class Result { 25974 constructor(solution) { 25975 const input = solution.input; 25976 let size = 0; 25977 let bytesAL = []; 25978 const randomizePostfixLength = []; 25979 const randomizeLengths = []; 25980 if ((solution.mode === Mode.C40 || 25981 solution.mode === Mode.TEXT || 25982 solution.mode === Mode.X12) && 25983 solution.getEndMode() !== Mode.ASCII) { 25984 size += this.prepend(Edge.getBytes(254), bytesAL); 25985 } 25986 let current = solution; 25987 while (current !== null) { 25988 size += this.prepend(current.getDataBytes(), bytesAL); 25989 if (current.previous === null || 25990 current.getPreviousStartMode() !== current.getMode()) { 25991 if (current.getMode() === Mode.B256) { 25992 if (size <= 249) { 25993 bytesAL.unshift(size); 25994 size++; 25995 } 25996 else { 25997 bytesAL.unshift(size % 250); 25998 bytesAL.unshift(size / 250 + 249); 25999 size += 2; 26000 } 26001 randomizePostfixLength.push(bytesAL.length); 26002 randomizeLengths.push(size); 26003 } 26004 this.prepend(current.getLatchBytes(), bytesAL); 26005 size = 0; 26006 } 26007 current = current.previous; 26008 } 26009 if (input.getMacroId() === 5) { 26010 size += this.prepend(Edge.getBytes(236), bytesAL); 26011 } 26012 else if (input.getMacroId() === 6) { 26013 size += this.prepend(Edge.getBytes(237), bytesAL); 26014 } 26015 if (input.getFNC1Character() > 0) { 26016 size += this.prepend(Edge.getBytes(232), bytesAL); 26017 } 26018 for (let i = 0; i < randomizePostfixLength.length; i++) { 26019 this.applyRandomPattern(bytesAL, bytesAL.length - randomizePostfixLength[i], randomizeLengths[i]); 26020 } 26021 // add padding 26022 const capacity = solution.getMinSymbolSize(bytesAL.length); 26023 if (bytesAL.length < capacity) { 26024 bytesAL.push(129); 26025 } 26026 while (bytesAL.length < capacity) { 26027 bytesAL.push(this.randomize253State(bytesAL.length + 1)); 26028 } 26029 this.bytes = new Uint8Array(bytesAL.length); 26030 for (let i = 0; i < this.bytes.length; i++) { 26031 this.bytes[i] = bytesAL[i]; 26032 } 26033 } 26034 prepend(bytes, into) { 26035 for (let i = bytes.length - 1; i >= 0; i--) { 26036 into.unshift(bytes[i]); 26037 } 26038 return bytes.length; 26039 } 26040 randomize253State(codewordPosition) { 26041 const pseudoRandom = ((149 * codewordPosition) % 253) + 1; 26042 const tempVariable = 129 + pseudoRandom; 26043 return tempVariable <= 254 ? tempVariable : tempVariable - 254; 26044 } 26045 applyRandomPattern(bytesAL, startPosition, length) { 26046 for (let i = 0; i < length; i++) { 26047 // See "B.1 253-state algorithm 26048 const Pad_codeword_position = startPosition + i; 26049 const Pad_codeword_value = bytesAL[Pad_codeword_position] & 0xff; 26050 const pseudo_random_number = ((149 * (Pad_codeword_position + 1)) % 255) + 1; 26051 const temp_variable = Pad_codeword_value + pseudo_random_number; 26052 bytesAL[Pad_codeword_position] = 26053 temp_variable <= 255 ? temp_variable : temp_variable - 256; 26054 } 26055 } 26056 getBytes() { 26057 return this.bytes; 26058 } 26059 } 26060 class Edge { 26061 constructor(input, mode, fromPosition, characterLength, previous) { 26062 this.input = input; 26063 this.mode = mode; 26064 this.fromPosition = fromPosition; 26065 this.characterLength = characterLength; 26066 this.previous = previous; 26067 this.allCodewordCapacities = [ 26068 3, 5, 8, 10, 12, 16, 18, 22, 30, 32, 36, 44, 49, 62, 86, 114, 144, 174, 204, 26069 280, 368, 456, 576, 696, 816, 1050, 1304, 1558, 26070 ]; 26071 this.squareCodewordCapacities = [ 26072 3, 5, 8, 12, 18, 22, 30, 36, 44, 62, 86, 114, 144, 174, 204, 280, 368, 456, 26073 576, 696, 816, 1050, 1304, 1558, 26074 ]; 26075 this.rectangularCodewordCapacities = [5, 10, 16, 33, 32, 49]; 26076 if (!(fromPosition + characterLength <= input.length())) { 26077 throw new Error('Invalid edge'); 26078 } 26079 let size = previous !== null ? previous.cachedTotalSize : 0; 26080 const previousMode = this.getPreviousMode(); 26081 /* 26082 * Switching modes 26083 * ASCII -> C40: latch 230 26084 * ASCII -> TEXT: latch 239 26085 * ASCII -> X12: latch 238 26086 * ASCII -> EDF: latch 240 26087 * ASCII -> B256: latch 231 26088 * C40 -> ASCII: word(c1,c2,c3), 254 26089 * TEXT -> ASCII: word(c1,c2,c3), 254 26090 * X12 -> ASCII: word(c1,c2,c3), 254 26091 * EDIFACT -> ASCII: Unlatch character,0,0,0 or c1,Unlatch character,0,0 or c1,c2,Unlatch character,0 or 26092 * c1,c2,c3,Unlatch character 26093 * B256 -> ASCII: without latch after n bytes 26094 */ 26095 switch (mode) { 26096 case Mode.ASCII: 26097 size++; 26098 if (input.isECI(fromPosition) || 26099 MinimalEncoder.isExtendedASCII(input.charAt(fromPosition), input.getFNC1Character())) { 26100 size++; 26101 } 26102 if (previousMode === Mode.C40 || 26103 previousMode === Mode.TEXT || 26104 previousMode === Mode.X12) { 26105 size++; // unlatch 254 to ASCII 26106 } 26107 break; 26108 case Mode.B256: 26109 size++; 26110 if (previousMode !== Mode.B256) { 26111 size++; // byte count 26112 } 26113 else if (this.getB256Size() === 250) { 26114 size++; // extra byte count 26115 } 26116 if (previousMode === Mode.ASCII) { 26117 size++; // latch to B256 26118 } 26119 else if (previousMode === Mode.C40 || 26120 previousMode === Mode.TEXT || 26121 previousMode === Mode.X12) { 26122 size += 2; // unlatch to ASCII, latch to B256 26123 } 26124 break; 26125 case Mode.C40: 26126 case Mode.TEXT: 26127 case Mode.X12: 26128 if (mode === Mode.X12) { 26129 size += 2; 26130 } 26131 else { 26132 let charLen = []; 26133 size += 26134 MinimalEncoder.getNumberOfC40Words(input, fromPosition, mode === Mode.C40, charLen) * 2; 26135 } 26136 if (previousMode === Mode.ASCII || previousMode === Mode.B256) { 26137 size++; // additional byte for latch from ASCII to this mode 26138 } 26139 else if (previousMode !== mode && 26140 (previousMode === Mode.C40 || 26141 previousMode === Mode.TEXT || 26142 previousMode === Mode.X12)) { 26143 size += 2; // unlatch 254 to ASCII followed by latch to this mode 26144 } 26145 break; 26146 case Mode.EDF: 26147 size += 3; 26148 if (previousMode === Mode.ASCII || previousMode === Mode.B256) { 26149 size++; // additional byte for latch from ASCII to this mode 26150 } 26151 else if (previousMode === Mode.C40 || 26152 previousMode === Mode.TEXT || 26153 previousMode === Mode.X12) { 26154 size += 2; // unlatch 254 to ASCII followed by latch to this mode 26155 } 26156 break; 26157 } 26158 this.cachedTotalSize = size; 26159 } 26160 // does not count beyond 250 26161 getB256Size() { 26162 let cnt = 0; 26163 let current = this; 26164 while (current !== null && current.mode === Mode.B256 && cnt <= 250) { 26165 cnt++; 26166 current = current.previous; 26167 } 26168 return cnt; 26169 } 26170 getPreviousStartMode() { 26171 return this.previous === null ? Mode.ASCII : this.previous.mode; 26172 } 26173 getPreviousMode() { 26174 return this.previous === null ? Mode.ASCII : this.previous.getEndMode(); 26175 } 26176 /** Returns Mode.ASCII in case that: 26177 * - Mode is EDIFACT and characterLength is less than 4 or the remaining characters can be encoded in at most 2 26178 * ASCII bytes. 26179 * - Mode is C40, TEXT or X12 and the remaining characters can be encoded in at most 1 ASCII byte. 26180 * Returns mode in all other cases. 26181 * */ 26182 getEndMode() { 26183 if (this.mode === Mode.EDF) { 26184 if (this.characterLength < 4) { 26185 return Mode.ASCII; 26186 } 26187 const lastASCII = this.getLastASCII(); // see 5.2.8.2 EDIFACT encodation Rules 26188 if (lastASCII > 0 && 26189 this.getCodewordsRemaining(this.cachedTotalSize + lastASCII) <= 26190 2 - lastASCII) { 26191 return Mode.ASCII; 26192 } 26193 } 26194 if (this.mode === Mode.C40 || 26195 this.mode === Mode.TEXT || 26196 this.mode === Mode.X12) { 26197 // see 5.2.5.2 C40 encodation rules and 5.2.7.2 ANSI X12 encodation rules 26198 if (this.fromPosition + this.characterLength >= this.input.length() && 26199 this.getCodewordsRemaining(this.cachedTotalSize) === 0) { 26200 return Mode.ASCII; 26201 } 26202 const lastASCII = this.getLastASCII(); 26203 if (lastASCII === 1 && 26204 this.getCodewordsRemaining(this.cachedTotalSize + 1) === 0) { 26205 return Mode.ASCII; 26206 } 26207 } 26208 return this.mode; 26209 } 26210 getMode() { 26211 return this.mode; 26212 } 26213 /** Peeks ahead and returns 1 if the postfix consists of exactly two digits, 2 if the postfix consists of exactly 26214 * two consecutive digits and a non extended character or of 4 digits. 26215 * Returns 0 in any other case 26216 **/ 26217 getLastASCII() { 26218 const length = this.input.length(); 26219 const from = this.fromPosition + this.characterLength; 26220 if (length - from > 4 || from >= length) { 26221 return 0; 26222 } 26223 if (length - from === 1) { 26224 if (MinimalEncoder.isExtendedASCII(this.input.charAt(from), this.input.getFNC1Character())) { 26225 return 0; 26226 } 26227 return 1; 26228 } 26229 if (length - from === 2) { 26230 if (MinimalEncoder.isExtendedASCII(this.input.charAt(from), this.input.getFNC1Character()) || 26231 MinimalEncoder.isExtendedASCII(this.input.charAt(from + 1), this.input.getFNC1Character())) { 26232 return 0; 26233 } 26234 if (HighLevelEncoder$1.isDigit(this.input.charAt(from)) && 26235 HighLevelEncoder$1.isDigit(this.input.charAt(from + 1))) { 26236 return 1; 26237 } 26238 return 2; 26239 } 26240 if (length - from === 3) { 26241 if (HighLevelEncoder$1.isDigit(this.input.charAt(from)) && 26242 HighLevelEncoder$1.isDigit(this.input.charAt(from + 1)) && 26243 !MinimalEncoder.isExtendedASCII(this.input.charAt(from + 2), this.input.getFNC1Character())) { 26244 return 2; 26245 } 26246 if (HighLevelEncoder$1.isDigit(this.input.charAt(from + 1)) && 26247 HighLevelEncoder$1.isDigit(this.input.charAt(from + 2)) && 26248 !MinimalEncoder.isExtendedASCII(this.input.charAt(from), this.input.getFNC1Character())) { 26249 return 2; 26250 } 26251 return 0; 26252 } 26253 if (HighLevelEncoder$1.isDigit(this.input.charAt(from)) && 26254 HighLevelEncoder$1.isDigit(this.input.charAt(from + 1)) && 26255 HighLevelEncoder$1.isDigit(this.input.charAt(from + 2)) && 26256 HighLevelEncoder$1.isDigit(this.input.charAt(from + 3))) { 26257 return 2; 26258 } 26259 return 0; 26260 } 26261 /** Returns the capacity in codewords of the smallest symbol that has enough capacity to fit the given minimal 26262 * number of codewords. 26263 **/ 26264 getMinSymbolSize(minimum) { 26265 switch (this.input.getShapeHint()) { 26266 case 1 /*
26266FORCE_SQUARE */: 26267 for (const capacity of this.squareCodewordCapacities) { 26268 if (capacity >= minimum) { 26269 return capacity; 26270 } 26271 } 26272 break; 26273 case 2 /*
vendor: 27,324 bytes, lines 26273-26947
26273FORCE_RECTANGLE */: 26274 for (const capacity of this.rectangularCodewordCapacities) { 26275 if (capacity >= minimum) { 26276 return capacity; 26277 } 26278 } 26279 break; 26280 } 26281 for (const capacity of this.allCodewordCapacities) { 26282 if (capacity >= minimum) { 26283 return capacity; 26284 } 26285 } 26286 return this.allCodewordCapacities[this.allCodewordCapacities.length - 1]; 26287 } 26288 /** Returns the remaining capacity in codewords of the smallest symbol that has enough capacity to fit the given 26289 * minimal number of codewords. 26290 **/ 26291 getCodewordsRemaining(minimum) { 26292 return this.getMinSymbolSize(minimum) - minimum; 26293 } 26294 static getBytes(c1, c2) { 26295 const result = new Uint8Array(c2 ? 2 : 1); 26296 result[0] = c1; 26297 if (c2) { 26298 result[1] = c2; 26299 } 26300 return result; 26301 } 26302 setC40Word(bytes, offset, c1, c2, c3) { 26303 const val16 = 1600 * (c1 & 0xff) + 40 * (c2 & 0xff) + (c3 & 0xff) + 1; 26304 bytes[offset] = val16 / 256; 26305 bytes[offset + 1] = val16 % 256; 26306 } 26307 getX12Value(c) { 26308 return c === 13 26309 ? 0 26310 : c === 42 26311 ? 1 26312 : c === 62 26313 ? 2 26314 : c === 32 26315 ? 3 26316 : c >= 48 && c <= 57 26317 ? c - 44 26318 : c >= 65 && c <= 90 26319 ? c - 51 26320 : c; 26321 } 26322 getX12Words() { 26323 if (!(this.characterLength % 3 === 0)) { 26324 throw new Error('X12 words must be a multiple of 3'); 26325 } 26326 const result = new Uint8Array((this.characterLength / 3) * 2); 26327 for (let i = 0; i < result.length; i += 2) { 26328 this.setC40Word(result, i, this.getX12Value(this.input.charAt(this.fromPosition + (i / 2) * 3)), this.getX12Value(this.input.charAt(this.fromPosition + (i / 2) * 3 + 1)), this.getX12Value(this.input.charAt(this.fromPosition + (i / 2) * 3 + 2))); 26329 } 26330 return result; 26331 } 26332 getShiftValue(c, c40, fnc1) { 26333 return (c40 && MinimalEncoder.isInC40Shift1Set(c)) || 26334 (!c40 && MinimalEncoder.isInTextShift1Set(c)) 26335 ? 0 26336 : (c40 && MinimalEncoder.isInC40Shift2Set(c, fnc1)) || 26337 (!c40 && MinimalEncoder.isInTextShift2Set(c, fnc1)) 26338 ? 1 26339 : 2; 26340 } 26341 getC40Value(c40, setIndex, c, fnc1) { 26342 if (c === fnc1) { 26343 if (!(setIndex === 2)) { 26344 throw new Error('FNC1 cannot be used in C40 shift 2'); 26345 } 26346 return 27; 26347 } 26348 if (c40) { 26349 return c <= 31 26350 ? c 26351 : c === 32 26352 ? 3 26353 : c <= 47 26354 ? c - 33 26355 : c <= 57 26356 ? c - 44 26357 : c <= 64 26358 ? c - 43 26359 : c <= 90 26360 ? c - 51 26361 : c <= 95 26362 ? c - 69 26363 : c <= 127 26364 ? c - 96 26365 : c; 26366 } 26367 else { 26368 return c === 0 26369 ? 0 26370 : setIndex === 0 && c <= 3 26371 ? c - 1 // is this a bug in the spec? 26372 : setIndex === 1 && c <= 31 26373 ? c 26374 : c === 32 26375 ? 3 26376 : c >= 33 && c <= 47 26377 ? c - 33 26378 : c >= 48 && c <= 57 26379 ? c - 44 26380 : c >= 58 && c <= 64 26381 ? c - 43 26382 : c >= 65 && c <= 90 26383 ? c - 64 26384 : c >= 91 && c <= 95 26385 ? c - 69 26386 : c === 96 26387 ? 0 26388 : c >= 97 && c <= 122 26389 ? c - 83 26390 : c >= 123 && c <= 127 26391 ? c - 96 26392 : c; 26393 } 26394 } 26395 getC40Words(c40, fnc1) { 26396 const c40Values = []; 26397 for (let i = 0; i < this.characterLength; i++) { 26398 const ci = this.input.charAt(this.fromPosition + i); 26399 if ((c40 && HighLevelEncoder$1.isNativeC40(ci)) || 26400 (!c40 && HighLevelEncoder$1.isNativeText(ci))) { 26401 c40Values.push(this.getC40Value(c40, 0, ci, fnc1)); 26402 } 26403 else if (!MinimalEncoder.isExtendedASCII(ci, fnc1)) { 26404 const shiftValue = this.getShiftValue(ci, c40, fnc1); 26405 c40Values.push(shiftValue); // Shift[123] 26406 c40Values.push(this.getC40Value(c40, shiftValue, ci, fnc1)); 26407 } 26408 else { 26409 const asciiValue = (ci & 0xff) - 128; 26410 if ((c40 && HighLevelEncoder$1.isNativeC40(asciiValue)) || 26411 (!c40 && HighLevelEncoder$1.isNativeText(asciiValue))) { 26412 c40Values.push(1); // Shift 2 26413 c40Values.push(30); // Upper Shift 26414 c40Values.push(this.getC40Value(c40, 0, asciiValue, fnc1)); 26415 } 26416 else { 26417 c40Values.push(1); // Shift 2 26418 c40Values.push(30); // Upper Shift 26419 const shiftValue = this.getShiftValue(asciiValue, c40, fnc1); 26420 c40Values.push(shiftValue); // Shift[123] 26421 c40Values.push(this.getC40Value(c40, shiftValue, asciiValue, fnc1)); 26422 } 26423 } 26424 } 26425 if (c40Values.length % 3 !== 0) { 26426 if (!((c40Values.length - 2) % 3 === 0 && 26427 this.fromPosition + this.characterLength === this.input.length())) { 26428 throw new Error('C40 words must be a multiple of 3'); 26429 } 26430 c40Values.push(0); // pad with 0 (Shift 1) 26431 } 26432 const result = new Uint8Array((c40Values.length / 3) * 2); 26433 let byteIndex = 0; 26434 for (let i = 0; i < c40Values.length; i += 3) { 26435 this.setC40Word(result, byteIndex, c40Values[i] & 0xff, c40Values[i + 1] & 0xff, c40Values[i + 2] & 0xff); 26436 byteIndex += 2; 26437 } 26438 return result; 26439 } 26440 getEDFBytes() { 26441 const numberOfThirds = Math.ceil(this.characterLength / 4.0); 26442 const result = new Uint8Array(numberOfThirds * 3); 26443 let pos = this.fromPosition; 26444 const endPos = Math.min(this.fromPosition + this.characterLength - 1, this.input.length() - 1); 26445 for (let i = 0; i < numberOfThirds; i += 3) { 26446 const edfValues = []; 26447 for (let j = 0; j < 4; j++) { 26448 if (pos <= endPos) { 26449 edfValues[j] = this.input.charAt(pos++) & 0x3f; 26450 } 26451 else { 26452 edfValues[j] = pos === endPos + 1 ? 0x1f : 0; 26453 } 26454 } 26455 let val24 = edfValues[0] << 18; 26456 val24 |= edfValues[1] << 12; 26457 val24 |= edfValues[2] << 6; 26458 val24 |= edfValues[3]; 26459 result[i] = (val24 >> 16) & 0xff; 26460 result[i + 1] = (val24 >> 8) & 0xff; 26461 result[i + 2] = val24 & 0xff; 26462 } 26463 return result; 26464 } 26465 getLatchBytes() { 26466 switch (this.getPreviousMode()) { 26467 case Mode.ASCII: 26468 case Mode.B256: // after B256 ends (via length) we are back to ASCII 26469 switch (this.mode) { 26470 case Mode.B256: 26471 return Edge.getBytes(231); 26472 case Mode.C40: 26473 return Edge.getBytes(230); 26474 case Mode.TEXT: 26475 return Edge.getBytes(239); 26476 case Mode.X12: 26477 return Edge.getBytes(238); 26478 case Mode.EDF: 26479 return Edge.getBytes(240); 26480 } 26481 break; 26482 case Mode.C40: 26483 case Mode.TEXT: 26484 case Mode.X12: 26485 if (this.mode !== this.getPreviousMode()) { 26486 switch (this.mode) { 26487 case Mode.ASCII: 26488 return Edge.getBytes(254); 26489 case Mode.B256: 26490 return Edge.getBytes(254, 231); 26491 case Mode.C40: 26492 return Edge.getBytes(254, 230); 26493 case Mode.TEXT: 26494 return Edge.getBytes(254, 239); 26495 case Mode.X12: 26496 return Edge.getBytes(254, 238); 26497 case Mode.EDF: 26498 return Edge.getBytes(254, 240); 26499 } 26500 } 26501 break; 26502 case Mode.EDF: 26503 // The rightmost EDIFACT edge always contains an unlatch character 26504 if (this.mode !== Mode.EDF) { 26505 throw new Error('Cannot switch from EDF to ' + this.mode); 26506 } 26507 break; 26508 } 26509 return new Uint8Array(0); 26510 } 26511 // Important: The function does not return the length bytes (one or two) in case of B256 encoding 26512 getDataBytes() { 26513 switch (this.mode) { 26514 case Mode.ASCII: 26515 if (this.input.isECI(this.fromPosition)) { 26516 return Edge.getBytes(241, this.input.getECIValue(this.fromPosition) + 1); 26517 } 26518 else if (MinimalEncoder.isExtendedASCII(this.input.charAt(this.fromPosition), this.input.getFNC1Character())) { 26519 return Edge.getBytes(235, this.input.charAt(this.fromPosition) - 127); 26520 } 26521 else if (this.characterLength === 2) { 26522 return Edge.getBytes(this.input.charAt(this.fromPosition) * 10 + 26523 this.input.charAt(this.fromPosition + 1) + 26524 130); 26525 } 26526 else if (this.input.isFNC1(this.fromPosition)) { 26527 return Edge.getBytes(232); 26528 } 26529 else { 26530 return Edge.getBytes(this.input.charAt(this.fromPosition) + 1); 26531 } 26532 case Mode.B256: 26533 return Edge.getBytes(this.input.charAt(this.fromPosition)); 26534 case Mode.C40: 26535 return this.getC40Words(true, this.input.getFNC1Character()); 26536 case Mode.TEXT: 26537 return this.getC40Words(false, this.input.getFNC1Character()); 26538 case Mode.X12: 26539 return this.getX12Words(); 26540 case Mode.EDF: 26541 return this.getEDFBytes(); 26542 } 26543 } 26544 } 26545 class Input extends MinimalECIInput { 26546 constructor(stringToEncode, priorityCharset, fnc1, shape, macroId) { 26547 super(stringToEncode, priorityCharset, fnc1); 26548 this.shape = shape; 26549 this.macroId = macroId; 26550 } 26551 getMacroId() { 26552 return this.macroId; 26553 } 26554 getShapeHint() { 26555 return this.shape; 26556 } 26557 } 26558 26559 class DataMatrixWriter { 26560 encode(contents, format, width, height, hints = null) { 26561 if (contents.trim() === '') { 26562 throw new Error('Found empty contents'); 26563 } 26564 if (format !== BarcodeFormat$1.DATA_MATRIX) { 26565 throw new Error('Can only encode DATA_MATRIX, but got ' + format); 26566 } 26567 if (width < 0 || height < 0) { 26568 throw new Error('Requested dimensions can\'t be negative: ' + width + 'x' + height); 26569 } 26570 // Try to get force shape & min / max size 26571 let shape = 0 /* FORCE_NONE */; 26572 let minSize = null; 26573 let maxSize = null; 26574 if (hints != null) { 26575 const requestedShape = hints.get(EncodeHintType$1.DATA_MATRIX_SHAPE); 26576 if (requestedShape != null) { 26577 shape = requestedShape; 26578 } 26579 const requestedMinSize = hints.get(EncodeHintType$1.MIN_SIZE); 26580 if (requestedMinSize != null) { 26581 minSize = requestedMinSize; 26582 } 26583 const requestedMaxSize = hints.get(EncodeHintType$1.MAX_SIZE); 26584 if (requestedMaxSize != null) { 26585 maxSize = requestedMaxSize; 26586 } 26587 } 26588 // 1. step: Data encodation 26589 let encoded; 26590 const hasCompactionHint = hints != null && 26591 hints.has(EncodeHintType$1.DATA_MATRIX_COMPACT) && 26592 Boolean(hints.get(EncodeHintType$1.DATA_MATRIX_COMPACT).toString()); 26593 if (hasCompactionHint) { 26594 const hasGS1FormatHint = hints.has(EncodeHintType$1.GS1_FORMAT) && 26595 Boolean(hints.get(EncodeHintType$1.GS1_FORMAT).toString()); 26596 let charset = null; 26597 const hasEncodingHint = hints.has(EncodeHintType$1.CHARACTER_SET); 26598 if (hasEncodingHint) { 26599 charset = Charset.forName(hints.get(EncodeHintType$1.CHARACTER_SET).toString()); 26600 } 26601 encoded = MinimalEncoder.encodeHighLevel(contents, charset, hasGS1FormatHint ? 0x1d : -1, shape); 26602 } 26603 else { 26604 const hasForceC40Hint = hints != null && 26605 hints.has(EncodeHintType$1.FORCE_C40) && 26606 Boolean(hints.get(EncodeHintType$1.FORCE_C40).toString()); 26607 encoded = HighLevelEncoder$1.encodeHighLevel(contents, shape, minSize, maxSize, hasForceC40Hint); 26608 } 26609 const symbolInfo = SymbolInfo.lookup(encoded.length, shape, minSize, maxSize, true); 26610 // 2. step: ECC generation 26611 const codewords = ErrorCorrection.encodeECC200(encoded, symbolInfo); 26612 // 3. step: Module placement in Matrix 26613 const placement = new DefaultPlacement(codewords, symbolInfo.getSymbolDataWidth(), symbolInfo.getSymbolDataHeight()); 26614 placement.place(); 26615 // 4. step: low-level encoding 26616 return this.encodeLowLevel(placement, symbolInfo, width, height); 26617 } 26618 /** 26619 * Encode the given symbol info to a bit matrix. 26620 * 26621 * @param placement The DataMatrix placement. 26622 * @param symbolInfo The symbol info to encode. 26623 * @return The bit matrix generated. 26624 */ 26625 encodeLowLevel(placement, symbolInfo, width, height) { 26626 const symbolWidth = symbolInfo.getSymbolDataWidth(); 26627 const symbolHeight = symbolInfo.getSymbolDataHeight(); 26628 const matrix = new ByteMatrix(symbolInfo.getSymbolWidth(), symbolInfo.getSymbolHeight()); 26629 let matrixY = 0; 26630 for (let y = 0; y < symbolHeight; y++) { 26631 // Fill the top edge with alternate 0 / 1 26632 let matrixX; 26633 if (y % symbolInfo.matrixHeight === 0) { 26634 matrixX = 0; 26635 for (let x = 0; x < symbolInfo.getSymbolWidth(); x++) { 26636 matrix.setBoolean(matrixX, matrixY, x % 2 === 0); 26637 matrixX++; 26638 } 26639 matrixY++; 26640 } 26641 matrixX = 0; 26642 for (let x = 0; x < symbolWidth; x++) { 26643 // Fill the right edge with full 1 26644 if (x % symbolInfo.matrixWidth === 0) { 26645 matrix.setBoolean(matrixX, matrixY, true); 26646 matrixX++; 26647 } 26648 matrix.setBoolean(matrixX, matrixY, placement.getBit(x, y)); 26649 matrixX++; 26650 // Fill the right edge with alternate 0 / 1 26651 if (x % symbolInfo.matrixWidth === symbolInfo.matrixWidth - 1) { 26652 matrix.setBoolean(matrixX, matrixY, y % 2 === 0); 26653 matrixX++; 26654 } 26655 } 26656 matrixY++; 26657 // Fill the bottom edge with full 1 26658 if (y % symbolInfo.matrixHeight === symbolInfo.matrixHeight - 1) { 26659 matrixX = 0; 26660 for (let x = 0; x < symbolInfo.getSymbolWidth(); x++) { 26661 matrix.setBoolean(matrixX, matrixY, true); 26662 matrixX++; 26663 } 26664 matrixY++; 26665 } 26666 } 26667 return this.convertByteMatrixToBitMatrix(matrix, width, height); 26668 } 26669 /** 26670 * Convert the ByteMatrix to BitMatrix. 26671 * 26672 * @param reqHeight The requested height of the image (in pixels) with the Datamatrix code 26673 * @param reqWidth The requested width of the image (in pixels) with the Datamatrix code 26674 * @param matrix The input matrix. 26675 * @return The output matrix. 26676 */ 26677 convertByteMatrixToBitMatrix(matrix, reqWidth, reqHeight) { 26678 const matrixWidth = matrix.getWidth(); 26679 const matrixHeight = matrix.getHeight(); 26680 const outputWidth = Math.max(reqWidth, matrixWidth); 26681 const outputHeight = Math.max(reqHeight, matrixHeight); 26682 const multiple = Math.min(outputWidth / matrixWidth, outputHeight / matrixHeight); 26683 let leftPadding = (outputWidth - matrixWidth * multiple) / 2; 26684 let topPadding = (outputHeight - matrixHeight * multiple) / 2; 26685 let output; 26686 // remove padding if requested width and height are too small 26687 if (reqHeight < matrixHeight || reqWidth < matrixWidth) { 26688 leftPadding = 0; 26689 topPadding = 0; 26690 output = new BitMatrix(matrixWidth, matrixHeight); 26691 } 26692 else { 26693 output = new BitMatrix(reqWidth, reqHeight); 26694 } 26695 output.clear(); 26696 for (let inputY = 0, outputY = topPadding; inputY < matrixHeight; inputY++, outputY += multiple) { 26697 // Write the contents of this row of the bytematrix 26698 for (let inputX = 0, outputX = leftPadding; inputX < matrixWidth; inputX++, outputX += multiple) { 26699 if (matrix.get(inputX, inputY) === 1) { 26700 output.setRegion(outputX, outputY, multiple, multiple); 26701 } 26702 } 26703 } 26704 return output; 26705 } 26706 } 26707 26708 /* 26709 * Copyright 2013 ZXing authors 26710 * 26711 * Licensed under the Apache License, Version 2.0 (the "License"); 26712 * you may not use this file except in compliance with the License. 26713 * You may obtain a copy of the License at 26714 * 26715 * http://www.apache.org/licenses/LICENSE-2.0 26716 * 26717 * Unless required by applicable law or agreed to in writing, software 26718 * distributed under the License is distributed on an "AS IS" BASIS, 26719 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 26720 * See the License for the specific language governing permissions and 26721 * limitations under the License. 26722 */ 26723 /** 26724 * Aztec 2D code representation 26725 * 26726 * @author Rustam Abdullaev 26727 */ 26728 /*public final*/ class AztecCode { 26729 /** 26730 * @return {@code true} if compact instead of full mode 26731 */ 26732 isCompact() { 26733 return this.compact; 26734 } 26735 setCompact(compact) { 26736 this.compact = compact; 26737 } 26738 /** 26739 * @return size in pixels (width and height) 26740 */ 26741 getSize() { 26742 return this.size; 26743 } 26744 setSize(size) { 26745 this.size = size; 26746 } 26747 /** 26748 * @return number of levels 26749 */ 26750 getLayers() { 26751 return this.layers; 26752 } 26753 setLayers(layers) { 26754 this.layers = layers; 26755 } 26756 /** 26757 * @return number of data codewords 26758 */ 26759 getCodeWords() { 26760 return this.codeWords; 26761 } 26762 setCodeWords(codeWords) { 26763 this.codeWords = codeWords; 26764 } 26765 /** 26766 * @return the symbol image 26767 */ 26768 getMatrix() { 26769 return this.matrix; 26770 } 26771 setMatrix(matrix) { 26772 this.matrix = matrix; 26773 } 26774 } 26775 26776 class Collections { 26777 /** 26778 * The singletonList(T) method is used to return an immutable list containing only the specified object. 26779 */ 26780 static singletonList(item) { 26781 return [item]; 26782 } 26783 /** 26784 * The min(Collection<? extends T>, Comparator<? super T>) method is used to return the minimum element of the given collection, according to the order induced by the specified comparator. 26785 */ 26786 static min(collection, comparator) { 26787 return collection.sort(comparator)[0]; 26788 } 26789 } 26790 26791 /* 26792 * Copyright 2013 ZXing authors 26793 * 26794 * Licensed under the Apache License, Version 2.0 (the "License"); 26795 * you may not use this file except in compliance with the License. 26796 * You may obtain a copy of the License at 26797 * 26798 * http://www.apache.org/licenses/LICENSE-2.0 26799 * 26800 * Unless required by applicable law or agreed to in writing, software 26801 * distributed under the License is distributed on an "AS IS" BASIS, 26802 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 26803 * See the License for the specific language governing permissions and 26804 * limitations under the License. 26805 */ 26806 class Token { 26807 constructor(previous) { 26808 this.previous = previous; 26809 } 26810 getPrevious() { 26811 return this.previous; 26812 } 26813 } 26814 26815 /* 26816 * Copyright 2013 ZXing authors 26817 * 26818 * Licensed under the Apache License, Version 2.0 (the "License"); 26819 * you may not use this file except in compliance with the License. 26820 * You may obtain a copy of the License at 26821 * 26822 * http://www.apache.org/licenses/LICENSE-2.0 26823 * 26824 * Unless required by applicable law or agreed to in writing, software 26825 * distributed under the License is distributed on an "AS IS" BASIS, 26826 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 26827 * See the License for the specific language governing permissions and 26828 * limitations under the License. 26829 */ 26830 /*final*/ class SimpleToken extends Token { 26831 constructor(previous, value, bitCount) { 26832 super(previous); 26833 this.value = value; 26834 this.bitCount = bitCount; 26835 } 26836 /** 26837 * @Override 26838 */ 26839 appendTo(bitArray, text) { 26840 bitArray.appendBits(this.value, this.bitCount); 26841 } 26842 add(value, bitCount) { 26843 return new SimpleToken(this, value, bitCount); 26844 } 26845 addBinaryShift(start, byteCount) { 26846 // no-op can't binary shift a simple token 26847 console.warn('addBinaryShift on SimpleToken, this simply returns a copy of this token'); 26848 return new SimpleToken(this, start, byteCount); 26849 } 26850 /** 26851 * @Override 26852 */ 26853 toString() { 26854 let value = this.value & ((1 << this.bitCount) - 1); 26855 value |= 1 << this.bitCount; 26856 return '<' + Integer.toBinaryString(value | (1 << this.bitCount)).substring(1) + '>'; 26857 } 26858 } 26859 26860 /* 26861 * Copyright 2013 ZXing authors 26862 * 26863 * Licensed under the Apache License, Version 2.0 (the "License"); 26864 * you may not use this file except in compliance with the License. 26865 * You may obtain a copy of the License at 26866 * 26867 * http://www.apache.org/licenses/LICENSE-2.0 26868 * 26869 * Unless required by applicable law or agreed to in writing, software 26870 * distributed under the License is distributed on an "AS IS" BASIS, 26871 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 26872 * See the License for the specific language governing permissions and 26873 * limitations under the License. 26874 */ 26875 /*final*/ class BinaryShiftToken extends SimpleToken { 26876 constructor(previous, binaryShiftStart, binaryShiftByteCount) { 26877 super(previous, 0, 0); 26878 this.binaryShiftStart = binaryShiftStart; 26879 this.binaryShiftByteCount = binaryShiftByteCount; 26880 } 26881 /** 26882 * @Override 26883 */ 26884 appendTo(bitArray, text) { 26885 for (let i = 0; i < this.binaryShiftByteCount; i++) { 26886 if (i === 0 || (i === 31 && this.binaryShiftByteCount <= 62)) { 26887 // We need a header before the first character, and before 26888 // character 31 when the total byte code is <= 62 26889 bitArray.appendBits(31, 5); // BINARY_SHIFT 26890 if (this.binaryShiftByteCount > 62) { 26891 bitArray.appendBits(this.binaryShiftByteCount - 31, 16); 26892 } 26893 else if (i === 0) { 26894 // 1 <= binaryShiftByteCode <= 62 26895 bitArray.appendBits(Math.min(this.binaryShiftByteCount, 31), 5); 26896 } 26897 else { 26898 // 32 <= binaryShiftCount <= 62 and i == 31 26899 bitArray.appendBits(this.binaryShiftByteCount - 31, 5); 26900 } 26901 } 26902 bitArray.appendBits(text[this.binaryShiftStart + i], 8); 26903 } 26904 } 26905 addBinaryShift(start, byteCount) { 26906 // int bitCount = (byteCount * 8) + (byteCount <= 31 ? 10 : byteCount <= 62 ? 20 : 21); 26907 return new BinaryShiftToken(this, start, byteCount); 26908 } 26909 /** 26910 * @Override 26911 */ 26912 toString() { 26913 return '<' + this.binaryShiftStart + '::' + (this.binaryShiftStart + this.binaryShiftByteCount - 1) + '>'; 26914 } 26915 } 26916 26917 function addBinaryShift(token, start, byteCount) { 26918 // int bitCount = (byteCount * 8) + (byteCount <= 31 ? 10 : byteCount <= 62 ? 20 : 21); 26919 return new BinaryShiftToken(token, start, byteCount); 26920 } 26921 function add(token, value, bitCount) { 26922 return new SimpleToken(token, value, bitCount); 26923 } 26924 26925 const /*final*/ MODE_NAMES = [ 26926 'UPPER', 26927 'LOWER', 26928 'DIGIT', 26929 'MIXED', 26930 'PUNCT' 26931 ]; 26932 const /*final*/ MODE_UPPER = 0; // 5 bits 26933 const /*final*/ MODE_LOWER = 1; // 5 bits 26934 const /*final*/ MODE_DIGIT = 2; // 4 bits 26935 const /*final*/ MODE_MIXED = 3; // 5 bits 26936 const /*final*/ MODE_PUNCT = 4; // 5 bits 26937 const EMPTY_TOKEN = new SimpleToken(null, 0, 0); 26938 26939 // The Latch Table shows, for each pair of Modes, the optimal method for 26940 // getting from one mode to another. In the worst possible case, this can 26941 // be up to 14 bits. In the best possible case, we are already there! 26942 // The high half-word of each entry gives the number of bits. 26943 // The low half-word of each entry are the actual bits necessary to change 26944 const LATCH_TABLE = [ 26945 Int32Array.from([ 26946 0, 26947 (5 << 16) + 28,
vendor: 18,945 bytes, lines 26947-27422
26947 26948 (5 << 16) + 30, 26949 (5 << 16) + 29, 26950 (10 << 16) + (29 << 5) + 30 // UPPER -> MIXED -> PUNCT 26951 ]), 26952 Int32Array.from([ 26953 (9 << 16) + (30 << 4) + 14, 26954 0, 26955 (5 << 16) + 30, 26956 (5 << 16) + 29, 26957 (10 << 16) + (29 << 5) + 30 // LOWER -> MIXED -> PUNCT 26958 ]), 26959 Int32Array.from([ 26960 (4 << 16) + 14, 26961 (9 << 16) + (14 << 5) + 28, 26962 0, 26963 (9 << 16) + (14 << 5) + 29, 26964 (14 << 16) + (14 << 10) + (29 << 5) + 30 26965 // DIGIT -> UPPER -> MIXED -> PUNCT 26966 ]), 26967 Int32Array.from([ 26968 (5 << 16) + 29, 26969 (5 << 16) + 28, 26970 (10 << 16) + (29 << 5) + 30, 26971 0, 26972 (5 << 16) + 30 // MIXED -> PUNCT 26973 ]), 26974 Int32Array.from([ 26975 (5 << 16) + 31, 26976 (10 << 16) + (31 << 5) + 28, 26977 (10 << 16) + (31 << 5) + 30, 26978 (10 << 16) + (31 << 5) + 29, 26979 0 26980 ]) 26981 ]; 26982 26983 function static_SHIFT_TABLE(SHIFT_TABLE) { 26984 for (let table /*Int32Array*/ of SHIFT_TABLE) { 26985 Arrays.fill(table, -1); 26986 } 26987 SHIFT_TABLE[MODE_UPPER][MODE_PUNCT] = 0; 26988 SHIFT_TABLE[MODE_LOWER][MODE_PUNCT] = 0; 26989 SHIFT_TABLE[MODE_LOWER][MODE_UPPER] = 28; 26990 SHIFT_TABLE[MODE_MIXED][MODE_PUNCT] = 0; 26991 SHIFT_TABLE[MODE_DIGIT][MODE_PUNCT] = 0; 26992 SHIFT_TABLE[MODE_DIGIT][MODE_UPPER] = 15; 26993 return SHIFT_TABLE; 26994 } 26995 const /*final*/ SHIFT_TABLE = static_SHIFT_TABLE(Arrays.createInt32Array(6, 6)); // mode shift codes, per table 26996 26997 /* 26998 * Copyright 2013 ZXing authors 26999 * 27000 * Licensed under the Apache License, Version 2.0 (the "License"); 27001 * you may not use this file except in compliance with the License. 27002 * You may obtain a copy of the License at 27003 * 27004 * http://www.apache.org/licenses/LICENSE-2.0 27005 * 27006 * Unless required by applicable law or agreed to in writing, software 27007 * distributed under the License is distributed on an "AS IS" BASIS, 27008 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 27009 * See the License for the specific language governing permissions and 27010 * limitations under the License. 27011 */ 27012 /** 27013 * State represents all information about a sequence necessary to generate the current output. 27014 * Note that a state is immutable. 27015 */ 27016 /*final*/ class State { 27017 constructor(token, mode, binaryBytes, bitCount) { 27018 this.token = token; 27019 this.mode = mode; 27020 this.binaryShiftByteCount = binaryBytes; 27021 this.bitCount = bitCount; 27022 // Make sure we match the token 27023 // int binaryShiftBitCount = (binaryShiftByteCount * 8) + 27024 // (binaryShiftByteCount === 0 ? 0 : 27025 // binaryShiftByteCount <= 31 ? 10 : 27026 // binaryShiftByteCount <= 62 ? 20 : 21); 27027 // assert this.bitCount === token.getTotalBitCount() + binaryShiftBitCount; 27028 } 27029 getMode() { 27030 return this.mode; 27031 } 27032 getToken() { 27033 return this.token; 27034 } 27035 getBinaryShiftByteCount() { 27036 return this.binaryShiftByteCount; 27037 } 27038 getBitCount() { 27039 return this.bitCount; 27040 } 27041 // Create a new state representing this state with a latch to a (not 27042 // necessary different) mode, and then a code. 27043 latchAndAppend(mode, value) { 27044 // assert binaryShiftByteCount === 0; 27045 let bitCount = this.bitCount; 27046 let token = this.token; 27047 if (mode !== this.mode) { 27048 let latch = LATCH_TABLE[this.mode][mode]; 27049 token = add(token, latch & 0xffff, latch >> 16); 27050 bitCount += latch >> 16; 27051 } 27052 let latchModeBitCount = mode === MODE_DIGIT ? 4 : 5; 27053 token = add(token, value, latchModeBitCount); 27054 return new State(token, mode, 0, bitCount + latchModeBitCount); 27055 } 27056 // Create a new state representing this state, with a temporary shift 27057 // to a different mode to output a single value. 27058 shiftAndAppend(mode, value) { 27059 // assert binaryShiftByteCount === 0 && this.mode !== mode; 27060 let token = this.token; 27061 let thisModeBitCount = this.mode === MODE_DIGIT ? 4 : 5; 27062 // Shifts exist only to UPPER and PUNCT, both with tokens size 5. 27063 token = add(token, SHIFT_TABLE[this.mode][mode], thisModeBitCount); 27064 token = add(token, value, 5); 27065 return new State(token, this.mode, 0, this.bitCount + thisModeBitCount + 5); 27066 } 27067 // Create a new state representing this state, but an additional character 27068 // output in Binary Shift mode. 27069 addBinaryShiftChar(index) { 27070 let token = this.token; 27071 let mode = this.mode; 27072 let bitCount = this.bitCount; 27073 if (this.mode === MODE_PUNCT || this.mode === MODE_DIGIT) { 27074 // assert binaryShiftByteCount === 0; 27075 let latch = LATCH_TABLE[mode][MODE_UPPER]; 27076 token = add(token, latch & 0xffff, latch >> 16); 27077 bitCount += latch >> 16; 27078 mode = MODE_UPPER; 27079 } 27080 let deltaBitCount = this.binaryShiftByteCount === 0 || this.binaryShiftByteCount === 31 27081 ? 18 27082 : this.binaryShiftByteCount === 62 27083 ? 9 27084 : 8; 27085 let result = new State(token, mode, this.binaryShiftByteCount + 1, bitCount + deltaBitCount); 27086 if (result.binaryShiftByteCount === 2047 + 31) { 27087 // The string is as long as it's allowed to be. We should end it. 27088 result = result.endBinaryShift(index + 1); 27089 } 27090 return result; 27091 } 27092 // Create the state identical to this one, but we are no longer in 27093 // Binary Shift mode. 27094 endBinaryShift(index) { 27095 if (this.binaryShiftByteCount === 0) { 27096 return this; 27097 } 27098 let token = this.token; 27099 token = addBinaryShift(token, index - this.binaryShiftByteCount, this.binaryShiftByteCount); 27100 // assert token.getTotalBitCount() === this.bitCount; 27101 return new State(token, this.mode, 0, this.bitCount); 27102 } 27103 // Returns true if "this" state is better (equal: or) to be in than "that" 27104 // state under all possible circumstances. 27105 isBetterThanOrEqualTo(other) { 27106 let newModeBitCount = this.bitCount + (LATCH_TABLE[this.mode][other.mode] >> 16); 27107 if (this.binaryShiftByteCount < other.binaryShiftByteCount) { 27108 // add additional B/S encoding cost of other, if any 27109 newModeBitCount += 27110 State.calculateBinaryShiftCost(other) - 27111 State.calculateBinaryShiftCost(this); 27112 } 27113 else if (this.binaryShiftByteCount > other.binaryShiftByteCount && 27114 other.binaryShiftByteCount > 0) { 27115 // maximum possible additional cost (it: h) 27116 newModeBitCount += 10; 27117 } 27118 return newModeBitCount <= other.bitCount; 27119 } 27120 toBitArray(text) { 27121 // Reverse the tokens, so that they are in the order that they should 27122 // be output 27123 let symbols = []; 27124 for (let token = this.endBinaryShift(text.length).token; token !== null; token = token.getPrevious()) { 27125 symbols.unshift(token); 27126 } 27127 let bitArray = new BitArray(); 27128 // Add each token to the result. 27129 for (const symbol of symbols) { 27130 symbol.appendTo(bitArray, text); 27131 } 27132 // assert bitArray.getSize() === this.bitCount; 27133 return bitArray; 27134 } 27135 /** 27136 * @Override 27137 */ 27138 toString() { 27139 return StringUtils.format('%s bits=%d bytes=%d', MODE_NAMES[this.mode], this.bitCount, this.binaryShiftByteCount); 27140 } 27141 static calculateBinaryShiftCost(state) { 27142 if (state.binaryShiftByteCount > 62) { 27143 return 21; // B/S with extended length 27144 } 27145 if (state.binaryShiftByteCount > 31) { 27146 return 20; // two B/S 27147 } 27148 if (state.binaryShiftByteCount > 0) { 27149 return 10; // one B/S 27150 } 27151 return 0; 27152 } 27153 } 27154 State.INITIAL_STATE = new State(EMPTY_TOKEN, MODE_UPPER, 0, 0); 27155 27156 function static_CHAR_MAP(CHAR_MAP) { 27157 const spaceCharCode = StringUtils.getCharCode(' '); 27158 const pointCharCode = StringUtils.getCharCode('.'); 27159 const commaCharCode = StringUtils.getCharCode(','); 27160 CHAR_MAP[MODE_UPPER][spaceCharCode] = 1; 27161 const zUpperCharCode = StringUtils.getCharCode('Z'); 27162 const aUpperCharCode = StringUtils.getCharCode('A'); 27163 for (let c = aUpperCharCode; c <= zUpperCharCode; c++) { 27164 CHAR_MAP[MODE_UPPER][c] = c - aUpperCharCode + 2; 27165 } 27166 CHAR_MAP[MODE_LOWER][spaceCharCode] = 1; 27167 const zLowerCharCode = StringUtils.getCharCode('z'); 27168 const aLowerCharCode = StringUtils.getCharCode('a'); 27169 for (let c = aLowerCharCode; c <= zLowerCharCode; c++) { 27170 CHAR_MAP[MODE_LOWER][c] = c - aLowerCharCode + 2; 27171 } 27172 CHAR_MAP[MODE_DIGIT][spaceCharCode] = 1; 27173 const nineCharCode = StringUtils.getCharCode('9'); 27174 const zeroCharCode = StringUtils.getCharCode('0'); 27175 for (let c = zeroCharCode; c <= nineCharCode; c++) { 27176 CHAR_MAP[MODE_DIGIT][c] = c - zeroCharCode + 2; 27177 } 27178 CHAR_MAP[MODE_DIGIT][commaCharCode] = 12; 27179 CHAR_MAP[MODE_DIGIT][pointCharCode] = 13; 27180 const mixedTable = [ 27181 '\x00', 27182 ' ', 27183 '\x01', 27184 '\x02', 27185 '\x03', 27186 '\x04', 27187 '\x05', 27188 '\x06', 27189 '\x07', 27190 '\b', 27191 '\t', 27192 '\n', 27193 '\x0b', 27194 '\f', 27195 '\r', 27196 '\x1b', 27197 '\x1c', 27198 '\x1d', 27199 '\x1e', 27200 '\x1f', 27201 '@', 27202 '\\', 27203 '^', 27204 '_', 27205 '`', 27206 '|', 27207 '~', 27208 '\x7f' 27209 ]; 27210 for (let i = 0; i < mixedTable.length; i++) { 27211 CHAR_MAP[MODE_MIXED][StringUtils.getCharCode(mixedTable[i])] = i; 27212 } 27213 const punctTable = [ 27214 '\x00', 27215 '\r', 27216 '\x00', 27217 '\x00', 27218 '\x00', 27219 '\x00', 27220 '!', 27221 '\'', 27222 '#', 27223 '$', 27224 '%', 27225 '&', 27226 '\'', 27227 '(', 27228 ')', 27229 '*', 27230 '+', 27231 ',', 27232 '-', 27233 '.', 27234 '/', 27235 ':', 27236 ';', 27237 '<', 27238 '=', 27239 '>', 27240 '?', 27241 '[', 27242 ']', 27243 '{', 27244 '}' 27245 ]; 27246 for (let i = 0; i < punctTable.length; i++) { 27247 if (StringUtils.getCharCode(punctTable[i]) > 0) { 27248 CHAR_MAP[MODE_PUNCT][StringUtils.getCharCode(punctTable[i])] = i; 27249 } 27250 } 27251 return CHAR_MAP; 27252 } 27253 const CHAR_MAP = static_CHAR_MAP(Arrays.createInt32Array(5, 256)); 27254 27255 /* 27256 * Copyright 2013 ZXing authors 27257 * 27258 * Licensed under the Apache License, Version 2.0 (the "License"); 27259 * you may not use this file except in compliance with the License. 27260 * You may obtain a copy of the License at 27261 * 27262 * http://www.apache.org/licenses/LICENSE-2.0 27263 * 27264 * Unless required by applicable law or agreed to in writing, software 27265 * distributed under the License is distributed on an "AS IS" BASIS, 27266 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 27267 * See the License for the specific language governing permissions and 27268 * limitations under the License. 27269 */ 27270 /** 27271 * This produces nearly optimal encodings of text into the first-level of 27272 * encoding used by Aztec code. 27273 * 27274 * It uses a dynamic algorithm. For each prefix of the string, it determines 27275 * a set of encodings that could lead to this prefix. We repeatedly add a 27276 * character and generate a new set of optimal encodings until we have read 27277 * through the entire input. 27278 * 27279 * @author Frank Yellin 27280 * @author Rustam Abdullaev 27281 */ 27282 /*public final*/ class HighLevelEncoder { 27283 constructor(text) { 27284 this.text = text; 27285 } 27286 /** 27287 * @return text represented by this encoder encoded as a {@link BitArray} 27288 */ 27289 encode() { 27290 const spaceCharCode = StringUtils.getCharCode(' '); 27291 const lineBreakCharCode = StringUtils.getCharCode('\n'); 27292 let states = Collections.singletonList(State.INITIAL_STATE); 27293 for (let index = 0; index < this.text.length; index++) { 27294 let pairCode; 27295 let nextChar = index + 1 < this.text.length ? this.text[index + 1] : 0; 27296 switch (this.text[index]) { 27297 case StringUtils.getCharCode('\r'): 27298 pairCode = nextChar === lineBreakCharCode ? 2 : 0; 27299 break; 27300 case StringUtils.getCharCode('.'): 27301 pairCode = nextChar === spaceCharCode ? 3 : 0; 27302 break; 27303 case StringUtils.getCharCode(','): 27304 pairCode = nextChar === spaceCharCode ? 4 : 0; 27305 break; 27306 case StringUtils.getCharCode(':'): 27307 pairCode = nextChar === spaceCharCode ? 5 : 0; 27308 break; 27309 default: 27310 pairCode = 0; 27311 } 27312 if (pairCode > 0) { 27313 // We have one of the four special PUNCT pairs. Treat them specially. 27314 // Get a new set of states for the two new characters. 27315 states = HighLevelEncoder.updateStateListForPair(states, index, pairCode); 27316 index++; 27317 } 27318 else { 27319 // Get a new set of states for the new character. 27320 states = this.updateStateListForChar(states, index); 27321 } 27322 } 27323 // We are left with a set of states. Find the shortest one. 27324 const minState = Collections.min(states, (a, b) => { 27325 return a.getBitCount() - b.getBitCount(); 27326 }); 27327 // Convert it to a bit array, and return. 27328 return minState.toBitArray(this.text); 27329 } 27330 // We update a set of states for a new character by updating each state 27331 // for the new character, merging the results, and then removing the 27332 // non-optimal states. 27333 updateStateListForChar(states, index) { 27334 const result = []; 27335 for (let state /*State*/ of states) { 27336 this.updateStateForChar(state, index, result); 27337 } 27338 return HighLevelEncoder.simplifyStates(result); 27339 } 27340 // Return a set of states that represent the possible ways of updating this 27341 // state for the next character. The resulting set of states are added to 27342 // the "result" list. 27343 updateStateForChar(state, index, result) { 27344 let ch = (this.text[index] & 0xff); 27345 let charInCurrentTable = CHAR_MAP[state.getMode()][ch] > 0; 27346 let stateNoBinary = null; 27347 for (let mode /*int*/ = 0; mode <= MODE_PUNCT; mode++) { 27348 let charInMode = CHAR_MAP[mode][ch]; 27349 if (charInMode > 0) { 27350 if (stateNoBinary == null) { 27351 // Only create stateNoBinary the first time it's required. 27352 stateNoBinary = state.endBinaryShift(index); 27353 } 27354 // Try generating the character by latching to its mode 27355 if (!charInCurrentTable || 27356 mode === state.getMode() || 27357 mode === MODE_DIGIT) { 27358 // If the character is in the current table, we don't want to latch to 27359 // any other mode except possibly digit (which uses only 4 bits). Any 27360 // other latch would be equally successful *after* this character, and 27361 // so wouldn't save any bits. 27362 const latchState = stateNoBinary.latchAndAppend(mode, charInMode); 27363 result.push(latchState); 27364 } 27365 // Try generating the character by switching to its mode. 27366 if (!charInCurrentTable && 27367 SHIFT_TABLE[state.getMode()][mode] >= 0) { 27368 // It never makes sense to temporarily shift to another mode if the 27369 // character exists in the current mode. That can never save bits. 27370 const shiftState = stateNoBinary.shiftAndAppend(mode, charInMode); 27371 result.push(shiftState); 27372 } 27373 } 27374 } 27375 if (state.getBinaryShiftByteCount() > 0 || 27376 CHAR_MAP[state.getMode()][ch] === 0) { 27377 // It's never worthwhile to go into binary shift mode if you're not already 27378 // in binary shift mode, and the character exists in your current mode. 27379 // That can never save bits over just outputting the char in the current mode. 27380 let binaryState = state.addBinaryShiftChar(index); 27381 result.push(binaryState); 27382 } 27383 } 27384 static updateStateListForPair(states, index, pairCode) { 27385 const result = []; 27386 for (let state /*State*/ of states) { 27387 this.updateStateForPair(state, index, pairCode, result); 27388 } 27389 return this.simplifyStates(result); 27390 } 27391 static updateStateForPair(state, index, pairCode, result) { 27392 let stateNoBinary = state.endBinaryShift(index); 27393 // Possibility 1. Latch to C.MODE_PUNCT, and then append this code 27394 result.push(stateNoBinary.latchAndAppend(MODE_PUNCT, pairCode)); 27395 if (state.getMode() !== MODE_PUNCT) { 27396 // Possibility 2. Shift to C.MODE_PUNCT, and then append this code. 27397 // Every state except C.MODE_PUNCT (handled above) can shift 27398 result.push(stateNoBinary.shiftAndAppend(MODE_PUNCT, pairCode)); 27399 } 27400 if (pairCode === 3 || pairCode === 4) { 27401 // both characters are in DIGITS. Sometimes better to just add two digits 27402 let digitState = stateNoBinary 27403 .latchAndAppend(MODE_DIGIT, 16 - pairCode) // period or comma in DIGIT 27404 .latchAndAppend(MODE_DIGIT, 1); // space in DIGIT 27405 result.push(digitState); 27406 } 27407 if (state.getBinaryShiftByteCount() > 0) { 27408 // It only makes sense to do the characters as binary if we're already 27409 // in binary mode. 27410 let binaryState = state 27411 .addBinaryShiftChar(index) 27412 .addBinaryShiftChar(index + 1); 27413 result.push(binaryState); 27414 } 27415 } 27416 static simplifyStates(states) { 27417 let result = []; 27418 for (const newState of states) { 27419 let add = true; 27420 for (const oldState of result) { 27421 if (oldState.isBetterThanOrEqualTo(newState)) { 27422 add = false;
27423 break; 27424 } 27425 if (newState.isBetterThanOrEqualTo(oldState)) { 27426 // iterator.remove(); 27427 result = result.filter(x => x !== oldState); // remove old state 27428 } 27429 } 27430 if (add) { 27431 result.push(newState); 27432 } 27433 } 27434 return result; 27435 } 27436 } 27437 27438 /* 27439 * Copyright 2013 ZXing authors 27440 * 27441 * Licensed under the Apache License, Version 2.0 (the "License"); 27442 * you may not use this file except in compliance with the License. 27443 * You may obtain a copy of the License at 27444 * 27445 * http://www.apache.org/licenses/LICENSE-2.0 27446 * 27447 * Unless required by applicable law or agreed to in writing, software 27448 * distributed under the License is distributed on an "AS IS" BASIS, 27449 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 27450 * See the License for the specific language governing permissions and 27451 * limitations under the License. 27452 */ 27453 // package com.google.zxing.aztec.encoder; 27454 // import com.google.zxing.common.BitArray; 27455 // import com.google.zxing.common.BitMatrix; 27456 // import com.google.zxing.common.reedsolomon.GenericGF; 27457 // import com.google.zxing.common.reedsolomon.ReedSolomonEncoder; 27458 /** 27459 * Generates Aztec 2D barcodes. 27460 * 27461 * @author Rustam Abdullaev 27462 */ 27463 /*public final*/
vendor: 14,667 bytes, lines 27463-27782
27463 class Encoder { 27464 constructor() { 27465 } 27466 /** 27467 * Encodes the given binary content as an Aztec symbol 27468 * 27469 * @param data input data string 27470 * @return Aztec symbol matrix with metadata 27471 */ 27472 static encodeBytes(data) { 27473 return Encoder.encode(data, Encoder.DEFAULT_EC_PERCENT, Encoder.DEFAULT_AZTEC_LAYERS); 27474 } 27475 /** 27476 * Encodes the given binary content as an Aztec symbol 27477 * 27478 * @param data input data string 27479 * @param minECCPercent minimal percentage of error check words (According to ISO/IEC 24778:2008, 27480 * a minimum of 23% + 3 words is recommended) 27481 * @param userSpecifiedLayers if non-zero, a user-specified value for the number of layers 27482 * @return Aztec symbol matrix with metadata 27483 */ 27484 static encode(data, minECCPercent, userSpecifiedLayers) { 27485 // High-level encode 27486 let bits = new HighLevelEncoder(data).encode(); 27487 // stuff bits and choose symbol size 27488 let eccBits = Integer.truncDivision((bits.getSize() * minECCPercent), 100) + 11; 27489 let totalSizeBits = bits.getSize() + eccBits; 27490 let compact; 27491 let layers; 27492 let totalBitsInLayer; 27493 let wordSize; 27494 let stuffedBits; 27495 if (userSpecifiedLayers !== Encoder.DEFAULT_AZTEC_LAYERS) { 27496 compact = userSpecifiedLayers < 0; 27497 layers = Math.abs(userSpecifiedLayers); 27498 if (layers > (compact ? Encoder.MAX_NB_BITS_COMPACT : Encoder.MAX_NB_BITS)) { 27499 throw new IllegalArgumentException(StringUtils.format('Illegal value %s for layers', userSpecifiedLayers)); 27500 } 27501 totalBitsInLayer = Encoder.totalBitsInLayer(layers, compact); 27502 wordSize = Encoder.WORD_SIZE[layers]; 27503 let usableBitsInLayers = totalBitsInLayer - (totalBitsInLayer % wordSize); 27504 stuffedBits = Encoder.stuffBits(bits, wordSize); 27505 if (stuffedBits.getSize() + eccBits > usableBitsInLayers) { 27506 throw new IllegalArgumentException('Data to large for user specified layer'); 27507 } 27508 if (compact && stuffedBits.getSize() > wordSize * 64) { 27509 // Compact format only allows 64 data words, though C4 can hold more words than that 27510 throw new IllegalArgumentException('Data to large for user specified layer'); 27511 } 27512 } 27513 else { 27514 wordSize = 0; 27515 stuffedBits = null; 27516 // We look at the possible table sizes in the order Compact1, Compact2, Compact3, 27517 // Compact4, Normal4,... Normal(i) for i < 4 isn't typically used since Compact(i+1) 27518 // is the same size, but has more data. 27519 for (let i /*int*/ = 0;; i++) { 27520 if (i > Encoder.MAX_NB_BITS) { 27521 throw new IllegalArgumentException('Data too large for an Aztec code'); 27522 } 27523 compact = i <= 3; 27524 layers = compact ? i + 1 : i; 27525 totalBitsInLayer = Encoder.totalBitsInLayer(layers, compact); 27526 if (totalSizeBits > totalBitsInLayer) { 27527 continue; 27528 } 27529 // [Re]stuff the bits if this is the first opportunity, or if the 27530 // wordSize has changed 27531 if (stuffedBits == null || wordSize !== Encoder.WORD_SIZE[layers]) { 27532 wordSize = Encoder.WORD_SIZE[layers]; 27533 stuffedBits = Encoder.stuffBits(bits, wordSize); 27534 } 27535 let usableBitsInLayers = totalBitsInLayer - (totalBitsInLayer % wordSize); 27536 if (compact && stuffedBits.getSize() > wordSize * 64) { 27537 // Compact format only allows 64 data words, though C4 can hold more words than that 27538 continue; 27539 } 27540 if (stuffedBits.getSize() + eccBits <= usableBitsInLayers) { 27541 break; 27542 } 27543 } 27544 } 27545 let messageBits = Encoder.generateCheckWords(stuffedBits, totalBitsInLayer, wordSize); 27546 // generate mode message 27547 let messageSizeInWords = stuffedBits.getSize() / wordSize; 27548 let modeMessage = Encoder.generateModeMessage(compact, layers, messageSizeInWords); 27549 // allocate symbol 27550 let baseMatrixSize = (compact ? 11 : 14) + layers * 4; // not including alignment lines 27551 let alignmentMap = new Int32Array(baseMatrixSize); 27552 let matrixSize; 27553 if (compact) { 27554 // no alignment marks in compact mode, alignmentMap is a no-op 27555 matrixSize = baseMatrixSize; 27556 for (let i /*int*/ = 0; i < alignmentMap.length; i++) { 27557 alignmentMap[i] = i; 27558 } 27559 } 27560 else { 27561 matrixSize = baseMatrixSize + 1 + 2 * Integer.truncDivision((Integer.truncDivision(baseMatrixSize, 2) - 1), 15); 27562 let origCenter = Integer.truncDivision(baseMatrixSize, 2); 27563 let center = Integer.truncDivision(matrixSize, 2); 27564 for (let i /*int*/ = 0; i < origCenter; i++) { 27565 let newOffset = i + Integer.truncDivision(i, 15); 27566 alignmentMap[origCenter - i - 1] = center - newOffset - 1; 27567 alignmentMap[origCenter + i] = center + newOffset + 1; 27568 } 27569 } 27570 let matrix = new BitMatrix(matrixSize); 27571 // draw data bits 27572 for (let i /*int*/ = 0, rowOffset = 0; i < layers; i++) { 27573 let rowSize = (layers - i) * 4 + (compact ? 9 : 12); 27574 for (let j /*int*/ = 0; j < rowSize; j++) { 27575 let columnOffset = j * 2; 27576 for (let k /*int*/ = 0; k < 2; k++) { 27577 if (messageBits.get(rowOffset + columnOffset + k)) { 27578 matrix.set(alignmentMap[i * 2 + k], alignmentMap[i * 2 + j]); 27579 } 27580 if (messageBits.get(rowOffset + rowSize * 2 + columnOffset + k)) { 27581 matrix.set(alignmentMap[i * 2 + j], alignmentMap[baseMatrixSize - 1 - i * 2 - k]); 27582 } 27583 if (messageBits.get(rowOffset + rowSize * 4 + columnOffset + k)) { 27584 matrix.set(alignmentMap[baseMatrixSize - 1 - i * 2 - k], alignmentMap[baseMatrixSize - 1 - i * 2 - j]); 27585 } 27586 if (messageBits.get(rowOffset + rowSize * 6 + columnOffset + k)) { 27587 matrix.set(alignmentMap[baseMatrixSize - 1 - i * 2 - j], alignmentMap[i * 2 + k]); 27588 } 27589 } 27590 } 27591 rowOffset += rowSize * 8; 27592 } 27593 // draw mode message 27594 Encoder.drawModeMessage(matrix, compact, matrixSize, modeMessage); 27595 // draw alignment marks 27596 if (compact) { 27597 Encoder.drawBullsEye(matrix, Integer.truncDivision(matrixSize, 2), 5); 27598 } 27599 else { 27600 Encoder.drawBullsEye(matrix, Integer.truncDivision(matrixSize, 2), 7); 27601 for (let i /*int*/ = 0, j = 0; i < Integer.truncDivision(baseMatrixSize, 2) - 1; i += 15, j += 16) { 27602 for (let k /*int*/ = Integer.truncDivision(matrixSize, 2) & 1; k < matrixSize; k += 2) { 27603 matrix.set(Integer.truncDivision(matrixSize, 2) - j, k); 27604 matrix.set(Integer.truncDivision(matrixSize, 2) + j, k); 27605 matrix.set(k, Integer.truncDivision(matrixSize, 2) - j); 27606 matrix.set(k, Integer.truncDivision(matrixSize, 2) + j); 27607 } 27608 } 27609 } 27610 let aztec = new AztecCode(); 27611 aztec.setCompact(compact); 27612 aztec.setSize(matrixSize); 27613 aztec.setLayers(layers); 27614 aztec.setCodeWords(messageSizeInWords); 27615 aztec.setMatrix(matrix); 27616 return aztec; 27617 } 27618 static drawBullsEye(matrix, center, size) { 27619 for (let i /*int*/ = 0; i < size; i += 2) { 27620 for (let j /*int*/ = center - i; j <= center + i; j++) { 27621 matrix.set(j, center - i); 27622 matrix.set(j, center + i); 27623 matrix.set(center - i, j); 27624 matrix.set(center + i, j); 27625 } 27626 } 27627 matrix.set(center - size, center - size); 27628 matrix.set(center - size + 1, center - size); 27629 matrix.set(center - size, center - size + 1); 27630 matrix.set(center + size, center - size); 27631 matrix.set(center + size, center - size + 1); 27632 matrix.set(center + size, center + size - 1); 27633 } 27634 static generateModeMessage(compact, layers, messageSizeInWords) { 27635 let modeMessage = new BitArray(); 27636 if (compact) { 27637 modeMessage.appendBits(layers - 1, 2); 27638 modeMessage.appendBits(messageSizeInWords - 1, 6); 27639 modeMessage = Encoder.generateCheckWords(modeMessage, 28, 4); 27640 } 27641 else { 27642 modeMessage.appendBits(layers - 1, 5); 27643 modeMessage.appendBits(messageSizeInWords - 1, 11); 27644 modeMessage = Encoder.generateCheckWords(modeMessage, 40, 4); 27645 } 27646 return modeMessage; 27647 } 27648 static drawModeMessage(matrix, compact, matrixSize, modeMessage) { 27649 let center = Integer.truncDivision(matrixSize, 2); 27650 if (compact) { 27651 for (let i /*int*/ = 0; i < 7; i++) { 27652 let offset = center - 3 + i; 27653 if (modeMessage.get(i)) { 27654 matrix.set(offset, center - 5); 27655 } 27656 if (modeMessage.get(i + 7)) { 27657 matrix.set(center + 5, offset); 27658 } 27659 if (modeMessage.get(20 - i)) { 27660 matrix.set(offset, center + 5); 27661 } 27662 if (modeMessage.get(27 - i)) { 27663 matrix.set(center - 5, offset); 27664 } 27665 } 27666 } 27667 else { 27668 for (let i /*int*/ = 0; i < 10; i++) { 27669 let offset = center - 5 + i + Integer.truncDivision(i, 5); 27670 if (modeMessage.get(i)) { 27671 matrix.set(offset, center - 7); 27672 } 27673 if (modeMessage.get(i + 10)) { 27674 matrix.set(center + 7, offset); 27675 } 27676 if (modeMessage.get(29 - i)) { 27677 matrix.set(offset, center + 7); 27678 } 27679 if (modeMessage.get(39 - i)) { 27680 matrix.set(center - 7, offset); 27681 } 27682 } 27683 } 27684 } 27685 static generateCheckWords(bitArray, totalBits, wordSize) { 27686 // bitArray is guaranteed to be a multiple of the wordSize, so no padding needed 27687 let messageSizeInWords = bitArray.getSize() / wordSize; 27688 let rs = new ReedSolomonEncoder(Encoder.getGF(wordSize)); 27689 let totalWords = Integer.truncDivision(totalBits, wordSize); 27690 let messageWords = Encoder.bitsToWords(bitArray, wordSize, totalWords); 27691 rs.encode(messageWords, totalWords - messageSizeInWords); 27692 let startPad = totalBits % wordSize; 27693 let messageBits = new BitArray(); 27694 messageBits.appendBits(0, startPad); 27695 for (const messageWord /*: int*/ of Array.from(messageWords)) { 27696 messageBits.appendBits(messageWord, wordSize); 27697 } 27698 return messageBits; 27699 } 27700 static bitsToWords(stuffedBits, wordSize, totalWords) { 27701 let message = new Int32Array(totalWords); 27702 let i; 27703 let n; 27704 for (i = 0, n = stuffedBits.getSize() / wordSize; i < n; i++) { 27705 let value = 0; 27706 for (let j /*int*/ = 0; j < wordSize; j++) { 27707 value |= stuffedBits.get(i * wordSize + j) ? (1 << wordSize - j - 1) : 0; 27708 } 27709 message[i] = value; 27710 } 27711 return message; 27712 } 27713 static getGF(wordSize) { 27714 switch (wordSize) { 27715 case 4: 27716 return GenericGF.AZTEC_PARAM; 27717 case 6: 27718 return GenericGF.AZTEC_DATA_6; 27719 case 8: 27720 return GenericGF.AZTEC_DATA_8; 27721 case 10: 27722 return GenericGF.AZTEC_DATA_10; 27723 case 12: 27724 return GenericGF.AZTEC_DATA_12; 27725 default: 27726 throw new IllegalArgumentException('Unsupported word size ' + wordSize); 27727 } 27728 } 27729 static stuffBits(bits, wordSize) { 27730 let out = new BitArray(); 27731 let n = bits.getSize(); 27732 let mask = (1 << wordSize) - 2; 27733 for (let i /*int*/ = 0; i < n; i += wordSize) { 27734 let word = 0; 27735 for (let j /*int*/ = 0; j < wordSize; j++) { 27736 if (i + j >= n || bits.get(i + j)) { 27737 word |= 1 << (wordSize - 1 - j); 27738 } 27739 } 27740 if ((word & mask) === mask) { 27741 out.appendBits(word & mask, wordSize); 27742 i--; 27743 } 27744 else if ((word & mask) === 0) { 27745 out.appendBits(word | 1, wordSize); 27746 i--; 27747 } 27748 else { 27749 out.appendBits(word, wordSize); 27750 } 27751 } 27752 return out; 27753 } 27754 static totalBitsInLayer(layers, compact) { 27755 return ((compact ? 88 : 112) + 16 * layers) * layers; 27756 } 27757 } 27758 Encoder.DEFAULT_EC_PERCENT = 33; // default minimal percentage of error check words 27759 Encoder.DEFAULT_AZTEC_LAYERS = 0; 27760 Encoder.MAX_NB_BITS = 32; 27761 Encoder.MAX_NB_BITS_COMPACT = 4; 27762 Encoder.WORD_SIZE = Int32Array.from([ 27763 4, 6, 6, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 27764 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 27765 ]); 27766 27767 /* 27768 * Copyright 2013 ZXing authors 27769 * 27770 * Licensed under the Apache License, Version 2.0 (the "License"); 27771 * you may not use this file except in compliance with the License. 27772 * You may obtain a copy of the License at 27773 * 27774 * http://www.apache.org/licenses/LICENSE-2.0 27775 * 27776 * Unless required by applicable law or agreed to in writing, software 27777 * distributed under the License is distributed on an "AS IS" BASIS, 27778 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 27779 * See the License for the specific language governing permissions and 27780 * limitations under the License. 27781 */ 27782 /
vendor: 7,743 bytes, lines 27782-27944
27782** 27783 * Renders an Aztec code as a {@link BitMatrix}. 27784 */ 27785 /*public final*/ class AztecWriter { 27786 // @Override 27787 encode(contents, format, width, height) { 27788 return this.encodeWithHints(contents, format, width, height, null); 27789 } 27790 // @Override 27791 encodeWithHints(contents, format, width, height, hints) { 27792 let charset = StandardCharsets.ISO_8859_1; 27793 let eccPercent = Encoder.DEFAULT_EC_PERCENT; 27794 let layers = Encoder.DEFAULT_AZTEC_LAYERS; 27795 if (hints != null) { 27796 if (hints.has(EncodeHintType$1.CHARACTER_SET)) { 27797 charset = Charset.forName(hints.get(EncodeHintType$1.CHARACTER_SET).toString()); 27798 } 27799 if (hints.has(EncodeHintType$1.ERROR_CORRECTION)) { 27800 eccPercent = Integer.parseInt(hints.get(EncodeHintType$1.ERROR_CORRECTION).toString()); 27801 } 27802 if (hints.has(EncodeHintType$1.AZTEC_LAYERS)) { 27803 layers = Integer.parseInt(hints.get(EncodeHintType$1.AZTEC_LAYERS).toString()); 27804 } 27805 } 27806 return AztecWriter.encodeLayers(contents, format, width, height, charset, eccPercent, layers); 27807 } 27808 static encodeLayers(contents, format, width, height, charset, eccPercent, layers) { 27809 if (format !== BarcodeFormat$1.AZTEC) { 27810 throw new IllegalArgumentException('Can only encode AZTEC, but got ' + format); 27811 } 27812 let aztec = Encoder.encode(StringUtils.getBytes(contents, charset), eccPercent, layers); 27813 return AztecWriter.renderResult(aztec, width, height); 27814 } 27815 static renderResult(code, width, height) { 27816 let input = code.getMatrix(); 27817 if (input == null) { 27818 throw new IllegalStateException(); 27819 } 27820 let inputWidth = input.getWidth(); 27821 let inputHeight = input.getHeight(); 27822 let outputWidth = Math.max(width, inputWidth); 27823 let outputHeight = Math.max(height, inputHeight); 27824 let multiple = Math.min(outputWidth / inputWidth, outputHeight / inputHeight); 27825 let leftPadding = (outputWidth - (inputWidth * multiple)) / 2; 27826 let topPadding = (outputHeight - (inputHeight * multiple)) / 2; 27827 let output = new BitMatrix(outputWidth, outputHeight); 27828 for (let inputY /*int*/ = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) { 27829 // Write the contents of this row of the barcode 27830 for (let inputX /*int*/ = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) { 27831 if (input.get(inputX, inputY)) { 27832 output.setRegion(outputX, outputY, multiple, multiple); 27833 } 27834 } 27835 } 27836 return output; 27837 } 27838 } 27839 27840 exports.AbstractExpandedDecoder = AbstractExpandedDecoder; 27841 exports.ArgumentException = ArgumentException; 27842 exports.ArithmeticException = ArithmeticException; 27843 exports.AztecCode = AztecCode; 27844 exports.AztecCodeReader = AztecReader; 27845 exports.AztecCodeWriter = AztecWriter; 27846 exports.AztecDecoder = Decoder$2; 27847 exports.AztecDetector = Detector$3; 27848 exports.AztecDetectorResult = AztecDetectorResult; 27849 exports.AztecEncoder = Encoder; 27850 exports.AztecHighLevelEncoder = HighLevelEncoder; 27851 exports.AztecPoint = Point; 27852 exports.BarcodeFormat = BarcodeFormat$1; 27853 exports.Binarizer = Binarizer; 27854 exports.BinaryBitmap = BinaryBitmap; 27855 exports.BitArray = BitArray; 27856 exports.BitMatrix = BitMatrix; 27857 exports.BitSource = BitSource; 27858 exports.BrowserAztecCodeReader = BrowserAztecCodeReader; 27859 exports.BrowserBarcodeReader = BrowserBarcodeReader; 27860 exports.BrowserCodeReader = BrowserCodeReader; 27861 exports.BrowserDatamatrixCodeReader = BrowserDatamatrixCodeReader; 27862 exports.BrowserMultiFormatReader = BrowserMultiFormatReader; 27863 exports.BrowserPDF417Reader = BrowserPDF417Reader; 27864 exports.BrowserQRCodeReader = BrowserQRCodeReader; 27865 exports.BrowserQRCodeSvgWriter = BrowserQRCodeSvgWriter; 27866 exports.CharacterSetECI = CharacterSetECI; 27867 exports.ChecksumException = ChecksumException; 27868 exports.CodaBarReader = CodaBarReader; 27869 exports.Code128Reader = Code128Reader; 27870 exports.Code39Reader = Code39Reader; 27871 exports.Code93Reader = Code93Reader; 27872 exports.DataMatrixDecodedBitStreamParser = DecodedBitStreamParser$2; 27873 exports.DataMatrixDefaultPlacement = DefaultPlacement; 27874 exports.DataMatrixErrorCorrection = ErrorCorrection; 27875 exports.DataMatrixHighLevelEncoder = HighLevelEncoder$1; 27876 exports.DataMatrixReader = DataMatrixReader; 27877 exports.DataMatrixSymbolInfo = SymbolInfo; 27878 exports.DataMatrixWriter = DataMatrixWriter; 27879 exports.DecodeHintType = DecodeHintType$1; 27880 exports.DecoderResult = DecoderResult; 27881 exports.DefaultGridSampler = DefaultGridSampler; 27882 exports.DetectorResult = DetectorResult; 27883 exports.EAN13Reader = EAN13Reader; 27884 exports.EncodeHintType = EncodeHintType$1; 27885 exports.Exception = Exception; 27886 exports.FormatException = FormatException; 27887 exports.GenericGF = GenericGF; 27888 exports.GenericGFPoly = GenericGFPoly; 27889 exports.GlobalHistogramBinarizer = GlobalHistogramBinarizer; 27890 exports.GridSampler = GridSampler; 27891 exports.GridSamplerInstance = GridSamplerInstance; 27892 exports.HTMLCanvasElementLuminanceSource = HTMLCanvasElementLuminanceSource; 27893 exports.HybridBinarizer = HybridBinarizer; 27894 exports.ITFReader = ITFReader; 27895 exports.IllegalArgumentException = IllegalArgumentException; 27896 exports.IllegalStateException = IllegalStateException; 27897 exports.InvertedLuminanceSource = InvertedLuminanceSource; 27898 exports.LuminanceSource = LuminanceSource; 27899 exports.MathUtils = MathUtils; 27900 exports.MultiFormatOneDReader = MultiFormatOneDReader; 27901 exports.MultiFormatReader = MultiFormatReader; 27902 exports.MultiFormatWriter = MultiFormatWriter; 27903 exports.NotFoundException = NotFoundException; 27904 exports.OneDReader = OneDReader; 27905 exports.PDF417DecodedBitStreamParser = DecodedBitStreamParser; 27906 exports.PDF417DecoderErrorCorrection = ErrorCorrection$1; 27907 exports.PDF417Reader = PDF417Reader; 27908 exports.PDF417ResultMetadata = PDF417ResultMetadata; 27909 exports.PerspectiveTransform = PerspectiveTransform; 27910 exports.PlanarYUVLuminanceSource = PlanarYUVLuminanceSource; 27911 exports.QRCodeByteMatrix = ByteMatrix; 27912 exports.QRCodeDataMask = DataMask; 27913 exports.QRCodeDecodedBitStreamParser = DecodedBitStreamParser$1; 27914 exports.QRCodeDecoderErrorCorrectionLevel = ErrorCorrectionLevel; 27915 exports.QRCodeDecoderFormatInformation = FormatInformation; 27916 exports.QRCodeEncoder = Encoder$1; 27917 exports.QRCodeEncoderQRCode = QRCode; 27918 exports.QRCodeMaskUtil = MaskUtil; 27919 exports.QRCodeMatrixUtil = MatrixUtil; 27920 exports.QRCodeMode = Mode$2; 27921 exports.QRCodeReader = QRCodeReader; 27922 exports.QRCodeVersion = Version; 27923 exports.QRCodeWriter = QRCodeWriter; 27924 exports.RGBLuminanceSource = RGBLuminanceSource; 27925 exports.RSS14Reader = RSS14Reader; 27926 exports.RSSExpandedReader = RSSExpandedReader; 27927 exports.ReaderException = ReaderException; 27928 exports.ReedSolomonDecoder = ReedSolomonDecoder; 27929 exports.ReedSolomonEncoder = ReedSolomonEncoder; 27930 exports.ReedSolomonException = ReedSolomonException; 27931 exports.Result = Result$1; 27932 exports.ResultMetadataType = ResultMetadataType$1; 27933 exports.ResultPoint = ResultPoint; 27934 exports.StringUtils = StringUtils; 27935 exports.UnsupportedOperationException = UnsupportedOperationException; 27936 exports.VideoInputDevice = VideoInputDevice; 27937 exports.WhiteRectangleDetector = WhiteRectangleDetector; 27938 exports.WriterException = WriterException; 27939 exports.ZXingArrays = Arrays; 27940 exports.ZXingCharset = Charset; 27941 exports.ZXingInteger = Integer; 27942 exports.ZXingStandardCharsets = StandardCharsets; 27943 exports.ZXingStringBuilder = StringBuilder; 27944 exports.ZXingStringEncoding = StringEncoding;
27945 exports.ZXingSystem = System; 27946 exports.createAbstractExpandedDecoder = createDecoder; 27947 27948 Object.defineProperty(exports, '__esModule', { value: true }); 27949 27950})); 27951//# sourceMappingURL=index.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.