diff --git a/GreenshotPlugin/Core/Effects.cs b/GreenshotPlugin/Core/Effects.cs index 4dcbd2912..686ad7605 100644 --- a/GreenshotPlugin/Core/Effects.cs +++ b/GreenshotPlugin/Core/Effects.cs @@ -42,7 +42,7 @@ namespace Greenshot.Core { public class DropShadowEffect : IEffect { public DropShadowEffect() { Darkness = 0.6f; - ShadowSize = 9; + ShadowSize = 7; ShadowOffset = new Point(-1, -1); } public float Darkness { diff --git a/GreenshotPlugin/Core/ImageHelper.cs b/GreenshotPlugin/Core/ImageHelper.cs index 50dc3bb0b..07c11452e 100644 --- a/GreenshotPlugin/Core/ImageHelper.cs +++ b/GreenshotPlugin/Core/ImageHelper.cs @@ -659,27 +659,26 @@ namespace GreenshotPlugin.Core { /// Must be ODD! /// Bitmap public static Bitmap ApplyBoxBlur(Bitmap destinationBitmap, int range) { + // Range must be odd! if ((range & 1) == 0) { range++; - //throw new InvalidOperationException("Range must be odd!"); } + // We only need one fastbitmap as we use it as source and target (the reading is done for one line H/V, writing after "parsing" one line H/V) using (IFastBitmap fastBitmap = FastBitmap.Create(destinationBitmap)) { // Box blurs are frequently used to approximate a Gaussian blur. // By the central limit theorem, if applied 3 times on the same image, a box blur approximates the Gaussian kernel to within about 3%, yielding the same result as a quadratic convolution kernel. + // This might be true, but the GDI+ BlurEffect doesn't look the same, a 2x blur is more simular and we only make 2x Box-Blur. + // (Might also be a mistake in our blur, but for now it looks great) if (fastBitmap.hasAlphaChannel) { BoxBlurHorizontalAlpha(fastBitmap, range); BoxBlurVerticalAlpha(fastBitmap, range); BoxBlurHorizontalAlpha(fastBitmap, range); BoxBlurVerticalAlpha(fastBitmap, range); - BoxBlurHorizontalAlpha(fastBitmap, range); - BoxBlurVerticalAlpha(fastBitmap, range); } else { BoxBlurHorizontal(fastBitmap, range); BoxBlurVertical(fastBitmap, range); BoxBlurHorizontal(fastBitmap, range); BoxBlurVertical(fastBitmap, range); - BoxBlurHorizontal(fastBitmap, range); - BoxBlurVertical(fastBitmap, range); } return fastBitmap.UnlockAndReturnBitmap(); @@ -691,7 +690,7 @@ namespace GreenshotPlugin.Core { /// /// Target BitmapBuffer /// Range must be odd! - public static void BoxBlurHorizontal(IFastBitmap targetFastBitmap, int range) { + private static void BoxBlurHorizontal(IFastBitmap targetFastBitmap, int range) { if (targetFastBitmap.hasAlphaChannel) { throw new NotSupportedException("BoxBlurHorizontal should NOT be called for bitmaps with alpha channel"); } @@ -739,7 +738,7 @@ namespace GreenshotPlugin.Core { /// Source BitmapBuffer /// Target BitmapBuffer /// Range must be odd! - public static void BoxBlurHorizontalAlpha(IFastBitmap targetFastBitmap, int range) { + private static void BoxBlurHorizontalAlpha(IFastBitmap targetFastBitmap, int range) { if (!targetFastBitmap.hasAlphaChannel) { throw new NotSupportedException("BoxBlurHorizontalAlpha should be called for bitmaps with alpha channel"); } @@ -790,7 +789,7 @@ namespace GreenshotPlugin.Core { /// /// BitmapBuffer which previously was created with BoxBlurHorizontal /// Range must be odd! - public static void BoxBlurVertical(IFastBitmap targetFastBitmap, int range) { + private static void BoxBlurVertical(IFastBitmap targetFastBitmap, int range) { if (targetFastBitmap.hasAlphaChannel) { throw new NotSupportedException("BoxBlurVertical should NOT be called for bitmaps with alpha channel"); } @@ -841,7 +840,7 @@ namespace GreenshotPlugin.Core { /// /// BitmapBuffer which previously was created with BoxBlurHorizontal /// Range must be odd! - public static void BoxBlurVerticalAlpha(IFastBitmap targetFastBitmap, int range) { + private static void BoxBlurVerticalAlpha(IFastBitmap targetFastBitmap, int range) { if (!targetFastBitmap.hasAlphaChannel) { throw new NotSupportedException("BoxBlurVerticalAlpha should be called for bitmaps with alpha channel"); } @@ -929,6 +928,11 @@ namespace GreenshotPlugin.Core { offset.X += shadowSize - 1; offset.Y += shadowSize - 1; Bitmap returnImage = CreateEmpty(sourceBitmap.Width + (shadowSize * 2), sourceBitmap.Height + (shadowSize * 2), targetPixelformat, Color.Empty, sourceBitmap.HorizontalResolution, sourceBitmap.VerticalResolution); + // Make sure the shadow is odd, there is no reason for an even blur! + if ((shadowSize & 1) == 0) { + shadowSize++; + } + bool canUseGDIBlur = GDIplus.isBlurPossible(shadowSize); using (Graphics graphics = Graphics.FromImage(returnImage)) { // Make sure we draw with the best quality! graphics.SmoothingMode = SmoothingMode.HighQuality; @@ -943,7 +947,11 @@ namespace GreenshotPlugin.Core { cm.Matrix00 = 0; cm.Matrix11 = 0; cm.Matrix22 = 0; - cm.Matrix33 = darkness; + if (canUseGDIBlur) { + cm.Matrix33 = darkness + 0.1f; + } else { + cm.Matrix33 = darkness; + } ia.SetColorMatrix(cm); Rectangle shadowRectangle = new Rectangle(new Point(shadowSize, shadowSize), sourceBitmap.Size); graphics.DrawImage(sourceBitmap, shadowRectangle, 0, 0, sourceBitmap.Width, sourceBitmap.Height, GraphicsUnit.Pixel, ia); @@ -951,11 +959,14 @@ namespace GreenshotPlugin.Core { // blur "shadow", apply to whole new image // Gaussian - Rectangle newImageRectangle = new Rectangle(0, 0, returnImage.Width, returnImage.Height); - if (!GDIplus.ApplyBlur(returnImage, newImageRectangle, shadowSize, false)) { - // something went wrong, try normal software blur + if (canUseGDIBlur) { + // Use GDI Blur + Rectangle newImageRectangle = new Rectangle(0, 0, returnImage.Width, returnImage.Height); + GDIplus.ApplyBlur(returnImage, newImageRectangle, shadowSize, false); + } else { + // try normal software blur //returnImage = CreateBlur(returnImage, newImageRectangle, true, shadowSize, 1d, false, newImageRectangle); - ApplyBoxBlur(returnImage, shadowSize-2); + ApplyBoxBlur(returnImage, shadowSize); } if (returnImage != null) { diff --git a/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs b/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs index 0586992b9..e4a7c4508 100644 --- a/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs +++ b/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs @@ -165,7 +165,13 @@ namespace GreenshotPlugin.UnmanagedHelpers { return (IntPtr)FIELD_INFO_NATIVE_IMAGEATTRIBUTES.GetValue(imageAttributes); } - private static bool isBlurPossible(int radius) { + /// + /// Returns if a GDIPlus blur can be made for the supplied radius. + /// This accounts for the "bug" I reported here: http://social.technet.microsoft.com/Forums/en/w8itprogeneral/thread/99ddbe9d-556d-475a-8bab-84e25aa13a2c + /// + /// + /// + public static bool isBlurPossible(int radius) { if (Environment.OSVersion.Version.Major < 6) { return false; } else if ((Environment.OSVersion.Version.Major >= 6 && Environment.OSVersion.Version.Minor >= 2) && radius < 20) {