ayvazyan10 / nova-imagic
Imagic is a Laravel Nova field package that allows for image manipulation capabilities, such as cropping, resizing, quality adjustment, and WebP conversion. It utilizes the powerful Intervention Image class for image manipulation.
Requires
- php: ^8.1
- ext-fileinfo: *
- intervention/image: ^2.7|^3.11
- laravel/nova: ^4.0|^5.0
Requires (Dev)
- orchestra/testbench: ^7.0|^8.0|^9.0|^10.0
- phpunit/phpunit: ^9.6|^10.5|^11.0
Suggests
- ext-exif: Install the exif extension to orientate images automatically.
- ext-gd: Install the GD extension to process images using GD.
- ext-imagick: Install the Imagick extension to process image using ImageMagick.
Provides
None
Conflicts
None
Replaces
None
README
Imagic 2.0
A production-minded image field and personal media library for Laravel Nova.
Crop. Transform. Organize. Reuse. Store anywhere Laravel can.
Quick start · Media library · Field recipes · Configuration · Upgrade guide
Imagic turns a Nova image field into a complete image workflow. Users can upload one image or a sortable gallery, crop before upload, run predictable server-side transformations, and reuse their own uploads from an integrated media library. The backend writes through Laravel's filesystem abstraction, so local, S3, and S3-compatible disks share the same path-safe storage flow.
Important
These are the Imagic 2.x docs. The Composer constraints retain PHP 8.1 and Laravel 9–11 only for EOL migration compatibility; the security-maintained baseline is PHP 8.2+, Laravel 12, Nova 5, and Intervention Image 3. Version 2 also introduces private-by-default storage, owner-scoped media references, migrations, and the media manager. Read UPGRADE.md before upgrading from 1.x.
What ships in 2.0
| Capability | What it gives you | |
|---|---|---|
| 🖼️ | Nova image field | Single or sortable multiple images across form, detail, and index views |
| ✂️ | Visual editing | Responsive crop-before-upload with optional aspect-ratio and output dimensions |
| ✨ | Server transforms | Orientation, fit, widen, watermark, centered or positioned crop, resize, quality, and format conversion |
| ☁️ | Storage portability | Laravel disks, including remote S3/S3-compatible storage, without requiring local filesystem paths |
| 🗂️ | Personal media library | Per-user uploads, nested folders, search, filters, sorting, pagination, reuse, rename, move, and guarded deletion |
| 🛡️ | Safer uploads | MIME, extension, byte-size, dimensions, pixel-count, and batch limits before persistence |
| 🔒 | Stable ownership | Opaque object names, private defaults, owner-scoped routes, stable media:<uuid> values, and batch rollback |
Quick start
Nova uses a private Composer repository. Configure your licensed Nova Composer credentials, then install Imagic and run its auto-loaded migrations:
composer require ayvazyan10/nova-imagic:^2.0 php artisan migrate
Add the field to a Nova resource:
use Ayvazyan10\Imagic\Imagic; use Laravel\Nova\Http\Requests\NovaRequest; public function fields(NovaRequest $request): array { return [ Imagic::make('Gallery', 'images') ->multiple() ->mediaLibrary() ->maxFiles(12) ->maxFileSize(8 * 1024 * 1024) // Bytes ->liveCrop(aspectRatio: 4 / 3) ->fit(1600, 1200) ->quality(88) ->directory('products'), ]; }
For a multiple field, use a json, text, or longText database column. The
field understands Laravel array, json, object, and collection casts and
avoids double encoding.
The service provider, compiled Nova assets, media routes, migrations, and media library navigation entry are discovered automatically.
Optional publishing
Publish configuration only when the application needs different defaults:
php artisan vendor:publish --tag=imagic-config
Migrations are auto-loaded while the media library is enabled. Publish them only when your deployment process requires application-owned migration files:
php artisan vendor:publish --tag=imagic-migrations php artisan migrate
For an intentionally public local disk, create Laravel's storage link if the application does not already have one:
php artisan storage:link
Media library
The media library is not a generic server file browser. It is an authenticated, image-only catalog of uploads owned by the current Nova user.
It appears as Media Library in Nova's navigation and normally opens at
/nova/imagic-media. Its vendor API normally lives at
/nova-vendor/imagic; both paths are configurable.
The workflow
flowchart LR
A[Imagic field or media manager] --> B[Validate upload]
B --> C[Transform with GD or Imagick]
C --> D[Write original and thumbnail through Laravel Storage]
D --> E[Create owner-scoped catalog record]
E --> F[Persist stable media UUID reference]
F --> G[Resolve authorized Nova preview]
Loading
What users can do
- Upload one image or a validated batch.
- Create nested folders and rename or delete empty folders.
- Search by filename and filter by supported image type.
- Sort by name, size, or date and switch between grid and list views.
- Reuse library images from fields that enable
mediaLibrary(). - Reorder multiple values by drag-and-drop or keyboard controls.
- Rename or move catalog entries without changing immutable storage keys.
- Copy an authenticated Nova content URL.
- Permanently delete one or many selected items after confirmation.
Each query, preview, stream, update, move, and deletion is scoped to the current Nova user. An optional application gate can restrict the library further.
Caution
Deleting managed media removes its original and thumbnail. Imagic cannot know about every arbitrary model attribute that may reference that item, so it does not rewrite those attributes. Confirm shared references before deletion.
Field recipes
A single transformed image
Imagic::make('Cover', 'cover_image') ->fit(1200, 630) ->quality(85) ->convert();
A sortable, reusable gallery
Imagic::make('Gallery', 'gallery') ->multiple() ->maxFiles(20) ->mediaLibrary() ->liveCrop() ->widen(2000);
A centered server crop
Imagic::make('Avatar', 'avatar') ->crop(600, 600); // Omitted coordinates center the crop
To crop from the top-left instead, pass explicit coordinates:
Imagic::make('Avatar', 'avatar') ->crop(600, 600, 0, 0);
Watermark on S3
Imagic::make('Artwork', 'artwork') ->disk('s3') ->directory('artwork') ->watermark( storage_path('app/watermarks/brand.png'), 'bottom-right', 16, 16, ) ->quality(90);
The watermark source is a trusted local path configured by application code.
Never pass request input to watermark() or directory().
A deliberate public URL instead of a catalog reference
Cataloged values resolve through authenticated Nova routes even if the storage object is public. When a field must persist a public disk URL for use outside Nova, opt out explicitly:
Imagic::make('Public Image', 'public_image') ->mediaLibrary(false) ->disk('public') ->visibility('public') ->directory('site-images');
Use this mode only with a disk and data that are intentionally public.
Image pipeline
Configured server operations run in a fixed order:
- EXIF orientation when available
- fit
- widen
- watermark
- crop
- resize
- encode
Fluent call order does not change this pipeline. Fit, widen, and resize avoid upscaling. Interactive cropping happens in the browser before this server-side pipeline. Animated GIFs are not offered for client-side cropping.
Imagic accepts JPEG, PNG, GIF, and WebP by default. SVG is deliberately excluded because it may contain active content.
Field API
| Method | Purpose |
|---|---|
multiple(bool $enabled = true) |
Enable sortable multiple values |
mediaLibrary(bool $enabled = true) |
Show the picker and catalog direct uploads |
liveCrop(bool $enabled = true, ?float $aspectRatio = null) |
Enable interactive crop-before-upload |
cropAspectRatio(?float $ratio) |
Set or clear the interactive crop ratio |
maxFiles(int $maximum) |
Limit total items in a multiple field |
maxFileSize(int $bytes) |
Limit each direct field upload in bytes |
disk(string $disk) |
Override the configured Laravel disk |
directory(string $path) |
Override the safe relative storage directory |
visibility('private'|'public') |
Override filesystem visibility for the field |
crop(?int $width, ?int $height, ?int $left, ?int $top) |
Crop on the server; omitted coordinates center the crop |
fit(?int $width, ?int $height) |
Cover the requested bounds without upscaling |
resize(?int $width, ?int $height) |
Resize while preserving aspect ratio |
widen(?int $width) |
Resize proportionally by width |
quality(int $quality) |
Set output quality from 0 to 100 |
convert(bool $enabled = true) |
Convert to WebP, or preserve a supported source format |
driver('gd'|'imagick') |
Select the image-processing driver |
watermark(string $path, string $position = 'bottom-right', int $x = 0, int $y = 0) |
Overlay a trusted local watermark |
disk() and directory() may be combined. Directories must be relative, must
not start or end with /, and may not contain dot or backslash path segments.
Stored values and compatibility
Managed uploads persist as stable references instead of storage paths:
media:550e8400-e29b-41d4-a716-446655440000
A multiple field stores a JSON array of those references. During Nova serialization, Imagic expands references owned by the current user into the authorized preview metadata required by the UI. Private disk paths are not exposed in API responses, and a reference owned by another user is rejected on save.
Existing 1.x scalar URLs/paths, JSON arrays, and comma-separated input remain readable. Legacy files are not moved or automatically imported into the new catalog.
Authorization
Nova authentication and authorization middleware protect both the manager and vendor API. To add an application-specific rule, define a gate:
use Illuminate\Support\Facades\Gate; Gate::define('manage-imagic-media', function ($user): bool { return $user->is_admin; });
Then publish the config and set:
'media_library' => [ 'authorization_gate' => 'manage-imagic-media', // ... ],
The gate controls the navigation entry, page, and API. show_in_menu = false
hides the menu item; it is not an authorization control.
Configuration
The safe defaults live in config/imagic.php:
| Option | Default | Purpose |
|---|---|---|
disk |
Nova disk or public |
Disk for managed originals and thumbnails |
directory |
imagic |
Base path within the disk |
visibility |
private |
Default filesystem visibility |
field.visibility |
top-level visibility |
Direct field-upload visibility |
field.media_library |
true |
Catalog field uploads and show the picker |
field.live_crop |
false |
Enable live crop for all fields by default |
field.crop_aspect_ratio |
null |
Optional global crop ratio |
field.max_files |
20 |
Default total for a multiple field |
uploads.max_file_size |
12288 |
Maximum input size in KiB |
uploads.max_width / max_height |
12000 |
Maximum decoded dimensions |
uploads.max_pixels |
40000000 |
Pixel-count/decompression safety limit |
uploads.max_files |
20 |
Maximum manager batch size |
transform.driver |
gd |
gd or imagick |
transform.format |
webp |
Default manager output format |
transform.quality |
88 |
Default manager output quality |
thumbnail.width / height |
480 / 320 |
Media-manager thumbnail bounds |
media_library.enabled |
true |
Enable catalog migrations, routes, and UI |
media_library.authorization_gate |
null |
Optional application gate name |
media_library.per_page |
24 |
Default page size |
media_library.max_per_page |
100 |
Maximum API page size |
media_library.rate_limit |
120 |
Requests per user per minute |
Environment shortcuts cover the main storage and transformer settings:
IMAGIC_DISK=s3 IMAGIC_DIRECTORY=imagic IMAGIC_VISIBILITY=private # Optional; inherits IMAGIC_VISIBILITY when omitted IMAGIC_FIELD_VISIBILITY=private IMAGIC_DRIVER=imagick IMAGIC_FORMAT=webp
Warning
Filesystem visibility cannot make a file private when the selected local disk
is already exposed by the web server. In particular, a public disk behind
storage:link is publicly reachable regardless of the catalog's authenticated
proxy URL. Use a non-public local disk or a correctly private cloud bucket for
sensitive uploads.
For S3 or another remote disk, configure endpoint, region, credentials, bucket, and URL in the application's Laravel filesystem configuration. Imagic writes bytes through Laravel Storage and never asks a remote disk for a local path.
Compatibility and support
The Composer constraints remain broad enough to help existing applications move to Imagic 2 without combining the package migration with every framework upgrade. That install compatibility is not a promise that an EOL framework is safe to operate.
| Status | PHP | Laravel | Nova | Intervention Image |
|---|---|---|---|---|
| Current security-maintained baseline | 8.2+ | 12 | 5 | 3.11+ |
| EOL compatibility/migration only | 8.1 | 9 | 4 | 2.7 |
| EOL compatibility/migration only | 8.2 | 10 | 4 | 3.11+ |
| EOL compatibility/migration only | 8.3 | 11 | 5 | 3.11+ |
The CI matrix exercises the three legacy rows only to catch Imagic source regressions. Intervention Image 2.7 and Laravel 9–11 are upstream end-of-life; use the current baseline for production deployments. See Laravel's support policy for framework maintenance dates.
Warning
Composer may refuse a fresh legacy resolution because active framework advisories have no patched release on those lines. Do not disable Composer security blocking in a production application to install Imagic. Upgrade the application stack; the CI-only legacy override exists solely to detect Imagic regressions.
Runtime requirements:
- Composer 2
- PHP
fileinfoandmbstring - GD or Imagick
- EXIF recommended for camera orientation
- A modern browser supported by the installed Nova version
Refer to Laravel's Nova installation guide and Intervention Image's installation guide for their platform requirements.
Security and operational notes
- Uploads are untrusted input. Keep conservative byte, dimension, pixel, and batch limits for the memory available to PHP.
- Catalog routes and URLs are for authenticated Nova use, regardless of the underlying object's filesystem visibility.
- A
privatevisibility setting does not override a publicly mounted local storage directory; choose the disk and web-server mapping accordingly. - Keep Laravel, Nova, Intervention Image, PHP, and the GD/Imagick system libraries patched.
- Never disable Composer advisory blocking to keep an EOL application stack in production; upgrade to the security-maintained baseline instead.
- Use least-privilege filesystem credentials and bucket policies.
- Do not expose Nova vendor routes without their configured authentication and authorization middleware.
Report vulnerabilities privately according to SECURITY.md.
Project guides
| Guide | Use it for |
|---|---|
| Upgrade guide | Moving safely from Imagic 1.x to 2.x |
| Changelog | User-visible additions, fixes, and security changes |
| Security policy | Supported versions and private vulnerability reporting |
| Contributing guide | Local setup, tests, assets, and pull-request expectations |
| Release process | Licensed compatibility matrix and maintainer checklist |
License
Imagic is open-source software released under the MIT license. It is maintained by Razmik Ayvazyan.