Flash3D profesionnal tool


DistortImage 2.0, the fastest way to freely distort image with Flash in actionscript

March 24th, 2006 by kiroukou :: Resources, en :: RSS 2.0 :: trackback

Hi 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 :P

me distort

Here an example with a webcam stream :
placeholder for flash movie

Finally we decided to publish the following class.

JavaScript:
  1. /*
  2. ****************************
  3. * From a first idea and first implementation of Andre Michelle www.andre-michelle.com
  4. * @version 2.0
  5. * @author Thomas Pfeiffer - kiroukou - http://www.thomas-pfeiffer.info
  6. * @author Richard Lester - RichL
  7. * @author Didier Brun - foxy - http://www.foxaweb.com
  8. * @website: http://sandy.media-box.net
  9. * @description: Tesselate a movieclip into several triangles to allow free transform distorsion.
  10. * *************************
  11. * Licensed under the CREATIVE COMMONS Attribution-NonCommercial-ShareAlike 2.0
  12. * you may not use this file except in compliance with the License.
  13. * You may obtain a copy of the License at
  14. * http://creativecommons.org/licenses/by-nc-sa/2.0/fr/deed.en_GB
  15. ***************************
  16. * DistortImage class
  17. * Availability : Flash Player 8.
  18. **********************************************
  19. */
  20. import flash.geom.Matrix;
  21. import flash.display.BitmapData;
  22.  
  23. class DistortImage
  24. {
  25.     // -- texture to distord
  26.     public var texture:BitmapData;
  27.     /*
  28.     * Constructor
  29.     * @param mc MovieClip : the movieClip containing the distorded picture
  30.     * @param symbolId String : th link name of the picture in the library
  31.     * @param vseg Number : the vertical precision
  32.     * @param hseg Number : the horizontal precision
  33.     * @throws: An error in the second constructor parameter isn't a BitmapData or a MovieClip
  34.     */
  35.     public function DistortImage( mc: MovieClip, ptexture, vseg: Number, hseg: Number )
  36.     {
  37.         _mc = mc;
  38.         if( ptexture instanceof BitmapData )
  39.         {
  40.             texture = ptexture;
  41.         }
  42.         else if( ptexture instanceof MovieClip )
  43.         {
  44.             texture = new BitmapData( ptexture._width, ptexture._height );
  45.             texture.draw( ptexture );
  46.         }
  47.         else
  48.         {
  49.             throw new Error('Second argument in DistortImage class must be a BitmapData object or a Movieclip');
  50.         }
  51.         _vseg = vseg || 0;
  52.         _hseg = hseg || 0;
  53.         // --
  54.         _w = texture.width ;
  55.         _h = texture.height;
  56.         // --
  57.         _aMcs   = new Array();
  58.         _p   = new Array();
  59.         _tri    = new Array();
  60.         // --
  61.         __init();
  62.     }
  63.  
  64.     /**
  65.     * setTransform
  66.     *
  67.     * @param x0 Number the horizontal coordinate of the first point
  68.     * @param y0 Number the vertical coordinate of the first point   
  69.     * @param x1 Number the horizontal coordinate of the second point
  70.     * @param y1 Number the vertical coordinate of the second point 
  71.     * @param x2 Number the horizontal coordinate of the third point
  72.     * @param y2 Number the vertical coordinate of the third point   
  73.     * @param x3 Number the horizontal coordinate of the fourth point
  74.     * @param y3 Number the vertical coordinate of the fourth point  
  75.     *
  76.     * @description : Distord the bitmap to ajust it to those points.
  77.     */
  78.     function setTransform( x0:Number , y0:Number , x1:Number , y1:Number , x2:Number , y2:Number , x3:Number , y3:Number ): Void
  79.     {
  80.         var w:Number = _w;
  81.         var h:Number = _h;
  82.         var dx30:Number = x3 - x0;
  83.         var dy30:Number = y3 - y0;
  84.         var dx21:Number = x2 - x1;
  85.         var dy21:Number = y2 - y1;
  86.         var l:Number = _p.length;
  87.         while( --l> -1 )
  88.         {
  89.             var point:Object = _p[ l ];
  90.             var gx = ( point.x - _xMin ) / w;
  91.             var gy = ( point.y - _yMin ) / h;
  92.             var bx = x0 + gy * ( dx30 );
  93.             var by = y0 + gy * ( dy30 );
  94.  
  95.             point.sx = bx + gx * ( ( x1 + gy * ( dx21 ) ) - bx );
  96.             point.sy = by + gx * ( ( y1 + gy * ( dy21 ) ) - by );
  97.         }
  98.         __render();
  99.     }
  100.    
  101.    
  102.    
  103.     /////////////////////////
  104.     ///  PRIVATE METHODS  ///
  105.     /////////////////////////
  106.    
  107.     private function __init( Void ): Void
  108.     {
  109.         _p = new Array();
  110.         _tri = new Array();
  111.         var ix:Number, iy:Number;
  112.         var w2: Number = _w / 2;
  113.         var h2: Number = _h / 2;
  114.         _xMin = _yMin = 0;
  115.         _xMax = _w; _yMax = _h;
  116.         _hsLen = _w / ( _hseg + 1 );
  117.         _vsLen = _h / ( _vseg + 1 );
  118.         var x:Number, y:Number;
  119.         var p0:Object, p1:Object, p2:Object;
  120.        
  121.         // -- we create the points
  122.         for ( ix = 0 ; ix <_hseg + 2 ; ix++ )
  123.         {
  124.             for ( iy = 0 ; iy <_vseg + 2 ; iy++ )
  125.             {
  126.                 x = ix * _hsLen;
  127.                 y = iy * _vsLen;
  128.                 _p.push( { x: x, y: y, sx: x, sy: y } );
  129.             }
  130.         }
  131.         // -- we create the triangles
  132.         for ( ix = 0 ; ix <_vseg + 1 ; ix++ )
  133.         {
  134.             for ( iy = 0 ; iy <_hseg + 1 ; iy++ )
  135.             {
  136.                 p0 = _p[ iy + ix * ( _hseg + 2 ) ];
  137.                 p1 = _p[ iy + ix * ( _hseg + 2 ) + 1 ];
  138.                 p2 = _p[ iy + ( ix + 1 ) * ( _hseg + 2 ) ];
  139.                 __addTriangle( p0, p1, p2 );
  140.                 // --
  141.                 p0 = _p[ iy + ( ix + 1 ) * ( _vseg + 2 ) + 1 ];
  142.                 p1 = _p[ iy + ( ix + 1 ) * ( _vseg + 2 ) ];
  143.                 p2 = _p[ iy + ix * ( _vseg + 2 ) + 1 ];
  144.                 __addTriangle( p0, p1, p2 );
  145.             }
  146.         }
  147.         __render();
  148.     }
  149.    
  150.     private function __addTriangle( p0:Object, p1:Object, p2:Object ):Void
  151.     {
  152.         var u0:Number, v0:Number, u1:Number, v1:Number, u2:Number, v2:Number;
  153.         var tMat:Object = {};
  154.         // --      
  155.         u0 = p0.x; v0 = p0.y;
  156.         u1 = p1.x; v1 = p1.y;
  157.         u2 = p2.x; v2 = p2.y;
  158.         tMat.tx = -v0*(_w / (v1 - v0));
  159.         tMat.ty = -u0*(_h / (u2 - u0));
  160.         tMat.a = tMat.d = 0;
  161.         tMat.b = _h / (u2 - u0);
  162.         tMat.c = _w / (v1 - v0);
  163.         // --      
  164.         _tri.push( [p0, p1, p2, tMat] );   
  165.     }
  166.  
  167.     private function __render( Void ): Void
  168.     {
  169.         var vertices: Array;
  170.         var p0, p1, p2:Object;
  171.         var x0:Number, y0:Number;
  172.         var ih:Number = 1/_h, iw:Number = 1/_w;
  173.         var c:MovieClip = _mc; c.clear();
  174.         var a:Array;
  175.         var sM = {};
  176.         var tM = {};
  177.         //--
  178.         var l:Number = _tri.length;
  179.         while( --l> -1 )
  180.         {
  181.             a   = _tri[ l ];
  182.             p0  = a[0];
  183.             p1  = a[1];
  184.             p2  = a[2];
  185.             tM = a[3];
  186.             // --
  187.             sM.a = ( p1.sx - ( x0 = p0.sx ) ) * iw;
  188.             sM.b = ( p1.sy - ( y0 = p0.sy ) ) * iw;
  189.             sM.c = ( p2.sx - x0 ) * ih;
  190.             sM.d = ( p2.sy - y0 ) * ih;
  191.             sM.tx = x0;
  192.             sM.ty = y0;
  193.             // --
  194.             sM = __concat( sM, tM );
  195.             c.beginBitmapFill( texture, sM, false, false );
  196.             c.moveTo( x0, y0 );
  197.             c.lineTo( p1.sx, p1.sy );
  198.             c.lineTo( p2.sx, p2.sy );
  199.             c.endFill();
  200.         }
  201.     }
  202.  
  203.     private function __concat( m1, m2 ):Object
  204.     {   //Relies on the original triangles being right angled with p0 being the right angle.
  205.         //Therefore a = d = zero (before and after invert)
  206.         var mat = {};
  207.         mat.a  = m1.c * m2.b;
  208.         mat.b  = m1.d * m2.b;
  209.         mat.c  = m1.a * m2.c;
  210.         mat.d  = m1.b * m2.c;
  211.         mat.tx = m1.a * m2.tx + m1.c * m2.ty + m1.tx;
  212.         mat.ty = m1.b * m2.tx + m1.d * m2.ty + m1.ty;   
  213.         return mat;
  214.     }
  215.    
  216.     /////////////////////////
  217.     /// PRIVATE PROPERTIES //
  218.     /////////////////////////
  219.     private var _mc:MovieClip;
  220.     private var _w:Number;
  221.     private var _h:Number;
  222.     private var _xMin:Number, _xMax:Number, _yMin:Number, _yMax:Number;
  223.     // -- picture segmentation properties
  224.     private var _hseg:Number;
  225.     private var _vseg:Number;
  226.     private var _hsLen:Number;
  227.     private var _vsLen:Number;
  228.     // -- arrays of differents datas types
  229.     private var _p:Array;
  230.     private var _tri:Array;
  231.     private var _aMcs:Array;
  232.    
  233. }

