Measured on real AWS Lambda
The final profile ran at 05:51 UTC on August 9, 2026, in temporary us-east-1 Lambda functions using the managed Node.js 22 runtime and 512 MiB of memory. It compared x86_64 with ARM64 on the same JavaScript bundle, then explicitly selected the JPEG WASM accelerator for eligible full-resolution decodes. Every cell below is the median of three verified cold environments and three immediately paired warm invocations.
JavaScript reference: x86_64 versus ARM64
| Workflow | x86 cold total | ARM cold total | x86 warm operation | ARM warm operation | x86 max | ARM max |
|---|---|---|---|---|---|---|
| JPEG → 1024px PNG | 6,677.6 ms | 6,566.5 ms | 5,021.5 ms | 4,721.2 ms | 168 MiB | 168 MiB |
| JPEG → 1024px WebP | 6,870.4 ms | 7,095.4 ms | 5,140.9 ms | 4,886.2 ms | 158 MiB | 162 MiB |
| PNG → 1024px JPEG | 7,861.8 ms | 8,270.0 ms | 5,421.4 ms | 5,560.2 ms | 194 MiB | 201 MiB |
| PNG → 1024px WebP | 7,383.5 ms | 8,399.7 ms | 5,346.9 ms | 5,748.2 ms | 189 MiB | 190 MiB |
There is no universal architecture winner in this sample. ARM64 warm operation medians were about 5–6% lower on the two JPEG-input workflows and about 3–8% higher on the two PNG-input workflows. Maximum memory was equal or up to 7 MiB higher on ARM64.
Explicit JPEG WASM experiment
This profile resized the 4000 × 3000 JPEG to 3000 × 2250 so the planner requested a full-resolution decode and the accelerator was eligible. The reference JavaScript path remains the default. WASM does not apply to reduced-resolution JPEG decode, other codecs, or unrelated pipeline work.
| Architecture and output | JS cold total | WASM cold total | JS warm operation | WASM warm operation | Max used · JS / WASM | Cold WASM load |
|---|---|---|---|---|---|---|
| x86_64 · PNG | 16,589.5 ms | 15,337.5 ms | 14,437.7 ms | 13,201.0 ms | 171 / 178 MiB | 118.52 ms |
| x86_64 · WebP | 16,416.7 ms | 14,829.5 ms | 13,900.4 ms | 12,601.8 ms | 182 / 185 MiB | 119.52 ms |
| ARM64 · PNG | 15,722.4 ms | 13,882.2 ms | 13,623.6 ms | 11,461.9 ms | 198 / 197 MiB | 37.84 ms |
| ARM64 · WebP | 16,065.0 ms | 10,202.6 ms | 13,604.4 ms | 8,160.3 ms | 198 / 205 MiB | 57.41 ms |
The accepted cold operation lazily instantiated the module exactly once; its paired warm invocation reused that instance. WASM memory was 6.0 MiB in every accelerated row, while maximum AWS-reported memory sometimes increased. The ARM64 WebP median was substantially lower, but its three-sample distributions were variable; the exact values above should not be generalized beyond this fixture and profile.
operationMs includes JS/WASM input and output copies but excludes the S3 fixture read and output metadata validation. Those steps remain inside AWS Duration; cold total is Duration plus Init Duration.An earlier 04:50 UTC x86-only tier sweep embedded the fixtures in a roughly 5.2 MiB deployment, so its package and cold-start profile is obsolete. Its warm results still show the Lambda CPU-allocation effect: the JPEG → WebP operation took 10,601 ms at 256 MiB, 5,261 ms at 512 MiB, and 2,533 ms at 1024 MiB while maximum use stayed at 121, 122, and 120 MiB. All four measured 12-megapixel workflows completed at 256 MiB with 121–156 MiB maximum use. For latency-sensitive endpoints, start at 1024 MiB rather than sizing only from RSS. Read the tier-sweep report →
Read the final ARM64 and JPEG WASM report → Inspect the raw samples →
Earlier Jimp baseline
This separately recorded Jimp-only baseline predates the seven-engine profile above. In its 6000 × 4000 JPEG orientation, crop, resize, and encode workflow, PureJsImage used 118.6 MiB peak RSS versus Jimp’s 1,188.3 MiB and completed in 3,242.5 ms versus 3,762.9 ms.
| Workflow | PureJsImage | Jimp | PJI RSS | Jimp RSS |
|---|---|---|---|---|
| 6000×4000 orient, crop, resize, JPEG | 3,243 ms | 3,763 ms | 119 MiB | 1,188 MiB |
| JPEG crop and resize | 2,554 ms | 2,868 ms | 121 MiB | 1,197 MiB |
| 100-megapixel PNG downscale | 1,970 ms | 3,733 ms | 169 MiB | 1,274 MiB |
| 4000×3000 PNG resize | 496 ms | 944 ms | 142 MiB | 301 MiB |
| 4000×3000 BMP to JPEG | 149 ms | 719 ms | 153 MiB | 262 MiB |
| Large TIFF to JPEG | 109 ms | 639 ms | 133 MiB | 319 MiB |
Methodology
A timing is accepted only after its output passes the workflow’s structural or pixel validation. Input preparation, output validation, and exact-area quality measurement remain outside the timed and peak-RSS regions.
- Competitor profile: PureJsImage,
jimp@1.6.0,sharp@0.35.3with default concurrency and one processing thread,image-js@1.7.0, and jSquash JPEG 1.6.0, PNG 3.1.1, WebP 1.5.0, and resize 2.1.1. - Resize workflows use engine defaults. PureJsImage and Sharp use Lanczos 3; Jimp uses bilinear. Cross-kernel timings describe each package's default experience and are not matched-quality comparisons.
- Quality-enabled JPEG and PNG workflows independently decode input and output, apply exact-area resize and requested alpha flattening, and report premultiplied-RGBA PSNR. Fully transparent RGB does not count as visible error;
exactmeans every compared channel matched. - The detailed historical tables below use the separately recorded Jimp 1.6 baseline.
- Recorded environment: Node.js 24.16.0 on Linux x64, Intel Core i7-10700.
- Reports use median and p95 wall time across repeated runs.
- Absolute process peak RSS is the headline memory value.
- JSON is the authoritative machine-readable result; Markdown is the review summary.
Inputs include real photographs, phone-camera files, standards fixtures, transparent graphics, pathological dimensions, high-entropy data, and deterministic generated stress images. The corpus manifest records source, license, dimensions, and SHA-256.
Codec results
JPEG
Baseline JPEG reconstruction and encoding retain bounded MCU rows instead of a full source-resolution RGB or RGBA bitmap. Progressive decode and encode retain compact 16-bit coefficient planes; final decode reconstruction remains bounded-row.
For deterministic 2048×1536 quality-80 4:2:0 output, isolated cold progressive encoding took 343.01 ms and 100.44 MiB peak RSS versus 230.55 ms and 86.89 MiB for baseline. It retained 9.00 MiB of coefficients and produced 1,384,013 bytes versus 1,492,375 bytes, 7.26% smaller with identical independently decoded PSNR. Progressive output gathers statistics in a second pass and writes five scan-specific DHT markers; it remains a separate runtime and memory class.
| Workflow | PureJsImage wall | Jimp wall | PJI RSS | Jimp RSS |
|---|---|---|---|---|
| Large JPEG metadata | 0.2 ms | 5,285 ms | 97 MiB | 1,184 MiB |
| 4000×3000 resize to 1200 px | 894 ms | 1,395 ms | 106 MiB | 596 MiB |
| Twilio MMS JPEG to 1024 px | 853 ms | 1,364 ms | 105 MiB | 601 MiB |
| EXIF orientation 6 | 388 ms | 576 ms | 105 MiB | 254 MiB |
Ordered transforms to JPEG
These workflows use three isolated runs after one warmup and accept timings only when dimensions and pinned output pixels pass. PureJsImage’s arbitrary-angle rotation has a separate absolute baseline because Jimp uses different canvas sizing and sampling semantics.
| Workflow | PureJsImage wall | Jimp wall | PJI RSS | Jimp RSS |
|---|---|---|---|---|
| Rotate 90°, resize, JPEG | 1,795 ms | 2,052 ms | 175 MiB | 609 MiB |
| Resize, crop, resize, JPEG | 952 ms | 1,434 ms | 121 MiB | 584 MiB |
| Flip, flop, flatten to JPEG | 22 ms | 70 ms | 101 MiB | 153 MiB |
The 17-degree RGBA rotation and JPEG flattening absolute baseline is 254 ms with 141 MiB peak RSS.
TIFF
The focused TIFF profile used nine measured runs after two warmups. PureJsImage passed all 18 workflows; Jimp passed seven, lacked the eight bounded raw/region workflows, and returned invalid pixels in three decode-to-PNG cases.
| Workflow | PureJsImage wall | Jimp wall | PJI RSS | Jimp RSS |
|---|---|---|---|---|
| 4000×3000 TIFF metadata | 0.4 ms | 150.4 ms | 134.4 MiB | 289.8 MiB |
| 4000×3000 TIFF → 1000px JPEG | 144.4 ms | 663.0 ms | 214.9 MiB | 372.1 MiB |
| 7795×3122 LZW TIFF → 1000px PNG | 1,026.2 ms | 753.2 ms | 133.0 MiB | 284.8 MiB |
| PNG → Deflate TIFF | 24.5 ms | 97.3 ms | 111.4 MiB | 152.8 MiB |
The LZW workflow is the measured speed exception: PureJsImage was slower, while using 53.3% less peak RSS. PureJsImage report · Jimp report.
WebP
Jimp 1.6 exposes no WebP codec, so these are absolute baselines—not synthetic comparisons.
| Workflow | Median wall | Peak RSS |
|---|---|---|
| 1600×2000 WebP resize to JPEG | 519 ms | 167 MiB |
| Lossy WebP to PNG | 216 ms | 140 MiB |
| JPEG to lossy WebP | 965 ms | 112 MiB |
| PNG to lossless WebP | 50 ms | 108 MiB |
JPEG 2000
The explicit full-frame JP2 fallback was measured with a public-domain 1920 × 2172 NASA photograph. Metadata peaked at 97 MiB cold and 101 MiB warm. Resize to a 480 × 543 JPEG took 4,422 ms cold and 4,204 ms warm, with absolute process peaks of 192 MiB and 211 MiB. The reproducible gate requires metadata below 128 MiB and resize below 256 MiB. Comparable four-megapixel inputs need a 512 MiB Lambda tier for practical runtime headroom; smaller deployments should lower input pixel and decoded-byte limits.
AVIF and experimental HEIF
The restricted AVIF photo decoder measured 295 ms on a 768 × 512 Kodak image and 783 ms on a 1204 × 800 fox image. Its five-run photo benchmark reached 144 MiB maximum observed RSS. It retains padded full-frame YUV and RGBA state today, so this is a baseline rather than the target architecture.
The explicitly registered 4032 × 3024 iPhone HEIC auto-orient-and-resize-to-1200px-JPEG workflow measured 8,080 ms and 190 MiB cold peak RSS. Jimp exposes no HEIF decoder. Grid tile selection benefits crop workflows, while full decode memory remains an explicit optimization target.
allCodecs and these measurements use its direct experimental import. HEIC commonly carries HEVC/H.265 content that may be subject to third-party patent rights; PureJsImage's MIT license grants no third-party patent rights. Commercial users and distributors must assess their own licensing obligations.Bundle and deployment size
JPEG and PNG form the matched codec set because all five libraries support them. PureJsImage and jSquash can assemble exactly those entries. The normal public imports for Jimp, image-js, and Sharp include the additional codecs shown rather than offering equivalent codec-level tree shaking.
Competitor comparison
| Import | Version | Codecs included | Minified JS | gzip | Brotli | Installed | Packages |
|---|---|---|---|---|---|---|---|
| PureJsImage matched | 0.9.0 | JPEG, PNG | 145.4 KiB | 47.2 KiB | 39.6 KiB | 2.3 MiB | 1 |
| PureJsImage all | 0.9.0 | 9 codecs | 668.9 KiB | 240.7 KiB | 201.6 KiB | 2.3 MiB | 1 |
| Jimp | 1.6.0 | JPEG, PNG, TIFF, BMP, GIF | 577.4 KiB | 174.6 KiB | 139.5 KiB | 29.3 MiB | 70 |
| image-js | 1.7.0 | JPEG, PNG, TIFF, BMP | 361.5 KiB | 111.2 KiB | 94.3 KiB | 17.0 MiB | 46 |
| jSquash | JPEG 1.6.0; PNG 3.1.1; resize 2.1.1 | JPEG, PNG | 52.4 KiB | 16.0 KiB | 13.2 KiB | 1.0 MiB | 3 |
| Sharp JS wrapper | 0.35.3 | JPEG, PNG, TIFF, WebP, GIF, AVIF | 128.4 KiB | 38.3 KiB | 33.5 KiB | 18.9 MiB | 6 |
All JavaScript rows use the same esbuild settings: Node 22 target, ESM output, tree shaking, minification, no source map, gzip level 9, and Brotli quality 11. Installed size includes each engine's production dependency tree and required platform packages.
PureJsImage entry points
Applications can import only the codec entries they use. The root API itself pulls no codec implementation into the module graph.
| Entry | Minified | gzip | Brotli |
|---|---|---|---|
| Core API | 49.8 KiB | 16.2 KiB | 14.4 KiB |
| Core + PNG | 83.7 KiB | 28.0 KiB | 24.4 KiB |
| Core + JPEG | 120.2 KiB | 38.9 KiB | 33.1 KiB |
| Core + JPEG 2000 | 86.7 KiB | 28.0 KiB | 24.5 KiB |
| Core + WebP | 113.0 KiB | 39.1 KiB | 33.7 KiB |
| Core + experimental HEIF / HEIC | 148.0 KiB | 48.2 KiB | 41.6 KiB |
| Core + all codecs | 668.9 KiB | 240.7 KiB | 201.6 KiB |
Run npm run size to rebuild PureJsImage and reproduce both tables on the current platform.
Reproduce it
Prepare and verify the corpus before running profiles. Downloaded fixtures are checksum-pinned; generated fixtures are deterministic.
npm run fixtures:prepare
npm run fixtures:verify
npm run fixtures:avif
npm run fixtures:heif
npm run fixtures:jpeg
npm run build
npm run bench:competitors
npm run bench:competitors:charts
npm run bench:smoke
npm run bench:bmp
npm run bench:tiff
npm run bench:transforms
npm run bench:transforms:compare
npm run bench:webp
npm run bench:avif:b2
npm run bench:heif:cold
AWS_PROFILE=<profile> AWS_REGION=us-east-1 npm run bench:lambda:deploy
AWS_PROFILE=<profile> AWS_REGION=us-east-1 npm run bench:lambda:run
AWS_PROFILE=<profile> AWS_REGION=us-east-1 npm run bench:lambda:run:arm-wasm
AWS_PROFILE=<profile> AWS_REGION=us-east-1 npm run bench:lambda:destroynpm run bench:competitors builds PureJsImage and runs all seven engines in isolated workers. The chart command regenerates the three checked-in PNGs from the JSON report. See the benchmark harness guide for profiles and result interpretation.
Interpret results
- Compare equivalent complete workflows, not isolated kernels with different work.
- Use absolute peak RSS for Lambda tier decisions. Warmup can leave allocator pages resident and make a delta look deceptively small.
- Treat output dimensions, validity, pixel tolerances, and lossy quality/size as part of performance.
- Do not generalize one codec’s bounded path to another. WebP and current AVIF paths have different memory classes from baseline JPEG and sequential PNG.
- Re-run representative inputs on your hardware and Node version before selecting deployment limits or memory tiers.