Skip to content


[AS 3] Actionscript Image Crop Project – Part II – Copying Bitmap Data

I updated the other project and was able to create a new movie that will copy the bitmap data from the area the user selects, much like an image cropping tool. So far this project will dynamically load a .jpg image to the stage, allows the user to highlight an area within the image by dragging a selection over the image, and then a duplicated image of the highlighted area will be created and placed at the top left corner of the stage.

Here is my document class BitmapDataCrop.as:

package
{
	import flash.display.Sprite;
	import flash.display.MovieClip;
	import flash.display.Shape;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import fl.controls.Button;
	import flash.display.Loader;
   	import flash.display.LoaderInfo;
	import flash.net.URLRequest;
	import flash.geom.Rectangle;
	import flash.geom.Point;
	import flash.geom.Matrix;

	public class BitmapDataCrop extends Sprite
	{
		private var myRectangle:Shape;
		private var myRectSp:Sprite;
		private var beginX:Number; // top left x position
		private var beginY:Number; // top left y position
		private var endX:Number; // bottom right x position
		private var endY:Number; // bottom right y position
		private var btnX:Number; // button position
		private var btnY:Number; // button position
		private var copyBeginX:Number;
		private var copyBeginY:Number;
		private var button:Button;
		private var imgLoader:Loader;
		private var holder:MovieClip;
		private var imageBMP:BitmapData;
		private var bmpWidth:int;
		private var bmpHeight:int;

		public function BitmapDataCrop()
		{
			// Load in the image
			imgLoader = new Loader();
			imgLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoaded);

			imgLoader.load(new URLRequest("http://manewc.com/projects/flash/BlurFilter/gahlord.jpg"));
		}

		private function imageLoaded(e:Event):void
		{
			stage.addEventListener(MouseEvent.MOUSE_DOWN, rectStartingPoint);
			addChild(imgLoader);
		}

		private function rectStartingPoint(m:MouseEvent):void
		{
			beginX = mouseX;
			beginY = mouseY;

			stage.removeEventListener(MouseEvent.MOUSE_DOWN, rectStartingPoint);
			stage.addEventListener(MouseEvent.MOUSE_MOVE, rectDraw);
		}

		private function rectDraw(m:MouseEvent):void
		{
			endX = mouseX;
			endY = mouseY;

			stage.addEventListener(MouseEvent.MOUSE_UP, stopRectDraw);
		}

		private function stopRectDraw(m:MouseEvent):void
		{
			var myRectangle:Shape = new Shape();

			myRectangle.graphics.beginFill(0xffffff);
            myRectangle.graphics.lineStyle(1);
            myRectangle.graphics.drawRect(beginX, beginY, endX - beginX, endY - beginY);
            myRectangle.graphics.endFill();

			var myRectSp:Sprite = new Sprite();
			myRectSp.addChild(myRectangle);

			addChild(myRectSp);

			stage.removeEventListener(MouseEvent.MOUSE_MOVE, rectDraw);
			stage.removeEventListener(MouseEvent.MOUSE_UP, stopRectDraw);

			addButtons();
		}

		private function addButtons():void
		{
			button = new Button();
            button.width = 100;
            button.height = 30;

			/* Position the button near the mouse within the rectangular area */
			if (endX - beginX > 0)
			{
				btnX = endX - button.width - 10;
			}
			else
			{
				btnX = endX + 10;
			}

			if (endY - beginY > 0)
			{
				btnY = endY - button.height - 10;
			}
			else
			{
				btnY = endY + 10;
			}

			button.move ( btnX,btnY );
            button.label = "Copy Area";
            addChild(button);

			button.addEventListener(MouseEvent.CLICK, cropImage);
		}

		private function cropImage(e:Event):void
		{
			// Draw the image from the movie clip into a BitmapData Obj.
			imageBMP = new BitmapData(imgLoader.width,imgLoader.height);
			imageBMP.draw(imgLoader, new Matrix());

			var imageBMPData:BitmapData;
			var bmpWidth:int = Math.abs(endX - beginX);
			var bmpHeight:int = Math.abs(endY - beginY);
			imageBMPData = new BitmapData(bmpWidth, bmpHeight);

			if (beginX - endX > 0)
			{
				copyBeginX = endX;
			}
			else
			{
				copyBeginX = beginX;
			}

			if (beginY - endY > 0)
			{
				copyBeginY = endY;
			}
			else
			{
				copyBeginY = beginY;
			}

      		imageBMPData.copyPixels(imageBMP, new Rectangle(copyBeginX,copyBeginY,bmpWidth, bmpHeight), new Point(0,0));

			createCrop(imageBMPData);
		}

		function createCrop(imgd:BitmapData)
		{
			// Setup a holder mc to hold the clipped image
   			holder = new MovieClip();
			addChild(holder);

			var cropClip:Bitmap = new Bitmap(imgd);
			var tmp2:MovieClip = new MovieClip();
			tmp2.addChild(cropClip);
			tmp2.name = String("croppedImage")    // Added for Strict Mode

			holder.addChild(tmp2);
		}
	}
}

