Search code examples
actionscript-3flash-cs4

How to change the pixels in an image


i actually try to do the following: I have loaded an external image in a bitmapdata object and create a bitmap from it which i attach it to a sprite/MovieClip in order to have mouse events on it. Now under the previous logic i loaded two images (let's say circles) of the same size one that has a particular color and is covered by its black foreground circle. When i press left mouse button and hold it down i want while the mouse is moved to erase the foreground circle's pixels and so the background image starting to appear. I tried this to achieve but had no luck. In my best attempt i achieve to draw a line in the foreground image but i cannot reveal the background!

package
{
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.display.Loader;
    import flash.net.URLRequest;
    import flash.display.BitmapData;
    import flash.display.Bitmap;
    import flash.display.BlendMode;

    public class Test2 extends MovieClip
    {
        // properties - state

        // to attach the image and have mouse events
        private var frontImage:Sprite;
        private var backImage:Sprite;

        // to load the image
        private var myLoader:Loader;

        // to get the bitmap data of the image
        private var frontBitmapData:BitmapData;
        private var frontBitmap:Bitmap;

        // test
        private var frontMask:Bitmap;

        // constructor
        function Test2():void
        {
            // load the background image            
            backImage = new Sprite();
            attachImageToSprite1(new URLRequest("btest.jpg"));
            backImage.mouseEnabled = false;
            this.addChild( backImage );

            // load the front image 
            frontImage = new Sprite();
            attachImageToSprite2(new URLRequest("test.jpg"));
            frontImage.mouseEnabled = true; // enable mouse
            frontImage.buttonMode = true;   // set button mode 
            this.addChild(frontImage);  // load to stage

            this.frontImage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
            this.frontImage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
        }

        // methods
        private function attachImageToSprite1(Name:URLRequest):void
        {
            this.myLoader = new Loader();
            this.myLoader.load(Name);
            this.myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete1);
        }

        private function attachImageToSprite2(Name:URLRequest):void
        {
            this.myLoader = new Loader();
            this.myLoader.load(Name);
            this.myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete2);
        }

        private function getImageBitmapDataFromSprite(srcImage:Sprite):BitmapData
        {
            var tmpBitmapData:BitmapData = new BitmapData(frontImage.width, frontImage.height, true, 0xFFCCCCCC);
            tmpBitmapData.lock();
            tmpBitmapData.draw(frontImage);
            tmpBitmapData.unlock();
            return tmpBitmapData;
        }

        private function isPixelAlpha(bitmapdata:BitmapData):Boolean
        {
            var pixelValue:uint = bitmapdata.getPixel32(mouseX, mouseY);
            var alphaValue:uint = pixelValue >> 24 & 0xFF;
            //var red:uint = pixelValue >> 16 & 0xFF;
            //var green:uint = pixelValue >> 8 & 0xFF;
            //var blue:uint = pixelValue & 0xFF;
            return (alphaValue == 0x00) ? true : false;
        }

        private function deletePixelUnderMouse(bitmapdata:BitmapData, bitmap:Bitmap):void
        {
            bitmapdata.lock();
            if ( !isPixelAlpha(bitmapdata) ) {
                bitmapdata.setPixel32(mouseX, mouseY, 0xFF << 24);  // how to make the current pixel's alpha
            }                                                       // equal to zero.
            bitmap = new Bitmap(bitmapdata);
            bitmap.x = frontImage.x;
            bitmap.y = frontImage.y;
            this.frontImage.addChild(bitmap);
            bitmapdata.unlock();
        }

        // events
        public function onLoadComplete1(e:Event):void
        {
            frontImage.addChild(this.myLoader.content);
        }

        public function onLoadComplete2(e:Event):void
        {
            backImage.addChild(this.myLoader.content);
        }

        public function onMouseDown(e:MouseEvent):void
        {
            // delete a pixel from the sprite under the mouse
            frontBitmapData = getImageBitmapDataFromSprite(frontImage);
            deletePixelUnderMouse(frontBitmapData, frontBitmap);
            frontImage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseDown);
            trace("start");
        }

        public function onMouseUp(e:MouseEvent):void
        {
            frontImage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseDown);
            trace("stop")
        }
    }
}

Solution

  • Not sure if I got it right, but if you want a 'reveal' effect, as in you draw a mask to display a hidden image for example, this could be achieved slightly easier:

    var bitmapToReveal:BitmapData = new BitmapToReveal(0,0);
    var brush:BitmapData = new Brush(0,0);
    var canvasData:BitmapData = new BitmapData(bitmapToReveal.width,bitmapToReveal.height,true,0x00FFFFFF);
    var cursor:Point = new Point();//used as destination point when painting
    var zero:Point = new Point();//reused for painting
    var reveal:Bitmap = new Bitmap(bitmapToReveal);
    var canvas:Bitmap = new Bitmap(canvasData);
    reveal.cacheAsBitmap = canvas.cacheAsBitmap = true;
    addChild(reveal);
    addChild(canvas);
    reveal.mask = canvas;
    
    stage.addEventListener(MouseEvent.MOUSE_DOWN, brushDown);
    stage.addEventListener(MouseEvent.MOUSE_UP, brushUp);
    
    function brushDown(event:MouseEvent):void {
        this.addEventListener(Event.ENTER_FRAME, paint);
    }
    function brushUp(event:MouseEvent):void {
        this.removeEventListener(Event.ENTER_FRAME, paint);
    }
    function paint(event:Event):void {
        cursor.x = mouseX-brush.width*.5;
        cursor.y = mouseY-brush.height*.5;
        canvasData.copyPixels(brush,brush.rect,cursor,brush,zero,true);
    }
    

    I'm using two Bitmaps form the library(bitmapToReveal and brush). The main thing to look at is the copyPixels() method. I copy the brush bitmap into the canvas(an empty transparent bitmap data), using the offset cursor position(so the brush centered), and using the alpha channel to do that. Note that I've set cacheAsBitmap to true for both mask and maskee. You need to do that to get a transparent mask, which is key to the effect.

    Here is the result:

    bitmap brush

    You can 'paint' the mask here. CS4 Source is here.

    HTH, George