//------------------------------------------------------
        //
        //  Public Properties
        //
        //------------------------------------------------------

        private static void SourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ColorConvertedBitmap target = ((ColorConvertedBitmap)d);


            target.SourcePropertyChangedHook(e);



            // The first change to the default value of a mutable collection property (e.g. GeometryGroup.Children)
            // will promote the property value from a default value to a local value. This is technically a sub-property
            // change because the collection was changed and not a new collection set (GeometryGroup.Children.
            // Add versus GeometryGroup.Children = myNewChildrenCollection). However, we never marshalled
            // the default value to the compositor. If the property changes from a default value, the new local value
            // needs to be marshalled to the compositor. We detect this scenario with the second condition
            // e.OldValueSource != e.NewValueSource. Specifically in this scenario the OldValueSource will be
            // Default and the NewValueSource will be Local.
            if (e.IsASubPropertyChange &&
                (e.OldValueSource == e.NewValueSource))
            {
                return;
            }



            target.PropertyChanged(SourceProperty);
        }
        private static void SourceColorContextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ColorConvertedBitmap target = ((ColorConvertedBitmap)d);


            target.SourceColorContextPropertyChangedHook(e);

            target.PropertyChanged(SourceColorContextProperty);
        }
        private static void DestinationFormatPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ColorConvertedBitmap target = ((ColorConvertedBitmap)d);


            target.DestinationFormatPropertyChangedHook(e);

            target.PropertyChanged(DestinationFormatProperty);
        }
예제 #4
0
        /// <summary>
        ///     Coerce DestinationFormat
        /// </summary>
        private static object CoerceDestinationFormat(DependencyObject d, object value)
        {
            ColorConvertedBitmap bitmap = (ColorConvertedBitmap)d;

            if (!bitmap._bitmapInit.IsInInit)
            {
                return(bitmap._destinationFormat);
            }
            else
            {
                return(value);
            }
        }
예제 #5
0
        /// <summary>
        ///     Coerce SourceColorContext
        /// </summary>
        private static object CoerceSourceColorContext(DependencyObject d, object value)
        {
            ColorConvertedBitmap bitmap = (ColorConvertedBitmap)d;

            if (!bitmap._bitmapInit.IsInInit)
            {
                return(bitmap._sourceColorContext);
            }
            else
            {
                return(value);
            }
        }
        /// <summary>
        /// Implementation of Freezable.GetCurrentValueAsFrozenCore()
        /// </summary>
        protected override void GetCurrentValueAsFrozenCore(Freezable source)
        {
            ColorConvertedBitmap sourceColorConvertedBitmap = (ColorConvertedBitmap)source;

            // Set any state required before actual clone happens
            ClonePrequel(sourceColorConvertedBitmap);

            base.GetCurrentValueAsFrozenCore(source);



            // Set state once clone has finished
            ClonePostscript(sourceColorConvertedBitmap);
        }
예제 #7
0
        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;
                }

                originalFmt = PixelFormat.GetPixelFormat(wicSource);
                PixelFormat destFmt = originalFmt;

                // check that we need to change the format of the bitmap
                if (0 == (createOptions & BitmapCreateOptions.PreservePixelFormat))
                {
                    if (!IsCompatibleFormat(originalFmt))
                        changeFormat = true;

                    destFmt = BitmapSource.GetClosestDUCEFormat(originalFmt, palette);
                }

                if (frame != null &&
                    (createOptions & BitmapCreateOptions.IgnoreColorProfile) == 0 &&
                    frame.ColorContexts != null &&
                    frame.ColorContexts[0] != null &&
                    frame.ColorContexts[0].IsValid &&
                    !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;
        }
        /// <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.Get(SRID.ColorConvertedBitmapExtensionNoSourceImage));
            } 
            if (_sourceProfile == null) 
            {
                throw new InvalidOperationException(SR.Get(SRID.ColorConvertedBitmapExtensionNoSourceProfile)); 
            }

            // [BreakingChange] Dev10 Bug #454108
            // 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.Get(SRID.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;
        }
