Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message
file-manager-image-upload
file-manager-image-upload
m2code/file-manager
claude-code
image-upload
file-manager
image-processing
blurhash
watermark
avif
fluent-api

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.

Install
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.

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

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.

Variants

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

Accessing variants

// 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.

$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).

$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.

$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.

$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.

$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.

$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.

// These save to {public_disk}/uploads/images/abc123.png
ImageUploader::make()->upload($file, 'uploads/images');
ImageUploader::make()->upload($file, 'avatars');

Complete Example

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.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo