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

snapfit-sdk

v1.1.0

Published

Universal client-side image processing SDK. Resize, compress, convert, and AI-crop images in the browser — zero server, zero latency.

Readme

SnapFit

npm version license bundle size

Client-side image resizing, compression, and format conversion — processes files in the browser to exact pixel dimensions and KB targets before upload.

Install

npm install snapfit

For HEIC/iPhone photo support (peer dependency):

npm install snapfit heic2any

CDN (no build step):

<script src="https://cdn.jsdelivr.net/npm/snapfit/dist/snapfit.umd.js"></script>

Quick Start

Process a file for JEE Main upload — exact 200×230px, under 200KB, JPEG:

import { processImage } from 'snapfit';

const fileInput = document.getElementById('photo') as HTMLInputElement;

fileInput.addEventListener('change', async (e) => {
  const file = (e.target as HTMLInputElement).files?.[0];
  if (!file) return;

  const result = await processImage(file, {
    preset: 'jee-main-photo',
    onProgress: (percent) => {
      console.log(`Processing: ${percent}%`);
      progressBar.style.width = `${percent}%`;
    },
  });

  console.log(`Original: ${(result.originalSize / 1024).toFixed(1)} KB`);
  console.log(`Final:    ${(result.fileSize / 1024).toFixed(1)} KB`);
  console.log(`Size:     ${result.width}×${result.height}px`);
  console.log(`Ratio:    ${result.compressionRatio.toFixed(2)}x`);

  // Upload the processed blob
  const formData = new FormData();
  formData.append('photo', result.blob, 'photo.jpg');
  await fetch('/api/upload', { method: 'POST', body: formData });
});

Why SnapFit

  • Processes files entirely in the browser — images never leave the user's device before upload
  • Hits exact targets — binary-search compression converges to within 2KB of your target in 5–8 iterations
  • Handles HEIC out of the box — iPhone photos work with the heic2any peer dependency
  • 15 presets for Indian exam and government portals — JEE, NEET, UPSC, SBI PO, Aadhaar KYC, Schengen visa, and more
  • AI modes — face auto-crop for passport photos, signature extraction, document flattening (requires MediaPipe / OpenCV.js CDN; gracefully falls back when unavailable)
  • ~15KB gzipped for the core module — no AI or peer dependencies included
  • Tree-shakeableimport { resize } from 'snapfit' only ships resize code
  • TypeScript-first — full type definitions shipped in the package

API Reference

processImage(input, options)

All-in-one function. Resizes, compresses, converts, and optionally applies AI processing in a single call.

import { processImage } from 'snapfit';

const result = await processImage(file, options);

Options:

| Option | Type | Default | Description | |--------|------|---------|-------------| | preset | string | — | Named preset key or alias (e.g. 'jee-main-photo', 'jee-main'). Sets width, height, maxFileSize, and format. Manual options override preset values. | | mode | 'auto' \| 'passport' \| 'signature' \| 'document' | 'auto' | AI processing mode. 'passport' auto-crops to face. 'signature' extracts clean signature on white background. 'document' flattens and deskews. AI pipeline gracefully falls back when MediaPipe / OpenCV.js CDN is unavailable. | | format | 'jpeg' \| 'png' \| 'webp' | 'jpeg' | Output image format. | | quality | number | 0.92 | JPEG/WebP compression quality. Range: 01. Overridden during binary-search compression if maxFileSize is set. | | maxWidth | number | — | Maximum output width in pixels. Aspect ratio is preserved unless maxHeight is also set. | | maxHeight | number | — | Maximum output height in pixels. | | maxFileSize | number | — | Maximum output file size in bytes (e.g. 50 * 1024 for 50KB). Triggers binary-search compression. | | fit | 'cover' \| 'contain' \| 'fill' | 'cover' | How the image fills the target dimensions. 'cover' crops to fill (no letterbox). 'contain' fits inside (may add padding). 'fill' stretches to exact dimensions. | | onProgress | (percent: number) => void | — | Progress callback. Fires at approximately 15, 35, 65, 90, and 100 percent. |

