0
votes

I am working on a Pure ActionScript 3.0 project in which the user will be allowed to upload there own swfs into the application.

My objective is to load the swf and fit exactly on the stage. The problem is, when the user uploads the masked swf it is not exactly fitting to the stage when other swfs are working fine.

Consider my stage resolution is 800x600, when the user uploads the masked swf with stage width and height is 600x550 but the content width and height is 900 x 800.

How to fit this kind of swf into the stage?

2

2 Answers

1
votes

Per determining the bounds of a masked SWF, use BitmapData.

For example, I've created a 400x400 swf that's masked to 200x200 starting at 100x100 (download)

masked-swf

Loading this SWF would report 400x400 as width / height.

To obtain the visible bounds of the unmasked content, you could implement:

package
{
    import flash.display.BitmapData;
    import flash.display.Loader;
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.geom.Rectangle;
    import flash.net.URLRequest;

    [SWF(width = 400, height = 400, backgroundColor = 0xefefef, frameRate = 60)]
    public class X extends Sprite
    {

        private var loader:Loader;

        public function X()
        {
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;

            loader = new Loader();
            var url:URLRequest = new URLRequest("http://jasonsturges.com/labs/stack-overflow/examples/swf-mask/masked.swf");
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
            loader.load(url);
        }

        protected function completeHandler(event:Event):void
        {
            var bitmapData:BitmapData = new BitmapData(loader.width, loader.height, true, 0);
            bitmapData.draw(loader);
            var bounds:Rectangle = bitmapData.getColorBoundsRect(0xff000000, 0xff000000, true);
            trace(bounds);
        }
    }
}

Which reports:

(x=100, y=100, w=200, h=200)

So, the visible content is 200x200 starting at 100x100.

Per sizing to the stage, you need to determine what your constraint is to avoid blank / empty regions on the stage.

This can be implemented using a ratio variable:

var ratio:Number = 1.0;

Proportional scaling (by width):

var ratio:Number = stage.stageWidth / bounds.width;

loader.scaleX = ratio;
loader.scaleY = ratio;
loader.x = -(bounds.x * ratio);
loader.y = -(bounds.y * ratio);

Stretch display object to fit stage:

ader.scaleX = stage.stageWidth / bounds.width;
loader.scaleY = stage.stageHeight / bounds.height;
loader.x = -(bounds.x * (stage.stageWidth / bounds.width));
loader.y = -(bounds.y * (stage.stageHeight / bounds.height));

So, all together, to fit the loaded content stretched to fill the entire stage accounting for mask offset:

package
{
    import flash.display.BitmapData;
    import flash.display.Loader;
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.geom.Rectangle;
    import flash.net.URLRequest;

    [SWF(percentWidth = 100, percentHeight = 100, backgroundColor = 0xefefef, frameRate = 60)]
    public class X extends Sprite
    {

        private var loader:Loader;

        public function X()
        {
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;

            loader = new Loader();
            var url:URLRequest = new URLRequest("http://jasonsturges.com/labs/stack-overflow/examples/swf-mask/masked.swf");
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
            loader.load(url);
        }

        protected function completeHandler(event:Event):void
        {
            var bitmapData:BitmapData = new BitmapData(loader.width, loader.height, true, 0);
            bitmapData.draw(loader);
            var bounds:Rectangle = bitmapData.getColorBoundsRect(0xff000000, 0xff000000, true);
            trace(bounds);

            addChild(loader);

            loader.scaleX = stage.stageWidth / bounds.width;
            loader.scaleY = stage.stageHeight / bounds.height;
            loader.x = -(bounds.x * (stage.stageWidth / bounds.width));
            loader.y = -(bounds.y * (stage.stageHeight / bounds.height));
        }
    }
}
0
votes

You should compare both content and holder ratio to get an accurate fit. If you are loading external swf, your width/height information should come from the loaderInfo metadata of SWF not size of the loaded displayObject content. Here is a link to wonderfl to see it working: http://wonderfl.net/c/eRYv

And here the simple function to compare ratios:

function makeItFit(cont:Sprite, hold:Sprite):void{
        var holderRatio:Number = hold.width/hold.height;
        var contentRatio:Number = cont.width/cont.height;
        //compare both ratios to get the biggest side
        if(holderRatio < contentRatio){
           cont.width = hold.width; //width bigger, lets make it fit
           cont.scaleY = cont.scaleX; //adjust scale to avoid distortion
        }else{
           cont.height = hold.height;
           cont.scaleX = cont.scaleY;
        }
        //now the size is ok, lets center the thing
        cont.x = (hold.width - cont.width)/2;
        cont.y = (hold.height - cont.height)/2;
}

Remember, use loaderInfo width/height data if loading external swf. This is just an example.