Home Labs Galleries PetitOn

A Flash 3D Image Cube

Note: This is work in progress

[ToDo: Make this readable ;)]

You can download the resulting Flickr Spinnr WordPress plugin from Headzoo.

The Petit3DCube

This may well be my next project for my Flickr images.
I'm working on it, starting with a 3D Image Cube that presented images from the Movies library, and extending it to read in images from an external directory, and transforming them to bitmaps.


By changing the mouse sensitivity in the Actionscript, the mobility of the cube gets higher and it seems lighter.


ToDo is to fetch them from Flickr.


The Flickr Spinnr

The Flickr Spinnr by Headzoo is a PHP/Javascript based rotating image cube, which is also a WordPress plugin. Headzoo contacted me on the possibility to use my Flash presentation layer.
The Javascript cube is rather resource demanding and a bit slow.

Using the "query string" approach to pass variable to a Flash movie, the PHP part of his application could inject Flickr image urls to the Flash cube. In a first attempt to test the client side of this, here is the client side object inclusion. I'm using part the of Satay method.

Note: line wrap for readability. See "view source" for the real thing!

<object type="application/x-shockwave-flash" 
	data="getimages.swf?urls=24/99910620_9d8e88035b_s.jpg|28/99910610_7934d6f8fd_s.jpg|
	21/99640877_1593d0cb20_s.jpg|40/99610840_6850327f4d_s.jpg|39/99609458_73926f1e2c_s.jpg|
	36/96802041_763d88271c_s.jpg"  width="500" height="200" align="left" >
   <param name="movie" value="getimages.swf?urls=24/99910620_9d8e88035b_s.jpg|
	28/99910610_7934d6f8fd_s.jpg|21/99640877_1593d0cb20_s.jpg|40/99610840_6850327f4d_s.jpg|
	39/99609458_73926f1e2c_s.jpg|36/96802041_763d88271c_s.jpg" />
</object>

The Flash movie reads the urls from the query string and splits it into an Array, adding the base URL.
It then creates a MovieClip for each image and loads the corresponding thumbnail images from Flickr.
The clips are presented on the Stage with some translation between images.

stop();
var images:Array;
var outText:String="";
var done:Boolean=false
this.onEnterFrame = function(){
	if(!done){
	done = true;
	images=urls.split("|");
	for( var i=0; i < images.length; i++){
		var loader = new MovieClipLoader();
		images[i]="http://static.flickr.com/" + images[i];
		outText+= '\r'+images[i] ;
		image=this.createEmptyMovieClip("image"+i, getNextHighestDepth());
		loader.loadClip(images[i], image);
		image._x = 80*i + 4;
		image._y = 3;
	}
	report.text=outText;
	}
}

The boolean "done" makes sure that the work is done only once

Here is the result:


Geting Thumbnails from Flickr

With very slight changes to the Petit3DCube, it now gets the image URL:s from a query string and the thumbnails from Flickr.

This 3D cube uses thumbnail images from my Flickr account. The image urls are hard coded in the object inclusion tag, as a "query string" attached to the FlickrSpinnr.swf. The thumbnail images are fetched from Flickr using a PHP proxy. the proxy is neccessary to break out of the Flash security sand box, which doesn't allow media from another server to be manipulated. In this case we have to convert the JPEGs to bitmaps, to be able to deform them as the coube rotates.
Here is the result:

Nice, or what?
Next step will be to get the URL:s from Headzoo's PHP application

An unforseen problem showed its ugly head here. When I run the cube locally, it worked like clock work, but after uploading it to my server, the images where gone. I suspected it had something to do with the Flash security sand box. The strange thing was, that in the earlier experiment above, the SWF fetched images from Flickr and presented them without problem.

I searched high and low for a solution, and found that the only difference between the simple presentation and the cube, was that I used BitmapData to be able to deform the images, as the cube rotates.

Searching the web for an answer, gave a lot of complicated arguments, but finally I found that BitmapData.draw() is not allowed to be applied to media fetched from another server, than the one hosting the SWF. Surely a strange behavior, as the images can be readily fetched, but not workded on.
The solution was to let the Flash Movie fetch the images from flickr via a PHP proxy residing on the same server as the SWF.

The real McCoy

