Could this be the future of computer desktops? Could this be the future of, dare I say, Web 3.0 desktops?
Point one, I think the idea is intriguing, however I wonder how many people would actually want to use a computer desktop in this fashion. The concept, at least the idea of replicating a real desktop, reminds me of those cheesy desktop application/OS programs that shipped with PC's in the mid 90's. You had a in/out box, a tray of tools, a note pad, etc. Neat idea, bad execution. In this case though the execution is what makes it breath taking, the shuffling, dragging, sorting etc, makes it seem more like a real desktop, like you are interacting with physical objects. Maybe people are ready for that in a desktop/application. I still remember the days when people thought computer mice would just be a fad, no one wants to interact with a computer like that. Ahhh hindsight.
Point two, if this is the future of desktops, especially web based versions since that is where applications seem to be gravitating, what better tool for enabling such a concept than the Flash plugin. Honestly what other technology could possibly pull this off. AJAX, it does not have the display and rich interface abilities. Sparkle, wait and see .... still waiting (hmmm when is Avalon getting launched again). Using Flash and/or Flex a good development team could pull off something like this today (no I am not smoking anything).
If this is where applications are going, from an interaction standpoint, and it is a big IF, Adobe is in an amazing position to be the key technology enabler of such a computing revolution. Can't wait to see what the future holds.
I have had a few requests for the source code to my Bitmap Scratch Off Effect so here it is. You can download the source files here, just supply your own image. Feel free to use the effect where ever you wish, just note where you found it.
/**
* Creates an image that is revealed by scraping off the top layer
* @author Derrick Grigg
* @url http://dgrigg.innovasium.com
* @version 1.0
*/
import flash.display.BitmapData;
import flash.geom.Matrix;
import flash.geom.Rectangle;
import flash.geom.ColorTransform;
import mx.utils.Delegate;
import mx.controls.Button;
class com.dgrigg.views.BitmapScratch extends MovieClip {
private var image_bmp: BitmapData;
private var image_mc: MovieClip;
private var scratch_mc: MovieClip;
private var scraper_mc: MovieClip;
private var start_btn: Button;
private var brushHeight:Number = 34;
private var path: String;
private var xPos: Number;
private var onMouseMove: Function;
public function BitmapScratch(){
}
public function init(value:String):Void{
path = value;
Mouse.addListener(this);
image_mc = createEmptyMovieClip('image_mc', 1);
scraper_mc = attachMovie('scraper', 'scraper_mc', 10, {_x:_root._xmouse, _y:_root._ymouse, _visible: false});
onEnterFrame = function(){
//setup event listeners
start_btn.addEventListener('click', Delegate.create(this, handleStart));
delete onEnterFrame;
}
}
function handleStart(event:Object):Void {
event.target.visible = false;
onMouseMove = handleMouseMove;
var mcl = new MovieClipLoader();
mcl.onLoadInit = Delegate.create(this, setupImage)
mcl.onLoadComplete = Delegate.create(this, hideImage)
mcl.loadClip(path, image_mc);
}
private function handleMouseMove(Void):Void{
var x = _xmouse;
var y = _ymouse;
scraper_mc._x = x;
scraper_mc._y = y;
//determine how fast the mouse moved from the previous spot
//this value is used for the rectange width on the colour transform
//and in calculating the colour transform offset
var speed = Math.abs(xPos - x);
if (speed == 0){
speed = 2;
}
xPos = x;
var c = image_bmp.getPixel32(x, y);
var ct = new ColorTransform()
ct.alphaOffset = speed * -2;
image_bmp.colorTransform(new Rectangle(x-speed,y-16, speed, brushHeight), ct);
}
private function hideImage(target:MovieClip):Void{
xPos = _xmouse;
target._visible = false;
scraper_mc._x = _xmouse;
scraper_mc._y = _ymouse;
scraper_mc._visible = true;
Mouse.hide();
}
private function setupImage(target:MovieClip):Void{
//create the text that displays over the image
var text_mc = createEmptyMovieClip('text_mc', 4);
var text_txt = text_mc.createTextField('text_txt',10, (_width/2) - (300/2), (_height/2) - (150/2), 300, 150);
text_txt.wordWrap = true;
text_txt.selectable = false;
text_txt.text = 'Scrape off the top layer by moving the mouse back and forth. Faster scraping removes the top layer faster.';
var tf = new TextFormat();
tf.size = 20;
tf.font = '_sans';
tf.align = 'center';
text_txt.setTextFormat(tf);
var matrix = new Matrix();
matrix.scale(1, 1);
var w = target._width;
var h = target._height;
image_bmp = new BitmapData(w,h, true, 0xFFCCCCCC);
image_bmp.draw(text_mc,matrix);
text_mc.removeMovieClip();//remove the text clip now that's part of the bitmap
scratch_mc = createEmptyMovieClip('scratch_mc', 2);
scratch_mc.attachBitmap(image_bmp, 1);
target._visible = true;
}
}
Very funny post, perfect way to start a hump day, thanks Damien.
A few of my personal favourites:
Your code wipes out important data. You wrote some code that's supposed to overwrite application files with new files, but it goes haywire and deletes a bunch of the user's important data files.
You take great pride in the high volume of code you write. Being productive is good, unfortunately producing lots of lines of code isn't quite the same as being productive. Users never remark "Wow, this software may be buggy and hard to use, but at least there is a lot of code underneath." Far from being productive, spewing out tons of crap code slows down other devs and creates a huge maintenance burden for the future. (I had an english teacher in high school who called this verbal diarrhea).
I just came across a really good article by Andrew Guldman on Flash development. He covers off all the major points for Flash development, including:
Organization and preparation
Good coding practices
Code reuse
Team development
Application deployment
These ideas can be (and should be) applied to any Flash project; website, widget or RIA.
The only point I'm not real comfortable with is the section covering autogenerated movieclips. I understand the rationale behind the concept, I just do not personally like to leverage undocumented features that could go away or easily change in future Flash releases. My preference is to always have a library instance of any class that incorporates a visual piece, it is a little more setup time, but having them all in the library makes it easy to quickly find any visual pieces and it provides some consistency in that all visual pieces/classes are always represented in the library. It is a neat idea though, you can read more about it here.
I do not often use the CFFILE tag to write out large amounts of data, typically I only use it for adding a line to a log file or some other relatively small task. Recently however, I needed to create a process to write out large text files (approximately 5.5 MB, 17,500 lines of text) and I quickly discovered that the CFFILE tag is extremely inefficient for such a purpose. I had a simple loop that concatenated the text together and then used the CFFILE tag to write the file at the end. On average it was taking about 600 seconds to create the file. Once I started to think about it, the problem became very apparent. Every call using the CFFILE tag to write to a file does the following:
open the file
read the file
add the new text
save the file
close the file
All this is running through ColdFusion to the underlying Java classes so there is a lot of overhead and excess processing in all the running back and forth. Time to find a better solution.
Using CFFILE to write the file line by line.
My first idea was to break up the amount of work the CFFILE command had to do into smaller chunks, write the file one line at a time.
Average time to create the file was almost 140 seconds. Better than 400 seconds but still insane!
Using CFFILE and 'buffering' the output
Building on my first idea, I decided to try and buffer the output data, this would reduce the number of times the CFFILE tag would need to be called. I set a variable called logData and filled it with twenty lines of text before writing out the data
Average time to create the file was down to around 11 seconds. Much better but 11 seconds still seemed like a long time to write out the file. I tried different buffer sizes but the processing time was still much longer than I wanted.
Writing with Java.IO
I came to the conclusion that the only way to really speed up the process was to directly access the Java.IO classes from Coldfusion. It was time to put on the Java hat. Java has a slew of input/output file operation classes, I knew my solution was there ... somewhere.
<cfset logFile = CreateObject('java', 'java.io.File').init(logFilePath)>
<cfset fw = CreateObject('java', 'java.io.FileWriter').init(logFile)>
<cfset bw = CreateObject('java', 'java.io.BufferedWriter').init(fw, 4096)>
<cfset CrLf = Chr(13)&Chr(10)>
<cfset res = bw.write('##Software: Microsoft Internet Information Services 6' & CrLf)>
<cfset res = bw.write('##Version: 1.0' & CrLf)>
<cfset res = bw.write('##Date: #selectLogFile.log_stamp[1]#' & CrLf)>
<cfset res = bw.write('##Fields: date time cs-method cs-uri-stem c-ip cs(User-Agent) cs(Cookie) cs(Referer) cs-host' & CrLf)>
<cfloop from="1" to="#selectLogFile.RecordCount#" index="i">
<cfset res = bw.write(selectLogfile.log_entry[i] & CrLf)>
</cfloop>
<!--- output any remaining data in the buffer ---->
<cfset res = bw.flush()>
<cfset res = bw.close()>
Total time to create the file (in milliseconds)
Pass 1 - 1,563
Pass 2 - 1,062
Pass 3 - 1,094
Average time to create the file was down to an average of about 1 second.
Conclusion
600 seconds vs 1 second, hmmmm, I think I found a winner. The CFFILE is a very handy tag and saves having to write the extra lines of code for opening/closing etc. for simple file operations, however there is a huge performance hit when working with large files and having to use the CFFILE tag in an iterative process. As with any problem, there are always multiple solutions, pros and cons to each. For writing large files, the pros of the Java method significantly outweighed any perceived cons.
I have always thought image mosaics were pretty neat, not just because of the way they look, but because of the processes that are used to create the mosaic. With a better grasp on what is possible with images using the BitmapData class in Flash and a plethora of images available via the Flickr API I decided to try developing a Flash based image mosaic application.
Step 1 - Mapping the colours
This process is pulled directly from my one of my Pixel Fun samples. The concept is straight forward, load an image and then determine the dominate colour and grey scale value for each predefined block of the image. Sounds simple but as anyone who has tried to program massive amounts of looping in Flash will tell you, a nasty warning about a script slowing your movie will pop up pretty quickly if you do not handle things properly. In this case I have an image that is 400 pixels wide by 300 pixels high. With 10 x 10 blocks, it means I need to loop over 1200 blocks, 100 times each, that works out to 120,000 iterations. I used some trickery with the setInterval() method to break the iterations into smaller chunks, slow down the Flash engine and allow it to perform all those iterations without exploding.
Step 2 - Loading and processing the Flickr images
Photo mosaics require a lot of photos to sample, in order find photos that match the dominate colours determined in step 1. Thankfully Flickr has an API that allows developers to tap into their database of images. The trick in this step is loading the images from Flickr into the BitmapData class. A constraint on the BitmapData.draw() method is that any image in the source object must exist in the same domain as the swf. Thankfully my knowledge of Coldfusion saved the day. I created a cfm page that takes the URL of the image to load from Flickr, read the file and writes out the image header and data, thus allowing the image to 'exist' in the same domain.
Step 3 - Tiling the image
Speed was my enemy during this process. Originally in step 2 I loaded each image, determined the dominate colour value, saved that information in an array and then dumped the image. During this step I would use the array to find the images I needed and then reload each image back into Flash. The load/unload/reload process was much slower than I wanted so I did some testing to come up with a better solution. The solution I chose was to merge each image into an instance of the BitmapData class that could contain all the photos (the right side of the image in step 2), then by saving the x/y coordinates of the merged image I could easily copy the pixels from the large source bitmap into the mosaic as needed. It turns out this process has a technical term, blitting. It works like a charm and sped up the tiling process by an incredible amount. I used this same concept to create the mosaic. Instead of having 1200 movieclips to represent each tile in the mosaic (which brings the Flash player to it's knees as I discovered), I have one large bitmap that I merge the photos into.
Step 4 - Previewing tiles
Nothing overly exiting here except the finished product. As you roll over the mosaic the pointer's x/y position is tracked to determine which tile in the larger bitmap you are over. Using an associative array, the correct tile data can be found with no looping required, and the original source image block, with the RGB and grey scale values is displayed along with the mapped image and it's RGB and grey scale values, click the tile and you can view the original full size image in Flickr.
End Result
As they say 'a picture is worth a thousand words'.
Next steps
Hopefully as time permits I can extend this project out to include:
Source image uploading
Allowing the user to enter the sample photo search criteria
Zoom in/out capability
Downloading the finished mosaic
Search
About
Derrick Grigg is a professional Rich Internet Application (RIA) developer based in Toronto, Ontario, Canada. He specializes in architecting and developing applications using a variety of technologies, most notably Flash, Flex and Coldfusion.