npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@georeferencing/plugins

v0.6.0

Published

Optional local GeoTIFF, JPEG, PDF and session export plugins for georeferencing

Readme

@georeferencing/plugins

Optional local export formats for @georeferencing/core: GeoTIFF, JPEG, PDF, normalized-image world files, JSON sessions, QGIS control points and accuracy reports. Each format is enabled explicitly through controller configuration. Heavy implementations load when the user requests an export.

This package has no React or map-library dependency. The optional PDF map page takes a capture function, which every map adapter that supports capture provides. The React editor reads the same controller registry to display only configured export actions.

Installation and package selection

pnpm add @georeferencing/core @georeferencing/plugins
# Add the UI only if needed:
pnpm add @georeferencing/react @georeferencing/openlayers react@19 react-dom@19 ol@10

The package ships ESM, TypeScript declarations and codec-worker assets. Node.js 22.12+ is the declared tooling requirement; repository development uses pnpm 12.x. Install the same version of @georeferencing/plugins, @georeferencing/core and (if used) @georeferencing/react, and upgrade them together. Plugins declare core as a peer dependency and use your application's copy; a mismatched version is reported as a peer-dependency conflict rather than installing a second core whose projection registry and worker code are separate from the controller's. See keep package versions aligned.

Core alone enables no exports. Import only the factories your application uses. The root plugin barrel exports factories and types; per-format imports give bundlers a narrower dependency graph. Unused formats can be excluded from the browser bundle. Installing this package also installs its pdf-lib dependency, but PDF code is downloaded by the application only when its lazy export path runs.

Pure serializers

@georeferencing/plugins/serializers exposes exportPoints(document, definitions?), worldFile(fit, workingCrs, outputCrs) and accuracyReport(document, fit) without loading a codec worker or UI. These return text/placement values; the /data factories register full controller exports and downloadable artifacts.

import { importPoints, parseSession } from "@georeferencing/core";
import { exportPoints, accuracyReport, worldFile } from "@georeferencing/plugins/serializers";

Session validation and .points importing live in core. The worldFile() factory registered from @georeferencing/plugins/data (and the plugin root) is a separate controller export format.

Configure export formats

import { GeoreferencerController } from "@georeferencing/core";
import { createWorkerEngine } from "@georeferencing/core/engine";
import { geoTiff } from "@georeferencing/plugins/geotiff";
import { jpeg } from "@georeferencing/plugins/jpeg";
import { pdf } from "@georeferencing/plugins/pdf";

export function createExportEditor(workingCrs: string) {
  const engine = createWorkerEngine();
  const controller = new GeoreferencerController({
    workingCrs,
    engine,
    exports: [
      geoTiff(),
      jpeg({ quality: 0.92, background: [255, 255, 255] }),
      pdf({ paper: "A4", landscape: true, attribution: "Host-provided attribution" }),
    ],
  });
  return { controller, engine };
}

The caller loads an image and supplies GCPs through the controller or React UI. Raster/report exports require a current valid fit. Dispose the controller and its host-owned engine when the session is permanently finished.

| Factory | Import suffix | Format ID | Files / eligibility | | --- | --- | --- | --- | | geoTiff() | /geotiff | geotiff | Georeferenced TIFF; valid fit | | jpeg() | /jpeg | jpeg | JPEG, .jgw, .crs.json; valid fit | | pdf() | /pdf | pdf | PDF alignment/map report; valid fit and preview | | worldFile() | /data | world-file | Original-resolution normalized PNG, .pgw, CRS sidecar; Linear/Helmert (or also affine with { affine: true }) without reprojection | | session() | /data | session | Complete session JSON; fit may be unfinished | | points(definitions?) | /data | points | QGIS .points; fit may be unfinished | | accuracy() | /data | accuracy | Full-precision JSON diagnostics; valid fit |

All controller exports currently require loaded source image bytes. Register data exports only when needed:

import type { Definitions, GeoreferencerController } from "@georeferencing/core";
import { accuracy, points, session, worldFile } from "@georeferencing/plugins/data";

export function enableDataExports(
  controller: GeoreferencerController,
  definitions: Definitions,
) {
  controller.setExportFormats([session(), points(definitions), accuracy(), worldFile()]);
}

setExportFormats replaces the entire registry and cancels pending export work; it does not append formats. IDs must be unique. Configuration is runtime state, separate from saved session JSON. Removing all formats leaves alignment and host feature/draft saving available.

Run an export and consume every artifact

