我有一个Flash库,其中Sprite符号由其他sprite组成,并带有设计时应用的滤镜。我将这些符号嵌入到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符号宽100px,高100px;但它包含一个带有发光和模糊滤镜的子精灵,这会导致精灵看起来明显大于100x100。由于我无法确定容器的组成,我不能使用BitmapData.generateFilterRect()来获取应用于嵌套sprite的过滤器。
如何获得精灵及其过滤器的大小?
答案 0 :(得分: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;
}
答案 1 :(得分:0)
我不确定使用getBounds或getRect的常规方法是否可行,因为这些方法只返回正常的100x100平方。
我有一些建议给你。
首先,您可以动态应用过滤器。这样你就可以得到过滤器的数字,你可以用编程方式计算出实际尺寸。
您可以在fla中的movieclip中添加第二个图层,其中包含原始正方形的尺寸以及所有滤镜。然后将此方块的alpha设置为零
第三,你可以在fla中加一个png,其中包含方形加上,比如内部的发光。
就个人而言,我会选择中间选项,因为如果过滤器或原始方块要改变,则需要最少量的维护。
答案 2 :(得分:0)
嗯,有好消息和坏消息。坏消息是,确实没有一种有效的方法来“正确地”做到这一点。好消息是有足够的方法来近似它。
一般规则是宽度的大小是大约(filter.blurX * 1.5)+ sprite.width其中“filter” “是sprite.filters数组中的Filter。关于模糊和高度也是如此。另一个一般规则是最小x变为sprite.x - (filter.blurX * 1.5)/ 2;
这些数字都不是“Adobe官方”,但工作范围合理允许您基于此创建BitmapData的错误。
答案 3 :(得分:0)
这是另一种方法:只需将整个对象绘制到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 maximal possible size
* of a filtered object. Performance of the helper is inversely proportional to the product
* of these values.
*
* @param maxFilteredObjWidth Maximal width of a filtered object.
* @param maxFilteredObjHeight Maximal 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);
}
/**
* Determines boundary rectangle of an object relative to the given coordinate space.
*
* @param obj The object which bounds are being determined.
*
* @param space The coordinate space relative to which the bounds should be represented.
* If you pass null or the object itself, then 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 it's 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;
}
}
}
}