how to set a bitmap as a mask - actionscript-3

i want to apply a picture which contains transparent areas as a mask to a display object.
the mask only show the area which the mask has color.but in fact,the display object still show the whole area.so i convert bitmap to a vector image,that's solve the problem,but the convert method is horrible.
public static function createVectorImage(bd:BitmapData,colorKey:uint = 0):Shape{
if(bd==null){
return null;
}
var sh:Shape = new Shape();
var g:Graphics = sh.graphics;
g.beginBitmapFill(bd);
var beginPixel:int = -1;
var i:int,il:int,j:int,jl:int;
var value:uint;
for(i = 0,il=bd.height;i<il;i++){
for(j = 0,jl = bd.width;j<jl;j++){
value = bd.getPixel32(j,i);
if(value!=colorKey&&beginPixel==-1){
beginPixel = j;
}else if(value==colorKey&&beginPixel!=-1){
//draw rect
g.drawRect(beginPixel,i,j-beginPixel,1);
beginPixel = -1;
}
}
if(beginPixel!=-1){
g.drawRect(beginPixel,i,j-beginPixel,1);
beginPixel = -1
}
}
g.endFill();
return sh;
}
is there any way better than this?

You can convert your display object to a bitmap then apply a mask on it.
Convert you display object to a bitmap data:
var rect:Rectangle = displayObject.getRect();
var displayBD:BitmapData = new BitmapData(rect.width, rect.height, true, 0);
displayBD.draw(displayObject);
Apply the mask:
private static const ORIG:Point = new Point(0, 0);
private static function createBitmapDataWithMask(
baseBD:BitmapData, maskBD:BitmapData):BitmapData
{
var bitmapData:BitmapData;
bitmapData = new BitmapData(baseBD.width, baseBD.height, true, 0x000000);
bitmapData.copyPixels(baseBD, baseBD.rect, ORIG, maskBD, ORIG, true);
return bitmapData;
}
Display the bitmap data:
var bitmapData:BitmapData = createBitmapDataWithMask(displayBD, maskBD);
var bitmap:Bitmap = new Bitmap(bitmapData, "auto", true);
addChild(bitmap);
If you remove the bitmap from the stage, don't forget the free the bitmap data!
removeChild(bitmap);
bitmap.bitmapData.dispose();
bitmap = null;

Another option would be to use bitmap caching. It needs to be applied to the mask as well as the maskee:
var bd:BitmapData = new BitmapData(200, 200, true, 0x00000000);
bd.fillRect(new Rectangle(0, 0, 40, 40), 0xff000000);
var mask:Bitmap = new Bitmap(bd);
mask.cacheAsBitmap = true;
var maskee:Sprite = new Sprite();
maskee.cacheAsBitmap = true;
maskee.graphics.beginFill(0xff0000, 1);
maskee.graphics.drawRect(0, 0, 200, 200);
maskee.graphics.endFill();
maskee.mask = mask;
addChild(mask);
addChild(maskee);

Related

detect mask fill as3

how to detect if my mask is filled about 90%? here is my drawing code.
var my_shape:Sprite = new Sprite();
var bitmapData:BitmapData = new BitmapData(shida.width, shida.height);
bitmapData.draw(shida);
shidaq.addEventListener(MouseEvent.MOUSE_MOVE, draw);
function draw(e:MouseEvent):void {
addChild(my_shape);
my_shape.mask = shida;
my_shape.graphics.beginFill(0xA7A9AC,1);
my_shape.graphics.drawCircle(mouseX, mouseY, 40);
my_shape.graphics.endFill();
}

Away3d transparent bitmap Sprite3d

