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

sharp-web

v1.0.0

Published

Browser-based image processing library with a sharp-compatible fluent API, powered by the HTML Canvas API

Readme

sharp-web

Browser-based image processing library with a sharp-compatible fluent API, powered by the HTML Canvas API.

Process images entirely in the browser — no server round-trip, no WebAssembly binary, zero production dependencies.

Features

  • Sharp-compatible API — familiar fluent interface for anyone coming from Node.js sharp
  • Zero dependencies — uses only native browser APIs (Canvas, Image, Blob)
  • Lazy pipeline — no pixel work happens until an output method is awaited
  • Multiple input typesBlob, File, URL string, data URL, Uint8Array, ArrayBuffer, ImageData, HTMLImageElement, HTMLCanvasElement, raw pixel buffers
  • Multiple output formats — PNG, JPEG, WebP, raw RGBA pixels
  • Full TypeScript support — strict types and exported interfaces
  • Lightweight — minimal footprint with no external image processing libraries

Installation

npm install sharp-web

Quick Start

import sharp from "sharp-web";

// Resize an image from a URL
const buffer = await sharp("/images/photo.jpg")
  .resize(300, 200)
  .jpeg()
  .toBuffer();

// Process a file from <input type="file">
const file = inputElement.files[0];
const blob = await sharp(file).resize(800, 600).png().toBlob();

Usage

Importing

import sharp from "sharp-web";

// Or import the class directly
import { SharpWeb } from "sharp-web";

Input Types

sharp-web accepts a variety of image sources:

// From a URL or data URL
sharp("/images/photo.jpg");
sharp("data:image/png;base64,...");

// From a Blob or File
sharp(file);
sharp(blob);

// From an HTMLImageElement
sharp(document.querySelector("img"));

// From an HTMLCanvasElement
sharp(document.querySelector("canvas"));

// From raw pixel data (Uint8Array or ArrayBuffer)
sharp(rgbaBytes, {
  raw: { width: 100, height: 100, channels: 4 },
});

// From ImageData
sharp(ctx.getImageData(0, 0, width, height));

Resizing

// Resize to 300px wide, height auto-calculated to preserve aspect ratio
await sharp(input).resize(300).toBuffer();

// Resize to specific dimensions
await sharp(input).resize(300, 200).toBuffer();

// Resize with fit strategies
await sharp(input).resize(300, 200, { fit: "cover" }).toBuffer(); // crop to fill (default)
await sharp(input).resize(300, 200, { fit: "contain" }).toBuffer(); // fit within, may letterbox
await sharp(input).resize(300, 200, { fit: "fill" }).toBuffer(); // stretch to fill exactly
await sharp(input).resize(300, 200, { fit: "inside" }).toBuffer(); // scale down to fit inside
await sharp(input).resize(300, 200, { fit: "outside" }).toBuffer(); // scale up to cover

Cropping / Extraction

// Extract a 100x100 region starting at (10, 10)
await sharp(input).extract(10, 10, 100, 100).toBuffer();

// Or use an options object
await sharp(input)
  .extract({ left: 10, top: 10, width: 100, height: 100 })
  .toBuffer();

Rotation

// Rotate 90 degrees clockwise
await sharp(input).rotate(90).toBuffer();

// Arbitrary angle
await sharp(input).rotate(45).toBuffer();

Flipping

// Flip vertically (around horizontal axis)
await sharp(input).flip().toBuffer();

// Flop horizontally (mirror, around vertical axis)
await sharp(input).flop().toBuffer();

Compositing

Overlay one or more images on top of the base image:

await sharp(baseImage)
  .composite([
    { input: watermark, left: 10, top: 10, opacity: 0.5 },
    { input: overlay, left: 50, top: 50, blend: "multiply" },
  ])
  .toBuffer();

Supported blend modes: "source-over" (default), "multiply", "screen", "overlay", "darken", "lighten".

Chaining Operations

All transformation methods return this, so operations can be freely chained:

const result = await sharp(file)
  .resize(800, 600, { fit: "inside" })
  .rotate(90)
  .extract({ left: 0, top: 0, width: 400, height: 300 })
  .flip()
  .jpeg()
  .toBuffer();

Output Formats

// PNG (default)
await sharp(input).png().toBuffer();

// JPEG
await sharp(input).jpeg().toBuffer();

// WebP
await sharp(input).webp().toBuffer();

// Raw RGBA pixel bytes
await sharp(input).raw().toBuffer();

