Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Core / CSharp / System / Windows / Media / Imaging / BitmapSource.cs / 1 / 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 EventHandlerDownloadProgress { 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 EventHandlerDownloadFailed { 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 EventHandlerDecodeFailed { 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 ImageSource.PixelsToDIPs(this.DpiX, this.PixelWidth); } ////// Helper function to calculate Height. /// private double GetHeightInternal() { return ImageSource.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(); } 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"); if (offset < 0) { HRESULT.Check((int)WinCodecErrors.WINCODEC_ERR_VALUEOVERFLOW); } 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 = checked(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: There is a risk of buffer overruns when copying data to the buffer. /// This code can also be used to expose pixel information /// [SecurityCritical] internal 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 = checked(((sourceRect.Width * Format.BitsPerPixel) + 7) / 8); if ( stride < minStride ) throw new ArgumentOutOfRangeException("stride", SR.Get(SRID.ParameterCannotBeLessThan, minStride)); int minRequiredDestSize = checked((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); } ////// 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) { base.UpdateResource(channel, 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); } else { bool supportedFormat = (Array.IndexOf(s_supportedDUCEFormats, Format) != -1); if (supportedFormat && _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 (!supportedFormat) { #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)) { UpdateResource(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 virtual void UpdateBitmapSourceResource(DUCE.Channel channel, bool skipOnChannelCheck) { if (_needsUpdate) { _convertedDUCEMILPtr = null; _needsUpdate = false; } // 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)) { // We may end up loading in the bitmap bits so it's necessary to take the [....] 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 protected override void CloneCore(Freezable sourceFreezable) { BitmapSource sourceBitmap = (BitmapSource)sourceFreezable; base.CloneCore(sourceFreezable); CopyCommon(sourceBitmap); } ///Freezable.CloneCore . ////// Implementation of protected override void CloneCurrentValueCore(Freezable sourceFreezable) { BitmapSource sourceBitmap = (BitmapSource)sourceFreezable; base.CloneCurrentValueCore(sourceFreezable); CopyCommon(sourceBitmap); } ///Freezable.CloneCurrentValueCore . ////// Implementation of protected override void GetAsFrozenCore(Freezable sourceFreezable) { BitmapSource sourceBitmap = (BitmapSource)sourceFreezable; base.GetAsFrozenCore(sourceFreezable); CopyCommon(sourceBitmap); } ///Freezable.GetAsFrozenCore . ////// Implementation of 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(); ///Freezable.GetCurrentValueAsFrozenCore . ////// 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 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 = checked((rectWidth * pfStruct.InternalBitsPerPixel + 7) / 8); if (cbPixels < checked((rectHeight - 1) * cbStride + rectRowSize)) { return (int)(WinCodecErrors.WINCODEC_ERR_INSUFFICIENTBUFFER); } // Need to marshal int arraySize = checked(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. //------------------------------------------------------------------------------ // 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 EventHandlerDownloadProgress { 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 EventHandlerDownloadFailed { 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 EventHandlerDecodeFailed { 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 ImageSource.PixelsToDIPs(this.DpiX, this.PixelWidth); } ////// Helper function to calculate Height. /// private double GetHeightInternal() { return ImageSource.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(); } 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"); if (offset < 0) { HRESULT.Check((int)WinCodecErrors.WINCODEC_ERR_VALUEOVERFLOW); } 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 = checked(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: There is a risk of buffer overruns when copying data to the buffer. /// This code can also be used to expose pixel information /// [SecurityCritical] internal 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 = checked(((sourceRect.Width * Format.BitsPerPixel) + 7) / 8); if ( stride < minStride ) throw new ArgumentOutOfRangeException("stride", SR.Get(SRID.ParameterCannotBeLessThan, minStride)); int minRequiredDestSize = checked((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); } ////// 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) { base.UpdateResource(channel, 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); } else { bool supportedFormat = (Array.IndexOf(s_supportedDUCEFormats, Format) != -1); if (supportedFormat && _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 (!supportedFormat) { #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)) { UpdateResource(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 virtual void UpdateBitmapSourceResource(DUCE.Channel channel, bool skipOnChannelCheck) { if (_needsUpdate) { _convertedDUCEMILPtr = null; _needsUpdate = false; } // 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)) { // We may end up loading in the bitmap bits so it's necessary to take the [....] 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 protected override void CloneCore(Freezable sourceFreezable) { BitmapSource sourceBitmap = (BitmapSource)sourceFreezable; base.CloneCore(sourceFreezable); CopyCommon(sourceBitmap); } ///Freezable.CloneCore . ////// Implementation of protected override void CloneCurrentValueCore(Freezable sourceFreezable) { BitmapSource sourceBitmap = (BitmapSource)sourceFreezable; base.CloneCurrentValueCore(sourceFreezable); CopyCommon(sourceBitmap); } ///Freezable.CloneCurrentValueCore . ////// Implementation of protected override void GetAsFrozenCore(Freezable sourceFreezable) { BitmapSource sourceBitmap = (BitmapSource)sourceFreezable; base.GetAsFrozenCore(sourceFreezable); CopyCommon(sourceBitmap); } ///Freezable.GetAsFrozenCore . ////// Implementation of 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(); ///Freezable.GetCurrentValueAsFrozenCore . ////// 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 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 = checked((rectWidth * pfStruct.InternalBitsPerPixel + 7) / 8); if (cbPixels < checked((rectHeight - 1) * cbStride + rectRowSize)) { return (int)(WinCodecErrors.WINCODEC_ERR_INSUFFICIENTBUFFER); } // Need to marshal int arraySize = checked(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
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- DSGeneratorProblem.cs
- Icon.cs
- baseshape.cs
- SEHException.cs
- BamlLocalizableResourceKey.cs
- DrawingContextWalker.cs
- TextDecorationCollection.cs
- TransformDescriptor.cs
- SignatureDescription.cs
- XmlAggregates.cs
- CreateInstanceBinder.cs
- XmlQueryContext.cs
- TreeViewImageKeyConverter.cs
- GlyphCollection.cs
- RuleRef.cs
- RoutedEventHandlerInfo.cs
- StreamUpgradeAcceptor.cs
- CodeComment.cs
- TCEAdapterGenerator.cs
- DynamicDocumentPaginator.cs
- ShapingWorkspace.cs
- ObjectStorage.cs
- ChainOfDependencies.cs
- UrlMappingCollection.cs
- BevelBitmapEffect.cs
- ZoneButton.cs
- DataGridViewColumnHeaderCell.cs
- SqlCacheDependencySection.cs
- RowToParametersTransformer.cs
- PropertyGridView.cs
- SourceFileInfo.cs
- CodeDefaultValueExpression.cs
- WindowsTab.cs
- ThumbAutomationPeer.cs
- WSSecurityXXX2005.cs
- DataGridTableCollection.cs
- SQLInt64.cs
- NonPrimarySelectionGlyph.cs
- RichTextBoxConstants.cs
- TemplateControlBuildProvider.cs
- CardSpaceException.cs
- DetailsViewUpdatedEventArgs.cs
- XmlNodeComparer.cs
- RegexGroupCollection.cs
- StdRegProviderWrapper.cs
- ColumnTypeConverter.cs
- COM2PropertyPageUITypeConverter.cs
- Geometry.cs
- XmlSerializationWriter.cs
- WebPartConnectVerb.cs
- InvalidateEvent.cs
- XPathCompileException.cs
- XmlSchemaInclude.cs
- ObjectListDesigner.cs
- Descriptor.cs
- RequestSecurityTokenForRemoteTokenFactory.cs
- SendMailErrorEventArgs.cs
- DiagnosticEventProvider.cs
- ByteStorage.cs
- __ComObject.cs
- XmlSiteMapProvider.cs
- ScaleTransform3D.cs
- DrawListViewItemEventArgs.cs
- FileVersionInfo.cs
- BoundColumn.cs
- RpcAsyncResult.cs
- BitmapEffectDrawingContextState.cs
- HtmlContainerControl.cs
- InvalidOperationException.cs
- TemplateXamlParser.cs
- XmlAttributeAttribute.cs
- X509ChainPolicy.cs
- TargetParameterCountException.cs
- SocketManager.cs
- BufferedGraphics.cs
- ReflectPropertyDescriptor.cs
- _Semaphore.cs
- SourceLocation.cs
- HandlerBase.cs
- ObfuscateAssemblyAttribute.cs
- DecimalAnimationBase.cs
- ProfileProvider.cs
- TextTrailingWordEllipsis.cs
- SQLDateTime.cs
- DataGridViewCellConverter.cs
- DeploymentExceptionMapper.cs
- DllNotFoundException.cs
- MappingItemCollection.cs
- DataTemplateKey.cs
- ServicePerformanceCounters.cs
- RubberbandSelector.cs
- IIS7UserPrincipal.cs
- UpdatePanel.cs
- BrowserDefinition.cs
- IChannel.cs
- CustomError.cs
- XmlSchema.cs
- KeyedCollection.cs
- DataPagerCommandEventArgs.cs
- MessagePropertyAttribute.cs