• Flex采用遮罩方法图片裁剪


    Flex采用遮罩方法图片裁剪

    在线预览

      http://rj.8634.com/xiaoshandong/ImageCropperDemo/ImageCropperDemo.html

    源码工程下载

     http://files.cnblogs.com/files/ffmpeg/ImageCropper.zip

    截图

      

    源代码

    ImageCropperDemo.mxml

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:c="com.flexblocks.imagecropper.*" layout="absolute" width="610" height="500" horizontalScrollPolicy="off" verticalScrollPolicy="off"
                     viewSourceURL="srcview/index.html">
        <mx:Style>
            Label {
                color: #BBBBBB;
            }
            
            CheckBox {
                color: #BBBBBB;
                textRollOverColor: #BBBBBB;
                textSelectedColor: #BBBBBB;
            }                        
        
        
        
        
        
        </mx:Style>
        <mx:Script>
            <![CDATA[
            
                // Index of last image selected using the selectImage ComboBox
                
                private var lastSelectedImage:uint = 0;
                
                // Current values for the cropping rectangle, handle size, and aspect ratio constraint settings
                
                private var currentCropbox:Rectangle;
                private var currentHandleSize:uint = 10;
                private var currentCropConstraint:Boolean = false
                
                // Image 1 ("Image Larger then Component"): Last values for the cropping rectangle, handle size, and aspect ratio constraint settings
                
                private var img1Cropbox:Rectangle;
                private var img1HandleSize:uint = 10;
                private var img1CropConstraint:Boolean = false;
                
                // Image 2 ("Image Smaller than Component"): Last values for the cropping rectangle, handle size, and aspect ratio constraint settings
    
                private var img2Cropbox:Rectangle;            
                private var img2HandleSize:uint = 10;
                private var img2CropConstraint:Boolean = false;            
                
                // --------------------------------------------------------------------------------------------------
                // doImageSelect - Called when an image is selected using the selectImage ComboBox
                // --------------------------------------------------------------------------------------------------
    
                private function doImageSelect():void {
                    
                    // Remove the previously cropped image
                    
                    croppedImage.source = null;
                    croppedImage.width = 0;
                    croppedImage.height = 0;
                    
                    // Save the cropping rectangle, handle size and constraint option for the previous image so that these settings 
                    // may be restored when the image is re-selected
                    
                    if (lastSelectedImage == 0) { 
                        img1Cropbox = imageCropper.getCropRect(true);
                        img1HandleSize = imageCropper.handleSize;
                        img1CropConstraint = constrainToAspectRatio.selected;
                    }
                    else {
                        img2Cropbox = imageCropper.getCropRect(true);
                        img2HandleSize = imageCropper.handleSize;
                        img2CropConstraint = constrainToAspectRatio.selected;
                    }
                    
                    // Update the saved ComboBox index to the index for the newly selected image
                    
                    lastSelectedImage = selectImage.selectedIndex;    
                    
                    // Restore the cropping rectangle, handle size and constraint option for the image just selected
                                                
                    currentCropbox = lastSelectedImage == 0 ? img1Cropbox : img2Cropbox;
                    currentHandleSize = lastSelectedImage == 0 ? img1HandleSize : img2HandleSize;
                    currentCropConstraint = lastSelectedImage == 0 ? img1CropConstraint : img2CropConstraint;
                    
                    // Tell the ImageCropper component to begin loading the selected image
                    
                    imageCropper.sourceImage = selectImage.selectedItem.data;                
    
                    // Disable all controls while the image is loading. This is done after the sourceImage is assigned
                    // to the ImageCropper because when the ImageCropper is disabled a sourceImage cannot be assigned.
                    
                    enableControls(false, true);            
                }
    
                // --------------------------------------------------------------------------------------------------
                // imageReady - Called when the ImageCropper component has loaded and initialized an image
                // --------------------------------------------------------------------------------------------------
                
                private function imageReady():void {
                    
                    // Enable the controls (including the imageCropper). Note that the imageCropper must be enabled before changing property values or calling setCropRect().
                    
                    enableControls(true, true);
                                
                    // Restore the handle size that was previously saved for this image
                    
                    imageCropper.handleSize = currentHandleSize;
                    handleSize.value = currentHandleSize;
                    
                    // Restore "Constrain Crop Rectangle to Aspect Ratio" to the setting that was previously saved for the image
                    
                    imageCropper.constrainToAspectRatio = currentCropConstraint;
                    constrainToAspectRatio.selected = currentCropConstraint;
    
                    // If this image was not previously selected then set the cropping rectangle to include the entire image. Otherwise,
                    // restore the cropping rectangle to its previous value. Note that the cropping rectangle is relative to the component
                    // and not to the image because the componentRelative parameter in the call the to setCropRect is set to true.
                    
                    if (!currentCropbox) imageCropper.setCropRect();
                    else imageCropper.setCropRect(currentCropbox.width, currentCropbox.height, currentCropbox.x, currentCropbox.y, true);
                    
                    // Get the cropped image 
                    
                    doCrop();                
                }
                
                // --------------------------------------------------------------------------------------------------
                // doCrop - Get the cropped image from the ImageCropper component
                // --------------------------------------------------------------------------------------------------
    
                private function doCrop():void {
                    
                    // Get the cropped BitmapData
                    
                    var newImage:BitmapData = imageCropper.croppedBitmapData;
                    
                    // Set the width and height of the croppedImage Image based on the dimensions of the cropped image
                    
                    croppedImage.width = newImage.width;
                    croppedImage.height = newImage.height;
    
                    // Create a new Bitmap from the BitmapData and assign it to the croppedImage Image
                    
                    croppedImage.source = new Bitmap(newImage);
                    
                    // Display the cropping rectangle in relative to the ImageCropper component and relative to the image
                    
                    imageCropperRect.text = imageCropper.getCropRect(true, true).toString();
                    sourceImageRect.text = imageCropper.getCropRect(false, true).toString();
                }    
                
                // --------------------------------------------------------------------------------------------------
                // enableControls - Enables or disables the controls
                // --------------------------------------------------------------------------------------------------
                
                private function enableControls(enable:Boolean, includeEnabled:Boolean = false):void {
                    
                    // The checkbox to enable/disable the ImageCropper component is only affected if includeEnabled is set to true
                    
                    if (includeEnabled) enableComponent.enabled = enable;
                    
                    // Set the enabled state for all other controls
                    
                    imageCropper.enabled = enable;
                    selectImage.enabled = enable;
                    outlineColor.enabled = enable;
                    outlineAlpha.enabled = enable;
                    handleColor.enabled = enable;
                    handleAlpha.enabled = enable;
                    maskColor.enabled = enable;
                    maskAlpha.enabled = enable;
                    backgroundColor.enabled = enable;
                    backgroundAlpha.enabled = enable;
                    handleSize.enabled = enable;
                    constrainToAspectRatio.enabled = enable;
                }
            ]]>
        </mx:Script>
        <mx:Label x="14" y="11" text="ImageCropper Component" fontWeight="bold" color="#FFFFFF"/>
        <c:ImageCropper id="imageCropper" y="39" left="15" width="280" height="280" enabled="true" sourceImage="large.jpg" handleColor="#FF00FF" maskColor="#660066" maskAlpha="0.6"
                        sourceImageReady="imageReady()" sourceImageLoadError="trace('Error while loading image')" cropRectChanged="doCrop()" cropConstraintDisabled="constrainToAspectRatio.selected = false"
                        cropConstraintChanged="trace('Crop constraint changed'); doCrop()" cropDimensionsChanged="trace('Crop dimensions changed'); doCrop()" cropPositionChanged="trace('Crop position changed'); doCrop()" x="15"/>
        <mx:Label x="314" y="11" text="Cropped Image" fontWeight="bold" color="#FFFFFF"/>
        <mx:Canvas y="37" right="15" width="280" height="280" backgroundColor="#000000" x="315">
            <mx:Image id="croppedImage" scaleContent="false" y="0" x="0"/>
        </mx:Canvas>
        <mx:CheckBox id="enableComponent" x="15" y="338" enabled="false" label="Enable the ImageCropper Component" selected="true" change="enableControls(enableComponent.selected)"/>
        <mx:ComboBox id="selectImage" x="15" y="369" enabled="false" change="doImageSelect()" width="250">
            <mx:dataProvider>
                <mx:Array>
                    <mx:Object label="Image Larger then Component Size" data="large.jpg"/>
                    <mx:Object label="Image Smaller than Component Size" data="small.jpg"/>
                </mx:Array>
            </mx:dataProvider>
        </mx:ComboBox>
        <mx:Label x="314" y="340" text="Outline"/>
        <mx:ColorPicker id="outlineColor" x="391" y="337" enabled="false" selectedColor="#FFFFFF" change="imageCropper.outlineColor = outlineColor.selectedColor"/>
        <mx:HSlider id="outlineAlpha" x="422" y="340" width="171" enabled="false" allowTrackClick="true" minimum="0" maximum="1" snapInterval=".05" value="1" liveDragging="true" change="imageCropper.outlineAlpha = outlineAlpha.value"/>
        <mx:Label x="314" y="370" text="Handles"/>
        <mx:ColorPicker id="handleColor" x="391" y="369" enabled="false" selectedColor="#FF00FF" change="imageCropper.handleColor = handleColor.selectedColor"/>
        <mx:HSlider id="handleAlpha" x="422" y="371" width="171" enabled="false" allowTrackClick="true" minimum="0" maximum="1" snapInterval=".05" value=".5" liveDragging="true" change="imageCropper.handleAlpha = handleAlpha.value"/>
        <mx:Label x="314" y="404" text="Mask"/>
        <mx:ColorPicker id="maskColor" x="391" y="401" enabled="false" selectedColor="#660066" change="imageCropper.maskColor = maskColor.selectedColor"/>
        <mx:HSlider id="maskAlpha" x="422" y="404" width="171" enabled="false" allowTrackClick="true" minimum="0" maximum="1" value=".6" snapInterval=".05" liveDragging="true" change="imageCropper.maskAlpha = maskAlpha.value"/>
        <mx:Label x="314" y="435" text="Background"/>
        <mx:ColorPicker id="backgroundColor" x="391" y="432" enabled="false" selectedColor="#000000" change="imageCropper.backgroundColor = backgroundColor.selectedColor"/>
        <mx:HSlider id="backgroundAlpha" x="422" y="435" width="171" enabled="false" minimum="0" maximum="1" liveDragging="true" value="1" snapInterval=".05" allowTrackClick="true" change="imageCropper.backgroundAlpha = backgroundAlpha.value"/>
        <mx:Label x="13" y="435" text="Handle Size:"/>
        <mx:HSlider id="handleSize" x="92" y="435" width="177" enabled="false" allowTrackClick="true" minimum="3" maximum="20" value="10" snapInterval="1" liveDragging="true" change="imageCropper.handleSize = handleSize.value"/>
        <mx:CheckBox id="constrainToAspectRatio" x="15" y="402" enabled="false" label="Constrain Crop Rectangle to Aspect Ratio" selected="false" change="imageCropper.constrainToAspectRatio = constrainToAspectRatio.selected"/>
        <mx:Label x="13" y="466" text="ImageCropper Rect:"/>
        <mx:Label id="imageCropperRect" x="133" y="466"/>
        <mx:Label x="314" y="466" text="Crop Rect:"/>
        <mx:Label id="sourceImageRect" x="389" y="466"/>
        <s:Label id="Label1" height="18" width="50" text="Label" x="197" y="130" name="Label"/>
    </mx:Application>

    ImageCropper.as

    package com.flexblocks.imagecropper {
        
        import flash.display.Bitmap;
        import flash.display.BitmapData;
        import flash.display.Loader;
        import flash.display.Shape;
        import flash.events.Event;
        import flash.events.IOErrorEvent;
        import flash.events.MouseEvent;
        import flash.geom.Matrix;
        import flash.geom.Point;
        import flash.geom.Rectangle;
        import flash.net.URLRequest;
        
        import mx.core.UIComponent;
        import mx.managers.CursorManager;
        
        // Events
        
        /**
         * This event is dispatched when the component begins loading an image from a URL.
         */ 
        
        [Event(name="sourceImageLoading")]
        
        /**
         * This event is dispatched if an I/O error occurs while loading an image from a URL.
         */ 
        
        [Event(name="sourceImageLoadError")]
        
        /**
         * This event is dispatched when the component has completed loading an image from a URL or when a <code>BitmapData</code> object is specified for the <code>sourceImage</code> parameter.
         */ 
        
        [Event(name="sourceImageReady")]
        
        /**
         * This event is dispatched whenever the cropping rectangle is resized or repositioned using the mouse.
         */
         
        [Event(name="cropRectChanged")]
        
        /**
         * This event is dispatched whenever <code>constrainToAspectRatio</code> is set to <code>true</code> and the component alters the aspect ratio of the cropping rectangle.
         * 
         * <p>One situation where the component will alter the aspect ratio of the cropping rectangle is if the cropping rectangle handle size is increased and the cropping rectangle is
         * not large enough to contain the increased size of the handles. The other situation where the component will alter the aspect ratio of the cropping rectangle is when the cropping rectangle is initialized following
         * a call to <code>setCropRect</code> and the parameters passed to <code>setCropRect</code> necessitate that the component change the cropping rectangle in order for it to be properly displayed within the component 
         * (e.g., the coordinates passed for the cropping rectangle place part of the cropping rectangle outside of the component's display area).</p>
         */
         
        [Event(name="cropConstraintChanged")]
        
        /**
         * If <code>constrainToAspectRatio</code> is set to <code>true</code> and a call to <code>setCropRect</code> is executed with a <code>width</code> or <code>height</code> value less than or equal to zero, 
         * then <code>constrainToAspectRatio</code> will be disabled and this event will be dispatched.
         */    
        
        [Event(name="cropConstraintDisabled")]
        
        /**
         * This event is dispatched whenever the component alters the position of the cropping rectangle.
         * 
         * <p>If the cropping rectangle handle size is increased by setting the <code>handleSize</code> property and there is not enough room within the cropping rectangle to contain the larger handles, 
         * then the component will increase the size of the cropping rectangle. If the position of the cropping rectangle changes when its size is increased, then this event will be dispatched.</p>
         * 
         * <p>This event is also dispatched if the position of the cropping rectangle is specified in a call to <code>setCropRect</code> but the cropping rectangle cannot be properly displayed in the component
         * at the specified position. In this case the component will adjust the position of the cropping rectangle and dispatch the <code>cropPositionChanged</code> event.
         */    
        
        [Event(name="cropPositionChanged")]
    
        /**
         * This event is dispatched whenever the component alters the dimensions of the cropping rectangle.
         * 
         * <p>If the cropping rectangle handle size is increased by setting the <code>handleSize</code> property and there is not enough room within the cropping rectangle to contain the larger handles, 
         * then the component will increase the size of the cropping rectangle and dispatch this event.</p>
         * 
         * <p>This event is also dispatched if the width and height of the cropping rectangle are specified in a call to <code>setCropRect</code> but the cropping rectangle cannot be properly displayed in the component
         * using the specified dimensions. In this case the component will adjust the dimensions of the cropping rectangle and dispatch the <code>cropDimensionsChanged</code> event.
         */    
        
        [Event(name="cropDimensionsChanged")]
        
        /**
         * The ImageCropper component accepts a <code>String</code> (URL) pointing to an image file, or a <code>BitmapData</code> object that contains an image, and displays the image within the 
         * component. If the size of the image exceeds the component's dimensions then the image is scaled so that it will entirely fit within the component.
         *  
         * <p>The image may be visually cropped by adjusting the boundries of a cropping rectangle using any of the four handles on the corners 
         * of the rectangle. At any time a <code>BitmapData</code> object containing the cropped portion of the image may be retrieved, or 
         * a <code>Rectangle</code> may be retrieved that defines the cropped portion of the image.</p>
         * 
         * <p>The cropping rectangle may be initialized using coordinates and dimensions relative to the component's display or relative to the source image.</p>
         */
        
        public class ImageCropper extends UIComponent {
            
            // Track the enabled state of the component
            
            private var componentEnabled:Boolean = true;
            
            // Hand cursor for moving the cropping rectangle
            
            [Embed(source="hand.gif")]
            private var handCursor:Class;
            private var handCursorID:int = -1;
            
            // Source image object (can be a String object or a BitmapData object)
            
            private var imageSource:Object = null;
                    
            // Component dimensions
            
            private var componentWidth:Number;
            private var componentHeight:Number;
    
            // Component bitmap variables
    
            private var componentBitmap:Bitmap;
            private var componentBitmapData:BitmapData;
    
            // Variables for loading an image
            
            private var newImageLoaded:Boolean = false;
            private var currentSource:Loader;
            
            // Component colors and alpha values
            
            private var bkgndColor:uint = 0xFF000000;
            private var bkgndAlpha:uint = 0xFF000000;
            private var cropMaskColor:uint = 0x4CFF0000;
            private var cropMaskAlpha:uint = 0x4C000000;
            private var cropHandleColor:uint = 0xFFFF0000;
            private var cropHandleAlpha:Number = .5;
            private var cropSelectionOutlineColor:uint = 0xFFFFFFFF;
            private var cropSelectionOutlineAlpha:Number = 1.; 
            
            // Image scaling variables        
            
            private var imageLocation:Point;
            private var imageScaleFactor:Number;
            private var imageScaledWidth:Number;
            private var imageScaledHeight:Number;
            private var imageBitmapData:BitmapData;
            private var scaledImageBitmapData:BitmapData;
            
            // Image cropping variables
            
            private var cropX:Number;
            private var cropY:Number;
            private var cropWidth:Number;
            private var cropHeight:Number;        
            private var newCroppingRect:Boolean = false;
            private var cropRatioActive:Boolean = false;
            private var cropRatio:Number = 0;
            private var cropRect:Rectangle;    
            private var croppingRectBitmapData:BitmapData;
            private var anchorX:Number;
            private var anchorY:Number;
            private var activeHandle:int;
            private var croppingRectIsImageScale:Boolean;
            private var cropMaskChanged:Boolean = false;
            
            // Crop sizing variables
            
            private var cropHandleSize:Number = 10;
            private var cropRectMinimumSize:Number = 20;
            
            // Flag used to prevent a null object reference if updateDisplayList() is called by the Flex callLaterDispatcher() after destroy() is executed
            
            private var destroyed:Boolean = false;
            
            // Flag to indicate whether mouse listeners are active
            
            private var mouseListenersActive:Boolean = false;
            
            // Event constants
            
            /**
             * Constant value for the <code>sourceImageLoading</code> event.
             */
            
            public const SOURCE_IMAGE_LOADING:String = "sourceImageLoading";
            
            /**
             * Constant value for the <code>sourceImageLoadError</code> event.
             */
            
            public const SOURCE_IMAGE_LOAD_ERROR:String = "sourceImageLoadError";
            
            /**
             * Constant value for the <code>sourceImageReady</code> event.
             */
    
            public const SOURCE_IMAGE_READY:String = "sourceImageReady";
    
            /**
             * Constant value for the <code>cropRectChanged</code> event.
             */
    
            public const CROP_RECT_CHANGED:String = "cropRectChanged";
    
            /**
             * Constant value for the <code>cropConstraintChanged</code> event.
             */
    
            public const CROP_CONSTRAINT_CHANGED:String = "cropConstraintChanged";
    
            /**
             * Constant value for the <code>cropConstraintDisabled</code> event.
             */
    
            public const CROP_CONSTRAINT_DISABLED:String = "cropConstraintDisabled";
            
            /**
             * Constant value for the <code>cropPositionChanged</code> event.
             */
    
            public const CROP_POSITION_CHANGED:String = "cropPositionChanged";
                    
            /**
             * Constant value for the <code>cropDimensionsChanged</code> event.
             */
    
            public const CROP_DIMENSIONS_CHANGED:String = "cropDimensionsChanged";        
    
            /**
             * The version number of the ImageCropper component.
             */
    
            public const VERSION:Number = 1.0;        
            
            // --------------------------------------------------------------------------------------------------
            // ImageCropper - Constructor
            // --------------------------------------------------------------------------------------------------
    
            /**
             * Class constructor.
             */
            
            public function ImageCropper() {
                
                // Initialize the superclass
                        
                super();
            }
            
            // --------------------------------------------------------------------------------------------------
            // destroy - Call this function when finished using the component to release resources for garbage collection
            // --------------------------------------------------------------------------------------------------
    
            /**
             * Call this method to dereference resources when the <code>ImageCropper</code> component is no longer needed. For example, if the <code>ImageCropper</code> component is
             * used in a pop-up window and the window is closed, call <code>destroy</code> when removing the window. 
             */
            
            public function destroy():void {
                
                // Set to prevent a null object reference if updateDisplayList() is called by the Flex callLaterDispatcher() after destroy() is executed
                
                destroyed = true;
    
                // Release memory used by Bitmaps and BitmapData objects
                
                if (componentBitmapData != null) {
                    componentBitmapData.dispose();
                    componentBitmapData = null;
                    componentBitmap = null;
                }
                
                if (imageBitmapData != null) {
                    imageBitmapData.dispose();
                    imageBitmapData = null;
                }            
                
                if (scaledImageBitmapData != null) {
                    scaledImageBitmapData.dispose();
                    scaledImageBitmapData = null;
                }
    
                // Remove hand cursor if active
                
                if (handCursorID >= 0) {
                    CursorManager.removeCursor(handCursorID);
                    handCursorID = -1;
                }
                
                // Release any active listeners 
                
                activateListeners(false); 
            }
            
            // --------------------------------------------------------------------------------------------------
            // GET enabled - Returns whether or not the component is enabled
            // --------------------------------------------------------------------------------------------------
    
            /**
             * Whether the component can accept user interaction or changes to properties. If the <code>enabled</code> property is set to <code>false</code> then the cropping rectangle is removed
             * and all component properties become read-only (except for the <code>enabled</code> property). In addition, calls to the <code>setCropRect</code> method are ignored. 
             * 
             * <p>The component may be re-enabled by setting the <code>enabled</code> property to <code>true</code>. 
             * 
             * @default true
             */
                    
            public override function get enabled():Boolean {
                
                return componentEnabled;
            }    
    
            // --------------------------------------------------------------------------------------------------
            // SET enabled - Sets whether or not the component is enabled
            // --------------------------------------------------------------------------------------------------
    
            /**
             * @private
             */
            
            public override function set enabled(value:Boolean):void {
                
                // If the requested enabled state is different than the current enabled state
                
                if (componentEnabled != value) {
                
                    // Call the super method
                    
                    super.enabled = value;
                        
                    // Save the new enbled state
                    
                    componentEnabled = value;
                    
                    // If an image is being displayed, activate or deactive the mouse listeners depending on the new enabled state
                    
                    if (imageBitmapData != null) activateListeners(componentEnabled);
                    
                    // Remove hand cursor if active
                    
                    if (handCursorID >= 0) {
                        CursorManager.removeCursor(handCursorID);
                        handCursorID = -1;
                    }                                
                
                    // Schedule a redraw
                
                    invalidateDisplayList();
                }
            }
    
            // --------------------------------------------------------------------------------------------------
            // GET backgroundColor - Returns the component's background color (behind the image)
            // --------------------------------------------------------------------------------------------------
    
            /**
             * The background color for the component. The component background will be visible only when an image does not entirely fill the component area.
             * 
             * @default 0x00000000
             */
                    
            public function get backgroundColor():uint {
                return (bkgndColor & 0x00FFFFFF);
            }    
    
            // --------------------------------------------------------------------------------------------------
            // SET backgroundColor - Sets the component's background color (behind the image)
            // --------------------------------------------------------------------------------------------------
    
            /**
             * @private
             */
            
            public function set backgroundColor(value:uint):void {
                
                // If the ImageCropper component is enabled ...
                
                if (componentEnabled) {
    
                    bkgndColor = value;
                    
                    // Mask off high-order 8 bits and replace with the background alpha value
                    
                    bkgndColor &= 0x00FFFFFF;
                    bkgndColor |= bkgndAlpha;
                    
                    // Schedule a redraw
                    
                    invalidateDisplayList();
                }
            }
                            
            // --------------------------------------------------------------------------------------------------
            // GET backgroundAlpha - Returns the alpha level for the component's background color
            // --------------------------------------------------------------------------------------------------
    
            /**
             * The level of transparency (0 to 1) for the component's background. The component background will be visible only when an image does not entirely fill the component area.
             * 
             * @default 0
             */
            
            public function get backgroundAlpha():Number {
                if (bkgndAlpha > 0) return (bkgndAlpha >> 48) / 100;
                else return 0;
            }
    
            // --------------------------------------------------------------------------------------------------
            // SET backgroundAlpha - Sets the alpha level for the component's background color
            // --------------------------------------------------------------------------------------------------
    
            /**
             * @private
             */
    
            public function set backgroundAlpha(value:Number):void {
                
                // If the ImageCropper component is enabled ...
                
                if (componentEnabled) {
        
                    // Value must be between 0 and 1
                    
                    if (value > 1) value = 1;
                    else if (value < 0) value = 0;
                    
                    // Convert the Number to an 8 bit value and position the bits as the high order 8 bits
                    
                    var a:uint = Math.round(value * 255);
                    bkgndAlpha = (Math.round(value * 255)) << 24;
                    
                    // Set the high order 8 bits of the background color to the alpha value
                    
                    bkgndColor &= 0x00FFFFFF;
                    bkgndColor |= bkgndAlpha;
                    
                    // Schedule a redraw
                    
                    invalidateDisplayList();
                }
            }
                    
            // --------------------------------------------------------------------------------------------------
            // GET maskColor - Returns the color used to mask unselected crop area
            // --------------------------------------------------------------------------------------------------
    
            /**
             * The color of the mask used to indicate the non-selected portion of the cropped image. The mask will be visible only when the dimensions of the cropping rectangle are smaller than the dimensions of the image.
             * 
             * @default 0x00FF0000
             */
    
            public function get maskColor():uint {
                return (cropMaskColor & 0x00FFFFFF);
            }    
    
            // --------------------------------------------------------------------------------------------------
            // SET maskColor - Sets the color used to mask unselected crop area
            // --------------------------------------------------------------------------------------------------
    
            /**
             * @private
             */
    
            public function set maskColor(value:uint):void {
                
                // If the ImageCropper component is enabled ...
                
                if (componentEnabled) {
                
                    cropMaskColor = value;
                    
                    // Mask off high-order 8 bits and replace with the mask alpha value
                    
                    cropMaskColor &= 0x00FFFFFF;
                    cropMaskColor |= cropMaskAlpha;
                    
                    // Set a flag to indicate that a mask property has changed and schedule a property update
                    
                    cropMaskChanged = true;
                    invalidateProperties();
                }
            }
                                    
            // --------------------------------------------------------------------------------------------------
            // GET maskAlpha - Returns the alpha level for the unselected crop area
            // --------------------------------------------------------------------------------------------------
    
            /**
             * The level of transparency (0 to 1) for the mask that is used to indicate the non-selected portion of the cropped image. The mask will only be visible when the dimensions of the cropping rectangle are smaller than the dimensions of the image.
             * 
             * @default 0.3
             */
            
            public function get maskAlpha():Number {
                if (cropMaskAlpha > 0) return (cropMaskAlpha >> 48) / 100;
                else return 0;
            }                
    
            // --------------------------------------------------------------------------------------------------
            // SET maskAlpha - Sets the alpha level for the unselected crop area
            // --------------------------------------------------------------------------------------------------
    
            /**
             * @private
             */
    
            public function set maskAlpha(value:Number):void {
                
                // If the ImageCropper component is enabled ...
                
                if (componentEnabled) {
        
                    // Value must be between 0 and 1
                    
                    if (value > 1) value = 1;
                    else if (value < 0) value = 0;
                    
                    // Convert the Number to an 8 bit value and position the bits as the high order 8 bits
                    
                    var a:uint = Math.round(value * 255);
                    cropMaskAlpha = (Math.round(value * 255)) << 24;
                    
                    // Set the high order 8 bits of the mask color to the alpha value
                    
                    cropMaskColor &= 0x00FFFFFF;
                    cropMaskColor |= cropMaskAlpha;
                    
                    // Set a flag to indicate that a mask property has changed and schedule a property update
                    
                    cropMaskChanged = true;
                    invalidateProperties();
                }
            }        
    
            // --------------------------------------------------------------------------------------------------
            // GET handleColor - Returns the color of the cropping handles
            // --------------------------------------------------------------------------------------------------
    
            /**
             * The color used for the four corner handles of the cropping rectangle.
             * 
             * @default 0x00FF0000
             */
    
            public function get handleColor():uint {
                return (cropHandleColor & 0x00FFFFFF);
            }    
    
            // --------------------------------------------------------------------------------------------------
            // SET handleColor - Sets the color of the cropping handles
            // --------------------------------------------------------------------------------------------------
    
            /**
             * @private
             */
    
            public function set handleColor(value:uint):void {
                
                // If the ImageCropper component is enabled ...
                
                if (componentEnabled) {
        
                    cropHandleColor = value;
                    
                    // Mask off high-order 8 bits and replace with the crop handle alpha value
                    
                    cropHandleColor &= 0x00FFFFFF;
                    cropHandleColor |= cropHandleAlpha;
                    
                    // Set a flag to indicate that a mask property has changed and schedule a property update
                    
                    cropMaskChanged = true;
                    invalidateProperties();
                }
            }        
                                    
            // --------------------------------------------------------------------------------------------------
            // GET handleAlpha - Returns the alpha level for the crop handles
            // --------------------------------------------------------------------------------------------------
    
            /**
             * The level of transparency (0 to 1) for the four corner handles of the cropping rectangle.
             * 
             * @default 0.5
             */
    
            public function get handleAlpha():Number {
                return cropHandleAlpha;
            }
    
            // --------------------------------------------------------------------------------------------------
            // SET handleAlpha - Sets the alpha level for the crop handles
            // --------------------------------------------------------------------------------------------------
    
            /**
             * @private
             */
    
            public function set handleAlpha(value:Number):void {
                
                // If the ImageCropper component is enabled ...
                
                if (componentEnabled) {
    
                    // Value must be between 0 and 1
                    
                    if (value > 1) value = 1;
                    else if (value < 0) value = 0;
                    
                    // Save the new alpha value
                    
                    cropHandleAlpha = value;
                    
                    // Set a flag to indicate that a mask property has changed and schedule a property update
                    
                    cropMaskChanged = true;
                    invalidateProperties();
                }
            }
                                    
            // --------------------------------------------------------------------------------------------------
            // GET outlineColor - Returns the color of the crop area outline
            // --------------------------------------------------------------------------------------------------
    
            /**
             * The color used for single pixel outline drawn around the cropping rectangle and around the four corner handles of the cropping rectangle.
             * 
             * @default 0x00FFFFFF
             */
    
            public function get outlineColor():uint {
                return cropSelectionOutlineColor;
            }
            
            // --------------------------------------------------------------------------------------------------
            // SET outlineColor - Sets the color of the crop area outline
            // --------------------------------------------------------------------------------------------------
    
            /**
             * @private
             */
    
            public function set outlineColor(value:uint):void {
                
                // If the ImageCropper component is enabled ...
                
                if (componentEnabled) {
    
                    cropSelectionOutlineColor = value;
                    
                    // Set a flag to indicate that a mask property has changed and schedule a property update
                    
                    cropMaskChanged = true;
                    invalidateProperties();
                }
            }        
            
            // --------------------------------------------------------------------------------------------------
            // GET outlineAlpha - Returns the alpha level for the crop area outline
            // --------------------------------------------------------------------------------------------------
    
            /**
             * The level of transparency (0 to 1) used for the single pixel outline drawn around the cropping rectangle and around the four corner handles of the cropping rectangle.
             * 
             * @default 0
             */
    
            public function get outlineAlpha():Number {
                return cropSelectionOutlineAlpha;
            }
                    
            // --------------------------------------------------------------------------------------------------
            // SET outlineAlpha - Sets the alpha level for the crop area outline
            // --------------------------------------------------------------------------------------------------
    
            /**
             * @private
             */
    
            public function set outlineAlpha(value:Number):void {
                
                // If the ImageCropper component is enabled ...
                
                if (componentEnabled) {
    
                    // Value must be between 0 and 1
                    
                    if (value > 1) value = 1;
                    else if (value < 0) value = 0;
                    
                    // Save the new alpha value
                    
                    cropSelectionOutlineAlpha = value;
                    
                    // Set a flag to indicate that a mask property has changed and schedule a property update
                    
                    cropMaskChanged = true;
                    invalidateProperties();
                }
            }
            
            // --------------------------------------------------------------------------------------------------
            // GET handleSize - Returns the size of the cropping handles
            // --------------------------------------------------------------------------------------------------
    
            /**
             * The size of each of the four corner handles of the cropping rectangle. The minimum allowed handle size is 3. 
             * 
             * @default 10
             */
    
            public function get handleSize():Number {
                return cropHandleSize;
            }
            
            // --------------------------------------------------------------------------------------------------
            // SET handleSize - Sets the size of the cropping handles (the minimum handle size is 3)
            // --------------------------------------------------------------------------------------------------
    
            /**
             * @private
             */
    
            public function set handleSize(value:Number):void {
                
                // If the ImageCropper component is enabled ...
                
                if (componentEnabled) {
        
                    // Remove hand cursor if active
                    
                    if (handCursorID >= 0) {
                        CursorManager.removeCursor(handCursorID);
                        handCursorID = -1;
                    }
                    
                    // Minimum habdle size is 3
                    
                    cropHandleSize = value < 3 ? 3 : value;
                    
                    // Set the minimum allowed size for the cropping rectangle to twice the size of a handle
                    
                    cropRectMinimumSize = value * 2;
                    
                    // Set a flag to indicate that a mask property has changed and schedule a property update
                    
                    cropMaskChanged = true;
                    invalidateProperties();
                }
            }
            
            // --------------------------------------------------------------------------------------------------
            // GET constrainToAspectRatio - Returns whether or not the dimensions of the cropping rectangle are constrained to the ratio of cropping rectangle's current width and height
            // --------------------------------------------------------------------------------------------------
    
            /**
             * If set to <code>true</code> then the cropping rectangle will always maintain the aspect ratio that was active when the <code>constrainToAspectRatio</code> property was set.
             * For example, suppose the cropping rectangle has dimensions of 200 x 100 (an aspect ratio of 2:1). If <code>constrainToAspectRatio</code> is set to <code>true</code> then 
             * dragging any of the handles will cause the cropping rectangle to maintain a 2:1 relationship between the width and the height. If dragging a handle causes the width to increase 
             * to 400, then the height of the cropping rectangle will be adjusted to 200. If the height is changed to 50, then the width will be adjusted to 100.
             * 
             * <p>Enabling <code>constrainToAspectRatio</code> can be useful if you wish to crop an image so that it can be scaled to fixed dimensions without distortion. For example,
             * suppose that you want to crop an image so that it will exactly fit a target area that is 400 pixels wide and 600 pixels high. Since the target area has an aspect ratio of 2:3
             * you'll want to call the <code>setCropRect</code> method to set an initial cropping rectangle with dimensions that conform to the target aspect ratio. In this case, let's say that 
             * we set the cropping rectangle to a width of 80 and to a height of 120 (a ratio of 2:3). Now when we set <code>constrainToAspectRatio</code>
             * to <code>true</code> the cropping rectangle will always maintain a width to height ratio of 2:3. Once the portion of the image to crop is selected, all that needs to be
             * done is to retrieve the <code>BitmapData</code> from the <code>croppedBitmapData</code> parameter and then scale the <code>BitmapData</code> to the final size (400 x 600).<p>
             * 
             * Setting <code>constrainToAspectRatio</code> to <code>false</code> allows the width and height of the cropping rectangle to be adjusted independently. 
             * 
             * @default false
             */
    
            public function get constrainToAspectRatio():Boolean {
                return cropRatioActive;
            }
            
            // --------------------------------------------------------------------------------------------------
            // SET constrainToAspectRatio - Sets whether or not to constrain the dimensions of the cropping rectangle to the ratio of cropping rectangle's current width and height
            // --------------------------------------------------------------------------------------------------
    
            /**
             * @private
             */
    
            public function set constrainToAspectRatio(constrain:Boolean):void {
                
                // If the ImageCropper component is enabled ...
                
                if (componentEnabled) {
                
                    // If constrainToAspectRatio is true and both the width and height of the cropping rectangle is non-zero, calculate the cropRatio
                    
                    if (constrain) {                
                        if (cropRect != null) cropRatio = cropRect.width / cropRect.height;
                        else cropRatio = 0;
                    }
                    else cropRatio = 0;
                    
                    // Set a flag to indicate if the cropping rectangle is constained to the aspect ratio
                    
                    cropRatioActive = constrain;
                }
            }        
    
            // --------------------------------------------------------------------------------------------------
            // GET sourceImage - Returns the source image as a BitmapData object
            // --------------------------------------------------------------------------------------------------
    
            /**
             * Either a <code>String</code> that contains a URL pointing to an image or a <code>BitmapData</code> object that contains an image.
             * 
             * <p>If a URL <code>String</code> is assigned to this parameter, then a <code>sourceImageLoading</code> event will be dispatched and the 
             * component will begin loading the referenced image. Once the image has been loaded then a <code>sourceImageReady</code> event will be dispatched
             * and the image will be displayed in the component. If an error occurs while loading the image, then a <code>sourceImageLoadError</code> event will be dispatched</p>
             * 
             * <p>If a <code>BitmapData</code> object is assigned to this parameter, then a <code>sourceImageReady</code> event will immediately be dispatched
             * and the image contained in the <code>BitmapData</code> object will be displayed in the component.</p>
             * 
             * <p>When reading this parameter an <code>Object</code> will be returned of type <code>String</code> or of type <code>BitmapData</code>, depending upon what type of
             * object was last assigned to the <code>sourceImage</code> parameter. If no assignment was made to the <code>sourceImage</code> parameter, then <code>null</code> is returned.</p>
             */
    
            public function get sourceImage():Object {
                return imageSource;
            }
                                    
            // --------------------------------------------------------------------------------------------------
            // SET sourceImage - Sets the source image to be cropped
            // --------------------------------------------------------------------------------------------------
    
            /**
             * @private
             */
    
            public function set sourceImage(value:Object):void {
                
                // If the ImageCropper component is enabled ...
                
                if (componentEnabled) {
            
                    // If a URL String or a BitmapData object has been passed
                    
                    if (value != null && (value is String || value is BitmapData)) {
                        
                        // Remove hand cursor if active
                        
                        if (handCursorID >= 0) {
                            CursorManager.removeCursor(handCursorID);
                            handCursorID = -1;
                        }                
                    
                        // If an image has already been loaded, erase the image from the display and make sure listeners are disabled
                        
                        if (imageBitmapData != null) {
                            if (componentBitmap != null) componentBitmapData.fillRect(componentBitmapData.rect, bkgndColor);        
                            imageBitmapData.dispose();
                            imageBitmapData = null;
                            imageSource = null;
                            activateListeners(false);
                        }
        
                        // If a URL was passed
                        
                        if (value is String) {
                                                    
                            // Create a loader for the requested image
                            
                            currentSource = new Loader();
                            
                            // Add listeners
                            
                            sourceLoadListeners(true);
        
                            // Begin loading the requested image
                            
                            currentSource.load(new URLRequest(String(value)));
                            
                            // Dispatch load event
                            
                            dispatchEvent(new Event(SOURCE_IMAGE_LOADING));                    
                        }
                        
                        // Else a BitmapData object was passed
                        
                        else {
                        
                            // Clone passed BitmapData for the image
                            
                            imageBitmapData = BitmapData(value).clone();
                            
                            // Set flag that new image has been loaded
                            
                            newImageLoaded = true;            
                            
                            // Mark the component so that updateDisplayList() is  called during the next screen update
                
                            invalidateDisplayList();
                            
                            // Save image source object
                        
                            imageSource = imageBitmapData;
                        
                            // Add event listeners
                            
                            activateListeners(true);
                            
                            // Dispatch image loaded notification event
                        
                            dispatchEvent(new Event(SOURCE_IMAGE_READY));                    
                        }
                    }
                }
            }
            
            // --------------------------------------------------------------------------------------------------
            // GET croppedBitmapData - Returns the bitmap data for the cropped image at actual size
            // --------------------------------------------------------------------------------------------------
    
            /**
             * The cropped source image as a <code>BitmapData</code> object. The cropped portion of the source image is defined by the position and the dimensions of the cropping rectangle.
             */
    
            public function get croppedBitmapData():BitmapData {
            
                // If this function is called before the component has a chance to create componentBitmapData, then call initializeDisplay()
                
                if (componentBitmapData == null) initializeDisplay(this.width, this.height);
                        
                // If the image has not been rendered yet, create a scaled version of the image that will fit within the component
                        
                if (newImageLoaded) createScaledImage();        
    
                // If the cropping rectangle has changed but has not yet been initialized, then initialize the cropping rectangle before proceeding
                
                if (newCroppingRect) initializeCroppingRect();
                
                // Extract cropped area from image
                
                var croppedBitmap:BitmapData = null;
                var sourceImageRect:Rectangle = getCropRect();
                
                if (imageBitmapData != null && sourceImageRect != null && sourceImageRect.width > 0 && sourceImageRect.height > 0) {
                    croppedBitmap = new BitmapData(sourceImageRect.width, sourceImageRect.height, false);
                    croppedBitmap.copyPixels(imageBitmapData, sourceImageRect, new Point(0, 0));
                }
                
                return croppedBitmap;
            }
            
            // --------------------------------------------------------------------------------------------------
            // setCropRect - Set the initial crop area
            // --------------------------------------------------------------------------------------------------
            
            /**
             * This method defines the position and the dimensions of the cropping rectangle within the component.
             * 
             * <p>Note that values specified for the <code>width</code>, <code>height</code>, <code>x</code> and <code>y</code> parameters can be relative to either the component (if <code>componentRelative</code> is <code>true</code>)
             * or to the source image (if <code>componentRelative</code> is <code>false</code>).</p>
             * 
               * <p>For example, suppose the component has dimensions of 250x250 but the source image has dimensions of 500x500. In this case the component will automatically scale the source image so that it fits within
               * the component area. If <code>componentRelative</code> is set to <code>false</code> then setting a cropping rectangle with dimensions of 100x50 will result in a cropping rectangle being drawn in the component
               * area with dimensions of 50x25 (i.e. the cropping rectangle dimensions are relative to the source image). If <code>componentRelative</code> is set to <code>true</code> then the cropping rectangle will be drawn with 
               * dimensions of 100x50 (i.e. the cropping rectangle dimensions are relative to the component area).</p>
               * 
               * <p>If the <code>width</code> or the <code>height</code> parameter is assigned a value of zero, then the cropping rectangle will be set to the full size of the image and any values specified for 
               * the <code>x</code> and <code>y</code> parameters will be ignored.</p>
             * 
             * @param width Sets the width of the cropping rectangle. Setting <code>width</code> to zero will result in both the width and the height of the cropping rectangle being set to the size of the image displayed in the component.
             * 
             * @param height Sets the height of the cropping rectangle. Setting <code>height</code> to zero will result in both the width and the height of the cropping rectangle being set to the size of the image displayed in the component.
             * 
             * @param x Sets the horizontal position of the cropping rectangle. Setting <code>x</code> to -1 will result in the cropping rectangle being centered vertically and horizontally in the component.
             * 
             * @param y Sets the vertical position of the cropping rectangle. Setting <code>y</code> to -1 will result in the cropping rectangle being centered vertically and horizontally in the component.
             * 
             * @param componentRelative When set to <code>true</code> then the <code>width</code>, <code>height</code>, <code>x</code> and <code>y</code> parameters are relative to the image 
             * displayed in the component. When <code>componentRelative</code> is set to <code>false</code> then the parameters are relative to the source image. If the source image completely fits within
             * the component without scaling, then <code>componentRelative</code> in essence has no effect since the component image and the source image are identical.
             */
    
            public function setCropRect(Number = 0, height:Number = 0, x:Number = -1, y:Number = -1, componentRelative:Boolean = false):void {
                
                // If the ImageCropper component is enabled ...
                
                if (componentEnabled) {
    
                    // Remove hand cursor if active
                    
                    if (handCursorID >= 0) {
                        CursorManager.removeCursor(handCursorID);
                        handCursorID = -1;
                    }        
                    
                    // Make sure crop area values are not less than minimum allowed values
                    
                    if (width < 0) width = 0;
                    if (height < 0) height = 0;
                    if (x < -1) x = -1;
                    if (y < -1) y = -1;
                    
                    // Save the initial position coordinates. If they are greater than or equal to zero then they are used to position the top-left corner of the cropping rectangle. 
                    
                    cropX = x;
                    cropY = y;
                    
                    // Set the dimensions of the cropping rectangle
                    
                    cropWidth = width;
                    cropHeight = height;
        
                    // If either dimension is zero than the crop area will be set to the scaled image area. If the image has not yet been loaded the cropRatioActive will be set to false
                    // because there is no way to detemine an aspect ratio.
        
                    if (cropWidth == 0 || cropHeight == 0) {
                        
                        // If one dimension is zero, then set the other dimension to zero
                        
                        cropWidth = 0;
                        cropHeight = 0;
                        
                        // If the cropping rectangle is constrained to the aspect ratio
                        
                        if (cropRatioActive) {
                            
                            // If there is an image then set the cropping rectangle's dimensions equal to the scaled image size (the ratio is set below)
                            
                            if (scaledImageBitmapData != null) {
                                cropWidth = scaledImageBitmapData.width - 1;
                                cropHeight = scaledImageBitmapData.height - 1;
                            }
                            
                            // Else there is no image so there cannot be an aspect ratio constraint on the cropping rectangle
                            
                            else {
                                dispatchEvent(new Event(CROP_CONSTRAINT_DISABLED));
                                cropRatioActive = false;
                            }
                        }
                    }
                    
                    // If componentRelative is set to true, then the cropping rectangle size will be set to the actual size specified (assuming it will fit within the image area).
                    // If componentRelative is set to false, then the cropping rectangle size represents the size of the final image so the cropping rectangle will be scaled to match the scale of the selected image
                    
                    croppingRectIsImageScale = !componentRelative;
                    
                    // If constrainToAspectRatio is true and both the width and height of the cropping rectangle is non-zero, calculate the cropRatio
                    
                    if (cropRatioActive) cropRatio = cropWidth / cropHeight;
                    else cropRatio = 0;
                    
                    // Set the "newCroppingRect" flag so that a BitMapData object will be constructed when updateDisplayList() is next called
                    
                    newCroppingRect = true;
                    
                    // Invalidate the display list in order to schedule a call to updateDisplayList()
                                
                    invalidateDisplayList();
                }        
            }    
                    
            // --------------------------------------------------------------------------------------------------
            // getCropRect - Return the selected crop area
            // --------------------------------------------------------------------------------------------------
    
            /**
             * Returns the position and the dimensions of the cropped portion of the image as a <code>Rectangle</code>.
             * 
             * @param componentRelative If set to <code>true</code> then the <code>Rectangle</code> returned represents the position and dimensions of the cropping rectangle in the component.
             * If set to <code>false</code> then the <code>Rectangle</code> returned represents the position and dimensions of the crop area in the source image.
             * 
             * @param roundValues If set to <code>true</code> then all values in the returned <code>Rectangle</code> are rounded to integer values.
             * 
             * @return The position and dimensions of the crop area relative to the component (if <code>componentRelative</code> is <code>true</code>) or relative to the source image 
             * (if <code>componentRelative</code> is <code>false</code>). If a cropping rectangle has not been defined, then <code>null</code> will be returned.
             */
            
            public function getCropRect(componentRelative:Boolean = false, roundValues:Boolean = false):Rectangle {
            
                // The cropRect must be defined
                
                if (cropRect != null) {
                    
                    var requestedRect:Rectangle;
                
                    // If the position and size of the cropping area in the component is requested, return the current cropRect
                    
                    if (componentRelative) requestedRect = cropRect.clone();
                    
                    // Else the cropRect is translated back to unscaled coordinates and dimensions and returned
                    
                    else requestedRect = new Rectangle(cropRect.x / imageScaleFactor, cropRect.y / imageScaleFactor, cropRect.width / imageScaleFactor, cropRect.height / imageScaleFactor);
                    
                    // If rounding was requested, round each rectangle value
                    
                    if (roundValues) {
                        requestedRect.x = Math.round(requestedRect.x);
                        requestedRect.y = Math.round(requestedRect.y);
                        requestedRect.width = Math.round(requestedRect.width);
                        requestedRect.height = Math.round(requestedRect.height);
                    }
                    
                    // Return the Rectangle
                    
                    return requestedRect; 
                }
                
                else return null;
            }                                
            
            // --------------------------------------------------------------------------------------------------
            // sourceLoadSuccess - Called when the source image has been loaded and initialized
            // --------------------------------------------------------------------------------------------------
    
            private function sourceLoadSuccess(event:Event):void {
                
                // Get the  bitmap data for the loaded image 
                
                imageBitmapData = Bitmap(currentSource.content).bitmapData.clone();
                            
                // Remove the event listeners for loading the image and release the Loader
                
                sourceLoadListeners(false);
                
                // Save image source object
                    
                imageSource = imageBitmapData;
                
                // Set flag that new image has been loaded
                
                newImageLoaded = true;
                
                // Mark the component so that updateDisplayList() is  called during the next screen update
    
                invalidateDisplayList();
                                
                // Add event listeners
                        
                activateListeners(true);
    
                // Dispatch image loaded notification event
                    
                dispatchEvent(new Event(SOURCE_IMAGE_READY));                    
            }        
            
            // --------------------------------------------------------------------------------------------------
            // sourceLoadFailure - Called when an error occurs loading the source image 
            // --------------------------------------------------------------------------------------------------
    
            private function sourceLoadFailure(event:IOErrorEvent):void {
    
                // Remove the event listeners
                
                sourceLoadListeners(false);
    
                // Dispatch image load error notification event
                    
                dispatchEvent(new Event(SOURCE_IMAGE_LOAD_ERROR));                                
            }        
            
            // --------------------------------------------------------------------------------------------------
            // sourceLoadListeners - Adds or removes listeners to monitor the source image load process
            // --------------------------------------------------------------------------------------------------
    
            private function sourceLoadListeners(addListeners:Boolean):void {
                        
                // If listeners are being added
                
                if (addListeners) {
                
                    // Request to be notified when the image has been loaded and initialized
                            
                    currentSource.contentLoaderInfo.addEventListener(Event.INIT, sourceLoadSuccess);
                            
                    // Request to be notified if an error occurs during the image load process
                            
                    currentSource.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, sourceLoadFailure);
                }
                
                // Else release resources
                
                else {
                    
                    // Remove the listeners
                    
                    currentSource.contentLoaderInfo.removeEventListener(Event.INIT, sourceLoadSuccess);
                    currentSource.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, sourceLoadFailure);
                    
                    // Release the loader
                
                    try {
                        currentSource.close();
                    }
                    catch(e:Error) {};
                    
                    currentSource.unload();
                    currentSource = null;                
                }    
            }        
                                    
            // --------------------------------------------------------------------------------------------------
            // activateListeners - Called to assign or release listeners for the component (mouse listeners should only be active when a source image is assigned) 
            // --------------------------------------------------------------------------------------------------
    
            private function activateListeners(addListeners:Boolean):void {
    
                if (addListeners && !mouseListenersActive) {
                    this.addEventListener(MouseEvent.MOUSE_DOWN, doMouseDown);
                    this.addEventListener(MouseEvent.MOUSE_MOVE, doMouseMove);
                    mouseListenersActive = true;
                }
                
                // Remove event listeners
                
                else if (!addListeners && mouseListenersActive) {
                    this.removeEventListener(MouseEvent.MOUSE_MOVE, doMouseMove);
                    this.removeEventListener(MouseEvent.MOUSE_DOWN, doMouseDown);
                    this.removeEventListener(MouseEvent.MOUSE_UP, doMouseUp);
                    systemManager.stage.removeEventListener(Event.MOUSE_LEAVE, doMouseUp);
                    systemManager.stage.removeEventListener(MouseEvent.MOUSE_UP, doMouseUp);
                    mouseListenersActive = false;
                    if (currentSource != null) sourceLoadListeners(false);
                }        
            }
            
            // --------------------------------------------------------------------------------------------------
            // mouseLocation - Given a mouse event, returns -1 if the mouse is outside of the cropping rectangle, 1 if the mouse is in the top-left handle, 2 if the mouse is in the top-right handle,
            //                 3 if the mouse is in the bottom-left handle, 4 if the mouse is in the bottom-right handle, or 0 if the mouse is in the interior of the cropping rectangle
            // --------------------------------------------------------------------------------------------------
    
            private function mouseLocation(event:MouseEvent):int {
                
                // Get the location of the mouse relative to the image area
                
                var mouseXLoc:Number = event.localX - imageLocation.x;
                var mouseYLoc:Number = event.localY - imageLocation.y;
                            
                // If the cropping rectangle contains the mouse location point
                
                if (cropRect != null && cropRect.contains(mouseXLoc, mouseYLoc)) {
                
                    // Calculate the distance between the top-left corner of the cropping rectangle to the mouse location
                    
                    var mouseDeltaX:Number = mouseXLoc - cropRect.x;
                    var mouseDeltaY:Number = mouseYLoc - cropRect.y;
                    
                    // Top-left handle?
                    
                    if (mouseDeltaX <= cropHandleSize && mouseDeltaY <= cropHandleSize) return 1;
                    
                    // Top-right handle?
                    
                    else if (mouseDeltaX >= cropRect.width - cropHandleSize && mouseDeltaY <= cropRect.width && mouseDeltaY <= cropHandleSize) return 2;
                    
                    // Bottom-left handle?
                                    
                    else if (mouseDeltaX <= cropHandleSize && mouseDeltaY >= cropRect.height - cropHandleSize && mouseDeltaY <= cropRect.height) return 3;
    
                    // Bottom-right handle?
    
                    else if (mouseDeltaX >= cropRect.width - cropHandleSize && mouseDeltaY <= cropRect.height && mouseDeltaY >= cropRect.height - cropHandleSize && mouseDeltaY <= cropRect.height) return 4;
                    
                    // Cropping rectangle interior
                    
                    else return 0;
                }
                
                // The mouse is not in the cropping rectangle area
                
                else return -1;
            }                                
                    
            // --------------------------------------------------------------------------------------------------
            // doMouseDown
            // --------------------------------------------------------------------------------------------------
    
            private function doMouseDown(event:MouseEvent):void {
                
                // Find out where the mouse down even occurred
                
                var mouseLoc:int = mouseLocation(event);            
                
                // If the cropping rectangle contains the mouse location point
                
                if (mouseLoc >= 0) {
                
                    // Calculate the distance between the top-left corner of the cropping rectangle to the mouse location
                    
                    var mouseDeltaX:Number = event.localX - imageLocation.x - cropRect.x;
                    var mouseDeltaY:Number = event.localY - imageLocation.y - cropRect.y;
    
                    // Top-left handle?
                    
                    if (mouseLoc == 1) {
                        anchorX = mouseDeltaX;
                        anchorY = mouseDeltaY;                    
                        activeHandle = 1;
                    }                    
                    
                    // Top-right handle?
                    
                    else if (mouseLoc == 2) {
                        anchorX = mouseDeltaX - cropRect.width;
                        anchorY = mouseDeltaY;    
                        activeHandle = 2;
                    }                    
                    
                    // Bottom-left handle?
                                    
                    else if (mouseLoc == 3) {
                        anchorX = mouseDeltaX;
                        anchorY = mouseDeltaY - cropRect.height;    
                        activeHandle = 3;
                    }
    
                    // Bottom-right handle?
    
                    else if (mouseLoc == 4) {
                        anchorX = mouseDeltaX - cropRect.width;
                        anchorY = mouseDeltaY - cropRect.height;    
                        activeHandle = 4;
                    }
                    
                    // Cropping rectangle interior
                    
                    else {
                        anchorX = mouseDeltaX;
                        anchorY = mouseDeltaY;
                        activeHandle = 0;
                    }
                    
                    // Add listener for mouse events
                    
                    this.addEventListener(MouseEvent.MOUSE_UP, doMouseUp);
                    systemManager.stage.addEventListener(Event.MOUSE_LEAVE, doMouseExit);
                    systemManager.stage.addEventListener(MouseEvent.MOUSE_UP, doMouseUp);
                }
            }
                
            // --------------------------------------------------------------------------------------------------
            // doMouseExit - Called when the mouse is outside of the Player area
            // --------------------------------------------------------------------------------------------------
    
            private function doMouseExit(event:Event):void {
                doMouseUp(null);
            }
            
            // --------------------------------------------------------------------------------------------------
            // doMouseUp
            // --------------------------------------------------------------------------------------------------
    
            private function doMouseUp(event:MouseEvent):void {
            
                // Clear active handle tracking variable
                
                activeHandle = -1;
                
                // Remove listeners
                
                this.removeEventListener(MouseEvent.MOUSE_UP, doMouseUp);
                systemManager.stage.removeEventListener(Event.MOUSE_LEAVE, doMouseUp);
                systemManager.stage.removeEventListener(MouseEvent.MOUSE_UP, doMouseUp);
                
                // Send event that the crop area has been updated 
                
                dispatchEvent(new Event(CROP_RECT_CHANGED));
            }        
                        
            // --------------------------------------------------------------------------------------------------
            // doMouseMove - Follow the mouse and move or resize the cropping rectangle
            // --------------------------------------------------------------------------------------------------
    
            private function doMouseMove(event:MouseEvent):void {
                
                // If a cropping rectangle has been set and the mouse button is down
                
                if (croppingRectBitmapData != null && event.buttonDown) {
                    
                    // Local variables
                    
                    var topX:Number;
                    var topY:Number;
                    var btmX:Number;
                    var btmY:Number;
                    
                    var scaledW:Number;
                    var scaledH:Number; 
                
                    // Get the location of the mouse relative to the cropping rectangle bitmap
                    
                    var mouseX:Number = event.localX - imageLocation.x;
                    var mouseY:Number = event.localY - imageLocation.y;
                    
                    // Drag cropping rectangle
                    
                    if (activeHandle == 0) {
                    
                        // Calculate the new top-left corner of the cropping rectangle
                        
                        cropRect.x = mouseX - anchorX;
                        cropRect.y = mouseY - anchorY;
                        
                        // Make sure that the entire cropping rectangle stays within the image area
                        
                        if (cropRect.x < 0) cropRect.x = 0;
                        else {
                            var maxX:Number = Math.floor(imageScaledWidth - cropRect.width - 1);
                            if (cropRect.x > maxX) cropRect.x = maxX;
                        }
                        
                        if (cropRect.y < 0) cropRect.y = 0;
                        else {
                            var maxY:Number = Math.floor(imageScaledHeight - cropRect.height - 1);
                            if (cropRect.y > maxY) cropRect.y = maxY;
                        }
                    }
                    
                    // Top-left Handle
                    
                    else if (activeHandle == 1) {
                        
                        // Get the new position of the top-left corner of the cropping rectangle
                        
                        topX = mouseX - anchorX;
                        topY = mouseY - anchorY;
                        
                        // If the new position of the top-left corner of the cropping rectangle is outside the top or left margin, then set the corner to the top or left margin
                        
                        if (topX < 0) topX = 0;
                        if (topY < 0) topY = 0;
                        
                        // Get the current position of the bottom-right corner of the cropping rectangle
                                            
                        btmX = cropRect.x + cropRect.width;
                        btmY = cropRect.y + cropRect.height;
                        
                        // Calculate the new width of the cropping rectangle
                        
                        cropRect.width = btmX - topX;
                        
                        // If the new width is less than the minimum allowed size then set the new width to the minimum
                        
                        if (cropRect.width < cropRectMinimumSize) {
                            cropRect.width = cropRectMinimumSize;
                            topX = btmX - cropRectMinimumSize;
                        }
                        
                        // Set the new x position for the top-left corner of the cropping rectangle
                        
                        cropRect.x = topX;
    
                        // Calculate the new height of the cropping rectangle
                        
                        cropRect.height = btmY - topY;
                        
                        // If the new height is less than the minimum allowed size then set the new height to the minimum
                        
                        if (cropRect.height < cropRectMinimumSize) {
                            cropRect.height = cropRectMinimumSize;
                            cropRect.y = btmY - cropRectMinimumSize;
                        }
                        else cropRect.y = topY;
                        
                        // If a cropping ratio is defined
                        
                        if (cropRatioActive) {
                            
                            // If the cropping rectangle is not at the correct ratio
                        
                            if (cropRect.width / cropRect.height != cropRatio) {
                                
                                // Get a new scaled width for the cropping rectangle
                                
                                scaledW = cropRect.height * cropRatio;
                                
                                // If the new width is less then the minimum allowed width
                                
                                if (scaledW < cropRectMinimumSize) {
                                    
                                    // Set the width to the minimum
                                    
                                    scaledW = cropRectMinimumSize;
                                    
                                    // Scale the height for the new width
                                    
                                    scaledH = scaledW / cropRatio;
                                    
                                    // Adjust the y coordinate of the cropping rectangle for the new scaled height
                                    
                                    cropRect.y = cropRect.y + (cropRect.height - scaledH);
                                    
                                    // Set the new height of the cropping rectangle
                                    
                                    cropRect.height = scaledH;
                                }
                                
                                // Move the horizontal position to compensate for the scaled width
                                
                                cropRect.x += cropRect.width - scaledW;
                                
                                // If the new width is to the left of the left margin
                                
                                if (cropRect.x < 0) {
                                    
                                    // Reduce the width of the cropping rectangle by the amount that the cropping rectangle extends past the left margin
                                    
                                    scaledW += cropRect.x;
                                    
                                    // Set the left edge of the cropping rectangle to the left margin
                                    
                                    cropRect.x = 0;
    
                                    // Scale the height for the new width
                                    
                                    scaledH = scaledW / cropRatio;
                                    
                                    // Adjust the y coordinate of the cropping rectangle for the new scaled height
                                    
                                    cropRect.y = cropRect.y + (cropRect.height - scaledH);
                                    
                                    // Set the new height of the cropping rectangle
                                    
                                    cropRect.height = scaledH;
                                }
                                
                                // Set the scaled width for the cropping rectangle
                                
                                cropRect.width = scaledW;                                                        
                            }
                        }                    
                    }
                    
                    // Top-right Handle
                    
                    else if (activeHandle == 2) {
                        
                        // Get the new position of the top-right corner of the cropping rectangle
                        
                        topX = mouseX - anchorX;
                        topY = mouseY - anchorY;
                                            
                        // Get the current position of the bottom-left corner of the cropping rectangle
                                            
                        btmX = cropRect.x;
                        btmY = cropRect.y + cropRect.height;
                        
                        // If the new position of the top-right corner of the cropping rectangle is outside the top or right margin, then set the corner to the top or right margin
                        
                        if (topX > imageScaledWidth - 1) topX = imageScaledWidth - 1;
                        if (topY < 0) topY = 0;
                        
                        // Calculate the new width of the cropping rectangle
                        
                        cropRect.width = topX - btmX;
                        
                        // If the new width is less than the minimum allowed size then set the new width to the minimum
                        
                        if (cropRect.width < cropRectMinimumSize) {
                            cropRect.width = cropRectMinimumSize;
                            topX = btmX + cropRectMinimumSize;
                        }
                        
                        // Set the new x position for the top-left corner of the cropping rectangle
                        
                        cropRect.x = btmX;
                        
                        // Calculate the new height of the cropping rectangle
                        
                        cropRect.height = btmY - topY;
                        
                        // If the new height is less than the minimum allowed size then set the new height to the minimum
                        
                        if (cropRect.height < cropRectMinimumSize) {
                            cropRect.height = cropRectMinimumSize;
                            cropRect.y = btmY - cropRectMinimumSize;
                        }
                        else cropRect.y = topY;
                        
                        // If a cropping ratio is defined
                        
                        if (cropRatioActive) {
                            
                            // If the cropping rectangle is not at the correct ratio
                        
                            if (cropRect.width / cropRect.height != cropRatio) {
                                
                                // Get a new scaled width for the cropping rectangle
                                
                                scaledW = cropRect.height * cropRatio;
                                
                                // If the new width is less then the minimum allowed width
                                
                                if (scaledW < cropRectMinimumSize) {
                                    
                                    // Set the width to the minimum
                                    
                                    scaledW = cropRectMinimumSize;
                                    
                                    // Scale the height for the new width
                                    
                                    scaledH = scaledW / cropRatio;
                                    
                                    // Adjust the y coordinate of the cropping rectangle for the new scaled height
                                    
                                    cropRect.y = cropRect.y + (cropRect.height - scaledH);
                                    
                                    // Set the new height of the cropping rectangle
                                    
                                    cropRect.height = scaledH;
                                }
                                
                                // If the new width exceeds the maximum allowed width
                                
                                if (cropRect.x + scaledW > imageScaledWidth - 1) {
                                    
                                    // Set the width to the maximum allowed
                                    
                                    scaledW = imageScaledWidth - 1 - cropRect.x;
                                    
                                    // Scale the height for the new width
                                    
                                    scaledH = scaledW / cropRatio;
                                    
                                    // Adjust the y coordinate of the cropping rectangle for the new scaled height
                                    
                                    cropRect.y = cropRect.y + (cropRect.height - scaledH);
                                    
                                    // Set the new height of the cropping rectangle
                                    
                                    cropRect.height = scaledH;
                                }
                                
                                // Set the scaled width for the cropping rectangle
                                
                                cropRect.width = scaledW;                            
                            }
                        }
                    }
                    
                    // Bottom-left Handle
                    
                    else if (activeHandle == 3) {
                        
                        // Get the new position of the bottom-left corner of the cropping rectangle
                        
                        btmX = mouseX - anchorX;
                        btmY = mouseY - anchorY;
    
                        // If the new position of the bottom-left corner of the cropping rectangle is outside the bottom or left margin, then set the corner to the bottom or left margin
                        
                        if (btmX < 0) btmX = 0;
                        if (btmY > imageScaledHeight - 1) btmY = imageScaledHeight - 1;
    
                        // Get the current position of the top-right corner of the cropping rectangle
                                            
                        topX = cropRect.x + cropRect.width;
                        topY = cropRect.y;
    
                        // Calculate the new width of the cropping rectangle
                        
                        cropRect.width = topX - btmX;
                        
                        // If the new width is less than the minimum allowed size then set the new width to the minimum
                        
                        if (cropRect.width < cropRectMinimumSize) {
                            cropRect.width = cropRectMinimumSize;
                            btmX = topX - cropRectMinimumSize;
                        }
                        
                        // Set the new x position for the top-left corner of the cropping rectangle
                        
                        cropRect.x = btmX;
                        
                        // Calculate the new height of the cropping rectangle
                        
                        cropRect.height = btmY - topY;
                        
                        // If the new height is less than the minimum allowed size then set the new height to the minimum
                        
                        if (cropRect.height < cropRectMinimumSize) cropRect.height = cropRectMinimumSize;
    
                        // Set the new y position for the top-left corner of the cropping rectangle
                        
                        cropRect.y = topY;
                        
                        // If a cropping ratio is defined
                        
                        if (cropRatioActive) {
                            
                            // If the cropping rectangle is not at the correct ratio
                        
                            if (cropRect.width / cropRect.height != cropRatio) {
                                
                                // Get a new scaled width for the cropping rectangle
                                
                                scaledW = cropRect.height * cropRatio;
                                
                                // If the new width is less then the minimum allowed width
                                
                                if (scaledW < cropRectMinimumSize) {
                                    
                                    // Set the width to the minimum
                                    
                                    scaledW = cropRectMinimumSize;
                                    
                                    // Scale the height for the new width
                                    
                                    scaledH = scaledW / cropRatio;
                                                                    
                                    // Set the new height of the cropping rectangle
                                    
                                    cropRect.height = scaledH;
                                }
                                
                                // Move the horizontal position to compensate for the scaled width
                                
                                cropRect.x += cropRect.width - scaledW;
                                
                                // If the new width is to the left of the left margin
                                
                                if (cropRect.x < 0) {
                                    
                                    // Reduce the width of the cropping rectangle by the amount that the cropping rectangle extends past the left margin
                                    
                                    scaledW += cropRect.x;
                                    
                                    // Set the left edge of the cropping rectangle to the left margin
                                    
                                    cropRect.x = 0;
    
                                    // Scale the height for the new width
                                    
                                    scaledH = scaledW / cropRatio;
                                    
                                    // Set the new height of the cropping rectangle
                                    
                                    cropRect.height = scaledH;
                                }
                                
                                // Set the scaled width for the cropping rectangle
                                
                                cropRect.width = scaledW;                                                        
                            }
                        }                    
                    }
                    
                    // Bottom-right Handle                
                    
                    else if (activeHandle == 4) {
                        
                        // Get the new position of the bottom-left corner of the cropping rectangle
                        
                        btmX = mouseX - anchorX;
                        btmY = mouseY - anchorY;
                        
                        // If the new position of the bottom-right corner of the cropping rectangle is outside the bottom or right margin, then set the corner to the bottom or right margin
                        
                        if (btmX > imageScaledWidth - 1) btmX = imageScaledWidth - 1;
                        if (btmY > imageScaledHeight - 1) btmY = imageScaledHeight - 1;
    
                        // Get the current position of the top-left corner of the cropping rectangle
                                            
                        topX = cropRect.x;
                        topY = cropRect.y;
                        
                        // Calculate the new width of the cropping rectangle
                        
                        cropRect.width = btmX - topX;
                        
                        // If the new width is less than the minimum allowed size then set the new width to the minimum
                        
                        if (cropRect.width < cropRectMinimumSize) {
                            cropRect.width = cropRectMinimumSize;
                            btmX = topX + cropRectMinimumSize;
                        }
                                            
                        // Calculate the new height of the cropping rectangle
                        
                        cropRect.height = btmY - topY;
                        
                        // If the new height is less than the minimum allowed size then set the new height to the minimum
                        
                        if (cropRect.height < cropRectMinimumSize) cropRect.height = cropRectMinimumSize;
                        
                        // If a cropping ratio is defined
                        
                        if (cropRatioActive) {
                            
                            // If the cropping rectangle is not at the correct ratio
                        
                            if (cropRect.width / cropRect.height != cropRatio) {
                                
                                // Get a new scaled width for the cropping rectangle
                                
                                scaledW = cropRect.height * cropRatio;
                                
                                // If the new width is less then the minimum allowed width
                                
                                if (scaledW < cropRectMinimumSize) {
                                    
                                    // Set the width to the minimum
                                    
                                    scaledW = cropRectMinimumSize;
                                    
                                    // Scale the height for the new width
                                    
                                    scaledH = scaledW / cropRatio;
                                                                    
                                    // Set the new height of the cropping rectangle
                                    
                                    cropRect.height = scaledH;
                                }
                                
                                // If the new width exceeds the maximum allowed width
                                
                                if (cropRect.x + scaledW > imageScaledWidth - 1) {
                                    
                                    // Set the width to the maximum allowed
                                    
                                    scaledW = imageScaledWidth - 1 - cropRect.x;
                                    
                                    // Scale the height for the new width
                                    
                                    scaledH = scaledW / cropRatio;
                                                                    
                                    // Set the new height of the cropping rectangle
                                    
                                    cropRect.height = scaledH;
                                }
                                
                                // Set the scaled width for the cropping rectangle
                                
                                cropRect.width = scaledW;                            
                            }
                        }                    
                    }        
                            
                    // Render the cropping rectangle on top of the image
                    
                    drawCroppingRect();
                    
                    // Invalidate the display list to redraw the component
                    
                    invalidateDisplayList();                
                }
                
                // Else a handle is not active
                
                else {
                    
                    // If the cropping rectangle is smaller than the image dimensions and if the mouse is within the cropping rectangle but not in a handle then show the hand cursor
                    
                    if ((cropRect.width + 1 < Math.floor(imageScaledWidth) || cropRect.height + 1 < Math.floor(imageScaledHeight)) && mouseLocation(event) == 0) {
                        if (handCursorID < 0) handCursorID = CursorManager.setCursor(handCursor, 2, -6, -3);
                    }
                    
                    // Else the mouse is in a handle or outside of the cropping rectangle
                    
                    else {
                        
                        // If the hand cursor is active, remove it
                        
                        if (handCursorID >= 0) {
                            CursorManager.removeCursor(handCursorID);
                            handCursorID = -1;
                        }                                        
                    }
                }
            }
            
            // --------------------------------------------------------------------------------------------------
            // drawCroppingRect
            // --------------------------------------------------------------------------------------------------
    
            private function drawCroppingRect():void {
                
                // If the BitmapData object has been constructed, proceed to draw the cropping rectangle
                
                if (croppingRectBitmapData && componentEnabled) {
                
                    // Clear the previous cropping rectangle by filling the bitmap with the mask color
                    
                    croppingRectBitmapData.fillRect(croppingRectBitmapData.rect, cropMaskColor);
                    
                    // Draw the transparent cropping rectangle area
                    
                    croppingRectBitmapData.fillRect(cropRect, 0x00FFFFFF);
                    
                    // Draw boarder around the cropping rectangle
                    
                    var border:Shape = new Shape();
                    border.graphics.lineStyle(1, cropSelectionOutlineColor, cropSelectionOutlineAlpha);
                    border.graphics.drawRect(cropRect.x, cropRect.y, cropRect.width, cropRect.height);
                    croppingRectBitmapData.draw(border);    
                    
                    // Draw corner handles
                    
                    var handles:Shape = new Shape();
                    handles.graphics.lineStyle(1, cropSelectionOutlineColor, cropSelectionOutlineAlpha);
                    
                    handles.graphics.beginFill(cropHandleColor, cropHandleAlpha);
                    handles.graphics.drawRect(cropRect.x, cropRect.y, cropHandleSize, cropHandleSize);
                    handles.graphics.endFill();
                    
                    handles.graphics.beginFill(cropHandleColor, cropHandleAlpha);
                    handles.graphics.drawRect(cropRect.x + cropRect.width - cropHandleSize, cropRect.y, cropHandleSize, cropHandleSize);
                    handles.graphics.endFill();
                    
                    handles.graphics.beginFill(cropHandleColor, cropHandleAlpha);
                    handles.graphics.drawRect(cropRect.x, cropRect.y + cropRect.height - cropHandleSize, cropHandleSize, cropHandleSize);
                    handles.graphics.endFill();
                    
                    handles.graphics.beginFill(cropHandleColor, cropHandleAlpha);
                    handles.graphics.drawRect(cropRect.x + cropRect.width - cropHandleSize, cropRect.y + cropRect.height - cropHandleSize, cropHandleSize, cropHandleSize);
                    handles.graphics.endFill();
                    
                    croppingRectBitmapData.draw(handles);
                }
            }        
    
            // --------------------------------------------------------------------------------------------------
            // commitProperties - Handle cropping rectangle property change (called by Flex when invalidateProperties is called after a change is made to a cropping rectangle property)
            // --------------------------------------------------------------------------------------------------
            
            /**
             * @private
             */
            
            override protected function commitProperties():void {
                
                super.commitProperties();
                
                // If a property for the cropping rectangle has been changed
                
                if (cropMaskChanged) {
                    
                    // Reset property changed flag
                    
                    cropMaskChanged = false;
                    
                    // Check the cropping rectangle size to make sure that there is enough space to display the handles with no overlap; if there isn't, then increase the size of the cropping rectangle.
    
                    if (cropRect != null && (cropRectMinimumSize > cropRect.width || cropRectMinimumSize > cropRect.height)) {
                        
                        var origRect:Rectangle = cropRect.clone();
                            
                        if (cropRect.y > imageScaledHeight - 1 - cropRectMinimumSize) cropRect.y = imageScaledHeight - 1 - cropRectMinimumSize;
                        if (cropRect.x > imageScaledWidth - 1 - cropRectMinimumSize) cropRect.x = imageScaledWidth - 1 - cropRectMinimumSize;
                        if (cropRect.height < cropRectMinimumSize) cropRect.height = cropRectMinimumSize;
                        if (cropRect.width < cropRectMinimumSize) cropRect.width = cropRectMinimumSize;
                        
                        // If the aspect ratio is constrained, make sure that it doesn't change unless it's not possible to maintain the aspect ratio in the available space (given the current crop handle size)
                        
                        if (constrainToAspectRatio && cropRect.width != cropRect.height * cropRatio) {
                            
                            // Calculate what the new cropping rectangle width or the new cropping rectangle height will have to be in order to maintain the correct aspect ratio
                            // (the dimension that is not less than the cropping rectangle cropRectMinimumSize will be used)
                            
                            var newWidth:Number = cropRect.height * cropRatio;
                            var newHeight:Number = cropRect.width / cropRatio;
                            
                            // Increase width
                            
                            if (newWidth > cropRectMinimumSize) {
                                
                                // Set the cropping rectangle to the width that will maintain the aspect ratio
                                
                                cropRect.width = newWidth;
                                
                                // If the new width causes the crop box to extend beyond the right edge ...
                                
                                if (cropRect.x + cropRect.width > imageScaledWidth - 1) {
                                    
                                    // Find out how far off the edge the cropping rectangle extends
                                    
                                    var wDelta:Number = (cropRect.x + cropRect.width) - (imageScaledWidth - 1);
                                    
                                    // If there is room to the left of the cropping rectangle, adjust the left edge of the cropping rectangle so it fits in the available space
                                    
                                    if (cropRect.x - wDelta >= 0) cropRect.x = cropRect.x - wDelta;
                                    
                                    // Else there is no way to maintain the aspect ratio so extend the cropping rectangle from the left edge to the right edge, calculate the new aspect ratio, and dispatch an event indicating that the ratio has been altered
                                    
                                    else {
                                        cropRect.x = 0;
                                        cropRect.width = imageScaledWidth - 1;
                                        cropRatio = cropRect.width / cropRect.height;
                                        dispatchEvent(new Event(CROP_CONSTRAINT_CHANGED));
                                    }
                                }
                            }
                            
                            // Increase height
                            
                            else {
                                
                                // Set the cropping rectangle to the height that will maintain the aspect ratio
                                
                                cropRect.height = newHeight;
                                
                                // If the new height causes the crop box to extend beyond the bottom edge ...
                                
                                if (cropRect.y + cropRect.height > imageScaledHeight - 1) {
                                    
                                    // Find out how far off the edge the cropping rectangle extends
                                    
                                    var hDelta:Number = (cropRect.y + cropRect.height) - (imageScaledHeight - 1);
                                    
                                    // If there is room above the cropping rectangle, adjust the top edge of the cropping rectangle so it fits in the available space
                                    
                                    if (cropRect.y - hDelta >= 0) cropRect.y = cropRect.y - hDelta;
                                    
                                    // Else there is no way to maintain the aspect ratio so extend the cropping rectangle from the top to the bottom, calculate the new aspect ratio, and dispatch an event indicating that the ratio has been altered
                                    
                                    else {
                                        cropRect.y = 0;
                                        cropRect.height = imageScaledHeight - 1;
                                        cropRatio = cropRect.width / cropRect.height;
                                        dispatchEvent(new Event(CROP_CONSTRAINT_CHANGED));
                                        
                                    }
                                }                            
                            }
                        }
    
                        // Dispatch events if the size of the handles cause the position or dimensions of the cropping rectangle to change
                        
                        if (cropRect.x != origRect.x || cropRect.y != origRect.y) dispatchEvent(new Event(CROP_POSITION_CHANGED));
                        if (cropRect.width != origRect.width || cropRect.height != origRect.height) dispatchEvent(new Event(CROP_DIMENSIONS_CHANGED));
                    }
                    
                    // Redraw the cropping rectangle area
                    
                    drawCroppingRect();
                    
                    // Schedule a display list update
                    
                    invalidateDisplayList();
                }
            }
    
            // --------------------------------------------------------------------------------------------------
            // measure - Sets the default component size and the component's minimum size in pixels 
            // --------------------------------------------------------------------------------------------------
            
            /**
             * @private
             */
            
            override protected function measure():void {
                
                super.measure();
                
                if (!isNaN(componentWidth) && !isNaN(componentHeight)) {
                
                    // Set default measurements
                    
                    measuredWidth = componentWidth;
                    measuredHeight = componentHeight;
                    
                    // Set optional minimum size measurements
                    
                    measuredMinWidth = componentWidth;
                    measuredMinHeight = componentHeight;
                }            
            }    
    
            // --------------------------------------------------------------------------------------------------
            // updateDisplayList - This method is called to size and position the children of the component based on all previous property and style settings.
            //                     It also draws any skins or graphic elements that the component uses. Note that the parent container determines the size of the component itself.
            // --------------------------------------------------------------------------------------------------
                                
            /**
             * @private
             */
    
            override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
    
                // The Flex callLaterDispatcher() can call updateDisplayList() after this component's destroy() method has been called but before it is garbage collected.
                // When destroy() is called the "destroyed" flag is set to prevent a null object reference error if updateDisplayList() is subsequently called.
                
                if (!destroyed) {
                
                    super.updateDisplayList(unscaledWidth, unscaledHeight);
                    
                    // If the dimensions of the component have changed, create a new bitmap to match the components new size
                    
                    if (unscaledWidth != componentWidth || unscaledHeight != componentHeight) initializeDisplay(unscaledWidth, unscaledHeight);
                    
                    // If an image is loaded
                    
                    if (imageBitmapData != null) {    
                        
                        // If the image has not been rendered yet, create a scaled version of the image that will fit within the component
                        
                        if (newImageLoaded) createScaledImage();
                                        
                        if (newCroppingRect) initializeCroppingRect();
                        
                        // Clear the current content
                        
                        componentBitmapData.fillRect(componentBitmapData.rect, bkgndColor);
                        
                        // Draw the scaled image in the component's display
                        
                        componentBitmapData.copyPixels(scaledImageBitmapData, scaledImageBitmapData.rect, imageLocation, null, null, true);
                        
                        // Draw the cropping overlay if the component is enabled
                        
                        if (componentEnabled && croppingRectBitmapData != null) componentBitmapData.copyPixels(croppingRectBitmapData, croppingRectBitmapData.rect, imageLocation, null, null, true);
                    }
                }            
            }
    
            // --------------------------------------------------------------------------------------------------
            // initializeDisplay - Create the bitmap that represents the component's display
            // --------------------------------------------------------------------------------------------------
            
            private function initializeDisplay(newWidth:int, newHeight:int):void {
                
                if (newWidth > 0 && newHeight > 0) {
                
                    // If a bitmap already exists (i.e., if the display area has been resized), remove the previous bitmap
        
                    if (componentBitmap != null) {
                        removeChild(componentBitmap);
                        componentBitmapData.dispose();
                    }
                    
                    // Create a Bitmap with smoothing enabled that matches the component's size and add it to the display list
                    
                    componentBitmapData = new BitmapData(newWidth, newHeight, true, bkgndColor);
                    componentBitmap = new Bitmap(componentBitmapData);
                    addChild(componentBitmap);
                    
                    // Save the current size of the component
                    
                    componentWidth = newWidth;
                    componentHeight = newHeight;    
                }
            }        
                        
            // --------------------------------------------------------------------------------------------------
            // initializeCroppingRect
            // --------------------------------------------------------------------------------------------------
            
            private function initializeCroppingRect():void {
                
                // The cropping rectangle cannot be initialized unless the imageCropper component is enabled and createScaledImage() has been called
                
                if (componentEnabled && scaledImageBitmapData != null) {
                    
                    // Determine if cropping rectangle is to be centered
                    
                    var centerCropRect:Boolean = (cropX == -1) || (cropY == -1);
                
                    // Clear the initialization flag that was set when newCroppingRect() was called
                    
                    newCroppingRect = false;
                    
                    // If a cropping rectangle was previously defined, dispose of the BitmapData
                    
                    if (croppingRectBitmapData != null) croppingRectBitmapData.dispose();
                    
                    // Create the BitmapData for the cropping rectangle (the display area should match the image's display area)
                    
                    croppingRectBitmapData = new BitmapData(scaledImageBitmapData.width, scaledImageBitmapData.height, true, 0xAA000000);
                    
                    // If the width or height is zero, then the cropping rectangle will be set to the size of the image
                    
                    if (cropWidth == 0 || cropHeight == 0) {
                        
                        // Set width and height to the size of the image
                        
                        cropWidth = scaledImageBitmapData.width - 1;
                        cropHeight = scaledImageBitmapData.height - 1;                    
                
                        // Save original cropping rectangle to determine if it had to be repositioned or resized in order to be valid
                    
                        var origRect:Rectangle = new Rectangle(cropX, cropY, cropWidth, cropHeight);
                        
                        // If the crop ratio is active, calculate the ratio and save it as the original ratio (in case it has to be changed later in this function)
                        
                        if (cropRatioActive) {
                            cropRatio = cropWidth / cropHeight;
                            var origCropRatio:Number = cropRatio;
                        }
                    }
                        
                    // If croppingRectIsImageScale is true, then scale the cropping rectangle dimensions so that it is drawn at the same scale as the selected image
                    
                    else if (croppingRectIsImageScale) {
                        
                        // If the crop ratio is active, save it as the original ratio (in case it has to be changed later in this function)
                        
                        if (cropRatioActive) origCropRatio = cropRatio;
                        
                        // If a specific location is defined for the cropping rectangle, convert the X and Y coordinates
    
                        if (cropX >= 0 && cropY >= 0) {
                            cropX *= imageScaleFactor;
                            cropY *= imageScaleFactor;
                        }
                        
                        // Convert width and height of the cropping rectangle
                        
                        cropWidth *= imageScaleFactor;
                        cropHeight *= imageScaleFactor;
                        
                        // Save original cropping rectangle to determine if it had to be repositioned or resized in order to be valid
                    
                        origRect = new Rectangle(cropX, cropY, cropWidth, cropHeight);                    
                        
                        // Make sure that the dimensions are not smaller than the size of the cropping rectangle handles
                        
                        if (cropWidth < cropRectMinimumSize) {
                            cropHeight = cropHeight * (cropRectMinimumSize / cropWidth)
                            cropWidth = cropRectMinimumSize;
                        }
                        
                        if (cropHeight < cropRectMinimumSize) {
                            cropWidth = cropWidth * (cropRectMinimumSize / cropHeight)
                            cropHeight = cropRectMinimumSize;
                        }
                    }
                    
                    // Esle save original cropping rectangle to determine if it had to be repositioned or resized in order to be valid
                    
                    else origRect = new Rectangle(cropX, cropY, cropWidth, cropHeight);                    
                    
                    // If the cropping rectangle is positioned absolutely (i.e., cropX and cropY > -1)
                    
                    if (!centerCropRect) {
                                            
                        // If the absolute positioning causes the cropping rectangle to extend beyond the image area, try to reposition the cropping rectangle so that it touches rather than exceeds the image boundry
    
                        if (cropX + cropWidth + 1 > scaledImageBitmapData.width) cropX = scaledImageBitmapData.width - cropWidth - 1;
                        if (cropY + cropHeight + 1 > scaledImageBitmapData.height) cropY = scaledImageBitmapData.height - cropHeight - 1;
                        
                        // If the top or left-edge of the cropping rectangle extends beyond the top or left edge of the image area then decrease the height or width so that it fits within the image area
                        // If a dimension of the cropping rectangle cannot fit, then set that dimension equal to the width or height of the image.
                        
                        if (cropX < 0) {
                            cropWidth += cropX;
                            if (cropWidth <= 0) cropWidth = scaledImageBitmapData.width - 1;
                            cropX = 0;
                        }
                        
                        if (cropY < 0) {
                            cropHeight += cropY;
                            if (cropHeight <= 0) cropHeight = scaledImageBitmapData.height - 1;
                            cropY = 0;
                        }
                    }
                
                    // Make sure that neither dimension exceeds the image dimensions
                    
                    if (cropWidth + 1 > scaledImageBitmapData.width) {
                        cropWidth = scaledImageBitmapData.width - 1;
                        if (cropRatioActive) cropHeight = cropWidth / cropRatio;
                    }
                    
                    if (cropHeight + 1 > scaledImageBitmapData.height) {
                        cropHeight = scaledImageBitmapData.height - 1;
                        if (cropRatioActive) cropWidth = cropHeight * cropRatio;
                    }
                    
                    // If the cropping rectangle is not absolutely positioned, then center the cropping rectangle in the image area
                    
                    if (centerCropRect) {
                        cropX = (scaledImageBitmapData.width - cropWidth) / 2;
                        cropY = (scaledImageBitmapData.height - cropHeight) / 2;
                    }
                                    
                    // If the absolute positioning causes the cropping rectangle to extend beyond the image area, try to reposition the cropping rectangle so that it touches rather than exceeds the image boundry
    
                    if (cropX + cropWidth + 1 > scaledImageBitmapData.width) cropX = scaledImageBitmapData.width - cropWidth - 1;
                    if (cropY + cropHeight + 1 > scaledImageBitmapData.height) cropY = scaledImageBitmapData.height - cropHeight - 1;
                    
                    // If adjusting cropX and cropY results in zero or negative space, reset the cropping rectangle to the image area
                    
                    if (scaledImageBitmapData.width - 1 <= cropX || scaledImageBitmapData.height - 1 <= cropY) {
                        cropX = 0;
                        cropY = 0;
                        cropWidth = scaledImageBitmapData.width - 1
                        cropHeight = scaledImageBitmapData.height - 1;
                    }
                    
                    // Create the initial cropping rectangle centered in the display area
                    
                    cropRect = new Rectangle(cropX, cropY, cropWidth, cropHeight); 
                    
                    // Draw the initial cropping rectangle
                    
                    drawCroppingRect();
                    
                    // Dispatch events if the position, size, and/or aspect ratio of the cropping rectangle was changed
                    
                    if (!centerCropRect && (cropX != origRect.x || cropY != origRect.y)) dispatchEvent(new Event(CROP_POSITION_CHANGED));
                    if (cropWidth != origRect.width || cropHeight != origRect.height) dispatchEvent(new Event(CROP_DIMENSIONS_CHANGED));
                    if (cropRatioActive && !isNaN() && cropRatio != origCropRatio) dispatchEvent(new Event(CROP_CONSTRAINT_CHANGED));
                }            
            }
            
            // --------------------------------------------------------------------------------------------------
            // createScaledImage - Create a scaled version of the source image that will fit in the component's display area
            // --------------------------------------------------------------------------------------------------
            
            private function createScaledImage():void {
    
                if (imageBitmapData != null) {
                    
                    var imageWidth:Number = imageBitmapData.width;
                    var imageHeight:Number = imageBitmapData.height;
    
                    // Clear the flag that indicates that the image has not been processed yet by the createScaledImage() method
                    
                    newImageLoaded = false;                
                    
                    // Initialize the scaling factor to 1 (unscaled)
                    
                    imageScaleFactor = 1;
                
                    // If the image size is larger than the component size
                    
                    if (imageWidth > componentWidth || imageHeight > componentHeight) {
                    
                        // Determine the ratio of the size of the loaded image to the component's size
                        
                        var newXScale:Number = imageWidth == 0 ? 1 : componentWidth / imageWidth;
                        var newYScale:Number = imageHeight == 0 ? 1 : componentHeight / imageHeight;
                        
                        // Calculate the scaling factor based on which dimension must be scaled in order for the image to fit within the component
                        
                        var x:Number = 0;
                        var y:Number = 0;
                        
                        if (newXScale > newYScale) {
                            x = Math.floor((componentWidth - imageWidth * newYScale));
                            imageScaleFactor = newYScale;
                        }
                        else {
                            y = Math.floor((componentHeight - imageHeight * newXScale));
                            imageScaleFactor = newXScale;
                        }
                        
                        // Create a matrix to perform the image scaling
                        
                        var scaleMatrix:Matrix = new Matrix();
                        scaleMatrix.scale(imageScaleFactor, imageScaleFactor);
                        
                        // Calculate the scaled size of the image
                        
                        imageScaledWidth = Math.ceil(imageBitmapData.width * imageScaleFactor);
                        imageScaledHeight = Math.ceil(imageBitmapData.height * imageScaleFactor);
                        
                        // Calculate the new coordinates for the image so that it is centered within the component
                        
                        imageLocation = new Point(x - ((unscaledWidth - imageScaledWidth) / 2), y - ((unscaledHeight - imageScaledHeight) / 2))            
                        
                        // If there is a scaled BitmapData object from a previous image, dispose of the data
                        
                        if (scaledImageBitmapData != null) scaledImageBitmapData.dispose();
                        
                        // Create a new BitmapData object to hold the scaled image
                        
                        scaledImageBitmapData = new BitmapData(imageScaledWidth, imageScaledHeight, true, bkgndColor);
                        
                        // Create the scaled image (use smoothing)
                        
                        scaledImageBitmapData.draw(imageBitmapData, scaleMatrix, null, null, null, true);
                    }
                    
                    // Else the image size is equal to or smaller than the component size
                    
                    else {
                        
                        // The scaled size is the actual size of the image
                        
                        imageScaledWidth = imageWidth;
                        imageScaledHeight = imageHeight;
                        
                        // Set the new coordinates for the image so that it is centered within the component
                        
                        imageLocation = new Point((componentWidth - imageWidth) / 2, (componentHeight - imageHeight) / 2);
                        
                        // The image is unscaled, so just clone the BitmapData
                        
                        scaledImageBitmapData = imageBitmapData.clone();                    
                    }
                }            
            }
        }
    }
  • 相关阅读:
    基于OpenStack构建企业私有云(8)Cinder
    基于OpenStack构建企业私有云(6)创建第一台云主机
    基于OpenStack创建企业私有云(7)Horizon
    基于OpenStack构建企业私有云(4)Nova
    python--006--三元运算、列表解析、生成器表达式
    python--006--迭代器协议和for循环工作机制
    python--005--文件操作(b,其他)
    python--005--文件操作(r,w,a)
    python--004--函数(其他内置函数)
    python--004--函数(zip、min、max)
  • 原文地址:https://www.cnblogs.com/ffmpeg/p/4381183.html
Copyright © 2020-2023  润新知