diff --git a/dist/decoder/decodeData/index.d.ts b/dist/decoder/decodeData/index.d.ts index 4cc0e24f..732b0f9b 100644 --- a/dist/decoder/decodeData/index.d.ts +++ b/dist/decoder/decodeData/index.d.ts @@ -6,7 +6,11 @@ export interface ByteChunk { type: Mode.Byte | Mode.Kanji; bytes: number[]; } -export declare type Chunks = Array; +export interface ECIChunk { + type: Mode.ECI; + assignmentNumber: number; +} +export declare type Chunks = Array; export interface DecodedQR { text: string; bytes: number[]; @@ -17,5 +21,6 @@ export declare enum Mode { Alphanumeric = "alphanumeric", Byte = "byte", Kanji = "kanji", + ECI = "eci", } export declare function decode(data: Uint8ClampedArray, version: number): DecodedQR; diff --git a/dist/jsQR.js b/dist/jsQR.js index 6352c01c..429afeac 100644 --- a/dist/jsQR.js +++ b/dist/jsQR.js @@ -809,6 +809,7 @@ var Mode; Mode["Alphanumeric"] = "alphanumeric"; Mode["Byte"] = "byte"; Mode["Kanji"] = "kanji"; + Mode["ECI"] = "eci"; })(Mode = exports.Mode || (exports.Mode = {})); var ModeByte; (function (ModeByte) { @@ -817,8 +818,8 @@ var ModeByte; ModeByte[ModeByte["Alphanumeric"] = 2] = "Alphanumeric"; ModeByte[ModeByte["Byte"] = 4] = "Byte"; ModeByte[ModeByte["Kanji"] = 8] = "Kanji"; + ModeByte[ModeByte["ECI"] = 7] = "ECI"; // StructuredAppend = 0x3, - // ECI = 0x7, // FNC1FirstPosition = 0x5, // FNC1SecondPosition = 0x9, })(ModeByte || (ModeByte = {})); @@ -938,6 +939,33 @@ function decode(data, version) { if (mode === ModeByte.Terminator) { return result; } + else if (mode === ModeByte.ECI) { + if (stream.readBits(1) === 0) { + result.chunks.push({ + type: Mode.ECI, + assignmentNumber: stream.readBits(7), + }); + } + else if (stream.readBits(1) === 0) { + result.chunks.push({ + type: Mode.ECI, + assignmentNumber: stream.readBits(14), + }); + } + else if (stream.readBits(1) === 0) { + result.chunks.push({ + type: Mode.ECI, + assignmentNumber: stream.readBits(21), + }); + } + else { + // ECI data seems corrupted + result.chunks.push({ + type: Mode.ECI, + assignmentNumber: -1, + }); + } + } else if (mode === ModeByte.Numeric) { var numericResult = decodeNumeric(stream, size); result.text += numericResult.text; diff --git a/docs/jsQR.js b/docs/jsQR.js index 6352c01c..429afeac 100644 --- a/docs/jsQR.js +++ b/docs/jsQR.js @@ -809,6 +809,7 @@ var Mode; Mode["Alphanumeric"] = "alphanumeric"; Mode["Byte"] = "byte"; Mode["Kanji"] = "kanji"; + Mode["ECI"] = "eci"; })(Mode = exports.Mode || (exports.Mode = {})); var ModeByte; (function (ModeByte) { @@ -817,8 +818,8 @@ var ModeByte; ModeByte[ModeByte["Alphanumeric"] = 2] = "Alphanumeric"; ModeByte[ModeByte["Byte"] = 4] = "Byte"; ModeByte[ModeByte["Kanji"] = 8] = "Kanji"; + ModeByte[ModeByte["ECI"] = 7] = "ECI"; // StructuredAppend = 0x3, - // ECI = 0x7, // FNC1FirstPosition = 0x5, // FNC1SecondPosition = 0x9, })(ModeByte || (ModeByte = {})); @@ -938,6 +939,33 @@ function decode(data, version) { if (mode === ModeByte.Terminator) { return result; } + else if (mode === ModeByte.ECI) { + if (stream.readBits(1) === 0) { + result.chunks.push({ + type: Mode.ECI, + assignmentNumber: stream.readBits(7), + }); + } + else if (stream.readBits(1) === 0) { + result.chunks.push({ + type: Mode.ECI, + assignmentNumber: stream.readBits(14), + }); + } + else if (stream.readBits(1) === 0) { + result.chunks.push({ + type: Mode.ECI, + assignmentNumber: stream.readBits(21), + }); + } + else { + // ECI data seems corrupted + result.chunks.push({ + type: Mode.ECI, + assignmentNumber: -1, + }); + } + } else if (mode === ModeByte.Numeric) { var numericResult = decodeNumeric(stream, size); result.text += numericResult.text; diff --git a/src/decoder/decodeData/index.ts b/src/decoder/decodeData/index.ts index 9f2078b9..f84163f2 100644 --- a/src/decoder/decodeData/index.ts +++ b/src/decoder/decodeData/index.ts @@ -12,7 +12,12 @@ export interface ByteChunk { bytes: number[]; } -export type Chunks = Array; +export interface ECIChunk { + type: Mode.ECI; + assignmentNumber: number; +} + +export type Chunks = Array; export interface DecodedQR { text: string; @@ -25,6 +30,7 @@ export enum Mode { Alphanumeric = "alphanumeric", Byte = "byte", Kanji = "kanji", + ECI = "eci", } enum ModeByte { @@ -33,8 +39,8 @@ enum ModeByte { Alphanumeric = 0x2, Byte = 0x4, Kanji = 0x8, + ECI = 0x7, // StructuredAppend = 0x3, - // ECI = 0x7, // FNC1FirstPosition = 0x5, // FNC1SecondPosition = 0x9, } @@ -178,6 +184,29 @@ export function decode(data: Uint8ClampedArray, version: number): DecodedQR { const mode = stream.readBits(4); if (mode === ModeByte.Terminator) { return result; + } else if (mode === ModeByte.ECI) { + if (stream.readBits(1) === 0) { + result.chunks.push({ + type: Mode.ECI, + assignmentNumber: stream.readBits(7), + }); + } else if (stream.readBits(1) === 0) { + result.chunks.push({ + type: Mode.ECI, + assignmentNumber: stream.readBits(14), + }); + } else if (stream.readBits(1) === 0) { + result.chunks.push({ + type: Mode.ECI, + assignmentNumber: stream.readBits(21), + }); + } else { + // ECI data seems corrupted + result.chunks.push({ + type: Mode.ECI, + assignmentNumber: -1, + }); + } } else if (mode === ModeByte.Numeric) { const numericResult = decodeNumeric(stream, size); result.text += numericResult.text; diff --git a/src/decoder/test-data/eci.png b/src/decoder/test-data/eci.png new file mode 100644 index 00000000..cf0b3a98 Binary files /dev/null and b/src/decoder/test-data/eci.png differ diff --git a/src/decoder/test.ts b/src/decoder/test.ts index c3cf3be7..dd3c4f96 100644 --- a/src/decoder/test.ts +++ b/src/decoder/test.ts @@ -81,4 +81,23 @@ describe("decode", () => { const matrix = new BitMatrix(d, Math.sqrt(d.length)); expect(decode(matrix)).toBeNull(); }); + + it("Supports ECI chunks", async () => { + const data = await loadBinarized("./src/decoder/test-data/eci.png"); + expect(decode(data)).toEqual({ + text: "7948,328,1019,149,12,12,15,4,14,11,32,4", + bytes: [55, 57, 52, 56, 44, 51, 50, 56, 44, 49, 48, 49, 57, 44, 49, 52, 57, 44, 49, 50, 44, 49, 50, 44, 49, 53, 44, + 52, 44, 49, 52, 44, 49, 49, 44, 51, 50, 44, 52], + chunks: [ + { + type: "eci", assignmentNumber: 26, + }, { + type: "byte", + bytes: [55, 57, 52, 56, 44, 51, 50, 56, 44, 49, 48, 49, 57, 44, 49, 52, 57, 44, 49, 50, 44, 49, 50, 44, 49, + 53, 44, 52, 44, 49, 52, 44, 49, 49, 44, 51, 50, 44, 52], + text: "7948,328,1019,149,12,12,15,4,14,11,32,4", + }, + ], + }); + }); }); diff --git a/tests/end-to-end/issue-61/input.png b/tests/end-to-end/issue-61/input.png new file mode 100644 index 00000000..53a6c0a7 Binary files /dev/null and b/tests/end-to-end/issue-61/input.png differ diff --git a/tests/end-to-end/issue-61/output.json b/tests/end-to-end/issue-61/output.json new file mode 100644 index 00000000..34bc6b22 --- /dev/null +++ b/tests/end-to-end/issue-61/output.json @@ -0,0 +1,129 @@ +{ + "binaryData": [ + 55, + 57, + 52, + 56, + 44, + 51, + 50, + 56, + 44, + 49, + 48, + 49, + 57, + 44, + 49, + 52, + 57, + 44, + 49, + 50, + 44, + 49, + 50, + 44, + 49, + 53, + 44, + 52, + 44, + 49, + 52, + 44, + 49, + 49, + 44, + 51, + 50, + 44, + 52 + ], + "data": "7948,328,1019,149,12,12,15,4,14,11,32,4", + "chunks": [ + { + "type": "eci", + "assignmentNumber": 26 + }, + { + "type": "byte", + "bytes": [ + 55, + 57, + 52, + 56, + 44, + 51, + 50, + 56, + 44, + 49, + 48, + 49, + 57, + 44, + 49, + 52, + 57, + 44, + 49, + 50, + 44, + 49, + 50, + 44, + 49, + 53, + 44, + 52, + 44, + 49, + 52, + 44, + 49, + 49, + 44, + 51, + 50, + 44, + 52 + ], + "text": "7948,328,1019,149,12,12,15,4,14,11,32,4" + } + ], + "location": { + "topRightCorner": { + "x": 383.84809348093484, + "y": 488.1519065190653 + }, + "topLeftCorner": { + "x": 173.02219884001437, + "y": 488.1141764615306 + }, + "bottomRightCorner": { + "x": 384.45612961610846, + "y": 698.7848078485414 + }, + "bottomLeftCorner": { + "x": 172.9384938617451, + "y": 699.061506138255 + }, + "topRightFinderPattern": { + "x": 358.5, + "y": 513.5 + }, + "topLeftFinderPattern": { + "x": 198.5, + "y": 513.5 + }, + "bottomLeftFinderPattern": { + "x": 198.5, + "y": 673.5 + }, + "bottomRightAlignmentPattern": { + "x": 337, + "y": 651.5 + } + } +} \ No newline at end of file diff --git a/tests/end-to-end/report.json b/tests/end-to-end/report.json index ad593cce..24fb4f5b 100644 --- a/tests/end-to-end/report.json +++ b/tests/end-to-end/report.json @@ -1,7 +1,7 @@ { "counts": { "failed": 47, - "successful": 206 + "successful": 207 }, "tests": { "0": true, @@ -221,6 +221,7 @@ "issue-54-2": false, "issue-59": true, "issue-59-inverted": true, + "issue-61": true, "japan-visa": false, "japanese-jean-ad": false, "kanji": true,