All the source files are available here : source files

32 Responses to “DistortImage 2.0, the fastest way to freely distort image with Flash in actionscript”

  1. April 1st, 2006 at 6:10 pm :: nodename » The Sandy AS2 3D API and a Flash Cubic Panorama Tutorial

    [...] 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 [...]

  2. April 1st, 2006 at 6:12 pm :: nodename » Prospects for Immersive Panoramas in Flash

    [...] 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. [...]

  3. May 16th, 2006 at 11:06 am :: Bram Vaessen

    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!

  4. May 30th, 2006 at 7:23 am :: Josh Bunting

    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.

  5. May 30th, 2006 at 8:38 am :: kiroukou

    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

  6. May 30th, 2006 at 5:58 pm :: Josh Bunting

    Thomas,
    That did it. Brilliant! Thanks again for the great class.

    Josh

  7. July 4th, 2006 at 4:14 pm :: C4RL05

    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

  8. August 12th, 2006 at 10:50 pm :: Bill Underwood

    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!

  9. September 14th, 2006 at 8:12 pm :: Nabil Sayegh

    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?)

  10. September 18th, 2006 at 7:06 pm :: j

    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

  11. September 22nd, 2006 at 12:39 pm :: Erick Souza

    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.....

  12. November 23rd, 2006 at 1:27 am :: Jase

    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

  13. January 5th, 2007 at 9:54 am :: Mino

    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

  14. February 11th, 2007 at 10:03 pm :: merger

    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

  15. February 12th, 2007 at 10:28 pm :: 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!

  16. February 13th, 2007 at 3:29 pm :: Stan

    You and have helped me. At me the same problem was.

  17. March 5th, 2007 at 4:03 pm :: adam chrabaszcz

    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.

  18. April 17th, 2007 at 7:27 pm :: brett

    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?

  19. April 25th, 2007 at 10:01 am :: Carles Sanz

    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

  20. April 26th, 2007 at 5:16 pm :: silver surfer

    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

  21. October 22nd, 2007 at 3:09 pm :: Leigh

    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

  22. October 22nd, 2007 at 3:41 pm :: Leigh

    also.... Is it just me, or is it impossible to register to the forum at the moment?

  23. October 23rd, 2007 at 5:34 pm :: kiroukou

    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.

  24. December 9th, 2007 at 12:03 pm :: Saya

    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?

  25. March 7th, 2008 at 1:38 am :: Ricky

    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);

  26. April 8th, 2008 at 12:28 am :: Jarred

    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!

  27. May 1st, 2008 at 5:44 pm :: Robb

    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.

  28. June 5th, 2008 at 1:58 pm :: Max

    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

  29. June 10th, 2008 at 9:59 am :: ajitpal singh

    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????

  30. June 20th, 2008 at 3:00 pm :: Robert

    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?

  31. July 3rd, 2008 at 12:34 pm :: Kingoman

    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?

  32. July 10th, 2008 at 12:08 pm :: Sentinel

    Txs for this class, soz about my english :P, if any day I use it in a real-project, sure I do a donation!!!

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>