import type { ExportResult, GeoreferencerController } from "@georeferencing/core";

export async function exportSelected(
  controller: GeoreferencerController,
  id: string,
  consume: (result: ExportResult) => Promise<void>,
) {
  const unavailable = controller.getExportUnavailable(id);
  if (unavailable) throw new Error(unavailable);
  const result = await controller.export(id);
  if (result) await consume(result);
  return result;
}

ExportResult contains:

| Field | Meaning | | --- | --- | | format | Registered format ID | | document | Frozen document revision actually processed | | blob | Primary encoded artifact, also files[0].blob | | files | Suggested filename and Blob for every artifact, including required sidecars | | raster | Optional full-resolution, pre-encoding RGBA raster, bounds and CRS | | worldFile | Optional original-pixel placement text and explicit CRS |

Save/download each files entry with its filename. The React component's onExport(result) intercepts this same result instead of default downloads. Hosts that create object URLs must revoke them after use. A completed export is not a persistence acknowledgement and does not clear the dirty flag.

Missing formats, invalid eligibility and concurrent exports reject before work starts. Lazy-load/processing failures return null and populate snapshot errors; the operation can be retried. Cancellation and stale work also return null. Use cancelExport() to abort. Image replacement, re-alignment, suspension and format-registry changes discard obsolete outputs. Newer drawing edits can remain in the draft while the result retains the exact earlier document snapshot.

exportRaster() is an alias for export("geotiff"), and exportWorldFile() aliases export("world-file"). Their matching plugins must be registered.

GeoTIFF output

geoTiff() uses the core full-resolution warp followed by a dedicated codec worker. Configure spatial and creation settings through controller.setOutput:

import type { GeoreferencerController } from "@georeferencing/core";

export function configureTiff(controller: GeoreferencerController) {
  controller.setOutput({
    ...controller.getSnapshot().document.output,
    crs: "EPSG:3857",
    resolution: [2, 2], // two output-CRS units per pixel; choose for your data
    resampler: "bilinear",
    compression: "deflate",
    rowsPerStrip: 256,
    predictor: 2,
  });
}

| Setting | Behavior | | --- | --- | | crs | Explicit output CRS; register required definitions with the engine | | bounds | Optional outer-edge crop extent in output CRS | | resolution | Positive x/y pixel sizes in output units; omitted means estimated resolution | | resampler | nearest, bilinear, cubic, cubicSpline or lanczos | | compression | none, deflate or packbits | | rowsPerStrip | Integer 1–4096; default bounded by 256 and raster height | | predictor | 1 or 2; horizontal predictor 2 requires Deflate | | sourceNoData | Source byte or RGB triple excluded before interpolation | | noData | Optional output byte 0–255 with a GDAL no-data tag; otherwise retain alpha |

Output is north-up, PixelIsArea, 8-bit RGB or unassociated RGBA. Bounds locate outer pixel edges; the first row is at maxY. Numeric no-data cannot preserve partial alpha; choose a value that does not collide with valid RGB data. Deflate requires browser CompressionStream support.

This encoder writes classic TIFF below 4 GiB and requires an EPSG code below 32767; EPSG URI/URN aliases are accepted (geoTiffEpsg from /tiff resolves them). The geoTiff() format reports an ineligible output CRS or TIFF option before any rendering starts. BigTIFF, COG layout, arbitrary-WKT GeoKeys, scientific sample preservation and multipage output are outside the supported envelope. See the capabilities and limits for the supported output envelope and QGIS compatibility boundaries.

JPEG output

jpeg({ quality, background }) shares the same full-resolution warp and output grid, then encodes a lossy JPEG. quality is 0–1, default 0.92. background is an RGB byte tuple, default white; transparent pixels are composited onto it. TIFF compression and predictor settings do not affect JPEG.

JPEG has no embedded CRS. Keep all three files together: the image, .jgw world file and .crs.json metadata. The world file uses the upper-left pixel centre and negative y pixel size. JSON records CRS, bounds, dimensions, source identity, revision and encoding options. result.raster retains the unflattened RGBA warp; decoded JPEG pixels can differ because of alpha composition and lossy encoding.

PDF and supplementary exports

pdf() creates a report from the aligned preview, including GCPs/residuals, parameters, source/revision information and an embedded full-precision JSON attachment. It is a report, not a geospatial PDF raster export.

Options include paper (A4, A3, Letter), landscape, margin in PDF points, projection definitions, attribution and an optional capture function for a map page.

