Problem/Motivation
The image style generation has been improved in #2027423: Make image style system flexible. Now a module can change the way image derivatives are generated. However, right now altering the derivative URI can be done by extending \Drupal\image\Entity\ImageStyle
. This is a problem because the last module to override the image style class wins, and everyone else loses.
Proposed resolution
Allow modules to alter the image style derivative generated URI by implementing a new hook_image_style_uri_alter()
.
Remaining tasks
None.
User interface changes
None.
API changes
New hook hook_image_style_uri_alter()
.
Data model changes
None.
Beta phase evaluation
Issue category | Feature because gives new, more flexible, ways for modules to handle the image derivatives generation. |
---|---|
Issue priority | Not critical because right now modules still can alter the image derivative generation the last win and all other lose. |
Disruption | No disruption. |
Comment | File | Size | Author |
---|---|---|---|
#112 | 1358896-101-reroll.patch | 8.07 KB | SocialNicheGuru |
#101 | 1358896-101.patch | 8.38 KB | bceyssens |
| |||
#99 | 1358896-99.patch | 8.4 KB | bceyssens |
#96 | 1358896-96.patch | 8.37 KB | a.dmitriiev |
#95 | 1358896-95.patch | 8.37 KB | a.dmitriiev |
Comments
Comment #1
Dave ReidActually the better method would be to allow the stream wrappers themselves implement a getImageStyleUri() function and have image_style_path() return the result of that method if possible.
Comment #2
Dave ReidShould work something like
Comment #3
becw CreditAttribution: becw commentedThis would be super useful for anyone using remote stream wrappers. It would make it easy to create local derivatives for non-writable stream wrappers, and it would also allow core image styles to be automatically generated on stream wrappers that don't use file-path-like naming.
image_style_create_derivative()
will already create derivatives on non-local stream wrappers (by creating them in a remote location and copying them over).Comment #4
Dave ReidComment #5
Dave ReidInitial patch, very rough.
Comment #6
tms320c CreditAttribution: tms320c commentedI believe this comment may be useful here as well.
In short, style generation problem seems to rise from the hook_menu() implementation in image.module. If url path is not identical with path used by "public:" wrapper and is not "private", Drupal won't invoke image_style_deliver() callback.
I have implemented hook_menu() in my module and syles work after that. Of course, I tested it with very simple module, but I believe that if a wrapper is implemented correctly (see File API and PHP streams) it won't have problems with styles creation/deletion.
From the other hand, implementing special-puropse method like getImageStyleUri(), which serves very specific task in otherwise generic file system is arguable.
Comment #7
Dave ReidComment #8
benshell CreditAttribution: benshell commentedI've created a related patch where I took a different approach to figuring out where to store image derivatives: #1821166: Support image style derivatives using a different file scheme than the original image
Comment #9
claudiu.cristea@benshell, your approach is too particular and assume that all derivatives will use the same scheme.
Rerolled #5. If passes, we need to add an alteration point so that modules can decide to use different schemes for different image styles. Coming soon.
Comment #11
claudiu.cristeaLooking back to #9 it doesn't seems to me a good approach to let the stream wrapper define a policy for derivative location.
There's another approach that allows extending of
\Drupal\image\Plugin\Core\Entity\ImageStyle
in order to provide alteration of derivatives stream wrapper, path and even access: #2027423: Make image style system flexible.Comment #12
claudiu.cristeaMarking this as duplicate of #2027423: Make image style system flexible.
Comment #13
Dave ReidThere is still a valid need for at least an alter hook in Drupal 7 since the changes in #2027423: Make image style system flexible are not backportable at all. I also question the actual flexibility, because I know for a fact that in D7 now, there would be several different modules that would want to alter the way image styles are generated. With the current code in D8 the last module to override the image style generation class wins, and everyone else loses. Which is not flexible.
Comment #14
Dave ReidLet's start out a little simpler with just a new alter hook so that modules that want to change the image style path doesn't fail to invalid token.
Comment #15
claudiu.cristeaHere, the alterable is
$result
. The others ($style_name
and$uri
) are context variables. That said, why not passing as context everything that was previously processed inimage_style_path()
? I would go with this:This will assure that alter implementations will not have to recompute again
$scheme
and$path
.Also there's need for a new entry in docs:
image.api.php
with the newhook_image_style_path_alter()
.Let's add an empty line before
return
.Comment #16
deviantintegral CreditAttribution: deviantintegral at Lullabot for NBCUniversal commentedI ended up using the patch at #14 to support image styles in the amazons3 module. It's working pretty well, though it is a (mild) annoyance to be completely throwing out $result to recreate it in an alter hook.
I found this useful not just for managing the stream wrapper, but also for changing the entire URL. For S3, we have to ensure that there is always a bucket in the URL and don't have bare paths like s3://image.jpg. With this, I was able to do nearly all of the heavy lifting of image generation in contrib code without having to patch image module at all.
Comment #17
deviantintegral CreditAttribution: deviantintegral at Lullabot for NBCUniversal commentedAnyone following this might be interested in #2479523: Add a hook_file_stream_wrapper_uri_normalize_alter() hook too.
Comment #18
Dave ReidReviewing the original issue, we're going to want this alter hook for Drupal 8 as well.
Comment #21
tim520 CreditAttribution: tim520 commentedHi all,
I found error message in Watchdog : Amazon S3 was unable to create an image style derivative. Check the temporary directory configuration and permissions.
But some of my images could be generated correctly, some not.
What is wrong ?
Thanks
Comment #24
claudiu.cristeaAdded:
hook_image_style_uri_alter()
.hook_image_style_uri_alter()
.Comment #26
claudiu.cristeaComment #27
claudiu.cristeaGreen. Reassigning.
Comment #28
mondrake@claudiu.cristea, what about
ImageStyle::flush()
? If I am not mistaken, with the patch in #26 the altered URI can be anything, and therefore there is no guarantee that derivative images will be flushed. I think that at least the initial part of the altered URI should be enforced to be '{scheme}://styles/{style-name}' so that ::flush() can do its job.Comment #29
claudiu.cristea@mondrake, that we cannot do because we'll lose exactly the main point of this feature request. Modules should take care of their own flushing policy by implementing:
hook_image_style_flush()
.Comment #30
mondrakeAh yeah forgot about that... then maybe we need a comment in the hook docs to make clear that implementations should take care of flushing the custom directories. Also some test for altering URI to a totally arbitrary directory structure and that flushing actually removes it.
Comment #31
claudiu.cristea@mondrake, Just take a look at ImageStyle::flush(). He handles very well the flushing of derivatives inside Drupal. That's because he uses also ::buildUri() to detect the location of file that needs to be flushed. And ::buildUri() returns something already altered ;)
But, it's true that we need to add some docs for the cases when developers are altering the URIs to make them point outside Drupal (to Instagram, etc.)
Comment #32
mondrakeTrue, but only if a path to a image is passed (i.e. a single derivative needs to be flushed).
But if you are flushing (or updating) the ImageStyle entity, all the derivative images need to be flushed. This occurs by deleting the entire directory and all its files. And here ::buildUri() is not used, only the pattern {scheme}://styles/{style-name} for each writable scheme is deleted.
If, say, your unaltered URI is
public://styles/mystyle/public/field/image/bingo.png
and your altered URI is
public://mymodule/mystyle/bingo.png
then ImageStyle::flush itself will not remove the /mystyle directory from public://mymodule, with the consequence that the derivative images will be out of sync. So, that's where
hook_image_style_flush()
should also care about.Comment #33
claudiu.cristea@mondrake, yes, that makes sense. But implementing a whole testing scenario seems to much. I think, now, the docs are enough.
Comment #34
mondrakeFine with me, thanks. Leaving at NR for @Dave Reid.
Comment #36
mondrakeNitpicks:
"Append a different extension to the image file name, if the image style specifies so."
... before it is returned.
Comment #37
claudiu.cristeaThank you for these findings.
Comment #38
claudiu.cristeaOuch! Sorry, I didn't wanted to unassign.
Comment #42
mondrake@claudiu, I have been still thinking about #32.
Now we are building the URI and then pass it to the alter hook with the context.
What about if, instead, we pass, by reference, the components, like e.g. based on the example:
then, let the hook alter the components, and build the URI only after returning from the alters.
This way we could also add the same alter hook in
ImageStyle::flush
, and pass only scheme + basepath, for example something likeso that the flushing of the image style is covered the same way of the flushing of a single derivative?
Comment #43
Anonymous (not verified) CreditAttribution: Anonymous commentedI have created s3 wrapper for d8 and now im stuck with image derivatives :D
Comment #47
grndlvl CreditAttribution: grndlvl at GollyGood Software for Zivtech commentedRe-rolled against 8.3.x
Comment #49
orbistertius CreditAttribution: orbistertius as a volunteer commentedI was searching for a way to make image styles of a private image public. What you are doing here makes a lot of sence to me so please push this into the next release so I can create a module (my first d8 module) adding to the image style form a radio element "Storage as" with "same as original" (default), "public file" and "private file". What can I do to make this work go into core?
Comment #50
josephdpurcell CreditAttribution: josephdpurcell at Digital Bridge Solutions commentedI believe this issue addresses what was described #1903190: Allow image style derivatives of private images to be stored on the public file system.
Using Drupal 8.3.5 I was able to apply this patch and use the following hook to allow the watermark image style of an image field using private storage to have those watermarked images be available publicly:
So, the patch works!
I'm setting this to RTBC given that it has tests, works as described/meets requirements, and in my expedited review of the code I didn't find any obvious issues.
Comment #51
andypostComment #52
Wim LeersBunch of nits, plus missing CR.
s/uri/URI/
s/schema/scheme/
===
Comment #53
harsha012 CreditAttribution: harsha012 as a volunteer and at Red Crackle commentedfixed the nit picks and added the CR
https://www.drupal.org/node/2917669
Comment #54
orbistertius CreditAttribution: orbistertius as a volunteer commented#50 worked for me, hope to see this patch applied to the core soon.
Comment #55
claudiu.cristeaThese replacements were left out: s/uri/URI
Comment #56
harsha012 CreditAttribution: harsha012 as a volunteer and at Red Crackle commentedfixed nit picks #55
Comment #57
claudiu.cristeaThis issue has been RTBC'd in #50. Since #50 there were only nits fixes. I'm RTBCing back (only for the nits part #50 => #56).
I've also improved the change record.
Thank you for the work here.
Comment #58
Wim LeersSorry, once more:
Nit: "on a different scheme" sounds strange? In a different stream wrapper?
Doesn't this mean only writeable stream wrappers can be used?
See
\Drupal\Core\StreamWrapper\StreamWrapperInterface::WRITE
.s/uri/URI/
"in the public:// stream wrapper" seems kind of pointless to mention?
===
Let's use
ModuleHandlerInterface::class
, this is easier to refactor in the future.Comment #59
harsha012 CreditAttribution: harsha012 as a volunteer and at Red Crackle commentedWorked as per the nit picks
Comment #60
claudiu.cristeaI don't understand the "writable" thing. Probably we want to say: "Low resolution, watermarked images are available in the public readable stream wrapper."
The correct phrase would be: "The 'watermarked_low_resolution' derivatives are available publicly."
This should be:
Comment #61
harsha012 CreditAttribution: harsha012 as a volunteer and at Red Crackle commentedfixed as per #60
Comment #62
claudiu.cristeaThank you. RTBC for changes since #50.
Comment #63
larowlanHi
I discussed this with @catch and we're not hugely keen on having config entities fire alter hooks.
To try and understand why this is still needed, can we get an issue summary update here?
I see in #12 this was marked as a duplicate and in #13 it was moved to Drupal 7 only.
But then in #18 it was moved back to Drupal 8, but without mentioning why, in particular what the need is that can't be solved by #2027423: Make image style system flexible. I note it was tagged `Media initiative` at the same time, so can we get some information on how the two are related?
Can someone provide some examples of why this is needed - thanks.
Lee
Comment #66
mondrakeRelated, #2986669: Split ImageStyle into the config entity and a separate event-based image processing service
Comment #67
dpagini CreditAttribution: dpagini as a volunteer commentedHere's an attempt at a re-roll for 8.5.5 (and hopefully 8.6.x). I would be interested in the traction that the approach proposed by @mondrake gets, though...
Comment #68
AMDandy CreditAttribution: AMDandy commentedI've applied #67 against 8.5.6 and the paths are updated but the image is a 404. I've run drush if --all but they're still 404'ing. Did I miss a step?
Comment #70
PrineShazar CreditAttribution: PrineShazar commentedRe-rolling patch from dpagini for 8.7.x
Comment #72
xxronis CreditAttribution: xxronis as a volunteer commentedComment #74
xxronis CreditAttribution: xxronis as a volunteer commentedre-rolling the 8.8.x patch
Comment #76
vsujeetkumar CreditAttribution: vsujeetkumar at Srijan | A Material+ Company for Drupal India Association commentedRe-roll patch created for 9.1.x.
Comment #79
ThomasDik CreditAttribution: ThomasDik at Synetic commentedModified patch for 9.2.x.
Comment #81
vsujeetkumar CreditAttribution: vsujeetkumar at Srijan | A Material+ Company for Drupal India Association commentedFixed the fail tests, Please have a look.
Comment #82
vsujeetkumar CreditAttribution: vsujeetkumar at Srijan | A Material+ Company for Drupal India Association commentedInterdiff added.
Comment #83
Kevin.- CreditAttribution: Kevin.- at Synetic commentedRe-rolling patch for 9.3.x.
Comment #84
joachim CreditAttribution: joachim at Factorial GmbH commentedAdding a constructor to an entity class with DI seems a bit weird to me. Entity objects don't do DI, and I seem to remember the reasons involve something like serialisation.
That might not affect config entities, but still, there's no support for this in the Entity system yet.
Comment #85
ankithashettyUpdated patch in #83 with the changes suggested in #84, i.e., removed constructor from an entity class as it doesn't support DI.
Thanks!
Comment #88
a.dmitriiev CreditAttribution: a.dmitriiev as a volunteer and at 1xINTERNET commentedCleanup patch from #85 to not inject module handler service to ImageStyle in tests.
Comment #89
a.dmitriiev CreditAttribution: a.dmitriiev as a volunteer and at 1xINTERNET commentedComment #91
a.dmitriiev CreditAttribution: a.dmitriiev as a volunteer and at 1xINTERNET commentedThe tests are broken, because now the container is needed to be set in unit test because of \Drupal::moduleHandler() call.
Also, I've noticed that when accessing the url of the image derivative that was made public with a hook, but the original image is in private filesystem, the derivative itself is not automatically created, like it is done for images that are in public folder. Maybe there was something wrong with my NGINX settings, I will check more.
Comment #92
a.dmitriiev CreditAttribution: a.dmitriiev as a volunteer and at 1xINTERNET commentedFix unit tests
Comment #93
a.dmitriiev CreditAttribution: a.dmitriiev as a volunteer and at 1xINTERNET commentedComment #94
a.dmitriiev CreditAttribution: a.dmitriiev as a volunteer and at 1xINTERNET commentedI can confirm that in
web/core/modules/image/src/Controller/ImageStyleDownloadController.php
on line 160 the source of the image can't be found and controller throws an exception 'Error generating image, missing source file.' This happens when the private image has a public derivative url. So it means that the derivative is not created automatically like for "normal" image styles. I suggest to add here the alter hook. Or the concept of changing the url should be changed and it should be as a setting on ImageStyle entity to select the scheme of the derivative.Comment #95
a.dmitriiev CreditAttribution: a.dmitriiev as a volunteer and at 1xINTERNET commentedThis change includes automatic image derivative creation. Be aware that it also requires another alter hook, so that the original file uri can be restored to point for example to different scheme.
Comment #96
a.dmitriiev CreditAttribution: a.dmitriiev as a volunteer and at 1xINTERNET commentedRe-uploading the patch with fixed code standards
Comment #98
bceyssensAfter implementing the new alter hook, patch #96 seems to do the trick for us!
Comment #99
bceyssensRerolled patch against #96 for 9.4.3.
Comment #101
bceyssensRerolled patch against #96 for 9.5.0.
Comment #102
smustgrave CreditAttribution: smustgrave at Mobomo commentedTagging for CR update as a new api function
hook_image_style_source_alter
doesn't seem to be referencedAlso was previously tagged for IS update which may still need to happen
Did not test patch.
Comment #103
catchI hadn't seen this yet, it looks like the same use-case as #3354207: Allow image style derivatives to use a separate stream wrapper except that would just allow the stream wrapper to be configured. #3027639: Make css/js optimized assets path configurable shows what it looks like.
Comment #105
Dave ReidComment #106
djg_tram CreditAttribution: djg_tram commentedOh, dear me, a major showstopper and nothing has changed for years. :-( That hook would be desperately needed, up to the latest 10.1 and more... What could we do to make it happen ASAP?
Comment #107
djg_tram CreditAttribution: djg_tram commentedFor those who happen to be in my shoes: create a route subscriber and alter the route
image.style_private
to your own controller. CopyDrupal\image\Controller\ImageStyleDownloadController::deliver()
to it and modify it to either do something entirely different, or probably just handle your own case and callparent::deliver()
to get the original behavior.In my case, I mostly copied it in its entirety, leaving out where it calls the `hook_file_download_alter()` hook and doing by own permission based decision instead. YMMV.
Comment #108
fonant CreditAttribution: fonant commented@djg_tram - I can managed to get the derived image written to the public filesystem, but how do I tell Drupal to use the public URL for this image, rather than the private
/system/files/...
one?Comment #109
a.dmitriiev CreditAttribution: a.dmitriiev as a volunteer and at 1xINTERNET commented@fonant, if you use the patch and the hook, there is no need to do anything else. The uri of the image is changed for image style, so if it is public then the url will be for public scheme.
Comment #110
fonant CreditAttribution: fonant commented@a.dmitriiev thanks, I was wondering how @djg_tram had managed with his method.
I now have this working with the patch and a custom module with a hook. Needs a bit more work and some tidying before I post it here.
Comment #111
SocialNicheGuru CreditAttribution: SocialNicheGuru commentedNow that #2786735: Image derivative generation does not work if effect "Convert" in use and file stored in private filesystem patch in #101 no longer applies
Comment #112
SocialNicheGuru CreditAttribution: SocialNicheGuru commentedRerolled 101 to apply to Drupal 10.2.x with the commit, #2786735: Image derivative generation does not work if effect "Convert" in use and file stored in private filesystem which causes the conflict.
Comment #113
SocialNicheGuru CreditAttribution: SocialNicheGuru commentedI am testing it.
the uri has changed.
but i can't seem to get the image_style with the new public uri to be generated.
Should I add code to the hook to generate the image style
I used the example from the patch.
But I am unclear how can the image_style be generated once I rewrite the uri with the hook.
drush cr does not seem to be doing it
Comment #114
a.dmitriiev CreditAttribution: a.dmitriiev as a volunteer and at 1xINTERNET commentedI have the patch and this hook in a custom module.