curious one this.
I'm working on a process that generates PDF files, combining data from various sources. The last piece of this process I need to complete is merging in image files.
This is actually fairly straightforward but the problem I have is the image files aren't stored with file extensions. Locally, I can change the filename, but in production this isn't an option.
So because a filename looks like : B71637CB-A49C-0653-EF813918736BDEB7
This will not work:
<cfimage action="writeTobrowser" source="#FilePath#>
Same with
<img src="#FilePath#">.
So, any ideas on how I can work around this? Here's the code in context:
<cfdocument format="PDF" name="report" filename="#fileToDownloadimage#" overwrite="yes">
<cfdocumentsection>
<cfimage action="writeTobrowser" source="#FilePath#.jpg">
</cfdocumentsection>
</cfdocument>
So here's what ended up working:
<cfdocument format="PDF" name="report" filename="#fileToDownloadimage#" overwrite="yes">
<cfdocumentsection>
<cfset fileObject = fileReadBinary('#FilePath#') />
<cfset imageObject = imageNew(fileObject) />
<cfimage action="writeTobrowser" source="#imageObject#">
</cfdocumentsection>
</cfdocument>
Alex's answer got me down the right path so I'm perfectly happy to leave the kudos in place, cos I wasn't getting anywhere near this!
If you need to embed the images into the PDF document, try HTML's inline image capabilities:
<cfset fileLocation = "/path/to/images/B71637CB-A49C-0653-EF813918736BDEB7">
<cfset imageContent = fileReadBinary(fileLocation)>
<cfset imageContentAsBase64 = toBase64(imageContent)>
<cfoutput>
<img src="data:image/jpeg;base64, #imageContentAsBase64#" />
</cfoutput>
You can try creating a cfm page that outputs your content using cfcontent as in:
<cfcontent type="image/jpg" file="path/#fielpath#">
Then you would you include THAT cfm page as the source for your image as in
<img src="myFancyImageOuputer.cfm?image=#filepath#">
This should work but it may require some trial and error. :)
Ray has some additional tips here:
http://www.raymondcamden.com/2007/09/14/Serving-up-CFIMages-via-Image-Tags-and-a-NonCF-Friday-contest
Related
I am trying to create a search method to attach files on my outbound emails. I need to search inside a folder and find all the files that begin with a certain character and then attach them to the email. I just need a head start on how you could create such a search method so any pointers or links to references will be appreciated.
This is What I have so far but it does not seem to work correct when I use a path instead of GetBaseTemplatePath()
<cfscript>
attributes.attachments = 2011093475839213;
</cfscript>
<cfset Directory = "E:\sites\Example.com\FileFolder\#attributes.attachments#">
<cfset CurrentDirectory=Directory>
<cfset CurrentDirectory=ListDeleteAt(CurrentDirectory,ListLen(CurrentDirectory,"/\"),"/\")>
<cfoutput>
<b>Current Directory:</b> #CurrentDirectory#
<br />
</cfoutput>
<cfdirectory action="list" directory="#CurrentDirectory#" name="result">
<cfdump var="#result#">
When I change the code slightly by
<cfset CurrentDirectory=GetBaseTemplatePath()>
My code works and I get the list of all the files in my current directory. Do I have a mistake on my path that I cannot see?
This is my CFMAIL part which I do have an issue with.
When I dump my #result# query I get all the files inside the folder. Then I get this error:
The resource 2011093475839213.pdf was not found.
The root cause was: ''.
I do receive an email despite the error, just not the attached files.
<!--- Email Test --->
<CFMAIL FROM="user1#example.com" TO="user2#example.com" SUBJECT="Test" type="HTML">
<P> This is the attachment test</P>
<p> For this test to be successful, we need to receive some file attachments with this email</p>
<cfloop query="result">
<cfmailparam file="#result.name#" disposition="attachment">
</cfloop>
</cfmail>
<!--- Email Test Ends --->
The cfdirectory tag will allow you to search through folder(s) with a specific pattern. Using the query it returns, you can loop over it and attach all the files you need to the email.
http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7f99.html
Something like this:
<cfdirectory action="list" directory="#myDirectory#" name="myDir">
<cfmail subject="My Subject" to="yourAddress" from="myAddress">
My Message
<cfsilent>
<cfloop query="myDir">
<cfif Left(myDir.name,1) eq "Z">
<cfmailparam file="#myDirectory & myDir.name#">
</cfif>
</cfloop>
</cfsilent>
</cfmail>
I'm not having any issues writing the content to the .doc file. The problem I'm having is getting the file to NOT download to the user's browser automatically after creation. I just want to have the .doc file created in the background, then the user can download the file from a web page at anytime. Here's the code I'm working with:
<cfheader name="Content-disposition" value="filename=Quote_#arguments.QuoteNumber#_#arguments.Revision#.doc">
<cfcontent type="application/msword">
<cfoutput>#WordDoc#</cfoutput>
<cffile action="copy" source="#application.AbsPath#\media\quotes\BlankQuote.doc" destination="#application.AbsPath#\media\quotes\Quote_#arguments.QuoteNumber#_#arguments.Revision#.doc" />
<cffile action="write" file="#application.AbsPath#\media\quotes\Quote_#arguments.QuoteNumber#_#arguments.Revision#.doc" output="#WordDoc#" />
You're problem is the <cfheader> tag... that's what is triggering the doc to open.
I would do something like this instead.
<cfsavecontent variable="whatever">
<cfoutput>#WordDoc#</cfoutput>
</cfsavecontent>
<cffile action="write" file="#application.AbsPath#\media\quotes\Quote_#arguments.QuoteNumber#_#arguments.Revision#.doc" output="#whatever#" />
cffile is giving a head ache now.
My cfm is like this -
`
<cfif session.ismac and session.browsermake eq "firefox">
<cfset size = "55">
</cfif>
<cfset onChange = "document.frmMain.submit1.disabled = true;setdisplayname(this,this.form.dummy);">
<cfif displayname EQ "">
<cfset size = "document.frmMain.submit1.disabled = true;setdisplayname(this,this.form.displayname);">
</cfif>
<cfinput type="file" name="File#thisUploader#" id="File#thisUploader#" size="#size#" onKeyPress="return false;" onchange="#onChange#">
`
and in my cfc the code is like this -
<cffile accept="image/*" action="upload" destination="#application.artworkfilepath#\bulkuploads\#session.loginname#\#form.category#\" filefield="form.File#thisUploader#" nameconflict="makeunique">
and if I dump - <cfoutput>
You uploaded #cffile.ClientFileName#.#cffile.ClientFileExt#
successfully to #cffile.ServerDirectory#.
</cfoutput>
<cfabort>
I get corrct things and no error.
But when i look into the folder there is nothing.
Anyidea? I have added the dump of cffile now. What do you make out of it?
cfform code is like this <cfform id="frmMain" name="frmMain" action="process_multi.cfm" enctype="multipart/form-data" target="_self" method="post">
do a fileExists() directly after the statement and let us know what that says...
you don't have a directorywatcher on the directory do you?
Your cffile nameconfict attribute is set to makeunique, which tells ColdFusion to rename the file to something new when it arrives at the server--if the file already exists.
However, you are using cffile.ClientFileName and cffile.ClientFileExt to refer to the file file--which maps to the unchanged file name as it was received during upload.
Change your code references to cffile.ServerFileName and cffile.ServerFileExt for the final renamed result.
I have been having problems with toBase64() for awhile. I am hoping someone can tell me why CF toBase64() seems to lost something i.e. in my example it reduces the quality of an image.
I have a solution (see last code example below), but I hate not understanding why and would love to solve this is CF.
If anyone would be so kind to run the code below, you would then see that after toBase64 conversion the image quality is bad. Nothing major, but it does not look as good after the encoding. If you have never noticed, then try it, you will see what I mean.
Does anyone know why, or how to solve this in CF?
<!--- EXAMPLE 1 --->
<!--- GET IMAGE - --->
<cfset image = ImageNew("test.png")>
<!--- BEFORE GOOD--->
<cfimage action="writeToBrowser" source="#image#" >
<cfset image = toBinary(toBase64(image)) />
<!--- AFTER --->
<cfimage action="writeToBrowser" source="#image#" >
<!--- Example 2 --->
<cfset image = ImageNew("test.png")>
<cfset FileWrite(expandPath('./converted.image'),toBinary(toBase64(image))) />
<!--- without any cfimage processing, the outputted file is a JPEG --->
My solution was to use a java add-on and everything seemed ok but for reasons I won't go into here not something I can do live.
image = createObject("java","it.sauronsoftware.base64.Base64").encode(image);
toBinary(image );
Sample image output of code above can be found here: http://i56.tinypic.com/29fwiq.png
First is before toBase64 second is after, you can see the image has lost a bit of quality after toBase64 function on the second output.
Update: As pointed out by Peter, the issue seems to be with the automatic output/conversion code within the ImageObject to provide the binary output for the toBase64 function to encode.
Update I have submitted this as a bug in CF 9.0.1, please vote for bug 3177303
https://bugbase.adobe.com/index.cfm?event=bug&id=3177303
use toBase64(imageGetBlob(myImg))
see: http://blog.dkferguson.com/index.cfm/2010/4/27/All-your-base64-are-not-equal
I see no one has mentioned the imageWriteBase64() function that has been in ColdFusion since version 8. I am not sure why.
http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-796b.html
I have been using it this week for the first time and it seems to be going great. I have not noticed any problems with quality loss.
<cfdirectory action="list" directory="#expandPath('./images')#" name="imageDir" type="file" />
<cfloop query="imageDir">
<cfset ext = listLast(imageDir.name, ".") />
<cfset name = imageDir.name />
<cfset imagePath = imageDir.directory & "/" & name />
<cfset imageFile = imageNew(imagePath) />
<cfset imageWriteBase64(imageFile,"#expandPath('./base64')#/#name#.txt",ext, true) />
</cfloop>
I have a service on a Coldfusion 9 server that creates image banners on the fly for us. A separate machine has to save these files with something like:
wget http://myserver.com/services/local/bannerCreator/250x250-v3.cfm?prodID=3&percentSaving=19
The problem is that I can't think of how to get coldfusion to write out binary data without using a temporary file. At the minute the image is just displayed as an image tag like this:
<cfimage action = "writeToBrowser" source="#banner#" width="#banner.width#" height="#banner.height#" />
Any ideas? Or should I just use a temporary file?
I can't test because you're not giving any example code for how your images are generated, but have you tried something along this line?
<cfcontent reset="true" variable="#imageData#" type="image/jpg" />
Update: So I went ahead and created my own image; I'll assume you're doing something similar. This works perfectly for me:
<cfset img = imageNew("",200,200,"rgb","red") />
<cfcontent variable="#toBinary(toBase64(img))#" type="image/png" reset="true" />
This works without writing to file, and without using a virtual file system ("ramdisk")
If you have the binary bytes of an file/image, you can replace the output buffer with it's contents like so:
<cfscript>
// eg. this is how you get a file as a binary stream
// var fileBytes = fileReadBinary( '/path/to/your/file.jpg' );
// get the http response
var response = getPageContext().getFusionContext().getResponse();
// set the appropriate mime type
response.setHeader( 'Content-Type', 'image/jpg' );
// replace the output stream contents with the binary
response.getOutputStream().writeThrough( fileBytes );
// leave immediately to ensure no whitespace is added
abort;
</cfscript>
Pretty much what <cfcontent> does when you use reset="true"
The advantage of this method over <cfcontent> is that we can write it inside our cfscript based cfcs.
I found the solution above
<cfcontent variable="#toBinary(toBase64(img))#" type="image/png" reset="true" />
to not quite work for me.
Setting type="image/png" is just setting the mime type of the response. I don't think it's necessarily encoding the image as PNG. As such, generating a transparent png (image type "argb") was giving me odd colours, when compared to the <cfimage action = "writeToBrowser"...> method.
I figured that somehow I needed to explicitly encode the image data as PNG and output the binary data directly.
With some digging around in the underlying java, I came up with this, which so far seems to work for me.
This example draws a transparent png with a black circle.
<!--- create the image and draw it --->
<cfset img = ImageNew("", 23, 23, "argb")>
<cfset ImageSetDrawingColor(img, "black")>
<cfset ImageDrawOval(img, 0, 0, 21, 21, true)>
<!--- get the response object --->
<cfset response = getPageContext().getFusionContext().getResponse()>
<!--- set the response mime type --->
<cfset response.setHeader('Content-Type', 'image/png')>
<!--- get the underlying image data --->
<cfset bImage = ImageGetBufferedImage(img)>
<!--- get the magical object to do the png encoding --->
<cfset ImageIO = createObject("java", "javax.imageio.ImageIO")>
<!--- encode the image data as png and write it directly to the response stream --->
<cfset ImageIO.write(bImage, "png", response.getResponse().getOutputStream())>
I hope that helps someone!
Take out the height and width attributes and add the format attribute:
<cfimage action = "writeToBrowser" source="#banner#" format="png" />
wget should honor the redirection to the physical file CF creates in the CFFileServlet folder but if it doesn't there is a flag you can set to make it --max-redirect=10.
And as you suggest, a temporary file would work too. Just write the file and use cfheader and cfcontent to write it out. Just make sure to make the temp file name more unique.
<cfimage action="write" destination="tempfile.png" source="#banner#" format="png" />
<cfheader name="content-disposition" value="attachment; filename=banner.png" />
<cfcontent file="tempfile.png" deletefile="true" type="image/png" />
I do a similar thing, and you need to combine using tags and cfscript. There are image functions that are required. There are a lot of image functions available, once you have an image in memory as a variable. You can get the image into memory using CFFILE or CFHTTP or a number of other ways.
In my case, I read an image file into memory using CFIMAGE tag, then manipulate it with CFSCRIPT image functions by adding text to the bottom, then outputting the resulting image as a .png (or a .jpg if you prefer) to the browser. The only file stored on the server is the original image file. In your case instead of reading in an image you'd call it using a cfhttp tag as you already do. Here's my code:
<!---Get the image for processing ...--->
<cfimage action="read" source="#application.approotABS#\webcam\webcam.jpg" name="CamImage" />
<!--- prepare the text for overlay --->
<cfscript>
attr=structNew();
attr.font = "Arial";
attr.size = 15;
ImageSetDrawingColor(CamImage, "white");
ImageDrawText(CamImage, 'LIVE FROM STUDIO 1', 18,(ImageGetHeight(CamImage)-54), attr);
ImageDrawText(CamImage, '#ShowOnNow.showname#', 18,(ImageGetHeight(CamImage)-36), attr);
ImageDrawText(CamImage, datestring,18,(ImageGetHeight(CamImage)-18), attr);
</cfscript>
<!--- further down the page, output the manipulated image: ---->
<div class="webcam">
<cfimage action="writeToBrowser" source="#Camimage#" >
</div>
You can see it in action at http://hawkesburyradio.com.au/index.cfm?pid=111538
(I am using CF9 with Windows Server )