optimag
v0.1.0
Published
Tiny browser-side TypeScript image optimization library for pre-upload compression.
Maintainers
Readme
optimag
Tiny browser-side TypeScript helper for shrinking images before uploading them to object storage.
Install
npm install optimagUsage
import { optimizeImage } from "optimag";
const input = fileInput.files?.[0];
if (input) {
const result = await optimizeImage(input, {
maxWidth: 1920,
maxHeight: 1920,
quality: 0.82,
mimeType: "image/webp",
});
await fetch("/upload", {
method: "POST",
body: result.file,
});
}React Guide
Use the optimizer inside a file input change handler or form submit handler. The library depends on browser APIs, so call it only on the client.
import { ChangeEvent, useState } from "react";
import { optimizeImage } from "optimag";
export function ImageUploader() {
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
const [isUploading, setIsUploading] = useState(false);
const [message, setMessage] = useState<string | null>(null);
async function handleChange(event: ChangeEvent<HTMLInputElement>) {
const input = event.target.files?.[0];
if (!input) {
return;
}
setIsUploading(true);
setMessage(null);
try {
const optimized = await optimizeImage(input, {
maxWidth: 1600,
maxHeight: 1600,
quality: 0.8,
mimeType: "image/webp",
});
const formData = new FormData();
formData.append("file", optimized.file);
const response = await fetch("/api/upload", {
method: "POST",
body: formData,
});
if (!response.ok) {
throw new Error("Upload failed.");
}
setPreviewUrl(URL.createObjectURL(optimized.file));
setMessage(
`Saved ${Math.round(optimized.savedBytes / 1024)} KB before upload.`,
);
} catch (error) {
setMessage(error instanceof Error ? error.message : "Upload failed.");
} finally {
setIsUploading(false);
}
}
return (
<div>
<input
type="file"
accept="image/*"
onChange={handleChange}
disabled={isUploading}
/>
{previewUrl ? <img src={previewUrl} alt="Preview" width={240} /> : null}
{message ? <p>{message}</p> : null}
</div>
);
}React integration notes:
- Call
optimizeImageonly in browser event handlers, effects, or other client-only code. - In Next.js App Router, put the component behind
"use client"because server components cannot access canvas orFile. - Upload
result.fileinFormDataif your backend expects a standard browser file upload. - If you create preview URLs with
URL.createObjectURL, revoke old URLs when replacing them in a long-lived component.
Publish To npm
The package is configured for public npm publishing. Before publishing:
npm login
npm run typecheck
npm run build
npm publishNotes:
prepublishOnlyalready runs typechecking and build duringnpm publish.- The name
optimagwas not present in the npm registry when checked on March 9, 2026, but npm names can change at any time, so recheck before your final publish.
API
optimizeImage(blob, options) returns:
blob: the optimized output blobfile: aFilewrapper ready for form uploadswidth/height: output dimensionsoriginalWidth/originalHeight: input dimensionsmimeType: output mime typeoriginalSize/outputSize: byte sizes before and after optimizationsavedBytes: how many bytes were removed
Options:
maxWidth: resize down if the source is wider than thismaxHeight: resize down if the source is taller than thisquality: compression quality from0to1mimeType: output format, typicallyimage/jpeg,image/png, orimage/webpkeepOriginalIfSmaller: defaults totrue; returns the original image if recompression makes it largerfileName: override the generated output filename
Notes
- Runs entirely in the browser using
createImageBitmapand canvas APIs. - Keeps aspect ratio automatically.
- Falls back to the original file when the optimized result is not actually smaller.
