DistortImage 2.0, the fastest way to freely distort image with Flash in actionscript
March 24th, 2006 by kiroukou :: Resources, en :: RSS 2.0 :: trackbackHi all,
As I thought, the idea I told you about in my previous post has been implemented ! Thanks to Richard Lester and Didier Brun we were able to run my idea correctly.
But in the same time we found some nice optimizations that we can add to the original DistordImage class. And after acomplete benchmark, we can see that the two solutions performances are equivalent now. The new class runs between 2.5 3 times faster !
But a feature we wanted to take under consideration was to allow the user to distort a Video Stream as easily as possible.
You can see an example of myself distorted using my webcam stream
Here an example with a webcam stream :
Finally we decided to publish the following class.
-
/*
-
****************************
-
* From a first idea and first implementation of Andre Michelle www.andre-michelle.com
-
* @version 2.0
-
* @author Thomas Pfeiffer - kiroukou - http://www.thomas-pfeiffer.info
-
* @author Richard Lester - RichL
-
* @author Didier Brun - foxy - http://www.foxaweb.com
-
* @website: http://sandy.media-box.net
-
* @description: Tesselate a movieclip into several triangles to allow free transform distorsion.
-
* *************************
-
* Licensed under the CREATIVE COMMONS Attribution-NonCommercial-ShareAlike 2.0
-
* you may not use this file except in compliance with the License.
-
* You may obtain a copy of the License at
-
* http://creativecommons.org/licenses/by-nc-sa/2.0/fr/deed.en_GB
-
***************************
-
* DistortImage class
-
* Availability : Flash Player 8.
-
**********************************************
-
*/
-
import flash.geom.Matrix;
-
import flash.display.BitmapData;
-
-
class DistortImage
-
{
-
// -- texture to distord
-
public var texture:BitmapData;
-
/*
-
* Constructor
-
* @param mc MovieClip : the movieClip containing the distorded picture
-
* @param symbolId String : th link name of the picture in the library
-
* @param vseg Number : the vertical precision
-
* @param hseg Number : the horizontal precision
-
* @throws: An error in the second constructor parameter isn't a BitmapData or a MovieClip
-
*/
-
public function DistortImage( mc: MovieClip, ptexture, vseg: Number, hseg: Number )
-
{
-
_mc = mc;
-
if( ptexture instanceof BitmapData )
-
{
-
texture = ptexture;
-
}
-
else if( ptexture instanceof MovieClip )
-
{
-
texture = new BitmapData( ptexture._width, ptexture._height );
-
texture.draw( ptexture );
-
}
-
else
-
{
-
throw new Error('Second argument in DistortImage class must be a BitmapData object or a Movieclip');
-
}
-
_vseg = vseg || 0;
-
_hseg = hseg || 0;
-
// --
-
_w = texture.width ;
-
_h = texture.height;
-
// --
-
_aMcs = new Array();
-
_p = new Array();
-
_tri = new Array();
-
// --
-
__init();
-
}
-
-
/**
-
* setTransform
-
*
-
* @param x0 Number the horizontal coordinate of the first point
-
* @param y0 Number the vertical coordinate of the first point
-
* @param x1 Number the horizontal coordinate of the second point
-
* @param y1 Number the vertical coordinate of the second point
-
* @param x2 Number the horizontal coordinate of the third point
-
* @param y2 Number the vertical coordinate of the third point
-
* @param x3 Number the horizontal coordinate of the fourth point
-
* @param y3 Number the vertical coordinate of the fourth point
-
*
-
* @description : Distord the bitmap to ajust it to those points.
-
*/
-
function setTransform( x0:Number , y0:Number , x1:Number , y1:Number , x2:Number , y2:Number , x3:Number , y3:Number ): Void
-
{
-
var w:Number = _w;
-
var h:Number = _h;
-
var dx30:Number = x3 - x0;
-
var dy30:Number = y3 - y0;
-
var dx21:Number = x2 - x1;
-
var dy21:Number = y2 - y1;
-
var l:Number = _p.length;
-
while( --l> -1 )
-
{
-
var point:Object = _p[ l ];
-
var gx = ( point.x - _xMin ) / w;
-
var gy = ( point.y - _yMin ) / h;
-
var bx = x0 + gy * ( dx30 );
-
var by = y0 + gy * ( dy30 );
-
-
point.sx = bx + gx * ( ( x1 + gy * ( dx21 ) ) - bx );
-
point.sy = by + gx * ( ( y1 + gy * ( dy21 ) ) - by );
-
}
-
__render();
-
}
-
-
-
-
/////////////////////////
-
/// PRIVATE METHODS ///
-
/////////////////////////
-
-
private function __init( Void ): Void
-
{
-
_p = new Array();
-
_tri = new Array();
-
var ix:Number, iy:Number;
-
var w2: Number = _w / 2;
-
var h2: Number = _h / 2;
-
_xMin = _yMin = 0;
-
_xMax = _w; _yMax = _h;
-
_hsLen = _w / ( _hseg + 1 );
-
_vsLen = _h / ( _vseg + 1 );
-
var x:Number, y:Number;
-
var p0:Object, p1:Object, p2:Object;
-
-
// -- we create the points
-
for ( ix = 0 ; ix <_hseg + 2 ; ix++ )
-
{
-
for ( iy = 0 ; iy <_vseg + 2 ; iy++ )
-
{
-
x = ix * _hsLen;
-
y = iy * _vsLen;
-
_p.push( { x: x, y: y, sx: x, sy: y } );
-
}
-
}
-
// -- we create the triangles
-
for ( ix = 0 ; ix <_vseg + 1 ; ix++ )
-
{
-
for ( iy = 0 ; iy <_hseg + 1 ; iy++ )
-
{
-
p0 = _p[ iy + ix * ( _hseg + 2 ) ];
-
p1 = _p[ iy + ix * ( _hseg + 2 ) + 1 ];
-
p2 = _p[ iy + ( ix + 1 ) * ( _hseg + 2 ) ];
-
__addTriangle( p0, p1, p2 );
-
// --
-
p0 = _p[ iy + ( ix + 1 ) * ( _vseg + 2 ) + 1 ];
-
p1 = _p[ iy + ( ix + 1 ) * ( _vseg + 2 ) ];
-
p2 = _p[ iy + ix * ( _vseg + 2 ) + 1 ];
-
__addTriangle( p0, p1, p2 );
-
}
-
}
-
__render();
-
}
-
-
private function __addTriangle( p0:Object, p1:Object, p2:Object ):Void
-
{
-
var u0:Number, v0:Number, u1:Number, v1:Number, u2:Number, v2:Number;
-
var tMat:Object = {};
-
// --
-
u0 = p0.x; v0 = p0.y;
-
u1 = p1.x; v1 = p1.y;
-
u2 = p2.x; v2 = p2.y;
-
tMat.tx = -v0*(_w / (v1 - v0));
-
tMat.ty = -u0*(_h / (u2 - u0));
-
tMat.a = tMat.d = 0;
-
tMat.b = _h / (u2 - u0);
-
tMat.c = _w / (v1 - v0);
-
// --
-
_tri.push( [p0, p1, p2, tMat] );
-
}
-
-
private function __render( Void ): Void
-
{
-
var vertices: Array;
-
var p0, p1, p2:Object;
-
var x0:Number, y0:Number;
-
var ih:Number = 1/_h, iw:Number = 1/_w;
-
var c:MovieClip = _mc; c.clear();
-
var a:Array;
-
var sM = {};
-
var tM = {};
-
//--
-
var l:Number = _tri.length;
-
while( --l> -1 )
-
{
-
a = _tri[ l ];
-
p0 = a[0];
-
p1 = a[1];
-
p2 = a[2];
-
tM = a[3];
-
// --
-
sM.a = ( p1.sx - ( x0 = p0.sx ) ) * iw;
-
sM.b = ( p1.sy - ( y0 = p0.sy ) ) * iw;
-
sM.c = ( p2.sx - x0 ) * ih;
-
sM.d = ( p2.sy - y0 ) * ih;
-
sM.tx = x0;
-
sM.ty = y0;
-
// --
-
sM = __concat( sM, tM );
-
c.beginBitmapFill( texture, sM, false, false );
-
c.moveTo( x0, y0 );
-
c.lineTo( p1.sx, p1.sy );
-
c.lineTo( p2.sx, p2.sy );
-
c.endFill();
-
}
-
}
-
-
private function __concat( m1, m2 ):Object
-
{ //Relies on the original triangles being right angled with p0 being the right angle.
-
//Therefore a = d = zero (before and after invert)
-
var mat = {};
-
mat.a = m1.c * m2.b;
-
mat.b = m1.d * m2.b;
-
mat.c = m1.a * m2.c;
-
mat.d = m1.b * m2.c;
-
mat.tx = m1.a * m2.tx + m1.c * m2.ty + m1.tx;
-
mat.ty = m1.b * m2.tx + m1.d * m2.ty + m1.ty;
-
return mat;
-
}
-
-
/////////////////////////
-
/// PRIVATE PROPERTIES //
-
/////////////////////////
-
private var _mc:MovieClip;
-
private var _w:Number;
-
private var _h:Number;
-
private var _xMin:Number, _xMax:Number, _yMin:Number, _yMax:Number;
-
// -- picture segmentation properties
-
private var _hseg:Number;
-
private var _vseg:Number;
-
private var _hsLen:Number;
-
private var _vsLen:Number;
-
// -- arrays of differents datas types
-
private var _p:Array;
-
private var _tri:Array;
-
private var _aMcs:Array;
-
-
}
All the source files are available here : source files


