@pallasoft/ps-file-components 1.5.0 → 2.0.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 (147) hide show
  1. package/dist/components/ps-document-scanner-loader.d.ts +1 -1
  2. package/dist/components/ps-document-scanner-sheet.d.ts +1 -1
  3. package/dist/components/ps-document-scanner-sheet.js +40 -110
  4. package/dist/components/ps-document-scanner.d.ts +1 -1
  5. package/dist/components/ps-document-scanner.js +2 -3
  6. package/dist/components/ps-scan-camera-view.d.ts +2 -9
  7. package/dist/components/ps-scan-camera-view.js +3 -12
  8. package/dist/components/ps-scan-crop-editor.d.ts +4 -4
  9. package/dist/components/ps-scan-crop-editor.js +9 -9
  10. package/dist/components/ps-scan-permission-view.d.ts +2 -3
  11. package/dist/components/ps-scan-permission-view.js +2 -2
  12. package/dist/components/ps-scan-photo-button.d.ts +2 -3
  13. package/dist/components/ps-scan-photo-button.js +5 -5
  14. package/dist/components/ps-scan-preview.d.ts +12 -0
  15. package/dist/components/ps-scan-preview.js +10 -0
  16. package/dist/components/ps-scan-shutter.d.ts +1 -2
  17. package/dist/components/ps-scan-shutter.js +1 -1
  18. package/dist/constants/ps-document-scanner-labels.d.ts +5 -34
  19. package/dist/constants/ps-document-scanner-labels.js +5 -34
  20. package/dist/constants/ps-scan-chrome-classes.d.ts +0 -2
  21. package/dist/constants/ps-scan-chrome-classes.js +0 -2
  22. package/dist/constants/ps-scan-config.d.ts +24 -31
  23. package/dist/constants/ps-scan-config.js +24 -31
  24. package/dist/constants/ps-scan-step.d.ts +1 -1
  25. package/dist/constants/ps-scan-step.js +1 -1
  26. package/dist/esm/components/ps-document-scanner-sheet.js +41 -111
  27. package/dist/esm/components/ps-document-scanner.js +2 -3
  28. package/dist/esm/components/ps-scan-camera-view.js +3 -12
  29. package/dist/esm/components/ps-scan-crop-editor.js +9 -9
  30. package/dist/esm/components/ps-scan-permission-view.js +2 -2
  31. package/dist/esm/components/ps-scan-photo-button.js +5 -5
  32. package/dist/esm/components/ps-scan-preview.js +6 -0
  33. package/dist/esm/components/ps-scan-shutter.js +1 -1
  34. package/dist/esm/constants/ps-document-scanner-labels.js +5 -34
  35. package/dist/esm/constants/ps-scan-chrome-classes.js +0 -2
  36. package/dist/esm/constants/ps-scan-config.js +24 -31
  37. package/dist/esm/constants/ps-scan-step.js +1 -1
  38. package/dist/esm/hooks/use-ps-scan-live-detection.js +17 -21
  39. package/dist/esm/hooks/use-ps-scan-photo.js +42 -0
  40. package/dist/esm/index.js +0 -2
  41. package/dist/esm/services/ps-scan-camera-service.js +2 -2
  42. package/dist/esm/services/ps-scan-canny-service.js +93 -0
  43. package/dist/esm/services/ps-scan-canvas-service.js +7 -1
  44. package/dist/esm/services/ps-scan-edge-service.js +73 -137
  45. package/dist/esm/services/ps-scan-file-name-service.js +2 -11
  46. package/dist/esm/services/ps-scan-geometry-service.js +36 -0
  47. package/dist/esm/services/ps-scan-hull-service.js +0 -39
  48. package/dist/esm/services/ps-scan-image-filter-service.js +0 -21
  49. package/dist/esm/services/ps-scan-morphology-service.js +44 -0
  50. package/dist/esm/services/ps-scan-pipeline-service.js +9 -19
  51. package/dist/esm/services/ps-scan-polygon-service.js +75 -0
  52. package/dist/esm/services/ps-scan-region-service.js +52 -0
  53. package/dist/esm/services/ps-scan-stability-service.js +9 -22
  54. package/dist/esm/services/ps-scan-warp-service.js +8 -2
  55. package/dist/esm/services/ps-scan-yield-service.js +5 -0
  56. package/dist/hooks/use-ps-scan-live-detection.d.ts +1 -1
  57. package/dist/hooks/use-ps-scan-live-detection.js +16 -20
  58. package/dist/hooks/use-ps-scan-photo.d.ts +9 -0
  59. package/dist/hooks/use-ps-scan-photo.js +46 -0
  60. package/dist/index.d.ts +0 -2
  61. package/dist/index.js +0 -2
  62. package/dist/models/ps-document-scanner-props.d.ts +0 -4
  63. package/dist/models/ps-document-scanner-sheet-props.d.ts +0 -4
  64. package/dist/models/ps-scan-gradient.d.ts +4 -0
  65. package/dist/models/ps-scan-live-detection.d.ts +0 -1
  66. package/dist/models/ps-scan-located.d.ts +5 -0
  67. package/dist/models/ps-scan-photo.d.ts +9 -0
  68. package/dist/models/ps-scan-region.d.ts +5 -0
  69. package/dist/models/ps-scan-result.d.ts +6 -0
  70. package/dist/models/ps-scan-stability.d.ts +0 -3
  71. package/dist/services/ps-scan-camera-service.js +2 -2
  72. package/dist/services/ps-scan-canny-service.d.ts +7 -0
  73. package/dist/services/ps-scan-canny-service.js +97 -0
  74. package/dist/services/ps-scan-canvas-service.js +7 -1
  75. package/dist/services/ps-scan-edge-service.d.ts +5 -5
  76. package/dist/services/ps-scan-edge-service.js +73 -137
  77. package/dist/services/ps-scan-file-name-service.d.ts +1 -3
  78. package/dist/services/ps-scan-file-name-service.js +2 -11
  79. package/dist/services/ps-scan-geometry-service.d.ts +2 -0
  80. package/dist/services/ps-scan-geometry-service.js +36 -0
  81. package/dist/services/ps-scan-hull-service.d.ts +0 -2
  82. package/dist/services/ps-scan-hull-service.js +0 -39
  83. package/dist/services/ps-scan-image-filter-service.d.ts +0 -1
  84. package/dist/services/ps-scan-image-filter-service.js +0 -21
  85. package/dist/services/ps-scan-morphology-service.d.ts +7 -0
  86. package/dist/services/ps-scan-morphology-service.js +48 -0
  87. package/dist/services/ps-scan-pipeline-service.d.ts +2 -5
  88. package/dist/services/ps-scan-pipeline-service.js +9 -19
  89. package/dist/services/ps-scan-polygon-service.d.ts +8 -0
  90. package/dist/services/ps-scan-polygon-service.js +79 -0
  91. package/dist/services/ps-scan-region-service.d.ts +4 -0
  92. package/dist/services/ps-scan-region-service.js +56 -0
  93. package/dist/services/ps-scan-stability-service.d.ts +1 -3
  94. package/dist/services/ps-scan-stability-service.js +9 -22
  95. package/dist/services/ps-scan-warp-service.d.ts +1 -1
  96. package/dist/services/ps-scan-warp-service.js +8 -2
  97. package/dist/services/ps-scan-yield-service.d.ts +3 -0
  98. package/dist/services/ps-scan-yield-service.js +9 -0
  99. package/package.json +1 -1
  100. package/dist/components/ps-scan-page-list.d.ts +0 -14
  101. package/dist/components/ps-scan-page-list.js +0 -22
  102. package/dist/components/ps-scan-page-stack.d.ts +0 -7
  103. package/dist/components/ps-scan-page-stack.js +0 -6
  104. package/dist/components/ps-scan-review.d.ts +0 -24
  105. package/dist/components/ps-scan-review.js +0 -37
  106. package/dist/constants/ps-scan-filter.d.ts +0 -7
  107. package/dist/constants/ps-scan-filter.js +0 -9
  108. package/dist/constants/ps-scan-output-format.d.ts +0 -5
  109. package/dist/constants/ps-scan-output-format.js +0 -7
  110. package/dist/esm/components/ps-scan-page-list.js +0 -18
  111. package/dist/esm/components/ps-scan-page-stack.js +0 -2
  112. package/dist/esm/components/ps-scan-review.js +0 -33
  113. package/dist/esm/constants/ps-scan-filter.js +0 -6
  114. package/dist/esm/constants/ps-scan-output-format.js +0 -4
  115. package/dist/esm/hooks/use-ps-scan-pages.js +0 -62
  116. package/dist/esm/hooks/use-ps-scan-previews.js +0 -57
  117. package/dist/esm/services/ps-scan-enhance-service.js +0 -97
  118. package/dist/esm/services/ps-scan-order-service.js +0 -13
  119. package/dist/esm/services/ps-scan-output-service.js +0 -24
  120. package/dist/esm/services/ps-scan-pdf-service.js +0 -56
  121. package/dist/hooks/use-ps-scan-pages.d.ts +0 -12
  122. package/dist/hooks/use-ps-scan-pages.js +0 -66
  123. package/dist/hooks/use-ps-scan-previews.d.ts +0 -2
  124. package/dist/hooks/use-ps-scan-previews.js +0 -61
  125. package/dist/models/ps-scan-added-page.d.ts +0 -5
  126. package/dist/models/ps-scan-levels.d.ts +0 -4
  127. package/dist/models/ps-scan-output-options.d.ts +0 -7
  128. package/dist/models/ps-scan-page.d.ts +0 -12
  129. package/dist/models/ps-scan-pdf-page.d.ts +0 -5
  130. package/dist/services/ps-scan-enhance-service.d.ts +0 -9
  131. package/dist/services/ps-scan-enhance-service.js +0 -101
  132. package/dist/services/ps-scan-order-service.d.ts +0 -4
  133. package/dist/services/ps-scan-order-service.js +0 -17
  134. package/dist/services/ps-scan-output-service.d.ts +0 -5
  135. package/dist/services/ps-scan-output-service.js +0 -28
  136. package/dist/services/ps-scan-pdf-service.d.ts +0 -5
  137. package/dist/services/ps-scan-pdf-service.js +0 -60
  138. /package/dist/esm/models/{ps-scan-added-page.js → ps-scan-gradient.js} +0 -0
  139. /package/dist/esm/models/{ps-scan-levels.js → ps-scan-located.js} +0 -0
  140. /package/dist/esm/models/{ps-scan-output-options.js → ps-scan-photo.js} +0 -0
  141. /package/dist/esm/models/{ps-scan-page.js → ps-scan-region.js} +0 -0
  142. /package/dist/esm/models/{ps-scan-pdf-page.js → ps-scan-result.js} +0 -0
  143. /package/dist/models/{ps-scan-added-page.js → ps-scan-gradient.js} +0 -0
  144. /package/dist/models/{ps-scan-levels.js → ps-scan-located.js} +0 -0
  145. /package/dist/models/{ps-scan-output-options.js → ps-scan-photo.js} +0 -0
  146. /package/dist/models/{ps-scan-page.js → ps-scan-region.js} +0 -0
  147. /package/dist/models/{ps-scan-pdf-page.js → ps-scan-result.js} +0 -0
