@mikashboks/capture-intelligence-core 0.1.0

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.
Files changed (89) hide show
  1. package/dist/cjs/__fixtures__/address-flow.fixtures.d.ts +35 -0
  2. package/dist/cjs/__fixtures__/address-flow.fixtures.d.ts.map +1 -0
  3. package/dist/cjs/__fixtures__/address-flow.fixtures.js +186 -0
  4. package/dist/cjs/__fixtures__/address-flow.fixtures.js.map +1 -0
  5. package/dist/cjs/__fixtures__/metadata-review.fixtures.d.ts +11 -0
  6. package/dist/cjs/__fixtures__/metadata-review.fixtures.d.ts.map +1 -0
  7. package/dist/cjs/__fixtures__/metadata-review.fixtures.js +69 -0
  8. package/dist/cjs/__fixtures__/metadata-review.fixtures.js.map +1 -0
  9. package/dist/cjs/address-proof.d.ts +33 -0
  10. package/dist/cjs/address-proof.d.ts.map +1 -0
  11. package/dist/cjs/address-proof.js +97 -0
  12. package/dist/cjs/address-proof.js.map +1 -0
  13. package/dist/cjs/document-classifier.d.ts +19 -0
  14. package/dist/cjs/document-classifier.d.ts.map +1 -0
  15. package/dist/cjs/document-classifier.js +213 -0
  16. package/dist/cjs/document-classifier.js.map +1 -0
  17. package/dist/cjs/flow-routing.d.ts +7 -0
  18. package/dist/cjs/flow-routing.d.ts.map +1 -0
  19. package/dist/cjs/flow-routing.js +45 -0
  20. package/dist/cjs/flow-routing.js.map +1 -0
  21. package/dist/cjs/index.d.ts +25 -0
  22. package/dist/cjs/index.d.ts.map +1 -0
  23. package/dist/cjs/index.js +83 -0
  24. package/dist/cjs/index.js.map +1 -0
  25. package/dist/cjs/metadata-review.d.ts +10 -0
  26. package/dist/cjs/metadata-review.d.ts.map +1 -0
  27. package/dist/cjs/metadata-review.js +93 -0
  28. package/dist/cjs/metadata-review.js.map +1 -0
  29. package/dist/cjs/metrics.d.ts +115 -0
  30. package/dist/cjs/metrics.d.ts.map +1 -0
  31. package/dist/cjs/metrics.js +302 -0
  32. package/dist/cjs/metrics.js.map +1 -0
  33. package/dist/cjs/quality-checks.d.ts +170 -0
  34. package/dist/cjs/quality-checks.d.ts.map +1 -0
  35. package/dist/cjs/quality-checks.js +417 -0
  36. package/dist/cjs/quality-checks.js.map +1 -0
  37. package/dist/cjs/sobel.d.ts +61 -0
  38. package/dist/cjs/sobel.d.ts.map +1 -0
  39. package/dist/cjs/sobel.js +179 -0
  40. package/dist/cjs/sobel.js.map +1 -0
  41. package/dist/cjs/types.d.ts +98 -0
  42. package/dist/cjs/types.d.ts.map +1 -0
  43. package/dist/cjs/types.js +38 -0
  44. package/dist/cjs/types.js.map +1 -0
  45. package/dist/esm/__fixtures__/address-flow.fixtures.d.ts +35 -0
  46. package/dist/esm/__fixtures__/address-flow.fixtures.d.ts.map +1 -0
  47. package/dist/esm/__fixtures__/address-flow.fixtures.js +183 -0
  48. package/dist/esm/__fixtures__/address-flow.fixtures.js.map +1 -0
  49. package/dist/esm/__fixtures__/metadata-review.fixtures.d.ts +11 -0
  50. package/dist/esm/__fixtures__/metadata-review.fixtures.d.ts.map +1 -0
  51. package/dist/esm/__fixtures__/metadata-review.fixtures.js +66 -0
  52. package/dist/esm/__fixtures__/metadata-review.fixtures.js.map +1 -0
  53. package/dist/esm/address-proof.d.ts +33 -0
  54. package/dist/esm/address-proof.d.ts.map +1 -0
  55. package/dist/esm/address-proof.js +86 -0
  56. package/dist/esm/address-proof.js.map +1 -0
  57. package/dist/esm/document-classifier.d.ts +19 -0
  58. package/dist/esm/document-classifier.d.ts.map +1 -0
  59. package/dist/esm/document-classifier.js +209 -0
  60. package/dist/esm/document-classifier.js.map +1 -0
  61. package/dist/esm/flow-routing.d.ts +7 -0
  62. package/dist/esm/flow-routing.d.ts.map +1 -0
  63. package/dist/esm/flow-routing.js +41 -0
  64. package/dist/esm/flow-routing.js.map +1 -0
  65. package/dist/esm/index.d.ts +25 -0
  66. package/dist/esm/index.d.ts.map +1 -0
  67. package/dist/esm/index.js +19 -0
  68. package/dist/esm/index.js.map +1 -0
  69. package/dist/esm/metadata-review.d.ts +10 -0
  70. package/dist/esm/metadata-review.d.ts.map +1 -0
  71. package/dist/esm/metadata-review.js +90 -0
  72. package/dist/esm/metadata-review.js.map +1 -0
  73. package/dist/esm/metrics.d.ts +115 -0
  74. package/dist/esm/metrics.d.ts.map +1 -0
  75. package/dist/esm/metrics.js +291 -0
  76. package/dist/esm/metrics.js.map +1 -0
  77. package/dist/esm/quality-checks.d.ts +170 -0
  78. package/dist/esm/quality-checks.d.ts.map +1 -0
  79. package/dist/esm/quality-checks.js +400 -0
  80. package/dist/esm/quality-checks.js.map +1 -0
  81. package/dist/esm/sobel.d.ts +61 -0
  82. package/dist/esm/sobel.d.ts.map +1 -0
  83. package/dist/esm/sobel.js +173 -0
  84. package/dist/esm/sobel.js.map +1 -0
  85. package/dist/esm/types.d.ts +98 -0
  86. package/dist/esm/types.d.ts.map +1 -0
  87. package/dist/esm/types.js +35 -0
  88. package/dist/esm/types.js.map +1 -0
  89. package/package.json +65 -0