예제 #9
0
        internal override void FinalizeCreation() 
        {
            _bitmapInit.EnsureInitializedComplete(); 
            Uri uri = UriSource; 
            if (_baseUri != null)
                uri = new Uri(_baseUri, UriSource); 

            if ((CreateOptions & BitmapCreateOptions.IgnoreImageCache) != 0)
            {
                ImagingCache.RemoveFromImageCache(uri); 
            }
 
            BitmapImage bitmapImage = CheckCache(uri); 

            if (bitmapImage != null && 
                bitmapImage.CheckAccess() &&
                bitmapImage.SourceRect.Equals(SourceRect) &&
                bitmapImage.DecodePixelWidth == DecodePixelWidth &&
                bitmapImage.DecodePixelHeight == DecodePixelHeight && 
                bitmapImage.Rotation == Rotation &&
                (bitmapImage.CreateOptions & BitmapCreateOptions.IgnoreColorProfile) == 
                (CreateOptions & BitmapCreateOptions.IgnoreColorProfile) 
               )
            { 
                _syncObject = bitmapImage.SyncObject;
                lock (_syncObject)
                {
                    WicSourceHandle = bitmapImage.WicSourceHandle; 
                    IsSourceCached = bitmapImage.IsSourceCached;
                    _convertedDUCEPtr = bitmapImage._convertedDUCEPtr; 
 
                    //
                    // We nee d to keep the strong reference to the cached image for a few reasons: 
                    //
                    //    The application may release the original cached image and then keep a
                    //    reference to this image only, in which case, the cache can be collected.
                    //    This will cause a few undesirable results: 
                    //    1. The application may choose to decode the same URI again in which case
                    //       we will not retrieve it from the cache even though we have a copy already 
                    //       decoded. 
                    //    2. The original cached image holds onto the file stream indirectly which if
                    //       collected can cause bad behavior if the entire image is not loaded into 
                    //       memory.
                    //
                    _cachedBitmapImage = bitmapImage;
                } 
                UpdateCachedSettings();
                return; 
            } 

            BitmapDecoder decoder = null; 
            if (_decoder == null)
            {
                // Note: We do not want to insert in the cache if there is a chance that
                //       the decode pixel width/height may cause the decoder LOD to change 
                decoder = BitmapDecoder.CreateFromUriOrStream(
                    _baseUri, 
                    UriSource, 
                    StreamSource,
                    CreateOptions & ~BitmapCreateOptions.DelayCreation, 
                    BitmapCacheOption.None, // do not cache the frames since we will do that here
                    _uriCachePolicy,
                    false
                    ); 

                if (decoder.IsDownloading) 
                { 
                    _isDownloading = true;
                    _decoder = decoder; 
                    decoder.DownloadProgress += OnDownloadProgress;
                    decoder.DownloadCompleted += OnDownloadCompleted;
                    decoder.DownloadFailed += OnDownloadFailed;
                } 
                else
                { 
                    Debug.Assert(decoder.SyncObject != null); 
                }
            } 
            else
            {
                // We already had a decoder, meaning we were downloading
                Debug.Assert(!_decoder.IsDownloading); 
                decoder = _decoder;
                _decoder = null; 
            } 

            if (decoder.Frames.Count == 0) 
            {
                throw new System.ArgumentException(SR.Get(SRID.Image_NoDecodeFrames));
            }
 
            BitmapFrame frame = decoder.Frames[0];
            BitmapSource source = frame; 
 
            Int32Rect sourceRect = SourceRect;
 
            if (sourceRect.X == 0 && sourceRect.Y == 0 &&
                sourceRect.Width == source.PixelWidth &&
                sourceRect.Height == source.PixelHeight)
            { 
                sourceRect = Int32Rect.Empty;
            } 
 
            if (!sourceRect.IsEmpty)
            { 
                CroppedBitmap croppedSource = new CroppedBitmap();
                croppedSource.BeginInit();
                croppedSource.Source = source;
                croppedSource.SourceRect = sourceRect; 
                croppedSource.EndInit();
 
                source = croppedSource; 
                if (_isDownloading)
                { 
                    // Unregister the download events because this is a dummy image. See comment below.
                    source.UnregisterDownloadEventSource();
                }
            } 

            int finalWidth = DecodePixelWidth; 
            int finalHeight = DecodePixelHeight; 

            if (finalWidth == 0 && finalHeight == 0) 
            {
                finalWidth = source.PixelWidth;
                finalHeight = source.PixelHeight;
            } 
            else if (finalWidth == 0)
            { 
                finalWidth = (source.PixelWidth * finalHeight) / source.PixelHeight; 
            }
            else if (finalHeight == 0) 
            {
                finalHeight = (source.PixelHeight * finalWidth) / source.PixelWidth;
            }
 
            if (finalWidth != source.PixelWidth || finalHeight != source.PixelHeight ||
                Rotation != Rotation.Rotate0) 
            { 
                TransformedBitmap transformedSource = new TransformedBitmap();
                transformedSource.BeginInit(); 
                transformedSource.Source = source;

                TransformGroup transformGroup = new TransformGroup();
 
                if (finalWidth != source.PixelWidth || finalHeight != source.PixelHeight)
                { 
                    int oldWidth = source.PixelWidth; 
                    int oldHeight = source.PixelHeight;
 
                    Debug.Assert(oldWidth > 0 && oldHeight > 0);

                    transformGroup.Children.Add(
                        new ScaleTransform( 
                            (1.0*finalWidth)/ oldWidth,
                            (1.0*finalHeight)/oldHeight)); 
                } 

                if (Rotation != Rotation.Rotate0) 
                {
                    double rotation = 0.0;

                    switch (Rotation) 
                    {
                        case Rotation.Rotate0: 
                            rotation = 0.0; 
                            break;
                        case Rotation.Rotate90: 
                            rotation = 90.0;
                            break;
                        case Rotation.Rotate180:
                            rotation = 180.0; 
                            break;
                        case Rotation.Rotate270: 
                            rotation = 270.0; 
                            break;
                        default: 
                            Debug.Assert(false);
                            break;
                    }
 
                    transformGroup.Children.Add(new RotateTransform(rotation));
                } 
 
                transformedSource.Transform = transformGroup;
 
                transformedSource.EndInit();

                source = transformedSource;
                if (_isDownloading) 
                {
                    // 
                    // If we're currently downloading, then the BitmapFrameDecode isn't actually 
                    // the image, it's just a 1x1 placeholder. The chain we're currently building
                    // will be replaced with another chain once download completes, so there's no 
                    // need to have this chain handle DownloadCompleted.
                    //
                    // Having this chain handle DownloadCompleted is actually a bad thing. Because
                    // the dummy is just 1x1, the TransformedBitmap we're building here will have 
                    // a large scaling factor (to scale the image from 1x1 up to whatever
                    // DecodePixelWidth/Height specifies). When the TransformedBitmap receives 
                    // DownloadCompleted from the BFD, it will call into WIC to create a new 
                    // bitmap scaler using the same large scaling factor, which can produce a huge
                    // bitmap (since the BFD is now no longer 1x1). This problem is made worse if 
                    // this BitmapImage has BitmapCacheOption.OnLoad, since that will put a
                    // CachedBitmap after the TransformedBitmap. When DownloadCompleted propagates
                    // from the TransformedBitmap down to the CachedBitmap, the CachedBitmap will
                    // call CreateBitmapFromSource using the TransformedBitmap, which calls 
                    // CopyPixels on the huge TransformedBitmap. We want to avoid chewing up the
                    // CPU and the memory, so we unregister the download event handlers here. 
                    // 
                    source.UnregisterDownloadEventSource();
                } 
            }

            //
            // If the original image has a color profile and IgnoreColorProfile is not one of the create options, 
            // apply the profile so bits are color-corrected.
            // 
            if ((CreateOptions & BitmapCreateOptions.IgnoreColorProfile) == 0 && 
                frame.ColorContexts != null &&
                frame.ColorContexts[0] != null && 
                frame.ColorContexts[0].IsValid &&
                source.Format.Format != PixelFormatEnum.Extended
                )
            { 
                // NOTE: Never do this for a non-MIL pixel format, because the format converter has
                // special knowledge to deal with the profile 
 
                PixelFormat duceFormat = BitmapSource.GetClosestDUCEFormat(source.Format, source.Palette);
                bool changeFormat = (source.Format != duceFormat); 
                ColorContext destinationColorContext;

                // We need to make sure, we can actually create the ColorContext for the destination duceFormat
                // If the duceFormat is gray or scRGB, the following is not supported, so we cannot 
                // create the ColorConvertedBitmap
                try 
                { 
                    destinationColorContext= new ColorContext(duceFormat);
                } 
                catch (NotSupportedException)
                {
                    destinationColorContext = null;
                } 

                if (destinationColorContext != null) 
                { 
                    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( 
                            source, 
                            frame.ColorContexts[0],
                            destinationColorContext, 
                            duceFormat
                            );

                        source = colorConvertedBitmap; 
                        if (_isDownloading)
                        { 
                            // Unregister the download events because this is a dummy image. See comment above. 
                            source.UnregisterDownloadEventSource();
                        } 
                        conversionSuccess = true;
                    }
                    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 && !badColorContext && changeFormat)
                    {   // If the conversion failed, we first use 
                        // a FormatConvertedBitmap, and then Color Convert that one... 
                        FormatConvertedBitmap formatConvertedBitmap = new FormatConvertedBitmap(source, duceFormat, source.Palette, 0.0);
 
                        ColorConvertedBitmap colorConvertedBitmap = new ColorConvertedBitmap(
                            formatConvertedBitmap,
                            frame.ColorContexts[0],
                            destinationColorContext, 
                            duceFormat
                            ); 
 
                        source = colorConvertedBitmap;
                        if (_isDownloading) 
                        {
                            // Unregister the download events because this is a dummy image. See comment above.
                            source.UnregisterDownloadEventSource();
                        } 
                    }
                } 
            } 

            if (CacheOption != BitmapCacheOption.None) 
            {
                try
                {
                    // The bitmaps bits could be corrupt, and this will cause an exception if the CachedBitmap forces a decode. 
                    CachedBitmap cachedSource = new CachedBitmap(source, CreateOptions & ~BitmapCreateOptions.DelayCreation, CacheOption);
                    source = cachedSource; 
                    if (_isDownloading) 
                    {
                        // Unregister the download events because this is a dummy image. See comment above. 
                        source.UnregisterDownloadEventSource();
                    }
                }
                catch (Exception e) 
                {
                    RecoverFromDecodeFailure(e); 
                    CreationCompleted = true; // we're bailing out because the decode failed 
                    return;
                } 
            }

            // If CacheOption == OnLoad, no need to keep the stream around
            if (decoder != null && CacheOption == BitmapCacheOption.OnLoad) 
            {
                decoder.CloseStream(); 
            } 
            else if (CacheOption != BitmapCacheOption.OnLoad)
            { 
                //ensure that we don't GC the source
                _finalSource = source;
            }
 
            WicSourceHandle = source.WicSourceHandle;
            IsSourceCached = source.IsSourceCached; 
 
            CreationCompleted = true;
            UpdateCachedSettings(); 

            // Only insert in the imaging cache if download is complete
            if (!IsDownloading)
            { 
                InsertInCache(uri);
            } 
        } 
