WriteableBitmap.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 / WriteableBitmap.cs / 1 / WriteableBitmap.cs

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

namespace System.Windows.Media.Imaging
{ 
    #region WriteableBitmap
 
    ///  
    /// WriteableBitmap provides caching functionality for a BitmapSource.
    ///  
    public sealed class WriteableBitmap : System.Windows.Media.Imaging.BitmapSource
    {

        ///  
        /// Internal constructor
        ///  
        internal WriteableBitmap() 
        {
        } 

        /// 
        /// Construct a WriteableBitmap
        ///  
        /// Input BitmapSource
        ///  
        /// Critical: Accesses _wicSource 
        /// PublicOK: Inputs are safe
        ///  
        [SecurityCritical]
        public WriteableBitmap(BitmapSource source)
            : base(true) // Use base class virtuals
        { 
            if (source == null)
            { 
                throw new ArgumentNullException("source"); 
            }
 
            BeginInit();

            _syncObject = source.SyncObject;
            lock (_syncObject) 
            {
                WicSourceHandle = CreateCachedBitmap( 
                    null, 
                    source.WicSourceHandle,
                    BitmapCreateOptions.None, 
                    BitmapCacheOption.OnLoad,
                    source.Palette
                    );
            } 

            EndInit(); 
        } 

        ///  
        /// Construct a WriteableBitmap
        /// 
        /// 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
        ///  
        /// Critical: Accesses _wicSource
        /// PublicOK: Inputs are safe
        /// 
        [SecurityCritical] 
        public WriteableBitmap(
            int pixelWidth, 
            int pixelHeight, 
            double dpiX,
            double dpiY, 
            PixelFormat pixelFormat,
            BitmapPalette palette
            )
            : base(true) // Use base class virtuals 
        {
            BeginInit(); 
 
            if (pixelFormat.Palettized)
            { 
                if (palette == null)
                {
                    throw new InvalidOperationException(SR.Get(SRID.Image_IndexedPixelFormatRequiresPalette));
                } 
            }
 
            int i = Array.IndexOf(s_supportedDUCEFormats, pixelFormat); 

            if (i == -1) 
            {
                throw new System.ArgumentException(SR.Get(SRID.Effect_PixelFormat, pixelFormat), "pixelFormat");
            }
 

            using (FactoryMaker factoryMaker = new FactoryMaker()) 
            { 
                BitmapSourceSafeMILHandle /* IWICBitmapSource */ pIWICSource = null;
 
                Guid formatGuid = pixelFormat.Guid;

                HRESULT.Check(UnsafeNativeMethods.WICImagingFactory.CreateBitmap(
                    factoryMaker.ImagingFactoryPtr, 
                    (uint)pixelWidth,
                    (uint)pixelHeight, 
                    ref formatGuid, 
                    WICBitmapCreateCacheOptions.WICBitmapCacheOnLoad,
                    out pIWICSource 
                    ));

                HRESULT.Check(UnsafeNativeMethods.WICBitmap.SetResolution(pIWICSource, dpiX, dpiY));
 
                if (pixelFormat.Palettized)
                { 
                    HRESULT.Check(UnsafeNativeMethods.WICBitmap.SetPalette(pIWICSource, palette.InternalPalette)); 
                }
 
                _syncObject = pIWICSource;
                WicSourceHandle = pIWICSource;
            }
 
            EndInit();
        } 
 
        #region Public Methods
 
        /// 
        ///     Shadows inherited Copy() with a strongly typed
        ///     version for convenience.
        ///  
        public new WriteableBitmap Clone()
        { 
            return (WriteableBitmap)base.Clone(); 
        }
 
        /// 
        ///     Shadows inherited CloneCurrentValue() with a
        ///     strongly typed version for convenience.
        ///  
        public new WriteableBitmap CloneCurrentValue()
        { 
            return (WriteableBitmap)base.CloneCurrentValue(); 
        }
 
