3

デザイン時にフィルターが適用された他のスプライトで構成されたスプライトシンボルを含むFlashライブラリがあります。これらのシンボルを次のようにFlexアプリケーションに埋め込みます。

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
    <mx:Script>
        <![CDATA[
            [Bindable]
            [Embed(source="Resources.swf", symbol="SquareContainer")]
            private var squareContainer_class:Class;

            private function log(msg:String):void {
                    output.text = output.text + "\n" + msg;
            }
        ]]>
    </mx:Script>

    <mx:VBox horizontalAlign="center" width="100%" height="100%" >
        <mx:Image id="squareContainer" source="{squareContainer_class}"/>
        <mx:Button click="log(squareContainer.width + ', ' + squareContainer.height);"/>
        <mx:TextArea id="output" width="100%" height="100%" />
    </mx:VBox>

</mx:Application>

この例では、SquareContainerシンボルは幅100ピクセル、高さ100ピクセルです。ただし、グローとブラーのフィルターを備えた子スプライトが含まれているため、スプライトは100x100よりも大幅に大きく表示されます。コンテナーの構成を確実に知ることができないため、BitmapData.generateFilterRect()を使用して、ネストされたスプライトに適用されたフィルターを取得することはできません。

スプライトとそのフィルターのサイズを取得するにはどうすればよいですか?

4

4 に答える 4

4

おお、スウィート成功!(そしてヒントをありがとう) 友人は、ネストされたスプライトに存在する可能性のあるフィルターを処理するための素敵な再帰関数で問題を解決するのを手伝ってくれました:

private function getDisplayObjectRectangle(container:DisplayObjectContainer, processFilters:Boolean):Rectangle {
    var final_rectangle:Rectangle = processDisplayObjectContainer(container, processFilters);

    // translate to local
    var local_point:Point = container.globalToLocal(new Point(final_rectangle.x, final_rectangle.y));
    final_rectangle = new Rectangle(local_point.x, local_point.y, final_rectangle.width, final_rectangle.height);       

    return final_rectangle;
}

private function processDisplayObjectContainer(container:DisplayObjectContainer, processFilters:Boolean):Rectangle {
    var result_rectangle:Rectangle = null;

    // Process if container exists
    if (container != null) {
        var index:int = 0;
        var displayObject:DisplayObject;

        // Process each child DisplayObject
        for(var childIndex:int = 0; childIndex < container.numChildren; childIndex++){
            displayObject = container.getChildAt(childIndex);

            //If we are recursing all children, we also get the rectangle of children within these children.
            if (displayObject is DisplayObjectContainer) {

                // Let's drill into the structure till we find the deepest DisplayObject
                var displayObject_rectangle:Rectangle = processDisplayObjectContainer(displayObject as DisplayObjectContainer, processFilters);

                // Now, stepping out, uniting the result creates a rectangle that surrounds siblings
                if (result_rectangle == null) { 
                    result_rectangle = displayObject_rectangle.clone(); 
                } else {
                    result_rectangle = result_rectangle.union(displayObject_rectangle);
                }                       
            }                       
        }

        // Get bounds of current container, at this point we're stepping out of the nested DisplayObjects
        var container_rectangle:Rectangle = container.getBounds(container.stage);

        if (result_rectangle == null) { 
            result_rectangle = container_rectangle.clone(); 
        } else {
            result_rectangle = result_rectangle.union(container_rectangle);
        }


        // Include all filters if requested and they exist
        if ((processFilters == true) && (container.filters.length > 0)) {
            var filterGenerater_rectangle:Rectangle = new Rectangle(0,0,result_rectangle.width, result_rectangle.height);
            var bmd:BitmapData = new BitmapData(result_rectangle.width, result_rectangle.height, true, 0x00000000);

            var filter_minimumX:Number = 0;
            var filter_minimumY:Number = 0;

            var filtersLength:int = container.filters.length;
            for (var filtersIndex:int = 0; filtersIndex < filtersLength; filtersIndex++) {                      
                var filter:BitmapFilter = container.filters[filtersIndex];

                var filter_rectangle:Rectangle = bmd.generateFilterRect(filterGenerater_rectangle, filter);

                filter_minimumX = filter_minimumX + filter_rectangle.x;
                filter_minimumY = filter_minimumY + filter_rectangle.y;

                filterGenerater_rectangle = filter_rectangle.clone();
                filterGenerater_rectangle.x = 0;
                filterGenerater_rectangle.y = 0;

                bmd = new BitmapData(filterGenerater_rectangle.width, filterGenerater_rectangle.height, true, 0x00000000);                      
            }

            // Reposition filter_rectangle back to global coordinates
            filter_rectangle.x = result_rectangle.x + filter_minimumX;
            filter_rectangle.y = result_rectangle.y + filter_minimumY;

            result_rectangle = filter_rectangle.clone();
        }               
    } else {
        throw new Error("No displayobject was passed as an argument");
    }

    return result_rectangle;
}
于 2009-01-29T16:30:26.807 に答える
1

