@pallasoft/ps-file-components 1.4.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 (194) 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 +64 -86
  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-file-picker-actions.d.ts +10 -0
  7. package/dist/components/ps-file-picker-actions.js +21 -0
  8. package/dist/components/ps-file-picker.d.ts +7 -1
  9. package/dist/components/ps-file-picker.js +30 -6
  10. package/dist/components/ps-scan-button.d.ts +13 -0
  11. package/dist/components/ps-scan-button.js +9 -0
  12. package/dist/components/ps-scan-camera-view.d.ts +11 -8
  13. package/dist/components/ps-scan-camera-view.js +14 -16
  14. package/dist/components/ps-scan-crop-editor.d.ts +4 -4
  15. package/dist/components/ps-scan-crop-editor.js +24 -8
  16. package/dist/components/ps-scan-denied-steps.d.ts +6 -0
  17. package/dist/components/ps-scan-denied-steps.js +33 -0
  18. package/dist/components/ps-scan-icon-button.d.ts +4 -3
  19. package/dist/components/ps-scan-icon-button.js +3 -1
  20. package/dist/components/ps-scan-illustration.d.ts +1 -0
  21. package/dist/components/ps-scan-illustration.js +6 -0
  22. package/dist/components/ps-scan-loupe.d.ts +10 -0
  23. package/dist/components/ps-scan-loupe.js +31 -0
  24. package/dist/components/ps-scan-permission-view.d.ts +10 -0
  25. package/dist/components/ps-scan-permission-view.js +48 -0
  26. package/dist/components/ps-scan-photo-button.d.ts +7 -0
  27. package/dist/components/ps-scan-photo-button.js +20 -0
  28. package/dist/components/ps-scan-preview.d.ts +12 -0
  29. package/dist/components/ps-scan-preview.js +10 -0
  30. package/dist/components/ps-scan-shutter.d.ts +6 -0
  31. package/dist/components/ps-scan-shutter.js +6 -0
  32. package/dist/components/ps-scan-viewfinder-overlay.d.ts +8 -0
  33. package/dist/components/ps-scan-viewfinder-overlay.js +28 -0
  34. package/dist/components/ps-upload-row.js +1 -1
  35. package/dist/constants/ps-document-scanner-labels.d.ts +39 -38
  36. package/dist/constants/ps-document-scanner-labels.js +39 -38
  37. package/dist/constants/ps-file-picker-labels.d.ts +5 -3
  38. package/dist/constants/ps-file-picker-labels.js +5 -3
  39. package/dist/constants/ps-scan-camera-status.d.ts +4 -0
  40. package/dist/constants/ps-scan-camera-status.js +4 -0
  41. package/dist/constants/ps-scan-chrome-classes.d.ts +10 -0
  42. package/dist/constants/ps-scan-chrome-classes.js +13 -0
  43. package/dist/constants/ps-scan-config.d.ts +34 -24
  44. package/dist/constants/ps-scan-config.js +34 -24
  45. package/dist/constants/ps-scan-platform.d.ts +6 -0
  46. package/dist/constants/ps-scan-platform.js +8 -0
  47. package/dist/constants/ps-scan-step.d.ts +1 -1
  48. package/dist/constants/ps-scan-step.js +1 -1
  49. package/dist/esm/components/ps-document-scanner-sheet.js +67 -89
  50. package/dist/esm/components/ps-document-scanner.js +2 -3
  51. package/dist/esm/components/ps-file-picker-actions.js +17 -0
  52. package/dist/esm/components/ps-file-picker.js +31 -7
  53. package/dist/esm/components/ps-scan-button.js +5 -0
  54. package/dist/esm/components/ps-scan-camera-view.js +17 -19
  55. package/dist/esm/components/ps-scan-crop-editor.js +26 -10
  56. package/dist/esm/components/ps-scan-denied-steps.js +29 -0
  57. package/dist/esm/components/ps-scan-icon-button.js +3 -1
  58. package/dist/esm/components/ps-scan-illustration.js +2 -0
  59. package/dist/esm/components/ps-scan-loupe.js +27 -0
  60. package/dist/esm/components/ps-scan-permission-view.js +44 -0
  61. package/dist/esm/components/ps-scan-photo-button.js +16 -0
  62. package/dist/esm/components/ps-scan-preview.js +6 -0
  63. package/dist/esm/components/ps-scan-shutter.js +2 -0
  64. package/dist/esm/components/ps-scan-viewfinder-overlay.js +24 -0
  65. package/dist/esm/components/ps-upload-row.js +1 -1
  66. package/dist/esm/constants/ps-document-scanner-labels.js +39 -38
  67. package/dist/esm/constants/ps-file-picker-labels.js +5 -3
  68. package/dist/esm/constants/ps-scan-camera-status.js +4 -0
  69. package/dist/esm/constants/ps-scan-chrome-classes.js +10 -0
  70. package/dist/esm/constants/ps-scan-config.js +34 -24
  71. package/dist/esm/constants/ps-scan-platform.js +5 -0
  72. package/dist/esm/constants/ps-scan-step.js +1 -1
  73. package/dist/esm/hooks/use-ps-scan-camera.js +52 -15
  74. package/dist/esm/hooks/use-ps-scan-live-detection.js +41 -0
  75. package/dist/esm/hooks/use-ps-scan-photo.js +42 -0
  76. package/dist/esm/index.js +1 -2
  77. package/dist/esm/models/ps-scan-region.js +1 -0
  78. package/dist/esm/models/ps-scan-result.js +1 -0
  79. package/dist/esm/models/ps-scan-stability.js +1 -0
  80. package/dist/esm/services/ps-scan-camera-service.js +52 -7
  81. package/dist/esm/services/ps-scan-canny-service.js +93 -0
  82. package/dist/esm/services/ps-scan-canvas-service.js +13 -1
  83. package/dist/esm/services/ps-scan-edge-service.js +73 -137
  84. package/dist/esm/services/ps-scan-file-name-service.js +2 -11
  85. package/dist/esm/services/ps-scan-geometry-service.js +56 -0
  86. package/dist/esm/services/ps-scan-hull-service.js +0 -39
  87. package/dist/esm/services/ps-scan-image-filter-service.js +0 -21
  88. package/dist/esm/services/ps-scan-morphology-service.js +44 -0
  89. package/dist/esm/services/ps-scan-pipeline-service.js +9 -19
  90. package/dist/esm/services/ps-scan-platform-service.js +15 -0
  91. package/dist/esm/services/ps-scan-polygon-service.js +75 -0
  92. package/dist/esm/services/ps-scan-region-service.js +52 -0
  93. package/dist/esm/services/ps-scan-stability-service.js +28 -0
  94. package/dist/esm/services/ps-scan-warp-service.js +8 -2
  95. package/dist/esm/services/ps-scan-yield-service.js +5 -0
  96. package/dist/hooks/use-ps-scan-camera.d.ts +3 -1
  97. package/dist/hooks/use-ps-scan-camera.js +52 -15
  98. package/dist/hooks/use-ps-scan-live-detection.d.ts +3 -0
  99. package/dist/hooks/use-ps-scan-live-detection.js +45 -0
  100. package/dist/hooks/use-ps-scan-photo.d.ts +9 -0
  101. package/dist/hooks/use-ps-scan-photo.js +46 -0
  102. package/dist/index.d.ts +1 -2
  103. package/dist/index.js +1 -2
  104. package/dist/models/ps-document-scanner-props.d.ts +0 -3
  105. package/dist/models/ps-document-scanner-sheet-props.d.ts +0 -3
  106. package/dist/models/ps-file-picker-scan.d.ts +4 -0
  107. package/dist/models/ps-scan-gradient.d.ts +4 -0
  108. package/dist/models/ps-scan-live-detection.d.ts +4 -0
  109. package/dist/models/ps-scan-located.d.ts +5 -0
  110. package/dist/models/ps-scan-photo.d.ts +9 -0
  111. package/dist/models/ps-scan-region.d.ts +5 -0
  112. package/dist/models/ps-scan-region.js +2 -0
  113. package/dist/models/ps-scan-result.d.ts +6 -0
  114. package/dist/models/ps-scan-result.js +2 -0
  115. package/dist/models/ps-scan-stability.d.ts +5 -0
  116. package/dist/models/ps-scan-stability.js +2 -0
  117. package/dist/services/ps-scan-camera-service.d.ts +4 -0
  118. package/dist/services/ps-scan-camera-service.js +52 -7
  119. package/dist/services/ps-scan-canny-service.d.ts +7 -0
  120. package/dist/services/ps-scan-canny-service.js +97 -0
  121. package/dist/services/ps-scan-canvas-service.d.ts +1 -0
  122. package/dist/services/ps-scan-canvas-service.js +13 -1
  123. package/dist/services/ps-scan-edge-service.d.ts +5 -5
  124. package/dist/services/ps-scan-edge-service.js +73 -137
  125. package/dist/services/ps-scan-file-name-service.d.ts +1 -3
  126. package/dist/services/ps-scan-file-name-service.js +2 -11
  127. package/dist/services/ps-scan-geometry-service.d.ts +4 -0
  128. package/dist/services/ps-scan-geometry-service.js +56 -0
  129. package/dist/services/ps-scan-hull-service.d.ts +0 -2
  130. package/dist/services/ps-scan-hull-service.js +0 -39
  131. package/dist/services/ps-scan-image-filter-service.d.ts +0 -1
  132. package/dist/services/ps-scan-image-filter-service.js +0 -21
  133. package/dist/services/ps-scan-morphology-service.d.ts +7 -0
  134. package/dist/services/ps-scan-morphology-service.js +48 -0
  135. package/dist/services/ps-scan-pipeline-service.d.ts +2 -5
  136. package/dist/services/ps-scan-pipeline-service.js +9 -19
  137. package/dist/services/ps-scan-platform-service.d.ts +4 -0
  138. package/dist/services/ps-scan-platform-service.js +19 -0
  139. package/dist/services/ps-scan-polygon-service.d.ts +8 -0
  140. package/dist/services/ps-scan-polygon-service.js +79 -0
  141. package/dist/services/ps-scan-region-service.d.ts +4 -0
  142. package/dist/services/ps-scan-region-service.js +56 -0
  143. package/dist/services/ps-scan-stability-service.d.ts +7 -0
  144. package/dist/services/ps-scan-stability-service.js +32 -0
  145. package/dist/services/ps-scan-warp-service.d.ts +1 -1
  146. package/dist/services/ps-scan-warp-service.js +8 -2
  147. package/dist/services/ps-scan-yield-service.d.ts +3 -0
  148. package/dist/services/ps-scan-yield-service.js +9 -0
  149. package/package.json +3 -3
  150. package/dist/components/ps-scan-page-list.d.ts +0 -12
  151. package/dist/components/ps-scan-page-list.js +0 -23
  152. package/dist/components/ps-scan-review.d.ts +0 -23
  153. package/dist/components/ps-scan-review.js +0 -20
  154. package/dist/constants/ps-scan-filter.d.ts +0 -7
  155. package/dist/constants/ps-scan-filter.js +0 -9
  156. package/dist/constants/ps-scan-output-format.d.ts +0 -5
  157. package/dist/constants/ps-scan-output-format.js +0 -7
  158. package/dist/esm/components/ps-scan-page-list.js +0 -19
  159. package/dist/esm/components/ps-scan-review.js +0 -16
  160. package/dist/esm/constants/ps-scan-filter.js +0 -6
  161. package/dist/esm/constants/ps-scan-output-format.js +0 -4
  162. package/dist/esm/hooks/use-ps-scan-pages.js +0 -62
  163. package/dist/esm/hooks/use-ps-scan-previews.js +0 -57
  164. package/dist/esm/services/ps-scan-enhance-service.js +0 -97
  165. package/dist/esm/services/ps-scan-order-service.js +0 -13
  166. package/dist/esm/services/ps-scan-output-service.js +0 -24
  167. package/dist/esm/services/ps-scan-pdf-service.js +0 -56
  168. package/dist/hooks/use-ps-scan-pages.d.ts +0 -12
  169. package/dist/hooks/use-ps-scan-pages.js +0 -66
  170. package/dist/hooks/use-ps-scan-previews.d.ts +0 -2
  171. package/dist/hooks/use-ps-scan-previews.js +0 -61
  172. package/dist/models/ps-scan-added-page.d.ts +0 -5
  173. package/dist/models/ps-scan-levels.d.ts +0 -4
  174. package/dist/models/ps-scan-output-options.d.ts +0 -7
  175. package/dist/models/ps-scan-page.d.ts +0 -12
  176. package/dist/models/ps-scan-pdf-page.d.ts +0 -5
  177. package/dist/services/ps-scan-enhance-service.d.ts +0 -9
  178. package/dist/services/ps-scan-enhance-service.js +0 -101
  179. package/dist/services/ps-scan-order-service.d.ts +0 -4
  180. package/dist/services/ps-scan-order-service.js +0 -17
  181. package/dist/services/ps-scan-output-service.d.ts +0 -5
  182. package/dist/services/ps-scan-output-service.js +0 -28
  183. package/dist/services/ps-scan-pdf-service.d.ts +0 -5
  184. package/dist/services/ps-scan-pdf-service.js +0 -60
  185. /package/dist/esm/models/{ps-scan-added-page.js → ps-file-picker-scan.js} +0 -0
  186. /package/dist/esm/models/{ps-scan-levels.js → ps-scan-gradient.js} +0 -0
  187. /package/dist/esm/models/{ps-scan-output-options.js → ps-scan-live-detection.js} +0 -0
  188. /package/dist/esm/models/{ps-scan-page.js → ps-scan-located.js} +0 -0
  189. /package/dist/esm/models/{ps-scan-pdf-page.js → ps-scan-photo.js} +0 -0
  190. /package/dist/models/{ps-scan-added-page.js → ps-file-picker-scan.js} +0 -0
  191. /package/dist/models/{ps-scan-levels.js → ps-scan-gradient.js} +0 -0
  192. /package/dist/models/{ps-scan-output-options.js → ps-scan-live-detection.js} +0 -0
  193. /package/dist/models/{ps-scan-page.js → ps-scan-located.js} +0 -0
  194. /package/dist/models/{ps-scan-pdf-page.js → ps-scan-photo.js} +0 -0
