Page 1 of 1

How to add a shadow to an image ?

Posted: 2011-11-19T17:53:41-07:00
by spok
I'm trying to write a function that adds a shadow to an image but it doesn't work.
Here is my code. The program crashes at the call of the MagickMergeImageLayers.
Any help ?
Thanks.

Code: Select all

void magickShadow (char * filename)
{ 	
	MagickWandGenesis(); 

	MagickWand * pic = NewMagickWand();
	MagickReadImage(pic,filename); 

	PixelWand *blackwand = NewPixelWand();
	PixelSetColor(blackwand,"black");

	PixelWand *whitewand = NewPixelWand();
	PixelSetColor(whitewand,"white");

	MagickWand * shadow = CloneMagickWand(pic);
	MagickSetImageBackgroundColor(shadow,blackwand);
      
	MagickShadowImage(shadow,90,30,100,100);
	MagickAddImage(shadow,pic);
	MagickSetImageBackgroundColor(shadow,whitewand);

	MagickWand * merge=MagickMergeImageLayers(shadow,MergeLayer); // !!! The program crashes here !!!

	MagickWriteImage(merge,filename);

	DestroyMagickWand(merge);
	DestroyMagickWand(shadow);
	DestroyMagickWand(pic); 
	DestroyPixelWand(blackwand);
	DestroyPixelWand(whitewand);
	
	MagickWandTerminus(); 
}

Re: How to add a shadow to an image ?

Posted: 2011-11-19T20:24:41-07:00
by magick
Add MagickResetIterator(shadow) right before the MagickMergeImageLayers() method call. In the mean-time we'll add a patch to ImageMagick to prevent the fault. Thanks.

Re: How to add a shadow to an image ?

Posted: 2011-11-20T02:19:23-07:00
by spok
Thank you. It doesn't crash now.
However it doesn't provide the result I'd like to obtain.

here is my new code :

Code: Select all


void magickShadow (char * filename)
{ 	
	MagickWandGenesis(); 

	PixelWand *ShadowColor = NewPixelWand(); 
	PixelSetColor(ShadowColor,"gray");
	
	PixelWand *BackgroundColor = NewPixelWand(); 
	PixelSetColor(BackgroundColor,"green");

	MagickWand * pic = NewMagickWand(); 
	MagickReadImage(pic,filename); 
	MagickSetImageBackgroundColor(pic,BackgroundColor);

	MagickWand * shadow = CloneMagickWand(pic); 
	MagickSetImageBackgroundColor(shadow,ShadowColor);
	MagickShadowImage(shadow,100,30,100,100);
    
	MagickAddImage(pic,shadow);

	MagickResetIterator(pic);
	MagickWand * merge=MagickMergeImageLayers(pic,MergeLayer);

	MagickWriteImage(merge,filename);

	DestroyMagickWand(merge);
	DestroyMagickWand(shadow);
	DestroyMagickWand(pic); 
	DestroyPixelWand(ShadowColor);
	DestroyPixelWand(BackgroundColor);
	
	MagickWandTerminus(); 
}


and here is the image it provides

Image

Of course it is not what I want.
I'd like the green background first, then above it, the gray shadow and then the pic.
So there is something I do in the wrong order.

If I swap the shadow and the pic like this :

Code: Select all

	MagickAddImage(shadow,pic);

	MagickResetIterator(shadow);
	MagickWand * merge=MagickMergeImageLayers(shadow,MergeLayer);
I obtain the following pic, which is neither what I want.

Image

Any help ? Thanks.

BTW I noticed that when the sigma parameter of the MagickShadowImage is relatively high (which produces the blur effect I want) it takes almost 20 secondes to process the image ! Is there any way to accelerate the process or is just too complex to calculate the blur shadow ?

Re: How to add a shadow to an image ?

Posted: 2011-11-20T09:51:44-07:00
by spok
Anyone can help please ?
I spent several hours on it without finding a solution.
Thanks.

Re: How to add a shadow to an image ?

Posted: 2011-11-21T01:58:40-07:00
by spok
I have finally found a solution inspired from the following thread (viewtopic.php?f=6&t=8140) and using MagickMosaicImages instead of MagickMergeImageLayers.
However the MagickResetIterator is still needed.
Here is the code.

Code: Select all

void magickShadow (char * filename)
{    
       MagickWandGenesis();

	PixelWand *ShadowColor       = NewPixelWand(); PixelSetColor(ShadowColor,"gray");
	PixelWand *BackgroundColor = NewPixelWand(); PixelSetColor(BackgroundColor,"white");

       MagickWand * pic = NewMagickWand(); MagickReadImage(pic,filename);

       MagickWand * shadow = NewMagickWand(); shadow=CloneMagickWand(pic);
       MagickSetImageBackgroundColor(shadow,ShadowColor);
       MagickShadowImage(shadow,100,30,100,100);

       MagickAddImage(shadow,pic);
       MagickResetIterator(shadow);
       MagickSetImageBackgroundColor(shadow,BackgroundColor);

       MagickWand * merge= MagickMosaicImages(shadow);

       MagickWriteImage(merge,filename);

	DestroyMagickWand(merge);
	DestroyMagickWand(pic);
       DestroyMagickWand(shadow);
       DestroyPixelWand(ShadowColor);
       DestroyPixelWand(BackgroundColor);
       
       MagickWandTerminus();
    }
and here is an example of the image it produces.

Image

Re: How to add a shadow to an image ?

Posted: 2011-11-21T03:10:40-07:00
by spok
I just tried the previous function with MagickMergeImageLayers instead of MagickMosaicImages and now it works !!!
Don't know what happened before...
Anyhow, you can replace MagickMosaicImages with MagickMergeImageLayers and it works.
Furthermore MagickMergeImageLayers allows to move the shadow easly around the image which seems to be not the case for MagickMosaicImages.

However, the shadow function is very slow if sigma is a little high.
Is there any way to make it faster ?

Re: How to add a shadow to an image ?

Posted: 2011-11-30T21:00:49-07:00
by anthony
The sigma function is a blur, and for large sigmas you get very large slow blurs.

The alternative is to DIY the problem and replace the blur step with a FFT blur. This uses a different method that is faster when large blurs are used....
http://www.imagemagick.org/Usage/fourier/#blurring

Of course you will need a separate pre-prepared 'blurring image' (gausian kernel) and figure out blurring using FFT from magick wand.

The actual DIY steps of shadowing is given in..
http://www.imagemagick.org/Usage/blur/#shadow_internals