| File: SystemDrawingExtension.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\Extensions\PresentationFramework-SystemDrawing\PresentationFramework-SystemDrawing.csproj (PresentationFramework-SystemDrawing) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #nullable enable // Description: Helper methods for code that uses types from System.Drawing. using System; using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Windows; using System.Windows.Media.Imaging; namespace MS.Internal { //FxCop can't tell that this class is instantiated via reflection, so suppress the FxCop warning. [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] internal class SystemDrawingExtension : SystemDrawingExtensionMethods { internal override bool IsBitmap(object? data) => data is Bitmap; internal override bool IsImage(object? data) => data is Image; internal override bool IsMetafile(object? data) => data is Metafile; internal override nint GetHandleFromMetafile(object? data) => data switch { Metafile metafile => metafile.GetHenhmetafile(), _ => 0 }; internal override object GetMetafileFromHemf(nint hMetafile) => new Metafile(hMetafile, deleteEmf: false); internal override object? GetBitmap(object? data) => GetBitmapImpl(data); internal override nint GetHBitmap(object? data, out int width, out int height) { Bitmap? bitmapData = GetBitmapImpl(data); if (bitmapData is null) { width = height = 0; return IntPtr.Zero; } // GDI+ returns a DIBSECTION based HBITMAP. The clipboard deals well // only with bitmaps created using CreateCompatibleBitmap(). So, we // convert the DIBSECTION into a compatible bitmap. width = bitmapData.Size.Width; height = bitmapData.Size.Height; return bitmapData.GetHbitmap(); } internal override nint GetHBitmapFromBitmap(object? data) => data is Bitmap bitmap ? bitmap.GetHbitmap() : 0; internal override nint ConvertMetafileToHBitmap(nint handle) { Metafile metafile = new(handle, deleteEmf: false); // Initialize the bitmap size to render the metafile. int bitmapheight = metafile.Size.Height; int bitmapwidth = metafile.Size.Width; // We use System.Drawing to render metafile into the bitmap. Bitmap bmp = new Bitmap(bitmapwidth, bitmapheight); Graphics graphics = Graphics.FromImage(bmp); graphics.DrawImage(metafile, 0, 0, bitmapwidth, bitmapheight); return bmp.GetHbitmap(); } internal override Stream GetCommentFromGifStream(Stream stream) { // Read the GIF header Bitmap bitmap = new(stream); // Read the comment as that is where the ISF is stored. // For reference the tag is PropertyTagExifUserComment [0x9286] or 37510 (int) PropertyItem? piComment = bitmap.GetPropertyItem(37510); // Want to make this throw in the same way it used to for now. It would be good // to redo this to return null and handle the null case in the various callers. return new MemoryStream(piComment!.Value!); } internal override void SaveMetafileToImageStream(MemoryStream metafileStream, Stream imageStream) { Metafile metafile = new(metafileStream); metafile.Save(imageStream, ImageFormat.Png); } // Get a bitmap from the given data (either BitmapSource or Bitmap) private static Bitmap? GetBitmapImpl(object? data) { if (data is BitmapSource bitmapSource) { // Convert BitmapSource to System.Drawing.Bitmap to get Win32 HBITMAP. BitmapEncoder bitmapEncoder; Stream bitmapStream; bitmapEncoder = new BmpBitmapEncoder(); bitmapEncoder.Frames.Add(BitmapFrame.Create(bitmapSource)); bitmapStream = new MemoryStream(); bitmapEncoder.Save(bitmapStream); return new Bitmap(bitmapStream); } else { // Get Bitmap data from data object. return data as Bitmap; } } internal override object GetBitmapFromBitmapSource(object source) { BitmapSource contentImage = (BitmapSource)source; int imageWidth = (int)contentImage.Width; int imageHeight = (int)contentImage.Height; Bitmap bitmapFinal = new(imageWidth, imageHeight, PixelFormat.Format32bppRgb); BitmapData bmData = bitmapFinal.LockBits( new Rectangle(0, 0, imageWidth, imageHeight), ImageLockMode.WriteOnly, PixelFormat.Format32bppRgb); FormatConvertedBitmap formatConverter = new FormatConvertedBitmap(); formatConverter.BeginInit(); formatConverter.Source = contentImage; formatConverter.DestinationFormat = System.Windows.Media.PixelFormats.Bgr32; formatConverter.EndInit(); formatConverter.CopyPixels( new Int32Rect(0, 0, imageWidth, imageHeight), bmData.Scan0, bmData.Stride * (bmData.Height - 1) + (bmData.Width * 4), bmData.Stride); bitmapFinal.UnlockBits(bmData); return bitmapFinal; } #if WindowsMetaFile // Convert the bitmap to the windows metafile to write it as "\wmetafile" control on rtf content internal override string ConvertToMetafileHexDataString(Stream imageStream) { MemoryStream metafileStream = new MemoryStream(); // Get the graphics to write image on the metafile Graphics graphics = Graphics.FromHwnd(IntPtr.Zero); // Create the empty metafile Metafile metafile = new Metafile(metafileStream, graphics.GetHdc(), EmfType.EmfOnly); // Release HDC graphics.ReleaseHdc(); // Create the graphics for metafile destination Graphics graphicsTarget = Graphics.FromImage(metafile); // Create bitmap from the image source stream Bitmap bitmap = new Bitmap(imageStream); // Draw the bitmap image to the metafile graphicsTarget.DrawImage(bitmap, Point.Empty); // Dispose graphics target graphicsTarget.Dispose(); // Move to the start position metafileStream.Position = 0; // Create the enhance metafile from metafile stream what we rendered from the bitmap image Metafile enhanceMetafile = new Metafile(metafileStream); // Get the enhance metafile handle from the enhance metafile IntPtr hdc = UnsafeNativeMethods.CreateCompatibleDC(new HandleRef(this, IntPtr.Zero)); IntPtr hEnhanceMetafile = enhanceMetafile.GetHenhmetafile(); // Convert the enhance metafile to the windows metafile with Win32 GDI uint windowsMetafileSize = UnsafeNativeMethods.GetWinMetaFileBits(hEnhanceMetafile, 0, null, /*MapMode:MM_ANISOTROPIC*/8, hdc); Byte[] windowsMetafileBytes = new Byte[windowsMetafileSize]; UnsafeNativeMethods.GetWinMetaFileBits(hEnhanceMetafile, windowsMetafileSize, windowsMetafileBytes, /*MapMode:MM_ANISOTROPIC*/8, hdc); // Dispose metafile and metafile stream metafile.Dispose(); metafileStream.Dispose(); // return the windows metafile hex data string return ConvertToImageHexDataString(windowsMetafileBytes); } #endif } }