hh-shipments 0.3.23 → 0.3.24
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/package.json +1 -1
- package/public/app.js +31 -14
- package/public/index.html +1 -1
- package/src/extract.js +39 -7
package/package.json
CHANGED
package/public/app.js
CHANGED
|
@@ -382,24 +382,41 @@ async function decodeBarcode(file) {
|
|
|
382
382
|
try { bmp = await createImageBitmap(file); } catch (e) { return null; }
|
|
383
383
|
const hints = new Map([[ZXing.DecodeHintType.TRY_HARDER, true]]);
|
|
384
384
|
const reader = new ZXing.BrowserMultiFormatReader(hints);
|
|
385
|
+
// Aggressive region/scale sweep: labels photographed at angles need multiple
|
|
386
|
+
// crops. The UPS 1Z barcode is typically in the lower half.
|
|
385
387
|
const regions = [
|
|
386
|
-
[0, 0, 1, 1],
|
|
387
|
-
[0, 0.
|
|
388
|
-
[0, 0.
|
|
388
|
+
[0, 0, 1, 1],
|
|
389
|
+
[0, 0.30, 1, 0.40],
|
|
390
|
+
[0, 0.50, 1, 0.45],
|
|
391
|
+
[0, 0.60, 1, 0.35],
|
|
392
|
+
[0.05, 0.55, 0.90, 0.40],
|
|
389
393
|
];
|
|
390
394
|
try {
|
|
391
395
|
for (const [fx, fy, fw, fh] of regions) {
|
|
392
|
-
const
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
396
|
+
for (const scale of [1, 1.5, 2]) {
|
|
397
|
+
const sw = Math.round(bmp.width * fw), sh = Math.round(bmp.height * fh);
|
|
398
|
+
if (sw < 80 || sh < 40) continue;
|
|
399
|
+
const canvas = document.createElement('canvas');
|
|
400
|
+
canvas.width = Math.round(sw * scale);
|
|
401
|
+
canvas.height = Math.round(sh * scale);
|
|
402
|
+
const ctx = canvas.getContext('2d');
|
|
403
|
+
ctx.drawImage(bmp, bmp.width * fx, bmp.height * fy, sw, sh, 0, 0, canvas.width, canvas.height);
|
|
404
|
+
// Boost contrast: barcodes need sharp black/white separation
|
|
405
|
+
try {
|
|
406
|
+
const img = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
407
|
+
const d = img.data;
|
|
408
|
+
for (let i = 0; i < d.length; i += 4) {
|
|
409
|
+
const v = 0.299 * d[i] + 0.587 * d[i + 1] + 0.114 * d[i + 2];
|
|
410
|
+
const nv = v < 128 ? 0 : 255;
|
|
411
|
+
d[i] = d[i + 1] = d[i + 2] = nv;
|
|
412
|
+
}
|
|
413
|
+
ctx.putImageData(img, 0, 0);
|
|
414
|
+
} catch (e) {}
|
|
415
|
+
const url = canvas.toDataURL('image/png');
|
|
416
|
+
const text = await decodeOne(reader, url);
|
|
417
|
+
const num = strictTracking(text);
|
|
418
|
+
if (num) return num;
|
|
419
|
+
}
|
|
403
420
|
}
|
|
404
421
|
} finally { bmp.close(); }
|
|
405
422
|
return null;
|
package/public/index.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
6
6
|
<meta name="theme-color" content="#0a84ff">
|
|
7
|
-
<meta name="app-version" content="0.3.
|
|
7
|
+
<meta name="app-version" content="0.3.24">
|
|
8
8
|
<title>HH Shipments</title>
|
|
9
9
|
<link rel="manifest" href="/manifest.webmanifest">
|
|
10
10
|
<link rel="apple-touch-icon" href="/icon-192.png">
|
package/src/extract.js
CHANGED
|
@@ -152,20 +152,51 @@
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
// UPS number split by spaces/dashes: "1Z 9999 99 ..." (or "12 ..."/"IZ ..." misreads)
|
|
155
|
+
// Hot-zone: text right after "TRACKING" often has a dropped character
|
|
156
|
+
// (e.g. "17 1) 539 031342 3923" = 17 chars, missing the J in 1XJ).
|
|
157
|
+
// Try expanding punct confusions that may hide two chars.
|
|
158
|
+
function expandPunctHotZone(text, found, seen) {
|
|
159
|
+
var m = /TRACKING\s*#?\s*:?\s*([0-9A-Z)\]}(\[{|!\s-]{15,25})/i.exec(text);
|
|
160
|
+
if (!m) return;
|
|
161
|
+
var raw = m[1].replace(/[\s-]/g, '');
|
|
162
|
+
// Don't swallow trailing English words ("thanks", "you") as number chars
|
|
163
|
+
raw = raw.replace(/(THANK|THANKS|YOU|PLEASE)$/i, '');
|
|
164
|
+
if (/^(1Z|12|IZ|17)/i.test(raw) && (raw.length === 17 || raw.length === 16 || raw.length === 18)) {
|
|
165
|
+
var anchored = raw.replace(/^(12|IZ|17)/i, '1Z');
|
|
166
|
+
// ")" may be "XJ" collapsed (X+J look like ) when smudged)
|
|
167
|
+
var expanded = anchored.replace(/\)/g, 'XJ').replace(/\(/g, 'CC');
|
|
168
|
+
if (/^1Z[0-9A-Z]{16}$/.test(expanded)) {
|
|
169
|
+
var num = repairUpsTail(expanded.slice(2)) || expanded;
|
|
170
|
+
if (num && UPS_STRICT.test(num) && /[A-Z]/.test(num.slice(2, 8)) && !seen[num]) {
|
|
171
|
+
seen[num] = true;
|
|
172
|
+
found.push({ number: num, carrier: 'ups', confidence: 'high', ocr_fixed: true });
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
155
178
|
function spacedUpsIn(text, found, seen, conf) {
|
|
156
|
-
|
|
179
|
+
// Anchor covers common 1Z misreads: 12, IZ, 17 (7→Z confusion)
|
|
180
|
+
var m, re = /\b(?:1Z|12|IZ|17)[\s-]?(?:[0-9A-Z)\]}(\[{|!][\s-]?){16}\b/gi;
|
|
157
181
|
while ((m = re.exec(text)) !== null) {
|
|
158
182
|
var ups = normalize(m[0]);
|
|
159
183
|
var num = null;
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
184
|
+
// Normalize the anchor: 12/IZ/17 → 1Z
|
|
185
|
+
var anchored = ups.replace(/^(12|IZ|17)/i, '1Z');
|
|
186
|
+
if (/^1Z[0-9A-Z]{6}[0-9]{10}$/.test(anchored)) num = anchored; // fully strict
|
|
187
|
+
else if (/^1Z[0-9A-Z]{16}$/.test(anchored)) {
|
|
188
|
+
// Repair tail; if repair fails the candidate is invalid — never accept raw
|
|
189
|
+
num = repairUpsTail(anchored.slice(2));
|
|
190
|
+
}
|
|
191
|
+
else num = repairUpsZ(anchored) || repairUpsTail(anchored.slice(2));
|
|
192
|
+
// ")" can be X or J — try X variant if J mapping failed validation
|
|
193
|
+
if (!num && /\)/.test(anchored)) {
|
|
194
|
+
var xVar = anchored.replace(/\)/g, 'X');
|
|
195
|
+
if (/^1Z[0-9A-Z]{16}$/.test(xVar)) num = repairUpsTail(xVar.slice(2));
|
|
164
196
|
}
|
|
165
|
-
else num = repairUpsZ(ups) || repairUpsTail(ups.slice(2));
|
|
166
197
|
if (num && !seen[num]) {
|
|
167
198
|
seen[num] = true;
|
|
168
|
-
found.push({ number: num, carrier: 'ups', confidence:
|
|
199
|
+
found.push({ number: num, carrier: 'ups', confidence: 'high', ocr_fixed: num !== ups });
|
|
169
200
|
}
|
|
170
201
|
}
|
|
171
202
|
}
|
|
@@ -316,6 +347,7 @@
|
|
|
316
347
|
// pass already tried the hot zones at high confidence). Repairs are
|
|
317
348
|
// strict-structure-validated, so they stay high confidence.
|
|
318
349
|
spacedUpsIn(text, found, seen, 'high');
|
|
350
|
+
expandPunctHotZone(text, found, seen);
|
|
319
351
|
looseUpsIn(text, found, seen, 'high');
|
|
320
352
|
// b) long digit-like runs with OCR confusions -> fix -> re-match digit formats
|
|
321
353
|
var runRe = /[0-9OILSBoilszb]{10,24}/g, run;
|