diff --git a/GreenshotPlugin/Core/FastBitmap.cs b/GreenshotPlugin/Core/FastBitmap.cs
index 49bbb58b1..ec80b1906 100644
--- a/GreenshotPlugin/Core/FastBitmap.cs
+++ b/GreenshotPlugin/Core/FastBitmap.cs
@@ -107,6 +107,13 @@ namespace GreenshotPlugin.Core {
set;
}
+ ///
+ /// Returns if this FastBitmap has an alpha channel
+ ///
+ bool hasAlphaChannel {
+ get;
+ }
+
///
/// Draw the stored bitmap to the destionation bitmap at the supplied point
///
@@ -129,10 +136,16 @@ namespace GreenshotPlugin.Core {
public unsafe abstract class FastBitmap : IFastBitmap {
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(FastBitmap));
- protected const int AINDEX = 3;
- protected const int RINDEX = 2;
- protected const int GINDEX = 1;
- protected const int BINDEX = 0;
+ protected const int PIXELFORMAT_INDEX_A = 3;
+ protected const int PIXELFORMAT_INDEX_R = 2;
+ protected const int PIXELFORMAT_INDEX_G = 1;
+ protected const int PIXELFORMAT_INDEX_B = 0;
+
+ public const int COLOR_INDEX_R = 0;
+ public const int COLOR_INDEX_G = 1;
+ public const int COLOR_INDEX_B = 2;
+ public const int COLOR_INDEX_A = 3;
+
protected Rectangle area = Rectangle.Empty;
///
/// If this is set to true, the bitmap will be disposed when disposing the IFastBitmap
@@ -289,6 +302,12 @@ namespace GreenshotPlugin.Core {
return bitmap;
}
+ public virtual bool hasAlphaChannel {
+ get {
+ return false;
+ }
+ }
+
///
/// Destructor
///
@@ -513,7 +532,7 @@ namespace GreenshotPlugin.Core {
/// Color
public override Color GetColorAt(int x, int y) {
int offset = (x * 3) + (y * stride);
- return Color.FromArgb(255, pointer[RINDEX + offset], pointer[GINDEX + offset], pointer[BINDEX + offset]);
+ return Color.FromArgb(255, pointer[PIXELFORMAT_INDEX_R + offset], pointer[PIXELFORMAT_INDEX_G + offset], pointer[PIXELFORMAT_INDEX_B + offset]);
}
///
@@ -525,9 +544,9 @@ namespace GreenshotPlugin.Core {
///
public override void SetColorAt(int x, int y, Color color) {
int offset = (x * 3) + (y * stride);
- pointer[RINDEX + offset] = color.R;
- pointer[GINDEX + offset] = color.G;
- pointer[BINDEX + offset] = color.B;
+ pointer[PIXELFORMAT_INDEX_R + offset] = color.R;
+ pointer[PIXELFORMAT_INDEX_G + offset] = color.G;
+ pointer[PIXELFORMAT_INDEX_B + offset] = color.B;
}
///
@@ -535,13 +554,12 @@ namespace GreenshotPlugin.Core {
///
///
///
- /// byte[4] as reference (a,r,g,b)
+ /// byte[4] as reference (r,g,b)
public override void GetColorAt(int x, int y, byte[] color) {
int offset = (x * 3) + (y * stride);
- color[0] = 255;
- color[1] = pointer[RINDEX + offset];
- color[2] = pointer[GINDEX + offset];
- color[3] = pointer[BINDEX + offset];
+ color[PIXELFORMAT_INDEX_R] = pointer[PIXELFORMAT_INDEX_R + offset];
+ color[PIXELFORMAT_INDEX_G] = pointer[PIXELFORMAT_INDEX_G + offset];
+ color[PIXELFORMAT_INDEX_B] = pointer[PIXELFORMAT_INDEX_B + offset];
}
///
@@ -549,12 +567,12 @@ namespace GreenshotPlugin.Core {
///
///
///
- /// byte[4] as reference (a,r,g,b)
+ /// byte[4] as reference (r,g,b)
public override void SetColorAt(int x, int y, byte[] color) {
int offset = (x * 3) + (y * stride);
- pointer[RINDEX + offset] = color[1];
- pointer[GINDEX + offset] = color[2];
- pointer[BINDEX + offset] = color[3];
+ pointer[PIXELFORMAT_INDEX_R + offset] = color[PIXELFORMAT_INDEX_R];
+ pointer[PIXELFORMAT_INDEX_G + offset] = color[PIXELFORMAT_INDEX_G];
+ pointer[PIXELFORMAT_INDEX_B + offset] = color[PIXELFORMAT_INDEX_B];
}
}
@@ -576,7 +594,7 @@ namespace GreenshotPlugin.Core {
/// Color
public override Color GetColorAt(int x, int y) {
int offset = (x * 4) + (y * stride);
- return Color.FromArgb(255, pointer[RINDEX + offset], pointer[GINDEX + offset], pointer[BINDEX + offset]);
+ return Color.FromArgb(255, pointer[PIXELFORMAT_INDEX_R + offset], pointer[PIXELFORMAT_INDEX_G + offset], pointer[PIXELFORMAT_INDEX_B + offset]);
}
///
@@ -588,9 +606,9 @@ namespace GreenshotPlugin.Core {
///
public override void SetColorAt(int x, int y, Color color) {
int offset = (x * 4) + (y * stride);
- pointer[RINDEX + offset] = color.R;
- pointer[GINDEX + offset] = color.G;
- pointer[BINDEX + offset] = color.B;
+ pointer[PIXELFORMAT_INDEX_R + offset] = color.R;
+ pointer[PIXELFORMAT_INDEX_G + offset] = color.G;
+ pointer[PIXELFORMAT_INDEX_B + offset] = color.B;
}
///
@@ -601,10 +619,9 @@ namespace GreenshotPlugin.Core {
/// byte[4] as reference (a,r,g,b)
public override void GetColorAt(int x, int y, byte[] color) {
int offset = (x * 4) + (y * stride);
- color[0] = 255;
- color[1] = pointer[RINDEX + offset];
- color[2] = pointer[GINDEX + offset];
- color[3] = pointer[BINDEX + offset];
+ color[COLOR_INDEX_R] = pointer[PIXELFORMAT_INDEX_R + offset];
+ color[COLOR_INDEX_G] = pointer[PIXELFORMAT_INDEX_G + offset];
+ color[COLOR_INDEX_B] = pointer[PIXELFORMAT_INDEX_B + offset];
}
///
@@ -612,12 +629,12 @@ namespace GreenshotPlugin.Core {
///
///
///
- /// byte[4] as reference (a,r,g,b)
+ /// byte[4] as reference (r,g,b)
public override void SetColorAt(int x, int y, byte[] color) {
int offset = (x * 4) + (y * stride);
- pointer[RINDEX + offset] = color[1]; // R
- pointer[GINDEX + offset] = color[2];
- pointer[BINDEX + offset] = color[3];
+ pointer[PIXELFORMAT_INDEX_R + offset] = color[COLOR_INDEX_R]; // R
+ pointer[PIXELFORMAT_INDEX_G + offset] = color[COLOR_INDEX_G];
+ pointer[PIXELFORMAT_INDEX_B + offset] = color[COLOR_INDEX_B];
}
}
@@ -625,6 +642,12 @@ namespace GreenshotPlugin.Core {
/// This is the implementation of the IFastBitmap for 32 bit images with Alpha
///
public unsafe class Fast32ARGBBitmap : FastBitmap {
+ public override bool hasAlphaChannel {
+ get {
+ return true;
+ }
+ }
+
public Color BackgroundBlendColor {
get;
set;
@@ -641,7 +664,7 @@ namespace GreenshotPlugin.Core {
/// Color
public override Color GetColorAt(int x, int y) {
int offset = (x * 4) + (y * stride);
- return Color.FromArgb(pointer[AINDEX + offset], pointer[RINDEX + offset], pointer[GINDEX + offset], pointer[BINDEX + offset]);
+ return Color.FromArgb(pointer[PIXELFORMAT_INDEX_A + offset], pointer[PIXELFORMAT_INDEX_R + offset], pointer[PIXELFORMAT_INDEX_G + offset], pointer[PIXELFORMAT_INDEX_B + offset]);
}
///
@@ -653,10 +676,10 @@ namespace GreenshotPlugin.Core {
///
public override void SetColorAt(int x, int y, Color color) {
int offset = (x * 4) + (y * stride);
- pointer[AINDEX + offset] = color.A;
- pointer[RINDEX + offset] = color.R;
- pointer[GINDEX + offset] = color.G;
- pointer[BINDEX + offset] = color.B;
+ pointer[PIXELFORMAT_INDEX_A + offset] = color.A;
+ pointer[PIXELFORMAT_INDEX_R + offset] = color.R;
+ pointer[PIXELFORMAT_INDEX_G + offset] = color.G;
+ pointer[PIXELFORMAT_INDEX_B + offset] = color.B;
}
///
@@ -664,13 +687,13 @@ namespace GreenshotPlugin.Core {
///
///
///
- /// byte[4] as reference (a,r,g,b)
+ /// byte[4] as reference (r,g,b,a)
public override void GetColorAt(int x, int y, byte[] color) {
int offset = (x * 4) + (y * stride);
- color[0] = pointer[AINDEX + offset];
- color[1] = pointer[RINDEX + offset];
- color[2] = pointer[GINDEX + offset];
- color[3] = pointer[BINDEX + offset];
+ color[COLOR_INDEX_R] = pointer[PIXELFORMAT_INDEX_R + offset];
+ color[COLOR_INDEX_G] = pointer[PIXELFORMAT_INDEX_G + offset];
+ color[COLOR_INDEX_B] = pointer[PIXELFORMAT_INDEX_B + offset];
+ color[COLOR_INDEX_A] = pointer[PIXELFORMAT_INDEX_A + offset];
}
///
@@ -678,13 +701,13 @@ namespace GreenshotPlugin.Core {
///
///
///
- /// byte[4] as reference (a,r,g,b)
+ /// byte[4] as reference (r,g,b,a)
public override void SetColorAt(int x, int y, byte[] color) {
int offset = (x * 4) + (y * stride);
- pointer[AINDEX + offset] = color[0];
- pointer[RINDEX + offset] = color[1]; // R
- pointer[GINDEX + offset] = color[2];
- pointer[BINDEX + offset] = color[3];
+ pointer[PIXELFORMAT_INDEX_R + offset] = color[COLOR_INDEX_R]; // R
+ pointer[PIXELFORMAT_INDEX_G + offset] = color[COLOR_INDEX_G];
+ pointer[PIXELFORMAT_INDEX_B + offset] = color[COLOR_INDEX_B];
+ pointer[PIXELFORMAT_INDEX_A + offset] = color[COLOR_INDEX_A];
}
///
@@ -696,10 +719,10 @@ namespace GreenshotPlugin.Core {
/// Color
public Color GetBlendedColorAt(int x, int y) {
int offset = (x * 4) + (y * stride);
- int a = pointer[AINDEX + offset];
- int red = pointer[RINDEX + offset];
- int green = pointer[GINDEX + offset];
- int blue = pointer[BINDEX + offset];
+ int a = pointer[PIXELFORMAT_INDEX_A + offset];
+ int red = pointer[PIXELFORMAT_INDEX_R + offset];
+ int green = pointer[PIXELFORMAT_INDEX_G + offset];
+ int blue = pointer[PIXELFORMAT_INDEX_B + offset];
if (a < 255) {
// As the request is to get without alpha, we blend.
diff --git a/GreenshotPlugin/Core/ImageHelper.cs b/GreenshotPlugin/Core/ImageHelper.cs
index 83cb460c4..a7cde338c 100644
--- a/GreenshotPlugin/Core/ImageHelper.cs
+++ b/GreenshotPlugin/Core/ImageHelper.cs
@@ -658,29 +658,94 @@ namespace GreenshotPlugin.Core {
/// Bitmap to blur
/// Must be ODD!
/// Bitmap
- public static Bitmap BoxBlur(Bitmap sourceBitmap, int range) {
+ public static Bitmap ApplyBoxBlur(Bitmap destinationBitmap, int range) {
if ((range & 1) == 0) {
range++;
//throw new InvalidOperationException("Range must be odd!");
}
- using (IFastBitmap bbbDest = FastBitmap.CreateCloneOf(sourceBitmap, PixelFormat.Format32bppArgb)) {
- BoxBlurHorizontal(bbbDest, range);
- BoxBlurVertical(bbbDest, range);
- BoxBlurHorizontal(bbbDest, range + 1);
- BoxBlurVertical(bbbDest, range + 1);
- return bbbDest.UnlockAndReturnBitmap();
+ 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.
+ 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();
}
}
///
/// BoxBlurHorizontal is a private helper method for the BoxBlur
///
- /// Source BitmapBuffer
- /// Target BitmapBuffer
+ /// Target BitmapBuffer
/// Range must be odd!
- private static void BoxBlurHorizontal(IFastBitmap bbbDest, int range) {
- int w = bbbDest.Width;
- int h = bbbDest.Height;
+ public static void BoxBlurHorizontal(IFastBitmap targetFastBitmap, int range) {
+ if (targetFastBitmap.hasAlphaChannel) {
+ throw new NotSupportedException("BoxBlurHorizontal should NOT be called for bitmaps with alpha channel");
+ }
+ int w = targetFastBitmap.Width;
+ int h = targetFastBitmap.Height;
+ int halfRange = range / 2;
+ Color[] newColors = new Color[w];
+ byte[] tmpColor = new byte[3];
+ for (int y = 0; y < h; y++) {
+ int hits = 0;
+ int r = 0;
+ int g = 0;
+ int b = 0;
+ for (int x = -halfRange; x < w; x++) {
+ int oldPixel = x - halfRange - 1;
+ if (oldPixel >= 0) {
+ targetFastBitmap.GetColorAt(oldPixel, y, tmpColor);
+ r -= tmpColor[FastBitmap.COLOR_INDEX_R];
+ g -= tmpColor[FastBitmap.COLOR_INDEX_G];
+ b -= tmpColor[FastBitmap.COLOR_INDEX_B];
+ hits--;
+ }
+
+ int newPixel = x + halfRange;
+ if (newPixel < w) {
+ targetFastBitmap.GetColorAt(newPixel, y, tmpColor);
+ r += tmpColor[FastBitmap.COLOR_INDEX_R];
+ g += tmpColor[FastBitmap.COLOR_INDEX_G];
+ b += tmpColor[FastBitmap.COLOR_INDEX_B];
+ hits++;
+ }
+
+ if (x >= 0) {
+ newColors[x] = Color.FromArgb(255, (byte)(r / hits), (byte)(g / hits), (byte)(b / hits));
+ }
+ }
+ for (int x = 0; x < w; x++) {
+ targetFastBitmap.SetColorAt(x, y, newColors[x]);
+ }
+ }
+ }
+ ///
+ /// BoxBlurHorizontal is a private helper method for the BoxBlur, only for IFastBitmaps with alpha channel
+ ///
+ /// Source BitmapBuffer
+ /// Target BitmapBuffer
+ /// Range must be odd!
+ public static void BoxBlurHorizontalAlpha(IFastBitmap targetFastBitmap, int range) {
+ if (!targetFastBitmap.hasAlphaChannel) {
+ throw new NotSupportedException("BoxBlurHorizontalAlpha should be called for bitmaps with alpha channel");
+ }
+ int w = targetFastBitmap.Width;
+ int h = targetFastBitmap.Height;
int halfRange = range / 2;
Color[] newColors = new Color[w];
byte[] tmpColor = new byte[4];
@@ -693,21 +758,21 @@ namespace GreenshotPlugin.Core {
for (int x = -halfRange; x < w; x++) {
int oldPixel = x - halfRange - 1;
if (oldPixel >= 0) {
- bbbDest.GetColorAt(oldPixel, y, tmpColor);
- a -= tmpColor[0];
- r -= tmpColor[1];
- g -= tmpColor[2];
- b -= tmpColor[3];
+ targetFastBitmap.GetColorAt(oldPixel, y, tmpColor);
+ a -= tmpColor[FastBitmap.COLOR_INDEX_A];
+ r -= tmpColor[FastBitmap.COLOR_INDEX_R];
+ g -= tmpColor[FastBitmap.COLOR_INDEX_G];
+ b -= tmpColor[FastBitmap.COLOR_INDEX_B];
hits--;
}
int newPixel = x + halfRange;
if (newPixel < w) {
- bbbDest.GetColorAt(newPixel, y, tmpColor);
- a += tmpColor[0];
- r += tmpColor[1];
- g += tmpColor[2];
- b += tmpColor[3];
+ targetFastBitmap.GetColorAt(newPixel, y, tmpColor);
+ a += tmpColor[FastBitmap.COLOR_INDEX_A];
+ r += tmpColor[FastBitmap.COLOR_INDEX_R];
+ g += tmpColor[FastBitmap.COLOR_INDEX_G];
+ b += tmpColor[FastBitmap.COLOR_INDEX_B];
hits++;
}
@@ -716,7 +781,7 @@ namespace GreenshotPlugin.Core {
}
}
for (int x = 0; x < w; x++) {
- bbbDest.SetColorAt(x, y, newColors[x]);
+ targetFastBitmap.SetColorAt(x, y, newColors[x]);
}
}
}
@@ -724,11 +789,66 @@ namespace GreenshotPlugin.Core {
///
/// BoxBlurVertical is a private helper method for the BoxBlur
///
- /// BitmapBuffer which previously was created with BoxBlurHorizontal
+ /// BitmapBuffer which previously was created with BoxBlurHorizontal
/// Range must be odd!
- private static void BoxBlurVertical(IFastBitmap bbbDest, int range) {
- int w = bbbDest.Width;
- int h = bbbDest.Height;
+ public static void BoxBlurVertical(IFastBitmap targetFastBitmap, int range) {
+ if (targetFastBitmap.hasAlphaChannel) {
+ throw new NotSupportedException("BoxBlurVertical should NOT be called for bitmaps with alpha channel");
+ }
+ int w = targetFastBitmap.Width;
+ int h = targetFastBitmap.Height;
+ int halfRange = range / 2;
+ Color[] newColors = new Color[h];
+ int oldPixelOffset = -(halfRange + 1) * w;
+ int newPixelOffset = (halfRange) * w;
+ byte[] tmpColor = new byte[4];
+ for (int x = 0; x < w; x++) {
+ int hits = 0;
+ int r = 0;
+ int g = 0;
+ int b = 0;
+ for (int y = -halfRange; y < h; y++) {
+ int oldPixel = y - halfRange - 1;
+ if (oldPixel >= 0) {
+ targetFastBitmap.GetColorAt(x, oldPixel, tmpColor);
+ r -= tmpColor[FastBitmap.COLOR_INDEX_R];
+ g -= tmpColor[FastBitmap.COLOR_INDEX_G];
+ b -= tmpColor[FastBitmap.COLOR_INDEX_B];
+ hits--;
+ }
+
+ int newPixel = y + halfRange;
+ if (newPixel < h) {
+ targetFastBitmap.GetColorAt(x, newPixel, tmpColor);
+ r += tmpColor[FastBitmap.COLOR_INDEX_R];
+ g += tmpColor[FastBitmap.COLOR_INDEX_G];
+ b += tmpColor[FastBitmap.COLOR_INDEX_B];
+ hits++;
+ }
+
+ if (y >= 0) {
+ newColors[y] = Color.FromArgb(255, (byte)(r / hits), (byte)(g / hits), (byte)(b / hits));
+ }
+ }
+
+ for (int y = 0; y < h; y++) {
+ targetFastBitmap.SetColorAt(x, y, newColors[y]);
+ }
+ }
+ }
+
+ ///
+ /// BoxBlurVertical is a private helper method for the BoxBlur
+ ///
+ /// BitmapBuffer which previously was created with BoxBlurHorizontal
+ /// Range must be odd!
+ public static void BoxBlurVerticalAlpha(IFastBitmap targetFastBitmap, int range) {
+ if (!targetFastBitmap.hasAlphaChannel) {
+ throw new NotSupportedException("BoxBlurVerticalAlpha should be called for bitmaps with alpha channel");
+ }
+
+ int w = targetFastBitmap.Width;
+ int h = targetFastBitmap.Height;
int halfRange = range / 2;
Color[] newColors = new Color[h];
int oldPixelOffset = -(halfRange + 1) * w;
@@ -744,22 +864,22 @@ namespace GreenshotPlugin.Core {
int oldPixel = y - halfRange - 1;
if (oldPixel >= 0) {
//int colorg = pixels[index + oldPixelOffset];
- bbbDest.GetColorAt(x, oldPixel, tmpColor);
- a -= tmpColor[0];
- r -= tmpColor[1];
- g -= tmpColor[2];
- b -= tmpColor[3];
+ targetFastBitmap.GetColorAt(x, oldPixel, tmpColor);
+ a -= tmpColor[FastBitmap.COLOR_INDEX_A];
+ r -= tmpColor[FastBitmap.COLOR_INDEX_R];
+ g -= tmpColor[FastBitmap.COLOR_INDEX_G];
+ b -= tmpColor[FastBitmap.COLOR_INDEX_B];
hits--;
}
int newPixel = y + halfRange;
if (newPixel < h) {
//int colorg = pixels[index + newPixelOffset];
- bbbDest.GetColorAt(x, newPixel, tmpColor);
- a += tmpColor[0];
- r += tmpColor[1];
- g += tmpColor[2];
- b += tmpColor[3];
+ targetFastBitmap.GetColorAt(x, newPixel, tmpColor);
+ a += tmpColor[FastBitmap.COLOR_INDEX_A];
+ r += tmpColor[FastBitmap.COLOR_INDEX_R];
+ g += tmpColor[FastBitmap.COLOR_INDEX_G];
+ b += tmpColor[FastBitmap.COLOR_INDEX_B];
hits++;
}
@@ -769,12 +889,11 @@ namespace GreenshotPlugin.Core {
}
for (int y = 0; y < h; y++) {
- bbbDest.SetColorAt(x, y, newColors[y]);
+ targetFastBitmap.SetColorAt(x, y, newColors[y]);
}
}
}
-
///
/// This method fixes the problem that we can't apply a filter outside the target bitmap,
/// therefor the filtered-bitmap will be shifted if we try to draw it outside the target bitmap.
@@ -807,41 +926,40 @@ namespace GreenshotPlugin.Core {
/// Bitmap with the shadow, is bigger than the sourceBitmap!!
public static Bitmap CreateShadow(Image sourceBitmap, float darkness, int shadowSize, Point shadowOffset, out Point offset, PixelFormat targetPixelformat) {
// Create a new "clean" image
- Bitmap returnImage = null;
offset = shadowOffset;
offset.X += shadowSize - 1;
offset.Y += shadowSize - 1;
- using (Bitmap tmpImage = CreateEmpty(sourceBitmap.Width + (shadowSize * 2), sourceBitmap.Height + (shadowSize * 2), targetPixelformat, Color.Empty, sourceBitmap.HorizontalResolution, sourceBitmap.VerticalResolution)) {
- using (Graphics graphics = Graphics.FromImage(tmpImage)) {
- // Make sure we draw with the best quality!
- graphics.SmoothingMode = SmoothingMode.HighQuality;
- graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
- graphics.CompositingQuality = CompositingQuality.HighQuality;
- graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ Bitmap returnImage = CreateEmpty(sourceBitmap.Width + (shadowSize * 2), sourceBitmap.Height + (shadowSize * 2), targetPixelformat, Color.Empty, sourceBitmap.HorizontalResolution, sourceBitmap.VerticalResolution);
+ using (Graphics graphics = Graphics.FromImage(returnImage)) {
+ // Make sure we draw with the best quality!
+ graphics.SmoothingMode = SmoothingMode.HighQuality;
+ graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
+ graphics.CompositingQuality = CompositingQuality.HighQuality;
+ graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
- // Draw "shadow" offsetted
- ImageAttributes ia = new ImageAttributes();
- ColorMatrix cm = new ColorMatrix();
- cm.Matrix00 = 0;
- cm.Matrix11 = 0;
- cm.Matrix22 = 0;
- 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);
- }
- // blur "shadow", apply to whole new image
- //using (Bitmap blurImage = FastBlur(newImage, shadowSize-1)) {
+ // Draw "shadow" offsetted
+ ImageAttributes ia = new ImageAttributes();
+ ColorMatrix cm = new ColorMatrix();
+ cm.Matrix00 = 0;
+ cm.Matrix11 = 0;
+ cm.Matrix22 = 0;
+ 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);
+ }
+ // blur "shadow", apply to whole new image
- // Gaussian
- Rectangle newImageRectangle = new Rectangle(0, 0, tmpImage.Width, tmpImage.Height);
- returnImage = CreateBlur(tmpImage, newImageRectangle, true, shadowSize, 1d, false, newImageRectangle);
+ // 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
+ //returnImage = CreateBlur(returnImage, newImageRectangle, true, shadowSize, 1d, false, newImageRectangle);
+ ApplyBoxBlur(returnImage, shadowSize);
- // Box
- //returnImage = BoxBlur(tmpImage, shadowSize);
-
//returnImage = FastBlur(tmpImage, shadowSize - 1);
}
+
if (returnImage != null) {
using (Graphics graphics = Graphics.FromImage(returnImage)) {
// Make sure we draw with the best quality!
diff --git a/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs b/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs
index 0e78a3a71..d641407b4 100644
--- a/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs
+++ b/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs
@@ -164,7 +164,16 @@ namespace GreenshotPlugin.UnmanagedHelpers {
}
return (IntPtr)FIELD_INFO_NATIVE_IMAGEATTRIBUTES.GetValue(imageAttributes);
}
-
+
+ private static bool canApply() {
+ if (Environment.OSVersion.Version.Major < 6) {
+ return false;
+ } else if ((Environment.OSVersion.Version.Major >= 6 && Environment.OSVersion.Version.Minor >= 2) && radius < 20) {
+ return false;
+ }
+ return true;
+ }
+
///
/// Use the GDI+ blur effect on the bitmap
///
@@ -174,7 +183,7 @@ namespace GreenshotPlugin.UnmanagedHelpers {
/// 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, int radius, bool expandEdges) {
- if (Environment.OSVersion.Version.Major < 6) {
+ if (!canApply()) {
return false;
}
IntPtr hBlurParams = IntPtr.Zero;
@@ -228,11 +237,10 @@ namespace GreenshotPlugin.UnmanagedHelpers {
///
/// 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) {
+ if (!canApply()) {
return false;
}
+
IntPtr hBlurParams = IntPtr.Zero;
IntPtr hEffect = IntPtr.Zero;