A reader asked me this morning if ColdFusion 8 can create images from URLs. This is often used to provide a snap shot of a remote site. Turns out this is relatively easy. Damon Cooper of Adobe showed an example of this a few weeks ago. It takes all of two tags:
<cfdocument src="http://www.raymondcamden.com" name="pdfdata" format="pdf" />
<cfpdf source="pdfdata" pages="1" action="thumbnail" destination="." format="jpg" overwrite="true" resolution="high" scale="25">
The first line simply uses cfdocument with the src attribute. I point to a URL (in this case, my blog) and store the result in a PDF variable.
Next I use the cfpdf tag to create a thumbnail. I specify the JPG format, use a high resolution, and set a scale to 25% just for the heck of it. Also note I only do page 1. By default the cfpdf/action="thumbnail" tag will create a thumbnail for each page of the PDF, but all we really want is the first page.
That's it. Done. Complete. Simple as pie. But of course I had to go a bit crazy and make a UDF out of it. The code below allows you to pass a URL (and an optional scale). It will then handle making the image, reading it into a CF8 Image object, deleting the file, and returning the object. You can then save it, or do whatever. For my tests, I did:
<cfset myimage = getThumbnail("http://www.coldfusionjedi.com",30)>
<cfimage action="writeToBrowser" source="#myimage#">
The "writeToBrowser" action lets me test without actually saving a file, but I believe it doesn't work in IE. (Not that I care.) Enjoy, and let me know how it works for you. I'll probably add options to let you specify an image type as well.
The image quality is pretty good I think. It is not the same as what you see from Firefox, but for a thumbnail, I think it works ok:

