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.
Maintainers
Readme
SnapFit
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 snapfitFor HEIC/iPhone photo support (peer dependency):
npm install snapfit heic2anyCDN (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
heic2anypeer 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-shakeable —
import { 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: 0–1. 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: 0–1. |
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: 0–1. |
For HEIC input files, heic2any must be installed as a peer dependency:
npm install heic2anyResult: 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
