| Install | |
|---|---|
composer require pjedesigns/filament-image-editor |
|
| Latest Version: | v1.0.0 |
| PHP: | ^8.2 |
A powerful, client-side image editor plugin for Laravel Filament applications with crop, filter, and annotation tools.
Install the package via Composer:
composer require pjedesigns/filament-image-editor
Publish the config file (optional):
php artisan vendor:publish --tag="filament-image-editor-config"
Use the ImageEditor field in your Filament form:
use Pjedesigns\FilamentImageEditor\Forms\Components\ImageEditor;
public static function form(Form $form): Form
{
return $form->schema([
ImageEditor::make('avatar')
->label('Profile Picture')
->required(),
]);
}
Configure how images are stored:
ImageEditor::make('photo')
->disk('public')
->directory('photos')
->visibility('public')
->shouldPreserveFilenames() // Keep original filename (slugified)
By default, images are saved with a UUID filename (e.g., 550e8400-e29b-41d4-a716-446655440000.jpg). Use shouldPreserveFilenames() to keep the original filename:
ImageEditor::make('photo')
->shouldPreserveFilenames() // "My Vacation Photo.PNG" → "my-vacation-photo.jpg"
The original filename is slugified (lowercase, special characters replaced with hyphens) and the extension is set based on the output format.
Important: This component only supports single-file collections. When defining your Spatie Media Library collection on the model, you must use
->singleFile():// In your Model public function registerMediaCollections(): void { $this->addMediaCollection('avatar') ->singleFile(); // Required for ImageEditor }
ImageEditor::make('photo')
->collection('photos')
->conversion('thumb')
->responsiveImages()
->customProperties(['source' => 'editor'])
You can pass a Closure to customProperties() to generate properties based on the current record:
use Illuminate\Database\Eloquent\Model;
ImageEditor::make('photo')
->collection('photos')
->customProperties(fn (?Model $record) => [
'custom_property' => $record?->custom_property ?: (string) 'default',
'source' => 'editor',
]);
ImageEditor::make('image')
->openOnSelect(true) // Open editor immediately when file selected (default)
->openOnSelect(false) // Skip editor - upload image directly, edit later via "Edit" button
->modalSize('6xl') // Modal size (sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl, 6xl, 7xl, full)
->tools(['crop', 'filter', 'draw']) // Available tools
->previewMaxHeight(400) // Maximum height for image preview in pixels (default: 400)
The previewMaxHeight option controls the maximum height of the image preview on the form. Images smaller than this height will display at their natural size without stretching, while larger images will be constrained to the max height. This prevents pixelation when displaying smaller conversion images.
When openOnSelect(false) is set:
ImageEditor::make('image')
->cropAspectRatios([
'free' => null,
'1:1' => 1,
'16:9' => 16/9,
'cinematic' => 2.35,
])
->defaultAspectRatio('16:9')
->cropMinSize(width: 100, height: 100)
->cropMaxSize(width: 4000, height: 4000)
->enableRotation(true)
->enableFlip(true)
ImageEditor::make('image')
->filterPresets([
'original', 'grayscale', 'sepia', 'vintage',
'warm', 'cool', 'dramatic', 'fade', 'vivid',
])
->adjustments(['brightness', 'contrast', 'saturation'])
->disableFilters() // Only show adjustments
->disableAdjustments() // Only show filter presets
ImageEditor::make('image')
->drawingTools(['select', 'freehand', 'eraser', 'line', 'arrow', 'rectangle', 'ellipse', 'text'])
->defaultStrokeColor('#FF0000')
->defaultStrokeWidth(4)
->defaultFillColor('transparent')
->colorPalette([
'#FFFFFF', '#000000', '#FF0000', '#00FF00', '#0000FF',
])
->fonts(['Arial', 'Helvetica', 'Georgia'])
->disableDrawing() // Remove drawing tool entirely
ImageEditor::make('image')
->outputFormat('webp') // jpeg, png, webp
->outputQuality(0.85) // 0.0 to 1.0
->maxOutputSize(width: 2000, height: 2000)
ImageEditor::make('image')
->acceptedFileTypes(['image/jpeg', 'image/png', 'image/webp'])
->maxFileSize(5 * 1024) // 5MB in KB
->minDimensions(width: 800, height: 600) // Warning threshold
ImageEditor::make('image')
->historyLimit(50)
->enableKeyboardShortcuts(true)
When the editor is open:
| Shortcut | Action |
|---|---|
Ctrl/Cmd + Z |
Undo |
Ctrl/Cmd + Y |
Redo |
Ctrl/Cmd + Shift + Z |
Redo |
Delete / Backspace |
Delete selected shape |
Ctrl/Cmd + D |
Duplicate selected |
Escape |
Deselect / Cancel |
The editor provides several ways to zoom and pan around the image:
The "Fit" option in the zoom dropdown resets the view to fit the entire image in the viewport.
You can also use the editor as a standalone Livewire component:
<livewire:image-editor-modal
wire:model="editedImage"
:source="$originalImageUrl"
:config="[
'tools' => ['crop', 'filter'],
'cropAspectRatios' => ['1:1' => 1, '16:9' => 16/9],
]"
/>
For programmatic usage outside of Livewire:
window.FilamentImageEditor.open({
source: '/path/to/image.jpg',
tools: ['crop', 'filter', 'draw'],
onApply: (file) => {
console.log('Edited image:', file);
},
onCancel: () => {
console.log('User cancelled');
}
});
After publishing the config, you can set defaults in config/filament-image-editor.php:
return [
'storage' => [
'disk' => 'public',
'directory' => 'images',
'visibility' => 'public',
],
'output' => [
'format' => 'jpeg',
'quality' => 0.92,
],
'ui' => [
'preview_max_height' => 400, // Max height for image preview in pixels
],
'tools' => ['crop', 'filter', 'draw'],
'crop' => [
'aspect_ratios' => [
'free' => null,
'1:1' => 1,
'4:3' => 4/3,
'16:9' => 16/9,
],
'enable_rotation' => true,
'enable_flip' => true,
],
// ... more options
];
For full test coverage including Livewire integration tests, publish the tests to your Laravel application:
# Publish tests to your application
php artisan vendor:publish --tag=filament-image-editor-tests
# Run the tests
php artisan test tests/Feature/FilamentImageEditor
This publishes tests to tests/Feature/FilamentImageEditor/ and runs all 44 tests including:
When developing the package itself:
# Install dependencies
composer install
# Run standalone tests (skips Livewire integration tests)
composer test
# Or run via the parent Laravel application for full coverage
cd /path/to/laravel-app
php artisan test packages/pjedesigns/filament-image-editor/tests
Note: Livewire integration tests require a full Laravel application context and will be skipped when running standalone via
composer test. Use the publish method above or run via a Laravel application for complete test coverage.
Please see CHANGELOG for more information on what has changed recently.
Please see CONTRIBUTING for details.
If you discover any security-related issues, please email paul@pjedesigns.com instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.