Getting Started

imgcraft is a chainable image transform pipeline that runs in both Node.js and the browser. One API, everywhere.

Install

npm install imgcraft
npm install imgcraft

Node.js requires sharp as an optional peer dependency:

npm install imgcraft sharp
npm install imgcraft sharp

Browser usage requires no additional install — WebAssembly is bundled automatically.

First image

import { img } from 'imgcraft'

const buffer = await img('photo.jpg')
  .resize(800, 600)
  .webp({ quality: 85 })
  .toBuffer()
import { img } from 'imgcraft'

const buffer = await img('photo.jpg')
  .resize(800, 600)
  .webp({ quality: 85 })
  .toBuffer()

img() accepts a file path (Node.js), Buffer, Uint8Array, ArrayBuffer, or a browser File / Blob.

Output methods

MethodReturnsEnvironment
.toBuffer()Buffer (Node) / Uint8Array (browser)Node + Browser
.toFile(path)Promise<void>Node only
.toStream()ReadableStream<Uint8Array>Node only
.toDataURL()Promise<string> (base64 data URI)Browser
.meta()Promise<MetadataResult>Node + Browser
// Write to disk
await img('photo.jpg').resize(800).toFile('./output.jpg')

// Stream (e.g. pipe to HTTP response)
const stream = await img('photo.jpg').resize(800).toStream()

// Browser — display in an <img> tag
const url = await img(file).resize(400).toDataURL()
document.querySelector('img').src = url
// Write to disk
await img('photo.jpg').resize(800).toFile('./output.jpg')

// Stream (e.g. pipe to HTTP response)
const stream = await img('photo.jpg').resize(800).toStream()

// Browser — display in an <img> tag
const url = await img(file).resize(400).toDataURL()
document.querySelector('img').src = url

Node vs Browser

imgcraft detects your runtime automatically. No flag needed.

EnvironmentEngineNotes
Node.jssharpFull feature set, fastest
BrowserWASMSame API, no server required
// Node.js — uses sharp
const out = await img('photo.jpg').resize(800).toBuffer()

// Browser — same API, WASM engine selected automatically
const out = await img(fileInput).resize(800).toDataURL()
// Node.js — uses sharp
const out = await img('photo.jpg').resize(800).toBuffer()

// Browser — same API, WASM engine selected automatically
const out = await img(fileInput).resize(800).toDataURL()

AI operations (removeBackground, smartCrop, upscale) are Node.js only — they load ONNX and TensorFlow models on first use.

Chaining transforms

Every method returns the same Pipeline instance, so transforms compose left to right:

const buffer = await img('photo.jpg')
  .resize(1200)           // scale down
  .sharpen()              // recover detail
  .brightness(1.05)       // slight lift
  .webp({ quality: 85 }) // encode
  .toBuffer()
const buffer = await img('photo.jpg')
  .resize(1200)           // scale down
  .sharpen()              // recover detail
  .brightness(1.05)       // slight lift
  .webp({ quality: 85 }) // encode
  .toBuffer()

Batch processing

batch() applies the same pipeline to multiple inputs in parallel:

import { batch } from 'imgcraft'

await batch(['a.jpg', 'b.jpg', 'c.jpg'], { concurrency: 4 })
  .resize(800)
  .webp({ quality: 85 })
  .toDir('./output')
import { batch } from 'imgcraft'

await batch(['a.jpg', 'b.jpg', 'c.jpg'], { concurrency: 4 })
  .resize(800)
  .webp({ quality: 85 })
  .toDir('./output')

Output options:

// Write to a directory (filename preserved, extension changed to match format)
await batch(inputs).resize(800).webp().toDir('./out')

// Get results as an array of Uint8Array
const buffers = await batch(inputs).resize(800).toBuffers()

// 1:1 path mapping
await batch(inputs).resize(800).toFiles(['./a-sm.jpg', './b-sm.jpg', './c-sm.jpg'])
// Write to a directory (filename preserved, extension changed to match format)
await batch(inputs).resize(800).webp().toDir('./out')

// Get results as an array of Uint8Array
const buffers = await batch(inputs).resize(800).toBuffers()

// 1:1 path mapping
await batch(inputs).resize(800).toFiles(['./a-sm.jpg', './b-sm.jpg', './c-sm.jpg'])

TypeScript

imgcraft is written in strict TypeScript. All transforms are fully typed.

import type { Pipeline, MetadataResult } from 'imgcraft'

async function thumbnail(input: string): Promise<Buffer> {
  return img(input).resize(200, 200, { fit: 'cover' }).jpeg({ quality: 75 }).toBuffer()
}
import type { Pipeline, MetadataResult } from 'imgcraft'

async function thumbnail(input: string): Promise<Buffer> {
  return img(input).resize(200, 200, { fit: 'cover' }).jpeg({ quality: 75 }).toBuffer()
}

Next steps

  • Transforms — resize, crop, rotate, flip, flop
  • Filters — blur, sharpen, colour adjustments
  • Format — JPEG, PNG, WebP, AVIF options
  • AI Operations — background removal, smart crop, upscale
  • Batch — concurrent processing
  • REST API — hosted endpoint for any language