File: commonui\System\Drawing\Image.cs
Project: ndp\fx\src\System.Drawing.csproj (System.Drawing)
//------------------------------------------------------------------------------
// <copyright file="Image.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
namespace System.Drawing {
    using System.Runtime.Serialization.Formatters;
    using System.Threading;
    using System.Runtime.InteropServices;
    using System.Runtime.Serialization;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System;
    using System.Drawing.Design;
    using System.IO;    
    using System.Reflection;    
    using System.ComponentModel;
    using ArrayList = System.Collections.ArrayList;
    using Microsoft.Win32;
    using System.Drawing.Imaging;
    using System.Drawing.Internal;
    using System.Security;
    using System.Security.Permissions;
    using System.Globalization;
    using System.Runtime.Versioning;
 
    /**
     * Represent an image object (could be bitmap or vector)
     */
    /// <include file='doc\Image.uex' path='docs/doc[@for="Image"]/*' />
    /// <devdoc>
    ///    An abstract base class that provides
    ///    functionality for 'Bitmap', 'Icon', 'Cursor', and 'Metafile' descended classes.
    /// </devdoc>
    [
    TypeConverterAttribute(typeof(ImageConverter)),
    Editor("System.Drawing.Design.ImageEditor, " + AssemblyRef.SystemDrawingDesign, typeof(UITypeEditor)),
    ImmutableObject(true)
    ]
    [Serializable]
    [ComVisible(true)]
    public abstract class Image : MarshalByRefObject, ISerializable, ICloneable, IDisposable {
 
#if FINALIZATION_WATCH
        private string allocationSite = Graphics.GetAllocationStack();
#endif
 
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.GetThumbnailImageAbort"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        // The signature of this delegate is incorrect. The signature of the corresponding 
        // native callback function is:
        // extern "C" {
        //     typedef BOOL (CALLBACK * ImageAbort)(VOID *);
        //     typedef ImageAbort DrawImageAbort;
        //     typedef ImageAbort GetThumbnailImageAbort;
        // }
        // However, as this delegate is not used in both GDI 1.0 and 1.1, we choose not
        // to modify it in Dev10, in order not to break exsiting code
        public delegate bool GetThumbnailImageAbort();
 
        /*
         * Handle to native image object
         */
        internal IntPtr nativeImage;
 
        // used to work around lack of animated gif encoder... rarely set...
        //
        byte[] rawData;
 
        //userData : so that user can use TAGS with IMAGES..
        private object userData;
 
        /**
         * Constructor can't be invoked directly
         */
        internal Image() {
        }
 
        /**
         * Constructor used in deserialization
         */
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        internal Image(SerializationInfo info, StreamingContext context) {
            SerializationInfoEnumerator sie = info.GetEnumerator();
            if (sie == null) {
                return;
            }
            for (; sie.MoveNext();) {
                if (String.Equals(sie.Name, "Data", StringComparison.OrdinalIgnoreCase))
                {
                    try {
                        byte[] dat = (byte[])sie.Value;
                        if (dat != null) {
                            InitializeFromStream(new MemoryStream(dat));
                        }
 
                    }
                    catch (ExternalException e) {
                        Debug.Fail("failure: " + e.ToString());
                    }
                    catch (ArgumentException e) {
                        Debug.Fail("failure: " + e.ToString());
                    }
                    catch (OutOfMemoryException e) {
                        Debug.Fail("failure: " + e.ToString());
                    }
                    catch (InvalidOperationException e) {
                        Debug.Fail("failure: " + e.ToString());
                    }
                    catch (NotImplementedException e) {
                        Debug.Fail("failure: " + e.ToString());
                    }
                    catch (FileNotFoundException e) {
                        Debug.Fail("failure: " + e.ToString());
                    }
                }
            }
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.Tag"]/*' />
        [
        Localizable(false),
        Bindable(true),
        DefaultValue(null),
        TypeConverter(typeof(StringConverter))
        ]
        public object Tag {
            get {
                return userData;
            }
            set {
                userData = value;
            }
        }
 
        /**
        * Create an image object from a URL
        */
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.FromFile"]/*' />
        /// <devdoc>
        ///    Creates an <see cref='System.Drawing.Image'/> from the specified file.
        /// </devdoc>
        // [Obsolete("Use Image.FromFile(string, useEmbeddedColorManagement)")]
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static Image FromFile(String filename) {
            return Image.FromFile(filename, false);
        }
        
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.FromFile1"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static Image FromFile(String filename,
                                     bool useEmbeddedColorManagement) {
            
            // SECREVIEW : The File.Exists() below will do the demand for the FileIOPermission
            //             for us. So, we do not need an additional demand anymore.
            //
            if (!File.Exists(filename)) {
                // I have to do this so I can give a meaningful
                // error back to the user. File.Exists() cal fail because of either
                // a failure to demand security or because the file does not exist.
                // Always telling the user that the file does not exist is not a good
                // choice. So, we demand the permission again. This means that we are
                // going to demand the permission twice for the failure case, but that's
                // better than always demanding the permission twice.
                //
                IntSecurity.DemandReadFileIO(filename);
 
                throw new FileNotFoundException(filename);
            }
 
            //GDI+ will read this file multiple times.  Get the fully qualified path
            //so if our app changes default directory we won't get an error
            // SECREVIEW : If path does exist, the caller must have FileIOPermissionAccess.PathDiscovery permission. 
            //             Note that unlike most members of the Path class, this method accesses the file system.
            //
            filename = Path.GetFullPath(filename);
 
            IntPtr image = IntPtr.Zero;
            int status;
            
            if (useEmbeddedColorManagement) {
                status = SafeNativeMethods.Gdip.GdipLoadImageFromFileICM(filename, out image);
            }
            else {
                status = SafeNativeMethods.Gdip.GdipLoadImageFromFile(filename, out image);
            }
            
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            status = SafeNativeMethods.Gdip.GdipImageForceValidation(new HandleRef(null, image));
 
            if (status != SafeNativeMethods.Gdip.Ok) {
                SafeNativeMethods.Gdip.GdipDisposeImage(new HandleRef(null, image));
                throw SafeNativeMethods.Gdip.StatusException(status);
            }
 
            Image img = CreateImageObject(image);
 
            EnsureSave(img, filename, null);
 
            return img;
        }
 
 
        /**
         * Create an image object from a data stream
         */
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.FromStream"]/*' />
        /// <devdoc>
        ///    Creates an <see cref='System.Drawing.Image'/> from the specified data
        ///    stream.
        /// </devdoc>
        // [Obsolete("Use Image.FromStream(stream, useEmbeddedColorManagement)")]
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static Image FromStream(Stream stream) {
            return Image.FromStream(stream, false);
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.FromStream1"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static Image FromStream(Stream stream, 
                                       bool useEmbeddedColorManagement) 
        {
            return FromStream( stream, useEmbeddedColorManagement, true );
        }
        
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.FromStream2"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static Image FromStream(Stream stream, bool useEmbeddedColorManagement, bool validateImageData ) {
            if( !validateImageData ) {
                IntSecurity.UnmanagedCode.Demand();
            }
            
