File: System\Windows\ColorConvertedBitmapExtension.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework)
// 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.
 
/***************************************************************************\
*
*
*  Class for Xaml markup extension for static resource references.
*
*
\***************************************************************************/
using System.IO;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
 
namespace System.Windows
{
    /// <summary>
    ///  Class for Xaml markup extension for ColorConvertedBitmap with non-embedded profile.
    /// </summary>
    [MarkupExtensionReturnType(typeof(ColorConvertedBitmap))]
    public class ColorConvertedBitmapExtension : MarkupExtension
    {
        /// <summary>
        ///  Constructor that takes no parameters
        /// </summary>
        public ColorConvertedBitmapExtension()
        {
        }
        
        /// <summary>
        ///  Constructor that takes the markup for a "{ColorConvertedBitmap image source.icc destination.icc}"
        /// </summary>
        public ColorConvertedBitmapExtension(
            object image) 
        {
            ArgumentNullException.ThrowIfNull(image);
 
            string[] tokens = ((string)image).Split(' ');
 
            foreach (string str in tokens)
            {
                if (str.Length > 0)
                {
                    if (_image == null)
                    {
                        _image = str;
                    }
                    else if (_sourceProfile == null)
                    {
                        _sourceProfile = str;
                    }
                    else if (_destinationProfile == null)
                    {
                        _destinationProfile = str;
                    }
                    else
                    {
                        throw new InvalidOperationException(SR.ColorConvertedBitmapExtensionSyntax);
                    }
                }
            }
        }
        
        /// <summary>
        ///  Return an object that should be set on the targetObject's targetProperty
        ///  for this markup extension.  For ColorConvertedBitmapExtension, this is the object found in
        ///  a resource dictionary in the current parent chain that is keyed by ResourceKey
        /// </summary>
        /// <returns>
        ///  The object to set on this property.
        /// </returns>
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (_image == null)
            {
                throw new InvalidOperationException(SR.ColorConvertedBitmapExtensionNoSourceImage);
            }
            if (_sourceProfile == null)
            {
                throw new InvalidOperationException(SR.ColorConvertedBitmapExtensionNoSourceProfile);
            }
            
            // [BreakingChange] 
            // (NullReferenceException in ColorConvertedBitmapExtension.ProvideValue)
            // We really should throw an ArgumentNullException here for serviceProvider.
 
            // Save away the BaseUri.
            IUriContext uriContext = serviceProvider.GetService(typeof(IUriContext)) as IUriContext;
            if( uriContext == null )
            {
                throw new InvalidOperationException(SR.Format(SR.MarkupExtensionNoContext, GetType().Name, "IUriContext" ));
            }
            _baseUri = uriContext.BaseUri;
            
 
            Uri imageUri = GetResolvedUri(_image);
            Uri sourceProfileUri = GetResolvedUri(_sourceProfile);
            Uri destinationProfileUri = GetResolvedUri(_destinationProfile);
 
            ColorContext sourceContext = new ColorContext(sourceProfileUri);
            ColorContext destinationContext = destinationProfileUri != null ?
                                                new ColorContext(destinationProfileUri) :
                                                new ColorContext(PixelFormats.Default);
 
            BitmapDecoder decoder = BitmapDecoder.Create(
                                                                imageUri,
                                                                BitmapCreateOptions.IgnoreColorProfile | BitmapCreateOptions.IgnoreImageCache,
                                                                BitmapCacheOption.None
                                                                );
 
            BitmapSource bitmap = decoder.Frames[0];
            FormatConvertedBitmap formatConverted = new FormatConvertedBitmap(bitmap, PixelFormats.Bgra32, null, 0.0);
 
            object result = formatConverted;
 
            try
            {
                ColorConvertedBitmap colorConverted = new ColorConvertedBitmap(formatConverted, sourceContext, destinationContext, PixelFormats.Bgra32);
                result= colorConverted;
            }
            catch (FileFormatException)
            {   // Gracefully ignore non-matching profile
                // If the file contains a bad color context, we catch the exception here
                // since color transform isn't possible
                // with the given color context.
            }
 
            return result;
        }
 
        private Uri GetResolvedUri(string uri)
        {
            if (uri == null)
            {
                return null;
            }
 
            return new Uri(_baseUri,uri);
        }
 
        string _image;
        string _sourceProfile;
        Uri _baseUri;
        string _destinationProfile;
    }
}