The effects provided by imagecache_actions are divided over 5 sub-modules that must be enabled separately for their effects to become visible. The sub-module an effect lives in is now not always logical but more based on historical or practical reasons like code reuse.

I would like to move the following effects;
aspect switcher from canvas to custom
change file format from color to custom
autorotate from autorotate to custom

This implies that we would have to rename custom to something more logical. A broader term that encompasses the above effects as well as its current effects (custom and subroutine). I can't come up with a good name now but terms that come up are meta, structural, system.

@dman:
- What do yo think of this idea
- Can you think of a good name for this sub-module?
- Are there other effects that could/should be moved? (image mask and rounded corners come to my mind as well as alpha transparency)

I will look into upgrade consequences and do the actual moving around of code.

Comments

dman’s picture

You are quite right that the grouping is historical and not at all planned.
At the time, the concern was to
* avoid a huge 5000-line file with everything in
* avoid bootstrapping all that code that would only get invoked less than 1% of the time
* Add some effects 'brand new' without disturbing existing code - autorotate was a stand-alone contribution that was adopted into the family.

Way back then, Drupal didn't have a history of using lazy-loaded plugin libraries - modules generally included all their own code and the idea of splitting things into inc files was new.
Some of the grouping was (as you've observed) to get a little code re-use inside a library - but thats just architectural choices for conditions that are no longer valid. A number of those needs have been ironed out, and I don't THINK there are any actions left that sneakily call each others routines (the overlay subroutine used to be a sneaky workhorse for a few other effects - but it's now being called through the API in all cases I think).
I didn't used to have a central imagecache_actions-core library of re-usable stuff then either.

TODAY, I think your suggestion is great - but we if refactoring, we may as well take it further.
When we can't find a good name for a group of actions, or clear reasons why something should be one place or another - it means that support & docs cannot be intuitive, and the grouping or distinction is probably unnecessary.
SO: Why not do it properly and

  • Bring all the action declarations back into a central module
  • split all the inc files off into separate libraries

I think the implications would be in how the existing image effects remember the module name that provides processes, so there will be a hook_upgrade needed there. This would be a major point release, so refactoring should probably be done in 7.x-2.x

I'm keen for this

fietserwin’s picture

Agree. Preferably I would like to come up with some plugin system, but as the various callbacks are quite different regarding who, when and how often they are called I think that we should not come up with 1 plugin class per effect but 2 or 3.

Admin related info in hook_image_effect_info() (called during image style editing):
- label
- help
- form callback
- summary theme

Creation related info in hook_image_effect_info() (called during (the 1 time) image derivative creation):
- effect callback related info in hook_image_effect_info()
- toolkit specific code via toolkit invoke()

Usage related info in hook_image_effect_info() (called during image derivative referencing: used on "every" page):
- dimensions passthrough
- dimensions callback

Thus, if the latter makes that all effect code is loaded on "every" page request we miss the goal of lazy loading.

We need a clear picture of how to:
- divide the callbacks over various plugins
- discovery (and registration) of (new) effects
- loading and calling plugins given the current way that the callbacks are called.

Shall we start by doing some further code clean up's in 7.x-1.x and in the meantime think about this plugin system? D8 based? Sandbox?

dman’s picture

Bah. Another reason to hate that dimensions callback.

I say no. We don't need another layer of plugin callback stuff just to deal with the *three* phases of effect hooks.
I see where you are going with this, but I feel that for the code we have here, the added overhead (and mental complexity) would be greater than what we save by trying to push things out into additional inc files.

I'd have to refresh my memory, but if the callback file can be defined adequately in the hook_image_effects_info, then we are probably OK still.
Edit: Damn, it's not. I must have been thinking of another thing.

Most of our effects - the actual processing part - are not more than a dozen lines ling. The admin forms for them are often quite a lot bigger than the job itself.
It's rare that the processing phase requires too much extra code - the alpha-pixel-blend routine is already in its own lazy-loaded lib - partly for efficiency, partly to split off externally-sourced contrib code.
And it will be really annoying if we had to maintain the dimensions callback in a separate place from the process callback. It's not worth trying to split those off.

> Thus, if the latter makes that all effect code is loaded on "every" page request we miss the goal of lazy loading.

I don't mind if the *process* code for one effect is loaded if it's required to get the *dimensions* calculation. The lazy-loading I care about is avoiding the process code for every available effect, even the unused ones being loaded all the time.
We have 20 effects but the site uses only 3. It's OK that all the related code for those three effects is bootstrapped, it's not great if all 20 are.
... and if we do proceed with splitting each effect into its own file - rather than the groups of 3 or 4 we have now - we will be winning there already! The greater granularity of individual effects will have better payoffs than trying to split the parts of each effect into phases. (I predict)

So, my attitude is
* The perfect is the enemy of the good.
* Avoid premature optimization (unless you are prepared to benchmark it)
* Don't sacrifice readability, maintainability, brevity or sanity for lazy-loading tricks

So if we can avoid doing our own plugin layer, lets leave it out. Ideally it should be driven from core (where the hook_info could define callback files).
As it is, I guess we still have to put some sort of delegator into the .module file to catch the requests coming from core and pass them on to the inc files. As long as the incoming arguments include the name of the effect somewhere, that can probably be done pretty cleanly.
Damn, I really was thinking that the core info would allow us to specify the code file...

Yes, any other cleanups can be done in the current branch first - I like to do housekeeping sort of stuff at this point also.
Changes that will require a proper hook_update - and that certainly will include renaming or moving filenames around - should be the next branch.

fietserwin’s picture

I guess you are right. But apart from lazy loading I would also like to ease the work one has to do to add a new effect. It should be so easy that it becomes a viable alternative for custom actions (no PHP in the database) and to get more production ready code posted here in the issue queue.

Next problem: the name of the effect is NOT passed to the callbacks, I already had an early look at that. This means that each callback can be handling only 1 effect, unless it can discriminate based on the data array (what I don;t want to).
What we could do is use hook_image_styles_alter(): this is called when all actual image styles with their effects and their data has been loaded and add the name of the effect as entry in the data array. This info is cached, so won't be executed too often and a clear cache in an update hook suffices to activate it.

Having this name we can have 1 callback per effect callback that loads the necessary file(s) and routes the callback further.

Suggestion: let's file an issue for D8 to add that name to all these callbacks: a simple backwards compatible API change. I think we are not too late for that yet. And as it is B.C. it can even be backported, but that will be more difficult to establish.

Short term:
- let's postpone the real work on this.
- release 7.x-1.2 (no open bugs in the issue queue at this moment, though some errors are listed in the code and in the readme).
- do some further code cleaning and have a look at all todo's in the code and simple and reasonable feature requests - - schedule a 7.x-1.3 release in another few months.

dman’s picture

Hm. It's a bugger that the name of the effect isn't immediately available. I guess we could insert it into the data consistently when settings are returned and pull it out later. Messy.
Your hook_image_styles_alter() idea would probably be a little cleaner than that.

To go to the other extreme, the system
* as it stands right now,
* and as it was initially set up in the imagecache days,
* and the way in which it is simplest to add just one more action any time you want ...

Is to have each effect in its own module. :-)

I know we all have an aversion to adding too many modules to the list ... but with the D7 registry cache, it's possibly even more efficient to have a dozen trivial modules than to try and force it all into one and then add our own autoloader abstraction into it anyway.
It could be that trying to group them into bigger packages at all is premature optimization with no demonstrable performance advantage.

Conceptually - one module : one effect - is clearly the easiest to develop and extend. It might be worth stepping back and giving that another think about.

fietserwin’s picture

My idea, in making it easy to add effects, was to take away the administrative code (hook_this, hook_that, .info file, .module file) and have people "only" complete 1 template file that contains clear instructions and sample code. OTOH: there will always be edge cases that need more code, examples: hook_exit() in text, hook_image_style_flush() for subroutine and aspect switcher.

I'll think about it again.

fietserwin’s picture

with #1821854: Convert image effects into plugins on its way, I think we should/will postpone most of this to D8. I don't think it will be a good use of our time to do something similar yet in D7.

dman’s picture

Status: Active » Postponed

fair enough

fietserwin’s picture

I'm thinking of trying to convert our image effects to some kind of D8 plugin lookalikes to ease the conversion of D7 to D8 and simultaneous maintenance (on both versions) after that. I will come back to this after some tries.

BTW: Do you have any thoughts on #2073759: Convert toolkit operations to plugins.

dman’s picture

I know what you mean. Yeah,it could be worth a try, though I don't know what shape D8 plugins are.
If it means a big OO rewrite, it could be scary. But I agree, if there is any refactoring, it should be to move in the direction of what it has to be in the future

fietserwin’s picture

Issue summary: View changes
Status: Postponed » Closed (won't fix)

No longer for D7. D8 effects are plugins, only loaded when needed, so reorganizing there is no longer needed.