From 3f4d93f2b68e0df3960779d963a48991176013bf Mon Sep 17 00:00:00 2001 From: RKrom Date: Tue, 12 Feb 2013 16:36:09 +0000 Subject: [PATCH] Fixed an issue with the FastBitmap, renamed methods in the BitmapBuffer to be equal to the FastBitmap implementation. In general it's now very easy to switch from the BitmapBuffer to the FastBitmap implementation, but one should consider that the BitmapBuffer checks the x,y if they are inside... and supports a "apply rectangle". Had to "refactor" the CreateBlur for this. Changed the CreateShadow to work with the BoxBlur, this changes the time to create a shadow of a 1280x1024 from ~2.6 to ~1.2 seconds on my PC... which is still slow. The resulting effect seems to be extremely similar... good enough for me. git-svn-id: http://svn.code.sf.net/p/greenshot/code/trunk@2480 7dccd23d-a4a3-4e1f-8c07-b4c1b4018ab4 --- GreenshotPlugin/Core/BitmapBuffer.cs | 104 +++++++------ GreenshotPlugin/Core/FastBitmap.cs | 215 ++++++++++++++++++++++++--- GreenshotPlugin/Core/ImageHelper.cs | 211 ++++++++------------------ 3 files changed, 315 insertions(+), 215 deletions(-) diff --git a/GreenshotPlugin/Core/BitmapBuffer.cs b/GreenshotPlugin/Core/BitmapBuffer.cs index 6a99c499d..04576203f 100644 --- a/GreenshotPlugin/Core/BitmapBuffer.cs +++ b/GreenshotPlugin/Core/BitmapBuffer.cs @@ -64,6 +64,11 @@ namespace GreenshotPlugin.Core { } } + public Bitmap UnlockAndReturnBitmap() { + Unlock(); + return Bitmap; + } + public PixelFormat PixelFormat { get { return bitmap.PixelFormat; @@ -208,9 +213,9 @@ namespace GreenshotPlugin.Core { } } - /** - * Unlock the System Memory - */ + /// + /// Unlock the System Memory + /// public void Unlock() { if (bitsLocked) { bitmap.UnlockBits(bmData); @@ -218,24 +223,31 @@ namespace GreenshotPlugin.Core { } } - /** - * Draw the stored bitmap to the destionation bitmap at the supplied point - */ + /// + /// Draw the stored bitmap to the destionation bitmap at the supplied point + /// + /// + /// public void DrawTo(Graphics graphics, Point destination) { DrawTo(graphics, null, destination); } - /** - * Draw the stored Bitmap on the Destination bitmap with the specified rectangle - * Be aware that the stored bitmap will be resized to the specified rectangle!! - */ + /// + /// Draw the stored Bitmap on the Destination bitmap with the specified rectangle + /// Be aware that the stored bitmap will be resized to the specified rectangle!! + /// + /// + /// public void DrawTo(Graphics graphics, Rectangle destinationRect) { DrawTo(graphics, destinationRect, null); } - /** - * private helper to draw the bitmap - */ + /// + /// private helper to draw the bitmap + /// + /// + /// + /// private void DrawTo(Graphics graphics, Rectangle? destinationRect, Point? destination) { if (destinationRect.HasValue) { // Does the rect have any pixels? @@ -288,10 +300,13 @@ namespace GreenshotPlugin.Core { } } - /** - * Set the color at location x,y - * Before the first time this is called the Lock() should be called once! - */ + /// + /// Set the color at location x,y + /// Before the first time this is called the Lock() should be called once! + /// + /// + /// + /// public void SetColorAt(int x, int y, Color color) { if(x>=0 && y>=0 && x + /// 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]; @@ -314,11 +332,14 @@ namespace GreenshotPlugin.Core { 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! - */ - public void GetColorIn(int x, int y, byte[] color) { + /// + /// 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 GetColorAt(int x, int y, byte[] color) { if (x >= 0 && y >= 0 && x < rect.Width && y < rect.Height) { int offset = x * bytesPerPixel + y * stride; color[0] = (aIndex == -1) ? (byte)255 : (byte)pointer[aIndex + offset]; @@ -333,11 +354,14 @@ namespace GreenshotPlugin.Core { } } - /** - * Set the color at location x,y as an array - * Before the first time this is called the Lock() should be called once! - */ - public void SetColorArrayAt(int x, int y, byte[] colors) { + /// + /// Set the color at location x,y as an array + /// Before the first time this is called the Lock() should be called once! + /// + /// + /// + /// + public void SetColorAt(int x, int y, byte[] colors) { if(x>=0 && y>=0 && x + /// Set some internal values for accessing the bitmap according to the PixelFormat + /// private void PrepareForPixelFormat() { // aIndex is only set if the pixel format supports "A". aIndex = -1; diff --git a/GreenshotPlugin/Core/FastBitmap.cs b/GreenshotPlugin/Core/FastBitmap.cs index 44e9f9c42..aa4a66e65 100644 --- a/GreenshotPlugin/Core/FastBitmap.cs +++ b/GreenshotPlugin/Core/FastBitmap.cs @@ -29,20 +29,79 @@ namespace GreenshotPlugin.Core { /// The interface for the FastBitmap /// public interface IFastBitmap : IDisposable { + /// + /// Get the color at x,y + /// The returned Color object depends on the underlying pixel format + /// + /// int x + /// int y + /// Color Color GetColorAt(int x, int y); + + /// + /// Set the color at the specified location + /// + /// int x + /// int y + /// Color void SetColorAt(int x, int y, Color color); + + /// + /// Get the color at x,y + /// The returned byte[] color depends on the underlying pixel format + /// + /// int x + /// int y + /// Set the color at the specified location + /// + /// int x + /// int y + /// byte[] color + void SetColorAt(int x, int y, byte[] color); + + /// + /// Lock the bitmap + /// void Lock(); + + /// + /// Unlock the bitmap + /// void Unlock(); + + /// + /// Unlock the bitmap and get the underlying bitmap in one call + /// + /// Bitmap UnlockAndReturnBitmap(); + + /// + /// Size of the underlying image + /// Size Size { get; } + + /// + /// Height of the underlying image + /// int Height { get; } + + /// + /// Width of the underlying image + /// int Width { get; } + + /// + /// Does the underlying image need to be disposed + /// bool NeedsDispose { get; set; @@ -55,6 +114,10 @@ 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; /// /// If this is set to true, the bitmap will be disposed when disposing the IFastBitmap /// @@ -86,6 +149,7 @@ namespace GreenshotPlugin.Core { case PixelFormat.Format32bppRgb: return new Fast32RGBBitmap(source); case PixelFormat.Format32bppArgb: + case PixelFormat.Format32bppPArgb: return new Fast32ARGBBitmap(source); default: throw new NotSupportedException(string.Format("Not supported Pixelformat {0}", source.PixelFormat)); @@ -97,7 +161,7 @@ namespace GreenshotPlugin.Core { /// /// Bitmap to access /// IFastBitmap - public static IFastBitmap CreateDestinationFor(Bitmap source, PixelFormat pixelFormat) { + public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat) { Bitmap destination = ImageHelper.CloneArea(source, Rectangle.Empty, pixelFormat); IFastBitmap fastBitmap = Create(destination); ((FastBitmap)fastBitmap).NeedsDispose = true; @@ -119,8 +183,13 @@ namespace GreenshotPlugin.Core { return fastBitmap; } + /// + /// Constructor which stores the image and locks it when called + /// + /// protected FastBitmap(Bitmap bitmap) { this.bitmap = bitmap; + Lock(); } /// @@ -272,8 +341,13 @@ namespace GreenshotPlugin.Core { public abstract Color GetColorAt(int x, int y); public abstract void SetColorAt(int x, int y, Color color); + public abstract void GetColorAt(int x, int y, byte[] color); + public abstract void SetColorAt(int x, int y, byte[] color); } + /// + /// This is the implementation of the FastBitmat for the 8BPP pixelformat + /// public unsafe class FastChunkyBitmap : FastBitmap { // Used for indexed images private Color[] colorEntries; @@ -295,6 +369,26 @@ namespace GreenshotPlugin.Core { return colorEntries[colorIndex]; } + /// + /// Get the color from the specified location into the specified array + /// + /// + /// + /// byte[4] as reference + public override void GetColorAt(int x, int y, byte[] color) { + throw new NotImplementedException("No performance gain!"); + } + + /// + /// Set the color at the specified location from the specified array + /// + /// + /// + /// byte[4] as reference + public override void SetColorAt(int x, int y, byte[] color) { + throw new NotImplementedException("No performance gain!"); + } + /// /// Get the color-index from the specified location /// @@ -361,7 +455,7 @@ namespace GreenshotPlugin.Core { /// Color public override Color GetColorAt(int x, int y) { int offset = (x * 3) + (y * stride); - return Color.FromArgb(255, pointer[2 + offset], pointer[1 + offset], pointer[offset]); + return Color.FromArgb(255, pointer[RINDEX + offset], pointer[GINDEX + offset], pointer[BINDEX + offset]); } /// @@ -373,10 +467,38 @@ namespace GreenshotPlugin.Core { /// public override void SetColorAt(int x, int y, Color color) { int offset = (x * 3) + (y * stride); - pointer[2 + offset] = color.R; - pointer[1 + offset] = color.G; - pointer[offset] = color.B; + pointer[RINDEX + offset] = color.R; + pointer[GINDEX + offset] = color.G; + pointer[BINDEX + offset] = color.B; } + + /// + /// Get the color from the specified location into the specified array + /// + /// + /// + /// byte[4] as reference (a,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]; + } + + /// + /// Set the color at the specified location from the specified array + /// + /// + /// + /// byte[4] as reference (a,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]; + } + } /// @@ -396,7 +518,7 @@ namespace GreenshotPlugin.Core { /// Color public override Color GetColorAt(int x, int y) { int offset = (x * 4) + (y * stride); - return Color.FromArgb(255, pointer[2 + offset], pointer[1 + offset], pointer[offset]); + return Color.FromArgb(255, pointer[RINDEX + offset], pointer[GINDEX + offset], pointer[BINDEX + offset]); } /// @@ -408,9 +530,36 @@ namespace GreenshotPlugin.Core { /// public override void SetColorAt(int x, int y, Color color) { int offset = (x * 4) + (y * stride); - pointer[2 + offset] = color.R; - pointer[1 + offset] = color.G; - pointer[offset] = color.B; + pointer[RINDEX + offset] = color.R; + pointer[GINDEX + offset] = color.G; + pointer[BINDEX + offset] = color.B; + } + + /// + /// Get the color from the specified location into the specified array + /// + /// + /// + /// 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]; + } + + /// + /// Set the color at the specified location from the specified array + /// + /// + /// + /// byte[4] as reference (a,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]; } } @@ -434,7 +583,7 @@ namespace GreenshotPlugin.Core { /// Color public override Color GetColorAt(int x, int y) { int offset = (x * 4) + (y * stride); - return Color.FromArgb(pointer[3 + offset], pointer[2 + offset], pointer[1 + offset], pointer[offset]); + return Color.FromArgb(pointer[AINDEX + offset], pointer[RINDEX + offset], pointer[GINDEX + offset], pointer[BINDEX + offset]); } /// @@ -446,10 +595,38 @@ namespace GreenshotPlugin.Core { /// public override void SetColorAt(int x, int y, Color color) { int offset = (x * 4) + (y * stride); - pointer[3 + offset] = color.A; - pointer[2 + offset] = color.R; - pointer[1 + offset] = color.G; - pointer[offset] = color.B; + pointer[AINDEX + offset] = color.A; + pointer[RINDEX + offset] = color.R; + pointer[GINDEX + offset] = color.G; + pointer[BINDEX + offset] = color.B; + } + + /// + /// Get the color from the specified location into the specified array + /// + /// + /// + /// 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] = pointer[AINDEX + offset]; + color[1] = pointer[RINDEX + offset]; + color[2] = pointer[GINDEX + offset]; + color[3] = pointer[BINDEX + offset]; + } + + /// + /// Set the color at the specified location from the specified array + /// + /// + /// + /// byte[4] as reference (a,r,g,b) + 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]; } /// @@ -459,12 +636,12 @@ namespace GreenshotPlugin.Core { /// X coordinate /// Y Coordinate /// Color - public Color GetColorAtWithoutAlpha(int x, int y) { + public Color GetBlendedColorAt(int x, int y) { int offset = (x * 4) + (y * stride); - int a = pointer[3 + offset]; - int red = pointer[2 + offset]; - int green = pointer[1 + offset]; - int blue = pointer[offset]; + int a = pointer[AINDEX + offset]; + int red = pointer[RINDEX + offset]; + int green = pointer[GINDEX + offset]; + int blue = pointer[BINDEX + 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 12996f461..b45c35996 100644 --- a/GreenshotPlugin/Core/ImageHelper.cs +++ b/GreenshotPlugin/Core/ImageHelper.cs @@ -487,10 +487,12 @@ namespace GreenshotPlugin.Core { byte[] settingColor = new byte[4]; byte[] readingColor = new byte[4]; - using (BitmapBuffer bbbDest = new BitmapBuffer(sourceBitmap, applyRect, true)) { - bbbDest.Lock(); - using (BitmapBuffer bbbSrc = new BitmapBuffer(sourceBitmap, applyRect, false)) { - bbbSrc.Lock(); + using (BitmapBuffer dst = new BitmapBuffer(sourceBitmap, applyRect, true)) { + //using (IFastBitmap dst = FastBitmap.CreateEmpty(sourceBitmap.Size, sourceBitmap.PixelFormat, Color.Empty)) { + dst.Lock(); + using (BitmapBuffer src = new BitmapBuffer(sourceBitmap, applyRect, false)) { + //using (IFastBitmap src = FastBitmap.Create(sourceBitmap)) { + src.Lock(); Random rand = new Random(); unchecked { int r = blurRadius; @@ -519,12 +521,12 @@ namespace GreenshotPlugin.Core { gSums[wx] = 0; bSums[wx] = 0; - if (srcX >= 0 && srcX < bbbDest.Width) { + if (srcX >= 0 && srcX < src.Width) { for (int wy = 0; wy < wlen; ++wy) { int srcY = y + wy - r; - if (srcY >= 0 && srcY < bbbDest.Height) { - bbbSrc.GetColorIn(srcX, srcY, readingColor); + if (srcY >= 0 && srcY < src.Height) { + src.GetColorAt(srcX, srcY, readingColor); int wp = w[wy]; waSums[wx] += wp; @@ -553,13 +555,13 @@ namespace GreenshotPlugin.Core { if (parentBounds.Contains(applyRect.Left, applyRect.Top + y) ^ invert) { if (waSum == 0 || wcSum == 0) { - bbbDest.SetUncheckedColorArrayAt(0, y, nullColor); + dst.SetColorAt(0, y, nullColor); } else { settingColor[0] = (byte)(aSum / waSum); settingColor[1] = (byte)(rSum / wcSum); settingColor[2] = (byte)(gSum / wcSum); settingColor[3] = (byte)(bSum / wcSum); - bbbDest.SetUncheckedColorArrayAt(0, y, settingColor); + dst.SetColorAt(0, y, settingColor); } } @@ -609,7 +611,7 @@ namespace GreenshotPlugin.Core { if ((useExportQuality || rand.NextDouble() < previewQuality) && srcY >= 0 && srcY < applyRect.Height) { int wp = w[wy]; waSums[wx] += wp; - bbbSrc.GetColorIn(srcX, srcY, readingColor); + src.GetColorAt(srcX, srcY, readingColor); wp *= readingColor[0] + (readingColor[0] >> 7); wcSums[wx] += wp; wp >>= 8; @@ -633,21 +635,20 @@ namespace GreenshotPlugin.Core { wcSum >>= 8; if (parentBounds.Contains(applyRect.Left + x, applyRect.Top + y) ^ invert) { if (waSum == 0 || wcSum == 0) { - bbbDest.SetUncheckedColorArrayAt(x, y, nullColor); + dst.SetColorAt(x, y, nullColor); } else { settingColor[0] = (byte)(aSum / waSum); settingColor[1] = (byte)(rSum / wcSum); settingColor[2] = (byte)(gSum / wcSum); settingColor[3] = (byte)(bSum / wcSum); - bbbDest.SetUncheckedColorArrayAt(x, y, settingColor); + dst.SetColorAt(x, y, settingColor); } } } } } } - bbbDest.Unlock(); - return bbbDest.Bitmap; + return dst.UnlockAndReturnBitmap(); } } @@ -659,17 +660,15 @@ namespace GreenshotPlugin.Core { /// Bitmap public static Bitmap BoxBlur(Bitmap sourceBitmap, int range) { if ((range & 1) == 0) { - throw new InvalidOperationException("Range must be odd!"); + range++; + //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); - } + using (IFastBitmap bbbDest = FastBitmap.CreateCloneOf(sourceBitmap, PixelFormat.Format32bppArgb)) { + BoxBlurHorizontal(bbbDest, range); BoxBlurVertical(bbbDest, range); - bbbDest.Unlock(); - return bbbDest.Bitmap; + BoxBlurHorizontal(bbbDest, range + 1); + BoxBlurVertical(bbbDest, range + 1); + return bbbDest.UnlockAndReturnBitmap(); } } @@ -679,11 +678,11 @@ namespace GreenshotPlugin.Core { /// 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; + private static void BoxBlurHorizontal(IFastBitmap bbbDest, int range) { + int w = bbbDest.Width; + int h = bbbDest.Height; int halfRange = range / 2; - int[] newColors = new int[w]; + Color[] newColors = new Color[w]; byte[] tmpColor = new byte[4]; for (int y = 0; y < h; y++) { int hits = 0; @@ -694,7 +693,7 @@ namespace GreenshotPlugin.Core { for (int x = -halfRange; x < w; x++) { int oldPixel = x - halfRange - 1; if (oldPixel >= 0) { - bbbSrc.GetUncheckedColorIn(oldPixel, y, tmpColor); + bbbDest.GetColorAt(oldPixel, y, tmpColor); a -= tmpColor[0]; r -= tmpColor[1]; g -= tmpColor[2]; @@ -704,7 +703,7 @@ namespace GreenshotPlugin.Core { int newPixel = x + halfRange; if (newPixel < w) { - bbbSrc.GetUncheckedColorIn(newPixel, y, tmpColor); + bbbDest.GetColorAt(newPixel, y, tmpColor); a += tmpColor[0]; r += tmpColor[1]; g += tmpColor[2]; @@ -713,11 +712,11 @@ namespace GreenshotPlugin.Core { } if (x >= 0) { - newColors[x] = ((byte)(a / hits)) << 24 | ((byte)(r / hits) << 16) | ((byte)(g / hits) << 8 ) | ((byte)(b / hits)); + newColors[x] = Color.FromArgb((byte)(a / hits), (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); } } for (int x = 0; x < w; x++) { - bbbDest.SetARGB(x, y, newColors[x]); + bbbDest.SetColorAt(x, y, newColors[x]); } } } @@ -727,11 +726,11 @@ namespace GreenshotPlugin.Core { /// /// BitmapBuffer which previously was created with BoxBlurHorizontal /// Range must be odd! - private static void BoxBlurVertical(BitmapBuffer bbbDest, int range) { + private static void BoxBlurVertical(IFastBitmap bbbDest, int range) { int w = bbbDest.Width; int h = bbbDest.Height; int halfRange = range / 2; - int[] newColors = new int[h]; + Color[] newColors = new Color[h]; int oldPixelOffset = -(halfRange + 1) * w; int newPixelOffset = (halfRange) * w; byte[] tmpColor = new byte[4]; @@ -745,7 +744,7 @@ namespace GreenshotPlugin.Core { int oldPixel = y - halfRange - 1; if (oldPixel >= 0) { //int colorg = pixels[index + oldPixelOffset]; - bbbDest.GetUncheckedColorIn(x, oldPixel, tmpColor); + bbbDest.GetColorAt(x, oldPixel, tmpColor); a -= tmpColor[0]; r -= tmpColor[1]; g -= tmpColor[2]; @@ -756,7 +755,7 @@ namespace GreenshotPlugin.Core { int newPixel = y + halfRange; if (newPixel < h) { //int colorg = pixels[index + newPixelOffset]; - bbbDest.GetUncheckedColorIn(x, newPixel, tmpColor); + bbbDest.GetColorAt(x, newPixel, tmpColor); a += tmpColor[0]; r += tmpColor[1]; g += tmpColor[2]; @@ -765,121 +764,26 @@ namespace GreenshotPlugin.Core { } if (y >= 0) { - newColors[y] = ((byte)(a / hits)) << 24 | ((byte)(r / hits) << 16) | ((byte)(g / hits) << 8) | ((byte)(b / hits)); + newColors[y] = Color.FromArgb((byte)(a / hits), (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); } } for (int y = 0; y < h; y++) { - bbbDest.SetARGB(x, y, newColors[y]); + bbbDest.SetColorAt(x, y, newColors[y]); } } } - public static Bitmap FastBlur(Bitmap sourceBitmap, int radius) { - if (radius < 1) return null; - - var rct = new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height); - var dest = new int[rct.Width * rct.Height]; - var source = new int[rct.Width * rct.Height]; - var bits = sourceBitmap.LockBits(rct, ImageLockMode.ReadWrite, sourceBitmap.PixelFormat); - Marshal.Copy(bits.Scan0, source, 0, source.Length); - sourceBitmap.UnlockBits(bits); - - int w = rct.Width; - int h = rct.Height; - int wm = w - 1; - int hm = h - 1; - int wh = w * h; - int div = radius + radius + 1; - var r = new int[wh]; - var g = new int[wh]; - var b = new int[wh]; - int rsum, gsum, bsum, x, y, i, p1, p2, yi; - var vmin = new int[max(w, h)]; - var vmax = new int[max(w, h)]; - - var dv = new int[256 * div]; - for (i = 0; i < 256 * div; i++) { - dv[i] = (i / div); - } - - int yw = yi = 0; - - for (y = 0; y < h; y++) { // blur horizontal - rsum = gsum = bsum = 0; - for (i = -radius; i <= radius; i++) { - int p = source[yi + min(wm, max(i, 0))]; - rsum += (p & 0xff0000) >> 16; - gsum += (p & 0x00ff00) >> 8; - bsum += p & 0x0000ff; - } - for (x = 0; x < w; x++) { - - r[yi] = dv[rsum]; - g[yi] = dv[gsum]; - b[yi] = dv[bsum]; - - if (y == 0) { - vmin[x] = min(x + radius + 1, wm); - vmax[x] = max(x - radius, 0); - } - p1 = source[yw + vmin[x]]; - p2 = source[yw + vmax[x]]; - - rsum += ((p1 & 0xff0000) - (p2 & 0xff0000)) >> 16; - gsum += ((p1 & 0x00ff00) - (p2 & 0x00ff00)) >> 8; - bsum += (p1 & 0x0000ff) - (p2 & 0x0000ff); - yi++; - } - yw += w; - } - - for (x = 0; x < w; x++) { // blur vertical - rsum = gsum = bsum = 0; - int yp = -radius * w; - for (i = -radius; i <= radius; i++) { - yi = max(0, yp) + x; - rsum += r[yi]; - gsum += g[yi]; - bsum += b[yi]; - yp += w; - } - yi = x; - for (y = 0; y < h; y++) { - dest[yi] = unchecked((int)(0xff000000u | (uint)(dv[rsum] << 16) | (uint)(dv[gsum] << 8) | (uint)dv[bsum])); - if (x == 0) { - vmin[y] = min(y + radius + 1, hm) * w; - vmax[y] = max(y - radius, 0) * w; - } - p1 = x + vmin[y]; - p2 = x + vmax[y]; - - rsum += r[p1] - r[p2]; - gsum += g[p1] - g[p2]; - bsum += b[p1] - b[p2]; - - yi += w; - } - } - - // copy back to image - Bitmap newImage = CreateEmptyLike(sourceBitmap, Color.Empty); - var bits2 = newImage.LockBits(rct, ImageLockMode.ReadWrite, newImage.PixelFormat); - Marshal.Copy(dest, 0, bits2.Scan0, dest.Length); - newImage.UnlockBits(bits); - return newImage; - - } - - private static int min(int a, int b) { return Math.Min(a, b); } - private static int max(int a, int b) { return Math.Max(a, b); } - - /** - * 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. - * It will also account for the Invert flag. - */ + /// + /// 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. + /// It will also account for the Invert flag. + /// + /// + /// + /// + /// public static Rectangle CreateIntersectRectangle(Size applySize, Rectangle rect, bool invert) { Rectangle myRect; if (invert) { @@ -927,10 +831,16 @@ namespace GreenshotPlugin.Core { graphics.DrawImage(sourceBitmap, shadowRectangle, 0, 0, sourceBitmap.Width, sourceBitmap.Height, GraphicsUnit.Pixel, ia); } // blur "shadow", apply to whole new image - Rectangle newImageRectangle = new Rectangle(0, 0, tmpImage.Width, tmpImage.Height); //using (Bitmap blurImage = FastBlur(newImage, shadowSize-1)) { + + // Gaussian + Rectangle newImageRectangle = new Rectangle(0, 0, tmpImage.Width, tmpImage.Height); returnImage = CreateBlur(tmpImage, newImageRectangle, true, shadowSize, 1d, false, newImageRectangle); + + // Box //returnImage = BoxBlur(tmpImage, shadowSize); + + //returnImage = FastBlur(tmpImage, shadowSize - 1); } if (returnImage != null) { using (Graphics graphics = Graphics.FromImage(returnImage)) { @@ -976,18 +886,17 @@ namespace GreenshotPlugin.Core { /// Bitmap to create a b/w off /// b/w bitmap public static Bitmap CreateMonochrome(Image sourceImage) { - using (BitmapBuffer bb = new BitmapBuffer(sourceImage, true)) { - bb.Lock(); - for (int y = 0; y < bb.Height; y++) { - for (int x = 0; x < bb.Width; x++) { - Color color = bb.GetColorAt(x, y); - int colorBrightness = (color.R+color.G+color.B > 382) ? 255 : 0; + using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(sourceImage, sourceImage.PixelFormat)) { + fastBitmap.Lock(); + for (int y = 0; y < fastBitmap.Height; y++) { + for (int x = 0; x < fastBitmap.Width; x++) { + Color color = fastBitmap.GetColorAt(x, y); + int colorBrightness = (color.R + color.G + color.B > 382) ? 255 : 0; Color monoColor = Color.FromArgb(color.A, colorBrightness, colorBrightness, colorBrightness); - bb.SetColorAt(x, y, monoColor); + fastBitmap.SetColorAt(x, y, monoColor); } } - bb.Unlock(); - return bb.Bitmap; + return fastBitmap.UnlockAndReturnBitmap(); } }