CF: Saving a Fusioncharts graph as an image to email it - coldfusion

Does anyone have an example of this? Google is not my friend tonight. I have the newest version of FusionCharts. I'm trying to figure out how to save a graph as an image file to email it.
I know how to save and then insert images into HTML emails, and I've done this before with other graph products. I just cannot fine 1 good example of how to do this with Fusioncharts.
Thanks!

Use the following code in a template and point the imageSaveURL property at that template.
Your chart submits all necessary data for the chart to be reconstructed. In my example I'm serving it to the browser but you could save it locally and then attach to a cfmail if necessary.
I'm pretty sure I got this from the fusioncharts forums originally. This was updated for fusioncharts 3.1.
<cfif structKeyExists(Form, "width") >
<cfset width = int(Form.width) />
<cfelse>
<cfset width = int(Form.Meta_Width) />
</cfif>
<cfif structKeyExists(Form, "height") >
<cfset height = int(Form.height) />
<cfelse>
<cfset height = int(Form.Meta_Height) />
</cfif>
<cfif structKeyExists(Form, "data") >
<cfset Form.data = Form.data />
<cfelse>
<cfif structKeyExists(Form, "stream") >
<cfset Form.data = Form.stream />
</cfif>
</cfif>
<cfset user = viewState.getValue("user", structNew()) />
<!--- Impose some limits to mitigate DOS attacks --->
<cfif Not (0 lte width and width lte 5000)>
<cfthrow message="Width out of range." />
</cfif>
<cfif Not (0 lte height and height lte 5000)>
<cfthrow message="Height out of range." />
</cfif>
<!--- Check if we have the chart data --->
<cfif Not StructKeyExists(Form, "data") or Not Len(Trim( Form.data ))>
<cfthrow message="Image Data not supplied." />
</cfif>
<!--- Default background color is white --->
<cfif Not StructKeyExists(Form, "bgcolor") or Not Len(Trim( Form.bgcolor ))>
<cfset Form.bgcolor = "FFFFFF" />
</cfif>
<cfset gColor = CreateObject("java", "java.awt.Color") />
<cfset chart = CreateObject("java", "java.awt.image.BufferedImage") />
<cfset chart.init( JavaCast("int", width), JavaCast("int", height), chart.TYPE_3BYTE_BGR) />
<cfset gr = chart.createGraphics() />
<cfset gr.setColor( gColor.decode("##" & Form.bgcolor) ) />
<cfset gr.fillRect(0, 0, JavaCast("int", width), JavaCast("int", height)) />
<!--- Get rows with pixels --->
<cfset rows = ListToArray(Form.data, ";") />
<cfloop from="1" to="#ArrayLen(rows)#" index="i">
<cfset pixels = ListToArray(rows[i], ",") />
<!--- Horizontal index (x scale) --->
<cfset horizIndex = 0 />
<cfloop from="1" to="#ArrayLen(pixels)#" index="j">
<cfif ListLen(pixels[j], "_") eq 2>
<!--- We have the color and the number of times it must be repeated --->
<cfset color = ListGetAt(pixels[j], 1, "_") />
<cfset repeat = ListGetAt(pixels[j], 2, "_") />
<cfelse>
<!--- Background color; how many pixels to skip --->
<cfset color = "" />
<cfset repeat = ListGetAt(pixels[j], 1, "_") />
</cfif>
<cfif Len(Trim(color))>
<!--- If the hexadecimal code is less than 6 characters, prefix with 0 to get a 6 char color --->
<cfif Len(Trim(color)) lt 6>
<cfset color = RepeatString(0, 6 - Len(Trim(color))) & color />
</cfif>
<!--- Draw a horizontal line for the number of pixels we must repeat --->
<cfset gr.setColor(gColor.decode("##" & color)) />
<cfset gr.drawLine(JavaCast("int", horizIndex), JavaCast("int", i - 1), JavaCast("int", horizIndex + repeat -1), JavaCast("int", i - 1)) />
</cfif>
<cfset horizIndex = horizIndex + repeat />
</cfloop>
</cfloop>
<!--- Get writer for Jpeg --->
<cfset writer = "" />
<cfset iter = CreateObject("java", "javax.imageio.ImageIO").getImageWritersByFormatName("jpg") />
<cfloop condition="iter.hasNext()">
<cfset writer = iter.next() />
</cfloop>
<!--- Set Jpeg quality to maximum --->
<cfset jpgParams = CreateObject("java", "javax.imageio.plugins.jpeg.JPEGImageWriteParam").init( CreateObject("java", "java.util.Locale").init("en") ) />
<cfset jpgParams.setCompressionMode( jpgParams.MODE_EXPLICIT ) />
<cfset jpgParams.setCompressionQuality( 1 ) />
<!--- Write image to a memory stream --->
<cfset imageOutput = CreateObject("java", "java.io.ByteArrayOutputStream").init() />
<cfset writer.setOutput( CreateObject("java", "javax.imageio.stream.MemoryCacheImageOutputStream").init( imageOutput ) ) />
<cfset writer.write(JavaCast("null", 0), CreateObject("java", "javax.imageio.IIOImage").init(chart, JavaCast("null", 0), JavaCast("null", 0)), jpgParams) />
<!--- Stream the image to the browser (hint browser to display the Save dialog) --->
<cfset filename="whatever.jpg" />
<cfheader name="Content-Disposition" value="attachment; filename=""#filename#""">
<cfcontent type="image/jpeg" variable="#imageOutput.toByteArray()#">

