API Reference

Auto-gegenereerd via Reflection — blijft altijd in sync met src/.

Filter: alleAppCacheCmsDbDebugDynamicEventsFilesFormHtmlHttpImageLogMediaSecuritySessionStdlibSupportView

GdBackend

Framework\Image\Backend\GdBackend
final class

GD-implementatie van {@see ImageBackendInterface}.

GD is gebouwd in PHP en bijna overal aanwezig — handig als fallback
wanneer ext-imagick ontbreekt. Ondersteunt jpg/png/webp; AVIF alleen
als PHP gebouwd is tegen libavif (vaak niet — gooit dan een
ImageBackendException).

Voor productie met avif-support en betere kleur-management is
{@see ImagickBackend} sterker. De keuze gebeurt in bootstrap.

__construct()
1 public method
transform(string $imageBytes, \TransformSpec $spec): string

ImageBackendException

Framework\Image\Backend\ImageBackendException
final class

Backend kon niet decoden / encoden / transformeren — meestal corrupte
input of een format-mismatch. Mapt naar HTTP 422 in de handler.

__construct(string $message = '', int $code = 0, ?Throwable $previous = NULL)

ImageBackendInterface

Framework\Image\Backend\ImageBackendInterface
interface

Pure transform-laag: image-bytes in, image-bytes uit.

Geen IO, geen cache, geen network — alleen de berekening. De Transformer
en Handler zijn verantwoordelijk voor source-IO en cache-write.

V1: alleen {@see ImagickBackend}. libvips/GD-backends kunnen later
worden toegevoegd via dezelfde interface.

1 public method
transform(string $imageBytes, \TransformSpec $spec): string

ImagickBackend

Framework\Image\Backend\ImagickBackend
final class

Imagick-implementatie van {@see ImageBackendInterface}.

Mapping van fit-modes naar Imagick-API:
- Cover → cropThumbnailImage (vult target, snijdt af)
- Contain → thumbnailImage met `bestfit=true` + zwarte/transparante padding
- Fit → scaleImage met aspect-ratio behouden, geen padding
- Crop → exact cropImage centered (vereist W én H)

Output-format via {@see Format} → setImageFormat. AVIF/WebP vereisen
een Imagick gebouwd tegen libheif/libwebp — vrijwel alle moderne
distros hebben dit.

__construct()
1 public method
transform(string $imageBytes, \TransformSpec $spec): string

VariantCache

Framework\Image\Cache\VariantCache
final class

Schrijft / leest bytes onder een relative path binnen een root-directory.

Wordt twee keer gebruikt:
- Voor de getransformeerde varianten (`data/cache/img/`)
- Voor geëxtraheerde video-frames (`data/cache/img/frames/`)

Schrijven gaat atomair (tmp-file + rename) zodat een crash midden in de
write geen halve files achterlaat — een halve file zou nginx als geldige
cache-hit serveren en de browser zou corrupt content krijgen.

Path-traversal guard: relative path mag geen `..` of absolute prefix bevatten.

__construct(string $root)
4 public methods
exists(string $relativePath): bool
path(string $relativePath): string
read(string $relativePath): ?string
write(string $relativePath, string $bytes): void

FitMode

Framework\Image\FitMode
enum

Hoe een afbeelding in z'n target-box past. Spiegelt CSS object-fit
voor consistentie met Framework\Media\DisplayMode.

5 public methods
static cases(): array
static from(string|int $value): static
static fromToken(string $token): self
token(): string
static tryFrom(string|int $value): ?static
Cases: Cover, Contain, Fit, Crop

Format

Framework\Image\Format
enum

Output-formaat voor de transform.

Format::Auto is een marker — UrlBuilder weigert 'm. Image::url() resolved
Auto naar een concreet formaat op basis van de Accept-header van de
huidige request, vóór 'ie de URL bouwt.

6 public methods
static cases(): array
extension(): string
static from(string|int $value): static
static fromExtension(string $ext): self
mimeType(): string
static tryFrom(string|int $value): ?static
Cases: Webp, Avif, Jpeg, Png, Auto

HmacSigner

Framework\Image\HmacSigner
final class

HMAC-SHA256 signer met rotation-support.