I'm adding some circles to away3d as sprite3ds, but for some reason they all have white backgrounds that I can't seem to remove. Anyone know what I'm missing:
var hotspot:Hotspot = e.target as Hotspot;
var spBoard:Sprite = new Sprite();
spBoard.x = circleX;
spBoard.y = circleY;
var shCircle:Shape = new Shape();
shCircle.graphics.lineStyle(2,0x000000);
shCircle.graphics.drawCircle(0,0,circleR);
shCircle.x = 0;
shCircle.y = 0;
var shFill:Shape = new Shape();
shFill.graphics.lineStyle(1,0x000000);
shFill.graphics.moveTo(0,0);
shFill.graphics.lineTo(circleR,0);
shFill.x = 0;
shFill.y = 0;
var shAngle:Shape = new Shape();
var shArrow:Shape = new Shape();
shArrow.graphics.lineStyle();
shArrow.graphics.beginFill(0x000000);
shArrow.graphics.moveTo(angleR,1);
shArrow.graphics.lineTo(angleR-5,8);
shArrow.graphics.lineTo(angleR+5,8);
shArrow.graphics.lineTo(angleR,1);
shArrow.graphics.endFill();
spBoard.addChild(shFill);
spBoard.addChild(shAngle);
spBoard.addChild(shArrow);
spBoard.addChild(shCircle);
var hotspotTimer:MovieClip = new MovieClip();
hotspotTimer.addChild(spBoard);
var bounds:Rectangle = hotspotTimer.getBounds(hotspotTimer);
var bitmapData : BitmapData = new BitmapData(512, 512);
bitmapData.draw(hotspotTimer);
var bitmapPointsTexture:BitmapTexture = new BitmapTexture(bitmapData);
var _pointsMaterial:TextureMaterial = new TextureMaterial(bitmapPointsTexture);
var inworldHotspotTimer:Sprite3D = new Sprite3D(_pointsMaterial,bitmapData.width,bitmapData.height);
inworldHotspotTimer.x = hotspot.x;
inworldHotspotTimer.y = hotspot.y;
inworldHotspotTimer.z = hotspot.z;
scene.addChild(inworldHotspotTimer);
}
I've seen in blog posts such as this
http://www.allforthecode.co.uk/aftc/forum/user/modules/forum/article.php?index=6&subindex=4&aid=315
On how they do it, but they're using an older version with the BitmapMaterial removed.
Change the line that declares the bitmapdata to this:
var bitmapData : BitmapData = new BitmapData(512, 512, true, 0x00808080);
If you don't fill the bitmap with a color that has alpha of 0, you'll get the borders in the texture.

How to scale BitmapData AS3?

I am editing an air application for a client, and he wants the images that you import to be scaled to 650x650 when you save them by using the code below. I tried changing the values but when the image is exported some part is missing:
function menuItemClick1(event:Event):void{
var mat:Matrix = new Matrix();
mat.scale(2.0,2.0);
var bmpData:BitmapData = new BitmapData(this.template_mc.width * 2, this.template_mc.height * 2, false, 0xFFFFFF);
bmpData.draw(this.template_mc, mat);
var _bmp:Bitmap = new Bitmap(bmpData);
_bmp.smoothing = true;
//
imgBytes = PNGEncoder.encode(_bmp.bitmapData);
fs = new FileStream();
targetFile = File.desktopDirectory.resolvePath("icons/image.png");
targetFile.browseForSave("Save Your File");
targetFile.addEventListener(Event.SELECT, onSaveSelect);
}
I tried changing to this with no luck:
mat.scale(1.0,1.0);
var bmpData:BitmapData = new BitmapData(650,650, false, 0xFFFFFF);
Calculate matrix scale ratio this way:
var mat:Matrix = new Matrix();
var ratio:Number =Math.min(650/this.template_mc.width,650/this.template_mc.height);
mat.scale(ratio,ratio);
var bmpData:BitmapData = new BitmapData(650, 650, false, 0xFFFFFF);
bmpData.draw(this.template_mc, mat);

AS3 bitmapdata.draw without adding to display list/ Stage

I want to be able to cahce HTML text as bitmap, for use in AlivePDF. My testing works well with TextArea or if the component is on the Stage or visible. But I want to be able to crunch text blocks that dont necessarily sit on screen. Does anyone know how to do this?
What I have failing so far
public static function rasterizeText( text:String, width:int = 100, height:int = 100, x:int = 0, y:int = 0 ):BitmapData {
var textRenderer:TextArea = new TextArea();
textRenderer.width = width;
textRenderer.height = height;
textRenderer.htmlText = text;
var bitdata:BitmapData = new BitmapData(width, height, true, 0xFF000000)
bitdata.draw( textRenderer );
return bitdata;
}
Your code should work fine. There is no need to add textRenderer to the stage in order to draw it into the BitmapData. You are drawing your textRenderer onto a solid black background. Maybe your text is also black and that is why you can not see it?
Try changing 0xFF000000 to e.g. 0xFFFF0000 and see if the text will show up.
No it wasn't a color issue. Also I had the color set to FF000000 which at least should have been showing up black. TextArea didn't seem to play nice with bitmaps, although TextField works perfectly fine.
Edit: I'm guessing TextArea wasn't working as spark or mx because they're a FlexSprite thingy, which act differently to normal AS3 Sprites. They'll defer rendering until they're added to the display list.
Working function:
public function rasterizeText( text:String,
width:int = 100, height:int = 100 ):BitmapData {
var tf:TextField = new TextField();
tf.multiline = true;
tf.wordWrap = true;
tf.width = width;
tf.height = height;
tf.htmlText = text;
var bd:BitmapData = new BitmapData(width, height, true,0x00000000);
bd.draw(tf);
return bd;
}
This was not working (I tried mx & spark textarea components):
public function rasterizeText( text:String,
width:int = 100, height:int = 100 ):BitmapData {
var textRenderer:TextArea = new TextArea();
textRenderer.width = width;
textRenderer.height = height;
textRenderer.textFlow = TextConverter.importToFlow( text, TextConverter.TEXT_FIELD_HTML_FORMAT );
var bitdata:BitmapData = new BitmapData( width, height, false, 0xFF000000 )
bitdata.draw( textRenderer );
return bitdata;
}
However it would work when drawing from the Stage:
public function rasterizeText( text:String,
width:int = 100, height:int = 100 ):BitmapData {
var textRenderer:TextArea = new TextArea();
textRenderer.width = width;
textRenderer.height = height;
textRenderer.textFlow = TextConverter.importToFlow( text, TextConverter.TEXT_FIELD_HTML_FORMAT );
canvas.addElement( textRenderer );
var bitdata:BitmapData = new BitmapData( width, height, false, 0xFF000000 )
bitdata.draw( canvas );
return bitdata;
}

