diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index 6b2dfaf1e..32a818284 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -797,7 +797,7 @@ namespace Greenshot.Drawing { break; case Effects.TornEdge: using (Bitmap tmpImage = ImageHelper.CreateTornEdge((Bitmap)Image)) { - newImage = ImageHelper.CreateShadow(tmpImage, 1f, 6, ref offset, PixelFormat.Format32bppArgb); //Image.PixelFormat); + newImage = ImageHelper.CreateShadow(tmpImage, 1f, 7, ref offset, PixelFormat.Format32bppArgb); //Image.PixelFormat); } break; case Effects.Border: diff --git a/GreenshotPlugin/Core/BitmapBuffer.cs b/GreenshotPlugin/Core/BitmapBuffer.cs index 4aa42ad37..3ff4a4476 100644 --- a/GreenshotPlugin/Core/BitmapBuffer.cs +++ b/GreenshotPlugin/Core/BitmapBuffer.cs @@ -62,6 +62,12 @@ namespace GreenshotPlugin.Core { } } + public PixelFormat PixelFormat { + get { + return bitmap.PixelFormat; + } + } + [NonSerialized] private BitmapData bmData; [NonSerialized] @@ -69,6 +75,8 @@ namespace GreenshotPlugin.Core { [NonSerialized] private byte* pointer; [NonSerialized] + private int* intPointer; + [NonSerialized] private int stride; /* bytes per pixel row */ [NonSerialized] private int aIndex = -1; @@ -219,7 +227,8 @@ namespace GreenshotPlugin.Core { bitsLocked = true; IntPtr Scan0 = bmData.Scan0; - pointer = (byte*)(void*)Scan0; + pointer = (byte*)(void*)Scan0; + intPointer = (int*)(void*)Scan0; PrepareForPixelFormat(); stride = bmData.Stride; @@ -300,6 +309,28 @@ namespace GreenshotPlugin.Core { pointer[offset] = color; } + /// + /// Use only when 32-bit bitmap! + /// + /// x + /// y + /// int with argb value + public int GetARGB(int x, int y) { + int offset = (y * (stride >> 2)) + x; + return intPointer[offset]; + } + + /// + /// Use only when 32-bit bitmap! + /// + /// x + /// y + /// argb value + public void SetARGB(int x, int y, int argb) { + int offset = (y * (stride>>2)) + x; + intPointer[offset] = argb; + } + /// /// Retrieve the color at location x,y /// Before the first time this is called the Lock() should be called once! @@ -372,6 +403,18 @@ namespace GreenshotPlugin.Core { } } + /** + * Retrieve the color at location x,y to a byte[] + * Before the first time this is called the Lock() should be called once! + */ + public void GetUncheckedColorIn(int x, int y, byte[] color) { + int offset = x * bytesPerPixel + y * stride; + color[0] = (aIndex == -1) ? (byte)255 : (byte)pointer[aIndex + offset]; + color[1] = pointer[rIndex + offset]; + color[2] = pointer[gIndex + offset]; + color[3] = pointer[bIndex + offset]; + } + /** * Retrieve the color at location x,y to a byte[] * Before the first time this is called the Lock() should be called once! diff --git a/GreenshotPlugin/Core/ImageHelper.cs b/GreenshotPlugin/Core/ImageHelper.cs index 71c1c9777..08466b402 100644 --- a/GreenshotPlugin/Core/ImageHelper.cs +++ b/GreenshotPlugin/Core/ImageHelper.cs @@ -593,6 +593,130 @@ namespace GreenshotPlugin.Core { } } + /// + /// Create a new Bitmap with the BoxBlur result of the sourceBitmap + /// + /// Bitmap to blur + /// Must be ODD! + /// Bitmap + public static Bitmap BoxBlur(Bitmap sourceBitmap, int range) { + if ((range & 1) == 0) { + throw new InvalidOperationException("Range must be odd!"); + } + using (BitmapBuffer bbbDest = new BitmapBuffer(sourceBitmap, true)) { + bbbDest.Lock(); + using (BitmapBuffer bbbSrc = new BitmapBuffer(sourceBitmap, false)) { + bbbSrc.Lock(); + BoxBlurHorizontal(bbbSrc, bbbDest, range); + } + BoxBlurVertical(bbbDest, range); + bbbDest.Unlock(); + return bbbDest.Bitmap; + } + } + + /// + /// BoxBlurHorizontal is a private helper method for the BoxBlur + /// + /// Source BitmapBuffer + /// Target BitmapBuffer + /// Range must be odd! + private static void BoxBlurHorizontal(BitmapBuffer bbbSrc, BitmapBuffer bbbDest, int range) { + int w = bbbSrc.Width; + int h = bbbSrc.Height; + int halfRange = range / 2; + int[] newColors = new int[w]; + byte[] tmpColor = new byte[4]; + for (int y = 0; y < h; y++) { + int hits = 0; + int a = 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) { + bbbSrc.GetUncheckedColorIn(oldPixel, y, tmpColor); + a -= tmpColor[0]; + r -= tmpColor[1]; + g -= tmpColor[2]; + b -= tmpColor[3]; + hits--; + } + + int newPixel = x + halfRange; + if (newPixel < w) { + bbbSrc.GetUncheckedColorIn(newPixel, y, tmpColor); + a += tmpColor[0]; + r += tmpColor[1]; + g += tmpColor[2]; + b += tmpColor[3]; + hits++; + } + + if (x >= 0) { + newColors[x] = ((byte)(a / hits)) << 24 | ((byte)(r / hits) << 16) | ((byte)(g / hits) << 8 ) | ((byte)(b / hits)); + } + } + for (int x = 0; x < w; x++) { + bbbDest.SetARGB(x, y, newColors[x]); + } + } + } + + /// + /// BoxBlurVertical is a private helper method for the BoxBlur + /// + /// BitmapBuffer which previously was created with BoxBlurHorizontal + /// Range must be odd! + private static void BoxBlurVertical(BitmapBuffer bbbDest, int range) { + int w = bbbDest.Width; + int h = bbbDest.Height; + int halfRange = range / 2; + int[] newColors = new int[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 a = 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) { + //int colorg = pixels[index + oldPixelOffset]; + bbbDest.GetUncheckedColorIn(x, oldPixel, tmpColor); + a -= tmpColor[0]; + r -= tmpColor[1]; + g -= tmpColor[2]; + b -= tmpColor[3]; + hits--; + } + + int newPixel = y + halfRange; + if (newPixel < h) { + //int colorg = pixels[index + newPixelOffset]; + bbbDest.GetUncheckedColorIn(x, newPixel, tmpColor); + a += tmpColor[0]; + r += tmpColor[1]; + g += tmpColor[2]; + b += tmpColor[3]; + hits++; + } + + if (y >= 0) { + newColors[y] = ((byte)(a / hits)) << 24 | ((byte)(r / hits) << 16) | ((byte)(g / hits) << 8) | ((byte)(b / hits)); + } + } + + for (int y = 0; y < h; y++) { + bbbDest.SetARGB(x, y, newColors[y]); + } + } + } + public static Bitmap FastBlur(Bitmap sourceBitmap, int radius) { if (radius < 1) return null; @@ -747,6 +871,7 @@ namespace GreenshotPlugin.Core { Rectangle newImageRectangle = new Rectangle(0, 0, tmpImage.Width, tmpImage.Height); //using (Bitmap blurImage = FastBlur(newImage, shadowSize-1)) { returnImage = CreateBlur(tmpImage, newImageRectangle, true, shadowSize, 1d, false, newImageRectangle); + //returnImage = BoxBlur(tmpImage, shadowSize); } if (returnImage != null) { using (Graphics graphics = Graphics.FromImage(returnImage)) { diff --git a/GreenshotPlugin/Core/WindowsHelper.cs b/GreenshotPlugin/Core/WindowsHelper.cs index aa1098e6b..bacf49bd9 100644 --- a/GreenshotPlugin/Core/WindowsHelper.cs +++ b/GreenshotPlugin/Core/WindowsHelper.cs @@ -776,32 +776,25 @@ namespace GreenshotPlugin.Core { Size borderSize = new Size(); if (!Maximised) { - Screen displayScreen = null; - - // Find the screen where the window is and check if it fits - foreach(Screen screen in Screen.AllScreens) { - if (screen.WorkingArea.Contains(windowRectangle)) { - displayScreen = screen; - break; + // Assume using it's own location + formLocation = windowRectangle.Location; + using (Region workingArea = new Region(Screen.PrimaryScreen.WorkingArea)) { + // Find the screen where the window is and check if it fits + foreach (Screen screen in Screen.AllScreens) { + workingArea.Union(screen.WorkingArea); } - } - if (displayScreen == null) { - // If none found we find the biggest screen - foreach(Screen screen in Screen.AllScreens) { - if (displayScreen == null || (screen.Bounds.Width >= displayScreen.Bounds.Width && screen.Bounds.Height >= displayScreen.Bounds.Height)) { - displayScreen = screen; + + // If the formLocation is not inside the visible area + if (!workingArea.AreRectangleCornersVisisble(windowRectangle)) { + // If none found we find the biggest screen + foreach (Screen screen in Screen.AllScreens) { + Rectangle newWindowRectangle = new Rectangle(screen.WorkingArea.Location, windowRectangle.Size); + if (workingArea.AreRectangleCornersVisisble(newWindowRectangle)) { + formLocation = screen.WorkingArea.Location; + break; + } } } - // check if the window will fit - if (displayScreen != null && displayScreen.Bounds.Contains(new Rectangle(Point.Empty, windowRectangle.Size))) { - formLocation = new Point(displayScreen.Bounds.X, displayScreen.Bounds.Y); - } else { - // No, just use the primary screen - formLocation = new Point(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y); - } - } else { - // The window actually fits, so while capturing create the copy over the original - formLocation = new Point(windowRectangle.X, windowRectangle.Y); } } else { //GetClientRect(out windowRectangle); diff --git a/GreenshotPlugin/UnmanagedHelpers/GDI32.cs b/GreenshotPlugin/UnmanagedHelpers/GDI32.cs index ec8422584..cecb70d72 100644 --- a/GreenshotPlugin/UnmanagedHelpers/GDI32.cs +++ b/GreenshotPlugin/UnmanagedHelpers/GDI32.cs @@ -23,6 +23,20 @@ using System.Drawing; using System.Runtime.InteropServices; namespace GreenshotPlugin.UnmanagedHelpers { + public static class GDIExtensions { + public static bool AreRectangleCornersVisisble(this Region region, Rectangle rectangle) { + Point topLeft = new Point(rectangle.X, rectangle.Y); + Point topRight = new Point(rectangle.X + rectangle.Width, rectangle.Y); + Point bottomLeft = new Point(rectangle.X, rectangle.Y + rectangle.Height); + Point bottomRight = new Point(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height); + bool topLeftVisible = region.IsVisible(topLeft); + bool topRightVisible = region.IsVisible(topRight); + bool bottomLeftVisible = region.IsVisible(bottomLeft); + bool bottomRightVisible = region.IsVisible(bottomRight); + + return topLeftVisible && topRightVisible && bottomLeftVisible && bottomRightVisible; + } + } /// /// GDI32 Helpers ///