| By Michael Givens | Article Rating: |
|
| December 25, 2006 09:15 AM EST | Reads: |
16,954 |
By the time you read this, another MAX will be in the history books. In fact, with a record attendance of around 3,500 developers and designers, this MAX in Vegas will also be in the record books.
Along with the usual great conference sessions, this year there was a special event referred to as the "BarCamp - The unconference event" called MAXUP. I presented a MAXUP demo, A Flex 2 Signature Panel at MAXUP, where I showed the audience how easy it was to combine a Flex 2 UI for capturing a mouse-created signature with the ActionSript 3 Drawing API and a remote object call to a ColdFusion component. Leveraging work that James Ward blogged about on cayambe.com, I retooled the back-end as a ColdFusion CFC (I make remote object calls to the CFC's functions), and made some minor UI changes to create a signature panel that could be used for online NDA agreements or e-signatures.
Adobe Flex 2 Builder allowed me to lay out very quickly a simple UI where a user can use a mouse (or even better a drawing pen) to write out messages (See Figure 1).
The signature pad captures a visitor's IP address via a remote object call to a CFC method getVisitorIP() during the Flex application's initialize event:
MXML:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize=" roSign.getVisitorIP()"
creationComplete="setColor()" styleName="plain" viewSourceURL="srcview/index.html" horizontalAlign="center"
verticalAlign="top">
<mx:RemoteObject id="roSign"
destination="ColdFusion"
source="flex2_training.components.signature"
fault="mx.controls.Alert.show(event.fault.faultDetail.toString(), 'Alert');"
showBusyCursor="true">
<mx:method name="getVisitorIP" result="my_IP_handler(event.result)"/>
<mx:method name="doUpload" result="my_CFC_handler(event.result)"/>
</mx:RemoteObject>
CFC:
<cffunction name="getVisitorIP" displayname=
"Get IP Address" hint="Returns Visitor's' IP address" access="remote" returntype="string">
<cfset sIP = "#CGI.Remote_Addr#">
<cfreturn sIP />
</cffunction>
Clicking the 'Accept' button triggers the click event that calls the remote object doUpload and corresponding CFC method:
MXML:
<mx:RemoteObject id="roSign"
destination="ColdFusion"
source="flex2_training.components.signature"
fault="mx.controls.Alert.show(event.fault.faultDetail.toString(), 'Alert');"
showBusyCursor="true">
<mx:method name="getVisitorIP" result="my_IP_handler(event.result)"/>
<mx:method name="doUpload" result="my_CFC_handler(event.result)"/>
</mx:RemoteObject>
<mx:Script>
<![CDATA[
import mx.rpc.events.ResultEvent;
import flash.events.Event;
private var sIP:String;
private function doSave():void {
var bd:BitmapData = new BitmapData(canvas.width,canvas.height);
bd.draw(canvas);
var ba:ByteArray = PNGEnc.encode(bd); // See the PNGEnc.as code
roSign.doUpload(ba,sIP); // pass the ByteArray and the Visitor's IP address
}
]]>
</mx:Script>
CFC:
<cffunction name="doUpload" displayname=
"Save Signature" hint="Saves a PNG Signature" access="remote" output="false" returntype="any">
<cfargument name="sigbytes" required="true" type="binary">
<cfargument name="ip_suffix" required="true" type="string">
<cfscript>
var myUUID = "";
var SigFileName = "";
</cfscript>
<!--- create a FileOutputStream --->
<cfobject type="java" action="CREATE" class="java.io.FileOutputStream" name="oStream">
<cfscript>
myUUID = CreateUUID(); // create a unique id
// call init method, passing in the full path to the desired jpg
oStream.init(expandPath("../converted_pngs/signature_#arguments.ip_suffix#_#myUUID#.png"));
oStream.write(arguments.sigbytes);
oStream.close();
SigFileName = getSigFileName("#arguments.ip_suffix#_#myUUID#");
</cfscript>
<cfreturn SigFileName />
</cffunction>
Once the doUpload method is complete, the event.result is returned (the dynamic file name [including both an IP address and a UUID] of the stored PNG image file) and assigned to a Flex string variable, SigFileName:
MXML:
<mx:Script>
<![CDATA[
........ abbreviated for space saving ........
private var SigFileName:String;
private function my_CFC_handler(result:Object):void {
SigFileName = result.toString();
btnView.enabled = true;
}
]]>
</mx:Script>
Clicking on the 'View' button triggers the click event and the function doView(), which opens the page and the saved PNG image as shown in Figure 2:
MXML:
<mx:Script>
<![CDATA[
........ abbreviated for space saving ........
private function doView():void {
var u:URLRequest = new URLRequest("../welcome.cfm?sig=" + SigFileName + ".png");
navigateToURL(u,"_self");
}
]]>
</mx:Script>
The complete code listing is available at: http://webcfmx.no-ip.info/flextraining/signature/bin/srcview/index.html
PNGEnc.as:
package {
import flash.geom.*;
import flash.display.*;
import flash.utils.*;
public class PNGEnc {
public static function encode(img:BitmapData):ByteArray {
// Create output byte array
var png:ByteArray = new ByteArray();
// Write PNG signature
png.writeUnsignedInt(0x89504e47);
png.writeUnsignedInt(0x0D0A1A0A);
// Build IHDR chunk
var IHDR:ByteArray = new ByteArray();
IHDR.writeInt(img.width);
IHDR.writeInt(img.height);
IHDR.writeUnsignedInt(0x08060000); // 32bit RGBA
IHDR.writeByte(0);
writeChunk(png,0x49484452,IHDR);
// Build IDAT chunk
var IDAT:ByteArray= new ByteArray();
for(var i:int=0;i < img.height;i++) {
// no filter
IDAT.writeByte(0);
var p:uint;
if ( !img.transparent ) {
for(var j:int=0;j < img.width;j++) {
p = img.getPixel(j,i);
IDAT.writeUnsignedInt(
uint(((p&0xFFFFFF) << 8)|0xFF));
}
} else {
for(var k:int=0;k < img.width;k++) {
p = img.getPixel32(k,i);
IDAT.writeUnsignedInt(
uint(((p&0xFFFFFF) << 8)|
(p>>>24)));
}
}
}
IDAT.compress();
writeChunk(png,0x49444154,IDAT);
// Build IEND chunk
writeChunk(png,0x49454E44,null);
// return PNG
return png;
}
private static var crcTable:Array;
private static var crcTableComputed:Boolean = false;
private static function writeChunk(png:ByteArray,
type:uint, data:ByteArray):void {
if (!crcTableComputed) {
crcTableComputed = true;
crcTable = [];
for (var n:uint = 0; n < 256; n++) {
var c:uint = n;
for (var k:uint = 0; k < 8; k++) {
if (c & 1) {
c = uint(uint(0xedb88320) ^
uint(c >>> 1));
} else {
c = uint(c >>> 1);
}
}
crcTable[n] = c;
}
}
var len:uint = 0;
if (data != null) {
len = data.length;
}
png.writeUnsignedInt(len);
var p:uint = png.position;
png.writeUnsignedInt(type);
if ( data != null ) {
png.writeBytes(data);
}
var e:uint = png.position;
png.position = p;
var d:uint = 0xffffffff;
for (var i:int = 0; i < (e-p); i++) {
d = uint(crcTable[
(d ^ png.readUnsignedByte()) &
uint(0xff)] ^ uint(d >>> 8));
}
d = uint(d^uint(0xffffffff));
png.position = e;
png.writeUnsignedInt(d);
}
}
}
MAXUP was a great success. Although somewhat nervous before my presentation, I was grinning ear-to-ear afterwards from Adobe's Ted Patrick's encouragement. He said, "Mike, I like the way you used AMF to pass the byte-array to the server-side code." Thanks, Ted. (Figure 3)
Reflecting on how much easier it was to create this example compared to the two-month-long project of doing it with the Flash 7 IDE/Flex 1.5/CFMX 6.1/Apache Batik, I am simply amazed by Flex 2's versatility and efficiency in getting the job done quickly. If you still haven't had a chance to try out the Flex 2-CFMX 7.0.2 dynamic duo, I hope this example helps lure you in a bit further.
Published December 25, 2006 Reads 16,954
Copyright © 2006 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Michael Givens
Mike Givens is the CTO of U Saw It Enterprises, a Web technology consulting firm based in Marietta, GA. He is an Adobe Corporate Champion known to share his experience and evangelism of all things Adobe. Certified in both ColdFusion 5 and as an Advanced CFMX Developer, he has been using ColdFusion since the days of Allaire Spectra. For the last 11 years, he has been seen with his head down - deep in the code.
![]() |
Todd Cullen 12/25/06 01:48:45 PM EST | |||
Great Article! I've always thought it'd be a nice feature to capture someones signature digitally. I had no idea it would be that easy, relatively speaking. Thanks for the post. |
||||
- Adobe’s Aiming ColdFusion at Multiple Clouds
- Cloud Computing Journal: Adobe to Deliver ColdFusion in the Cloud
- Adobe May Cooperate with Apple to Transplant Flash Player to iPhone
- Adobe Flex Developer Earns $100K in New York City
- Adobe LiveCycle Enterprise Suite 2 for Cloud Computing
- Adobe Betas Target RIAs and Cloud Computing
- Adobe Cans Another 9% of its Workforce
- Moyea DVD4Web Converter V2.0 Converts DVD to FLV Fast and Synchronously with Watermarks
- Adobe Fiddles with its Web Apps
- Adobe & Salesforce Cut Cloud Deal
- Hosting.com Launches ColdFusion 9 in the Cloud
- The Real Time Infrastructure Ultimatum
- Adobe’s Aiming ColdFusion at Multiple Clouds
- Eval JavaScript in a Global Context
- Fig Leaf Software to Exhibit at Government IT Conference & Expo
- Cloud Computing Journal: Adobe to Deliver ColdFusion in the Cloud
- Is Microsoft as Free as Open Source?
- Adobe Reader Sued
- The Planet Named “Bronze Sponsor” of Cloud Computing Expo
- Microsoft Expression Web Has Got Game
- Adobe May Cooperate with Apple to Transplant Flash Player to iPhone
- Adobe Flex Developer Earns $100K in New York City
- Bruce Chizen Joins Voyager Capital as Venture Partner
- My Top Seven Wishes From Adobe MAX 2009
- The Next Programming Models, RIAs and Composite Applications
- Where Are RIA Technologies Headed in 2008?
- Constructing an Application with Flash Forms from the Ground Up
- AJAX World RIA Conference & Expo Kicks Off in New York City
- CFEclipse: The Developer's IDE, Eclipse For ColdFusion
- Personal Branding Checklist
- Adobe Flex 2: Advanced DataGrid
- Has the Technology Bounceback Begun?
- Building a Zip Code Proximity Search with ColdFusion
- i-Technology Viewpoint: We Need Not More Frameworks, But Better Programmers
- The Asynchronous CFML Gateway
- Web Services Using ColdFusion and Apache CXF






