[...] A note about texture mapping in Flash. I didn’t go into detail about the transformation-matrix method of texture mapping in my article Prospects for Immersive Panoramas in Flash. The idea is that since a single Matrix cannot perform a 3D perspective transformation, we implement it by slicing the texture into smaller pieces (generally triangles) and doing a matrix transformation on each of them. So there’s a tradeoff: the more pieces we cut the texture into, the better the result approximates the true perspective transformation, and the slower our movie runs. This is how Sandy does it, and you can see the technique abstracted into a standalone class by Thomas Pfeiffer here: DistortImage. This class gives you Photoshop-style free transform in Flash. | Permalink [...]
[...] Update 2006/1/28: The idea of the transformation-matrix method of texture mapping is that since a single Matrix cannot perform a 3D perspective transformation, we implement it by slicing the texture into smaller pieces (generally triangles) and doing a matrix transformation on each of them. So there’s a tradeoff: the more pieces we cut the texture into, the better the result approximates the true perspective transformation, and the slower our movie runs. This is how the Flash 3D package Sandy does it, and you can see the technique abstracted into a standalone class by Thomas Pfeiffer here: DistortImage. This class gives you Photoshop-style free transform in Flash. [...]
The class works great, but I do have small problem:
I need a animated mask layer to mask a distorted image.
The first frame(s) are no problem, the mask works,
but at the first keyframe in the mask layer the distorted image dissapears (even if nothing has changed in the mask itself)
If I try the mask layer on another layer with normal objects it does work.
So do you know a workaround for this??? and thanks for the great class!
This is a really great class. A class like this helps open doors to interesting and decent looking 3d creations using flash. I have toyed with this class for a bit and noticed that the triangular image splicing is very visible when images get medium to large sized. It was mentioned that the quality of the image could be improved by increasing the number of triangles that the image was spliced into. What is the best way to edit the class to have control over how many triangular splices is applied to a given image? Again, I think this class is great and I could really use help getting my distorted images to look their best.
Hi,
Well if you set an hseg and vseg to 0, you'll have only two triangles!
If hseg and vseg equal to 1, you'll have 8 triangles.
hseg and vseg equal to 2, you'll have 18 triangles (If I make no mistakes).
In the next version, I'll give the possibility to create yourself the points and triangles, in order to obtain a better distortion.
Is it what you needed?
Thomas
Thomas,
That did it. Brilliant! Thanks again for the great class.
Josh
Hi Thomas,
I've noticed that it doesn't work with different hseg and vseg values. Fortunatelly, it can be easily fixed by changing the way you setup the triangles in the __init() function:
// -- we create the triangles
for ( ix = 0 ; ix
Hi Thomas,
I saw this notice at the end of this page and wasn't sure the correct way to contact you about it. Is it anything serious?
QUOTE...
A GARBAGE ERROR has occured!
Go to the Contact section and notify to me!
ENDQUOTE...
BTW, Thanks AGAIN for this great library! Congratulations!
Hi Kiroukou, excellent work!
I have a question about the license: "CREATIVE COMMONS Attribution-NonCommercial-ShareAlike 2.0"
What does NonCommercial mean?
I would like to use the distortion code in a project (website/shop) that I get paid for.
Does the whole project need to be free (*.fla)?
Of course I would donate something (How much would be appropriate?)
wait so how do i use this new 2.0 with a picture instead of a video. i cant seem to make it work without an argument error. thanks
Distorção de imagens dinâmicamente...
No Flash ainda não é possível distorcer imagens bitmaps nativamente via Actionscript, o efeito "Distort", presente também no Photoshop. O Thomas Pfeiffer do Sandy Project, junto ao Andre Michelle, Richard Lester e Didier Brun, desenvolveram a class.....
I am struggling with this class. I can see it's utility, but I can't for the life of me get it to do ANYTHING. And all I need is a SIMPLE perspective skew for a bitmap....I'm about to give up.
Could someone please provide some simple (no web-cam interactivity, no super duper tweeny majig, just a simple skewed perspective of a stationery BitmapImage) documentation?
If I sound like I'm being demanding, I apologize. I do really appreciate that you are sharing this class, I am just frustrated that I can't make it work.... My problem, not yours.
Thanks for any help you can offer.
jase
Hi,
This class is awesome.
I tried it and played with it, still amaze me.
I found a little problem when distorting images with text.
See screenshot at http://grahamedia.net/distort.jpg
Is there a way to make the text appear better?
I tried increasing the vseg & hseg to 100 still the text looks jaggy.
Please help.
Thanks before,
-Mino
Hi,
is there a way to distort images loaded from files, not from library?
if I attach a movieClip from the library it works great but if I try to load it from a file with loadMovie or loadClip it doesn't.
for example:
this works:
import DistortImage;
var mc:MovieClip = this.createEmptyMovieClip('test', 1);
this.attachMovie("mcmc","img_mc",this.getNextHighestDepth());
var d:DistortImage = new DistortImage( mc, img_mc , 2, 2 );
d.setTransform(100, 100, 200, 120, 200, 200 ,100, 200);
and this doesn't:
import DistortImage;
var mc:MovieClip = this.createEmptyMovieClip('test', 1);
this.createEmptyMovieClip("img_mc", this.getNextHighestDepth());
img_mc.loadMovie("file.jpg");
var d:DistortImage = new DistortImage( mc, img_mc , 2, 2 );
d.setTransform(100, 100, 200, 120, 200, 200 ,100, 200);
best regards
merger
ok. I've managed to do it. the problem was that the loaded jpg didn't load yet. so onLoadComplete gotoAndStop(3) and in the 3rd frame distort the image. great class!
You and have helped me. At me the same problem was.
hi,
I can't find any contact to You Kiroukou.
I would like to use this class in a project that I'm being paid and would love to pay for the class. Please contact me.
Is it possible to apply the distortion to a movieclip containing more than one image?
I am loading a couple jpgs into an mc and I want to distort the entire clip rather than each bitmap seperately. Does it only work on a single bitmap?
Hi Kiroukou,
I have used your class to do some tests in actionscript 3 project. To do this, I translated your class in actionscript 3.
If you are interesting to have it, I'll send you the code, but I don't know where?
Best regards
after creating a distort image object than applying a transformation (via fuse kit tween) to it how can I re target that same distort image object?
basically i create a bitmap object then draw it into an MC, then I apply the setTransform() function.
but after applying the function how do I re target that same distort image bitmap that was pushed into the MC, so I can call another setTransform() to it.
thanks
Great class!
Is there any way of distorting an MC with an animation inside it?
If it works with a webcam in realtime, surely it can do the same with animation...... right?
Any feedback would really be appreciated.
thanks
also.... Is it just me, or is it impossible to register to the forum at the moment?
It can be used with movieclips right. But it is always a bitmap version of the Movieclip frame that you'll see. So no interaction there.
The forum registration shall be fixed. Sorry for the pb.
I tried to make 2 simultaneous distortion, but only one picture was loaded. I think, I have problem with the variable.
This is the variable section,
/* a */
var mcx:MovieClip = this.createEmptyMovieClip ('xx', 1);
var bx:BitmapData = new BitmapData( texturex._width, texturex._height );
var dx:DistortImage = new DistortImage ( mcx, bx, 3, 3 );
/* b */
var mcy:MovieClip = this.createEmptyMovieClip ('yy', 1);
var by:BitmapData = new BitmapData( texturey._width, texturey._height );
var dy:DistortImage = new DistortImage ( mcy, by, 3, 3 );
With this condition, the picture for /* b */ is loaded. And when this code switched, /* a */ is loaded. Can you please help me to create 2 or more distortion at one time?
I tried to load a jpg then distort it, why doesn't it run the distort function once it has loaded the jpg?
import DistortImage;
var loadListener:Object = new Object();
loadListener.onLoadComplete = function(target_mc:MovieClip, httpStatus:Number):Void {
var d:DistortImage = new DistortImage(cover, image, 9, 9);
d.setTransform(-219,-325,271,-333,242,330,-275,261);
};
var mc_t:MovieClip = this.createEmptyMovieClip("cover", this.getNextHighestDepth());
var mc_b:MovieClip = this.createEmptyMovieClip("image", this.getNextHighestDepth());
var mcLoader:MovieClipLoader = new MovieClipLoader();
mcLoader.addListener(loadListener);
mcLoader.loadClip("Current-Editon-Sample.jpg",mc_b);
I have the same question as Ricky. I am doing almost the exact same thing. I'm listening for the load, then onLoadComplete, running a function to distort the image. I've even tried gotoAndStop(5), putting in the extra frames (not using a function call), but can't get the distortImage class to run on the MC that loads the external image.
If somebody understands this, can you please pass the information along, so that those who find this post later after we've documented well how to do this can find the information helpful as well?
Thanks!
By The Way: Awesome class!
Try using the onLoadInit method. I have found in the past that the onLoadInit method is more reliable than the onLoadComplete. Also, you are inside a different scope when the onLoadInit is called. Try accessing those mc's from within the scope of the handler.
import DistortImage;
var loadListener:Object = new Object();
loadListener.onLoadInit = function(target_mc:MovieClip):Void {
var d:DistortImage = new DistortImage(target_mc._parent.cover, target_mc, 9, 9);
d.setTransform(-219,-325,271,-333,242,330,-275,261);
};
var mc_t:MovieClip = this.createEmptyMovieClip("cover", this.getNextHighestDepth());
var mc_b:MovieClip = this.createEmptyMovieClip("image", this.getNextHighestDepth());
var mcLoader:MovieClipLoader = new MovieClipLoader();
mcLoader.addListener(loadListener);
mcLoader.loadClip("Current-Editon-Sample.jpg",mc_b);
These are all just suggestions I am not sure if it will work but it's worth a shot. If that doesn't work try putting the d:Distort.. etc in a function external from the handler, and pass the target_mc to it. Just a suggestion.
I'm completely stuck with this... =o((
First I downloaded the Sandy-AS2-package (1.2), and extracted it into a folder. Then I adjusted my AS2-settings in Flash CS3, so that it points to this additional folder. Afterwards I created a new Flash-File (AS2), and added "import DistortImage;" into the first line of my Actionscriptlayer. But what next?
Everything I read was much too complex for my needs: all I need is to distort one image, and fill it into an empty MovieClip I positioned on my stage. It will later be shown as the "program" on a TV-screen which is slightly distorted, so I need to adjust the image as well. I know I could easily distort the image in Photoshop before, but I wanna know the way it's done in AS.
Any proposals, any help?
Thanks bunches, and best regards from Germany
thax!!! it is a nice example.... well i was trying with bitmap using mask.. i got a problem can we find which layer is having mask or not just by coding and getting that layer name????
I'm been having a lot of success with this class. It's works wonderfully. However, ss there anyway I can prevent A DistorImage object from covering a foregound image?
I tried distorting an image but the image looks very jaggy and not smooth at all when I distort the it. How do I fix that?
Txs for this class, soz about my english :P, if any day I use it in a real-project, sure I do a donation!!!