PHPackages                             isapp/laravel-imagetools - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Image &amp; Media](/categories/media)
4. /
5. isapp/laravel-imagetools

ActiveLibrary[Image &amp; Media](/categories/media)

isapp/laravel-imagetools
========================

Laravel image tools: deterministic, query-driven image generation (vite-imagetools-like).

1.1.0(3w ago)6419↑260%[1 PRs](https://github.com/isap-ou/laravel-imagetools/pulls)MITPHPPHP ^8.2CI passing

Since Nov 5Pushed 1w agoCompare

[ Source](https://github.com/isap-ou/laravel-imagetools)[ Packagist](https://packagist.org/packages/isapp/laravel-imagetools)[ RSS](/packages/isapp-laravel-imagetools/feed)WikiDiscussions main Synced 2d ago

READMEChangelog (3)Dependencies (33)Versions (9)Used By (0)

Laravel Image Tools
===================

[](#laravel-image-tools)

Deterministic, query‑driven image generation for Laravel — inspired by **vite-imagetools**.

[![Laravel Image Tools by ISAPP](https://camo.githubusercontent.com/0addbccc6aa9cad43ae41e9ebcb81409c196c8f3cd3483663fbf465ee5efe53f/68747470733a2f2f7374617469632e697361702e6d652f6c61726176656c2d696d616765746f6f6c732e706e67)](https://isapp.be/laravel-imagetools)

[![Packagist](https://camo.githubusercontent.com/4e47477dc1e3d30582183797750a659155125ac842aaa79a3d14b942271f3a12/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f69736170702f6c61726176656c2d696d616765746f6f6c732e737667)](https://packagist.org/packages/isapp/laravel-imagetools)[![Tests](https://github.com/isap-ou/laravel-imagetools/actions/workflows/run-tests.yml/badge.svg)](https://github.com/isap-ou/laravel-imagetools/actions/workflows/run-tests.yml)[![PHP](https://camo.githubusercontent.com/f3b8c8374c888037d9298c1c5725e05987f94eb7e09dd9bc2fd8f91141c66525/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f69736170702f6c61726176656c2d696d616765746f6f6c732e737667)](https://packagist.org/packages/isapp/laravel-imagetools)[![License](https://camo.githubusercontent.com/a05de16618b9d4b90a2378742e352dd618692798184ab739f2c6694d6c240c58/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f697361702d6f752f6c61726176656c2d696d616765746f6f6c732e737667)](#license)

- Call it once in Blade/PHP and get a public URL: ```
    {{ ImageTools::asset('public/images/hero.jpg?w=1200&h=630&fit=contain&format=webp&q=82') }}
    ```
- Files are written to your configured filesystem disk with **stable names**(e.g. `hero--a1b2c3d4e5.webp`), perfect for long‑lived CDN caching.
- A tiny **PHP manifest** maps your canonical request to the stored file, so subsequent calls are instant.

---

Features
--------

[](#features)

- 🔁 **Deterministic filenames** based on the source + sorted query options
- 🧩 **Simple query API**: `w`, `h`, `fit`, `q`, `format`
- 📦 **One disk to rule them all** — works with `public`, S3/R2 or any Laravel disk
- 🔎 **Scanner command** to pre‑generate all images referenced in your code
- 🧹 **Clear command** to remove generated files &amp; the manifest
- ⏳ **Deferred generation** via a `queue` flag — defer heavy/responsive work to the queue

Requirements
------------

[](#requirements)

- PHP **8.2+**
- Laravel **10+** (works with 10/11/12)
- Image driver: **Imagick** (recommended) or **GD** for [`spatie/image`](https://github.com/spatie/image)

Installation
------------

[](#installation)

```
composer require isapp/laravel-imagetools
```

Auto‑discovery will register the service provider and the `ImageTools` facade.

### Publish config (optional)

[](#publish-config-optional)

If you want to customize defaults, publish the config file:

```
php artisan vendor:publish --provider="Isapp\\ImageTools\\ServiceProvider"
```

Quick start
-----------

[](#quick-start)

```

```

**Pure PHP**

```
use Isapp\\ImageTools\\Facades\\ImageTools;

$url = ImageTools::asset('resource/images/placeholder.jpg?w=640&q=75&format=webp');
```

**Source on another disk** — read the original from any Laravel disk (e.g. S3), mirroring `Storage::disk()` (see [Reading the source from a disk](#reading-the-source-from-a-disk-eg-s3)):

```
ImageTools::disk('s3')->asset('assets/hero.jpg?w=1200&format=webp');
```

**Also supported** (and detected by the scanner):

```
{{ app(Isapp\ImageTools\ImageTools::class)->asset('resource/images/pic.jpg?w=800') }}
{{ app('image-tools')->asset('resource/images/pic.jpg?w=800') }}
{{ \Illuminate\Support\Facades\App::make('image-tools')->asset('resource/images/pic.jpg?w=800') }}
{{ App::make(Isapp\ImageTools\ImageTools::class)->asset('resource/images/pic.jpg?w=800') }}
```

Configuration
-------------

[](#configuration)

All options live in `config/image-tools.php` (with inline comments). You can also control them via ENV:

```
IMAGE_TOOLS_DISK=public
IMAGE_TOOLS_MANIFEST_PATH=bootstrap/cache/image-tools.php
IMAGE_TOOLS_BLADE_PATHS=resources/views,modules/*/resources/views
IMAGE_TOOLS_PHP_PATHS=app,modules

# Deferred generation (optional)
IMAGE_TOOLS_QUEUE_CONNECTION=redis   # defaults to QUEUE_CONNECTION
IMAGE_TOOLS_QUEUE_NAME=images        # defaults to "default"
IMAGE_TOOLS_QUEUE_UNIQUE_FOR=3600
```

Key options:

- **`disk`** — Laravel filesystem disk where processed files are written and served from (`public`, `s3`, `r2`, …).
- **`manifest_path`** — Path to the PHP manifest file that stores the mapping (relative paths resolve from the project base path).
- **`blade_paths`** — Directories with Blade templates to scan for usages.
- **`php_paths`** — Additional PHP directories to scan (controllers, services, etc.).

> The request is **canonicalized**: query keys are sorted before hashing, so `?h=630&w=1200` equals `?w=1200&h=630`.

> **Zero‑downtime deploys (Forge, Envoyer, Deployer, Vapor):** the manifest is written at runtime when `asset()` generates an image on demand. `bootstrap/cache` is **per‑release**, so those entries are lost on the next deploy (the images are simply regenerated). If you rely on on‑demand generation, point the manifest at the **shared** `storage` directory, e.g. `IMAGE_TOOLS_MANIFEST_PATH=storage/app/image-tools.php`. If you only pre‑generate at build time with `imagetools:generate`, the default is fine.

### Query options

[](#query-options)

KeyTypeDescription`w``int`Target width (px).`h``int`Target height (px).`fit``enum`Geometry mode from `Spatie\Image\Enums\Fit` (e.g. `Contain`, `Fill`, `Max`, …). Requires `w` and `h`.`q``int`Output quality (`1..100`).`format``enum`Output format: `jpeg`, `png`, `gif`, `webp`, `avif`.> `queue` is a **control flag**, not a transform — see below. It is excluded from the canonical name, so `?w=800` and `?w=800&queue=1` resolve to the **same** file.

Deferred (queued) generation
----------------------------

[](#deferred-queued-generation)

On a page with many images — especially responsive `srcset` with several widths — generating them all on the first request can be slow. Add a truthy **`queue`**flag to defer generation to the queue:

```

```

When the image hasn't been generated yet:

- `asset()` returns the **final, deterministic URL immediately** (filenames are a hash of the source + options, so the URL is known before the file exists).
- A `GenerateImageJob` is dispatched to the queue; the file appears once a worker processes it. Until then the URL 404s — make sure a worker is running (`php artisan queue:work`).

The job is **unique** per derivative (`ShouldBeUnique`), so many concurrent page renders of the same not-yet-generated image collapse into a single job instead of a storm of duplicates. This requires a cache store that supports atomic locks (`file`, `redis`, `database`, `memcached`, …).

Configuration (all optional — see `config/image-tools.php`):

- **`queue_connection`** — falls back to `QUEUE_CONNECTION`. If that resolves to `sync`, the job runs inline (no real deferral) — expected Laravel behaviour.
- **`queue_name`** — queue to dispatch on (default `"default"`).
- **`unique_for`** — seconds the uniqueness lock is held (default `3600`).

> Pre-generating with `php artisan imagetools:generate` ignores the `queue` flag and produces the same files, so you can warm everything at build time instead.

Reading the source from a disk (e.g. S3)
----------------------------------------

[](#reading-the-source-from-a-disk-eg-s3)

By default the **source** image is read locally, relative to `base_path()`. To read the original from a configured Laravel filesystem disk instead — for example an S3 bucket — scope the call with `disk()`, mirroring `Storage::disk()`:

```
use Isapp\ImageTools\Facades\ImageTools;

// Reads s3:///assets/hero.jpg, processes it, writes the result to the
// configured output disk (image-tools.disk).
ImageTools::disk('s3')->asset('assets/hero.jpg?w=1200&format=webp');
```

```

```

- The original is streamed to a temporary local file (the image driver loads from a path), processed, and the temp copy is removed.
- The **source disk participates in the identity**: the same path read from different disks produces distinct files and manifest keys (no collisions).
- `disk()` returns a scoped copy — it does not mutate the shared instance.
- The **output** disk is still `config('image-tools.disk')`; `disk()` only changes where the *source* is read from.

> The scanner command detects plain `ImageTools::asset('…')` calls; the fluent `disk('…')->asset('…')` form is generated on demand (or via the queue), not pre-discovered at build time.

Commands
--------

[](#commands)

### Pre‑generate from code (CI‑friendly)

[](#pregenerate-from-code-cifriendly)

Scans your codebase and generates images for discovered usages.

```
php artisan imagetools:generate
```

The scanner looks into `config('image-tools.blade_paths')` and `config('image-tools.php_paths')` and detects:

- `ImageTools::asset('…')`
- Container‑resolved calls (e.g. `app(ImageTools::class)->asset('…')`, `app('image-tools')->asset('…')`, `App::make(...)->asset('…')`)

### Clear generated files

[](#clear-generated-files)

Deletes all files referenced in the current manifest and then removes the manifest file.

```
php artisan imagetools:clear
```

What gets written
-----------------

[](#what-gets-written)

- A processed file on the configured **disk**, under `image-tools/--.`.
- A PHP **manifest** (by default `bootstrap/cache/image-tools.php`) with entries like: ```
    return [
        'resource/images/hero.jpg?h=630&w=1200&fit=contain&format=webp&q=82' => [
            'path' => 'image-tools/hero--a1b2c3d4e5.webp',
            'disk' => 'public',
        ],
    ];
    ```

Tips
----

[](#tips)

- **Deterministic names** → long CDN cache is safe; change options or the source to bust the cache.
- **Disks**: for S3/R2 configure a public bucket or use signed URLs as needed.
- **Quality/Formats**: `webp`/`avif` usually win; measure before/after.

Troubleshooting
---------------

[](#troubleshooting)

- **`Class ...\ImageTools not found`** — ensure the package is installed and auto‑discovered; run `composer dump-autoload`.
- **`ImagickException` / missing extension** — install and enable Imagick (preferred) or GD for your PHP runtime.
- **`width(): Argument #1 must be of type int`** — pass numeric values in the query (`w=640`, not `w=640px`).
- **`fit` requires `w` and `h`** — when using `fit`, provide both dimensions.
- **No URL / 404** — check the configured `disk` has a URL generator (`php artisan storage:link` for `public` disk).

Testing
-------

[](#testing)

```
composer test
```

The suite includes an **S3 integration test** (PHPUnit group `s3`) that runs against a real S3‑compatible endpoint to verify uploads, URL generation and the clear command. It is **skipped** unless `AWS_ENDPOINT` + `AWS_BUCKET` are set, so the default run needs no infrastructure. To run it locally against MinIO:

```
docker run -d -p 9000:9000 -e MINIO_ROOT_USER=minio \
  -e MINIO_ROOT_PASSWORD=minio12345 minio/minio server /data
aws --endpoint-url http://127.0.0.1:9000 s3 mb s3://test   # create the bucket

AWS_ENDPOINT=http://127.0.0.1:9000 AWS_BUCKET=test \
  AWS_ACCESS_KEY_ID=minio AWS_SECRET_ACCESS_KEY=minio12345 \
  AWS_USE_PATH_STYLE_ENDPOINT=true vendor/bin/phpunit --group s3
```

CI runs this automatically in a dedicated MinIO job.

Versioning
----------

[](#versioning)

This package follows [Semantic Versioning](https://semver.org). See [CHANGELOG.md](CHANGELOG.md) for release notes.

Security
--------

[](#security)

If you discover a security issue, please email **** instead of opening a public issue.

Contributing
------------

[](#contributing)

Contributions are welcome! If you have suggestions for improvements, new features, or find any issues, feel free to submit a pull request or open an issue in this repository.

Thank you for helping make this package better for the community!

License
-------

[](#license)

This project is open-sourced software licensed under the [MIT License](https://opensource.org/licenses/MIT).

You are free to use, modify, and distribute it in your projects, as long as you comply with the terms of the license.

Credits
-------

[](#credits)

Built by [ISAPP](https://isapp.be). Uses the excellent [`spatie/image`](https://github.com/spatie/image).

---

Check out our software development services at [isapp.be](https://isapp.be).

###  Health Score

47

—

FairBetter than 93% of packages

Maintenance96

Actively maintained with recent releases

Popularity21

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~53 days

Total

5

Last Release

25d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/9bfb1eae1e3e43813da6740e5eaa39307a95db7561c2d27e7e8aa24233cdcbeb?d=identicon)[andrii-trush](/maintainers/andrii-trush)

---

Top Contributors

[![andrii-trush](https://avatars.githubusercontent.com/u/14265776?v=4)](https://github.com/andrii-trush "andrii-trush (16 commits)")

---

Tags

image-generationimage-toolslaravelspatielaravelimagecdnoptimizerImageTools

###  Code Quality

TestsPHPUnit

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/isapp-laravel-imagetools/health.svg)

```
[![Health](https://phpackages.com/badges/isapp-laravel-imagetools/health.svg)](https://phpackages.com/packages/isapp-laravel-imagetools)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M346](/packages/psalm-plugin-laravel)[moonshine/moonshine

Laravel administration panel

1.3k253.1k81](/packages/moonshine-moonshine)[laravel/ai

The official AI SDK for Laravel.

1.0k3.2M194](/packages/laravel-ai)[blade-ui-kit/blade-icons

A package to easily make use of icons in your Laravel Blade views.

2.5k42.5M404](/packages/blade-ui-kit-blade-icons)[spatie/laravel-medialibrary

Associate files with Eloquent models

6.1k43.2M631](/packages/spatie-laravel-medialibrary)[illuminate/session

The Illuminate Session package.

9939.3M850](/packages/illuminate-session)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