Result:

interface ProcessImageResult {
  blob: Blob;             // Processed image as a Blob — ready for FormData upload
  dataUrl: string;        // Base64 data URL — ready for <img src>
  width: number;          // Final image width in pixels
  height: number;         // Final image height in pixels
  fileSize: number;       // Final file size in bytes
  format: 'jpeg' | 'png' | 'webp';
  originalSize: number;   // Original file size in bytes
  compressionRatio: number; // originalSize / fileSize (e.g. 4.2 means 4.2x smaller)
  preset?: string;        // Preset key used, if any
  warnings: string[];     // Non-fatal issues (e.g. 'Could not reach target size — minimum quality reached')
}

resize(file, options)

Resize an image to exact pixel dimensions.

import { resize } from 'snapfit';

const result = await resize(file, {
  width: 200,
  height: 230,
  fit: 'cover', // default
});

Options:

| Option | Type | Default | Description | |--------|------|---------|-------------| | width | number | — | Target width in pixels. Required if height is not set. | | height | number | — | Target height in pixels. Required if width is not set. | | fit | 'cover' \| 'contain' \| 'fill' | 'cover' | How the image fills the target dimensions. |

Result: Returns a SnapFitResult — see Result Shape.


compress(file, options)

Compress an image to a target file size using binary search on JPEG quality.

import { compress } from 'snapfit';

const result = await compress(file, {
  maxSizeKB: 50,
  quality: 0.9, // starting quality for binary search
});

Options:

| Option | Type | Default | Description | |--------|------|---------|-------------| | maxSizeKB | number | — | Target maximum file size in kilobytes. Required. | | quality | number | 0.8 | Starting quality for binary search. Range: 01. |

Algorithm: Starts at the given quality, exports to blob, checks size, then binary-searches the quality value to converge within 2KB of the target in 5–8 iterations. If quality 0.1 still exceeds the target, dimensions are reduced proportionally.

Result: Returns a SnapFitResult — see Result Shape.


convert(file, options)

Convert an image to a different format.

import { convert } from 'snapfit';

const result = await convert(file, {
  format: 'jpeg',
  quality: 0.9,
});

Options:

| Option | Type | Default | Description | |--------|------|---------|-------------| | format | 'jpeg' \| 'png' \| 'webp' | — | Target format. Required. | | quality | number | 0.92 | Compression quality for JPEG and WebP. Ignored for PNG (lossless). Range: 01. |

For HEIC input files, heic2any must be installed as a peer dependency:

npm install heic2any

Result: Returns a SnapFitResult — see Result Shape.


mount(selector, config) — Drop-in Widget

Mount a drag-and-drop upload widget into any container element. No React or framework required.

import SnapFit from 'snapfit';

SnapFit.mount('#upload-area', {
  preset: 'jee-main-photo',
  onComplete: (result) => {
    document.getElementById('preview').src = result.dataUrl;
    console.log(`Ready to upload: ${(result.fileSize / 1024).toFixed(1)} KB`);
  },
  onError: (err) => {
    console.error('Processing failed:', err.message);
  },
});

Config:

| Option | Type | Description | |--------|------|-------------| | preset | string | Preset key to apply to uploaded files. | | processOptions | ProcessImageOptions | Full options object — used instead of preset for manual configuration. | | onComplete | (result: ProcessImageResult) => void | Called after successful processing. | | onError | (err: Error) => void | Called if processing fails. | | onProgress | (percent: number) => void | Progress callback during processing. | | accept | string | MIME types or extensions to accept (e.g. 'image/*,.heic'). Defaults to 'image/*,.heic'. | | label | string | Custom label text shown in the drop zone. |

CDN usage:

<div id="upload-area"></div>
<script src="https://cdn.jsdelivr.net/npm/snapfit/dist/snapfit.umd.js"></script>
<script>
  SnapFit.mount('#upload-area', {
    preset: 'jee-main-photo',
    onComplete: (result) => {
      document.getElementById('preview').src = result.dataUrl;
    },
  });