            if (stream == null){
                throw new ArgumentException(SR.GetString(SR.InvalidArgument, "stream", "null"));
            }
 
            IntPtr image = IntPtr.Zero;
            int status;
            
            if (useEmbeddedColorManagement) {
                status = SafeNativeMethods.Gdip.GdipLoadImageFromStreamICM(new GPStream(stream), out image);
            }
            else {
                status = SafeNativeMethods.Gdip.GdipLoadImageFromStream(new GPStream(stream), out image);
            }
            
            if (status != SafeNativeMethods.Gdip.Ok){
                throw SafeNativeMethods.Gdip.StatusException(status);
            }
 
            if( validateImageData ) {
                status = SafeNativeMethods.Gdip.GdipImageForceValidation(new HandleRef(null, image));
 
                if (status != SafeNativeMethods.Gdip.Ok) {
                    SafeNativeMethods.Gdip.GdipDisposeImage(new HandleRef(null, image));
                    throw SafeNativeMethods.Gdip.StatusException(status);
                }
            }
 
            Image img = CreateImageObject(image);
 
            EnsureSave(img, null, stream);
 
            return img;
        }
 
        // Used for serialization
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        private void InitializeFromStream(Stream stream) {
            IntPtr image = IntPtr.Zero;
 
            int status = SafeNativeMethods.Gdip.GdipLoadImageFromStream(new GPStream(stream), out image);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            status = SafeNativeMethods.Gdip.GdipImageForceValidation(new HandleRef(null, image));
 
            if (status != SafeNativeMethods.Gdip.Ok) {
                SafeNativeMethods.Gdip.GdipDisposeImage(new HandleRef(null, image));
                throw SafeNativeMethods.Gdip.StatusException(status);
            }
 
            this.nativeImage = image;
 
            int type = -1;
 
            status = SafeNativeMethods.Gdip.GdipGetImageType(new HandleRef(this, nativeImage), out type);
 
            EnsureSave(this, null, stream);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
        }
 
        internal Image(IntPtr nativeImage) {
            SetNativeImage(nativeImage);
        }
 
        /**
         * Make a copy of the image object
         */
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.Clone"]/*' />
        /// <devdoc>
        ///    Creates an exact copy of this <see cref='System.Drawing.Image'/>.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public object Clone() {
            IntPtr cloneImage = IntPtr.Zero;
 
            int status = SafeNativeMethods.Gdip.GdipCloneImage(new HandleRef(this, nativeImage), out cloneImage);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            status = SafeNativeMethods.Gdip.GdipImageForceValidation(new HandleRef(null, cloneImage));
 
            if (status != SafeNativeMethods.Gdip.Ok) {
                SafeNativeMethods.Gdip.GdipDisposeImage(new HandleRef(null, cloneImage));
                throw SafeNativeMethods.Gdip.StatusException(status);
            }
 