これは少し異なるアプローチです。オブジェクト全体を描画してBitmapDataから、ビットマップの非透明領域の境界を計算します。このアプローチは、特に複雑なオブジェクトではパフォーマンスが向上する可能性があります。

package lup.utils
{
    import flash.display.BitmapData;
    import flash.display.DisplayObject;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.geom.Rectangle;

    public class BoundsHelper
    {
        private var _hBmd:BitmapData;
        private var _hBmdRect:Rectangle;
        private var _hMtr:Matrix;
        private var _hPoint:Point;

        private var _xMin:Number;
        private var _xMax:Number;
        private var _yMin:Number;
        private var _yMax:Number;

        /**
         * Specify maxFilteredObjWidth and maxFilteredObjHeight to match the maximum possible size
         * of a filtered object. Performance of the helper is inversely proportional to the product
         * of these values.
         *
         * @param maxFilteredObjWidth Maximum width of a filtered object.
         * @param maxFilteredObjHeight Maximum height of a filtered object.
         */
        public function BoundsHelper(maxFilteredObjWidth:Number = 500, maxFilteredObjHeight:Number = 500) {
            _hMtr = new Matrix();
            _hPoint = new Point();
            _hBmd = new BitmapData(maxFilteredObjWidth, maxFilteredObjHeight, true, 0);
            _hBmdRect = new Rectangle(0, 0, maxFilteredObjWidth, maxFilteredObjHeight);
        }

        /**
         * Calculates the boundary rectangle of an object relative to the given coordinate space.
         *
         * @param obj The object which bounds are to be determined.
         *
         * @param space The coordinate space relative to which the bounds should be represented.
         *        If you pass null or the object itself, then the bounds will be represented
         *        relative to the (untransformed) object.
         *
         * @param dst Destination rectangle to store the result in. If you pass null,
         *        new rectangle will be created and returned. Otherwise, the passed
         *        rectangle will be updated and returned.
         */
        public function getRealBounds(obj:DisplayObject, space:DisplayObject = null, dst:Rectangle = null):Rectangle {
            var tx:Number = (_hBmdRect.width  - obj.width ) / 2,
                ty:Number = (_hBmdRect.height - obj.height) / 2;

            // get transformation matrix that translates the object to the center of the bitmap
            _hMtr.identity();
            _hMtr.translate(tx, ty);

            // clear the bitmap so it will contain only pixels with zero alpha channel
            _hBmd.fillRect(_hBmdRect, 0);
            // draw the object; it will be drawn untransformed, except for translation
            // caused by _hMtr matrix
            _hBmd.draw(obj, _hMtr);

            // get the area which encloses all pixels with nonzero alpha channel (i.e. our object)
            var bnd:Rectangle = dst ? dst : new Rectangle(),
                selfBnd:Rectangle = _hBmd.getColorBoundsRect(0xFF000000, 0x00000000, false);

            // transform the area to eliminate the effect of _hMtr transformation; now we've obtained
            // the bounds of the object in its own coord. system (self bounds)
            selfBnd.offset(-tx, -ty);

            if (space && space !== obj) { // the dst coord space is different from the object's one
                // so we need to obtain transformation matrix from the object's coord space to the dst one
                var mObjToSpace:Matrix;

                if (space === obj.parent) {
                    // optimization
                    mObjToSpace = obj.transform.matrix;
                } else if (space == obj.stage) {
                    // optimization
                    mObjToSpace = obj.transform.concatenatedMatrix;
                } else {
                    // general case
                    var mStageToSpace:Matrix = space.transform.concatenatedMatrix; // space -> stage
                        mStageToSpace.invert();                                    // stage -> space
                    mObjToSpace = obj.transform.concatenatedMatrix;                // obj -> stage
                    mObjToSpace.concat(mStageToSpace);                             // obj -> space
                }

                // now we transform all four vertices of the boundary rectangle to the target space
                // and determine the bounds of this transformed shape

                _xMin =  Number.MAX_VALUE;
                _xMax = -Number.MAX_VALUE;
                _yMin =  Number.MAX_VALUE;
                _yMax = -Number.MAX_VALUE;

                expandBounds(mObjToSpace.transformPoint(getPoint(selfBnd.x, selfBnd.y)));
                expandBounds(mObjToSpace.transformPoint(getPoint(selfBnd.right, selfBnd.y)));
                expandBounds(mObjToSpace.transformPoint(getPoint(selfBnd.x, selfBnd.bottom)));
                expandBounds(mObjToSpace.transformPoint(getPoint(selfBnd.right, selfBnd.bottom)));

                bnd.x = _xMin;
                bnd.y = _yMin;
                bnd.width = _xMax - _xMin;
                bnd.height = _yMax - _yMin;
            } else {
                // the dst coord space is the object's one, so we simply return the self bounds
                bnd.x = selfBnd.x;
                bnd.y = selfBnd.y;
                bnd.width = selfBnd.width;
                bnd.height = selfBnd.height;
            }

            return bnd;
        }

        private function getPoint(x:Number, y:Number):Point {
            _hPoint.x = x;
            _hPoint.y = y;
            return _hPoint;
        }

        private function expandBounds(p:Point):void {
            if (p.x < _xMin) {
                _xMin = p.x;
            }
            if (p.x > _xMax) {
                _xMax = p.x;
            }
            if (p.y < _yMin) {
                _yMin = p.y;
            }
            if (p.y > _yMax) {
                _yMax = p.y;
            }
        }
    }
}
于 2013-01-22T21:05:15.660 に答える
0

