How to add a shadow to an image ?

The MagickWand interface is a new high-level C API interface to ImageMagick core methods. We discourage the use of the core methods and encourage the use of this API instead. Post MagickWand questions, bug reports, and suggestions to this forum.
Post Reply
spok
Posts: 36
Joined: 2011-10-31T07:32:23-07:00
Authentication code: 8675308

How to add a shadow to an image ?

Post by spok » 2011-11-19T17:53:41-07:00

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(); 
}

User avatar
magick
Site Admin
Posts: 11040
Joined: 2003-05-31T11:32:55-07:00

Re: How to add a shadow to an image ?

Post by magick » 2011-11-19T20:24:41-07:00

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.

spok
Posts: 36
Joined: 2011-10-31T07:32:23-07:00
Authentication code: 8675308

Re: How to add a shadow to an image ?

Post by spok » 2011-11-20T02:19:23-07:00

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 ?

spok
Posts: 36
Joined: 2011-10-31T07:32:23-07:00
Authentication code: 8675308

Re: How to add a shadow to an image ?

Post by spok » 2011-11-20T09:51:44-07:00

Anyone can help please ?
I spent several hours on it without finding a solution.
Thanks.

spok
Posts: 36
Joined: 2011-10-31T07:32:23-07:00
Authentication code: 8675308

Re: How to add a shadow to an image ?

Post by spok » 2011-11-21T01:58:40-07:00

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

spok
Posts: 36
Joined: 2011-10-31T07:32:23-07:00
Authentication code: 8675308

Re: How to add a shadow to an image ?

Post by spok » 2011-11-21T03:10:40-07:00

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 ?

User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: How to add a shadow to an image ?

Post by anthony » 2011-11-30T21:00:49-07:00

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
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/

Post Reply