PageRenderTime 34ms CodeModel.GetById 18ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 1ms

/source/Plug-in/fck/editor/filemanager/connectors/cfm/image.cfc

http://prosporous.googlecode.com/
ColdFusion CFScript | 1325 lines | 1131 code | 164 blank | 30 comment | 72 complexity | 4e1749eea2fde2453af354e9eb38d0e3 MD5 | raw file
   1<!---
   2	image.cfc v2.19, written by Rick Root (rick@webworksllc.com)
   3	Derivative of work originally done originally by James Dew.
   4
   5	Related Web Sites:
   6	- http://www.opensourcecf.com/imagecfc (home page)
   7	- http://www.cfopen.org/projects/imagecfc (project page)
   8
   9	LICENSE
  10	-------
  11	Copyright (c) 2007, Rick Root <rick@webworksllc.com>
  12	All rights reserved.
  13
  14	Redistribution and use in source and binary forms, with or
  15	without modification, are permitted provided that the
  16	following conditions are met:
  17
  18	- Redistributions of source code must retain the above
  19	  copyright notice, this list of conditions and the
  20	  following disclaimer.
  21	- Redistributions in binary form must reproduce the above
  22	  copyright notice, this list of conditions and the
  23	  following disclaimer in the documentation and/or other
  24	  materials provided with the distribution.
  25	- Neither the name of the Webworks, LLC. nor the names of
  26	  its contributors may be used to endorse or promote products
  27	  derived from this software without specific prior written
  28	  permission.
  29
  30	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  31	CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  32	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  33	MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  34	DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  35	CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  36	SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  37	BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  38	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  39	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  40	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  41	OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  42	SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  43
  44	============================================================
  45	This is a derivative work.  Following is the original
  46	Copyright notice.
  47	============================================================
  48
  49	Copyright (c) 2004 James F. Dew <jdew@yggdrasil.ca>
  50
  51	Permission to use, copy, modify, and distribute this software for any
  52	purpose with or without fee is hereby granted, provided that the above
  53	copyright notice and this permission notice appear in all copies.
  54
  55	THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  56	WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  57	MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  58	ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  59	WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  60	ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  61	OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  62--->
  63<!---
  64	SPECIAL NOTE FOR HEADLESS SYSTEMS
  65	---------------------------------
  66	If you get a "cannot connect to X11 server" when running certain
  67	parts of this component under Bluedragon (Linux), you must
  68	add "-Djava.awt.headless=true" to the java startup line in
  69	<bluedragon>/bin/StartBluedragon.sh.  This isssue is discussed
  70	in the Bluedragon Installation Guide section 3.8.1 for
  71	Bluedragon 6.2.1.
  72
  73	Bluedragon may also report a ClassNotFound exception when trying
  74	to instantiate the java.awt.image.BufferedImage class.  This is
  75	most likely the same issue.
  76
  77	If you get "This graphics environment can be used only in the
  78	software emulation mode" when calling certain parts of this
  79	component under Coldfusion MX, you should refer to Technote
  80	ID #18747:  http://www.macromedia.com/go/tn_18747
  81--->
  82
  83<cfcomponent displayname="Image">
  84
  85<cfset variables.throwOnError = "Yes">
  86<cfset variables.defaultJpegCompression = "90">
  87<cfset variables.interpolation = "bicubic">
  88<cfset variables.textAntiAliasing = "Yes">
  89<cfset variables.tempDirectory = "#expandPath(".")#">
  90
  91<cfset variables.javanulls = "no">
  92<cftry>
  93	<cfset nullvalue = javacast("null","")>
  94	<cfset variables.javanulls = "yes">
  95	<cfcatch type="any">
  96		<cfset variables.javanulls = "no">
  97		<!--- javacast null not supported, so filters won't work --->
  98	</cfcatch>
  99</cftry>
 100<!---
 101<cfif javanulls>
 102	<cfset variables.blurFilter = createObject("component","blurFilter")>
 103	<cfset variables.sharpenFilter = createObject("component","sharpenFilter")>
 104	<cfset variables.posterizeFilter = createObject("component","posterizeFilter")>
 105</cfif>
 106--->
 107
 108<cfset variables.Math = createobject("java", "java.lang.Math")>
 109<cfset variables.arrObj = createobject("java", "java.lang.reflect.Array")>
 110<cfset variables.floatClass = createobject("java", "java.lang.Float").TYPE>
 111<cfset variables.intClass = createobject("java", "java.lang.Integer").TYPE>
 112<cfset variables.shortClass = createobject("java", "java.lang.Short").TYPE>
 113
 114<cffunction name="getImageInfo" access="public" output="true" returntype="struct" hint="Rotate an image (+/-)90, (+/-)180, or (+/-)270 degrees.">
 115	<cfargument name="objImage" required="yes" type="Any">
 116	<cfargument name="inputFile" required="yes" type="string">
 117
 118	<cfset var retVal = StructNew()>
 119	<cfset var loadImage = StructNew()>
 120	<cfset var img = "">
 121
 122	<cfset retVal.errorCode = 0>
 123	<cfset retVal.errorMessage = "">
 124
 125	<cfif inputFile neq "">
 126		<cfset loadImage = readImage(inputFile, "NO")>
 127		<cfif loadImage.errorCode is 0>
 128			<cfset img = loadImage.img>
 129		<cfelse>
 130			<cfset retVal = throw(loadImage.errorMessage)>
 131			<cfreturn retVal>
 132		</cfif>
 133		<cfset retVal.metaData = getImageMetadata(loadImage.inFile)>
 134	<cfelse>
 135		<cfset img = objImage>
 136		<cfset retVal.metadata = getImageMetadata("")>
 137	</cfif>
 138	<cftry>
 139		<cfset retVal.width = img.getWidth()>
 140		<cfset retVal.height = img.getHeight()>
 141		<cfset retVal.colorModel = img.getColorModel().toString()>
 142		<cfset retVal.colorspace = img.getColorModel().getColorSpace().toString()>
 143		<cfset retVal.objColorModel = img.getColorModel()>
 144		<cfset retVal.objColorspace = img.getColorModel().getColorSpace()>
 145		<cfset retVal.sampleModel = img.getSampleModel().toString()>
 146		<cfset retVal.imageType = img.getType()>
 147		<cfset retVal.misc = img.toString()>
 148		<cfset retVal.canModify = true>
 149		<cfreturn retVal>
 150		<cfcatch type="any">
 151			<cfset retVal = throw( "#cfcatch.message#: #cfcatch.detail#")>
 152			<cfreturn retVal>
 153		</cfcatch>
 154	</cftry>
 155</cffunction>
 156
 157<cffunction name="getImageMetadata" access="private" output="false" returntype="query">
 158	<cfargument name="inFile" required="yes" type="Any"><!--- java.io.File --->
 159
 160	<cfset var retQry = queryNew("dirName,tagName,tagValue")>
 161	<cfset var paths = arrayNew(1)>
 162	<cfset var loader = "">
 163	<cfset var JpegMetadatareader = "">
 164	<cfset var myMetadata = "">
 165	<cfset var directories = "">
 166	<cfset var currentDirectory = "">
 167	<cfset var tags = "">
 168	<cfset var currentTag = "">
 169	<cfset var tagName = "">
 170
 171	<cftry>
 172	<cfscript>
 173		paths = arrayNew(1);
 174		paths[1] = expandPath("metadata-extractor-2.3.1.jar");
 175		loader = createObject("component", "javaloader.JavaLoader").init(paths);
 176
 177		//at this stage we only have access to the class, but we don't have an instance
 178		JpegMetadataReader = loader.create("com.drew.imaging.jpeg.JpegMetadataReader");
 179
 180		myMetaData = JpegMetadataReader.readMetadata(inFile);
 181		directories = myMetaData.getDirectoryIterator();
 182		while (directories.hasNext()) {
 183			currentDirectory = directories.next();
 184			tags = currentDirectory.getTagIterator();
 185			while (tags.hasNext()) {
 186				currentTag = tags.next();
 187				if (currentTag.getTagName() DOES NOT CONTAIN "Unknown") { //leave out the junk data
 188					queryAddRow(retQry);
 189					querySetCell(retQry,"dirName",replace(currentTag.getDirectoryName(),' ','_','ALL'));
 190					tagName = replace(currentTag.getTagName(),' ','','ALL');
 191					tagName = replace(tagName,'/','','ALL');
 192					querySetCell(retQry,"tagName",tagName);
 193					querySetCell(retQry,"tagValue",currentTag.getDescription());
 194				}
 195			}
 196		}
 197		return retQry;
 198		</cfscript>
 199		<cfcatch type="any">
 200			<cfreturn retQry />
 201		</cfcatch>
 202	</cftry>
 203</cffunction>
 204
 205<cffunction name="flipHorizontal" access="public" output="true" returntype="struct" hint="Flip an image horizontally.">
 206	<cfargument name="objImage" required="yes" type="Any">
 207	<cfargument name="inputFile" required="yes" type="string">
 208	<cfargument name="outputFile" required="yes" type="string">
 209	<cfargument name="jpegCompression" required="no" type="numeric" default="#variables.defaultJpegCompression#">
 210
 211	<cfreturn flipflop(objImage, inputFile, outputFile, "horizontal", jpegCompression)>
 212</cffunction>
 213
 214<cffunction name="flipVertical" access="public" output="true" returntype="struct" hint="Flop an image vertically.">
 215	<cfargument name="objImage" required="yes" type="Any">
 216	<cfargument name="inputFile" required="yes" type="string">
 217	<cfargument name="outputFile" required="yes" type="string">
 218	<cfargument name="jpegCompression" required="no" type="numeric" default="#variables.defaultJpegCompression#">
 219
 220	<cfreturn flipflop(objImage, inputFile, outputFile, "vertical", jpegCompression)>
 221</cffunction>
 222
 223<cffunction name="scaleWidth" access="public" output="true" returntype="struct" hint="Scale an image to a specific width.">
 224	<cfargument name="objImage" required="yes" type="Any">
 225	<cfargument name="inputFile" required="yes" type="string">
 226	<cfargument name="outputFile" required="yes" type="string">
 227	<cfargument name="newWidth" required="yes" type="numeric">
 228	<cfargument name="jpegCompression" required="no" type="numeric" default="#variables.defaultJpegCompression#">
 229
 230	<cfreturn resize(objImage, inputFile, outputFile, newWidth, 0, "false", "false", jpegCompression)>
 231</cffunction>
 232
 233<cffunction name="scaleHeight" access="public" output="true" returntype="struct" hint="Scale an image to a specific height.">
 234	<cfargument name="objImage" required="yes" type="Any">
 235	<cfargument name="inputFile" required="yes" type="string">
 236	<cfargument name="outputFile" required="yes" type="string">
 237	<cfargument name="newHeight" required="yes" type="numeric">
 238	<cfargument name="jpegCompression" required="no" type="numeric" default="#variables.defaultJpegCompression#">
 239
 240	<cfreturn resize(objImage, inputFile, outputFile, 0, newHeight, "false", "false", jpegCompression)>
 241</cffunction>
 242
 243<cffunction name="resize" access="public" output="true" returntype="struct" hint="Resize an image to a specific width and height.">
 244	<cfargument name="objImage" required="yes" type="Any">
 245	<cfargument name="inputFile" required="yes" type="string">
 246	<cfargument name="outputFile" required="yes" type="string">
 247	<cfargument name="newWidth" required="yes" type="numeric">
 248	<cfargument name="newHeight" required="yes" type="numeric">
 249	<cfargument name="preserveAspect" required="no" type="boolean" default="FALSE">
 250	<cfargument name="cropToExact" required="no" type="boolean" default="FALSE">
 251	<cfargument name="jpegCompression" required="no" type="numeric" default="#variables.defaultJpegCompression#">
 252
 253	<cfset var retVal = StructNew()>
 254	<cfset var loadImage = StructNew()>
 255	<cfset var saveImage = StructNew()>
 256	<cfset var at = "">
 257	<cfset var op = "">
 258	<cfset var w = "">
 259	<cfset var h = "">
 260	<cfset var scale = 1>
 261	<cfset var scaleX = 1>
 262	<cfset var scaleY = 1>
 263	<cfset var resizedImage = "">
 264	<cfset var rh = getRenderingHints()>
 265	<cfset var specifiedWidth = arguments.newWidth>
 266	<cfset var specifiedHeight = arguments.newHeight>
 267	<cfset var imgInfo = "">
 268	<cfset var img = "">
 269	<cfset var cropImageResult = "">
 270	<cfset var cropOffsetX = "">
 271	<cfset var cropOffsetY = "">
 272
 273	<cfset retVal.errorCode = 0>
 274	<cfset retVal.errorMessage = "">
 275
 276	<cfif inputFile neq "">
 277		<cfset loadImage = readImage(inputFile, "NO")>
 278		<cfif loadImage.errorCode is 0>
 279			<cfset img = loadImage.img>
 280		<cfelse>
 281			<cfset retVal = throw(loadImage.errorMessage)>
 282			<cfreturn retVal>
 283		</cfif>
 284	<cfelse>
 285		<cfset img = objImage>
 286	</cfif>
 287	<cfif img.getType() eq 0>
 288		<cfset img = convertImageObject(img,img.TYPE_3BYTE_BGR)>
 289	</cfif>
 290	<cfscript>
 291		resizedImage = CreateObject("java", "java.awt.image.BufferedImage");
 292		at = CreateObject("java", "java.awt.geom.AffineTransform");
 293		op = CreateObject("java", "java.awt.image.AffineTransformOp");
 294
 295		w = img.getWidth();
 296		h = img.getHeight();
 297
 298		if (preserveAspect and cropToExact and newHeight gt 0 and newWidth gt 0)
 299		{
 300			if (w / h gt newWidth / newHeight){
 301				newWidth = 0;
 302			} else if (w / h lt newWidth / newHeight){
 303				newHeight = 0;
 304		    }
 305		} else if (preserveAspect and newHeight gt 0 and newWidth gt 0) {
 306			if (w / h gt newWidth / newHeight){
 307				newHeight = 0;
 308			} else if (w / h lt newWidth / newHeight){
 309				newWidth = 0;
 310		    }
 311		}
 312		if (newWidth gt 0 and newHeight eq 0) {
 313			scale = newWidth / w;
 314			w = newWidth;
 315			h = round(h*scale);
 316		} else if (newHeight gt 0 and newWidth eq 0) {
 317			scale = newHeight / h;
 318			h = newHeight;
 319			w = round(w*scale);
 320		} else if (newHeight gt 0 and newWidth gt 0) {
 321			w = newWidth;
 322			h = newHeight;
 323		} else {
 324			retVal = throw( retVal.errorMessage);
 325			return retVal;
 326		}
 327		resizedImage.init(javacast("int",w),javacast("int",h),img.getType());
 328
 329		w = w / img.getWidth();
 330		h = h / img.getHeight();
 331
 332
 333
 334		op.init(at.getScaleInstance(javacast("double",w),javacast("double",h)), rh);
 335		// resizedImage = op.createCompatibleDestImage(img, img.getColorModel());
 336		op.filter(img, resizedImage);
 337
 338		imgInfo = getimageinfo(resizedImage, "");
 339		if (imgInfo.errorCode gt 0)
 340		{
 341			return imgInfo;
 342		}
 343
 344		cropOffsetX = max( Int( (imgInfo.width/2) - (newWidth/2) ), 0 );
 345		cropOffsetY = max( Int( (imgInfo.height/2) - (newHeight/2) ), 0 );
 346		// There is a chance that the image is exactly the correct
 347		// width and height and don't need to be cropped
 348		if
 349			(
 350			preserveAspect and cropToExact
 351			and
 352			(imgInfo.width IS NOT specifiedWidth OR imgInfo.height IS NOT specifiedHeight)
 353			)
 354		{
 355			// Get the correct offset to get the center of the image
 356			cropOffsetX = max( Int( (imgInfo.width/2) - (specifiedWidth/2) ), 0 );
 357			cropOffsetY = max( Int( (imgInfo.height/2) - (specifiedHeight/2) ), 0 );
 358
 359			cropImageResult = crop( resizedImage, "", "", cropOffsetX, cropOffsetY, specifiedWidth, specifiedHeight );
 360			if ( cropImageResult.errorCode GT 0)
 361			{
 362				return cropImageResult;
 363			} else {
 364				resizedImage = cropImageResult.img;
 365			}
 366		}
 367		if (outputFile eq "")
 368		{
 369			retVal.img = resizedImage;
 370			return retVal;
 371		} else {
 372			saveImage = writeImage(outputFile, resizedImage, jpegCompression);
 373			if (saveImage.errorCode gt 0)
 374			{
 375				return saveImage;
 376			} else {
 377				return retVal;
 378			}
 379		}
 380	</cfscript>
 381</cffunction>
 382
 383<cffunction name="crop" access="public" output="true" returntype="struct" hint="Crop an image.">
 384	<cfargument name="objImage" required="yes" type="Any">
 385	<cfargument name="inputFile" required="yes" type="string">
 386	<cfargument name="outputFile" required="yes" type="string">
 387	<cfargument name="fromX" required="yes" type="numeric">
 388	<cfargument name="fromY" required="yes" type="numeric">
 389	<cfargument name="newWidth" required="yes" type="numeric">
 390	<cfargument name="newHeight" required="yes" type="numeric">
 391	<cfargument name="jpegCompression" required="no" type="numeric" default="#variables.defaultJpegCompression#">
 392
 393	<cfset var retVal = StructNew()>
 394	<cfset var loadImage = StructNew()>
 395	<cfset var saveImage = StructNew()>
 396	<cfset var croppedImage = "">
 397	<cfset var rh = getRenderingHints()>
 398	<cfset var img = "">
 399
 400	<cfset retVal.errorCode = 0>
 401	<cfset retVal.errorMessage = "">
 402
 403	<cfif inputFile neq "">
 404		<cfset loadImage = readImage(inputFile, "NO")>
 405		<cfif loadImage.errorCode is 0>
 406			<cfset img = loadImage.img>
 407		<cfelse>
 408			<cfset retVal = throw(loadImage.errorMessage)>
 409			<cfreturn retVal>
 410		</cfif>
 411	<cfelse>
 412		<cfset img = objImage>
 413	</cfif>
 414	<cfif img.getType() eq 0>
 415		<cfset img = convertImageObject(img,img.TYPE_3BYTE_BGR)>
 416	</cfif>
 417	<cfscript>
 418		if (fromX + newWidth gt img.getWidth()
 419			OR
 420			fromY + newHeight gt img.getHeight()
 421			)
 422		{
 423			retval = throw( "The cropped image dimensions go beyond the original image dimensions.");
 424			return retVal;
 425		}
 426		croppedImage = img.getSubimage(javaCast("int", fromX), javaCast("int", fromY), javaCast("int", newWidth), javaCast("int", newHeight) );
 427		if (outputFile eq "")
 428		{
 429			retVal.img = croppedImage;
 430			return retVal;
 431		} else {
 432			saveImage = writeImage(outputFile, croppedImage, jpegCompression);
 433			if (saveImage.errorCode gt 0)
 434			{
 435				return saveImage;
 436			} else {
 437				return retVal;
 438			}
 439		}
 440	</cfscript>
 441</cffunction>
 442
 443<cffunction name="rotate" access="public" output="true" returntype="struct" hint="Rotate an image (+/-)90, (+/-)180, or (+/-)270 degrees.">
 444	<cfargument name="objImage" required="yes" type="Any">
 445	<cfargument name="inputFile" required="yes" type="string">
 446	<cfargument name="outputFile" required="yes" type="string">
 447	<cfargument name="degrees" required="yes" type="numeric">
 448	<cfargument name="jpegCompression" required="no" type="numeric" default="#variables.defaultJpegCompression#">
 449
 450	<cfset var retVal = StructNew()>
 451	<cfset var img = "">
 452	<cfset var loadImage = StructNew()>
 453	<cfset var saveImage = StructNew()>
 454	<cfset var at = "">
 455	<cfset var op = "">
 456	<cfset var w = 0>
 457	<cfset var h = 0>
 458	<cfset var iw = 0>
 459	<cfset var ih = 0>
 460	<cfset var x = 0>
 461	<cfset var y = 0>
 462	<cfset var rotatedImage = "">
 463	<cfset var rh = getRenderingHints()>
 464
 465	<cfset retVal.errorCode = 0>
 466	<cfset retVal.errorMessage = "">
 467
 468	<cfif inputFile neq "">
 469		<cfset loadImage = readImage(inputFile, "NO")>
 470		<cfif loadImage.errorCode is 0>
 471			<cfset img = loadImage.img>
 472		<cfelse>
 473			<cfset retVal = throw(loadImage.errorMessage)>
 474			<cfreturn retVal>
 475		</cfif>
 476	<cfelse>
 477		<cfset img = objImage>
 478	</cfif>
 479	<cfif img.getType() eq 0>
 480		<cfset img = convertImageObject(img,img.TYPE_3BYTE_BGR)>
 481	</cfif>
 482	<cfif ListFind("-270,-180,-90,90,180,270",degrees) is 0>
 483		<cfset retVal = throw( "At this time, image.cfc only supports rotating images in 90 degree increments.")>
 484		<cfreturn retVal>
 485	</cfif>
 486
 487	<cfscript>
 488		rotatedImage = CreateObject("java", "java.awt.image.BufferedImage");
 489		at = CreateObject("java", "java.awt.geom.AffineTransform");
 490		op = CreateObject("java", "java.awt.image.AffineTransformOp");
 491
 492		iw = img.getWidth(); h = iw;
 493		ih = img.getHeight(); w = ih;
 494
 495		if(arguments.degrees eq 180) { w = iw; h = ih; }
 496
 497		x = (w/2)-(iw/2);
 498		y = (h/2)-(ih/2);
 499
 500		rotatedImage.init(javacast("int",w),javacast("int",h),img.getType());
 501
 502		at.rotate(arguments.degrees * 0.0174532925,w/2,h/2);
 503		at.translate(x,y);
 504		op.init(at, rh);
 505
 506		op.filter(img, rotatedImage);
 507
 508		if (outputFile eq "")
 509		{
 510			retVal.img = rotatedImage;
 511			return retVal;
 512		} else {
 513			saveImage = writeImage(outputFile, rotatedImage, jpegCompression);
 514			if (saveImage.errorCode gt 0)
 515			{
 516				return saveImage;
 517			} else {
 518				return retVal;
 519			}
 520		}
 521	</cfscript>
 522</cffunction>
 523
 524<cffunction name="convert" access="public" output="true" returntype="struct" hint="Convert an image from one format to another.">
 525	<cfargument name="objImage" required="yes" type="Any">
 526	<cfargument name="inputFile" required="yes" type="string">
 527	<cfargument name="outputFile" required="yes" type="string">
 528	<cfargument name="jpegCompression" required="no" type="numeric" default="#variables.defaultJpegCompression#">
 529
 530	<cfset var retVal = StructNew()>
 531	<cfset var loadImage = StructNew()>
 532	<cfset var saveImage = StructNew()>
 533	<cfset var img = "">
 534
 535	<cfset retVal.errorCode = 0>
 536	<cfset retVal.errorMessage = "">
 537
 538	<cfif inputFile neq "">
 539		<cfset loadImage = readImage(inputFile, "NO")>
 540		<cfif loadImage.errorCode is 0>
 541			<cfset img = loadImage.img>
 542		<cfelse>
 543			<cfset retVal = throw(loadImage.errorMessage)>
 544			<cfreturn retVal>
 545		</cfif>
 546	<cfelse>
 547		<cfset img = objImage>
 548	</cfif>
 549
 550	<cfscript>
 551		if (outputFile eq "")
 552		{
 553			retVal = throw( "The convert method requires a valid output filename.");
 554			return retVal;
 555		} else {
 556			saveImage = writeImage(outputFile, img, jpegCompression);
 557			if (saveImage.errorCode gt 0)
 558			{
 559				return saveImage;
 560			} else {
 561				return retVal;
 562			}
 563		}
 564	</cfscript>
 565</cffunction>
 566
 567<cffunction name="setOption" access="public" output="true" returnType="void" hint="Sets values for allowed CFC options.">
 568	<cfargument name="key" type="string" required="yes">
 569	<cfargument name="val" type="string" required="yes">
 570
 571	<cfset var validKeys = "interpolation,textantialiasing,throwonerror,defaultJpegCompression">
 572	<cfset arguments.key = lcase(trim(arguments.key))>
 573	<cfset arguments.val = lcase(trim(arguments.val))>
 574	<cfif listFind(validKeys, arguments.key) gt 0>
 575		<cfset variables[arguments.key] = arguments.val>
 576	</cfif>
 577</cffunction>
 578
 579<cffunction name="getOption" access="public" output="true" returnType="any" hint="Returns the current value for the specified CFC option.">
 580	<cfargument name="key" type="string" required="yes">
 581
 582	<cfset var validKeys = "interpolation,textantialiasing,throwonerror,defaultJpegCompression">
 583	<cfset arguments.key = lcase(trim(arguments.key))>
 584	<cfif listFindNoCase(validKeys, arguments.key) gt 0>
 585		<cfreturn variables[arguments.key]>
 586	<cfelse>
 587		<cfreturn "">
 588	</cfif>
 589</cffunction>
 590
 591<cffunction name="getRenderingHints" access="private" output="true" returnType="any" hint="Internal method controls various aspects of rendering quality.">
 592	<cfset var rh = CreateObject("java","java.awt.RenderingHints")>
 593	<cfset var initMap = CreateObject("java","java.util.HashMap")>
 594	<cfset initMap.init()>
 595	<cfset rh.init(initMap)>
 596	<cfset rh.put(rh.KEY_ALPHA_INTERPOLATION, rh.VALUE_ALPHA_INTERPOLATION_QUALITY)> <!--- QUALITY, SPEED, DEFAULT --->
 597	<cfset rh.put(rh.KEY_ANTIALIASING, rh.VALUE_ANTIALIAS_ON)> <!--- ON, OFF, DEFAULT --->
 598	<cfset rh.put(rh.KEY_COLOR_RENDERING, rh.VALUE_COLOR_RENDER_QUALITY)>  <!--- QUALITY, SPEED, DEFAULT --->
 599	<cfset rh.put(rh.KEY_DITHERING, rh.VALUE_DITHER_DEFAULT)> <!--- DISABLE, ENABLE, DEFAULT --->
 600	<cfset rh.put(rh.KEY_RENDERING, rh.VALUE_RENDER_QUALITY)> <!--- QUALITY, SPEED, DEFAULT --->
 601	<cfset rh.put(rh.KEY_FRACTIONALMETRICS, rh.VALUE_FRACTIONALMETRICS_DEFAULT)> <!--- DISABLE, ENABLE, DEFAULT --->
 602	<cfset rh.put(rh.KEY_STROKE_CONTROL, rh.VALUE_STROKE_DEFAULT)>
 603
 604	<cfif variables.textAntiAliasing>
 605		<cfset rh.put(rh.KEY_TEXT_ANTIALIASING, rh.VALUE_TEXT_ANTIALIAS_ON)>
 606	<cfelse>
 607		<cfset rh.put(rh.KEY_TEXT_ANTIALIASING, rh.VALUE_TEXT_ANTIALIAS_OFF)>
 608	</cfif>
 609
 610	<cfif variables.interpolation eq "nearest_neighbor">
 611		<cfset rh.put(rh.KEY_INTERPOLATION, rh.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)>
 612	<cfelseif variables.interpolation eq "bilinear">
 613		<cfset rh.put(rh.KEY_INTERPOLATION, rh.VALUE_INTERPOLATION_BILINEAR)>
 614	<cfelse>
 615		<cfset rh.put(rh.KEY_INTERPOLATION, rh.VALUE_INTERPOLATION_BICUBIC)>
 616	</cfif>
 617
 618	<cfreturn rh>
 619</cffunction>
 620
 621<cffunction name="readImage" access="public" output="true" returntype="struct" hint="Reads an image from a local file.  Requires an absolute path.">
 622	<cfargument name="source" required="yes" type="string">
 623	<cfargument name="forModification" required="no" type="boolean" default="yes">
 624
 625	<cfif isURL(source)>
 626		<cfreturn readImageFromURL(source, forModification)>
 627	<cfelse>
 628		<cfreturn readImageFromFile(source, forModification)>
 629	</cfif>
 630</cffunction>
 631
 632<cffunction name="readImageFromFile" access="private" output="true" returntype="struct" hint="Reads an image from a local file.  Requires an absolute path.">
 633	<cfargument name="inputFile" required="yes" type="string">
 634	<cfargument name="forModification" required="no" type="boolean" default="yes">
 635
 636	<cfset var retVal = StructNew()>
 637	<cfset var img = "">
 638	<cfset var inFile = "">
 639	<cfset var filename = getFileFromPath(inputFile)>
 640	<cfset var extension = lcase(listLast(inputFile,"."))>
 641	<cfset var imageIO = CreateObject("java", "javax.imageio.ImageIO")>
 642	<cfset var validExtensionsToRead = ArrayToList(imageIO.getReaderFormatNames())>
 643
 644	<cfset retVal.errorCode = 0>
 645	<cfset retVal.errorMessage = "">
 646
 647	<cfif not fileExists(arguments.inputFile)>
 648		<cfset retVal = throw("The specified file #Chr(34)##arguments.inputFile##Chr(34)# could not be found.")>
 649		<cfreturn retVal>
 650	<cfelseif listLen(filename,".") lt 2>
 651		<cfset retVal = throw("Sorry, image files without extensions cannot be manipulated.")>
 652		<cfreturn retVal>
 653	<cfelseif listFindNoCase(validExtensionsToRead, extension) is 0>
 654		<cfset retVal = throw("Java is unable to read #extension# files.")>
 655		<cfreturn retVal>
 656	<cfelseif NOT fileExists(arguments.inputFile)>
 657		<cfset retVal = throw("The specified input file does not exist.")>
 658		<cfreturn retVal>
 659	<cfelse>
 660		<cfset img = CreateObject("java", "java.awt.image.BufferedImage")>
 661		<cfset inFile = CreateObject("java", "java.io.File")>
 662		<cfset inFile.init(arguments.inputFile)>
 663		<cfif NOT inFile.canRead()>
 664			<cfset retVal = throw("Unable to open source file #Chr(34)##arguments.inputFile##Chr(34)#.")>
 665			<cfreturn retVal>
 666		<cfelse>
 667			<cftry>
 668				<cfset img = imageIO.read(inFile)>
 669				<cfcatch type="any">
 670					<cfset retval = throw("An error occurred attempting to read the specified image.  #cfcatch.message# - #cfcatch.detail#")>
 671					<cfreturn retVal>
 672				</cfcatch>
 673			</cftry>
 674			<cfset retVal.img = img>
 675			<cfset retVal.inFile = inFile>
 676			<cfreturn retVal>
 677		</cfif>
 678	</cfif>
 679</cffunction>
 680
 681<cffunction name="readImageFromURL" access="private" output="true" returntype="struct" hint="Read an image from a URL.  Requires an absolute URL.">
 682	<cfargument name="inputURL" required="yes" type="string">
 683	<cfargument name="forModification" required="no" type="boolean" default="yes">
 684
 685	<cfset var retVal = StructNew()>
 686	<cfset var img = CreateObject("java", "java.awt.image.BufferedImage")>
 687	<cfset var inURL	= CreateObject("java", "java.net.URL")>
 688	<cfset var imageIO = CreateObject("java", "javax.imageio.ImageIO")>
 689
 690	<cfset retVal.errorCode = 0>
 691	<cfset retVal.errorMessage = "">
 692
 693
 694	<cfset inURL.init(arguments.inputURL)>
 695	<cftry>
 696		<cfset img = imageIO.read(inURL)>
 697		<cfcatch type="any">
 698			<cfset retval = throw("An error occurred attempting to read the specified image.  #cfcatch.message# - #cfcatch.detail#")>
 699			<cfreturn retVal>
 700		</cfcatch>
 701	</cftry>
 702	<cfset retVal.img = img>
 703	<cfreturn retVal>
 704</cffunction>
 705
 706<cffunction name="writeImage" access="public" output="true" returntype="struct" hint="Write an image to disk.">
 707	<cfargument name="outputFile" required="yes" type="string">
 708	<cfargument name="img" required="yes" type="any">
 709	<cfargument name="jpegCompression" required="no" type="numeric" default="#variables.defaultJpegCompression#">
 710
 711	<cfset var retVal = StructNew()>
 712	<cfset var outFile = "">
 713	<cfset var filename = getFileFromPath(outputFile)>
 714	<cfset var extension = lcase(listLast(filename,"."))>
 715	<cfset var imageIO = CreateObject("java", "javax.imageio.ImageIO")>
 716	<cfset var validExtensionsToWrite = ArrayToList(imageIO.getWriterFormatNames())>
 717	<!--- used for jpeg output method --->
 718	<cfset var out = "">
 719	<cfset var fos = "">
 720	<cfset var JPEGCodec = "">
 721	<cfset var encoder = "">
 722	<cfset var param = "">
 723	<cfset var quality = javacast("float", jpegCompression/100)>
 724	<cfset var tempOutputFile = "#variables.tempDirectory#\#createUUID()#.#extension#">
 725
 726	<cfset retVal.errorCode = 0>
 727	<cfset retVal.errorMessage = "">
 728
 729	<cfif listFindNoCase(validExtensionsToWrite, extension) eq 0>
 730		<cfset throw("Java is unable to write #extension# files.  Valid formats include: #validExtensionsToWrite#")>
 731	</cfif>
 732
 733	<cfif extension neq "jpg" and extension neq "jpeg">
 734		<!---
 735			Simple output method for non jpeg images
 736		--->
 737		<cfset outFile = CreateObject("java", "java.io.File")>
 738		<cfset outFile.init(tempOutputFile)>
 739		<cfset imageIO.write(img, extension, outFile)>
 740	<cfelse>
 741		<cfscript>
 742			/*
 743				JPEG output method handles compression
 744			*/
 745			out = createObject("java", "java.io.BufferedOutputStream");
 746			fos = createObject("java", "java.io.FileOutputStream");
 747			fos.init(tempOutputFile);
 748			out.init(fos);
 749			JPEGCodec = createObject("java", "com.sun.image.codec.jpeg.JPEGCodec");
 750			encoder = JPEGCodec.createJPEGEncoder(out);
 751		    param = encoder.getDefaultJPEGEncodeParam(img);
 752		    param.setQuality(quality, false);
 753		    encoder.setJPEGEncodeParam(param);
 754		    encoder.encode(img);
 755		    out.close();
 756		</cfscript>
 757	</cfif>
 758	<!--- move file to its final destination --->
 759	<cffile action="MOVE" source="#tempOutputFile#" destination="#arguments.outputFile#">
 760	<cfreturn retVal>
 761</cffunction>
 762
 763<cffunction name="flipflop" access="private" output="true" returntype="struct" hint="Internal method used for flipping and flopping images.">
 764	<cfargument name="objImage" required="yes" type="Any">
 765	<cfargument name="inputFile" required="yes" type="string">
 766	<cfargument name="outputFile" required="yes" type="string">
 767	<cfargument name="direction" required="yes" type="string"><!--- horizontal or vertical --->
 768	<cfargument name="jpegCompression" required="no" type="numeric" default="#variables.defaultJpegCompression#">
 769
 770	<cfset var retVal = StructNew()>
 771	<cfset var loadImage = StructNew()>
 772	<cfset var saveImage = StructNew()>
 773	<cfset var flippedImage = "">
 774	<cfset var rh = getRenderingHints()>
 775	<cfset var img = "">
 776
 777	<cfset retVal.errorCode = 0>
 778	<cfset retVal.errorMessage = "">
 779
 780	<cfif inputFile neq "">
 781		<cfset loadImage = readImage(inputFile, "NO")>
 782		<cfif loadImage.errorCode is 0>
 783			<cfset img = loadImage.img>
 784		<cfelse>
 785			<cfset retVal = throw(loadImage.errorMessage)>
 786			<cfreturn retVal>
 787		</cfif>
 788	<cfelse>
 789		<cfset img = objImage>
 790	</cfif>
 791	<cfif img.getType() eq 0>
 792		<cfset img = convertImageObject(img,img.TYPE_3BYTE_BGR)>
 793	</cfif>
 794	<cfscript>
 795		flippedImage = CreateObject("java", "java.awt.image.BufferedImage");
 796		at = CreateObject("java", "java.awt.geom.AffineTransform");
 797		op = CreateObject("java", "java.awt.image.AffineTransformOp");
 798
 799		flippedImage.init(img.getWidth(), img.getHeight(), img.getType());
 800
 801		if (direction eq "horizontal") {
 802			at = at.getScaleInstance(-1, 1);
 803			at.translate(-img.getWidth(), 0);
 804		} else {
 805			at = at.getScaleInstance(1,-1);
 806			at.translate(0, -img.getHeight());
 807		}
 808		op.init(at, rh);
 809		op.filter(img, flippedImage);
 810
 811		if (outputFile eq "")
 812		{
 813			retVal.img = flippedImage;
 814			return retVal;
 815		} else {
 816			saveImage = writeImage(outputFile, flippedImage, jpegCompression);
 817			if (saveImage.errorCode gt 0)
 818			{
 819				return saveImage;
 820			} else {
 821				return retVal;
 822			}
 823		}
 824	</cfscript>
 825</cffunction>
 826
 827
 828
 829<cffunction name="filterFastBlur" access="public" output="true" returntype="struct" hint="Internal method used for flipping and flopping images.">
 830	<cfargument name="objImage" required="yes" type="Any">
 831	<cfargument name="inputFile" required="yes" type="string">
 832	<cfargument name="outputFile" required="yes" type="string">
 833	<cfargument name="blurAmount" required="yes" type="numeric">
 834	<cfargument name="iterations" required="yes" type="numeric">
 835	<cfargument name="jpegCompression" required="no" type="numeric" default="#variables.defaultJpegCompression#">
 836
 837	<cfset var retVal = StructNew()>
 838	<cfset var loadImage = StructNew()>
 839	<cfset var saveImage = StructNew()>
 840	<cfset var srcImage = "">
 841	<cfset var destImage = "">
 842	<cfset var rh = getRenderingHints()>
 843
 844	<cfset retVal.errorCode = 0>
 845	<cfset retVal.errorMessage = "">
 846
 847	<cfif NOT variables.javanulls>
 848		<cfset throw("Sorry, but the blur filter is not supported on this platform.")>
 849	</cfif>
 850	<cfif inputFile neq "">
 851		<cfset loadImage = readImage(inputFile, "NO")>
 852		<cfif loadImage.errorCode is 0>
 853			<cfset srcImage = loadImage.img>
 854		<cfelse>
 855			<cfset retVal = throw(loadImage.errorMessage)>
 856			<cfreturn retVal>
 857		</cfif>
 858	<cfelse>
 859		<cfset srcImage = objImage>
 860	</cfif>
 861	<cfif srcImage.getType() eq 0>
 862		<cfset srcImage = convertImageObject(srcImage,srcImage.TYPE_3BYTE_BGR)>
 863	</cfif>
 864
 865	<cfscript>
 866
 867		// initialize the blur filter
 868		variables.blurFilter.init(arguments.blurAmount);
 869		// move the source image into the destination image
 870		// so we can repeatedly blur it.
 871		destImage = srcImage;
 872
 873		for (i=1; i lte iterations; i=i+1)
 874		{
 875			// do the blur i times
 876			destImage = variables.blurFilter.filter(destImage);
 877		}
 878
 879
 880		if (outputFile eq "")
 881		{
 882			// return the image object
 883			retVal.img = destImage;
 884			return retVal;
 885		} else {
 886			// write the image object to the specified file.
 887			saveImage = writeImage(outputFile, destImage, jpegCompression);
 888			if (saveImage.errorCode gt 0)
 889			{
 890				return saveImage;
 891			} else {
 892				return retVal;
 893			}
 894		}
 895	</cfscript>
 896</cffunction>
 897
 898<cffunction name="filterSharpen" access="public" output="true" returntype="struct" hint="Internal method used for flipping and flopping images.">
 899	<cfargument name="objImage" required="yes" type="Any">
 900	<cfargument name="inputFile" required="yes" type="string">
 901	<cfargument name="outputFile" required="yes" type="string">
 902	<cfargument name="jpegCompression" required="no" type="numeric" default="#variables.defaultJpegCompression#">
 903
 904	<cfset var retVal = StructNew()>
 905	<cfset var loadImage = StructNew()>
 906	<cfset var saveImage = StructNew()>
 907	<cfset var srcImage = "">
 908	<cfset var destImage = "">
 909	<cfset var rh = getRenderingHints()>
 910
 911	<cfset retVal.errorCode = 0>
 912	<cfset retVal.errorMessage = "">
 913
 914	<cfif NOT variables.javanulls>
 915		<cfset throw("Sorry, but the blur filter is not supported on this platform.")>
 916	</cfif>
 917
 918	<cfif inputFile neq "">
 919		<cfset loadImage = readImage(inputFile, "NO")>
 920		<cfif loadImage.errorCode is 0>
 921			<cfset srcImage = loadImage.img>
 922		<cfelse>
 923			<cfset retVal = throw(loadImage.errorMessage)>
 924			<cfreturn retVal>
 925		</cfif>
 926	<cfelse>
 927		<cfset srcImage = objImage>
 928	</cfif>
 929	<cfif srcImage.getType() eq 0>
 930		<cfset srcImage = convertImageObject(srcImage,srcImage.TYPE_3BYTE_BGR)>
 931	</cfif>
 932
 933	<cfscript>
 934		// initialize the sharpen filter
 935		variables.sharpenFilter.init();
 936
 937		destImage = variables.sharpenFilter.filter(srcImage);
 938
 939
 940		if (outputFile eq "")
 941		{
 942			// return the image object
 943			retVal.img = destImage;
 944			return retVal;
 945		} else {
 946			// write the image object to the specified file.
 947			saveImage = writeImage(outputFile, destImage, jpegCompression);
 948			if (saveImage.errorCode gt 0)
 949			{
 950				return saveImage;
 951			} else {
 952				return retVal;
 953			}
 954		}
 955	</cfscript>
 956</cffunction>
 957
 958
 959<cffunction name="filterPosterize" access="public" output="true" returntype="struct" hint="Internal method used for flipping and flopping images.">
 960	<cfargument name="objImage" required="yes" type="Any">
 961	<cfargument name="inputFile" required="yes" type="string">
 962	<cfargument name="outputFile" required="yes" type="string">
 963	<cfargument name="amount" required="yes" type="string">
 964	<cfargument name="jpegCompression" required="no" type="numeric" default="#variables.defaultJpegCompression#">
 965
 966	<cfset var retVal = StructNew()>
 967	<cfset var loadImage = StructNew()>
 968	<cfset var saveImage = StructNew()>
 969	<cfset var srcImage = "">
 970	<cfset var destImage = "">
 971	<cfset var rh = getRenderingHints()>
 972
 973	<cfset retVal.errorCode = 0>
 974	<cfset retVal.errorMessage = "">
 975
 976	<cfif NOT variables.javanulls>
 977		<cfset throw("Sorry, but the blur filter is not supported on this platform.")>
 978	</cfif>
 979
 980	<cfif inputFile neq "">
 981		<cfset loadImage = readImage(inputFile, "NO")>
 982		<cfif loadImage.errorCode is 0>
 983			<cfset srcImage = loadImage.img>
 984		<cfelse>
 985			<cfset retVal = throw(loadImage.errorMessage)>
 986			<cfreturn retVal>
 987		</cfif>
 988	<cfelse>
 989		<cfset srcImage = objImage>
 990	</cfif>
 991	<cfif srcImage.getType() eq 0>
 992		<cfset srcImage = convertImageObject(srcImage,srcImage.TYPE_3BYTE_BGR)>
 993	</cfif>
 994	<cfif srcImage.getType() neq 5>
 995		<cfset throw("ImageCFC cannot posterize this image type (#srcImage.getType()#)")>
 996	</cfif>
 997	<cfscript>
 998		// initialize the posterize filter
 999		variables.posterizeFilter.init(arguments.amount);
