I'm definitely not the first person to do this - but I've been itching to do drop shadows ever since I started playing with ColdFusion 8's new image functionality. My UDF is rather simple. It takes an image and duplicates it. It fills the canvas with white - and than adds an offset black square the same size as the original image. It does a blur, and then pastes on the original image.
That by itself isn't too interesting, but what was interesting is why I had to duplicate the original image. When I first wrote the code, I simply used imageNew. However, whenever I tried to imageOverlay the original image onto the new one, I got:
Overlay operation requires the two sources to match in number of bands and data type.
Stumped - I dumped imageInfo on both. I wasn't sure what bands meant - but colormode_type on my original image was "ComponentColorModel" ,and the value in my new image made from scratch was "PackedColorModel". That made as much sense to me as arithmetic would make to Paris Hilton. So for the heck of it, I just tried imageNew using ARGB. I figured grayscale wouldn't work. Using ARGB didn't help at all. So does anyone know how you would make an image from scratch that would work with a (as far as I know) average JPG? The code is pasted at the very bottom. Let me show some examples of the output. First the original image.
Writing PHP is hard!
1 <cfset myimage=makeShadow("sadgirl.jpg",5,5)>
2 <cfimage action="writeToBrowser" source="#myimage#">
2 <cfimage action="writeToBrowser" source="#myimage#">
.Net makes Mommy and Daddy fight.
1 <cfset myimage=makeShadow("sadgirl.jpg",5,5, "90,0,0")>
2 <cfimage action="writeToBrowser" source="#myimage#">
2 <cfimage action="writeToBrowser" source="#myimage#">
Rails broke all my toys and Ruby killed my dog!
1 <cffunction name="makeShadow" returnType="any" output="false">
2 <cfargument name="image" type="any" required="true">
3 <cfargument name="offset" type="numeric" required="true">
4 <cfargument name="blur" type="numeric" required="true">
5 <cfargument name="shadowcol" type="string" required="false" default="145,145,145">
6 <cfargument name="backgroundcol" type="string" required="false" default="white">
7
8 <cfset var newwidth = "">
9 <cfset var newheight = "">
10 <cfset var shadow = "">
11
12 <!--- if not image, assume path --->
13 <cfif not isImage(arguments.image) and not isImageFile(arguments.image)>
14 <cfthrow message="The value passed to makeShadow was not an image.">
15 </cfif>
16
17 <cfif isImageFile(arguments.image)>
18 <cfset arguments.image = imageRead(arguments.image)>
19 </cfif>
20
21 <cfset newwidth = arguments.image.width + (2*offset)>
22 <cfset newheight = arguments.image.height + (2*offset)>
23
24 <!--- make a black image the same size as orig --->
25 <cfset shadow = duplicate(arguments.image)>
26 <cfset imageResize(shadow, newwidth, newheight)>
27 <cfset imageSetDrawingColor(shadow,arguments.backgroundcol)>
28 <cfset imageDrawRect(shadow, 0, 0, newwidth, newheight, true)>
29 <cfset imageSetDrawingColor(shadow,arguments.shadowcol)>
30 <cfset imageDrawRect(shadow, arguments.offset, arguments.offset, arguments.image.width, arguments.image.height, true)>
31
32 <cfset imageBlur(shadow, arguments.blur)>
33
34 <!--- copy orig --->
35 <cfset imagePaste(shadow,arguments.image,0,0)>
36
37 <cfreturn shadow>
38 </cffunction>
2 <cfargument name="image" type="any" required="true">
3 <cfargument name="offset" type="numeric" required="true">
4 <cfargument name="blur" type="numeric" required="true">
5 <cfargument name="shadowcol" type="string" required="false" default="145,145,145">
6 <cfargument name="backgroundcol" type="string" required="false" default="white">
7
8 <cfset var newwidth = "">
9 <cfset var newheight = "">
10 <cfset var shadow = "">
11
12 <!--- if not image, assume path --->
13 <cfif not isImage(arguments.image) and not isImageFile(arguments.image)>
14 <cfthrow message="The value passed to makeShadow was not an image.">
15 </cfif>
16
17 <cfif isImageFile(arguments.image)>
18 <cfset arguments.image = imageRead(arguments.image)>
19 </cfif>
20
21 <cfset newwidth = arguments.image.width + (2*offset)>
22 <cfset newheight = arguments.image.height + (2*offset)>
23
24 <!--- make a black image the same size as orig --->
25 <cfset shadow = duplicate(arguments.image)>
26 <cfset imageResize(shadow, newwidth, newheight)>
27 <cfset imageSetDrawingColor(shadow,arguments.backgroundcol)>
28 <cfset imageDrawRect(shadow, 0, 0, newwidth, newheight, true)>
29 <cfset imageSetDrawingColor(shadow,arguments.shadowcol)>
30 <cfset imageDrawRect(shadow, arguments.offset, arguments.offset, arguments.image.width, arguments.image.height, true)>
31
32 <cfset imageBlur(shadow, arguments.blur)>
33
34 <!--- copy orig --->
35 <cfset imagePaste(shadow,arguments.image,0,0)>
36
37 <cfreturn shadow>
38 </cffunction>
Comment 1 written by Michael McConnell on 10 October 2007, at 4:33 PM
Comment 2 written by Dave Dugdale on 10 October 2007, at 5:11 PM
Comment 3 written by Sana on 10 October 2007, at 5:14 PM
Could you send more than one images to browser at a time; like this,
<cfset myimage=makeShadow("sadgirl1.jpg",5,5, "90,0,0")>
<cfimage action="writeToBrowser" source="#myimage#">
<cfset myimage=makeShadow("sadgirl2.jpg",5,5, "90,0,0")>
<cfimage action="writeToBrowser" source="#myimage#">
.NET is far more powerfull than JAI, I would suggest have a look to APIs
System.Drawing.Imaging
System.Drawing
no doubt that CF is cool, but certainly not in every functionality.
Thanks
Comment 4 written by Raymond Camden on 10 October 2007, at 5:23 PM
1) Yes, you can use N writeToBrowser actions in one request.
2) Heh, well, you have to remember that CF's image stuff is a layer on top of the lower level code (not sure if it is JAI, I assume it is). CF lets you use Dot Net as easily as Java. So I could use either of them. But the point is - 99% of what I need is covered in the functions CFML gives me. That's where the real power is. I mean - have you seen other CF Image demos? It truly is simple to work with images.
Comment 5 written by James Edmunds on 10 October 2007, at 6:41 PM
Comment 6 written by Raymond Camden on 10 October 2007, at 7:50 PM
Comment 7 written by Jon Hartmann on 10 October 2007, at 8:22 PM
Comment 8 written by Jeff Self on 11 October 2007, at 7:59 AM
It could be argued that ImageMagick is more powerful than .Net's imaging stuff. ImageMagick can be used by Ruby, PHP, and even Java. And I'm guessing that it would be possible to use ImageMagick with ColdFusion as well.
And ColdFusion could possibly get much more powerful features with imaging in the next release. After all, who owns ColdFusion? And aren't they known for having some photo software?
I'm sure .Net is a good development platform, but until it runs on a Mac or Linux (yes I know about Mono), many of us aren't interested in it. We prefer development environments that run on more than a single platform.
Just my opinion.
Comment 9 written by Raymond Camden on 11 October 2007, at 8:07 AM
Comment 10 written by Connie DeCinko on 27 April 2009, at 2:52 PM
Did you resolve the issue with this error?
Overlay operation requires the two sources to match in number of bands and data type.
Comment 11 written by Raymond Camden on 27 April 2009, at 4:04 PM
Comment 12 written by Gavy on 24 May 2009, at 1:33 AM
<cfset imagePaste(shadow,arguments.image,0,0)>
to paste the image on to the browser. What if we need to store image in the folder. do we need to use the filewrite function even if the cfimage latest patch is applied.
using of getimagebytes (undocumented feature) and the filewrite function to make it work.
Comment 13 written by Raymond Camden on 24 May 2009, at 7:54 AM
Comment 14 written by Dani on 17 October 2009, at 12:32 AM
Ray, is there any way to get a transparent background instead of a white one?
Thanks!!
Comment 15 written by Raymond Camden on 17 October 2009, at 8:33 AM
Comment 16 written by Dani on 17 October 2009, at 9:40 AM
What I do set the transparency to the color, not to the white background. I guess I'm a little bit confused.
Thanks Ray.
Comment 17 written by Dani on 17 October 2009, at 10:00 AM
Dani
Comment 18 written by Raymond Camden on 18 October 2009, at 9:39 AM
Comment 19 written by Dani on 18 October 2009, at 10:24 AM
I fact, looking at your blog, that is exactly what I want. Each comment looks like is above the background, it doesn't look flat. If I'm not wrong, I see a drop shadow at the lower right corner. The problem is that I can't create a graphic because each image has a different size (are paintings).
This is where I would like to apply it:
http://www.thiezmultimedia.com/catherine/en/index....
The drop shadow would go instead of the frame around the painting.
Thanks Ray for your time.
Comment 20 written by Raymond Camden on 18 October 2009, at 10:46 PM
Comment 21 written by Ali on 19 October 2009, at 10:47 AM
I have a design that requires a couple of images to have the shadow top-right
Thanks
Comment 22 written by Raymond Camden on 19 October 2009, at 10:52 AM
Comment 23 written by Ali on 19 October 2009, at 11:16 AM
Comment 24 written by Jim Gibson on 27 November 2009, at 10:42 AM
Comment 25 written by Jim Gibson on 27 November 2009, at 11:22 AM
Comment 26 written by Amer Ghalayini on 7 December 2009, at 6:41 AM
Comment 27 written by Daniel Gaspar on 11 December 2009, at 10:42 AM
The only way I could get this to work when using the imageNew() function is by saving the new image to a temp directory then loading it again.
<cfset MyTempImage = imageNew('','400','400','rgb','FFFFFF') />
<cfset ImageWrite(MyTempImage,GetTempDirectory()&'MyTempImage.jpg','.99') />
<cfset MyTempImage = ImageRead(GetTempDirectory()&'MyTempImage.jpg') />
This is with CF 8. Kind of a hack and feels like yet another CF 'gotcha'. (like isDefined("session.myVar")!).
Anyone else find a better way around this?
-Dan
Comment 28 written by Daniel Gaspar on 14 December 2009, at 4:15 PM
[Add Comment] [Subscribe to Comments]