`sign()` gebruikt altijd het huidige secret. `verify()` probeert eerst
het huidige, dan (als gezet) het vorige — zodat tijdens een rotation-
grace-period URLs gegenereerd onder het oude secret nog geldig zijn.

Beide vergelijkingen via `hash_equals()` om timing-attacks te voorkomen.

__construct(string $currentSecret, ?string $previousSecret = NULL)
2 public methods
sign(string $payload): string
verify(string $payload, string $signature): bool

ImageHandler

Framework\Image\Http\ImageHandler
final class

HTTP-handler voor `/img/...`-routes.

Flow:
1. Parse URL → ParsedUrl (intern hash óf extern URL + sig-verify)
2. Variant-cache check → hit: serve direct, miss: stap 3
3. Resolve source-bytes (FileStorage óf remote-fetch+ingest)
4. StillFrame-extractie (passthrough / GIF frame 0 / video frame via ffmpeg)
Voor video: tussencache zodat ffmpeg niet per maat opnieuw runt
5. Transform via backend
6. Schrijf naar variant-cache zodat nginx volgende requests direct serveert

__construct(\UrlParser $urlParser, \FileStorageSource $internalSource, \RemoteUrlSource $remoteSource, \StillFrameRegistry $stillFrames, \Transformer $transformer, \VariantCache $variantCache, \VariantCache $frameCache)

Image

Framework\Image\Image
final class

Publieke facade voor URL-generatie.

Source mag zijn:
- {@see FileRecord} — gebruikt `contentHash` voor lokale, of `externalUrl`
voor externe (YouTube/Vimeo etc. zijn doorgaans niet relevant voor
image-transform, maar Realworks-style "extern via URL" werkt zo)
- `string` met sha256-hash (64 hex chars) — direct internal
- `string` met http(s) URL — extern, met HMAC-signing

Format::Auto resolveert op aanroep-tijd op basis van de huidige
Accept-header. Dat gebeurt via de `acceptHeaderProvider`-closure
zodat we op één Image-instance per request blijven (singleton in
de container) en de URL toch context-bewust is.

__construct(\UrlBuilder $builder, Closure $acceptHeaderProvider)
1 public method
url(\FileRecord|string $source, ?int $width = NULL, ?int $height = NULL, \FitMode $fit = \Framework\Image\FitMode::Cover, \Format $format = \Framework\Image\Format::Auto, int $quality = 75, int $dpr = 1): string

FileStorageSource

Framework\Image\Source\FileStorageSource
final class

Resolveert een sha256-hash naar bytes via de bestaande FileStorage.

Mime-type komt uit `finfo_buffer()` op de eerste paar KB — zo werkt 't
ook voor files die zonder extensie in storage zijn gezet (b.v. via
Realworks-import).

__construct(\FileStorage $storage)
1 public method
resolve(string $identifier): \SourceResult

RemoteFetchException

Framework\Image\Source\RemoteFetchException
final class

Externe fetch faalde (timeout, non-2xx, te groot, niet-toegestaan content-type).
Mapt naar HTTP 502 / 415 in de handler afhankelijk van de oorzaak.

__construct(string $message, string $reason, ?Throwable $previous = NULL)

RemoteUrlSource

Framework\Image\Source\RemoteUrlSource
final class

Haalt een externe URL op, valideert content-type + grootte, en ingest
de bytes in de gedeelde FileStorage. Volgende calls met dezelfde URL
(en dus dezelfde bytes/hash) zijn dedupe-gratis.

Gooit {@see RemoteFetchException} bij netwerkfouten, niet-2xx-status,
verboden content-type of een body groter dan `maxBytes`.

__construct(\Client $client, \FileStorage $storage, int $maxBytes = 20971520, float $timeoutSeconds = 5.0, array $allowedMimePrefixes = array ( 0 => 'image/', 1 => 'video/', ), string $userAgent = 'FrameworkImage/1.0 (+https://framework.multiminded.nl/image)')
1 public method
resolve(string $identifier): \SourceResult

SourceNotFoundException

Framework\Image\Source\SourceNotFoundException
final class

Source-resolver kon de identifier niet vinden.
Mapt naar HTTP 404 in de handler.

__construct(string $message = '', int $code = 0, ?Throwable $previous = NULL)

SourceResolverInterface

Framework\Image\Source\SourceResolverInterface
interface

Levert ruwe bytes voor een transform-pijplijn.

