Saving SVG to PNG on your cold fusion server

I built a client side javascript SVG to PNG converter that works on *modern* browsers, however, depending on your target audience the browsers that frequent your site may be less than modern – i.e. IE. In this situation you only have one option, convert the image on the server side and then render it using the good old image tag.

First, cold fusion ships with some outdated batik files (which handle the cfimage tag) , so you will need to update those first, and add the missing files that will add your svg to -> image processing ability. I used the steps found in this post to accomplish the task; I’ll list them here in short format so you can get into the ext chart part of this project.

  1. Stop your cold fusion service
  2. Download the files from the batik website http://xmlgraphics.apache.org/batik/download.cgi
  3. Rename the jar files in /wwwroot/WEB-INF/cfform/jars/  that start with batik by adding the extension .old
  4. Copy the batik jar files into /wwwroot/WEB-INF/lib
  5. Restart Cold Fusion

Next, let’s assume that we have two files, one called convertImage.cfm and one called convertImage.cfc, of course, we want to pass the svg markup to the cfm which will pass the data to the cfc for processing.

<cfcase value="saveChart">
        <cfset saveChart = data.saveChart( svg=form.svg) />
        <cfset json = "{'success':'#saveChart#'}" />
</cfcase>

The code below goes in the cfc file.

<cffunction name="saveChart" >
        <cfargument name="svg" />
            <cftry>
            <cfset svgFile = "c:\websites\temp.svg" />
            <cfset jpgFile = replace("c:\websites\temp.svg", ".svg", ".jpg") />
            <cfset pngFile = (pngPath) />--->
            <cffile action="delete" file="c:\websites\temp.jpg" >

	<cfif FileExists(svgFile)>
            	<cffile action="delete" file="c:\websites\temp.svg" >
            	<cffile action="write" file="c:\websites\temp.svg" output="#svg#" >
           <cfelse>
           	<cffile action="write" file="c:\websites\temp.svg" output="#svg#"  >
           </cfif>

            <cfset t = createObject("java", "org.apache.batik.transcoder.image.JPEGTranscoder").init() />
            <cfset svgURI = createObject("java", "java.io.File").init(svgFile).toURL().toString() />
            <cfset input 	= createObject("java", "org.apache.batik.transcoder.TranscoderInput").init(svgURI) />
            <cfset ostream 	= createObject("java", "java.io.FileOutputStream").init(jpgFile) />
            <cfset output 	= createObject("java", "org.apache.batik.transcoder.TranscoderOutput").init(ostream) />
            <cfset t.transcode(input, output) />
            <cfset ostream.flush() />
            <cfset ostream.close() />

            <cfcatch type="any">
          		 <cfreturn "false" />
            </cfcatch>
            </cftry>
        <cfreturn "true" />
    </cffunction>

The function below would go in your javascript controller.

   saveChart: function(me){
        this.dTask.delay(500, function(){
                var svg = me.up('panel').down('chart').save(
                    {
                        type    :'image/svg+xml'
                    }
                );

                Ext.Ajax.request({
                    url: 'convertImage.cfm?remoteEvent=saveChart',
                    params: {
                        svg: svg
                    },
                    success: function(){
                        // process server response here
                        window.open('temp.jpg');
                    }
                });
        });
    },

A look at cold fusion, ext and cfqueryparam strategies

In a perfect world all user input data would conform to the max length of the database fields that you want to put them in right? As we all know, we don’t live in a perfect world, so you as a developer are forced (hopefully) to build in several layers of redundancy in your data validation methods. The steps below outline some pretty basic concepts when it comes to handling string input from an ext app using cold fusion as the back end language.
You should be using cfqueryparam for all of your input by now, but just in case you are not consider the following example from Adobe itself.

You have a table called sometable and you are updating somelement based on passing someprimamrykey to the server. On the other side you have written the following and are patiently waiting for the data to come via the url and populate the following values:

<cfparam name=" somelement " default="" >
<cfparam name=" someprimamrykey " default="">
<cfquery name="my_cool_query" datasource="big_db" >

UPDATE  my_table
SET
some_column = '#somelement #'
WHERE
my_primar_key = # someprimamrykey #

</cfquery>

Now let’s plug in some values we’ll replace somelement with ‘Acme Incorporated’ and replace someprimarykey with an integer like say 7. So far so good, right? Of course, this is all taken from the query string below that is visible for all to see.

https://my_site.org? somelement= Acme%20Incorporated& someprimamrykey=7

Now since we have a keen eye for detail we immediately notice that the primary key looks like an integer and could be used in the WHERE statement of the query which is – where else but at the end. Knowing this we enter the following value in the textbox on our site that corresponds with someprimarykey, ’7 DELETE from user_table’.

We’ll type in the following url to do the trick:

https://my_site.org? somelement= Acme%20Incorporated& 7%20DELETE%20from%20user_table

Now the query that will get run is below:

UPDATE  my_table
SET
some_column = 'Acme Incorporated' 
WHERE
my_primar_key = 7 DELETE from user_table
</cfquery>

Uh-oh we just deleted all the users, of course this assumes that we know the name of the user table but say you are running some open source content management system, then all of the names are known variables, right?

How can we stop this from happening?

Let’s take the following steps on the client side in our Ext code:

Make sure you set the maxLength AND the enforceMaxlength config options in your extjs code to stop the user from having the ability to enter strings of any length.
If you want to restrict the input to alpha numeric only use the built in Ext.Vtype in the text fields vtype config option. If you need to get fancy, or want to make sure that other characters get let in like those in foreign languages that are not a-z you could look into writing your own vtype and adding it to this config option.