@@ -1,23 +0,0 @@
1
- import { PsDocumentScannerLabels } from '../constants/ps-document-scanner-labels';
2
- import { PsScanFilter } from '../constants/ps-scan-filter';
3
- import type { PsLabelSet } from '../models/ps-label-set';
4
- import type { PsScanPage } from '../models/ps-scan-page';
5
- export interface PsScanReviewProps {
6
- canAddPage: boolean;
7
- error: string;
8
- isBusy: boolean;
9
- labels: PsLabelSet<typeof PsDocumentScannerLabels>;
10
- onAddPage: () => void;
11
- onDelete: () => void;
12
- onEditCrop: () => void;
13
- onFilter: (filter: PsScanFilter) => void;
14
- onFinish: () => void;
15
- onMove: (from: number, to: number) => void;
16
- onRetake: () => void;
17
- onRotate: () => void;
18
- onSelect: (id: string) => void;
19
- page: PsScanPage;
20
- pages: PsScanPage[];
21
- previews: Record<string, string>;
22
- }
23
- export declare const PsScanReview: ({ canAddPage, error, isBusy, labels, onAddPage, onDelete, onEditCrop, onFilter, onFinish, onMove, onRetake, onRotate, onSelect, page, pages, previews, }: PsScanReviewProps) => import("react").JSX.Element;
@@ -1,20 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PsScanReview = void 0;
4
- const jsx_runtime_1 = require("react/jsx-runtime");
5
- const ps_core_components_1 = require("@pallasoft/ps-core-components");
6
- const ps_icons_1 = require("@pallasoft/ps-icons");
7
- const ps_scan_filter_1 = require("../constants/ps-scan-filter");
8
- const ps_scan_icon_button_1 = require("./ps-scan-icon-button");
9
- const ps_scan_page_list_1 = require("./ps-scan-page-list");
10
- const PsScanReview = ({ canAddPage, error, isBusy, labels, onAddPage, onDelete, onEditCrop, onFilter, onFinish, onMove, onRetake, onRotate, onSelect, page, pages, previews, }) => {
11
- const filters = [
12
- { key: ps_scan_filter_1.PsScanFilter.Original, label: labels.filterOriginal },
13
- { key: ps_scan_filter_1.PsScanFilter.Colour, label: labels.filterColour },
14
- { key: ps_scan_filter_1.PsScanFilter.Greyscale, label: labels.filterGreyscale },
15
- { key: ps_scan_filter_1.PsScanFilter.Document, label: labels.filterDocument },
16
- ];
17
- const preview = previews[page.id];
18
- return ((0, jsx_runtime_1.jsxs)("div", { className: 'flex h-full min-h-0 flex-col lg:flex-row', children: [(0, jsx_runtime_1.jsx)("div", { className: 'flex min-h-0 flex-1 items-center justify-center bg-slate-950 p-3', children: preview === undefined ? ((0, jsx_runtime_1.jsx)("span", { "aria-hidden": 'true', className: 'ps-skeleton h-full w-2/3 rounded' })) : ((0, jsx_runtime_1.jsx)("img", { alt: labels.page, className: 'max-h-full max-w-full object-contain', src: preview })) }), (0, jsx_runtime_1.jsxs)("div", { className: 'flex max-h-[55%] min-h-0 shrink-0 flex-col gap-3 overflow-y-auto bg-surface px-4 pt-3 lg:max-h-none lg:w-80 lg:border-l lg:border-line', children: [(0, jsx_runtime_1.jsxs)("div", { className: 'flex flex-wrap items-center gap-2', children: [(0, jsx_runtime_1.jsx)(ps_scan_icon_button_1.PsScanIconButton, { label: labels.rotate, onClick: onRotate, children: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-5', iconKey: ps_icons_1.PsIconKey.Rotate }) }), (0, jsx_runtime_1.jsx)(ps_scan_icon_button_1.PsScanIconButton, { label: labels.editCrop, onClick: onEditCrop, children: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-5', iconKey: ps_icons_1.PsIconKey.Pencil }) }), (0, jsx_runtime_1.jsx)(ps_scan_icon_button_1.PsScanIconButton, { label: labels.retake, onClick: onRetake, children: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-5', iconKey: ps_icons_1.PsIconKey.Refresh }) }), (0, jsx_runtime_1.jsx)(ps_scan_icon_button_1.PsScanIconButton, { label: labels.deletePage, onClick: onDelete, children: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-5', iconKey: ps_icons_1.PsIconKey.Trash }) })] }), (0, jsx_runtime_1.jsx)("div", { "aria-label": labels.filters, className: 'flex flex-wrap gap-2', role: 'group', children: filters.map((filter) => ((0, jsx_runtime_1.jsx)("button", { "aria-pressed": page.filter === filter.key, className: `ps-focus-ring min-h-11 rounded-ps-control border px-3 text-sm font-medium transition ${page.filter === filter.key ? 'border-primary bg-primary-soft text-primary' : 'border-line bg-surface text-ink hover:border-primary/40'}`, onClick: () => onFilter(filter.key), type: 'button', children: filter.label }, filter.key))) }), (0, jsx_runtime_1.jsxs)("section", { "aria-label": labels.pages, className: 'min-h-0', children: [(0, jsx_runtime_1.jsxs)("h3", { className: 'mb-2 text-sm font-semibold text-ink', children: [labels.pages, " (", pages.length, ")"] }), (0, jsx_runtime_1.jsx)(ps_scan_page_list_1.PsScanPageList, { activeId: page.id, labels: labels, onMove: onMove, onSelect: onSelect, pages: pages, previews: previews })] }), error === '' ? null : ((0, jsx_runtime_1.jsx)("p", { className: 'text-sm text-danger', role: 'alert', children: error })), (0, jsx_runtime_1.jsxs)("div", { className: 'sticky bottom-0 mt-auto flex flex-wrap gap-3 bg-surface pt-2 pb-[max(0.75rem,env(safe-area-inset-bottom))]', children: [(0, jsx_runtime_1.jsx)(ps_core_components_1.PsButton, { className: 'flex-1', disabled: !canAddPage || isBusy, leadingIcon: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-4', iconKey: ps_icons_1.PsIconKey.Plus }), onClick: onAddPage, variant: 'surface', children: labels.addPage }), (0, jsx_runtime_1.jsx)(ps_core_components_1.PsButton, { className: 'flex-1', isLoading: isBusy, loadingLabel: labels.finishing, onClick: onFinish, variant: 'primary', children: labels.finish })] })] })] }));
19
- };
20
- exports.PsScanReview = PsScanReview;
@@ -1,7 +0,0 @@
1
- export declare const PsScanFilter: {
2
- readonly Colour: "colour";
3
- readonly Document: "document";
4
- readonly Greyscale: "greyscale";
5
- readonly Original: "original";
6
- };
7
- export type PsScanFilter = (typeof PsScanFilter)[keyof typeof PsScanFilter];
@@ -1,9 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PsScanFilter = void 0;
4
- exports.PsScanFilter = {
5
- Colour: 'colour',
6
- Document: 'document',
7
- Greyscale: 'greyscale',
8
- Original: 'original',
9
- };
@@ -1,5 +0,0 @@
1
- export declare const PsScanOutputFormat: {
2
- readonly Jpeg: "jpeg";
3
- readonly Pdf: "pdf";
4
- };
5
- export type PsScanOutputFormat = (typeof PsScanOutputFormat)[keyof typeof PsScanOutputFormat];
@@ -1,7 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PsScanOutputFormat = void 0;
4
- exports.PsScanOutputFormat = {
5
- Jpeg: 'jpeg',
6
- Pdf: 'pdf',
7
- };
@@ -1,19 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { PsSortableList } from '@pallasoft/ps-core-components';
3
- import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
4
- import { PsIcon, PsIconKey } from '@pallasoft/ps-icons';
5
- import { PsScanTemplateService } from '../services/ps-scan-template-service';
6
- import { PsScanIconButton } from './ps-scan-icon-button';
7
- export const PsScanPageList = ({ activeId, labels, onMove, onSelect, pages, previews, }) => {
8
- const items = pages.map((page, index) => ({
9
- id: page.id,
10
- label: `${labels.page} ${index + 1}`,
11
- }));
12
- const say = (template, label, position) => PsScanTemplateService.fill(template, { count: pages.length, page: label, position });
13
- return (_jsx(PsSortableList, { announcements: {
14
- cancelled: (label) => say(labels.reorderCancelled, label, 0),
15
- dropped: (label, position) => say(labels.reorderDropped, label, position),
16
- lifted: (label, position) => say(labels.reorderLifted, label, position),
17
- moved: (label, position) => say(labels.reorderMoved, label, position),
18
- }, className: 'flex flex-col gap-2', getHandleLabel: (label) => PsScanTemplateService.fill(labels.dragPage, { page: label }), instructions: labels.reorderInstructions, items: items, onMove: (_id, from, to) => onMove(from, to), renderItem: ({ handle, index, isDragging, item }) => (_jsxs("div", { className: PallasoftClassNameService.merge('flex items-center gap-2 rounded-ps-control border bg-surface p-1.5', item.id === activeId ? 'border-primary' : 'border-line', isDragging ? 'opacity-80 shadow-lg' : ''), children: [handle, _jsxs("button", { "aria-current": item.id === activeId, "aria-label": item.label, className: 'ps-focus-ring flex min-h-11 min-w-0 flex-1 items-center gap-3 rounded-ps-control text-left', onClick: () => onSelect(item.id), type: 'button', children: [previews[item.id] === undefined ? (_jsx("span", { className: 'ps-skeleton h-14 w-10 shrink-0 rounded' })) : (_jsx("img", { alt: '', className: 'h-14 w-10 shrink-0 rounded border border-line bg-white object-cover object-top', src: previews[item.id] })), _jsx("span", { className: 'truncate text-sm font-medium text-ink', children: item.label })] }), _jsx(PsScanIconButton, { disabled: index === 0, label: PsScanTemplateService.fill(labels.moveUp, { page: item.label }), onClick: () => onMove(index, index - 1), children: _jsx(PsIcon, { "aria-hidden": 'true', className: 'size-5 -rotate-90', iconKey: PsIconKey.ChevronRight }) }), _jsx(PsScanIconButton, { disabled: index === pages.length - 1, label: PsScanTemplateService.fill(labels.moveDown, { page: item.label }), onClick: () => onMove(index, index + 1), children: _jsx(PsIcon, { "aria-hidden": 'true', className: 'size-5 rotate-90', iconKey: PsIconKey.ChevronRight }) })] })), role: 'list' }));
19
- };
@@ -1,16 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { PsButton } from '@pallasoft/ps-core-components';
3
- import { PsIcon, PsIconKey } from '@pallasoft/ps-icons';
4
- import { PsScanFilter } from '../constants/ps-scan-filter';
5
- import { PsScanIconButton } from './ps-scan-icon-button';
6
- import { PsScanPageList } from './ps-scan-page-list';
7
- export const PsScanReview = ({ canAddPage, error, isBusy, labels, onAddPage, onDelete, onEditCrop, onFilter, onFinish, onMove, onRetake, onRotate, onSelect, page, pages, previews, }) => {
8
- const filters = [
9
- { key: PsScanFilter.Original, label: labels.filterOriginal },
10
- { key: PsScanFilter.Colour, label: labels.filterColour },
11
- { key: PsScanFilter.Greyscale, label: labels.filterGreyscale },
12
- { key: PsScanFilter.Document, label: labels.filterDocument },
13
- ];
14
- const preview = previews[page.id];
15
- return (_jsxs("div", { className: 'flex h-full min-h-0 flex-col lg:flex-row', children: [_jsx("div", { className: 'flex min-h-0 flex-1 items-center justify-center bg-slate-950 p-3', children: preview === undefined ? (_jsx("span", { "aria-hidden": 'true', className: 'ps-skeleton h-full w-2/3 rounded' })) : (_jsx("img", { alt: labels.page, className: 'max-h-full max-w-full object-contain', src: preview })) }), _jsxs("div", { className: 'flex max-h-[55%] min-h-0 shrink-0 flex-col gap-3 overflow-y-auto bg-surface px-4 pt-3 lg:max-h-none lg:w-80 lg:border-l lg:border-line', children: [_jsxs("div", { className: 'flex flex-wrap items-center gap-2', children: [_jsx(PsScanIconButton, { label: labels.rotate, onClick: onRotate, children: _jsx(PsIcon, { "aria-hidden": 'true', className: 'size-5', iconKey: PsIconKey.Rotate }) }), _jsx(PsScanIconButton, { label: labels.editCrop, onClick: onEditCrop, children: _jsx(PsIcon, { "aria-hidden": 'true', className: 'size-5', iconKey: PsIconKey.Pencil }) }), _jsx(PsScanIconButton, { label: labels.retake, onClick: onRetake, children: _jsx(PsIcon, { "aria-hidden": 'true', className: 'size-5', iconKey: PsIconKey.Refresh }) }), _jsx(PsScanIconButton, { label: labels.deletePage, onClick: onDelete, children: _jsx(PsIcon, { "aria-hidden": 'true', className: 'size-5', iconKey: PsIconKey.Trash }) })] }), _jsx("div", { "aria-label": labels.filters, className: 'flex flex-wrap gap-2', role: 'group', children: filters.map((filter) => (_jsx("button", { "aria-pressed": page.filter === filter.key, className: `ps-focus-ring min-h-11 rounded-ps-control border px-3 text-sm font-medium transition ${page.filter === filter.key ? 'border-primary bg-primary-soft text-primary' : 'border-line bg-surface text-ink hover:border-primary/40'}`, onClick: () => onFilter(filter.key), type: 'button', children: filter.label }, filter.key))) }), _jsxs("section", { "aria-label": labels.pages, className: 'min-h-0', children: [_jsxs("h3", { className: 'mb-2 text-sm font-semibold text-ink', children: [labels.pages, " (", pages.length, ")"] }), _jsx(PsScanPageList, { activeId: page.id, labels: labels, onMove: onMove, onSelect: onSelect, pages: pages, previews: previews })] }), error === '' ? null : (_jsx("p", { className: 'text-sm text-danger', role: 'alert', children: error })), _jsxs("div", { className: 'sticky bottom-0 mt-auto flex flex-wrap gap-3 bg-surface pt-2 pb-[max(0.75rem,env(safe-area-inset-bottom))]', children: [_jsx(PsButton, { className: 'flex-1', disabled: !canAddPage || isBusy, leadingIcon: _jsx(PsIcon, { "aria-hidden": 'true', className: 'size-4', iconKey: PsIconKey.Plus }), onClick: onAddPage, variant: 'surface', children: labels.addPage }), _jsx(PsButton, { className: 'flex-1', isLoading: isBusy, loadingLabel: labels.finishing, onClick: onFinish, variant: 'primary', children: labels.finish })] })] })] }));
16
- };
@@ -1,6 +0,0 @@
1
- export const PsScanFilter = {
2
- Colour: 'colour',
3
- Document: 'document',
4
- Greyscale: 'greyscale',
5
- Original: 'original',
6
- };
@@ -1,4 +0,0 @@
1
- export const PsScanOutputFormat = {
2
- Jpeg: 'jpeg',
3
- Pdf: 'pdf',
4
- };
@@ -1,62 +0,0 @@
1
- import { useCallback, useEffect, useRef, useState } from 'react';
2
- import { PsScanFilter } from '../constants/ps-scan-filter';
3
- import { PsScanOrderService } from '../services/ps-scan-order-service';
4
- import { PsScanPipelineService } from '../services/ps-scan-pipeline-service';
5
- export const usePsScanPages = () => {
6
- const [pages, setPages] = useState([]);
7
- const urls = useRef(new Set());
8
- const counter = useRef(0);
9
- useEffect(() => () => {
10
- urls.current.forEach((url) => URL.revokeObjectURL(url));
11
- urls.current.clear();
12
- }, []);
13
- const build = useCallback(async (source) => {
14
- const prepared = await PsScanPipelineService.prepare(source);
15
- const sourceUrl = URL.createObjectURL(source);
16
- counter.current += 1;
17
- urls.current.add(sourceUrl);
18
- return {
19
- isDetected: prepared.isDetected,
20
- page: {
21
- corners: prepared.corners,
22
- filter: PsScanFilter.Document,
23
- height: prepared.height,
24
- id: `scan-page-${counter.current}`,
25
- rotation: 0,
26
- source,
27
- sourceUrl,
28
- width: prepared.width,
29
- },
30
- };
31
- }, []);
32
- const add = useCallback(async (sources) => {
33
- const built = [];
34
- for (const source of sources)
35
- built.push(await build(source));
36
- setPages((current) => [...current, ...built.map((item) => item.page)]);
37
- return built;
38
- }, [build]);
39
- const replace = useCallback(async (id, source) => {
40
- const built = await build(source);
41
- setPages((current) => current.map((page) => {
42
- if (page.id !== id)
43
- return page;
44
- URL.revokeObjectURL(page.sourceUrl);
45
- urls.current.delete(page.sourceUrl);
46
- return { ...built.page, filter: page.filter, id: page.id };
47
- }));
48
- return built;
49
- }, [build]);
50
- const update = useCallback((id, patch) => setPages((current) => current.map((page) => (page.id === id ? { ...page, ...patch } : page))), []);
51
- const setCorners = useCallback((id, corners) => update(id, { corners }), [update]);
52
- const remove = useCallback((id) => setPages((current) => {
53
- const target = current.find((page) => page.id === id);
54
- if (target !== undefined) {
55
- URL.revokeObjectURL(target.sourceUrl);
56
- urls.current.delete(target.sourceUrl);
57
- }
58
- return current.filter((page) => page.id !== id);
59
- }), []);
60
- const move = useCallback((from, to) => setPages((current) => PsScanOrderService.move(current, from, to)), []);
61
- return { add, move, pages, remove, replace, setCorners, update };
62
- };
@@ -1,57 +0,0 @@
1
- import { useEffect, useRef, useState } from 'react';
2
- import { PsScanConfig } from '../constants/ps-scan-config';
3
- import { PsScanCanvasService } from '../services/ps-scan-canvas-service';
4
- import { PsScanPipelineService } from '../services/ps-scan-pipeline-service';
5
- export const usePsScanPreviews = (pages) => {
6
- const rasters = useRef(new Map());
7
- const urls = useRef(new Map());
8
- const [previews, setPreviews] = useState({});
9
- const signature = pages
10
- .map((page) => `${page.id}:${page.filter}:${page.rotation}:${page.corners.map((point) => `${point.x.toFixed(4)},${point.y.toFixed(4)}`).join(';')}`)
11
- .join('|');
12
- useEffect(() => {
13
- let isCancelled = false;
14
- const timer = setTimeout(async () => {
15
- const stale = [];
16
- for (const page of pages) {
17
- if (isCancelled)
18
- return;
19
- let raster = rasters.current.get(page.id);
20
- if (raster === undefined) {
21
- raster = await PsScanPipelineService.measure(page.source);
22
- rasters.current.set(page.id, raster);
23
- }
24
- const processed = PsScanPipelineService.process(page, raster, PsScanConfig.previewMaxDimension);
25
- const blob = await PsScanCanvasService.encode(processed, PsScanConfig.defaultJpegQuality);
26
- if (isCancelled)
27
- return;
28
- const previous = urls.current.get(page.id);
29
- if (previous !== undefined)
30
- stale.push(previous);
31
- urls.current.set(page.id, URL.createObjectURL(blob));
32
- }
33
- if (isCancelled)
34
- return;
35
- const ids = new Set(pages.map((page) => page.id));
36
- urls.current.forEach((url, id) => {
37
- if (ids.has(id))
38
- return;
39
- stale.push(url);
40
- urls.current.delete(id);
41
- rasters.current.delete(id);
42
- });
43
- setPreviews(Object.fromEntries(urls.current));
44
- setTimeout(() => stale.forEach((url) => URL.revokeObjectURL(url)), 1000);
45
- }, PsScanConfig.previewDebounceMs);
46
- return () => {
47
- isCancelled = true;
48
- clearTimeout(timer);
49
- };
50
- }, [signature]);
51
- useEffect(() => () => {
52
- urls.current.forEach((url) => URL.revokeObjectURL(url));
53
- urls.current.clear();
54
- rasters.current.clear();
55
- }, []);
56
- return previews;
57
- };
@@ -1,97 +0,0 @@
1
- import { PsScanConfig } from '../constants/ps-scan-config';
2
- import { PsScanFilter } from '../constants/ps-scan-filter';
3
- import { PsScanImageFilterService } from './ps-scan-image-filter-service';
4
- import { PsScanRasterService } from './ps-scan-raster-service';
5
- export class PsScanEnhanceService {
6
- static apply(source, filter) {
7
- if (filter === PsScanFilter.Original)
8
- return source;
9
- if (filter === PsScanFilter.Colour)
10
- return PsScanEnhanceService.colour(source);
11
- if (filter === PsScanFilter.Greyscale)
12
- return PsScanEnhanceService.greyscale(source);
13
- return PsScanEnhanceService.document(source);
14
- }
15
- static colour(source) {
16
- const gray = PsScanImageFilterService.grayscale(source);
17
- const { black, white } = PsScanEnhanceService.levels(gray);
18
- const gain = 255 / Math.max(1, white - black);
19
- const target = PsScanRasterService.create(source.width, source.height);
20
- for (let at = 0; at < source.data.length; at += 4) {
21
- target.data[at] = (source.data[at] - black) * gain;
22
- target.data[at + 1] = (source.data[at + 1] - black) * gain;
23
- target.data[at + 2] = (source.data[at + 2] - black) * gain;
24
- target.data[at + 3] = 255;
25
- }
26
- return target;
27
- }
28
- static document(source) {
29
- const { height, width } = source;
30
- const gray = PsScanImageFilterService.grayscale(source);
31
- const integral = new Float64Array((width + 1) * (height + 1));
32
- for (let y = 0; y < height; y += 1) {
33
- let row = 0;
34
- for (let x = 0; x < width; x += 1) {
35
- row += gray[y * width + x];
36
- integral[(y + 1) * (width + 1) + x + 1] = integral[y * (width + 1) + x + 1] + row;
37
- }
38
- }
39
- const half = Math.max(PsScanConfig.adaptiveWindowMin, Math.floor(Math.min(width, height) / PsScanConfig.adaptiveWindowDivisor)) >> 1;
40
- const target = PsScanRasterService.create(width, height);
41
- for (let y = 0; y < height; y += 1) {
42
- const y0 = Math.max(0, y - half);
43
- const y1 = Math.min(height, y + half + 1);
44
- for (let x = 0; x < width; x += 1) {
45
- const x0 = Math.max(0, x - half);
46
- const x1 = Math.min(width, x + half + 1);
47
- const sum = integral[y1 * (width + 1) + x1] -
48
- integral[y0 * (width + 1) + x1] -
49
- integral[y1 * (width + 1) + x0] +
50
- integral[y0 * (width + 1) + x0];
51
- const mean = sum / ((x1 - x0) * (y1 - y0));
52
- const value = gray[y * width + x] < mean * PsScanConfig.adaptiveRatio ? 0 : 255;
53
- const at = (y * width + x) * 4;
54
- target.data[at] = value;
55
- target.data[at + 1] = value;
56
- target.data[at + 2] = value;
57
- target.data[at + 3] = 255;
58
- }
59
- }
60
- return target;
61
- }
62
- static greyscale(source) {
63
- const gray = PsScanImageFilterService.grayscale(source);
64
- const { black, white } = PsScanEnhanceService.levels(gray);
65
- const gain = 255 / Math.max(1, white - black);
66
- const target = PsScanRasterService.create(source.width, source.height);
67
- for (let index = 0; index < gray.length; index += 1) {
68
- const value = (gray[index] - black) * gain;
69
- const at = index * 4;
70
- target.data[at] = value;
71
- target.data[at + 1] = value;
72
- target.data[at + 2] = value;
73
- target.data[at + 3] = 255;
74
- }
75
- return target;
76
- }
77
- static levels(gray) {
78
- const bins = new Uint32Array(256);
79
- gray.forEach((value) => {
80
- bins[value] += 1;
81
- });
82
- const find = (fraction) => {
83
- const target = gray.length * fraction;
84
- let cumulative = 0;
85
- for (let bin = 0; bin < 256; bin += 1) {
86
- cumulative += bins[bin];
87
- if (cumulative >= target)
88
- return bin;
89
- }
90
- return 255;
91
- };
92
- return {
93
- black: find(PsScanConfig.levelLowPercentile),
94
- white: find(PsScanConfig.levelHighPercentile),
95
- };
96
- }
97
- }
@@ -1,13 +0,0 @@
1
- export class PsScanOrderService {
2
- static move(items, from, to) {
3
- if (from === to || from < 0 || to < 0 || from >= items.length || to >= items.length)
4
- return items;
5
- const next = [...items];
6
- const [item] = next.splice(from, 1);
7
- next.splice(to, 0, item);
8
- return next;
9
- }
10
- static step(items, index, direction) {
11
- return PsScanOrderService.move(items, index, index + direction);
12
- }
13
- }
@@ -1,24 +0,0 @@
1
- import { PsScanOutputFormat } from '../constants/ps-scan-output-format';
2
- import { PsScanFileNameService } from './ps-scan-file-name-service';
3
- import { PsScanPdfService } from './ps-scan-pdf-service';
4
- import { PsScanPipelineService } from './ps-scan-pipeline-service';
5
- export class PsScanOutputService {
6
- static async build(pages, options) {
7
- const rendered = [];
8
- for (const page of pages)
9
- rendered.push(await PsScanPipelineService.render(page, options.maxDimension, options.jpegQuality));
10
- const type = PsScanFileNameService.mimeType(options.format);
11
- if (options.format === PsScanOutputFormat.Jpeg)
12
- return rendered.map((item, index) => new File([item.blob], PsScanFileNameService.build(options.fileName, options.format, index, rendered.length), { type }));
13
- const jpegs = await Promise.all(rendered.map(async (item) => ({
14
- height: item.height,
15
- jpeg: new Uint8Array(await item.blob.arrayBuffer()),
16
- width: item.width,
17
- })));
18
- return [
19
- new File([PsScanPdfService.build(jpegs)], PsScanFileNameService.build(options.fileName, options.format, 0, 1), {
20
- type,
21
- }),
22
- ];
23
- }
24
- }
@@ -1,56 +0,0 @@
1
- import { PsScanConfig } from '../constants/ps-scan-config';
2
- export class PsScanPdfService {
3
- static build(pages) {
4
- const encoder = new TextEncoder();
5
- const chunks = [];
6
- const offsets = [];
7
- let length = 0;
8
- const push = (chunk) => {
9
- chunks.push(chunk);
10
- length += chunk.length;
11
- };
12
- const text = (value) => push(encoder.encode(value));
13
- const begin = (id) => {
14
- offsets[id] = length;
15
- text(`${id} 0 obj\n`);
16
- };
17
- const kids = pages.map((_, index) => `${3 + index * 3} 0 R`).join(' ');
18
- push(Uint8Array.from([
19
- 0x25, 0x50, 0x44, 0x46, 0x2d, 0x31, 0x2e, 0x34, 0x0a, 0x25, 0xe2, 0xe3, 0xcf, 0xd3, 0x0a,
20
- ]));
21
- begin(1);
22
- text('<< /Type /Catalog /Pages 2 0 R >>\nendobj\n');
23
- begin(2);
24
- text(`<< /Type /Pages /Kids [${kids}] /Count ${pages.length} >>\nendobj\n`);
25
- pages.forEach((page, index) => {
26
- const pageId = 3 + index * 3;
27
- const widthPt = PsScanPdfService.points(page.width);
28
- const heightPt = PsScanPdfService.points(page.height);
29
- const content = `q ${widthPt} 0 0 ${heightPt} 0 0 cm /Im0 Do Q`;
30
- begin(pageId);
31
- 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`);
32
- begin(pageId + 1);
33
- text(`<< /Length ${content.length} >>\nstream\n${content}\nendstream\nendobj\n`);
34
- begin(pageId + 2);
35
- text(`<< /Type /XObject /Subtype /Image /Width ${page.width} /Height ${page.height} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /DCTDecode /Length ${page.jpeg.length} >>\nstream\n`);
36
- push(page.jpeg);
37
- text('\nendstream\nendobj\n');
38
- });
39
- const count = 3 + pages.length * 3;
40
- const xrefAt = length;
41
- text(`xref\n0 ${count}\n0000000000 65535 f \n`);
42
- for (let id = 1; id < count; id += 1)
43
- text(`${String(offsets[id]).padStart(10, '0')} 00000 n \n`);
44
- text(`trailer\n<< /Size ${count} /Root 1 0 R >>\nstartxref\n${xrefAt}\n%%EOF\n`);
45
- const out = new Uint8Array(length);
46
- let at = 0;
47
- chunks.forEach((chunk) => {
48
- out.set(chunk, at);
49
- at += chunk.length;
50
- });
51
- return out;
52
- }
53
- static points(pixels) {
54
- return Math.round((pixels * PsScanConfig.pdfPointsPerInch * 100) / PsScanConfig.pdfDpi) / 100;
55
- }
56
- }
@@ -1,12 +0,0 @@
1
- import type { PsScanAddedPage } from '../models/ps-scan-added-page';
2
- import type { PsScanPage } from '../models/ps-scan-page';
3
- import type { PsScanQuad } from '../models/ps-scan-quad';
4
- export declare const usePsScanPages: () => {
5
- add: (sources: Blob[]) => Promise<PsScanAddedPage[]>;
6
- move: (from: number, to: number) => void;
7
- pages: PsScanPage[];
8
- remove: (id: string) => void;
9
- replace: (id: string, source: Blob) => Promise<PsScanAddedPage>;
10
- setCorners: (id: string, corners: PsScanQuad) => void;
11
- update: (id: string, patch: Partial<Pick<PsScanPage, "corners" | "filter" | "rotation">>) => void;
12
- };
@@ -1,66 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.usePsScanPages = void 0;
4
- const react_1 = require("react");
5
- const ps_scan_filter_1 = require("../constants/ps-scan-filter");
6
- const ps_scan_order_service_1 = require("../services/ps-scan-order-service");
7
- const ps_scan_pipeline_service_1 = require("../services/ps-scan-pipeline-service");
8
- const usePsScanPages = () => {
9
- const [pages, setPages] = (0, react_1.useState)([]);
10
- const urls = (0, react_1.useRef)(new Set());
11
- const counter = (0, react_1.useRef)(0);
12
- (0, react_1.useEffect)(() => () => {
13
- urls.current.forEach((url) => URL.revokeObjectURL(url));
14
- urls.current.clear();
15
- }, []);
16
- const build = (0, react_1.useCallback)(async (source) => {
17
- const prepared = await ps_scan_pipeline_service_1.PsScanPipelineService.prepare(source);
18
- const sourceUrl = URL.createObjectURL(source);
19
- counter.current += 1;
20
- urls.current.add(sourceUrl);
21
- return {
22
- isDetected: prepared.isDetected,
23
- page: {
24
- corners: prepared.corners,
25
- filter: ps_scan_filter_1.PsScanFilter.Document,
26
- height: prepared.height,
27
- id: `scan-page-${counter.current}`,
28
- rotation: 0,
29
- source,
30
- sourceUrl,
31
- width: prepared.width,
32
- },
33
- };
34
- }, []);
35
- const add = (0, react_1.useCallback)(async (sources) => {
36
- const built = [];
37
- for (const source of sources)
38
- built.push(await build(source));
39
- setPages((current) => [...current, ...built.map((item) => item.page)]);
40
- return built;
41
- }, [build]);
42
- const replace = (0, react_1.useCallback)(async (id, source) => {
43
- const built = await build(source);
44
- setPages((current) => current.map((page) => {
45
- if (page.id !== id)
46
- return page;
47
- URL.revokeObjectURL(page.sourceUrl);
48
- urls.current.delete(page.sourceUrl);
49
- return { ...built.page, filter: page.filter, id: page.id };
50
- }));
51
- return built;
52
- }, [build]);
53
- const update = (0, react_1.useCallback)((id, patch) => setPages((current) => current.map((page) => (page.id === id ? { ...page, ...patch } : page))), []);
54
- const setCorners = (0, react_1.useCallback)((id, corners) => update(id, { corners }), [update]);
55
- const remove = (0, react_1.useCallback)((id) => setPages((current) => {
56
- const target = current.find((page) => page.id === id);
57
- if (target !== undefined) {
58
- URL.revokeObjectURL(target.sourceUrl);
59
- urls.current.delete(target.sourceUrl);
60
- }
61
- return current.filter((page) => page.id !== id);
62
- }), []);
63
- const move = (0, react_1.useCallback)((from, to) => setPages((current) => ps_scan_order_service_1.PsScanOrderService.move(current, from, to)), []);
64
- return { add, move, pages, remove, replace, setCorners, update };
65
- };
66
- exports.usePsScanPages = usePsScanPages;
@@ -1,2 +0,0 @@
1
- import type { PsScanPage } from '../models/ps-scan-page';
2
- export declare const usePsScanPreviews: (pages: PsScanPage[]) => Record<string, string>;
@@ -1,61 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.usePsScanPreviews = void 0;
4
- const react_1 = require("react");
5
- const ps_scan_config_1 = require("../constants/ps-scan-config");
6
- const ps_scan_canvas_service_1 = require("../services/ps-scan-canvas-service");
7
- const ps_scan_pipeline_service_1 = require("../services/ps-scan-pipeline-service");
8
- const usePsScanPreviews = (pages) => {
9
- const rasters = (0, react_1.useRef)(new Map());
10
- const urls = (0, react_1.useRef)(new Map());
11
- const [previews, setPreviews] = (0, react_1.useState)({});
12
- const signature = pages
13
- .map((page) => `${page.id}:${page.filter}:${page.rotation}:${page.corners.map((point) => `${point.x.toFixed(4)},${point.y.toFixed(4)}`).join(';')}`)
14
- .join('|');
15
- (0, react_1.useEffect)(() => {
16
- let isCancelled = false;
17
- const timer = setTimeout(async () => {
18
- const stale = [];
19
- for (const page of pages) {
20
- if (isCancelled)
21
- return;
22
- let raster = rasters.current.get(page.id);
23
- if (raster === undefined) {
24
- raster = await ps_scan_pipeline_service_1.PsScanPipelineService.measure(page.source);
25
- rasters.current.set(page.id, raster);
26
- }
27
- const processed = ps_scan_pipeline_service_1.PsScanPipelineService.process(page, raster, ps_scan_config_1.PsScanConfig.previewMaxDimension);
28
- const blob = await ps_scan_canvas_service_1.PsScanCanvasService.encode(processed, ps_scan_config_1.PsScanConfig.defaultJpegQuality);
29
- if (isCancelled)
30
- return;
31
- const previous = urls.current.get(page.id);
32
- if (previous !== undefined)
33
- stale.push(previous);
34
- urls.current.set(page.id, URL.createObjectURL(blob));
35
- }
36
- if (isCancelled)
37
- return;
38
- const ids = new Set(pages.map((page) => page.id));
39
- urls.current.forEach((url, id) => {
40
- if (ids.has(id))
41
- return;
42
- stale.push(url);
43
- urls.current.delete(id);
44
- rasters.current.delete(id);
45
- });
46
- setPreviews(Object.fromEntries(urls.current));
47
- setTimeout(() => stale.forEach((url) => URL.revokeObjectURL(url)), 1000);
48
- }, ps_scan_config_1.PsScanConfig.previewDebounceMs);
49
- return () => {
50
- isCancelled = true;
51
- clearTimeout(timer);
52
- };
53
- }, [signature]);
54
- (0, react_1.useEffect)(() => () => {
55
- urls.current.forEach((url) => URL.revokeObjectURL(url));
56
- urls.current.clear();
57
- rasters.current.clear();
58
- }, []);
59
- return previews;
60
- };
61
- exports.usePsScanPreviews = usePsScanPreviews;
@@ -1,5 +0,0 @@
1
- import type { PsScanPage } from './ps-scan-page';
2
- export interface PsScanAddedPage {
3
- isDetected: boolean;
4
- page: PsScanPage;
5
- }
@@ -1,4 +0,0 @@
1
- export interface PsScanLevels {
2
- black: number;
3
- white: number;
4
- }
@@ -1,7 +0,0 @@
1
- import type { PsScanOutputFormat } from '../constants/ps-scan-output-format';
2
- export interface PsScanOutputOptions {
3
- fileName: string;
4
- format: PsScanOutputFormat;
5
- jpegQuality: number;
6
- maxDimension: number;
7
- }
@@ -1,12 +0,0 @@
1
- import type { PsScanFilter } from '../constants/ps-scan-filter';
2
- import type { PsScanQuad } from './ps-scan-quad';
3
- export interface PsScanPage {
4
- corners: PsScanQuad;
5
- filter: PsScanFilter;
6
- height: number;
7
- id: string;
8
- rotation: number;
9
- source: Blob;
10
- sourceUrl: string;
11
- width: number;
12
- }