@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 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 depend
24
- on core; a mismatched version can install a second copy of core whose projection
25
- registry and worker code are separate from the controller's. See
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. BigTIFF, COG layout, arbitrary-WKT GeoKeys, scientific sample preservation
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.
@@ -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;
@@ -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
- /** Register original-resolution normalized PNG, world file and explicit CRS sidecar. */
13
- export declare function worldFile(): ExportFormat;
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
- /** Register original-resolution normalized PNG, world file and explicit CRS sidecar. */
28
- export function worldFile() {
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) => ["linear", "helmert"].includes(doc.model) &&
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
- : "World-file output requires Linear/Helmert without reprojection.",
36
- load: async () => (await import("./data-export.js")).worldFileExporter,
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.replace(/[^\x20-\x7e]/g, "?"), width = Math.max(1, Math.floor(contentWidth / (size * (fixed ? 0.6 : 0.55))));
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();
@@ -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
- * @throws {@link core.GeoreferenceError} For ineligible models or different working/output CRSs.
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.
@@ -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
- * @throws {@link core.GeoreferenceError} For ineligible models or different working/output CRSs.
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 (!["linear", "helmert"].includes(fit.model) || workingCrs !== outputCrs)
30
- fail("WORLD_FILE", "World-file-only output requires Linear/Helmert without reprojection.");
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
- * Validate byte no-data, strip height, compression and predictor compatibility before
8
- * encoding.
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
- export declare function validateTiffOptions(options: TiffOptions): void;
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
- const compressionCodes = { none: 1, deflate: 8, packbits: 32773 };
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 = Number(/^EPSG:(\d+)$/.exec(crs)?.[1]);
156
- if (!epsg || epsg >= 32767)
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,