ColorTransform removes shadow

I've got movie clip on stage that has shadow filter.
When I apply ColorTransform to that movie clip, the shadow removes.
var ct:ColorTransform = new ColorTransform;
ct.color = 0x99CC00;
lamp.transform.colorTransform = ct;
How to save shadow?
The idea is to
save the filters (shadow) of your clip lamp,
apply the transformation,
put the clip in a master clip and
re-apply the filters to this untransformed parent.
code:
var lampFilters:Array = lamp.filters.slice(); //save filters
lamp.filters = []; //empty filters
var ct:ColorTransform = new ColorTransform();
ct.color = 0x99CC00;
lamp.transform.colorTransform = ct; //apply your transformation
var superLamp:Sprite = new Sprite();
superLamp.addChild(lamp); //nest the clip
addChild(superLamp);
superLamp.filters = lampFilters; //re-apply the filters
ColorTransform will transform the entire MovieClip, unfortunately, the filter is included. I suggest you layer lamp and apply the transform to the top most layer keeping the bottom layer (shadow) untouched.
Test example:
var ball:Sprite = new Sprite();
ball.graphics.beginFill(0x00FF00, 1);
ball.graphics.drawCircle(50, 50, 50);
ball.graphics.endFill();
ball.filters = [new DropShadowFilter()]; //default black
ball.addEventListener(MouseEvent.CLICK, changeColor);
addChild(ball);
//...
private function changeColor(evt:MouseEvent):void {
var ball:Sprite = evt.target as Sprite;
var ct:ColorTransform = new ColorTransform();
ct.color = 0x99CC00; // green-ish
ball.transform.colorTransform = ct;
ball.filters = [new DropShadowFilter(4, 45, 0xFFFFFF)]; //now white
}
Even with the shadow filter reapplied you can see it's still going to be green-ish as set by the transform.
You should use nested display objects to achieve this...
for instance you can create a movieclip within another movieclip. apply the colortransform to inner movie clip and apply the shadow to outer movie clip. works like a charm for me :)
Here is an alternate method that does not require a parent object. You basically use an AdjustColor and ColorMatrix to change the color instead of a ColorTransform.
Note:If you are using an IDE other than Flash, like Flex or FlashDevelop, you will need to include flash.swc into your library from 'Common/Configuration/ActionScript 3.0/libs/flash.swc' for the fl.motion.AdjustColor package/class. You can also Google the swc.
var mc:Sprite = new Sprite();
mc.graphics.beginFill(0xFF0000);
mc.graphics.drawCircle(100, 100, 100);
mc.graphics.endFill();
addChild(mc);
// White out the entire shape first
var whiteAC:AdjustColor = new AdjustColor();
whiteAC.brightness = 100;
whiteAC.contrast = 100;
whiteAC.saturation = -100;
whiteAC.hue = 0;
var whiteMatrix:Array = whiteAC.CalculateFinalFlatArray();
var whiteCMF:ColorMatrixFilter = new ColorMatrixFilter(whiteMatrix);
// Now use ColorMatrixFilter to change color
var colorMatrix:Array = hexToMatrix(0x0000FF);
var colorCMF:ColorMatrixFilter = new ColorMatrixFilter(colorMatrix);
// Create Drop Shadow
var myDropShadow:DropShadowFilter = new DropShadow();
mc.filters = [whiteCMF, colorCMF, myDropShadow];
function hexToMatrix ( hex:uint, alpha:Number = 1 )
{
var r:Number = ((hex & 0xFF0000) >> 16);
var g:Number = ((hex & 0x00FF00) >> 8);
var b:Number = ((hex & 0x0000FF));
var matrix:Array = [];
matrix = matrix.concat([r, 0, 0, 0, 0]); // red
matrix = matrix.concat([0, g, 0, 0, 0]); // green
matrix = matrix.concat([0, 0, b, 0, 0]); // blue
matrix = matrix.concat([0, 0, 0, alpha, 0]); // alpha
return matrix;
}