Could CF image processing be killing your ColdFusion server? Explanation and solutions.
Note: This blog post is from 2012. Some content may be outdated--though not necessarily. Same with links and subsequent comments from myself or others. Corrections are welcome, in the comments. And I may revise the content as necessary.Are you having slow ColdFusion pages and wondering what may be the cause? There can of course be many root causes, but a common one that I'm finding lately as I help people is due to using certain of CF's image processing features, especially resizing such as to create thumbnails after a file is uploaded (or when many files are uploaded).
Such folks may be using the CFIMAGE action="resize" tag, or the imageResize() or ImageScaleToFit() functions to do resizing. (Or they may be also processing images using ImageRotate, ImageShear, or ImageTranslate, though the defaults for those are not problematic like the resize/scale tag/function processing).
The "problem" (if this is the cause of a slow page) is due to a default "interpolation" setting for CFIMAGE resizing, imageResize, and ImageScaletoFit. The default may not perform well at all. The good news is that the value is configurable, and you can test to compare quality/performance of difference values, as will explained below. There are still some other things to consider also. (If you're currently using CFIMAGE to do resizing, jump to the last section of this entry to see an example of code switching from the "slow" approach to the faster one. But really, you ought to read the rest of this entry to understand what's being proposed.)
While I offer all the info here for your consideration, if you need help implementing the solution, or better understanding how to find and resolve these or other problems affecting your CF server performance, see more on my CF server troubleshooting consulting services.
Problem: Default "Interpolation" value is "highestquality"
Solution: There are alternative values for "interpolation"
So the first "good news" is that there is a range of options one can set for this interpolation value, and the opposite one is "highestperformance". For many people, changing to that value has no negative impact on quality (again, that may depend on the image, its size, what you're using the result for, etc.) but it offers a GREAT improvement in performance. You need to test for yourself.
Implementation 1: Controlling Interpolation in the CFIMAGE tagSo if you use CFIMAGE action="resize", what can you do? Well, the "bad news" is that for CF8 and CF9, the CFIMAGE tag has no means for you to affect the interpolation value. It has no INTERPOLATION attribute.
Some great news is that CF10 adds this attribute (for use specifically with action="resize"), but note that the default is still "highestquality", so you will want to consider changing it. See the docs for CF10 on CFIMAGE for the range of INTERPOLATION attribute values.
If you're on CF 8 or 9, though, you will need to consider changing your code to use the imageResize() function instead, which is discussed in the next section.
(Note that, for now, only the action="rewrite" option for CFIMAGE makes any use of interpolation at all.)
Implementation 2: Controlling Interpolation in the imageResize(), imageScaleToFit(), and other image processing functions
In all three releases (CF 8, 9, and 10), the imageResize() function--and the perhaps less-well-known imageScaleToFit()--all have an available (optional) argument for controlling the interpolation value. It's the 4th arg in both imageResize() and imageScaleToFit(). But in all three releases, the value for each again defaults to "highestquality".
Specifying it as "highestperformance" (or some value between the two) again may have a noticeable effect on improving performance without much loss of image quality. See the docs on these functions (here's a link to the CF9 CFML reference.) Test things for yourself, and report here if it helps.
(As an interesting aside, the docs suggest that while imageRotate(), imageShear(), and imageTranslate() functions also have an optional interploation argument, theirs each defaults to the fastest of the values they offer. One wonders why Adobe chose for resizing and scaling to opt for the opposite values.)
Changing from CFIMAGE will require reading and writing the file a new way
Finally, if you do have to change from using CFIMAGE to the imageResize() function (not required for CF10), you may also need to deal with how to load the image from disk into memory, and write it out, if you're also doing that in the one tag.
CFIMAGE has both a SOURCE and DESTINATION attribute which can point to a file on disk to be read/written. The imageResize() function's does not support that. Instead, its first ("name") argument instead expects to be passed a variable with an image in it, such as is created by other CFML image-processing tags or functions. imageNew() can read an image from disk into memory.
Similarly, the result of calling imageResize() is a manipulation of that image object in memory. The function has no means to write out the result. That can be done with either imageWrite() or another CFIMAGE action="write".
So to change from using the tag-based resize to function-based, you may need to add a line of code to load the image from disk, such as using imageNew(), and one to write the resulting image to disk, such as using imageWrite().
Consider the following tag-based resize code, which reads, resizes, and writes out an image (available in the CFDOCS directory, if you installed that with ColdFusion):
That could be re-written as either:
or (for those who prefer script to tags):
Again, test things for yourself to determine whether changing to highestperformance results in an image quality you (and your users) can find acceptable. See the docs for a range of alternative options to consider. And if you move up to CF10, note that you can solve the problem with CFIMAGE action="rewrite" by just adding the new INTERPOLATION attribute right onto the tag.
For more on the many (many) new features of CF10, check out my blog entry on the topic.
And again if you need help solving these or such other problems affecting your CF server performance, let me know how I can help, via my CF server troubleshooting consulting services.
Of course I welcome and encourage followup and feedback here on this particular problem. And for solutions to other such knotty CF troubleshooting challenges, see my cf911.com site of CF server troubleshooting resources.
For more content like this from Charlie Arehart:
Need more help with problems?
- Signup to get his blog posts by email:
- Follow his blog RSS feed
- View the rest of his blog posts
- View his blog posts on the Adobe CF portal
- If you may prefer direct help, rather than digging around here/elsewhere or via comments, he can help via his online consulting services
- See that page for more on how he can help a) over the web, safely and securely, b) usually very quickly, c) teaching you along the way, and d) with satisfaction guaranteed
BTW, if folks don't notice it, the fastest in his table, at .031 sec, is more than 50 times faster than the slowest (1.7 secs)! Sadly, I suspect most won't do the math, so it's a real good thing you mentioned the one taking 4-minutes. That should get their attention. :-)
I notice you also (in a comment on that entry) pointed to still another related entry of yours, which may interest folks reading this one:
That said, I notice that your entry refers to "resizing" but shows only imagescaletofit. There's no mention of CFIMAGE action="resize" or imageresize. If you don't mind, I'll add a comment mentioning cfimage action="resize" and imageresize, so that others may more readily find your blog entry if they go searching for those terms.
I'll also point to my entry here for still more info on changing from the one to the other, and also highlight that 50x improvement which your entry shows.
We can't have enough coverage of this problem (and the good news also that CF10 offers an easier workaround for CFIMAGE). Keep up the great work!
For example, on a 2600x1950 3.5mb JPG image, it took 297ms to read the image, 4,735ms to scale the image to 320x320 ("highestPerformance" = 1,922ms) and the resultant filesize was 56.9k ("highestPerformance" = 72.9k).
I switched to CFX_OpenImage (C++ tag) and it took 15ms to read the image, 469ms to scale the image to 320x320 and the resultant filesize was 20.2k and the quality looked consistent with the CFImage image.
After switching to CFX_OpenImage, we haven't encountered any more timeout issues... even when multiple images were concurrently being resized.
I'd be interested in comparing CF9 to CF10, but I'm guessing that it wouldn't come close to the performance we now have from using the free C++ tag.
That said, I would certainly not recommend someone update to CF10 "just for this one improvement", but if you did try it and it was faster, then the good news is that yes that speed boost would also come with CF10, as it comes on a much more updated JVM than what's in CF9.
If you may be tempted to check it out, please do report back what you find. But I'll understand that you may not be interested in changing code that you have now using the custom tag.
Hey, if either your info on that or mine on the jvm update helps someone, then it will have been worthwhile to have this added discussion here. Thanks for chiming in.
Do you know if CF10 still chokes on CMYK images? (If fixed, that would be a new feature.) This was another reason we switched to OpenImage as we got tired of informing graphic designers that their images were in the "wrong format." (In addition to CMYK, we are now able to read EPS images & generate JPG thumbnails.)
My client would be interested in upgrading to CF10 if PDF generation was better, but many of the new features weren't compelling enough because we are already doing the same thing using third-party libraries and modules.
I have CF10 + CFX_OpenImage installed on my developer workstation. I'll run the same tests & post the results.
Original image: 2600x1950 3.5mb JPG
Output Image: 320x320 max w/.80 quality
CFImage ImageScaletoFit "highestQuality": 2,255ms
CFImage ImageScaletoFit "highestPerformance": 383ms
OpenImage ImageScaletoFit: 280ms (w/verbose debugging enabled)
CFImage ImageRead (to get dimensions): 202ms
OpenImage: 7ms (w/verbose debugging enabled)
CFImage filesize: 56k
CFImage "highestPerformance" filesize: 73k (poor quality image)
OpenImage filesize: 20k
I wrote a CFLoop to perform the test 10 times & appended the execution times to an array to be averaged... here are those results:
CFImage_Read = 213
OpenImage_Read = 7
CFImage_imageScaleToFit = 2,272
OpenImage_imageScaleToFit = 243
CFImage_imageScaleToFit_Fast = 408 (poor quality image)
OpenImage_imageScaleToFit_usingCommands = 221
I set the output quality to 100% and none of the generation times were affected. Here are the outputted file sizes:
CFImage "highestQuality": 169k
CGimage "highestPerformance": 189k (noticeable degradation)
OpenImage: 122k (47k smaller)
Even though CF10's CFImage may be faster than CF9, I'll still use CFX_OpenImage for the performance gain, smaller file sizes & ability to work with CMYK/EPS images.
BTW, James, I did not assert that CF10 offered any performance gain for CFIMAGE (your last sentence). I said only that CF10 offered the option to control the interpolation differently than had been available in CF 8/9 (albeit, yes, changing that interpolation level in any release has improved performance for man). Still, thanks for offering your details of how there are still some challenges. Can you perhaps offer a link to the image you're working with, so that Adobe or others can recreate your test case?
And Russ, I can see that it is hard for Adobe to "just change the default". That would break backward compatibility for code that intentionally relies on the default being highestquality. But I can see an argument for letting that default be set at the server, application, or jvm config level. There are pros and cons to such configurability, though, so I appreciate the challenge Adobe would have addressing this problem.
Short of that, it's why I am writing this entry, to implore people to consider changing the interpolation value. Despite James' more unfortunate experience with certain kinds of files, I find that by far most people are definitely helped by changing the interpolation, so it seems very much worth trumpeting as an option to consider.
We didn't have any control over the dimensions of the JPG images that were uploaded. Some images were far larger than what we needed. (The images being uploaded were also resized to be used to generate PDF files.) When multiple users were uploading, it could take 80+ seconds to process each image & the CPU would be pegged at 100%.
If needed, I can provide a large JPG image to test, but we were experiencing really slow times on any images over 3,500 pixels wide taken by many different digital cameras.
As for your first paragraph, I acknowledged in the entry that there could be a tradeoff between performance and quality, but I pointed out as well that many folks find there to be none at all, and that the highestperformance (or any of the options between that and highestquality).
Let's leave it that yours is one of those experiences that was worse than most. I hope readers will not be discouraged to still consider everything else that was offered, in case it may well help them, as it has many who I've assisted in my consulting practice when faced with this being the root cause of poor performance.
"we fixed the issue where CMYK images were not working with 64 bit OS and MAC OS"
They also said they would hope to create a blog entry soon (on blogs.coldfusion.com) about it.
But if you or anyone who experienced the issue before might want to test it, perhaps you will find things have improved. If not, then besides reporting that here if you'd like (for the sake of the conversation), please do also then file a bug report at https://bugbase.adob..., so that they can address it.
I'd mentioned in an earlier comment above that Adobe would be coming out with a blog entry to discuss it. Shilpi did a few days later, at http://www.shilpikha... .
She clarified that the image resize improvements (with respect to CMYK issues) were made with respect to "Mac and 64bit OS".
If anyone has any remaining resize issues due to color, I'm sure they'd want to hear about it.
But again, per the main point of my blog entry here, please do be sure first to try changing the interpolation level, whether in imageresize or (in CF10, forward) with CFIMAGE.
I linked this blog post in the comments of the above one.
I have a follow up question to confirm what update you had applied (you mention there you were on 10, and a commenter there, Paul, mentions using 11 but doesn't clarify if he had this specific issue there). You can answer there and readers of this who are interested can take up the conversation there. :-)