@ekipnico/image-transform
v1.0.0
Published
Image format conversion (png/jpeg/webp), lossy/lossless encoding, web-ready resize
Readme
@ekipnico/image-transform
Image format conversion (PNG / JPEG / WebP), lossy/lossless encoding, and web-ready resize. Powered by sharp.
Install
npm install @ekipnico/image-transformUsage
import { transformImage } from '@ekipnico/image-transform';
const result = await transformImage(buffer, {
format: 'webp',
mode: 'lossy',
maxWidth: 2000,
maxHeight: 2000,
});
// {
// buffer: <Buffer ...>, // encoded output
// format: 'webp',
// mode: 'lossy',
// width: 1600,
// height: 900,
// bytes: 84210,
// originalBytes: 1240312,
// originalFormat: 'jpeg',
// originalWidth: 4000,
// originalHeight: 2250,
// compressionRatio: 0.068 // 6.8% of original size
// }Same ImageInput types as the rest of the pipeline (Buffer, { url }, { base64 }).
Lossy vs Lossless — what's the difference?
| | Lossy | Lossless |
|---|---|---|
| File size | Small | Large |
| Quality loss | Yes (perceptual, irreversible) | None |
| Best for | Photos, gradients, the public web | Logos, icons, screenshots, transparency, archival |
| Re-encoding | Degrades each pass | Stable, no degradation |
| Quality knob | quality: 1-100 | n/a (always pixel-perfect) |
Rule of thumb for the web: lossy WebP at quality 75-85 is the sweet spot for photos. Use lossless for UI assets, line art, or anywhere the source is already small and detail-critical.
Format compatibility
The mode flag is only meaningful for WebP. The other formats are fixed:
| Format | Mode behavior |
|---|---|
| png | Always lossless. mode flag ignored. effort controls compressionLevel (0-9). |
| jpeg | Always lossy. mode flag ignored. quality knob only. |
| webp | Honors mode. Lossless = pixel-perfect, larger. Lossy = uses quality, smaller. |
The result object echoes back the mode actually applied, so if you pass format: 'png', mode: 'lossy' you'll get mode: 'lossless' back. Trust the result, not the request.
Config
| Field | Default | Notes |
|---|---|---|
| format | 'webp' | 'png' / 'jpeg' / 'webp' |
| mode | 'lossy' | 'lossy' / 'lossless' (WebP only) |
| quality | 82 | 1-100. Used for jpeg always; webp lossy. Ignored for png. |
| maxWidth | 2000 | 0 = no cap |
| maxHeight | 2000 | 0 = no cap |
| fit | 'inside' | 'inside' / 'cover' / 'contain' |
| stripMetadata | true | Drops EXIF/ICC/XMP. EXIF orientation is honored before stripping. |
| effort | 4 | Encoder effort. webp 0-6, png compressionLevel 0-9. |
Class API
import { ImageTransformer } from '@ekipnico/image-transform';
const transformer = new ImageTransformer();
const result = await transformer.transform(input, config);Apify-friendly
The TransformResult (minus buffer) is JSON-serializable, so it drops cleanly into an Apify Dataset record. Push the buffer to KVS separately:
const { buffer, ...meta } = await transformImage(input, config);
await Actor.setValue(`img-${id}.${meta.format}`, buffer, { contentType: `image/${meta.format}` });
await Actor.pushData(meta);Testing locally
npm install
npx tsx test.ts # uses default test image
npx tsx test.ts https://example.com/photo.jpgOutputs out-<format>-<mode>.<ext> files in cwd.
