@scanmate/image-fix 0.0.3 → 0.0.5
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/README.md +115 -200
- package/dist/index.esm.js +3 -2785
- package/dist/index.esm.js.map +1 -1
- package/dist/src/index.d.ts +17 -51
- package/dist/src/index.d.ts.map +1 -1
- package/package.json +5 -7
- package/dist/src/lib/align.d.ts +0 -136
- package/dist/src/lib/align.d.ts.map +0 -1
- package/dist/src/lib/analysis/content.d.ts +0 -50
- package/dist/src/lib/analysis/content.d.ts.map +0 -1
- package/dist/src/lib/analysis/score.d.ts +0 -18
- package/dist/src/lib/analysis/score.d.ts.map +0 -1
- package/dist/src/lib/estimate/coarse.d.ts +0 -43
- package/dist/src/lib/estimate/coarse.d.ts.map +0 -1
- package/dist/src/lib/estimate/features.d.ts +0 -72
- package/dist/src/lib/estimate/features.d.ts.map +0 -1
- package/dist/src/lib/estimate/match.d.ts +0 -38
- package/dist/src/lib/estimate/match.d.ts.map +0 -1
- package/dist/src/lib/estimate/models.d.ts +0 -41
- package/dist/src/lib/estimate/models.d.ts.map +0 -1
- package/dist/src/lib/estimate/phaseCorrelation.d.ts +0 -34
- package/dist/src/lib/estimate/phaseCorrelation.d.ts.map +0 -1
- package/dist/src/lib/estimate/ransac.d.ts +0 -36
- package/dist/src/lib/estimate/ransac.d.ts.map +0 -1
- package/dist/src/lib/image/codec.d.ts +0 -30
- package/dist/src/lib/image/codec.d.ts.map +0 -1
- package/dist/src/lib/image/gray.d.ts +0 -67
- package/dist/src/lib/image/gray.d.ts.map +0 -1
- package/dist/src/lib/image/raster.d.ts +0 -19
- package/dist/src/lib/image/raster.d.ts.map +0 -1
- package/dist/src/lib/image/resize.d.ts +0 -32
- package/dist/src/lib/image/resize.d.ts.map +0 -1
- package/dist/src/lib/image/warp.d.ts +0 -28
- package/dist/src/lib/image/warp.d.ts.map +0 -1
- package/dist/src/lib/math/fft.d.ts +0 -15
- package/dist/src/lib/math/fft.d.ts.map +0 -1
- package/dist/src/lib/math/linalg.d.ts +0 -34
- package/dist/src/lib/math/linalg.d.ts.map +0 -1
- package/dist/src/lib/math/matrix.d.ts +0 -75
- package/dist/src/lib/math/matrix.d.ts.map +0 -1
- package/dist/src/lib/math/random.d.ts +0 -13
- package/dist/src/lib/math/random.d.ts.map +0 -1
- package/dist/src/lib/regions.d.ts +0 -75
- package/dist/src/lib/regions.d.ts.map +0 -1
- package/dist/src/lib/testing/synthetic.d.ts +0 -73
- package/dist/src/lib/testing/synthetic.d.ts.map +0 -1
- package/dist/src/lib/types.d.ts +0 -86
- package/dist/src/lib/types.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -1,69 +1,40 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@scanmate/image-fix`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> **Deprecated Facade Package.** `@scanmate/image-fix` has been split into focused, modular packages. This package remains available as a backward-compatible facade re-exporting all core APIs.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
flatbed scan of it comes back — turned a couple of degrees, at some other
|
|
7
|
-
resolution, cropped differently, under a shadow. Two questions are then almost
|
|
8
|
-
impossible to answer:
|
|
5
|
+
---
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
In practice, an OCR engine reads a crooked page at a different scale as a
|
|
12
|
-
different document: line grouping differs, so the diff is noise.
|
|
13
|
-
2. **Was the box at (x, y) signed?** That question is about a fixed rectangle,
|
|
14
|
-
and a rectangle only means something once both images agree where (x, y) is.
|
|
7
|
+
## Modern Package Structure
|
|
15
8
|
|
|
16
|
-
|
|
17
|
-
and the scan; it gives you the scan resampled onto the original's canvas, plus
|
|
18
|
-
the transform it used and how much it trusts it.
|
|
9
|
+
For all new projects and upgrades, prefer importing directly from the focused packages:
|
|
19
10
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
11
|
+
| You used in `@scanmate/image-fix` | Now lives in package | Primary Purpose |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `alignScan`, `alignPages`, `polishTranslation`, estimators | **[`@scanmate/align`](../align)** | Geometric registration & alignment |
|
|
14
|
+
| `compareRegions`, `diffDocument`, `renderDiff`, `diffPage` | **[`@scanmate/diff`](../diff)** | Visual change detection & form region verification |
|
|
15
|
+
| `decodeImage`, `encodeImage`, `inkMap`, `warpRaster`, `Matrix3` | **[`@scanmate/ink`](../ink)** | Low-level pixel kernel, illumination division & geometry |
|
|
16
|
+
| `extractPair`, `extractPages`, `inspectPage`, `renderPage` | **[`@scanmate/extract`](../extract)** | PDF document rendering, inspection & DPI auto-resolution |
|
|
25
17
|
|
|
26
|
-
|
|
18
|
+
---
|
|
27
19
|
|
|
28
|
-
|
|
29
|
-
npm install @scanmate/image-fix
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Quick start
|
|
33
|
-
|
|
34
|
-
```ts
|
|
35
|
-
import { readFile } from 'node:fs/promises'
|
|
36
|
-
import { alignScan, compareRegions } from '@scanmate/image-fix'
|
|
37
|
-
|
|
38
|
-
const original = await readFile('contract.page1.png') // rendered from the PDF
|
|
39
|
-
const scanned = await readFile('returned.jpg') // what came back
|
|
40
|
-
|
|
41
|
-
const result = alignScan(original, scanned)
|
|
42
|
-
|
|
43
|
-
console.log(result.confidence) // 0.96
|
|
44
|
-
console.log(result.transform.rotationDeg) // -2.68
|
|
45
|
-
console.log(result.transform.scaleX) // 1.449
|
|
20
|
+
## Architectural Changes & Breaking Notes
|
|
46
21
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
{ id: 'signature', rect: { x: 76, y: 905, width: 420, height: 78 } },
|
|
50
|
-
])
|
|
22
|
+
1. **Asynchronous Codec Operations**: All functions that encode or decode images (`decodeImage`, `encodeImage`, `alignScan`, `compareRegions`, `diffDocument`, `renderDiff`) are now **asynchronous** (`Promise`-based) because the image codec migrated to libvips via `sharp`. This yields a **~20x speedup** when encoding full-page PNGs and enables native support for TIFF, HEIF, WebP, and AVIF formats.
|
|
23
|
+
2. **Metadata Inspection**: `sniffFormat` has been replaced by `readImageMetadata` in `@scanmate/ink`.
|
|
51
24
|
|
|
52
|
-
|
|
53
|
-
console.log(signature.added) // 0.056 - 5.6% of the box is ink that is not in the original
|
|
54
|
-
```
|
|
25
|
+
---
|
|
55
26
|
|
|
56
|
-
|
|
57
|
-
engine. `result.raster` is the same thing undecoded, if your OCR engine takes
|
|
58
|
-
raw RGBA.
|
|
27
|
+
## Installation
|
|
59
28
|
|
|
60
|
-
|
|
29
|
+
```bash
|
|
30
|
+
# Using npm
|
|
31
|
+
npm install @scanmate/image-fix
|
|
61
32
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
scale + skew + matching + model
|
|
33
|
+
# Or install the modular packages directly:
|
|
34
|
+
npm install @scanmate/align @scanmate/diff @scanmate/ink @scanmate/extract
|
|
65
35
|
```
|
|
66
36
|
|
|
37
|
+
---
|
|
67
38
|
> What follows is the reasoning. For the full algorithm - the formulae, every
|
|
68
39
|
> constant, the coordinate-frame algebra and the measured error - see
|
|
69
40
|
> [`documentation/fix.md`](https://github.com/russoedu/scanmate/blob/main/documentation/fix.md).
|
|
@@ -110,182 +81,126 @@ FAST corners, oriented by the intensity centroid of their patch, described by
|
|
|
110
81
|
256 steered BRIEF bits — an ORB, written out, because the native one is
|
|
111
82
|
unavailable here.
|
|
112
83
|
|
|
113
|
-
|
|
114
|
-
now at the same scale and nearly the same angle, so a fixed-offset descriptor
|
|
115
|
-
describes the same thing on both, and any correspondence that jumps across the
|
|
116
|
-
page can be thrown out on sight. RANSAC then recovers only the small residual,
|
|
117
|
-
which is composed onto the coarse transform.
|
|
118
|
-
|
|
119
|
-
RANSAC is not optional. A page of text is full of things that genuinely look
|
|
120
|
-
identical — every lowercase "e", every corner of every table cell — so matching
|
|
121
|
-
produces a lot of confident nonsense, and least squares over all of it is
|
|
122
|
-
dragged wherever the wrong matches point. RANSAC ignores the average: it fits
|
|
123
|
-
the smallest sample that determines a transform and counts how many of the rest
|
|
124
|
-
agree. Measured on the test suite, it recovers the right answer with 60% of the
|
|
125
|
-
matches wrong.
|
|
126
|
-
|
|
127
|
-
If the feature stage comes up short — a near-blank form has few corners — the
|
|
128
|
-
coarse estimate is returned alone and `result.method` says `'coarse'`.
|
|
129
|
-
|
|
130
|
-
### 4. The warp
|
|
131
|
-
|
|
132
|
-
Inverse mapping: walk each output pixel and reach back into the scan, rather
|
|
133
|
-
than pushing scan pixels forward, which leaves the output full of pinholes
|
|
134
|
-
wherever the transform stretches, like spray-painting through a rotated
|
|
135
|
-
stencil. Minification pre-filters first, so shrinking a 300 dpi scan averages
|
|
136
|
-
the strokes instead of beating against them into moiré.
|
|
137
|
-
|
|
138
|
-
## Choosing a model
|
|
84
|
+
## Quick Start
|
|
139
85
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
| model | DOF | use when |
|
|
144
|
-
| --- | --- | --- |
|
|
145
|
-
| `similarity` (default) | 4 | a flatbed or sheet-fed scan. The page is flat, so it can only be turned, resized and moved. |
|
|
146
|
-
| `affine` | 6 | one axis is stretched — a feed roller slipping. |
|
|
147
|
-
| `homography` | 8 | a photograph taken off-axis, where the far edge of the page really is smaller than the near one. |
|
|
148
|
-
|
|
149
|
-
Use the simplest one the physical situation allows. A homography fitted to a
|
|
150
|
-
flatbed scan has four extra parameters to spend on fitting noise.
|
|
151
|
-
|
|
152
|
-
## API
|
|
86
|
+
```ts
|
|
87
|
+
import { alignScan, compareRegions, decodeImage } from '@scanmate/image-fix'
|
|
88
|
+
import { readFile } from 'node:fs/promises'
|
|
153
89
|
|
|
154
|
-
|
|
90
|
+
const original = await decodeImage(await readFile('contract_p1.png'))
|
|
91
|
+
const scanned = await decodeImage(await readFile('returned_scan.jpg'))
|
|
155
92
|
|
|
156
|
-
|
|
157
|
-
`async` signature would imply the event loop is free during the call, and it is
|
|
158
|
-
not. To align several pages at once, put it in a worker thread.
|
|
93
|
+
const result = await alignScan(original, scanned, { model: 'similarity' })
|
|
159
94
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
95
|
+
const [sigReport] = compareRegions(original, result.raster, [
|
|
96
|
+
{ id: 'signature', rect: { x: 76, y: 905, width: 420, height: 78 } },
|
|
97
|
+
])
|
|
98
|
+
```
|
|
163
99
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Facade Architecture & Dependency Topology
|
|
103
|
+
|
|
104
|
+
```mermaid
|
|
105
|
+
flowchart TD
|
|
106
|
+
App["Application / Legacy Caller"] --> Facade["@scanmate/image-fix<br/>(Backward Compatibility Facade)"]
|
|
107
|
+
|
|
108
|
+
subgraph ModularPackages["ScanMate Core Ecosystem"]
|
|
109
|
+
Align["@scanmate/align<br/>Registration & RANSAC Engine"]
|
|
110
|
+
Diff["@scanmate/diff<br/>Change Detection & Region Reports"]
|
|
111
|
+
Extract["@scanmate/extract<br/>PDF Parsing & Skia Rendering"]
|
|
112
|
+
Ink["@scanmate/ink<br/>Pixel Kernel & Sharp Codec"]
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
Facade --> Align
|
|
116
|
+
Facade --> Diff
|
|
117
|
+
Facade --> Extract
|
|
118
|
+
Facade --> Ink
|
|
119
|
+
|
|
120
|
+
Align --> Ink
|
|
121
|
+
Diff --> Ink
|
|
122
|
+
Extract --> Ink
|
|
123
|
+
Diff -. optional .-> Align
|
|
124
|
+
Extract -. optional .-> Align
|
|
175
125
|
```
|
|
176
126
|
|
|
177
|
-
|
|
178
|
-
Above ~0.6 is a solid match on a printed page; below ~0.3, treat the alignment
|
|
179
|
-
as failed and do not trust any region report built on it.
|
|
127
|
+
---
|
|
180
128
|
|
|
181
|
-
|
|
129
|
+
## Comprehensive Re-Export API Reference
|
|
182
130
|
|
|
183
|
-
|
|
184
|
-
| --- | --- | --- |
|
|
185
|
-
| `model` | `'similarity'` | see above |
|
|
186
|
-
| `workingSize` | `1400` | longest side for feature detection. Bigger is more precise and quadratically slower |
|
|
187
|
-
| `coarseSize` | `512` | longest side for the coarse guess |
|
|
188
|
-
| `maxFeatures` | `1200` | keypoint budget per image |
|
|
189
|
-
| `ransacThreshold` | `3` | inlier radius, in working-resolution pixels |
|
|
190
|
-
| `minInliers` | `12` | below this the feature stage is not trusted |
|
|
191
|
-
| `maxSkewDeg` | `12` | largest per-page skew considered |
|
|
192
|
-
| `interpolation` | `'bilinear'` | or `'bicubic'` (sharper strokes when upscaling), `'nearest'` |
|
|
193
|
-
| `background` | white | RGBA fill where the scan does not cover the canvas |
|
|
194
|
-
| `output` | `'png'` | `'jpeg'` or `'none'`. Encoding is most of the cost on a big page |
|
|
195
|
-
| `seed` | fixed | seeds RANSAC and the descriptor pattern, so the same bytes give the same matrix |
|
|
196
|
-
|
|
197
|
-
### `compareRegions(original, aligned, regions, options?): RegionReport[]`
|
|
198
|
-
|
|
199
|
-
Answers "was this box filled in?" as arithmetic: count the ink inside the
|
|
200
|
-
rectangle that is in the scan and not in the original.
|
|
131
|
+
### 1. Alignment Methods (Delegates to [`@scanmate/align`](../align))
|
|
201
132
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
133
|
+
#### `alignScan(original, scanned, options?: AlignOptions): Promise<AlignResult>`
|
|
134
|
+
Resamples scanned page onto original canvas.
|
|
135
|
+
- **Options**:
|
|
136
|
+
- `model` (`'similarity'` | `'affine'` | `'homography'`, default: `'similarity'`): Geometric model.
|
|
137
|
+
- `workingSize` (default: 1400): Longest dimension for feature matching.
|
|
138
|
+
- `coarseSize` (default: 512): Initial coarse sweep resolution.
|
|
139
|
+
- `maxFeatures` (default: 1200): ORB keypoint cap per image.
|
|
140
|
+
- `ransacThreshold` (default: 3.0): Inlier reprojection error bound in px.
|
|
141
|
+
- `minInliers` (default: 12): Minimum inliers needed to trust feature stage.
|
|
142
|
+
- `interpolation` (`'bilinear'` | `'bicubic'` | `'nearest'`): Resampling kernel.
|
|
143
|
+
- `output` (`'png'` | `'jpeg'` | `'none'`): Encoded output format.
|
|
208
144
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
refuses two images on different canvases outright.
|
|
145
|
+
#### `alignPages(pages, options?: AlignPagesOptions): Promise<AlignedPage[]>`
|
|
146
|
+
Multi-page document batch alignment handler.
|
|
212
147
|
|
|
213
|
-
|
|
214
|
-
diffing. Alignment is good to about a pixel, never to zero, and printed text is
|
|
215
|
-
mostly edges, so without it a half-pixel shift lights up the outline of every
|
|
216
|
-
character as new ink — the way a proofreader ignores a letter sitting a hair
|
|
217
|
-
off the baseline. What it cannot absorb is a signature, which is ink where the
|
|
218
|
-
original has none.
|
|
148
|
+
---
|
|
219
149
|
|
|
220
|
-
|
|
221
|
-
as a multiple of that threshold, clamped to 1, if you want a number rather than
|
|
222
|
-
a boolean.
|
|
150
|
+
### 2. Diffing & Change Detection (Delegates to [`@scanmate/diff`](../diff))
|
|
223
151
|
|
|
224
|
-
|
|
152
|
+
#### `compareRegions(original, aligned, regions, options?: RegionOptions): RegionReport[]`
|
|
153
|
+
Evaluates form fields to check if signatures or checkboxes were filled.
|
|
154
|
+
- **Options**:
|
|
155
|
+
- `tolerance` (default: 2): Morphological dilation radius in pixels.
|
|
156
|
+
- `threshold` (default: 0.02): Added ink ratio for `filled: true`.
|
|
225
157
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
nothing was written on it.
|
|
158
|
+
#### `diffDocument(original, aligned, regions?, options?: RegionOptions): DocumentDiff`
|
|
159
|
+
Computes whole-page and per-region ink addition/subtraction metrics in one pass.
|
|
229
160
|
|
|
230
|
-
|
|
161
|
+
#### `renderDiff(original, aligned, options?: RegionOptions): Raster`
|
|
162
|
+
Renders 4-color RGBA visual overlay (Red = scan additions, Blue = template deletions, Grey = matched ink).
|
|
231
163
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
almost entirely grey with a red signature; a misaligned one is red and blue
|
|
235
|
-
confetti along every stroke — the fastest way to tell those two failures apart.
|
|
164
|
+
#### `diffPage(options: DiffOptions): Promise<PageDiff>`
|
|
165
|
+
Full page change detection isolating unexpected handwritten edits via 2-pass connected component analysis.
|
|
236
166
|
|
|
237
|
-
|
|
167
|
+
---
|
|
238
168
|
|
|
239
|
-
|
|
240
|
-
`decodeImage`, `encodeImage`, `toGrayscale`, `inkMap`, `binarize`, `dilate`,
|
|
241
|
-
`estimateSkew`, `contentExtent`, `estimateCoarse`, `detectAndDescribe`,
|
|
242
|
-
`matchFeatures`, `fitSimilarity` / `fitAffine` / `fitHomography`, `ransac`,
|
|
243
|
-
`phaseCorrelate`, `warpRaster`, `warpGray`, and the `Matrix3` helpers.
|
|
169
|
+
### 3. Kernel & Pixel Operations (Delegates to [`@scanmate/ink`](../ink))
|
|
244
170
|
|
|
245
|
-
|
|
171
|
+
#### `decodeImage(buffer, options?: DecodeOptions): Promise<Raster>`
|
|
172
|
+
Decodes image bytes to RGBA `Raster` via `sharp`.
|
|
173
|
+
- **Options**: `pageNumber` (for multi-page TIFF), `maxWidth`, `maxHeight`.
|
|
246
174
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
folder because the same trick smoke-tests a deployment without shipping sample
|
|
251
|
-
scans:
|
|
175
|
+
#### `encodeImage(raster, options?: EncodeOptions): Promise<Uint8Array>`
|
|
176
|
+
Encodes RGBA `Raster` to PNG/JPEG bytes via `sharp`.
|
|
177
|
+
- **Options**: `format` (`'png'`, `'jpeg'`, `'webp'`, `'avif'`), `quality` (1-100), `compression` (0-9).
|
|
252
178
|
|
|
253
|
-
|
|
254
|
-
|
|
179
|
+
#### `inkMap(gray, options?: InkOptions): GrayImage`
|
|
180
|
+
Performs background division ($I_{ink} = 1 - I / I_{bg}$).
|
|
181
|
+
- **Options**: `blurRadius` (default: 25), `invert` (default: true).
|
|
255
182
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
183
|
+
#### `warpRaster(raster, output, invMatrix, options?: WarpOptions): void`
|
|
184
|
+
Resamples input `Raster` using inverse 3x3 homography matrix.
|
|
185
|
+
- **Options**: `interpolation` (`'bilinear'`, `'bicubic'`, `'nearest'`), `background` (`RGBA`).
|
|
259
186
|
|
|
260
|
-
|
|
261
|
-
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
### 4. PDF Extraction & Inspection (Delegates to [`@scanmate/extract`](../extract))
|
|
262
190
|
|
|
263
|
-
|
|
191
|
+
#### `extractPair(options: ExtractPairOptions): Promise<PairedDocument>`
|
|
192
|
+
Parses, auto-detects scan DPI, and renders paired original/scanned PDF pages.
|
|
193
|
+
- **Options**: `original`, `scanned`, `dpi` (`'native'` or fixed number), `pageSelection`.
|
|
264
194
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
- **The page must be recognisably the same page.** It is registration, not
|
|
268
|
-
retrieval: it will happily align the wrong document badly and tell you so
|
|
269
|
-
through a low `confidence`. Check that number.
|
|
270
|
-
- **Flat pages only.** A creased or curled page needs a non-rigid warp;
|
|
271
|
-
`homography` will get the plane right and leave the curl.
|
|
272
|
-
- **Not scale-free.** `maxScaleRatio` (default 6) bounds how far apart the two
|
|
273
|
-
resolutions may be. Beyond that, resample first.
|
|
274
|
-
- **Blank pages degrade gracefully, not magically.** With almost no printing
|
|
275
|
-
there is nothing to register on; you get `method: 'coarse'` and a low
|
|
276
|
-
confidence, which is the honest answer.
|
|
195
|
+
#### `inspectPage(pdf, pageIndex): Promise<PageMetadata>`
|
|
196
|
+
Inspects PDF operator streams and classifies page as `'scanned'`, `'born-digital'`, or `'mixed'`.
|
|
277
197
|
|
|
278
|
-
|
|
198
|
+
---
|
|
279
199
|
|
|
280
|
-
|
|
281
|
-
in roughly 1.6 s, of which the feature stage is about half. Lower `workingSize`
|
|
282
|
-
to trade accuracy for speed; set `output: 'none'` if you are going to hand
|
|
283
|
-
`raster` straight to something else, since PNG encoding a big page is a
|
|
284
|
-
substantial share of the total.
|
|
200
|
+
## License
|
|
285
201
|
|
|
286
|
-
|
|
287
|
-
100 megapixel scan will hurt.
|
|
202
|
+
MIT © [ScanMate Team](https://github.com/russoedu/scanmate)
|
|
288
203
|
|
|
289
|
-
##
|
|
204
|
+
## Where the algorithms went
|
|
290
205
|
|
|
291
|
-
|
|
206
|
+
[`documentation/algorithms.md`](./documentation/algorithms.md) maps every algorithm this package used to carry to the package that documents it now.
|