Skip to main content
ImageUtils is a static utility class that wraps the Canvas adapter for common image operations. It is environment-agnostic: the same calls work in Node.js (CanvasKit), the browser (HTMLCanvasElement), and Web Workers (OffscreenCanvas).

ImageType

ImageType is an enum listing the image formats supported by GeoPackage JS.
import { ImageType } from '@ngageoint/geopackage';

enum ImageType {
  PNG  = 'png',
  JPEG = 'jpeg',
  JPG  = 'jpg',
  TIFF = 'tiff',
  WEBP = 'webp',
}

ImageType.getMimeType()

Converts an ImageType value to its MIME type string.
ImageType.getMimeType(type?: ImageType): string
type
ImageType
The image type to convert. Defaults to ImageType.PNG.
ImageType.getMimeType(ImageType.JPEG); // 'image/jpeg'
ImageType.getMimeType(ImageType.PNG);  // 'image/png'

ImageType.getTypeFromMimeType()

Converts a MIME type string back to an ImageType enum value.
ImageType.getTypeFromMimeType(mimeType: string): ImageType
mimeType
string
required
A MIME type string such as 'image/png' or 'image/jpeg'.
Throws GeoPackageException if the MIME type is not recognised.

Static methods

getImage()

Loads raw image bytes, a base64 data URL, or a file path into a GeoPackageImage. If the value passed is already a GeoPackageImage it is returned unchanged.
public static async getImage(
  data: Uint8Array | Buffer | string,
  contentType?: string
): Promise<GeoPackageImage>
data
Uint8Array | Buffer | string
required
Raw image bytes, a base64 data URL string, a file path (Node.js), or an existing GeoPackageImage.
contentType
string
MIME type of the image data. Defaults to 'image/png'.
Returns null if decoding fails rather than throwing, so always check the return value.
import { ImageUtils, ImageType } from '@ngageoint/geopackage';
import fs from 'fs';

const bytes = fs.readFileSync('/data/tile.png');
const image = await ImageUtils.getImage(bytes, 'image/png');

if (image) {
  console.log(`${image.getWidth()}x${image.getHeight()}`);
  image.dispose(); // free CanvasKit memory in Node.js
}

getImageSize()

Returns the pixel dimensions of an image from its raw bytes or file path without fully decoding it. This is a synchronous operation backed by the image-size library.
public static getImageSize(
  data: Buffer | string
): ISizeCalculationResult
data
Buffer | string
required
Raw image bytes (Buffer) or a file path (string).
Returns an ISizeCalculationResult with width, height, and type properties.
import { ImageUtils } from '@ngageoint/geopackage';
import fs from 'fs';

const bytes = fs.readFileSync('/data/tile.png');
const { width, height, type } = ImageUtils.getImageSize(bytes);
console.log(width, height, type); // 256 256 'png'

getScaledImage()

Loads an image from bytes or a file path and returns a new GeoPackageImage scaled by the given factor. If scale is exactly 1.0 the original image is returned without re-encoding.
public static async getScaledImage(
  data: Buffer | string,
  scale: number
): Promise<GeoPackageImage>
data
Buffer | string
required
Raw image bytes or a file path.
scale
number
required
Uniform scale factor. 0.5 halves both dimensions; 2 doubles them.
Returns null if the image could not be loaded or scaled.
The original image is automatically disposed after scaling. Only the returned scaled image needs to be disposed.
import { ImageUtils } from '@ngageoint/geopackage';
import fs from 'fs';

const bytes = fs.readFileSync('/data/tile.png');
const scaled = await ImageUtils.getScaledImage(bytes, 0.5);

if (scaled) {
  console.log(`${scaled.getWidth()}x${scaled.getHeight()}`);
  scaled.dispose();
}

scaleImage()

Scales an existing GeoPackageImage to exact pixel dimensions. The source image is automatically disposed.
public static async scaleImage(
  image: GeoPackageImage,
  scaledWidth: number,
  scaledHeight: number
): Promise<GeoPackageImage>
image
GeoPackageImage
required
The source image. Do not use this image after the call — it is disposed internally.
scaledWidth
number
required
Target width in pixels.
scaledHeight
number
required
Target height in pixels.
Returns null if scaling fails.
image is disposed inside scaleImage(). Do not call image.dispose() yourself after passing it to this method.
import { ImageUtils } from '@ngageoint/geopackage';

// image was obtained from Canvas.createImage() or a tile retriever
const thumbnail = await ImageUtils.scaleImage(image, 64, 64);
if (thumbnail) {
  // use thumbnail...
  thumbnail.dispose();
}

writeImageToBytes()

Encodes a GeoPackageImage to a Uint8Array in the specified format.
public static async writeImageToBytes(
  image: GeoPackageImage,
  imageFormat: ImageType,
  compressionQuality: number
): Promise<Uint8Array>
image
GeoPackageImage
required
The image to encode.
imageFormat
ImageType
required
Target format, e.g. ImageType.PNG or ImageType.JPEG.
compressionQuality
number
required
Quality from 0 to 1. Only meaningful for lossy formats such as ImageType.JPEG. Pass 1.0 for lossless formats.
import { ImageUtils, ImageType } from '@ngageoint/geopackage';
import fs from 'fs';

const bytes = await ImageUtils.writeImageToBytes(image, ImageType.JPEG, 0.85);
fs.writeFileSync('/output/tile.jpg', bytes);
image.dispose();

isFullyTransparent()

Checks whether every pixel in the image is fully transparent (alpha = 0). Useful for skipping blank tiles.
public static async isFullyTransparent(
  data: Uint8Array | Buffer,
  width: number,
  height: number
): Promise<boolean>
data
Uint8Array | Buffer
required
Raw image bytes.
width
number
required
Expected image width in pixels.
height
number
required
Expected image height in pixels.
Returns true if all pixels are fully transparent, false otherwise.
import { ImageUtils } from '@ngageoint/geopackage';

const blank = await ImageUtils.isFullyTransparent(tileBytes, 256, 256);
if (!blank) {
  // render the tile
}

Complete example

The following example shows a typical Node.js workflow: load a tile from a GeoPackage, scale it to a thumbnail size, encode it as JPEG, and save it to disk.
import {
  GeoPackageManager,
  GeoPackageTileRetriever,
  ImageUtils,
  ImageType,
} from '@ngageoint/geopackage';
import fs from 'fs';

const geoPackage = await GeoPackageManager.open('/data/world.gpkg');
try {
  const retriever = new GeoPackageTileRetriever(geoPackage, 'tiles', 256, 256);
  const tileBytes = await retriever.getTileData(0, 0, 0);

  if (tileBytes) {
    // Decode bytes into a GeoPackageImage
    const image = await ImageUtils.getImage(tileBytes, 'image/png');

    if (image && !(await ImageUtils.isFullyTransparent(tileBytes, image.getWidth(), image.getHeight()))) {
      // Scale to 64x64 thumbnail (disposes original image internally)
      const thumb = await ImageUtils.scaleImage(image, 64, 64);

      if (thumb) {
        const jpegBytes = await ImageUtils.writeImageToBytes(thumb, ImageType.JPEG, 0.9);
        fs.writeFileSync('/output/thumb.jpg', jpegBytes);
        thumb.dispose();
      }
    } else {
      image?.dispose();
    }
  }
} finally {
  geoPackage.close();
}

Build docs developers (and LLMs) love