            return CreateImageObject(cloneImage);
        }
 
        /**
         * Dispose of resources associated with the Image object
         */
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.Dispose"]/*' />
        /// <devdoc>
        ///    Cleans up Windows resources for this
        /// <see cref='System.Drawing.Image'/>.
        /// </devdoc>
        public void Dispose() {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.Dispose2"]/*' />
        protected virtual void Dispose(bool disposing) {
#if FINALIZATION_WATCH
            if (!disposing && nativeImage != IntPtr.Zero)
                Debug.WriteLine("**********************\nDisposed through finalization:\n" + allocationSite);
#endif
            if (nativeImage != IntPtr.Zero) {
                try{
#if DEBUG
                    int status = 
#endif
                    SafeNativeMethods.Gdip.GdipDisposeImage(new HandleRef(this, nativeImage));
#if DEBUG
                    Debug.Assert(status == SafeNativeMethods.Gdip.Ok, "GDI+ returned an error status: " + status.ToString(CultureInfo.InvariantCulture));
#endif
                }
                catch( Exception ex ){
                    if( ClientUtils.IsSecurityOrCriticalException( ex ) ) {
                        throw;
                    }
 
                    Debug.Fail( "Exception thrown during Dispose: " + ex.ToString() );
                }
                finally{
                    nativeImage = IntPtr.Zero;
                }
            }
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.Finalize"]/*' />
        /// <devdoc>
        ///    Cleans up Windows resources for this
        /// <see cref='System.Drawing.Image'/>.
        /// </devdoc>
        ~Image() {
            Dispose(false);
        }
 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        internal static void EnsureSave(Image image, string filename, Stream dataStream) {
 
            if (image.RawFormat.Equals(ImageFormat.Gif)) {
                bool animatedGif = false;
 
                Guid[] dimensions = image.FrameDimensionsList;
                foreach (Guid guid in dimensions) {
                    FrameDimension dimension = new FrameDimension(guid);
                    if (dimension.Equals(FrameDimension.Time)) {
                        animatedGif = image.GetFrameCount(FrameDimension.Time) > 1;
                        break;
                    }
                }
 
 
                if (animatedGif) {
                    try {
                        Stream created = null;
                        long lastPos = 0;
                        if (dataStream != null) {
                            lastPos = dataStream.Position;
                            dataStream.Position = 0;
                        }
 
                        try {
                            if (dataStream == null) {
                                created = dataStream = File.OpenRead(filename);
                            }
 
                            image.rawData = new byte[(int)dataStream.Length];
                            dataStream.Read(image.rawData, 0, (int)dataStream.Length);
                        }
                        finally {
                            if (created != null) {
                                created.Close();
                            }
                            else {
                                dataStream.Position = lastPos;
                            }
                        }
                    }
                    // possible exceptions for reading the filename
                    catch (UnauthorizedAccessException) {
                    }
                    catch (DirectoryNotFoundException) {
                    }
                    catch (IOException) {
                    }
                    // possible exceptions for setting/getting the position inside dataStream
                    catch (NotSupportedException) {
                    }
                    catch (ObjectDisposedException) {
                    }
                    // possible exception when reading stuff into dataStream
                    catch (ArgumentException) {
                    }
                }
            }
        }
 
        private enum ImageTypeEnum  {
            Bitmap = 1,
            Metafile = 2,
        }
 
        /* FxCop rule 'AvoidBuildingNonCallableCode' - Left here in case it is needed in the future.
        private ImageTypeEnum ImageType
        {
            get { 
                int type = -1;
 
                int status = SafeNativeMethods.Gdip.GdipGetImageType(new HandleRef(this, nativeImage), out type);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);
 
                return(ImageTypeEnum) type;
            }
        }
        */
 
        internal static Image CreateImageObject(IntPtr nativeImage) {
            Image image;
 
            int type = -1;
 
            int status = SafeNativeMethods.Gdip.GdipGetImageType(new HandleRef(null, nativeImage), out type);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            switch ((ImageTypeEnum)type) {
                case ImageTypeEnum.Bitmap:     
                    image = Bitmap.FromGDIplus(nativeImage);
                    break;
 
                case ImageTypeEnum.Metafile:
                    image = Metafile.FromGDIplus(nativeImage);
                    break;
 
                default:
                    throw new ArgumentException(SR.GetString(SR.InvalidImage));
            }
 
            return image;
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.ISerializable.GetObjectData"]/*' />
        /// <devdoc>
        ///     ISerializable private implementation
        /// </devdoc>
        /// <internalonly/>
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
        [SuppressMessage("Microsoft.Usage", "CA2240:ImplementISerializableCorrectly")]        
        void ISerializable.GetObjectData(SerializationInfo si, StreamingContext context) {
            using( MemoryStream stream = new MemoryStream() ) {
                Save( stream );
                si.AddValue("Data", stream.ToArray(), typeof(byte[]));
            }
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.GetEncoderParameterList"]/*' />
        /// <devdoc>
        ///    Returns information about the codecs used
        ///    for this <see cref='System.Drawing.Image'/>.
        /// </devdoc>
        public EncoderParameters GetEncoderParameterList(Guid encoder) {
            EncoderParameters p;
            int size;
 
            int status = SafeNativeMethods.Gdip.GdipGetEncoderParameterListSize(new HandleRef(this, nativeImage), 
                                                                 ref encoder, 
                                                                 out size);
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            if (size <= 0)
                return null;
 
            IntPtr buffer = Marshal.AllocHGlobal(size);
 
            status = SafeNativeMethods.Gdip.GdipGetEncoderParameterList(new HandleRef(this, nativeImage),
                                                         ref encoder, 
                                                         size,
                                                         buffer);
 
            try{
                if (status != SafeNativeMethods.Gdip.Ok) {
                    throw SafeNativeMethods.Gdip.StatusException(status);
                }
 
                p = EncoderParameters.ConvertFromMemory(buffer);
            }
            finally{
                Marshal.FreeHGlobal(buffer);
            }
 
            return p;  
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.Save"]/*' />
        /// <devdoc>
        ///    Saves this <see cref='System.Drawing.Image'/> to the specified file.
        /// </devdoc>
        public void Save(string filename) {
            Save( filename, RawFormat );
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.Save1"]/*' />
        /// <devdoc>
        ///    Saves this <see cref='System.Drawing.Image'/> to the specified file in the
        ///    specified format.
        /// </devdoc>
        public void Save(string filename, ImageFormat format) {
            if (format == null)
                throw new ArgumentNullException("format");
 
            ImageCodecInfo codec = format.FindEncoder();
 
            if (codec == null)
                codec = ImageFormat.Png.FindEncoder();
 
            Save(filename, codec, null);
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.Save2"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Saves this <see cref='System.Drawing.Image'/> to the specified file in the specified format
        ///       and with the specified encoder parameters.
        ///    </para>
        /// </devdoc>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly")]
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        public void Save(string filename, ImageCodecInfo encoder, EncoderParameters encoderParams) {
            if (filename == null)
                throw new ArgumentNullException("filename");
            if (encoder == null)
                throw new ArgumentNullException("encoder");
 
            IntSecurity.DemandWriteFileIO(filename);
 
            IntPtr encoderParamsMemory = IntPtr.Zero;
 
            if (encoderParams != null) {
                rawData = null;
                encoderParamsMemory = encoderParams.ConvertToMemory();
            }
            int status = SafeNativeMethods.Gdip.Ok;
 
            try {
                Guid g = encoder.Clsid;
                bool saved = false;
 
                if (rawData != null) {
                    ImageCodecInfo rawEncoder = RawFormat.FindEncoder();
                    if (rawEncoder != null && rawEncoder.Clsid == g) {
                        using (FileStream fs = File.OpenWrite(filename)) {
                            fs.Write(rawData, 0, rawData.Length);
                            saved = true;
                        }
                    }
                }
 
                if (!saved) {
                    status = SafeNativeMethods.Gdip.GdipSaveImageToFile(new HandleRef(this, nativeImage),
                                                             filename,
                                                             ref g,
                                                             new HandleRef(encoderParams, encoderParamsMemory));
                }
            }
            finally {
                if (encoderParamsMemory != IntPtr.Zero) {
                    Marshal.FreeHGlobal(encoderParamsMemory);
                }
            }
 
            if (status != SafeNativeMethods.Gdip.Ok) {
                throw SafeNativeMethods.Gdip.StatusException(status);
            }
        }
 
        internal void Save(MemoryStream stream) {
            // Jpeg loses data, so we don't want to use it to serialize...
            //
            ImageFormat dest = RawFormat;
            if (dest == ImageFormat.Jpeg) {
                dest = ImageFormat.Png;
            }
            ImageCodecInfo codec = dest.FindEncoder();
 
            // If we don't find an Encoder (for things like Icon), we
            // just switch back to PNG...
            //
            if (codec == null) {
                codec = ImageFormat.Png.FindEncoder();
            }
            Save(stream, codec, null);
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.Save3"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Saves this <see cref='System.Drawing.Image'/> to the specified stream in the specified
        ///       format.
        ///    </para>
        /// </devdoc>
        public void Save(Stream stream, ImageFormat format) {
            if (format == null)
                throw new ArgumentNullException("format");
 
            ImageCodecInfo codec = format.FindEncoder();
            Save(stream, codec, null);
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.Save4"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Saves this <see cref='System.Drawing.Image'/> to the specified stream in the specified
        ///       format.
        ///    </para>
        /// </devdoc>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly")]
        public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams) {
            if (stream == null){
                throw new ArgumentNullException("stream");
            }
            if (encoder == null) {
                throw new ArgumentNullException("encoder");
            }
 
            IntPtr encoderParamsMemory = IntPtr.Zero;
 
            if (encoderParams != null) {
                rawData = null;
                encoderParamsMemory = encoderParams.ConvertToMemory();
            }
 
            int status = SafeNativeMethods.Gdip.Ok;
 
            try {
                Guid g = encoder.Clsid;
                bool saved = false;
 
                if (rawData != null) {
                    ImageCodecInfo rawEncoder = RawFormat.FindEncoder();
                    if (rawEncoder != null && rawEncoder.Clsid == g) {
                        stream.Write(rawData, 0, rawData.Length);
                        saved = true;
                    }
                }
 
                if (!saved) {
                    status = SafeNativeMethods.Gdip.GdipSaveImageToStream(new HandleRef(this, nativeImage),
                                                                     new UnsafeNativeMethods.ComStreamFromDataStream(stream),
                                                                     ref g,
                                                                     new HandleRef(encoderParams, encoderParamsMemory));
                }
            }
            finally {
                if (encoderParamsMemory != IntPtr.Zero) {
                    Marshal.FreeHGlobal(encoderParamsMemory);
                }
            }
            
            if (status != SafeNativeMethods.Gdip.Ok) {
                throw SafeNativeMethods.Gdip.StatusException(status);
            }
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.SaveAdd"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Adds an <see cref='System.Drawing.Imaging.EncoderParameters'/> to this
        ///    <see cref='System.Drawing.Image'/>.
        ///    </para>
        /// </devdoc>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly")]
        public void SaveAdd(EncoderParameters encoderParams) {
            IntPtr encoder = IntPtr.Zero;
            if (encoderParams != null) {
                encoder = encoderParams.ConvertToMemory();
            }
 
            rawData = null;
            int status = SafeNativeMethods.Gdip.GdipSaveAdd(new HandleRef(this, nativeImage), new HandleRef(encoderParams, encoder));
 
            if (encoder != IntPtr.Zero) {
                Marshal.FreeHGlobal(encoder);
            }
            if (status != SafeNativeMethods.Gdip.Ok) {
                throw SafeNativeMethods.Gdip.StatusException(status);
            }
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.SaveAdd1"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Adds an <see cref='System.Drawing.Imaging.EncoderParameters'/> to the
        ///       specified <see cref='System.Drawing.Image'/>.
        ///    </para>
        /// </devdoc>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly")]
        public void SaveAdd(Image image, EncoderParameters encoderParams) {
            IntPtr encoder = IntPtr.Zero;
 
            if (image == null) {
                throw new ArgumentNullException("image");
            }
            if (encoderParams != null) {
                encoder = encoderParams.ConvertToMemory();
            }
 
            rawData = null;
            int status = SafeNativeMethods.Gdip.GdipSaveAddImage(new HandleRef(this, nativeImage), new HandleRef(image, image.nativeImage), new HandleRef(encoderParams, encoder));
 
            if (encoder != IntPtr.Zero){
                Marshal.FreeHGlobal(encoder);
            }
            if (status != SafeNativeMethods.Gdip.Ok) {
                throw SafeNativeMethods.Gdip.StatusException(status);
            }
        }
 
        /**
         * Return; image size information
         */
        private SizeF _GetPhysicalDimension() {
            float width;
            float height;
 
            int status = SafeNativeMethods.Gdip.GdipGetImageDimension(new HandleRef(this, nativeImage), out width, out height);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            return new SizeF(width, height);
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.PhysicalDimension"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets the width and height of this
        ///    <see cref='System.Drawing.Image'/>.
        ///    </para>
        /// </devdoc>
        public SizeF PhysicalDimension {
            get { return _GetPhysicalDimension();}
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.Size"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets the width and height of this <see cref='System.Drawing.Image'/>.
        ///    </para>
        /// </devdoc>
        public Size Size {
            get {
                return new Size(Width, Height);
            }
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.Width"]/*' />
        /// <devdoc>
        ///    Gets the width of this <see cref='System.Drawing.Image'/>.
        /// </devdoc>
        [
        DefaultValue(false),
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public int Width {
            get {
                int width; 
 
                int status = SafeNativeMethods.Gdip.GdipGetImageWidth(new HandleRef(this, nativeImage), out width);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);
 
                return width;
            }
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.Height"]/*' />
        /// <devdoc>
        ///    Gets the height of this <see cref='System.Drawing.Image'/>.
        /// </devdoc>
        [
        DefaultValue(false),
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public int Height {
            get {
                int height; 
 
                int status = SafeNativeMethods.Gdip.GdipGetImageHeight(new HandleRef(this, nativeImage), out height);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);
 
                return height;
            }
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.HorizontalResolution"]/*' />
        /// <devdoc>
        ///    Gets the horizontal resolution, in
        ///    pixels-per-inch, of this <see cref='System.Drawing.Image'/>.
        /// </devdoc>
        public float HorizontalResolution {
            get {
                float horzRes; 
 
                int status = SafeNativeMethods.Gdip.GdipGetImageHorizontalResolution(new HandleRef(this, nativeImage), out horzRes);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);
 
                return horzRes;
            }
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.VerticalResolution"]/*' />
        /// <devdoc>
        ///    Gets the vertical resolution, in
        ///    pixels-per-inch, of this <see cref='System.Drawing.Image'/>.
        /// </devdoc>
        public float VerticalResolution {
            get {
                float vertRes; 
 
                int status = SafeNativeMethods.Gdip.GdipGetImageVerticalResolution(new HandleRef(this, nativeImage), out vertRes);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);
 
                return vertRes;
            }
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.Flags"]/*' />
        /// <devdoc>
        ///    Gets attribute flags for this <see cref='System.Drawing.Image'/>.
        /// </devdoc>
        [Browsable(false)]
        public int Flags {
            get {
                int flags; 
 
                int status = SafeNativeMethods.Gdip.GdipGetImageFlags(new HandleRef(this, nativeImage), out flags);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);
 
                return flags;
            }
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.RawFormat"]/*' />
        /// <devdoc>
        ///    Gets the format of this <see cref='System.Drawing.Image'/>.
        /// </devdoc>
        public ImageFormat RawFormat {
            get {
                Guid guid = new Guid();
 
                int status = SafeNativeMethods.Gdip.GdipGetImageRawFormat(new HandleRef(this, nativeImage), ref guid);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);
 
 
                return new ImageFormat(guid);
            }
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.PixelFormat"]/*' />
        /// <devdoc>
        ///    Gets the pixel format for this <see cref='System.Drawing.Image'/>.
        /// </devdoc>
        public PixelFormat PixelFormat {
            get {
                int format;
 
                int status = SafeNativeMethods.Gdip.GdipGetImagePixelFormat(new HandleRef(this, nativeImage), out format);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    return PixelFormat.Undefined;
                else
                    return(PixelFormat)format;
            }
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.GetBounds"]/*' />
        /// <devdoc>
        ///    Gets a bounding rectangle in
        ///    the specified units for this <see cref='System.Drawing.Image'/>.
        /// </devdoc>        
        [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")]
        public RectangleF GetBounds(ref GraphicsUnit pageUnit) {
            GPRECTF gprectf = new GPRECTF();
 
            int status = SafeNativeMethods.Gdip.GdipGetImageBounds(new HandleRef(this, nativeImage), ref gprectf, out pageUnit);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            return gprectf.ToRectangleF();
        }
 
        private ColorPalette _GetColorPalette() {
            int size = -1;
 
            int status = SafeNativeMethods.Gdip.GdipGetImagePaletteSize(new HandleRef(this, nativeImage), out size);
            // "size" is total byte size:
            // sizeof(ColorPalette) + (pal->Count-1)*sizeof(ARGB)
 
            if (status != SafeNativeMethods.Gdip.Ok) {
                throw SafeNativeMethods.Gdip.StatusException(status);
            }
 
            ColorPalette palette = new ColorPalette(size);
 
            // Memory layout is:
            //    UINT Flags
            //    UINT Count
            //    ARGB Entries[size]
 
            IntPtr memory = Marshal.AllocHGlobal(size);
 
            status = SafeNativeMethods.Gdip.GdipGetImagePalette(new HandleRef(this, nativeImage), memory, size);
 
            try {
                if (status != SafeNativeMethods.Gdip.Ok) {
                    throw SafeNativeMethods.Gdip.StatusException(status);
                }
 
                palette.ConvertFromMemory(memory);
            }
            finally {
                Marshal.FreeHGlobal(memory);
            }
 
            return palette;
        }
 
        private void _SetColorPalette(ColorPalette palette) {
            IntPtr memory = palette.ConvertToMemory();
 
            int status = SafeNativeMethods.Gdip.GdipSetImagePalette(new HandleRef(this, nativeImage), memory);
 
            if (memory != IntPtr.Zero) {
                Marshal.FreeHGlobal(memory);
            }
            if (status != SafeNativeMethods.Gdip.Ok) {
                throw SafeNativeMethods.Gdip.StatusException(status);
            }
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.Palette"]/*' />
        /// <devdoc>
        ///    Gets or sets the color
        ///    palette used for this <see cref='System.Drawing.Image'/>.
        /// </devdoc>
        [Browsable(false)]
        public ColorPalette Palette
        {
            get {
                return _GetColorPalette();
            }
            set {
                _SetColorPalette(value);
            }
        }
 
        // Thumbnail support
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.GetThumbnailImage"]/*' />
        /// <devdoc>
        ///    Returns the thumbnail for this <see cref='System.Drawing.Image'/>.
        /// </devdoc>
        public Image GetThumbnailImage(int thumbWidth, int thumbHeight, 
                                       GetThumbnailImageAbort callback, IntPtr callbackData) {
            IntPtr thumbImage = IntPtr.Zero;
 
            int status = SafeNativeMethods.Gdip.GdipGetImageThumbnail(new HandleRef(this, nativeImage), thumbWidth, thumbHeight, out thumbImage,
                                                       callback, callbackData);
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            return CreateImageObject(thumbImage);
        }
 
        // Multi-frame support
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.FrameDimensionsList"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Gets an array of GUIDs that represent the
        ///       dimensions of frames within this <see cref='System.Drawing.Image'/>.
        ///    </para>
        /// </devdoc>        
        [Browsable(false)]
        public Guid[] FrameDimensionsList {
            [SuppressMessage("Microsoft.Performance", "CA1808:AvoidCallsThatBoxValueTypes")]
            get {
                int count;
 
                int status = SafeNativeMethods.Gdip.GdipImageGetFrameDimensionsCount(new HandleRef(this, nativeImage), out count);
 
                if (status != SafeNativeMethods.Gdip.Ok) {
                    throw SafeNativeMethods.Gdip.StatusException(status);
                }
 
                Debug.Assert(count >= 0, "FrameDimensionsList returns bad count");                    
                if (count <= 0) {
                    return new Guid[0];
                }
 
                int size = (int) Marshal.SizeOf(typeof(Guid));
 
                IntPtr buffer = Marshal.AllocHGlobal(checked(size*count));
                if (buffer == IntPtr.Zero) {
                    throw SafeNativeMethods.Gdip.StatusException(SafeNativeMethods.Gdip.OutOfMemory);
                }
 
                status = SafeNativeMethods.Gdip.GdipImageGetFrameDimensionsList(new HandleRef(this, nativeImage), buffer, count);
 
                if (status != SafeNativeMethods.Gdip.Ok) {
                    Marshal.FreeHGlobal(buffer);
                    throw SafeNativeMethods.Gdip.StatusException(status);
                }
 
                Guid[] guids = new Guid[count];
 
                try {
                    for (int i=0; i<count; i++) {
                        guids[i] = (Guid) UnsafeNativeMethods.PtrToStructure((IntPtr)((long)buffer + size*i), typeof(Guid));
                    }
                }
                finally {
                    Marshal.FreeHGlobal(buffer);
                }
 
                return guids;
            }
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.GetFrameCount"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Returns the number of frames of the given
        ///       dimension.
        ///    </para>
        /// </devdoc>
        public int GetFrameCount(FrameDimension dimension) {
            int[] count = new int[] { 0};
 
            Guid dimensionID = dimension.Guid;
            int status = SafeNativeMethods.Gdip.GdipImageGetFrameCount(new HandleRef(this, nativeImage), ref dimensionID, count);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            return count[0];
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.SelectActiveFrame"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Selects the frame specified by the given
        ///       dimension and index.
        ///    </para>
        /// </devdoc>
        public int SelectActiveFrame(FrameDimension dimension, int frameIndex) {
            int[] count = new int[] { 0};
 
            Guid dimensionID = dimension.Guid;
            int status = SafeNativeMethods.Gdip.GdipImageSelectActiveFrame(new HandleRef(this, nativeImage), ref dimensionID, frameIndex);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            return count[0];
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.RotateFlip"]/*' />
        /// <devdoc>
        ///    <para>
        ///    </para>
        /// </devdoc>
        public void RotateFlip(RotateFlipType rotateFlipType) {
 
            int status = SafeNativeMethods.Gdip.GdipImageRotateFlip(new HandleRef(this, nativeImage), unchecked((int) rotateFlipType));
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.PropertyIdList"]/*' />
        /// <devdoc>
        ///    Gets an array of the property IDs stored in
        ///    this <see cref='System.Drawing.Image'/>.
        /// </devdoc>
        [Browsable(false)]
        public int[] PropertyIdList
        {
            get {
                int count;
 
                int status = SafeNativeMethods.Gdip.GdipGetPropertyCount(new HandleRef(this, nativeImage), out count);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);
 
                int[] propid = new int[count];
 
                //if we have a 0 count, just return our empty array
                if (count == 0)
                    return propid;
 
                status = SafeNativeMethods.Gdip.GdipGetPropertyIdList(new HandleRef(this, nativeImage), count, propid);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);
 
                return propid;    
            }
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.GetPropertyItem"]/*' />
        /// <devdoc>
        ///    Gets the specified property item from this
        /// <see cref='System.Drawing.Image'/>.
        /// </devdoc>
        public PropertyItem GetPropertyItem(int propid) {
            PropertyItem propitem;
            int size;
 
            int status = SafeNativeMethods.Gdip.GdipGetPropertyItemSize(new HandleRef(this, nativeImage), propid, out size);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            if (size == 0)
                return null;
 
            IntPtr propdata = Marshal.AllocHGlobal(size);
 
            if (propdata == IntPtr.Zero)
                throw SafeNativeMethods.Gdip.StatusException(SafeNativeMethods.Gdip.OutOfMemory);
 
            status = SafeNativeMethods.Gdip.GdipGetPropertyItem(new HandleRef(this, nativeImage), propid, size, propdata);
 
            try {
                if (status != SafeNativeMethods.Gdip.Ok) {
                    throw SafeNativeMethods.Gdip.StatusException(status);
                }
 
                propitem = PropertyItemInternal.ConvertFromMemory(propdata, 1)[0];
            }
            finally {
                Marshal.FreeHGlobal(propdata);
            }
 
            return propitem;
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.RemovePropertyItem"]/*' />
        /// <devdoc>
        ///    Removes the specified property item from
        ///    this <see cref='System.Drawing.Image'/>.
        /// </devdoc>
        public void RemovePropertyItem(int propid) {
            int status = SafeNativeMethods.Gdip.GdipRemovePropertyItem(new HandleRef(this, nativeImage), propid);
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.SetPropertyItem"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Sets the specified property item to the
        ///       specified value.
        ///    </para>
        /// </devdoc>
        public void SetPropertyItem(PropertyItem propitem) {
            PropertyItemInternal propItemInternal = PropertyItemInternal.ConvertFromPropertyItem(propitem);
 
            using (propItemInternal) {
                int status = SafeNativeMethods.Gdip.GdipSetPropertyItem(new HandleRef(this, nativeImage), propItemInternal);
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);
            }
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.PropertyItems"]/*' />
        /// <devdoc>
        ///    Gets an array of <see cref='System.Drawing.Imaging.PropertyItem'/> objects that describe this <see cref='System.Drawing.Image'/>.
        /// </devdoc>
        [Browsable(false)]
        public PropertyItem[] PropertyItems
        {
            get {
                int size;
                int count;
 
                int status = SafeNativeMethods.Gdip.GdipGetPropertyCount(new HandleRef(this, nativeImage), out count);               
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);
 
                status = SafeNativeMethods.Gdip.GdipGetPropertySize(new HandleRef(this, nativeImage), out size, ref count);
 
                if (status != SafeNativeMethods.Gdip.Ok)
                    throw SafeNativeMethods.Gdip.StatusException(status);
 
                if (size == 0 || count == 0)
                    return new PropertyItem[0];
 
                IntPtr propdata = Marshal.AllocHGlobal(size);
 
                status = SafeNativeMethods.Gdip.GdipGetAllPropertyItems(new HandleRef(this, nativeImage), size, count, propdata);
 
                PropertyItem[] props = null;
 
                try {
                    if (status != SafeNativeMethods.Gdip.Ok) {
                        throw SafeNativeMethods.Gdip.StatusException(status);
                    }
 
                    props = PropertyItemInternal.ConvertFromMemory(propdata, count);
                }
                finally {
                    Marshal.FreeHGlobal(propdata);
                }
 
                return props;
            }
        }
 
        internal void SetNativeImage(IntPtr handle) {
            if (handle == IntPtr.Zero)
                throw new ArgumentException(SR.GetString(SR.NativeHandle0), "handle");
 
            nativeImage = handle;
        }
 
        // !! Ambiguous to offer constructor for 'FromHbitmap'
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.FromHbitmap"]/*' />
        /// <devdoc>
        ///    Creates a <see cref='System.Drawing.Bitmap'/> from a Windows handle.
        /// </devdoc>
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static Bitmap FromHbitmap(IntPtr hbitmap) {
            IntSecurity.ObjectFromWin32Handle.Demand();
 
            return FromHbitmap(hbitmap, IntPtr.Zero);
        }
 
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.FromHbitmap1"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Creates a <see cref='System.Drawing.Bitmap'/> from the specified Windows
        ///       handle with the specified color palette.
        ///    </para>
        /// </devdoc>
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static Bitmap FromHbitmap(IntPtr hbitmap, IntPtr hpalette) {
            IntSecurity.ObjectFromWin32Handle.Demand();
 
            IntPtr bitmap = IntPtr.Zero;
            int status = SafeNativeMethods.Gdip.GdipCreateBitmapFromHBITMAP(new HandleRef(null, hbitmap), new HandleRef(null, hpalette), out bitmap);
 
            if (status != SafeNativeMethods.Gdip.Ok)
                throw SafeNativeMethods.Gdip.StatusException(status);
 
            return Bitmap.FromGDIplus(bitmap);
        }
 
        /*
         * Return the pixel size for the specified format (in bits)
         */
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.GetPixelFormatSize"]/*' />
        /// <devdoc>
        ///    Returns the size of the specified pixel
        ///    format.
        /// </devdoc>
        public static int GetPixelFormatSize(PixelFormat pixfmt) {
            return(unchecked((int)pixfmt) >> 8) & 0xFF;
        }
 
        /*
         * Determine if the pixel format can have alpha channel
         */
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.IsAlphaPixelFormat"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Returns a value indicating whether the
        ///       pixel format contains alpha information.
        ///    </para>
        /// </devdoc>
        public static bool IsAlphaPixelFormat(PixelFormat pixfmt) {
            return(pixfmt & PixelFormat.Alpha) != 0;
        }
 
        /*
         * Determine if the pixel format is an extended format,
         * i.e. supports 16-bit per channel
         */
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.IsExtendedPixelFormat"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Returns a value indicating whether the pixel format is extended.
        ///    </para>
        /// </devdoc>
        public static bool IsExtendedPixelFormat(PixelFormat pixfmt) {
            return(pixfmt & PixelFormat.Extended) != 0;
        }
 
        /*
         * Determine if the pixel format is canonical format:
         *   PixelFormat32bppARGB
         *   PixelFormat32bppPARGB
         *   PixelFormat64bppARGB
         *   PixelFormat64bppPARGB
         */
        /// <include file='doc\Image.uex' path='docs/doc[@for="Image.IsCanonicalPixelFormat"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Returns a value indicating whether the pixel format is canonical.
        ///    </para>
        /// </devdoc>
        public static bool IsCanonicalPixelFormat(PixelFormat pixfmt) {
            return(pixfmt & PixelFormat.Canonical) != 0;
        }
    }
}