Download the PHP package laraextend/media-toolkit without Composer
On this page you can find all versions of the php package laraextend/media-toolkit. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download laraextend/media-toolkit
More information about laraextend/media-toolkit
Files in laraextend/media-toolkit
Package media-toolkit
Short Description A comprehensive Laravel media toolkit for processing images, animated images, vector graphics, audio and video — with automatic optimization, responsive variants, next-gen formats (WebP, AVIF), smart caching and Artisan commands.
License MIT
Homepage https://github.com/laraextend/media-toolkit
Informations about the package media-toolkit
Laravel Media Toolkit
A comprehensive Laravel media toolkit for automatic image optimization, transformations, responsive variants, next-gen formats and more — ready to use directly in Blade.
laraextend/media-toolkit handles the heavy lifting for you: images are resized, cropped, filtered, compressed, converted to modern formats (WebP, AVIF) and rendered as responsive <img> or <picture> tags via a clean fluent API.
Roadmap: Future releases will extend the toolkit to cover animated images (GIF/APNG/WebP animated) and video transcoding — all behind the same
Media::facade.
✨ Features
- 🔗 Fluent Builder API —
Media::image($path)->resize(800)->grayscale()->html(alt: 'Hero') - 🎬 Video Support —
Media::video($path)->controls()->muted()->html(class: 'w-full') - 🎵 Audio Support —
Media::audio($path)->controls()->preload('none')->html() - 🖼️ SVG Support —
Media::svg($path)->html(alt: 'Icon')or->inline()->html(class: 'fill-current') - 🧩 Four Blade Components —
<x-media::img>,<x-media::responsive-img>,<x-media::picture>,<x-media::img-url> - 🖼️ Four Blade Helpers —
img(),responsive_img(),picture()andimg_url()(deprecated, still available) - 📐 Image Transformations — resize, fit, stretch, crop with automatic proportional scaling
- 🎨 Image Filters — grayscale, sepia, negate, brightness, contrast, colorize, blur, smooth, rotate, flip, watermark
- 📱 Automatic Responsive Variants — Generates 5 breakpoint sizes (0.5×, 0.75×, 1×, 1.5×, 2×) with
srcset - 🌐 Next-Gen Formats — WebP, AVIF, JPEG, PNG with automatic fallback
- ⚡ Smart Caching — Manifest-based cache with automatic invalidation and filter-aware cache keys
- 🔧 Artisan Commands —
media:cache-clearandmedia:cache-warmwith optional--type=flag - ⚙️ Configurable — Publish
config/media-toolkit.phpto customize quality, formats, breakpoints and more - 🏎️ Performance-Optimized — Lazy loading,
fetchpriority,decoding="async"by default - 🛡️ Memory-Safe Fallback — Automatically serves original images when GD memory would be exceeded
- 📦 Zero Config — Works immediately after installation
- 🔄 GD & Imagick — Automatic driver detection
- ⚡ Livewire & Alpine.js Ready — Blade components forward
wire:*,x-*anddata-*attributes automatically
📋 Requirements
- PHP >= 8.2
- Laravel >= 10.x
- Intervention Image >= 3.0 (
intervention/image) - GD or Imagick PHP extension
- Optional: AVIF support in GD (
imageavif) or Imagick
🚀 Installation
The ServiceProvider and
MediaFacade alias are registered automatically via Laravel's Auto-Discovery.
Optional: Publish Configuration
🔗 Fluent API — Media::image()
The primary API is a fluent builder accessed through the Media facade.
📐 Transformations
resize(?int $width, ?int $height) — Proportional Resize
Scale the image while preserving aspect ratio. Provide width, height, or both (contain-box).
Chain ->upscale() to allow resizing beyond the original dimensions (capped by default):
fit(int $width, int $height) — Cover + Crop
Scale so the image fills the frame completely, cropping the overflow from center.
stretch(int $width, int $height) — Exact Dimensions, No Aspect Ratio
Resize to exact dimensions, ignoring aspect ratio.
crop(int $width, int $height, int|string $x = 0, int|string $y = 0) — Region Extract
Extract a region from the original image without scaling. String offsets: 'left', 'center', 'right', 'top', 'bottom'.
Note: Only one size/crop operation can be used per chain. Combining
resize()+fit()etc. throws aMediaBuilderException.
original() — No Processing
Serve the original file without any transformation or optimization.
original()locks the chain — callingresize(),format(),quality(), filters orwatermark()afterwards throws aMediaBuilderException.
🎨 Filters
Filters are stackable and can be combined in any order.
| Method | Description |
|---|---|
->grayscale() |
Convert to black & white |
->sepia() |
Apply a warm sepia tone |
->negate() |
Invert all colors |
->brightness(int $level) |
Adjust brightness: −255 (darkest) to +255 (brightest) |
->contrast(int $level) |
Adjust contrast: −100 to +100 |
->colorize(int $r, int $g, int $b) |
Tint with RGB offset: −255 to +255 per channel |
->blur(int $amount = 1) |
Apply blur (amount = number of passes) |
->smooth(int $level) |
Smooth/sharpen: −10 (max sharpen) to +10 (max smooth) |
->rotate(int\|string $angle) |
Rotate degrees CCW, or 'auto' for EXIF-based rotation |
->flipHorizontal() |
Mirror left-right |
->flipVertical() |
Mirror top-bottom |
->flipBoth() |
Mirror both axes |
watermark(string $source, string $position, int $padding, int $opacity) — Overlay
Position values: 'top-left' 'top-center' 'top-right' 'center-left' 'center' 'center-right' 'bottom-left' 'bottom-center' 'bottom-right'
The source parameter accepts multiple formats:
🖼️ Output Methods
->url() — URL String
->html(string $alt, string $class, ?string $id, array $attributes) — HTML Tag
Output depends on the active output mode set via ->responsive() or ->picture():
->responsive(?string $sizes) — Switch to srcset Mode
->picture(?array $formats, ?string $fallback, string $imgClass, string $sourceClass) — Switch to <picture> Mode
⚙️ Output Modifiers
These can be chained anywhere before ->url() or ->html():
| Method | Description |
|---|---|
->format(string $format) |
Output format: webp, avif, jpg, jpeg, png |
->quality(int $quality) |
Quality 1–100 (overrides config) |
->loading(string $loading) |
'lazy' or 'eager' |
->fetchpriority(string $priority) |
'auto', 'high', 'low' (high → forces eager) |
->noCache() |
Skip the manifest cache, always regenerate |
🧩 Blade Components
All components use the media namespace and map to the Media::image() builder.
Attributes placed directly on the component tag (
wire:key,data-*,x-*) are forwarded automatically. Use:extra-attributes="[...]"for programmatic attribute arrays.
<x-media::img> — Single Optimized Image
Props: src, alt, width, height, class, format, quality, loading, fetchpriority, id, original, extra-attributes
<x-media::responsive-img> — Responsive with srcset
Additional props: sizes, quality
<x-media::picture> — Multi-Format with Fallback
Additional props: formats, fallback-format, img-class, source-class, quality
The Blade attribute bag (
wire:key,x-*,@*etc.) is applied to the outer<picture>element. Useextra-attributesfor the inner<img>.
<x-media::img-url> — URL Only
Props: src, width, format, quality, original
🖼️ Legacy Blade Helpers
The four global helper functions are still available but marked @deprecated. They are now thin wrappers around Media::image().
⚙️ Configuration
config/media-toolkit.php:
Example .env overrides:
📐 Responsive Variants — How It Works
When you specify width: 800, the following variants are generated:
| Factor | Calculation | Result |
|---|---|---|
| 0.5× | 800 × 0.5 | 400w |
| 0.75× | 800 × 0.75 | 600w |
| 1.0× | 800 × 1.0 | 800w |
| 1.5× | 800 × 1.5 | 1200w |
| 2.0× | 800 × 2.0 | 1600w |
Automatic constraints:
- Variants smaller than
min_width(default 100px) are skipped - Variants wider than the original image are skipped (no artificial upscaling)
- If the original width is ≤ 2× the target, the original width is added as an additional variant
- Duplicates are automatically removed
⚡ Performance
Loading Behavior
Setting
fetchpriority('high')automatically forcesloading="eager", even iflazywas set explicitly.
🔧 Artisan Commands
Clear Cache
Deletes all optimized media variants from public/<output_dir>/:
Warm Cache
Regenerates any variants whose source file has changed since they were last generated:
Both commands accept --type= for future multi-type support (image, video, audio).
In Your Deployment Pipeline
💾 Caching — How It Works
Each unique combination of source file, dimensions, format, operations and filters gets its own cache directory in public/<output_dir>/ (default: public/media/optimized/):
The manifest.json stores the last-modified timestamp of the source file. On every request:
- Does the cache directory with manifest exist? → Yes: Check timestamp
- Has the source changed? → No: Serve from cache ✓
- Has the source changed? → Yes: Delete old cache, regenerate variants
You never need to clear the cache manually when replacing images — changes are detected automatically.
Concurrent Request Safety
Manifest files are written atomically using a temp-file-then-rename pattern:
- Image variants are processed and saved to disk
- The manifest is written to a temporary file (
manifest.tmp.<pid>) - The temp file is renamed to
manifest.json— an atomic operation on POSIX systems (Linux, macOS)
This guarantees that concurrent readers never encounter partially-written JSON, even when multiple requests try to generate the same image simultaneously.
Memory Check Order — Cache Always Wins
The memory-bypass check (on_memory_limit) happens after the cache check, not before:
- Cache exists? → Serve immediately — no processing, no memory check needed
- Cache miss → Check if GD can process the image within the PHP memory limit
- Memory too low → Show placeholder / fallback per
on_memory_limitsetting - Memory ok → Process, cache, and serve
Result: A cached image is always served from disk regardless of current PHP memory availability. The on_memory_limit fallback only activates when generating a variant for the first time.
🛠️ Practical Examples
Hero Banner (Above the Fold)
Logo (Fixed Size, Eager)
Product Gallery with Lightbox
Open Graph Meta Tags
CSS Background
Grayscale Thumbnail Grid
Livewire Repeater
⚠️ Error Handling
Error handling behaviour is configurable per error type in config/media-toolkit.php:
Modes
| Mode | html() returns |
url() returns |
|---|---|---|
'placeholder' |
Inline SVG <img> with label text |
'' (empty string) |
'broken' |
<img src="original-path"> — browser shows broken-image icon |
'' (empty string) |
'exception' |
Throws MediaBuilderException |
Throws MediaBuilderException |
'original' (memory-limit only) |
Serve the unprocessed source file | URL of source file copy |
Default values: on_not_found=placeholder, on_error=placeholder, on_memory_limit=placeholder.
Override via .env:
Memory-Safe Fallback (GD)
When the GD driver detects that processing a large image would exceed the PHP memory limit, the behaviour is controlled by on_memory_limit (default: 'placeholder').
Setting MEDIA_ON_MEMORY_LIMIT=original serves the raw source file unchanged with data-media-toolkit-status="original-fallback" and data-media-toolkit-reason="memory-limit" attributes on the <img>.
📋 Logging & Failure Registry
Every error (not found, processing failure, memory bypass) is written to the Laravel application log and recorded in a local failure registry for offline retry.
Log Configuration
Override via .env:
Failure Registry
Failed images are persisted to storage/media-toolkit/failures.json so you can retry them later without re-deploying:
media:process-pending Command
Retry all registered failures with an unlimited memory limit (useful for processing large images that were bypassed at request time due to GD memory constraints):
Note: The command regenerates the base resize/format variant. Operations (filters, watermarks) cannot be reproduced from the fingerprint alone — a warning is shown for entries with non-trivial operation chains.
🔀 GD vs. Imagick
| Feature | GD | Imagick |
|---|---|---|
| JPEG | ✅ | ✅ |
| PNG | ✅ | ✅ |
| WebP | ✅ (if imagewebp available) |
✅ |
| AVIF | ✅ (if imageavif available, PHP 8.1+) |
✅ (if compiled with AVIF) |
Imagick is automatically preferred when available and generally offers better quality and performance for large images.
🎬 Video — Media::video()
Serves a video file unchanged and renders a <video> HTML element. No transcoding is performed — the source file is copied once to the public output directory.
Supported extensions: mp4, webm, ogg, mov
Chain Methods
| Method | Description |
|---|---|
->controls(bool $show = true) |
Show/hide the native browser controls bar (default: true) |
->autoplay() |
Start playback automatically (requires ->muted() in most browsers) |
->muted() |
Mute the audio track |
->loop() |
Loop the video when it ends |
->preload(string) |
Preload hint: 'none' | 'metadata' (default) | 'auto' |
->poster(string $path) |
Poster image shown before playback; same path format as the source |
->width(int) |
Display width in pixels |
->height(int) |
Display height in pixels |
html() Signature
🎵 Audio — Media::audio()
Serves an audio file unchanged and renders an <audio> HTML element. No transcoding is performed.
Supported extensions: mp3, ogg, wav, aac, m4a, opus, flac
Chain Methods
| Method | Description |
|---|---|
->controls(bool $show = true) |
Show/hide the native browser controls bar (default: true) |
->autoplay() |
Start playback automatically |
->muted() |
Mute the audio |
->loop() |
Loop the audio when it ends |
->preload(string) |
Preload hint: 'none' | 'metadata' (default) | 'auto' |
html() Signature
🖼️ SVG — Media::svg()
Serves an SVG file as a public URL or embeds it inline in the HTML. No processing is performed.
Chain Methods
| Method | Description |
|---|---|
->inline(bool $sanitize = true) |
Embed SVG content directly in HTML; $sanitize = true (default) removes <script> and on* attributes |
->width(int) |
Width in pixels — applied to <img> or the <svg> element |
->height(int) |
Height in pixels — applied to <img> or the <svg> element |
html() Signature
- Default mode:
$altis the<img alt>attribute. - Inline mode:
$altsetsaria-labelandrole="img"on the<svg>element.
SVG Sanitization
When ->inline() is called with the default $sanitize = true, the following are removed from the SVG before output:
| Threat | What is removed |
|---|---|
| Scripting | All <script> elements |
| Event handlers | All on* attributes (e.g. onclick, onload, onerror) |
| Protocol injection | href, src, xlink:href values starting with javascript: |
Note: This is a structural filter, not a full HTML sanitizer. For untrusted user-uploaded SVGs, use a dedicated library such as Symfony's HtmlSanitizer.
🆙 Upgrading from v1
Breaking Changes in v2:
| Area | v1 | v2 |
|---|---|---|
| Blade namespace | <x-laraextend::img> |
<x-media::img> |
| Output directory | public/img/optimized/ |
public/media/optimized/ |
| Config structure | flat keys | nested under image.* |
Config key quality.webp |
config('media-toolkit.quality.webp') |
config('media-toolkit.image.quality.webp') |
Config key responsive.* |
config('media-toolkit.responsive.*') |
config('media-toolkit.image.responsive.*') |
Config key defaults.* |
config('media-toolkit.defaults.*') |
config('media-toolkit.image.defaults.*') |
| Artisan: clear cache | media:img-clear |
media:cache-clear |
| Artisan: warm cache | media:img-warm |
media:cache-warm |
| Error behavior | env-based (empty string / HTML comment) | configurable placeholder / broken / exception |
Migration steps:
-
Update
config/media-toolkit.phpto the new nested structure (or re-publish it): -
Clear the old cache directory:
-
Update
.gitignore: - Update Blade templates — replace
<x-laraextend::*>with<x-media::*>. The helper functions (img(),responsive_img(),picture(),img_url()) are still available but now go through the new builder and are marked deprecated.
📂 .gitignore
🤝 Contributing
Contributions are welcome! Please fork the repository, create your feature branch and submit a pull request.
📄 Changelog
All notable changes are documented in the CHANGELOG.
🔒 Security
Built-in Input Validation
Every source path and watermark path is validated before any filesystem access occurs. The following are rejected with a MediaBuilderException:
| Threat | Example | Check |
|---|---|---|
| Directory traversal | ../../etc/passwd |
.. in any path segment |
| Null byte injection | image.jpg\0.php |
\x00 in path |
| Log injection (CRLF) | image.jpg\nFAKE_LOG |
\r / \n in path |
| Disallowed file type | config/database.php |
Extension whitelist |
Allowed image extensions: jpg, jpeg, png, gif, webp, avif, bmp, tiff, tif
Watermark Path Confinement
Watermark sources are validated against their respective root directories:
- Relative paths → must resolve within
base_path() - Web paths (
/...) → must resolve withinpublic_path() - HTTP(S) URLs → extracted URL path must resolve within
public_path()
Memory Safety (GD)
When the GD driver estimates that processing would exceed the PHP memory limit, the image is never loaded — preventing fatal OOM errors. Image dimensions from EXIF metadata are capped at 65 535 px per axis to prevent integer overflow through adversarially crafted image headers.
Developer Responsibility
The package validates paths structurally. It does not enforce which directories developers may use as image sources. If you accept image paths from user input, ensure the input is validated by your application before passing it to Media::image().
Reporting Vulnerabilities
If you discover a security issue, please send an email to [email protected] instead of creating a public issue.
📜 License
MIT License. See LICENSE for details.
Made with ❤️ by LaraExtend
All versions of media-toolkit with dependencies
illuminate/support Version ^10.0|^11.0|^12.0|^13.0
illuminate/console Version ^10.0|^11.0|^12.0|^13.0
illuminate/filesystem Version ^10.0|^11.0|^12.0|^13.0
intervention/image Version ^3.0