Manipulations
All manipulation methods return a new Image instance (immutable):
$image->crop(800, 600)->greyscale()->blur(5)->quality(80);
Manipulations are collected and only executed when the image URL is resolved (lazy).
Combining manipulations
A chain carries at most one resize intent. Calling a second sizing method doesn’t add a second resize — it folds into or replaces the first, so the chain never double-resamples:
$image->cover(800, 600)->width(400);
// → cover(400, 300): same crop window as cover(800, 600), just scaled down
$image->cropToRatio('1:1')->width(400);
// → cover(400, 400): the ratio and the explicit width combine into a concrete crop
That second form is why widths() works naturally on a ratio-based chain — each generated width folds into the same crop instead of competing with it.
Non-sizing operations — blur(), watermark(), manualCrop(), trim(), and the rest — are never folded and keep their order relative to the resize intent. Geometry operations (rotate(), manualCrop(), trim(), border()) are special: when one sits between two sizing calls, the two calls were authored against different canvases, so they don’t combine — the later sizing call resets the intent and applies after the geometry operation. This is a property of the operation, not of its arguments: a rotate(180) or an overlay border resets the intent too, even though it leaves dimensions untouched.
$image->cover(800, 600)->rotate(90)->width(400);
// → rotate(90) then width(400): 400px wide as written — the cover framing is dropped
If you need both a crop framing and a final size around a geometry operation, give the final geometry in a single sizing call after it.