さて、良いニュースと悪いニュースがあります。悪いニュースは、これを「正しい方法」で行う効果的な方法が実際にはないということです。良いニュースは、それを概算する適切な方法があるということです。

一般的な規則として、幅のサイズはおおよそ(filter.blurX * 1.5)+ sprite.widthです。ここで、「filter」はsprite.filters配列のFilterです。ぼかしと高さについても同じことが言えます。もう1つの一般的なルールは、最小のxがsprite.x-(filter.blurX * 1.5)/2になることです。

これらの数値はいずれも「アドビの公式」ではありませんが、それに基づいてBitmapDataを作成できるように、十分な許容誤差内で機能します。

于 2009-01-21T20:09:39.333 に答える
0

これらのメソッドは通常の 100x100 の正方形を返すだけなので、getBounds または getRect の通常のメソッドを使用してこれが可能かどうかはわかりません。

いくつか提案があります。

まず、フィルタを動的に適用できます。そうすれば、フィルターの数値が得られ、実際のサイズを計算するためにプログラムで計算を行うことができます。

fla のムービークリップに 2 番目のレイヤーを追加できます。これは、元の正方形とすべてのフィルターの寸法を持ちます。次に、この正方形のアルファをゼロに設定します

3 つ目は、fla に四角形とその中にグローを含む png を作成することです。

個人的には、フィルターまたは元の正方形が変更された場合に必要なメンテナンスが最小限になるため、中間のオプションを使用します。

于 2009-01-21T19:34:17.860 に答える