Skip to content

[Cropperjs] Upgrade to Intervention Image v4 and make the image driver configurable#3679

Open
deluxetom wants to merge 3 commits into
symfony:3.xfrom
deluxetom:cropperjs-intervention-v4
Open

[Cropperjs] Upgrade to Intervention Image v4 and make the image driver configurable#3679
deluxetom wants to merge 3 commits into
symfony:3.xfrom
deluxetom:cropperjs-intervention-v4

Conversation

@deluxetom

Copy link
Copy Markdown
Q A
Bug fix? no
New feature? yes
Deprecations? no
Documentation? yes
Issues Fix #3394
License MIT

Resolves the indirect intervention/image v2 deprecations reported in #3394 by upgrading the dependency to v4, and adds the ability to choose the image driver (proposal/discussion in #3678).

What changes

  • intervention/image: ^2.5^4.0 (drops v2). The Crop model migrates to the v4 API: make()decodeBinary(), the resize(closure) aspect-ratio + upsize calls → scaleDown(), encode() + getEncoded()encodeUsingFileExtension(), and the type-hints move to ImageManagerInterface / ImageInterface.
  • Configurable image driver via a new bundle configuration:
# config/packages/cropperjs.yaml
cropperjs:
    driver: gd            # gd (default), imagick or vips
    driver_service: ~     # optional: a custom Intervention DriverInterface service (takes precedence)

The ImageManager is built through ImageManager::usingDriver(). gd / imagick are bundled with intervention/image; vips uses the official intervention/image-driver-vips package, declared under composer suggest (it needs libvips + ext-ffi). Selecting vips without that package fails fast at container compile time with an actionable message. driver_service lets advanced users inject a fully custom / pre-configured DriverInterface.

Backward compatibility

The bundle's public API is unchanged and gd remains the zero-config default, so existing apps behave exactly as before. The only requirement change is intervention/image v4 (PHP >= 8.3, already satisfied by the bundle's PHP >= 8.4 floor).

Tests

CropTest is parameterized over the gd and imagick drivers and now covers the crop region (locking the crop() argument order), setCroppedMaxSize() downscaling, thumbnail downscaling and output format. New ConfigurationTest and CropperjsExtensionTest cover the driver configuration, the custom-driver precedence and the fail-fast vips guard.

@carsonbot carsonbot added Cropperjs Documentation Improvements or additions to documentation Feature New Feature Status: Needs Review Needs to be reviewed labels Jun 11, 2026
@deluxetom deluxetom force-pushed the cropperjs-intervention-v4 branch from d756cf4 to c5a7ee9 Compare June 11, 2026 21:33
…r configurable

Migrate the server-side cropping from intervention/image ^2.5 (v2) to ^4.0,
which removes the indirect v2 deprecations reported in symfony#3394. The Crop model
now uses the v4 API (decodeBinary/scaleDown/encodeUsingFileExtension and
ImageManagerInterface).

Add a configurable image driver through a new bundle configuration:

 * cropperjs.driver: gd (default), imagick or vips
 * cropperjs.driver_service: a custom Intervention DriverInterface service,
   which takes precedence over driver

The ImageManager is built via ImageManager::usingDriver(); selecting vips
without the intervention/image-driver-vips package fails fast with a helpful
message. GD remains the zero-config default, preserving current behavior.

Tests are parameterized over the gd and imagick drivers and now cover the
crop region, max-size downscaling and output format paths.
@deluxetom deluxetom force-pushed the cropperjs-intervention-v4 branch from c5a7ee9 to 9d5a7e3 Compare June 11, 2026 21:40
@carsonbot carsonbot added Status: Reviewed Has been reviewed by a maintainer and removed Status: Needs Review Needs to be reviewed labels Jun 12, 2026
@deluxetom

Copy link
Copy Markdown
Author

@Kocal @MrYamous let me know if you see anything that needs to be updated

Comment thread src/Cropperjs/src/Model/Crop.php Outdated

if (!empty($this->options['rotate'])) {
$image->rotate(-1 * $this->options['rotate']);
$image->rotate(-1 * $this->options['rotate'], 'ffffff');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In V4 the rotate() rotates clockwise by default (from upgrade guide), i'm not sure the -1 is still appropriated with this change. Tests are done with a 90 degrees rotation so I don't think it's noticeable. Maybe we need to add a new test for that ?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified: in v2 rotate() turned counter-clockwise for positive angles, so the -1 * matched cropper.js (which rotates clockwise for positive degrees). In v4 rotate() turns clockwise for positive angles (RotateModifier docblock says "Clockwise rotation angle", and the GD modifier negates internally for imagerotate), so the negation now inverts the output relative to the cropper preview.

Dropped the -1 and added a directional test (testGetCroppedImageRotatesClockwise): a left-red/right-blue image rotated 90° should land red on top and blue on the bottom. The existing 90° tests only asserted dimensions, which are direction-agnostic, so they couldn't catch this. Fixed in 72f9563.

deluxetom and others added 2 commits June 17, 2026 06:22
In v2 rotate() turned counter-clockwise for positive angles, so the
crop applied -1 * rotate to match cropper.js (clockwise positive). In
v4 rotate() turns clockwise for positive angles, so the negation now
inverts the output relative to the cropper preview. Pass the angle
directly and add a directional test (the existing 90° tests only
asserted dimensions, which are direction-agnostic).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
v4's Config::$backgroundColor already defaults to 'ffffff', and
rotate(angle, null) falls back to it, so passing 'ffffff' explicitly is
redundant. Omitting it keeps the same white-corner output while letting
a custom driver_service ImageManager control the fill via its own config.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Cropperjs Documentation Improvements or additions to documentation Feature New Feature Status: Reviewed Has been reviewed by a maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Cropperjs] Indirect deprecations with intervention/image

4 participants