internal ColorTransform(SafeMILHandle bitmapSource, ColorContext srcContext, ColorContext dstContext, System.Windows.Media.PixelFormat pixelFormat) { InitializeICM(); if (srcContext == null) { srcContext = new ColorContext(pixelFormat); } if (dstContext == null) { dstContext = new ColorContext(pixelFormat); } _inputColorType = srcContext.ColorType; _outputColorType = dstContext.ColorType; //if this failed or the handle is invalid, we can't continue if (srcContext.ProfileHandle != null && !srcContext.ProfileHandle.IsInvalid) { //if this failed or the handle is invalid, we can't continue if (dstContext.ProfileHandle != null && !dstContext.ProfileHandle.IsInvalid) { _colorTransformHelper.CreateTransform(srcContext.ProfileHandle, dstContext.ProfileHandle); } } }
/// <summary> /// Construct a ColorConvertedBitmap /// </summary> /// <param name="source">Input BitmapSource to color convert</param> /// <param name="sourceColorContext">Source Color Context</param> /// <param name="destinationColorContext">Destination Color Context</param> /// <param name="format">Destination Pixel format</param> public ColorConvertedBitmap(BitmapSource source, ColorContext sourceColorContext, ColorContext destinationColorContext, PixelFormat format) : base(true) // Use base class virtuals { if (source == null) { throw new ArgumentNullException("source"); } if (sourceColorContext == null) { throw new ArgumentNullException("sourceColorContext"); } if (destinationColorContext == null) { throw new ArgumentNullException("destinationColorContext"); } _bitmapInit.BeginInit(); Source = source; SourceColorContext = sourceColorContext; DestinationColorContext = destinationColorContext; DestinationFormat = format; _bitmapInit.EndInit(); FinalizeCreation(); }
private async Task ProcessTask(Tuple<int, int, double> task) { int width = task.Item1; int height = task.Item2; double k = task.Item3; WriteableBitmap bitmap = (WriteableBitmap)MainImage.Source; // Create new bitmap if current bit is invalid or obsolete. if (bitmap == null || bitmap.PixelWidth != width || bitmap.PixelWidth != height) { bitmap = new WriteableBitmap(width, height, 96.0, 96.0, PixelFormats.Bgr32, null); } ColorContext cc = new ColorContext(PixelFormats.Bgr32); this.Title = cc.ProfileUri.ToString(); bitmap.Lock(); IntPtr buffer = bitmap.BackBuffer; int stride = bitmap.BackBufferStride; // Generate the content of the bitmap. await Task.Run(() => FillBitmap(buffer, width, height, stride, k)); bitmap.AddDirtyRect(new Int32Rect(0, 0, width, height)); bitmap.Unlock(); MainImage.Source = bitmap; }
internal ColorTransform(ColorContext srcContext, ColorContext dstContext) { InitializeICM(); if (srcContext == null) { srcContext = new ColorContext(PixelFormats.Bgra32); } if (dstContext == null) { dstContext = new ColorContext(PixelFormats.Bgra32); } _inputColorType = srcContext.ColorType; _outputColorType = dstContext.ColorType; _colorTransformHelper.CreateTransform(srcContext.ProfileHandle, dstContext.ProfileHandle); }
//------------------------------------------------------ // // Equality Methods/Properties // //------------------------------------------------------ #region Equality methods and Properties /// <summary> /// Equals method /// </summary> override public bool Equals(object obj) { ColorContext context = obj as ColorContext; return(context == this); }
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; }
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) { ColorContext colorContext = new ColorContext(frame.Format); IntPtr[] colorContextPtrs = new IntPtr[1] { colorContext.ColorContextHandle.DangerousGetHandle() }; int hr = UnsafeNativeMethods.WICBitmapFrameEncode.SetColorContexts( frameEncodeHandle, 1, colorContextPtrs ); // It's possible that some encoders may not support color contexts so don't check hr if (hr == HRESULT.S_OK) { // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeColorContextsSet; } } // if the caller has explicitly provided color contexts, add them to the encoder else { IList<ColorContext> colorContexts = frame.ColorContexts; if (colorContexts != null && colorContexts.Count > 0) { int count = colorContexts.Count; // Marshal can't convert SafeMILHandle[] so we must { IntPtr[] colorContextPtrs = new IntPtr[count]; for (int i = 0; i < count; ++i) { colorContextPtrs[i] = colorContexts[i].ColorContextHandle.DangerousGetHandle(); } int hr = UnsafeNativeMethods.WICBitmapFrameEncode.SetColorContexts( frameEncodeHandle, (uint)count, colorContextPtrs ); // It's possible that some encoders may not support color contexts so don't check hr if (hr == HRESULT.S_OK) { // Helpful for debugging stress and remote dumps _encodeState = EncodeState.FrameEncodeColorContextsSet; } } } } // 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; } }
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); } }
/// <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; }
/// <summary> /// Convert Stream to BitmapSource. /// </summary> /// <param name="stream">Stream</param> /// <param name="outerSize">Target outer size</param> /// <param name="willReadExif">Whether Exif metadata will be read from Stream</param> /// <param name="destinationProfile">Destination color profile for color management</param> /// <returns>BitmapSource</returns> private static BitmapSource ConvertStreamToBitmapSource(Stream stream, Size outerSize, bool willReadExif, ColorContext destinationProfile) { if (0 < stream.Position) stream.Seek(0, SeekOrigin.Begin); var bitmapFrame = BitmapFrame.Create( stream, BitmapCreateOptions.IgnoreColorProfile | BitmapCreateOptions.PreservePixelFormat, // For color management BitmapCacheOption.OnLoad); var orientation = willReadExif ? GetExifOrientation(bitmapFrame) : 0; // 0 means invalid. var bitmapSource = ResizeAndReflectExifOrientation(bitmapFrame, outerSize, orientation); if (destinationProfile != null) { var sourceProfile = GetColorProfile(bitmapFrame); bitmapSource = ConvertColorProfile(bitmapSource, sourceProfile, destinationProfile); } bitmapSource.Freeze(); return bitmapSource; }
/// <summary> /// Convert byte array to BitmapSource applying Uniform transformation. /// </summary> /// <param name="bytes">Byte array</param> /// <param name="outerSize">Target outer size</param> /// <param name="willReadExif">Whether Exif metadata will be read from byte array</param> /// <param name="destinationProfile">Destination color profile for color management</param> /// <returns>BitmapSource</returns> internal static async Task<BitmapSource> ConvertBytesToBitmapSourceUniformAsync(byte[] bytes, Size outerSize, bool willReadExif, ColorContext destinationProfile = null) { if ((bytes == null) || !bytes.Any()) throw new ArgumentNullException("bytes"); try { using (var ms = new MemoryStream()) { await ms.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); if (willReadExif || (destinationProfile != null)) { return await Task.Run(() => ConvertStreamToBitmapSource(ms, outerSize, willReadExif, destinationProfile)); } return await Task.Run(() => ConvertStreamToBitmapImageUniform(ms, outerSize)); } } catch (Exception ex) { Debug.WriteLine("Failed to convert byte array to BitmapSource. {0}", ex); if (IsImageNotSupported(ex)) throw new ImageNotSupportedException(); throw; } }
/// <summary> /// Convert byte array to BitmapSource. /// </summary> /// <param name="bytes">Byte array</param> /// <param name="targetWidth">Target width</param> /// <param name="willReadExif">Whether Exif metadata will be read from byte array</param> /// <param name="destinationProfile">Destination color profile for color management</param> /// <returns>BitmapSource</returns> internal static async Task<BitmapSource> ConvertBytesToBitmapSourceAsync(byte[] bytes, double targetWidth, bool willReadExif, ColorContext destinationProfile = null) { return await ConvertBytesToBitmapSourceAsync(bytes, targetWidth, 0D, willReadExif, destinationProfile).ConfigureAwait(false); }
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; } }