@pallasoft/ps-file-components 1.3.0 → 1.5.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 (216) hide show
  1. package/dist/components/ps-document-scanner-loader.d.ts +1 -0
  2. package/dist/components/ps-document-scanner-loader.js +40 -0
  3. package/dist/components/ps-document-scanner-sheet.d.ts +2 -0
  4. package/dist/components/ps-document-scanner-sheet.js +186 -0
  5. package/dist/components/ps-document-scanner.d.ts +2 -0
  6. package/dist/components/ps-document-scanner.js +17 -0
  7. package/dist/components/ps-file-picker-actions.d.ts +10 -0
  8. package/dist/components/ps-file-picker-actions.js +21 -0
  9. package/dist/components/ps-file-picker.d.ts +7 -1
  10. package/dist/components/ps-file-picker.js +30 -6
  11. package/dist/components/ps-file-viewer-pane.d.ts +2 -0
  12. package/dist/components/ps-file-viewer-pane.js +39 -0
  13. package/dist/components/ps-scan-button.d.ts +13 -0
  14. package/dist/components/ps-scan-button.js +9 -0
  15. package/dist/components/ps-scan-camera-view.d.ts +27 -0
  16. package/dist/components/ps-scan-camera-view.js +34 -0
  17. package/dist/components/ps-scan-crop-editor.d.ts +13 -0
  18. package/dist/components/ps-scan-crop-editor.js +69 -0
  19. package/dist/components/ps-scan-denied-steps.d.ts +6 -0
  20. package/dist/components/ps-scan-denied-steps.js +33 -0
  21. package/dist/components/ps-scan-icon-button.d.ts +11 -0
  22. package/dist/components/ps-scan-icon-button.js +9 -0
  23. package/dist/components/ps-scan-illustration.d.ts +1 -0
  24. package/dist/components/ps-scan-illustration.js +6 -0
  25. package/dist/components/ps-scan-loupe.d.ts +10 -0
  26. package/dist/components/ps-scan-loupe.js +31 -0
  27. package/dist/components/ps-scan-page-list.d.ts +14 -0
  28. package/dist/components/ps-scan-page-list.js +22 -0
  29. package/dist/components/ps-scan-page-stack.d.ts +7 -0
  30. package/dist/components/ps-scan-page-stack.js +6 -0
  31. package/dist/components/ps-scan-permission-view.d.ts +11 -0
  32. package/dist/components/ps-scan-permission-view.js +48 -0
  33. package/dist/components/ps-scan-photo-button.d.ts +8 -0
  34. package/dist/components/ps-scan-photo-button.js +20 -0
  35. package/dist/components/ps-scan-review.d.ts +24 -0
  36. package/dist/components/ps-scan-review.js +37 -0
  37. package/dist/components/ps-scan-shutter.d.ts +7 -0
  38. package/dist/components/ps-scan-shutter.js +6 -0
  39. package/dist/components/ps-scan-viewfinder-overlay.d.ts +8 -0
  40. package/dist/components/ps-scan-viewfinder-overlay.js +28 -0
  41. package/dist/components/ps-upload-row.js +1 -1
  42. package/dist/constants/ps-document-scanner-labels.d.ts +80 -0
  43. package/dist/constants/ps-document-scanner-labels.js +83 -0
  44. package/dist/constants/ps-file-picker-labels.d.ts +5 -3
  45. package/dist/constants/ps-file-picker-labels.js +5 -3
  46. package/dist/constants/ps-scan-camera-status.d.ts +11 -0
  47. package/dist/constants/ps-scan-camera-status.js +13 -0
  48. package/dist/constants/ps-scan-chrome-classes.d.ts +12 -0
  49. package/dist/constants/ps-scan-chrome-classes.js +15 -0
  50. package/dist/constants/ps-scan-config.d.ts +48 -0
  51. package/dist/constants/ps-scan-config.js +51 -0
  52. package/dist/constants/ps-scan-corner-order.d.ts +1 -0
  53. package/dist/constants/ps-scan-corner-order.js +4 -0
  54. package/dist/constants/ps-scan-filter.d.ts +7 -0
  55. package/dist/constants/ps-scan-filter.js +9 -0
  56. package/dist/constants/ps-scan-output-format.d.ts +5 -0
  57. package/dist/constants/ps-scan-output-format.js +7 -0
  58. package/dist/constants/ps-scan-platform.d.ts +6 -0
  59. package/dist/constants/ps-scan-platform.js +8 -0
  60. package/dist/constants/ps-scan-step.d.ts +6 -0
  61. package/dist/constants/ps-scan-step.js +8 -0
  62. package/dist/esm/components/ps-document-scanner-loader.js +4 -0
  63. package/dist/esm/components/ps-document-scanner-sheet.js +182 -0
  64. package/dist/esm/components/ps-document-scanner.js +13 -0
  65. package/dist/esm/components/ps-file-picker-actions.js +17 -0
  66. package/dist/esm/components/ps-file-picker.js +31 -7
  67. package/dist/esm/components/ps-file-viewer-pane.js +35 -0
  68. package/dist/esm/components/ps-scan-button.js +5 -0
  69. package/dist/esm/components/ps-scan-camera-view.js +30 -0
  70. package/dist/esm/components/ps-scan-crop-editor.js +65 -0
  71. package/dist/esm/components/ps-scan-denied-steps.js +29 -0
  72. package/dist/esm/components/ps-scan-icon-button.js +5 -0
  73. package/dist/esm/components/ps-scan-illustration.js +2 -0
  74. package/dist/esm/components/ps-scan-loupe.js +27 -0
  75. package/dist/esm/components/ps-scan-page-list.js +18 -0
  76. package/dist/esm/components/ps-scan-page-stack.js +2 -0
  77. package/dist/esm/components/ps-scan-permission-view.js +44 -0
  78. package/dist/esm/components/ps-scan-photo-button.js +16 -0
  79. package/dist/esm/components/ps-scan-review.js +33 -0
  80. package/dist/esm/components/ps-scan-shutter.js +2 -0
  81. package/dist/esm/components/ps-scan-viewfinder-overlay.js +24 -0
  82. package/dist/esm/components/ps-upload-row.js +1 -1
  83. package/dist/esm/constants/ps-document-scanner-labels.js +80 -0
  84. package/dist/esm/constants/ps-file-picker-labels.js +5 -3
  85. package/dist/esm/constants/ps-scan-camera-status.js +10 -0
  86. package/dist/esm/constants/ps-scan-chrome-classes.js +12 -0
  87. package/dist/esm/constants/ps-scan-config.js +48 -0
  88. package/dist/esm/constants/ps-scan-corner-order.js +1 -0
  89. package/dist/esm/constants/ps-scan-filter.js +6 -0
  90. package/dist/esm/constants/ps-scan-output-format.js +4 -0
  91. package/dist/esm/constants/ps-scan-platform.js +5 -0
  92. package/dist/esm/constants/ps-scan-step.js +5 -0
  93. package/dist/esm/hooks/use-ps-focus-trap.js +45 -0
  94. package/dist/esm/hooks/use-ps-scan-camera.js +99 -0
  95. package/dist/esm/hooks/use-ps-scan-live-detection.js +45 -0
  96. package/dist/esm/hooks/use-ps-scan-pages.js +62 -0
  97. package/dist/esm/hooks/use-ps-scan-previews.js +57 -0
  98. package/dist/esm/index.js +8 -0
  99. package/dist/esm/models/ps-document-scanner-props.js +1 -0
  100. package/dist/esm/models/ps-document-scanner-sheet-props.js +1 -0
  101. package/dist/esm/models/ps-file-picker-scan.js +1 -0
  102. package/dist/esm/models/ps-file-viewer-pane-props.js +1 -0
  103. package/dist/esm/models/ps-scan-added-page.js +1 -0
  104. package/dist/esm/models/ps-scan-camera-session.js +1 -0
  105. package/dist/esm/models/ps-scan-decoded-image.js +1 -0
  106. package/dist/esm/models/ps-scan-levels.js +1 -0
  107. package/dist/esm/models/ps-scan-live-detection.js +1 -0
  108. package/dist/esm/models/ps-scan-output-options.js +1 -0
  109. package/dist/esm/models/ps-scan-page.js +1 -0
  110. package/dist/esm/models/ps-scan-pdf-page.js +1 -0
  111. package/dist/esm/models/ps-scan-prepared.js +1 -0
  112. package/dist/esm/models/ps-scan-quad.js +1 -0
  113. package/dist/esm/models/ps-scan-raster.js +1 -0
  114. package/dist/esm/models/ps-scan-rendered-page.js +1 -0
  115. package/dist/esm/models/ps-scan-stability.js +1 -0
  116. package/dist/esm/services/ps-scan-camera-service.js +95 -0
  117. package/dist/esm/services/ps-scan-canvas-service.js +52 -0
  118. package/dist/esm/services/ps-scan-edge-service.js +156 -0
  119. package/dist/esm/services/ps-scan-enhance-service.js +97 -0
  120. package/dist/esm/services/ps-scan-file-name-service.js +25 -0
  121. package/dist/esm/services/ps-scan-geometry-service.js +116 -0
  122. package/dist/esm/services/ps-scan-homography-service.js +46 -0
  123. package/dist/esm/services/ps-scan-hull-service.js +59 -0
  124. package/dist/esm/services/ps-scan-image-filter-service.js +52 -0
  125. package/dist/esm/services/ps-scan-order-service.js +13 -0
  126. package/dist/esm/services/ps-scan-output-service.js +24 -0
  127. package/dist/esm/services/ps-scan-pdf-service.js +56 -0
  128. package/dist/esm/services/ps-scan-pipeline-service.js +40 -0
  129. package/dist/esm/services/ps-scan-platform-service.js +15 -0
  130. package/dist/esm/services/ps-scan-raster-service.js +67 -0
  131. package/dist/esm/services/ps-scan-stability-service.js +41 -0
  132. package/dist/esm/services/ps-scan-template-service.js +5 -0
  133. package/dist/esm/services/ps-scan-warp-service.js +35 -0
  134. package/dist/hooks/use-ps-focus-trap.d.ts +2 -0
  135. package/dist/hooks/use-ps-focus-trap.js +49 -0
  136. package/dist/hooks/use-ps-scan-camera.d.ts +11 -0
  137. package/dist/hooks/use-ps-scan-camera.js +103 -0
  138. package/dist/hooks/use-ps-scan-live-detection.d.ts +3 -0
  139. package/dist/hooks/use-ps-scan-live-detection.js +49 -0
  140. package/dist/hooks/use-ps-scan-pages.d.ts +12 -0
  141. package/dist/hooks/use-ps-scan-pages.js +66 -0
  142. package/dist/hooks/use-ps-scan-previews.d.ts +2 -0
  143. package/dist/hooks/use-ps-scan-previews.js +61 -0
  144. package/dist/index.d.ts +8 -0
  145. package/dist/index.js +8 -0
  146. package/dist/models/ps-document-scanner-props.d.ts +16 -0
  147. package/dist/models/ps-document-scanner-props.js +2 -0
  148. package/dist/models/ps-document-scanner-sheet-props.d.ts +14 -0
  149. package/dist/models/ps-document-scanner-sheet-props.js +2 -0
  150. package/dist/models/ps-file-picker-scan.d.ts +4 -0
  151. package/dist/models/ps-file-picker-scan.js +2 -0
  152. package/dist/models/ps-file-viewer-pane-props.d.ts +12 -0
  153. package/dist/models/ps-file-viewer-pane-props.js +2 -0
  154. package/dist/models/ps-scan-added-page.d.ts +5 -0
  155. package/dist/models/ps-scan-added-page.js +2 -0
  156. package/dist/models/ps-scan-camera-session.d.ts +5 -0
  157. package/dist/models/ps-scan-camera-session.js +2 -0
  158. package/dist/models/ps-scan-decoded-image.d.ts +6 -0
  159. package/dist/models/ps-scan-decoded-image.js +2 -0
  160. package/dist/models/ps-scan-levels.d.ts +4 -0
  161. package/dist/models/ps-scan-levels.js +2 -0
  162. package/dist/models/ps-scan-live-detection.d.ts +5 -0
  163. package/dist/models/ps-scan-live-detection.js +2 -0
  164. package/dist/models/ps-scan-output-options.d.ts +7 -0
  165. package/dist/models/ps-scan-output-options.js +2 -0
  166. package/dist/models/ps-scan-page.d.ts +12 -0
  167. package/dist/models/ps-scan-page.js +2 -0
  168. package/dist/models/ps-scan-pdf-page.d.ts +5 -0
  169. package/dist/models/ps-scan-pdf-page.js +2 -0
  170. package/dist/models/ps-scan-prepared.d.ts +7 -0
  171. package/dist/models/ps-scan-prepared.js +2 -0
  172. package/dist/models/ps-scan-quad.d.ts +2 -0
  173. package/dist/models/ps-scan-quad.js +2 -0
  174. package/dist/models/ps-scan-raster.d.ts +5 -0
  175. package/dist/models/ps-scan-raster.js +2 -0
  176. package/dist/models/ps-scan-rendered-page.d.ts +5 -0
  177. package/dist/models/ps-scan-rendered-page.js +2 -0
  178. package/dist/models/ps-scan-stability.d.ts +8 -0
  179. package/dist/models/ps-scan-stability.js +2 -0
  180. package/dist/services/ps-scan-camera-service.d.ts +14 -0
  181. package/dist/services/ps-scan-camera-service.js +99 -0
  182. package/dist/services/ps-scan-canvas-service.d.ts +9 -0
  183. package/dist/services/ps-scan-canvas-service.js +56 -0
  184. package/dist/services/ps-scan-edge-service.d.ts +9 -0
  185. package/dist/services/ps-scan-edge-service.js +160 -0
  186. package/dist/services/ps-scan-enhance-service.d.ts +9 -0
  187. package/dist/services/ps-scan-enhance-service.js +101 -0
  188. package/dist/services/ps-scan-file-name-service.d.ts +6 -0
  189. package/dist/services/ps-scan-file-name-service.js +29 -0
  190. package/dist/services/ps-scan-geometry-service.d.ts +20 -0
  191. package/dist/services/ps-scan-geometry-service.js +120 -0
  192. package/dist/services/ps-scan-homography-service.d.ts +7 -0
  193. package/dist/services/ps-scan-homography-service.js +50 -0
  194. package/dist/services/ps-scan-hull-service.d.ts +6 -0
  195. package/dist/services/ps-scan-hull-service.js +63 -0
  196. package/dist/services/ps-scan-image-filter-service.d.ts +6 -0
  197. package/dist/services/ps-scan-image-filter-service.js +56 -0
  198. package/dist/services/ps-scan-order-service.d.ts +4 -0
  199. package/dist/services/ps-scan-order-service.js +17 -0
  200. package/dist/services/ps-scan-output-service.d.ts +5 -0
  201. package/dist/services/ps-scan-output-service.js +28 -0
  202. package/dist/services/ps-scan-pdf-service.d.ts +5 -0
  203. package/dist/services/ps-scan-pdf-service.js +60 -0
  204. package/dist/services/ps-scan-pipeline-service.d.ts +10 -0
  205. package/dist/services/ps-scan-pipeline-service.js +44 -0
  206. package/dist/services/ps-scan-platform-service.d.ts +4 -0
  207. package/dist/services/ps-scan-platform-service.js +19 -0
  208. package/dist/services/ps-scan-raster-service.d.ts +6 -0
  209. package/dist/services/ps-scan-raster-service.js +71 -0
  210. package/dist/services/ps-scan-stability-service.d.ts +9 -0
  211. package/dist/services/ps-scan-stability-service.js +45 -0
  212. package/dist/services/ps-scan-template-service.d.ts +3 -0
  213. package/dist/services/ps-scan-template-service.js +9 -0
  214. package/dist/services/ps-scan-warp-service.d.ts +6 -0
  215. package/dist/services/ps-scan-warp-service.js +39 -0
  216. package/package.json +9 -6
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsScanGeometryService = void 0;
4
+ const ps_scan_config_1 = require("../constants/ps-scan-config");
5
+ class PsScanGeometryService {
6
+ static area(points) {
7
+ let sum = 0;
8
+ points.forEach((point, index) => {
9
+ const next = points[(index + 1) % points.length];
10
+ sum += point.x * next.y - next.x * point.y;
11
+ });
12
+ return Math.abs(sum) / 2;
13
+ }
14
+ static clamp(point) {
15
+ return { x: Math.min(1, Math.max(0, point.x)), y: Math.min(1, Math.max(0, point.y)) };
16
+ }
17
+ static cover(container, content) {
18
+ if (container.width <= 0 || container.height <= 0 || content.width <= 0 || content.height <= 0)
19
+ return { height: 0, width: 0 };
20
+ const scale = Math.max(container.width / content.width, container.height / content.height);
21
+ return { height: content.height * scale, width: content.width * scale };
22
+ }
23
+ static defaultQuad() {
24
+ const inset = 0.08;
25
+ return [
26
+ { x: inset, y: inset },
27
+ { x: 1 - inset, y: inset },
28
+ { x: 1 - inset, y: 1 - inset },
29
+ { x: inset, y: 1 - inset },
30
+ ];
31
+ }
32
+ static distance(from, to) {
33
+ return Math.hypot(to.x - from.x, to.y - from.y);
34
+ }
35
+ static fit(container, content) {
36
+ if (container.width <= 0 || container.height <= 0 || content.width <= 0 || content.height <= 0)
37
+ return { height: 0, width: 0 };
38
+ const scale = Math.min(container.width / content.width, container.height / content.height);
39
+ return { height: content.height * scale, width: content.width * scale };
40
+ }
41
+ static fitWithin(size, maxDimension) {
42
+ const longest = Math.max(size.width, size.height);
43
+ if (longest <= maxDimension)
44
+ return { height: Math.round(size.height), width: Math.round(size.width) };
45
+ const scale = maxDimension / longest;
46
+ return {
47
+ height: Math.max(1, Math.round(size.height * scale)),
48
+ width: Math.max(1, Math.round(size.width * scale)),
49
+ };
50
+ }
51
+ static inset(quad, distance) {
52
+ const centre = {
53
+ x: quad.reduce((sum, point) => sum + point.x, 0) / quad.length,
54
+ y: quad.reduce((sum, point) => sum + point.y, 0) / quad.length,
55
+ };
56
+ return quad.map((point) => {
57
+ const length = PsScanGeometryService.distance(point, centre);
58
+ const ratio = length <= distance ? 0 : (length - distance) / length;
59
+ return {
60
+ x: centre.x + (point.x - centre.x) * ratio,
61
+ y: centre.y + (point.y - centre.y) * ratio,
62
+ };
63
+ });
64
+ }
65
+ static isConvex(points) {
66
+ let sign = 0;
67
+ for (let index = 0; index < points.length; index += 1) {
68
+ const a = points[index];
69
+ const b = points[(index + 1) % points.length];
70
+ const c = points[(index + 2) % points.length];
71
+ const cross = (b.x - a.x) * (c.y - b.y) - (b.y - a.y) * (c.x - b.x);
72
+ if (Math.abs(cross) < 1e-9)
73
+ return false;
74
+ if (sign === 0)
75
+ sign = Math.sign(cross);
76
+ else if (Math.sign(cross) !== sign)
77
+ return false;
78
+ }
79
+ return true;
80
+ }
81
+ static isUsable(quad) {
82
+ return (PsScanGeometryService.isConvex(quad) &&
83
+ PsScanGeometryService.area(quad) > ps_scan_config_1.PsScanConfig.minCornerGap * ps_scan_config_1.PsScanConfig.minCornerGap);
84
+ }
85
+ static nudge(quad, index, dx, dy) {
86
+ const moved = PsScanGeometryService.clamp({ x: quad[index].x + dx, y: quad[index].y + dy });
87
+ const next = quad.map((point, at) => (at === index ? moved : point));
88
+ return PsScanGeometryService.isUsable(next) ? next : quad;
89
+ }
90
+ static order(points) {
91
+ const centre = {
92
+ x: points.reduce((sum, point) => sum + point.x, 0) / points.length,
93
+ y: points.reduce((sum, point) => sum + point.y, 0) / points.length,
94
+ };
95
+ const sorted = [...points].sort((a, b) => Math.atan2(a.y - centre.y, a.x - centre.x) - Math.atan2(b.y - centre.y, b.x - centre.x));
96
+ const sums = sorted.map((point) => point.x + point.y);
97
+ const start = sums.indexOf(Math.min(...sums));
98
+ return [0, 1, 2, 3].map((offset) => sorted[(start + offset) % 4]);
99
+ }
100
+ static outputSize(quad, raster) {
101
+ const pixels = PsScanGeometryService.toPixels(quad, raster);
102
+ const width = (PsScanGeometryService.distance(pixels[0], pixels[1]) +
103
+ PsScanGeometryService.distance(pixels[3], pixels[2])) /
104
+ 2;
105
+ const height = (PsScanGeometryService.distance(pixels[0], pixels[3]) +
106
+ PsScanGeometryService.distance(pixels[1], pixels[2])) /
107
+ 2;
108
+ return { height: Math.max(1, Math.round(height)), width: Math.max(1, Math.round(width)) };
109
+ }
110
+ static rotateSize(size, rotation) {
111
+ return rotation % 180 === 0 ? size : { height: size.width, width: size.height };
112
+ }
113
+ static toPixels(quad, size) {
114
+ return quad.map((point) => ({
115
+ x: point.x * size.width,
116
+ y: point.y * size.height,
117
+ }));
118
+ }
119
+ }
120
+ exports.PsScanGeometryService = PsScanGeometryService;
@@ -0,0 +1,7 @@
1
+ import type { PsPoint } from '../models/ps-point';
2
+ import type { PsScanQuad } from '../models/ps-scan-quad';
3
+ export declare class PsScanHomographyService {
4
+ static apply(matrix: number[], x: number, y: number): PsPoint;
5
+ static fromUnitSquare(quad: PsScanQuad): number[];
6
+ private static solve;
7
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsScanHomographyService = void 0;
4
+ class PsScanHomographyService {
5
+ static apply(matrix, x, y) {
6
+ const w = matrix[6] * x + matrix[7] * y + matrix[8];
7
+ return {
8
+ x: (matrix[0] * x + matrix[1] * y + matrix[2]) / w,
9
+ y: (matrix[3] * x + matrix[4] * y + matrix[5]) / w,
10
+ };
11
+ }
12
+ static fromUnitSquare(quad) {
13
+ const unit = [
14
+ [0, 0],
15
+ [1, 0],
16
+ [1, 1],
17
+ [0, 1],
18
+ ];
19
+ const rows = [];
20
+ unit.forEach(([u, v], index) => {
21
+ const { x, y } = quad[index];
22
+ rows.push([u, v, 1, 0, 0, 0, -u * x, -v * x, x]);
23
+ rows.push([0, 0, 0, u, v, 1, -u * y, -v * y, y]);
24
+ });
25
+ return [...PsScanHomographyService.solve(rows), 1];
26
+ }
27
+ static solve(rows) {
28
+ const size = rows.length;
29
+ const matrix = rows.map((row) => [...row]);
30
+ for (let column = 0; column < size; column += 1) {
31
+ let pivot = column;
32
+ for (let row = column + 1; row < size; row += 1)
33
+ if (Math.abs(matrix[row][column]) > Math.abs(matrix[pivot][column]))
34
+ pivot = row;
35
+ [matrix[column], matrix[pivot]] = [matrix[pivot], matrix[column]];
36
+ const lead = matrix[column][column];
37
+ if (Math.abs(lead) < 1e-12)
38
+ return [1, 0, 0, 0, 1, 0, 0, 0];
39
+ for (let row = 0; row < size; row += 1) {
40
+ if (row === column)
41
+ continue;
42
+ const factor = matrix[row][column] / lead;
43
+ for (let at = column; at <= size; at += 1)
44
+ matrix[row][at] -= factor * matrix[column][at];
45
+ }
46
+ }
47
+ return matrix.map((row, index) => row[size] / row[index]);
48
+ }
49
+ }
50
+ exports.PsScanHomographyService = PsScanHomographyService;
@@ -0,0 +1,6 @@
1
+ import type { PsPoint } from '../models/ps-point';
2
+ export declare class PsScanHullService {
3
+ static bestQuad(hull: PsPoint[]): PsPoint[];
4
+ static convexHull(input: PsPoint[]): PsPoint[];
5
+ private static reduce;
6
+ }
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsScanHullService = void 0;
4
+ const ps_scan_config_1 = require("../constants/ps-scan-config");
5
+ const ps_scan_geometry_service_1 = require("./ps-scan-geometry-service");
6
+ class PsScanHullService {
7
+ static bestQuad(hull) {
8
+ const points = PsScanHullService.reduce(hull, ps_scan_config_1.PsScanConfig.hullCandidateLimit);
9
+ if (points.length <= 4)
10
+ return points;
11
+ let best = points.slice(0, 4);
12
+ let bestArea = 0;
13
+ for (let a = 0; a < points.length - 3; a += 1)
14
+ for (let b = a + 1; b < points.length - 2; b += 1)
15
+ for (let c = b + 1; c < points.length - 1; c += 1)
16
+ for (let d = c + 1; d < points.length; d += 1) {
17
+ const candidate = [points[a], points[b], points[c], points[d]];
18
+ const area = ps_scan_geometry_service_1.PsScanGeometryService.area(candidate);
19
+ if (area > bestArea) {
20
+ bestArea = area;
21
+ best = candidate;
22
+ }
23
+ }
24
+ return best;
25
+ }
26
+ static convexHull(input) {
27
+ const points = [...input].sort((a, b) => (a.x === b.x ? a.y - b.y : a.x - b.x));
28
+ if (points.length < 3)
29
+ return points;
30
+ const cross = (o, a, b) => (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);
31
+ const build = (list) => {
32
+ const chain = [];
33
+ list.forEach((point) => {
34
+ while (chain.length >= 2 &&
35
+ cross(chain[chain.length - 2], chain[chain.length - 1], point) <= 0)
36
+ chain.pop();
37
+ chain.push(point);
38
+ });
39
+ chain.pop();
40
+ return chain;
41
+ };
42
+ return [...build(points), ...build([...points].reverse())];
43
+ }
44
+ static reduce(hull, limit) {
45
+ const points = [...hull];
46
+ while (points.length > limit) {
47
+ let weakest = 0;
48
+ let weakestArea = Infinity;
49
+ points.forEach((point, index) => {
50
+ const previous = points[(index - 1 + points.length) % points.length];
51
+ const next = points[(index + 1) % points.length];
52
+ const area = ps_scan_geometry_service_1.PsScanGeometryService.area([previous, point, next]);
53
+ if (area < weakestArea) {
54
+ weakestArea = area;
55
+ weakest = index;
56
+ }
57
+ });
58
+ points.splice(weakest, 1);
59
+ }
60
+ return points;
61
+ }
62
+ }
63
+ exports.PsScanHullService = PsScanHullService;
@@ -0,0 +1,6 @@
1
+ import type { PsScanRaster } from '../models/ps-scan-raster';
2
+ export declare class PsScanImageFilterService {
3
+ static blur(gray: Uint8ClampedArray, width: number, height: number): Uint8ClampedArray;
4
+ static grayscale(raster: PsScanRaster): Uint8ClampedArray;
5
+ static sobel(gray: Uint8ClampedArray, width: number, height: number): Uint16Array;
6
+ }
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsScanImageFilterService = void 0;
4
+ class PsScanImageFilterService {
5
+ static blur(gray, width, height) {
6
+ const kernel = [1, 4, 6, 4, 1];
7
+ const pass = new Float32Array(width * height);
8
+ const out = new Uint8ClampedArray(width * height);
9
+ for (let y = 0; y < height; y += 1)
10
+ for (let x = 0; x < width; x += 1) {
11
+ let sum = 0;
12
+ for (let k = -2; k <= 2; k += 1)
13
+ sum += gray[y * width + Math.min(width - 1, Math.max(0, x + k))] * kernel[k + 2];
14
+ pass[y * width + x] = sum / 16;
15
+ }
16
+ for (let y = 0; y < height; y += 1)
17
+ for (let x = 0; x < width; x += 1) {
18
+ let sum = 0;
19
+ for (let k = -2; k <= 2; k += 1)
20
+ sum += pass[Math.min(height - 1, Math.max(0, y + k)) * width + x] * kernel[k + 2];
21
+ out[y * width + x] = sum / 16;
22
+ }
23
+ return out;
24
+ }
25
+ static grayscale(raster) {
26
+ const out = new Uint8ClampedArray(raster.width * raster.height);
27
+ for (let index = 0; index < out.length; index += 1) {
28
+ const at = index * 4;
29
+ out[index] =
30
+ 0.299 * raster.data[at] + 0.587 * raster.data[at + 1] + 0.114 * raster.data[at + 2];
31
+ }
32
+ return out;
33
+ }
34
+ static sobel(gray, width, height) {
35
+ const out = new Uint16Array(width * height);
36
+ for (let y = 1; y < height - 1; y += 1)
37
+ for (let x = 1; x < width - 1; x += 1) {
38
+ const i = y * width + x;
39
+ const gx = -gray[i - width - 1] +
40
+ gray[i - width + 1] -
41
+ 2 * gray[i - 1] +
42
+ 2 * gray[i + 1] -
43
+ gray[i + width - 1] +
44
+ gray[i + width + 1];
45
+ const gy = -gray[i - width - 1] -
46
+ 2 * gray[i - width] -
47
+ gray[i - width + 1] +
48
+ gray[i + width - 1] +
49
+ 2 * gray[i + width] +
50
+ gray[i + width + 1];
51
+ out[i] = Math.hypot(gx, gy) / 4;
52
+ }
53
+ return out;
54
+ }
55
+ }
56
+ exports.PsScanImageFilterService = PsScanImageFilterService;
@@ -0,0 +1,4 @@
1
+ export declare class PsScanOrderService {
2
+ static move<T>(items: T[], from: number, to: number): T[];
3
+ static step<T>(items: T[], index: number, direction: number): T[];
4
+ }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsScanOrderService = void 0;
4
+ class PsScanOrderService {
5
+ static move(items, from, to) {
6
+ if (from === to || from < 0 || to < 0 || from >= items.length || to >= items.length)
7
+ return items;
8
+ const next = [...items];
9
+ const [item] = next.splice(from, 1);
10
+ next.splice(to, 0, item);
11
+ return next;
12
+ }
13
+ static step(items, index, direction) {
14
+ return PsScanOrderService.move(items, index, index + direction);
15
+ }
16
+ }
17
+ exports.PsScanOrderService = PsScanOrderService;
@@ -0,0 +1,5 @@
1
+ import type { PsScanOutputOptions } from '../models/ps-scan-output-options';
2
+ import type { PsScanPage } from '../models/ps-scan-page';
3
+ export declare class PsScanOutputService {
4
+ static build(pages: PsScanPage[], options: PsScanOutputOptions): Promise<File[]>;
5
+ }
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsScanOutputService = void 0;
4
+ const ps_scan_output_format_1 = require("../constants/ps-scan-output-format");
5
+ const ps_scan_file_name_service_1 = require("./ps-scan-file-name-service");
6
+ const ps_scan_pdf_service_1 = require("./ps-scan-pdf-service");
7
+ const ps_scan_pipeline_service_1 = require("./ps-scan-pipeline-service");
8
+ class PsScanOutputService {
9
+ static async build(pages, options) {
10
+ const rendered = [];
11
+ for (const page of pages)
12
+ rendered.push(await ps_scan_pipeline_service_1.PsScanPipelineService.render(page, options.maxDimension, options.jpegQuality));
13
+ const type = ps_scan_file_name_service_1.PsScanFileNameService.mimeType(options.format);
14
+ if (options.format === ps_scan_output_format_1.PsScanOutputFormat.Jpeg)
15
+ return rendered.map((item, index) => new File([item.blob], ps_scan_file_name_service_1.PsScanFileNameService.build(options.fileName, options.format, index, rendered.length), { type }));
16
+ const jpegs = await Promise.all(rendered.map(async (item) => ({
17
+ height: item.height,
18
+ jpeg: new Uint8Array(await item.blob.arrayBuffer()),
19
+ width: item.width,
20
+ })));
21
+ return [
22
+ new File([ps_scan_pdf_service_1.PsScanPdfService.build(jpegs)], ps_scan_file_name_service_1.PsScanFileNameService.build(options.fileName, options.format, 0, 1), {
23
+ type,
24
+ }),
25
+ ];
26
+ }
27
+ }
28
+ exports.PsScanOutputService = PsScanOutputService;
@@ -0,0 +1,5 @@
1
+ import type { PsScanPdfPage } from '../models/ps-scan-pdf-page';
2
+ export declare class PsScanPdfService {
3
+ static build(pages: PsScanPdfPage[]): Uint8Array<ArrayBuffer>;
4
+ private static points;
5
+ }
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsScanPdfService = void 0;
4
+ const ps_scan_config_1 = require("../constants/ps-scan-config");
5
+ class PsScanPdfService {
6
+ static build(pages) {
7
+ const encoder = new TextEncoder();
8
+ const chunks = [];
9
+ const offsets = [];
10
+ let length = 0;
11
+ const push = (chunk) => {
12
+ chunks.push(chunk);
13
+ length += chunk.length;
14
+ };
15
+ const text = (value) => push(encoder.encode(value));
16
+ const begin = (id) => {
17
+ offsets[id] = length;
18
+ text(`${id} 0 obj\n`);
19
+ };
20
+ const kids = pages.map((_, index) => `${3 + index * 3} 0 R`).join(' ');
21
+ push(Uint8Array.from([
22
+ 0x25, 0x50, 0x44, 0x46, 0x2d, 0x31, 0x2e, 0x34, 0x0a, 0x25, 0xe2, 0xe3, 0xcf, 0xd3, 0x0a,
23
+ ]));
24
+ begin(1);
25
+ text('<< /Type /Catalog /Pages 2 0 R >>\nendobj\n');
26
+ begin(2);
27
+ text(`<< /Type /Pages /Kids [${kids}] /Count ${pages.length} >>\nendobj\n`);
28
+ pages.forEach((page, index) => {
29
+ const pageId = 3 + index * 3;
30
+ const widthPt = PsScanPdfService.points(page.width);
31
+ const heightPt = PsScanPdfService.points(page.height);
32
+ const content = `q ${widthPt} 0 0 ${heightPt} 0 0 cm /Im0 Do Q`;
33
+ begin(pageId);
34
+ text(`<< /Type /Page /Parent 2 0 R /MediaBox [0 0 ${widthPt} ${heightPt}] /Resources << /XObject << /Im0 ${pageId + 2} 0 R >> >> /Contents ${pageId + 1} 0 R >>\nendobj\n`);
35
+ begin(pageId + 1);
36
+ text(`<< /Length ${content.length} >>\nstream\n${content}\nendstream\nendobj\n`);
37
+ begin(pageId + 2);
38
+ text(`<< /Type /XObject /Subtype /Image /Width ${page.width} /Height ${page.height} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /DCTDecode /Length ${page.jpeg.length} >>\nstream\n`);
39
+ push(page.jpeg);
40
+ text('\nendstream\nendobj\n');
41
+ });
42
+ const count = 3 + pages.length * 3;
43
+ const xrefAt = length;
44
+ text(`xref\n0 ${count}\n0000000000 65535 f \n`);
45
+ for (let id = 1; id < count; id += 1)
46
+ text(`${String(offsets[id]).padStart(10, '0')} 00000 n \n`);
47
+ text(`trailer\n<< /Size ${count} /Root 1 0 R >>\nstartxref\n${xrefAt}\n%%EOF\n`);
48
+ const out = new Uint8Array(length);
49
+ let at = 0;
50
+ chunks.forEach((chunk) => {
51
+ out.set(chunk, at);
52
+ at += chunk.length;
53
+ });
54
+ return out;
55
+ }
56
+ static points(pixels) {
57
+ return Math.round((pixels * ps_scan_config_1.PsScanConfig.pdfPointsPerInch * 100) / ps_scan_config_1.PsScanConfig.pdfDpi) / 100;
58
+ }
59
+ }
60
+ exports.PsScanPdfService = PsScanPdfService;
@@ -0,0 +1,10 @@
1
+ import type { PsScanPage } from '../models/ps-scan-page';
2
+ import type { PsScanPrepared } from '../models/ps-scan-prepared';
3
+ import type { PsScanRaster } from '../models/ps-scan-raster';
4
+ import type { PsScanRenderedPage } from '../models/ps-scan-rendered-page';
5
+ export declare class PsScanPipelineService {
6
+ static prepare(source: Blob): Promise<PsScanPrepared>;
7
+ static measure(source: Blob): Promise<PsScanRaster>;
8
+ static process(page: Pick<PsScanPage, 'corners' | 'filter' | 'rotation'>, raster: PsScanRaster, maxDimension: number): PsScanRaster;
9
+ static render(page: PsScanPage, maxDimension: number, quality: number): Promise<PsScanRenderedPage>;
10
+ }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsScanPipelineService = void 0;
4
+ const ps_scan_config_1 = require("../constants/ps-scan-config");
5
+ const ps_scan_canvas_service_1 = require("./ps-scan-canvas-service");
6
+ const ps_scan_edge_service_1 = require("./ps-scan-edge-service");
7
+ const ps_scan_enhance_service_1 = require("./ps-scan-enhance-service");
8
+ const ps_scan_geometry_service_1 = require("./ps-scan-geometry-service");
9
+ const ps_scan_raster_service_1 = require("./ps-scan-raster-service");
10
+ const ps_scan_warp_service_1 = require("./ps-scan-warp-service");
11
+ class PsScanPipelineService {
12
+ static async prepare(source) {
13
+ const decoded = await ps_scan_canvas_service_1.PsScanCanvasService.decode(source, ps_scan_config_1.PsScanConfig.detectMaxDimension * 2);
14
+ const detected = ps_scan_edge_service_1.PsScanEdgeService.detect(decoded.raster);
15
+ return {
16
+ corners: detected === null ? ps_scan_geometry_service_1.PsScanGeometryService.defaultQuad() : detected,
17
+ height: decoded.naturalHeight,
18
+ isDetected: detected !== null,
19
+ width: decoded.naturalWidth,
20
+ };
21
+ }
22
+ static async measure(source) {
23
+ const decoded = await ps_scan_canvas_service_1.PsScanCanvasService.decode(source, ps_scan_config_1.PsScanConfig.previewMaxDimension);
24
+ return decoded.raster;
25
+ }
26
+ static process(page, raster, maxDimension) {
27
+ const size = ps_scan_geometry_service_1.PsScanGeometryService.fitWithin(ps_scan_geometry_service_1.PsScanGeometryService.outputSize(page.corners, raster), maxDimension);
28
+ const warped = ps_scan_warp_service_1.PsScanWarpService.warp(raster, ps_scan_geometry_service_1.PsScanGeometryService.toPixels(page.corners, {
29
+ height: raster.height - 1,
30
+ width: raster.width - 1,
31
+ }), size.width, size.height);
32
+ return ps_scan_raster_service_1.PsScanRasterService.rotate(ps_scan_enhance_service_1.PsScanEnhanceService.apply(warped, page.filter), page.rotation);
33
+ }
34
+ static async render(page, maxDimension, quality) {
35
+ const decoded = await ps_scan_canvas_service_1.PsScanCanvasService.decode(page.source, ps_scan_config_1.PsScanConfig.decodeMaxDimension);
36
+ const raster = PsScanPipelineService.process(page, decoded.raster, maxDimension);
37
+ return {
38
+ blob: await ps_scan_canvas_service_1.PsScanCanvasService.encode(raster, quality),
39
+ height: raster.height,
40
+ width: raster.width,
41
+ };
42
+ }
43
+ }
44
+ exports.PsScanPipelineService = PsScanPipelineService;
@@ -0,0 +1,4 @@
1
+ import { PsScanPlatform } from '../constants/ps-scan-platform';
2
+ export declare class PsScanPlatformService {
3
+ static detect(): PsScanPlatform;
4
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsScanPlatformService = void 0;
4
+ const ps_scan_platform_1 = require("../constants/ps-scan-platform");
5
+ class PsScanPlatformService {
6
+ static detect() {
7
+ if (typeof navigator === 'undefined')
8
+ return ps_scan_platform_1.PsScanPlatform.Desktop;
9
+ const agent = navigator.userAgent;
10
+ if (/iPhone|iPad|iPod/i.test(agent))
11
+ return ps_scan_platform_1.PsScanPlatform.Ios;
12
+ if (/Macintosh/i.test(agent) && navigator.maxTouchPoints > 1)
13
+ return ps_scan_platform_1.PsScanPlatform.Ios;
14
+ if (/Android/i.test(agent))
15
+ return ps_scan_platform_1.PsScanPlatform.Android;
16
+ return ps_scan_platform_1.PsScanPlatform.Desktop;
17
+ }
18
+ }
19
+ exports.PsScanPlatformService = PsScanPlatformService;
@@ -0,0 +1,6 @@
1
+ import type { PsScanRaster } from '../models/ps-scan-raster';
2
+ export declare class PsScanRasterService {
3
+ static create(width: number, height: number): PsScanRaster;
4
+ static resize(source: PsScanRaster, width: number, height: number): PsScanRaster;
5
+ static rotate(source: PsScanRaster, degrees: number): PsScanRaster;
6
+ }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsScanRasterService = void 0;
4
+ class PsScanRasterService {
5
+ static create(width, height) {
6
+ return { data: new Uint8ClampedArray(width * height * 4), height, width };
7
+ }
8
+ static resize(source, width, height) {
9
+ if (width === source.width && height === source.height)
10
+ return source;
11
+ const target = PsScanRasterService.create(width, height);
12
+ const scaleX = source.width / width;
13
+ const scaleY = source.height / height;
14
+ for (let y = 0; y < height; y += 1) {
15
+ const y0 = Math.floor(y * scaleY);
16
+ const y1 = Math.min(source.height, Math.max(y0 + 1, Math.ceil((y + 1) * scaleY)));
17
+ for (let x = 0; x < width; x += 1) {
18
+ const x0 = Math.floor(x * scaleX);
19
+ const x1 = Math.min(source.width, Math.max(x0 + 1, Math.ceil((x + 1) * scaleX)));
20
+ let r = 0;
21
+ let g = 0;
22
+ let b = 0;
23
+ let a = 0;
24
+ let count = 0;
25
+ for (let sy = y0; sy < y1; sy += 1)
26
+ for (let sx = x0; sx < x1; sx += 1) {
27
+ const at = (sy * source.width + sx) * 4;
28
+ r += source.data[at];
29
+ g += source.data[at + 1];
30
+ b += source.data[at + 2];
31
+ a += source.data[at + 3];
32
+ count += 1;
33
+ }
34
+ const out = (y * width + x) * 4;
35
+ target.data[out] = r / count;
36
+ target.data[out + 1] = g / count;
37
+ target.data[out + 2] = b / count;
38
+ target.data[out + 3] = a / count;
39
+ }
40
+ }
41
+ return target;
42
+ }
43
+ static rotate(source, degrees) {
44
+ const turns = ((Math.round(degrees / 90) % 4) + 4) % 4;
45
+ if (turns === 0)
46
+ return source;
47
+ const swapped = turns % 2 === 1;
48
+ const width = swapped ? source.height : source.width;
49
+ const height = swapped ? source.width : source.height;
50
+ const target = PsScanRasterService.create(width, height);
51
+ for (let y = 0; y < source.height; y += 1)
52
+ for (let x = 0; x < source.width; x += 1) {
53
+ let tx = x;
54
+ let ty = y;
55
+ if (turns === 1)
56
+ [tx, ty] = [source.height - 1 - y, x];
57
+ else if (turns === 2)
58
+ [tx, ty] = [source.width - 1 - x, source.height - 1 - y];
59
+ else
60
+ [tx, ty] = [y, source.width - 1 - x];
61
+ const from = (y * source.width + x) * 4;
62
+ const to = (ty * width + tx) * 4;
63
+ target.data[to] = source.data[from];
64
+ target.data[to + 1] = source.data[from + 1];
65
+ target.data[to + 2] = source.data[from + 2];
66
+ target.data[to + 3] = source.data[from + 3];
67
+ }
68
+ return target;
69
+ }
70
+ }
71
+ exports.PsScanRasterService = PsScanRasterService;
@@ -0,0 +1,9 @@
1
+ import type { PsScanQuad } from '../models/ps-scan-quad';
2
+ import type { PsScanStability } from '../models/ps-scan-stability';
3
+ export declare class PsScanStabilityService {
4
+ static disarm(state: PsScanStability): PsScanStability;
5
+ static initial(): PsScanStability;
6
+ static movement(from: PsScanQuad, to: PsScanQuad): number;
7
+ static next(state: PsScanStability, detected: PsScanQuad | null, elapsedMs: number): PsScanStability;
8
+ static progress(state: PsScanStability): number;
9
+ }
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsScanStabilityService = void 0;
4
+ const ps_scan_config_1 = require("../constants/ps-scan-config");
5
+ const ps_scan_geometry_service_1 = require("./ps-scan-geometry-service");
6
+ class PsScanStabilityService {
7
+ static disarm(state) {
8
+ return { ...state, isArmed: false, stableMs: 0 };
9
+ }
10
+ static initial() {
11
+ return { isArmed: true, misses: 0, quad: null, raw: null, stableMs: 0 };
12
+ }
13
+ static movement(from, to) {
14
+ return Math.max(...from.map((point, index) => ps_scan_geometry_service_1.PsScanGeometryService.distance(point, to[index])));
15
+ }
16
+ static next(state, detected, elapsedMs) {
17
+ if (detected === null) {
18
+ const misses = state.misses + 1;
19
+ return misses > ps_scan_config_1.PsScanConfig.liveMissLimit
20
+ ? { isArmed: true, misses, quad: null, raw: null, stableMs: 0 }
21
+ : { ...state, misses, stableMs: 0 };
22
+ }
23
+ if (state.quad === null || state.raw === null)
24
+ return { ...state, misses: 0, quad: detected, raw: detected, stableMs: 0 };
25
+ const movement = PsScanStabilityService.movement(state.raw, detected);
26
+ const weight = ps_scan_config_1.PsScanConfig.liveSmoothing;
27
+ const quad = state.quad.map((point, index) => ({
28
+ x: point.x + (detected[index].x - point.x) * weight,
29
+ y: point.y + (detected[index].y - point.y) * weight,
30
+ }));
31
+ return {
32
+ isArmed: state.isArmed || movement > ps_scan_config_1.PsScanConfig.liveRearmMovement,
33
+ misses: 0,
34
+ quad,
35
+ raw: detected,
36
+ stableMs: movement <= ps_scan_config_1.PsScanConfig.liveStillMovement ? state.stableMs + elapsedMs : 0,
37
+ };
38
+ }
39
+ static progress(state) {
40
+ if (!state.isArmed || state.quad === null)
41
+ return 0;
42
+ return Math.min(1, state.stableMs / ps_scan_config_1.PsScanConfig.autoCaptureMs);
43
+ }
44
+ }
45
+ exports.PsScanStabilityService = PsScanStabilityService;