BitmapSource.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / System / Windows / Media / Imaging / BitmapSource.cs / 3 / BitmapSource.cs

                            //------------------------------------------------------------------------------ 
//  Microsoft Avalon
//  Copyright (c) Microsoft Corporation, All Rights Reserved.
//
//  File: BitmapSource.cs 
//
//----------------------------------------------------------------------------- 
 
using System;
using System.IO; 
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Reflection; 
using MS.Internal;
using System.Diagnostics; 
using System.Windows.Media; 
using System.Globalization;
using System.Security; 
using System.Net;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using System.Windows.Media.Animation; 
using System.Windows.Media.Composition;
using MS.Win32; 
using System.IO.Packaging; 
using UnsafeNativeMethods=MS.Win32.PresentationCore.UnsafeNativeMethods;
using SR=MS.Internal.PresentationCore.SR; 
using SRID=MS.Internal.PresentationCore.SRID;
using MS.Internal.PresentationCore;                        // SecurityHelper

namespace System.Windows.Media.Imaging 
{
    #region BitmapSource 
 
    /// 
    /// Interface for Bitmap Sources, included decoders and effects 
    /// 
    [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)]
    public abstract class BitmapSource : ImageSource, DUCE.IResource
    { 
        #region Constructor
 
        ///  
        /// Create a BitmapSource from an array of pixels.
        ///  
        /// Width of the Bitmap
        /// Height of the Bitmap
        /// Horizontal DPI of the Bitmap
        /// Vertical DPI of the Bitmap 
        /// Format of the Bitmap
        /// Palette of the Bitmap 
        /// Array of pixels 
        /// stride
        public static BitmapSource Create( 
            int pixelWidth,
            int pixelHeight,
            double dpiX,
            double dpiY, 
            PixelFormat pixelFormat,
            Imaging.BitmapPalette palette, 
            System.Array pixels, 
            int stride
            ) 
        {
            return new CachedBitmap(
                        pixelWidth, pixelHeight,
                        dpiX, dpiY, 
                        pixelFormat, palette,
                        pixels, stride); 
        } 

 
        /// 
        /// Create a BitmapSource from an array of pixels in unmanaged memory.
        /// 
        /// Width of the Bitmap 
        /// Height of the Bitmap
        /// Horizontal DPI of the Bitmap 
        /// Vertical DPI of the Bitmap 
        /// Format of the Bitmap
        /// Palette of the Bitmap 
        /// Pointer to the buffer in memory
        /// Size of the buffer
        /// stride
        ///  
        ///     Callers must have UnmanagedCode permission to call this API.
        ///  
        ///  
        /// Critical - access critical code, accepts pointer arguments
        /// PublicOK - demands unmanaged code permission 
        /// 
        [SecurityCritical]
        unsafe public static BitmapSource Create(
            int pixelWidth, 
            int pixelHeight,
            double dpiX, 
            double dpiY, 
            PixelFormat pixelFormat,
            Imaging.BitmapPalette palette, 
            IntPtr buffer,
            int bufferSize,
            int stride
            ) 
        {
            SecurityHelper.DemandUnmanagedCode(); 
 
            return new CachedBitmap(
                        pixelWidth, pixelHeight, 
                        dpiX, dpiY,
                        pixelFormat, palette,
                        buffer, bufferSize, stride);
        } 

 
        ///  
        /// Constructor
        ///  
        /// 
        /// Critical: Accesses _wicSource
        /// TreatAsSafe: Inputs are safe
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        protected BitmapSource() 
        { 
            // Synchronize for *this* object only by default.
            _syncObject = _bitmapInit; 
            _isSourceCached = false;
        }

        ///  
        /// Internal Constructor
        /// 
        /// useVirtuals: Should properties and methods like PixelWidth and CopyPixels use their "default" implementation. 
        /// 
        ///  
        /// Critical: Accesses _wicSource
        /// TreatAsSafe: Input (bool) is safe
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal BitmapSource(bool useVirtuals)
        { 
            _useVirtuals = true; 
            _isSourceCached = false;
 
            // Synchronize for *this* object only by default.
            _syncObject = _bitmapInit;
        }
 
        /// 
        /// Creates a copy of this object. 
        ///  
        /// The copy.
        public new BitmapSource Clone() 
        {
            return (BitmapSource) base.Clone();
        }
 
        /// 
        /// Shadows inherited CloneCurrentValue() with a strongly typed version for convenience. 
        ///  
        /// The copy.
        public new BitmapSource CloneCurrentValue() 
        {
            return (BitmapSource) base.CloneCurrentValue();
        }
 
        #endregion Constructor
 
        #region Public properties and methods 

        ///  
        /// Native format of the bitmap's data.
        /// If the BitmapSource is directly readable, this is the format the
        /// pixels will be in when they are read.
        ///  
        public virtual System.Windows.Media.PixelFormat Format
        { 
            get 
            {
                ReadPreamble(); 
                EnsureShouldUseVirtuals();
                _bitmapInit.EnsureInitializedComplete();
                CompleteDelayedCreation();
 
                return _format;
            } 
        } 

        ///  
        /// Width, in pixels, of the bitmap.
        /// 
        public virtual int PixelWidth
        { 
            get
            { 
                ReadPreamble(); 
                EnsureShouldUseVirtuals();
                _bitmapInit.EnsureInitializedComplete(); 
                CompleteDelayedCreation();

                return _pixelWidth;
            } 
        }
 
        ///  
        /// Height, in pixels, of the bitmap.
        ///  
        public virtual int PixelHeight
        {
            get
            { 
                ReadPreamble();
                EnsureShouldUseVirtuals(); 
                _bitmapInit.EnsureInitializedComplete(); 
                CompleteDelayedCreation();
 
                return _pixelHeight;
            }
        }
 

        ///  
        /// Horizontal DPI of the bitmap. 
        /// 
        public virtual double DpiX 
        {
            get
            {
                ReadPreamble(); 
                EnsureShouldUseVirtuals();
                _bitmapInit.EnsureInitializedComplete(); 
                CompleteDelayedCreation(); 

                return _dpiX; 
            }
        }

 
        /// 
        /// Vertical DPI of the bitmap. 
        ///  
        public virtual double DpiY
        { 
            get
            {
                ReadPreamble();
                EnsureShouldUseVirtuals(); 
                _bitmapInit.EnsureInitializedComplete();
                CompleteDelayedCreation(); 
 
                return _dpiY;
            } 
        }

        /// 
        /// Retrieve and set the bitmap palette. 
        /// 
        ///  
        ///     Critical: This calls into PixelFormat.InternalBitsPerPixel getter, which is critical 
        ///     PublicOK: It's safe because it doesn't return the BitsPerPixel value to the user
        ///  
        public virtual Imaging.BitmapPalette Palette
        {
            [SecurityCritical ]
            get 
            {
                ReadPreamble(); 
                EnsureShouldUseVirtuals(); 
                _bitmapInit.EnsureInitializedComplete();
                CompleteDelayedCreation(); 

                if (_palette == null)
                {
                    // update the local palette 
                    if (_format.Palettized)
                    { 
                        int colorCount = 1 << _format.InternalBitsPerPixel; 

                        _palette = Imaging.BitmapPalette.CreateFromBitmapSource(this); 
                    }

                }
 
                return _palette;
            } 
        } 

        ///  
        /// Returns true if the BitmapSource is downloading content
        /// 
        public virtual bool IsDownloading
        { 
            get
            { 
                ReadPreamble(); 
                EnsureShouldUseVirtuals();
                return false; 
            }
        }

        ///  
        /// Raised when downloading content is done
        /// May not be raised for all content. 
        ///  
        public virtual event EventHandler DownloadCompleted
        { 
            add
            {
                WritePreamble();
                EnsureShouldUseVirtuals(); 
                _downloadEvent.AddEvent(value);
            } 
            remove 
            {
                WritePreamble(); 
                EnsureShouldUseVirtuals();
                _downloadEvent.RemoveEvent(value);
            }
        } 

        ///  
        /// Raised when download has progressed 
        /// May not be raised for all content.
        ///  
        public virtual event EventHandler DownloadProgress
        {
            add
            { 
                WritePreamble();
                EnsureShouldUseVirtuals(); 
                _progressEvent.AddEvent(value); 
            }
            remove 
            {
                WritePreamble();
                EnsureShouldUseVirtuals();
                _progressEvent.RemoveEvent(value); 
            }
        } 
 
        /// 
        /// Raised when download has failed 
        /// May not be raised for all content.
        /// 
        public virtual event EventHandler DownloadFailed
        { 
            add
            { 
                WritePreamble(); 
                EnsureShouldUseVirtuals();
                _failedEvent.AddEvent(value); 
            }
            remove
            {
                WritePreamble(); 
                EnsureShouldUseVirtuals();
                _failedEvent.RemoveEvent(value); 
            } 
        }
 
        /// 
        /// Raised when decoding has failed
        /// May not be raised for all content.
        ///  
        public virtual event EventHandler DecodeFailed
        { 
            add 
            {
                WritePreamble(); 
                EnsureShouldUseVirtuals();
                _decodeFailedEvent.AddEvent(value);
            }
            remove 
            {
                WritePreamble(); 
                EnsureShouldUseVirtuals(); 
                _decodeFailedEvent.RemoveEvent(value);
            } 
        }


        ///  
        /// Copy the pixel data from the bitmap into the array of pixels that
        /// has the specified stride, starting at the offset (specified in number 
        /// of pixels from the beginning). An empty rect (all 0s) will copy the 
        /// entire bitmap.
        ///  
        /// Source rect to copy. Int32Rect.Empty specifies the entire rect
        /// Destination array
        /// Stride
        /// Offset in the array to begin copying 
        /// 
        ///     Critical: This code can be used to expose pixel information 
        ///     PublicOk: There is an inheritance demand to prevent sub classing and there is 
        ///     a web permission demand to prevent non site of origin requests
        ///  
        [SecurityCritical]
        [SecurityPermission(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public virtual void CopyPixels(Int32Rect sourceRect, Array pixels, int stride, int offset)
        { 

            EnsureShouldUseVirtuals(); 
 
            // Demand Site Of origin on the URI if it passes then this  information is ok to expose
            CheckIfSiteOfOrigin(); 

            CriticalCopyPixels(sourceRect, pixels, stride, offset);
        }
 
        /// 
        /// Copy the pixel data from the bitmap into the array of pixels that 
        /// has the specified stride, starting at the offset (specified in number 
        /// of pixels from the beginning).
        ///  
        /// Destination array
        /// Stride
        /// Offset to begin at
        ///  
        ///     Critical: This code can be used to expose pixel information
        ///     PublicOk: There is an inheritance demand to prevent sub classing and there is 
        ///     a web permission demand to prevent non site of origin requests 
        /// 
        [SecurityCritical] 
        [SecurityPermission(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public virtual void CopyPixels(Array pixels, int stride, int offset)
        {
            Int32Rect sourceRect = Int32Rect.Empty; 
            EnsureShouldUseVirtuals();
 
            // Demand Site Of origin on the URI if it passes then this  information is ok to expose 
            CheckIfSiteOfOrigin();
 
            CopyPixels(sourceRect, pixels, stride, offset);
        }

        ///  
        /// Copy the pixel data from the bitmap into the array of pixels that
        /// has the specified stride, starting at the offset (specified in number 
        /// of pixels from the beginning). An empty rect (all 0s) will copy the 
        /// entire bitmap.
        ///  
        /// Source rect to copy. Int32Rect.Empty specified entire Bitmap
        /// Pointer to the buffer
        /// Size of buffer
        /// Stride 
        /// 
        ///     Critical: This code can be used to expose pixel information 
        ///     PublicOk: There is an inheritance demand to prevent sub classing and there is 
        ///     a web permission demand to prevent non site of origin requests
        ///  
        [SecurityCritical]
        [SecurityPermission(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public virtual void CopyPixels(Int32Rect sourceRect, IntPtr buffer, int bufferSize, int stride) 
        {
            ReadPreamble(); 
            EnsureShouldUseVirtuals(); 
            _bitmapInit.EnsureInitializedComplete();
            CompleteDelayedCreation(); 

            // Demand Site Of origin on the URI if it passes then this  information is ok to expose
            CheckIfSiteOfOrigin();
 
            CriticalCopyPixels(sourceRect, buffer, bufferSize, stride);
        } 
 
        /// 
        /// Get the width of the bitmap in measure units (96ths of an inch). 
        /// 
        public override double Width
        {
            get 
            {
                ReadPreamble(); 
 
                return GetWidthInternal();
            } 
        }

        /// 
        /// Get the width of the bitmap in measure units (96ths of an inch). 
        /// 
        public override double Height 
        { 
            get
            { 
                ReadPreamble();

                return GetHeightInternal();
            } 
        }
 
        ///  
        /// Get the Metadata of the bitmap
        ///  
        public override ImageMetadata Metadata
        {
            get
            { 
                ReadPreamble();
 
                return null; 
            }
        } 

        #endregion

        #region Internal, Protected and Private properties and methods 

        ///  
        /// Helper function to calculate Width. 
        /// 
        private double GetWidthInternal() 
        {
            return PixelsToDIPs(this.DpiX, this.PixelWidth);
        }
 
        /// 
        /// Helper function to calculate Height. 
        ///  
        private double GetHeightInternal()
        { 
            return PixelsToDIPs(this.DpiY, this.PixelHeight);
        }

        ///  
        /// Get the Size for the bitmap
        ///  
        internal override Size Size 
        {
            get 
            {
                ReadPreamble();

                return new Size(Math.Max(0, GetWidthInternal()), 
                                Math.Max(0, GetHeightInternal()));
            } 
        } 

        internal bool DelayCreation 
        {
            get
            {
                return _delayCreation; 
            }
            set 
            { 
                _delayCreation = value;
 
                if (_delayCreation)
                {
                    CreationCompleted = false;
                } 
            }
        } 
 
        internal bool CreationCompleted
        { 
            get
            {
                return _creationComplete;
            } 
            set
            { 
                _creationComplete = value; 
            }
        } 

        ///
        /// Demand that the bitmap should be created if it was delay-created.
        /// 
        internal void CompleteDelayedCreation()
        { 
            // Protect against multithreaded contention on delayed creation. 
            if (DelayCreation)
            { 
                lock (_syncObject)
                {
                    if (DelayCreation)
                    { 
                        EnsureShouldUseVirtuals();
 
                        DelayCreation = false; 

                        FinalizeCreation(); 

                        CreationCompleted = true;
                    }
                } 
            }
        } 
 
        internal virtual void FinalizeCreation()
        { 
            throw new NotImplementedException();
        }

        internal virtual Int32Rect GetUpdateRect() 
        {
            throw new NotImplementedException(); 
        } 

        private void EnsureShouldUseVirtuals() 
        {
            if (_useVirtuals == false)
            {
                throw new NotImplementedException(); 
            }
        } 
 
        internal object SyncObject
        { 
            get
            {
                Debug.Assert(_syncObject != null);
                return _syncObject; 
            }
        } 
 
        internal bool IsSourceCached
        { 
            get
            {
                return _isSourceCached;
            } 
            set
            { 
                _isSourceCached = value; 
            }
        } 

        /// 
        /// Critical - access safehandle that points to unmanaged resource
        /// TreatAsSafe - Set: Its safe because any value is OK as the SafeHandle cannot be created 
        ///                    by an arbitrary IntPtr.
        ///  
        internal BitmapSourceSafeMILHandle WicSourceHandle 
        {
            [SecurityCritical] 
            get
            {
                CompleteDelayedCreation();
                if (_wicSource == null || _wicSource.IsInvalid) 
                {
                    ManagedBitmapSource managedBitmapSource = new ManagedBitmapSource(this); 
                    _wicSource = new BitmapSourceSafeMILHandle(Marshal.GetComInterfaceForObject( 
                            managedBitmapSource,
                            typeof(System.Windows.Media.Imaging.BitmapSource.IWICBitmapSource))); 
                }

                return _wicSource;
            } 
            [SecurityCritical, SecurityTreatAsSafe]
            set 
            { 
                if (value != null)
                { 
                    IntPtr wicSource = IntPtr.Zero;
                    Guid _uuidWicBitmapSource = MILGuidData.IID_IWICBitmapSource;
                    HRESULT.Check(UnsafeNativeMethods.MILUnknown.QueryInterface(
                        value, 
                        ref _uuidWicBitmapSource,
                        out wicSource) ); 
 
                    _wicSource = new BitmapSourceSafeMILHandle(wicSource);
                    UpdateCachedSettings(); 
                }
                else
                    _wicSource = null;
            } 
        }
 
        /// 
        /// Update local variables from the unmanaged resource
        /// 
        /// 
        /// Critical - access/creates critical resources
        /// 
        [SecurityCritical] 
        internal virtual void UpdateCachedSettings()
        { 
            EnsureShouldUseVirtuals(); 

            uint pw, ph; 

            lock (_syncObject)
            {
                _format = PixelFormat.GetPixelFormat(_wicSource); 

                HRESULT.Check(UnsafeNativeMethods.WICBitmapSource.GetSize( 
                    _wicSource, 
                    out pw,
                    out ph)); 

                HRESULT.Check(UnsafeNativeMethods.WICBitmapSource.GetResolution(
                    _wicSource,
                    out _dpiX, 
                    out _dpiY));
            } 
 
            _pixelWidth = (int)pw;
            _pixelHeight = (int)ph; 
        }

        /// 
        /// CriticalCopyPixels 
        /// 
        ///  
        ///  
        /// 
        ///  
        /// 
        ///     Critical: This code can be used to expose pixel information
        /// 
        [SecurityCritical] 
        [FriendAccessAllowed] // Built into Core, also used by Framework.
        unsafe internal void CriticalCopyPixels(Int32Rect sourceRect, Array pixels, int stride, int offset) 
        { 
            ReadPreamble();
            _bitmapInit.EnsureInitializedComplete(); 
            CompleteDelayedCreation();

            if (pixels == null)
                throw new System.ArgumentNullException("pixels"); 

            if (pixels.Rank != 1) 
                throw new ArgumentException (SR.Get (SRID.Collection_BadRank), "pixels"); 

            int elementSize = -1; 

            if (pixels is byte[])
                elementSize = 1;
            else if (pixels is short[] || pixels is ushort[]) 
                elementSize = 2;
            else if (pixels is int[] || pixels is uint[] || pixels is float[]) 
                elementSize = 4; 
            else if (pixels is double[])
                elementSize = 8; 

            if (elementSize == -1)
                throw new ArgumentException(SR.Get(SRID.Image_InvalidArrayForPixel));
 
            int destBufferSize = elementSize * (pixels.Length - offset);
 
 
            if (pixels is byte[])
            { 
                fixed(void * pixelArray = &((byte[])pixels)[offset])
                    CriticalCopyPixels(sourceRect, (IntPtr)pixelArray, destBufferSize, stride);
            }
            else if (pixels is short[]) 
            {
                fixed(void * pixelArray = &((short[])pixels)[offset]) 
                    CriticalCopyPixels(sourceRect, (IntPtr)pixelArray, destBufferSize, stride); 
            }
            else if (pixels is ushort[]) 
            {
                fixed(void * pixelArray = &((ushort[])pixels)[offset])
                    CriticalCopyPixels(sourceRect, (IntPtr)pixelArray, destBufferSize, stride);
            } 
            else if (pixels is int[])
            { 
                fixed(void * pixelArray = &((int[])pixels)[offset]) 
                    CriticalCopyPixels(sourceRect, (IntPtr)pixelArray, destBufferSize, stride);
            } 
            else if (pixels is uint[])
            {
                fixed(void * pixelArray = &((uint[])pixels)[offset])
                    CriticalCopyPixels(sourceRect, (IntPtr)pixelArray, destBufferSize, stride); 
            }
            else if (pixels is float[]) 
            { 
                fixed(void * pixelArray = &((float[])pixels)[offset])
                    CriticalCopyPixels(sourceRect, (IntPtr)pixelArray, destBufferSize, stride); 
            }
            else if (pixels is double[])
            {
                fixed(void * pixelArray = &((double[])pixels)[offset]) 
                    CriticalCopyPixels(sourceRect, (IntPtr)pixelArray, destBufferSize, stride);
            } 
 
        }
 
        /// 
        /// CriticalCopyPixels
        /// 
        ///  
        /// 
        ///  
        ///  
        /// 
        ///     Critical: This code can be used to expose pixel information 
        /// 
        [SecurityCritical]
        private void CriticalCopyPixels(Int32Rect sourceRect, IntPtr buffer, int bufferSize, int stride)
        { 
            if ( buffer == IntPtr.Zero )
                throw new ArgumentNullException("buffer"); 
 
            if ( stride <= 0 )
                throw new ArgumentOutOfRangeException("stride", SR.Get(SRID.ParameterMustBeGreaterThanZero)); 

            if ( sourceRect.Width <= 0 )
                sourceRect.Width = PixelWidth;
 
            if ( sourceRect.Height <= 0 )
                sourceRect.Height = PixelHeight; 
 
            if ( sourceRect.Width > PixelWidth )
                throw new ArgumentOutOfRangeException("sourceRect.Width", SR.Get(SRID.ParameterCannotBeGreaterThan, PixelWidth)); 

            if ( sourceRect.Height > PixelHeight )
                throw new ArgumentOutOfRangeException("sourceRect.Height", SR.Get(SRID.ParameterCannotBeGreaterThan, PixelHeight));
 
            int minStride = ((sourceRect.Width * Format.BitsPerPixel) + 7) / 8;
            if ( stride < minStride ) 
                throw new ArgumentOutOfRangeException("stride", SR.Get(SRID.ParameterCannotBeLessThan, minStride)); 

            int minRequiredDestSize = (stride * (sourceRect.Height - 1)) + minStride; 
            if ( bufferSize < minRequiredDestSize )
                throw new ArgumentOutOfRangeException("buffer", SR.Get(SRID.ParameterCannotBeLessThan, minRequiredDestSize));

            lock ( _syncObject ) 
            {
                HRESULT.Check(UnsafeNativeMethods.WICBitmapSource.CopyPixels( 
                    WicSourceHandle, 
                    ref sourceRect,
                    (uint)stride, 
                    (uint)bufferSize,
                    buffer
                    ));
            } 
        }
 
        ///  
        ///     Critical: This code is used to check and grant access to pixel data
        ///     TreatAsSafe: This code does not elevate 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        protected void CheckIfSiteOfOrigin()
        { 
            string uri = null;
 
            // This call is inheritance demand protected. It is overridden in 
            // BitmapFrameDecoder and BitmapImage
            if (CanSerializeToString()) 
            {
                // This call returns the URI either as an absolute URI which the user
                // passed in, in the first place or as the string "image"
                // we only allow this code to succeed in the case of Uri and if it is site of 
                // origin or pack:. In all other conditions we fail
                uri = ConvertToString(null,null); 
            } 

            SecurityHelper.DemandMediaAccessPermission(uri); 
        }

        private double PixelsToDIPs(double dpi, int pixels)
        { 
            // Obtain the natural size in MIL Device Independant Pixels (DIPs, or 1/96") of the bitmap.
            // This is: (Bitmap Pixels) / (Bitmap DotsPerInch) * (DIPs per inch) 
 
            float dpif = (float)dpi;
 
            // To be consistent with BitmapBrush
            //
            // Floating-point precision is used to maintain consistent
            // logic with BitmapBrush DPI scaling, which is implemented in 
            // unmanaged code using single-precision math.  Any changes to
            // this logic must also be updated in the UCE BitmapBrush 
            // resource to maintain this consistency. 

            if (dpif < 0.0F || FloatUtil.IsCloseToDivideByZero(96.0F, dpif)) 
            {
                dpif = 96.0F;
            }
 
            return (double)(pixels * (96.0F / dpif));
        } 
 
        /// 
        /// Called when DUCE resource requires updating 
        /// 
        /// 
        /// Critical - access critical resource _convertedDUCEMILPtr
        /// TreatAsSafe - All inputs verified 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal override void UpdateResource(DUCE.Channel channel, bool skipOnChannelCheck) 
        {
            UpdateBitmapSourceResource(channel, skipOnChannelCheck); 
        }

        /// 
        /// Critical - access/create critical resource, returns unmanaged pointer 
        /// 
        internal virtual BitmapSourceSafeMILHandle DUCECompatibleMILPtr 
        { 
            [SecurityCritical]
            get 
            {
                Guid guidMILBs = MILGuidData.IID_IMILBitmapSource;
                BitmapSourceSafeMILHandle /* IWICBitmapSource */ pIWICSource = WicSourceHandle;
                IntPtr pIMILSource = IntPtr.Zero; 

                // if we've already cached the MILPtr, reuse it. 
                if (_convertedDUCEMILPtr != null && !_convertedDUCEMILPtr.IsInvalid) 
                {
                    // already in friendly format 
                    Debug.Assert(_isSourceCached);

                    // In the case that the BitmapSource is writeable, assert that the
                    // WicSource and DUCE pointer are different 
                    if (_isWriteable)
                    { 
                        Debug.Assert(_wicSource != _convertedDUCEMILPtr); 
                    }
                } 
                else
                {
                    bool supportedFormatAndWritable = (Array.IndexOf(s_supportedDUCEFormats, Format) != -1) && !_isWriteable;
 
                    if (supportedFormatAndWritable && _isSourceCached)
                    { 
                        #region Make sure the image is decoded on the UI thread 

                        // In the case that the source is cached (ie it is already an IWICBitmap), 
                        // its possible that the bitmap is a demand bitmap. The demand bitmap only
                        // copies the source bits when absolutely required (ie CopyPixels). This means
                        // that if a decode frame is attached to the demand bitmap, it may decode bits
                        // on the render thread (bad!). To prevent that, we call CopyPixels for the first 
                        // pixel which will decode the entire image.
                        // 
                        // Ideally, we need an implementation of IWICBitmap that can cache on a scanline 
                        // basis as well can be forced to "realize" its cache when requested. Consider
                        // adding a method on IWICBitmap such as RealizeCache(WICRect *). 
                        //
                        Int32Rect sourceRect = new Int32Rect(0, 0, 1, 1);
                        PixelFormat format = Format;
                        int bufferSize = (format.BitsPerPixel + 7) / 8; 
                        byte[] buffer = new byte[bufferSize];
 
                        // If the bitmap has corrupt pixel data, we may not have detected it until now. 
                        // At this point the user cannot recover gracefully, so we'll display a 1x1 image
                        // similar to what LateBoundDecoder does before it's done downloading. 

                        try
                        {
                            unsafe 
                            {
                                fixed (void* pixelArray = &((byte[])buffer)[0]) 
                                { 
                                    HRESULT.Check(UnsafeNativeMethods.WICBitmapSource.CopyPixels(
                                        pIWICSource, 
                                        ref sourceRect,
                                        (uint)bufferSize,
                                        (uint)bufferSize,
                                        (IntPtr)pixelArray 
                                        ));
                                } 
                            } 
                        }
                        catch (Exception e) 
                        {
                            RecoverFromDecodeFailure(e);

                            // the source will change during recovery, so we need to grab its new value 
                            pIWICSource = WicSourceHandle;
                        } 
 
                        #endregion
                    } 
                    else // needs caching
                    {
                        BitmapSourceSafeMILHandle pIWicConverter = null;
 
                        using (FactoryMaker factoryMaker = new FactoryMaker())
                        { 
                            try 
                            {
                                if (!supportedFormatAndWritable) 
                                {
                                    #region Convert the source to a compatible format that's writable

                                    Guid destFmt = GetClosestDUCEFormat(Format, Palette).Guid; 

                                    // This forces a cached system memory copy of the image in PARGB32 format.  This is 
                                    // necessary to avoid format conversion in the UCE during render and accompanying 
                                    // sychronization locks with UI thread during bitmap access.
 
                                    HRESULT.Check(UnsafeNativeMethods.WICImagingFactory.CreateFormatConverter(
                                        factoryMaker.ImagingFactoryPtr,
                                        out pIWicConverter));
 
                                    HRESULT.Check(UnsafeNativeMethods.WICFormatConverter.Initialize(
                                        pIWicConverter, 
                                        pIWICSource, 
                                        ref destFmt,
                                        DitherType.DitherTypeNone, 
                                        new SafeMILHandle(IntPtr.Zero, 0),
                                        0,
                                        WICPaletteType.WICPaletteTypeCustom));
 
                                    pIWICSource = pIWicConverter;
 
                                    #endregion 
                                }
 
                                #region Cache the source in memory to ensure it's not decoded/converted on the render thread

                                HRESULT.Check(UnsafeNativeMethods.WICImagingFactory.CreateBitmapFromSource(
                                        factoryMaker.ImagingFactoryPtr, 
                                        pIWICSource,
                                        WICBitmapCreateCacheOptions.WICBitmapCacheOnLoad, 
                                        out pIWICSource)); 

                                _isSourceCached = true; 

                                #endregion
                            }
                            finally 
                            {
                                if (pIWicConverter != null) 
                                    pIWicConverter.Close(); 
                            }
                        } 
                    }

                    HRESULT.Check(UnsafeNativeMethods.MILUnknown.QueryInterface(
                        pIWICSource, 
                        ref guidMILBs,
                        out pIMILSource)); 
 
                    _convertedDUCEMILPtr = new BitmapSourceSafeMILHandle(pIMILSource);
                } 

                return _convertedDUCEMILPtr;
            }
        } 

        internal override DUCE.ResourceHandle AddRefOnChannelCore(DUCE.Channel channel) 
        { 
            if (_duceResource.CreateOrAddRefOnChannel(channel, DUCE.ResourceType.TYPE_BITMAPSOURCE))
            { 
                UpdateBitmapSourceResource(channel, true /* skip "on channel" check - we already know that we're on channel */ );
            }

            return _duceResource.GetHandle(channel); 
        }
 
        DUCE.ResourceHandle DUCE.IResource.AddRefOnChannel(DUCE.Channel channel) 
        {
            // Reconsider the need for this lock when removing the MultiChannelResource. 
            using (CompositionEngineLock.Acquire())
            {
                return AddRefOnChannelCore(channel);
            } 
        }
 
        internal override int GetChannelCountCore() 
        {
            return _duceResource.GetChannelCount(); 
        }

        int DUCE.IResource.GetChannelCount()
        { 
            return GetChannelCountCore();
        } 
 
        internal override DUCE.Channel GetChannelCore(int index)
        { 
            return _duceResource.GetChannel(index);
        }

        DUCE.Channel DUCE.IResource.GetChannel(int index) 
        {
            return GetChannelCore(index); 
        } 

        ///  
        /// SecurityCritical: This code calls critical code SendCommandBitmapSource
        /// SecurityTreatAsSafe: The code called into demands
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal void UpdateBitmapSourceResource(DUCE.Channel channel, bool skipOnChannelCheck)
        { 
            Int32Rect updateRect = Int32Rect.Empty; 

            if (_needsUpdate) 
            {
                _convertedDUCEMILPtr = null;
                _needsUpdate = false;
            } 

            if (_isWriteable) 
            { 
                updateRect = GetUpdateRect();
            } 

            // If we're told we can skip the channel check, then we must be on channel
            Debug.Assert(!skipOnChannelCheck || _duceResource.IsOnChannel(channel));
 
            if (skipOnChannelCheck || _duceResource.IsOnChannel(channel))
            { 
                base.UpdateResource(channel, skipOnChannelCheck); 

                // We may end up loading in the bitmap bits so it's necessary to take the sync lock here. 
                lock (_syncObject)
                {
                    channel.SendCommandBitmapSource(
                        _duceResource.GetHandle(channel), 
                        DUCECompatibleMILPtr,
                        true, 
                        true); 
                }
            } 
        }

        /// 
        /// Called when a failure to decode is detected. 
        /// 
        ///  
        /// Critical - access critical resource WicSourceHandle 
        /// TreatAsSafe - All inputs verified
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal void RecoverFromDecodeFailure(Exception e)
        {
            // Set the source to an empty image in case the user doesn't respond to the failed event 
            byte[] pixels = new byte[4];
            WicSourceHandle = Create(1, 1, 96, 96, PixelFormats.Pbgra32, null, pixels, 4).WicSourceHandle; 
            IsSourceCached = true; 

            // Let the user know that we've failed to decode so they can gracefully handle the failure. 
            // Typically, the user would replace this image with a "failure" image
            OnDecodeFailed(this, new ExceptionEventArgs(e));
        }
 
        internal override void ReleaseOnChannelCore(DUCE.Channel channel)
        { 
            Debug.Assert(_duceResource.IsOnChannel(channel)); 

            _duceResource.ReleaseOnChannel(channel); 
        }

        void DUCE.IResource.ReleaseOnChannel(DUCE.Channel channel)
        { 
            //
            using (CompositionEngineLock.Acquire()) 
            { 
                ReleaseOnChannelCore(channel);
            } 
        }

        internal override DUCE.ResourceHandle GetHandleCore(DUCE.Channel channel)
        { 
            return _duceResource.GetHandle(channel);
        } 
 
        DUCE.ResourceHandle DUCE.IResource.GetHandle(DUCE.Channel channel)
        { 
            using (CompositionEngineLock.Acquire())
            {
                return GetHandleCore(channel);
            } 
        }
 
        /// Returns the closest format that is supported by the rendering engine 
        /// 
        /// Critical - access a property that accesses unmanaged code 
        /// TreatAsSafe - inputs are safe and trusted, does not expose information from the property
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal static PixelFormat GetClosestDUCEFormat(PixelFormat format, BitmapPalette palette) 
        {
            int i = Array.IndexOf(s_supportedDUCEFormats, format); 
 
            if (i != -1)
            { 
                return (PixelFormat)s_supportedDUCEFormats.GetValue(i);
            }

            int bitsPerPixel = format.InternalBitsPerPixel; 

            if (bitsPerPixel == 1) 
            { 
                return PixelFormats.Indexed1;
            } 
            else if (bitsPerPixel == 2)
            {
                return PixelFormats.Indexed2;
            } 
            else if (bitsPerPixel <= 4)
            { 
                return PixelFormats.Indexed4; 
            }
            else if (bitsPerPixel <= 8) 
            {
                return PixelFormats.Indexed8;
            }
            else if (bitsPerPixel <= 16 && format.Format != PixelFormatEnum.Gray16)     // For Gray16, one of the RGB Formats is closest 
            {
                return PixelFormats.Bgr555; 
            } 
            else if (format.HasAlpha || BitmapPalette.DoesPaletteHaveAlpha(palette))
            { 
                return PixelFormats.Pbgra32;
            }
            else
            { 
                return PixelFormats.Bgr32;
            } 
        } 

        /// Creates a IWICBitmap 
        /// 
        /// Critical - access critical resource
        /// 
        [SecurityCritical] 
        internal static BitmapSourceSafeMILHandle CreateCachedBitmap(
            BitmapFrame frame, 
            BitmapSourceSafeMILHandle wicSource, 
            BitmapCreateOptions createOptions,
            BitmapCacheOption cacheOption, 
            BitmapPalette palette
            )
        {
            BitmapSourceSafeMILHandle wicConverter = null; 
            BitmapSourceSafeMILHandle wicConvertedSource = null;
 
            // For NoCache, return the original 
            if (cacheOption == BitmapCacheOption.None)
            { 
                return wicSource;
            }

            using (FactoryMaker factoryMaker = new FactoryMaker()) 
            {
                IntPtr wicFactory = factoryMaker.ImagingFactoryPtr; 
                bool changeFormat = false; 
                PixelFormat originalFmt = PixelFormats.Pbgra32;
 
                WICBitmapCreateCacheOptions wicCache = WICBitmapCreateCacheOptions.WICBitmapCacheOnLoad;
                if (cacheOption == BitmapCacheOption.OnDemand)
                {
                    wicCache = WICBitmapCreateCacheOptions.WICBitmapCacheOnDemand; 
                }
                else if (cacheOption == BitmapCacheOption.OnLoad) 
                { 
                    wicCache = WICBitmapCreateCacheOptions.WICBitmapCacheOnLoad;
                } 


                originalFmt = PixelFormat.GetPixelFormat(wicSource);
                PixelFormat destFmt = originalFmt; 

                // check that we need to change the format of the bitmap 
                if (0 == (createOptions & BitmapCreateOptions.PreservePixelFormat)) 
                {
                    if (Array.IndexOf(BitmapSource.s_supportedDUCEFormats, originalFmt) == -1) 
                        changeFormat = true;

                    destFmt = BitmapSource.GetClosestDUCEFormat(originalFmt, palette);
                } 

                if (frame != null && 
                    ((createOptions & BitmapCreateOptions.IgnoreColorProfile) == 0) && 
                    frame.ColorContexts != null &&
                    frame.ColorContexts[0] != null && 
                    !frame._isColorCorrected &&
                    PixelFormat.GetPixelFormat(wicSource).Format != PixelFormatEnum.Extended)
                {
                    ColorContext destinationColorContext; 

                    // We need to make sure, we can actually create the ColorContext for the destination destFmt 
                    // If the destFmt is gray or scRGB, the following is not supported, so we cannot 
                    // create the ColorConvertedBitmap
                    try 
                    {
                        destinationColorContext = new ColorContext(destFmt);
                    }
                    catch (NotSupportedException) 
                    {
                        destinationColorContext = null; 
                    } 

                    if (destinationColorContext != null) 
                    {
                        // NOTE: Never do this for a non-MIL pixel format, because the format converter has
                        // special knowledge to deal with the profile
 
                        bool conversionSuccess = false;
                        bool badColorContext = false; 
 
                        // First try if the color converter can handle the source format directly
                        // Its possible that the color converter does not support certain pixelformats, so put a try/catch here. 
                        try
                        {
                            ColorConvertedBitmap colorConvertedBitmap = new ColorConvertedBitmap(
                                frame, 
                                frame.ColorContexts[0],
                                destinationColorContext, 
                                destFmt 
                                );
 
                            wicSource = colorConvertedBitmap.WicSourceHandle;
                            frame._isColorCorrected = true;
                            conversionSuccess = true;
                            changeFormat = false;   // Changeformat no longer necessary, because destFmt already created 
                            // by ColorConvertedBitmap
                        } 
                        catch (NotSupportedException) 
                        {
                        } 
                        catch (FileFormatException)
                        {
                            // If the file contains a bad color context, we catch the exception here
                            // and don't bother trying the color conversion below, since color transform isn't possible 
                            // with the given color context.
                            badColorContext = true; 
                        } 

                        if (!conversionSuccess && changeFormat && !badColorContext) 
                        {   // If the conversion failed, we first use
                            // a FormatConvertedBitmap, and then Color Convert that one...
                            changeFormat = false;
 
                            FormatConvertedBitmap formatConvertedBitmap = new FormatConvertedBitmap(frame, destFmt, null, 0.0);
 
                            ColorConvertedBitmap colorConvertedBitmap = new ColorConvertedBitmap( 
                                formatConvertedBitmap,
                                frame.ColorContexts[0], 
                                destinationColorContext,
                                destFmt
                                );
 
                            wicSource = colorConvertedBitmap.WicSourceHandle;
                            frame._isColorCorrected = true; 
                            Debug.Assert(destFmt == colorConvertedBitmap.Format); 
                            changeFormat = false;   // Changeformat no longer necessary, because destFmt already created
                            // by ColorConvertedBitmap 
                        }
                    }
                }
 
                if (changeFormat)
                { 
                    // start up a format converter 
                    Guid fmtDestFmt = destFmt.Guid;
                    HRESULT.Check(UnsafeNativeMethods.WICCodec.WICConvertBitmapSource( 
                            ref fmtDestFmt,
                            wicSource,
                            out wicConverter));
 
                    // dump the converted contents into a bitmap
                    HRESULT.Check(UnsafeNativeMethods.WICImagingFactory.CreateBitmapFromSource( 
                            wicFactory, 
                            wicConverter,
                            wicCache, 
                            out wicConvertedSource));
                }
                else
                { 
                    // Create the unmanaged resources
                    HRESULT.Check(UnsafeNativeMethods.WICImagingFactory.CreateBitmapFromSource( 
                            wicFactory, 
                            wicSource,
                            wicCache, 
                            out wicConvertedSource));
                }

                wicConvertedSource.CalculateSize(); 
            }
 
            return wicConvertedSource; 
        }
 
        /// Called when decode fails
        private void OnDecodeFailed(object sender, ExceptionEventArgs e)
        {
            _decodeFailedEvent.InvokeEvents(this, e); 
        }
 
        #endregion 

        #region Animatable and Freezable 

        /// 
        /// Called by the base Freezable class to make this object
        /// frozen. 
        /// 
        protected override bool FreezeCore(bool isChecking) 
        { 
            if (!base.FreezeCore(isChecking))
            { 
                return false;
            }

            if (IsDownloading) 
            {
                return false; 
            } 

            return true; 
        }

        /// 
        /// Copy the fields not covered by DPs.  This is used by 
        /// CloneCore(), CloneCurrentValueCore(), GetAsFrozenCore() and
        /// GetCurrentValueAsFrozenCore(). 
        ///  
        /// 
        /// SecurityCritical: This code accesses unmanaged resources 
        /// SecurityTreatAsSafe: Inputs are verified
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        private void CopyCommon(BitmapSource sourceBitmap) 
        {
            _isClone = sourceBitmap._isClone; 
            _useVirtuals = sourceBitmap._useVirtuals; 
            _delayCreation = sourceBitmap.DelayCreation;
            _creationComplete = sourceBitmap.CreationCompleted; 
            WicSourceHandle = sourceBitmap.WicSourceHandle; // always do this near the top
            _syncObject = sourceBitmap.SyncObject;
            IsSourceCached = sourceBitmap.IsSourceCached;
 
            if (sourceBitmap._downloadEvent != null)
            { 
                _downloadEvent = sourceBitmap._downloadEvent.Clone(); 
            }
 
            if (sourceBitmap._progressEvent != null)
            {
                _progressEvent = sourceBitmap._progressEvent.Clone();
            } 

            if (sourceBitmap._failedEvent != null) 
            { 
                _failedEvent = sourceBitmap._failedEvent.Clone();
            } 

            if (sourceBitmap._decodeFailedEvent != null)
            {
                _decodeFailedEvent = sourceBitmap._decodeFailedEvent.Clone(); 
            }
 
            _format = sourceBitmap.Format; 
            _pixelWidth = sourceBitmap.PixelWidth;
            _pixelHeight = sourceBitmap.PixelHeight; 
            _dpiX = sourceBitmap.DpiX;
            _dpiY = sourceBitmap.DpiY;
            _palette = sourceBitmap.Palette;
            _isClone = true; 
        }
 
        ///  
        /// Implementation of Freezable.CloneCore.
        ///  
        protected override void CloneCore(Freezable sourceFreezable)
        {
            BitmapSource sourceBitmap = (BitmapSource)sourceFreezable;
            base.CloneCore(sourceFreezable); 

            CopyCommon(sourceBitmap); 
        } 

        ///  
        /// Implementation of Freezable.CloneCurrentValueCore.
        /// 
        protected override void CloneCurrentValueCore(Freezable sourceFreezable)
        { 
            BitmapSource sourceBitmap = (BitmapSource)sourceFreezable;
            base.CloneCurrentValueCore(sourceFreezable); 
 
            CopyCommon(sourceBitmap);
        } 

        /// 
        /// Implementation of Freezable.GetAsFrozenCore.
        ///  
        protected override void GetAsFrozenCore(Freezable sourceFreezable)
        { 
            BitmapSource sourceBitmap = (BitmapSource)sourceFreezable; 
            base.GetAsFrozenCore(sourceFreezable);
 
            CopyCommon(sourceBitmap);
        }

        ///  
        /// Implementation of Freezable.GetCurrentValueAsFrozenCore.
        ///  
        protected override void GetCurrentValueAsFrozenCore(Freezable sourceFreezable) 
        {
            BitmapSource sourceBitmap = (BitmapSource)sourceFreezable; 
            base.GetCurrentValueAsFrozenCore(sourceFreezable);

            CopyCommon(sourceBitmap);
        } 

        #endregion 
 
        #region Data Members
 
        private bool _isClone = false;
        private bool _delayCreation = false;
        private bool _creationComplete = false;
        private bool _useVirtuals = false; 
        internal BitmapInitialize _bitmapInit = new BitmapInitialize();
 
        ///  
        /// Critical: Unmanaged IWICBitmapSource handle. Access only through WicSourceHandle
        ///  
        [SecurityCritical]
        internal BitmapSourceSafeMILHandle _wicSource = null;

        ///  
        /// Critical: Unmanaged IWICBitmapSource handle.
        ///  
        [SecurityCritical] 
        internal BitmapSourceSafeMILHandle _convertedDUCEMILPtr;
 
        internal object _syncObject;
        internal bool _isSourceCached;
        internal bool _needsUpdate;
        internal bool _isColorCorrected; 
        internal bool _isWriteable;
        internal UniqueEventHelper _downloadEvent = new UniqueEventHelper(); 
        internal UniqueEventHelper _progressEvent = new UniqueEventHelper(); 
        internal UniqueEventHelper _failedEvent = new UniqueEventHelper();
        internal UniqueEventHelper _decodeFailedEvent = new UniqueEventHelper(); 

        // cached properties. should always reflect the unmanaged copy
        internal PixelFormat _format = PixelFormats.Default;
        internal int _pixelWidth = 0; 
        internal int _pixelHeight = 0;
        internal double _dpiX = 96.0; 
        internal double _dpiY = 96.0; 
        internal BitmapPalette _palette = null;
 
        /// Duce resource
        internal DUCE.MultiChannelResource _duceResource = new DUCE.MultiChannelResource();

        /// List of supported DUCE formats 
        /// NOTE: Please add formats in increasing bpp order
        internal static Array s_supportedDUCEFormats = 
            new PixelFormat[13] 
            {
                PixelFormats.Indexed1, 
                PixelFormats.BlackWhite,
                PixelFormats.Indexed2,
                PixelFormats.Gray2,
                PixelFormats.Indexed4, 
                PixelFormats.Gray4,
                PixelFormats.Indexed8, 
                PixelFormats.Gray8, 
                PixelFormats.Bgr555,
                PixelFormats.Bgr565, 
                PixelFormats.Bgr32,
                PixelFormats.Bgra32,
                PixelFormats.Pbgra32
            }; 

        #endregion 
 
        #region Interface definitions
 
        //*************************************************************
        //
        //  IMILBitmapSource
        // 
        //*************************************************************
 
        // Guid: IID_IMILBitmapSource 
        [ComImport(), Guid("7543696A-BC8D-46b0-5F81-8D95728972BE"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
        internal interface IMILBitmapSource 
        {
            [PreserveSig]
            int GetSize(
                out int puiWidth, 
                out int puiHeight
            ); 
 
            [PreserveSig]
            int GetPixelFormat( 
                out PixelFormatEnum pPixelFormat
            );

            [PreserveSig] 
            int GetResolution(
                out double pDpiX, 
                out double pDpiY 
            );
 
            [PreserveSig]
            int GetPalette(
                IntPtr /* IMILPalette */ pIPalette
            ); 

            // SizeParamIndex says which parameter specifies the size of the array, 
            // which we are saying is cbStride. 
            [PreserveSig]
            int CopyPixels( 
                IntPtr prc,
                int cbStride,
                int cbPixels,
                IntPtr pvPixels 
            );
        } 
 
        //**************************************************************
        // 
        //  IWICBitmapSource
        //
        //*************************************************************
 
        // Guid: IID_IWICBitmapSource
        [ComImport(), Guid("00000120-a8f2-4877-ba0a-fd2b6645fb94"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] 
        internal interface IWICBitmapSource 
        {
            [PreserveSig] 
            int GetSize(
                out int puiWidth,
                out int puiHeight
            ); 

            [PreserveSig] 
            int GetPixelFormat( 
                out Guid guidFormat
            ); 

            [PreserveSig]
            int GetResolution(
                out double pDpiX, 
                out double pDpiY
            ); 
 
            [PreserveSig]
            int GetPalette( 
                IntPtr /* IWICPalette */ pIPalette
            );

            // SizeParamIndex says which parameter specifies the size of the array, 
            // which we are saying is cbStride.
            [PreserveSig] 
            int CopyPixels( 
                IntPtr prc,
                int cbStride, 
                int cbPixels,
                IntPtr pvPixels
            );
        } 

        #endregion 
 
        #region Managed Bitmap Source
 
        //**************************************************************
        //
        //  ManagedBitmapSource
        // 
        //**************************************************************
 
        [ClassInterface(ClassInterfaceType.None)] 
        internal class ManagedBitmapSource : IMILBitmapSource, IWICBitmapSource
        { 
            private BitmapSource _bitmapSource;

            private ManagedBitmapSource()
            { 
            }
 
            public ManagedBitmapSource(BitmapSource bitmapSource) 
            {
                if (bitmapSource == null) 
                {
                    throw new System.ArgumentNullException("bitmapSource");
                }
                _bitmapSource = bitmapSource; 
            }
 
            int IWICBitmapSource.GetSize(out int puiWidth, out int puiHeight) 
            {
                return ((IMILBitmapSource)this).GetSize(out puiWidth, out puiHeight); 
            }

            int IMILBitmapSource.GetSize(out int puiWidth, out int puiHeight)
            { 
                puiWidth = _bitmapSource.PixelWidth;
                puiHeight = _bitmapSource.PixelHeight; 
                return NativeMethods.S_OK; 
            }
 
            int IWICBitmapSource.GetPixelFormat(out Guid guidFormat)
            {
                guidFormat = _bitmapSource.Format.Guid;
                return NativeMethods.S_OK; 
            }
 
            int IMILBitmapSource.GetPixelFormat(out PixelFormatEnum pPixelFormat) 
            {
                pPixelFormat = _bitmapSource.Format.Format; 
                return NativeMethods.S_OK;
            }

            int IWICBitmapSource.GetResolution(out double pDpiX, out double pDpiY) 
            {
                return ((IMILBitmapSource)this).GetResolution(out pDpiX, out pDpiY); 
            } 

            int IMILBitmapSource.GetResolution(out double pDpiX, out double pDpiY) 
            {
                pDpiX = _bitmapSource.DpiX;
                pDpiY = _bitmapSource.DpiY;
                return NativeMethods.S_OK; 
            }
 
            ///  
            /// Critical - access critical resource, unamanged pointer
            ///  
            [SecurityCritical]
            int IMILBitmapSource.GetPalette(IntPtr /* IMILPalette */ pIPalette)
            {
                IntPtr pIWICPalette = IntPtr.Zero; 
                Guid guidIWICPalette = MILGuidData.IID_IWICPalette;
 
                try 
                {
                    HRESULT.Check(UnsafeNativeMethods.MILUnknown.QueryInterface( 
                        pIPalette,
                        ref guidIWICPalette,
                        out pIWICPalette) );
 
                    HRESULT.Check(((IWICBitmapSource)this).GetPalette(pIWICPalette));
 
                } 
                finally
                { 
                    UnsafeNativeMethods.MILUnknown.ReleaseInterface(ref pIWICPalette);
                }

                return NativeMethods.S_OK; 
            }
 
            int IWICBitmapSource.GetPalette(IntPtr /* IWICPalette */ pIPalette) 
            {
                // 

                BitmapPalette palette = _bitmapSource.Palette;
                if ((palette == null) || (palette.InternalPalette == null)  || (SecurityHelper.SafeHandleIsInvalid(palette.InternalPalette)))
                { 
                    return (int)WinCodecErrors.WINCODEC_ERR_PALETTEUNAVAILABLE;
                } 
 
                HRESULT.Check(UnsafeNativeMethods.WICPalette.InitializeFromPalette(pIPalette, palette.InternalPalette));
 
                return NativeMethods.S_OK;
            }

            int IWICBitmapSource.CopyPixels(IntPtr prc, int cbStride, int cbPixels, IntPtr pvPixels) 
            {
                return ((IMILBitmapSource)this).CopyPixels(prc, cbStride, cbPixels, pvPixels); 
            } 

            ///  
            ///     Critical: This code can be used to expose pixel information
            /// 
            [SecurityCritical]
            int IMILBitmapSource.CopyPixels(IntPtr prc, int cbStride, int cbPixels, IntPtr pvPixels) 
            {
                if( cbStride < 0 ) 
                { 
                    return NativeMethods.E_INVALIDARG;
                } 

                if( pvPixels == IntPtr.Zero )
                {
                    return NativeMethods.E_INVALIDARG; 
                }
 
                Int32Rect rc; 

                if (prc == IntPtr.Zero) 
                {
                    rc = new Int32Rect(0,0,_bitmapSource.PixelWidth, _bitmapSource.PixelHeight);
                }
                else 
                {
                    rc = (Int32Rect)Marshal.PtrToStructure(prc, typeof(Int32Rect)); 
                } 

                int rectHeight, rectWidth; 

                rectHeight = rc.Height;
                rectWidth = rc.Width;
 
                if (rc.Width < 1 || rc.Height < 1)
                { 
                    return NativeMethods.E_INVALIDARG; 
                }
 
                // assuming cbStride can't be negative, but that prc.Height can
                PixelFormat pfStruct = _bitmapSource.Format;

                if( pfStruct.Format == PixelFormatEnum.Default || 
                    pfStruct.Format == PixelFormatEnum.Extended )
                { 
                    return (int)(WinCodecErrors.WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT); 
                }
 

                int rectRowSize = (rectWidth * pfStruct.InternalBitsPerPixel + 7) / 8;

                if (cbPixels < (rectHeight - 1) * cbStride + rectRowSize) 
                {
                    return (int)(WinCodecErrors.WINCODEC_ERR_INSUFFICIENTBUFFER); 
                } 

                // Need to marshal 
                int arraySize = rectHeight * rectRowSize;
                byte[] managedArray = new byte[arraySize];

                // perform the copy 
                _bitmapSource.CopyPixels(rc, managedArray, rectRowSize, 0);
 
                { 
                    // transfer the contents of the relevant rect from the managed array to pvPixels
                    long rowPtr = pvPixels.ToInt64(); 
                    for( int y = 0; y < rectHeight; y++ )
                    {
                        Marshal.Copy(managedArray, y*rectRowSize, new IntPtr(rowPtr), rectRowSize);
                        rowPtr += cbStride; 
                    }
                } 
 
                return NativeMethods.S_OK;
            } 
        }

        #endregion
    } 

    #endregion // BitmapSource 
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK