Hi dman,

I've spent some time this afternoon trying to create an imagecache action that simulates Photoshop's 'Overlay' blend mode (when used for a single colour). This allows an image tint to be applied without loosing the contrast in your images...

Here is the code for this Custom Action - I'd love to see this made into another ImageCache Actions action at some stage. When I have more time I'll have to dig in to your code and work out how to do this myself (and commit).

I hope other Drupalers find this useful! :-)

-sydneyshan
Enigma Digital, Australia


$color = '#DDB9A6';

imagealphablending($image->resource, true);
imagesavealpha($image->resource, true);

$w = $image->info['width'];
$h = $image->info['height'];

$color = preg_replace('/^#/','',$color); //Get rid of "#" if it's there
$r_overlay = hexdec("0x{$color[0]}{$color[1]}");
$g_overlay = hexdec("0x{$color[2]}{$color[3]}");
$b_overlay = hexdec("0x{$color[4]}{$color[5]}");

for($y=0;$y<$h;$y++) {
      for($x=0;$x<$w;$x++) {
         $rgb = imagecolorat($image->resource, $x, $y);
         $r_source = ($rgb >> 16) & 0xFF;
         $g_source = ($rgb >> 8) & 0xFF;
         $b_source = $rgb & 0xFF;

         if($r_source <= 128){
            $final_r = (2 * $r_source * $r_overlay)/256;
         }else{
            $final_r = 255 - (((255 - (2 * ($r_source - 128))) * (255 - $r_overlay))/256);
         }
         if($g_source <= 128){
            $final_g = (2 * $g_source * $g_overlay)/256;
         }else{
            $final_g = 255 - (((255 - (2 * ($g_source - 128))) * (255 - $g_overlay))/256);
         }
         if($b_source <= 128){
            $final_b = (2 * $b_source * $b_overlay)/256;
         }else{
            $final_b = 255 - (((255 - (2 * ($b_source - 128))) * (255 - $b_overlay))/256);
         }
         $final_colour = imagecolorallocate($image->resource, $final_r, $final_g, $final_b);
         imagesetpixel($image->resource, $x, $y, $final_colour);
      }
}

return $image;

See attached images for results...

Original image: imagecache-actions-overlay-0.png
With overlay code applied: imagecache-actions-overlay-1.png
With desaturate and overlay code applied: imagecache-actions-overlay-2.png

Comments

sydneyshan’s picture

PS: credit to http://www.gamedev.net/blog/862/entry-2249668-pixel-blend-mode-algorithm... for providing the basics of the algorithm.

dman’s picture

Well, it looks like a good sort of algorithm - importantly, the contributed code is done in the right way and does what it intends.
( there is a small utility imagecache_actions_hex2rgba() for translating colors ... but it would only save you three lines in this case)

It's just - I don't have the visual acuity or the terminology to tell what this process is doing that's different from the cheap 'colorize' (GD colorshift) behavior. I'm sure it is - but I can't describe what.
The default 'colorshift' sure does turn out muddier than your version.

Adding it as a plugin is quite possible, though it could be good to use to the actual imageapi module for reference over my own examples here. OTOH, copying from examples is a lot easier.
Based on my own trial & error, I documented (notes-to-self) in imagecache_canvasactions.module:

* Notes about imagecache action extensions. For each action:
 * 1: Impliment imagecache_HOOK_form($formdata) to define the config form.
 * 1a: Impliment theme_imagecache_HOOK_form if needed - optional
 * 2: Impliment imagecache_HOOK_image(&$image, $data) to DO the process
 * 3: Impliment theme_imagecache_HOOK($element) to return a text description of
 * the setting
 * 4: Declare the action in HOOK_imagecache_actions()
 *
 *
 * API ref for hook_image()
 *
 * @param $image array defining an image file, including  :
 *   $image- >source as the filename,
 *   $image->info array
 *   $image->resource handle on the image object
 *
 * @param $action array of settings as defined in your form.
 *
 */
sydneyshan’s picture

StatusFileSize
new282.35 KB

Hey dman,

To explain, (from http://www.northlite.net/ps/blend.htm):

Screen: brightens the image by lightning the lower layer based on the lightness of the upper layer.
Multiply: darkens the lower layer based on the darkenss of the upper layer. No part of the image will get lighter. Any applied tone darker than white darkens the lower layer. White becomes transparent.

Overlay: Overlay multiplies the light colors and screens the dark colors.

So essentially, Overlay allows us to apply a colour tint to an image without loosing the blacks/darks or whites/lights.

I've attached what the 'Color Shift' imagecache action does to the original image using the same colour #DDB9A6 (unusable!).

I'm contemplating turning this in to a suite of actions - overlay image, overlay colour, screen image, screen colour, multipy image, multiply colour (maybe more). Would you prefer these to be attached to your project Imagecache Actions, or contributed as a separate project?

-sydneyshan
Enigma Digital, Australia

dman’s picture

It sounds like you have a handle on what these effects are really all about. I've never quite got the terminology myself.
I reckon I'd be interested in opening up coloractions.module for a few contributions like this, and I wouldn't mind having someone else on board with this project.

Bear in mind, that performance can be a huge thing with imagecache & actions, and the per-pixel transforms are pretty expensive.
Also, as soon as you do it in GD, some folk will want it in ImageMagick as well, which is an entirely different story (though probably already has what you want and does it better - once you figure out the magic word)

dman’s picture

I've given you git access, so feel free to merge your versions into coloractions when you can

sydneyshan’s picture

Thanks dman,

I'm in the process of getting up to speed on the whole git approach to contribution. Whilst I've been working with PHP for 12 years or so I haven't used any version control/collaborative tools to date (beyond simple patch generation). This is a good catalyst for me to learn to do so.

I don't mind looking in to the ImageMagick side of things - I've dealt with it a number of times to do some pretty tricky stuff (generating GIF animations with optimised colour tables). I think this gives a good start: http://www.imagemagick.org/Usage/compose/#overlay

I'll check back shortly when I've got my local dev environment equipped for git contribution.

sydneyshan’s picture

Assigned: Unassigned » sydneyshan
Status: Active » Fixed

This has now been committed to the 6.x-2.x-dev branch. Sweet - my first git commit!

sydneyshan’s picture

Status: Fixed » Closed (fixed)
tkeppens’s picture

Can you explain in a few words how to use/apply the overlay effect that you added? I downloaded the dev version, but whey I add an "Overlay: source image to canvas" action I just get a blank preview image.

Thanks in advance!

sydneyshan’s picture

Hi Toon,

The Overlay Source Image to Canvas is a different imagecache action than the one seen above in this thread. This action simply performs a colour tint using the 'overlay' algorithm.

Sydneyshan

tkeppens’s picture

Hey Shannon,

Thanks for getting back to me. The effect I need *is* the effect of this thread, I just don't see how to configure imagecache to overlay an image with another image, which is a result of a previous action.

Imagine these steps:

1. 'Take' the source image
2. Duplicatie the source image and alter brightness & color tint
3. Overlay the source image with this duplicate

I figure from this thread that it's possible, just don't see how.. :)

Any help would be greatly appreciated!

Thanks.

dman’s picture

What you describe is not possible through the imagecache pipeline, though you could make it happen using custom_action code.
If you want to "alter brightness & color tint" of the source image, I can't see why you find step 1 & 3 necessary.

It's not straightforward through the UI to split off multiple canvases, change them and recombine. There is basically one working canvas at one time.

sydneyshan’s picture

Hi tkeppens,

I wonder if you could achieve what you're trying to do with some clever usage of imagecache URLs...?

ie

http://www.mitchelhanlon.com.au/sites/default/files/imagecache/homepage-...

This would theoretically take the pre-rendered image from /sites/default/files/staff-photo/mitchel_hanlon.jpg, process it with the 'staff-photo' imagecache preset, then process it with the 'homepage-image' imagecache preset. I don't know what would happen if the the source imagecache-generated image did not exist.

There may also be a module out there to combine multiple imagecache profiles for a desired output... dman?

dman’s picture

I thought about that solution, however, describing how exactly to do it is harder than just doing it. So, eek.
Um, you do have the ability to call subfunctions and re-use other processes with the custom_action php code, and that's the way to start.
A lightweight example of how to call another preset is described at http://drupal.org/node/1114948#comment-4306146

Some assembly required.

In short, this exact scenario being described in #11 is really hard to build a UI for (as it would have to include parameters for alignment and transparancy and ?? other actions in the mix to make it useful) so - this is where you get to use php code to get your desired result. Scan the existing action callbacks for some examples of how to do what you want, but I just do not understand - from this description - why or what result you are looking for. So use PHP code to just do it.