Tiny image processing utilities built on top of sharp with a friendly typed API:
- Resize to named sizes (numbers, objects, or tuples)
- Optional smart crop around a hotspot
- Generate an LQIP (low‑quality image placeholder) data URL
- Return consistent metadata (width, height, ratio, format, mimetype, filesize)
The library ships ESM and CJS bundles with TypeScript typings.
- Node.js >= 18 or Bun >= 1.1
sharpnative binaries (automatically installed vianpm,pnpm,yarn, orbun)
Using Bun (recommended for tests and development):
bun add @norabelle-labs/image-processing sharpUsing npm:
npm install @norabelle-labs/image-processing sharpUsing pnpm:
pnpm add @norabelle-labs/image-processing sharpUsing yarn:
yarn add @norabelle-labs/image-processing sharpimport processImage, { defaultOptions } from "@norabelle-labs/image-processing";
// or named API
// import { processImage } from "@norabelle-labs/image-processing";
const file = await Bun.file("./fixtures/input.jpg").arrayBuffer();
const result = await processImage(Buffer.from(file), "input.jpg");
console.log(result.metadata);
// {
// width: 1920,
// height: 1080,
// ratio: 1.777...
// format: 'jpeg',
// filesize: 1234567,
// filename: 'input.jpg',
// mimetype: 'image/jpeg'
// }
console.log(Object.keys(result.sizes)); // [ 'original', 'large', 'medium', 'small', 'thumb' ]
console.log(result.lqip); // data:image/webp;base64,...const { processImage, defaultOptions } = require("@norabelle-labs/image-processing");
(async () => {
const fs = require("node:fs/promises");
const buf = await fs.readFile("./fixtures/input.jpg");
const out = await processImage(buf, "input.jpg");
console.log(out.metadata);
})();source: anysharpinput (Buffer, ArrayBuffer, file path, etc.)filename: used formetadata.filenameoptions:format: asharpoutput format (e.g.'webp','jpeg')sizes: record of named sizes; values can be:- number: max dimension (width for landscape, height for portrait),
fit: "inside"and no enlargement - object:
{ width, height, fit?, hotspot? } - tuple:
[width, height, hotspot?, fit?] - the string
'original'
- number: max dimension (width for landscape, height for portrait),
Returns { sizes, lqip, metadata } where:
sizes: a map of your size name to{ data: Buffer, format }(buffer contains the converted image)lqip: adata:image/webp;base64,...placeholdermetadata:{ width, height, ratio, format, filesize, filename, mimetype }
Errors: Throws ImageProcessingError with code INVALID_IMAGE when the input is unreadable.
Low-level helper used by processImage that performs optional crop/resize and converts to format.
Creates a small, blurred WebP and returns a data: URL string.
export const defaultOptions = {
format: 'webp',
sizes: {
original: 'original',
large: 1200,
medium: 600,
small: 300,
thumb: 160,
}
}The main types are exported from ./types:
ProcessedImage<Sizes>ImageMetadataNamedSize,NamedSizes,NamedSizeOptions,NamedSizeArrayImageProcessingOptions<Sizes>ImageProcessingError
This repo uses tsup to produce ESM, CJS and type declarations into dist/.
- Build:
bun run build
# or: npm run build / pnpm build / yarn buildOutput files:
- ESM:
dist/index.js - CJS:
dist/index.cjs - Types:
dist/index.d.ts
Package exports is configured for both environments and includes types.
This project uses the Bun test runner. Tests live in tests/.
- Run tests:
bun test- Type-check:
bun run typecheckResize to explicit dimensions and crop around a hotspot:
import { processImage } from "@norabelle-labs/image-processing";
const src = await Bun.file("./hero.jpg").arrayBuffer();
const { sizes } = await processImage(Buffer.from(src), "hero.jpg", {
format: "webp",
sizes: {
hero: { width: 1600, height: 900, fit: "cover", hotspot: [1200, 400] },
thumb: 200,
},
});
await Bun.write("./public/hero.webp", sizes.hero.data);MIT