        /// 
        /// Update the pixels of this Bitmap
        /// 
        /// Area to update 
        /// Input buffer
        /// Size of the buffer 
        /// Stride 
        /// 
        /// Critical - access critical code, accepts pointer arguments 
        /// PublicOK - demands unmanaged code permission
        /// 
        [SecurityCritical]
        public unsafe void WritePixels( 
            Int32Rect sourceRect,
            IntPtr buffer, 
            int bufferSize, 
            int stride
            ) 
        {
            SecurityHelper.DemandUnmanagedCode();

            WritePreamble(); 

            if (bufferSize < 1) 
            { 
                throw new ArgumentOutOfRangeException("bufferSize", SR.Get(SRID.ParameterCannotBeLessThan, 1));
            } 

            if (stride < 1)
            {
                throw new ArgumentOutOfRangeException("stride", SR.Get(SRID.ParameterCannotBeLessThan, 1)); 
            }
 
            if (sourceRect.IsEmpty || sourceRect.Width <= 0 || sourceRect.Height <= 0) 
            {
                return; 
            }

            SafeMILHandle pILock = null;
            HRESULT.Check(UnsafeNativeMethods.WICBitmap.Lock( 
                WicSourceHandle,
                ref sourceRect, 
                LockFlags.MIL_LOCK_WRITE, 
                out pILock
                )); 

            try
            {
                uint lockBufferSize = 0; 
                IntPtr pData = IntPtr.Zero;
                HRESULT.Check(UnsafeNativeMethods.WICBitmapLock.GetDataPointer( 
                    pILock, 
                    ref lockBufferSize,
                    ref pData 
                    ));

                uint lockBufferStride = 0;
                HRESULT.Check(UnsafeNativeMethods.WICBitmapLock.GetStride( 
                    pILock,
                    ref lockBufferStride 
                    )); 

                uint copyStride = (uint)(((Format.InternalBitsPerPixel * sourceRect.Width) + 7) / 8); 

                if (bufferSize < (copyStride * sourceRect.Height))
                {
                    HRESULT.Check((int)WinCodecErrors.WINCODEC_ERR_INSUFFICIENTBUFFER); 
                }
 
 
                unsafe
                { 
                    CopyPixelBuffer(
                        (byte*)pData,
                        lockBufferStride,
                        (byte*)buffer, 
                        (uint)stride,
                        sourceRect.Height, 
                        copyStride 
                        );
                } 
            }
            finally
            {
                // 
                // Release the lock as having it GC'd can
                // cause issues when reacquiring 
                // 
                pILock.Dispose();
                pILock = null; 
            }

            // Add the source rect to the update list
            if (_updateRects == null) 
            {
                _updateRects = new ArrayList(); 
            } 

            _updateRects.Add(sourceRect); 

            // Trigger a update of the UCE resource
            _needsUpdate = true;
            RegisterForAsyncUpdateResource(); 
            WritePostscript();
        } 
 