Identifier-vorm verschilt per implementatie:
- {@see FileStorageSource}: een sha256-hash
- {@see RemoteUrlSource}: een http(s) URL

Implementaties moeten {@see SourceNotFoundException} gooien als de
identifier niet leidt tot bytes.

1 public method
resolve(string $identifier): \SourceResult

SourceResult

Framework\Image\Source\SourceResult
final class

Resultaat van een SourceResolver: ruwe bytes + mime-type + content-hash.

Bytes kunnen image, gif of video zijn — dat bepaalt de StillFrameExtractor.
`sourceHash` is sha256 van de bytes; gebruikt als cache-key voor
geëxtraheerde frames (zodat twee URLs die naar dezelfde video wijzen
hetzelfde frame delen).

__construct(string $rawBytes, string $mimeType, string $sourceHash)

SpecCodec

Framework\Image\SpecCodec
final class

Codeert / decodeert een TransformSpec van/naar het canonieke URL-token.

Format: {w}x{h}-{fit}-q{quality}[-dpr{n}]
- w of h mag ontbreken (bv. "800" of "x600")
- fit en quality zijn altijd aanwezig (URLs blijven leesbaar)
- dpr verschijnt alleen als > 1

Encoder is strikt (canonieke volgorde, voorspelbare cache-key).
Decoder is permissief: tokens mogen in willekeurige volgorde — handig
bij handmatig getypte URLs of toekomstige migraties.

2 public methods
decode(string $token, \Format $format): \TransformSpec
encode(\TransformSpec $spec): string

GifFrameExtractor

Framework\Image\StillFrame\GifFrameExtractor
final class

Extract het eerste frame van een (animated) GIF via Imagick.

Output is een **PNG** — lossless intermediate, want we willen geen
kwaliteitsverlies vóór de Transformer er wat mee doet. De Transformer
kiest het uiteindelijke output-format.

Vereist `ext-imagick`. Als de extensie ontbreekt gooit de constructor
een StillFrameException — bootstrap moet 'm dan niet binden.

__construct()
1 public method
extract(string $rawBytes, string $mimeType): string

PassthroughExtractor

Framework\Image\StillFrame\PassthroughExtractor
final class

No-op extractor voor formaten die de ImageBackend rechtstreeks aankan
(jpg/png/webp/avif/svg). Geeft de bytes ongewijzigd door.

1 public method
extract(string $rawBytes, string $mimeType): string

StillFrameException

Framework\Image\StillFrame\StillFrameException
final class

Fout bij frame-extractie (gif/video). Mapt naar HTTP 422 / 500 in de handler.

__construct(string $message = '', int $code = 0, ?Throwable $previous = NULL)

StillFrameExtractor

Framework\Image\StillFrame\StillFrameExtractor
interface

Vertaalt ruwe source-bytes naar **image-bytes** die de Transformer kan
verwerken. Implementaties zijn responsible voor:
- jpg/png/webp/avif/svg → bytes ongewijzigd doorgeven
- gif → frame 0 extracten als losse image
- mp4/mov/webm → frame extractie via ffmpeg

De selectie gebeurt in {@see StillFrameRegistry} op basis van mime-type.

1 public method
extract(string $rawBytes, string $mimeType): string

StillFrameRegistry

Framework\Image\StillFrame\StillFrameRegistry
final class

Kiest een {@see StillFrameExtractor} op basis van het mime-type.