Headzoo wrote a better proxy for getting images from Flickr without hazzle. We also added the user NSID to the query string:

<.... &nsid="users NSID here" />

So here we go

That way it is possible to link the images on the cube to the appropiate single image page at Flickr.
A new problem arose in that the cube images would haphazardly link to the wrong Flickr page. At first I thougt it would have someting to do with scoping issues in the Actionscript code, but I soon realized it was something else.

All JPEG images are loaded from Flickr in a loop using one MovieClipLoader object. When an image is fully loaded the loader fires an onLoadInit event. The event handler then processes the MovieClip containing that image, converts it to a bitmap and pastes it to the cube. The event handler increments an image counter, and that number is used to extract the Flickr image URL from an arrycontaining all image URL:s

The loop initiating the image loading process runs concurrently to the event handler processes, so we have a race condition. Depending on how long it takes to load an image and how long it takes for the event handler to process the image, images may be processed in any order. Using a global image count variable as an index into the URL:s array, is unreliable to say the least. The best way to make a strong coupling between the cube image and the corrresponding Flickr page, would be to send the index value of the loading loop to the event handler

The event handler, however, will only take the source of the event as an argument, in this case the MovieClip holding the image, so we must use teh image holder as a vehicle for the index value. The problem with this approach is that when the image is loaded, a new clip with the loaded image will take its place, and any properties added to the original clip is lost.

The solution is the same we use to keep event handlers as onPress, when loading anything into a MovieClip. We use an internal container to load media into. So we add the loop index as a property to the original MovieClip, and we add an internal MovieClip to load the image into. The outer MovieClip is untouched by the image load, and the inner clip is sent to the onLoadInit handler. When the event handler is invoked, we can extract the image index from the clips parent as

imgNo=image_clip._parent.imgNo

Yet another problem is that the images are mirrored (flipped) around the y-axis, as they are pasted to the cube. One could live with that in a 0.3 version, but stubbornness wouldn't. So I tried to move the cube faces and to move the points to turn the cube inside out, but to no avail. Then I decided to do something different. If you cannot change the 3D engine mathematically, you may be able to change the original images, before transforming them to bitmaps. You can do a horizontal flip by giving a MovieClip a negative x scale. So I applied that to the container of the original image.

content_mc._xscale *= -1;

The flip is relative to the container's registration point in the upper left corner of the MovieClip, so the axis of rotation goes along the left edge.
This means that after the flip, the registration point is in the upper right corner, the clip has moved to the left by its width. To compensate for this, we have to translate it to the right by that amount

content_mc._x = content_mc._width;

Now, when we take a snapshot of the clip, we order the BimapData.draw() method to catch the clip as it is on Stage, with its transformation matrix.

myBitmap.draw(content_mc,content_mc.transform.matrix);

Finally we start to get the whole thing together to make the ver 0.3 of the Flickr Spinnr WordPress plugin. Another hurdle wil show up though. When deilvering the SWF from withing the WordPress plugi directory, the SWF get confused as to where it comes from. When adressing the Flickr images, it doesnt fing the PHP proxy class, that does the actual connection to the Flickr service.
A possibility would be to use the BASE attribute, of the object inclusion tag to set the base url. That way the SWF would know where to find the proxy. The BASE attribute is not that useful, as it can only take a url one level below the document root. We are deeper than that. The solution is to pass the full url of the flickrspinnr plugins directiory to the movie. As before we add the parameter to the query string: &base=[full url goes here]. The Actionscript will pick up the url and call the proxy on that url.

Including a default image

If the user and/or tag option(s) results in less than six images, not all faces of the cube are built, which results in a strange looking an incompleate cube. The effect gets even worse, as the logic calculates which images are on the backside of the cube. Such an image is regarded as "hidden" and is not drawn. So images "hiding" behind a non exististing cube face mysterously disappear.

In the last version of FlickrSpinnr this problem is solved by the introduction of a default image, which acts as a standin for missing images. This image resides in the library of the Flash Movie and is always present. This solution has the advantage that the cube is always a cube, even when images are fetched from Flickr or the server local cache. You can see the effect of having only four images here.

Inclusion in existing static page

Is it possible to include the FlickrSpinnr in an already existing static HTML document, without changeing the file extension to PHP? Some answers are given in this experiments.