Get array key and structure data from an array with structure - coldfusion

I've got an array that has a structure. Problem is that I can't output the array number and the structure data in the same loop, but if I have two different loops, the data will show without any errors.
The code below has two different loops showing how I can access the array number and structure data separately.
How do you output the array number and structure data in the same loop?
Code can be tested here https://cffiddle.org/
<!--- Create new structure --->
<cfset structRe = StructNew() />
<!--- Add data to structure --->
<cfset structRe.id = "14">
<cfset structRe.title = "Title">
<!--- Create new Array --->
<cfset arryRe = ArrayNew(1) />
<!--- Add structure to array --->
<cfset ArrayAppend(arryRe, structRe)>
<cfoutput>
<cfdump var="#arryRe#" />
</cfoutput>
<!--- Loop to access structure --->
<cfloop array ="#arryRe#" index="i">
<cfoutput>
#i.id# #i.title# <br />
</cfoutput>
</cfloop>
<!--- Loop to access array number --->
<cfloop array ="#arryRe#" item="item" index="i">
<cfoutput>
#i# <br />
</cfoutput>
</cfloop>

Simplifying your code a bit, and adding local scope (assuming you're in a function), here's another way to do this, too:
<cfset local.arrayRe = [
{"id": "14", "title": "Title Fourteen"}
, {"id": "15", "title": "Title Fifteen"}
] />
<cfloop array="#local.arrayRe#" index="local.i" item="local.stItem">
<cfoutput>
Item ##: #local.i#, ID: #local.stItem.id#, Title: #local.stItem.title#<br />
</cfoutput>
</cfloop>

Just figured it out.
<cfloop array ="#arryRe#" item="item" index="i">
<cfoutput>
#i# #item.id# #item.title#<br />
</cfoutput>
</cfloop>

Related

Query created from Query returned from cfspreadsheet not having proper values

Today I came across a very odd case while reading a vlue from a spreadsheet and trying to filter them on a condition and a create a spreadsheet from the filtered data. Here are my steps
Read Excel sheet
<cfspreadsheet action="read" src="#local.sFilePath#" excludeHeaderRow="true" headerrow ="1" query="local.qExcelData" sheet="1" />
Create a holding Query
<cfset local.columnNames = "LoanNumber,Product," />
<cfset local.qSuccessData = queryNew(local.columnNames,"VarChar,VarChar") />
Filter the Excel returned query on a condition and add the valid ones into the new Holding query
<cfloop query="local.qExcelData" >
<cfif ListFind(local.nExceptionRowList,local.qExcelData.currentrow) EQ 0>
<cfset queryAddRow(local.qSuccessData) />
<cfset querySetCell(local.qSuccessData, 'LoanNumber', local.qExcelData['Loan Number']) />
<cfset querySetCell(local.qSuccessData, 'Product', local.qExcelData['Product']) />
</cfif>
</cfloop>
Create the new spreadsheet
<cfspreadsheet action="write" query="local.qSuccessData" filename="#local.sTempSuccessFile#" overwrite="true">
However I am getting the following content in my excel sheet
Loannumber Product
coldfusion.sql.column#87875656we coldfusion.sql.column#89989ER
Please help on this to get it work.
I believe the query loop is not mapping values to the Holding-Query properly.
Please modify your loop as below:
<cfloop query="local.qExcelData" >
<cfif ListFind(local.nExceptionRowList,local.qExcelData.currentrow) EQ 0>
<cfset queryAddRow(local.qSuccessData) />
<cfset querySetCell(local.qSuccessData, 'LoanNumber', local.qExcelData['Loan Number'][currentRow]) />
<cfset querySetCell(local.qSuccessData, 'Product', local.qExcelData['Product'][currentRow]) />
</cfif>
</cfloop>

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.

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

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.

Evaluate function

Is there a better way to write the following?
<cfloop list="#qry.Columnlist#" index="FieldName">
<cfset "form.#FieldName#" = Evaluate("qry.#FieldName#")>
</cfloop>
This loop is assigning every field in the query to a corresponding form field.
I understand the evaluate function is shunned.
<cfloop list="#qry.Columnlist#" index="FieldName">
<cfset form[FieldName] = qry[FieldName][1]>
</cfloop>
?
Assuming you are returning a single recordset the following will work.
<cfloop list="#qry.Columnlist#" index="FieldName">
<cfset "form.#FieldName#" = qry[FieldName][1]>
</cfloop>
Tangential, but if you were looping over multiple rows of a query, you could use the currentRow variable in the query object to do the same thing as the accepted answer.
<cfset var someStruct = {} />
<cfset var colummnList = queryObj.columnList />
<cfloop query="queryObj">
<cfset someStruct[currentRow] = {} />
<cfloop list="#columnList#" index="fieldName">
<cfset someStruct[currentRow][fieldName] = queryObj[fieldName][currentRow] />
</cfloop>
</cfloop>