A Trick of Using PNGs to Mask Images

Problem Summery: I want an approach to mask images with given PNGs. However, the inner of some of the PNG images are transparent. After I set the PNG as a mask, the area of the masked image below the inner of the PNG is invisible.

Search-256x256 Demo | DownloadDownload Full Project

clip_image002

PNG

clip_image004

Current effect

The problem is how to approach to the effect like this:

clip_image006

Target effect

Solution Summery: The method floodFill of class BitmapData provides me a way to achieve my goal. For a mask image, if the pixel is transparent or its color is #FFFFFF, the pixel of the masked image below the pixel are invisible; otherwise, they are visible. floodFill will perform a flood fill operation on an image starting at an (x, y) coordinate and filling with a certain color, it is similar to the paint bucket tool in various paint programs. Therefore, if the center pixel of PNG is transparent, I do a flood fill operation starting at the center coordinate with the color #FF000000. Now, the pixels of the masked image below the pixels of the inner of the shape will be visible.

Following is the source of ArbitraryPNGMask.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
	xmlns:mx="http://www.adobe.com/2006/mxml"
	layout="horizontal"
	backgroundColor="#FFFFFF"
	paddingTop="0"
	paddingRight="0"
	paddingLeft="0"
	paddingBottom="0" viewSourceURL="srcview/index.html">

	<mx:Script>
		<![CDATA[
			import mx.core.UIComponent;
			import mx.events.FlexEvent;
			import mx.controls.Image;
			import mx.controls.listClasses.IListItemRenderer;

			private function initMask():void
			{
				var bitmapData:BitmapData = new BitmapData(picture.width,picture.height);
				bitmapData.floodFill(bitmapData.width/2,bitmapData.height/2,0xFF000000);
				maskImage.source = new Bitmap(bitmapData);
			}			

			private function getMaskImage(data:Object):Bitmap
			{
				var itemRenderer:IListItemRenderer = maskList.itemToItemRenderer(data);
				var bitmap:Bitmap;
				var bitmapData:BitmapData;			

				bitmapData = Bitmap(Image(itemRenderer).content).bitmapData.clone();				

				var pixel:uint = bitmapData.getPixel32(int(bitmapData.width/2),int(bitmapData.height/2));
				// extract the alpha value from the given ARGB value.
				var alpha:uint = pixel >> 24;

				// if the center pixel is transparent, suppose the mask is a png
				// image consist of a closed shape, this will fill the inner of
				// the closed shape with the RGB color 0x000000 inorder to make
				// the image area below the inner visible.
				if(alpha == 0x00)
					bitmapData.floodFill(bitmapData.width/2,bitmapData.height/2,0xFF000000);							

				bitmap = new Bitmap(bitmapData);
				return bitmap;
			}

			private function startDragging():void
			{
				oldMouseX = maskImage.mouseX;
				oldMouseY = maskImage.mouseY;
				maskImage.addEventListener(Event.ENTER_FRAME,doDrag);
			}

			private function endDragging():void
			{
				maskImage.removeEventListener(Event.ENTER_FRAME,doDrag);
			}

			private var oldMouseX:Number = 0;
			private var oldMouseY:Number = 0;

			private function doDrag(event:Event):void
			{
				var offsetX:Number = maskImage.mouseX - oldMouseX;
				var offsetY:Number = maskImage.mouseY - oldMouseY;
				maskImage.x += offsetX;
				maskImage.y += offsetY;
			}
		]]>
	</mx:Script>

	<mx:XML id="masksDataSource"
		source="assets/masks.xml"/>

	<mx:List id="maskList"
		dataProvider="{masksDataSource.mask}"
		height="100%">
		<mx:itemRenderer>
			<mx:Component>
				<mx:Image
					source="{data.@path}"
					height="80"/>
			</mx:Component>
		</mx:itemRenderer>
	</mx:List>

	<mx:Canvas
		width="100%"
		height="100%">
		<mx:Image id="picture"
			source="assets/picture.jpg"
			mask="{maskImage}"
			cacheAsBitmap="true"
			creationComplete="initMask()"
			/>

		<mx:Image id="maskImage"
			source="{getMaskImage(maskList.selectedItem)}"
			cacheAsBitmap="true"
			buttonMode="true"
			mouseChildren="false"
			mouseDown="startDragging();"
			mouseUp="endDragging();"/>
	</mx:Canvas>
</mx:Application>
Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • DZone
  • Reddit
  • Technorati
  • StumbleUpon
  • Twitter
RSS Enjoy this Post? Subscribe to Ntt.cc

RSS Feed   RSS Feed     Email Feed  Email Feed Follow us Follow us
You can leave a response, or trackback from your own site.

4 Responses to “A Trick of Using PNGs to Mask Images”

  1. [...] Summery: Continue the sample posted before A Trick of Using PNGs to Mask Images, When you browse a web page rendered in HTML with fire fox, IE, etc., click the right button of [...]

  2. raja says:

    How can we rotate and resize mask dynamically like in editors?

  3. ilias says:

    I have an image and a frame ( .png ) , how i can set the frame as a frame of my image? Please answer me , urgent!!!

  4. John says:

    Exceptional…just what I was looking for.. Thank you for sharing your code

Leave a Reply