Great, now that you have all of your client side validation in place lets work on making the server side is just as secure.

Always use cfqueryparam with the maxlength attribute set to the same maxlength as the database element and the ext maxlength above, this will make sure that cold fusion throws an error when someone tries to pass in a string that is longer than the specified maxlength. Why, you might ask, we already took care of that on the client side, didn’t we? Well, chances are you are still passing the variable and someone could inject their own value and pass it directly to the server, for instance, by modifying the URL above like we just did in the example.

Let’s see what happens to the input in the example above if we were to use cfqueryparam instead of just outputting the vale in the query directly, as in the code below the whole query would have failed due to the fact that the Delete statement was tacked onto the end of the primary key which is an integer.

UPDATE  my_table
SET
some_column = <cfqueryparam cfsqltype="cf_sql_varchar"  value="Acme Incorporated"
			maxlength="20"	 /> 
WHERE
my_primar_key =  <cfqueryparam cfsqltype="cf_sql_integer" 	value="7 DELETE from user_table " />
</cfquery>

If this had been a where clause looking at a string value instead of an integer, no damage would have been done as the cfqueryparam tag would have escaped the output with single quotes which would have meant that the SQL would have evaluated the whole string.

Some cold fusion cfqueryparam / extjs form field tips for xtype numberfield

If you code in cold fusion you should be using cfqueryparam when you are inputting data into your back end database, that’s a given as it is pretty effective against sql injection hacks, but when you do this you run the risk of throwing errors that you never worried about previously. The two most common problems are maxlength violations, and null value errors in numeric fields, to handle these two issues in your Extjs project I suggest the following approach:

Client Side Considerations:

Always use the xtype:numberfield, or the Ext.form.field.Number input control.

Make sure that you set a valid minValue, or it will default to negative infinity, and you may also need to set a maxValue if you do not want the user to enter a number greater than the ceiling on the data type.

Remember that decimals are allowed by default, so if you want to store the input in an integer field make sure you set allowDecimals to false.
Decide if this is a required field, if so set allowBlank to false to make sure that the user enters a number before submitting the field.

Server Side Considerations:

When you always want a value in the database field (for example a price or quantity field) — Always use cold fusion’s val() function around your input variables as it will convert the numeric characters at the beginning of a string to a number, but, will replace the value with a zero if there are leading characters, meaning the end result is you will always get a valid number in your number field. See the code below.

UPDATE  some_table
SET 
some_currency_value  = <cfqueryparam cfsqltype="cf_sql_float"		value="#val(some_user_input_data)#"	/>

In the example above if some_user_input_data was set to XYZ6563 then the code above would set the value zero. If the numbers were in front of the letters then the letters would be removed and the value entered into database would be 6563 and XYZ would be left off.

When you may actually want a null in the database field – If you do not want to use the val() function but still want to prevent invalid data input from causing cold fusion errors on the back end of your application you can use the IsValid() function coupled with the null attribute in cfqueryparam and ensure that your invalid values insert a null into the field.

Here’s how and why.

UPDATE  some_table
SET 
some_int_value  = <cfqueryparam cfsqltype="cf_sql_integer" 	
value="# some_user_input_data #"
 null="#not IsValid('integer', some_user_input_data)#"  />

The null attribute is looking for a yes or a no, a 1 or a 0 to tell it to ignore the value in the value field and just put the NULL into the database using not in front will reverse the 1 or zero that the Isvalid function returns thus telling cold fusion to place a NULL in the database when the value passed was not a valid integer. You can take a look at more features of the IsValid function here.

There you have it, some tips on keeping your number field values in place and ensuring that the integrity of your back end data stays sound.

A little bit about JSON

A little bit about JSON, or Javascript Object Notation. As you start using the Javascript Ajax libraries, you will certainly run into JSON so it is extremely important that you get a handle on the basics of JSON.

The basic format of a properly formatted JSON string is:

{ name:'value',name:'value',name:[{sub_value:'value',sub_value:'value'},
{sub_value:'value',sub_value:'value'}]}

The values in the example above are in quotes due to the fact that they strings, if you had numeric values the quotes would be optional, as with boolean values and null. Let’s take a look at how this translates in the real world. Suppose we had the following table in a database that contained name, age, and gender.

Name Age Sex
Barney Rubble 32 Male
Fred Flintstone 33 Male
Betty Rubble 32 Female
Pebbles 1 Female
Bamm Bamm 2 Male




The JSON representation of this table would then be:

{results:5,data:[{name:'Barney Rubble',age:32,sex:'Male'},
{name:'Fred Flinstone',age:33,sex:'Male'},
{name:'Betty Rubble',age:32,sex:'Female'},
{name:'Pebbles',age:1,sex:'Female'},
{name:'Bamm Bamm',age:2,sex:'Male'}]}

You probably will not want to write the JSON by hand as in the example above, so in real life you would write a function that would convert the data from a table into the JSON format. A sample function might look like :

<cffunction name="getFlinstones" hint="get all the flinstones" returntype="string" >

<cfquery name="getData" datasource="flinstoneDB" >

        Select name, age, sex from flinstones

</cfquery>
<cfset json = "{results:#getData.recordcount#,data:[" >
<cfloop query="getData">
     <cfset json = json + "{name:'#getData.name#',age:'#getData.age#',sex:'#getData.sex#'}," >
</cfloop>
<cfset json = Trim(json)>
<cfset json = left(json, len(json)-1)>
<cfset json = json + "]}">
<cfreturn json>
</cffunction>

Of course most languages come with Json support like php: http://php.net/manual/en/book.json.php or cold fusion: http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=JavaScriptFcns_07a.html.

Look for the editable Json grid next.