In ColdFusion, how would you increase the canvas size of an image without actually stretching the image? I played with this today while eating my peanut butter and jelly (PB&J FTW) and came up with the following solution. The basic idea is pretty simple. You make a new image of the desired canvas size and then just paste in the old image. Here is a simple hard coded example.
<cfset img = "/Users/ray/Pictures/darth.jpg">
<cfset imgOb = imageNew(img)>
<cfset newWidth = "800">
<cfset newHeight = "800">
<cfset newImg = imageNew("", newWidth, newHeight, "rgb", "white")>
<cfset imagePaste(newImg, imgOb, 0, 0)>
<!--- make it easy to see the image --->
<body bgcolor="yellow">
<cfimage action="writeToBrowser" source="#newImg#">
I begin with my source image that is read into a proper image variable. I create my canvas (newImg) with the desired size. Lastly, I paste it in. Because I used a white background I spit out a yellow background on the page to make it stand out a bit more.
Here is the result - and forgive me - I'm feeling lazy. I resized it for the web page via HTML. If you click you will see the full image in all its glory.
It works, but what if we want to center the image in the canvas? We just need to add a bit of math.
<cfset img = "/Users/ray/Pictures/darth.jpg">
<cfset imgOb = imageNew(img)>
<cfset newWidth = "800">
<cfset newHeight = "800">
<cfset newImg = imageNew("", newWidth, newHeight, "rgb", "white")>
<!--- position it in the center --->
<cfset centerX = (newWidth - imgOb.width)/2>
<cfset centerY = (newHeight - imgOb.height)/2>
<cfset imagePaste(newImg, imgOb, centerX, centerY)>
<!--- make it easy to see the image --->
<body bgcolor="yellow">
<cfimage action="writeToBrowser" source="#newImg#">
Woot. I'm so happy I took all those calculus classes in college. The result is now centered:
Ok, so it works - but maybe we can make it a bit more abstract? Here is a simple UDF that lets you pass in an image, new dimensions, as well as a text-based position, and have it return the new image to you. It should probably use a dynamic color model, and it may barf if you use a smaller image, but it works with my simple tests.
<cffunction name="resizeCanvas" output="false">
<cfargument name="sourceImage" required="true" hint="Can be file, url, or image object.">
<cfargument name="newWidth" required="true" type="numeric" hint="New canvas width.">
<cfargument name="newHeight" required="true" type="numeric" hint="new canvas height.">
<cfargument name="canvasbackgroundcolor" required="false" type="string" hint="BG color for canvas." default="white">
<cfargument name="position" required="false" type="string" hint="Where is the image positioned. Values are TL (top left), TR, BL, BR, Center" default="center">
<cfset var img = "">
<cfset var canvas = "">
<cfset var centerX = "">
<cfset var centerY = "">
<!--- first, is our sourceImage a string or an ob? --->
<cfif not isImage(arguments.sourceImage)>
<cfset img = imageNew(arguments.sourceImage)>
<cfelse>
<cfset img = arguments.sourceImage>
</cfif>
<!--- now make our canvas --->
<cfset canvas = imageNew("", arguments.newWidth, arguments.newHeight, "rgb", arguments.canvasbackgroundcolor)>
<!--- where we paste is based on position --->
<cfswitch expression="#arguments.position#">
<!--- Top Left --->
<cfcase value="TL">
<cfset imagePaste(canvas, img, 0, 0)>
</cfcase>
<!--- Top Right --->
<cfcase value="TR">
<cfset imagePaste(canvas, img, arguments.newWidth - img.width, 0)>
</cfcase>
<!--- Bottom Right --->
<cfcase value="BR">
<cfset imagePaste(canvas, img, arguments.newWidth - img.width, arguments.newHeight - img.height)>
</cfcase>
<!--- Bottom Left --->
<cfcase value="BL">
<cfset imagePaste(canvas, img, 0, arguments.newHeight - img.height)>
</cfcase>
<!--- center --->
<cfdefaultcase>
<cfset centerX = (newWidth - img.width)/2>
<cfset centerY = (newHeight - img.height)/2>
<cfset imagePaste(canvas, img, centerX, centerY)>
</cfdefaultcase>
</cfswitch>
<cfreturn canvas>
</cffunction>
And some sample code to run it:
<cfset img = "/Users/ray/Pictures/darth.jpg">
<cfimage action="writeToBrowser" source="#resizeCanvas(img,500,500,'blue')#">
<cfimage action="writeToBrowser" source="#resizeCanvas(img,500,500,'blue','TR')#">
<cfimage action="writeToBrowser" source="#resizeCanvas(img,500,500,'blue','BR')#">
<cfimage action="writeToBrowser" source="#resizeCanvas(img,500,500,'blue','BL')#">
Which gives us this lovely montage:
Hopefully this will be helpful for others. I may need to add this to the imageUtils project.