Uploads and processes images using the ImageUploader fluent API. Use when user asks to "upload an image", "process image upload", "generate blurhash", "create image variants", "add watermark to upload", "optimize image upload", "generate thumbnail", "convert to AVIF on upload", or "handle image processing". Covers blurhash, AVIF/WebP optimization, watermark, low quality placeholder variants, SVG handling, base64 input, and accessing upload results.
php artisan boost:add-skill m2code/file-manager
Save this content to: .claude/skills/file-manager-image-upload/SKILL.md
# Image Upload with Processing
## Overview
Use the `ImageUploader` fluent API to upload images with optional processing. The API generates structured file variants (original, optimized, low_quality, watermark) and a blurhash string for placeholder UIs.
This skill covers **programmatic upload from PHP code**. For HTTP API uploads (from frontend/mobile), use the `file-manager-api-integration` skill.
## Quick Reference
```php
use M2code\FileManager\Application\Uploader\ImageUploader;
$result = ImageUploader::make()
->blur() // Generate BlurHash
->optimize('avif') // AVIF with WebP fallback
->watermark() // Apply watermark
->lowQuality() // Generate low quality placeholder
->upload($file, 'uploads/images');
```
## Input Types
The `upload()` method accepts three input types. No manual conversion is needed.
| Input Type | Example | Processing |
|------------|---------|------------|
| `UploadedFile` | `$request->file('photo')` | Full pipeline |
| Base64 data URI | `'data:image/png;base64,...'` | Full pipeline (raster only) |
| Raw SVG string | `'<svg xmlns=...>...</svg>'` | Original only, processing skipped |
For detailed input behavior, see [references/input-types.md](references/input-types.md).
## Variants
The upload result contains structured variants accessible via `$result->variants`. For full details, see [references/variant-types.md](references/variant-types.md).
| Variant Key | Generated By | Description |
|-------------|-------------|-------------|
| `original` | Always | The original uploaded file |
| `optimized` | `->optimize()` | AVIF/WebP optimized version |
| `low_quality` | `->lowQuality()` | Low quality JPEG placeholder |
| `watermark` | `->watermark()` | Watermarked version |
### Accessing variants
```php
// Preferred: via variants collection
$result->variants->get('original')?->path;
$result->variants->get('optimized')?->path;
$result->blurhash; // the BlurHash string (null if not generated)
// Backward-compatible accessors (still available)
$result->path; // alias for original path
$result->optimizedPath; // alias for optimized path (null if not generated)
$result->lowQualityPath; // alias for low_quality path (null if not generated)
$result->watermarkPath; // alias for watermark path (null if not generated)
```
Always use null-safe access (`?->`) because variants that were not requested will be `null`.
## Processing Options
### blur()
Generates a BlurHash string for the uploaded image. The blurhash is accessible via `$result->blurhash`.
```php
$result = ImageUploader::make()
->blur()
->upload($file, 'photos');
$result->blurhash; // "L6Df8^_4D%M{%MD%M{D%"
```
### optimize(string $format = 'avif')
Generates an optimized variant in the specified format. Supported values: `'avif'`, `'webp'`. If AVIF is not supported by the installed Imagick, it falls back to WebP. If neither is supported, the optimized variant is skipped (no error thrown).
```php
$result = ImageUploader::make()
->optimize('avif') // or 'webp'
->upload($file, 'photos');
$result->variants->get('optimized')?->path; // "photos/abc123.avif"
```
Important: the variant key is always `optimized`, regardless of the format used.
### watermark()
Applies a watermark overlay to the image. Requires the watermark configuration to be set up in the image processing layer.
```php
$result = ImageUploader::make()
->watermark()
->upload($file, 'photos');
$result->variants->get('watermark')?->path;
```
### lowQuality()
Generates a low-quality JPEG placeholder image, useful for progressive loading UIs.
```php
$result = ImageUploader::make()
->lowQuality()
->upload($file, 'photos');
$result->variants->get('low_quality')?->path;
```
### withOptions(array $options)
Alternative to fluent method chaining. Accepts an associative array. Only boolean values are processed; non-boolean values are silently ignored.
```php
$result = ImageUploader::make()
->withOptions([
'blurhash' => true,
'optimize' => false,
'watermark' => true,
'low_quality' => false,
])
->upload($file, 'photos');
```
Supported option keys: `blurhash`, `optimize`, `watermark`, `low_quality`.
## SVG Behavior
SVG files are handled specially. When an SVG is detected (MIME type `image/svg+xml`), all image processing is **silently skipped**. Only the `original` variant is saved, and `$result->blurhash` is `null`.
```php
$svg = '<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64">...</svg>';
$result = ImageUploader::make()
->blur()
->watermark()
->upload($svg, 'icons');
// Only original exists:
$result->variants->get('original')?->path; // not null
$result->variants->get('low_quality'); // null
$result->variants->get('optimized'); // null
$result->variants->get('watermark'); // null
$result->blurhash; // null
```
This behavior is automatic. No special flag or check is needed.
## File Storage
Files are saved to the filesystem disk configured by `FILE_MANAGER_DISK` (default: `public`). The second argument to `upload()` is the destination folder relative to that disk's root.
```php
// These save to {public_disk}/uploads/images/abc123.png
ImageUploader::make()->upload($file, 'uploads/images');
ImageUploader::make()->upload($file, 'avatars');
```
## Complete Example
```php
use M2code\FileManager\Application\Uploader\ImageUploader;
use M2code\FileManager\Facades\FileManager;
use M2code\FileManager\Facades\FileUrl;
// Upload with all processing enabled
$result = ImageUploader::make()
->blur()
->lowQuality()
->watermark()
->optimize('avif')
->upload($request->file('photo'), 'uploads/profiles');
// Store paths for database
$originalPath = $result->variants->get('original')?->path;
$optimizedPath = $result->variants->get('optimized')?->path;
$blurhash = $result->blurhash;
// Generate URLs for the frontend
$url = FileUrl::getUrl($optimizedPath ?? $originalPath);
$signedUrl = FileUrl::getSignedUrl($originalPath, now()->addHour());
// Clean up when deleting the parent record
FileManager::deleteVariants($result->variants);
```
## Common Mistakes
1. **Assuming variants always exist** — Always use null-safe access (`?->`). If you didn't call `->watermark()`, the watermark variant is `null`.
2. **Not handling SVG separately** — SVG uploads silently skip processing. If your code expects a blurhash for all uploads, check for null.
3. **Forgetting the folder argument** — `upload($file, 'folder')` requires the second argument. It determines where files are stored on the configured disk.
4. **Using `optimize()` with wrong format name** — Only `'avif'` and `'webp'` are supported. The variant key is always `optimized` regardless of format.
Use the ImageUploader fluent API to upload images with optional processing. The API generates structured file variants (original, optimized, low_quality, watermark) and a blurhash string for placeholder UIs.
This skill covers programmatic upload from PHP code. For HTTP API uploads (from frontend/mobile), use the file-manager-api-integration skill.
use M2code\FileManager\Application\Uploader\ImageUploader;
$result = ImageUploader::make()
->blur() // Generate BlurHash
->optimize('avif') // AVIF with WebP fallback
->watermark() // Apply watermark
->lowQuality() // Generate low quality placeholder
->upload($file, 'uploads/images');
The upload() method accepts three input types. No manual conversion is needed.
| Input Type | Example | Processing |
|---|---|---|
UploadedFile |
$request->file('photo') |
Full pipeline |
| Base64 data URI | 'data:image/png;base64,...' |
Full pipeline (raster only) |
| Raw SVG string | '<svg xmlns=...>...</svg>' |
Original only, processing skipped |
For detailed input behavior, see references/input-types.md.
The upload result contains structured variants accessible via $result->variants. For full details, see references/variant-types.md.
| Variant Key | Generated By | Description |
|---|---|---|
original |
Always | The original uploaded file |
optimized |
->optimize() |
AVIF/WebP optimized version |
low_quality |
->lowQuality() |
Low quality JPEG placeholder |
watermark |
->watermark() |
Watermarked version |
// Preferred: via variants collection
$result->variants->get('original')?->path;
$result->variants->get('optimized')?->path;
$result->blurhash; // the BlurHash string (null if not generated)
// Backward-compatible accessors (still available)
$result->path; // alias for original path
$result->optimizedPath; // alias for optimized path (null if not generated)
$result->lowQualityPath; // alias for low_quality path (null if not generated)
$result->watermarkPath; // alias for watermark path (null if not generated)
Always use null-safe access (?->) because variants that were not requested will be null.
Generates a BlurHash string for the uploaded image. The blurhash is accessible via $result->blurhash.
$result = ImageUploader::make()
->blur()
->upload($file, 'photos');
$result->blurhash; // "L6Df8^_4D%M{%MD%M{D%"
Generates an optimized variant in the specified format. Supported values: 'avif', 'webp'. If AVIF is not supported by the installed Imagick, it falls back to WebP. If neither is supported, the optimized variant is skipped (no error thrown).
$result = ImageUploader::make()
->optimize('avif') // or 'webp'
->upload($file, 'photos');
$result->variants->get('optimized')?->path; // "photos/abc123.avif"
Important: the variant key is always optimized, regardless of the format used.
Applies a watermark overlay to the image. Requires the watermark configuration to be set up in the image processing layer.
$result = ImageUploader::make()
->watermark()
->upload($file, 'photos');
$result->variants->get('watermark')?->path;
Generates a low-quality JPEG placeholder image, useful for progressive loading UIs.
$result = ImageUploader::make()
->lowQuality()
->upload($file, 'photos');
$result->variants->get('low_quality')?->path;
Alternative to fluent method chaining. Accepts an associative array. Only boolean values are processed; non-boolean values are silently ignored.
$result = ImageUploader::make()
->withOptions([
'blurhash' => true,
'optimize' => false,
'watermark' => true,
'low_quality' => false,
])
->upload($file, 'photos');
Supported option keys: blurhash, optimize, watermark, low_quality.
SVG files are handled specially. When an SVG is detected (MIME type image/svg+xml), all image processing is silently skipped. Only the original variant is saved, and $result->blurhash is null.
$svg = '<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64">...</svg>';
$result = ImageUploader::make()
->blur()
->watermark()
->upload($svg, 'icons');
// Only original exists:
$result->variants->get('original')?->path; // not null
$result->variants->get('low_quality'); // null
$result->variants->get('optimized'); // null
$result->variants->get('watermark'); // null
$result->blurhash; // null
This behavior is automatic. No special flag or check is needed.
Files are saved to the filesystem disk configured by FILE_MANAGER_DISK (default: public). The second argument to upload() is the destination folder relative to that disk's root.
// These save to {public_disk}/uploads/images/abc123.png
ImageUploader::make()->upload($file, 'uploads/images');
ImageUploader::make()->upload($file, 'avatars');
use M2code\FileManager\Application\Uploader\ImageUploader;
use M2code\FileManager\Facades\FileManager;
use M2code\FileManager\Facades\FileUrl;
// Upload with all processing enabled
$result = ImageUploader::make()
->blur()
->lowQuality()
->watermark()
->optimize('avif')
->upload($request->file('photo'), 'uploads/profiles');
// Store paths for database
$originalPath = $result->variants->get('original')?->path;
$optimizedPath = $result->variants->get('optimized')?->path;
$blurhash = $result->blurhash;
// Generate URLs for the frontend
$url = FileUrl::getUrl($optimizedPath ?? $originalPath);
$signedUrl = FileUrl::getSignedUrl($originalPath, now()->addHour());
// Clean up when deleting the parent record
FileManager::deleteVariants($result->variants);
Assuming variants always exist — Always use null-safe access (?->). If you didn't call ->watermark(), the watermark variant is null.
Not handling SVG separately — SVG uploads silently skip processing. If your code expects a blurhash for all uploads, check for null.
Forgetting the folder argument — upload($file, 'folder') requires the second argument. It determines where files are stored on the configured disk.
Using optimize() with wrong format name — Only 'avif' and 'webp' are supported. The variant key is always optimized regardless of format.
How can I help you explore Laravel packages today?