import { captureOpenLayersMap } from "@georeferencing/openlayers";
import { pdf } from "@georeferencing/plugins/pdf";
import type OLMap from "ol/Map.js";

export function mapReport(currentMap: () => OLMap | undefined) {
  return pdf({
    capture: () => {
      const map = currentMap();
      return map ? captureOpenLayersMap(map) : undefined;
    },
    paper: "A4",
    margin: 40,
  });
}

capture runs when the export starts and returns a MapCapture (image, CRS, extent, rotation, attribution) or undefined to skip the map page. Use captureOpenLayersMap, captureMapLibreMap or a map binding's capture(); Leaflet maps cannot be captured because their tiles are DOM images. Capture uses the currently rendered map without moving the view or waiting for pending tiles, and map sources must permit CORS canvas export. Omit capture for an aligned-raster-only report. PDF cancellation discards a late result but cannot interrupt synchronous PDF generation or undo a module download.

The worldFile() plugin exports orientation-normalized original-resolution PNG pixels with matching placement; a world file itself contains no CRS. QGIS .points exports use the QGIS source-y convention and placeholder residual columns; use accuracy() for computed diagnostics. A session download preserves metadata and features, but not original file bytes, undo history or credentials. Neither a downloaded session nor a report counts as a host save.

Worker assets and memory

With Vite, use worker: { format: "es" }. Default codec URLs resolve relative to the installed plugin module, including packed consumers. Each codec can override its worker independently:

import { geoTiff } from "@georeferencing/plugins/geotiff";
import { jpeg } from "@georeferencing/plugins/jpeg";

export const formats = [
  geoTiff({ workerUrl: "/my-app/assets/geotiff.js" }),
  jpeg({ workerUrl: "/my-app/assets/jpeg.js", quality: 0.9 }),
];

Copy the matching dist/workers/geotiff.js or jpeg.js, adjacent legal notices and dist/licenses when deploying assets yourself. Alternatively supply a workerFactory returning a fresh dedicated module worker. Vite supports asset imports from @georeferencing/plugins/geotiff-worker?worker and @georeferencing/plugins/jpeg-worker?worker. Respect the deployment base and CSP.

Raster codecs inherit engine limits, projection definitions, scheduling and cancellation. Temporary raster buffers transfer to the encoder and back; the editor preview is never transferred. Low-level callers must treat submitted buffers as detached until the returned raster arrives. Aborting terminates a codec worker. Core defaults are 24MP input/output and 768 MiB estimated reservation; compression and buffers may require a smaller practical output. These estimates are not measured process-memory caps or streaming guarantees.

Custom exporters and low-level APIs

A custom descriptor implements core's ExportFormat contract; it does not need to depend on this package. Respect the supplied AbortSignal and frozen document. The first file's Blob must be the primary returned Blob.

import type { ExportFormat } from "@georeferencing/core";

export const provenance: ExportFormat = {
  id: "provenance",
  label: "Export provenance",
  requiresFit: false,
  load: async () => ({
    async run({ document, signal }) {
      signal.throwIfAborted();
      const blob = new Blob([JSON.stringify({
        documentId: document.id,
        revision: document.documentRevision,
        source: document.sourceImage,
      })], { type: "application/json" });
      return { blob, files: [{ name: "provenance.json", blob }] };
    },
  }),
};

For a larger implementation, have load dynamically import your own module. Use raster: true to request shared raster output controls, and unavailable for additional pure eligibility checks. All exporters share the controller's revision and cancellation contract.

@georeferencing/plugins/tiff exposes low-level TIFF encoders and option validation. /report exposes createPdfReport, captureMap and structural map interfaces. Bypassing the controller makes the caller responsible for matching revisions, limits, cancellation and resource cleanup. Custom codec workers can use installEncoderWorker from @georeferencing/core/encoder-worker.

Troubleshooting and license

| Symptom | Check | | --- | --- | | No export buttons / EXPORT_DISABLED | Register the intended format on the controller | | Lazy module or codec load fails | Bundler output, asset base URL and CSP; retry after correcting deployment | | JPEG appears unreferenced in another app | Keep both sidecars and configure/read the recorded CRS | | PDF cannot capture a map | Loaded canvas layers, visible map size and CORS; omit optional map capture if unsupported | | TIFF option or memory error | Compatible compression/predictor/no-data settings and output size |

MIT licensed, with bundled third-party notices in dist/licenses. Public TypeDoc comments ship in declarations and are published as the API documentation. Source, issues and contribution notes are in the GitHub repository.