views:

181

answers:

1

Hi, 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")
        }
    }
}
+2  A: 

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

George Profenza
Really, thank you George. Very helpful.
Ponty
also something else ... could i use another object like a sprite instead of the brush object?
Ponty
Of course you can. Easiest way with this setup is to make BitmapData version of your clip using draw() and that should be it...just replace the declaration on line 2 with this:var brushClip:MovieClip = new SpriteBrush();var brush:BitmapData = new BitmapData(brushClip.width,brushClip.height,true,0x00FFFFFF);Alternatively, you could attach the sprite and keep doing something like canvas.draw(brushClip,brushClip.transform.matrix);This would copy the brush with translation applied to it, assuming you would update it's position to follow the mouse.
George Profenza
See http://lifesine.eu/so/changePixels/bitmapPaint2.fla and http://lifesine.eu/so/changePixels/bitmapPaint3.flaGoodluck!
George Profenza
if i have several different background images of same size and same number of same foreground images that cover them where the images are jpg files what do you suggest?
Ponty
not sure I understand. You mean you have different images to reveal, each image having a custom associated 'brush' and you want to have something like layers ? 'different background images' = images to 'reveal' ? - 'same number of foreground images' = custom 'brushes' for each background to reveal ?
George Profenza
please check my version to see what i want to achieve:http://www.filesend.net/download.php?f=c9c21cc5d1be49b6a65eb0779b48692bbut i would like to do it like you way of appearing the background image.
Ponty
I see, I misunderstood. I got all enthusiastic because I thought you were onto something creative :) Anyway...you need kind of a reverse effect, where your are not reavealing, but hiding/eroding an image to display what's under it. You could achieve it if you draw and copy full values into the alpha channel. I didn't do that, I just used opposite colours for 'lottery ticket scratch' surface and brush, and set an appropiate blend more for the 'scratch surface' to get the thing done quick/cheap :).Updated fla here: http://lifesine.eu/so/changePixels/bitmapPaint4.fla
George Profenza