@@ -1,16 +1,22 @@
1
+ import { PsScanConfig } from '../constants/ps-scan-config';
1
2
  import { PsScanHomographyService } from './ps-scan-homography-service';
2
3
  import { PsScanRasterService } from './ps-scan-raster-service';
4
+ import { PsScanYieldService } from './ps-scan-yield-service';
3
5
  export class PsScanWarpService {
4
- static warp(source, pixelQuad, width, height) {
6
+ static async warp(source, pixelQuad, width, height) {
5
7
  const matrix = PsScanHomographyService.fromUnitSquare(pixelQuad);
6
8
  const target = PsScanRasterService.create(width, height);
7
9
  const spanX = Math.max(1, width - 1);
8
10
  const spanY = Math.max(1, height - 1);
9
- for (let y = 0; y < height; y += 1)
11
+ const rowsPerChunk = Math.max(1, Math.floor(PsScanConfig.warpChunkPixels / width));
12
+ for (let y = 0; y < height; y += 1) {
10
13
  for (let x = 0; x < width; x += 1) {
11
14
  const point = PsScanHomographyService.apply(matrix, x / spanX, y / spanY);
12
15
  PsScanWarpService.sample(source, point.x, point.y, target.data, (y * width + x) * 4);
13
16
  }
17
+ if ((y + 1) % rowsPerChunk === 0)
18
+ await PsScanYieldService.next();
19
+ }
14
20
  return target;
15
21
  }
16
22
  static sample(source, x, y, out, at) {
@@ -0,0 +1,5 @@
1
+ export class PsScanYieldService {
2
+ static async next() {
3
+ await new Promise((resolve) => setTimeout(resolve, 0));
4
+ }
5
+ }
@@ -1,3 +1,3 @@
1
1
  import { type RefObject } from 'react';
2
2
  import type { PsScanLiveDetection } from '../models/ps-scan-live-detection';
3
- export declare const usePsScanLiveDetection: (videoRef: RefObject<HTMLVideoElement | null>, isActive: boolean, isAuto: boolean, onSteady: () => void) => PsScanLiveDetection;
3
+ export declare const usePsScanLiveDetection: (videoRef: RefObject<HTMLVideoElement | null>, isActive: boolean) => PsScanLiveDetection;
@@ -6,43 +6,39 @@ const ps_scan_config_1 = require("../constants/ps-scan-config");
6
6
  const ps_scan_canvas_service_1 = require("../services/ps-scan-canvas-service");
7
7
  const ps_scan_edge_service_1 = require("../services/ps-scan-edge-service");
8
8
  const ps_scan_stability_service_1 = require("../services/ps-scan-stability-service");
9
- const usePsScanLiveDetection = (videoRef, isActive, isAuto, onSteady) => {
10
- const [detection, setDetection] = (0, react_1.useState)({ progress: 0, quad: null });
11
- const isAutoRef = (0, react_1.useRef)(isAuto);
12
- const onSteadyRef = (0, react_1.useRef)(onSteady);
13
- isAutoRef.current = isAuto;
14
- onSteadyRef.current = onSteady;
9
+ const usePsScanLiveDetection = (videoRef, isActive) => {
10
+ const [detection, setDetection] = (0, react_1.useState)({ quad: null });
15
11
  (0, react_1.useEffect)(() => {
16
12
  if (!isActive) {
17
- setDetection({ progress: 0, quad: null });
13
+ setDetection({ quad: null });
18
14
  return;
19
15
  }
16
+ let isCancelled = false;
20
17
  let state = ps_scan_stability_service_1.PsScanStabilityService.initial();
21
- let last = performance.now();
22
18
  let timer;
23
- const tick = () => {
19
+ const tick = async () => {
24
20
  const video = videoRef.current;
25
- const now = performance.now();
26
21
  if (video !== null && video.videoWidth > 0 && document.visibilityState === 'visible') {
27
22
  try {
28
23
  const raster = ps_scan_canvas_service_1.PsScanCanvasService.sample(video, ps_scan_config_1.PsScanConfig.liveDetectMaxDimension);
29
- state = ps_scan_stability_service_1.PsScanStabilityService.next(state, ps_scan_edge_service_1.PsScanEdgeService.detect(raster), now - last);
24
+ const quad = await ps_scan_edge_service_1.PsScanEdgeService.detect(raster, ps_scan_config_1.PsScanConfig.liveDetectMaxDimension);
25
+ if (isCancelled)
26
+ return;
27
+ state = ps_scan_stability_service_1.PsScanStabilityService.next(state, quad);
30
28
  }
31
29
  catch {
32
30
  state = ps_scan_stability_service_1.PsScanStabilityService.initial();
33
31
  }
34
- const progress = isAutoRef.current ? ps_scan_stability_service_1.PsScanStabilityService.progress(state) : 0;
35
- setDetection({ progress, quad: state.quad });
36
- if (progress >= 1) {
37
- state = ps_scan_stability_service_1.PsScanStabilityService.disarm(state);
38
- onSteadyRef.current();
39
- }
32
+ setDetection((current) => (current.quad === state.quad ? current : { quad: state.quad }));
40
33
  }
41
- last = now;
42
- timer = setTimeout(tick, ps_scan_config_1.PsScanConfig.liveDetectIntervalMs);
34
+ if (!isCancelled)
35
+ timer = setTimeout(tick, ps_scan_config_1.PsScanConfig.liveDetectIntervalMs);
43
36
  };
44
37
  timer = setTimeout(tick, ps_scan_config_1.PsScanConfig.liveDetectIntervalMs);
45
- return () => clearTimeout(timer);
38
+ return () => {
39
+ isCancelled = true;
40
+ clearTimeout(timer);
41
+ };
46
42
  }, [isActive]);
47
43
  return detection;
48
44
  };
@@ -0,0 +1,9 @@
1
+ import type { PsScanPhoto } from '../models/ps-scan-photo';
2
+ import type { PsScanQuad } from '../models/ps-scan-quad';
3
+ export declare const usePsScanPhoto: () => {
4
+ clear: () => void;
5
+ detectAgain: () => Promise<boolean>;
6
+ load: (source: Blob) => Promise<PsScanPhoto>;
7
+ photo: PsScanPhoto | null;
8
+ setCorners: (corners: PsScanQuad) => void;
9
+ };
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.usePsScanPhoto = void 0;
4
+ const react_1 = require("react");
5
+ const ps_scan_pipeline_service_1 = require("../services/ps-scan-pipeline-service");
6
+ const usePsScanPhoto = () => {
7
+ const [photo, setPhoto] = (0, react_1.useState)(null);
8
+ const url = (0, react_1.useRef)('');
9
+ const release = (0, react_1.useCallback)(() => {
10
+ if (url.current !== '')
11
+ URL.revokeObjectURL(url.current);
12
+ url.current = '';
13
+ }, []);
14
+ (0, react_1.useEffect)(() => release, [release]);
15
+ const load = (0, react_1.useCallback)(async (source) => {
16
+ const prepared = await ps_scan_pipeline_service_1.PsScanPipelineService.prepare(source);
17
+ const next = {
18
+ corners: prepared.corners,
19
+ height: prepared.height,
20
+ isDetected: prepared.isDetected,
21
+ source,
22
+ sourceUrl: URL.createObjectURL(source),
23
+ width: prepared.width,
24
+ };
25
+ release();
26
+ url.current = next.sourceUrl;
27
+ setPhoto(next);
28
+ return next;
29
+ }, [release]);
30
+ const setCorners = (0, react_1.useCallback)((corners) => setPhoto((current) => (current === null ? current : { ...current, corners })), []);
31
+ const detectAgain = (0, react_1.useCallback)(async () => {
32
+ if (photo === null)
33
+ return false;
34
+ const prepared = await ps_scan_pipeline_service_1.PsScanPipelineService.prepare(photo.source);
35
+ setPhoto((current) => current === null
36
+ ? current
37
+ : { ...current, corners: prepared.corners, isDetected: prepared.isDetected });
38
+ return prepared.isDetected;
39
+ }, [photo]);
40
+ const clear = (0, react_1.useCallback)(() => {
41
+ release();
42
+ setPhoto(null);
43
+ }, [release]);
44
+ return { clear, detectAgain, load, photo, setCorners };
45
+ };
46
+ exports.usePsScanPhoto = usePsScanPhoto;
package/dist/index.d.ts CHANGED
@@ -71,7 +71,5 @@ export * from './hooks/use-ps-in-view';
71
71
  export * from './hooks/use-ps-upload-queue';
72
72
  export * from './components/ps-document-scanner';
73
73
  export * from './constants/ps-document-scanner-labels';
74
- export * from './constants/ps-scan-filter';
75
- export * from './constants/ps-scan-output-format';
76
74
  export * from './models/ps-document-scanner-props';
77
75
  export * from './models/ps-file-picker-scan';
package/dist/index.js CHANGED
@@ -87,7 +87,5 @@ __exportStar(require("./hooks/use-ps-in-view"), exports);
87
87
  __exportStar(require("./hooks/use-ps-upload-queue"), exports);
88
88
  __exportStar(require("./components/ps-document-scanner"), exports);
89
89
  __exportStar(require("./constants/ps-document-scanner-labels"), exports);
90
- __exportStar(require("./constants/ps-scan-filter"), exports);
91
- __exportStar(require("./constants/ps-scan-output-format"), exports);
92
90
  __exportStar(require("./models/ps-document-scanner-props"), exports);
93
91
  __exportStar(require("./models/ps-file-picker-scan"), exports);
@@ -1,16 +1,12 @@
1
1
  import type { PsDocumentScannerLabels } from '../constants/ps-document-scanner-labels';
2
- import type { PsScanOutputFormat } from '../constants/ps-scan-output-format';
3
2
  import type { PsLabelSet } from './ps-label-set';
4
3
  export interface PsDocumentScannerProps {
5
4
  className?: string;
6
5
  fileName?: string;
7
- isAutoCapture?: boolean;
8
6
  isOpen: boolean;
9
7
  jpegQuality?: number;
10
8
  labels?: Partial<PsLabelSet<typeof PsDocumentScannerLabels>>;
11
9
  maxDimension?: number;
12
- maxPages?: number;
13
10
  onClose: () => void;
14
11
  onComplete: (files: File[]) => void;
15
- outputFormat?: PsScanOutputFormat;
16
12
  }
@@ -1,14 +1,10 @@
1
1
  import type { PsDocumentScannerLabels } from '../constants/ps-document-scanner-labels';
2
- import type { PsScanOutputFormat } from '../constants/ps-scan-output-format';
3
2
  import type { PsLabelSet } from './ps-label-set';
4
3
  export interface PsDocumentScannerSheetProps {
5
4
  fileName: string;
6
- isAutoCapture: boolean;
7
5
  jpegQuality: number;
8
6
  labels: PsLabelSet<typeof PsDocumentScannerLabels>;
9
7
  maxDimension: number;
10
- maxPages: number;
11
8
  onClose: () => void;
12
9
  onComplete: (files: File[]) => void;
13
- outputFormat: PsScanOutputFormat;
14
10
  }
@@ -0,0 +1,4 @@
1
+ export interface PsScanGradient {
2
+ direction: Uint8Array;
3
+ magnitude: Float32Array;
4
+ }
@@ -1,5 +1,4 @@
1
1
  import type { PsScanQuad } from './ps-scan-quad';
2
2
  export interface PsScanLiveDetection {
3
- progress: number;
4
3
  quad: PsScanQuad | null;
5
4
  }
@@ -0,0 +1,5 @@
1
+ import type { PsScanQuad } from './ps-scan-quad';
2
+ export interface PsScanLocated {
3
+ isDetected: boolean;
4
+ quad: PsScanQuad;
5
+ }
@@ -0,0 +1,9 @@
1
+ import type { PsScanQuad } from './ps-scan-quad';
2
+ export interface PsScanPhoto {
3
+ corners: PsScanQuad;
4
+ height: number;
5
+ isDetected: boolean;
6
+ source: Blob;
7
+ sourceUrl: string;
8
+ width: number;
9
+ }
@@ -0,0 +1,5 @@
1
+ import type { PsPoint } from './ps-point';
2
+ export interface PsScanRegion {
3
+ area: number;
4
+ boundary: PsPoint[];
5
+ }
@@ -0,0 +1,6 @@
1
+ export interface PsScanResult {
2
+ blob: Blob;
3
+ height: number;
4
+ url: string;
5
+ width: number;
6
+ }
@@ -1,8 +1,5 @@
1
1
  import type { PsScanQuad } from './ps-scan-quad';
2
2
  export interface PsScanStability {
3
- isArmed: boolean;
4
3
  misses: number;
5
4
  quad: PsScanQuad | null;
6
- raw: PsScanQuad | null;
7
- stableMs: number;
8
5
  }
@@ -54,8 +54,8 @@ class PsScanCameraService {
54
54
  audio: false,
55
55
  video: {
56
56
  facingMode: { ideal: 'environment' },
57
- height: { ideal: 1440 },
58
- width: { ideal: 1920 },
57
+ height: { ideal: 2160 },
58
+ width: { ideal: 3840 },
59
59
  },
60
60
  });
61
61
  const track = stream.getVideoTracks()[0];
@@ -0,0 +1,7 @@
1
+ export declare class PsScanCannyService {
2
+ static edges(gray: Uint8ClampedArray, width: number, height: number): Uint8Array;
3
+ private static gradient;
4
+ private static highThreshold;
5
+ private static hysteresis;
6
+ private static suppress;
7
+ }
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsScanCannyService = void 0;
4
+ const ps_scan_config_1 = require("../constants/ps-scan-config");
5
+ class PsScanCannyService {
6
+ static edges(gray, width, height) {
7
+ const gradient = PsScanCannyService.gradient(gray, width, height);
8
+ const ridges = PsScanCannyService.suppress(gradient, width, height);
9
+ const high = PsScanCannyService.highThreshold(ridges);
10
+ return PsScanCannyService.hysteresis(ridges, width, height, high * ps_scan_config_1.PsScanConfig.cannyLowRatio, high);
11
+ }
12
+ static gradient(gray, width, height) {
13
+ const magnitude = new Float32Array(width * height);
14
+ const direction = new Uint8Array(width * height);
15
+ for (let y = 1; y < height - 1; y += 1)
16
+ for (let x = 1; x < width - 1; x += 1) {
17
+ const i = y * width + x;
18
+ const gx = -gray[i - width - 1] +
19
+ gray[i - width + 1] -
20
+ 2 * gray[i - 1] +
21
+ 2 * gray[i + 1] -
22
+ gray[i + width - 1] +
23
+ gray[i + width + 1];
24
+ const gy = -gray[i - width - 1] -
25
+ 2 * gray[i - width] -
26
+ gray[i - width + 1] +
27
+ gray[i + width - 1] +
28
+ 2 * gray[i + width] +
29
+ gray[i + width + 1];
30
+ const ax = Math.abs(gx);
31
+ const ay = Math.abs(gy);
32
+ magnitude[i] = Math.hypot(gx, gy) / 4;
33
+ if (ay <= ax * 0.41421356)
34
+ direction[i] = 0;
35
+ else if (ay >= ax * 2.41421356)
36
+ direction[i] = 2;
37
+ else
38
+ direction[i] = gx * gy > 0 ? 1 : 3;
39
+ }
40
+ return { direction, magnitude };
41
+ }
42
+ static highThreshold(ridges) {
43
+ const values = [];
44
+ for (let index = 0; index < ridges.length; index += 1)
45
+ if (ridges[index] > 0)
46
+ values.push(ridges[index]);
47
+ if (values.length === 0)
48
+ return ps_scan_config_1.PsScanConfig.cannyMinHigh;
49
+ values.sort((a, b) => a - b);
50
+ const at = Math.min(values.length - 1, Math.floor(values.length * ps_scan_config_1.PsScanConfig.cannyHighPercentile));
51
+ return Math.max(ps_scan_config_1.PsScanConfig.cannyMinHigh, values[at]);
52
+ }
53
+ static hysteresis(ridges, width, height, low, high) {
54
+ const out = new Uint8Array(width * height);
55
+ const stack = [];
56
+ for (let index = 0; index < ridges.length; index += 1)
57
+ if (ridges[index] >= high) {
58
+ out[index] = 1;
59
+ stack.push(index);
60
+ }
61
+ while (stack.length > 0) {
62
+ const index = stack.pop();
63
+ if (index === undefined)
64
+ break;
65
+ const x = index % width;
66
+ const y = (index - x) / width;
67
+ for (let dy = -1; dy <= 1; dy += 1)
68
+ for (let dx = -1; dx <= 1; dx += 1) {
69
+ const nx = x + dx;
70
+ const ny = y + dy;
71
+ if (nx < 0 || ny < 0 || nx >= width || ny >= height)
72
+ continue;
73
+ const next = ny * width + nx;
74
+ if (out[next] === 0 && ridges[next] >= low) {
75
+ out[next] = 1;
76
+ stack.push(next);
77
+ }
78
+ }
79
+ }
80
+ return out;
81
+ }
82
+ static suppress(gradient, width, height) {
83
+ const { direction, magnitude } = gradient;
84
+ const out = new Float32Array(width * height);
85
+ const offsets = [1, width + 1, width, width - 1];
86
+ for (let y = 1; y < height - 1; y += 1)
87
+ for (let x = 1; x < width - 1; x += 1) {
88
+ const i = y * width + x;
89
+ const offset = offsets[direction[i]];
90
+ const value = magnitude[i];
91
+ if (value >= magnitude[i - offset] && value > magnitude[i + offset])
92
+ out[i] = value;
93
+ }
94
+ return out;
95
+ }
96
+ }
97
+ exports.PsScanCannyService = PsScanCannyService;
@@ -1,11 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PsScanCanvasService = void 0;
4
+ const ps_scan_config_1 = require("../constants/ps-scan-config");
4
5
  const ps_scan_geometry_service_1 = require("./ps-scan-geometry-service");
5
6
  class PsScanCanvasService {
6
7
  static async decode(blob, maxDimension) {
7
8
  const bitmap = await createImageBitmap(blob, { imageOrientation: 'from-image' });
8
- const size = ps_scan_geometry_service_1.PsScanGeometryService.fitWithin({ height: bitmap.height, width: bitmap.width }, maxDimension);
9
+ const capped = ps_scan_geometry_service_1.PsScanGeometryService.fitWithin({ height: bitmap.height, width: bitmap.width }, maxDimension);
10
+ const shrink = Math.min(1, Math.sqrt(ps_scan_config_1.PsScanConfig.decodeMaxPixels / (capped.width * capped.height)));
11
+ const size = {
12
+ height: Math.max(1, Math.round(capped.height * shrink)),
13
+ width: Math.max(1, Math.round(capped.width * shrink)),
14
+ };
9
15
  const context = PsScanCanvasService.context(size.width, size.height);
10
16
  context.drawImage(bitmap, 0, 0, size.width, size.height);
11
17
  const naturalHeight = bitmap.height;
@@ -1,9 +1,9 @@
1
+ import type { PsScanLocated } from '../models/ps-scan-located';
1
2
  import type { PsScanQuad } from '../models/ps-scan-quad';
2
3
  import type { PsScanRaster } from '../models/ps-scan-raster';
3
4
  export declare class PsScanEdgeService {
4
- static detect(source: PsScanRaster): PsScanQuad | null;
5
- private static dilate;
6
- private static foreground;
7
- private static largestComponent;
8
- private static threshold;
5
+ static detect(source: PsScanRaster, maxDimension: number): Promise<PsScanQuad | null>;
6
+ static locate(source: PsScanRaster, maxDimension: number): Promise<PsScanLocated>;
7
+ private static candidate;
8
+ private static normalise;
9
9
  }