Available Image Operations
April 29, 2026 · View on GitHub
Complete reference for the operations exposed via ImageVariant. Every fluent method on ImageVariant is a thin wrapper that constructs an Operation instance under src/Operation/ and stores it; the canonical source of truth for parameter types is the operation class.
For a custom operation that's not in this list, register it on a custom OperationRegistry and pass that registry into ImageProcessor. See Custom operations at the bottom.
Basic usage
use PhpCollective\Infrastructure\Storage\Processor\Image\ImageVariantCollection;
$collection = ImageVariantCollection::create();
$collection->addNew('thumbnail')
->scale(300, 300)
->optimize();
Resize / scale
resize(int $width, int $height, bool $preventUpscale = false)
Stretch the image to exact width and height. Aspect ratio is not preserved.
$collection->addNew('exact-size')->resize(200, 200);
scale(int $width, int $height, bool $preventUpscale = false)
Fit the image within $width × $height while preserving aspect ratio.
$collection->addNew('thumbnail')->scale(300, 300);
heighten(int $height, bool $preventUpscale = false)
Resize to a specific height; width follows the aspect ratio.
$collection->addNew('portrait')->heighten(400);
widen(int $width, bool $preventUpscale = false)
Resize to a specific width; height follows the aspect ratio.
$collection->addNew('landscape')->widen(600);
Crop / cover
crop(int $width, int $height, ?int $x = null, ?int $y = null, Position $position = Position::Center)
Cut a rectangle out. When $x and $y are both set, the crop is positioned at those exact pixel coordinates; otherwise the crop is positioned by the alignment.
use PhpCollective\Infrastructure\Storage\Processor\Image\Position;
$collection->addNew('square')->crop(200, 200);
$collection->addNew('top-strip')->crop(800, 100, position: Position::TopCenter);
$collection->addNew('exact')->crop(200, 200, x: 50, y: 50);
cover(int $width, int $height, Position $position = Position::Center, bool $preventUpscale = false)
Zoom-crop to exact dimensions while preserving aspect ratio. The image is scaled to cover the area and the overflow is cropped at the chosen alignment.
$collection->addNew('avatar')->cover(150, 150);
$collection->addNew('hero')->cover(1200, 400, Position::TopCenter);
Rotation / flipping
rotate(int $angle)
Rotate the image clockwise by the given angle in degrees.
$collection->addNew('rotated')->rotate(90);
flipHorizontal() / flipVertical()
Mirror horizontally or vertically.
$collection->addNew('mirrored')->flipHorizontal();
$collection->addNew('flipped')->flipVertical();
flip(FlipDirection|string $direction)
Mirror by direction. Accepts the FlipDirection enum (preferred) or the string codes 'h' / 'v' / 'horizontal' / 'vertical'.
use PhpCollective\Infrastructure\Storage\Processor\Image\FlipDirection;
$collection->addNew('typed')->flip(FlipDirection::Horizontal);
$collection->addNew('config-driven')->flip($config['flip'] ?? 'h');
orient()
Auto-rotate based on EXIF orientation. Best placed first in a pipeline so subsequent operations work on the visually correct orientation.
$collection->addNew('phone-upload')
->orient()
->cover(1024, 768)
->optimize();
Color / tone
brightness(int $level) / contrast(int $level)
Channel adjustments in the -100..100 range. 0 leaves the image unchanged.
$collection->addNew('punchy')
->brightness(10)
->contrast(15);
grayscale()
Convert to grayscale.
$collection->addNew('mono')->grayscale();
colorize(int $red = 0, int $green = 0, int $blue = 0)
Tint by shifting each channel in the -100..100 range.
$collection->addNew('warm')->colorize(10, 0, -10);
Effects
sharpen(int $amount)
Sharpen, 0..100.
$collection->addNew('crisp')->sharpen(15);
blur(int $level = 5)
Gaussian-style blur, 0..100. Defaults to 5 (intervention's default).
$collection->addNew('soft')->blur(20);
pixelate(int $size)
Privacy-redaction effect. $size is the pixel block size.
$collection->addNew('redacted')->pixelate(12);
trim(int $tolerance = 0)
Strip uniform-coloured border areas. $tolerance is 0..100; 0 only trims exact-match colours.
$collection->addNew('content-only')->trim(5);
Canvas
resizeCanvas(int $width, int $height, ?string $background = null, Position $position = Position::Center)
Resize the working canvas without resampling the source image. New pixel area introduced by growing the canvas is filled with $background.
$collection->addNew('framed')
->resizeCanvas(800, 600, background: '#ffffff', position: Position::Center);
padding(int $amount, ?string $background = null)
Add $amount pixels of padding on every side, filled with $background.
$collection->addNew('padded')->padding(20, '#000000');
Watermark / overlay
place(string $image, Position $position = Position::BottomCenter, int $x = 0, int $y = 0, float $opacity = 1.0)
Insert another image on top of the current one.
$collection->addNew('watermarked')
->scale(1024, 1024)
->place('logo.png', Position::BottomRight, x: -10, y: -10, opacity: 0.6);
Format / output
convert(Format|string $format)
Re-encode the variant in a different format than the source. The variant's stored path's extension is swapped to match. Accepts the Format enum (preferred — type-safe) or an extension string for config-driven setups; aliases like jpg / tif / pjpeg / heif resolve to their canonical case.
use PhpCollective\Infrastructure\Storage\Processor\Image\Format;
$collection->addNew('webp-version')
->scale(1200, 800)
->convert(Format::Webp);
// Config-driven
$collection->addNew('config-driven')->convert($config['format'] ?? 'webp');
optimize()
Run the variant through spatie/image-optimizer after encoding. Reduces file size; requires the optimizer's CLI tools (jpegoptim, optipng, …) to be installed on the system.
$collection->addNew('web-large')
->scale(1920, 1080)
->optimize();
Custom callbacks
callback(callable $callback)
Escape hatch for one-off image manipulation that no first-class operation covers. The callback receives the intervention/image instance and modifies it in place.
$collection->addNew('custom')
->callback(function ($image) {
$image->brightness(10);
$image->contrast(5);
});
Note:
Callbackoperations don't survive atoArray()round-trip cleanly (closures are not serialisable). Use them for in-process pipelines, not for persisted variant configurations.
Chaining
All operations chain:
$collection->addNew('hero-mobile')
->orient()
->cover(750, 500, Position::TopCenter)
->sharpen(8)
->convert('webp')
->optimize();
Position constants
The Position enum covers every alignment intervention/image accepts, in both top-left and left-top forms:
use PhpCollective\Infrastructure\Storage\Processor\Image\Position;
Position::Center
Position::TopCenter Position::BottomCenter
Position::TopLeft Position::TopRight
Position::LeftTop Position::RightTop
Position::LeftCenter Position::RightCenter
Position::LeftBottom Position::RightBottom
Position::BottomLeft Position::BottomRight
For config-driven setups: Position::fromName($string) does case/whitespace normalisation and throws with a clear list of valid names on bad input.
Common patterns
Profile pictures / avatars
$collection->addNew('avatar')
->orient()
->cover(150, 150)
->optimize();
Responsive images
foreach ([320 => 'mobile', 768 => 'tablet', 1920 => 'desktop'] as $width => $name) {
$collection->addNew($name)
->scale($width, $width)
->convert('webp')
->optimize();
}
Watermarked deliverable
$collection->addNew('preview')
->scale(1200, 1200)
->place('watermark.png', Position::BottomCenter, opacity: 0.5)
->optimize();
Custom operations
ImageProcessor accepts a custom OperationRegistry as its fifth constructor argument. This lets apps add operations the package doesn't ship with — for example a domain-specific recolouring step.
use PhpCollective\Infrastructure\Storage\Processor\Image\Operation\Operation;
use PhpCollective\Infrastructure\Storage\Processor\Image\Operation\OperationContext;
use PhpCollective\Infrastructure\Storage\Processor\Image\Operation\OperationRegistry;
final class TintOperation implements Operation
{
public function __construct(public readonly string $color) {}
public function name(): string { return 'tint'; }
public function apply(OperationContext $context): void {
$context->image->fill($this->color);
}
public function toArray(): array { return ['color' => $this->color]; }
}
$registry = OperationRegistry::default()
->register('tint', static fn (array $args): Operation => new TintOperation((string)$args['color']));
$processor = new ImageProcessor(
$storage,
$pathBuilder,
$imageManager,
urlBuilder: null,
operationRegistry: $registry,
);
// On the variant side, attach the operation directly via add()
$collection->addNew('tinted')->add(new TintOperation('#ffaa00'));