{"_id":"@conaonda/ol-cog-layers","_rev":"3-a92d4c054fe77ee9e9b71fc468e29d7e","name":"@conaonda/ol-cog-layers","dist-tags":{"latest":"0.3.2"},"versions":{"0.1.0":{"name":"@conaonda/ol-cog-layers","version":"0.1.0","keywords":["openlayers","cog","geotiff","webgl","gis"],"license":"MIT","_id":"@conaonda/ol-cog-layers@0.1.0","maintainers":[{"name":"conaonda","email":"conaonda@gmail.com"}],"homepage":"https://github.com/conaonda/ol-cog-layers#readme","bugs":{"url":"https://github.com/conaonda/ol-cog-layers/issues"},"dist":{"shasum":"9bcabd278f701768e40615c576bda112bb888dc6","tarball":"https://registry.npmjs.org/@conaonda/ol-cog-layers/-/ol-cog-layers-0.1.0.tgz","fileCount":27,"integrity":"sha512-B8aEa2VwdyInGR/xucXWPO7ALW3VE2qUqpO3JTKlPmY3f3FZFVzoCWO07HCuNx1+g8p8I1rJGqeVENhEUsiiYA==","signatures":[{"sig":"MEYCIQDtK8JrLqfvLMNONu9hbx7fuAhAjhUZl8VbtwLgUvxtTgIhAJ6OgKwLhZPffYUHgeMJ7Ev0rAPMTQxpRFlDC5P44vSr","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1286235},"main":"dist/ol-cog-layers.js","type":"module","module":"dist/ol-cog-layers.js","exports":{".":{"import":"./dist/ol-cog-layers.js"}},"gitHead":"ee2f23b1e19b95ea55799200ba154462019f9bc5","scripts":{"build":"vite build"},"_npmUser":{"name":"conaonda","email":"conaonda@gmail.com"},"repository":{"url":"git+https://github.com/conaonda/ol-cog-layers.git","type":"git"},"_npmVersion":"11.9.0","description":"OpenLayers COG rendering layers — WebGL tile + Canvas image pipelines","directories":{},"_nodeVersion":"24.14.0","dependencies":{"geotiff":"^2.1.3"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^6.1.0"},"peerDependencies":{"ol":">=10.0.0"},"_npmOperationalInternal":{"tmp":"tmp/ol-cog-layers_0.1.0_1772209701759_0.8829615307119283","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@conaonda/ol-cog-layers","version":"0.1.1","keywords":["openlayers","cog","geotiff","webgl","gis"],"license":"MIT","_id":"@conaonda/ol-cog-layers@0.1.1","maintainers":[{"name":"conaonda","email":"conaonda@gmail.com"}],"homepage":"https://github.com/conaonda/ol-cog-layers#readme","bugs":{"url":"https://github.com/conaonda/ol-cog-layers/issues"},"dist":{"shasum":"7fc64817a249570b55774b1891a7ab350764c27b","tarball":"https://registry.npmjs.org/@conaonda/ol-cog-layers/-/ol-cog-layers-0.1.1.tgz","fileCount":32,"integrity":"sha512-Q3ShXP59JLKGgOdQKQdjUKDN1v5ZOMwuDT14O+j6nEgroyup7Ox6JHCf2dZxnInipKEG7JmXVEdEAcwafHd7LA==","signatures":[{"sig":"MEQCIEcfeeHPhppZtNTy1mK735RfKEZ1QnaQBtid9ovAL9rDAiB3w28D5IVlR7DVQdRvXHlgVEfIg33P+j67MMTzzCgRdA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1314650},"main":"dist/ol-cog-layers.js","type":"module","module":"dist/ol-cog-layers.js","exports":{".":{"import":"./dist/ol-cog-layers.js"}},"gitHead":"7e9169d12e8a73544320db0ec6abdc03c5bc941f","scripts":{"build":"vite build"},"_npmUser":{"name":"conaonda","email":"conaonda@gmail.com"},"repository":{"url":"git+https://github.com/conaonda/ol-cog-layers.git","type":"git"},"_npmVersion":"11.9.0","description":"OpenLayers COG rendering layers — WebGL tile + Canvas image pipelines","directories":{},"_nodeVersion":"24.14.0","dependencies":{"geotiff":"^2.1.3"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^6.1.0"},"peerDependencies":{"ol":">=10.0.0"},"_npmOperationalInternal":{"tmp":"tmp/ol-cog-layers_0.1.1_1772227316800_0.1140743365327106","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"@conaonda/ol-cog-layers","version":"0.3.2","description":"OpenLayers COG rendering layers — WebGL tile + Canvas image pipelines","type":"module","main":"dist/ol-cog-layers.cjs","module":"dist/ol-cog-layers.js","types":"types/index.d.ts","exports":{".":{"types":"./types/index.d.ts","import":"./dist/ol-cog-layers.js","require":"./dist/ol-cog-layers.cjs"}},"sideEffects":false,"scripts":{"build":"vite build","test":"vitest run","lint":"eslint src","format":"prettier --write src","examples":"vite --config vite.config.examples.js","examples:build":"vite build --config vite.config.examples.js"},"peerDependencies":{"ol":">=10.0.0"},"dependencies":{"geotiff":"^2.1.3"},"devDependencies":{"@eslint/js":"^9.0.0","@vitest/coverage-v8":"^3.2.4","eslint":"^9.0.0","globals":"^16.0.0","ol":"^10.0.0","playwright":"^1.58.2","prettier":"^3.0.0","vite":"^6.1.0","vitest":"^3.0.0"},"engines":{"node":">=18"},"license":"MIT","author":{"name":"conaonda"},"repository":{"type":"git","url":"git+https://github.com/conaonda/ol-cog-layers.git"},"bugs":{"url":"https://github.com/conaonda/ol-cog-layers/issues"},"homepage":"https://github.com/conaonda/ol-cog-layers#readme","keywords":["openlayers","cog","geotiff","webgl","gis"],"gitHead":"56ddceffa1ac15245dbb2c3ed0c19bd2a00b2338","_id":"@conaonda/ol-cog-layers@0.3.2","_nodeVersion":"24.14.0","_npmVersion":"11.9.0","dist":{"integrity":"sha512-E+eLSYd1dkVvV+1aSK/F2QrbvHt1UP5uTT7ddvtjR6eJ3U0cBaFOpBGMBX6dHyh3kxUo1YCNDO0IE15FTPVw+g==","shasum":"1c2b0b089153d434f6174cdd7a64b5aa7c2dc626","tarball":"https://registry.npmjs.org/@conaonda/ol-cog-layers/-/ol-cog-layers-0.3.2.tgz","fileCount":58,"unpackedSize":2533039,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCHy342opNMNvU48COfn0FHh9a/Xoj5VT35PWZD1fQ0CwCIQCM0i6t4yVeviVNn3A24YlmxD7y0P3hyJuzi8i2KR/6mQ=="}]},"_npmUser":{"name":"conaonda","email":"conaonda@gmail.com"},"directories":{},"maintainers":[{"name":"conaonda","email":"conaonda@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ol-cog-layers_0.3.2_1772357762195_0.38930716278063215"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-27T16:28:21.685Z","modified":"2026-03-01T09:36:02.540Z","0.1.0":"2026-02-27T16:28:22.017Z","0.1.1":"2026-02-27T21:21:57.043Z","0.3.2":"2026-03-01T09:36:02.407Z"},"bugs":{"url":"https://github.com/conaonda/ol-cog-layers/issues"},"license":"MIT","homepage":"https://github.com/conaonda/ol-cog-layers#readme","keywords":["openlayers","cog","geotiff","webgl","gis"],"repository":{"type":"git","url":"git+https://github.com/conaonda/ol-cog-layers.git"},"description":"OpenLayers COG rendering layers — WebGL tile + Canvas image pipelines","maintainers":[{"name":"conaonda","email":"conaonda@gmail.com"}],"readme":"# @conaonda/ol-cog-layers\n\n**Why this library?** OpenLayers' built-in `ol/source/GeoTIFF` assumes the COG's native CRS matches the view projection, or relies on its internal reprojection pipeline. When you load a UTM-projected COG (e.g. EPSG:32615) onto an EPSG:3857 web map, the built-in approach often produces misaligned tiles, broken extents, or simply fails for rotated GeoTIFFs that use a `ModelTransformation` matrix.\n\n`ol-cog-layers` solves this with a single function call — and its `projectionMode: 'affine'` mode bypasses OL's reprojection entirely, patching the tile grid and renderer to apply a GPU-accelerated affine transform directly. This means:\n\n- UTM COGs render **pixel-perfect** on EPSG:3857 basemaps\n- **Rotated/skewed GeoTIFFs** (with ModelTransformation) display at the correct position and angle\n- No CPU-side reprojection overhead — everything stays on the GPU\n\n## Features\n\n- **WebGL Tile Pipeline** (`createCOGLayer`) — GPU-accelerated rendering via `ol/layer/WebGLTile`\n- **Canvas Image Pipeline** (`createCOGImageLayer`) — CPU-based rendering via `ol/layer/Image`, works on devices without WebGL float support\n- **Affine transform support** — correctly renders rotated/skewed GeoTIFFs\n- **Automatic band detection** — RGB vs grayscale auto-detection from GeoTIFF metadata\n- **Min/Max from overview** — fast statistics extraction from the coarsest overview level\n- **Built-in colormaps** — viridis, inferno, plasma for single-band visualization\n\n## How `projectionMode: 'affine'` Works\n\nWhen `projectionMode` is set to `'affine'`, ol-cog-layers:\n\n1. Reads the GeoTIFF's `ModelTransformation` (or `ModelTiepoint` + `ModelPixelScale`)\n2. Computes an affine matrix mapping **pixel coordinates → view CRS**\n3. Creates a custom `TileGrid` aligned to the COG's native pixel grid\n4. **Patches the WebGL tile renderer** to apply the affine transform on the GPU — no per-tile reprojection\n\nThis is especially critical for SAR imagery (e.g. Umbra, Capella) where the `ModelTransformation` includes rotation terms that OL's standard pipeline cannot handle.\n\n## Install\n\n```bash\nnpm install @conaonda/ol-cog-layers\n```\n\n## Peer Dependencies\n\n- `ol` >= 10.0.0\n\n## Usage\n\n### WebGL Tile Layer\n\n```js\nimport { Map, View } from 'ol'\nimport TileLayer from 'ol/layer/Tile'\nimport OSM from 'ol/source/OSM'\nimport { createCOGLayer } from '@conaonda/ol-cog-layers'\n\n// SkySat RGB imagery (UTM → EPSG:3857 via affine)\nconst { layer, extent, projection } = await createCOGLayer({\n  url: 'https://storage.googleapis.com/pdd-stac/disasters/hurricane-harvey/0831/SkySat_20170831T195552Z_RGB.tif',\n  viewProjection: 'EPSG:3857',\n  projectionMode: 'affine',\n})\n\nconst map = new Map({\n  target: 'map',\n  layers: [\n    new TileLayer({ source: new OSM() }),\n    layer,\n  ],\n  view: new View({ projection: 'EPSG:3857' }),\n})\n\nmap.getView().fit(extent)\n```\n\n### Canvas Image Layer\n\n```js\nimport { createCOGImageLayer } from '@conaonda/ol-cog-layers'\n\nconst result = await createCOGImageLayer({\n  url: 'https://example.com/image.tif',\n  viewProjection: 'EPSG:3857',\n  // Optional:\n  // projectionMode: 'affine',\n  // opacity: 1,\n  // resolutionMultiplier: 1,\n})\n\nmap.addLayer(result.layer)\nmap.getView().fit(result.extent)\n\n// Dynamic updates\nresult.setColormap('viridis')  // 'viridis' | 'inferno' | 'plasma' | null\nresult.setStats([{ min: 0, max: 1000 }])  // override min/max\n```\n\n### Colormaps (WebGL)\n\n```js\nimport { buildStyleWithColormap, detectBands, getMinMaxFromOverview } from '@conaonda/ol-cog-layers'\nimport { fromUrl } from 'geotiff'\n\nconst tiff = await fromUrl('https://example.com/dem.tif')\nconst bandInfo = await detectBands(tiff)\nconst { stats } = await getMinMaxFromOverview(tiff, bandInfo.bands)\n\nconst style = buildStyleWithColormap(bandInfo, stats, 'viridis')\nlayer.setStyle(style)\n```\n\n### Utility Functions\n\n```js\nimport {\n  detectBands,          // Auto-detect band type (rgb/gray) and band indices\n  getTotalBands,        // Get number of data bands (excluding alpha)\n  getMinMaxFromOverview, // Extract min/max stats from coarsest overview\n  buildStyle,           // Build WebGL style expression from band info and stats\n  createCOGSource,      // Create ol/source/GeoTIFF with defaults\n  COLORMAPS,            // { grayscale, viridis, inferno, plasma }\n  applyColormapToPixel, // Apply colormap LUT to a normalized value (0-255)\n} from '@conaonda/ol-cog-layers'\n```\n\n## API\n\n### `createCOGLayer(options)`\n\n| Option | Type | Default | Description |\n|---|---|---|---|\n| `url` | `string` | — | COG file URL |\n| `viewProjection` | `string` | — | Target map projection (e.g. `'EPSG:3857'`) |\n| `bandInfo` | `object` | auto-detect | `{ type: 'rgb'|'gray', bands: number[] }` |\n| `projectionMode` | `string` | — | Set to `'affine'` for rotated GeoTIFFs |\n| `targetTileSize` | `number` | `256` | Target tile size in pixels |\n| `opacity` | `number` | `1` | Layer opacity |\n| `preload` | `number` | `0` | Number of adjacent zoom levels to preload tiles for |\n\nReturns: `Promise<{ layer, source, extent, center, projection, zoom, tiff }>`\n\n### `createCOGImageLayer(options)`\n\n| Option | Type | Default | Description |\n|---|---|---|---|\n| `url` | `string` | — | COG file URL |\n| `viewProjection` | `string` | — | Target map projection |\n| `projectionMode` | `string` | `'reproject'` | `'reproject'` or `'affine'` |\n| `opacity` | `number` | `1` | Layer opacity |\n| `resolutionMultiplier` | `number` | `1` | Resolution scale factor |\n| `debounceMs` | `number` | `500` | Debounce delay (ms) before re-fetching raster data on view change |\n\nReturns: `Promise<{ layer, source, extent, center, projection, tiff, getStats(), getBandInfo(), setStats(stats), setColormap(name) }>`\n\n## License\n\nMIT\n","readmeFilename":"README.md","author":{"name":"conaonda"}}