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(); } }