Download the PHP package zielu92/filament-image-labeler without Composer
On this page you can find all versions of the php package zielu92/filament-image-labeler. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download zielu92/filament-image-labeler
More information about zielu92/filament-image-labeler
Files in zielu92/filament-image-labeler
Package filament-image-labeler
Short Description A Filament plugin for annotating images with rectangles and polygons. Provides an Annotorious-powered canvas, polymorphic persistence layer, a HasAnnotations trait for any Eloquent model, and opt-in automatic annotation via a model-defined hook.
License MIT
Homepage https://github.com/zielu92/filament-image-labeler
Informations about the package filament-image-labeler
Filament Image Labeler
A Filament plugin for labeling images — draw rectangles and polygons, name them, color them, all inside one form field. Built on Annotorious, with a polymorphic persistence layer so any Eloquent model can keep its annotations.
Features
- Annotation canvas with a toolbar under the image: Select / Rectangle / Polygon / Label, plus undo / redo / delete
- Built-in Labels panel — every distinct label gets a row with a color dot, edit and delete
- Built-in Label Details panel — rename a label (renames every shape using it) and pick its color
- Label pills rendered over the shapes on the canvas
- Two-way selection: click a shape to load its label, click a row to select the shape
- Polymorphic
annotationstable — attach annotations to any model HasAnnotationstrait withsyncAnnotations()for easy CRUD- Optional automatic annotation — a model overrides
autoAnnotate()to turn an image into suggestions (any backend you like: local model, detection API, LLM); the editor gets an Annotate button, optionally auto-running when the image loads - Works with private/public file storage, Filament v5 compatible, translations (en/de/pl)
Installation
How It Works
ImageLabel is a self-contained form field. Its Livewire state is an array of shapes:
target.selectoris Annotorious' internal geometry — pixel coordinates in the image's natural size; polygons use{ "type": "POLYGON", "geometry": { "points": [[x, y], ...], "bounds": {...} } }. Store it as-is, it round-trips.labelis free text; shapes sharing a label share a row in the Labels panel.coloris assigned deterministically from a hash of the label name and can be overridden per label in the UI. Colors are denormalized onto each shape, so the state array is all you need to persist.
Usage
1. Add the trait to your model
This gives your model $photo->annotations() (morphMany), $photo->syncAnnotations(array $data) and automatic cascade delete.
2. Add the field to your Filament form
The image closure is re-evaluated whenever the form renders, so the canvas follows the form: make the photo field ->live() and resolve the URL from its state (this also covers freshly uploaded, not-yet-saved files):
As a fallback the field also reacts to a Livewire::dispatch('image-labeler-update-url', $url) event. Pass the field's state path as a second argument (..., $url, 'annotations')) when a page renders multiple ImageLabel fields, so only the matching one updates.
Keyboard
In edit mode: Delete / Backspace removes the selected shape(s), Esc deselects or cancels an in-progress polygon, and Ctrl/Cmd+Z / Ctrl/Cmd+Y (or the toolbar arrows) undo/redo.
3. Persist on save, hydrate on edit
Map the field state onto syncAnnotations() — the app decides what goes into metadata:
AnnotationColor::forLabel('USB Port') returns the same color the canvas picks for a label by default — use it when your metadata was saved without an explicit color.
The syncAnnotations Method
Behavior: creates missing rows (matched by annotation_id), updates existing ones, deletes rows whose annotation_id is absent, [] clears all. geometry accepts an array or JSON string; metadata is nullable and yours to shape.
Automatic annotation
Let a model label its own images. The package defines only that it happens and what shape the answer has — how you find things in the image is entirely yours (local model, hosted detector, vision LLM, hardcoded test data).
1. Override the hook on your model. The contract: return a list of AnnotationSuggestion DTOs (label + normalized box/polygon). The trait default returns null, which keeps the feature off:
AnnotationSuggestion is the DTO the package defines (src/Support/AnnotationSuggestion.php): immutable, validates its geometry, exposes label + normalized points. Build it with ::box($label, $x, $y, $w, $h) / ::polygon($label, [[x, y], ...]). A plain array ['label' => ..., 'box' => ...] is accepted too — the package converts it with AnnotationSuggestion::fromArray() — so JSON straight from a detection API works without ceremony.
2. Choose what does the thinking — it's your method, per model. The package never calls anything itself, so every model can annotate completely differently: a YOLO endpoint here, a face-detection service there, an LLM somewhere else, an ONNX runtime in-process, a python sidecar, hardcoded fixtures in tests. Models share a strategy via a trait/base class, or branch inside the hook by whatever you know about the record:
Return null (or an empty array) when there is nothing to report — the field simply gets no shapes.
3. Enable the field:
What happens: clicking Annotate (or image load, with autoAnnotateOnLoad()) calls your autoAnnotate(), then the editor turns every suggestion into a normal shape right there on the canvas — the normalized points are scaled against the image the browser displays, so placement works for any URL, including protected/private ones. From there it is manual work: keep editing, undo, save through syncAnnotations() as usual. Results are never silently replaced on re-run; new shapes are appended (a multiple(false) field replaces).
Notes:
- The button renders only when the field is enabled and the record actually overrides the hook; read-only fields never annotate.
- Execution is synchronous with a spinner; a slow backend can hit request timeouts — that's your method's contract to keep snappy (queued execution may come later).
- If your method throws, the editor shows the error under the toolbar and leaves your shapes untouched.
$path: the package hands your method a local file when it can get one without requesting your own server — plain paths, public/storage/...URLs, remote http(s) downloads (max 20 MB). Same-host URLs (e.g. Livewire's local upload preview route) yieldnull; write your method so the URL alone is enough when that matters.- Security: remote
$pathdownloads refuse destinations that resolve to private, loopback, link-local (e.g. the cloud metadata address169.254.169.254) or reserved IP ranges, and never follow redirects — so an app that builds image URLs from user-controlled state can't turn the fetch into an SSRF probe. If your images genuinely live on an internal host, opt in viaconfig('filament-image-labeler.allow_private_image_hosts')(publishable config file, envIMAGE_LABELER_ALLOW_PRIVATE_IMAGE_HOSTS). Results are also discarded if the image is swapped or cleared mid-request.
ImageLabel Configuration
| Method | Description | Default |
|---|---|---|
->image(string\|Closure $url) |
Image URL to annotate | required |
->enableSquare(bool\|Closure) |
Show the Rectangle tool button | true |
->enablePolygon(bool\|Closure) |
Show the Polygon tool button | true |
->enableClear(bool\|Closure) |
Show the delete/clear toolbar button | true |
->multiple(bool\|Closure) |
Allow multiple shapes (new shape replaces old when false) |
true |
->coloredAnnotations(array\|null $palette) |
Palette used for default label colors | ImageLabel::DEFAULT_PALETTE |
->readOnly(bool\|Closure $condition) |
Display mode: shapes render, hovering shows the label; no toolbar or panels | false |
->enableAutoAnnotation(bool\|Closure) |
Show the Annotate button (needs an autoAnnotate() override on the model) |
false |
->autoAnnotateOnLoad(bool\|Closure) |
Also run automatic annotation when the image (re)loads | false |
->autoAnnotateButton(bool\|Closure) |
Show the toolbar button at all (turn off for hands-off, load-only annotation) | true |
->autoAnnotateButtonLabel(string\|Closure\|null) |
Button text | 'Annotate' (translated) |
->autoAnnotateButtonIcon(string\|Closure\|null) |
Button icon; null for none |
'heroicon-m-sparkles' |
Read-only display
To show a saved photo's annotations without editing — e.g. on a view page or anywhere a form field fits — hydrate the same state and mark the field read-only:
Shapes are drawn in their label colors; hovering a shape shows a tooltip with its label and color. No drawing, selection, or panels.
In edit mode the canvas, toolbar and the Labels / Label Details panels appear only while an image is set — the field owns label state internally, no repeater wiring needed.
Upgrading from v0.1
The app-side Repeater pattern is gone: the field now manages labels/colors itself and its state entries carry label and color. Old saved data still works — target geometry is unchanged; rows without a label in metadata simply hydrate as Unlabeled.
Testing
Changelog
Please see CHANGELOG for more information on what has changed recently.
Credits
This package uses Annotorious for the image annotation canvas, licensed under the BSD 3-Clause License.
License
The MIT License (MIT). Please see License File for more information.
All versions of filament-image-labeler with dependencies
filament/forms Version ^5.0
livewire/livewire Version ^4.0
spatie/laravel-package-tools Version ^1.15.0