DistordImage, the way to distord bitmaps by code
November 1st, 2005 by Kiroukou :: Resources, en :: RSS 2.0 :: trackbackWho never hoped to be able to transform some bitmaps directly by code. Yes We can now skew and scale a MovieClip in Flash8, but when you need to map a bitmap on a more complex support, you just can't.
But thanks to Andre Michelle we were able to do that for two years, but this technics wasn't really optimized and precise.
Today Flash 8 brings some new possibilities making this very accurate.
Here is the example :
Play with the anchors clips to distort the picture
Here is the class :
JavaScript:
-
/**********************************************
-
* Copyright (c) 2005 Thomas PFEIFFER. All rights
-
* reserved.
-
*
-
* 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.
-
*
-
* Description
-
* _________
-
* Tesselate a movieclip into several triangles
-
* to allow free transform distorsion.
-
****************************
-
* From an idea and a first implementation from (C) Andre Michelle
-
* http://www.andre-michelle.com
-
****************************
-
* @author Thomas Pfeiffer - kiroukou
-
* @contact kiroukou@@gmail..com
-
**********************************************/
-
-
import flash.geom.Matrix;
-
import flash.display.BitmapData;
-
-
class com.kiroukou.graphics.DistordImage
-
{
-
private var _mc: MovieClip;
-
private var _w: Number;
-
private var _h: Number;
-
// -- skew and translation matrix
-
private var _sMat:Matrix ;
-
private var _tMat:Matrix ;
-
-
private var _xMin, _xMax, _yMin, _yMax: Number;
-
-
private var _hseg: Number;
-
private var _vseg: Number;
-
-
private var _hsLen: Number;
-
private var _vsLen: Number;
-
-
private var _p: Array;
-
private var _tri: Array;
-
-
private 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
-
*/
-
public function DistordImage( mc: MovieClip, symbolId: String, vseg: Number, hseg: Number )
-
{
-
_mc = mc;
-
_texture = BitmapData.loadBitmap( symbolId );
-
_vseg = vseg;
-
_hseg = hseg;
-
-
_w = _texture.width ;
-
_h = _texture.height;
-
__init();
-
-
}
-
-
-
private function __init( Void ): Void
-
{
-
_p = new Array();
-
_tri = new Array();
-
-
var ix: Number;
-
var 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;
-
// -- we create the points
-
for ( ix = 0 ; ix <_vseg + 2 ; ix++ )
-
{
-
for ( iy = 0 ; iy <_hseg + 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++ )
-
{
-
_tri.push([ _p[ iy + ix * ( _hseg + 2 ) ] , _p[ iy + ix * ( _hseg + 2 ) + 1 ] , _p[ iy + ( ix + 1 ) * ( _hseg + 2 ) ] ] );
-
_tri.push([ _p[ iy + ( ix + 1 ) * ( _hseg + 2 ) + 1 ] , _p[ iy + ( ix + 1 ) * ( _hseg + 2 ) ] , _p[ iy + ix * ( _hseg + 2 ) + 1 ] ] );
-
}
-
}
-
-
__render();
-
}
-
-
/* 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 function __render( Void ): Void
-
{
-
-
var t: Number;
-
var vertices: Array;
-
var p0, p1, p2:Object;
-
var c:MovieClip = _mc;
-
var a:Array;
-
c.clear();
-
_sMat = new Matrix();
-
_tMat = new Matrix();
-
-
var l:Number = _tri.length;
-
while( --l> -1 )
-
{
-
a = _tri[ l ];
-
p0 = a[0];
-
p1 = a[1];
-
p2 = a[2];
-
var x0: Number = p0.sx;
-
var y0: Number = p0.sy;
-
var x1: Number = p1.sx;
-
var y1: Number = p1.sy;
-
var x2: Number = p2.sx;
-
var y2: Number = p2.sy;
-
-
var u0: Number = p0.x;
-
var v0: Number = p0.y;
-
var u1: Number = p1.x;
-
var v1: Number = p1.y;
-
var u2: Number = p2.x;
-
var v2: Number = p2.y;
-
-
_tMat.tx = u0;
-
_tMat.ty = v0;
-
-
_tMat.a = ( u1 - u0 ) / _w;
-
_tMat.b = ( v1 - v0 ) / _w;
-
_tMat.c = ( u2 - u0 ) / _h;
-
_tMat.d = ( v2 - v0 ) / _h;
-
-
_sMat.a = ( x1 - x0 ) / _w;
-
_sMat.b = ( y1 - y0 ) / _w;
-
_sMat.c = ( x2 - x0 ) / _h;
-
_sMat.d = ( y2 - y0 ) / _h;
-
-
_sMat.tx = x0;
-
_sMat.ty = y0;
-
-
_tMat.invert();
-
_tMat.concat( _sMat );
-
-
c.beginBitmapFill( _texture, _tMat, false, false );
-
c.moveTo( x0, y0 );
-
c.lineTo( x1, y1 );
-
c.lineTo( x2, y2 );
-
c.endFill();
-
}
-
}
-
}
You can find the fla : here
Have fun


Je connais pas la distortion en as. Tu écris :
* Tesselate a movieclip into several triangles
* to allow free transform distorsion.
Pourquoi faut-il creer des triangles ? Avec Flash8, ses matrices et ses transform, le skewing n'est plus (+ou-) automatique ?
Salut William
Le but de decouper cette image en triangles, vient surtout du fait que c'est plus simple. Quand on veut deformer une image il y a beacoup de choses à faire et à prendre en compte. L'idée de "mailler" une image est très utile, et le choix du triangle vient du fait que l'on retrouve ainsi une base (au sens mathématique) d'un repère à 2 dimensions (meme dimension spatial que l'image). Ainsi on arrive à repérer un point par rapport à un repère local (la surface triangulaire auquel ce point appartient), et du coup on peut retrouver sa position apres modification du centre de son repere local (homothétie et rotation).
Apres là intervient la manipulation mathématique d'Andre Michelle qui a reussi a recuperer la transformation de chaque repere et calculer la matrice associée. Ainsi en passant a la methode de dessin (draw) la matrice equivalent, il retrouve le morceau d'image deformé correctement.
On aurait pu tout refaire "à la main" en manipulant les pixels, mais il faut refaire un échantillonage des points, et pour avoir des resultats corrects, un echantilonnage bilinéaire est nécéssaire, ce qui rendrai les calculs tres tres lourds.
Ensuite pour ta deuxieme question, je pense que tu te rend compte que le rendu que tu as sur l'exemple, est loin d'un simple skew
++
Ok, merci pour ces explications
- Pour le skew, en fait, ce qui manque a flash c'est une fonction quad comme celle de director. J'ai pas regardé dans l'as3 mais je pense que ce ne doit pas y etre. J'imagine que ca doit etre dans votre wishlist
- Pour la partie améliorée d'Andre Michelle, vous savez si c'est lui qui trouve ces fonctions mathématiques miraculeuses où si il les trouve deci-delà ?
En effet quad est exactementce qui nous faudrai
Sinon pour la formule d'andre michelle, c pas tres dur mathématiquement, c juste un changement de repère, mais il reste qu'il à eu l'idée et la talent pour le faire
Damn, this is really great! Excelent work
And thnx alot
Greetz Erik
That's a nice little effect with some tidy code. Thanks for the effort and for sharing it. I'm sure an occassion will arise eventually when I'll be needing such an engine.
Salut Kiroukou,
Superbe classe
Je me demandais... comment appliquer un tel effet sur des TextField dynamiquement instanciés.
Aurais-tu une idée ?
Mike.
Slt
Il faudrai que je modifie un peu cette classe pour qu'elle recoive en parametre du constructeur soit le bitmapData soit son indentifiant de liaison. Ainsi si tu passe une instance de bitmapData (contenant ton texte dynamique), toute se passera facilement
++
The SWF won't load !
Here's the actual URL : http://lesitekilestbien.free.fr/distordImage/meshtextured.swf
Hi Quentin
I know the problem... Just wonder why it doesn't load. I'm going to check if the url is correct (I think so).
[...] 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 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 [...]
The link to the swf is repaired !
HAve fun
[...] Aqui el link a Web del autor de la clase [...]
[...] Pour ceux qui ne le sauraient pas, je suis à l’origine du projet Sandy, projet ayant pour but de créer une librairie permettant de concevoir des scènes 3D pour Flash. Lors de la réalisation de ce moteur, j’ai développé une classe permettant de déformer un bitmap par le code (chose impossible nativement). Vous pouvez voir le résutat ici : http://sandy.media-box.net/blog/distordimage-the-way-to-distord-bitmaps-by-code.html [...]
Concernant le skew (le calcul) que Andre michelle aurait trouvé ...
, il lui a suffit de lire le texturage sous GBA (GameBoy Advance) :
d'ailleurs en voici le lien :
http://user.chem.tue.nl/jakvijn/tonc/affine.htm
si vous allez a la page d'accueil du site
vous y trouverez aussi des infos sur le mode 7 aussi
bonne lecture...
[...] But in the same time we found some pretty potimizations that we can add to the original DistordImage class. And after some complete benchmark, we can see that the two solutions are equivalent in performance now. The new class runs between 2.5 3 times faster ! [...]
its distorT not distorD
bajjzhdx...
bajjzhdx...
Hi, this effect is awesome!
I'd like to use it for my flash learning.
Could you please teach me how to use the class?
Where should I put the class above?
Thanks before.
we're using this class for a project that adds perspective to a flv file. It works fine if the flv is referenced with a relative url but breaks if we change that to an absolute url. the audio plays, but the video content is not visible. we added an animation to the mc and that animation stops as well. it's as if flash just stops trying if it gets an absolute path. any ideas?
Hi,
Does anyone know how to change this code, so I can have an animated image that is being distorted? I thougt maybe you need to use the BitmapData.draw method to draw a new image into the bitmapdata but it doesn't work, any ideas??
thanks.
phil
Salut,
Je travaille actuellement sur un site en flash. J'aurais aimé partir de ta classe pour développer une fonctionnalité de ce site. Comme le site en question sera mis en ligne par une entreprise (mais pas pour vendre des choses), je ne sais pas si la licence l'autorise. Peux tu me dire si tu es d'accord ou pas.
Merci d'avance,
Hélo
DistordImage is a very useful class. Congratulations! I would like to use your class in a commercial project. I would change the code a bit to allow bitmaps to import externally. I would be very grateful if you would grant me permission. Thanks
Brad
This idea is the greatest thing I have ever seen in AS.
By the way.. Why are those useless comments there?
Great code!!!
Nice!
Merci beaucoup pour le code, vous avez sauvé mon emploi
(jexagère)
Sérieux, le code est facile à travailler et pas trop lourd.
Merci!!
foda, usei muito já... valeu mesmo
How can this be altered to work on loaded images?
…yes it can. I've sorted it and it works a treat. Great bit of scripting. Thanks.
How do I get the latest copy of the DistortImage class for AS3.
This is fanstastic - I've got no experience of using classes in AS2, please could you outline how to set up that class file. Please Please
Hi, this script is fantastic, but I can't get it working when I dynamically load a jpg using loadMovie(); a black square appears in the DistortImage area.
Have you been able to do this with this class?
oh, I figured it out. The image hadn't loaded yet. Contact me through my website if anyone else is having trouble with this, as it was boggling me for longer than it should
Hi kiroukou,
just fantastic stuff. was looking for how to do this, and saw numerous people saying how impossible it was.
Anyway, just writing to say good on ya
It’s really nice example. But it’s not work on text.
I have tried with text But it become distorted the text then skew.
Is any way to improve text quality when distort/skew?
I really need for T-Shirt design project.