Posted in Actionscript 3, Image Effects.


12 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. Shahar says

    Cool program… do you know how hard it would be to use a circle or a formless shape instead of the rectangle?

  2. admin says

    Interesting thought Shahar. Not sure if it is possible, but when I get more time I would like to experiment and see if it is possible.

  3. Shahar says

    well, if im not missing anything, i think that a circle shouldnt be that difficult – just need to change the draw rectangle function to do a circle instead – save the initial x,y and then use the end x,y to get the radius and thats it isnt it?
    free form of course is much more difficult :-) .
    i think an oval shape would be a bit harder than circle but definetly achievable in a couple of hours…
    unless you think im missing something.

  4. admin says

    I think my main concern would be what actually gets created with the bitmapData in the cropImage function. Although I don’t really know, I would be interested in finding out if there is an issue. I am thinking that the final image will be rectangular in shape but display a circular crop with a background color as a filler for the outer edge of the circle. hmmm.

  5. Rui Cruz says

    Hi, I implemented something like this on http://adigitalbook.com, but i found out a problem with copypixel method… :(

    loss of image quality, I load the source picture to a Image component, onComplete I Bitmap(Image.content), and bitmap.smoothing = true, everything all right… but when I crop, I loss quality :(

    maybe you can help me!

  6. admin says

    Hello Rui, Sorry for your troubles – I am not totally sure what the issue is without seeing your code. Are you setting the smoothing parameter to true because your object is being scaled or rotated?

  7. velu says

    Great Job!!!

    I have one doubt dude, I hope you will clear this…On your example you loaded the external image using loader. so that the registration point of the loader would be the top-left corner.In this case you can crop the image easily. But If you change the registration point of the loader (may be centre position) and then load the image,you can’t crop the image easily.

    What I am trying to say instead of using loader keep some movieclip on the stage,the registration point of the movieclip should be centre. Using this movieclip you load some image and then try to crop. you will find out some difficulty. If you feel this also very easy, please share with me how can do that……..

    Thanks for understanding
    velu

  8. Greg says

    Thanks for the great example I adapted it to crop images for thumbnails to 80 x 60
    private function imgLoaded(event:Event):void{
    var rect:Rectangle = new Rectangle(0,0,80,60);
    thumbnail = new Sprite;
    thumbnailBorder = new Sprite;
    thumbnailBorder.x = 17;
    thumbnailBorder.y = 39;
    thumbnailBorder.graphics.lineStyle(2,0×8c8c8c,1,true);
    thumbnailBorder.graphics.drawRoundRect(0, 0, 82, 62,10);
    thumbnailBorder.name = “thumb_border”;
    if(event.currentTarget.loader.width > 80 || event.currentTarget.loader.height > 60){
    imageBitMap = new BitmapData(event.currentTarget.loader.width,event.currentTarget.loader.height);
    imageBitMap.draw(event.currentTarget.loader, new Matrix());
    var tempBitMap:BitmapData;
    tempBitMap = new BitmapData(80,60);
    start = new Point(0,0)
    tempBitMap.copyPixels(imageBitMap,rect,start);
    thumbBitmap = new Bitmap(tempBitMap);
    }else{
    thumbBitmap = Bitmap(event.currentTarget.loader.content);
    }
    thumbnail.addChild(thumbBitmap);
    thumbnail.x = 18;
    thumbnail.y = 40;
    handler.addChild(thumbnail);
    handler.addChild(thumbnailBorder);
    }

  9. Varun Upadhyay says

    If i change Image width and height after loading then it will not work properly. So any idea how to resolve that problem? this code is only for actual size Image.

  10. lee says

    Great example. Getting ready to use some of your code for a freeform cropping tool. Not so much a crop as a bit of mask magic. I’ll have the user “paint” the crop area onto the photo then crop uut the square boundary of the image below the paint. Once this is finished the painted clip will become a mask over the cropped area to give the effect of a free form cropping. I’ll post my example when I finish it. Thanks again.

  11. Vergil Castelo says

    Great example. I am trying to adapt your example to use with corner crop marks and an image already in place (as opposed to loaded) but I’m having targeting the right object and keep coming up with errors. My code is tied to a cropTool movieclip on the main timeline, and everything is loaded into it, but for some reason from the button I am not able to target the image for copying correctly. Is it too much to ask for you to take a quick look I’ve posted my files here http://www.theworldeater.com/~verg/croptool.zip Any help would be greatly appreciated as I’ve looked to your work for inspiration numerous tmes. Thanks.

  12. Vipin says

    hi … Thanks for nice example…
    i have a little problem…when i am trying to set position of loader somewhere in stage…and try to crop …it display a blank image cut… Can anyone tell me what is actualy wrong that i am doing…

    Thanks in Advance



Some HTML is OK

or, reply to this post via trackback.