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 / BitmapEncoder.cs / 1 / BitmapEncoder.cs
//------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation, 2003 // // File: BitmapEncoder.cs // //----------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.ComponentModel.Design.Serialization; using System.Reflection; using System.IO; using MS.Internal; using System.Diagnostics; using System.Windows.Media; using System.Windows.Threading; using System.Globalization; using System.Runtime.InteropServices; using System.Windows.Media.Imaging; using System.Security; using System.Security.Permissions; using MS.Win32.PresentationCore; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; using System.Diagnostics.CodeAnalysis; #pragma warning disable 1634, 1691 // suppressing PreSharp warnings namespace System.Windows.Media.Imaging { #region PROPBAG2 [StructLayout(LayoutKind.Sequential, Pack=1)] internal struct PROPBAG2 { internal UInt32 dwType; internal ushort vt; internal ushort cfType; internal IntPtr dwHint; [SecurityCritical] internal IntPtr pstrName; //this is string array internal Guid clsid; ////// Critical -Initializes a pointer to unmanaged memory to hold onto a string /// TreatAsSafe - there are no inputs /// [SecurityCritical, SecurityTreatAsSafe] internal void Init(String name) { pstrName = Marshal.StringToCoTaskMemUni(name); } ////// Critical -Releases an unmanaged pointer into unmanaged memory. /// TreatAsSafe - there are no inputs /// [SecurityCritical, SecurityTreatAsSafe] internal void Clear() { Marshal.FreeCoTaskMem(pstrName); pstrName = IntPtr.Zero; } } #endregion #region BitmapEncoder ////// BitmapEncoder collects a set of frames (BitmapSource's) with their associated /// thumbnails and saves them to a specified stream. In addition /// to frame-specific thumbnails, there can also be an bitmap-wide /// (global) thumbnail, if the codec supports it. /// public abstract class BitmapEncoder : DispatcherObject { #region Constructors ////// Constructor. /// protected BitmapEncoder() { } ////// Internal Constructor. /// internal BitmapEncoder(bool isBuiltIn) { _isBuiltIn = isBuiltIn; } ////// Creates a BitmapEncoder from a container format Guid /// /// Container format for the codec ////// Critical - guid used for creation of critical resources /// [SecurityCritical] public static BitmapEncoder Create(Guid containerFormat) { if (containerFormat == Guid.Empty) { throw new ArgumentException( SR.Get(SRID.Image_GuidEmpty, "containerFormat"), "containerFormat" ); } else if (containerFormat == MILGuidData.GUID_ContainerFormatBmp) { return new BmpBitmapEncoder(); } else if (containerFormat == MILGuidData.GUID_ContainerFormatGif) { return new GifBitmapEncoder(); } else if (containerFormat == MILGuidData.GUID_ContainerFormatJpeg) { return new JpegBitmapEncoder(); } else if (containerFormat == MILGuidData.GUID_ContainerFormatPng) { return new PngBitmapEncoder(); } else if (containerFormat == MILGuidData.GUID_ContainerFormatTiff) { return new TiffBitmapEncoder(); } else if (containerFormat == MILGuidData.GUID_ContainerFormatWmp) { return new WmpBitmapEncoder(); } else { return new UnknownBitmapEncoder(containerFormat); } } #endregion #region Public Properties ////// Set or get the bitmap's color profile. /// public virtual ReadOnlyCollectionColorContexts { get { VerifyAccess(); EnsureBuiltIn(); return _readOnlycolorContexts; } set { VerifyAccess(); EnsureBuiltIn(); if (value == null) { throw new ArgumentNullException("value"); } if (!_supportsColorContext) { throw new InvalidOperationException(SR.Get(SRID.Image_EncoderNoColorContext)); } _readOnlycolorContexts = value; } } /// /// Set or get the bitmap's global embedded thumbnail. /// public virtual BitmapSource Thumbnail { get { VerifyAccess(); EnsureBuiltIn(); return _thumbnail; } set { VerifyAccess(); EnsureBuiltIn(); if (value == null) { throw new ArgumentNullException("value"); } if (!_supportsGlobalThumbnail) { throw new InvalidOperationException(SR.Get(SRID.Image_EncoderNoGlobalThumbnail)); } _thumbnail = value; } } ////// Set or get the bitmap's global embedded metadata. /// public virtual BitmapMetadata Metadata { get { VerifyAccess(); EnsureBuiltIn(); EnsureMetadata(true); return _metadata; } set { VerifyAccess(); EnsureBuiltIn(); if (value == null) { throw new ArgumentNullException("value"); } if (value.GuidFormat != ContainerFormat) { throw new InvalidOperationException(SR.Get(SRID.Image_MetadataNotCompatible)); } if (!_supportsGlobalMetadata) { throw new InvalidOperationException(SR.Get(SRID.Image_EncoderNoGlobalMetadata)); } _metadata = value; } } ////// Set or get the bitmap's global preview /// public virtual BitmapSource Preview { get { VerifyAccess(); EnsureBuiltIn(); return _preview; } set { VerifyAccess(); EnsureBuiltIn(); if (value == null) { throw new ArgumentNullException("value"); } if (!_supportsPreview) { throw new InvalidOperationException(SR.Get(SRID.Image_EncoderNoPreview)); } _preview = value; } } ////// The info that identifies this codec. /// ////// Critical - Access unmanaged code, codecs /// PublicOK - Getting codecinfo data is OK /// public virtual BitmapCodecInfo CodecInfo { [SecurityCritical ] get { VerifyAccess(); EnsureBuiltIn(); EnsureUnmanagedEncoder(); // There should always be a codec info. if (_codecInfo == null) { SafeMILHandle /* IWICBitmapEncoderInfo */ codecInfoHandle = new SafeMILHandle(); HRESULT.Check(UnsafeNativeMethods.WICBitmapEncoder.GetEncoderInfo( _encoderHandle, out codecInfoHandle )); _codecInfo = new BitmapCodecInfoInternal(codecInfoHandle); } return _codecInfo; } } ////// Provides access to this bitmap's palette /// public virtual BitmapPalette Palette { get { VerifyAccess(); EnsureBuiltIn(); return _palette; } set { VerifyAccess(); EnsureBuiltIn(); if (value == null) { throw new ArgumentNullException("value"); } _palette = value; } } ////// Access to the individual frames. /// public virtual IListFrames { get { VerifyAccess(); EnsureBuiltIn(); if (_frames == null) { _frames = new List (0); } return _frames; } set { VerifyAccess(); EnsureBuiltIn(); if (value == null) { throw new ArgumentNullException("value"); } _frames = value; } } #endregion #region Public Methods /// /// Save (encode) the bitmap to the specified stream. /// /// Stream to save into ////// Critical - calls unmanaged code /// [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] [SecurityCritical] public virtual void Save(System.IO.Stream stream) { VerifyAccess(); EnsureBuiltIn(); EnsureUnmanagedEncoder(); // No-op to get rid of build error if (_encodeState == EncodeState.None) { } if (_hasSaved) { throw new InvalidOperationException(SR.Get(SRID.Image_OnlyOneSave)); } if (_frames == null) { throw new System.NotSupportedException(SR.Get(SRID.Image_NoFrames, null)); } int count = _frames.Count; if (count <= 0) { throw new System.NotSupportedException(SR.Get(SRID.Image_NoFrames, null)); } IntPtr comStream = IntPtr.Zero; SafeMILHandle encoderHandle = _encoderHandle; try { comStream = StreamAsIStream.IStreamFrom(stream); // does this addref the stream? HRESULT.Check(UnsafeNativeMethods.WICBitmapEncoder.Initialize( encoderHandle, comStream, WICBitmapEncodeCacheOption.WICBitmapEncodeNoCache )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.EncoderInitialized; // Save global thumbnail if any. if (_thumbnail != null) { Debug.Assert(_supportsGlobalThumbnail); SafeMILHandle thumbnailBitmapSource = _thumbnail.WicSourceHandle; lock (_thumbnail.SyncObject) { HRESULT.Check(UnsafeNativeMethods.WICBitmapEncoder.SetThumbnail( encoderHandle, thumbnailBitmapSource )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.EncoderThumbnailSet; } } // Save global palette if any. if (_palette != null && _palette.Colors.Count > 0) { SafeMILHandle paletteHandle = _palette.InternalPalette; HRESULT.Check(UnsafeNativeMethods.WICBitmapEncoder.SetPalette( encoderHandle, paletteHandle )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.EncoderPaletteSet; } // Save global metadata if any. if (_metadata != null && _metadata.GuidFormat == ContainerFormat) { Debug.Assert(_supportsGlobalMetadata); EnsureMetadata(false); if (_metadata.InternalMetadataHandle != _metadataHandle) { PROPVARIANT propVar = new PROPVARIANT(); try { propVar.Init(_metadata); lock (_metadata.SyncObject) { HRESULT.Check(UnsafeNativeMethods.WICMetadataQueryWriter.SetMetadataByName( _metadataHandle, "/", ref propVar )); } } finally { propVar.Clear(); } } } for (int i = 0; i < count; i++) { SafeMILHandle frameEncodeHandle = new SafeMILHandle(); SafeMILHandle encoderOptions = new SafeMILHandle(); HRESULT.Check(UnsafeNativeMethods.WICBitmapEncoder.CreateNewFrame( encoderHandle, out frameEncodeHandle, out encoderOptions )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.EncoderCreatedNewFrame; _frameHandles.Add(frameEncodeHandle); SaveFrame(frameEncodeHandle, encoderOptions, _frames[i]); // If multiple frames are not supported, break out if (!_supportsMultipleFrames) { break; } } // Now let the encoder know we are done encoding the file. HRESULT.Check(UnsafeNativeMethods.WICBitmapEncoder.Commit(encoderHandle)); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.EncoderCommitted; } finally { UnsafeNativeMethods.MILUnknown.ReleaseInterface(ref comStream); } _hasSaved = true; } #endregion #region Internal Properties / Methods ////// Returns the container format for this encoder /// internal virtual Guid ContainerFormat { get { return Guid.Empty; } } ////// Returns whether metadata is fixed size or not. /// internal virtual bool IsMetadataFixedSize { get { return false; } } ////// Setups the encoder and other properties before encoding each frame /// internal virtual void SetupFrame(SafeMILHandle frameEncodeHandle, SafeMILHandle encoderOptions) { throw new NotImplementedException(); } #endregion #region Private Methods ////// Checks to see if encoder is built in. /// private void EnsureBuiltIn() { if (!_isBuiltIn) { throw new NotImplementedException(); } } ////// Checks to see if encoder has built-in metadata. /// ////// Critical - Accesses unmanaged code /// TreatAsSafe - inputs are verified or safe /// [SecurityCritical, SecurityTreatAsSafe] private void EnsureMetadata(bool createBitmapMetadata) { if (!_supportsGlobalMetadata) { return; } if (_metadataHandle == null) { SafeMILHandle /* IWICMetadataQueryWriter */ metadataHandle = new SafeMILHandle(); int hr = UnsafeNativeMethods.WICBitmapEncoder.GetMetadataQueryWriter( _encoderHandle, out metadataHandle ); if (hr == (int)WinCodecErrors.WINCODEC_ERR_UNSUPPORTEDOPERATION) { _supportsGlobalMetadata = false; return; } HRESULT.Check(hr); _metadataHandle = metadataHandle; } if (createBitmapMetadata && _metadata == null && _metadataHandle != null) { _metadata = new BitmapMetadata(_metadataHandle, false, IsMetadataFixedSize, _metadataHandle); } } ////// Creates the unmanaged encoder object /// ////// Critical - calls unmanaged code, codecs, creates codec based on GUID /// [SecurityCritical] private void EnsureUnmanagedEncoder() { if (_encoderHandle == null) { using (FactoryMaker myFactory = new FactoryMaker()) { SafeMILHandle encoderHandle = null; Guid vendorMicrosoft = new Guid(MILGuidData.GUID_VendorMicrosoft); Guid containerFormat = ContainerFormat; HRESULT.Check(UnsafeNativeMethods.WICImagingFactory.CreateEncoder( myFactory.ImagingFactoryPtr, ref containerFormat, ref vendorMicrosoft, out encoderHandle )); _encoderHandle = encoderHandle; } } } ////// Save the frame /// ////// Critical - calls unmanaged code /// [SecurityCritical] private void SaveFrame(SafeMILHandle frameEncodeHandle, SafeMILHandle encoderOptions, BitmapFrame frame) { SetupFrame(frameEncodeHandle, encoderOptions); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeInitialized; // Set the size HRESULT.Check(UnsafeNativeMethods.WICBitmapFrameEncode.SetSize( frameEncodeHandle, frame.PixelWidth, frame.PixelHeight )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeSizeSet; // Set the resolution double dpiX = frame.DpiX; double dpiY = frame.DpiY; if (dpiX <= 0) { dpiX = 96; } if (dpiY <= 0) { dpiY = 96; } HRESULT.Check(UnsafeNativeMethods.WICBitmapFrameEncode.SetResolution( frameEncodeHandle, dpiX, dpiY )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeResolutionSet; if (_supportsFrameThumbnails) { // Set the thumbnail. BitmapSource thumbnail = frame.Thumbnail; if (thumbnail != null) { SafeMILHandle thumbnailHandle = thumbnail.WicSourceHandle; lock (thumbnail.SyncObject) { HRESULT.Check(UnsafeNativeMethods.WICBitmapFrameEncode.SetThumbnail( frameEncodeHandle, thumbnailHandle )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeThumbnailSet; } } } //if the source has been color corrected, we want to use a corresponding color profile if (frame._isColorCorrected) { unsafe { IntPtr* pcolorContextslocal = stackalloc IntPtr[1]; pcolorContextslocal[0] = IntPtr.Zero; try { Guid wicColorContextGuid = MILGuidData.IID_IWICColorContext; ColorContext colorContext = new ColorContext(frame.Format); HRESULT.Check(UnsafeNativeMethods.MILUnknown.QueryInterface(colorContext.ColorContextHandle, ref wicColorContextGuid, out pcolorContextslocal[0])); int hr = UnsafeNativeMethods.WICBitmapFrameEncode.SetColorContexts( frameEncodeHandle, (uint)1, (IntPtr)pcolorContextslocal ); // It's possible that some encoders may not support color contexts if (hr == HRESULT.S_OK) { // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeColorContextsSet; } } finally { #pragma warning suppress 6031 UnsafeNativeMethods.MILUnknown.Release(pcolorContextslocal[0]); } } } // if the caller has explicitly provided color context(s), add it/them to the encoder else if ((frame.ColorContexts != null) && (frame.ColorContexts.Count > 0)) { unsafe { int iCount = frame.ColorContexts.Count; IntPtr* pcolorContextslocal = stackalloc IntPtr[iCount]; for (int i = 0; i < iCount; i++) pcolorContextslocal[i] = IntPtr.Zero; try { for (int i = 0; i < iCount; i++) { Guid wicColorContextGuid = MILGuidData.IID_IWICColorContext; HRESULT.Check(UnsafeNativeMethods.MILUnknown.QueryInterface(frame.ColorContexts[i].ColorContextHandle, ref wicColorContextGuid, out pcolorContextslocal[i])); } int hr = UnsafeNativeMethods.WICBitmapFrameEncode.SetColorContexts( frameEncodeHandle, (uint)iCount, (IntPtr)pcolorContextslocal ); // It's possible that some encoders may not support color contexts if (hr == HRESULT.S_OK) { // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeColorContextsSet; } } finally { for (int i = 0; i < iCount; i++) { #pragma warning suppress 6031 UnsafeNativeMethods.MILUnknown.Release(pcolorContextslocal[i]); } } } } // Set the pixel format and palette lock (frame.SyncObject) { SafeMILHandle outSourceHandle = new SafeMILHandle(); SafeMILHandle bitmapSourceHandle = frame.WicSourceHandle; SafeMILHandle paletteHandle = new SafeMILHandle(); // Set the pixel format and palette of the bitmap. // This could (but hopefully won't) introduce a format converter. HRESULT.Check(UnsafeNativeMethods.WICCodec.WICSetEncoderFormat( bitmapSourceHandle, paletteHandle, frameEncodeHandle, out outSourceHandle )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeFormatSet; _writeSourceHandles.Add(outSourceHandle); // Set the metadata if (_supportsFrameMetadata) { BitmapMetadata metadata = frame.Metadata as BitmapMetadata; // If the frame has metadata associated with a different container format, then we ignore it. if (metadata != null && metadata.GuidFormat == ContainerFormat) { SafeMILHandle /* IWICMetadataQueryWriter */ metadataHandle = new SafeMILHandle(); HRESULT.Check(UnsafeNativeMethods.WICBitmapFrameEncode.GetMetadataQueryWriter( frameEncodeHandle, out metadataHandle )); PROPVARIANT propVar = new PROPVARIANT(); try { propVar.Init(metadata); lock (metadata.SyncObject) { HRESULT.Check(UnsafeNativeMethods.WICMetadataQueryWriter.SetMetadataByName( metadataHandle, "/", ref propVar )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeMetadataSet; } } finally { propVar.Clear(); } } } Int32Rect r = new Int32Rect(); HRESULT.Check(UnsafeNativeMethods.WICBitmapFrameEncode.WriteSource( frameEncodeHandle, outSourceHandle, ref r )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeSourceWritten; HRESULT.Check(UnsafeNativeMethods.WICBitmapFrameEncode.Commit( frameEncodeHandle )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeCommitted; } } #endregion #region Internal Abstract /// "Seals" the object internal abstract void SealObject(); #endregion #region Data Members /// does encoder support a preview? internal bool _supportsPreview = true; /// does encoder support a global thumbnail? internal bool _supportsGlobalThumbnail = true; /// does encoder support a global metadata? internal bool _supportsGlobalMetadata = true; /// does encoder support per frame thumbnails? internal bool _supportsFrameThumbnails = true; /// does encoder support per frame thumbnails? internal bool _supportsFrameMetadata = true; /// does encoder support multiple frames? internal bool _supportsMultipleFrames = false; /// does encoder support color context? internal bool _supportsColorContext = false; /// is it a built in encoder private bool _isBuiltIn; /// Internal WIC encoder handle private SafeMILHandle _encoderHandle; /// metadata private BitmapMetadata _metadata; /// Internal WIC metadata handle private SafeMILHandle _metadataHandle; /// colorcontext private ReadOnlyCollection_readOnlycolorContexts; /// codecinfo private BitmapCodecInfoInternal _codecInfo; /// thumbnail private BitmapSource _thumbnail; /// preview private BitmapSource _preview; /// palette private BitmapPalette _palette; /// frames private IList _frames; /// true if Save has been called. private bool _hasSaved; /// The below data members have been added for stress or remote dump debugging purposes /// By the time we get an exception in managed code, we loose all context of what was /// on the stack and our locals are gone. The below will cache some critcal locals and state /// so they can be retrieved during debugging. private IList _frameHandles = new List (0); private IList _writeSourceHandles = new List (0); private enum EncodeState { None = 0, EncoderInitialized = 1, EncoderThumbnailSet = 2, EncoderPaletteSet = 3, EncoderCreatedNewFrame = 4, FrameEncodeInitialized = 5, FrameEncodeSizeSet = 6, FrameEncodeResolutionSet = 7, FrameEncodeThumbnailSet = 8, FrameEncodeMetadataSet = 9, FrameEncodeFormatSet = 10, FrameEncodeSourceWritten = 11, FrameEncodeCommitted = 12, EncoderCommitted = 13, FrameEncodeColorContextsSet = 14, }; private EncodeState _encodeState; #endregion } #endregion // BitmapEncoder } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation, 2003 // // File: BitmapEncoder.cs // //----------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.ComponentModel.Design.Serialization; using System.Reflection; using System.IO; using MS.Internal; using System.Diagnostics; using System.Windows.Media; using System.Windows.Threading; using System.Globalization; using System.Runtime.InteropServices; using System.Windows.Media.Imaging; using System.Security; using System.Security.Permissions; using MS.Win32.PresentationCore; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; using System.Diagnostics.CodeAnalysis; #pragma warning disable 1634, 1691 // suppressing PreSharp warnings namespace System.Windows.Media.Imaging { #region PROPBAG2 [StructLayout(LayoutKind.Sequential, Pack=1)] internal struct PROPBAG2 { internal UInt32 dwType; internal ushort vt; internal ushort cfType; internal IntPtr dwHint; [SecurityCritical] internal IntPtr pstrName; //this is string array internal Guid clsid; /// /// Critical -Initializes a pointer to unmanaged memory to hold onto a string /// TreatAsSafe - there are no inputs /// [SecurityCritical, SecurityTreatAsSafe] internal void Init(String name) { pstrName = Marshal.StringToCoTaskMemUni(name); } ////// Critical -Releases an unmanaged pointer into unmanaged memory. /// TreatAsSafe - there are no inputs /// [SecurityCritical, SecurityTreatAsSafe] internal void Clear() { Marshal.FreeCoTaskMem(pstrName); pstrName = IntPtr.Zero; } } #endregion #region BitmapEncoder ////// BitmapEncoder collects a set of frames (BitmapSource's) with their associated /// thumbnails and saves them to a specified stream. In addition /// to frame-specific thumbnails, there can also be an bitmap-wide /// (global) thumbnail, if the codec supports it. /// public abstract class BitmapEncoder : DispatcherObject { #region Constructors ////// Constructor. /// protected BitmapEncoder() { } ////// Internal Constructor. /// internal BitmapEncoder(bool isBuiltIn) { _isBuiltIn = isBuiltIn; } ////// Creates a BitmapEncoder from a container format Guid /// /// Container format for the codec ////// Critical - guid used for creation of critical resources /// [SecurityCritical] public static BitmapEncoder Create(Guid containerFormat) { if (containerFormat == Guid.Empty) { throw new ArgumentException( SR.Get(SRID.Image_GuidEmpty, "containerFormat"), "containerFormat" ); } else if (containerFormat == MILGuidData.GUID_ContainerFormatBmp) { return new BmpBitmapEncoder(); } else if (containerFormat == MILGuidData.GUID_ContainerFormatGif) { return new GifBitmapEncoder(); } else if (containerFormat == MILGuidData.GUID_ContainerFormatJpeg) { return new JpegBitmapEncoder(); } else if (containerFormat == MILGuidData.GUID_ContainerFormatPng) { return new PngBitmapEncoder(); } else if (containerFormat == MILGuidData.GUID_ContainerFormatTiff) { return new TiffBitmapEncoder(); } else if (containerFormat == MILGuidData.GUID_ContainerFormatWmp) { return new WmpBitmapEncoder(); } else { return new UnknownBitmapEncoder(containerFormat); } } #endregion #region Public Properties ////// Set or get the bitmap's color profile. /// public virtual ReadOnlyCollectionColorContexts { get { VerifyAccess(); EnsureBuiltIn(); return _readOnlycolorContexts; } set { VerifyAccess(); EnsureBuiltIn(); if (value == null) { throw new ArgumentNullException("value"); } if (!_supportsColorContext) { throw new InvalidOperationException(SR.Get(SRID.Image_EncoderNoColorContext)); } _readOnlycolorContexts = value; } } /// /// Set or get the bitmap's global embedded thumbnail. /// public virtual BitmapSource Thumbnail { get { VerifyAccess(); EnsureBuiltIn(); return _thumbnail; } set { VerifyAccess(); EnsureBuiltIn(); if (value == null) { throw new ArgumentNullException("value"); } if (!_supportsGlobalThumbnail) { throw new InvalidOperationException(SR.Get(SRID.Image_EncoderNoGlobalThumbnail)); } _thumbnail = value; } } ////// Set or get the bitmap's global embedded metadata. /// public virtual BitmapMetadata Metadata { get { VerifyAccess(); EnsureBuiltIn(); EnsureMetadata(true); return _metadata; } set { VerifyAccess(); EnsureBuiltIn(); if (value == null) { throw new ArgumentNullException("value"); } if (value.GuidFormat != ContainerFormat) { throw new InvalidOperationException(SR.Get(SRID.Image_MetadataNotCompatible)); } if (!_supportsGlobalMetadata) { throw new InvalidOperationException(SR.Get(SRID.Image_EncoderNoGlobalMetadata)); } _metadata = value; } } ////// Set or get the bitmap's global preview /// public virtual BitmapSource Preview { get { VerifyAccess(); EnsureBuiltIn(); return _preview; } set { VerifyAccess(); EnsureBuiltIn(); if (value == null) { throw new ArgumentNullException("value"); } if (!_supportsPreview) { throw new InvalidOperationException(SR.Get(SRID.Image_EncoderNoPreview)); } _preview = value; } } ////// The info that identifies this codec. /// ////// Critical - Access unmanaged code, codecs /// PublicOK - Getting codecinfo data is OK /// public virtual BitmapCodecInfo CodecInfo { [SecurityCritical ] get { VerifyAccess(); EnsureBuiltIn(); EnsureUnmanagedEncoder(); // There should always be a codec info. if (_codecInfo == null) { SafeMILHandle /* IWICBitmapEncoderInfo */ codecInfoHandle = new SafeMILHandle(); HRESULT.Check(UnsafeNativeMethods.WICBitmapEncoder.GetEncoderInfo( _encoderHandle, out codecInfoHandle )); _codecInfo = new BitmapCodecInfoInternal(codecInfoHandle); } return _codecInfo; } } ////// Provides access to this bitmap's palette /// public virtual BitmapPalette Palette { get { VerifyAccess(); EnsureBuiltIn(); return _palette; } set { VerifyAccess(); EnsureBuiltIn(); if (value == null) { throw new ArgumentNullException("value"); } _palette = value; } } ////// Access to the individual frames. /// public virtual IListFrames { get { VerifyAccess(); EnsureBuiltIn(); if (_frames == null) { _frames = new List (0); } return _frames; } set { VerifyAccess(); EnsureBuiltIn(); if (value == null) { throw new ArgumentNullException("value"); } _frames = value; } } #endregion #region Public Methods /// /// Save (encode) the bitmap to the specified stream. /// /// Stream to save into ////// Critical - calls unmanaged code /// [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] [SecurityCritical] public virtual void Save(System.IO.Stream stream) { VerifyAccess(); EnsureBuiltIn(); EnsureUnmanagedEncoder(); // No-op to get rid of build error if (_encodeState == EncodeState.None) { } if (_hasSaved) { throw new InvalidOperationException(SR.Get(SRID.Image_OnlyOneSave)); } if (_frames == null) { throw new System.NotSupportedException(SR.Get(SRID.Image_NoFrames, null)); } int count = _frames.Count; if (count <= 0) { throw new System.NotSupportedException(SR.Get(SRID.Image_NoFrames, null)); } IntPtr comStream = IntPtr.Zero; SafeMILHandle encoderHandle = _encoderHandle; try { comStream = StreamAsIStream.IStreamFrom(stream); // does this addref the stream? HRESULT.Check(UnsafeNativeMethods.WICBitmapEncoder.Initialize( encoderHandle, comStream, WICBitmapEncodeCacheOption.WICBitmapEncodeNoCache )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.EncoderInitialized; // Save global thumbnail if any. if (_thumbnail != null) { Debug.Assert(_supportsGlobalThumbnail); SafeMILHandle thumbnailBitmapSource = _thumbnail.WicSourceHandle; lock (_thumbnail.SyncObject) { HRESULT.Check(UnsafeNativeMethods.WICBitmapEncoder.SetThumbnail( encoderHandle, thumbnailBitmapSource )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.EncoderThumbnailSet; } } // Save global palette if any. if (_palette != null && _palette.Colors.Count > 0) { SafeMILHandle paletteHandle = _palette.InternalPalette; HRESULT.Check(UnsafeNativeMethods.WICBitmapEncoder.SetPalette( encoderHandle, paletteHandle )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.EncoderPaletteSet; } // Save global metadata if any. if (_metadata != null && _metadata.GuidFormat == ContainerFormat) { Debug.Assert(_supportsGlobalMetadata); EnsureMetadata(false); if (_metadata.InternalMetadataHandle != _metadataHandle) { PROPVARIANT propVar = new PROPVARIANT(); try { propVar.Init(_metadata); lock (_metadata.SyncObject) { HRESULT.Check(UnsafeNativeMethods.WICMetadataQueryWriter.SetMetadataByName( _metadataHandle, "/", ref propVar )); } } finally { propVar.Clear(); } } } for (int i = 0; i < count; i++) { SafeMILHandle frameEncodeHandle = new SafeMILHandle(); SafeMILHandle encoderOptions = new SafeMILHandle(); HRESULT.Check(UnsafeNativeMethods.WICBitmapEncoder.CreateNewFrame( encoderHandle, out frameEncodeHandle, out encoderOptions )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.EncoderCreatedNewFrame; _frameHandles.Add(frameEncodeHandle); SaveFrame(frameEncodeHandle, encoderOptions, _frames[i]); // If multiple frames are not supported, break out if (!_supportsMultipleFrames) { break; } } // Now let the encoder know we are done encoding the file. HRESULT.Check(UnsafeNativeMethods.WICBitmapEncoder.Commit(encoderHandle)); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.EncoderCommitted; } finally { UnsafeNativeMethods.MILUnknown.ReleaseInterface(ref comStream); } _hasSaved = true; } #endregion #region Internal Properties / Methods ////// Returns the container format for this encoder /// internal virtual Guid ContainerFormat { get { return Guid.Empty; } } ////// Returns whether metadata is fixed size or not. /// internal virtual bool IsMetadataFixedSize { get { return false; } } ////// Setups the encoder and other properties before encoding each frame /// internal virtual void SetupFrame(SafeMILHandle frameEncodeHandle, SafeMILHandle encoderOptions) { throw new NotImplementedException(); } #endregion #region Private Methods ////// Checks to see if encoder is built in. /// private void EnsureBuiltIn() { if (!_isBuiltIn) { throw new NotImplementedException(); } } ////// Checks to see if encoder has built-in metadata. /// ////// Critical - Accesses unmanaged code /// TreatAsSafe - inputs are verified or safe /// [SecurityCritical, SecurityTreatAsSafe] private void EnsureMetadata(bool createBitmapMetadata) { if (!_supportsGlobalMetadata) { return; } if (_metadataHandle == null) { SafeMILHandle /* IWICMetadataQueryWriter */ metadataHandle = new SafeMILHandle(); int hr = UnsafeNativeMethods.WICBitmapEncoder.GetMetadataQueryWriter( _encoderHandle, out metadataHandle ); if (hr == (int)WinCodecErrors.WINCODEC_ERR_UNSUPPORTEDOPERATION) { _supportsGlobalMetadata = false; return; } HRESULT.Check(hr); _metadataHandle = metadataHandle; } if (createBitmapMetadata && _metadata == null && _metadataHandle != null) { _metadata = new BitmapMetadata(_metadataHandle, false, IsMetadataFixedSize, _metadataHandle); } } ////// Creates the unmanaged encoder object /// ////// Critical - calls unmanaged code, codecs, creates codec based on GUID /// [SecurityCritical] private void EnsureUnmanagedEncoder() { if (_encoderHandle == null) { using (FactoryMaker myFactory = new FactoryMaker()) { SafeMILHandle encoderHandle = null; Guid vendorMicrosoft = new Guid(MILGuidData.GUID_VendorMicrosoft); Guid containerFormat = ContainerFormat; HRESULT.Check(UnsafeNativeMethods.WICImagingFactory.CreateEncoder( myFactory.ImagingFactoryPtr, ref containerFormat, ref vendorMicrosoft, out encoderHandle )); _encoderHandle = encoderHandle; } } } ////// Save the frame /// ////// Critical - calls unmanaged code /// [SecurityCritical] private void SaveFrame(SafeMILHandle frameEncodeHandle, SafeMILHandle encoderOptions, BitmapFrame frame) { SetupFrame(frameEncodeHandle, encoderOptions); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeInitialized; // Set the size HRESULT.Check(UnsafeNativeMethods.WICBitmapFrameEncode.SetSize( frameEncodeHandle, frame.PixelWidth, frame.PixelHeight )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeSizeSet; // Set the resolution double dpiX = frame.DpiX; double dpiY = frame.DpiY; if (dpiX <= 0) { dpiX = 96; } if (dpiY <= 0) { dpiY = 96; } HRESULT.Check(UnsafeNativeMethods.WICBitmapFrameEncode.SetResolution( frameEncodeHandle, dpiX, dpiY )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeResolutionSet; if (_supportsFrameThumbnails) { // Set the thumbnail. BitmapSource thumbnail = frame.Thumbnail; if (thumbnail != null) { SafeMILHandle thumbnailHandle = thumbnail.WicSourceHandle; lock (thumbnail.SyncObject) { HRESULT.Check(UnsafeNativeMethods.WICBitmapFrameEncode.SetThumbnail( frameEncodeHandle, thumbnailHandle )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeThumbnailSet; } } } //if the source has been color corrected, we want to use a corresponding color profile if (frame._isColorCorrected) { unsafe { IntPtr* pcolorContextslocal = stackalloc IntPtr[1]; pcolorContextslocal[0] = IntPtr.Zero; try { Guid wicColorContextGuid = MILGuidData.IID_IWICColorContext; ColorContext colorContext = new ColorContext(frame.Format); HRESULT.Check(UnsafeNativeMethods.MILUnknown.QueryInterface(colorContext.ColorContextHandle, ref wicColorContextGuid, out pcolorContextslocal[0])); int hr = UnsafeNativeMethods.WICBitmapFrameEncode.SetColorContexts( frameEncodeHandle, (uint)1, (IntPtr)pcolorContextslocal ); // It's possible that some encoders may not support color contexts if (hr == HRESULT.S_OK) { // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeColorContextsSet; } } finally { #pragma warning suppress 6031 UnsafeNativeMethods.MILUnknown.Release(pcolorContextslocal[0]); } } } // if the caller has explicitly provided color context(s), add it/them to the encoder else if ((frame.ColorContexts != null) && (frame.ColorContexts.Count > 0)) { unsafe { int iCount = frame.ColorContexts.Count; IntPtr* pcolorContextslocal = stackalloc IntPtr[iCount]; for (int i = 0; i < iCount; i++) pcolorContextslocal[i] = IntPtr.Zero; try { for (int i = 0; i < iCount; i++) { Guid wicColorContextGuid = MILGuidData.IID_IWICColorContext; HRESULT.Check(UnsafeNativeMethods.MILUnknown.QueryInterface(frame.ColorContexts[i].ColorContextHandle, ref wicColorContextGuid, out pcolorContextslocal[i])); } int hr = UnsafeNativeMethods.WICBitmapFrameEncode.SetColorContexts( frameEncodeHandle, (uint)iCount, (IntPtr)pcolorContextslocal ); // It's possible that some encoders may not support color contexts if (hr == HRESULT.S_OK) { // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeColorContextsSet; } } finally { for (int i = 0; i < iCount; i++) { #pragma warning suppress 6031 UnsafeNativeMethods.MILUnknown.Release(pcolorContextslocal[i]); } } } } // Set the pixel format and palette lock (frame.SyncObject) { SafeMILHandle outSourceHandle = new SafeMILHandle(); SafeMILHandle bitmapSourceHandle = frame.WicSourceHandle; SafeMILHandle paletteHandle = new SafeMILHandle(); // Set the pixel format and palette of the bitmap. // This could (but hopefully won't) introduce a format converter. HRESULT.Check(UnsafeNativeMethods.WICCodec.WICSetEncoderFormat( bitmapSourceHandle, paletteHandle, frameEncodeHandle, out outSourceHandle )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeFormatSet; _writeSourceHandles.Add(outSourceHandle); // Set the metadata if (_supportsFrameMetadata) { BitmapMetadata metadata = frame.Metadata as BitmapMetadata; // If the frame has metadata associated with a different container format, then we ignore it. if (metadata != null && metadata.GuidFormat == ContainerFormat) { SafeMILHandle /* IWICMetadataQueryWriter */ metadataHandle = new SafeMILHandle(); HRESULT.Check(UnsafeNativeMethods.WICBitmapFrameEncode.GetMetadataQueryWriter( frameEncodeHandle, out metadataHandle )); PROPVARIANT propVar = new PROPVARIANT(); try { propVar.Init(metadata); lock (metadata.SyncObject) { HRESULT.Check(UnsafeNativeMethods.WICMetadataQueryWriter.SetMetadataByName( metadataHandle, "/", ref propVar )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeMetadataSet; } } finally { propVar.Clear(); } } } Int32Rect r = new Int32Rect(); HRESULT.Check(UnsafeNativeMethods.WICBitmapFrameEncode.WriteSource( frameEncodeHandle, outSourceHandle, ref r )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeSourceWritten; HRESULT.Check(UnsafeNativeMethods.WICBitmapFrameEncode.Commit( frameEncodeHandle )); // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeCommitted; } } #endregion #region Internal Abstract /// "Seals" the object internal abstract void SealObject(); #endregion #region Data Members /// does encoder support a preview? internal bool _supportsPreview = true; /// does encoder support a global thumbnail? internal bool _supportsGlobalThumbnail = true; /// does encoder support a global metadata? internal bool _supportsGlobalMetadata = true; /// does encoder support per frame thumbnails? internal bool _supportsFrameThumbnails = true; /// does encoder support per frame thumbnails? internal bool _supportsFrameMetadata = true; /// does encoder support multiple frames? internal bool _supportsMultipleFrames = false; /// does encoder support color context? internal bool _supportsColorContext = false; /// is it a built in encoder private bool _isBuiltIn; /// Internal WIC encoder handle private SafeMILHandle _encoderHandle; /// metadata private BitmapMetadata _metadata; /// Internal WIC metadata handle private SafeMILHandle _metadataHandle; /// colorcontext private ReadOnlyCollection_readOnlycolorContexts; /// codecinfo private BitmapCodecInfoInternal _codecInfo; /// thumbnail private BitmapSource _thumbnail; /// preview private BitmapSource _preview; /// palette private BitmapPalette _palette; /// frames private IList _frames; /// true if Save has been called. private bool _hasSaved; /// The below data members have been added for stress or remote dump debugging purposes /// By the time we get an exception in managed code, we loose all context of what was /// on the stack and our locals are gone. The below will cache some critcal locals and state /// so they can be retrieved during debugging. private IList _frameHandles = new List (0); private IList _writeSourceHandles = new List (0); private enum EncodeState { None = 0, EncoderInitialized = 1, EncoderThumbnailSet = 2, EncoderPaletteSet = 3, EncoderCreatedNewFrame = 4, FrameEncodeInitialized = 5, FrameEncodeSizeSet = 6, FrameEncodeResolutionSet = 7, FrameEncodeThumbnailSet = 8, FrameEncodeMetadataSet = 9, FrameEncodeFormatSet = 10, FrameEncodeSourceWritten = 11, FrameEncodeCommitted = 12, EncoderCommitted = 13, FrameEncodeColorContextsSet = 14, }; private EncodeState _encodeState; #endregion } #endregion // BitmapEncoder } // 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
- DiagnosticsConfigurationHandler.cs
- TextEditorSelection.cs
- CodePageUtils.cs
- Section.cs
- TableStyle.cs
- PageStatePersister.cs
- CalendarAutomationPeer.cs
- TreeNodeSelectionProcessor.cs
- SymbolDocumentGenerator.cs
- XmlAttributeCollection.cs
- SqlStream.cs
- XmlReaderSettings.cs
- ProvidePropertyAttribute.cs
- CssClassPropertyAttribute.cs
- precedingsibling.cs
- UshortList2.cs
- ExtendedProtectionPolicy.cs
- NativeWindow.cs
- RequiredFieldValidator.cs
- UriTemplateHelpers.cs
- DrawingAttributes.cs
- securitycriticaldata.cs
- StylusPoint.cs
- SafeNativeMethods.cs
- Classification.cs
- CodeAssignStatement.cs
- EventManager.cs
- CursorConverter.cs
- Canvas.cs
- InvalidFilterCriteriaException.cs
- SqlConnectionPoolGroupProviderInfo.cs
- OutputCacheSettings.cs
- GridEntryCollection.cs
- InstalledFontCollection.cs
- DependencyObjectType.cs
- QilValidationVisitor.cs
- HostingPreferredMapPath.cs
- util.cs
- HopperCache.cs
- HtmlControlPersistable.cs
- _RequestCacheProtocol.cs
- InvokeCompletedEventArgs.cs
- ElementNotAvailableException.cs
- CacheForPrimitiveTypes.cs
- TraceListeners.cs
- XmlAutoDetectWriter.cs
- CalendarDay.cs
- EntityObject.cs
- DataGridItemCollection.cs
- MethodExpr.cs
- FormViewPageEventArgs.cs
- ECDiffieHellman.cs
- ObjectStorage.cs
- XmlWrappingWriter.cs
- cache.cs
- DataGridViewColumnCollection.cs
- LocalFileSettingsProvider.cs
- RegexRunnerFactory.cs
- Accessible.cs
- Typography.cs
- SqlInternalConnectionSmi.cs
- SecurityRuntime.cs
- ConfigsHelper.cs
- FaultDescription.cs
- SafeArrayRankMismatchException.cs
- ObjectHelper.cs
- MarkupWriter.cs
- XmlSerializationReader.cs
- StructuralType.cs
- DataRow.cs
- HttpApplicationStateWrapper.cs
- ServiceModelExtensionElement.cs
- BaseInfoTable.cs
- Sql8ExpressionRewriter.cs
- SendReply.cs
- ScriptReferenceEventArgs.cs
- MethodCallConverter.cs
- XmlSerializerOperationBehavior.cs
- ListItemCollection.cs
- WebBrowserHelper.cs
- PropertyManager.cs
- DebugView.cs
- MinMaxParagraphWidth.cs
- UnsignedPublishLicense.cs
- GridViewColumnHeader.cs
- StrongNameMembershipCondition.cs
- PageFunction.cs
- ViewStateModeByIdAttribute.cs
- METAHEADER.cs
- ManualWorkflowSchedulerService.cs
- SqlConnectionManager.cs
- ScopeElement.cs
- ConfigurationElementProperty.cs
- _ConnectionGroup.cs
- CollectionViewSource.cs
- WindowsUserNameSecurityTokenAuthenticator.cs
- URLIdentityPermission.cs
- StreamGeometryContext.cs
- DesignerEditorPartChrome.cs
- DisableDpiAwarenessAttribute.cs