diff --git a/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs b/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs index 2d94b397b..0e78a3a71 100644 --- a/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs +++ b/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs @@ -24,6 +24,8 @@ using System.Runtime.InteropServices; using System.Security; using Microsoft.Win32.SafeHandles; using System.Reflection; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; namespace GreenshotPlugin.UnmanagedHelpers { /// @@ -47,6 +49,46 @@ namespace GreenshotPlugin.UnmanagedHelpers { public bool ExpandEdges; } + /// + /// GDI Plus unit description. + /// + public enum GpUnit { + /// + /// World coordinate (non-physical unit). + /// + UnitWorld, + + /// + /// Variable - for PageTransform only. + /// + UnitDisplay, + + /// + /// Each unit is one device pixel. + /// + UnitPixel, + + /// + /// Each unit is a printer's point, or 1/72 inch. + /// + UnitPoint, + + /// + /// Each unit is 1 inch. + /// + UnitInch, + + /// + /// Each unit is 1/300 inch. + /// + UnitDocument, + + /// + /// Each unit is 1 millimeter. + /// + UnitMillimeter + } + /// /// GDIplus Helpers /// @@ -55,6 +97,9 @@ namespace GreenshotPlugin.UnmanagedHelpers { [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)] private static extern int GdipBitmapApplyEffect(IntPtr bitmap, IntPtr effect, ref RECT rectOfInterest, bool useAuxData, IntPtr auxData, int auxDataSize); + + [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)] + private static extern int GdipDrawImageFX(IntPtr graphics, IntPtr bitmap, ref RECTF source, IntPtr matrix, IntPtr effect, IntPtr imageAttributes, GpUnit srcUnit); [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)] private static extern int GdipSetEffectParameters(IntPtr effect, IntPtr parameters, uint size); [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)] @@ -63,26 +108,72 @@ namespace GreenshotPlugin.UnmanagedHelpers { private static extern int GdipDeleteEffect(IntPtr effect); private static Guid BlurEffectGuid = new Guid("{633C80A4-1843-482B-9EF2-BE2834C5FDD4}"); - // Constant "FieldInfo" for getting the nativeImage from the image + // Constant "FieldInfo" for getting the nativeImage from the Bitmap private static readonly FieldInfo FIELD_INFO_NATIVE_IMAGE = typeof(Bitmap).GetField("nativeImage", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - + // Constant "FieldInfo" for getting the NativeGraphics from the Graphics + private static readonly FieldInfo FIELD_INFO_NATIVE_GRAPHICS = typeof(Graphics).GetField("nativeGraphics", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); + // Constant "FieldInfo" for getting the nativeMatrix from the Matrix + private static readonly FieldInfo FIELD_INFO_NATIVE_MATRIX = typeof(Matrix).GetField("nativeMatrix", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); + // Constant "FieldInfo" for getting the nativeImageAttributes from the ImageAttributes + private static readonly FieldInfo FIELD_INFO_NATIVE_IMAGEATTRIBUTES = typeof(ImageAttributes).GetField("nativeImageAttributes", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); + /// /// Get the nativeImage field from the bitmap /// /// - /// + /// IntPtr private static IntPtr GetNativeImage(Bitmap bitmap) { + if (bitmap == null) { + return IntPtr.Zero; + } return (IntPtr)FIELD_INFO_NATIVE_IMAGE.GetValue(bitmap); } + /// + /// Get the NativeGraphics field from the graphics + /// + /// + /// IntPtr + private static IntPtr GetNativeGraphics(Graphics graphics) { + if (graphics == null) { + return IntPtr.Zero; + } + return (IntPtr)FIELD_INFO_NATIVE_GRAPHICS.GetValue(graphics); + } + + /// + /// Get the nativeMatrix field from the matrix + /// + /// + /// IntPtr + private static IntPtr GetNativeMatrix(Matrix matrix) { + if (matrix == null) { + return IntPtr.Zero; + } + return (IntPtr)FIELD_INFO_NATIVE_MATRIX.GetValue(matrix); + } + + /// + /// Get the nativeImageAttributes field from the ImageAttributes + /// + /// + /// IntPtr + private static IntPtr GetNativeImageAttributes(ImageAttributes imageAttributes) { + if (imageAttributes == null) { + return IntPtr.Zero; + } + return (IntPtr)FIELD_INFO_NATIVE_IMAGEATTRIBUTES.GetValue(imageAttributes); + } + /// /// Use the GDI+ blur effect on the bitmap /// /// Bitmap to apply the effect to /// Rectangle to apply the blur effect to /// 0-255 + /// bool true if the edges are expanded with the radius /// false if there is no GDI+ available or an exception occured - public static bool ApplyBlur(Bitmap destinationBitmap, Rectangle area, float radius) { + public static bool ApplyBlur(Bitmap destinationBitmap, Rectangle area, int radius, bool expandEdges) { if (Environment.OSVersion.Version.Major < 6) { return false; } @@ -93,12 +184,12 @@ namespace GreenshotPlugin.UnmanagedHelpers { // Create a BlurParams struct and set the values BlurParams blurParams = new BlurParams(); blurParams.Radius = radius; - blurParams.ExpandEdges = false; + blurParams.ExpandEdges = expandEdges; // Allocate space in unmanaged memory hBlurParams = Marshal.AllocHGlobal(Marshal.SizeOf(blurParams)); // Copy the structure to the unmanaged memory - Marshal.StructureToPtr(blurParams, hBlurParams, true); + Marshal.StructureToPtr(blurParams, hBlurParams, false); // Create the GDI+ BlurEffect, using the Guid int status = GdipCreateEffect(BlurEffectGuid, out hEffect); @@ -131,5 +222,66 @@ namespace GreenshotPlugin.UnmanagedHelpers { } } } + + /// + /// Draw the image on the graphics with GDI+ blur effect + /// + /// false if there is no GDI+ available or an exception occured + public static bool DrawWithBlur(Graphics graphics, Bitmap image, Rectangle source, Matrix transform, ImageAttributes imageAttributes, int radius, bool expandEdges) { + if (Environment.OSVersion.Version.Major < 6) { + return false; + } else if ((Environment.OSVersion.Version.Major >= 6 && Environment.OSVersion.Version.Minor >= 2) && radius < 20) { + return false; + } + IntPtr hBlurParams = IntPtr.Zero; + IntPtr hEffect = IntPtr.Zero; + + try { + // Create a BlurParams struct and set the values + BlurParams blurParams = new BlurParams(); + blurParams.Radius = radius; + //blurParams.Padding = radius; + blurParams.ExpandEdges = false; + + // Allocate space in unmanaged memory + hBlurParams = Marshal.AllocHGlobal(Marshal.SizeOf(blurParams)); + // Copy the structure to the unmanaged memory + Marshal.StructureToPtr(blurParams, hBlurParams, true); + + // Create the GDI+ BlurEffect, using the Guid + int status = GdipCreateEffect(BlurEffectGuid, out hEffect); + + // Set the blurParams to the effect + GdipSetEffectParameters(hEffect, hBlurParams, (uint)Marshal.SizeOf(blurParams)); + + // Somewhere it said we can use destinationBitmap.GetHbitmap(), this doesn't work!! + // Get the private nativeImage property from the Bitmap + IntPtr hBitmap = GetNativeImage(image); + IntPtr hGraphics = GetNativeGraphics(graphics); + IntPtr hMatrix = GetNativeMatrix(transform); + IntPtr hAttributes = GetNativeImageAttributes(imageAttributes); + + // Create a RECT from the Rectangle + RECTF sourceRECF = new RECTF(source); + // Apply the effect to the bitmap in the specified area + GdipDrawImageFX(hGraphics, hBitmap, ref sourceRECF, hMatrix, hEffect, hAttributes, GpUnit.UnitPixel); + + // Everything worked, return true + return true; + } catch (Exception ex) { + LOG.Error("Problem using GdipBitmapApplyEffect: ", ex); + return false; + } finally { + if (hEffect != null) { + // Delete the effect + GdipDeleteEffect(hEffect); + } + if (hBlurParams != IntPtr.Zero) { + // Free the memory + Marshal.FreeHGlobal(hBlurParams); + } + } + } + } } diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs.cs b/GreenshotPlugin/UnmanagedHelpers/Structs.cs index 5f4d56d6e..4a1802bc7 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Structs.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Structs.cs @@ -211,6 +211,104 @@ namespace GreenshotPlugin.UnmanagedHelpers { } } + /// + /// A floating point GDI Plus width/hight based rectangle. + /// + [StructLayout(LayoutKind.Sequential)] + public struct RECTF { + /// + /// The X corner location of the rectangle. + /// + public float X; + + /// + /// The Y corner location of the rectangle. + /// + public float Y; + + /// + /// The width of the rectangle. + /// + public float Width; + + /// + /// The height of the rectangle. + /// + public float Height; + + /// + /// Creates a new GDI Plus rectangle. + /// + /// The X corner location of the rectangle. + /// The Y corner location of the rectangle. + /// The width of the rectangle. + /// The height of the rectangle. + public RECTF(float x, float y, float width, float height) { + X = x; + Y = y; + Width = width; + Height = height; + } + + /// + /// Creates a new GDI Plus rectangle from a System.Drawing.RectangleF. + /// + /// The rectangle to base this GDI Plus rectangle on. + public RECTF(RectangleF rect) { + X = rect.X; + Y = rect.Y; + Width = rect.Width; + Height = rect.Height; + } + + /// + /// Creates a new GDI Plus rectangle from a System.Drawing.Rectangle. + /// + /// The rectangle to base this GDI Plus rectangle on. + public RECTF(Rectangle rect) { + X = rect.X; + Y = rect.Y; + Width = rect.Width; + Height = rect.Height; + } + + /// + /// Returns a RectangleF for this GDI Plus rectangle. + /// + /// A System.Drawing.RectangleF structure. + public RectangleF ToRectangle() { + return new RectangleF(X, Y, Width, Height); + } + + /// + /// Returns a RectangleF for a GDI Plus rectangle. + /// + /// The GDI Plus rectangle to get the RectangleF for. + /// A System.Drawing.RectangleF structure. + public static RectangleF ToRectangle(RECTF rect) { + return rect.ToRectangle(); + } + + /// + /// Returns a GDI Plus rectangle for a RectangleF structure. + /// + /// The RectangleF to get the GDI Plus rectangle for. + /// A GDI Plus rectangle structure. + public static RECTF FromRectangle(RectangleF rect) { + return new RECTF(rect); + } + + /// + /// Returns a GDI Plus rectangle for a Rectangle structure. + /// + /// The Rectangle to get the GDI Plus rectangle for. + /// A GDI Plus rectangle structure. + public static RECTF FromRectangle(Rectangle rect) { + return new RECTF(rect); + } + } + + /// /// The structure for the WindowInfo /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms632610%28v=vs.85%29.aspx