@sythos/js_barcode_universal 1.5.8 → 1.5.9
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/LICENSE +5 -4
- package/NOTICE.md +2 -2
- package/README.md +17 -13
- package/bundle/sythos-barcode.esm.js +11658 -11244
- package/bundle/sythos-barcode.js +11658 -11244
- package/package.json +10 -3
- package/src/index.d.ts +1 -1
- package/src/index.js +508 -516
- package/src/js/aztec/decoder.js +208 -199
- package/src/js/aztec/detector.js +153 -126
- package/src/js/aztec/encoder.js +172 -153
- package/src/js/aztec/high-level.js +106 -101
- package/src/js/aztec/index.js +1 -12
- package/src/js/aztec/tables.js +106 -120
- package/src/js/aztecrune/decoder.js +76 -85
- package/src/js/aztecrune/detector.js +107 -93
- package/src/js/aztecrune/encoder.js +50 -68
- package/src/js/aztecrune/index.js +1 -16
- package/src/js/aztecrune/tables.js +59 -54
- package/src/js/compactpdf417/decoder.js +69 -74
- package/src/js/compactpdf417/detector.js +74 -75
- package/src/js/compactpdf417/encoder.js +68 -81
- package/src/js/compactpdf417/index.js +1 -13
- package/src/js/compactpdf417/tables.js +71 -80
- package/src/js/core/bit-buffer.js +106 -122
- package/src/js/core/bit-matrix.js +196 -194
- package/src/js/core/errors.js +13 -15
- package/src/js/core/galois-field.js +119 -133
- package/src/js/core/index.js +2 -19
- package/src/js/core/reed-solomon.js +195 -204
- package/src/js/databar/codec.js +93 -108
- package/src/js/databar/decoder.js +149 -140
- package/src/js/databar/encoder.js +47 -55
- package/src/js/databar/gs1.js +122 -123
- package/src/js/databar/index.js +4 -36
- package/src/js/databar/patterns.js +81 -85
- package/src/js/databar/tables.js +51 -52
- package/src/js/datamatrix/decoder.js +216 -182
- package/src/js/datamatrix/detector.js +161 -132
- package/src/js/datamatrix/encoder.js +192 -133
- package/src/js/datamatrix/index.js +1 -9
- package/src/js/datamatrix/tables.js +68 -69
- package/src/js/frameqr/decoder.js +102 -125
- package/src/js/frameqr/detector.js +101 -94
- package/src/js/frameqr/encoder.js +67 -80
- package/src/js/frameqr/index.js +1 -10
- package/src/js/frameqr/tables.js +145 -163
- package/src/js/image/binarizer.js +146 -162
- package/src/js/image/grid-sampler.js +63 -79
- package/src/js/image/index.js +0 -2
- package/src/js/image/luminance.js +129 -140
- package/src/js/image/perspective.js +112 -149
- package/src/js/micropdf417/compaction.js +64 -65
- package/src/js/micropdf417/decoder.js +106 -109
- package/src/js/micropdf417/detector.js +73 -70
- package/src/js/micropdf417/encoder.js +129 -154
- package/src/js/micropdf417/error-correction.js +6 -11
- package/src/js/micropdf417/index.js +2 -16
- package/src/js/micropdf417/tables.js +112 -99
- package/src/js/microqr/decoder.js +177 -182
- package/src/js/microqr/detector.js +240 -256
- package/src/js/microqr/encoder.js +239 -194
- package/src/js/microqr/index.js +0 -2
- package/src/js/microqr/tables.js +208 -200
- package/src/js/oned/addons.js +167 -191
- package/src/js/oned/index.js +27 -58
- package/src/js/oned/patterns.js +194 -213
- package/src/js/oned/reader.js +1003 -984
- package/src/js/oned/writers.js +411 -466
- package/src/js/pdf417/compaction.js +315 -222
- package/src/js/pdf417/decoder.js +71 -36
- package/src/js/pdf417/detector.js +377 -361
- package/src/js/pdf417/encoder.js +57 -46
- package/src/js/pdf417/error-correction.js +5 -8
- package/src/js/pdf417/tables.js +248 -250
- package/src/js/qr/decoder.js +311 -347
- package/src/js/qr/detector.js +378 -395
- package/src/js/qr/encoder.js +514 -599
- package/src/js/qr/index.js +0 -2
- package/src/js/qr/tables.js +375 -422
- package/src/js/render/image-data.js +57 -62
- package/src/js/render/index.js +21 -23
- package/src/js/render/options.js +82 -90
- package/src/js/render/png.js +144 -169
- package/src/js/render/svg.js +41 -44
- package/src/js/render/webgl.js +103 -109
- package/src/js/render/webgpu.js +205 -217
- package/src/js/rmqr/decoder.js +161 -53
- package/src/js/rmqr/detector.js +73 -41
- package/src/js/rmqr/encoder.js +253 -104
- package/src/js/rmqr/index.js +1 -5
- package/src/js/rmqr/tables.js +108 -85
- package/src/ts/aztec/decoder.ts +317 -0
- package/src/ts/aztec/detector.ts +224 -0
- package/src/ts/aztec/encoder.ts +257 -0
- package/src/ts/aztec/high-level.ts +211 -0
- package/src/ts/aztec/index.ts +45 -0
- package/src/ts/aztec/tables.ts +210 -0
- package/src/ts/aztecrune/decoder.ts +155 -0
- package/src/ts/aztecrune/detector.ts +166 -0
- package/src/ts/aztecrune/encoder.ts +121 -0
- package/src/ts/aztecrune/index.ts +49 -0
- package/src/ts/aztecrune/tables.ts +137 -0
- package/src/ts/compactpdf417/decoder.ts +128 -0
- package/src/ts/compactpdf417/detector.ts +139 -0
- package/src/ts/compactpdf417/encoder.ts +140 -0
- package/src/ts/compactpdf417/index.ts +17 -0
- package/src/ts/compactpdf417/tables.ts +173 -0
- package/src/ts/core/bit-buffer.ts +174 -0
- package/src/ts/core/bit-matrix.ts +241 -0
- package/src/ts/core/errors.ts +61 -0
- package/src/ts/core/galois-field.ts +207 -0
- package/src/ts/core/index.ts +56 -0
- package/src/ts/core/reed-solomon.ts +327 -0
- package/src/ts/databar/codec.ts +181 -0
- package/src/ts/databar/decoder.ts +215 -0
- package/src/ts/databar/encoder.ts +96 -0
- package/src/ts/databar/gs1.ts +177 -0
- package/src/ts/databar/index.ts +68 -0
- package/src/ts/databar/patterns.ts +143 -0
- package/src/ts/databar/tables.ts +124 -0
- package/src/ts/datamatrix/decoder.ts +262 -0
- package/src/ts/datamatrix/detector.ts +225 -0
- package/src/ts/datamatrix/encoder.ts +191 -0
- package/src/ts/datamatrix/index.ts +42 -0
- package/src/ts/datamatrix/tables.ts +123 -0
- package/src/ts/frameqr/decoder.ts +239 -0
- package/src/ts/frameqr/detector.ts +192 -0
- package/src/ts/frameqr/encoder.ts +156 -0
- package/src/ts/frameqr/index.ts +42 -0
- package/src/ts/frameqr/tables.ts +270 -0
- package/src/ts/image/binarizer.ts +270 -0
- package/src/ts/image/grid-sampler.ts +164 -0
- package/src/ts/image/index.ts +40 -0
- package/src/ts/image/luminance.ts +196 -0
- package/src/ts/image/perspective.ts +195 -0
- package/src/ts/index.d.ts +1 -1
- package/src/ts/index.ts +790 -0
- package/src/ts/micropdf417/compaction.ts +116 -0
- package/src/ts/micropdf417/decoder.ts +183 -0
- package/src/ts/micropdf417/detector.ts +149 -0
- package/src/ts/micropdf417/encoder.ts +209 -0
- package/src/ts/micropdf417/error-correction.ts +55 -0
- package/src/ts/micropdf417/index.ts +49 -0
- package/src/ts/micropdf417/tables.ts +184 -0
- package/src/ts/microqr/decoder.ts +245 -0
- package/src/ts/microqr/detector.ts +355 -0
- package/src/ts/microqr/encoder.ts +269 -0
- package/src/ts/microqr/index.ts +36 -0
- package/src/ts/microqr/tables.ts +316 -0
- package/src/ts/oned/addons.ts +420 -0
- package/src/ts/oned/index.ts +106 -0
- package/src/ts/oned/patterns.ts +384 -0
- package/src/ts/oned/reader.ts +1364 -0
- package/src/ts/oned/writers.ts +746 -0
- package/src/ts/pdf417/compaction.ts +298 -0
- package/src/ts/pdf417/decoder.ts +75 -0
- package/src/ts/pdf417/detector.ts +468 -0
- package/src/ts/pdf417/encoder.ts +91 -0
- package/src/ts/pdf417/error-correction.ts +47 -0
- package/src/ts/pdf417/index.ts +6 -0
- package/src/ts/pdf417/tables.ts +317 -0
- package/src/ts/qr/decoder.ts +575 -0
- package/src/ts/qr/detector.ts +630 -0
- package/src/ts/qr/encoder.ts +958 -0
- package/src/ts/qr/index.ts +44 -0
- package/src/ts/qr/tables.ts +737 -0
- package/src/ts/render/image-data.ts +125 -0
- package/src/ts/render/index.ts +130 -0
- package/src/ts/render/options.ts +160 -0
- package/src/ts/render/png.ts +295 -0
- package/src/ts/render/svg.ts +120 -0
- package/src/ts/render/webgl.ts +206 -0
- package/src/ts/render/webgpu.ts +369 -0
- package/src/ts/rmqr/decoder.ts +101 -0
- package/src/ts/rmqr/detector.ts +90 -0
- package/src/ts/rmqr/encoder.ts +172 -0
- package/src/ts/rmqr/index.ts +37 -0
- package/src/ts/rmqr/tables.ts +154 -0
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
*
|
|
28
28
|
* Original work. No code from any other barcode implementation.
|
|
29
29
|
*/
|
|
30
|
-
|
|
31
30
|
/**
|
|
32
31
|
* Greyscale conversion — the boundary between "an image" and "our problem".
|
|
33
32
|
*
|
|
@@ -39,158 +38,148 @@
|
|
|
39
38
|
*
|
|
40
39
|
* @module image/luminance
|
|
41
40
|
*/
|
|
42
|
-
|
|
43
41
|
import { NotFoundError } from '../core/errors.js';
|
|
44
|
-
|
|
45
42
|
/**
|
|
46
43
|
* @typedef {object} ImageLike
|
|
47
44
|
* @property {Uint8ClampedArray | Uint8Array | number[]} data RGBA, 4 bytes per pixel.
|
|
48
45
|
* @property {number} width
|
|
49
46
|
* @property {number} height
|
|
50
47
|
*/
|
|
51
|
-
|
|
52
48
|
export class LuminanceSource {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Build from any ImageData-shaped object.
|
|
66
|
-
*
|
|
67
|
-
* Transparent pixels are composited over white rather than read as black:
|
|
68
|
-
* a PNG barcode with a transparent background is common, and treating alpha
|
|
69
|
-
* as ink turns the entire quiet zone into a solid dark field.
|
|
70
|
-
*
|
|
71
|
-
* @param {ImageLike} image
|
|
72
|
-
* @returns {LuminanceSource}
|
|
73
|
-
*/
|
|
74
|
-
static fromImageData(image) {
|
|
75
|
-
const { data, width, height } = image;
|
|
76
|
-
if (!data || !width || !height) {
|
|
77
|
-
throw new NotFoundError('Image must be { data, width, height } with RGBA data');
|
|
49
|
+
/**
|
|
50
|
+
* @param {Uint8Array} grey One byte per pixel.
|
|
51
|
+
* @param {number} width
|
|
52
|
+
* @param {number} height
|
|
53
|
+
*/
|
|
54
|
+
constructor(grey, width, height) {
|
|
55
|
+
this.grey = grey;
|
|
56
|
+
this.width = width;
|
|
57
|
+
this.height = height;
|
|
78
58
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Build from any ImageData-shaped object.
|
|
61
|
+
*
|
|
62
|
+
* Transparent pixels are composited over white rather than read as black:
|
|
63
|
+
* a PNG barcode with a transparent background is common, and treating alpha
|
|
64
|
+
* as ink turns the entire quiet zone into a solid dark field.
|
|
65
|
+
*
|
|
66
|
+
* @param {ImageLike} image
|
|
67
|
+
* @returns {LuminanceSource}
|
|
68
|
+
*/
|
|
69
|
+
static fromImageData(image) {
|
|
70
|
+
const { data, width, height } = image;
|
|
71
|
+
if (!data || !width || !height) {
|
|
72
|
+
throw new NotFoundError('Image must be { data, width, height } with RGBA data');
|
|
73
|
+
}
|
|
74
|
+
if (data.length < width * height * 4) {
|
|
75
|
+
throw new NotFoundError(`Image data too short: ${data.length} bytes for ${width}x${height} RGBA ` +
|
|
76
|
+
`(expected ${width * height * 4})`);
|
|
77
|
+
}
|
|
78
|
+
const grey = new Uint8Array(width * height);
|
|
79
|
+
for (let i = 0, p = 0; i < grey.length; i++, p += 4) {
|
|
80
|
+
const a = data[p + 3];
|
|
81
|
+
let r = data[p], g = data[p + 1], b = data[p + 2];
|
|
82
|
+
if (a !== 255) {
|
|
83
|
+
// Composite over white.
|
|
84
|
+
const inv = 255 - a;
|
|
85
|
+
r = (r * a + 255 * inv) / 255;
|
|
86
|
+
g = (g * a + 255 * inv) / 255;
|
|
87
|
+
b = (b * a + 255 * inv) / 255;
|
|
88
|
+
}
|
|
89
|
+
// Integer luma approximation of Rec. 601: 0.299/0.587/0.114 scaled by 256.
|
|
90
|
+
grey[i] = (r * 77 + g * 150 + b * 29) >> 8;
|
|
91
|
+
}
|
|
92
|
+
return new LuminanceSource(grey, width, height);
|
|
84
93
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
grey[i] = (r * 77 + g * 150 + b * 29) >> 8;
|
|
94
|
+
/**
|
|
95
|
+
* Build directly from single-channel data, skipping conversion.
|
|
96
|
+
*
|
|
97
|
+
* @param {Uint8Array} grey
|
|
98
|
+
* @param {number} width
|
|
99
|
+
* @param {number} height
|
|
100
|
+
* @returns {LuminanceSource}
|
|
101
|
+
*/
|
|
102
|
+
static fromGrey(grey, width, height) {
|
|
103
|
+
if (grey.length < width * height) {
|
|
104
|
+
throw new NotFoundError('Greyscale buffer shorter than width * height');
|
|
105
|
+
}
|
|
106
|
+
return new LuminanceSource(grey, width, height);
|
|
99
107
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
* @param {Uint8Array} grey
|
|
107
|
-
* @param {number} width
|
|
108
|
-
* @param {number} height
|
|
109
|
-
* @returns {LuminanceSource}
|
|
110
|
-
*/
|
|
111
|
-
static fromGrey(grey, width, height) {
|
|
112
|
-
if (grey.length < width * height) {
|
|
113
|
-
throw new NotFoundError('Greyscale buffer shorter than width * height');
|
|
108
|
+
/**
|
|
109
|
+
* @param {number} x @param {number} y
|
|
110
|
+
* @returns {number} 0-255.
|
|
111
|
+
*/
|
|
112
|
+
get(x, y) {
|
|
113
|
+
return this.grey[y * this.width + x];
|
|
114
114
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* @param {number} y
|
|
128
|
-
* @param {Uint8Array} [out]
|
|
129
|
-
* @returns {Uint8Array}
|
|
130
|
-
*/
|
|
131
|
-
getRow(y, out) {
|
|
132
|
-
const row = out && out.length >= this.width ? out : new Uint8Array(this.width);
|
|
133
|
-
row.set(this.grey.subarray(y * this.width, (y + 1) * this.width));
|
|
134
|
-
return row;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Rotate 90 degrees clockwise.
|
|
139
|
-
*
|
|
140
|
-
* The 1D readers scan horizontally, so this is how they find vertically
|
|
141
|
-
* oriented barcodes: scan, rotate, scan again.
|
|
142
|
-
*
|
|
143
|
-
* @returns {LuminanceSource}
|
|
144
|
-
*/
|
|
145
|
-
rotate90() {
|
|
146
|
-
const { width: w, height: h, grey } = this;
|
|
147
|
-
const out = new Uint8Array(grey.length);
|
|
148
|
-
for (let y = 0; y < h; y++) {
|
|
149
|
-
for (let x = 0; x < w; x++) {
|
|
150
|
-
out[x * h + (h - 1 - y)] = grey[y * w + x];
|
|
151
|
-
}
|
|
115
|
+
/**
|
|
116
|
+
* @param {number} y
|
|
117
|
+
* @param {Uint8Array} [out]
|
|
118
|
+
* @returns {Uint8Array}
|
|
119
|
+
*/
|
|
120
|
+
getRow(y, out) {
|
|
121
|
+
const row = out && out.length >= this.width ? out : new Uint8Array(this.width);
|
|
122
|
+
row.set(this.grey.subarray(y * this.width, (y + 1) * this.width));
|
|
123
|
+
return row;
|
|
152
124
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const w = Math.floor(this.width / f);
|
|
169
|
-
const h = Math.floor(this.height / f);
|
|
170
|
-
const out = new Uint8Array(w * h);
|
|
171
|
-
const area = f * f;
|
|
172
|
-
for (let y = 0; y < h; y++) {
|
|
173
|
-
for (let x = 0; x < w; x++) {
|
|
174
|
-
let sum = 0;
|
|
175
|
-
for (let dy = 0; dy < f; dy++) {
|
|
176
|
-
const base = (y * f + dy) * this.width + x * f;
|
|
177
|
-
for (let dx = 0; dx < f; dx++) sum += this.grey[base + dx];
|
|
125
|
+
/**
|
|
126
|
+
* Rotate 90 degrees clockwise.
|
|
127
|
+
*
|
|
128
|
+
* The 1D readers scan horizontally, so this is how they find vertically
|
|
129
|
+
* oriented barcodes: scan, rotate, scan again.
|
|
130
|
+
*
|
|
131
|
+
* @returns {LuminanceSource}
|
|
132
|
+
*/
|
|
133
|
+
rotate90() {
|
|
134
|
+
const { width: w, height: h, grey } = this;
|
|
135
|
+
const out = new Uint8Array(grey.length);
|
|
136
|
+
for (let y = 0; y < h; y++) {
|
|
137
|
+
for (let x = 0; x < w; x++) {
|
|
138
|
+
out[x * h + (h - 1 - y)] = grey[y * w + x];
|
|
139
|
+
}
|
|
178
140
|
}
|
|
179
|
-
|
|
180
|
-
|
|
141
|
+
return new LuminanceSource(out, h, w);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Downscale by an integer factor with box averaging.
|
|
145
|
+
*
|
|
146
|
+
* Large camera frames are slow to scan and no more informative than a
|
|
147
|
+
* half-size copy; detectors use this to find candidates cheaply.
|
|
148
|
+
*
|
|
149
|
+
* @param {number} factor
|
|
150
|
+
* @returns {LuminanceSource}
|
|
151
|
+
*/
|
|
152
|
+
downscale(factor) {
|
|
153
|
+
const f = Math.max(1, Math.floor(factor));
|
|
154
|
+
if (f === 1)
|
|
155
|
+
return this;
|
|
156
|
+
const w = Math.floor(this.width / f);
|
|
157
|
+
const h = Math.floor(this.height / f);
|
|
158
|
+
const out = new Uint8Array(w * h);
|
|
159
|
+
const area = f * f;
|
|
160
|
+
for (let y = 0; y < h; y++) {
|
|
161
|
+
for (let x = 0; x < w; x++) {
|
|
162
|
+
let sum = 0;
|
|
163
|
+
for (let dy = 0; dy < f; dy++) {
|
|
164
|
+
const base = (y * f + dy) * this.width + x * f;
|
|
165
|
+
for (let dx = 0; dx < f; dx++)
|
|
166
|
+
sum += this.grey[base + dx];
|
|
167
|
+
}
|
|
168
|
+
out[y * w + x] = (sum / area) | 0;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return new LuminanceSource(out, w, h);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Invert. Some symbols are printed light-on-dark, and readers retry inverted
|
|
175
|
+
* when a first pass finds nothing.
|
|
176
|
+
*
|
|
177
|
+
* @returns {LuminanceSource}
|
|
178
|
+
*/
|
|
179
|
+
invert() {
|
|
180
|
+
const out = new Uint8Array(this.grey.length);
|
|
181
|
+
for (let i = 0; i < out.length; i++)
|
|
182
|
+
out[i] = 255 - this.grey[i];
|
|
183
|
+
return new LuminanceSource(out, this.width, this.height);
|
|
181
184
|
}
|
|
182
|
-
return new LuminanceSource(out, w, h);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Invert. Some symbols are printed light-on-dark, and readers retry inverted
|
|
187
|
-
* when a first pass finds nothing.
|
|
188
|
-
*
|
|
189
|
-
* @returns {LuminanceSource}
|
|
190
|
-
*/
|
|
191
|
-
invert() {
|
|
192
|
-
const out = new Uint8Array(this.grey.length);
|
|
193
|
-
for (let i = 0; i < out.length; i++) out[i] = 255 - this.grey[i];
|
|
194
|
-
return new LuminanceSource(out, this.width, this.height);
|
|
195
|
-
}
|
|
196
185
|
}
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
*
|
|
28
28
|
* Original work. No code from any other barcode implementation.
|
|
29
29
|
*/
|
|
30
|
-
|
|
31
30
|
/**
|
|
32
31
|
* Projective (perspective) transforms.
|
|
33
32
|
*
|
|
@@ -41,155 +40,119 @@
|
|
|
41
40
|
*
|
|
42
41
|
* @module image/perspective
|
|
43
42
|
*/
|
|
44
|
-
|
|
45
43
|
export class PerspectiveTransform {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
* @returns {Float32Array | number[]} The same array.
|
|
58
|
-
*/
|
|
59
|
-
transform(points) {
|
|
60
|
-
const { a11, a21, a31, a12, a22, a32, a13, a23, a33 } = this;
|
|
61
|
-
for (let i = 0; i < points.length; i += 2) {
|
|
62
|
-
const x = points[i];
|
|
63
|
-
const y = points[i + 1];
|
|
64
|
-
const w = a13 * x + a23 * y + a33;
|
|
65
|
-
points[i] = (a11 * x + a21 * y + a31) / w;
|
|
66
|
-
points[i + 1] = (a12 * x + a22 * y + a32) / w;
|
|
44
|
+
/* eslint-disable-next-line max-params */
|
|
45
|
+
constructor(a11, a21, a31, a12, a22, a32, a13, a23, a33) {
|
|
46
|
+
this.a11 = a11;
|
|
47
|
+
this.a21 = a21;
|
|
48
|
+
this.a31 = a31;
|
|
49
|
+
this.a12 = a12;
|
|
50
|
+
this.a22 = a22;
|
|
51
|
+
this.a32 = a32;
|
|
52
|
+
this.a13 = a13;
|
|
53
|
+
this.a23 = a23;
|
|
54
|
+
this.a33 = a33;
|
|
67
55
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Transform points in place.
|
|
58
|
+
*
|
|
59
|
+
* @param {Float32Array | number[]} points Interleaved [x0, y0, x1, y1, ...].
|
|
60
|
+
* @returns {Float32Array | number[]} The same array.
|
|
61
|
+
*/
|
|
62
|
+
transform(points) {
|
|
63
|
+
const { a11, a21, a31, a12, a22, a32, a13, a23, a33 } = this;
|
|
64
|
+
for (let i = 0; i < points.length; i += 2) {
|
|
65
|
+
const x = points[i];
|
|
66
|
+
const y = points[i + 1];
|
|
67
|
+
const w = a13 * x + a23 * y + a33;
|
|
68
|
+
points[i] = (a11 * x + a21 * y + a31) / w;
|
|
69
|
+
points[i + 1] = (a12 * x + a22 * y + a32) / w;
|
|
70
|
+
}
|
|
71
|
+
return points;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Transform a single point.
|
|
75
|
+
*
|
|
76
|
+
* @param {number} x @param {number} y
|
|
77
|
+
* @returns {{x: number, y: number}}
|
|
78
|
+
*/
|
|
79
|
+
transformPoint(x, y) {
|
|
80
|
+
const w = this.a13 * x + this.a23 * y + this.a33;
|
|
81
|
+
return {
|
|
82
|
+
x: (this.a11 * x + this.a21 * y + this.a31) / w,
|
|
83
|
+
y: (this.a12 * x + this.a22 * y + this.a32) / w,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Map the unit square — (0,0), (1,0), (1,1), (0,1) — onto an arbitrary quad.
|
|
88
|
+
*
|
|
89
|
+
* Corners are given in that same order, i.e. going around the quad, not
|
|
90
|
+
* as opposite pairs.
|
|
91
|
+
*
|
|
92
|
+
* @returns {PerspectiveTransform}
|
|
93
|
+
*/
|
|
94
|
+
/* eslint-disable-next-line max-params */
|
|
95
|
+
static squareToQuad(x0, y0, x1, y1, x2, y2, x3, y3) {
|
|
96
|
+
const dx3 = x0 - x1 + x2 - x3;
|
|
97
|
+
const dy3 = y0 - y1 + y2 - y3;
|
|
98
|
+
if (dx3 === 0 && dy3 === 0) {
|
|
99
|
+
// The quad is a parallelogram, so the map is affine and the projective
|
|
100
|
+
// terms vanish. Worth special-casing: it is the common case for flat
|
|
101
|
+
// scans, and the general solution divides by zero here.
|
|
102
|
+
return new PerspectiveTransform(x1 - x0, x2 - x1, x0, y1 - y0, y2 - y1, y0, 0, 0, 1);
|
|
103
|
+
}
|
|
104
|
+
const dx1 = x1 - x2;
|
|
105
|
+
const dx2 = x3 - x2;
|
|
106
|
+
const dy1 = y1 - y2;
|
|
107
|
+
const dy2 = y3 - y2;
|
|
108
|
+
const denominator = dx1 * dy2 - dx2 * dy1;
|
|
109
|
+
const a13 = (dx3 * dy2 - dx2 * dy3) / denominator;
|
|
110
|
+
const a23 = (dx1 * dy3 - dx3 * dy1) / denominator;
|
|
111
|
+
return new PerspectiveTransform(x1 - x0 + a13 * x1, x3 - x0 + a23 * x3, x0, y1 - y0 + a13 * y1, y3 - y0 + a23 * y3, y0, a13, a23, 1);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Map an arbitrary quad onto the unit square — the inverse of
|
|
115
|
+
* {@link squareToQuad}, via the adjugate.
|
|
116
|
+
*
|
|
117
|
+
* @returns {PerspectiveTransform}
|
|
118
|
+
*/
|
|
119
|
+
/* eslint-disable-next-line max-params */
|
|
120
|
+
static quadToSquare(x0, y0, x1, y1, x2, y2, x3, y3) {
|
|
121
|
+
return PerspectiveTransform.squareToQuad(x0, y0, x1, y1, x2, y2, x3, y3).inverse();
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Map one quad onto another, corner for corner.
|
|
125
|
+
*
|
|
126
|
+
* This is what turns four detected finder corners into a sampling grid:
|
|
127
|
+
* compose "detected quad -> unit square" with "unit square -> ideal grid".
|
|
128
|
+
*
|
|
129
|
+
* @returns {PerspectiveTransform}
|
|
130
|
+
*/
|
|
131
|
+
/* eslint-disable-next-line max-params */
|
|
132
|
+
static quadToQuad(sx0, sy0, sx1, sy1, sx2, sy2, sx3, sy3, dx0, dy0, dx1, dy1, dx2, dy2, dx3, dy3) {
|
|
133
|
+
const toSquare = PerspectiveTransform.quadToSquare(sx0, sy0, sx1, sy1, sx2, sy2, sx3, sy3);
|
|
134
|
+
const toQuad = PerspectiveTransform.squareToQuad(dx0, dy0, dx1, dy1, dx2, dy2, dx3, dy3);
|
|
135
|
+
return toSquare.times(toQuad);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Adjugate — the inverse up to a scale factor, which is irrelevant in
|
|
139
|
+
* homogeneous coordinates because the division by w cancels it.
|
|
140
|
+
*
|
|
141
|
+
* @returns {PerspectiveTransform}
|
|
142
|
+
*/
|
|
143
|
+
inverse() {
|
|
144
|
+
const { a11, a21, a31, a12, a22, a32, a13, a23, a33 } = this;
|
|
145
|
+
return new PerspectiveTransform(a22 * a33 - a23 * a32, a23 * a31 - a21 * a33, a21 * a32 - a22 * a31, a13 * a32 - a12 * a33, a11 * a33 - a13 * a31, a12 * a31 - a11 * a32, a12 * a23 - a13 * a22, a13 * a21 - a11 * a23, a11 * a22 - a12 * a21);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Matrix product: apply `this` first, then `other`.
|
|
149
|
+
*
|
|
150
|
+
* @param {PerspectiveTransform} other
|
|
151
|
+
* @returns {PerspectiveTransform}
|
|
152
|
+
*/
|
|
153
|
+
times(other) {
|
|
154
|
+
const { a11, a21, a31, a12, a22, a32, a13, a23, a33 } = this;
|
|
155
|
+
const o = other;
|
|
156
|
+
return new PerspectiveTransform(o.a11 * a11 + o.a21 * a12 + o.a31 * a13, o.a11 * a21 + o.a21 * a22 + o.a31 * a23, o.a11 * a31 + o.a21 * a32 + o.a31 * a33, o.a12 * a11 + o.a22 * a12 + o.a32 * a13, o.a12 * a21 + o.a22 * a22 + o.a32 * a23, o.a12 * a31 + o.a22 * a32 + o.a32 * a33, o.a13 * a11 + o.a23 * a12 + o.a33 * a13, o.a13 * a21 + o.a23 * a22 + o.a33 * a23, o.a13 * a31 + o.a23 * a32 + o.a33 * a33);
|
|
107
157
|
}
|
|
108
|
-
|
|
109
|
-
const dx1 = x1 - x2;
|
|
110
|
-
const dx2 = x3 - x2;
|
|
111
|
-
const dy1 = y1 - y2;
|
|
112
|
-
const dy2 = y3 - y2;
|
|
113
|
-
const denominator = dx1 * dy2 - dx2 * dy1;
|
|
114
|
-
const a13 = (dx3 * dy2 - dx2 * dy3) / denominator;
|
|
115
|
-
const a23 = (dx1 * dy3 - dx3 * dy1) / denominator;
|
|
116
|
-
|
|
117
|
-
return new PerspectiveTransform(
|
|
118
|
-
x1 - x0 + a13 * x1, x3 - x0 + a23 * x3, x0,
|
|
119
|
-
y1 - y0 + a13 * y1, y3 - y0 + a23 * y3, y0,
|
|
120
|
-
a13, a23, 1
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Map an arbitrary quad onto the unit square — the inverse of
|
|
126
|
-
* {@link squareToQuad}, via the adjugate.
|
|
127
|
-
*
|
|
128
|
-
* @returns {PerspectiveTransform}
|
|
129
|
-
*/
|
|
130
|
-
/* eslint-disable-next-line max-params */
|
|
131
|
-
static quadToSquare(x0, y0, x1, y1, x2, y2, x3, y3) {
|
|
132
|
-
return PerspectiveTransform.squareToQuad(x0, y0, x1, y1, x2, y2, x3, y3).inverse();
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Map one quad onto another, corner for corner.
|
|
137
|
-
*
|
|
138
|
-
* This is what turns four detected finder corners into a sampling grid:
|
|
139
|
-
* compose "detected quad -> unit square" with "unit square -> ideal grid".
|
|
140
|
-
*
|
|
141
|
-
* @returns {PerspectiveTransform}
|
|
142
|
-
*/
|
|
143
|
-
/* eslint-disable-next-line max-params */
|
|
144
|
-
static quadToQuad(
|
|
145
|
-
sx0, sy0, sx1, sy1, sx2, sy2, sx3, sy3,
|
|
146
|
-
dx0, dy0, dx1, dy1, dx2, dy2, dx3, dy3
|
|
147
|
-
) {
|
|
148
|
-
const toSquare = PerspectiveTransform.quadToSquare(sx0, sy0, sx1, sy1, sx2, sy2, sx3, sy3);
|
|
149
|
-
const toQuad = PerspectiveTransform.squareToQuad(dx0, dy0, dx1, dy1, dx2, dy2, dx3, dy3);
|
|
150
|
-
return toSquare.times(toQuad);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Adjugate — the inverse up to a scale factor, which is irrelevant in
|
|
155
|
-
* homogeneous coordinates because the division by w cancels it.
|
|
156
|
-
*
|
|
157
|
-
* @returns {PerspectiveTransform}
|
|
158
|
-
*/
|
|
159
|
-
inverse() {
|
|
160
|
-
const { a11, a21, a31, a12, a22, a32, a13, a23, a33 } = this;
|
|
161
|
-
return new PerspectiveTransform(
|
|
162
|
-
a22 * a33 - a23 * a32,
|
|
163
|
-
a23 * a31 - a21 * a33,
|
|
164
|
-
a21 * a32 - a22 * a31,
|
|
165
|
-
a13 * a32 - a12 * a33,
|
|
166
|
-
a11 * a33 - a13 * a31,
|
|
167
|
-
a12 * a31 - a11 * a32,
|
|
168
|
-
a12 * a23 - a13 * a22,
|
|
169
|
-
a13 * a21 - a11 * a23,
|
|
170
|
-
a11 * a22 - a12 * a21
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Matrix product: apply `this` first, then `other`.
|
|
176
|
-
*
|
|
177
|
-
* @param {PerspectiveTransform} other
|
|
178
|
-
* @returns {PerspectiveTransform}
|
|
179
|
-
*/
|
|
180
|
-
times(other) {
|
|
181
|
-
const { a11, a21, a31, a12, a22, a32, a13, a23, a33 } = this;
|
|
182
|
-
const o = other;
|
|
183
|
-
return new PerspectiveTransform(
|
|
184
|
-
o.a11 * a11 + o.a21 * a12 + o.a31 * a13,
|
|
185
|
-
o.a11 * a21 + o.a21 * a22 + o.a31 * a23,
|
|
186
|
-
o.a11 * a31 + o.a21 * a32 + o.a31 * a33,
|
|
187
|
-
o.a12 * a11 + o.a22 * a12 + o.a32 * a13,
|
|
188
|
-
o.a12 * a21 + o.a22 * a22 + o.a32 * a23,
|
|
189
|
-
o.a12 * a31 + o.a22 * a32 + o.a32 * a33,
|
|
190
|
-
o.a13 * a11 + o.a23 * a12 + o.a33 * a13,
|
|
191
|
-
o.a13 * a21 + o.a23 * a22 + o.a33 * a23,
|
|
192
|
-
o.a13 * a31 + o.a23 * a32 + o.a33 * a33
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
158
|
}
|