@@ -0,0 +1,400 @@
1
+ /**
2
+ * Quality checks -- threshold comparison logic and failure escalation rules.
3
+ *
4
+ * DOM-free: no HTMLElement, no document.*, no navigator.*. All functions
5
+ * operate on plain data (FrameMetrics, QualityCheckResults, numeric values).
6
+ *
7
+ * The DOM-coupled parts of quality-review.ts (banner updates, button state,
8
+ * shake animations, Svelte store, etc.) remain in the SDK. This module
9
+ * exposes the pure decision logic that can be reused in React Native or
10
+ * Node.js environments.
11
+ */
12
+ import { CAM_BRIGHTNESS_MIN, CAM_BRIGHTNESS_MAX, DOC_SUBMIT_ANYWAY_FAILURE_THRESHOLD, SELFIE_SUBMIT_ANYWAY_FAILURE_THRESHOLD, ADDRESS_SUBMIT_ANYWAY_FAILURE_THRESHOLD, } from './types.js';
13
+ import { checkDocumentLikelihood } from './document-classifier.js';
14
+ /* -- Quality bucket classification ---------------------------------------- */
15
+ /**
16
+ * Map a step signature string and optional review mode to a quality bucket.
17
+ */
18
+ export function getQualityBucket(stepSig, reviewMode = 'document') {
19
+ if (!stepSig)
20
+ return '';
21
+ if (reviewMode === 'front-door')
22
+ return 'address_front_door';
23
+ if (reviewMode === 'address-document')
24
+ return 'address_document';
25
+ if (stepSig.indexOf('selfie') !== -1)
26
+ return 'selfie';
27
+ if (stepSig.indexOf('address') !== -1)
28
+ return 'address_document';
29
+ if (stepSig.indexOf('back') !== -1)
30
+ return 'document_back';
31
+ return 'document_front';
32
+ }
33
+ /* -- Submit-anyway threshold lookup --------------------------------------- */
34
+ /**
35
+ * Get the number of consecutive failures required before the "submit anyway"
36
+ * override becomes available for a given step signature.
37
+ */
38
+ export function getSubmitAnywayThreshold(stepSig, reviewMode) {
39
+ const bucket = getQualityBucket(stepSig, reviewMode);
40
+ if (bucket === 'selfie')
41
+ return SELFIE_SUBMIT_ANYWAY_FAILURE_THRESHOLD;
42
+ if (bucket === 'document_front' || bucket === 'document_back') {
43
+ return DOC_SUBMIT_ANYWAY_FAILURE_THRESHOLD;
44
+ }
45
+ if (bucket === 'address_document' || bucket === 'address_front_door') {
46
+ return ADDRESS_SUBMIT_ANYWAY_FAILURE_THRESHOLD;
47
+ }
48
+ return Number.POSITIVE_INFINITY;
49
+ }
50
+ /**
51
+ * Create a fresh failure state.
52
+ */
53
+ export function createQualityFailureState() {
54
+ return {
55
+ document_front: 0,
56
+ document_back: 0,
57
+ selfie: 0,
58
+ address_document: 0,
59
+ address_front_door: 0,
60
+ lastFailedSignature: '',
61
+ };
62
+ }
63
+ /**
64
+ * Increment the failure counter for a bucket if this is a new failure
65
+ * (not a re-render of the same failed review).
66
+ *
67
+ * @param state - Mutable failure state
68
+ * @param stepSig - Step signature string
69
+ * @param failSignature - Unique signature for this failure (e.g. bucket + image src)
70
+ * @param anyFail - Whether any quality check actually failed
71
+ * @returns true if the counter was incremented
72
+ */
73
+ export function countFailedReview(state, stepSig, failSignature, anyFail, reviewMode) {
74
+ if (!anyFail)
75
+ return false;
76
+ const bucket = getQualityBucket(stepSig, reviewMode);
77
+ if (!bucket)
78
+ return false;
79
+ if (!failSignature || failSignature === state.lastFailedSignature)
80
+ return false;
81
+ const current = getFailureCount(state, bucket);
82
+ setFailureCount(state, bucket, current + 1);
83
+ state.lastFailedSignature = failSignature;
84
+ return true;
85
+ }
86
+ /**
87
+ * Check whether the submit-anyway override should be available.
88
+ */
89
+ export function shouldShowSubmitAnyway(state, stepSig, reviewMode) {
90
+ const bucket = getQualityBucket(stepSig, reviewMode);
91
+ if (!bucket)
92
+ return false;
93
+ const failCount = getFailureCount(state, bucket);
94
+ return failCount >= getSubmitAnywayThreshold(stepSig, reviewMode);
95
+ }
96
+ /* -- Internal helpers for typed bucket access ------------------------------ */
97
+ function getFailureCount(state, bucket) {
98
+ switch (bucket) {
99
+ case 'document_front': return state.document_front;
100
+ case 'document_back': return state.document_back;
101
+ case 'selfie': return state.selfie;
102
+ case 'address_document': return state.address_document;
103
+ case 'address_front_door': return state.address_front_door;
104
+ default: return 0;
105
+ }
106
+ }
107
+ function setFailureCount(state, bucket, value) {
108
+ switch (bucket) {
109
+ case 'document_front':
110
+ state.document_front = value;
111
+ break;
112
+ case 'document_back':
113
+ state.document_back = value;
114
+ break;
115
+ case 'selfie':
116
+ state.selfie = value;
117
+ break;
118
+ case 'address_document':
119
+ state.address_document = value;
120
+ break;
121
+ case 'address_front_door':
122
+ state.address_front_door = value;
123
+ break;
124
+ }
125
+ }
126
+ /**
127
+ * Run quality checks on a static document image. Returns the check results
128
+ * and a human-readable failure message.
129
+ *
130
+ * This is the pure-logic extraction from `runQualityCheck()`. The caller
131
+ * handles image loading, Canvas rasterization, and UI updates.
132
+ */
133
+ export function runDocumentQualityChecks(input) {
134
+ const checks = {};
135
+ const brightnessOk = input.avgBrightness >= CAM_BRIGHTNESS_MIN && input.avgBrightness <= CAM_BRIGHTNESS_MAX;
136
+ const sharpnessOk = input.laplacianVariance >= 60;
137
+ if (input.isAddressProof) {
138
+ checks['address_readable'] = sharpnessOk && brightnessOk;
139
+ }
140
+ else {
141
+ const textReadableOk = sharpnessOk && input.cornersOk !== false;
142
+ checks['text_readable'] = textReadableOk;
143
+ checks['good_lighting'] = brightnessOk;
144
+ if (input.cornersOk === true) {
145
+ checks['corners_visible'] = true;
146
+ }
147
+ else if (input.cornersOk === false) {
148
+ checks['corners_visible'] = false;
149
+ }
150
+ // Canvas heuristic: does this look like the submitted document type?
151
+ const docResult = checkDocumentLikelihood(input.grey, input.imgData, input.w, input.h, input.documentType);
152
+ const docLooksValid = docResult.isLikelyDoc && input.cornersOk !== false && textReadableOk;
153
+ checks['content_valid'] = docLooksValid;
154
+ // Surface glare detection
155
+ if (docResult.glareDetected) {
156
+ checks['glare_free'] = false;
157
+ }
158
+ if (!docResult.isLikelyDoc) {
159
+ checks['text_readable'] = false;
160
+ }
161
+ else if (input.cornersOk === false) {
162
+ checks['text_readable'] = false;
163
+ }
164
+ }
165
+ // Determine the prioritised failure message
166
+ const { anyFail, failMessage } = evaluateDocumentFailure(checks, input.isAddressProof);
167
+ return { checks, anyFail, failMessage };
168
+ }
169
+ /**
170
+ * Run basic selfie quality checks (lighting + sharpness, before face
171
+ * detection). Returns the `good_lighting` check result.
172
+ */
173
+ export function runSelfieQualityChecks(input) {
174
+ const checks = {};
175
+ const sharpnessOk = input.laplacianVariance >= 50;
176
+ const brightnessOk = input.avgBrightness >= 35 && input.avgBrightness <= 240;
177
+ checks['good_lighting'] = brightnessOk && sharpnessOk;
178
+ return checks;
179
+ }
180
+ /* -- Face quality checks -------------------------------------------------- */
181
+ /**
182
+ * Check face position and size relative to image dimensions.
183
+ * Returns an array of warning strings (empty = face is OK).
184
+ *
185
+ * @param faces - Detected faces
186
+ * @param imageWidth - Full image width
187
+ * @param imageHeight - Full image height
188
+ */
189
+ export function checkFaceInImage(faces, imageWidth, imageHeight) {
190
+ const warnings = [];
191
+ if (!faces || faces.length === 0) {
192
+ warnings.push('No face found. Try retaking.');
193
+ return warnings;
194
+ }
195
+ const face = faces[0];
196
+ const box = face.boundingBox;
197
+ const faceArea = box.width * box.height;
198
+ const imageArea = imageWidth * imageHeight;
199
+ const faceRatio = faceArea / imageArea;
200
+ if (faceRatio < 0.03) {
201
+ warnings.push('Face too small. Hold phone closer.');
202
+ }
203
+ const faceCenterX = box.x + box.width / 2;
204
+ const faceCenterY = box.y + box.height / 2;
205
+ const imageCenterX = imageWidth / 2;
206
+ const imageCenterY = imageHeight / 2;
207
+ const xTolerance = imageWidth * 0.25;
208
+ const yTolerance = imageHeight * 0.25;
209
+ if (Math.abs(faceCenterX - imageCenterX) >= xTolerance ||
210
+ Math.abs(faceCenterY - imageCenterY) >= yTolerance) {
211
+ warnings.push('Face is off-center. Try retaking.');
212
+ }
213
+ return warnings;
214
+ }
215
+ /**
216
+ * Check whether a detected face is well-centered and appropriately sized
217
+ * for live capture (stricter than static image checks).
218
+ *
219
+ * @param face - Detected face
220
+ * @param videoWidth - Video frame width
221
+ * @param videoHeight - Video frame height
222
+ */
223
+ export function isFaceCentered(face, videoWidth, videoHeight) {
224
+ const box = face.boundingBox;
225
+ const faceCenterX = box.x + box.width / 2;
226
+ const faceCenterY = box.y + box.height / 2;
227
+ const videoCenterX = videoWidth / 2;
228
+ const videoCenterY = videoHeight / 2;
229
+ const xTolerance = videoWidth * 0.2;
230
+ const yTolerance = videoHeight * 0.2;
231
+ const centeredX = Math.abs(faceCenterX - videoCenterX) < xTolerance;
232
+ const centeredY = Math.abs(faceCenterY - videoCenterY) < yTolerance;
233
+ const faceArea = box.width * box.height;
234
+ const videoArea = videoWidth * videoHeight;
235
+ const faceRatio = faceArea / videoArea;
236
+ const goodSize = faceRatio > 0.025 && faceRatio < 0.45;
237
+ return centeredX && centeredY && goodSize;
238
+ }
239
+ /* -- Failure evaluation helpers ------------------------------------------- */
240
+ /**
241
+ * Evaluate document quality check results and produce a prioritised failure
242
+ * message. Handles address-proof and ID-document modes.
243
+ */
244
+ export function evaluateDocumentFailure(checks, isAddressProof) {
245
+ let anyFail = false;
246
+ let failMessage = '';
247
+ if (isAddressProof) {
248
+ if (checks.hasOwnProperty('address_readable') && !checks['address_readable']) {
249
+ anyFail = true;
250
+ failMessage = 'Can\u2019t read the text. Try again in better light.';
251
+ }
252
+ }
253
+ else {
254
+ if (checks.hasOwnProperty('corners_visible') && !checks['corners_visible']) {
255
+ anyFail = true;
256
+ failMessage = 'Part of the ID is cut off. Show all 4 corners.';
257
+ }
258
+ else if (checks.hasOwnProperty('content_valid') && !checks['content_valid']) {
259
+ anyFail = true;
260
+ failMessage = 'Doesn\u2019t look like an ID. Show the full document and try again.';
261
+ }
262
+ else if (checks.hasOwnProperty('good_lighting') && !checks['good_lighting']) {
263
+ anyFail = true;
264
+ failMessage = 'Too dark or blurry. Try again in better light.';
265
+ }
266
+ else if (checks.hasOwnProperty('text_readable') && !checks['text_readable']) {
267
+ anyFail = true;
268
+ failMessage = 'Text is hard to read. Hold steady and try again.';
269
+ }
270
+ else if (checks.hasOwnProperty('glare_free') && !checks['glare_free']) {
271
+ anyFail = true;
272
+ failMessage = 'Glare on the ID. Tilt away from light and try again.';
273
+ }
274
+ }
275
+ return { anyFail, failMessage };
276
+ }
277
+ /**
278
+ * Evaluate selfie quality check results and produce a prioritised failure
279
+ * message.
280
+ */
281
+ export function evaluateSelfieFailure(checks) {
282
+ let anyFail = false;
283
+ let failMessage = '';
284
+ if (checks.hasOwnProperty('face_visible') && !checks['face_visible']) {
285
+ anyFail = true;
286
+ failMessage = 'Can\u2019t see your face. Center it and try again.';
287
+ }
288
+ else if (checks.hasOwnProperty('good_lighting') && !checks['good_lighting']) {
289
+ anyFail = true;
290
+ failMessage = 'Too dark. Move to better light and try again.';
291
+ }
292
+ return { anyFail, failMessage };
293
+ }
294
+ /**
295
+ * Evaluate quality failures for a specific review mode using the same
296
+ * prioritization rules as the SDK review banner.
297
+ */
298
+ export function evaluateReviewFailure(checks, options) {
299
+ if (options.reviewMode === 'selfie') {
300
+ return evaluateSelfieFailure(checks);
301
+ }
302
+ if (options.reviewMode === 'front-door') {
303
+ if (checks.hasOwnProperty('front_door_clear') && !checks['front_door_clear']) {
304
+ return {
305
+ anyFail: true,
306
+ failMessage: options.failMessage || 'Too dark or blurry. Retake the front of your house.',
307
+ };
308
+ }
309
+ return { anyFail: false, failMessage: '' };
310
+ }
311
+ if (options.reviewMode === 'address-document') {
312
+ return evaluateDocumentFailure(checks, true);
313
+ }
314
+ return evaluateDocumentFailure(checks, false);
315
+ }
316
+ /**
317
+ * Determine whether the "next" button should be disabled based on the
318
+ * current quality check state.
319
+ *
320
+ * @param checks - Current quality check results
321
+ * @param isSelfie - Whether this is a selfie review
322
+ * @param isAddressProof - Whether this is an address proof review
323
+ * @returns Disabled reason string (empty = should be enabled)
324
+ */
325
+ export function getNextButtonDisabledReason(checks, isSelfieOrOptions, isAddressProof = false) {
326
+ const options = typeof isSelfieOrOptions === 'boolean'
327
+ ? {
328
+ reviewMode: isSelfieOrOptions ? 'selfie' : isAddressProof ? 'address-document' : 'document',
329
+ }
330
+ : isSelfieOrOptions;
331
+ if (options.reviewMode === 'selfie') {
332
+ if (!checks.hasOwnProperty('face_visible')) {
333
+ return 'Reviewing selfie...';
334
+ }
335
+ if (!checks['face_visible']) {
336
+ return 'Please retake this selfie to continue';
337
+ }
338
+ if (checks.hasOwnProperty('good_lighting') && !checks['good_lighting']) {
339
+ return 'Please retake this selfie to continue';
340
+ }
341
+ return '';
342
+ }
343
+ if (options.reviewMode === 'front-door') {
344
+ const pendingMessage = options.pendingMessage || 'Reviewing photo...';
345
+ const failMessage = options.failMessage || 'Please retake this photo to continue';
346
+ if (!checks.hasOwnProperty('front_door_clear')) {
347
+ return pendingMessage;
348
+ }
349
+ if (!checks['front_door_clear']) {
350
+ return failMessage;
351
+ }
352
+ return '';
353
+ }
354
+ if (options.reviewMode === 'address-document') {
355
+ const pendingMessage = options.pendingMessage || 'Reviewing photo...';
356
+ const failMessage = options.failMessage || 'Please retake this photo to continue';
357
+ if (!checks.hasOwnProperty('address_readable')) {
358
+ return pendingMessage;
359
+ }
360
+ if (!checks['address_readable']) {
361
+ return failMessage;
362
+ }
363
+ return '';
364
+ }
365
+ const requiredDocChecks = ['content_valid', 'text_readable', 'good_lighting'];
366
+ for (let ci = 0; ci < requiredDocChecks.length; ci++) {
367
+ if (!checks.hasOwnProperty(requiredDocChecks[ci])) {
368
+ return 'Reviewing photo...';
369
+ }
370
+ }
371
+ for (let ri = 0; ri < requiredDocChecks.length; ri++) {
372
+ if (!checks[requiredDocChecks[ri]]) {
373
+ return 'Please retake this photo to continue';
374
+ }
375
+ }
376
+ if (checks.hasOwnProperty('corners_visible') && !checks['corners_visible']) {
377
+ return 'Please retake this photo to continue';
378
+ }
379
+ return '';
380
+ }
381
+ /**
382
+ * Get the override button text for the submit-anyway flow.
383
+ */
384
+ export function getOverrideButtonText(stepSig) {
385
+ const bucket = getQualityBucket(stepSig);
386
+ return bucket === 'selfie' ? 'Continue With This Selfie' : 'Continue With This Photo';
387
+ }
388
+ /**
389
+ * Get the override banner message based on failure count and bucket.
390
+ */
391
+ export function getOverrideBannerMessage(stepSig, failCount, reviewMode) {
392
+ const bucket = getQualityBucket(stepSig, reviewMode);
393
+ if (failCount >= 5) {
394
+ return 'Having trouble? Continue and our team will check it.';
395
+ }
396
+ return bucket === 'selfie'
397
+ ? 'Selfie is unclear. You can continue, but a better photo speeds things up.'
398
+ : 'Photo is unclear. You can continue, but a better photo speeds things up.';
399
+ }
400
+ //# sourceMappingURL=quality-checks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality-checks.js","sourceRoot":"","sources":["../../src/quality-checks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Sobel edge detection on raw pixel data.
3
+ *
4
+ * DOM-free: operates on Uint8Array greyscale buffers. No Canvas, no
5
+ * HTMLImageElement. The caller is responsible for rasterising / downscaling
6
+ * the image and converting to greyscale before calling these functions.
7
+ */
8
+ import type { DocumentCropResult } from './types.js';
9
+ /**
10
+ * Convert an RGBA pixel buffer to greyscale using fixed-point integer math.
11
+ * Uses ITU-R BT.601 approximate weights (77/150/29 out of 256).
12
+ *
13
+ * @param rgba - RGBA pixel buffer (length = width * height * 4)
14
+ * @param pixelCount - Total number of pixels (width * height)
15
+ * @returns Uint8Array of greyscale values, one byte per pixel
16
+ */
17
+ export declare function rgbaToGreyscale(rgba: Uint8ClampedArray | Uint8Array, pixelCount: number): Uint8Array;
18
+ /**
19
+ * Convert an RGBA pixel buffer to greyscale using the pico.js weighting
20
+ * scheme (2/7/1 out of 10). Used for face-detection compatibility.
21
+ *
22
+ * @param rgba - RGBA pixel buffer
23
+ * @param nrows - Number of rows (height)
24
+ * @param ncols - Number of columns (width)
25
+ * @returns Uint8Array of greyscale values
26
+ */
27
+ export declare function rgbaToGreyscalePico(rgba: Uint8ClampedArray | Uint8Array, nrows: number, ncols: number): Uint8Array;
28
+ /**
29
+ * Row and column Sobel edge energy profiles for a greyscale image.
30
+ */
31
+ export interface EdgeEnergyProfile {
32
+ /** Per-row accumulated Sobel magnitude */
33
+ rowEnergy: Float32Array;
34
+ /** Per-column accumulated Sobel magnitude */
35
+ colEnergy: Float32Array;
36
+ }
37
+ /**
38
+ * Compute Sobel edge energy profiles (per-row and per-column) for a
39
+ * greyscale image buffer. Used for document boundary detection.
40
+ *
41
+ * @param grey - Greyscale pixel array (w * h, one byte per pixel)
42
+ * @param w - Image width
43
+ * @param h - Image height
44
+ */
45
+ export declare function computeEdgeEnergyProfile(grey: Uint8Array, w: number, h: number): EdgeEnergyProfile;
46
+ /**
47
+ * Detect the crop region of a document within a greyscale image using
48
+ * Sobel edge energy profiling. Returns the crop rectangle in the original
49
+ * (pre-scale) coordinate space.
50
+ *
51
+ * This is the DOM-free algorithmic core of `detectDocumentCrop()`. The caller
52
+ * must handle image loading, downscaling, and greyscale conversion.
53
+ *
54
+ * @param grey - Greyscale pixels of the downscaled analysis image
55
+ * @param analysisW - Width of the analysis image
56
+ * @param analysisH - Height of the analysis image
57
+ * @param originalW - Width of the original (full-resolution) image
58
+ * @param originalH - Height of the original (full-resolution) image
59
+ */
60
+ export declare function detectDocumentCropFromGrey(grey: Uint8Array, analysisW: number, analysisH: number, originalW: number, originalH: number): DocumentCropResult;
61
+ //# sourceMappingURL=sobel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sobel.d.ts","sourceRoot":"","sources":["../../src/sobel.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAY,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAI/D;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,iBAAiB,GAAG,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,UAAU,CAOpG;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,iBAAiB,GAAG,UAAU,EACpC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,UAAU,CAUZ;AAID;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,0CAA0C;IAC1C,SAAS,EAAE,YAAY,CAAC;IACxB,6CAA6C;IAC7C,SAAS,EAAE,YAAY,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,UAAU,EAChB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR,iBAAiB,CA2BnB;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,kBAAkB,CAwFpB"}
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Sobel edge detection on raw pixel data.
3
+ *
4
+ * DOM-free: operates on Uint8Array greyscale buffers. No Canvas, no
5
+ * HTMLImageElement. The caller is responsible for rasterising / downscaling
6
+ * the image and converting to greyscale before calling these functions.
7
+ */
8
+ /* -- Greyscale conversion helpers ----------------------------------------- */
9
+ /**
10
+ * Convert an RGBA pixel buffer to greyscale using fixed-point integer math.
11
+ * Uses ITU-R BT.601 approximate weights (77/150/29 out of 256).
12
+ *
13
+ * @param rgba - RGBA pixel buffer (length = width * height * 4)
14
+ * @param pixelCount - Total number of pixels (width * height)
15
+ * @returns Uint8Array of greyscale values, one byte per pixel
16
+ */
17
+ export function rgbaToGreyscale(rgba, pixelCount) {
18
+ const grey = new Uint8Array(pixelCount);
19
+ for (let i = 0; i < pixelCount; i++) {
20
+ const p = i * 4;
21
+ grey[i] = (rgba[p] * 77 + rgba[p + 1] * 150 + rgba[p + 2] * 29) >> 8;
22
+ }
23
+ return grey;
24
+ }
25
+ /**
26
+ * Convert an RGBA pixel buffer to greyscale using the pico.js weighting
27
+ * scheme (2/7/1 out of 10). Used for face-detection compatibility.
28
+ *
29
+ * @param rgba - RGBA pixel buffer
30
+ * @param nrows - Number of rows (height)
31
+ * @param ncols - Number of columns (width)
32
+ * @returns Uint8Array of greyscale values
33
+ */
34
+ export function rgbaToGreyscalePico(rgba, nrows, ncols) {
35
+ const gray = new Uint8Array(nrows * ncols);
36
+ for (let r = 0; r < nrows; ++r)
37
+ for (let c = 0; c < ncols; ++c)
38
+ gray[r * ncols + c] =
39
+ (2 * rgba[r * 4 * ncols + 4 * c + 0] +
40
+ 7 * rgba[r * 4 * ncols + 4 * c + 1] +
41
+ 1 * rgba[r * 4 * ncols + 4 * c + 2]) /
42
+ 10;
43
+ return gray;
44
+ }
45
+ /**
46
+ * Compute Sobel edge energy profiles (per-row and per-column) for a
47
+ * greyscale image buffer. Used for document boundary detection.
48
+ *
49
+ * @param grey - Greyscale pixel array (w * h, one byte per pixel)
50
+ * @param w - Image width
51
+ * @param h - Image height
52
+ */
53
+ export function computeEdgeEnergyProfile(grey, w, h) {
54
+ const rowEnergy = new Float32Array(h);
55
+ const colEnergy = new Float32Array(w);
56
+ for (let y = 1; y < h - 1; y++) {
57
+ for (let x = 1; x < w - 1; x++) {
58
+ const gx = -grey[(y - 1) * w + (x - 1)] +
59
+ grey[(y - 1) * w + (x + 1)] -
60
+ 2 * grey[y * w + (x - 1)] +
61
+ 2 * grey[y * w + (x + 1)] -
62
+ grey[(y + 1) * w + (x - 1)] +
63
+ grey[(y + 1) * w + (x + 1)];
64
+ const gy = -grey[(y - 1) * w + (x - 1)] -
65
+ 2 * grey[(y - 1) * w + x] -
66
+ grey[(y - 1) * w + (x + 1)] +
67
+ grey[(y + 1) * w + (x - 1)] +
68
+ 2 * grey[(y + 1) * w + x] +
69
+ grey[(y + 1) * w + (x + 1)];
70
+ const mag = Math.abs(gx) + Math.abs(gy);
71
+ rowEnergy[y] += mag;
72
+ colEnergy[x] += mag;
73
+ }
74
+ }
75
+ return { rowEnergy, colEnergy };
76
+ }
77
+ /* -- Document crop detection ---------------------------------------------- */
78
+ /**
79
+ * Detect the crop region of a document within a greyscale image using
80
+ * Sobel edge energy profiling. Returns the crop rectangle in the original
81
+ * (pre-scale) coordinate space.
82
+ *
83
+ * This is the DOM-free algorithmic core of `detectDocumentCrop()`. The caller
84
+ * must handle image loading, downscaling, and greyscale conversion.
85
+ *
86
+ * @param grey - Greyscale pixels of the downscaled analysis image
87
+ * @param analysisW - Width of the analysis image
88
+ * @param analysisH - Height of the analysis image
89
+ * @param originalW - Width of the original (full-resolution) image
90
+ * @param originalH - Height of the original (full-resolution) image
91
+ */
92
+ export function detectDocumentCropFromGrey(grey, analysisW, analysisH, originalW, originalH) {
93
+ try {
94
+ if (analysisW <= 0 || analysisH <= 0)
95
+ return { crop: null, cornersOk: null };
96
+ const sc = Math.min(originalW / analysisW, originalH / analysisH);
97
+ const { rowEnergy, colEnergy } = computeEdgeEnergyProfile(grey, analysisW, analysisH);
98
+ // Find max energy for normalisation
99
+ let maxR = 0, maxC = 0;
100
+ for (let y2 = 0; y2 < analysisH; y2++) {
101
+ if (rowEnergy[y2] > maxR)
102
+ maxR = rowEnergy[y2];
103
+ }
104
+ for (let x2 = 0; x2 < analysisW; x2++) {
105
+ if (colEnergy[x2] > maxC)
106
+ maxC = colEnergy[x2];
107
+ }
108
+ if (maxR === 0 || maxC === 0)
109
+ return { crop: null, cornersOk: false };
110
+ // Scan inward from edges to find first row/col with >12% of max energy
111
+ const thr = 0.12;
112
+ const skip = 0.05;
113
+ let top = 0, bot = analysisH - 1, left = 0, right = analysisW - 1;
114
+ for (let yt = Math.round(analysisH * skip); yt < analysisH / 2; yt++) {
115
+ if (rowEnergy[yt] / maxR > thr) {
116
+ top = yt;
117
+ break;
118
+ }
119
+ }
120
+ for (let yb = Math.round(analysisH * (1 - skip)); yb > analysisH / 2; yb--) {
121
+ if (rowEnergy[yb] / maxR > thr) {
122
+ bot = yb;
123
+ break;
124
+ }
125
+ }
126
+ for (let xl = Math.round(analysisW * skip); xl < analysisW / 2; xl++) {
127
+ if (colEnergy[xl] / maxC > thr) {
128
+ left = xl;
129
+ break;
130
+ }
131
+ }
132
+ for (let xr = Math.round(analysisW * (1 - skip)); xr > analysisW / 2; xr--) {
133
+ if (colEnergy[xr] / maxC > thr) {
134
+ right = xr;
135
+ break;
136
+ }
137
+ }
138
+ const cw = right - left;
139
+ const ch = bot - top;
140
+ const edgeMargin = Math.round(Math.min(analysisW, analysisH) * 0.08);
141
+ if (cw < analysisW * 0.25 || ch < analysisH * 0.25)
142
+ return { crop: null, cornersOk: false };
143
+ if (cw > analysisW * 0.88 && ch > analysisH * 0.88)
144
+ return { crop: null, cornersOk: false };
145
+ const rawLeft = left;
146
+ const rawTop = top;
147
+ const rawRight = right;
148
+ const rawBot = bot;
149
+ // 3% padding
150
+ const pad = Math.round(Math.min(analysisW, analysisH) * 0.03);
151
+ left = Math.max(0, left - pad);
152
+ top = Math.max(0, top - pad);
153
+ right = Math.min(analysisW - 1, right + pad);
154
+ bot = Math.min(analysisH - 1, bot + pad);
155
+ const cornersConfident = rawLeft > edgeMargin &&
156
+ rawTop > edgeMargin &&
157
+ rawRight < analysisW - 1 - edgeMargin &&
158
+ rawBot < analysisH - 1 - edgeMargin;
159
+ return {
160
+ crop: {
161
+ x: Math.round(left * sc),
162
+ y: Math.round(top * sc),
163
+ w: Math.round((right - left) * sc),
164
+ h: Math.round((bot - top) * sc),
165
+ },
166
+ cornersOk: cornersConfident,
167
+ };
168
+ }
169
+ catch {
170
+ return { crop: null, cornersOk: null };
171
+ }
172
+ }
173
+ //# sourceMappingURL=sobel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sobel.js","sourceRoot":"","sources":["../../src/sobel.ts"],"names":[],"mappings":"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"}