meekmedia / image-optimizer
Private, client-side image compression widget for any PHP site. MozJPEG, WebP and OxiPNG via WebAssembly - images never leave the visitor's browser.
Package info
github.com/manish-sharmaa/image-optimizer
Language:JavaScript
pkg:composer/meekmedia/image-optimizer
Requires
- php: >=8.0
Requires (Dev)
- phpunit/phpunit: ^9.6
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Private, client-side image compression for any PHP site. Drop in a widget that compresses JPEG, PNG and WebP in the visitor's browser with the same WebAssembly codecs used by Google's Squoosh app (MozJPEG, libwebp, OxiPNG) - images never touch your server, so it works on the cheapest shared hosting and scales for free.
Built by Meek Media.
Why
- Private: files never leave the browser. No uploads, no storage, no GDPR surface.
- Real codecs: MozJPEG / WebP / OxiPNG via WASM - visibly better than
canvas.toBlob. - Live: dragging the quality slider or switching format re-compresses already-added images in place, sizes updating in real time.
- Server-proof: your PHP just prints markup and serves static files. No extensions,
no binaries, no
upload_max_filesize, no queue. - Graceful: if WASM can't load, it silently falls back to the browser's canvas encoder.
Install
Composer
composer require meekmedia/image-optimizer
No Composer? Download the release zip, unzip it anywhere PHP can read, and
require '<path>/image-optimizer/autoload.php';.
Quick start
- Publish the static assets into your public web root:
php vendor/meekmedia/image-optimizer/bin/publish-assets.php public/assets/image-optimizer
- Render the widget:
<?php use MeekMedia\ImageOptimizer\{Config, Optimizer}; $optimizer = new Optimizer(new Config( publicUrl: '/assets/image-optimizer', // URL where you published the assets publicPath: __DIR__ . '/assets/image-optimizer', // optional: enables mtime cache busting )); ?> <html> <head><?= $optimizer->headTags() ?></head> <body> <?= $optimizer->render(['formats' => ['auto', 'webp', 'mozjpeg', 'oxipng'], 'resize' => true]) ?> <?= $optimizer->scriptTags() ?> </body> </html>
That's it. See examples/plain-php/ for a runnable page.
Upgrading
After updating the package (Composer or the release zip), re-run the publish step so the new static assets land in your public web root:
php vendor/meekmedia/image-optimizer/bin/publish-assets.php public/assets/image-optimizer
Asset URLs are version-busted (?v=...), so browsers and CDNs with
long-lived cache headers pick up the republished files automatically -
no manual cache purge needed.
Options (render config)
| Key | Default | Meaning |
|---|---|---|
formats |
['webp','mozjpeg','oxipng'] |
Formats offered in the select. 'auto' keeps each image's own format. |
defaultFormat |
'webp' |
Pre-selected format. |
quality |
80 |
1-100. Ignored by OxiPNG (lossless). |
resize |
false |
Show a max-dimension input (fit-within, never upscales). |
maxFiles |
20 |
Batch limit per drop. |
Advanced (JS-only, via MeekImageOptimizer.mount(el, options)): strings to
override every UI string, and onFileComplete / onBatchComplete / onError
callbacks. A headless API is also exposed:
MeekImageOptimizer.create({assetsBase}).then(o => o.compress(file, opts)).
Notes
- v1 limitation:
render()(and the widget it mounts) supports only one instance per page - rendering it more than once on the same page isn't supported yet.
Theming
The widget is styled entirely through CSS custom properties - set them on
.mio-root:
.mio-root { --mio-accent: #32b49a; --mio-accent-contrast: #fff; --mio-bg: transparent; --mio-card-bg: #fff; --mio-text: #141414; --mio-muted: #6b7280; --mio-border: #e5e7eb; --mio-radius: 20px; --mio-font: inherit; }
Dark mode: redefine the same variables under your dark scope
(e.g. .dark .mio-root { ... }).
Server notes
- Serve
.wasmwith the right MIME type (the widget copes either way, but streaming compilation is faster). Apache/.htaccess:
AddType application/wasm .wasm
- All codecs are single-threaded WASM: no COOP/COEP headers are needed.
- Images above 24 megapixels are rejected client-side (mobile Safari canvas limits).
Browser support
Evergreen Chrome, Edge, Firefox, Safari (incl. iOS). Older browsers get the canvas fallback automatically.
Attribution & license
Apache-2.0. Bundles WebAssembly codecs from
jSquash, derived from Google's
Squoosh (both Apache-2.0) -
"Squoosh" is used for attribution only; this project is not affiliated with
Google. ZIP support by fflate (MIT).
See THIRD_PARTY_NOTICES.md.