Rotating images using the Matrix class

Somebody recently asked on a forum how you could rotate images using the Matrix class. I quickly built this super-simple little example which shows how to use the <mx:Rotate /> effect as well as the Matrix class’s rotate() method.

Full code after the jump.

If you’re new to transforms and matrices, check out Senocular.com’s excellent article, “Understanding the Transform Matrix in Flash 8“.

View MXML

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2007/09/14/rotating-images-using-the-matrix-class/ -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
        layout="horizontal"
        verticalAlign="middle"
        backgroundColor="white">

    <mx:String id="deg">&#0176;</mx:String>

    <mx:Script>
        <![CDATA[
            import mx.core.UIComponent;

            private function img1_effectEnd():void {
                /* Set the appropriate Label text. */
                lbl1.text = "img1.rotation = " + img1.rotation.toString() + deg;
            }

            private function img2_creationComplete():void {
                /* "Copy" the existing matrix. */
                var m1:Matrix = img2.transform.matrix;
                /* Rotate the matrix 45 degrees (note that we have to
                   convert from degrees to radians since the rotate()
                   method expects radians. */
                m1.rotate(degreesToRadians(45));
                /* Concatenate the original matrix onto the rotated
                   matrix so we don't lose the original X and Y
                   coordinates and any other effects. */
                m1.concat(img2.transform.matrix);
                /* "Copy" the new matrix over the existing matrix. */
                img2.transform.matrix = m1;
                /* Set the appropriate Label text. */
                lbl2.text = "img2.rotation = " + img2.rotation.toString() + deg;
            }

            private function img_rollOver(cTarget:UIComponent):void {
                cTarget.toolTip = cTarget.name + ".rotation = " + cTarget.rotation.toString();
            }

            private function radiansToDegrees(radians:Number):Number {
                var degrees:Number = radians * (180 / Math.PI);
                return degrees;
            }

            private function degreesToRadians(degrees:Number):Number {
                var radians:Number = degrees * (Math.PI / 180);
                return radians;
            }
        ]]>
    </mx:Script>

    <mx:Rotate id="rotate" angleFrom="0" angleTo="45" duration="1" />

    <mx:ApplicationControlBar dock="true">
        <mx:Label id="lbl1" />
        <mx:Spacer width="50" />
        <mx:Label id="lbl2" />
    </mx:ApplicationControlBar>

    <mx:Image id="img1"
            source="http://www.helpexamples.com/flash/images/logo.png"
            creationCompleteEffect="{rotate}"
            effectEnd="img1_effectEnd();"
            rollOver="img_rollOver(UIComponent(event.currentTarget));" />

    <mx:Spacer width="50" />

    <mx:Image id="img2"
            source="http://www.helpexamples.com/flash/images/logo.png"
            creationComplete="img2_creationComplete();"
            rollOver="img_rollOver(UIComponent(event.currentTarget));" />

</mx:Application>

View source is enabled in the following example.

And just for giggles, here is a similar example which lets you rotate the image using a couple of Button controls. Note that the rotation is done around the center point of the image by calling the Matrix class’s translate() method to move the image before and after the rotation.

View MXML

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2007/09/14/rotating-images-using-the-matrix-class/ -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
        layout="vertical"
        verticalAlign="middle"
        backgroundColor="white">

    <mx:Script>
        <![CDATA[
            private function button_click(evt:Event):void {
                var direction:int;
                switch (evt.currentTarget) {
                    case degreesUp:
                        direction = +1;
                        break;
                    case degreesDown:
                        direction = -1;
                        break;
                }

                var radians:Number = degreesToRadians(direction);
                var offsetWidth:Number = img.width / 2;
                var offsetHeight:Number = img.height / 2;
                var tempMatrix:Matrix = img.transform.matrix;
                tempMatrix.translate(-offsetWidth, -offsetHeight);
                tempMatrix.rotate(radians);
                tempMatrix.translate(+offsetWidth, +offsetHeight);

                img.transform.matrix = tempMatrix;

                rotateDeg = img.rotation;
            }

            private function radiansToDegrees(radians:Number):Number {
                var degrees:Number = radians * (180 / Math.PI);
                return degrees;
            }

            private function degreesToRadians(degrees:Number):Number {
                var radians:Number = degrees * (Math.PI / 180);
                return radians;
            }
        ]]>
    </mx:Script>

    <mx:Number id="rotateDeg">0</mx:Number>
    <mx:NumberFormatter id="numberFormatter" precision="0" />
    <mx:String id="deg">{String.fromCharCode(176)}</mx:String>

    <mx:ApplicationControlBar dock="true">
        <mx:Label text="rotation:" />
        <mx:Button id="degreesUp"
                label="+"
                autoRepeat="true"
                click="button_click(event);"
                buttonDown="button_click(event);" />
        <mx:Button id="degreesDown"
                label="-"
                autoRepeat="true"
                click="button_click(event);"
                buttonDown="button_click(event);" />
        <mx:Spacer width="50" />
        <mx:Label id="lbl"
                text="{numberFormatter.format(rotateDeg)}{deg}" />
    </mx:ApplicationControlBar>

    <mx:VBox>
        <mx:Image id="img"
                source="http://www.helpexamples.com/flash/images/logo.png" />
    </mx:VBox>

