Follow-up to #2420751: ImageEffectBase::transformDimensions() should have a sane default implementation

Problem/Motivation

All dimensions can be calculated, with a sole exception: when you use the rotation image effect with the "random rotation" setting enabled. But I can't imagine that's a very frequently used one. And even then… we could make it "deterministically random" if we'd want to: we could take the hash of the file name and map that to a float/integer between 0 and 360, and voila: deterministically random.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Wim Leers’s picture

Status: Needs work » Needs review
Issue tags: +API change

Hrm, this would require an API change; ImageEffectInterface::transformDimensions() would also have to receive the file URL. (Currently it only receives the dimensions of an image, which is insufficient — all images with the same dimensions would get the same rotation applied if we were to use that. That feels like it's "insufficiently random".)

But then it would be able to perform file operations. So it'd probably be better to receive a hash of the filename. Something like a $deterministic_randomness_hash parameter would probably make most sense.

Let's get feedback on that.

Wim Leers’s picture

Title: Make image effect rotate random determinist » Make RotateImageEffect's random rotation deterministic, so ::transformDimensions() can return the actual dimensions
attiks’s picture

I think it makes a lot of sense to also provide the file name, so image effects doing fancy stuff can use the image to do the calculations, but I guess that is another issue

Wim Leers’s picture

#4: yeah, it could make sense, but the danger in doing that is that operations that are now guaranteed to not cause I/O, might start causing I/O. That's why I proposed $deterministic_randomness_hash in #2.
So, yes, definitely another issue.

mondrake’s picture

#2, note that #1364670: ImageStyle::transformDimensions unable to deal with all effects. is proposing to add the URI to transformDimensions() signature.

But then it would be able to perform file operations. So it'd probably be better to receive a hash of the filename. Something like a $deterministic_randomness_hash parameter would probably make most sense.

A 'deterministic randomness hash' seems to me too specific for this use case. In the end, it would be able to perform I/O, but shall we babysit what you can do with the URI? If you just calculate a hash with it, then no problem!

Wim Leers’s picture

#6: well, that really is the fundamental question: do we guarantee no I/O happens at the interface level, or don't we? If we don't, we could just as well pass ImageInterface $image, which would be consistent with public function applyEffect(ImageInterface $image) on the same interface.

mondrake’s picture

#7 well passing ImageInterface $image is 100% I/O guaranteed ;)

I looked at where transformDimension() is called. We have two instances in HEAD, that basically can be reconducted to processing themes 'image_style' and 'responsive_image'. In both cases we do not have there an ImageInterface object instantiated before calling transformDimensions(), just the URI passed in $variables to the theme. For image_style, the actual loading and application of effects to the image is deferred to the file download controller that only runs createDerivative() if the derivative file URI is missing - i.e. only once per source image.

So, that would mean to add getting the $image object from the image.factory in the theme preprocess before calling transformDimensions(). Since all new image objects parse their file upon construction via the toolkit, we would have file I/O always, even if not needed.

So IMHO if we want to add anything, the URI is still the best option -

  1. no need to get image objects from the image factory, only pass an existing $variable to transformDimensions()
  2. with the URI parameter in transformDimensions()
  • most effects will just do nothing with it
  • some effects may use it to calculate an hash (the case here)
  • as last resort, some effects will use it to get an image object and get information from it or do other I/O operations directly on the file at the URI, who knows
mgifford’s picture

Status: Needs review » Active
fietserwin’s picture

Status: Active » Postponed

I fully agree with #8 and as such propose to postpone this issue on #1364670: ImageStyle::transformDimensions unable to deal with all effects.. The other issue should add the parameter, this issue can then make use of it to get "deterministic randomness" for the random rotation effect.

mondrake’s picture

Title: Make RotateImageEffect's random rotation deterministic, so ::transformDimensions() can return the actual dimensions » [PP-2] Make RotateImageEffect's random rotation deterministic, so ::transformDimensions() can return the actual dimensions

I suppose this would also need to wait for #1551686: Image rotate dimensions callback can calculate new dimensions for every angle, as currently only rotations of multiples of 90 degrees can be managed by RotateImageEffect::transformDimensions.

mondrake’s picture

Title: [PP-2] Make RotateImageEffect's random rotation deterministic, so ::transformDimensions() can return the actual dimensions » [PP-1] Make RotateImageEffect's random rotation deterministic, so ::transformDimensions() can return the actual dimensions
Component: image system » image.module
Wim Leers’s picture

Hurray!

mgifford’s picture

Status: Postponed » Active
fietserwin’s picture

Still postponed on another issue: #1551686: Image rotate dimensions callback can calculate new dimensions for every angle, as we do not yet calculate dimensions for angles that are not a multiple of 90 degrees. However the code changes/new features here will not interfere with code changes/new features in the other issue, it's only that the ultimate goal of this issue depends on both issues being resolved.

So, we could post a patch here that makes the random angle deterministic, but in itself that won't make transformDimensions() work for rotate in general. But because of this, not setting back to postponed.

mondrake’s picture

Issue tags: -Quickfix, -API change
mondrake’s picture

Status: Active » Needs review
FileSize
3.82 KB
58.02 KB

Patch.

This is built on top of #1551686-29: Image rotate dimensions callback can calculate new dimensions for every angle. It's quite simple now :)

The do-not-test patch is the incremental one for review, the other is the full patch for testing.

mondrake’s picture

Just realized that in random rotation, the degrees set in configuration define the maximum angle of rotation.

fietserwin’s picture

Status: Needs review » Needs work

I didn't do a thorough review yet but saw that rotation angles are defined as int while they are floats: you can define an angle of 3.5 degrees. Besides some casts and phpdoc comments, this may also influence the % operator (not sure how that operator treats floats) and thus e.g. the check for angles that are supposed to be a multiple of 90 degrees.

mondrake’s picture

Status: Needs work » Needs review

#19 - both the 'degrees' field in the Image effect form, and the config schema, only accept integer values. The GD toolkit ops may take floats (but I wonder if that makes sense anyway...). Supporting floats at effect level would then be a different issue.

fietserwin’s picture

Hmmm, then that would be a regression from D7 where I tested it yesterday and where, as it appears, function image_effect_integer_validate() DOES accept float values and so it works. I have filed a separate issue for this: #2576639: "Regression": accept floats for degrees in rotate effect.

mondrake’s picture

FileSize
1.85 KB
4.34 KB
165.34 KB

Rerolled against latest patch in #1551686: Image rotate dimensions callback can calculate new dimensions for every angle.

Also, since hash() returns a hex string, changed ::getRotationFromUri to convert that to integer via hexdec() instead of casting to int.

fietserwin’s picture

Status: Needs review » Needs work

This is only for the changes made here compared to the patch in the related issue #1551686: Image rotate dimensions callback can calculate new dimensions for every angle.

  1. +++ b/core/modules/image/src/Plugin/ImageEffect/RotateImageEffect.php
    @@ -58,6 +56,27 @@ public function transformDimensions(array &$dimensions, $uri) {
    +   *   An integer angle in the range 0-360.
    

    Change to (something like):
    An angle in the range from -$max_degrees to +$max_degrees.

  2. +++ b/core/modules/image/src/Plugin/ImageEffect/RotateImageEffect.php
    @@ -58,6 +56,27 @@ public function transformDimensions(array &$dimensions, $uri) {
    +    if (!$max_degrees || $max_degrees === 0) {
    +      return 0;
    +    }
    

    the second check falls entirely within the first check. Simplify the whole body to:
    $max_degrees = abs((int) $max_degrees);
    return $max_degrees === 0 ? 0 : (hexdec(hash(...;

mondrake’s picture

Title: [PP-1] Make RotateImageEffect's random rotation deterministic, so ::transformDimensions() can return the actual dimensions » Make RotateImageEffect's random rotation deterministic, so ::transformDimensions() can return the actual dimensions
Version: 8.0.x-dev » 8.1.x-dev

#1551686: Image rotate dimensions callback can calculate new dimensions for every angle has been committed, so this can be now worked on actively. Leaving to CNW for input in #23.

mondrake’s picture

Status: Needs work » Needs review
FileSize
955 bytes
4.32 KB

Rerolled and done #23.1 and .2

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.0-beta1 was released on March 2, 2016, which means new developments and disruptive changes should now be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Status: Needs review » Needs work

The last submitted patch, 25: 2420789-25.patch, failed testing.

mondrake’s picture

Status: Needs work » Needs review
FileSize
4.34 KB

Reroll

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.0-beta1 was released on August 3, 2016, which means new developments and disruptive changes should now be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs Review Queue Initiative, +Needs issue summary update

This issue is being reviewed by the kind folks in Slack, #need-reveiw-queue. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge require as a guide.

This appears it could still be relevant as the code is still similar.

Tagging for an issue summary update though for steps and proposed solution that matches the fix.

mondrake’s picture

smustgrave’s picture

If you're able to update the IS and reroll of the patch I can review again to help move the policy along.

mondrake’s picture

Sorry, I'm not interested here. If and when the policy issue is approved, I will be happy to provide deprecation patches.

I would just suggest to won't fix this issue unless there's anyone really interested to move it forward.

smustgrave’s picture

Status: Needs work » Postponed (maintainer needs more info)

Going to move to PNMI then since it was just sitting there for 7 years.

mondrake’s picture

Status: Postponed (maintainer needs more info) » Closed (won't fix)

Honestly… let’s see if anyone is interested. In that case, please reopen.