Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
Ben Nadel at cf.Objective() 2012 (Minneapolis, MN) with: Ryan Anklam
Ben Nadel at cf.Objective() 2012 (Minneapolis, MN) with: Ryan Anklam@bittersweetryan )

Fixing ImageScaleToFit() Invalid Size Errors In Earlier Versions Of Lucee CFML

By Ben Nadel on
Tags: ColdFusion

In earlier releases of Lucee CFML, calling the imageScaleToFit() function on an oblong image can result in a Java error, invalid size for image. This does not appear to affect the latest release of Lucee CFML (5.3.2.77); however, since people - like myself - may be running on earlier releases of Lucee, I thought it would be worth sharing a work-around for the issue.

To see the error in action, take a look at the following code, which attempts to resize an image, proportionally, to fit inside a 100 x 100 box:

<cfscript>

	img = imageNew(
		source = "",
		width = 16,
		height = 2000,
		canvasColor = "ff3366"
	);

	width = imageGetWidth( img );
	height = imageGetHeight( img );
	boxSize = 100;

	// When scaling the image, whichever dimension has the largest magnitude becomes
	// our limiting factor. This is the magnitude that drives the proportional scaling.
	sizeConstraint = max( width, height );

	// We only need to resize the image if some part of it doesn't fit inside the box.
	if ( sizeConstraint > boxSize ) {

		// CAUTION: In earlier versions of Lucee, this will not work because the
		// proportional scaling of the image will cause the WIDTH to be LESS THAN 1. As
		// such, the underlying Java code will try to create a canvas of WIDTH = 0, which
		// is invalid.
		imageScaleToFit( img, boxSize, boxSize, "highestPerformance" );

	}

	imageWrite( img, "./output-scaled.png" );

</cfscript>

As you can see, the image is highly oblong. Meaning, one dimension (height: 2000) is much larger than the other dimension (width: 16). These extreme proportions cause one of the dimensions to be scaled-down to less-than-one when trying to fit inside the box:

  • Height: 2000 => 100
  • Width: 16 => 0.8 (less than 1)

Therefore, when the underlying Java code goes to scale the image, casting the scaled-width to an int, it throws an error because the width is truncated as 0:

imageScaleToFit() throws an error when one of the dimensions scales down to zero in Lucee CFML.

This manifests itself in at least two different errors, depending on the version of Lucee being used:

  • invalid size for image
  • Width (0) and height (100) cannot be <= 0

To get around this issue, I am going to explicitly calculate the new dimensions and then use the imageResize() function instead of the imageScaleToFit() function. This will allow me to control the exact dimensions of the resultant canvas.

<cfscript>

	img = imageNew(
		source = "",
		width = 16,
		height = 2000,
		canvasColor = "ff3366"
	);

	width = imageGetWidth( img );
	height = imageGetHeight( img );
	boxSize = 100;

	// When scaling the image, whichever dimension has the largest magnitude becomes
	// our limiting factor. This is the magnitude that drives the proportional scaling.
	sizeConstraint = max( width, height );

	// We only need to resize the image if some part of it doesn't fit inside the box.
	if ( sizeConstraint > boxSize ) {

		// In order to get around the proportional scaling issues in earlier versions of
		// Lucee, we cannot rely on the auto-scaling of the image. Instead, we have to
		// explicitly calculate the dimensions and then use the imageResize() function
		// instead of the imageScaleToFit() function.
		scalingFactor = ( boxSize / sizeConstraint );

		// Make sure none of the scaled values drop below 1 - the scaled image has to
		// have non-zero dimensions.
		scaledWidth = max( fix( width * scalingFactor ), 1 );
		scaledHeight = max( fix( height * scalingFactor ), 1 );

		imageResize( img, scaledWidth, scaledHeight, "highestPerformance" );

	}

	imageWrite( img, "./output-resized.png" );

</cfscript>

As you can see, in this version, I am using the fix() and max() functions to ensure that neither of the scaled dimensions drops below 1. Then, I call the imageResize() function with the explicit dimensions to achieve the appropriate scaling.

Like I said above, this does not appear to affect the latest release of Lucee CFML; however, since I am not on the latest version of Lucee - and because there wasn't any Google love for this particular error - I wanted to share my work-around.


Reader Comments

@All,

I did find this issue logged in the Lucee JIRA site:

https://luceeserver.atlassian.net/browse/LDEV-2328

... it says that it is "awaiting approval"; so I am not sure if it is related to the issue I am talking about. It looks like the same issue; but, as I said in my post, this issue does not seem to manifest itself for me in the latest release of Lucee (5.3.2.77). As such, it could be different aspects of the same issue, addressing different parts? Not really sure.

Reply to this Comment

@All,

On taking a second-look at that JIRA ticket, it looks to be specifically about the imageResize() function; but, it expresses itself as the same Java error.

Reply to this Comment

The Lucee JIRA bug looks like it is different. It only errors out if a 4th non standard image quality parameter is added, like:

imageResize(img,100,'','hermite');

The following does not cause an error:

imageResize(img,100,'');
Reply to this Comment

Ben. This is a little off topic. But, I want to introduce mark up to my Blog comments. Which CF library do you use to convert mark up into HTML? Thanks

Reply to this Comment

@Charles,

Ah, ok cool. Yeah, to be honest, I didn't have the best patience to read the entire ticket :P

re: Blog Comments, as per the comments in the other post (which I just read), I run the raw user-comment through Flexmark to convert from Markdown to HTML. Then, I run the HTML through the Anti-sammy project (with very strict rules) to validate it and make sure the user didn't try to add anything malicious. Definitely use both as they go hand-in-hand and work towards different concerns.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
NEW: Some basic markdown formatting is now supported: bold, italic, blockquotes, lists, fenced code-blocks. Read more about markdown syntax »
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.