        /// 
        /// Update the pixels of this Bitmap 
        /// 
        /// Area to update
        /// Input buffer
        /// Stride 
        /// Input buffer offset
        ///  
        /// Critical - Access critical code - WicSourceHandle 
        /// PublicOk - Input is a managed buffer which is safe, other inputs are safe as well
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        public void WritePixels(
            Int32Rect sourceRect,
            Array pixels, 
            int stride,
            int offset 
            ) 
        {
            WritePreamble(); 

            if (sourceRect.IsEmpty || sourceRect.Width <= 0 || sourceRect.Height <= 0)
            {
                return; 
            }
 
            if (pixels == null) 
            {
                throw new System.ArgumentNullException("pixels"); 
            }

            if (pixels.Rank != 1)
            { 
                throw new ArgumentException (SR.Get(SRID.Collection_BadRank), "pixels");
            } 
 
            if (stride < 1)
            { 
                throw new ArgumentOutOfRangeException("stride", SR.Get(SRID.ParameterCannotBeLessThan, 1));
            }

            if (offset < 0) 
            {
                throw new ArgumentOutOfRangeException("stride", SR.Get(SRID.ParameterCannotBeLessThan, 0)); 
            } 

            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));
            } 

            uint inputBufferSize = (uint)(elementSize * (pixels.Length - offset)); 
 
            SafeMILHandle pILock = null;
            HRESULT.Check(UnsafeNativeMethods.WICBitmap.Lock( 
                WicSourceHandle,
                ref sourceRect,
                LockFlags.MIL_LOCK_WRITE,
                out pILock 
                ));
 
            try 
            {
                uint lockBufferSize = 0; 
                IntPtr pData = IntPtr.Zero;
                HRESULT.Check(UnsafeNativeMethods.WICBitmapLock.GetDataPointer(
                    pILock,
                    ref lockBufferSize, 
                    ref pData
                    )); 
 
                uint lockBufferStride = 0;
                HRESULT.Check(UnsafeNativeMethods.WICBitmapLock.GetStride( 
                    pILock,
                    ref lockBufferStride
                    ));
 
                uint copyStride = (uint)(((Format.InternalBitsPerPixel * sourceRect.Width) + 7) / 8);
 
                if (inputBufferSize < (copyStride * sourceRect.Height)) 
                {
                    HRESULT.Check((int)WinCodecErrors.WINCODEC_ERR_INSUFFICIENTBUFFER); 
                }

                unsafe
                { 
                    if (pixels is byte[])
                    { 
                        fixed (void *pixelArray = &((byte[])pixels)[offset]) 
                        {
                            CopyPixelBuffer( 
                                (byte*)pData,
                                lockBufferStride,
                                (byte*)pixelArray,
                                (uint)stride, 
                                sourceRect.Height,
                                copyStride 
                                ); 
                        }
                    } 
                    else if (pixels is short[])
                    {
                        fixed (void *pixelArray = &((short[])pixels)[offset])
                        { 
                            CopyPixelBuffer(
                                (byte*)pData, 
                                lockBufferStride, 
                                (byte*)pixelArray,
                                (uint)stride, 
                                sourceRect.Height,
                                copyStride
                                );
                        } 
                    }
                    else if (pixels is ushort[]) 
                    { 
                        fixed (void *pixelArray = &((ushort[])pixels)[offset])
                        { 
                            CopyPixelBuffer(
                                (byte*)pData,
                                lockBufferStride,
                                (byte*)pixelArray, 
                                (uint)stride,
                                sourceRect.Height, 
                                copyStride 
                                );
                        } 
                    }
                    else if (pixels is int[])
                    {
                        fixed (void *pixelArray = &((int[])pixels)[offset]) 
                        {
                            CopyPixelBuffer( 
                                (byte*)pData, 
                                lockBufferStride,
                                (byte*)pixelArray, 
                                (uint)stride,
                                sourceRect.Height,
                                copyStride
                                ); 
                        }
                    } 
                    else if (pixels is uint[]) 
                    {
                        fixed (void *pixelArray = &((uint[])pixels)[offset]) 
                        {
                            CopyPixelBuffer(
                                (byte*)pData,
                                lockBufferStride, 
                                (byte*)pixelArray,
                                (uint)stride, 
                                sourceRect.Height, 
                                copyStride
                                ); 
                        }
                    }
                    else if (pixels is float[])
                    { 
                        fixed (void *pixelArray = &((float[])pixels)[offset])
                        { 
                            CopyPixelBuffer( 
                                (byte*)pData,
                                lockBufferStride, 
                                (byte*)pixelArray,
                                (uint)stride,
                                sourceRect.Height,
                                copyStride 
                                );
                        } 
                    } 
                    else if (pixels is double[])
                    { 
                        fixed (void *pixelArray = &((double[])pixels)[offset])
                        {
                            CopyPixelBuffer(
                                (byte*)pData, 
                                lockBufferStride,
                                (byte*)pixelArray, 
                                (uint)stride, 
                                sourceRect.Height,
                                copyStride 
                                );
                        }
                    }
                } 
            }
            finally 
            { 
                //
                // Release the lock as having it GC'd can 
                // cause issues when reacquiring
                //
                pILock.Dispose();
                pILock = null; 
            }
 
            // Add the source rect to the update list 
            if (_updateRects == null)
            { 
                _updateRects = new ArrayList();
            }

            _updateRects.Add(sourceRect); 

            // Trigger a update of the UCE resource 
            _needsUpdate = true; 
            RegisterForAsyncUpdateResource();
            WritePostscript(); 
        }

        #endregion
 
        #region Protected Methods
 
        ///  
        /// Implementation of Freezable.CreateInstanceCore.
        ///  
        /// The new Freezable.
        /// 
        /// Critical - accesses critical code.
        /// TreatAsSafe - method only produces clone of original image. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        protected override Freezable CreateInstanceCore() 
        {
            return new WriteableBitmap(); 
        }

        /// 
        /// Implementation of Freezable.CloneCore. 
        /// 
        ///  
        /// Critical - accesses critical code. 
        /// TreatAsSafe - method only produces clone of original image.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        protected override void CloneCore(Freezable sourceFreezable)
        {
            WriteableBitmap sourceBitmap = (WriteableBitmap) sourceFreezable; 

            base.CloneCore(sourceFreezable); 
 
            CopyCommon(sourceBitmap);
        } 

        /// 
        /// Implementation of Freezable.CloneCurrentValueCore.
        ///  
        /// 
        /// Critical - accesses critical code. 
        /// TreatAsSafe - method only produces clone of original image. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        protected override void CloneCurrentValueCore(Freezable sourceFreezable)
        {
            WriteableBitmap sourceBitmap = (WriteableBitmap) sourceFreezable;
 
            base.CloneCurrentValueCore(sourceFreezable);
 
            CopyCommon(sourceBitmap); 
        }
 
        /// 
        /// Implementation of Freezable.GetAsFrozenCore.
        /// 
        ///  
        /// Critical - accesses critical code.
        /// TreatAsSafe - method only produces GetAsFrozen of original image. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        protected override void GetAsFrozenCore(Freezable sourceFreezable) 
        {
            WriteableBitmap sourceBitmap = (WriteableBitmap)sourceFreezable;

            base.GetAsFrozenCore(sourceFreezable); 

            CopyCommon(sourceBitmap); 
        } 

        ///  
        /// Implementation of Freezable.GetCurrentValueAsFrozenCore.
        /// 
        /// 
        /// Critical - accesses critical code. 
        /// TreatAsSafe - method only produces GetCurrentValueAsFrozen of original image.
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        protected override void GetCurrentValueAsFrozenCore(Freezable sourceFreezable)
        { 
            WriteableBitmap sourceBitmap = (WriteableBitmap)sourceFreezable;

            base.GetCurrentValueAsFrozenCore(sourceFreezable);
 
            CopyCommon(sourceBitmap);
        } 
 
        #endregion
 
        #region Private/Internal Methods

        /// 
        /// Common implementation for CloneCore(), CloneCurrentValueCore(), 
        /// GetAsFrozenCore(), and GetCurrentValueAsFrozenCore().
        ///  
        ///  
        /// Critical - access critical code -- WicSourceHandle
        ///  
        [SecurityCritical]
        private void CopyCommon(WriteableBitmap sourceBitmap)
        {
            // Avoid Animatable requesting resource updates for invalidations that occur during construction 
            Animatable_IsResourceInvalidationNecessary = false;
 
            BeginInit(); 

            using (FactoryMaker factoryMaker = new FactoryMaker()) 
            {
                BitmapSourceSafeMILHandle wicSource = null;

                HRESULT.Check(UnsafeNativeMethods.WICImagingFactory.CreateBitmapFromSource( 
                    factoryMaker.ImagingFactoryPtr,
                    sourceBitmap.WicSourceHandle, 
                    WICBitmapCreateCacheOptions.WICBitmapCacheOnLoad, 
                    out wicSource
                    )); 

                _syncObject = wicSource;
                WicSourceHandle = wicSource;
            } 

            EndInit(); 
 
            // The next invalidation will cause Animatable to register an UpdateResource callback
            Animatable_IsResourceInvalidationNecessary = true; 
        }


        // ISupportInitialize 

        ///  
        /// Prepare the bitmap to accept initialize paramters. 
        /// 
        private void BeginInit() 
        {
            _bitmapInit.BeginInit();
        }
 
        /// 
        /// Prepare the bitmap to accept initialize paramters. 
        ///  
        /// 
        /// Critical - access critical resources 
        /// TreatAsSafe - All inputs verified
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        private void EndInit() 
        {
            _bitmapInit.EndInit(); 
 
            FinalizeCreation();
        } 

        ///
        /// Create the unmanaged resources
        /// 
        /// 
        /// Critical - access critical resource 
        ///  
        [SecurityCritical]
        internal override void FinalizeCreation() 
        {
            _isWriteable = true;
            IsSourceCached = true;
            CreationCompleted = true; 
            UpdateCachedSettings();
        } 
 
        /// Takes a buffer and copies it to the output buffer
        ///  
        /// Critical: Does unsafe pointer operations
        /// 
        [SecurityCritical]
        private unsafe void CopyPixelBuffer( 
            byte *pOutputBuffer,
            uint outputBufferStride, 
            byte *pInputBuffer, 
            uint inputBufferStride,
            int height, 
            uint copyStride
            )
        {
            for (int i = 0; i < height; i++) 
            {
                for (int j = 0; j < copyStride; j++) 
                { 
                    pOutputBuffer[j] = pInputBuffer[j];
                } 

                pOutputBuffer += outputBufferStride;
                pInputBuffer += inputBufferStride;
            } 
        }
 
        /// Retrieves the update Rect and clears the array 
        internal override Int32Rect GetUpdateRect()
        { 
            if (_updateRects == null || _updateRects.Count == 0)
            {
                return Int32Rect.Empty;
            } 

            Int32Rect updateRect = (Int32Rect)_updateRects[0]; 
            Invariant.Assert(!updateRect.IsEmpty && updateRect.Width > 0 && updateRect.Height > 0); 

            Int32 right = updateRect.X + updateRect.Width - 1; 
            Int32 bottom = updateRect.Y + updateRect.Height - 1;

            for (int i = 1; i < _updateRects.Count; i++)
            { 
                Int32Rect currentRect = (Int32Rect)_updateRects[i];
 
                updateRect.X = Math.Min(updateRect.X, currentRect.X); 
                updateRect.Y = Math.Min(updateRect.X, currentRect.Y);
                right = Math.Max(right, currentRect.X + currentRect.Width - 1); 
                bottom = Math.Max(bottom, currentRect.Y + currentRect.Height - 1);
            }

            updateRect.Width = right - updateRect.X + 1; 
            updateRect.Height = bottom - updateRect.Y + 1;
 
            Invariant.Assert(!updateRect.IsEmpty && updateRect.Width > 0 && updateRect.Height > 0); 
            _updateRects.Clear();
 
            return updateRect;
        }

        #endregion 

        #region Data Members 
 
        ArrayList _updateRects;
 
        #endregion

    }
 
    #endregion // WriteableBitmap
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

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