@georeferencing/plugins 0.2.0 → 0.3.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/README.md +8 -5
- package/dist/data-export.d.ts +2 -1
- package/dist/data-export.js +3 -3
- package/dist/data.d.ts +9 -3
- package/dist/data.js +14 -6
- package/dist/geotiff.d.ts +2 -1
- package/dist/geotiff.js +2 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -1
- package/dist/jpeg.d.ts +2 -1
- package/dist/pdf.d.ts +2 -1
- package/dist/report.d.ts +7 -1
- package/dist/report.js +8 -2
- package/dist/serializers.d.ts +18 -4
- package/dist/serializers.js +16 -6
- package/dist/tiff-options.d.ts +27 -0
- package/dist/tiff-options.js +48 -0
- package/dist/tiff.d.ts +9 -9
- package/dist/tiff.js +5 -25
- package/dist/workers/geotiff.js +2 -2
- package/dist/workers/jpeg.js +1 -1
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -20,9 +20,10 @@ pnpm add @georeferencing/react react@19 react-dom@19 ol@10
|
|
|
20
20
|
The package ships ESM, TypeScript declarations and codec-worker assets. Node.js
|
|
21
21
|
22.12+ is the declared tooling requirement; repository development uses pnpm 12.x.
|
|
22
22
|
**Install the same version of `@georeferencing/plugins`, `@georeferencing/core`
|
|
23
|
-
and (if used) `@georeferencing/react`**, and upgrade them together. Plugins
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
and (if used) `@georeferencing/react`**, and upgrade them together. Plugins declare
|
|
24
|
+
core as a peer dependency and use your application's copy; a mismatched version is
|
|
25
|
+
reported as a peer-dependency conflict rather than installing a second core whose
|
|
26
|
+
projection registry and worker code are separate from the controller's. See
|
|
26
27
|
[keep package versions aligned](https://georeferencing-api-docs.gh.tobilg.com/Getting_started/#keep-package-versions-aligned).
|
|
27
28
|
|
|
28
29
|
Core alone enables no exports. Import only the factories your application uses.
|
|
@@ -80,7 +81,7 @@ its host-owned engine when the session is permanently finished.
|
|
|
80
81
|
| `geoTiff()` | `/geotiff` | `geotiff` | Georeferenced TIFF; valid fit |
|
|
81
82
|
| `jpeg()` | `/jpeg` | `jpeg` | JPEG, `.jgw`, `.crs.json`; valid fit |
|
|
82
83
|
| `pdf()` | `/pdf` | `pdf` | PDF alignment/map report; valid fit and preview |
|
|
83
|
-
| `worldFile()` | `/data` | `world-file` | Original-resolution normalized PNG, `.pgw`, CRS sidecar; Linear/Helmert without reprojection |
|
|
84
|
+
| `worldFile()` | `/data` | `world-file` | Original-resolution normalized PNG, `.pgw`, CRS sidecar; Linear/Helmert (or also affine with `{ affine: true }`) without reprojection |
|
|
84
85
|
| `session()` | `/data` | `session` | Complete session JSON; fit may be unfinished |
|
|
85
86
|
| `points(definitions?)` | `/data` | `points` | QGIS `.points`; fit may be unfinished |
|
|
86
87
|
| `accuracy()` | `/data` | `accuracy` | Full-precision JSON diagnostics; valid fit |
|
|
@@ -188,7 +189,9 @@ partial alpha; choose a value that does not collide with valid RGB data. Deflate
|
|
|
188
189
|
requires browser CompressionStream support.
|
|
189
190
|
|
|
190
191
|
This encoder writes classic TIFF below 4 GiB and requires an EPSG code below
|
|
191
|
-
32767
|
|
192
|
+
32767; EPSG URI/URN aliases are accepted (`geoTiffEpsg` from `/tiff` resolves them).
|
|
193
|
+
The `geoTiff()` format reports an ineligible output CRS or TIFF option before any
|
|
194
|
+
rendering starts. BigTIFF, COG layout, arbitrary-WKT GeoKeys, scientific sample preservation
|
|
192
195
|
and multipage output are outside the supported envelope. See the
|
|
193
196
|
[capabilities and limits](https://github.com/tobilg/georeferencing/blob/main/packages/documentation/guides/capabilities.md)
|
|
194
197
|
for the supported output envelope and QGIS compatibility boundaries.
|
package/dist/data-export.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Definitions, Exporter } from "@georeferencing/core";
|
|
2
|
+
import type { WorldFileOptions } from "./serializers.js";
|
|
2
3
|
/** @internal */
|
|
3
4
|
export declare const sessionExporter: Exporter;
|
|
4
5
|
/** @internal */
|
|
@@ -6,4 +7,4 @@ export declare function pointsExporter(definitions: Definitions): Exporter;
|
|
|
6
7
|
/** @internal */
|
|
7
8
|
export declare const accuracyExporter: Exporter;
|
|
8
9
|
/** @internal */
|
|
9
|
-
export declare const worldFileExporter: Exporter;
|
|
10
|
+
export declare const worldFileExporter: (options: WorldFileOptions) => Exporter;
|
package/dist/data-export.js
CHANGED
|
@@ -29,11 +29,11 @@ export const accuracyExporter = {
|
|
|
29
29
|
},
|
|
30
30
|
};
|
|
31
31
|
/** @internal */
|
|
32
|
-
export const worldFileExporter = {
|
|
32
|
+
export const worldFileExporter = (options) => ({
|
|
33
33
|
async run({ document, fit, file, engine, tag, signal, onProgress }) {
|
|
34
34
|
if (!fit || !file || !document.sourceImage)
|
|
35
35
|
throw Error("A matching image and fit are required.");
|
|
36
|
-
const placement = worldFile(fit, document.workingCrs, document.output.crs);
|
|
36
|
+
const placement = worldFile(fit, document.workingCrs, document.output.crs, options);
|
|
37
37
|
const result = await engine.run({ kind: "normalize", file, metadata: document.sourceImage }, tag, { signal, onProgress });
|
|
38
38
|
signal.throwIfAborted();
|
|
39
39
|
if (!result.blob)
|
|
@@ -54,4 +54,4 @@ export const worldFileExporter = {
|
|
|
54
54
|
],
|
|
55
55
|
};
|
|
56
56
|
},
|
|
57
|
-
};
|
|
57
|
+
});
|
package/dist/data.d.ts
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Optional session, QGIS points, world-file and accuracy exports.
|
|
3
|
-
* @module data
|
|
3
|
+
* @module @georeferencing/plugins/data
|
|
4
|
+
* @group @georeferencing/plugins
|
|
4
5
|
*/
|
|
5
6
|
import type { Definitions, ExportFormat } from "@georeferencing/core";
|
|
7
|
+
import type { WorldFileOptions } from "./serializers.js";
|
|
8
|
+
export type { WorldFileOptions } from "./serializers.js";
|
|
6
9
|
/** Register a complete version-1 JSON session download, even before a valid fit. */
|
|
7
10
|
export declare function session(): ExportFormat;
|
|
8
11
|
/** Register QGIS .points download, projecting targets with the supplied definitions. */
|
|
9
12
|
export declare function points(definitions?: Definitions): ExportFormat;
|
|
10
13
|
/** Register a full-precision JSON alignment report with training residual formulas. */
|
|
11
14
|
export declare function accuracy(): ExportFormat;
|
|
12
|
-
/**
|
|
13
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Register original-resolution normalized PNG, world file and explicit CRS sidecar.
|
|
17
|
+
* @param options - Set `affine` to also offer world files for Polynomial 1 fits.
|
|
18
|
+
*/
|
|
19
|
+
export declare function worldFile(options?: WorldFileOptions): ExportFormat;
|
package/dist/data.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { normalizeCrs } from "@georeferencing/core";
|
|
2
|
+
import { worldFileModels } from "./serializers.js";
|
|
1
3
|
/** Register a complete version-1 JSON session download, even before a valid fit. */
|
|
2
4
|
export function session() {
|
|
3
5
|
return {
|
|
@@ -24,15 +26,21 @@ export function accuracy() {
|
|
|
24
26
|
load: async () => (await import("./data-export.js")).accuracyExporter,
|
|
25
27
|
};
|
|
26
28
|
}
|
|
27
|
-
/**
|
|
28
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Register original-resolution normalized PNG, world file and explicit CRS sidecar.
|
|
31
|
+
* @param options - Set `affine` to also offer world files for Polynomial 1 fits.
|
|
32
|
+
*/
|
|
33
|
+
export function worldFile(options = {}) {
|
|
34
|
+
const models = worldFileModels(options);
|
|
29
35
|
return {
|
|
30
36
|
id: "world-file",
|
|
31
37
|
label: "World file & CRS",
|
|
32
|
-
unavailable: (doc) =>
|
|
33
|
-
doc.workingCrs === doc.output.crs
|
|
38
|
+
unavailable: (doc) => models.includes(doc.model) &&
|
|
39
|
+
normalizeCrs(doc.workingCrs) === normalizeCrs(doc.output.crs)
|
|
34
40
|
? null
|
|
35
|
-
:
|
|
36
|
-
|
|
41
|
+
: options.affine
|
|
42
|
+
? "World-file output requires a Linear, Helmert or affine fit without reprojection."
|
|
43
|
+
: "World-file output requires Linear/Helmert without reprojection.",
|
|
44
|
+
load: async () => (await import("./data-export.js")).worldFileExporter(options),
|
|
37
45
|
};
|
|
38
46
|
}
|
package/dist/geotiff.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Optional GeoTIFF export; import from `@georeferencing/plugins/geotiff`.
|
|
3
|
-
* @module geotiff
|
|
3
|
+
* @module @georeferencing/plugins/geotiff
|
|
4
|
+
* @group @georeferencing/plugins
|
|
4
5
|
*/
|
|
5
6
|
import type { ExportFormat } from "@georeferencing/core";
|
|
6
7
|
import type { RasterPluginOptions } from "./types.js";
|
package/dist/geotiff.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { geoTiffUnavailable } from "./tiff-options.js";
|
|
1
2
|
/**
|
|
2
3
|
* Register lazy GeoTIFF export. Encoding runs in a dedicated plugin worker using
|
|
3
4
|
* the controller engine's limits, projections, scheduler and cancellation.
|
|
@@ -8,6 +9,7 @@ export function geoTiff(options = {}) {
|
|
|
8
9
|
id: "geotiff",
|
|
9
10
|
label: "Export GeoTIFF",
|
|
10
11
|
raster: true,
|
|
12
|
+
unavailable: (document) => geoTiffUnavailable(document.output),
|
|
11
13
|
load: async () => {
|
|
12
14
|
const { renderAndEncode } = await import("./raster-export.js");
|
|
13
15
|
return {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Optional lazy export formats. Prefer per-format imports to give bundlers the
|
|
3
3
|
* narrowest dependency graph. Register descriptors with ControllerOptions.exports.
|
|
4
|
-
* @module plugins
|
|
4
|
+
* @module @georeferencing/plugins
|
|
5
|
+
* @group @georeferencing/plugins
|
|
5
6
|
*/
|
|
7
|
+
export type { WorldFileOptions } from "./data.js";
|
|
6
8
|
export { accuracy, points, session, worldFile } from "./data.js";
|
|
7
9
|
export { geoTiff } from "./geotiff.js";
|
|
8
10
|
export { jpeg } from "./jpeg.js";
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Optional lazy export formats. Prefer per-format imports to give bundlers the
|
|
3
3
|
* narrowest dependency graph. Register descriptors with ControllerOptions.exports.
|
|
4
|
-
* @module plugins
|
|
4
|
+
* @module @georeferencing/plugins
|
|
5
|
+
* @group @georeferencing/plugins
|
|
5
6
|
*/
|
|
6
7
|
export { accuracy, points, session, worldFile } from "./data.js";
|
|
7
8
|
export { geoTiff } from "./geotiff.js";
|
package/dist/jpeg.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Optional georeferenced JPEG export; import from `@georeferencing/plugins/jpeg`.
|
|
3
|
-
* @module jpeg
|
|
3
|
+
* @module @georeferencing/plugins/jpeg
|
|
4
|
+
* @group @georeferencing/plugins
|
|
4
5
|
*/
|
|
5
6
|
import type { ExportFormat } from "@georeferencing/core";
|
|
6
7
|
import type { JpegOptions } from "./types.js";
|
package/dist/pdf.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Optional PDF report; import from `@georeferencing/plugins/pdf`.
|
|
3
|
-
* @module pdf
|
|
3
|
+
* @module @georeferencing/plugins/pdf
|
|
4
|
+
* @group @georeferencing/plugins
|
|
4
5
|
*/
|
|
5
6
|
import type { ExportFormat } from "@georeferencing/core";
|
|
6
7
|
import type { ReportMap, ReportOptions } from "./report.js";
|
package/dist/report.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Low-level PDF report creation and optional OpenLayers map capture; pdf-lib loads lazily.
|
|
3
|
+
* Import from `@georeferencing/plugins/report`.
|
|
4
|
+
* @module @georeferencing/plugins/report
|
|
5
|
+
* @group @georeferencing/plugins
|
|
6
|
+
*/
|
|
1
7
|
import type { Definitions, Document, Fit } from "@georeferencing/core";
|
|
2
8
|
import type { Raster } from "@georeferencing/core/engine";
|
|
3
9
|
/** Minimal view contract needed to annotate a captured map; OpenLayers View satisfies it. */
|
|
@@ -64,7 +70,7 @@ export interface ReportOptions {
|
|
|
64
70
|
*
|
|
65
71
|
* Calls renderSync and copies available canvas content; does not await outstanding tiles or capture arbitrary DOM overlays. WebGL/non-canvas renderers are outside this capture contract.
|
|
66
72
|
* @param map - Visible initialized host map.
|
|
67
|
-
* @throws {@link core.GeoreferenceError} If the viewport is unavailable or a source taints canvas export.
|
|
73
|
+
* @throws {@link "@georeferencing/core".GeoreferenceError} If the viewport is unavailable or a source taints canvas export.
|
|
68
74
|
*/
|
|
69
75
|
export declare function captureMap(map: ReportMap): Promise<Blob>;
|
|
70
76
|
/**
|
package/dist/report.js
CHANGED
|
@@ -15,7 +15,7 @@ async function png(canvas) {
|
|
|
15
15
|
*
|
|
16
16
|
* Calls renderSync and copies available canvas content; does not await outstanding tiles or capture arbitrary DOM overlays. WebGL/non-canvas renderers are outside this capture contract.
|
|
17
17
|
* @param map - Visible initialized host map.
|
|
18
|
-
* @throws {@link core.GeoreferenceError} If the viewport is unavailable or a source taints canvas export.
|
|
18
|
+
* @throws {@link "@georeferencing/core".GeoreferenceError} If the viewport is unavailable or a source taints canvas export.
|
|
19
19
|
*/
|
|
20
20
|
export async function captureMap(map) {
|
|
21
21
|
map.renderSync();
|
|
@@ -99,8 +99,14 @@ export async function createPdfReport(doc, fit, raster, options = {}) {
|
|
|
99
99
|
page = pdf.addPage([pageWidth, pageHeight]);
|
|
100
100
|
y = pageHeight - margin;
|
|
101
101
|
};
|
|
102
|
+
// Standard fonts use WinAnsi: keep every encodable character (such as umlauts and
|
|
103
|
+
// accents) and replace the rest; the attached JSON retains the full Unicode text.
|
|
104
|
+
const encodable = new Set(font.getCharacterSet());
|
|
102
105
|
const text = (value, size = 10, fixed = false) => {
|
|
103
|
-
const safe = value.
|
|
106
|
+
const safe = Array.from(value.normalize("NFC"), (character) => {
|
|
107
|
+
const code = character.codePointAt(0);
|
|
108
|
+
return code >= 0x20 && encodable.has(code) ? character : "?";
|
|
109
|
+
}).join(""), width = Math.max(1, Math.floor(contentWidth / (size * (fixed ? 0.6 : 0.55))));
|
|
104
110
|
for (let i = 0; i < safe.length || i === 0; i += width) {
|
|
105
111
|
if (y < margin + size)
|
|
106
112
|
newPage();
|
package/dist/serializers.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pure serializers for QGIS points, world files and alignment accuracy reports.
|
|
3
3
|
* Import from `@georeferencing/plugins/serializers`; no workers or UI are loaded.
|
|
4
|
-
* @module serializers
|
|
4
|
+
* @module @georeferencing/plugins/serializers
|
|
5
|
+
* @group @georeferencing/plugins
|
|
5
6
|
*/
|
|
6
7
|
import type { Definitions, Document, Fit } from "@georeferencing/core";
|
|
7
8
|
/**
|
|
@@ -10,13 +11,26 @@ import type { Definitions, Document, Fit } from "@georeferencing/core";
|
|
|
10
11
|
* Residual columns are placeholders set to zero; use `accuracyReport` for actual diagnostics. IDs and snap provenance are not represented by this format.
|
|
11
12
|
*/
|
|
12
13
|
export declare function exportPoints(doc: Document, definitions?: Definitions): string;
|
|
14
|
+
/** Options for world-file placement. */
|
|
15
|
+
export interface WorldFileOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Also accept Polynomial 1 (affine) fits. A world file represents any affine transform
|
|
18
|
+
* exactly, including rotation and shear; QGIS offers world files only for Linear and
|
|
19
|
+
* Helmert, so this is opt-in.
|
|
20
|
+
* @defaultValue `false`
|
|
21
|
+
*/
|
|
22
|
+
affine?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** Models a world file can represent with the given options. @internal */
|
|
25
|
+
export declare function worldFileModels(options?: WorldFileOptions): string[];
|
|
13
26
|
/**
|
|
14
|
-
* Create a six-line world file plus an explicit CRS sidecar value for Linear or Helmert fits without reprojection.
|
|
27
|
+
* Create a six-line world file plus an explicit CRS sidecar value for Linear or Helmert fits (and optionally affine fits) without reprojection.
|
|
15
28
|
*
|
|
16
29
|
* Line order is A, D, B, E, C, F. The final two values locate the first pixel centre, `[0.5, 0.5]`. A world file alone contains no CRS.
|
|
17
|
-
* @
|
|
30
|
+
* @param options - Set `affine` to also accept Polynomial 1 fits.
|
|
31
|
+
* @throws {@link "@georeferencing/core".GeoreferenceError} For ineligible models or different working/output CRSs.
|
|
18
32
|
*/
|
|
19
|
-
export declare function worldFile(fit: Fit, workingCrs: string, outputCrs: string): {
|
|
33
|
+
export declare function worldFile(fit: Fit, workingCrs: string, outputCrs: string, options?: WorldFileOptions): {
|
|
20
34
|
/**
|
|
21
35
|
* Six newline-separated values in A, D, B, E, C, F order, including the pixel-centre
|
|
22
36
|
* offset.
|
package/dist/serializers.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ENGINE_VERSION, fail, forward, project } from "@georeferencing/core";
|
|
1
|
+
import { ENGINE_VERSION, fail, forward, normalizeCrs, project, } from "@georeferencing/core";
|
|
2
2
|
/**
|
|
3
3
|
* Export a QGIS-compatible `.points` text file. Targets are projected into the document working CRS; canonical image y is negated to QGIS source y-up coordinates.
|
|
4
4
|
*
|
|
@@ -19,15 +19,25 @@ export function exportPoints(doc, definitions = {}) {
|
|
|
19
19
|
.join("\n") +
|
|
20
20
|
"\n");
|
|
21
21
|
}
|
|
22
|
+
/** Models a world file can represent with the given options. @internal */
|
|
23
|
+
export function worldFileModels(options = {}) {
|
|
24
|
+
return options.affine
|
|
25
|
+
? ["linear", "helmert", "polynomial1"]
|
|
26
|
+
: ["linear", "helmert"];
|
|
27
|
+
}
|
|
22
28
|
/**
|
|
23
|
-
* Create a six-line world file plus an explicit CRS sidecar value for Linear or Helmert fits without reprojection.
|
|
29
|
+
* Create a six-line world file plus an explicit CRS sidecar value for Linear or Helmert fits (and optionally affine fits) without reprojection.
|
|
24
30
|
*
|
|
25
31
|
* Line order is A, D, B, E, C, F. The final two values locate the first pixel centre, `[0.5, 0.5]`. A world file alone contains no CRS.
|
|
26
|
-
* @
|
|
32
|
+
* @param options - Set `affine` to also accept Polynomial 1 fits.
|
|
33
|
+
* @throws {@link "@georeferencing/core".GeoreferenceError} For ineligible models or different working/output CRSs.
|
|
27
34
|
*/
|
|
28
|
-
export function worldFile(fit, workingCrs, outputCrs) {
|
|
29
|
-
if (!
|
|
30
|
-
|
|
35
|
+
export function worldFile(fit, workingCrs, outputCrs, options = {}) {
|
|
36
|
+
if (!worldFileModels(options).includes(fit.model) ||
|
|
37
|
+
normalizeCrs(workingCrs) !== normalizeCrs(outputCrs))
|
|
38
|
+
fail("WORLD_FILE", options.affine
|
|
39
|
+
? "World-file-only output requires a Linear, Helmert or affine fit without reprojection."
|
|
40
|
+
: "World-file-only output requires Linear/Helmert without reprojection.");
|
|
31
41
|
const a = forward(fit, [0, 0]), b = forward(fit, [1, 0]), c = forward(fit, [0, 1]), center = forward(fit, [0.5, 0.5]);
|
|
32
42
|
return {
|
|
33
43
|
/**
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { OutputSettings } from "@georeferencing/core";
|
|
2
|
+
/**
|
|
3
|
+
* Supported TIFF strip creation and no-data options, shared with raster output settings.
|
|
4
|
+
*/
|
|
5
|
+
export type TiffOptions = Pick<OutputSettings, "compression" | "noData" | "rowsPerStrip" | "predictor">;
|
|
6
|
+
/** TIFF compression tag values by setting. @internal */
|
|
7
|
+
export declare const compressionCodes: {
|
|
8
|
+
none: number;
|
|
9
|
+
deflate: number;
|
|
10
|
+
packbits: number;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Return the GeoTIFF EPSG code for a CRS identifier, accepting EPSG URI/URN aliases, or
|
|
14
|
+
* null when the CRS cannot be written as a GeoKey (custom WKT or codes from 32767).
|
|
15
|
+
*/
|
|
16
|
+
export declare function geoTiffEpsg(crs: string): number | null;
|
|
17
|
+
/**
|
|
18
|
+
* Validate byte no-data, strip height, compression and predictor compatibility before
|
|
19
|
+
* encoding.
|
|
20
|
+
*/
|
|
21
|
+
export declare function validateTiffOptions(options: TiffOptions): void;
|
|
22
|
+
/**
|
|
23
|
+
* Explain why GeoTIFF output is unavailable for these settings, or return null. Runs
|
|
24
|
+
* before rendering, so ineligible settings never cost a full-resolution render.
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
export declare function geoTiffUnavailable(output: OutputSettings): string | null;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { fail, normalizeCrs } from "@georeferencing/core";
|
|
2
|
+
/** TIFF compression tag values by setting. @internal */
|
|
3
|
+
export const compressionCodes = { none: 1, deflate: 8, packbits: 32773 };
|
|
4
|
+
/**
|
|
5
|
+
* Return the GeoTIFF EPSG code for a CRS identifier, accepting EPSG URI/URN aliases, or
|
|
6
|
+
* null when the CRS cannot be written as a GeoKey (custom WKT or codes from 32767).
|
|
7
|
+
*/
|
|
8
|
+
export function geoTiffEpsg(crs) {
|
|
9
|
+
const code = Number(/^EPSG:(\d+)$/.exec(normalizeCrs(crs))?.[1]);
|
|
10
|
+
return code > 0 && code < 32767 ? code : null;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Validate byte no-data, strip height, compression and predictor compatibility before
|
|
14
|
+
* encoding.
|
|
15
|
+
*/
|
|
16
|
+
export function validateTiffOptions(options) {
|
|
17
|
+
if (!Object.hasOwn(compressionCodes, options.compression ?? "none"))
|
|
18
|
+
fail("OUTPUT", "Unsupported TIFF compression.");
|
|
19
|
+
if (options.noData !== undefined &&
|
|
20
|
+
(!Number.isInteger(options.noData) ||
|
|
21
|
+
options.noData < 0 ||
|
|
22
|
+
options.noData > 255))
|
|
23
|
+
fail("NODATA", "Byte-image no-data must be an integer from 0 to 255.");
|
|
24
|
+
if (options.rowsPerStrip !== undefined &&
|
|
25
|
+
(!Number.isInteger(options.rowsPerStrip) ||
|
|
26
|
+
options.rowsPerStrip < 1 ||
|
|
27
|
+
options.rowsPerStrip > 4096))
|
|
28
|
+
fail("OUTPUT", "Rows per strip must be an integer from 1 to 4096.");
|
|
29
|
+
if (![1, 2].includes(options.predictor ?? 1) ||
|
|
30
|
+
(options.predictor === 2 && options.compression !== "deflate"))
|
|
31
|
+
fail("OUTPUT", "Horizontal prediction requires Deflate compression.");
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Explain why GeoTIFF output is unavailable for these settings, or return null. Runs
|
|
35
|
+
* before rendering, so ineligible settings never cost a full-resolution render.
|
|
36
|
+
* @internal
|
|
37
|
+
*/
|
|
38
|
+
export function geoTiffUnavailable(output) {
|
|
39
|
+
if (!geoTiffEpsg(output.crs))
|
|
40
|
+
return "GeoTIFF output requires an EPSG output CRS with a code below 32767.";
|
|
41
|
+
try {
|
|
42
|
+
validateTiffOptions(output);
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
return error.message;
|
|
47
|
+
}
|
|
48
|
+
}
|
package/dist/tiff.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import type { Extent, OutputSettings } from "@georeferencing/core";
|
|
2
|
-
/**
|
|
3
|
-
* Supported TIFF strip creation and no-data options, shared with raster output settings.
|
|
4
|
-
*/
|
|
5
|
-
export type TiffOptions = Pick<OutputSettings, "compression" | "noData" | "rowsPerStrip" | "predictor">;
|
|
6
1
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
2
|
+
* Low-level GeoTIFF encoding and TIFF creation-option validation, used by the GeoTIFF worker.
|
|
3
|
+
* Import from `@georeferencing/plugins/tiff`.
|
|
4
|
+
* @module @georeferencing/plugins/tiff
|
|
5
|
+
* @group @georeferencing/plugins
|
|
9
6
|
*/
|
|
10
|
-
|
|
7
|
+
import type { Extent, OutputSettings } from "@georeferencing/core";
|
|
8
|
+
import type { TiffOptions } from "./tiff-options.js";
|
|
9
|
+
export type { TiffOptions } from "./tiff-options.js";
|
|
10
|
+
export { geoTiffEpsg, validateTiffOptions } from "./tiff-options.js";
|
|
11
11
|
/**
|
|
12
12
|
* Encode an uncompressed north-up RGBA GeoTIFF synchronously using PixelIsArea. Allocates a complete ArrayBuffer; prefer encodeGeoTiffBlob for bounded-strip encoding.
|
|
13
13
|
* @param data - Row-major 8-bit RGBA with unassociated alpha.
|
|
@@ -29,7 +29,7 @@ export declare function encodeGeoTiff(data: Uint8ClampedArray, width: number, he
|
|
|
29
29
|
* @param geographic - True for geographic CRS GeoKeys, false for projected CRS GeoKeys; must agree with crs.
|
|
30
30
|
* @param options - Compression, strip height, predictor and optional RGB no-data.
|
|
31
31
|
* @param progress - Encoding progress fraction per completed strip.
|
|
32
|
-
* @throws {@link core.GeoreferenceError} For invalid layouts/settings, unavailable Deflate or partial transparency with numeric no-data.
|
|
32
|
+
* @throws {@link "@georeferencing/core".GeoreferenceError} For invalid layouts/settings, unavailable Deflate or partial transparency with numeric no-data.
|
|
33
33
|
*/
|
|
34
34
|
export declare function encodeGeoTiffBlob(data: Uint8ClampedArray, width: number, height: number, bounds: Extent, crs: string, geographic: boolean, options?: TiffOptions, progress?: (value: number) => void): Promise<Blob>;
|
|
35
35
|
/**
|
package/dist/tiff.js
CHANGED
|
@@ -1,26 +1,6 @@
|
|
|
1
1
|
import { fail } from "@georeferencing/core";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* Validate byte no-data, strip height, compression and predictor compatibility before
|
|
5
|
-
* encoding.
|
|
6
|
-
*/
|
|
7
|
-
export function validateTiffOptions(options) {
|
|
8
|
-
if (!Object.hasOwn(compressionCodes, options.compression ?? "none"))
|
|
9
|
-
fail("OUTPUT", "Unsupported TIFF compression.");
|
|
10
|
-
if (options.noData !== undefined &&
|
|
11
|
-
(!Number.isInteger(options.noData) ||
|
|
12
|
-
options.noData < 0 ||
|
|
13
|
-
options.noData > 255))
|
|
14
|
-
fail("NODATA", "Byte-image no-data must be an integer from 0 to 255.");
|
|
15
|
-
if (options.rowsPerStrip !== undefined &&
|
|
16
|
-
(!Number.isInteger(options.rowsPerStrip) ||
|
|
17
|
-
options.rowsPerStrip < 1 ||
|
|
18
|
-
options.rowsPerStrip > 4096))
|
|
19
|
-
fail("OUTPUT", "Rows per strip must be an integer from 1 to 4096.");
|
|
20
|
-
if (![1, 2].includes(options.predictor ?? 1) ||
|
|
21
|
-
(options.predictor === 2 && options.compression !== "deflate"))
|
|
22
|
-
fail("OUTPUT", "Horizontal prediction requires Deflate compression.");
|
|
23
|
-
}
|
|
2
|
+
import { compressionCodes, geoTiffEpsg, validateTiffOptions, } from "./tiff-options.js";
|
|
3
|
+
export { geoTiffEpsg, validateTiffOptions } from "./tiff-options.js";
|
|
24
4
|
function check(data, width, height, bounds) {
|
|
25
5
|
if (!Number.isSafeInteger(width) ||
|
|
26
6
|
!Number.isSafeInteger(height) ||
|
|
@@ -61,7 +41,7 @@ export function encodeGeoTiff(data, width, height, bounds, crs, geographic) {
|
|
|
61
41
|
* @param geographic - True for geographic CRS GeoKeys, false for projected CRS GeoKeys; must agree with crs.
|
|
62
42
|
* @param options - Compression, strip height, predictor and optional RGB no-data.
|
|
63
43
|
* @param progress - Encoding progress fraction per completed strip.
|
|
64
|
-
* @throws {@link core.GeoreferenceError} For invalid layouts/settings, unavailable Deflate or partial transparency with numeric no-data.
|
|
44
|
+
* @throws {@link "@georeferencing/core".GeoreferenceError} For invalid layouts/settings, unavailable Deflate or partial transparency with numeric no-data.
|
|
65
45
|
*/
|
|
66
46
|
export async function encodeGeoTiffBlob(data, width, height, bounds, crs, geographic, options = {}, progress) {
|
|
67
47
|
check(data, width, height, bounds);
|
|
@@ -152,8 +132,8 @@ function packBits(data) {
|
|
|
152
132
|
* and strip offsets. Rejects offsets reaching the 4 GiB classic-TIFF limit.
|
|
153
133
|
*/
|
|
154
134
|
function tiffHeader(width, height, bounds, crs, geographic, options, lengths, rows, channels) {
|
|
155
|
-
const epsg =
|
|
156
|
-
if (!epsg
|
|
135
|
+
const epsg = geoTiffEpsg(crs);
|
|
136
|
+
if (!epsg)
|
|
157
137
|
fail("CRS", "GeoTIFF requires an EPSG code below 32767 with a registered definition.");
|
|
158
138
|
const keys = [
|
|
159
139
|
1,
|