Update: I´ve rewritten the inverted mask-class from scratch and moved it here. It now support animated movieclips, video, webcam-feed and pretty much everything eles. I think.
About ten months ago I wrote a little as3-class that took care of something I think Adobe should have implemented in the FlashPlayer a long time ago, the inverted mask. As time went by I’ve added some features I found useful while working on projects at work. In this version you can swap between inverted and normal masks, hide/show the mask and remove it from memory.
Finally I just want to say: Adobe, I love Flash but I still think this is way to complicated. A simple DisplayObject.invertedMask = theMask; would be just fine. I know it’s easy to say ”just do it” but this is a feature a lot of developers would find useful.
Demo
The InvertedMask.as-class
package com.mattiasnorell.bitmap
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BlendMode;
import flash.display.DisplayObject;
import flash.display.Sprite;
/**
* Inverted Mask
* Version 2.0
*
* ...
* Original author: Rachel Diesel
* http://dieselation.com/2009/04/11/inverting-a-mask-in-actionscript-3/
*
* Pure AS3 code Mattias Norell
* http://blog.mattiasnorell.com/2010/08/21/pure-actionscript-3-inverted-mask-2/
*
*/
public class InvertedMask extends Sprite{
private var inverted:Sprite;
private var dup:BitmapData;
private var newAlpha:Bitmap;
private var isInverted:Boolean;
public function InvertedMask($parent:DisplayObject,$mask:DisplayObject,$maskPos:Object):void {
inverted = new Sprite();
inverted.x = $parent.x;
inverted.y = $parent.y;
dup = new BitmapData($mask.width, $mask.height, true, 0xffffff);
dup.draw($mask);
newAlpha = new Bitmap(dup, "auto", false);
newAlpha.x = $maskPos.x;
newAlpha.y = $maskPos.y;
newAlpha.blendMode = BlendMode.ERASE;
$mask.parent.removeChild($mask);
$parent.x=$parent.y = 0;
inverted.addChild($parent);
inverted.addChild(newAlpha);
inverted.blendMode = BlendMode.LAYER;
addChild(inverted);
isInverted = true;
}
public function moveMask($target:Object,$maskPos:Object):void {
$target.getChildAt(0).getChildAt(1).x = $maskPos.x;
$target.getChildAt(0).getChildAt(1).y = $maskPos.y;
}
public function Show():void{
inverted.blendMode = BlendMode.LAYER;
}
public function Hide():void{
inverted.blendMode = BlendMode.NORMAL;
}
public function autoShowHide():void{
(inverted.blendMode == BlendMode.LAYER) ? Hide() : Show();
}
public function swapMaskType($type:String = "auto"):void{
if($type == 'auto'){
$type = (isInverted == true) ? 'normal' : 'inverted';
}
if($type == 'inverted'){
Show();
inverted.mask = null;
isInverted = true;
}else if($type == 'normal'){
Hide();
inverted.mask = newAlpha;
isInverted = false;
}else{
trace("You must use either 'inverted','normal' or 'auto'.");
}
}
public function remove():void{
inverted.mask = null;
inverted.blendMode = BlendMode.NORMAL;
newAlpha.bitmapData.dispose();
newAlpha = null;
dup.dispose();
dup = null;
}
}
}
Source for the demo swf
When I code I use Flash Develop, hence the [Embed]-code below. If you use the Flash IDE just remove those two rows and import the image from the library.
package{
import flash.display.Sprite;
import flash.events.MouseEvent;
public class Main extends Sprite{
[Embed(source="image.jpg")]
public var imgCls:Class;
public function Main():void{
var img:Sprite = new Sprite();
img.addChild(new imgCls());
addChild(img);
var mask:Sprite = new Sprite();
mask.graphics.beginFill(0xFF0000,1);
mask.graphics.drawRect(0,0,30,30);
mask.graphics.endFill();
addChild(mask);
var newMask:InvertedMask = new InvertedMask(img, mask, { x:0, y:0 } );
addChild(newMask);
newMask.addEventListener(MouseEvent.MOUSE_MOVE, moveMask);
newMask.addEventListener(MouseEvent.CLICK, swap);
}
private function swap(e:MouseEvent):void {
e.currentTarget.swapMaskType();
}
private function moveMask(e:MouseEvent):void {
e.currentTarget.moveMask(e.currentTarget, { x:mouseX-10, y:mouseY-10 } );
}
}
}