<cffunction name="getThumbnail" returnType="any" output="false">
<cfargument name="url" type="string" required="true">
<cfargument name="scale" type="numeric" required="false" default="25">
<cfset var pdfdata = "">
<cfset var prefix = replace(createUUID(),"-","_","all")>
<cfset var myimage = "">
<!--- make the pdf --->
<cfdocument src="#arguments.url#" name="pdfdata" format="pdf" />
<!--- write out the image --->
<cfpdf source="pdfdata" pages="1" action="thumbnail" destination="." format="jpg" overwrite="true"
resolution="high" scale="#arguments.scale#" imagePrefix="#prefix#">
<!--- read it in --->
<cfset myimage = imageNew(expandPath('./#prefix#_page_1.jpg'))>
<!--- clean it up --->
<cffile action="delete" file="#expandPath('./#prefix#_page_1.jpg')#">
<cfreturn myimage>
</cffunction>
Archived Comments
What in the name of all that is holy is a 'snap snot'?
Dude I have no idea what you are talking about. (Whistles innocently)
Is the CFDocument generation of HTML any better than previous editions? IIRC it didn't support some/many CSS attributes.
Ray: idea for riaforge, automated application screenshots - give it a URL to where your app is set up as a demo, have it automatically grab a screenshot and store in the project. For a rainy day.
Cool! So maybe...then a Flash remoting CFC could take a screenshot of a site...and return that as a bytearray so it could be rendered in the Flash player? That would rock.
great!
I've been wanting to be able to do that for ages!
BD has a "jpg" format on their cfdocument, I was hoping Adobe would think this was a good idea too!
@Damien: I don't really know. I definitely saw oddities with my site being rendered - BUT - I could still read the site - I could still recognize it - so it was good enough I think.
Thanks Ray,
I knew if there was a way you would know how.
I think the quality is prety good, and while the CFDocument might not render every element perfectly, which browser does?
If you add in some IMAGE tags to dress up the final result, crop, put a border etc, would work well in lots of situations.
Nice solution. Just reading this, I have to wonder what the server cpu overhead would be if you are running that on every load. Maybe doing it once and saving the image if NOT fileExists.
I'll try it out and check out how much megahurtz it steels.
Great, this should be a new question on the coldfusion cookbook
Note that the writetobrowser action now writes the file to a disk cache and emits an img tag that references the CF file caching servlet.
Should work in any browser.
Thanks Tom. I wasn't sure about the IE thing.
why would the src attribute not be available to me
error:Attribute validation error for tag CFDOCUMENT.
You are using CF8, right?
MX7 - damn, soes this mean it does not work...I've been struggling with this for 2 days.
but even in Dreamweaver 8, the attribute doesn't show up. ) i have CFMX7 on the server and 8 on my machine.
Correct. Sorry. FYI, to make it work with DWMX8, I mean the editing, you need to get the updated tag library from labs. I believe. I'm not a DW users. (*cough*CFEclipse*cough*)
Wow, that's really cool. I didn't even think about the possibilities of a format="jpg" on the cfpdf tag. Good call Adobe.
What css media type does cfdocument use/recognise. I use a media type of screen and all I see is an unstyled page in the my thumbnail. Try pointing your code to: www.abingdon.org.uk
Ray, when I use your code, some thumbs have missing "sections" in them (they are blank or white). It seems that Flash does not get rendered in the thumbnail either. It also seems that some photos on simple HTML do not get rendered as well. Any idea as to why or how to improve on the accuracy of the "grab"? Thanks!
Here are a few sample URLs that get a little funky:
http://www.caraccessories.com/
http://www.partstrain.com/
Is this worthy of another blog entry?
That is all done behind the scenes. You would need to talk to Adobe about that.
Ray, when you say talk to adobe, is there a specific place to go to talk to them. I have a whole series of PDF files that when I run the code, like CV stated above, I get nothing but a JPG with a blank page. After a day of searching and trying different work-arounds, I still can't seem to get this to work correctly. By the way, your site is by far the best CF 8 resource I have found. Thank you.
You have two choices.
One is support. I don't know if that is free or not. I've only ever called support when I needed help with my CS3 install (oh god, the pain, the pain!). You would use that option if you need something fixed now.
If you just want to file a bug report, then go to www.adobe.com/go/wish. You can also use that URL to request a new feature.
Please can someone tell me if it is possible to possible to create a PDF with updateable fields, then use ColdFusion & pdf forms to merge the data.
For those of you that are wondering why the thumbnail doesn't look 100% like your browser window rendering, I think cfpdf reads your page like it would look if you were to print it. So it's not going to look 100% like your browser window unless you have created a stylesheet for media type "print".
At least that's been my observation. Still very cool.
Hey Ray,
I just tried this, and using the exact code in your eg there im seeing this exception
writeToBrowser:
coldfusion.image.Image$ReadImageMetadataException: Unable to read image source properly. D:\Domains\xxxxxx.com\wwwroot\0DBCEC5F_19B9_F849_B29064C59F3AC984_page_1.jpg (The system cannot find the file specified)
any ideas why this wouldnt work?
Interesting. It definitely worked before. This is an old blog entry, so it must be something that changed in 801.
Ok, I got it fixed. Just change the last line of the UDF to:
<cfreturn imageGetBlob(myimage)>
This makes the UDF return the binary data of the image, not a 'native cf image' which is barfing when you try to use it. It barfs because we delete the original temp source we used. As I said, something must have changed in 801.
Anyway, the binary data CAN be used with writeToBrowser, or you can save it, whatever. Either way, it's fixed now.
I know this is late in the game on this topic but is there any reason the site image can not be placed in a cftooltip tag so the user will see the image in a tooltip box before clicking on the actual link. This would avoid having to use some of the ad supported apps like <a href="http://www.snap.com">Snap Shots</a>.
You can do it - if you do an IMG tag pointing to a CFM that makes the snapshot. What you have to watch out for is speed. You would definitely want to cache your snapshots.
Hi Ray
Always find your blogs useful. A related question to this thread - whats the easiest way to convert CFML output or text to an image in CF?
Tim
Check the CF8 docs for imageDrawText()
Was having trouble with creating thumbnails from a pdf with cfpdf. Looked at this site, than I found that saving the pdf to Acrobat 8, than running the code, rendered the pdf correctly.
Its not working in cf9
error :
An error: ERROR encountered loading http://www.xxxx.com/: java.net.ConnectException: Connection timed out: connect occured during the rendering process of this document.
Works fine in cf8 but getting Connection timed out error using cf9 what to do??
Are you sure the machine can hit the URL at all? Try a simple test w/ cfhttp.
when i tried to call the url using cfhttp in cf9 i got dis result
but is working fine in cf8
Charset [empty string]
ErrorDetail Connect Exception: Connection timed out: connect
Filecontent Connection Failure
Header [empty string]
Mimetype Unable to determine MIME type of file.
Responseheader
struct [empty]
Statuscode Connection Failure. Status code unavailable.
Text YES
any other method of creating thumbnail without using cfdocument and cfpdf ??
Interesting - what's the URL again?
Tried to call the url as given. It worked fine in CF8
<cfhttp
timeout="120"
throwonerror="false"
url="http://www.barclaybrowning.com"
method="get"
useragent="Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.12) Gecko/20080201 Firefox/2.0.0.12"
getasbinary="yes"
result="pdfdata"
>
This, to me, sounds like a DNS issue. Are the CF8 and CF9 servers on the same physical box? If not - try this. RDP to the box. Open a browser. And then try to hit the URL. If it fails, it means your box can't reach the remote URL. Check your network settings.
Ok thanks.. will try it
Please check the link
http://testw.wineweb.com/we...
My site jibuas.com
But
4cornerswinery.com
adastrawines.com
amethystwines.com
avanguardiawines.com
etc...
not working
You miss my point. It doesn't matter if it works for me. If your server can't hit those URLs, it is a network issue on the box. The fact that some other tool (webshot?) also fails seems to imply the same.
Wow! Much better than the buggy CFX tag I was using before! Thank you!
Another url that gets funky httpp://www.barretire.com
<cfdocument src="http://www.coldfusionjedi.com" name="pdfdata" format="pdf" />
<cfpdf source="#pdfdata#" pages="1" action="thumbnail" destination="." format="jpg" overwrite="true" resolution="high" scale="25">
Railo seems to require # # around pdfdata when set as source in cfpdf.
Ray great sample. I was wondering if you had a suggestion how to possibly postpone the the thumbnail snap shot until the page is fully loaded. Thanks
If you are talking about things that happen via JS or otherwise, then no, that can't be done.
Hi
Can we have a screen shot of the current page where I first need to login.
I have tried for your above code but every time it gives me screen shot of login page.
If you try to use a screen shot of a page that requires you to login, this is not going to work. The CFHTTP call starts it's own session to the remote URL.
You can, however, make it work with a page that requires http authentication. Just add username/password to the cfhttp tag.
Hi ray, I know i may be asking a weird question here, but the thing is i have provided users an interface to upload videos. The issue is that how can i generate the thumbnails of the videos to show to the users so when they click, they can see it else a static type. I know this question seems stupid but i thought let's share with you, if we can come up with some idea,
i am using CF 8
You have a couple options.
One is to use ffmpeg, a command line tool that is a) free, b) very powerful, and c) a bit hard to use. It can make thumbnails from various points of the video.
The other option is ZenCoder. It isn't free, but they have an incredibly easy to use API.
Hello Ray. I'm using CFPDF to create thumbnails from a directory with a bunch of PDFs. Each of these PDFs is some artwork done. I may have 10 or i may Have 40 PDFs on that directory.
So I use the CFPDF within a CFFTP tag to loop trough the directory where the PDFs are and then create the thumbnails.
My problem is that when I have 40 PDFs, since I'm using a shared server, my script gets timed out. Is there any way to improve the performance of the thumbnails creation? Am I using more server resources by setting the "scale" property to, let say "10"? Should I reduce the size of my source PDF?
Thank you!
While you could possibly simply the operation of each generation, what if you simply did 10 at a time? Ie, your code runs on a schedule, hits the directory, and only does the first 10 it finds that do NOT have thumbnails generated?
Basically this works for a billing system.
My client is a photographer / packager. When he bills his clients, he always needs to send a contract sheet: a PDF with the thumbnails of what he is billing.
I can't think of any other way to do it other than at the time he creates the invoice. I could use CFPDF action = "optimize" to reduce its size, but I guess I'd be asking for more resources to the server. So far, my only solution (the one I can think of) is to create the thumbnails of already optimized PDFs. That means uploading lower res PDFs before the contract sheet is created.
@Dani,
I have the same time out issue with my host and did like Ray suggest. Added a field to database (ThumbCreated) looped though what I figure out I could before timeout if the Records were GT the timeout I would <cflocation to start again to start the timer again.
How do the PDFs end up in the directory though? Can't you take _that_ process and make the thumbnails right then?
@Mike: what you mean is to split the process? For example, I get the amount of PDFs I have in the directory and then through a loop a split the thumbnail creation process?
@Ray: my client uploads the PDF manually via FTP since is what he's use to. I couldn't find a multiple upload via CFFTP (mind that those PDFs are about 3 to 5 megs each).
Is he FTPing to your server? If so - you can use an Event Gateway to notice changes, or just use a scheduled task to scan the directory every few minutes.
I'll try that!! Thank you!
On another subject, I just noticed that my PDF created by cfdocument gets huge when embedding images on it.
Do you know of any fix or trick? I'm using CF 9.
None outside of running the optimize action.
Yup, it drops the size from 9.3 to 2.8 megs, but it does not give me the open in browser option.
So if I don't optimize, and I don't put a filename attribute, then Firefox asks me what to do.
As soon as I put the CFPDF tag to optimize, it saves the file, I don't get the Firefox window.
I'm a bit stuck.
"Yup, it drops the size from 9.3 to 2.8 megs, but it does not give me the open in browser option."
Err - why would it? It's modifying a file. If you want the user to download it, then you would serve it like normally do - with cfheader/cfcontent.
It's weird, when I try it, I have the Firefox windows that asks me to choose, but it is a 0 kb file (I didin't want to reduce it that much). What the code does is it saves the file on the server and then, in theory, in optimizes it and tell FF to ask me what to do.
Here is the code (i put it right after my closing cfdocument tag):
</cfdocument>
<cfheader name="Content-Disposition" value="inline; filename=thumbs_#URL.id#.pdf">
<cfcontent type="application/x-pdf">
<cfpdf action = "optimize"
source = "invoice/thumbnail_#URL.id#.pdf"
overwrite = "yes"
algo = "bilinear"
pages = "*" />
Oh no - that's not going to work. You are using cfdocument to generate a PDF in a variable thats served to the user immediately. You need to save the document to the file system. You can use the filename attribute of cfdocument to save it. You then use cfpdf on that file. You then 'serve' it up using cfheader/cfcontent.
but...that's what I'm doing...
<cfdocument format="pdf"
margintop = "0"
marginbottom = "0"
marginleft = "0"
marginright = "0"
fontembed="no"
overwrite="yes"
filename="invoice/thumbnail_#url.id#.pdf">
Weird. Maybe you can show the entire page of code? Please use pastebin.
How do I use pastebin?
Go to pastebin.com.
like this?
http://pastebin.com/sh3BLS0p
http://pastebin.com/3a52yA77
You forgot to actually serve the data:
<cfheader name="Content-Disposition" value="attachment; filename=thumbnail_#URL.id#.pdf">
<cfcontent type="application/x-pdf">
This doesn't actually include the real data. Add file=".." to your cfcontent tag with the value being the same as filename.
Thank you Ray, but it keep throwing me a "file not found" error.
So here are my steps:
1) Generate PDF (9 megs)
2) Optimize it with CFPDF action optimize. (at this point I see it being saved on the server with 2.8 megs)
3) Serve the file using the following code:
<cfpdf action = "optimize"
source = "invoice/thumbnail_#URL.id#.pdf"
overwrite = "yes"
algo = "bilinear"
pages = "*" />
<cfheader name="Content-Disposition" value="attachment; filename=thumbnail_#URL.id#.pdf">
<cfcontent type="application/x-pdf" file="invoice/thumbnail_#URL.id#.pdf">
Sorry, the code in my previous comment should start with <cfheader
Looks like the path in <cfheader FileName is wrong.
"thumbnail_#URL.id#.pdf"
@Mike: No - the filename in cfheader is made up - it can be anything.
@Dani - try using a full path, not relative.
Thanks to both!
@Ray, yes, I just read the documentation. It did work!
Thanks for your constant help.
Hi,
I have issue with client variables in cf10, when i creating client variables in one page it was effecting in that page only and i am not able to access that variables in another page in application. here is code in application CFC
this.Name = "test";
this.ApplicationTimeout = CreateTimeSpan(0,0,0,0);
this.ClientManagement= "yes";
this.ClientStorage = "clientstorage";
this.SessionManagement = true;
this.SessionTimeout = CreateTimeSpan( 0, 0, 20, 0 );
this.SetClientCookies = "yes";
this.SetDomainCookies = "no";
this.ScriptProtect = "all";
Raju, this comment is not on topic. I see you have already emailed me the same question and I will try to reply.
is this: >> this.ApplicationTimeout = CreateTimeSpan(0,0,0,0);
a mistake or you did it on your own, take a look