예제 #10
0
		/// <summary>
		/// Convert color profile of BitmapSource for color management.
		/// </summary>
		/// <param name="bitmapSource">Source BitmapSource</param>
		/// <param name="sourceProfile">Source color profile</param>
		/// <param name="destinationProfile">Destination color profile</param>
		/// <returns>Outcome BitmapSource</returns>
		/// <remarks>Source color profile is color profile embedded in image file and destination color profile is
		/// color profile used by the monitor to which the Window belongs.</remarks>
		public static BitmapSource ConvertColorProfile(BitmapSource bitmapSource, ColorContext sourceProfile, ColorContext destinationProfile)
		{
			var bitmapConverted = new ColorConvertedBitmap();
			bitmapConverted.BeginInit();
			bitmapConverted.Source = bitmapSource;
			bitmapConverted.SourceColorContext = sourceProfile;
			bitmapConverted.DestinationColorContext = destinationProfile;
			bitmapConverted.DestinationFormat = PixelFormats.Bgra32;
			bitmapConverted.EndInit();

			return bitmapConverted;
		}
예제 #11
0
 private void ClonePostscript(ColorConvertedBitmap otherColorConvertedBitmap) 
 { 
     EndInit();
 } 
예제 #12
0
 private void ClonePrequel(ColorConvertedBitmap otherColorConvertedBitmap)
 {
     BeginInit();
 } 