</script>

SnapFitResult

Returned by resize(), compress(), and convert().

interface SnapFitResult {
  blob: Blob;     // Processed image as a Blob
  dataURL: string; // Base64 data URL
  file: File;     // Processed image as a File object
  metadata: {
    originalSize: number;     // Original file size in bytes
    finalSize: number;        // Output file size in bytes
    width: number;            // Output width in pixels
    height: number;           // Output height in pixels
    format: string;           // Output format ('jpeg', 'png', 'webp')
    compressionRatio: number; // originalSize / finalSize
  };
}

Presets

Use a preset key or any of its aliases in processImage({ preset: '...' }).

| Preset Key | Aliases | Dimensions | Max Size | |---|---|---|---| | indian-passport | passport | 200×200 px | 500 KB | | jee-main-photo | jee-main | 200×230 px | 200 KB | | jee-main-signature | — | 160×60 px | 30 KB | | neet-ug-photo | neet, neet-ug | 200×230 px | 200 KB | | neet-ug-signature | — | 160×60 px | 30 KB | | upsc-cse-photo | upsc, upsc-cse | 280×350 px | 300 KB | | upsc-cse-signature | — | 280×90 px | 300 KB | | sbi-po-photo | sbi-po | 200×230 px | 50 KB | | ibps-po-photo | ibps-po | 200×230 px | 50 KB | | rrb-ntpc-photo | rrb-ntpc | 200×230 px | 100 KB | | cat-photo | cat | 200×230 px | 80 KB | | gate-photo | gate | 200×250 px | 200 KB | | aadhar-kyc-photo | aadhar, aadhar-kyc | 200×200 px | 200 KB | | pan-card-photo | pan-card | 213×213 px | 100 KB | | visa-schengen-photo | schengen | 295×413 px | 500 KB |

List all presets at runtime:

import { listPresets, getPreset } from 'snapfit';

listPresets();
// ['indian-passport', 'jee-main-photo', 'jee-main-signature', ...]

getPreset('jee-main-photo');
// { width: 200, height: 230, maxSizeKB: 200, format: 'jpeg', ... }

AI Modes

AI modes are included in the snapfit package. passport mode uses MediaPipe (loaded from CDN on demand). signature and document modes use OpenCV.js (loaded from CDN on demand). All modes fall back gracefully when their CDN dependency is unavailable.

| Mode | Description | |------|-------------| | 'passport' | Uses MediaPipe face detection to locate the face, crops to center it, and scales to the target dimensions. Suitable for passport and ID photo requirements. | | 'signature' | Isolates a handwritten signature from a photographed or scanned page. Outputs a clean black-on-white image suitable for official form uploads. | | 'document' | Detects document edges, applies perspective correction to remove skew, and normalizes contrast. Suitable for scanned ID cards and certificates. | | 'auto' | Uses the mode recommended by the active preset, or falls back to standard processing if the preset has no AI mode configured. |

import { processImage } from 'snapfit';

// Passport photo with face auto-crop
const result = await processImage(file, {
  preset: 'indian-passport',
  mode: 'passport',
});

// Signature extraction
const sig = await processImage(signaturePhoto, {
  preset: 'jee-main-signature',
  mode: 'signature',
});

Browser Support

| Browser | Minimum Version | Notes | |---------|----------------|-------| | Chrome | 80+ | Full support | | Firefox | 75+ | Full support | | Safari | 14+ | Full support | | Edge | 80+ | Full support |

HEIC support: HEIC decoding is handled by the heic2any peer dependency. Install it separately with npm install heic2any. Without it, passing a .heic file to any SnapFit function throws a SnapFitError with a descriptive message.

Node.js: The core module is browser-first (Canvas API). For Node.js/SSR environments, install canvas (npm install canvas) — SnapFit detects it automatically.


License

MIT — see LICENSE