|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.ComponentModel;
using MS.Internal;
using MS.Win32.PresentationCore;
namespace System.Windows.Media.Imaging
{
#region FormatConvertedBitmap
/// <summary>
/// FormatConvertedBitmap provides caching functionality for a BitmapSource.
/// </summary>
public sealed partial class FormatConvertedBitmap : Imaging.BitmapSource, ISupportInitialize
{
/// <summary>
/// Constructor
/// </summary>
public FormatConvertedBitmap() : base(true)
{
}
/// <summary>
/// Construct a FormatConvertedBitmap
/// </summary>
/// <param name="source">BitmapSource to apply to the format conversion to</param>
/// <param name="destinationFormat">Destionation Format to apply to the bitmap</param>
/// <param name="destinationPalette">Palette if format is palettized</param>
/// <param name="alphaThreshold">Alpha threshold</param>
public FormatConvertedBitmap(BitmapSource source, PixelFormat destinationFormat, BitmapPalette destinationPalette, double alphaThreshold)
: base(true) // Use base class virtuals
{
ArgumentNullException.ThrowIfNull(source);
if (alphaThreshold < (double)(0.0) || alphaThreshold > (double)(100.0))
{
throw new ArgumentException(SR.Image_AlphaThresholdOutOfRange);
}
_bitmapInit.BeginInit();
Source = source;
DestinationFormat = destinationFormat;
DestinationPalette = destinationPalette;
AlphaThreshold = alphaThreshold;
_bitmapInit.EndInit();
FinalizeCreation();
}
// ISupportInitialize
/// <summary>
/// Prepare the bitmap to accept initialize paramters.
/// </summary>
public void BeginInit()
{
WritePreamble();
_bitmapInit.BeginInit();
}
/// <summary>
/// Prepare the bitmap to accept initialize paramters.
/// </summary>
public void EndInit()
{
WritePreamble();
_bitmapInit.EndInit();
IsValidForFinalizeCreation(/* throwIfInvalid = */ true);
FinalizeCreation();
}
private void ClonePrequel(FormatConvertedBitmap otherFormatConvertedBitmap)
{
BeginInit();
}
private void ClonePostscript(FormatConvertedBitmap otherFormatConvertedBitmap)
{
EndInit();
}
///
/// Create the unmanaged resources
///
internal override void FinalizeCreation()
{
_bitmapInit.EnsureInitializedComplete();
BitmapSourceSafeMILHandle wicFormatter = null;
using (FactoryMaker factoryMaker = new FactoryMaker())
{
try
{
IntPtr wicFactory = factoryMaker.ImagingFactoryPtr;
HRESULT.Check(UnsafeNativeMethods.WICImagingFactory.CreateFormatConverter(
wicFactory,
out wicFormatter));
SafeMILHandle internalPalette;
if (DestinationPalette != null)
internalPalette = DestinationPalette.InternalPalette;
else
internalPalette = new SafeMILHandle();
Guid format = DestinationFormat.Guid;
lock (_syncObject)
{
HRESULT.Check(UnsafeNativeMethods.WICFormatConverter.Initialize(
wicFormatter,
Source.WicSourceHandle,
ref format,
DitherType.DitherTypeErrorDiffusion,
internalPalette,
AlphaThreshold,
WICPaletteType.WICPaletteTypeOptimal
));
}
//
// This is just a link in a BitmapSource chain. The memory is being used by
// the BitmapSource at the end of the chain, so no memory pressure needs
// to be added here.
//
WicSourceHandle = wicFormatter;
// Even if our source is cached, format conversion is expensive and so we'll
// always maintain our own cache for the purpose of rendering.
_isSourceCached = false;
}
catch
{
_bitmapInit.Reset();
throw;
}
finally
{
if (wicFormatter != null)
{
wicFormatter.Close();
}
}
}
CreationCompleted = true;
UpdateCachedSettings();
}
/// <summary>
/// Notification on source changing.
/// </summary>
private void SourcePropertyChangedHook(DependencyPropertyChangedEventArgs e)
{
if (!e.IsASubPropertyChange)
{
BitmapSource newSource = e.NewValue as BitmapSource;
_source = newSource;
RegisterDownloadEventSource(_source);
_syncObject = (newSource != null) ? newSource.SyncObject : _bitmapInit;
}
}
internal override bool IsValidForFinalizeCreation(bool throwIfInvalid)
{
if (Source == null)
{
if (throwIfInvalid)
{
throw new InvalidOperationException(SR.Format(SR.Image_NoArgument, "Source"));
}
return false;
}
if (DestinationFormat.Palettized)
{
if (DestinationPalette == null)
{
if (throwIfInvalid)
{
throw new InvalidOperationException(SR.Image_IndexedPixelFormatRequiresPalette);
}
return false;
}
else if ((1 << DestinationFormat.BitsPerPixel) < DestinationPalette.Colors.Count)
{
if (throwIfInvalid)
{
throw new InvalidOperationException(SR.Image_PaletteColorsDoNotMatchFormat);
}
return false;
}
}
return true;
}
/// <summary>
/// Notification on destination format changing.
/// </summary>
private void DestinationFormatPropertyChangedHook(DependencyPropertyChangedEventArgs e)
{
if (!e.IsASubPropertyChange)
{
_destinationFormat = (PixelFormat)e.NewValue;
}
}
/// <summary>
/// Notification on destination palette changing.
/// </summary>
private void DestinationPalettePropertyChangedHook(DependencyPropertyChangedEventArgs e)
{
if (!e.IsASubPropertyChange)
{
_destinationPalette = e.NewValue as BitmapPalette;
}
}
/// <summary>
/// Notification on alpha threshold changing.
/// </summary>
private void AlphaThresholdPropertyChangedHook(DependencyPropertyChangedEventArgs e)
{
if (!e.IsASubPropertyChange)
{
_alphaThreshold = (double)e.NewValue;
}
}
/// <summary>
/// Coerce Source
/// </summary>
private static object CoerceSource(DependencyObject d, object value)
{
FormatConvertedBitmap bitmap = (FormatConvertedBitmap)d;
if (!bitmap._bitmapInit.IsInInit)
{
return bitmap._source;
}
else
{
return value;
}
}
/// <summary>
/// Coerce DestinationFormat
/// </summary>
private static object CoerceDestinationFormat(DependencyObject d, object value)
{
FormatConvertedBitmap bitmap = (FormatConvertedBitmap)d;
if (!bitmap._bitmapInit.IsInInit)
{
return bitmap._destinationFormat;
}
else
{
//
// If the client is trying to create a FormatConvertedBitmap with a
// DestinationFormat == PixelFormats.Default, then coerce it to either
// the Source bitmaps format (providing the Source bitmap is non-null)
// or the original DP value.
//
if (((PixelFormat)value).Format == PixelFormatEnum.Default)
{
if (bitmap.Source != null)
{
return bitmap.Source.Format;
}
else
{
return bitmap._destinationFormat;
}
}
else
{
return value;
}
}
}
/// <summary>
/// Coerce DestinationPalette
/// </summary>
private static object CoerceDestinationPalette(DependencyObject d, object value)
{
FormatConvertedBitmap bitmap = (FormatConvertedBitmap)d;
if (!bitmap._bitmapInit.IsInInit)
{
return bitmap._destinationPalette;
}
else
{
return value;
}
}
/// <summary>
/// Coerce Transform
/// </summary>
private static object CoerceAlphaThreshold(DependencyObject d, object value)
{
FormatConvertedBitmap bitmap = (FormatConvertedBitmap)d;
if (!bitmap._bitmapInit.IsInInit)
{
return bitmap._alphaThreshold;
}
else
{
return value;
}
}
#region Data Members
private BitmapSource _source;
private PixelFormat _destinationFormat;
private BitmapPalette _destinationPalette;
private double _alphaThreshold;
#endregion
}
#endregion // FormatConvertedBitmap
}
|