@pallasoft/ps-file-components 1.2.4 → 1.4.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.
- package/dist/components/ps-document-scanner-loader.d.ts +1 -0
- package/dist/components/ps-document-scanner-loader.js +40 -0
- package/dist/components/ps-document-scanner-sheet.d.ts +2 -0
- package/dist/components/ps-document-scanner-sheet.js +138 -0
- package/dist/components/ps-document-scanner.d.ts +2 -0
- package/dist/components/ps-document-scanner.js +17 -0
- package/dist/components/ps-file-picker.d.ts +2 -1
- package/dist/components/ps-file-picker.js +2 -2
- package/dist/components/ps-file-viewer-pane.d.ts +2 -0
- package/dist/components/ps-file-viewer-pane.js +39 -0
- package/dist/components/ps-scan-camera-view.d.ts +17 -0
- package/dist/components/ps-scan-camera-view.js +27 -0
- package/dist/components/ps-scan-crop-editor.d.ts +13 -0
- package/dist/components/ps-scan-crop-editor.js +53 -0
- package/dist/components/ps-scan-icon-button.d.ts +10 -0
- package/dist/components/ps-scan-icon-button.js +7 -0
- package/dist/components/ps-scan-page-list.d.ts +12 -0
- package/dist/components/ps-scan-page-list.js +23 -0
- package/dist/components/ps-scan-review.d.ts +23 -0
- package/dist/components/ps-scan-review.js +20 -0
- package/dist/constants/ps-document-scanner-labels.d.ts +50 -0
- package/dist/constants/ps-document-scanner-labels.js +53 -0
- package/dist/constants/ps-file-picker-labels.d.ts +1 -0
- package/dist/constants/ps-file-picker-labels.js +1 -0
- package/dist/constants/ps-scan-camera-status.d.ts +7 -0
- package/dist/constants/ps-scan-camera-status.js +9 -0
- package/dist/constants/ps-scan-config.d.ts +31 -0
- package/dist/constants/ps-scan-config.js +34 -0
- package/dist/constants/ps-scan-corner-order.d.ts +1 -0
- package/dist/constants/ps-scan-corner-order.js +4 -0
- package/dist/constants/ps-scan-filter.d.ts +7 -0
- package/dist/constants/ps-scan-filter.js +9 -0
- package/dist/constants/ps-scan-output-format.d.ts +5 -0
- package/dist/constants/ps-scan-output-format.js +7 -0
- package/dist/constants/ps-scan-step.d.ts +6 -0
- package/dist/constants/ps-scan-step.js +8 -0
- package/dist/esm/components/ps-document-scanner-loader.js +4 -0
- package/dist/esm/components/ps-document-scanner-sheet.js +134 -0
- package/dist/esm/components/ps-document-scanner.js +13 -0
- package/dist/esm/components/ps-file-picker.js +3 -3
- package/dist/esm/components/ps-file-viewer-pane.js +35 -0
- package/dist/esm/components/ps-scan-camera-view.js +23 -0
- package/dist/esm/components/ps-scan-crop-editor.js +49 -0
- package/dist/esm/components/ps-scan-icon-button.js +3 -0
- package/dist/esm/components/ps-scan-page-list.js +19 -0
- package/dist/esm/components/ps-scan-review.js +16 -0
- package/dist/esm/constants/ps-document-scanner-labels.js +50 -0
- package/dist/esm/constants/ps-file-picker-labels.js +1 -0
- package/dist/esm/constants/ps-scan-camera-status.js +6 -0
- package/dist/esm/constants/ps-scan-config.js +31 -0
- package/dist/esm/constants/ps-scan-corner-order.js +1 -0
- package/dist/esm/constants/ps-scan-filter.js +6 -0
- package/dist/esm/constants/ps-scan-output-format.js +4 -0
- package/dist/esm/constants/ps-scan-step.js +5 -0
- package/dist/esm/hooks/use-ps-focus-trap.js +45 -0
- package/dist/esm/hooks/use-ps-scan-camera.js +62 -0
- package/dist/esm/hooks/use-ps-scan-pages.js +62 -0
- package/dist/esm/hooks/use-ps-scan-previews.js +57 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/models/ps-document-scanner-props.js +1 -0
- package/dist/esm/models/ps-document-scanner-sheet-props.js +1 -0
- package/dist/esm/models/ps-file-viewer-pane-props.js +1 -0
- package/dist/esm/models/ps-scan-added-page.js +1 -0
- package/dist/esm/models/ps-scan-camera-session.js +1 -0
- package/dist/esm/models/ps-scan-decoded-image.js +1 -0
- package/dist/esm/models/ps-scan-levels.js +1 -0
- package/dist/esm/models/ps-scan-output-options.js +1 -0
- package/dist/esm/models/ps-scan-page.js +1 -0
- package/dist/esm/models/ps-scan-pdf-page.js +1 -0
- package/dist/esm/models/ps-scan-prepared.js +1 -0
- package/dist/esm/models/ps-scan-quad.js +1 -0
- package/dist/esm/models/ps-scan-raster.js +1 -0
- package/dist/esm/models/ps-scan-rendered-page.js +1 -0
- package/dist/esm/services/ps-scan-camera-service.js +50 -0
- package/dist/esm/services/ps-scan-canvas-service.js +46 -0
- package/dist/esm/services/ps-scan-edge-service.js +156 -0
- package/dist/esm/services/ps-scan-enhance-service.js +97 -0
- package/dist/esm/services/ps-scan-file-name-service.js +25 -0
- package/dist/esm/services/ps-scan-geometry-service.js +96 -0
- package/dist/esm/services/ps-scan-homography-service.js +46 -0
- package/dist/esm/services/ps-scan-hull-service.js +59 -0
- package/dist/esm/services/ps-scan-image-filter-service.js +52 -0
- package/dist/esm/services/ps-scan-order-service.js +13 -0
- package/dist/esm/services/ps-scan-output-service.js +24 -0
- package/dist/esm/services/ps-scan-pdf-service.js +56 -0
- package/dist/esm/services/ps-scan-pipeline-service.js +40 -0
- package/dist/esm/services/ps-scan-raster-service.js +67 -0
- package/dist/esm/services/ps-scan-template-service.js +5 -0
- package/dist/esm/services/ps-scan-warp-service.js +35 -0
- package/dist/hooks/use-ps-focus-trap.d.ts +2 -0
- package/dist/hooks/use-ps-focus-trap.js +49 -0
- package/dist/hooks/use-ps-scan-camera.d.ts +9 -0
- package/dist/hooks/use-ps-scan-camera.js +66 -0
- package/dist/hooks/use-ps-scan-pages.d.ts +12 -0
- package/dist/hooks/use-ps-scan-pages.js +66 -0
- package/dist/hooks/use-ps-scan-previews.d.ts +2 -0
- package/dist/hooks/use-ps-scan-previews.js +61 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/models/ps-document-scanner-props.d.ts +15 -0
- package/dist/models/ps-document-scanner-props.js +2 -0
- package/dist/models/ps-document-scanner-sheet-props.d.ts +13 -0
- package/dist/models/ps-document-scanner-sheet-props.js +2 -0
- package/dist/models/ps-file-viewer-pane-props.d.ts +12 -0
- package/dist/models/ps-file-viewer-pane-props.js +2 -0
- package/dist/models/ps-scan-added-page.d.ts +5 -0
- package/dist/models/ps-scan-added-page.js +2 -0
- package/dist/models/ps-scan-camera-session.d.ts +5 -0
- package/dist/models/ps-scan-camera-session.js +2 -0
- package/dist/models/ps-scan-decoded-image.d.ts +6 -0
- package/dist/models/ps-scan-decoded-image.js +2 -0
- package/dist/models/ps-scan-levels.d.ts +4 -0
- package/dist/models/ps-scan-levels.js +2 -0
- package/dist/models/ps-scan-output-options.d.ts +7 -0
- package/dist/models/ps-scan-output-options.js +2 -0
- package/dist/models/ps-scan-page.d.ts +12 -0
- package/dist/models/ps-scan-page.js +2 -0
- package/dist/models/ps-scan-pdf-page.d.ts +5 -0
- package/dist/models/ps-scan-pdf-page.js +2 -0
- package/dist/models/ps-scan-prepared.d.ts +7 -0
- package/dist/models/ps-scan-prepared.js +2 -0
- package/dist/models/ps-scan-quad.d.ts +2 -0
- package/dist/models/ps-scan-quad.js +2 -0
- package/dist/models/ps-scan-raster.d.ts +5 -0
- package/dist/models/ps-scan-raster.js +2 -0
- package/dist/models/ps-scan-rendered-page.d.ts +5 -0
- package/dist/models/ps-scan-rendered-page.js +2 -0
- package/dist/services/ps-scan-camera-service.d.ts +10 -0
- package/dist/services/ps-scan-camera-service.js +54 -0
- package/dist/services/ps-scan-canvas-service.d.ts +8 -0
- package/dist/services/ps-scan-canvas-service.js +50 -0
- package/dist/services/ps-scan-edge-service.d.ts +9 -0
- package/dist/services/ps-scan-edge-service.js +160 -0
- package/dist/services/ps-scan-enhance-service.d.ts +9 -0
- package/dist/services/ps-scan-enhance-service.js +101 -0
- package/dist/services/ps-scan-file-name-service.d.ts +6 -0
- package/dist/services/ps-scan-file-name-service.js +29 -0
- package/dist/services/ps-scan-geometry-service.d.ts +18 -0
- package/dist/services/ps-scan-geometry-service.js +100 -0
- package/dist/services/ps-scan-homography-service.d.ts +7 -0
- package/dist/services/ps-scan-homography-service.js +50 -0
- package/dist/services/ps-scan-hull-service.d.ts +6 -0
- package/dist/services/ps-scan-hull-service.js +63 -0
- package/dist/services/ps-scan-image-filter-service.d.ts +6 -0
- package/dist/services/ps-scan-image-filter-service.js +56 -0
- package/dist/services/ps-scan-order-service.d.ts +4 -0
- package/dist/services/ps-scan-order-service.js +17 -0
- package/dist/services/ps-scan-output-service.d.ts +5 -0
- package/dist/services/ps-scan-output-service.js +28 -0
- package/dist/services/ps-scan-pdf-service.d.ts +5 -0
- package/dist/services/ps-scan-pdf-service.js +60 -0
- package/dist/services/ps-scan-pipeline-service.d.ts +10 -0
- package/dist/services/ps-scan-pipeline-service.js +44 -0
- package/dist/services/ps-scan-raster-service.d.ts +6 -0
- package/dist/services/ps-scan-raster-service.js +71 -0
- package/dist/services/ps-scan-template-service.d.ts +3 -0
- package/dist/services/ps-scan-template-service.js +9 -0
- package/dist/services/ps-scan-warp-service.d.ts +6 -0
- package/dist/services/ps-scan-warp-service.js +39 -0
- package/package.json +9 -6
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PsScanQuad } from '../models/ps-scan-quad';
|
|
2
|
+
import type { PsScanRaster } from '../models/ps-scan-raster';
|
|
3
|
+
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;
|
|
9
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PsScanEdgeService = 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
|
+
const ps_scan_hull_service_1 = require("./ps-scan-hull-service");
|
|
7
|
+
const ps_scan_image_filter_service_1 = require("./ps-scan-image-filter-service");
|
|
8
|
+
const ps_scan_raster_service_1 = require("./ps-scan-raster-service");
|
|
9
|
+
class PsScanEdgeService {
|
|
10
|
+
static detect(source) {
|
|
11
|
+
const scale = Math.min(1, ps_scan_config_1.PsScanConfig.detectMaxDimension / Math.max(source.width, source.height));
|
|
12
|
+
const width = Math.max(8, Math.round(source.width * scale));
|
|
13
|
+
const height = Math.max(8, Math.round(source.height * scale));
|
|
14
|
+
const raster = ps_scan_raster_service_1.PsScanRasterService.resize(source, width, height);
|
|
15
|
+
const gray = ps_scan_image_filter_service_1.PsScanImageFilterService.blur(ps_scan_image_filter_service_1.PsScanImageFilterService.grayscale(raster), width, height);
|
|
16
|
+
const edges = ps_scan_image_filter_service_1.PsScanImageFilterService.sobel(gray, width, height);
|
|
17
|
+
let mask = PsScanEdgeService.threshold(edges);
|
|
18
|
+
for (let step = 0; step < ps_scan_config_1.PsScanConfig.detectDilations; step += 1)
|
|
19
|
+
mask = PsScanEdgeService.dilate(mask, width, height);
|
|
20
|
+
const foreground = PsScanEdgeService.foreground(mask, width, height);
|
|
21
|
+
const component = PsScanEdgeService.largestComponent(foreground, width, height);
|
|
22
|
+
if (component.length < 8)
|
|
23
|
+
return null;
|
|
24
|
+
const hull = ps_scan_hull_service_1.PsScanHullService.convexHull(component);
|
|
25
|
+
if (hull.length < 4)
|
|
26
|
+
return null;
|
|
27
|
+
const quad = ps_scan_geometry_service_1.PsScanGeometryService.order(ps_scan_hull_service_1.PsScanHullService.bestQuad(hull));
|
|
28
|
+
const imageArea = width * height;
|
|
29
|
+
const quadArea = ps_scan_geometry_service_1.PsScanGeometryService.area(quad);
|
|
30
|
+
const hullArea = ps_scan_geometry_service_1.PsScanGeometryService.area(hull);
|
|
31
|
+
if (quadArea / imageArea < ps_scan_config_1.PsScanConfig.detectMinAreaRatio)
|
|
32
|
+
return null;
|
|
33
|
+
if (quadArea / imageArea > ps_scan_config_1.PsScanConfig.detectMaxAreaRatio)
|
|
34
|
+
return null;
|
|
35
|
+
if (hullArea > 0 && quadArea / hullArea < ps_scan_config_1.PsScanConfig.detectMinHullFill)
|
|
36
|
+
return null;
|
|
37
|
+
if (!ps_scan_geometry_service_1.PsScanGeometryService.isConvex(quad))
|
|
38
|
+
return null;
|
|
39
|
+
return quad.map((point) => ({
|
|
40
|
+
x: Math.min(1, Math.max(0, point.x / (width - 1))),
|
|
41
|
+
y: Math.min(1, Math.max(0, point.y / (height - 1))),
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
static dilate(mask, width, height) {
|
|
45
|
+
const out = new Uint8Array(mask.length);
|
|
46
|
+
for (let y = 0; y < height; y += 1)
|
|
47
|
+
for (let x = 0; x < width; x += 1) {
|
|
48
|
+
if (mask[y * width + x] === 0)
|
|
49
|
+
continue;
|
|
50
|
+
for (let dy = -1; dy <= 1; dy += 1)
|
|
51
|
+
for (let dx = -1; dx <= 1; dx += 1) {
|
|
52
|
+
const nx = x + dx;
|
|
53
|
+
const ny = y + dy;
|
|
54
|
+
if (nx >= 0 && ny >= 0 && nx < width && ny < height)
|
|
55
|
+
out[ny * width + nx] = 1;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
static foreground(mask, width, height) {
|
|
61
|
+
const background = new Uint8Array(mask.length);
|
|
62
|
+
const stack = [];
|
|
63
|
+
const seed = (index) => {
|
|
64
|
+
if (mask[index] === 0 && background[index] === 0) {
|
|
65
|
+
background[index] = 1;
|
|
66
|
+
stack.push(index);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
for (let x = 0; x < width; x += 1) {
|
|
70
|
+
seed(x);
|
|
71
|
+
seed((height - 1) * width + x);
|
|
72
|
+
}
|
|
73
|
+
for (let y = 0; y < height; y += 1) {
|
|
74
|
+
seed(y * width);
|
|
75
|
+
seed(y * width + width - 1);
|
|
76
|
+
}
|
|
77
|
+
while (stack.length > 0) {
|
|
78
|
+
const index = stack.pop();
|
|
79
|
+
if (index === undefined)
|
|
80
|
+
break;
|
|
81
|
+
const x = index % width;
|
|
82
|
+
const y = (index - x) / width;
|
|
83
|
+
if (x > 0)
|
|
84
|
+
seed(index - 1);
|
|
85
|
+
if (x < width - 1)
|
|
86
|
+
seed(index + 1);
|
|
87
|
+
if (y > 0)
|
|
88
|
+
seed(index - width);
|
|
89
|
+
if (y < height - 1)
|
|
90
|
+
seed(index + width);
|
|
91
|
+
}
|
|
92
|
+
return background.map((value) => 1 - value);
|
|
93
|
+
}
|
|
94
|
+
static largestComponent(mask, width, height) {
|
|
95
|
+
const seen = new Uint8Array(mask.length);
|
|
96
|
+
let best = [];
|
|
97
|
+
let bestSize = 0;
|
|
98
|
+
for (let start = 0; start < mask.length; start += 1) {
|
|
99
|
+
if (mask[start] === 0 || seen[start] === 1)
|
|
100
|
+
continue;
|
|
101
|
+
const members = [];
|
|
102
|
+
const stack = [start];
|
|
103
|
+
let size = 0;
|
|
104
|
+
seen[start] = 1;
|
|
105
|
+
while (stack.length > 0) {
|
|
106
|
+
const index = stack.pop();
|
|
107
|
+
if (index === undefined)
|
|
108
|
+
break;
|
|
109
|
+
const x = index % width;
|
|
110
|
+
const y = (index - x) / width;
|
|
111
|
+
let isBoundary = false;
|
|
112
|
+
size += 1;
|
|
113
|
+
for (let dy = -1; dy <= 1; dy += 1)
|
|
114
|
+
for (let dx = -1; dx <= 1; dx += 1) {
|
|
115
|
+
if (dx === 0 && dy === 0)
|
|
116
|
+
continue;
|
|
117
|
+
const nx = x + dx;
|
|
118
|
+
const ny = y + dy;
|
|
119
|
+
if (nx < 0 || ny < 0 || nx >= width || ny >= height) {
|
|
120
|
+
isBoundary = true;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
const next = ny * width + nx;
|
|
124
|
+
if (mask[next] === 0)
|
|
125
|
+
isBoundary = true;
|
|
126
|
+
else if (seen[next] === 0) {
|
|
127
|
+
seen[next] = 1;
|
|
128
|
+
stack.push(next);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (isBoundary)
|
|
132
|
+
members.push({ x, y });
|
|
133
|
+
}
|
|
134
|
+
if (size > bestSize) {
|
|
135
|
+
bestSize = size;
|
|
136
|
+
best = members;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return best;
|
|
140
|
+
}
|
|
141
|
+
static threshold(edges) {
|
|
142
|
+
const bins = new Uint32Array(512);
|
|
143
|
+
edges.forEach((value) => {
|
|
144
|
+
bins[Math.min(511, value)] += 1;
|
|
145
|
+
});
|
|
146
|
+
const target = edges.length * ps_scan_config_1.PsScanConfig.detectPercentile;
|
|
147
|
+
let cumulative = 0;
|
|
148
|
+
let high = 0;
|
|
149
|
+
for (let bin = 0; bin < bins.length; bin += 1) {
|
|
150
|
+
cumulative += bins[bin];
|
|
151
|
+
if (cumulative >= target) {
|
|
152
|
+
high = bin;
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const limit = Math.max(ps_scan_config_1.PsScanConfig.detectMinEdgeStrength, high * ps_scan_config_1.PsScanConfig.detectRelativeStrength);
|
|
157
|
+
return Uint8Array.from(edges, (value) => (value >= limit ? 1 : 0));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
exports.PsScanEdgeService = PsScanEdgeService;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { PsScanFilter } from '../constants/ps-scan-filter';
|
|
2
|
+
import type { PsScanRaster } from '../models/ps-scan-raster';
|
|
3
|
+
export declare class PsScanEnhanceService {
|
|
4
|
+
static apply(source: PsScanRaster, filter: PsScanFilter): PsScanRaster;
|
|
5
|
+
private static colour;
|
|
6
|
+
private static document;
|
|
7
|
+
private static greyscale;
|
|
8
|
+
private static levels;
|
|
9
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PsScanEnhanceService = void 0;
|
|
4
|
+
const ps_scan_config_1 = require("../constants/ps-scan-config");
|
|
5
|
+
const ps_scan_filter_1 = require("../constants/ps-scan-filter");
|
|
6
|
+
const ps_scan_image_filter_service_1 = require("./ps-scan-image-filter-service");
|
|
7
|
+
const ps_scan_raster_service_1 = require("./ps-scan-raster-service");
|
|
8
|
+
class PsScanEnhanceService {
|
|
9
|
+
static apply(source, filter) {
|
|
10
|
+
if (filter === ps_scan_filter_1.PsScanFilter.Original)
|
|
11
|
+
return source;
|
|
12
|
+
if (filter === ps_scan_filter_1.PsScanFilter.Colour)
|
|
13
|
+
return PsScanEnhanceService.colour(source);
|
|
14
|
+
if (filter === ps_scan_filter_1.PsScanFilter.Greyscale)
|
|
15
|
+
return PsScanEnhanceService.greyscale(source);
|
|
16
|
+
return PsScanEnhanceService.document(source);
|
|
17
|
+
}
|
|
18
|
+
static colour(source) {
|
|
19
|
+
const gray = ps_scan_image_filter_service_1.PsScanImageFilterService.grayscale(source);
|
|
20
|
+
const { black, white } = PsScanEnhanceService.levels(gray);
|
|
21
|
+
const gain = 255 / Math.max(1, white - black);
|
|
22
|
+
const target = ps_scan_raster_service_1.PsScanRasterService.create(source.width, source.height);
|
|
23
|
+
for (let at = 0; at < source.data.length; at += 4) {
|
|
24
|
+
target.data[at] = (source.data[at] - black) * gain;
|
|
25
|
+
target.data[at + 1] = (source.data[at + 1] - black) * gain;
|
|
26
|
+
target.data[at + 2] = (source.data[at + 2] - black) * gain;
|
|
27
|
+
target.data[at + 3] = 255;
|
|
28
|
+
}
|
|
29
|
+
return target;
|
|
30
|
+
}
|
|
31
|
+
static document(source) {
|
|
32
|
+
const { height, width } = source;
|
|
33
|
+
const gray = ps_scan_image_filter_service_1.PsScanImageFilterService.grayscale(source);
|
|
34
|
+
const integral = new Float64Array((width + 1) * (height + 1));
|
|
35
|
+
for (let y = 0; y < height; y += 1) {
|
|
36
|
+
let row = 0;
|
|
37
|
+
for (let x = 0; x < width; x += 1) {
|
|
38
|
+
row += gray[y * width + x];
|
|
39
|
+
integral[(y + 1) * (width + 1) + x + 1] = integral[y * (width + 1) + x + 1] + row;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const half = Math.max(ps_scan_config_1.PsScanConfig.adaptiveWindowMin, Math.floor(Math.min(width, height) / ps_scan_config_1.PsScanConfig.adaptiveWindowDivisor)) >> 1;
|
|
43
|
+
const target = ps_scan_raster_service_1.PsScanRasterService.create(width, height);
|
|
44
|
+
for (let y = 0; y < height; y += 1) {
|
|
45
|
+
const y0 = Math.max(0, y - half);
|
|
46
|
+
const y1 = Math.min(height, y + half + 1);
|
|
47
|
+
for (let x = 0; x < width; x += 1) {
|
|
48
|
+
const x0 = Math.max(0, x - half);
|
|
49
|
+
const x1 = Math.min(width, x + half + 1);
|
|
50
|
+
const sum = integral[y1 * (width + 1) + x1] -
|
|
51
|
+
integral[y0 * (width + 1) + x1] -
|
|
52
|
+
integral[y1 * (width + 1) + x0] +
|
|
53
|
+
integral[y0 * (width + 1) + x0];
|
|
54
|
+
const mean = sum / ((x1 - x0) * (y1 - y0));
|
|
55
|
+
const value = gray[y * width + x] < mean * ps_scan_config_1.PsScanConfig.adaptiveRatio ? 0 : 255;
|
|
56
|
+
const at = (y * width + x) * 4;
|
|
57
|
+
target.data[at] = value;
|
|
58
|
+
target.data[at + 1] = value;
|
|
59
|
+
target.data[at + 2] = value;
|
|
60
|
+
target.data[at + 3] = 255;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return target;
|
|
64
|
+
}
|
|
65
|
+
static greyscale(source) {
|
|
66
|
+
const gray = ps_scan_image_filter_service_1.PsScanImageFilterService.grayscale(source);
|
|
67
|
+
const { black, white } = PsScanEnhanceService.levels(gray);
|
|
68
|
+
const gain = 255 / Math.max(1, white - black);
|
|
69
|
+
const target = ps_scan_raster_service_1.PsScanRasterService.create(source.width, source.height);
|
|
70
|
+
for (let index = 0; index < gray.length; index += 1) {
|
|
71
|
+
const value = (gray[index] - black) * gain;
|
|
72
|
+
const at = index * 4;
|
|
73
|
+
target.data[at] = value;
|
|
74
|
+
target.data[at + 1] = value;
|
|
75
|
+
target.data[at + 2] = value;
|
|
76
|
+
target.data[at + 3] = 255;
|
|
77
|
+
}
|
|
78
|
+
return target;
|
|
79
|
+
}
|
|
80
|
+
static levels(gray) {
|
|
81
|
+
const bins = new Uint32Array(256);
|
|
82
|
+
gray.forEach((value) => {
|
|
83
|
+
bins[value] += 1;
|
|
84
|
+
});
|
|
85
|
+
const find = (fraction) => {
|
|
86
|
+
const target = gray.length * fraction;
|
|
87
|
+
let cumulative = 0;
|
|
88
|
+
for (let bin = 0; bin < 256; bin += 1) {
|
|
89
|
+
cumulative += bins[bin];
|
|
90
|
+
if (cumulative >= target)
|
|
91
|
+
return bin;
|
|
92
|
+
}
|
|
93
|
+
return 255;
|
|
94
|
+
};
|
|
95
|
+
return {
|
|
96
|
+
black: find(ps_scan_config_1.PsScanConfig.levelLowPercentile),
|
|
97
|
+
white: find(ps_scan_config_1.PsScanConfig.levelHighPercentile),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
exports.PsScanEnhanceService = PsScanEnhanceService;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { PsScanOutputFormat } from '../constants/ps-scan-output-format';
|
|
2
|
+
export declare class PsScanFileNameService {
|
|
3
|
+
static build(base: string, format: PsScanOutputFormat, index: number, count: number): string;
|
|
4
|
+
static mimeType(format: PsScanOutputFormat): string;
|
|
5
|
+
static sanitize(base: string): string;
|
|
6
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PsScanFileNameService = void 0;
|
|
4
|
+
const ps_scan_config_1 = require("../constants/ps-scan-config");
|
|
5
|
+
const ps_scan_output_format_1 = require("../constants/ps-scan-output-format");
|
|
6
|
+
class PsScanFileNameService {
|
|
7
|
+
static build(base, format, index, count) {
|
|
8
|
+
const stem = PsScanFileNameService.sanitize(base);
|
|
9
|
+
if (format === ps_scan_output_format_1.PsScanOutputFormat.Pdf)
|
|
10
|
+
return `${stem}.pdf`;
|
|
11
|
+
if (count <= 1)
|
|
12
|
+
return `${stem}.jpg`;
|
|
13
|
+
return `${stem}-${String(index + 1).padStart(String(count).length, '0')}.jpg`;
|
|
14
|
+
}
|
|
15
|
+
static mimeType(format) {
|
|
16
|
+
return format === ps_scan_output_format_1.PsScanOutputFormat.Pdf ? 'application/pdf' : 'image/jpeg';
|
|
17
|
+
}
|
|
18
|
+
static sanitize(base) {
|
|
19
|
+
const cleaned = Array.from(base)
|
|
20
|
+
.filter((char) => char.charCodeAt(0) >= 32)
|
|
21
|
+
.join('')
|
|
22
|
+
.replace(/\.(pdf|jpe?g)$/i, '')
|
|
23
|
+
.replace(/[\\/:*?"<>|]+/g, '-')
|
|
24
|
+
.replace(/\s+/g, ' ')
|
|
25
|
+
.replace(/^[\s.-]+|[\s.-]+$/g, '');
|
|
26
|
+
return cleaned.length === 0 ? ps_scan_config_1.PsScanConfig.defaultFileName : cleaned.slice(0, 80);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.PsScanFileNameService = PsScanFileNameService;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { PsPageSize } from '../models/ps-page-size';
|
|
2
|
+
import type { PsPoint } from '../models/ps-point';
|
|
3
|
+
import type { PsScanQuad } from '../models/ps-scan-quad';
|
|
4
|
+
export declare class PsScanGeometryService {
|
|
5
|
+
static area(points: PsPoint[]): number;
|
|
6
|
+
static clamp(point: PsPoint): PsPoint;
|
|
7
|
+
static defaultQuad(): PsScanQuad;
|
|
8
|
+
static distance(from: PsPoint, to: PsPoint): number;
|
|
9
|
+
static fit(container: PsPageSize, content: PsPageSize): PsPageSize;
|
|
10
|
+
static fitWithin(size: PsPageSize, maxDimension: number): PsPageSize;
|
|
11
|
+
static isConvex(points: PsPoint[]): boolean;
|
|
12
|
+
static isUsable(quad: PsScanQuad): boolean;
|
|
13
|
+
static nudge(quad: PsScanQuad, index: number, dx: number, dy: number): PsScanQuad;
|
|
14
|
+
static order(points: PsPoint[]): PsScanQuad;
|
|
15
|
+
static outputSize(quad: PsScanQuad, raster: PsPageSize): PsPageSize;
|
|
16
|
+
static rotateSize(size: PsPageSize, rotation: number): PsPageSize;
|
|
17
|
+
static toPixels(quad: PsScanQuad, size: PsPageSize): PsScanQuad;
|
|
18
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
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 defaultQuad() {
|
|
18
|
+
const inset = 0.08;
|
|
19
|
+
return [
|
|
20
|
+
{ x: inset, y: inset },
|
|
21
|
+
{ x: 1 - inset, y: inset },
|
|
22
|
+
{ x: 1 - inset, y: 1 - inset },
|
|
23
|
+
{ x: inset, y: 1 - inset },
|
|
24
|
+
];
|
|
25
|
+
}
|
|
26
|
+
static distance(from, to) {
|
|
27
|
+
return Math.hypot(to.x - from.x, to.y - from.y);
|
|
28
|
+
}
|
|
29
|
+
static fit(container, content) {
|
|
30
|
+
if (container.width <= 0 || container.height <= 0 || content.width <= 0 || content.height <= 0)
|
|
31
|
+
return { height: 0, width: 0 };
|
|
32
|
+
const scale = Math.min(container.width / content.width, container.height / content.height);
|
|
33
|
+
return { height: content.height * scale, width: content.width * scale };
|
|
34
|
+
}
|
|
35
|
+
static fitWithin(size, maxDimension) {
|
|
36
|
+
const longest = Math.max(size.width, size.height);
|
|
37
|
+
if (longest <= maxDimension)
|
|
38
|
+
return { height: Math.round(size.height), width: Math.round(size.width) };
|
|
39
|
+
const scale = maxDimension / longest;
|
|
40
|
+
return {
|
|
41
|
+
height: Math.max(1, Math.round(size.height * scale)),
|
|
42
|
+
width: Math.max(1, Math.round(size.width * scale)),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
static isConvex(points) {
|
|
46
|
+
let sign = 0;
|
|
47
|
+
for (let index = 0; index < points.length; index += 1) {
|
|
48
|
+
const a = points[index];
|
|
49
|
+
const b = points[(index + 1) % points.length];
|
|
50
|
+
const c = points[(index + 2) % points.length];
|
|
51
|
+
const cross = (b.x - a.x) * (c.y - b.y) - (b.y - a.y) * (c.x - b.x);
|
|
52
|
+
if (Math.abs(cross) < 1e-9)
|
|
53
|
+
return false;
|
|
54
|
+
if (sign === 0)
|
|
55
|
+
sign = Math.sign(cross);
|
|
56
|
+
else if (Math.sign(cross) !== sign)
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
static isUsable(quad) {
|
|
62
|
+
return (PsScanGeometryService.isConvex(quad) &&
|
|
63
|
+
PsScanGeometryService.area(quad) > ps_scan_config_1.PsScanConfig.minCornerGap * ps_scan_config_1.PsScanConfig.minCornerGap);
|
|
64
|
+
}
|
|
65
|
+
static nudge(quad, index, dx, dy) {
|
|
66
|
+
const moved = PsScanGeometryService.clamp({ x: quad[index].x + dx, y: quad[index].y + dy });
|
|
67
|
+
const next = quad.map((point, at) => (at === index ? moved : point));
|
|
68
|
+
return PsScanGeometryService.isUsable(next) ? next : quad;
|
|
69
|
+
}
|
|
70
|
+
static order(points) {
|
|
71
|
+
const centre = {
|
|
72
|
+
x: points.reduce((sum, point) => sum + point.x, 0) / points.length,
|
|
73
|
+
y: points.reduce((sum, point) => sum + point.y, 0) / points.length,
|
|
74
|
+
};
|
|
75
|
+
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));
|
|
76
|
+
const sums = sorted.map((point) => point.x + point.y);
|
|
77
|
+
const start = sums.indexOf(Math.min(...sums));
|
|
78
|
+
return [0, 1, 2, 3].map((offset) => sorted[(start + offset) % 4]);
|
|
79
|
+
}
|
|
80
|
+
static outputSize(quad, raster) {
|
|
81
|
+
const pixels = PsScanGeometryService.toPixels(quad, raster);
|
|
82
|
+
const width = (PsScanGeometryService.distance(pixels[0], pixels[1]) +
|
|
83
|
+
PsScanGeometryService.distance(pixels[3], pixels[2])) /
|
|
84
|
+
2;
|
|
85
|
+
const height = (PsScanGeometryService.distance(pixels[0], pixels[3]) +
|
|
86
|
+
PsScanGeometryService.distance(pixels[1], pixels[2])) /
|
|
87
|
+
2;
|
|
88
|
+
return { height: Math.max(1, Math.round(height)), width: Math.max(1, Math.round(width)) };
|
|
89
|
+
}
|
|
90
|
+
static rotateSize(size, rotation) {
|
|
91
|
+
return rotation % 180 === 0 ? size : { height: size.width, width: size.height };
|
|
92
|
+
}
|
|
93
|
+
static toPixels(quad, size) {
|
|
94
|
+
return quad.map((point) => ({
|
|
95
|
+
x: point.x * size.width,
|
|
96
|
+
y: point.y * size.height,
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
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,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,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;
|