@sythos/js_barcode_universal 1.3.1 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AI_USAGE.md +33 -0
- package/LICENSE +4 -2
- package/NOTICE.md +8 -5
- package/README.md +74 -23
- package/bundle/sythos-barcode.esm.js +2313 -92
- package/bundle/sythos-barcode.js +2229 -88
- package/examples/create.html +2 -1
- package/examples/read.html +1 -0
- package/licenses/README.md +6 -1
- package/licenses/aztec-rune.license +76 -0
- package/licenses/compact-pdf417.license +76 -0
- package/licenses/ean-2.license +74 -0
- package/licenses/ean-5.license +74 -0
- package/licenses/frameqr.license +6 -6
- package/licenses/gs1-databar.license +81 -0
- package/package.json +16 -4
- package/src/aztec/decoder.js +1 -0
- package/src/aztec/detector.js +1 -0
- package/src/aztec/encoder.js +1 -0
- package/src/aztec/high-level.js +1 -0
- package/src/aztec/index.js +1 -0
- package/src/aztec/tables.js +1 -0
- package/src/aztecrune/decoder.js +156 -0
- package/src/aztecrune/detector.js +167 -0
- package/src/aztecrune/encoder.js +122 -0
- package/src/aztecrune/index.js +50 -0
- package/src/aztecrune/tables.js +138 -0
- package/src/compactpdf417/decoder.js +129 -0
- package/src/compactpdf417/detector.js +140 -0
- package/src/compactpdf417/encoder.js +141 -0
- package/src/compactpdf417/index.js +22 -0
- package/src/compactpdf417/tables.js +174 -0
- package/src/core/bit-buffer.js +1 -0
- package/src/core/bit-matrix.js +1 -0
- package/src/core/errors.js +1 -0
- package/src/core/galois-field.js +1 -0
- package/src/core/index.js +1 -0
- package/src/core/reed-solomon.js +1 -0
- package/src/databar/codec.js +182 -0
- package/src/databar/decoder.js +115 -0
- package/src/databar/encoder.js +97 -0
- package/src/databar/gs1.js +178 -0
- package/src/databar/index.js +69 -0
- package/src/databar/patterns.js +144 -0
- package/src/databar/tables.js +125 -0
- package/src/datamatrix/decoder.js +1 -0
- package/src/datamatrix/detector.js +1 -0
- package/src/datamatrix/encoder.js +1 -0
- package/src/datamatrix/index.js +1 -0
- package/src/datamatrix/tables.js +1 -0
- package/src/frameqr/decoder.js +16 -15
- package/src/frameqr/detector.js +3 -2
- package/src/frameqr/encoder.js +8 -7
- package/src/frameqr/index.js +1 -0
- package/src/frameqr/tables.js +11 -10
- package/src/image/binarizer.js +1 -0
- package/src/image/grid-sampler.js +1 -0
- package/src/image/index.js +1 -0
- package/src/image/luminance.js +1 -0
- package/src/image/perspective.js +1 -0
- package/src/index.js +72 -8
- package/src/micropdf417/compaction.js +1 -0
- package/src/micropdf417/decoder.js +1 -0
- package/src/micropdf417/detector.js +1 -0
- package/src/micropdf417/encoder.js +1 -0
- package/src/micropdf417/error-correction.js +1 -0
- package/src/micropdf417/index.js +1 -0
- package/src/micropdf417/tables.js +1 -0
- package/src/microqr/decoder.js +1 -0
- package/src/microqr/detector.js +1 -0
- package/src/microqr/encoder.js +1 -0
- package/src/microqr/index.js +1 -0
- package/src/microqr/tables.js +1 -0
- package/src/oned/addons.js +421 -0
- package/src/oned/index.js +18 -0
- package/src/oned/patterns.js +1 -0
- package/src/oned/reader.js +1 -0
- package/src/oned/writers.js +1 -0
- package/src/pdf417/compaction.js +1 -0
- package/src/pdf417/decoder.js +1 -0
- package/src/pdf417/detector.js +1 -0
- package/src/pdf417/encoder.js +1 -0
- package/src/pdf417/error-correction.js +1 -0
- package/src/pdf417/index.js +5 -0
- package/src/pdf417/tables.js +1 -0
- package/src/qr/decoder.js +1 -0
- package/src/qr/detector.js +1 -0
- package/src/qr/encoder.js +1 -0
- package/src/qr/index.js +1 -0
- package/src/qr/tables.js +1 -0
- package/src/render/image-data.js +1 -0
- package/src/render/index.js +1 -0
- package/src/render/options.js +1 -0
- package/src/render/png.js +1 -0
- package/src/render/svg.js +1 -0
- package/src/render/webgl.js +1 -0
- package/src/render/webgpu.js +1 -0
- package/src/rmqr/decoder.js +1 -0
- package/src/rmqr/detector.js +1 -0
- package/src/rmqr/encoder.js +1 -0
- package/src/rmqr/index.js +1 -0
- package/src/rmqr/tables.js +1 -0
package/bundle/sythos-barcode.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Sythos Barcode Suite v1.
|
|
2
|
+
* Sythos Barcode Suite v1.4.1
|
|
3
3
|
*
|
|
4
4
|
* MIT License
|
|
5
5
|
*
|
|
@@ -1823,6 +1823,413 @@ __exports.encodeMSI = encodeMSI;
|
|
|
1823
1823
|
__exports.encodePharmacode = encodePharmacode;
|
|
1824
1824
|
};
|
|
1825
1825
|
|
|
1826
|
+
__modules["oned/addons.js"] = function (__require, __exports) {
|
|
1827
|
+
/**
|
|
1828
|
+
* UPC/EAN two- and five-digit supplements.
|
|
1829
|
+
*
|
|
1830
|
+
* Supplements are small symbols printed to the right of an EAN/UPC symbol.
|
|
1831
|
+
* They use the ordinary EAN odd/even digit patterns, a 1011 start guard and
|
|
1832
|
+
* 01 separators between digits. EAN-2 selects its parity from the numeric
|
|
1833
|
+
* value modulo four. EAN-5 derives a checksum from the five digits and uses
|
|
1834
|
+
* that value to select one of ten parity rows.
|
|
1835
|
+
*
|
|
1836
|
+
* This module intentionally keeps supplements separate from the base EAN/UPC
|
|
1837
|
+
* writers. `composeEANAddon` and the `*WithAddon` helpers are opt-in; existing
|
|
1838
|
+
* EAN/UPC APIs continue to return their original one-row matrices unchanged.
|
|
1839
|
+
*
|
|
1840
|
+
* @module oned/addons
|
|
1841
|
+
*/
|
|
1842
|
+
const { BitMatrix } = __require("core/bit-matrix.js");
|
|
1843
|
+
const { EncodeError, FormatError } = __require("core/errors.js");
|
|
1844
|
+
const { EAN_L, EAN_G } = __require("oned/patterns.js");
|
|
1845
|
+
const { encodeEAN13, encodeEAN8, encodeUPCA, encodeUPCE } = __require("oned/writers.js");
|
|
1846
|
+
|
|
1847
|
+
/** EAN-2 parity rows, indexed by the two-digit value modulo four. */
|
|
1848
|
+
const EAN2_PARITY = Object.freeze([
|
|
1849
|
+
'AA', 'AB', 'BA', 'BB',
|
|
1850
|
+
]);
|
|
1851
|
+
|
|
1852
|
+
/** EAN-5 parity rows, indexed by the supplemental checksum. */
|
|
1853
|
+
const EAN5_PARITY = Object.freeze([
|
|
1854
|
+
'BBAAA', 'BABAA', 'BAABA', 'BAAAB', 'ABBAA',
|
|
1855
|
+
'AABBA', 'AAABB', 'ABABA', 'ABAAB', 'AABAB',
|
|
1856
|
+
]);
|
|
1857
|
+
|
|
1858
|
+
/** Start guard used by both UPC/EAN supplemental symbols. */
|
|
1859
|
+
const EAN_ADDON_START = '1011';
|
|
1860
|
+
|
|
1861
|
+
/** Separator inserted between adjacent supplemental digits. */
|
|
1862
|
+
const EAN_ADDON_SEPARATOR = '01';
|
|
1863
|
+
const EAN2_WIDTH = EAN_ADDON_START.length + 2 * 7 + EAN_ADDON_SEPARATOR.length;
|
|
1864
|
+
const EAN5_WIDTH = EAN_ADDON_START.length + 5 * 7 + EAN_ADDON_SEPARATOR.length * 4;
|
|
1865
|
+
|
|
1866
|
+
/**
|
|
1867
|
+
* @param {unknown} value
|
|
1868
|
+
* @param {number} length
|
|
1869
|
+
* @param {string} format
|
|
1870
|
+
* @returns {string}
|
|
1871
|
+
*/
|
|
1872
|
+
function normalizeDigits(value, length, format) {
|
|
1873
|
+
const digits = String(value);
|
|
1874
|
+
if (!new RegExp(`^[0-9]{${length}}$`).test(digits)) {
|
|
1875
|
+
throw new EncodeError(`${format}: payload must contain exactly ${length} digits`);
|
|
1876
|
+
}
|
|
1877
|
+
return digits;
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
/**
|
|
1881
|
+
* EAN-5 supplemental checksum.
|
|
1882
|
+
*
|
|
1883
|
+
* The first, third and fifth digits carry weight three; the second and fourth
|
|
1884
|
+
* carry weight nine. The checksum is not printed as a sixth digit: it selects
|
|
1885
|
+
* the odd/even parity row for the five encoded digits.
|
|
1886
|
+
*
|
|
1887
|
+
* @param {string|number} value Five digits.
|
|
1888
|
+
* @returns {number} Checksum value, 0-9.
|
|
1889
|
+
*/
|
|
1890
|
+
function ean5Checksum(value) {
|
|
1891
|
+
const digits = normalizeDigits(value, 5, 'EAN-5');
|
|
1892
|
+
const weighted =
|
|
1893
|
+
3 * (Number(digits[0]) + Number(digits[2]) + Number(digits[4])) +
|
|
1894
|
+
9 * (Number(digits[1]) + Number(digits[3]));
|
|
1895
|
+
return weighted % 10;
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
/** Alias for callers that use the EAN family check-digit terminology. */
|
|
1899
|
+
const ean5CheckDigit = ean5Checksum;
|
|
1900
|
+
|
|
1901
|
+
/**
|
|
1902
|
+
* Resolve the EAN-2 parity row for a payload.
|
|
1903
|
+
*
|
|
1904
|
+
* @param {string|number} value Two digits.
|
|
1905
|
+
* @returns {string} Two-character A/B parity row.
|
|
1906
|
+
*/
|
|
1907
|
+
function ean2Parity(value) {
|
|
1908
|
+
const digits = normalizeDigits(value, 2, 'EAN-2');
|
|
1909
|
+
return EAN2_PARITY[Number(digits) % 4];
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
/**
|
|
1913
|
+
* Resolve the EAN-5 parity row for a payload.
|
|
1914
|
+
*
|
|
1915
|
+
* @param {string|number} value Five digits.
|
|
1916
|
+
* @returns {string} Five-character A/B parity row.
|
|
1917
|
+
*/
|
|
1918
|
+
function ean5Parity(value) {
|
|
1919
|
+
return EAN5_PARITY[ean5Checksum(value)];
|
|
1920
|
+
}
|
|
1921
|
+
|
|
1922
|
+
/**
|
|
1923
|
+
* Expand an A/B parity row into EAN digit patterns.
|
|
1924
|
+
*
|
|
1925
|
+
* @param {string} digits
|
|
1926
|
+
* @param {string} parity
|
|
1927
|
+
* @returns {string}
|
|
1928
|
+
*/
|
|
1929
|
+
function encodeDigitPatterns(digits, parity) {
|
|
1930
|
+
let modules = EAN_ADDON_START;
|
|
1931
|
+
for (let i = 0; i < digits.length; i++) {
|
|
1932
|
+
if (i > 0) modules += EAN_ADDON_SEPARATOR;
|
|
1933
|
+
const table = parity[i] === 'A' ? EAN_L : EAN_G;
|
|
1934
|
+
modules += table[Number(digits[i])];
|
|
1935
|
+
}
|
|
1936
|
+
return modules;
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
/**
|
|
1940
|
+
* Turn a module string into a one-row matrix and attach immutable source
|
|
1941
|
+
* metadata for composition/rendering callers.
|
|
1942
|
+
*
|
|
1943
|
+
* @param {string} modules
|
|
1944
|
+
* @param {{format: string, text: string, parity: string, checksum?: number}} metadata
|
|
1945
|
+
* @returns {BitMatrix}
|
|
1946
|
+
*/
|
|
1947
|
+
function toAddonMatrix(modules, metadata) {
|
|
1948
|
+
const matrix = new BitMatrix(modules.length, 1);
|
|
1949
|
+
for (let x = 0; x < modules.length; x++) {
|
|
1950
|
+
if (modules[x] === '1') matrix.set(x, 0);
|
|
1951
|
+
}
|
|
1952
|
+
matrix.eanAddon = Object.freeze({ ...metadata });
|
|
1953
|
+
return matrix;
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
/**
|
|
1957
|
+
* Encode an EAN-2 supplement.
|
|
1958
|
+
*
|
|
1959
|
+
* @param {string|number} value Exactly two decimal digits.
|
|
1960
|
+
* @returns {BitMatrix} A 20-module, one-row supplement.
|
|
1961
|
+
*/
|
|
1962
|
+
function encodeEAN2(value) {
|
|
1963
|
+
const digits = normalizeDigits(value, 2, 'EAN-2');
|
|
1964
|
+
const parity = ean2Parity(digits);
|
|
1965
|
+
const matrix = toAddonMatrix(encodeDigitPatterns(digits, parity), {
|
|
1966
|
+
format: 'ean2',
|
|
1967
|
+
text: digits,
|
|
1968
|
+
parity,
|
|
1969
|
+
});
|
|
1970
|
+
if (matrix.width !== EAN2_WIDTH) {
|
|
1971
|
+
throw new EncodeError(`EAN-2: internal width is ${matrix.width}, expected ${EAN2_WIDTH}`);
|
|
1972
|
+
}
|
|
1973
|
+
return matrix;
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
/**
|
|
1977
|
+
* Encode an EAN-5 supplement.
|
|
1978
|
+
*
|
|
1979
|
+
* @param {string|number} value Exactly five decimal digits.
|
|
1980
|
+
* @returns {BitMatrix} A 47-module, one-row supplement.
|
|
1981
|
+
*/
|
|
1982
|
+
function encodeEAN5(value) {
|
|
1983
|
+
const digits = normalizeDigits(value, 5, 'EAN-5');
|
|
1984
|
+
const checksum = ean5Checksum(digits);
|
|
1985
|
+
const parity = EAN5_PARITY[checksum];
|
|
1986
|
+
const matrix = toAddonMatrix(encodeDigitPatterns(digits, parity), {
|
|
1987
|
+
format: 'ean5',
|
|
1988
|
+
text: digits,
|
|
1989
|
+
parity,
|
|
1990
|
+
checksum,
|
|
1991
|
+
});
|
|
1992
|
+
if (matrix.width !== EAN5_WIDTH) {
|
|
1993
|
+
throw new EncodeError(`EAN-5: internal width is ${matrix.width}, expected ${EAN5_WIDTH}`);
|
|
1994
|
+
}
|
|
1995
|
+
return matrix;
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
/**
|
|
1999
|
+
* Encode either supported supplement length.
|
|
2000
|
+
*
|
|
2001
|
+
* @param {string|number} value Two or five decimal digits.
|
|
2002
|
+
* @returns {BitMatrix}
|
|
2003
|
+
*/
|
|
2004
|
+
function encodeEANAddon(value) {
|
|
2005
|
+
const digits = String(value);
|
|
2006
|
+
if (digits.length === 2) return encodeEAN2(digits);
|
|
2007
|
+
if (digits.length === 5) return encodeEAN5(digits);
|
|
2008
|
+
throw new EncodeError('EAN add-on: payload must contain exactly two or five digits');
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
/** Alias using the spelling used by some EAN documentation. */
|
|
2012
|
+
const encodeEANAddOn = encodeEANAddon;
|
|
2013
|
+
|
|
2014
|
+
/**
|
|
2015
|
+
* @param {BitMatrix} matrix
|
|
2016
|
+
* @param {number} offset
|
|
2017
|
+
* @param {string} pattern
|
|
2018
|
+
* @returns {boolean}
|
|
2019
|
+
*/
|
|
2020
|
+
function matches(matrix, offset, pattern) {
|
|
2021
|
+
if (offset < 0 || offset + pattern.length > matrix.width) return false;
|
|
2022
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
2023
|
+
if ((matrix.get(offset + i, 0) ? '1' : '0') !== pattern[i]) return false;
|
|
2024
|
+
}
|
|
2025
|
+
return true;
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
/**
|
|
2029
|
+
* @param {BitMatrix} matrix
|
|
2030
|
+
* @param {number} start
|
|
2031
|
+
* @param {2|5} digitCount
|
|
2032
|
+
* @returns {{format:string,text:string,parity:string,checksum?:number,end:number}|null}
|
|
2033
|
+
*/
|
|
2034
|
+
function decodeAt(matrix, start, digitCount) {
|
|
2035
|
+
const width = digitCount === 2 ? EAN2_WIDTH : EAN5_WIDTH;
|
|
2036
|
+
if (!matches(matrix, start, EAN_ADDON_START)) return null;
|
|
2037
|
+
if (start > 0 && matrix.get(start - 1, 0)) return null;
|
|
2038
|
+
|
|
2039
|
+
let offset = start + EAN_ADDON_START.length;
|
|
2040
|
+
let text = '';
|
|
2041
|
+
let parity = '';
|
|
2042
|
+
|
|
2043
|
+
for (let i = 0; i < digitCount; i++) {
|
|
2044
|
+
let found = null;
|
|
2045
|
+
for (let digit = 0; digit < 10; digit++) {
|
|
2046
|
+
for (const [letter, table] of [['A', EAN_L], ['B', EAN_G]]) {
|
|
2047
|
+
if (matches(matrix, offset, table[digit]) &&
|
|
2048
|
+
(!found || found.letter !== letter || found.digit !== digit)) {
|
|
2049
|
+
if (found) return null;
|
|
2050
|
+
found = { digit, letter };
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
if (!found) return null;
|
|
2055
|
+
text += String(found.digit);
|
|
2056
|
+
parity += found.letter;
|
|
2057
|
+
offset += 7;
|
|
2058
|
+
if (i < digitCount - 1) {
|
|
2059
|
+
if (!matches(matrix, offset, EAN_ADDON_SEPARATOR)) return null;
|
|
2060
|
+
offset += EAN_ADDON_SEPARATOR.length;
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
|
|
2064
|
+
if (offset - start !== width) return null;
|
|
2065
|
+
if (digitCount === 2) {
|
|
2066
|
+
if (EAN2_PARITY[Number(text) % 4] !== parity) return null;
|
|
2067
|
+
return { format: 'ean2', text, parity, end: offset };
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
const checksum = ean5Checksum(text);
|
|
2071
|
+
if (EAN5_PARITY[checksum] !== parity) return null;
|
|
2072
|
+
return { format: 'ean5', text, parity, checksum, end: offset };
|
|
2073
|
+
}
|
|
2074
|
+
|
|
2075
|
+
/**
|
|
2076
|
+
* Validate and decode an EAN-2 supplement. A leading quiet zone is accepted;
|
|
2077
|
+
* the decoder searches the row for a valid start guard so a composed base
|
|
2078
|
+
* EAN/UPC matrix can be passed directly as well.
|
|
2079
|
+
*
|
|
2080
|
+
* @param {BitMatrix} matrix One-row, module-aligned supplement or composition.
|
|
2081
|
+
* @returns {{format:'ean2',text:string,parity:string}}
|
|
2082
|
+
* @throws {FormatError} When no valid supplement is found.
|
|
2083
|
+
*/
|
|
2084
|
+
function decodeEAN2(matrix) {
|
|
2085
|
+
if (!matrix || !Number.isInteger(matrix.width) || matrix.height !== 1) {
|
|
2086
|
+
throw new FormatError('EAN-2: expected a one-row module matrix');
|
|
2087
|
+
}
|
|
2088
|
+
for (let start = 0; start + EAN2_WIDTH <= matrix.width; start++) {
|
|
2089
|
+
const result = decodeAt(matrix, start, 2);
|
|
2090
|
+
if (result) {
|
|
2091
|
+
const { end, ...publicResult } = result;
|
|
2092
|
+
void end;
|
|
2093
|
+
return publicResult;
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
throw new FormatError('EAN-2: start, parity or digit pattern is invalid');
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
/**
|
|
2100
|
+
* Validate and decode an EAN-5 supplement.
|
|
2101
|
+
*
|
|
2102
|
+
* @param {BitMatrix} matrix One-row, module-aligned supplement or composition.
|
|
2103
|
+
* @returns {{format:'ean5',text:string,parity:string,checksum:number}}
|
|
2104
|
+
* @throws {FormatError} When no valid supplement is found.
|
|
2105
|
+
*/
|
|
2106
|
+
function decodeEAN5(matrix) {
|
|
2107
|
+
if (!matrix || !Number.isInteger(matrix.width) || matrix.height !== 1) {
|
|
2108
|
+
throw new FormatError('EAN-5: expected a one-row module matrix');
|
|
2109
|
+
}
|
|
2110
|
+
for (let start = 0; start + EAN5_WIDTH <= matrix.width; start++) {
|
|
2111
|
+
const result = decodeAt(matrix, start, 5);
|
|
2112
|
+
if (result) {
|
|
2113
|
+
const { end, ...publicResult } = result;
|
|
2114
|
+
void end;
|
|
2115
|
+
return publicResult;
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
throw new FormatError('EAN-5: start, parity, checksum or digit pattern is invalid');
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
/**
|
|
2122
|
+
* Decode either supported supplement length.
|
|
2123
|
+
*
|
|
2124
|
+
* @param {BitMatrix} matrix One-row, module-aligned supplement or composition.
|
|
2125
|
+
* @returns {{format:'ean2'|'ean5',text:string,parity:string,checksum?:number}}
|
|
2126
|
+
* @throws {FormatError} When neither supplement grammar matches.
|
|
2127
|
+
*/
|
|
2128
|
+
function decodeEANAddon(matrix) {
|
|
2129
|
+
try {
|
|
2130
|
+
return decodeEAN5(matrix);
|
|
2131
|
+
} catch (fiveError) {
|
|
2132
|
+
try {
|
|
2133
|
+
return decodeEAN2(matrix);
|
|
2134
|
+
} catch (twoError) {
|
|
2135
|
+
throw new FormatError(`EAN add-on: ${fiveError.message}; ${twoError.message}`);
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
/** Alias using the spelling used by some EAN documentation. */
|
|
2141
|
+
const decodeEANAddOn = decodeEANAddon;
|
|
2142
|
+
|
|
2143
|
+
/**
|
|
2144
|
+
* Join a base EAN/UPC matrix and a supplement with the standard quiet gap.
|
|
2145
|
+
*
|
|
2146
|
+
* The helper does not alter either input. By default it inserts nine light
|
|
2147
|
+
* modules, the conventional separation between the base symbol and an add-on.
|
|
2148
|
+
* The result carries the supplement metadata under `eanAddon` for renderers or
|
|
2149
|
+
* callers that need to label the composed symbol.
|
|
2150
|
+
*
|
|
2151
|
+
* @param {BitMatrix} base Base EAN/UPC matrix.
|
|
2152
|
+
* @param {BitMatrix|string|number} addon Add-on matrix or two/five digits.
|
|
2153
|
+
* @param {{gap?:number}} [options]
|
|
2154
|
+
* @returns {BitMatrix}
|
|
2155
|
+
*/
|
|
2156
|
+
function composeEANAddon(base, addon, options = {}) {
|
|
2157
|
+
if (!base || !Number.isInteger(base.width) || base.height !== 1) {
|
|
2158
|
+
throw new TypeError('EAN add-on: base must be a one-row module matrix');
|
|
2159
|
+
}
|
|
2160
|
+
const addonMatrix = typeof addon === 'string' || typeof addon === 'number'
|
|
2161
|
+
? encodeEANAddon(addon)
|
|
2162
|
+
: addon;
|
|
2163
|
+
if (!addonMatrix || !Number.isInteger(addonMatrix.width) || addonMatrix.height !== 1) {
|
|
2164
|
+
throw new TypeError('EAN add-on: supplement must be a one-row module matrix or digits');
|
|
2165
|
+
}
|
|
2166
|
+
|
|
2167
|
+
const gap = options.gap === undefined ? 9 : Number(options.gap);
|
|
2168
|
+
if (!Number.isInteger(gap) || gap < 1) {
|
|
2169
|
+
throw new EncodeError(`EAN add-on: gap must be a positive integer, got ${options.gap}`);
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
const result = new BitMatrix(base.width + gap + addonMatrix.width, 1);
|
|
2173
|
+
for (let x = 0; x < base.width; x++) if (base.get(x, 0)) result.set(x, 0);
|
|
2174
|
+
for (let x = 0; x < addonMatrix.width; x++) {
|
|
2175
|
+
if (addonMatrix.get(x, 0)) result.set(base.width + gap + x, 0);
|
|
2176
|
+
}
|
|
2177
|
+
if (addonMatrix.eanAddon) result.eanAddon = { ...addonMatrix.eanAddon, gap };
|
|
2178
|
+
return result;
|
|
2179
|
+
}
|
|
2180
|
+
|
|
2181
|
+
/**
|
|
2182
|
+
* Compose an EAN-13 symbol with an EAN-2 or EAN-5 supplement.
|
|
2183
|
+
*
|
|
2184
|
+
* @param {string} value Base EAN-13 payload.
|
|
2185
|
+
* @param {string|number} addon Two or five supplemental digits.
|
|
2186
|
+
* @param {{gap?:number}} [options]
|
|
2187
|
+
* @returns {BitMatrix}
|
|
2188
|
+
*/
|
|
2189
|
+
function encodeEAN13WithAddon(value, addon, options = {}) {
|
|
2190
|
+
return composeEANAddon(encodeEAN13(value), addon, options);
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
/** @see encodeEAN13WithAddon */
|
|
2194
|
+
function encodeEAN8WithAddon(value, addon, options = {}) {
|
|
2195
|
+
return composeEANAddon(encodeEAN8(value), addon, options);
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
/** @see encodeEAN13WithAddon */
|
|
2199
|
+
function encodeUPCAWithAddon(value, addon, options = {}) {
|
|
2200
|
+
return composeEANAddon(encodeUPCA(value), addon, options);
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2203
|
+
/** @see encodeEAN13WithAddon */
|
|
2204
|
+
function encodeUPCEWithAddon(value, addon, options = {}) {
|
|
2205
|
+
return composeEANAddon(encodeUPCE(value), addon, options);
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
__exports.EAN2_PARITY = EAN2_PARITY;
|
|
2209
|
+
__exports.EAN5_PARITY = EAN5_PARITY;
|
|
2210
|
+
__exports.EAN_ADDON_START = EAN_ADDON_START;
|
|
2211
|
+
__exports.EAN_ADDON_SEPARATOR = EAN_ADDON_SEPARATOR;
|
|
2212
|
+
__exports.EAN2_WIDTH = EAN2_WIDTH;
|
|
2213
|
+
__exports.EAN5_WIDTH = EAN5_WIDTH;
|
|
2214
|
+
__exports.ean5Checksum = ean5Checksum;
|
|
2215
|
+
__exports.ean5CheckDigit = ean5CheckDigit;
|
|
2216
|
+
__exports.ean2Parity = ean2Parity;
|
|
2217
|
+
__exports.ean5Parity = ean5Parity;
|
|
2218
|
+
__exports.encodeEAN2 = encodeEAN2;
|
|
2219
|
+
__exports.encodeEAN5 = encodeEAN5;
|
|
2220
|
+
__exports.encodeEANAddon = encodeEANAddon;
|
|
2221
|
+
__exports.encodeEANAddOn = encodeEANAddOn;
|
|
2222
|
+
__exports.decodeEAN2 = decodeEAN2;
|
|
2223
|
+
__exports.decodeEAN5 = decodeEAN5;
|
|
2224
|
+
__exports.decodeEANAddon = decodeEANAddon;
|
|
2225
|
+
__exports.decodeEANAddOn = decodeEANAddOn;
|
|
2226
|
+
__exports.composeEANAddon = composeEANAddon;
|
|
2227
|
+
__exports.encodeEAN13WithAddon = encodeEAN13WithAddon;
|
|
2228
|
+
__exports.encodeEAN8WithAddon = encodeEAN8WithAddon;
|
|
2229
|
+
__exports.encodeUPCAWithAddon = encodeUPCAWithAddon;
|
|
2230
|
+
__exports.encodeUPCEWithAddon = encodeUPCEWithAddon;
|
|
2231
|
+
};
|
|
2232
|
+
|
|
1826
2233
|
__modules["oned/reader.js"] = function (__require, __exports) {
|
|
1827
2234
|
/**
|
|
1828
2235
|
* Linear barcode reading.
|
|
@@ -2716,7 +3123,10 @@ __modules["oned/index.js"] = function (__require, __exports) {
|
|
|
2716
3123
|
* Linear symbologies.
|
|
2717
3124
|
*
|
|
2718
3125
|
* @module oned
|
|
2719
|
-
*/
|
|
3126
|
+
*/
|
|
3127
|
+
const __reexport1 = __require("oned/addons.js"); __exports.EAN2_PARITY = __reexport1.EAN2_PARITY; __exports.EAN5_PARITY = __reexport1.EAN5_PARITY; __exports.EAN2_WIDTH = __reexport1.EAN2_WIDTH; __exports.EAN5_WIDTH = __reexport1.EAN5_WIDTH; __exports.EAN_ADDON_START = __reexport1.EAN_ADDON_START; __exports.EAN_ADDON_SEPARATOR = __reexport1.EAN_ADDON_SEPARATOR; __exports.ean2Parity = __reexport1.ean2Parity; __exports.ean5Checksum = __reexport1.ean5Checksum; __exports.ean5CheckDigit = __reexport1.ean5CheckDigit; __exports.ean5Parity = __reexport1.ean5Parity; __exports.encodeEAN2 = __reexport1.encodeEAN2; __exports.encodeEAN5 = __reexport1.encodeEAN5; __exports.encodeEANAddon = __reexport1.encodeEANAddon; __exports.encodeEANAddOn = __reexport1.encodeEANAddOn; __exports.decodeEAN2 = __reexport1.decodeEAN2; __exports.decodeEAN5 = __reexport1.decodeEAN5; __exports.decodeEANAddon = __reexport1.decodeEANAddon; __exports.decodeEANAddOn = __reexport1.decodeEANAddOn; __exports.composeEANAddon = __reexport1.composeEANAddon; __exports.encodeEAN13WithAddon = __reexport1.encodeEAN13WithAddon; __exports.encodeEAN8WithAddon = __reexport1.encodeEAN8WithAddon; __exports.encodeUPCAWithAddon = __reexport1.encodeUPCAWithAddon; __exports.encodeUPCEWithAddon = __reexport1.encodeUPCEWithAddon;
|
|
3128
|
+
const __reexport2 = __require("oned/reader.js"); __exports.decodeOneD = __reexport2.decodeOneD; __exports.decodeOneDStrict = __reexport2.decodeOneDStrict; __exports.patternVariance = __reexport2.patternVariance; __exports.recordPattern = __reexport2.recordPattern; __exports.toNarrowWidePattern = __reexport2.toNarrowWidePattern;
|
|
3129
|
+
const { encodeEAN2, encodeEAN5 } = __require("oned/addons.js");
|
|
2720
3130
|
|
|
2721
3131
|
/**
|
|
2722
3132
|
* Writers by format id, for the top-level `encode()` dispatcher.
|
|
@@ -2727,7 +3137,7 @@ __modules["oned/index.js"] = function (__require, __exports) {
|
|
|
2727
3137
|
* failing at runtime.
|
|
2728
3138
|
*
|
|
2729
3139
|
* @type {Record<string, {encode: Function, readable: boolean, label: string}>}
|
|
2730
|
-
*/
|
|
3140
|
+
*/
|
|
2731
3141
|
ean13: { encode: encodeEAN13, readable: true, label: 'EAN-13' },
|
|
2732
3142
|
ean8: { encode: encodeEAN8, readable: true, label: 'EAN-8' },
|
|
2733
3143
|
upca: { encode: encodeUPCA, readable: true, label: 'UPC-A' },
|
|
@@ -2746,8 +3156,13 @@ __modules["oned/index.js"] = function (__require, __exports) {
|
|
|
2746
3156
|
codabar: { encode: encodeCodabar, readable: true, label: 'Codabar' },
|
|
2747
3157
|
code11: { encode: encodeCode11, readable: false, label: 'Code 11' },
|
|
2748
3158
|
msi: { encode: encodeMSI, readable: false, label: 'MSI Plessey' },
|
|
2749
|
-
pharmacode: { encode: encodePharmacode, readable: false, label: 'Pharmacode' },
|
|
2750
|
-
|
|
3159
|
+
pharmacode: { encode: encodePharmacode, readable: false, label: 'Pharmacode' },
|
|
3160
|
+
// Supplements are writable standalone matrices, but their reader is
|
|
3161
|
+
// intentionally exposed through the EAN/UPC add-on helpers rather than the
|
|
3162
|
+
// generic one-dimensional scan pipeline.
|
|
3163
|
+
ean2: { encode: encodeEAN2, readable: false, label: 'EAN-2 supplement' },
|
|
3164
|
+
ean5: { encode: encodeEAN5, readable: false, label: 'EAN-5 supplement' },
|
|
3165
|
+
};
|
|
2751
3166
|
|
|
2752
3167
|
__exports.ONED_FORMATS = ONED_FORMATS;
|
|
2753
3168
|
};
|
|
@@ -12530,112 +12945,1775 @@ const __reexport3 = __require("frameqr/tables.js"); __exports.FRAMEQR_PROFILE =
|
|
|
12530
12945
|
|
|
12531
12946
|
};
|
|
12532
12947
|
|
|
12533
|
-
__modules["
|
|
12948
|
+
__modules["aztecrune/tables.js"] = function (__require, __exports) {
|
|
12534
12949
|
/**
|
|
12535
|
-
*
|
|
12950
|
+
* Aztec Rune geometry.
|
|
12536
12951
|
*
|
|
12537
|
-
*
|
|
12952
|
+
* Aztec Rune is the 11x11, one-byte member of the Aztec family. Two 4-bit
|
|
12953
|
+
* data words and five 4-bit Reed-Solomon check words are XORed with the fixed
|
|
12954
|
+
* Aztec Rune mask and written clockwise on the outer data ring. The finder and
|
|
12955
|
+
* corner orientation marks are independent of the value.
|
|
12956
|
+
*
|
|
12957
|
+
* The constants below are derived from the public Aztec Code specification and
|
|
12958
|
+
* are kept separate from the general Aztec implementation so a normal Aztec
|
|
12959
|
+
* decoder can never accidentally treat an 11x11 Rune as a regular symbol.
|
|
12960
|
+
*
|
|
12961
|
+
* @module aztecrune/tables
|
|
12538
12962
|
*/
|
|
12539
12963
|
const { BitMatrix } = __require("core/bit-matrix.js");
|
|
12964
|
+
const { fieldForWordSize } = __require("aztec/tables.js");
|
|
12965
|
+
const AZTEC_RUNE_SIZE = 11;
|
|
12966
|
+
const AZTEC_RUNE_DATA_BITS = 8;
|
|
12967
|
+
const AZTEC_RUNE_WORD_SIZE = 4;
|
|
12968
|
+
const AZTEC_RUNE_DATA_CODEWORDS = 2;
|
|
12969
|
+
const AZTEC_RUNE_ECC_CODEWORDS = 5;
|
|
12970
|
+
const AZTEC_RUNE_TOTAL_CODEWORDS = AZTEC_RUNE_DATA_CODEWORDS + AZTEC_RUNE_ECC_CODEWORDS;
|
|
12971
|
+
const AZTEC_RUNE_MASK = 0b1010;
|
|
12540
12972
|
|
|
12541
12973
|
/**
|
|
12542
|
-
*
|
|
12543
|
-
*
|
|
12544
|
-
* @property {number} [margin] Quiet-zone modules on every side. Default 4.
|
|
12545
|
-
* @property {string} [dark] Colour of set modules. Default '#000000'.
|
|
12546
|
-
* @property {string} [light] Colour of clear modules, or 'none' for transparent.
|
|
12547
|
-
* @property {number} [barHeight] For 1D symbols: total bar height in pixels.
|
|
12974
|
+
* Data-module coordinates in wire order: clockwise, starting at the top.
|
|
12975
|
+
* Every side contributes seven modules, for 28 bits in total.
|
|
12548
12976
|
*/
|
|
12977
|
+
const AZTEC_RUNE_DATA_POSITIONS = Object.freeze([
|
|
12978
|
+
...Array.from({ length: 7 }, (_, i) => [i + 2, 0]),
|
|
12979
|
+
...Array.from({ length: 7 }, (_, i) => [10, i + 2]),
|
|
12980
|
+
...Array.from({ length: 7 }, (_, i) => [8 - i, 10]),
|
|
12981
|
+
...Array.from({ length: 7 }, (_, i) => [0, 8 - i]),
|
|
12982
|
+
].map(([x, y]) => Object.freeze([x, y])));
|
|
12983
|
+
|
|
12984
|
+
const DATA_KEYS = new Set(AZTEC_RUNE_DATA_POSITIONS.map(([x, y]) => `${x},${y}`));
|
|
12549
12985
|
|
|
12986
|
+
/** @param {number} x @param {number} y @returns {boolean} */
|
|
12987
|
+
function isAztecRuneDataPosition(x, y) {
|
|
12988
|
+
return DATA_KEYS.has(`${x},${y}`);
|
|
12989
|
+
}
|
|
12550
12990
|
/**
|
|
12551
|
-
*
|
|
12552
|
-
*
|
|
12553
|
-
*
|
|
12554
|
-
*
|
|
12555
|
-
* four sides — padding first would leave a quiet zone one module tall against
|
|
12556
|
-
* bars a hundred pixels tall, which no scanner would accept.
|
|
12991
|
+
* Return the value of a structural module. Data positions return `null`.
|
|
12992
|
+
* The bull's-eye has five square rings including its one-module centre; its
|
|
12993
|
+
* even-radius rings are dark. The four corner groups are the orientation marks
|
|
12994
|
+
* described by the Aztec Rune specification.
|
|
12557
12995
|
*
|
|
12558
|
-
* @param {
|
|
12559
|
-
* @
|
|
12996
|
+
* @param {number} x @param {number} y
|
|
12997
|
+
* @returns {boolean|null}
|
|
12560
12998
|
*/
|
|
12561
|
-
function
|
|
12562
|
-
|
|
12563
|
-
|
|
12564
|
-
|
|
12565
|
-
|
|
12566
|
-
const barHeight = options.barHeight ?? null;
|
|
12999
|
+
function aztecRuneStructuralValue(x, y) {
|
|
13000
|
+
if (!Number.isInteger(x) || !Number.isInteger(y) || x < 0 || y < 0 || x >= AZTEC_RUNE_SIZE || y >= AZTEC_RUNE_SIZE) {
|
|
13001
|
+
return null;
|
|
13002
|
+
}
|
|
13003
|
+
if (isAztecRuneDataPosition(x, y)) return null;
|
|
12567
13004
|
|
|
12568
|
-
|
|
12569
|
-
|
|
13005
|
+
const distance = Math.max(Math.abs(x - 5), Math.abs(y - 5));
|
|
13006
|
+
if (distance <= 4) return (distance & 1) === 0;
|
|
12570
13007
|
|
|
12571
|
-
|
|
12572
|
-
|
|
12573
|
-
|
|
12574
|
-
|
|
12575
|
-
|
|
12576
|
-
|
|
12577
|
-
|
|
12578
|
-
|
|
12579
|
-
|
|
13008
|
+
// Corner orientation groups, clockwise from the upper-left corner:
|
|
13009
|
+
// three dark, white-dark-dark, dark-white-white, three white.
|
|
13010
|
+
if ((x === 0 && y <= 1) || (y === 0 && x <= 1)) return true;
|
|
13011
|
+
if ((x === 10 && y <= 1) || (y === 0 && x === 10)) return true;
|
|
13012
|
+
if (x === 9 && y === 0) return false;
|
|
13013
|
+
if (x === 10 && y === 10) return false;
|
|
13014
|
+
if (y === 10 && x >= 0 && x <= 1) return false;
|
|
13015
|
+
if (x === 0 && y >= 9) return false;
|
|
13016
|
+
if (x === 10 && y === 9) return true;
|
|
13017
|
+
|
|
13018
|
+
// All non-data cells are covered by the bull's-eye or the four corners.
|
|
13019
|
+
return false;
|
|
13020
|
+
}
|
|
13021
|
+
|
|
13022
|
+
/** Build only the fixed finder/orientation structure. */
|
|
13023
|
+
function buildAztecRuneStructure() {
|
|
13024
|
+
const matrix = new BitMatrix(AZTEC_RUNE_SIZE);
|
|
13025
|
+
for (let y = 0; y < AZTEC_RUNE_SIZE; y++) {
|
|
13026
|
+
for (let x = 0; x < AZTEC_RUNE_SIZE; x++) {
|
|
13027
|
+
const value = aztecRuneStructuralValue(x, y);
|
|
13028
|
+
if (value === true) matrix.set(x, y);
|
|
12580
13029
|
}
|
|
12581
13030
|
}
|
|
13031
|
+
return matrix;
|
|
13032
|
+
}
|
|
12582
13033
|
|
|
12583
|
-
|
|
13034
|
+
/** Return the field used by Rune data/check words. */
|
|
13035
|
+
function aztecRuneField() {
|
|
13036
|
+
return fieldForWordSize(AZTEC_RUNE_WORD_SIZE);
|
|
13037
|
+
}
|
|
12584
13038
|
|
|
12585
|
-
|
|
12586
|
-
|
|
12587
|
-
|
|
12588
|
-
|
|
12589
|
-
|
|
12590
|
-
|
|
12591
|
-
|
|
12592
|
-
|
|
12593
|
-
|
|
12594
|
-
|
|
12595
|
-
|
|
13039
|
+
/** Validate the fixed Rune contract and coordinate layout. */
|
|
13040
|
+
function validateAztecRuneTables() {
|
|
13041
|
+
const problems = [];
|
|
13042
|
+
if (AZTEC_RUNE_SIZE !== 11) problems.push('Rune symbol size must be 11');
|
|
13043
|
+
if (AZTEC_RUNE_TOTAL_CODEWORDS * AZTEC_RUNE_WORD_SIZE !== 28) problems.push('Rune outer ring must carry 28 bits');
|
|
13044
|
+
if (AZTEC_RUNE_DATA_POSITIONS.length !== 28) problems.push('Rune data ring must contain 28 modules');
|
|
13045
|
+
if (new Set(AZTEC_RUNE_DATA_POSITIONS.map(([x, y]) => `${x},${y}`)).size !== 28) problems.push('Rune data coordinates must be unique');
|
|
13046
|
+
const structure = buildAztecRuneStructure();
|
|
13047
|
+
for (let y = 0; y < AZTEC_RUNE_SIZE; y++) for (let x = 0; x < AZTEC_RUNE_SIZE; x++) {
|
|
13048
|
+
if (isAztecRuneDataPosition(x, y)) continue;
|
|
13049
|
+
const expected = aztecRuneStructuralValue(x, y) === true;
|
|
13050
|
+
if (structure.get(x, y) !== expected) problems.push(`Rune structure mismatch at ${x},${y}`);
|
|
13051
|
+
}
|
|
13052
|
+
return problems;
|
|
12596
13053
|
}
|
|
12597
13054
|
|
|
13055
|
+
__exports.AZTEC_RUNE_SIZE = AZTEC_RUNE_SIZE;
|
|
13056
|
+
__exports.AZTEC_RUNE_DATA_BITS = AZTEC_RUNE_DATA_BITS;
|
|
13057
|
+
__exports.AZTEC_RUNE_WORD_SIZE = AZTEC_RUNE_WORD_SIZE;
|
|
13058
|
+
__exports.AZTEC_RUNE_DATA_CODEWORDS = AZTEC_RUNE_DATA_CODEWORDS;
|
|
13059
|
+
__exports.AZTEC_RUNE_ECC_CODEWORDS = AZTEC_RUNE_ECC_CODEWORDS;
|
|
13060
|
+
__exports.AZTEC_RUNE_TOTAL_CODEWORDS = AZTEC_RUNE_TOTAL_CODEWORDS;
|
|
13061
|
+
__exports.AZTEC_RUNE_MASK = AZTEC_RUNE_MASK;
|
|
13062
|
+
__exports.AZTEC_RUNE_DATA_POSITIONS = AZTEC_RUNE_DATA_POSITIONS;
|
|
13063
|
+
__exports.isAztecRuneDataPosition = isAztecRuneDataPosition;
|
|
13064
|
+
__exports.aztecRuneStructuralValue = aztecRuneStructuralValue;
|
|
13065
|
+
__exports.buildAztecRuneStructure = buildAztecRuneStructure;
|
|
13066
|
+
__exports.aztecRuneField = aztecRuneField;
|
|
13067
|
+
__exports.validateAztecRuneTables = validateAztecRuneTables;
|
|
13068
|
+
};
|
|
13069
|
+
|
|
13070
|
+
__modules["aztecrune/encoder.js"] = function (__require, __exports) {
|
|
12598
13071
|
/**
|
|
12599
|
-
*
|
|
13072
|
+
* Aztec Rune encoder.
|
|
12600
13073
|
*
|
|
12601
|
-
*
|
|
12602
|
-
*
|
|
13074
|
+
* A Rune carries exactly one byte. Numeric strings are accepted for convenient
|
|
13075
|
+
* human-readable input and are normalized to the canonical three-digit text;
|
|
13076
|
+
* binary callers can pass one byte in an ArrayBuffer or typed-array view.
|
|
12603
13077
|
*
|
|
12604
|
-
* @
|
|
12605
|
-
* @returns {[number, number, number, number]}
|
|
13078
|
+
* @module aztecrune/encoder
|
|
12606
13079
|
*/
|
|
12607
|
-
|
|
12608
|
-
|
|
13080
|
+
const { BitMatrix } = __require("core/bit-matrix.js");
|
|
13081
|
+
const { EncodeError } = __require("core/errors.js");
|
|
13082
|
+
const { rsEncode } = __require("core/reed-solomon.js");
|
|
13083
|
+
const { AZTEC_RUNE_DATA_POSITIONS, AZTEC_RUNE_ECC_CODEWORDS, AZTEC_RUNE_MASK, AZTEC_RUNE_SIZE, aztecRuneField, buildAztecRuneStructure } = __require("aztecrune/tables.js");
|
|
12609
13084
|
|
|
12610
|
-
|
|
12611
|
-
|
|
12612
|
-
if (value === '
|
|
13085
|
+
/** @param {unknown} value @returns {number} */
|
|
13086
|
+
function normalizeAztecRuneValue(value) {
|
|
13087
|
+
if (typeof value === 'number') {
|
|
13088
|
+
if (Number.isInteger(value) && value >= 0 && value <= 255) return value;
|
|
13089
|
+
throw new EncodeError('Aztec Rune: numeric value must be an integer from 0 to 255');
|
|
13090
|
+
}
|
|
12613
13091
|
|
|
12614
|
-
if (value
|
|
12615
|
-
|
|
12616
|
-
const
|
|
12617
|
-
if (
|
|
12618
|
-
|
|
12619
|
-
|
|
12620
|
-
|
|
12621
|
-
|
|
12622
|
-
|
|
12623
|
-
|
|
12624
|
-
|
|
12625
|
-
|
|
12626
|
-
|
|
12627
|
-
|
|
12628
|
-
|
|
12629
|
-
|
|
12630
|
-
|
|
12631
|
-
|
|
12632
|
-
|
|
12633
|
-
|
|
12634
|
-
|
|
12635
|
-
|
|
12636
|
-
|
|
12637
|
-
|
|
12638
|
-
|
|
13092
|
+
if (typeof value === 'string') {
|
|
13093
|
+
if (!/^\d{1,3}$/.test(value)) throw new EncodeError('Aztec Rune: text input must contain one to three decimal digits');
|
|
13094
|
+
const numeric = Number(value);
|
|
13095
|
+
if (numeric > 255) throw new EncodeError('Aztec Rune: decimal value must be from 000 to 255');
|
|
13096
|
+
return numeric;
|
|
13097
|
+
}
|
|
13098
|
+
|
|
13099
|
+
let bytes = null;
|
|
13100
|
+
if (value instanceof ArrayBuffer) bytes = new Uint8Array(value);
|
|
13101
|
+
else if (ArrayBuffer.isView(value)) bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
13102
|
+
if (bytes) {
|
|
13103
|
+
if (bytes.length !== 1) throw new EncodeError('Aztec Rune: binary input must contain exactly one byte');
|
|
13104
|
+
return bytes[0];
|
|
13105
|
+
}
|
|
13106
|
+
throw new EncodeError('Aztec Rune: expected a number, decimal string or one-byte binary value');
|
|
13107
|
+
}
|
|
13108
|
+
|
|
13109
|
+
/** @param {number} value @returns {number[]} */
|
|
13110
|
+
function codewordsForValue(value) {
|
|
13111
|
+
const data = [value >>> 4, value & 0x0f];
|
|
13112
|
+
const parity = rsEncode(data, AZTEC_RUNE_ECC_CODEWORDS, aztecRuneField(), 1);
|
|
13113
|
+
return data.concat(parity).map((word) => word ^ AZTEC_RUNE_MASK);
|
|
13114
|
+
}
|
|
13115
|
+
|
|
13116
|
+
/** @param {BitMatrix} matrix @param {number[]} codewords */
|
|
13117
|
+
function writeDataRing(matrix, codewords) {
|
|
13118
|
+
for (let word = 0; word < codewords.length; word++) {
|
|
13119
|
+
for (let bit = 0; bit < 4; bit++) {
|
|
13120
|
+
const at = word * 4 + bit;
|
|
13121
|
+
const [x, y] = AZTEC_RUNE_DATA_POSITIONS[at];
|
|
13122
|
+
matrix.setValue(x, y, ((codewords[word] >>> (3 - bit)) & 1) !== 0);
|
|
13123
|
+
}
|
|
13124
|
+
}
|
|
13125
|
+
}
|
|
13126
|
+
|
|
13127
|
+
/**
|
|
13128
|
+
* Encode one byte as an Aztec Rune.
|
|
13129
|
+
*
|
|
13130
|
+
* @param {number|string|ArrayBuffer|ArrayBufferView} value
|
|
13131
|
+
* @param {{inverted?: boolean}} [options]
|
|
13132
|
+
* @returns {import('../core/bit-matrix.js').BitMatrix & {
|
|
13133
|
+
* format: 'aztecrune', value: number, inverted: boolean
|
|
13134
|
+
* }}
|
|
13135
|
+
*/
|
|
13136
|
+
function encodeAztecRune(value, options = {}) {
|
|
13137
|
+
const numeric = normalizeAztecRuneValue(value);
|
|
13138
|
+
if (options.inverted !== undefined && typeof options.inverted !== 'boolean') {
|
|
13139
|
+
throw new EncodeError('Aztec Rune: inverted must be boolean');
|
|
13140
|
+
}
|
|
13141
|
+
const inverted = options.inverted === true;
|
|
13142
|
+
const matrix = buildAztecRuneStructure();
|
|
13143
|
+
writeDataRing(matrix, codewordsForValue(numeric));
|
|
13144
|
+
if (inverted) {
|
|
13145
|
+
for (let y = 0; y < AZTEC_RUNE_SIZE; y++) for (let x = 0; x < AZTEC_RUNE_SIZE; x++) matrix.flip(x, y);
|
|
13146
|
+
}
|
|
13147
|
+
matrix.format = 'aztecrune';
|
|
13148
|
+
matrix.value = numeric;
|
|
13149
|
+
matrix.inverted = inverted;
|
|
13150
|
+
return matrix;
|
|
13151
|
+
}
|
|
13152
|
+
__exports.codewordsForValue = codewordsForValue;
|
|
13153
|
+
|
|
13154
|
+
__exports.normalizeAztecRuneValue = normalizeAztecRuneValue;
|
|
13155
|
+
__exports.encodeAztecRune = encodeAztecRune;
|
|
13156
|
+
};
|
|
13157
|
+
|
|
13158
|
+
__modules["aztecrune/decoder.js"] = function (__require, __exports) {
|
|
13159
|
+
/**
|
|
13160
|
+
* Aztec Rune decoder.
|
|
13161
|
+
*
|
|
13162
|
+
* The input is a square 11x11 module matrix. Structural modules are checked
|
|
13163
|
+
* before the seven masked GF(16) codewords are Reed-Solomon corrected. The
|
|
13164
|
+
* decoder tries the four in-plane quarter turns and both polarities, allowing
|
|
13165
|
+
* it to consume an oriented sampled image while still rejecting ordinary
|
|
13166
|
+
* Aztec/QR matrices.
|
|
13167
|
+
*
|
|
13168
|
+
* @module aztecrune/decoder
|
|
13169
|
+
*/
|
|
13170
|
+
const { FormatError } = __require("core/errors.js");
|
|
13171
|
+
const { rsDecode } = __require("core/reed-solomon.js");
|
|
13172
|
+
const { AZTEC_RUNE_DATA_CODEWORDS, AZTEC_RUNE_DATA_POSITIONS, AZTEC_RUNE_ECC_CODEWORDS, AZTEC_RUNE_MASK, AZTEC_RUNE_SIZE, aztecRuneField, aztecRuneStructuralValue } = __require("aztecrune/tables.js");
|
|
13173
|
+
|
|
13174
|
+
/** @param {import('../core/bit-matrix.js').BitMatrix} source @param {number} turns */
|
|
13175
|
+
function rotateClockwise(source, turns) {
|
|
13176
|
+
let current = source.clone();
|
|
13177
|
+
for (let turn = 0; turn < turns; turn++) {
|
|
13178
|
+
const out = new source.constructor(current.height, current.width);
|
|
13179
|
+
for (let y = 0; y < current.height; y++) for (let x = 0; x < current.width; x++) {
|
|
13180
|
+
if (current.get(x, y)) out.set(current.height - 1 - y, x);
|
|
13181
|
+
}
|
|
13182
|
+
current = out;
|
|
13183
|
+
}
|
|
13184
|
+
return current;
|
|
13185
|
+
}
|
|
13186
|
+
|
|
13187
|
+
/** @param {import('../core/bit-matrix.js').BitMatrix} matrix */
|
|
13188
|
+
function invert(matrix) {
|
|
13189
|
+
const out = matrix.clone();
|
|
13190
|
+
for (let y = 0; y < out.height; y++) for (let x = 0; x < out.width; x++) out.flip(x, y);
|
|
13191
|
+
return out;
|
|
13192
|
+
}
|
|
13193
|
+
|
|
13194
|
+
/** @param {import('../core/bit-matrix.js').BitMatrix} matrix @param {boolean} inverted */
|
|
13195
|
+
function structureMatches(matrix, inverted) {
|
|
13196
|
+
for (let y = 0; y < AZTEC_RUNE_SIZE; y++) for (let x = 0; x < AZTEC_RUNE_SIZE; x++) {
|
|
13197
|
+
const expected = aztecRuneStructuralValue(x, y);
|
|
13198
|
+
if (expected === null) continue;
|
|
13199
|
+
if (matrix.get(x, y) !== (inverted ? !expected : expected)) return false;
|
|
13200
|
+
}
|
|
13201
|
+
return true;
|
|
13202
|
+
}
|
|
13203
|
+
|
|
13204
|
+
/** @param {import('../core/bit-matrix.js').BitMatrix} matrix @param {boolean} inverted */
|
|
13205
|
+
function readCodewords(matrix, inverted) {
|
|
13206
|
+
const words = new Array(2 + AZTEC_RUNE_ECC_CODEWORDS).fill(0);
|
|
13207
|
+
for (let at = 0; at < AZTEC_RUNE_DATA_POSITIONS.length; at++) {
|
|
13208
|
+
const [x, y] = AZTEC_RUNE_DATA_POSITIONS[at];
|
|
13209
|
+
const bit = matrix.get(x, y) !== inverted;
|
|
13210
|
+
words[at >>> 2] = (words[at >>> 2] << 1) | (bit ? 1 : 0);
|
|
13211
|
+
}
|
|
13212
|
+
return words.map((word) => word ^ AZTEC_RUNE_MASK);
|
|
13213
|
+
}
|
|
13214
|
+
|
|
13215
|
+
/** @param {number} value @param {boolean} inverted @param {number} rotation @param {number} corrections */
|
|
13216
|
+
function result(value, inverted, rotation, corrections) {
|
|
13217
|
+
return {
|
|
13218
|
+
format: 'aztecrune',
|
|
13219
|
+
value,
|
|
13220
|
+
text: String(value).padStart(3, '0'),
|
|
13221
|
+
bytes: Uint8Array.of(value),
|
|
13222
|
+
dimension: AZTEC_RUNE_SIZE,
|
|
13223
|
+
inverted,
|
|
13224
|
+
rotation,
|
|
13225
|
+
corrections,
|
|
13226
|
+
};
|
|
13227
|
+
}
|
|
13228
|
+
|
|
13229
|
+
/**
|
|
13230
|
+
* Decode a square Aztec Rune matrix.
|
|
13231
|
+
*
|
|
13232
|
+
* @param {import('../core/bit-matrix.js').BitMatrix} matrix
|
|
13233
|
+
* @param {{inverted?: boolean|'auto', rotation?: number|'auto'}} [options]
|
|
13234
|
+
* @returns {{format:'aztecrune',value:number,text:string,bytes:Uint8Array,dimension:number,inverted:boolean,rotation:number,corrections:number}}
|
|
13235
|
+
* @throws {FormatError} For non-Rune geometry, structure or uncorrectable data.
|
|
13236
|
+
*/
|
|
13237
|
+
function decodeAztecRune(matrix, options = {}) {
|
|
13238
|
+
if (!matrix || matrix.width !== AZTEC_RUNE_SIZE || matrix.height !== AZTEC_RUNE_SIZE) {
|
|
13239
|
+
throw new FormatError(`Aztec Rune: expected an ${AZTEC_RUNE_SIZE}x${AZTEC_RUNE_SIZE} module matrix`);
|
|
13240
|
+
}
|
|
13241
|
+
const invertedModes = options.inverted === true ? [true] : options.inverted === false ? [false] : [false, true];
|
|
13242
|
+
const rotations = Number.isInteger(options.rotation)
|
|
13243
|
+
? [((options.rotation % 360) + 360) % 360]
|
|
13244
|
+
: [0, 90, 180, 270];
|
|
13245
|
+
|
|
13246
|
+
let checksumError = null;
|
|
13247
|
+
for (const requestedRotation of rotations) {
|
|
13248
|
+
if (requestedRotation % 90 !== 0) continue;
|
|
13249
|
+
// To canonicalize an input rotated clockwise by k degrees, rotate it
|
|
13250
|
+
// counter-clockwise by k. `turns` is the clockwise operation we apply.
|
|
13251
|
+
const turns = (4 - requestedRotation / 90) % 4;
|
|
13252
|
+
const canonicalRotation = requestedRotation;
|
|
13253
|
+
const rotated = turns === 0 ? matrix.clone() : rotateClockwise(matrix, turns);
|
|
13254
|
+
for (const inverted of invertedModes) {
|
|
13255
|
+
const canonical = inverted ? invert(rotated) : rotated;
|
|
13256
|
+
if (!structureMatches(canonical, false)) continue;
|
|
13257
|
+
const words = readCodewords(canonical, false);
|
|
13258
|
+
try {
|
|
13259
|
+
const corrections = rsDecode(words, AZTEC_RUNE_ECC_CODEWORDS, aztecRuneField(), 1);
|
|
13260
|
+
const value = (words[0] << 4) | words[1];
|
|
13261
|
+
return result(value, inverted, canonicalRotation, corrections);
|
|
13262
|
+
} catch (error) {
|
|
13263
|
+
checksumError = error;
|
|
13264
|
+
}
|
|
13265
|
+
}
|
|
13266
|
+
}
|
|
13267
|
+
|
|
13268
|
+
if (checksumError) {
|
|
13269
|
+
throw new FormatError(`Aztec Rune: Reed-Solomon check failed: ${checksumError.message}`);
|
|
13270
|
+
}
|
|
13271
|
+
throw new FormatError('Aztec Rune: structural pattern or orientation is invalid');
|
|
13272
|
+
}
|
|
13273
|
+
__exports.readCodewords = readCodewords; __exports.structureMatches = structureMatches;
|
|
13274
|
+
|
|
13275
|
+
__exports.decodeAztecRune = decodeAztecRune;
|
|
13276
|
+
};
|
|
13277
|
+
|
|
13278
|
+
__modules["aztecrune/detector.js"] = function (__require, __exports) {
|
|
13279
|
+
/**
|
|
13280
|
+
* Detector for Aztec Rune symbols.
|
|
13281
|
+
*
|
|
13282
|
+
* Rune has a fixed 11x11 geometry and a distinctive five-ring bull's-eye. This
|
|
13283
|
+
* detector targets binarized, module-aligned rasters (including an integer
|
|
13284
|
+
* scale, quiet zone and quarter turns). Arbitrary perspective and severe blur
|
|
13285
|
+
* remain detector-level limitations; callers needing those conditions should
|
|
13286
|
+
* pass a rectified 11x11 matrix to decodeAztecRune.
|
|
13287
|
+
*
|
|
13288
|
+
* @module aztecrune/detector
|
|
13289
|
+
*/
|
|
13290
|
+
const { NotFoundError } = __require("core/errors.js");
|
|
13291
|
+
const { BitMatrix } = __require("core/bit-matrix.js");
|
|
13292
|
+
const { decodeAztecRune } = __require("aztecrune/decoder.js");
|
|
13293
|
+
const { AZTEC_RUNE_SIZE } = __require("aztecrune/tables.js");
|
|
13294
|
+
|
|
13295
|
+
/** @typedef {{x:number,y:number}} Point */
|
|
13296
|
+
|
|
13297
|
+
/**
|
|
13298
|
+
* Find connected components of a polarity. Components touching the image
|
|
13299
|
+
* border are ignored when they exceed the plausible module area; this avoids
|
|
13300
|
+
* returning the light background as a candidate while retaining an inverted
|
|
13301
|
+
* Rune's isolated light centre module.
|
|
13302
|
+
*/
|
|
13303
|
+
function components(image, value) {
|
|
13304
|
+
const width = image.width;
|
|
13305
|
+
const height = image.height;
|
|
13306
|
+
const seen = new Uint8Array(width * height);
|
|
13307
|
+
const limit = Math.max(64, Math.floor(width * height * 0.04));
|
|
13308
|
+
const found = [];
|
|
13309
|
+
|
|
13310
|
+
for (let y = 0; y < height; y++) for (let x = 0; x < width; x++) {
|
|
13311
|
+
const start = y * width + x;
|
|
13312
|
+
if (seen[start] || image.get(x, y) !== value) continue;
|
|
13313
|
+
const queue = [[x, y]];
|
|
13314
|
+
seen[start] = 1;
|
|
13315
|
+
let head = 0;
|
|
13316
|
+
let minX = x; let maxX = x; let minY = y; let maxY = y;
|
|
13317
|
+
let count = 0;
|
|
13318
|
+
let touchesBorder = false;
|
|
13319
|
+
|
|
13320
|
+
while (head < queue.length) {
|
|
13321
|
+
const [px, py] = queue[head++];
|
|
13322
|
+
count++;
|
|
13323
|
+
minX = Math.min(minX, px); maxX = Math.max(maxX, px);
|
|
13324
|
+
minY = Math.min(minY, py); maxY = Math.max(maxY, py);
|
|
13325
|
+
if (px === 0 || py === 0 || px === width - 1 || py === height - 1) touchesBorder = true;
|
|
13326
|
+
for (const [nx, ny] of [[px - 1, py], [px + 1, py], [px, py - 1], [px, py + 1]]) {
|
|
13327
|
+
if (nx < 0 || ny < 0 || nx >= width || ny >= height) continue;
|
|
13328
|
+
const at = ny * width + nx;
|
|
13329
|
+
if (!seen[at] && image.get(nx, ny) === value) {
|
|
13330
|
+
seen[at] = 1;
|
|
13331
|
+
queue.push([nx, ny]);
|
|
13332
|
+
}
|
|
13333
|
+
}
|
|
13334
|
+
}
|
|
13335
|
+
|
|
13336
|
+
const boxWidth = maxX - minX + 1;
|
|
13337
|
+
const boxHeight = maxY - minY + 1;
|
|
13338
|
+
if (count <= limit && !touchesBorder &&
|
|
13339
|
+
Math.abs(boxWidth - boxHeight) <= Math.max(1, Math.ceil(Math.max(boxWidth, boxHeight) * 0.35)) &&
|
|
13340
|
+
count >= boxWidth * boxHeight * 0.45) {
|
|
13341
|
+
found.push({ x: (minX + maxX) / 2, y: (minY + maxY) / 2, width: boxWidth, height: boxHeight, count });
|
|
13342
|
+
}
|
|
13343
|
+
}
|
|
13344
|
+
return found.sort((a, b) => b.count - a.count);
|
|
13345
|
+
}
|
|
13346
|
+
/** @param {import('../core/bit-matrix.js').BitMatrix} image @param {Point} center @param {number} pitch */
|
|
13347
|
+
function sample(image, center, pitch) {
|
|
13348
|
+
const matrix = new BitMatrix(AZTEC_RUNE_SIZE);
|
|
13349
|
+
for (let y = 0; y < AZTEC_RUNE_SIZE; y++) for (let x = 0; x < AZTEC_RUNE_SIZE; x++) {
|
|
13350
|
+
const px = Math.round(center.x + (x - 5) * pitch);
|
|
13351
|
+
const py = Math.round(center.y + (y - 5) * pitch);
|
|
13352
|
+
if (px >= 0 && py >= 0 && px < image.width && py < image.height && image.get(px, py)) matrix.set(x, y);
|
|
13353
|
+
}
|
|
13354
|
+
return matrix;
|
|
13355
|
+
}
|
|
13356
|
+
|
|
13357
|
+
function corners(center, pitch) {
|
|
13358
|
+
const half = AZTEC_RUNE_SIZE * pitch / 2;
|
|
13359
|
+
return [
|
|
13360
|
+
{ x: center.x - half, y: center.y - half },
|
|
13361
|
+
{ x: center.x + half, y: center.y - half },
|
|
13362
|
+
{ x: center.x + half, y: center.y + half },
|
|
13363
|
+
{ x: center.x - half, y: center.y + half },
|
|
13364
|
+
];
|
|
13365
|
+
}
|
|
13366
|
+
|
|
13367
|
+
function sameCandidate(left, right) {
|
|
13368
|
+
return Math.hypot(left.center.x - right.center.x, left.center.y - right.center.y) <= Math.max(left.moduleSize, right.moduleSize) * 2;
|
|
13369
|
+
}
|
|
13370
|
+
|
|
13371
|
+
/**
|
|
13372
|
+
* Detect the most prominent Aztec Rune in a binarized image.
|
|
13373
|
+
*
|
|
13374
|
+
* @param {import('../core/bit-matrix.js').BitMatrix} binaryImage
|
|
13375
|
+
* @returns {{corners:Point[],dimension:11,moduleSize:number,matrix:BitMatrix,result:object}|null}
|
|
13376
|
+
*/
|
|
13377
|
+
function detectAztecRune(binaryImage) {
|
|
13378
|
+
if (!binaryImage || !binaryImage.width || !binaryImage.height) {
|
|
13379
|
+
throw new NotFoundError('detectAztecRune: no image supplied');
|
|
13380
|
+
}
|
|
13381
|
+
const candidates = [];
|
|
13382
|
+
for (const value of [true, false]) {
|
|
13383
|
+
for (const component of components(binaryImage, value)) {
|
|
13384
|
+
const pitch = (component.width + component.height) / 2;
|
|
13385
|
+
if (pitch < 0.8) continue;
|
|
13386
|
+
const matrix = sample(binaryImage, component, pitch);
|
|
13387
|
+
let decoded;
|
|
13388
|
+
try { decoded = decodeAztecRune(matrix); } catch { continue; }
|
|
13389
|
+
const candidate = {
|
|
13390
|
+
center: component,
|
|
13391
|
+
corners: corners(component, pitch),
|
|
13392
|
+
dimension: AZTEC_RUNE_SIZE,
|
|
13393
|
+
moduleSize: pitch,
|
|
13394
|
+
matrix,
|
|
13395
|
+
result: decoded,
|
|
13396
|
+
};
|
|
13397
|
+
if (!candidates.some((entry) => sameCandidate(entry, candidate))) candidates.push(candidate);
|
|
13398
|
+
}
|
|
13399
|
+
}
|
|
13400
|
+
candidates.sort((a, b) => b.moduleSize - a.moduleSize);
|
|
13401
|
+
const best = candidates[0];
|
|
13402
|
+
if (!best) return null;
|
|
13403
|
+
delete best.center;
|
|
13404
|
+
return best;
|
|
13405
|
+
}
|
|
13406
|
+
|
|
13407
|
+
/** Detect and decode one Aztec Rune, or return `null` when none is verified. */
|
|
13408
|
+
function detectAndDecodeAztecRune(binaryImage) {
|
|
13409
|
+
let detection;
|
|
13410
|
+
try { detection = detectAztecRune(binaryImage); } catch { return null; }
|
|
13411
|
+
if (!detection) return null;
|
|
13412
|
+
return { ...detection.result, corners: detection.corners, moduleSize: detection.moduleSize };
|
|
13413
|
+
}
|
|
13414
|
+
|
|
13415
|
+
__exports.detectAztecRune = detectAztecRune;
|
|
13416
|
+
__exports.detectAndDecodeAztecRune = detectAndDecodeAztecRune;
|
|
13417
|
+
};
|
|
13418
|
+
|
|
13419
|
+
__modules["aztecrune/index.js"] = function (__require, __exports) {
|
|
13420
|
+
/** Aztec Rune entry points. @module aztecrune */
|
|
13421
|
+
const __reexport0 = __require("aztecrune/encoder.js"); __exports.encodeAztecRune = __reexport0.encodeAztecRune; __exports.normalizeAztecRuneValue = __reexport0.normalizeAztecRuneValue;
|
|
13422
|
+
const __reexport1 = __require("aztecrune/decoder.js"); __exports.decodeAztecRune = __reexport1.decodeAztecRune;
|
|
13423
|
+
const __reexport2 = __require("aztecrune/detector.js"); __exports.detectAztecRune = __reexport2.detectAztecRune; __exports.detectAndDecodeAztecRune = __reexport2.detectAndDecodeAztecRune;
|
|
13424
|
+
const __reexport3 = __require("aztecrune/tables.js"); __exports.AZTEC_RUNE_SIZE = __reexport3.AZTEC_RUNE_SIZE; __exports.AZTEC_RUNE_DATA_BITS = __reexport3.AZTEC_RUNE_DATA_BITS; __exports.AZTEC_RUNE_WORD_SIZE = __reexport3.AZTEC_RUNE_WORD_SIZE; __exports.AZTEC_RUNE_DATA_CODEWORDS = __reexport3.AZTEC_RUNE_DATA_CODEWORDS; __exports.AZTEC_RUNE_ECC_CODEWORDS = __reexport3.AZTEC_RUNE_ECC_CODEWORDS; __exports.AZTEC_RUNE_TOTAL_CODEWORDS = __reexport3.AZTEC_RUNE_TOTAL_CODEWORDS; __exports.AZTEC_RUNE_MASK = __reexport3.AZTEC_RUNE_MASK; __exports.AZTEC_RUNE_DATA_POSITIONS = __reexport3.AZTEC_RUNE_DATA_POSITIONS; __exports.aztecRuneStructuralValue = __reexport3.aztecRuneStructuralValue; __exports.buildAztecRuneStructure = __reexport3.buildAztecRuneStructure; __exports.aztecRuneField = __reexport3.aztecRuneField; __exports.validateAztecRuneTables = __reexport3.validateAztecRuneTables;
|
|
13425
|
+
|
|
13426
|
+
|
|
13427
|
+
};
|
|
13428
|
+
|
|
13429
|
+
__modules["compactpdf417/tables.js"] = function (__require, __exports) {
|
|
13430
|
+
/**
|
|
13431
|
+
* Compact (truncated) PDF417 layout.
|
|
13432
|
+
*
|
|
13433
|
+
* Compact PDF417 is a geometric variant of PDF417, not a new high-level
|
|
13434
|
+
* compaction mode. It keeps the same codeword, cluster, row-indicator,
|
|
13435
|
+
* Reed–Solomon and Text/Byte/Numeric compaction rules, while omitting each
|
|
13436
|
+
* row's right row indicator and replacing the normal stop pattern with a
|
|
13437
|
+
* single dark module. The resulting symbol remains distinguishable from the
|
|
13438
|
+
* ordinary PDF417 layout by its width and row terminator.
|
|
13439
|
+
*
|
|
13440
|
+
* @module compactpdf417/tables
|
|
13441
|
+
*/
|
|
13442
|
+
const { EncodeError } = __require("core/errors.js");
|
|
13443
|
+
|
|
13444
|
+
/** PDF417 start pattern, in module widths. */
|
|
13445
|
+
const COMPACT_PDF417_START = '81111113';
|
|
13446
|
+
|
|
13447
|
+
/** Binary module representation of the start pattern. */
|
|
13448
|
+
const COMPACT_PDF417_START_BITS = '11111111010101000';
|
|
13449
|
+
|
|
13450
|
+
/** Compact PDF417's reduced stop is one dark module. */
|
|
13451
|
+
const COMPACT_PDF417_STOP_MODULES = 1;
|
|
13452
|
+
|
|
13453
|
+
/** Minimum/maximum number of rows and data columns. */
|
|
13454
|
+
const COMPACT_PDF417_LIMITS = Object.freeze({
|
|
13455
|
+
minRows: 3,
|
|
13456
|
+
maxRows: 90,
|
|
13457
|
+
minColumns: 1,
|
|
13458
|
+
maxColumns: 30,
|
|
13459
|
+
maxCodewords: 928,
|
|
13460
|
+
});
|
|
13461
|
+
|
|
13462
|
+
/**
|
|
13463
|
+
* Return the printed width in modules for a compact symbol.
|
|
13464
|
+
*
|
|
13465
|
+
* 17 start + 17 left indicator + 17 per codeword column + 1 reduced stop.
|
|
13466
|
+
* @param {number} columns
|
|
13467
|
+
*/
|
|
13468
|
+
function compactPdf417Width(columns) {
|
|
13469
|
+
if (!Number.isInteger(columns) || columns < 1 || columns > 30) {
|
|
13470
|
+
throw new RangeError(`Compact PDF417: columns must be an integer in 1..30, got ${columns}`);
|
|
13471
|
+
}
|
|
13472
|
+
return 35 + columns * 17;
|
|
13473
|
+
}
|
|
13474
|
+
|
|
13475
|
+
/**
|
|
13476
|
+
* Validate a compact matrix geometry and return its dimensions.
|
|
13477
|
+
*
|
|
13478
|
+
* @param {number} width
|
|
13479
|
+
* @param {number} height
|
|
13480
|
+
* @param {number} rowHeight
|
|
13481
|
+
*/
|
|
13482
|
+
function compactPdf417Geometry(width, height, rowHeight = 3) {
|
|
13483
|
+
if (!Number.isInteger(width) || !Number.isInteger(height)) {
|
|
13484
|
+
throw new RangeError('Compact PDF417: matrix dimensions must be integers');
|
|
13485
|
+
}
|
|
13486
|
+
if (!Number.isInteger(rowHeight) || rowHeight < 1) {
|
|
13487
|
+
throw new RangeError('Compact PDF417: rowHeight must be a positive integer');
|
|
13488
|
+
}
|
|
13489
|
+
if ((width - 35) % 17 !== 0) {
|
|
13490
|
+
throw new RangeError(`Compact PDF417: width ${width} does not match the compact layout`);
|
|
13491
|
+
}
|
|
13492
|
+
const columns = (width - 35) / 17;
|
|
13493
|
+
const rows = height / rowHeight;
|
|
13494
|
+
if (!Number.isInteger(rows) || rows < 3 || rows > 90) {
|
|
13495
|
+
throw new RangeError(`Compact PDF417: rows must be an integer in 3..90, got ${rows}`);
|
|
13496
|
+
}
|
|
13497
|
+
if (columns < 1 || columns > 30) {
|
|
13498
|
+
throw new RangeError(`Compact PDF417: columns must be an integer in 1..30, got ${columns}`);
|
|
13499
|
+
}
|
|
13500
|
+
return { rows, columns, rowHeight, width, height };
|
|
13501
|
+
}
|
|
13502
|
+
|
|
13503
|
+
/**
|
|
13504
|
+
* Validate encoder dimensions before codeword packing.
|
|
13505
|
+
* @param {object} options
|
|
13506
|
+
*/
|
|
13507
|
+
function validateCompactPdf417Options(options = {}) {
|
|
13508
|
+
const { minRows, maxRows, minColumns, maxColumns } = COMPACT_PDF417_LIMITS;
|
|
13509
|
+
const rowHeight = options.rowHeight ?? 3;
|
|
13510
|
+
if (!Number.isInteger(rowHeight) || rowHeight < 3) {
|
|
13511
|
+
throw new EncodeError('Compact PDF417: rowHeight must be an integer of at least 3');
|
|
13512
|
+
}
|
|
13513
|
+
for (const [name, value, min, max] of [
|
|
13514
|
+
['rows', options.rows, minRows, maxRows],
|
|
13515
|
+
['columns', options.columns, minColumns, maxColumns],
|
|
13516
|
+
]) {
|
|
13517
|
+
if (value !== undefined && (!Number.isInteger(value) || value < min || value > max)) {
|
|
13518
|
+
throw new EncodeError(`Compact PDF417: ${name} must be an integer in ${min}..${max}`);
|
|
13519
|
+
}
|
|
13520
|
+
}
|
|
13521
|
+
if (options.aspectRatio !== undefined &&
|
|
13522
|
+
(!Number.isFinite(options.aspectRatio) || options.aspectRatio <= 0)) {
|
|
13523
|
+
throw new EncodeError('Compact PDF417: aspectRatio must be positive');
|
|
13524
|
+
}
|
|
13525
|
+
return rowHeight;
|
|
13526
|
+
}
|
|
13527
|
+
|
|
13528
|
+
/**
|
|
13529
|
+
* The row indicator values used by ordinary PDF417 are retained unchanged.
|
|
13530
|
+
* Compact symbols omit only the right indicator, so the left indicator still
|
|
13531
|
+
* carries the row group, row count, error-correction level and column count.
|
|
13532
|
+
*/
|
|
13533
|
+
function compactPdf417Indicators(row, rows, columns, level) {
|
|
13534
|
+
const group = Math.floor(row / 3);
|
|
13535
|
+
const y = Math.floor((rows - 1) / 3);
|
|
13536
|
+
const z = level * 3 + (rows - 1) % 3;
|
|
13537
|
+
const v = columns - 1;
|
|
13538
|
+
if (row % 3 === 0) return 30 * group + y;
|
|
13539
|
+
if (row % 3 === 1) return 30 * group + z;
|
|
13540
|
+
return 30 * group + v;
|
|
13541
|
+
}
|
|
13542
|
+
|
|
13543
|
+
/**
|
|
13544
|
+
* Return all standard ECC levels which agree with the observed left
|
|
13545
|
+
* indicators. This is kept as a table helper so decoder and tests share the
|
|
13546
|
+
* same compact-layout rule.
|
|
13547
|
+
*/
|
|
13548
|
+
function compactPdf417MatchingLevels(leftIndicators, rows, columns) {
|
|
13549
|
+
const matches = [];
|
|
13550
|
+
for (let level = 0; level <= 8; level++) {
|
|
13551
|
+
if (leftIndicators.every((value, row) =>
|
|
13552
|
+
value === compactPdf417Indicators(row, rows, columns, level))) matches.push(level);
|
|
13553
|
+
}
|
|
13554
|
+
return matches;
|
|
13555
|
+
}
|
|
13556
|
+
|
|
13557
|
+
/** Validate representative layout invariants. */
|
|
13558
|
+
function validateCompactPdf417Tables() {
|
|
13559
|
+
const problems = [];
|
|
13560
|
+
for (const columns of [1, 2, 3, 10, 30]) {
|
|
13561
|
+
const width = compactPdf417Width(columns);
|
|
13562
|
+
if (width !== 35 + columns * 17) problems.push(`columns ${columns}: width mismatch`);
|
|
13563
|
+
}
|
|
13564
|
+
for (const rows of [3, 4, 5, 6, 90]) {
|
|
13565
|
+
const left = Array.from({ length: rows }, (_, row) => compactPdf417Indicators(row, rows, 3, 2));
|
|
13566
|
+
if (compactPdf417MatchingLevels(left, rows, 3).length !== 1) {
|
|
13567
|
+
problems.push(`rows ${rows}: row indicators do not identify one ECC level`);
|
|
13568
|
+
}
|
|
13569
|
+
}
|
|
13570
|
+
return problems;
|
|
13571
|
+
}
|
|
13572
|
+
|
|
13573
|
+
__exports.COMPACT_PDF417_START = COMPACT_PDF417_START;
|
|
13574
|
+
__exports.COMPACT_PDF417_START_BITS = COMPACT_PDF417_START_BITS;
|
|
13575
|
+
__exports.COMPACT_PDF417_STOP_MODULES = COMPACT_PDF417_STOP_MODULES;
|
|
13576
|
+
__exports.COMPACT_PDF417_LIMITS = COMPACT_PDF417_LIMITS;
|
|
13577
|
+
__exports.compactPdf417Width = compactPdf417Width;
|
|
13578
|
+
__exports.compactPdf417Geometry = compactPdf417Geometry;
|
|
13579
|
+
__exports.validateCompactPdf417Options = validateCompactPdf417Options;
|
|
13580
|
+
__exports.compactPdf417Indicators = compactPdf417Indicators;
|
|
13581
|
+
__exports.compactPdf417MatchingLevels = compactPdf417MatchingLevels;
|
|
13582
|
+
__exports.validateCompactPdf417Tables = validateCompactPdf417Tables;
|
|
13583
|
+
};
|
|
13584
|
+
|
|
13585
|
+
__modules["compactpdf417/encoder.js"] = function (__require, __exports) {
|
|
13586
|
+
/** Compact PDF417 (truncated PDF417) encoder. @module compactpdf417/encoder */
|
|
13587
|
+
const { BitMatrix } = __require("core/bit-matrix.js");
|
|
13588
|
+
const { EncodeError } = __require("core/errors.js");
|
|
13589
|
+
const { compactPdf417 } = __require("pdf417/compaction.js");
|
|
13590
|
+
const { pdf417ErrorCorrection, pdf417EccLength } = __require("pdf417/error-correction.js");
|
|
13591
|
+
const { pdf417PatternForCodeword } = __require("pdf417/tables.js");
|
|
13592
|
+
const { COMPACT_PDF417_START, compactPdf417Indicators, compactPdf417Width, validateCompactPdf417Options } = __require("compactpdf417/tables.js");
|
|
13593
|
+
|
|
13594
|
+
function appendWidths(matrix, y, x, sequence, height) {
|
|
13595
|
+
let dark = true;
|
|
13596
|
+
for (const digit of sequence) {
|
|
13597
|
+
const width = digit.charCodeAt(0) - 48;
|
|
13598
|
+
if (!Number.isInteger(width) || width < 1 || width > 8) {
|
|
13599
|
+
throw new EncodeError('Compact PDF417: invalid module-width sequence');
|
|
13600
|
+
}
|
|
13601
|
+
if (dark) matrix.setRegion(x, y, width, height);
|
|
13602
|
+
x += width;
|
|
13603
|
+
dark = !dark;
|
|
13604
|
+
}
|
|
13605
|
+
return x;
|
|
13606
|
+
}
|
|
13607
|
+
|
|
13608
|
+
function patternSequence(pattern) {
|
|
13609
|
+
return pattern.toString(2).padStart(17, '0').replace(/0+|1+/g, (run) => String(run.length));
|
|
13610
|
+
}
|
|
13611
|
+
|
|
13612
|
+
function dimensions(needed, level, options, rowHeight) {
|
|
13613
|
+
const ecc = pdf417EccLength(level);
|
|
13614
|
+
let best = null;
|
|
13615
|
+
for (let rows = options.rows ?? 3; rows <= (options.rows ?? 90); rows++) {
|
|
13616
|
+
for (let columns = options.columns ?? 1; columns <= (options.columns ?? 30); columns++) {
|
|
13617
|
+
if (rows * columns > 928 || rows * columns - ecc < needed) continue;
|
|
13618
|
+
const ratio = compactPdf417Width(columns) / (rows * rowHeight);
|
|
13619
|
+
const score = (rows * columns - ecc - needed) * 10 +
|
|
13620
|
+
Math.abs(ratio - (options.aspectRatio ?? 3));
|
|
13621
|
+
if (!best || score < best.score) best = { rows, columns, score };
|
|
13622
|
+
}
|
|
13623
|
+
}
|
|
13624
|
+
if (!best) {
|
|
13625
|
+
throw new EncodeError(
|
|
13626
|
+
'Compact PDF417: payload does not fit the requested dimensions and error correction level'
|
|
13627
|
+
);
|
|
13628
|
+
}
|
|
13629
|
+
return best;
|
|
13630
|
+
}
|
|
13631
|
+
|
|
13632
|
+
/**
|
|
13633
|
+
* Encode Compact PDF417.
|
|
13634
|
+
*
|
|
13635
|
+
* High-level Text/Byte/Numeric compaction is intentionally delegated to the
|
|
13636
|
+
* existing PDF417 compaction implementation. `compact` here describes only
|
|
13637
|
+
* the physical truncated layout: right row indicators are omitted and the
|
|
13638
|
+
* stop pattern is reduced to one dark module.
|
|
13639
|
+
*
|
|
13640
|
+
* @param {string|Uint8Array|number[]} value
|
|
13641
|
+
* @param {object} [options]
|
|
13642
|
+
* @returns {import('../core/bit-matrix.js').BitMatrix}
|
|
13643
|
+
*/
|
|
13644
|
+
function encodeCompactPDF417(value, options = {}) {
|
|
13645
|
+
const rowHeight = validateCompactPdf417Options(options);
|
|
13646
|
+
const level = options.eccLevel ?? 2;
|
|
13647
|
+
if (!Number.isInteger(level) || level < 0 || level > 8) {
|
|
13648
|
+
throw new EncodeError('Compact PDF417: eccLevel must be an integer in 0..8');
|
|
13649
|
+
}
|
|
13650
|
+
|
|
13651
|
+
const payload = compactPdf417(value, { compaction: options.compaction, charset: options.charset });
|
|
13652
|
+
const { rows, columns } = dimensions(payload.length + 1, level, options, rowHeight);
|
|
13653
|
+
const eccLength = pdf417EccLength(level);
|
|
13654
|
+
const dataLength = rows * columns - eccLength;
|
|
13655
|
+
const data = [dataLength, ...payload];
|
|
13656
|
+
while (data.length < dataLength) data.push(900);
|
|
13657
|
+
const codewords = data.concat(pdf417ErrorCorrection(data, level));
|
|
13658
|
+
|
|
13659
|
+
const matrix = new BitMatrix(compactPdf417Width(columns), rows * rowHeight);
|
|
13660
|
+
for (let row = 0; row < rows; row++) {
|
|
13661
|
+
const y = row * rowHeight;
|
|
13662
|
+
const cluster = (row % 3) * 3;
|
|
13663
|
+
let x = appendWidths(matrix, y, 0, COMPACT_PDF417_START, rowHeight);
|
|
13664
|
+
const left = compactPdf417Indicators(row, rows, columns, level);
|
|
13665
|
+
x = appendWidths(matrix, y, x, patternSequence(pdf417PatternForCodeword(left, cluster)), rowHeight);
|
|
13666
|
+
for (let column = 0; column < columns; column++) {
|
|
13667
|
+
const codeword = codewords[row * columns + column];
|
|
13668
|
+
x = appendWidths(matrix, y, x,
|
|
13669
|
+
patternSequence(pdf417PatternForCodeword(codeword, cluster)), rowHeight);
|
|
13670
|
+
}
|
|
13671
|
+
// Compact PDF417 terminates every row with one dark module, not the normal
|
|
13672
|
+
// right indicator plus 18-module stop pattern.
|
|
13673
|
+
matrix.setRegion(x, y, 1, rowHeight);
|
|
13674
|
+
x++;
|
|
13675
|
+
if (x !== matrix.width) throw new EncodeError('Compact PDF417: internal row width mismatch');
|
|
13676
|
+
}
|
|
13677
|
+
|
|
13678
|
+
matrix.compactPdf417 = {
|
|
13679
|
+
rows,
|
|
13680
|
+
columns,
|
|
13681
|
+
eccLevel: level,
|
|
13682
|
+
rowHeight,
|
|
13683
|
+
codewords,
|
|
13684
|
+
layout: 'compact',
|
|
13685
|
+
};
|
|
13686
|
+
return matrix;
|
|
13687
|
+
}
|
|
13688
|
+
__exports.compactPdf417Dimensions = dimensions;
|
|
13689
|
+
|
|
13690
|
+
__exports.encodeCompactPDF417 = encodeCompactPDF417;
|
|
13691
|
+
};
|
|
13692
|
+
|
|
13693
|
+
__modules["compactpdf417/decoder.js"] = function (__require, __exports) {
|
|
13694
|
+
/** Compact PDF417 decoder. @module compactpdf417/decoder */
|
|
13695
|
+
const { FormatError } = __require("core/errors.js");
|
|
13696
|
+
const { decodePdf417CompactionDetailed } = __require("pdf417/compaction.js");
|
|
13697
|
+
const { pdf417CorrectErrors, pdf417EccLength } = __require("pdf417/error-correction.js");
|
|
13698
|
+
const { pdf417CodewordForPattern } = __require("pdf417/tables.js");
|
|
13699
|
+
const { COMPACT_PDF417_START_BITS, compactPdf417Geometry, compactPdf417Indicators, compactPdf417MatchingLevels } = __require("compactpdf417/tables.js");
|
|
13700
|
+
|
|
13701
|
+
function bits(matrix, y, x, width) {
|
|
13702
|
+
let value = 0;
|
|
13703
|
+
for (let index = 0; index < width; index++) value = (value << 1) | (matrix.get(x + index, y) ? 1 : 0);
|
|
13704
|
+
return value;
|
|
13705
|
+
}
|
|
13706
|
+
|
|
13707
|
+
function patternString(matrix, y, x, width) {
|
|
13708
|
+
return bits(matrix, y, x, width).toString(2).padStart(width, '0');
|
|
13709
|
+
}
|
|
13710
|
+
|
|
13711
|
+
/**
|
|
13712
|
+
* Decode a compact/truncated PDF417 module matrix.
|
|
13713
|
+
*
|
|
13714
|
+
* The high-level payload uses the normal PDF417 Text/Byte/Numeric compaction
|
|
13715
|
+
* rules. This function only changes the physical row parser: no right row
|
|
13716
|
+
* indicator is expected and the final module of each row must be dark.
|
|
13717
|
+
*
|
|
13718
|
+
* @param {import('../core/bit-matrix.js').BitMatrix} matrix
|
|
13719
|
+
* @param {object} [options]
|
|
13720
|
+
* @param {number} [options.rowHeight]
|
|
13721
|
+
*/
|
|
13722
|
+
function decodeCompactPDF417(matrix, options = {}) {
|
|
13723
|
+
if (!matrix?.width || !matrix?.height) throw new FormatError('Compact PDF417: no matrix supplied');
|
|
13724
|
+
const rowHeight = options.rowHeight ?? matrix.compactPdf417?.rowHeight ?? 3;
|
|
13725
|
+
let geometry;
|
|
13726
|
+
try { geometry = compactPdf417Geometry(matrix.width, matrix.height, rowHeight); }
|
|
13727
|
+
catch (error) { throw new FormatError(error.message); }
|
|
13728
|
+
|
|
13729
|
+
const { rows, columns } = geometry;
|
|
13730
|
+
const all = [];
|
|
13731
|
+
const erasures = [];
|
|
13732
|
+
const leftIndicators = [];
|
|
13733
|
+
|
|
13734
|
+
for (let row = 0; row < rows; row++) {
|
|
13735
|
+
const y = row * rowHeight;
|
|
13736
|
+
if (patternString(matrix, y, 0, 17) !== COMPACT_PDF417_START_BITS) {
|
|
13737
|
+
throw new FormatError('Compact PDF417: missing start pattern');
|
|
13738
|
+
}
|
|
13739
|
+
const cluster = (row % 3) * 3;
|
|
13740
|
+
const leftDecoded = pdf417CodewordForPattern(bits(matrix, y, 17, 17));
|
|
13741
|
+
if (!leftDecoded || leftDecoded.cluster !== cluster) {
|
|
13742
|
+
throw new FormatError('Compact PDF417: invalid left row indicator');
|
|
13743
|
+
}
|
|
13744
|
+
leftIndicators.push(leftDecoded.codeword);
|
|
13745
|
+
|
|
13746
|
+
const dataStart = 34;
|
|
13747
|
+
const stopX = dataStart + columns * 17;
|
|
13748
|
+
if (!matrix.get(stopX, y)) throw new FormatError('Compact PDF417: missing reduced stop module');
|
|
13749
|
+
for (let column = 0; column < columns; column++) {
|
|
13750
|
+
const decoded = pdf417CodewordForPattern(bits(matrix, y, dataStart + column * 17, 17));
|
|
13751
|
+
if (!decoded || decoded.cluster !== cluster) {
|
|
13752
|
+
erasures.push(all.length);
|
|
13753
|
+
all.push(0);
|
|
13754
|
+
} else {
|
|
13755
|
+
all.push(decoded.codeword);
|
|
13756
|
+
}
|
|
13757
|
+
}
|
|
13758
|
+
}
|
|
13759
|
+
|
|
13760
|
+
const levels = compactPdf417MatchingLevels(leftIndicators, rows, columns);
|
|
13761
|
+
if (levels.length !== 1) throw new FormatError('Compact PDF417: row indicator mismatch');
|
|
13762
|
+
const level = levels[0];
|
|
13763
|
+
const eccLength = pdf417EccLength(level);
|
|
13764
|
+
if (all.length <= eccLength) throw new FormatError('Compact PDF417: insufficient codewords for ECC');
|
|
13765
|
+
|
|
13766
|
+
const corrected = all.slice();
|
|
13767
|
+
const corrections = pdf417CorrectErrors(corrected, level, erasures);
|
|
13768
|
+
const length = corrected[0];
|
|
13769
|
+
if (length < 1 || length > corrected.length - eccLength) {
|
|
13770
|
+
throw new FormatError('Compact PDF417: invalid symbol length descriptor');
|
|
13771
|
+
}
|
|
13772
|
+
const payload = corrected.slice(1, length);
|
|
13773
|
+
const decoded = decodePdf417CompactionDetailed(payload);
|
|
13774
|
+
return {
|
|
13775
|
+
...decoded,
|
|
13776
|
+
format: 'compact-pdf417',
|
|
13777
|
+
compact: true,
|
|
13778
|
+
codewords: corrected,
|
|
13779
|
+
rows,
|
|
13780
|
+
columns,
|
|
13781
|
+
eccLevel: level,
|
|
13782
|
+
rowHeight,
|
|
13783
|
+
corrections,
|
|
13784
|
+
};
|
|
13785
|
+
}
|
|
13786
|
+
|
|
13787
|
+
__exports.decodeCompactPDF417 = decodeCompactPDF417;
|
|
13788
|
+
};
|
|
13789
|
+
|
|
13790
|
+
__modules["compactpdf417/detector.js"] = function (__require, __exports) {
|
|
13791
|
+
/** Compact PDF417 detector for clean, integer-scaled rasters. @module compactpdf417/detector */
|
|
13792
|
+
const { BitMatrix } = __require("core/bit-matrix.js");
|
|
13793
|
+
const { compactPdf417Width } = __require("compactpdf417/tables.js");
|
|
13794
|
+
const { decodeCompactPDF417 } = __require("compactpdf417/decoder.js");
|
|
13795
|
+
|
|
13796
|
+
function rotateClockwise(source) {
|
|
13797
|
+
const out = new BitMatrix(source.height, source.width);
|
|
13798
|
+
for (let y = 0; y < source.height; y++) {
|
|
13799
|
+
for (let x = 0; x < source.width; x++) {
|
|
13800
|
+
if (source.get(x, y)) out.set(source.height - 1 - y, x);
|
|
13801
|
+
}
|
|
13802
|
+
}
|
|
13803
|
+
return out;
|
|
13804
|
+
}
|
|
13805
|
+
function cropAndDownsample(source, box, width, height, scale) {
|
|
13806
|
+
const out = new BitMatrix(width, height);
|
|
13807
|
+
for (let y = 0; y < height; y++) {
|
|
13808
|
+
for (let x = 0; x < width; x++) {
|
|
13809
|
+
let dark = 0;
|
|
13810
|
+
for (let dy = 0; dy < scale; dy++) {
|
|
13811
|
+
for (let dx = 0; dx < scale; dx++) {
|
|
13812
|
+
if (source.get(box.x + x * scale + dx, box.y + y * scale + dy)) dark++;
|
|
13813
|
+
}
|
|
13814
|
+
}
|
|
13815
|
+
if (dark * 2 >= scale * scale) out.set(x, y);
|
|
13816
|
+
}
|
|
13817
|
+
}
|
|
13818
|
+
return out;
|
|
13819
|
+
}
|
|
13820
|
+
|
|
13821
|
+
function cornersFor(box) {
|
|
13822
|
+
return [
|
|
13823
|
+
{ x: box.x, y: box.y },
|
|
13824
|
+
{ x: box.x + box.width, y: box.y },
|
|
13825
|
+
{ x: box.x + box.width, y: box.y + box.height },
|
|
13826
|
+
{ x: box.x, y: box.y + box.height },
|
|
13827
|
+
];
|
|
13828
|
+
}
|
|
13829
|
+
|
|
13830
|
+
function mapCorners(corners, toOriginal) {
|
|
13831
|
+
return corners.map((point) => toOriginal(point));
|
|
13832
|
+
}
|
|
13833
|
+
|
|
13834
|
+
/**
|
|
13835
|
+
* Detect one Compact PDF417 symbol in a binarized raster.
|
|
13836
|
+
*
|
|
13837
|
+
* The clean-raster detector uses the dark bounding box and enumerates legal
|
|
13838
|
+
* compact widths, integer module scales, row counts and row heights. It is
|
|
13839
|
+
* deliberately conservative: arbitrary perspective, non-integer resampling,
|
|
13840
|
+
* grayscale thresholding and damaged stop bars belong to a future photo
|
|
13841
|
+
* detector and are not claimed here.
|
|
13842
|
+
*
|
|
13843
|
+
* @param {import('../core/bit-matrix.js').BitMatrix} binaryImage
|
|
13844
|
+
* @param {object} [options]
|
|
13845
|
+
* @param {number} [options.rowHeight] Restrict the row-height search.
|
|
13846
|
+
* @returns {object|null}
|
|
13847
|
+
*/
|
|
13848
|
+
function detectCompactPDF417(binaryImage, options = {}) {
|
|
13849
|
+
if (!binaryImage?.width || !binaryImage?.height || typeof binaryImage.get !== 'function') return null;
|
|
13850
|
+
|
|
13851
|
+
let oriented = binaryImage;
|
|
13852
|
+
let toOriginal = (point) => ({ x: point.x, y: point.y });
|
|
13853
|
+
for (let rotation = 0; rotation < 4; rotation++) {
|
|
13854
|
+
const bounds = oriented.getBounds();
|
|
13855
|
+
if (bounds) {
|
|
13856
|
+
for (let columns = 1; columns <= 30; columns++) {
|
|
13857
|
+
const width = compactPdf417Width(columns);
|
|
13858
|
+
const scale = bounds.width / width;
|
|
13859
|
+
if (!Number.isInteger(scale) || scale < 1) continue;
|
|
13860
|
+
const baseHeight = bounds.height / scale;
|
|
13861
|
+
const rowHeights = Number.isInteger(options.rowHeight)
|
|
13862
|
+
? [options.rowHeight]
|
|
13863
|
+
: Array.from({ length: 18 }, (_, index) => index + 3);
|
|
13864
|
+
for (const rowHeight of rowHeights) {
|
|
13865
|
+
if (!Number.isInteger(baseHeight / rowHeight)) continue;
|
|
13866
|
+
const rows = baseHeight / rowHeight;
|
|
13867
|
+
if (rows < 3 || rows > 90) continue;
|
|
13868
|
+
const matrix = cropAndDownsample(oriented, bounds, width, baseHeight, scale);
|
|
13869
|
+
try {
|
|
13870
|
+
const result = decodeCompactPDF417(matrix, { rowHeight });
|
|
13871
|
+
const corners = mapCorners(cornersFor(bounds), toOriginal);
|
|
13872
|
+
return {
|
|
13873
|
+
...result,
|
|
13874
|
+
matrix,
|
|
13875
|
+
corners,
|
|
13876
|
+
rotation: rotation * 90,
|
|
13877
|
+
moduleSize: scale,
|
|
13878
|
+
compact: true,
|
|
13879
|
+
};
|
|
13880
|
+
} catch {
|
|
13881
|
+
// Try another geometry; a standard PDF417 or random artwork should
|
|
13882
|
+
// never be accepted unless the compact decoder validates every row.
|
|
13883
|
+
}
|
|
13884
|
+
}
|
|
13885
|
+
}
|
|
13886
|
+
}
|
|
13887
|
+
|
|
13888
|
+
const previous = oriented;
|
|
13889
|
+
const previousToOriginal = toOriginal;
|
|
13890
|
+
oriented = rotateClockwise(previous);
|
|
13891
|
+
toOriginal = (point) => previousToOriginal({ x: point.y, y: previous.height - point.x });
|
|
13892
|
+
}
|
|
13893
|
+
return null;
|
|
13894
|
+
}
|
|
13895
|
+
function detectAndDecodeCompactPDF417(binaryImage, options = {}) {
|
|
13896
|
+
return detectCompactPDF417(binaryImage, options);
|
|
13897
|
+
}
|
|
13898
|
+
|
|
13899
|
+
__exports.detectCompactPDF417 = detectCompactPDF417;
|
|
13900
|
+
__exports.detectAndDecodeCompactPDF417 = detectAndDecodeCompactPDF417;
|
|
13901
|
+
};
|
|
13902
|
+
|
|
13903
|
+
__modules["compactpdf417/index.js"] = function (__require, __exports) {
|
|
13904
|
+
/* Compact PDF417 public module exports. */
|
|
13905
|
+
const __reexport0 = __require("compactpdf417/tables.js"); __exports.COMPACT_PDF417_START = __reexport0.COMPACT_PDF417_START; __exports.COMPACT_PDF417_START_BITS = __reexport0.COMPACT_PDF417_START_BITS; __exports.COMPACT_PDF417_STOP_MODULES = __reexport0.COMPACT_PDF417_STOP_MODULES; __exports.COMPACT_PDF417_LIMITS = __reexport0.COMPACT_PDF417_LIMITS; __exports.compactPdf417Width = __reexport0.compactPdf417Width; __exports.compactPdf417Geometry = __reexport0.compactPdf417Geometry; __exports.compactPdf417Indicators = __reexport0.compactPdf417Indicators; __exports.compactPdf417MatchingLevels = __reexport0.compactPdf417MatchingLevels; __exports.validateCompactPdf417Options = __reexport0.validateCompactPdf417Options; __exports.validateCompactPdf417Tables = __reexport0.validateCompactPdf417Tables;
|
|
13906
|
+
const __reexport1 = __require("compactpdf417/encoder.js"); __exports.encodeCompactPDF417 = __reexport1.encodeCompactPDF417; __exports.compactPdf417Dimensions = __reexport1.compactPdf417Dimensions;
|
|
13907
|
+
const __reexport2 = __require("compactpdf417/decoder.js"); __exports.decodeCompactPDF417 = __reexport2.decodeCompactPDF417;
|
|
13908
|
+
const __reexport3 = __require("compactpdf417/detector.js"); __exports.detectCompactPDF417 = __reexport3.detectCompactPDF417; __exports.detectAndDecodeCompactPDF417 = __reexport3.detectAndDecodeCompactPDF417;
|
|
13909
|
+
|
|
13910
|
+
|
|
13911
|
+
};
|
|
13912
|
+
|
|
13913
|
+
__modules["databar/tables.js"] = function (__require, __exports) {
|
|
13914
|
+
/**
|
|
13915
|
+
* Static GS1 DataBar facts used by the GTIN compaction codec.
|
|
13916
|
+
*
|
|
13917
|
+
* The numbers in the DataBar-14 group tables are the public tables in
|
|
13918
|
+
* ISO/IEC 24724:2011, clauses 5.2.2 and 5.2.3. They describe values, not a
|
|
13919
|
+
* third-party implementation. Pattern construction deliberately belongs in
|
|
13920
|
+
* the renderer/encoder layer so this module stays a small, auditable contract.
|
|
13921
|
+
*
|
|
13922
|
+
* @module databar/tables
|
|
13923
|
+
*/
|
|
13924
|
+
|
|
13925
|
+
const group = (first, last, gsum, oddModules, evenModules, oddWidest, evenWidest, oddTotal, evenTotal) => Object.freeze({
|
|
13926
|
+
first, last, gsum, oddModules, evenModules, oddWidest, evenWidest, oddTotal, evenTotal,
|
|
13927
|
+
});
|
|
13928
|
+
|
|
13929
|
+
/** The four GTIN-only layouts sharing the DataBar-14 compaction rules. */
|
|
13930
|
+
const DATABAR14_VARIANTS = Object.freeze({
|
|
13931
|
+
omnidirectional: Object.freeze({ id: 'omnidirectional', rows: 1, modules: 96, checksumModulus: 79, pointOfSale: true }),
|
|
13932
|
+
truncated: Object.freeze({ id: 'truncated', rows: 1, modules: 96, checksumModulus: 79, pointOfSale: false }),
|
|
13933
|
+
stacked: Object.freeze({ id: 'stacked', rows: 2, modules: 50, checksumModulus: 79, pointOfSale: false }),
|
|
13934
|
+
'stacked-omnidirectional': Object.freeze({ id: 'stacked-omnidirectional', rows: 2, modules: 50, checksumModulus: 79, pointOfSale: true }),
|
|
13935
|
+
});
|
|
13936
|
+
|
|
13937
|
+
/** GS1 DataBar Limited is a distinct two-character symbology. */
|
|
13938
|
+
const DATABAR_LIMITED_VARIANT = Object.freeze({
|
|
13939
|
+
id: 'limited', rows: 1, checksumModulus: 89, pointOfSale: false,
|
|
13940
|
+
permittedIndicatorDigits: Object.freeze([0, 1]),
|
|
13941
|
+
});
|
|
13942
|
+
|
|
13943
|
+
/** (16,4) outside character groups, ISO/IEC 24724:2011 Table 1. */
|
|
13944
|
+
const DATABAR14_OUTSIDE_GROUPS = Object.freeze([
|
|
13945
|
+
group(0, 160, 0, 12, 4, 8, 1, 161, 1),
|
|
13946
|
+
group(161, 960, 161, 10, 6, 6, 3, 80, 10),
|
|
13947
|
+
group(961, 2014, 961, 8, 8, 4, 5, 31, 34),
|
|
13948
|
+
group(2015, 2714, 2015, 6, 10, 3, 6, 10, 70),
|
|
13949
|
+
group(2715, 2840, 2715, 4, 12, 1, 8, 1, 126),
|
|
13950
|
+
]);
|
|
13951
|
+
|
|
13952
|
+
/** (15,4) inside character groups, ISO/IEC 24724:2011 Table 2. */
|
|
13953
|
+
const DATABAR14_INSIDE_GROUPS = Object.freeze([
|
|
13954
|
+
group(0, 335, 0, 5, 10, 2, 7, 4, 84),
|
|
13955
|
+
group(336, 1035, 336, 7, 8, 4, 5, 20, 35),
|
|
13956
|
+
group(1036, 1515, 1036, 9, 6, 6, 3, 48, 10),
|
|
13957
|
+
group(1516, 1596, 1516, 11, 4, 8, 1, 81, 1),
|
|
13958
|
+
]);
|
|
13959
|
+
|
|
13960
|
+
/** Number of values carried by an inside (15,4) character. */
|
|
13961
|
+
const DATABAR14_INSIDE_RADIX = 1597;
|
|
13962
|
+
/** Number of values carried by one outside/inside character pair. */
|
|
13963
|
+
const DATABAR14_PAIR_RADIX = 4537077;
|
|
13964
|
+
/** Stand-alone and composite DataBar-14 payload domain, including linkage. */
|
|
13965
|
+
const DATABAR14_SYMBOL_LIMIT = 20000000000000n;
|
|
13966
|
+
|
|
13967
|
+
/** GS1 DataBar Limited divides its 13 data digits into two character values. */
|
|
13968
|
+
const DATABAR_LIMITED_PAIR_RADIX = 2013571;
|
|
13969
|
+
/** Offset that switches a DataBar Limited value from stand-alone to composite. */
|
|
13970
|
+
const DATABAR_LIMITED_LINKAGE_OFFSET = 2015133531096n;
|
|
13971
|
+
/** DataBar Limited carries GTIN values whose first digit is zero or one. */
|
|
13972
|
+
const DATABAR_LIMITED_DATA_LIMIT = 2000000000000n;
|
|
13973
|
+
|
|
13974
|
+
/** Locate the value group that an outside or inside character belongs to. */
|
|
13975
|
+
function dataBar14GroupFor(value, kind) {
|
|
13976
|
+
if (!Number.isInteger(value)) throw new TypeError('GS1 DataBar character value must be an integer');
|
|
13977
|
+
const groups = kind === 'outside' ? DATABAR14_OUTSIDE_GROUPS
|
|
13978
|
+
: kind === 'inside' ? DATABAR14_INSIDE_GROUPS : null;
|
|
13979
|
+
if (!groups) throw new RangeError(`Unknown GS1 DataBar character kind "${kind}"`);
|
|
13980
|
+
const found = groups.find((entry) => value >= entry.first && value <= entry.last);
|
|
13981
|
+
if (!found) throw new RangeError(`GS1 DataBar ${kind} character value ${value} is out of range`);
|
|
13982
|
+
return found;
|
|
13983
|
+
}
|
|
13984
|
+
/** Check the independently represented table identities. */
|
|
13985
|
+
function validateDataBarTables() {
|
|
13986
|
+
const problems = [];
|
|
13987
|
+
const validateGroups = (name, groups, expectedLast) => {
|
|
13988
|
+
let next = 0;
|
|
13989
|
+
for (const entry of groups) {
|
|
13990
|
+
if (entry.first !== next) problems.push(`${name}: gap before ${entry.first}`);
|
|
13991
|
+
if (entry.last < entry.first) problems.push(`${name}: inverted range ${entry.first}-${entry.last}`);
|
|
13992
|
+
if (entry.oddTotal * entry.evenTotal !== entry.last - entry.first + 1) {
|
|
13993
|
+
problems.push(`${name}: combination count mismatch at ${entry.first}`);
|
|
13994
|
+
}
|
|
13995
|
+
next = entry.last + 1;
|
|
13996
|
+
}
|
|
13997
|
+
if (next - 1 !== expectedLast) problems.push(`${name}: final value is ${next - 1}, expected ${expectedLast}`);
|
|
13998
|
+
};
|
|
13999
|
+
validateGroups('outside', DATABAR14_OUTSIDE_GROUPS, 2840);
|
|
14000
|
+
validateGroups('inside', DATABAR14_INSIDE_GROUPS, 1596);
|
|
14001
|
+
if (DATABAR14_PAIR_RADIX !== 2841 * DATABAR14_INSIDE_RADIX) problems.push('pair radix mismatch');
|
|
14002
|
+
if (DATABAR14_SYMBOL_LIMIT !== 2n * 10000000000000n) problems.push('symbol limit mismatch');
|
|
14003
|
+
if (DATABAR_LIMITED_LINKAGE_OFFSET !== BigInt(DATABAR_LIMITED_PAIR_RADIX) * 1000776n) {
|
|
14004
|
+
problems.push('limited linkage offset mismatch');
|
|
14005
|
+
}
|
|
14006
|
+
return problems;
|
|
14007
|
+
}
|
|
14008
|
+
|
|
14009
|
+
__exports.DATABAR14_VARIANTS = DATABAR14_VARIANTS;
|
|
14010
|
+
__exports.DATABAR_LIMITED_VARIANT = DATABAR_LIMITED_VARIANT;
|
|
14011
|
+
__exports.DATABAR14_OUTSIDE_GROUPS = DATABAR14_OUTSIDE_GROUPS;
|
|
14012
|
+
__exports.DATABAR14_INSIDE_GROUPS = DATABAR14_INSIDE_GROUPS;
|
|
14013
|
+
__exports.DATABAR14_INSIDE_RADIX = DATABAR14_INSIDE_RADIX;
|
|
14014
|
+
__exports.DATABAR14_PAIR_RADIX = DATABAR14_PAIR_RADIX;
|
|
14015
|
+
__exports.DATABAR14_SYMBOL_LIMIT = DATABAR14_SYMBOL_LIMIT;
|
|
14016
|
+
__exports.DATABAR_LIMITED_PAIR_RADIX = DATABAR_LIMITED_PAIR_RADIX;
|
|
14017
|
+
__exports.DATABAR_LIMITED_LINKAGE_OFFSET = DATABAR_LIMITED_LINKAGE_OFFSET;
|
|
14018
|
+
__exports.DATABAR_LIMITED_DATA_LIMIT = DATABAR_LIMITED_DATA_LIMIT;
|
|
14019
|
+
__exports.dataBar14GroupFor = dataBar14GroupFor;
|
|
14020
|
+
__exports.validateDataBarTables = validateDataBarTables;
|
|
14021
|
+
};
|
|
14022
|
+
|
|
14023
|
+
__modules["databar/codec.js"] = function (__require, __exports) {
|
|
14024
|
+
/**
|
|
14025
|
+
* GTIN validation and numeric compaction for GS1 DataBar GTIN-only symbols.
|
|
14026
|
+
*
|
|
14027
|
+
* This is intentionally not a bar-pattern encoder. It emits the exact symbol
|
|
14028
|
+
* character values required by ISO/IEC 24724:2011; a later encoder can turn
|
|
14029
|
+
* those values into widths without reinterpreting a GTIN or linkage flag.
|
|
14030
|
+
*
|
|
14031
|
+
* @module databar/codec
|
|
14032
|
+
*/
|
|
14033
|
+
const { DATABAR14_INSIDE_RADIX, DATABAR14_PAIR_RADIX, DATABAR14_SYMBOL_LIMIT, DATABAR_LIMITED_DATA_LIMIT, DATABAR_LIMITED_LINKAGE_OFFSET, DATABAR_LIMITED_PAIR_RADIX } = __require("databar/tables.js");
|
|
14034
|
+
|
|
14035
|
+
const GTIN_LENGTHS = new Set([8, 12, 13, 14]);
|
|
14036
|
+
|
|
14037
|
+
function digits(value, label) {
|
|
14038
|
+
const text = String(value);
|
|
14039
|
+
if (!/^\d+$/.test(text)) throw new TypeError(`${label} must contain only decimal digits`);
|
|
14040
|
+
return text;
|
|
14041
|
+
}
|
|
14042
|
+
|
|
14043
|
+
function asCharacterValue(value, label, maximum) {
|
|
14044
|
+
if (!Number.isInteger(value) || value < 0 || value > maximum) {
|
|
14045
|
+
throw new RangeError(`${label} must be an integer from 0 to ${maximum}`);
|
|
14046
|
+
}
|
|
14047
|
+
return value;
|
|
14048
|
+
}
|
|
14049
|
+
|
|
14050
|
+
/** Calculate the GS1 modulo-10 check digit for a GTIN body. */
|
|
14051
|
+
function gtinCheckDigit(body) {
|
|
14052
|
+
const text = digits(body, 'GTIN body');
|
|
14053
|
+
if (text.length < 1 || text.length > 13) throw new RangeError('GTIN body must contain 1 to 13 digits');
|
|
14054
|
+
let sum = 0;
|
|
14055
|
+
for (let i = text.length - 1, weight = 3; i >= 0; i--, weight = weight === 3 ? 1 : 3) {
|
|
14056
|
+
sum += Number(text[i]) * weight;
|
|
14057
|
+
}
|
|
14058
|
+
return String((10 - (sum % 10)) % 10);
|
|
14059
|
+
}
|
|
14060
|
+
|
|
14061
|
+
/** Return a checked 14-digit GTIN, preserving only its standardized digits. */
|
|
14062
|
+
function normalizeGTIN(value) {
|
|
14063
|
+
const input = digits(value, 'GTIN');
|
|
14064
|
+
if (!GTIN_LENGTHS.has(input.length)) {
|
|
14065
|
+
throw new RangeError('GTIN must contain 8, 12, 13, or 14 digits including its check digit');
|
|
14066
|
+
}
|
|
14067
|
+
if (gtinCheckDigit(input.slice(0, -1)) !== input.at(-1)) {
|
|
14068
|
+
throw new RangeError(`GTIN check digit is invalid for ${input}`);
|
|
14069
|
+
}
|
|
14070
|
+
return input.padStart(14, '0');
|
|
14071
|
+
}
|
|
14072
|
+
|
|
14073
|
+
/** Build a checked GTIN-14 from its thirteen-digit data body. */
|
|
14074
|
+
function makeGTIN14(body) {
|
|
14075
|
+
const input = digits(body, 'GTIN-14 body');
|
|
14076
|
+
if (input.length > 13) throw new RangeError('GTIN-14 body must contain at most 13 digits');
|
|
14077
|
+
const padded = input.padStart(13, '0');
|
|
14078
|
+
return padded + gtinCheckDigit(padded);
|
|
14079
|
+
}
|
|
14080
|
+
|
|
14081
|
+
function gtinFromSymbolValue(symbolValue) {
|
|
14082
|
+
const value = BigInt(symbolValue);
|
|
14083
|
+
if (value < 0n || value >= DATABAR14_SYMBOL_LIMIT) throw new RangeError('GS1 DataBar-14 symbol value is out of range');
|
|
14084
|
+
const linkage = value >= 10000000000000n;
|
|
14085
|
+
const body = (linkage ? value - 10000000000000n : value).toString().padStart(13, '0');
|
|
14086
|
+
return { linkage, gtin: body + gtinCheckDigit(body) };
|
|
14087
|
+
}
|
|
14088
|
+
|
|
14089
|
+
/**
|
|
14090
|
+
* Compact a GTIN into the four values shared by Omnidirectional, Truncated,
|
|
14091
|
+
* Stacked and Stacked Omnidirectional. The `physicalCharacters` sequence is
|
|
14092
|
+
* left-to-right on a linear DataBar-14 row: 1, 2, 4, 3.
|
|
14093
|
+
*/
|
|
14094
|
+
function encodeDataBar14GTIN(value, options = {}) {
|
|
14095
|
+
const gtin = normalizeGTIN(value);
|
|
14096
|
+
const linkage = options.linkage === true;
|
|
14097
|
+
if (options.linkage !== undefined && typeof options.linkage !== 'boolean') {
|
|
14098
|
+
throw new TypeError('GS1 DataBar linkage must be a boolean');
|
|
14099
|
+
}
|
|
14100
|
+
const dataBody = gtin.slice(0, -1);
|
|
14101
|
+
const symbolValue = BigInt(dataBody) + (linkage ? 10000000000000n : 0n);
|
|
14102
|
+
const leftPair = symbolValue / BigInt(DATABAR14_PAIR_RADIX);
|
|
14103
|
+
const rightPair = symbolValue % BigInt(DATABAR14_PAIR_RADIX);
|
|
14104
|
+
const outerLeft = Number(leftPair / BigInt(DATABAR14_INSIDE_RADIX));
|
|
14105
|
+
const innerLeft = Number(leftPair % BigInt(DATABAR14_INSIDE_RADIX));
|
|
14106
|
+
const outerRight = Number(rightPair / BigInt(DATABAR14_INSIDE_RADIX));
|
|
14107
|
+
const innerRight = Number(rightPair % BigInt(DATABAR14_INSIDE_RADIX));
|
|
14108
|
+
|
|
14109
|
+
return Object.freeze({
|
|
14110
|
+
gtin, linkage, symbolValue, leftPair, rightPair,
|
|
14111
|
+
logicalCharacters: Object.freeze({ outerLeft, innerLeft, outerRight, innerRight }),
|
|
14112
|
+
physicalCharacters: Object.freeze([outerLeft, innerLeft, innerRight, outerRight]),
|
|
14113
|
+
});
|
|
14114
|
+
}
|
|
14115
|
+
|
|
14116
|
+
/** Reconstruct and validate a GTIN from the four DataBar-14 character values. */
|
|
14117
|
+
function decodeDataBar14GTIN(values) {
|
|
14118
|
+
if (values === null || typeof values !== 'object') throw new TypeError('GS1 DataBar-14 characters must be an object');
|
|
14119
|
+
const outerLeft = asCharacterValue(values.outerLeft, 'outerLeft', 2840);
|
|
14120
|
+
const innerLeft = asCharacterValue(values.innerLeft, 'innerLeft', 1596);
|
|
14121
|
+
const outerRight = asCharacterValue(values.outerRight, 'outerRight', 2840);
|
|
14122
|
+
const innerRight = asCharacterValue(values.innerRight, 'innerRight', 1596);
|
|
14123
|
+
const leftPair = BigInt(outerLeft) * BigInt(DATABAR14_INSIDE_RADIX) + BigInt(innerLeft);
|
|
14124
|
+
const rightPair = BigInt(outerRight) * BigInt(DATABAR14_INSIDE_RADIX) + BigInt(innerRight);
|
|
14125
|
+
return Object.freeze({
|
|
14126
|
+
...gtinFromSymbolValue(leftPair * BigInt(DATABAR14_PAIR_RADIX) + rightPair),
|
|
14127
|
+
leftPair, rightPair,
|
|
14128
|
+
});
|
|
14129
|
+
}
|
|
14130
|
+
|
|
14131
|
+
/** Compact a DataBar Limited-eligible GTIN into its two data character values. */
|
|
14132
|
+
function encodeDataBarLimitedGTIN(value, options = {}) {
|
|
14133
|
+
const gtin = normalizeGTIN(value);
|
|
14134
|
+
const linkage = options.linkage === true;
|
|
14135
|
+
if (options.linkage !== undefined && typeof options.linkage !== 'boolean') {
|
|
14136
|
+
throw new TypeError('GS1 DataBar linkage must be a boolean');
|
|
14137
|
+
}
|
|
14138
|
+
const dataBody = BigInt(gtin.slice(0, -1));
|
|
14139
|
+
if (dataBody >= DATABAR_LIMITED_DATA_LIMIT) {
|
|
14140
|
+
throw new RangeError('GS1 DataBar Limited requires a GTIN whose indicator digit is 0 or 1');
|
|
14141
|
+
}
|
|
14142
|
+
const symbolValue = dataBody + (linkage ? DATABAR_LIMITED_LINKAGE_OFFSET : 0n);
|
|
14143
|
+
const left = Number(symbolValue / BigInt(DATABAR_LIMITED_PAIR_RADIX));
|
|
14144
|
+
const right = Number(symbolValue % BigInt(DATABAR_LIMITED_PAIR_RADIX));
|
|
14145
|
+
return Object.freeze({ gtin, linkage, symbolValue, left, right });
|
|
14146
|
+
}
|
|
14147
|
+
|
|
14148
|
+
/** Reconstruct and validate a GTIN from DataBar Limited data character values. */
|
|
14149
|
+
function decodeDataBarLimitedGTIN(values) {
|
|
14150
|
+
if (values === null || typeof values !== 'object') throw new TypeError('GS1 DataBar Limited characters must be an object');
|
|
14151
|
+
const left = asCharacterValue(values.left, 'left', 1994036);
|
|
14152
|
+
const right = asCharacterValue(values.right, 'right', DATABAR_LIMITED_PAIR_RADIX - 1);
|
|
14153
|
+
let symbolValue = BigInt(left) * BigInt(DATABAR_LIMITED_PAIR_RADIX) + BigInt(right);
|
|
14154
|
+
const linkage = symbolValue >= DATABAR_LIMITED_LINKAGE_OFFSET;
|
|
14155
|
+
if (linkage) symbolValue -= DATABAR_LIMITED_LINKAGE_OFFSET;
|
|
14156
|
+
if (symbolValue < 0n || symbolValue >= DATABAR_LIMITED_DATA_LIMIT) {
|
|
14157
|
+
throw new RangeError('GS1 DataBar Limited character values do not encode a permitted GTIN');
|
|
14158
|
+
}
|
|
14159
|
+
const body = symbolValue.toString().padStart(13, '0');
|
|
14160
|
+
return Object.freeze({ linkage, gtin: body + gtinCheckDigit(body), symbolValue: BigInt(left) * BigInt(DATABAR_LIMITED_PAIR_RADIX) + BigInt(right) });
|
|
14161
|
+
}
|
|
14162
|
+
|
|
14163
|
+
/** GS1 transmitted form for the GTIN-only DataBar variants. */
|
|
14164
|
+
function dataBarGtinTransmission(value) {
|
|
14165
|
+
return `]e001${normalizeGTIN(value)}`;
|
|
14166
|
+
}
|
|
14167
|
+
|
|
14168
|
+
__exports.gtinCheckDigit = gtinCheckDigit;
|
|
14169
|
+
__exports.normalizeGTIN = normalizeGTIN;
|
|
14170
|
+
__exports.makeGTIN14 = makeGTIN14;
|
|
14171
|
+
__exports.encodeDataBar14GTIN = encodeDataBar14GTIN;
|
|
14172
|
+
__exports.decodeDataBar14GTIN = decodeDataBar14GTIN;
|
|
14173
|
+
__exports.encodeDataBarLimitedGTIN = encodeDataBarLimitedGTIN;
|
|
14174
|
+
__exports.decodeDataBarLimitedGTIN = decodeDataBarLimitedGTIN;
|
|
14175
|
+
__exports.dataBarGtinTransmission = dataBarGtinTransmission;
|
|
14176
|
+
};
|
|
14177
|
+
|
|
14178
|
+
__modules["databar/gs1.js"] = function (__require, __exports) {
|
|
14179
|
+
/** GS1 element-string codec used by GS1 DataBar Expanded. @module databar/gs1 */
|
|
14180
|
+
const { EncodeError, FormatError } = __require("core/errors.js");
|
|
14181
|
+
const GS1_SEPARATOR = '\x1d';
|
|
14182
|
+
|
|
14183
|
+
const EXACT = new Map([
|
|
14184
|
+
['00', [18, true]], ['01', [14, true]], ['02', [14, true]],
|
|
14185
|
+
['10', [20, false]], ['11', [6, true]], ['12', [6, true]],
|
|
14186
|
+
['13', [6, true]], ['15', [6, true]], ['16', [6, true]],
|
|
14187
|
+
['17', [6, true]], ['20', [2, true]], ['21', [20, false]],
|
|
14188
|
+
['22', [29, false]], ['30', [8, false]], ['37', [8, false]],
|
|
14189
|
+
['240', [30, false]], ['241', [30, false]], ['242', [6, false]],
|
|
14190
|
+
['243', [20, false]], ['250', [30, false]], ['251', [30, false]],
|
|
14191
|
+
['253', [30, false]], ['254', [20, false]], ['255', [13, true]],
|
|
14192
|
+
['400', [30, false]], ['401', [30, false]], ['402', [17, true]],
|
|
14193
|
+
['403', [30, false]], ['410', [13, true]], ['411', [13, true]],
|
|
14194
|
+
['412', [13, true]], ['413', [13, true]], ['414', [13, true]],
|
|
14195
|
+
['415', [13, true]], ['416', [13, true]], ['417', [13, true]],
|
|
14196
|
+
['420', [20, false]], ['421', [15, false]], ['422', [3, true]],
|
|
14197
|
+
['423', [15, false]], ['424', [3, true]], ['425', [3, true]],
|
|
14198
|
+
['426', [3, true]], ['427', [3, false]],
|
|
14199
|
+
['7001', [13, true]], ['7002', [30, false]], ['7003', [10, true]],
|
|
14200
|
+
['7004', [4, false]], ['7005', [12, false]], ['7006', [6, true]],
|
|
14201
|
+
['7007', [12, false]], ['7008', [3, false]], ['7009', [10, false]],
|
|
14202
|
+
['7010', [2, false]], ['7020', [20, false]], ['7021', [20, false]],
|
|
14203
|
+
['7022', [20, false]], ['710', [20, false]], ['711', [20, false]],
|
|
14204
|
+
['712', [20, false]], ['713', [20, false]], ['714', [20, false]],
|
|
14205
|
+
['715', [20, false]],
|
|
14206
|
+
['8001', [14, true]], ['8002', [20, false]], ['8003', [30, false]],
|
|
14207
|
+
['8004', [30, false]], ['8005', [6, true]], ['8006', [18, true]],
|
|
14208
|
+
['8007', [34, false]], ['8008', [12, false]], ['8009', [50, false]],
|
|
14209
|
+
['8010', [30, false]], ['8011', [12, false]], ['8012', [20, false]],
|
|
14210
|
+
['8013', [30, false]], ['8017', [18, true]], ['8018', [18, true]],
|
|
14211
|
+
['8019', [10, false]], ['8020', [25, false]], ['8026', [18, true]],
|
|
14212
|
+
['8110', [70, false]], ['8111', [4, true]], ['8112', [70, false]],
|
|
14213
|
+
['8200', [70, false]],
|
|
14214
|
+
]);
|
|
14215
|
+
|
|
14216
|
+
function rangedAI(ai) {
|
|
14217
|
+
if (/^31[0-6]\d$/.test(ai) || /^32[0-7]\d$/.test(ai) ||
|
|
14218
|
+
/^33[0-7]\d$/.test(ai) || /^34[0-9]\d$/.test(ai) ||
|
|
14219
|
+
/^35[0-7]\d$/.test(ai) || /^36[0-9]\d$/.test(ai)) return [6, true];
|
|
14220
|
+
if (/^390\d$/.test(ai) || /^392\d$/.test(ai)) return [15, false];
|
|
14221
|
+
if (/^391\d$/.test(ai) || /^393\d$/.test(ai)) return [18, false];
|
|
14222
|
+
if (/^394\d$/.test(ai)) return [4, true];
|
|
14223
|
+
if (/^395\d$/.test(ai)) return [6, true];
|
|
14224
|
+
if (/^703\d$/.test(ai) || /^723\d$/.test(ai)) return [30, false];
|
|
14225
|
+
return undefined;
|
|
14226
|
+
}
|
|
14227
|
+
function gs1AIInfo(ai) {
|
|
14228
|
+
if (typeof ai !== 'string' || !/^\d{2,4}$/.test(ai)) return undefined;
|
|
14229
|
+
const spec = EXACT.get(ai) || rangedAI(ai);
|
|
14230
|
+
if (!spec) return undefined;
|
|
14231
|
+
return { ai, length: spec[0], fixed: spec[1] };
|
|
14232
|
+
}
|
|
14233
|
+
|
|
14234
|
+
function assertCharacters(value, label, ErrorType) {
|
|
14235
|
+
if (/[^\x20-\x7e]/.test(value)) {
|
|
14236
|
+
throw new ErrorType(`GS1: ${label} contains a character outside the GS1 element-string character set`);
|
|
14237
|
+
}
|
|
14238
|
+
}
|
|
14239
|
+
|
|
14240
|
+
function validateElement(ai, value, ErrorType) {
|
|
14241
|
+
const info = gs1AIInfo(ai);
|
|
14242
|
+
if (!info) throw new ErrorType(`GS1: unsupported or invalid Application Identifier ${ai}`);
|
|
14243
|
+
if (value.length === 0) throw new ErrorType(`GS1: AI ${ai} must not be empty`);
|
|
14244
|
+
if (info.fixed ? value.length !== info.length : value.length > info.length) {
|
|
14245
|
+
const expectation = info.fixed ? `exactly ${info.length}` : `at most ${info.length}`;
|
|
14246
|
+
throw new ErrorType(`GS1: AI ${ai} requires ${expectation} characters`);
|
|
14247
|
+
}
|
|
14248
|
+
assertCharacters(value, `AI ${ai}`, ErrorType);
|
|
14249
|
+
return { ai, value, fixed: info.fixed };
|
|
14250
|
+
}
|
|
14251
|
+
function parseGS1ElementString(input) {
|
|
14252
|
+
if (typeof input !== 'string' || input.length === 0) {
|
|
14253
|
+
throw new EncodeError('GS1: element string must be a non-empty string');
|
|
14254
|
+
}
|
|
14255
|
+
const elements = [];
|
|
14256
|
+
let offset = 0;
|
|
14257
|
+
while (offset < input.length) {
|
|
14258
|
+
const match = /^\((\d{2,4})\)/.exec(input.slice(offset));
|
|
14259
|
+
if (!match) throw new EncodeError(`GS1: expected an Application Identifier at offset ${offset}`);
|
|
14260
|
+
const ai = match[1];
|
|
14261
|
+
offset += match[0].length;
|
|
14262
|
+
const next = input.indexOf('(', offset);
|
|
14263
|
+
const end = next < 0 ? input.length : next;
|
|
14264
|
+
elements.push(validateElement(ai, input.slice(offset, end), EncodeError));
|
|
14265
|
+
offset = end;
|
|
14266
|
+
}
|
|
14267
|
+
return elements;
|
|
14268
|
+
}
|
|
14269
|
+
function encodeGS1ElementString(input) {
|
|
14270
|
+
const elements = Array.isArray(input)
|
|
14271
|
+
? input.map(({ ai, value }) => validateElement(String(ai), String(value), EncodeError))
|
|
14272
|
+
: parseGS1ElementString(input);
|
|
14273
|
+
return elements.map((element, index) =>
|
|
14274
|
+
`${element.ai}${element.value}${!element.fixed && index + 1 < elements.length ? GS1_SEPARATOR : ''}`
|
|
14275
|
+
).join('');
|
|
14276
|
+
}
|
|
14277
|
+
|
|
14278
|
+
function matchAIAt(data, offset) {
|
|
14279
|
+
for (const length of [4, 3, 2]) {
|
|
14280
|
+
const ai = data.slice(offset, offset + length);
|
|
14281
|
+
if (gs1AIInfo(ai)) return ai;
|
|
14282
|
+
}
|
|
14283
|
+
return undefined;
|
|
14284
|
+
}
|
|
14285
|
+
function decodeGS1ElementString(data) {
|
|
14286
|
+
if (typeof data !== 'string' || data.length === 0) {
|
|
14287
|
+
throw new FormatError('GS1: encoded data must be a non-empty string');
|
|
14288
|
+
}
|
|
14289
|
+
const elements = [];
|
|
14290
|
+
let offset = 0;
|
|
14291
|
+
while (offset < data.length) {
|
|
14292
|
+
if (data[offset] === GS1_SEPARATOR) {
|
|
14293
|
+
throw new FormatError(`GS1: unexpected separator at offset ${offset}`);
|
|
14294
|
+
}
|
|
14295
|
+
const ai = matchAIAt(data, offset);
|
|
14296
|
+
if (!ai) throw new FormatError(`GS1: unknown Application Identifier at offset ${offset}`);
|
|
14297
|
+
offset += ai.length;
|
|
14298
|
+
const info = gs1AIInfo(ai);
|
|
14299
|
+
let value;
|
|
14300
|
+
if (info.fixed) {
|
|
14301
|
+
value = data.slice(offset, offset + info.length);
|
|
14302
|
+
if (value.length !== info.length || value.includes(GS1_SEPARATOR)) {
|
|
14303
|
+
throw new FormatError(`GS1: truncated fixed-length AI ${ai}`);
|
|
14304
|
+
}
|
|
14305
|
+
offset += info.length;
|
|
14306
|
+
} else {
|
|
14307
|
+
const separator = data.indexOf(GS1_SEPARATOR, offset);
|
|
14308
|
+
const end = separator < 0 ? data.length : separator;
|
|
14309
|
+
value = data.slice(offset, end);
|
|
14310
|
+
offset = separator < 0 ? data.length : separator + 1;
|
|
14311
|
+
}
|
|
14312
|
+
elements.push(validateElement(ai, value, FormatError));
|
|
14313
|
+
}
|
|
14314
|
+
return elements;
|
|
14315
|
+
}
|
|
14316
|
+
function formatGS1Elements(elements) {
|
|
14317
|
+
return elements.map(({ ai, value }) => `(${ai})${value}`).join('');
|
|
14318
|
+
}
|
|
14319
|
+
|
|
14320
|
+
__exports.GS1_SEPARATOR = GS1_SEPARATOR;
|
|
14321
|
+
__exports.gs1AIInfo = gs1AIInfo;
|
|
14322
|
+
__exports.parseGS1ElementString = parseGS1ElementString;
|
|
14323
|
+
__exports.encodeGS1ElementString = encodeGS1ElementString;
|
|
14324
|
+
__exports.decodeGS1ElementString = decodeGS1ElementString;
|
|
14325
|
+
__exports.formatGS1Elements = formatGS1Elements;
|
|
14326
|
+
};
|
|
14327
|
+
|
|
14328
|
+
__modules["databar/patterns.js"] = function (__require, __exports) {
|
|
14329
|
+
/** Mathematical width construction for GS1 DataBar characters. @module databar/patterns */
|
|
14330
|
+
const { dataBar14GroupFor } = __require("databar/tables.js");
|
|
14331
|
+
|
|
14332
|
+
function combinations(n, r) {
|
|
14333
|
+
if (n < r || r < 0) return 0;
|
|
14334
|
+
if (r === 0 || n === r) return 1;
|
|
14335
|
+
let result = 1;
|
|
14336
|
+
const k = Math.min(r, n - r);
|
|
14337
|
+
for (let i = 1; i <= k; i++) result = result * (n - k + i) / i;
|
|
14338
|
+
return result;
|
|
14339
|
+
}
|
|
14340
|
+
|
|
14341
|
+
/**
|
|
14342
|
+
* Unrank one constrained positive composition.
|
|
14343
|
+
*
|
|
14344
|
+
* The rank is the GS1 DataBar symbol-character value inside its group. This
|
|
14345
|
+
* implementation follows the combinatorial definition directly: it counts
|
|
14346
|
+
* every remaining admissible suffix rather than storing third-party patterns.
|
|
14347
|
+
*/
|
|
14348
|
+
function dataBarWidths(rank, modules, elements, maximumWidth, noNarrow) {
|
|
14349
|
+
if (!Number.isInteger(rank) || rank < 0) throw new RangeError('GS1 DataBar width rank must be non-negative');
|
|
14350
|
+
const widths = new Array(elements).fill(0);
|
|
14351
|
+
let remaining = modules;
|
|
14352
|
+
let narrowMask = 0;
|
|
14353
|
+
|
|
14354
|
+
for (let bar = 0; bar < elements - 1; bar++) {
|
|
14355
|
+
let count = 0;
|
|
14356
|
+
for (let width = 1; ; width++) {
|
|
14357
|
+
narrowMask |= width === 1 ? 1 << bar : 0;
|
|
14358
|
+
count = combinations(remaining - width - 1, elements - bar - 2);
|
|
14359
|
+
|
|
14360
|
+
if (noNarrow && narrowMask === 0 && remaining - width - (elements - bar - 1) >= elements - bar - 1) {
|
|
14361
|
+
count -= combinations(remaining - width - (elements - bar), elements - bar - 2);
|
|
14362
|
+
}
|
|
14363
|
+
|
|
14364
|
+
if (elements - bar - 1 > 1) {
|
|
14365
|
+
let tooWide = 0;
|
|
14366
|
+
for (let last = remaining - width - (elements - bar - 2); last > maximumWidth; last--) {
|
|
14367
|
+
tooWide += combinations(remaining - width - last - 1, elements - bar - 3);
|
|
14368
|
+
}
|
|
14369
|
+
count -= tooWide * (elements - 1 - bar);
|
|
14370
|
+
} else if (remaining - width > maximumWidth) {
|
|
14371
|
+
count--;
|
|
14372
|
+
}
|
|
14373
|
+
|
|
14374
|
+
if (rank < count) {
|
|
14375
|
+
widths[bar] = width;
|
|
14376
|
+
remaining -= width;
|
|
14377
|
+
break;
|
|
14378
|
+
}
|
|
14379
|
+
rank -= count;
|
|
14380
|
+
narrowMask &= ~(1 << bar);
|
|
14381
|
+
}
|
|
14382
|
+
}
|
|
14383
|
+
widths[elements - 1] = remaining;
|
|
14384
|
+
if (rank !== 0 || widths.some((width) => width < 1 || width > maximumWidth)) {
|
|
14385
|
+
throw new RangeError('GS1 DataBar width rank exceeds its character group');
|
|
14386
|
+
}
|
|
14387
|
+
return widths;
|
|
14388
|
+
}
|
|
14389
|
+
|
|
14390
|
+
/** Convert one DataBar-14 character value into its eight alternating widths. */
|
|
14391
|
+
function dataBar14CharacterWidths(value, kind) {
|
|
14392
|
+
const group = dataBar14GroupFor(value, kind);
|
|
14393
|
+
const offset = value - group.gsum;
|
|
14394
|
+
const outside = kind === 'outside';
|
|
14395
|
+
const oddRank = outside ? Math.floor(offset / group.evenTotal) : offset % group.oddTotal;
|
|
14396
|
+
const evenRank = outside ? offset % group.evenTotal : Math.floor(offset / group.oddTotal);
|
|
14397
|
+
const odd = dataBarWidths(oddRank, group.oddModules, 4, group.oddWidest, !outside);
|
|
14398
|
+
const even = dataBarWidths(evenRank, group.evenModules, 4, group.evenWidest, outside);
|
|
14399
|
+
const result = [];
|
|
14400
|
+
for (let i = 0; i < 4; i++) result.push(odd[i], even[i]);
|
|
14401
|
+
return result;
|
|
14402
|
+
}
|
|
14403
|
+
|
|
14404
|
+
const inverseCharacterMaps = new Map();
|
|
14405
|
+
|
|
14406
|
+
/** Recover a character value from its canonical eight-width representation. */
|
|
14407
|
+
function dataBar14ValueForWidths(widths, kind) {
|
|
14408
|
+
if (!Array.isArray(widths) || widths.length !== 8 || widths.some((width) => !Number.isInteger(width) || width < 1)) {
|
|
14409
|
+
throw new TypeError('GS1 DataBar character widths must contain eight positive integers');
|
|
14410
|
+
}
|
|
14411
|
+
if (kind !== 'outside' && kind !== 'inside') throw new RangeError(`Unknown GS1 DataBar character kind "${kind}"`);
|
|
14412
|
+
let inverse = inverseCharacterMaps.get(kind);
|
|
14413
|
+
if (!inverse) {
|
|
14414
|
+
inverse = new Map();
|
|
14415
|
+
const maximum = kind === 'outside' ? 2840 : 1596;
|
|
14416
|
+
for (let value = 0; value <= maximum; value++) {
|
|
14417
|
+
inverse.set(dataBar14CharacterWidths(value, kind).join(','), value);
|
|
14418
|
+
}
|
|
14419
|
+
inverseCharacterMaps.set(kind, inverse);
|
|
14420
|
+
}
|
|
14421
|
+
const value = inverse.get(widths.join(','));
|
|
14422
|
+
if (value === undefined) throw new RangeError(`Invalid GS1 DataBar ${kind} character widths`);
|
|
14423
|
+
return value;
|
|
14424
|
+
}
|
|
14425
|
+
|
|
14426
|
+
/** Nine finder patterns, expressed as normative five-element widths. */
|
|
14427
|
+
const DATABAR14_FINDERS = Object.freeze([
|
|
14428
|
+
Object.freeze([3, 8, 2, 1, 1]), Object.freeze([3, 5, 5, 1, 1]),
|
|
14429
|
+
Object.freeze([3, 3, 7, 1, 1]), Object.freeze([3, 1, 9, 1, 1]),
|
|
14430
|
+
Object.freeze([2, 7, 4, 1, 1]), Object.freeze([2, 5, 6, 1, 1]),
|
|
14431
|
+
Object.freeze([2, 3, 8, 1, 1]), Object.freeze([1, 5, 7, 1, 1]),
|
|
14432
|
+
Object.freeze([1, 3, 9, 1, 1]),
|
|
14433
|
+
]);
|
|
14434
|
+
|
|
14435
|
+
/** Weight sequence generated as powers of three modulo 79. */
|
|
14436
|
+
const DATABAR14_CHECKSUM_WEIGHTS = Object.freeze(Array.from({ length: 32 }, (_, index) => {
|
|
14437
|
+
let value = 1;
|
|
14438
|
+
for (let i = 0; i < index; i++) value = (value * 3) % 79;
|
|
14439
|
+
return value;
|
|
14440
|
+
}));
|
|
14441
|
+
|
|
14442
|
+
__exports.dataBarWidths = dataBarWidths;
|
|
14443
|
+
__exports.dataBar14CharacterWidths = dataBar14CharacterWidths;
|
|
14444
|
+
__exports.dataBar14ValueForWidths = dataBar14ValueForWidths;
|
|
14445
|
+
__exports.DATABAR14_FINDERS = DATABAR14_FINDERS;
|
|
14446
|
+
__exports.DATABAR14_CHECKSUM_WEIGHTS = DATABAR14_CHECKSUM_WEIGHTS;
|
|
14447
|
+
};
|
|
14448
|
+
|
|
14449
|
+
__modules["databar/encoder.js"] = function (__require, __exports) {
|
|
14450
|
+
/** GS1 DataBar Omnidirectional and Truncated encoder. @module databar/encoder */
|
|
14451
|
+
const { BitMatrix } = __require("core/bit-matrix.js");
|
|
14452
|
+
const { EncodeError } = __require("core/errors.js");
|
|
14453
|
+
const { encodeDataBar14GTIN } = __require("databar/codec.js");
|
|
14454
|
+
const { DATABAR14_CHECKSUM_WEIGHTS, DATABAR14_FINDERS, dataBar14CharacterWidths } = __require("databar/patterns.js");
|
|
14455
|
+
|
|
14456
|
+
function finderIndexes(characters) {
|
|
14457
|
+
const widths = characters.map((value, index) =>
|
|
14458
|
+
dataBar14CharacterWidths(value, index === 0 || index === 3 ? 'outside' : 'inside')
|
|
14459
|
+
);
|
|
14460
|
+
let checksum = 0;
|
|
14461
|
+
const weightOffsets = [0, 8, 24, 16];
|
|
14462
|
+
for (let character = 0; character < 4; character++) {
|
|
14463
|
+
for (let element = 0; element < 8; element++) {
|
|
14464
|
+
checksum += widths[character][element] * DATABAR14_CHECKSUM_WEIGHTS[weightOffsets[character] + element];
|
|
14465
|
+
}
|
|
14466
|
+
}
|
|
14467
|
+
checksum %= 79;
|
|
14468
|
+
if (checksum >= 8) checksum++;
|
|
14469
|
+
if (checksum >= 72) checksum++;
|
|
14470
|
+
return { widths, checksum, left: Math.floor(checksum / 9), right: checksum % 9 };
|
|
14471
|
+
}
|
|
14472
|
+
|
|
14473
|
+
function widthsToMatrix(widths, height) {
|
|
14474
|
+
const width = widths.reduce((sum, value) => sum + value, 0);
|
|
14475
|
+
const matrix = new BitMatrix(width, height);
|
|
14476
|
+
let dark = false;
|
|
14477
|
+
let x = 0;
|
|
14478
|
+
for (const run of widths) {
|
|
14479
|
+
if (dark) matrix.setRegion(x, 0, run, height);
|
|
14480
|
+
x += run;
|
|
14481
|
+
dark = !dark;
|
|
14482
|
+
}
|
|
14483
|
+
return matrix;
|
|
14484
|
+
}
|
|
14485
|
+
|
|
14486
|
+
/** Encode a checked GTIN as DataBar Omnidirectional or Truncated. */
|
|
14487
|
+
function encodeDataBar14(value, options = {}) {
|
|
14488
|
+
const variant = options.variant ?? 'omnidirectional';
|
|
14489
|
+
if (variant !== 'omnidirectional' && variant !== 'truncated') {
|
|
14490
|
+
throw new EncodeError('GS1 DataBar-14 physical encoder currently supports omnidirectional and truncated');
|
|
14491
|
+
}
|
|
14492
|
+
const height = options.height ?? (variant === 'omnidirectional' ? 33 : 13);
|
|
14493
|
+
if (!Number.isInteger(height) || height < (variant === 'omnidirectional' ? 33 : 13)) {
|
|
14494
|
+
throw new EncodeError(`GS1 DataBar ${variant} height is below its normative minimum`);
|
|
14495
|
+
}
|
|
14496
|
+
const compacted = encodeDataBar14GTIN(value, { linkage: options.linkage });
|
|
14497
|
+
const characters = compacted.physicalCharacters;
|
|
14498
|
+
const check = finderIndexes(characters);
|
|
14499
|
+
const widths = [1, 1];
|
|
14500
|
+
widths.push(...check.widths[0]);
|
|
14501
|
+
widths.push(...DATABAR14_FINDERS[check.left]);
|
|
14502
|
+
widths.push(...check.widths[1].slice().reverse());
|
|
14503
|
+
widths.push(...check.widths[2]);
|
|
14504
|
+
widths.push(...DATABAR14_FINDERS[check.right].slice().reverse());
|
|
14505
|
+
widths.push(...check.widths[3].slice().reverse());
|
|
14506
|
+
widths.push(1, 1);
|
|
14507
|
+
const matrix = widthsToMatrix(widths, height);
|
|
14508
|
+
matrix.databar = Object.freeze({ variant, gtin: compacted.gtin, linkage: compacted.linkage, checksum: check.checksum });
|
|
14509
|
+
return matrix;
|
|
14510
|
+
}
|
|
14511
|
+
|
|
14512
|
+
__exports.encodeDataBar14 = encodeDataBar14;
|
|
14513
|
+
};
|
|
14514
|
+
|
|
14515
|
+
__modules["databar/decoder.js"] = function (__require, __exports) {
|
|
14516
|
+
/** Clean-matrix decoder for GS1 DataBar Omnidirectional and Truncated. @module databar/decoder */
|
|
14517
|
+
const { ChecksumError, FormatError } = __require("core/errors.js");
|
|
14518
|
+
const { decodeDataBar14GTIN } = __require("databar/codec.js");
|
|
14519
|
+
const { DATABAR14_CHECKSUM_WEIGHTS, DATABAR14_FINDERS, dataBar14ValueForWidths } = __require("databar/patterns.js");
|
|
14520
|
+
|
|
14521
|
+
function sampledRuns(matrix) {
|
|
14522
|
+
if (!matrix || !Number.isInteger(matrix.width) || !Number.isInteger(matrix.height)) {
|
|
14523
|
+
throw new TypeError('GS1 DataBar decoder expects a BitMatrix-like value');
|
|
14524
|
+
}
|
|
14525
|
+
if (matrix.width % 96 !== 0) throw new FormatError('GS1 DataBar-14 matrix width must be an integer multiple of 96 modules');
|
|
14526
|
+
const scale = matrix.width / 96;
|
|
14527
|
+
const y = Math.floor(matrix.height / 2);
|
|
14528
|
+
const bits = Array.from({ length: 96 }, (_, x) => matrix.get(x * scale + Math.floor(scale / 2), y));
|
|
14529
|
+
if (bits[0] || !bits[95]) throw new FormatError('GS1 DataBar-14 guard pattern is invalid');
|
|
14530
|
+
const runs = [];
|
|
14531
|
+
let current = bits[0];
|
|
14532
|
+
let length = 0;
|
|
14533
|
+
for (const bit of bits) {
|
|
14534
|
+
if (bit === current) length++;
|
|
14535
|
+
else {
|
|
14536
|
+
runs.push(length);
|
|
14537
|
+
current = bit;
|
|
14538
|
+
length = 1;
|
|
14539
|
+
}
|
|
14540
|
+
}
|
|
14541
|
+
runs.push(length);
|
|
14542
|
+
if (runs.length !== 46 || runs[0] !== 1 || runs[1] !== 1 || runs[44] !== 1 || runs[45] !== 1) {
|
|
14543
|
+
throw new FormatError('GS1 DataBar-14 element count or guard widths are invalid');
|
|
14544
|
+
}
|
|
14545
|
+
return runs;
|
|
14546
|
+
}
|
|
14547
|
+
|
|
14548
|
+
function finderIndex(widths) {
|
|
14549
|
+
const key = widths.join(',');
|
|
14550
|
+
return DATABAR14_FINDERS.findIndex((candidate) => candidate.join(',') === key);
|
|
14551
|
+
}
|
|
14552
|
+
|
|
14553
|
+
function expectedChecksum(widths) {
|
|
14554
|
+
const offsets = [0, 8, 24, 16];
|
|
14555
|
+
let checksum = 0;
|
|
14556
|
+
for (let character = 0; character < 4; character++) {
|
|
14557
|
+
for (let element = 0; element < 8; element++) {
|
|
14558
|
+
checksum += widths[character][element] * DATABAR14_CHECKSUM_WEIGHTS[offsets[character] + element];
|
|
14559
|
+
}
|
|
14560
|
+
}
|
|
14561
|
+
checksum %= 79;
|
|
14562
|
+
if (checksum >= 8) checksum++;
|
|
14563
|
+
if (checksum >= 72) checksum++;
|
|
14564
|
+
return checksum;
|
|
14565
|
+
}
|
|
14566
|
+
|
|
14567
|
+
/** Decode a clean or integer-scaled 96-module DataBar-14 matrix. */
|
|
14568
|
+
function decodeDataBar14(matrix) {
|
|
14569
|
+
const runs = sampledRuns(matrix);
|
|
14570
|
+
const widths = [
|
|
14571
|
+
runs.slice(2, 10),
|
|
14572
|
+
runs.slice(15, 23).slice().reverse(),
|
|
14573
|
+
runs.slice(23, 31),
|
|
14574
|
+
runs.slice(36, 44).slice().reverse(),
|
|
14575
|
+
];
|
|
14576
|
+
const leftFinder = finderIndex(runs.slice(10, 15));
|
|
14577
|
+
const rightFinder = finderIndex(runs.slice(31, 36).slice().reverse());
|
|
14578
|
+
if (leftFinder < 0 || rightFinder < 0) throw new FormatError('GS1 DataBar-14 finder pattern is invalid');
|
|
14579
|
+
const encodedChecksum = leftFinder * 9 + rightFinder;
|
|
14580
|
+
if (encodedChecksum !== expectedChecksum(widths)) throw new ChecksumError('GS1 DataBar-14 checksum mismatch');
|
|
14581
|
+
|
|
14582
|
+
const outerLeft = dataBar14ValueForWidths(widths[0], 'outside');
|
|
14583
|
+
const innerLeft = dataBar14ValueForWidths(widths[1], 'inside');
|
|
14584
|
+
const innerRight = dataBar14ValueForWidths(widths[2], 'inside');
|
|
14585
|
+
const outerRight = dataBar14ValueForWidths(widths[3], 'outside');
|
|
14586
|
+
const decoded = decodeDataBar14GTIN({ outerLeft, innerLeft, outerRight, innerRight });
|
|
14587
|
+
return Object.freeze({
|
|
14588
|
+
format: 'databar-omnidirectional',
|
|
14589
|
+
text: decoded.gtin,
|
|
14590
|
+
gtin: decoded.gtin,
|
|
14591
|
+
linkage: decoded.linkage,
|
|
14592
|
+
symbologyIdentifier: ']e0',
|
|
14593
|
+
});
|
|
14594
|
+
}
|
|
14595
|
+
|
|
14596
|
+
__exports.decodeDataBar14 = decodeDataBar14;
|
|
14597
|
+
};
|
|
14598
|
+
|
|
14599
|
+
__modules["databar/index.js"] = function (__require, __exports) {
|
|
14600
|
+
/** Verified GS1 DataBar data-layer primitives. @module databar */
|
|
14601
|
+
const __reexport0 = __require("databar/codec.js"); __exports.dataBarGtinTransmission = __reexport0.dataBarGtinTransmission; __exports.decodeDataBar14GTIN = __reexport0.decodeDataBar14GTIN; __exports.decodeDataBarLimitedGTIN = __reexport0.decodeDataBarLimitedGTIN; __exports.encodeDataBar14GTIN = __reexport0.encodeDataBar14GTIN; __exports.encodeDataBarLimitedGTIN = __reexport0.encodeDataBarLimitedGTIN; __exports.gtinCheckDigit = __reexport0.gtinCheckDigit; __exports.makeGTIN14 = __reexport0.makeGTIN14; __exports.normalizeGTIN = __reexport0.normalizeGTIN;
|
|
14602
|
+
const __reexport1 = __require("databar/gs1.js"); __exports.GS1_SEPARATOR = __reexport1.GS1_SEPARATOR; __exports.decodeGS1ElementString = __reexport1.decodeGS1ElementString; __exports.encodeGS1ElementString = __reexport1.encodeGS1ElementString; __exports.formatGS1Elements = __reexport1.formatGS1Elements; __exports.gs1AIInfo = __reexport1.gs1AIInfo; __exports.parseGS1ElementString = __reexport1.parseGS1ElementString;
|
|
14603
|
+
const __reexport2 = __require("databar/tables.js"); __exports.DATABAR14_VARIANTS = __reexport2.DATABAR14_VARIANTS; __exports.DATABAR_LIMITED_VARIANT = __reexport2.DATABAR_LIMITED_VARIANT; __exports.dataBar14GroupFor = __reexport2.dataBar14GroupFor; __exports.validateDataBarTables = __reexport2.validateDataBarTables;
|
|
14604
|
+
const __reexport3 = __require("databar/encoder.js"); __exports.encodeDataBar14 = __reexport3.encodeDataBar14;
|
|
14605
|
+
const __reexport4 = __require("databar/decoder.js"); __exports.decodeDataBar14 = __reexport4.decodeDataBar14;
|
|
14606
|
+
const __reexport5 = __require("databar/patterns.js"); __exports.DATABAR14_CHECKSUM_WEIGHTS = __reexport5.DATABAR14_CHECKSUM_WEIGHTS; __exports.DATABAR14_FINDERS = __reexport5.DATABAR14_FINDERS; __exports.dataBar14CharacterWidths = __reexport5.dataBar14CharacterWidths; __exports.dataBar14ValueForWidths = __reexport5.dataBar14ValueForWidths; __exports.dataBarWidths = __reexport5.dataBarWidths;
|
|
14607
|
+
|
|
14608
|
+
|
|
14609
|
+
};
|
|
14610
|
+
|
|
14611
|
+
__modules["render/options.js"] = function (__require, __exports) {
|
|
14612
|
+
/**
|
|
14613
|
+
* Shared render options, normalised once so every backend agrees.
|
|
14614
|
+
*
|
|
14615
|
+
* @module render/options
|
|
14616
|
+
*/
|
|
14617
|
+
const { BitMatrix } = __require("core/bit-matrix.js");
|
|
14618
|
+
|
|
14619
|
+
/**
|
|
14620
|
+
* @typedef {object} RenderOptions
|
|
14621
|
+
* @property {number} [scale] Pixels per module. Default 8.
|
|
14622
|
+
* @property {number} [margin] Quiet-zone modules on every side. Default 4.
|
|
14623
|
+
* @property {string} [dark] Colour of set modules. Default '#000000'.
|
|
14624
|
+
* @property {string} [light] Colour of clear modules, or 'none' for transparent.
|
|
14625
|
+
* @property {number} [barHeight] For 1D symbols: total bar height in pixels.
|
|
14626
|
+
*/
|
|
14627
|
+
|
|
14628
|
+
/**
|
|
14629
|
+
* Expand and pad the matrix, and resolve every dimension.
|
|
14630
|
+
*
|
|
14631
|
+
* Linear symbols arrive one module tall. They are stretched to `barHeight`
|
|
14632
|
+
* *before* the quiet zone is applied, so the margin ends up uniform on all
|
|
14633
|
+
* four sides — padding first would leave a quiet zone one module tall against
|
|
14634
|
+
* bars a hundred pixels tall, which no scanner would accept.
|
|
14635
|
+
*
|
|
14636
|
+
* @param {BitMatrix} matrix
|
|
14637
|
+
* @param {RenderOptions} options
|
|
14638
|
+
*/
|
|
14639
|
+
function normalizeOptions(matrix, options = {}) {
|
|
14640
|
+
const scale = Math.max(1, Math.floor(options.scale ?? 8));
|
|
14641
|
+
const margin = Math.max(0, Math.floor(options.margin ?? 4));
|
|
14642
|
+
const dark = options.dark ?? '#000000';
|
|
14643
|
+
const light = options.light ?? '#ffffff';
|
|
14644
|
+
const barHeight = options.barHeight ?? null;
|
|
14645
|
+
|
|
14646
|
+
let base = matrix;
|
|
14647
|
+
const is1D = matrix.height === 1;
|
|
14648
|
+
|
|
14649
|
+
if (is1D) {
|
|
14650
|
+
// Default to a bar height that stays scannable: tall enough that a laser
|
|
14651
|
+
// crossing at a slight angle still passes through the whole symbol.
|
|
14652
|
+
const targetPixels = barHeight ?? Math.max(40, Math.round(matrix.width * scale * 0.15));
|
|
14653
|
+
const rows = Math.max(1, Math.round(targetPixels / scale));
|
|
14654
|
+
base = new BitMatrix(matrix.width, rows);
|
|
14655
|
+
for (let x = 0; x < matrix.width; x++) {
|
|
14656
|
+
if (!matrix.get(x, 0)) continue;
|
|
14657
|
+
for (let y = 0; y < rows; y++) base.set(x, y);
|
|
14658
|
+
}
|
|
14659
|
+
}
|
|
14660
|
+
|
|
14661
|
+
const source = margin > 0 ? base.withMargin(margin) : base;
|
|
14662
|
+
|
|
14663
|
+
return {
|
|
14664
|
+
scale,
|
|
14665
|
+
margin,
|
|
14666
|
+
dark,
|
|
14667
|
+
light,
|
|
14668
|
+
is1D,
|
|
14669
|
+
source,
|
|
14670
|
+
rowHeight: scale,
|
|
14671
|
+
pixelWidth: source.width * scale,
|
|
14672
|
+
pixelHeight: source.height * scale,
|
|
14673
|
+
};
|
|
14674
|
+
}
|
|
14675
|
+
|
|
14676
|
+
/**
|
|
14677
|
+
* Parse a CSS colour into RGBA bytes.
|
|
14678
|
+
*
|
|
14679
|
+
* Supports the forms a barcode actually needs: #rgb, #rgba, #rrggbb,
|
|
14680
|
+
* #rrggbbaa, rgb(), rgba(), plus 'none' and 'transparent'.
|
|
14681
|
+
*
|
|
14682
|
+
* @param {string} colour
|
|
14683
|
+
* @returns {[number, number, number, number]}
|
|
14684
|
+
*/
|
|
14685
|
+
function parseColor(colour) {
|
|
14686
|
+
const value = String(colour).trim().toLowerCase();
|
|
14687
|
+
|
|
14688
|
+
if (value === 'none' || value === 'transparent') return [0, 0, 0, 0];
|
|
14689
|
+
if (value === 'white') return [255, 255, 255, 255];
|
|
14690
|
+
if (value === 'black') return [0, 0, 0, 255];
|
|
14691
|
+
|
|
14692
|
+
if (value[0] === '#') {
|
|
14693
|
+
const hex = value.slice(1);
|
|
14694
|
+
const expand = (c) => parseInt(c + c, 16);
|
|
14695
|
+
if (hex.length === 3) {
|
|
14696
|
+
return [expand(hex[0]), expand(hex[1]), expand(hex[2]), 255];
|
|
14697
|
+
}
|
|
14698
|
+
if (hex.length === 4) {
|
|
14699
|
+
return [expand(hex[0]), expand(hex[1]), expand(hex[2]), expand(hex[3])];
|
|
14700
|
+
}
|
|
14701
|
+
if (hex.length === 6) {
|
|
14702
|
+
return [
|
|
14703
|
+
parseInt(hex.slice(0, 2), 16),
|
|
14704
|
+
parseInt(hex.slice(2, 4), 16),
|
|
14705
|
+
parseInt(hex.slice(4, 6), 16),
|
|
14706
|
+
255,
|
|
14707
|
+
];
|
|
14708
|
+
}
|
|
14709
|
+
if (hex.length === 8) {
|
|
14710
|
+
return [
|
|
14711
|
+
parseInt(hex.slice(0, 2), 16),
|
|
14712
|
+
parseInt(hex.slice(2, 4), 16),
|
|
14713
|
+
parseInt(hex.slice(4, 6), 16),
|
|
14714
|
+
parseInt(hex.slice(6, 8), 16),
|
|
14715
|
+
];
|
|
14716
|
+
}
|
|
12639
14717
|
}
|
|
12640
14718
|
|
|
12641
14719
|
const fn = value.match(/^rgba?\(([^)]+)\)$/);
|
|
@@ -13791,6 +15869,9 @@ const micropdf417 = __require("micropdf417/index.js");
|
|
|
13791
15869
|
const microqr = __require("microqr/index.js");
|
|
13792
15870
|
const rmqr = __require("rmqr/index.js");
|
|
13793
15871
|
const frameqr = __require("frameqr/index.js");
|
|
15872
|
+
const aztecRune = __require("aztecrune/index.js");
|
|
15873
|
+
const compactPdf417 = __require("compactpdf417/index.js");
|
|
15874
|
+
const databar = __require("databar/index.js");
|
|
13794
15875
|
__exports.BitMatrix = BitMatrix;
|
|
13795
15876
|
const __reexport0 = __require("core/errors.js"); __exports.BarcodeError = __reexport0.BarcodeError; __exports.EncodeError = __reexport0.EncodeError; __exports.NotFoundError = __reexport0.NotFoundError; __exports.FormatError = __reexport0.FormatError; __exports.ChecksumError = __reexport0.ChecksumError;
|
|
13796
15877
|
const __reexport1 = __require("image/luminance.js"); __exports.LuminanceSource = __reexport1.LuminanceSource;
|
|
@@ -13804,7 +15885,12 @@ const __reexport7 = __require("render/index.js"); __exports.renderToCanvasAutoAs
|
|
|
13804
15885
|
const __reexport8 = __require("qr/index.js"); __exports.encodeQR = __reexport8.encodeQR; __exports.decodeQR = __reexport8.decodeQR; __exports.detectQR = __reexport8.detectQR; __exports.detectAndDecodeQR = __reexport8.detectAndDecodeQR;
|
|
13805
15886
|
const __reexport9 = __require("datamatrix/index.js"); __exports.encodeDataMatrix = __reexport9.encodeDataMatrix; __exports.decodeDataMatrix = __reexport9.decodeDataMatrix; __exports.detectDataMatrix = __reexport9.detectDataMatrix; __exports.detectAndDecodeDataMatrix = __reexport9.detectAndDecodeDataMatrix;
|
|
13806
15887
|
const __reexport10 = __require("aztec/index.js"); __exports.encodeAztec = __reexport10.encodeAztec; __exports.decodeAztec = __reexport10.decodeAztec; __exports.detectAztec = __reexport10.detectAztec; __exports.detectAndDecodeAztec = __reexport10.detectAndDecodeAztec;
|
|
15888
|
+
Object.assign(__exports, __require("aztecrune/index.js"));
|
|
13807
15889
|
const __reexport11 = __require("pdf417/index.js"); __exports.encodePDF417 = __reexport11.encodePDF417; __exports.decodePDF417 = __reexport11.decodePDF417; __exports.detectPDF417 = __reexport11.detectPDF417; __exports.detectAndDecodePDF417 = __reexport11.detectAndDecodePDF417;
|
|
15890
|
+
Object.assign(__exports, __require("compactpdf417/index.js"));
|
|
15891
|
+
// DataBar currently exposes verified GS1 data-layer codecs only; physical
|
|
15892
|
+
// symbol rendering and image detection remain deliberately out of scope.
|
|
15893
|
+
Object.assign(__exports, __require("databar/index.js"));
|
|
13808
15894
|
const __reexport12 = __require("micropdf417/index.js"); __exports.encodeMicroPDF417 = __reexport12.encodeMicroPDF417; __exports.decodeMicroPDF417 = __reexport12.decodeMicroPDF417; __exports.detectMicroPDF417 = __reexport12.detectMicroPDF417; __exports.detectAndDecodeMicroPDF417 = __reexport12.detectAndDecodeMicroPDF417;
|
|
13809
15895
|
const __reexport13 = __require("microqr/index.js"); __exports.encodeMicroQR = __reexport13.encodeMicroQR; __exports.decodeMicroQR = __reexport13.decodeMicroQR; __exports.detectMicroQR = __reexport13.detectMicroQR; __exports.detectAndDecodeMicroQR = __reexport13.detectAndDecodeMicroQR;
|
|
13810
15896
|
const __reexport14 = __require("rmqr/index.js"); __exports.encodeRMQR = __reexport14.encodeRMQR; __exports.decodeRMQR = __reexport14.decodeRMQR; __exports.detectRMQR = __reexport14.detectRMQR; __exports.detectAndDecodeRMQR = __reexport14.detectAndDecodeRMQR;
|
|
@@ -13850,6 +15936,11 @@ const rmqrCanEncode = typeof rmqr.encodeRMQR === 'function';
|
|
|
13850
15936
|
const rmqrCanDecode = typeof rmqr.detectAndDecodeRMQR === 'function';
|
|
13851
15937
|
const frameQrCanEncode = typeof frameqr.encodeFrameQR === 'function';
|
|
13852
15938
|
const frameQrCanDecode = typeof frameqr.detectAndDecodeFrameQR === 'function';
|
|
15939
|
+
const aztecRuneCanEncode = typeof aztecRune.encodeAztecRune === 'function';
|
|
15940
|
+
const aztecRuneCanDecode = typeof aztecRune.detectAndDecodeAztecRune === 'function';
|
|
15941
|
+
const compactPdf417CanEncode = typeof compactPdf417.encodeCompactPDF417 === 'function';
|
|
15942
|
+
const compactPdf417CanDecode = typeof compactPdf417.detectAndDecodeCompactPDF417 === 'function';
|
|
15943
|
+
const dataBarCanEncode = typeof databar.encodeDataBar14 === 'function';
|
|
13853
15944
|
|
|
13854
15945
|
/**
|
|
13855
15946
|
* Every format this build supports.
|
|
@@ -13891,6 +15982,13 @@ function listFormats() {
|
|
|
13891
15982
|
canRead: aztecCanDecode,
|
|
13892
15983
|
kind: /** @type {'2D'} */ ('2D'),
|
|
13893
15984
|
});
|
|
15985
|
+
formats.push({
|
|
15986
|
+
id: 'aztecrune',
|
|
15987
|
+
label: 'Aztec Rune',
|
|
15988
|
+
canWrite: aztecRuneCanEncode,
|
|
15989
|
+
canRead: aztecRuneCanDecode,
|
|
15990
|
+
kind: /** @type {'2D'} */ ('2D'),
|
|
15991
|
+
});
|
|
13894
15992
|
formats.push({
|
|
13895
15993
|
id: 'pdf417',
|
|
13896
15994
|
label: 'PDF417',
|
|
@@ -13898,6 +15996,13 @@ function listFormats() {
|
|
|
13898
15996
|
canRead: pdf417CanDecode,
|
|
13899
15997
|
kind: /** @type {'2D'} */ ('2D'),
|
|
13900
15998
|
});
|
|
15999
|
+
formats.push({
|
|
16000
|
+
id: 'compactpdf417',
|
|
16001
|
+
label: 'Compact PDF417',
|
|
16002
|
+
canWrite: compactPdf417CanEncode,
|
|
16003
|
+
canRead: compactPdf417CanDecode,
|
|
16004
|
+
kind: /** @type {'2D'} */ ('2D'),
|
|
16005
|
+
});
|
|
13901
16006
|
formats.push({
|
|
13902
16007
|
id: 'micropdf417',
|
|
13903
16008
|
label: 'MicroPDF417',
|
|
@@ -13926,6 +16031,13 @@ function listFormats() {
|
|
|
13926
16031
|
canRead: frameQrCanDecode,
|
|
13927
16032
|
kind: /** @type {'2D'} */ ('2D'),
|
|
13928
16033
|
});
|
|
16034
|
+
formats.push({
|
|
16035
|
+
id: 'gs1databar14',
|
|
16036
|
+
label: 'GS1 DataBar Omnidirectional / Truncated',
|
|
16037
|
+
canWrite: dataBarCanEncode,
|
|
16038
|
+
canRead: false,
|
|
16039
|
+
kind: /** @type {'1D'} */ ('1D'),
|
|
16040
|
+
});
|
|
13929
16041
|
|
|
13930
16042
|
return formats;
|
|
13931
16043
|
}
|
|
@@ -13979,9 +16091,15 @@ function encode(text, options = {}) {
|
|
|
13979
16091
|
if (format === 'aztec' || format === 'aztec-code') {
|
|
13980
16092
|
return aztec.encodeAztec(value, options);
|
|
13981
16093
|
}
|
|
16094
|
+
if (format === 'aztecrune' || format === 'aztec-rune' || format === 'rune') {
|
|
16095
|
+
return aztecRune.encodeAztecRune(value, options);
|
|
16096
|
+
}
|
|
13982
16097
|
if (format === 'pdf417' || format === 'pdf-417') {
|
|
13983
16098
|
return pdf417.encodePDF417(value, options);
|
|
13984
16099
|
}
|
|
16100
|
+
if (format === 'compactpdf417' || format === 'compact-pdf417' || format === 'compact-pdf-417') {
|
|
16101
|
+
return compactPdf417.encodeCompactPDF417(value, options);
|
|
16102
|
+
}
|
|
13985
16103
|
if (format === 'micropdf417' || format === 'micro-pdf417' || format === 'micro-pdf-417') {
|
|
13986
16104
|
return micropdf417.encodeMicroPDF417(value, options);
|
|
13987
16105
|
}
|
|
@@ -13994,10 +16112,13 @@ function encode(text, options = {}) {
|
|
|
13994
16112
|
if (format === 'frameqr' || format === 'frame-qr' || format === 'canvas-qr') {
|
|
13995
16113
|
return frameqr.encodeFrameQR(value, options);
|
|
13996
16114
|
}
|
|
16115
|
+
if (format === 'gs1databar14' || format === 'gs1-databar14' || format === 'databar') {
|
|
16116
|
+
return databar.encodeDataBar14(value, options);
|
|
16117
|
+
}
|
|
13997
16118
|
|
|
13998
16119
|
const entry = ONED_FORMATS[format];
|
|
13999
16120
|
if (!entry) {
|
|
14000
|
-
const known = [...Object.keys(ONED_FORMATS), 'qr', 'datamatrix', 'aztec', 'pdf417', 'micropdf417', 'microqr', 'rmqr', 'frameqr'].join(', ');
|
|
16121
|
+
const known = [...Object.keys(ONED_FORMATS), 'qr', 'datamatrix', 'aztec', 'aztecrune', 'pdf417', 'compactpdf417', 'micropdf417', 'microqr', 'rmqr', 'frameqr', 'gs1databar14'].join(', ');
|
|
14001
16122
|
throw new EncodeError(`Unknown format "${format}". Known formats: ${known}`);
|
|
14002
16123
|
}
|
|
14003
16124
|
return entry.encode(value, options);
|
|
@@ -14047,7 +16168,9 @@ function decode(image, options = {}) {
|
|
|
14047
16168
|
const wantQR = !want || want.has('qr') || want.has('qrcode');
|
|
14048
16169
|
const wantDataMatrix = !want || want.has('datamatrix') || want.has('data-matrix');
|
|
14049
16170
|
const wantAztec = !want || want.has('aztec') || want.has('aztec-code');
|
|
16171
|
+
const wantAztecRune = !want || want.has('aztecrune') || want.has('aztec-rune') || want.has('rune');
|
|
14050
16172
|
const wantPDF417 = !want || want.has('pdf417') || want.has('pdf-417');
|
|
16173
|
+
const wantCompactPDF417 = !want || want.has('compactpdf417') || want.has('compact-pdf417') || want.has('compact-pdf-417');
|
|
14051
16174
|
const wantMicroPDF417 = !want || want.has('micropdf417') || want.has('micro-pdf417') || want.has('micro-pdf-417');
|
|
14052
16175
|
const wantMicroQR = !want || want.has('microqr') || want.has('micro-qr');
|
|
14053
16176
|
const wantRMQR = !want || want.has('rmqr') || want.has('r-mqr') || want.has('rectangular-micro-qr');
|
|
@@ -14104,6 +16227,15 @@ function decode(image, options = {}) {
|
|
|
14104
16227
|
}
|
|
14105
16228
|
}
|
|
14106
16229
|
|
|
16230
|
+
if (wantAztecRune && aztecRuneCanDecode) {
|
|
16231
|
+
try {
|
|
16232
|
+
const found = aztecRune.detectAndDecodeAztecRune(bits);
|
|
16233
|
+
if (found) results.push({ ...found, format: 'aztecrune' });
|
|
16234
|
+
} catch {
|
|
16235
|
+
/* no Aztec Rune in this pass */
|
|
16236
|
+
}
|
|
16237
|
+
}
|
|
16238
|
+
|
|
14107
16239
|
if (wantPDF417 && pdf417CanDecode) {
|
|
14108
16240
|
try {
|
|
14109
16241
|
const found = pdf417.detectAndDecodePDF417(bits);
|
|
@@ -14113,6 +16245,15 @@ function decode(image, options = {}) {
|
|
|
14113
16245
|
}
|
|
14114
16246
|
}
|
|
14115
16247
|
|
|
16248
|
+
if (wantCompactPDF417 && compactPdf417CanDecode) {
|
|
16249
|
+
try {
|
|
16250
|
+
const found = compactPdf417.detectAndDecodeCompactPDF417(bits);
|
|
16251
|
+
if (found) results.push({ ...found, format: 'compactpdf417' });
|
|
16252
|
+
} catch {
|
|
16253
|
+
/* no Compact PDF417 in this pass */
|
|
16254
|
+
}
|
|
16255
|
+
}
|
|
16256
|
+
|
|
14116
16257
|
if (wantMicroPDF417 && microPdf417CanDecode) {
|
|
14117
16258
|
// MicroPDF417 detection measures runs across the whole raster. Hybrid
|
|
14118
16259
|
// thresholding can alter uniform modules near local-window boundaries,
|
|
@@ -14191,7 +16332,7 @@ function decodeStrict(image, options) {
|
|
|
14191
16332
|
}
|
|
14192
16333
|
|
|
14193
16334
|
/** Library version, matching package.json. */
|
|
14194
|
-
const VERSION = '1.
|
|
16335
|
+
const VERSION = '1.4.1';
|
|
14195
16336
|
|
|
14196
16337
|
__exports.listFormats = listFormats;
|
|
14197
16338
|
__exports.encode = encode;
|