</mx:Application>

View source is enabled in the following example.

23 thoughts on “Rotating images using the Matrix class

  1. Flanture,

    Thanks, good catch! Another case of me forgetting to web-friendly the MXML code after posting it in the Interwebs.

    Example updated above and should hopefully work now. I’ll try and get View Source-able SWFs posted later this evening.

    Peter

  2. Hello I have Problem :(

    I want to leave this image on the position. an image will to rotate automacally.
    I see that mxml, why do you not use with ? I am ztying with problem of rotating image. :(

    Thanks Joe Corner Reeve

  3. beautiful! thank you, thank you, searched entire web for this and this is the only working example in all of googleland. thanks!

    c

  4. If you examine the example carefully, it doesn’t rotate consistently around the exact center of the image. And then, if you go through an entire 360 degrees, the image position will be about 10 pixels or so below where it started.

    Using absolute positioning, try this function below instead. You have to pass the original x and y of the image control, don’t use the .x or .y properties since they change when the image is transformed.

    private function transformImage(img:Image, x:Number, y:Number, angle:Number):void {
    
    	var offsetWidth:Number = img.contentWidth / 2 ;
    	var offsetHeight:Number = img.contentHeight / 2 ;
    
    	var sin=Math.sin(angle);
    	var cos=Math.cos(angle);
    
    	var tempMatrix:Matrix = new Matrix();
    
    	tempMatrix.a = cos;
    	tempMatrix.b = -sin;
    	tempMatrix.c = sin;
    	tempMatrix.d = cos;
    
    	tempMatrix.tx = x - cos * offsetWidth - sin * offsetHeight \+ offsetWidth;
    	tempMatrix.ty = y \+ sin * offsetWidth - cos * offsetHeight \+ offsetHeight;
    
    	img.transform.matrix = tempMatrix;
    
    }
    
  5. Is it okay to use this on my own site? I’m happy to link back to you from my new site which I hope to have running by the end of January. Happy New Year to you, I hope it’s a good one!

  6. Man, I got worked trying to integrate this into my own application. If the the Image is not the only thing included in the VBox, this example no longer behaves as advertised. Seems that the matrix is relative to whatever container the Image resides in, not the Image itself. Just making sure this is clear to others who are still new to this stuff.

  7. private function transformImage(img:Image, x:Number, y:Number, angle:Number):void {

    var offsetWidth:Number = img.contentWidth / 2 ;
    var offsetHeight:Number = img.contentHeight / 2 ;

    var sin=Math.sin(angle);
    var cos=Math.cos(angle);

    var tempMatrix:Matrix = new Matrix();

    tempMatrix.a = cos;
    tempMatrix.b = -sin;
    tempMatrix.c = sin;
    tempMatrix.d = cos;

    tempMatrix.tx = x – cos * offsetWidth – sin * offsetHeight + offsetWidth;
    tempMatrix.ty = y + sin * offsetWidth – cos * offsetHeight + offsetHeight;

    img.transform.matrix = tempMatrix;

  8. Im losing my head here…
    I’m trying to adapt this sample using slider insted button but it just won’t work. My code:

    <code>
    private function rotateImage(evt:SliderEvent):void {
    evt.preventDefault();
    var tar:Slider = Slider(evt.currentTarget);

    var direction:int;

    direction = tar.value;

    var radians:Number = degreesToRadians(direction);

    var offsetWidth:Number = abc.width / 2;
    var offsetHeight:Number = abc.height / 2;

    var tempMatrix:Matrix = abc.transform.matrix;

    tempMatrix.translate(-offsetWidth, -offsetHeight);
    tempMatrix.rotate(radians);
    tempMatrix.translate(+offsetWidth, +offsetHeight);

    abc.transform.matrix = tempMatrix;

    cmtTxt.text = “Rotating image…” + direction;
    }
    </code>

    I have the radiansToDegrees and degreesToRadians functions. The thing is, when I use this code, the X, Y, scaleX and scaleY get all mess and the image jumps from one side to the other. By the way, image its inside a canvas and yes, I am accessing the image.

    Thanks!

  9. i have a problem with big images, when i rotate the image this get over other components like application control bar, there’s some way to resolve this issue? Cheers

    1. I too have this issue .. have u got solution for this?.. if any body has solution for this please share with me..

  10. Aren’t there any developers out there who know how to spell and use good grammar? What is with you people?

    1. Many of us are from non-english-speaking countries (and I’m not even sure what last sentence is correct…). Anyway… the thing is, nowadays, English is the unviversal language, and web try to adjust to it as good as we can, but it’s not easy, specially when the conversation is about technologies. Not my case, but there are a lot of fully qualified Flex developer in India, for example.
      I don’t think that’s something to be sorry for… good grammar or bad grammar, the important thing is to give something back to the community that always helps us.

  11. Here is the code you need to rotate the item when it is not at the origin. The inverted matrix is to get to the local coordinates of the item, the offsets are to rotate around the middle, and then the items initial transform is concatenated to get back to the global coordinates. I wasn’t totally brushed up on my linear algebra and it sounds like this can save everyone some time.

    The radians variable is the change in rotation to apply.

    var offsetWidth:Number = item.width / 2;
    var offsetHeight:Number = item.height / 2;
     
    var invertedMatrix:Matrix = item.transform.matrix;
    invertedMatrix.invert();
     
    var matrix:Matrix = item.transform.matrix;
    matrix.concat(invertedMatrix);
    matrix.translate(-offsetWidth, -offsetHeight);
    matrix.rotate(radians);
    matrix.translate(offsetWidth, offsetHeight);
    matrix.concat(item.transform.matrix);
     
    item.transform.matrix = matrix;
  12. Hello,
    i am trying to rotate my image which is a child of my view panel.
    I wrote something like that :

    var rotate:mx.effects.Rotate = new mx.effects.Rotate();
    //var iTmp:Image = new Image();
    //iTmp = viewerPanel.getChildAt(0) as Image;
    rotate.target= viewerPanel.getChildAt(0);
    rotate.angleFrom=viewerPanel.getChildAt(0).rotation;
    rotate.angleTo=viewerPanel.getChildAt(0).rotation – 90;
    rotate.duration=1000;
    rotate.originX=viewerPanel.getChildAt(0).width/2;
    rotate.originY=viewerPanel.getChildAt(0).height/2;
    rotate.play();

    it rotates the panel from top left.

    then i wrote something like that :
    var iTmp:Image = new Image();
    iTmp = viewerPanel.getChildAt(0) as Image;
    var q:Number = 90 * Math.PI / 180 // 30 degrees in radians
    var m:Matrix = new Matrix();
    var centerX:Number = iTmp.width / 2;
    var centerY:Number = iTmp.height /2;
    m.translate(-1 * centerX, -1 * centerY);
    m.rotate(q);
    viewerPanel.removeChildAt(0);
    viewerPanel.addChild(iTmp);
    and this made the same thing.

    So How can i rotate an image which is added to a panel as a child ?
    Thank you.

  13. How do i set the duration for the rotation of a matrix object.
    I cant seem to find someMatrix.rotate.duration or someMatrix.duration…

  14. Hi, I’m using the above code to rotate and zoom images (SWF images). Currently I’m facing with a problem, where some of the SWF graphics are rotating and zooming perfectly, but there are some image, where this is not working. Graphics are jumping out of screen without controll. The only difference between the good and bad swf objects is the filetype. 7.0 is good others are not so :o( . Tried to convert objects to 7.0 but this is not working also. Have You ever seen this type of problem? Where can I find any solution for it? Any suggestion, what could be wrong? Many thanks in advance, Zsolt

Comments are closed.