1000
1001		destImage = variables.posterizeFilter.filter(srcImage);
1002
1003
1004		if (outputFile eq "")
1005		{
1006			// return the image object
1007			retVal.img = destImage;
1008			return retVal;
1009		} else {
1010			// write the image object to the specified file.
1011			saveImage = writeImage(outputFile, destImage, jpegCompression);
1012			if (saveImage.errorCode gt 0)
1013			{
1014				return saveImage;
1015			} else {
1016				return retVal;
1017			}
1018		}
1019	</cfscript>
1020</cffunction>
1021
1022
1023<cffunction name="addText" access="public" output="true" returntype="struct" hint="Add text to an image.">
1024	<cfargument name="objImage" required="yes" type="Any">
1025	<cfargument name="inputFile" required="yes" type="string">
1026	<cfargument name="outputFile" required="yes" type="string">
1027	<cfargument name="x" required="yes" type="numeric">
1028	<cfargument name="y" required="yes" type="numeric">
1029	<cfargument name="fontDetails" required="yes" type="struct">
1030	<cfargument name="content" required="yes" type="String">
1031	<cfargument name="jpegCompression" required="no" type="numeric" default="#variables.defaultJpegCompression#">
1032
1033	<cfset var retVal = StructNew()>
1034	<cfset var loadImage = StructNew()>
1035	<cfset var img = "">
1036	<cfset var saveImage = StructNew()>
1037	<cfset var g2d = "">
1038	<cfset var bgImage = "">
1039	<cfset var fontImage = "">
1040	<cfset var overlayImage = "">
1041	<cfset var Color = "">
1042	<cfset var font = "">
1043	<cfset var font_stream = "">
1044	<cfset var ac = "">
1045	<cfset var rgb = "">
1046
1047	<cfset retVal.errorCode = 0>
1048	<cfset retVal.errorMessage = "">
1049
1050	<cfparam name="arguments.fontDetails.size" default="12">
1051	<cfparam name="arguments.fontDetails.color" default="black">
1052	<cfparam name="arguments.fontDetails.fontFile" default="">
1053	<cfparam name="arguments.fontDetails.fontName" default="serif">
1054
1055	<cfif arguments.fontDetails.fontFile neq "" and not fileExists(arguments.fontDetails.fontFile)>
1056		<cfset retVal = throw("The specified font file #Chr(34)##arguments.inputFile##Chr(34)# could not be found on the server.")>
1057		<cfreturn retVal>
1058	</cfif>
1059	<cftry>
1060		<cfset rgb = getRGB(arguments.fontDetails.color)>
1061		<cfcatch type="any">
1062			<cfset retVal = throw("Invalid color #Chr(34)##arguments.fontDetails.color##Chr(34)#")>
1063			<cfreturn retVal>
1064		</cfcatch>
1065	</cftry>
1066	<cfif inputFile neq "">
1067		<cfset loadImage = readImage(inputFile, "NO")>
1068		<cfif loadImage.errorCode is 0>
1069			<cfset img = loadImage.img>
1070		<cfelse>
1071			<cfset retVal = throw(loadImage.errorMessage)>
1072			<cfreturn retVal>
1073		</cfif>
1074	<cfelse>
1075		<cfset img = objImage>
1076	</cfif>
1077	<cfif img.getType() eq 0>
1078		<cfset img = convertImageObject(img,img.TYPE_3BYTE_BGR)>
1079	</cfif>
1080	<cfscript>
1081		// load objects
1082		bgImage = CreateObject("java", "java.awt.image.BufferedImage");
1083		fontImage = CreateObject("java", "java.awt.image.BufferedImage");
1084		overlayImage = CreateObject("java", "java.awt.image.BufferedImage");
1085		Color = CreateObject("java","java.awt.Color");
1086		font = createObject("java","java.awt.Font");
1087		font_stream = createObject("java","java.io.FileInputStream");
1088		ac = CreateObject("Java", "java.awt.AlphaComposite");
1089
1090		// set up basic needs
1091		fontColor = Color.init(javacast("int", rgb.red), javacast("int", rgb.green), javacast("int", rgb.blue));
1092
1093		if (fontDetails.fontFile neq "")
1094		{
1095			font_stream.init(arguments.fontDetails.fontFile);
1096			font = font.createFont(font.TRUETYPE_FONT, font_stream);
1097			font = font.deriveFont(javacast("float",arguments.fontDetails.size));
1098		} else {
1099			font.init(fontDetails.fontName, evaluate(fontDetails.style), fontDetails.size);
1100		}
1101		// get font metrics using a 1x1 bufferedImage
1102		fontImage.init(1,1,img.getType());
1103		g2 = fontImage.createGraphics();
1104		g2.setRenderingHints(getRenderingHints());
1105		fc = g2.getFontRenderContext();
1106		bounds = font.getStringBounds(content,fc);
1107
1108		g2 = img.createGraphics();
1109		g2.setRenderingHints(getRenderingHints());
1110		g2.setFont(font);
1111		g2.setColor(fontColor);
1112		// in case you want to change the alpha
1113		// g2.setComposite(ac.getInstance(ac.SRC_OVER, 0.50));
1114
1115		// the location (arguments.fontDetails.size+y) doesn't really work
1116		// the way I want it to.
1117		g2.drawString(content,javacast("int",x),javacast("int",arguments.fontDetails.size+y));
1118
1119		if (outputFile eq "")
1120		{
1121			retVal.img = img;
1122			return retVal;
1123		} else {
1124			saveImage = writeImage(outputFile, img, jpegCompression);
1125			if (saveImage.errorCode gt 0)
1126			{
1127				return saveImage;
1128			} else {
1129				return retVal;
1130			}
1131		}
1132	</cfscript>
1133</cffunction>
1134
1135<cffunction name="watermark" access="public" output="false">
1136	<cfargument name="objImage1" required="yes" type="Any">
1137	<cfargument name="objImage2" required="yes" type="Any">
1138	<cfargument name="inputFile1" required="yes" type="string">
1139	<cfargument name="inputFile2" required="yes" type="string">
1140	<cfargument name="alpha" required="yes" type="numeric">
1141	<cfargument name="placeAtX" required="yes" type="numeric">
1142	<cfargument name="placeAtY" required="yes" type="numeric">
1143	<cfargument name="outputFile" required="yes" type="string">
1144	<cfargument name="jpegCompression" required="no" type="numeric" default="#variables.defaultJpegCompression#">
1145
1146	<cfset var retVal = StructNew()>
1147	<cfset var loadImage = StructNew()>
1148	<cfset var originalImage = "">
1149	<cfset var wmImage = "">
1150	<cfset var saveImage = StructNew()>
1151	<cfset var ac = "">
1152	<cfset var rh = getRenderingHints()>
1153
1154	<cfset retVal.errorCode = 0>
1155	<cfset retVal.errorMessage = "">
1156
1157	<cfif inputFile1 neq "">
1158		<cfset loadImage = readImage(inputFile1, "NO")>
1159		<cfif loadImage.errorCode is 0>
1160			<cfset originalImage = loadImage.img>
1161		<cfelse>
1162			<cfset retVal = throw(loadImage.errorMessage)>
1163			<cfreturn retVal>
1164		</cfif>
1165	<cfelse>
1166		<cfset originalImage = objImage1>
1167	</cfif>
1168	<cfif originalImage.getType() eq 0>
1169		<cfset originalImage = convertImageObject(originalImage,originalImage.TYPE_3BYTE_BGR)>
1170	</cfif>
1171
1172	<cfif inputFile2 neq "">
1173		<cfset loadImage = readImage(inputFile2, "NO")>
1174		<cfif loadImage.errorCode is 0>
1175			<cfset wmImage = loadImage.img>
1176		<cfelse>
1177			<cfset retVal = throw(loadImage.errorMessage)>
1178			<cfreturn retVal>
1179		</cfif>
1180	<cfelse>
1181		<cfset wmImage = objImage2>
1182	</cfif>
1183	<cfif wmImage.getType() eq 0>
1184		<cfset wmImage = convertImageObject(wmImage,wmImage.TYPE_3BYTE_BGR)>
1185	</cfif>
1186
1187
1188	<cfscript>
1189		at = CreateObject("java", "java.awt.geom.AffineTransform");
1190		op = CreateObject("java", "java.awt.image.AffineTransformOp");
1191		ac = CreateObject("Java", "java.awt.AlphaComposite");
1192		gfx = originalImage.getGraphics();
1193		gfx.setComposite(ac.getInstance(ac.SRC_OVER, alpha));
1194
1195		at.init();
1196		// op.init(at,op.TYPE_BILINEAR);
1197		op.init(at, rh);
1198
1199		gfx.drawImage(wmImage, op, javaCast("int",arguments.placeAtX), javacast("int", arguments.placeAtY));
1200
1201		gfx.dispose();
1202
1203		if (outputFile eq "")
1204		{
1205			retVal.img = originalImage;
1206			return retVal;
1207		} else {
1208			saveImage = writeImage(outputFile, originalImage, jpegCompression);
1209			if (saveImage.errorCode gt 0)
1210			{
1211				return saveImage;
1212			} else {
1213				return retVal;
1214			}
1215		}
1216	</cfscript>
1217</cffunction>
1218
1219<cffunction name="isURL" access="private" output="false" returnType="boolean">
1220	<cfargument name="stringToCheck" required="yes" type="string">
1221	<cfif REFindNoCase("^(((https?:)\/\/))[-[:alnum:]\?%,\.\/&##!@:=\+~_]+[A-Za-z0-9\/]$",stringToCheck) NEQ 0>
1222		<cfreturn true>
1223	<cfelse>
1224		<cfreturn false>
1225	</cfif>
1226</cffunction>
1227
1228<!--- function returns RGB values in a structure for hex or the 16
1229	HTML named colors --->
1230<cffunction name="getRGB" access="private" output="true" returnType="struct">
1231	<cfargument name="color" type="string" required="yes">
1232
1233	<cfset var retVal = structNew()>
1234	<cfset var cnt = 0>
1235	<cfset var namedColors = "aqua,black,blue,fuchsia,gray,green,lime,maroon,navy,olive,purple,red,silver,teal,white,yellow">
1236	<cfset var namedColorsHexValues = "00ffff,000000,0000ff,ff00ff,808080,008000,00ff00,800000,000080,808080,ff0000,c0c0c0,008080,ffffff,ffff00">
1237
1238	<cfset retVal.red = 0>
1239	<cfset retVal.green = 0>
1240	<cfset retVal.blue = 0>
1241
1242	<cfset arguments.color = trim(arguments.color)>
1243	<cfif len(arguments.color) is 0>
1244		<cfreturn retVal>
1245	<cfelseif listFind(namedColors, arguments.color) gt 0>
1246		<cfset arguments.color = listGetAt(namedColorsHexValues, listFind(namedColors, arguments.color))>
1247	</cfif>
1248	<cfif left(arguments.color,1) eq "##">
1249		<cfset arguments.color = right(arguments.color,len(arguments.color)-1)>
1250	</cfif>
1251	<cfif len(arguments.color) neq 6>
1252		<cfreturn retVal>
1253	<cfelse>
1254		<cftry>
1255			<cfset retVal.red = InputBaseN(mid(arguments.color,1,2),16)>
1256			<cfset retVal.green = InputBaseN(mid(arguments.color,3,2),16)>
1257			<cfset retVal.blue = InputBaseN(mid(arguments.color,5,2),16)>
1258			<cfcatch type="any">
1259				<cfset retVal.red = 0>
1260				<cfset retVal.green = 0>
1261				<cfset retVal.blue = 0>
1262				<cfreturn retVal>
1263			</cfcatch>
1264		</cftry>
1265	</cfif>
1266	<cfreturn retVal>
1267</cffunction>
1268
1269<cffunction name="throw" access="private" output="false" returnType="struct">
1270	<cfargument name="detail" type="string" required="yes">
1271	<cfargument name="force" type="boolean" required="no" default="no">
1272
1273	<cfset var retVal = StructNew()>
1274
1275	<cfif variables.throwOnError or arguments.force>
1276		<cfthrow detail="#arguments.detail#" message="#arguments.detail#">
1277	<cfelse>
1278		<cfset retVal.errorCode = 1>
1279		<cfset retVal.errorMessage = arguments.detail>
1280		<cfreturn retVal>
1281	</cfif>
1282</cffunction>
1283
1284<cffunction name="debugDump" access="private">
1285	<cfdump var="#arguments#"><cfabort>
1286</cffunction>
1287
1288<cffunction name="convertImageObject" access="private" output="false" returnType="any">
1289	<cfargument name="bImage" type="Any" required="yes">
1290	<cfargument name="type" type="numeric" required="yes">
1291
1292	<cfscript>
1293	// convert the image to a specified BufferedImage type and return it
1294
1295	var width = bImage.getWidth();
1296	var height = bImage.getHeight();
1297	var newImage = createObject("java","java.awt.image.BufferedImage").init(javacast("int",width), javacast("int",height), javacast("int",type));
1298	// int[] rgbArray = new int[width*height];
1299	var rgbArray = variables.arrObj.newInstance(variables.intClass, javacast("int",width*height));
1300
1301	bImage.getRGB(
1302		javacast("int",0),
1303		javacast("int",0),
1304		javacast("int",width),
1305		javacast("int",height),
1306		rgbArray,
1307		javacast("int",0),
1308		javacast("int",width)
1309		);
1310	newImage.setRGB(
1311		javacast("int",0),
1312		javacast("int",0),
1313		javacast("int",width),
1314		javacast("int",height),
1315		rgbArray,
1316		javacast("int",0),
1317		javacast("int",width)
1318		);
1319	return newImage;
1320	</cfscript>
1321
1322</cffunction>
1323
1324</cfcomponent>
1325