Output Methods

// As Uint8Array
const buffer = await sharp(input).toBuffer();

// As Blob
const blob = await sharp(input).toBlob();

// As data URL (e.g. for setting img.src)
const dataUrl = await sharp(input).toDataURL();
document.querySelector("img").src = dataUrl;

Metadata

Retrieve image metadata without processing:

const meta = await sharp(input).metadata();
console.log(meta.width); // number
console.log(meta.height); // number
console.log(meta.format); // "png" | "jpeg" | "webp" | "raw" | ...
console.log(meta.channels); // 3 | 4
console.log(meta.hasAlpha); // boolean
console.log(meta.space); // "srgb"
console.log(meta.size); // byte size (when available)

Cloning

Create independent copies of a pipeline to produce multiple outputs from the same source:

const base = sharp(file).resize(300);

const [png, jpeg] = await Promise.all([
  base.clone().png().toBuffer(),
  base.clone().jpeg().toBuffer(),
]);

API Reference

sharp(input, options?)

Creates a new processing pipeline.

| Parameter | Type | Description | | --------- | ------------------- | -------------------------------------------------------------------------- | | input | SharpInput | Image source (see Input Types) | | options | SharpInputOptions | Optional. Use { raw: { width, height, channels } } for raw pixel buffers |

Returns a SharpWeb instance.

Transformation Methods

All return this for chaining.

| Method | Description | | ----------------------------------- | ----------------------------------------------------------------------------------------- | | resize(width?, height?, options?) | Resize image. Options: { fit: "cover" \| "contain" \| "fill" \| "inside" \| "outside" } | | extract(left, top, width, height) | Crop a rectangular region | | rotate(angle?) | Rotate clockwise by degrees | | flip() | Flip vertically | | flop() | Flip horizontally (mirror) | | composite(layers) | Overlay images with positioning, blend modes, and opacity |

Format Methods

All return this for chaining.

| Method | Description | | -------- | ---------------------------------- | | png() | Set output format to PNG (default) | | jpeg() | Set output format to JPEG | | webp() | Set output format to WebP | | raw() | Output raw RGBA pixel bytes |

Output Methods

| Method | Returns | Description | | ------------- | --------------------- | --------------------------------------------- | | toBuffer() | Promise<Uint8Array> | Encoded image bytes (or raw RGBA if .raw()) | | toBlob() | Promise<Blob> | Encoded image as Blob | | toDataURL() | Promise<string> | Base64-encoded data URL string | | metadata() | Promise<Metadata> | Image metadata without processing | | clone() | SharpWeb | Independent copy of the pipeline |

Exported Types

import type {
  SharpInput, // Union of all accepted input types
  SharpInputOptions, // Options for raw pixel inputs
  RawInputOptions, // { width, height, channels }
  Metadata, // Image metadata object
  ExtractOptions, // { left, top, width, height }
  ResizeOptions, // { fit? }
  CompositeInput, // Layer descriptor for composite()
} from "sharp-web";

Browser Compatibility

sharp-web relies on the Canvas API, which is supported in all modern browsers. Output format support depends on the browser:

| Format | Chrome | Firefox | Safari | Edge | | ------ | ------ | ------- | ------ | ---- | | PNG | Yes | Yes | Yes | Yes | | JPEG | Yes | Yes | Yes | Yes | | WebP | Yes | Yes | Yes* | Yes |

* Safari 16+ supports WebP encoding.

Differences from Node.js sharp

sharp-web aims for API compatibility with sharp but runs entirely in the browser using Canvas. Key differences:

  • No native binaries — no libvips dependency; purely JavaScript + Canvas API
  • Browser only — requires DOM APIs (HTMLCanvasElement, HTMLImageElement, Blob, etc.)
  • Subset of operations — supports resize, crop, rotate, flip, flop, and composite. Operations like blur, sharpen, colour manipulation, and format-specific encoding options are not yet implemented.
  • Canvas quality limits — image processing fidelity depends on the browser's Canvas implementation

Development

# Install dependencies
bun install

# Type-check
bun run test

# Lint
bun run lint

# Build (compile + generate docs)
bun run build

This project uses:

  • TypeScript with strict mode
  • ESLint (v9 flat config) with typescript-eslint
  • Prettier for formatting (via lint-staged on pre-commit)
  • Conventional Commits enforced by commitlint
  • Semantic Release for automated versioning and publishing

License

MIT © ByteLand Technology Limited