예제 #13
0
 private void ClonePostscript(ColorConvertedBitmap otherColorConvertedBitmap)
 {
     EndInit();
 }
예제 #14
0
 private void ClonePrequel(ColorConvertedBitmap otherColorConvertedBitmap)
 {
     BeginInit();
 }
예제 #15
0
        internal override void FinalizeCreation()
        {
            _bitmapInit.EnsureInitializedComplete();
            Uri uri = UriSource;

            if (_baseUri != null)
            {
                uri = new Uri(_baseUri, UriSource);
            }

            if ((CreateOptions & BitmapCreateOptions.IgnoreImageCache) != 0)
            {
                ImagingCache.RemoveFromImageCache(uri);
            }

            BitmapImage bitmapImage = CheckCache(uri);

            if (bitmapImage != null &&
                bitmapImage.CheckAccess() &&
                bitmapImage.SourceRect.Equals(SourceRect) &&
                bitmapImage.DecodePixelWidth == DecodePixelWidth &&
                bitmapImage.DecodePixelHeight == DecodePixelHeight &&
                bitmapImage.Rotation == Rotation &&
                (bitmapImage.CreateOptions & BitmapCreateOptions.IgnoreColorProfile) ==
                (CreateOptions & BitmapCreateOptions.IgnoreColorProfile)
                )
            {
                _syncObject = bitmapImage.SyncObject;
                lock (_syncObject)
                {
                    WicSourceHandle   = bitmapImage.WicSourceHandle;
                    IsSourceCached    = bitmapImage.IsSourceCached;
                    _convertedDUCEPtr = bitmapImage._convertedDUCEPtr;

                    //
                    // We nee d to keep the strong reference to the cached image for a few reasons:
                    //
                    //    The application may release the original cached image and then keep a
                    //    reference to this image only, in which case, the cache can be collected.
                    //    This will cause a few undesirable results:
                    //    1. The application may choose to decode the same URI again in which case
                    //       we will not retrieve it from the cache even though we have a copy already
                    //       decoded.
                    //    2. The original cached image holds onto the file stream indirectly which if
                    //       collected can cause bad behavior if the entire image is not loaded into
                    //       memory.
                    //
                    _cachedBitmapImage = bitmapImage;
                }
                UpdateCachedSettings();
                return;
            }

            BitmapDecoder decoder = null;

            if (_decoder == null)
            {
                // Note: We do not want to insert in the cache if there is a chance that
                //       the decode pixel width/height may cause the decoder LOD to change
                decoder = BitmapDecoder.CreateFromUriOrStream(
                    _baseUri,
                    UriSource,
                    StreamSource,
                    CreateOptions & ~BitmapCreateOptions.DelayCreation,
                    BitmapCacheOption.None, // do not cache the frames since we will do that here
                    _uriCachePolicy,
                    false
                    );

                if (decoder.IsDownloading)
                {
                    _isDownloading             = true;
                    _decoder                   = decoder;
                    decoder.DownloadProgress  += OnDownloadProgress;
                    decoder.DownloadCompleted += OnDownloadCompleted;
                    decoder.DownloadFailed    += OnDownloadFailed;
                }
                else
                {
                    Debug.Assert(decoder.SyncObject != null);
                }
            }
            else
            {
                // We already had a decoder, meaning we were downloading
                Debug.Assert(!_decoder.IsDownloading);
                decoder  = _decoder;
                _decoder = null;
            }

            if (decoder.Frames.Count == 0)
            {
                throw new System.ArgumentException(SR.Get(SRID.Image_NoDecodeFrames));
            }

            BitmapFrame  frame  = decoder.Frames[0];
            BitmapSource source = frame;

            Int32Rect sourceRect = SourceRect;

            if (sourceRect.X == 0 && sourceRect.Y == 0 &&
                sourceRect.Width == source.PixelWidth &&
                sourceRect.Height == source.PixelHeight)
            {
                sourceRect = Int32Rect.Empty;
            }

            if (!sourceRect.IsEmpty)
            {
                CroppedBitmap croppedSource = new CroppedBitmap();
                croppedSource.BeginInit();
                croppedSource.Source     = source;
                croppedSource.SourceRect = sourceRect;
                croppedSource.EndInit();

                source = croppedSource;
                if (_isDownloading)
                {
                    // Unregister the download events because this is a dummy image. See comment below.
                    source.UnregisterDownloadEventSource();
                }
            }

            int finalWidth  = DecodePixelWidth;
            int finalHeight = DecodePixelHeight;

            if (finalWidth == 0 && finalHeight == 0)
            {
                finalWidth  = source.PixelWidth;
                finalHeight = source.PixelHeight;
            }
            else if (finalWidth == 0)
            {
                finalWidth = (source.PixelWidth * finalHeight) / source.PixelHeight;
            }
            else if (finalHeight == 0)
            {
                finalHeight = (source.PixelHeight * finalWidth) / source.PixelWidth;
            }

            if (finalWidth != source.PixelWidth || finalHeight != source.PixelHeight ||
                Rotation != Rotation.Rotate0)
            {
                TransformedBitmap transformedSource = new TransformedBitmap();
                transformedSource.BeginInit();
                transformedSource.Source = source;

                TransformGroup transformGroup = new TransformGroup();

                if (finalWidth != source.PixelWidth || finalHeight != source.PixelHeight)
                {
                    int oldWidth  = source.PixelWidth;
                    int oldHeight = source.PixelHeight;

                    Debug.Assert(oldWidth > 0 && oldHeight > 0);

                    transformGroup.Children.Add(
                        new ScaleTransform(
                            (1.0 * finalWidth) / oldWidth,
                            (1.0 * finalHeight) / oldHeight));
                }

                if (Rotation != Rotation.Rotate0)
                {
                    double rotation = 0.0;

                    switch (Rotation)
                    {
                    case Rotation.Rotate0:
                        rotation = 0.0;
                        break;

                    case Rotation.Rotate90:
                        rotation = 90.0;
                        break;

                    case Rotation.Rotate180:
                        rotation = 180.0;
                        break;

                    case Rotation.Rotate270:
                        rotation = 270.0;
                        break;

                    default:
                        Debug.Assert(false);
                        break;
                    }

                    transformGroup.Children.Add(new RotateTransform(rotation));
                }

                transformedSource.Transform = transformGroup;

                transformedSource.EndInit();

                source = transformedSource;
                if (_isDownloading)
                {
                    //
                    // If we're currently downloading, then the BitmapFrameDecode isn't actually
                    // the image, it's just a 1x1 placeholder. The chain we're currently building
                    // will be replaced with another chain once download completes, so there's no
                    // need to have this chain handle DownloadCompleted.
                    //
                    // Having this chain handle DownloadCompleted is actually a bad thing. Because
                    // the dummy is just 1x1, the TransformedBitmap we're building here will have
                    // a large scaling factor (to scale the image from 1x1 up to whatever
                    // DecodePixelWidth/Height specifies). When the TransformedBitmap receives
                    // DownloadCompleted from the BFD, it will call into WIC to create a new
                    // bitmap scaler using the same large scaling factor, which can produce a huge
                    // bitmap (since the BFD is now no longer 1x1). This problem is made worse if
                    // this BitmapImage has BitmapCacheOption.OnLoad, since that will put a
                    // CachedBitmap after the TransformedBitmap. When DownloadCompleted propagates
                    // from the TransformedBitmap down to the CachedBitmap, the CachedBitmap will
                    // call CreateBitmapFromSource using the TransformedBitmap, which calls
                    // CopyPixels on the huge TransformedBitmap. We want to avoid chewing up the
                    // CPU and the memory, so we unregister the download event handlers here.
                    //
                    source.UnregisterDownloadEventSource();
                }
            }

            //
            // If the original image has a color profile and IgnoreColorProfile is not one of the create options,
            // apply the profile so bits are color-corrected.
            //
            if ((CreateOptions & BitmapCreateOptions.IgnoreColorProfile) == 0 &&
                frame.ColorContexts != null &&
                frame.ColorContexts[0] != null &&
                frame.ColorContexts[0].IsValid &&
                source.Format.Format != PixelFormatEnum.Extended
                )
            {
                // NOTE: Never do this for a non-MIL pixel format, because the format converter has
                // special knowledge to deal with the profile

                PixelFormat  duceFormat   = BitmapSource.GetClosestDUCEFormat(source.Format, source.Palette);
                bool         changeFormat = (source.Format != duceFormat);
                ColorContext destinationColorContext;

                // We need to make sure, we can actually create the ColorContext for the destination duceFormat
                // If the duceFormat is gray or scRGB, the following is not supported, so we cannot
                // create the ColorConvertedBitmap
                try
                {
                    destinationColorContext = new ColorContext(duceFormat);
                }
                catch (NotSupportedException)
                {
                    destinationColorContext = null;
                }

                if (destinationColorContext != null)
                {
                    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(
                            source,
                            frame.ColorContexts[0],
                            destinationColorContext,
                            duceFormat
                            );

                        source = colorConvertedBitmap;
                        if (_isDownloading)
                        {
                            // Unregister the download events because this is a dummy image. See comment above.
                            source.UnregisterDownloadEventSource();
                        }
                        conversionSuccess = true;
                    }
                    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 && !badColorContext && changeFormat)
                    {   // If the conversion failed, we first use
                        // a FormatConvertedBitmap, and then Color Convert that one...
                        FormatConvertedBitmap formatConvertedBitmap = new FormatConvertedBitmap(source, duceFormat, source.Palette, 0.0);

                        ColorConvertedBitmap colorConvertedBitmap = new ColorConvertedBitmap(
                            formatConvertedBitmap,
                            frame.ColorContexts[0],
                            destinationColorContext,
                            duceFormat
                            );

                        source = colorConvertedBitmap;
                        if (_isDownloading)
                        {
                            // Unregister the download events because this is a dummy image. See comment above.
                            source.UnregisterDownloadEventSource();
                        }
                    }
                }
            }

            if (CacheOption != BitmapCacheOption.None)
            {
                try
                {
                    // The bitmaps bits could be corrupt, and this will cause an exception if the CachedBitmap forces a decode.
                    CachedBitmap cachedSource = new CachedBitmap(source, CreateOptions & ~BitmapCreateOptions.DelayCreation, CacheOption);
                    source = cachedSource;
                    if (_isDownloading)
                    {
                        // Unregister the download events because this is a dummy image. See comment above.
                        source.UnregisterDownloadEventSource();
                    }
                }
                catch (Exception e)
                {
                    RecoverFromDecodeFailure(e);
                    CreationCompleted = true; // we're bailing out because the decode failed
                    return;
                }
            }

            // If CacheOption == OnLoad, no need to keep the stream around
            if (decoder != null && CacheOption == BitmapCacheOption.OnLoad)
            {
                decoder.CloseStream();
            }
            else if (CacheOption != BitmapCacheOption.OnLoad)
            {
                //ensure that we don't GC the source
                _finalSource = source;
            }

            WicSourceHandle = source.WicSourceHandle;
            IsSourceCached  = source.IsSourceCached;

            CreationCompleted = true;
            UpdateCachedSettings();

            // Only insert in the imaging cache if download is complete
            if (!IsDownloading)
            {
                InsertInCache(uri);
            }
        }