Default-mapping:
- image/gif → GifFrameExtractor
- video/* → VideoFrameExtractor
- alles anders → PassthroughExtractor (jpg/png/webp/avif/svg)

Bootstrap kan via de constructor extractors weglaten als de
vereiste deps ontbreken (bv. geen Imagick → geen Gif-handler).

__construct(\StillFrameExtractor $passthrough, ?\StillFrameExtractor $gif = NULL, ?\StillFrameExtractor $video = NULL)
2 public methods
extract(string $rawBytes, string $mimeType): string
pick(string $mimeType): \StillFrameExtractor

VideoFrameExtractor

Framework\Image\StillFrame\VideoFrameExtractor
final class

Extract een frame uit een video via een ffmpeg subprocess.

Werkt via stdin/stdout pipes — geen temp-files nodig:
ffmpeg -i pipe:0 -ss <seconds> -frames:v 1 -f image2 -vcodec mjpeg pipe:1

Output is JPEG (lossy maar compact); de Transformer re-encodeert toch
naar het uiteindelijke formaat. Default frame-time is 1 seconde — dat
vermijdt zwarte/intro-frames die vaak op t=0 staan.

`$ffmpegBinary` is configureerbaar (settings.php) zodat servers met
een non-standard pad (bv. `/usr/local/bin/ffmpeg`) ook werken.

__construct(string $ffmpegBinary = 'ffmpeg', float $frameTimeSeconds = 1.0, int $timeoutSeconds = 10)
2 public methods
extract(string $rawBytes, string $mimeType): string
static isFfmpegAvailable(string $binary = 'ffmpeg'): bool

Cheap check — caller (bootstrap) kan beslissen of de extractor
geregistreerd moet worden.

TransformBounds

Framework\Image\TransformBounds
final class

Project-bounds voor TransformSpec — voorkomt dat een geldige URL een
50000×50000-render kan triggeren die de RAM opvreet.

Config in config/settings.php onder de 'image'-sleutel.

__construct(int $maxWidth = 2600, int $maxHeight = 2600, int $maxDpr = 3)
1 public method
validate(\TransformSpec $spec): void

TransformSpec

Framework\Image\TransformSpec
final class

Wat we met een afbeelding willen doen — onafhankelijk van waar 'ie vandaan komt.

Validatie hier is intrinsiek (logische correctheid). Project-bounds
(max-w/h/dpr) leven in {@see TransformBounds} omdat die per project
configureerbaar zijn (config/settings.php).

__construct(?int $width = NULL, ?int $height = NULL, \FitMode $fit = \Framework\Image\FitMode::Cover, \Format $format = \Framework\Image\Format::Webp, int $quality = 75, int $dpr = 1)
3 public methods
effectiveHeight(): ?int
effectiveWidth(): ?int
withFormat(\Format $format): self

Transformer

Framework\Image\Transformer
final class

Orchestreert: bounds-validate → backend transform.

Geen IO. Caller (Handler) is verantwoordelijk voor source-IO en
cache-write. Deze klasse is dunne glue tussen TransformBounds en
de backend zodat beide testbaar blijven zonder elkaar.

__construct(\ImageBackendInterface $backend, \TransformBounds $bounds)
1 public method
transform(string $imageBytes, \TransformSpec $spec): string

InvalidUrlException

Framework\Image\Url\InvalidUrlException
final class
__construct(string $message = '', int $code = 0, ?Throwable $previous = NULL)

ParsedUrl

Framework\Image\Url\ParsedUrl
final class

Resultaat van UrlParser. Discriminate via isInternal() / isExternal().

4 public methods
static external(string $sourceUrl, \TransformSpec $spec): self
static internal(string $fileHash, \TransformSpec $spec): self
isExternal(): bool
isInternal(): bool

UrlBuilder

Framework\Image\Url\UrlBuilder
final class

Bouwt URLs voor de image-handler.

- Intern: /img/{prefix}/{file-hash}/{spec}.{ext}
- Extern: /img/extern/{prefix}/{url-hash}/{spec}.{ext}?u={base64url}&sig={hmac}

Format::Auto wordt door deze klasse niet geresolved — caller moet
eerst een concreet formaat kiezen (Image-facade doet dat op basis van
Accept-header).

__construct(\SpecCodec $codec, \HmacSigner $signer)
3 public methods
buildExternal(string $sourceUrl, \TransformSpec $spec): string
buildInternal(string $fileHash, \TransformSpec $spec): string
signaturePayload(string $sourceUrl, string $specToken, string $extension): string

UrlParser

Framework\Image\Url\UrlParser
final class

Parseert URLs gegenereerd door UrlBuilder en verifieert HMAC voor extern.

__construct(\SpecCodec $codec, \HmacSigner $signer)
1 public method
parse(string $path, string $queryString): \ParsedUrl

Image

Framework\Media\Source\Image
final class

Image bron — rendert een `<img>`-element. Ondersteunt `loading="lazy"`,
`fetchpriority`, `width`/`height`, `alt`. Geen poster (heeft geen video).

__construct(string $url, ?int $width = NULL, ?int $height = NULL)
1 public method
render(\Variant $variant, \RenderOptions $options): \El