Checkout out the latest blog post Export Chart Images at Server Side where two options (wkhtmltoimage and PhantomJS. ) has been described with step-by-step instructions for both.
For ColdFusion, you can try the below code:
For example:
<cfexecute name="C:\Program Files\wkhtmltopdf\wkhtmltoimage.exe" arguments="--javascript-delay 10000 http://docs.fusioncharts.com/charts/Code/MyFirstChart/ms-weekly-sales-no-animation.html savedimage.png" />
While executing the above script, we provide the following arguments:
Call wkhtmltoimage
Pass the URL of your webpage to it
Pass the path and name of the image file (with extension) where the image will be saved
If required, any additional delay to ensure the chart is completely rendered.

Related

CFspreadsheet adding a % to format a column

I am using CF10 and trying to add a % sign to a spreadsheet.
I am having an issue with adding a % sign on my 5th column entries. (Only the entries starting the second row (not the header) and not the blank cells when the query is done running.
<cftry>
<cfset objSpreadsheet = SpreadsheetNew()>
<cfset assocRows = ''>
<!--- Create and format the header row. --->
<cfset SpreadsheetAddRow( objSpreadsheet, "Associate Name,Location,Checklists Generated by Associate,Checklists Generated by Selected Location(s),Associate Percentage of Location Total" )>
<cfset rowNumber = 1 />
<cfoutput query="GetEmployeeInfo">
<cfset rowNumber++ />
<cfset rowList = "'#(rnA eq 1)?assoc_name:''#','#(rnl eq 1)?trans_location:''#','#checklistsByAssocLoc#','#assocChecklistsByLoc#','#DecimalFormat(totalChecklistsByAssocLocPct)#'">
<!--- Make list of rows --->
<cfif (rnA eq 1)>
<cfset assocRows = ListAppend(assocRows, rowNumber)>
</cfif>
<cfset SpreadsheetAddRow( objSpreadsheet, rowList)>
<cfif rnTotAssoc EQ 1>
<cfset rowNumber++ />
<cfset rowList = "'Associate Total','','#totalChecklistsByAssoc#','#totalAssocChecklistsByAllFilteredLoc#','#DecimalFormat(totalChecklistsByLocPct)#'" >
<cfset SpreadsheetAddRow( objSpreadsheet, rowList )>
</cfif>
</cfoutput>
<cfset SpreadSheetSetColumnWidth(objSpreadsheet,1,25)>
<cfset SpreadSheetSetColumnWidth(objSpreadsheet,2,25)>
<cfset SpreadSheetSetColumnWidth(objSpreadsheet,3,25)>
<cfset SpreadSheetSetColumnWidth(objSpreadsheet,4,25)>
<cfset SpreadSheetSetColumnWidth(objSpreadsheet,5,25)>
<!--- Move the line here --->
<cfset SpreadsheetFormatRow( objSpreadsheet, {bold=true, textwrap="true", alignment="center"}, 1 )>
<cfloop list="#assocRows#" index="i">
<cfset SpreadsheetFormatCell(objSpreadsheet, {'bold' : 'true'}, i, 1)>
</cfloop>
<cfheader name="Content-Disposition" value="inline; filename=CS_#Dateformat(NOW(),'MMDDYYYY')#.xls">
<cfcontent type="application/vnd.ms-excel" variable="#SpreadsheetReadBinary( objSpreadsheet )#">
<cfcatch type = "any">
#rowList#
<cfabort>
</cfcatch>
</cftry>
I have tried adding:
'#DecimalFormat(totalChecklistsByLocPct)# %'"
which then excel doesnt know the correct format.
Then I tried:
<cfset spreadsheetFormatCell( objSpreadsheet, {dataformat: "0.00%"}, 2 )>
Which then just through an error:
Parameter validation error for the SPREADSHEETFORMATCELL function.
Any help on how to add this % sign to the 5 column (not the header or blank cells once the query stops) would be greatly appreciated.
EDIT
Also tried:
<cfset rowList = "'#(rnA eq 1)?assoc_name:''#','#(rnl eq 1)?trans_location:''#','#checklistsByAssocLoc#','#assocChecklistsByLoc#','#NumberFormat(totalChecklistsByAssocLocPct, '0.00')# %'">
Excel still through the error saying its formatted as text.

Column Formatting cfspreadsheet

I am using cfspreadheet in ColdFusion 10. I am aligning my 5th column to the right. Columns 1 through 44 align right then 44 through 73 start aligning left again. Is this typical when trying to format a spreadsheet?
<cfset SpreadsheetFormatColumn( objSpreadsheet, {alignment="right"}, 5 )>
All the spreadsheet code:
<cftry>
<cfset objSpreadsheet = SpreadsheetNew()>
<cfset assocRows = ''>
<!--- Create and format the header row. --->
<cfset SpreadsheetAddRow( objSpreadsheet, "Associate Name,Location,Checklists Generated by Associate,Checklists Generated by Selected Location(s),Associate Percentage of Location Total" )>
<cfset rowNumber = 1 />
<cfoutput query="GetEmployeeInfo">
<cfset rowNumber++ />
<cfset rowList = "'#(rnA eq 1)?assoc_name:''#','#(rnl eq 1)?trans_location:''#','#checklistsByAssocLoc#','#assocChecklistsByLoc#','#DecimalFormat(totalChecklistsByAssocLocPct)#%'">
<!--- Make list of rows --->
<cfif (rnA eq 1)>
<cfset assocRows = ListAppend(assocRows, rowNumber)>
</cfif>
<cfset SpreadsheetAddRow( objSpreadsheet, rowList)>
<cfif rnTotAssoc EQ 1>
<cfset rowNumber++ />
<cfset rowList = "'Associate Total','','#totalChecklistsByAssoc#','#totalAssocChecklistsByAllFilteredLoc#','#DecimalFormat(totalChecklistsByLocPct)#%'" >
<cfset SpreadsheetAddRow( objSpreadsheet, rowList )>
</cfif>
</cfoutput>
<cfset SpreadSheetSetColumnWidth(objSpreadsheet,1,25)>
<cfset SpreadSheetSetColumnWidth(objSpreadsheet,2,25)>
<cfset SpreadSheetSetColumnWidth(objSpreadsheet,3,25)>
<cfset SpreadSheetSetColumnWidth(objSpreadsheet,4,25)>
<cfset SpreadSheetSetColumnWidth(objSpreadsheet,5,25)>
<!--- Move the line here --->
<cfset SpreadsheetFormatColumn(objSpreadsheet, {alignment="right"}, 5 )>
<cfset SpreadsheetFormatRow(objSpreadsheet, {bold=true, textwrap="true", alignment="center"}, 1 )>
<cfloop list="#assocRows#" index="i">
<cfset SpreadsheetFormatCell(objSpreadsheet, {'bold' : 'true'}, i, 1)>
</cfloop>
<!---<cfset spreadsheetFormatColumn( objSpreadsheet, {dataformat: "0.00%"}, 5 )>--->
<cfheader name="Content-Disposition" value="inline; filename=CS_#Dateformat(NOW(),'MMDDYYYY')#.xls">
<cfcontent type="application/vnd.ms-excel" variable="#SpreadsheetReadBinary( objSpreadsheet )#">
<cfcatch type = "any">
#rowList#
<cfabort>
</cfcatch>
</cftry>
I should add if I remove the percent signs '%' in the decimal format it does align right completely. But I am trying to make it work with the % signs.

Error with multiple PDF Generation in CF

I'm getting an error when producing a multi-page PDF.
The pages attribute is not specified for the MERGE action in the cfpdf tag.
The line that is causing the issue is: <cfpdf action="merge" source="#ArrayToList(variables.pdfList)#" destination="promega.pdf" overwrite="yes" />
I tried looking in Adobe's documentation bug cannot find an attribute pages for the merge action. Thoughts?
<!--- Append PDF to list for merge printing later --->
<cfset ArrayAppend(variables.pdfList, "#expandPath('.')#\general.pdf") />
<cfset variables.userAgenda = GetAttendeeSchedule(
variables.event_key,
variables.badgeNum
) />
<!--- Field CFID is the id of the agenda item; use this for certificate selection --->
<cfif variables.userAgenda.recordcount>
<cfloop query="variables.userAgenda">
<cfset variables.title = Trim(variables.userAgenda.CUSTOMFIELDNAMEONFORM) />
<cfpdfform source="#expandPath('.')#\promega_certificate.pdf" destination="#cfid#.pdf" action="populate">
<cfset variables.startdate = replace(CUSTOMFIELDSTARTDATE, "T", " ") />
<cfpdfformparam name="WORKSHOP" value="#variables.title#">
<cfpdfformparam name="NAME" value="#variables.badgeInfo.FirstName# #variables.badgeInfo.LastName#">
<cfpdfformparam name="STARTDATE" value="#DateFormat(variables.startdate, "medium" )#">
</cfpdfform>
<!--- Append PDF to list for merge printing later --->
<cfset ArrayAppend(variables.pdfList, "#expandPath('.')#\#cfid#.pdf") />
</cfloop>
</cfif>
<cfif ArrayLen(variables.pdfList)>
<cfpdf action="merge" source="#ArrayToList(variables.pdfList)#" destination="promega.pdf" overwrite="yes" />
<!--- Delete individual files --->
<cfloop list="#ArrayToList(variables.pdfList)#" index='i'>
<cffile action="delete" file="#i#" />
</cfloop>
<cftry>
<cffile action="delete" file="#expandPath('.')#\general.pdf" />
<cfcatch></cfcatch>
</cftry>
<cfheader name="Content-Disposition" value="attachment;filename=promega.pdf">
<cfcontent type="application/octet-stream" file="#expandPath('.')#\promega.pdf" deletefile="Yes">
<cflocation url="index.cfm" addtoken="false" />
</cfif>
This happens when source is a single file rather than a comma separated list of files. I'm guessing that if it's a single file is is expecting to extract some pages rather than add.
I tried the following on my coldfusion 9 machine and it worked just fine:
<cfset strPath = GetDirectoryFromPath(GetCurrentTemplatePath()) />
<Cfset pdflist = arrayNew(1)>
<Cfset pdflist[1] = "#strPath#page1.pdf">
<Cfset pdflist[2] = "#strPath#page2.pdf">
<cfpdf action="merge" source="#ArrayToList(pdflist)#" destination="#strPath#merged.pdf" overwrite="yes" />
You could try to merge the pages like this and check whether you still get an error:
<cfset strPath = GetDirectoryFromPath(GetCurrentTemplatePath()) />
<Cfset pdflist = arrayNew(1)>
<Cfset pdflist[1] = "#strPath#page1.pdf">
<Cfset pdflist[2] = "#strPath#page2.pdf">
<cfpdf action="merge" destination="#strPath#merged.pdf" overwrite="yes">
<Cfloop from=1 to="#arraylen(pdflist)#" index="x">
<cfpdfparam source="#pdfList[x]#">
</cfloop>
</cfpdf>

How to compare two images in ColdFusion

I am trying to compare images and find if they are same or not. Images can have same name but the actual image might be different. The code that I have so far.
<cfset dirToReadFrom = #ExpandPath( '../properties-feed/unzipped/' )# />
<cfdirectory
action="list"
directory="#dirToReadFrom#"
listinfo="name"
name="qFile"
sort="asc"
filter="*.jpg"
/>
<cfset images = ArrayNew(1)>
<cfoutput query="qFile">
<cfset ArrayAppend(images, #qFile.name#)>
</cfoutput>
<cfset dirToCreate = #ExpandPath( './assets/images/resized/original/' )# />
<cfif not DirectoryExists(dirToCreate)>
<cfdirectory action = "create" directory = "#dirToCreate#" />
<cfoutput><p>Your directory has been created.</p></cfoutput>
</cfif>
<cfzip
action="unzip"
file="#ExpandPath( '../properties-feed/data.zip/' )#"
destination="#ExpandPath( './assets/images/resized/original/' )#"
overwrite="true"
/>
<cfset dirToReadFromOriginal = #ExpandPath( './assets/images/resized/original/' )# />
<cfdirectory
action="list"
directory="#dirToReadFromOriginal#"
listinfo="name"
name="qFileOriginal"
sort="asc"
filter="*.jpg"
/>
<cfset imagesLatest = ArrayNew(1)>
<cfoutput query="qFileOriginal">
<cfset ArrayAppend(imagesLatest, #qFileOriginal.name#)>
</cfoutput>
<!--- Loop over your current images --->
<cfloop query="qFileOriginal">
<!--- Check for a matching file name --->
<cfquery name="fileExists" dbtype="query">
SELECT
COUNT(*) AS num_Rec
FROM
qfile
WHERE
name = <cfqueryparam cfsqltype="cf_sql_varchar" value="#qFileOriginal.name#" />
</cfquery>
<!--- do we have a matching file name? --->
<cfif val(fileExists.num_rec)>
<cfimage action="read" name="newImage" source="#dirToReadFrom##qFile.name#"/>
<cfimage action="read" name="originalImage" source="#dirToReadFromOriginal##qFileOriginal.name#"/>
<cfset newImageBlob = ImageGetBlob(newImage) />
<cfset originalImageBlob = ImageGetBlob(originalImage) />
<!--- Compare --->
<cfif toString(newImageBlob) eq toString(originalImageBlob) >
Images are same
<cfelse>
DIFFERENT
</cfif>
</cfif>
</cfloop>
The code doesn't seem to be working. Can Anyone see what am I doing wrong?
Update 1 from comments
The result that I actually get is that the first images are same and the rest of images in files are different. But this is not correct as most of the images that I am comparing are same.
Update 2 from comments
It incorrectly identifies same images as being different. What I actually get is that the first two images are same and the rest is different. Which is not right as most of the images I have are same.
I've always just done this with BinaryEncode(), and then compare the resulting strings. You have to be careful though, as compression can make the files different even though they look (to the eye) exactly the same.

watermarking on Images and Issue with Text Placement

I am working on watermarking an image and am having a problem with my code. It does create a watermark in the bottom right side corner, but the text is not written.
Can anyone spot what is wrong with the code?
<cfset objImage = ImageRead("#UploadDir2#\#uploadfile#") />
<cfset objImage2 = ImageRead("#UploadDir2#\#uploadfile#") />
<cfset ImageResize(objImage,800,"")>
<cfif form.textonImage NEQ "">
<cfset objWatermark = ImageNew("",20,20,"rgb","##F0F0F0")/>
<cfset ImageSetDrawingColor(objWatermark,"##000000") />
<cfset ImageDrawRect(objWatermark,0,0,(objWatermark.GetWidth() - 1),(objWatermark.GetHeight() - 1)) />
<cfset ImageSetAntialiasing(objWatermark,"on") />
<cfset objAttributes = {Font = "Verdana",Size = "8",Style = "bold"} />
<cfset ImageDrawText(objWatermark,"#form.textonImage#",11,40,objAttributes) />
<cfset ImageSetDrawingTransparency(objImage,60) />
<cfset ImagePaste(objImage,objWatermark,(objImage.GetWidth() - objWatermark.GetWidth() - 0),(objImage.GetHeight() - objWatermark.GetHeight() - 0)) />
</cfif>
<cfset ImageWrite(objImage,"#UploadDir2#\#uploadfile#")>
<cfset ImageResize(objImage2,#request.pic_th_width#,"")>
<cfif form.textonImage IS NOT "">
<cfset objWatermark = ImageNew("",#request.pic_th_width#,#request.pic_th_width#,"rgb","##F0F0F0")/>
<cfset ImageSetDrawingColor(objWatermark,"##000000") />
<cfset ImageDrawRect(objWatermark,0,0,(objWatermark.GetWidth() - 0),(objWatermark.GetHeight() - 0)) />
<cfset ImageSetAntialiasing(objWatermark,"on") />
<cfset objAttributes = {Font = "Verdana",Size = "20",Style = "bold"} />
<cfset ImageDrawText(objWatermark,"#form.textonImage#",11,40,objAttributes) />
<cfset ImageSetDrawingTransparency(objImage2,60) />
<cfset ImagePaste(objImage2,objWatermark,(objImage2.GetWidth() - objWatermark.GetWidth() - 0),(objImage2.GetHeight() - objWatermark.GetHeight() - 0)) />
</cfif>
EDIT:
I answered my own question, so let's delete it or ignore it.