예제 #16
0
        private ImageSource GetBitmapSource(SvgImageElement element, WpfDrawingContext context)
        {
            BitmapSource bitmapSource = this.GetBitmap(element, context);
            if (bitmapSource == null)
            {
                return bitmapSource;
            }

            SvgColorProfileElement colorProfile = (SvgColorProfileElement)element.ColorProfile;
            if (colorProfile == null)
            {
                return bitmapSource;
            }
            else
            {
                BitmapFrame bitmapSourceFrame   = BitmapFrame.Create(bitmapSource);
                ColorContext sourceColorContext = null;
                IList<ColorContext> colorContexts = bitmapSourceFrame.ColorContexts;
                if (colorContexts != null && colorContexts.Count != 0)
                {
                    sourceColorContext = colorContexts[0];
                }
                else
                {
                    sourceColorContext = new ColorContext(bitmapSource.Format);
                    //sourceColorContext = new ColorContext(PixelFormats.Default);
                }

                SvgUriReference svgUri = colorProfile.UriReference;
                Uri profileUri = new Uri(svgUri.AbsoluteUri);

                ColorContext destColorContext = new ColorContext(profileUri);
                ColorConvertedBitmap convertedBitmap = new ColorConvertedBitmap(bitmapSource,
                    sourceColorContext, destColorContext, bitmapSource.Format);

                return convertedBitmap;
            }
        }