diff --git a/Greenshot/Drawing/Filters/AbstractFilter.cs b/Greenshot/Drawing/Filters/AbstractFilter.cs index 37715a09e..148ab8ed4 100644 --- a/Greenshot/Drawing/Filters/AbstractFilter.cs +++ b/Greenshot/Drawing/Filters/AbstractFilter.cs @@ -63,25 +63,8 @@ namespace Greenshot.Drawing.Filters { return parent; } - /** - * 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. - */ - protected Rectangle IntersectRectangle(Size applySize, Rectangle rect) { - Rectangle myRect; - if (Invert) { - myRect = new Rectangle(0, 0, applySize.Width, applySize.Height); - } else { - Rectangle applyRect = new Rectangle(0,0, applySize.Width, applySize.Height); - myRect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); - myRect.Intersect(applyRect); - } - return myRect; - } - public virtual void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { - applyRect = IntersectRectangle(applyBitmap.Size, rect); + applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); if (applyRect.Width == 0 || applyRect.Height == 0) { // nothing to do diff --git a/Greenshot/Drawing/Filters/BlurFilter.cs b/Greenshot/Drawing/Filters/BlurFilter.cs index 46174f571..3ad741eb3 100644 --- a/Greenshot/Drawing/Filters/BlurFilter.cs +++ b/Greenshot/Drawing/Filters/BlurFilter.cs @@ -20,9 +20,10 @@ using System.Drawing; using Greenshot.Drawing.Fields; using Greenshot.Plugin.Drawing; using GreenshotPlugin.Core; +using System.Drawing.Imaging; namespace Greenshot.Drawing.Filters { - [Serializable()] + [Serializable()] public class BlurFilter : AbstractFilter { public double previewQuality; public double PreviewQuality { @@ -35,201 +36,12 @@ namespace Greenshot.Drawing.Filters { AddField(GetType(), FieldType.PREVIEW_QUALITY, 1.0d); } - public static int[] CreateGaussianBlurRow(int amount) { - int size = 1 + (amount * 2); - int[] weights = new int[size]; + public unsafe override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { + int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS); + double previewQuality = GetFieldValueAsDouble(FieldType.PREVIEW_QUALITY); - for (int i = 0; i <= amount; ++i) - { - // 1 + aa - aa + 2ai - ii - weights[i] = 16 * (i + 1); - weights[weights.Length - i - 1] = weights[i]; - } - - return weights; - } - - public unsafe override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { - applyRect = IntersectRectangle(applyBitmap.Size, rect); - - if (applyRect.Height <= 0 || applyRect.Width <= 0) { - return; - } - - int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS); - double previewQuality = GetFieldValueAsDouble(FieldType.PREVIEW_QUALITY); - - // do nothing when nothing can be done! - if (blurRadius < 1) { - return; - } - - using (BitmapBuffer bbbDest = new BitmapBuffer(applyBitmap, applyRect)) { - bbbDest.Lock(); - using (BitmapBuffer bbbSrc = new BitmapBuffer(applyBitmap, applyRect)) { - bbbSrc.Lock(); - Random rand = new Random(); - - int r = blurRadius; - int[] w = CreateGaussianBlurRow(r); - int wlen = w.Length; - long[] waSums = new long[wlen]; - long[] wcSums = new long[wlen]; - long[] aSums = new long[wlen]; - long[] bSums = new long[wlen]; - long[] gSums = new long[wlen]; - long[] rSums = new long[wlen]; - for (int y = 0; y < applyRect.Height; ++y) { - long waSum = 0; - long wcSum = 0; - long aSum = 0; - long bSum = 0; - long gSum = 0; - long rSum = 0; - - for (int wx = 0; wx < wlen; ++wx) { - int srcX = wx - r; - waSums[wx] = 0; - wcSums[wx] = 0; - aSums[wx] = 0; - bSums[wx] = 0; - gSums[wx] = 0; - rSums[wx] = 0; - - if (srcX >= 0 && srcX < bbbDest.Width) { - for (int wy = 0; wy < wlen; ++wy) { - int srcY = y + wy - r; - - if (srcY >= 0 && srcY < bbbDest.Height) { - int[] colors = bbbSrc.GetColorArrayAt(srcX, srcY); - int wp = w[wy]; - - waSums[wx] += wp; - wp *= colors[0] + (colors[0] >> 7); - wcSums[wx] += wp; - wp >>= 8; - - aSums[wx] += wp * colors[0]; - bSums[wx] += wp * colors[3]; - gSums[wx] += wp * colors[2]; - rSums[wx] += wp * colors[1]; - } - } - - int wwx = w[wx]; - waSum += wwx * waSums[wx]; - wcSum += wwx * wcSums[wx]; - aSum += wwx * aSums[wx]; - bSum += wwx * bSums[wx]; - gSum += wwx * gSums[wx]; - rSum += wwx * rSums[wx]; - } - } - - wcSum >>= 8; - - if (waSum == 0 || wcSum == 0) { - SetColorAt(bbbDest, 0, y, new int[]{0,0,0,0}); - } else { - int alpha = (int)(aSum / waSum); - int blue = (int)(bSum / wcSum); - int green = (int)(gSum / wcSum); - int red = (int)(rSum / wcSum); - - SetColorAt(bbbDest, 0, y, new int[]{alpha, red, green, blue}); - } - - for (int x = 1; x < applyRect.Width; ++x) { - for (int i = 0; i < wlen - 1; ++i) { - waSums[i] = waSums[i + 1]; - wcSums[i] = wcSums[i + 1]; - aSums[i] = aSums[i + 1]; - bSums[i] = bSums[i + 1]; - gSums[i] = gSums[i + 1]; - rSums[i] = rSums[i + 1]; - } - - waSum = 0; - wcSum = 0; - aSum = 0; - bSum = 0; - gSum = 0; - rSum = 0; - - int wx; - for (wx = 0; wx < wlen - 1; ++wx) { - long wwx = (long)w[wx]; - waSum += wwx * waSums[wx]; - wcSum += wwx * wcSums[wx]; - aSum += wwx * aSums[wx]; - bSum += wwx * bSums[wx]; - gSum += wwx * gSums[wx]; - rSum += wwx * rSums[wx]; - } - - wx = wlen - 1; - - waSums[wx] = 0; - wcSums[wx] = 0; - aSums[wx] = 0; - bSums[wx] = 0; - gSums[wx] = 0; - rSums[wx] = 0; - - int srcX = x + wx - r; - - if (srcX >= 0 && srcX < applyRect.Width) { - for (int wy = 0; wy < wlen; ++wy) { - int srcY = y + wy - r; - // only when in EDIT mode, ignore some pixels depending on preview quality - if ((renderMode==RenderMode.EXPORT || rand.NextDouble()= 0 && srcY < applyRect.Height) { - int[] colors = bbbSrc.GetColorArrayAt(srcX, srcY); - int wp = w[wy]; - - waSums[wx] += wp; - wp *= colors[0] + (colors[0] >> 7); - wcSums[wx] += wp; - wp >>= 8; - - aSums[wx] += wp * (long)colors[0]; - bSums[wx] += wp * (long)colors[3]; - gSums[wx] += wp * (long)colors[2]; - rSums[wx] += wp * (long)colors[1]; - } - } - - int wr = w[wx]; - waSum += (long)wr * waSums[wx]; - wcSum += (long)wr * wcSums[wx]; - aSum += (long)wr * aSums[wx]; - bSum += (long)wr * bSums[wx]; - gSum += (long)wr * gSums[wx]; - rSum += (long)wr * rSums[wx]; - } - - wcSum >>= 8; - - if (waSum == 0 || wcSum == 0) { - SetColorAt(bbbDest, x, y, new int[]{0,0,0,0}); - } else { - int alpha = (int)(aSum / waSum); - int blue = (int)(bSum / wcSum); - int green = (int)(gSum / wcSum); - int red = (int)(rSum / wcSum); - - SetColorAt(bbbDest, x, y, new int[]{alpha, red, green, blue}); - } - } - } - } - bbbDest.DrawTo(graphics, applyRect.Location); - } + ImageHelper.ApplyBlur(graphics, applyBitmap, rect, renderMode == RenderMode.EXPORT, blurRadius, previewQuality, Invert, parent.Bounds); + return; } - - private void SetColorAt(BitmapBuffer bbb, int x, int y, int[] colors) { - if(parent.Contains(applyRect.Left+x, applyRect.Top+y) ^ Invert) { - bbb.SetColorArrayAt(x, y, colors); - } - } - } + } } diff --git a/Greenshot/Drawing/Filters/MagnifierFilter.cs b/Greenshot/Drawing/Filters/MagnifierFilter.cs index 43107c7b2..ece9cc484 100644 --- a/Greenshot/Drawing/Filters/MagnifierFilter.cs +++ b/Greenshot/Drawing/Filters/MagnifierFilter.cs @@ -37,7 +37,7 @@ namespace Greenshot.Drawing.Filters { public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { magnificationFactor = GetFieldValueAsInt(FieldType.MAGNIFICATION_FACTOR); - applyRect = IntersectRectangle(applyBitmap.Size, rect); + applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); bbbSrc = new BitmapBuffer(applyBitmap, applyRect); try { diff --git a/Greenshot/Drawing/Filters/PixelizationFilter.cs b/Greenshot/Drawing/Filters/PixelizationFilter.cs index 8006a34c9..47c396bba 100644 --- a/Greenshot/Drawing/Filters/PixelizationFilter.cs +++ b/Greenshot/Drawing/Filters/PixelizationFilter.cs @@ -77,7 +77,7 @@ namespace Greenshot.Drawing.Filters { public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { int pixelSize = GetFieldValueAsInt(FieldType.PIXEL_SIZE); - applyRect = IntersectRectangle(applyBitmap.Size, rect); + applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); Apply(graphics, applyBitmap, applyRect, pixelSize); } diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index 1c3787051..682503f05 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -34,12 +34,16 @@ using Greenshot.Plugin.Drawing; using GreenshotPlugin.Core; using Greenshot.Memento; using IniFile; +using Greenshot.Drawing.Filters; +using System.Drawing.Drawing2D; namespace Greenshot.Drawing { public delegate void SurfaceElementEventHandler(object source, DrawableContainerList element); public delegate void SurfaceDrawingModeEventHandler(object source, DrawingModes drawingMode); public enum DrawingModes { None, Rect, Ellipse, Text, Line, Arrow, Crop, Highlight, Obfuscate, Bitmap, Path } + public enum Effects { Shadow, TornEdge } + /// /// Description of Surface. /// @@ -522,17 +526,29 @@ namespace Greenshot.Drawing { return false; } - public void ApplyBitmapEffect() { - Rectangle cropRectangle = new Rectangle(Point.Empty, Image.Size); - Bitmap tmpImage = ((Bitmap)Image).Clone(cropRectangle, Image.PixelFormat); - tmpImage.SetResolution(Image.HorizontalResolution, Image.VerticalResolution); + public void ApplyBitmapEffect(Effects effect) { + Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); + Bitmap newImage = null; - // Currently only one effect exists, others could follow - ImageHelper.ApplyTornEdge(tmpImage); + Point offset = Point.Empty; + switch (effect) { + case Effects.Shadow: + newImage = ImageHelper.CreateShadow((Bitmap)Image, 0.8f, 8, Image.PixelFormat, out offset); + break; + case Effects.TornEdge: + using (Bitmap tmpImage = ImageHelper.CreateTornEdge((Bitmap)Image)) { + newImage = ImageHelper.CreateShadow(tmpImage, 0.8f, 8, Image.PixelFormat, out offset); + } + break; + } - // Make undoable - MakeUndoable(new SurfaceCropMemento(this, cropRectangle), false); - SetImage(tmpImage, false); + if (newImage != null) { + // Make sure the elements move according to the offset the effect made the bitmap move + elements.MoveBy(offset.X, offset.Y); + // Make undoable + MakeUndoable(new SurfaceCropMemento(this, imageRectangle), false); + SetImage(newImage, false); + } } public bool isCropPossible(ref Rectangle cropRectangle) { @@ -757,6 +773,10 @@ namespace Greenshot.Drawing { Bitmap clone = ImageHelper.CloneImageToBitmap(Image); // otherwise we would have a problem drawing the image to the surface... :( using (Graphics graphics = Graphics.FromImage(clone)) { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; elements.Draw(graphics, (Bitmap)clone, renderMode, new Rectangle(Point.Empty, clone.Size)); } return clone; @@ -792,6 +812,10 @@ namespace Greenshot.Drawing { } // Elements might need the bitmap, so we copy the part we need using (Graphics graphics = Graphics.FromImage(buffer)) { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; graphics.DrawImage(Image, clipRectangle, clipRectangle, GraphicsUnit.Pixel); graphics.SetClip(targetGraphics); elements.Draw(graphics, buffer, RenderMode.EDIT, clipRectangle); diff --git a/GreenshotNetworkImportPlugin/HTTPReceiver.cs b/GreenshotNetworkImportPlugin/HTTPReceiver.cs index 514fe0b6b..0120fb157 100644 --- a/GreenshotNetworkImportPlugin/HTTPReceiver.cs +++ b/GreenshotNetworkImportPlugin/HTTPReceiver.cs @@ -26,6 +26,7 @@ using System.Net; using System.Text; using Greenshot.Plugin; +using GreenshotPlugin.Core; namespace GreenshotNetworkImportPlugin { public class HTTPReceiver { @@ -127,10 +128,11 @@ namespace GreenshotNetworkImportPlugin { using (MemoryStream memoryStream = new MemoryStream(imageBytes, 0, imageBytes.Length)) { // Convert byte[] to Image memoryStream.Write(imageBytes, 0, imageBytes.Length); - Image image = Image.FromStream(memoryStream, true); - ICapture capture = host.GetCapture(image); - capture.CaptureDetails.Title = title; - host.ImportCapture(capture); + using (Image image = Bitmap.FromStream(memoryStream, true)) { + ICapture capture = host.GetCapture(ImageHelper.CloneImageToBitmap(image)); + capture.CaptureDetails.Title = title; + host.ImportCapture(capture); + } response.StatusCode = (int)HttpStatusCode.OK; byte[] content = Encoding.UTF8.GetBytes("Greenshot-OK"); response.ContentType = "text"; diff --git a/GreenshotPlugin/Core/ImageHelper.cs b/GreenshotPlugin/Core/ImageHelper.cs index c8234ed01..fce665abe 100644 --- a/GreenshotPlugin/Core/ImageHelper.cs +++ b/GreenshotPlugin/Core/ImageHelper.cs @@ -59,12 +59,13 @@ namespace GreenshotPlugin.Core { } Bitmap bmp = new Bitmap(thumbWidth, thumbHeight); - using (Graphics gr = System.Drawing.Graphics.FromImage(bmp)) { - gr.SmoothingMode = SmoothingMode.HighQuality ; - gr.CompositingQuality = CompositingQuality.HighQuality; - gr.InterpolationMode = InterpolationMode.High; - System.Drawing.Rectangle rectDestination = new System.Drawing.Rectangle(0, 0, thumbWidth, thumbHeight); - gr.DrawImage(image, rectDestination, 0, 0, srcWidth, srcHeight, GraphicsUnit.Pixel); + using (Graphics graphics = System.Drawing.Graphics.FromImage(bmp)) { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + Rectangle rectDestination = new Rectangle(0, 0, thumbWidth, thumbHeight); + graphics.DrawImage(image, rectDestination, 0, 0, srcWidth, srcHeight, GraphicsUnit.Pixel); } return bmp; } @@ -301,44 +302,52 @@ namespace GreenshotPlugin.Core { /// /// Make the picture look like it's torn /// - /// Bitmap to modify - public static void ApplyTornEdge(Bitmap bitmap) { + /// Bitmap to make torn edge off + /// Changed bitmap + public static Bitmap CreateTornEdge(Bitmap sourceBitmap) { + Rectangle cropRectangle = new Rectangle(Point.Empty, sourceBitmap.Size); + Bitmap returnImage = sourceBitmap.Clone(cropRectangle, PixelFormat.Format32bppArgb); + try { + returnImage.SetResolution(sourceBitmap.HorizontalResolution, sourceBitmap.VerticalResolution); + } catch (Exception ex) { + LOG.Warn("An exception occured while setting the resolution.", ex); + } GraphicsPath path = new GraphicsPath(); Random random = new Random(); - int regionWidth = 14; - int regionHeight = 14; - int HorizontalRegions = (int)(bitmap.Width / regionWidth); - int VerticalRegions = (int)(bitmap.Height / regionHeight); + int regionWidth = 20; + int regionHeight = 20; + int HorizontalRegions = (int)(sourceBitmap.Width / regionWidth); + int VerticalRegions = (int)(sourceBitmap.Height / regionHeight); int distance = 12; // Start Point previousEndingPoint = Point.Empty; Point newEndingPoint = Point.Empty; - + path.AddLine(new Point(sourceBitmap.Width, 0), Point.Empty); // Top for (int i = 0; i < HorizontalRegions; i++) { int x = (int)previousEndingPoint.X + regionWidth; - int y = random.Next(0, distance); + int y = random.Next(1, distance); newEndingPoint = new Point(x, y); path.AddLine(previousEndingPoint, newEndingPoint); previousEndingPoint = newEndingPoint; } // end top - newEndingPoint = new Point(bitmap.Width, 0); + newEndingPoint = new Point(sourceBitmap.Width, 0); path.AddLine(previousEndingPoint, newEndingPoint); previousEndingPoint = newEndingPoint; path.CloseFigure(); // Right for (int i = 0; i < VerticalRegions; i++) { - int x = bitmap.Width - random.Next(0, distance); + int x = sourceBitmap.Width - random.Next(1, distance); int y = (int)previousEndingPoint.Y + regionHeight; newEndingPoint = new Point(x, y); path.AddLine(previousEndingPoint, newEndingPoint); previousEndingPoint = newEndingPoint; } // end right - newEndingPoint = new Point(bitmap.Width, bitmap.Height); + newEndingPoint = new Point(sourceBitmap.Width, sourceBitmap.Height); path.AddLine(previousEndingPoint, newEndingPoint); previousEndingPoint = newEndingPoint; path.CloseFigure(); @@ -346,20 +355,20 @@ namespace GreenshotPlugin.Core { // Bottom for (int i = 0; i < HorizontalRegions; i++) { int x = (int)previousEndingPoint.X - regionWidth; - int y = bitmap.Height - random.Next(0, distance); + int y = sourceBitmap.Height - random.Next(1, distance); newEndingPoint = new Point(x, y); path.AddLine(previousEndingPoint, newEndingPoint); previousEndingPoint = newEndingPoint; } // end Bottom - newEndingPoint = new Point(0, bitmap.Height); + newEndingPoint = new Point(0, sourceBitmap.Height); path.AddLine(previousEndingPoint, newEndingPoint); previousEndingPoint = newEndingPoint; path.CloseFigure(); // Left for (int i = 0; i < VerticalRegions; i++) { - int x = random.Next(0, distance); + int x = random.Next(1, distance); int y = (int)previousEndingPoint.Y - regionHeight; newEndingPoint = new Point(x, y); path.AddLine(previousEndingPoint, newEndingPoint); @@ -372,17 +381,294 @@ namespace GreenshotPlugin.Core { path.CloseFigure(); // Draw - using (Graphics graphics = Graphics.FromImage(bitmap)) { - Color fillColor = Color.White; - if (bitmap.PixelFormat == PixelFormat.Format32bppArgb) { + using (Graphics graphics = Graphics.FromImage(returnImage)) { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + + if (Image.IsAlphaPixelFormat(returnImage.PixelFormat)) { + // When using transparency we can't draw with Color.Transparency so we clear graphics.SetClip(path); graphics.Clear(Color.Transparent); } else { - using (Brush brush = new SolidBrush( Color.White)) { + using (Brush brush = new SolidBrush(Color.White)) { graphics.FillPath(brush, path); } } } + return returnImage; + } + + /// + /// Helper Method for the ApplyBlur + /// + /// + /// + private static int[] CreateGaussianBlurRow(int amount) { + int size = 1 + (amount * 2); + int[] weights = new int[size]; + + for (int i = 0; i <= amount; ++i) { + // 1 + aa - aa + 2ai - ii + weights[i] = 16 * (i + 1); + weights[weights.Length - i - 1] = weights[i]; + } + + return weights; + } + + /// + /// Apply sourceBitmap with a blur to the targetGraphics + /// + /// Target to draw to + /// Source to blur + /// Area to blur + /// Use full quality + /// Radius of the blur + /// Quality, use 1d for normal anything less skipps calculations + /// true if the blur needs to occur outside of the area + /// Rectangle limiting the area when using invert + public static void ApplyBlur(Graphics targetGraphics, Bitmap sourceBitmap, Rectangle rect, bool export, int blurRadius, double previewQuality, bool invert, Rectangle parentBounds) { + Rectangle applyRect = CreateIntersectRectangle(sourceBitmap.Size, rect, invert); + + if (applyRect.Height <= 0 || applyRect.Width <= 0) { + return; + } + // do nothing when nothing can be done! + if (blurRadius < 1) { + return; + } + Color nullColor = Color.White; + if (sourceBitmap.PixelFormat == PixelFormat.Format32bppArgb) { + nullColor = Color.Transparent; + } + + using (BitmapBuffer bbbDest = new BitmapBuffer(sourceBitmap, applyRect)) { + bbbDest.Lock(); + using (BitmapBuffer bbbSrc = new BitmapBuffer(sourceBitmap, applyRect)) { + bbbSrc.Lock(); + Random rand = new Random(); + + int r = blurRadius; + int[] w = CreateGaussianBlurRow(r); + int wlen = w.Length; + long[] waSums = new long[wlen]; + long[] wcSums = new long[wlen]; + long[] aSums = new long[wlen]; + long[] bSums = new long[wlen]; + long[] gSums = new long[wlen]; + long[] rSums = new long[wlen]; + for (int y = 0; y < applyRect.Height; ++y) { + long waSum = 0; + long wcSum = 0; + long aSum = 0; + long bSum = 0; + long gSum = 0; + long rSum = 0; + + for (int wx = 0; wx < wlen; ++wx) { + int srcX = wx - r; + waSums[wx] = 0; + wcSums[wx] = 0; + aSums[wx] = 0; + bSums[wx] = 0; + gSums[wx] = 0; + rSums[wx] = 0; + + if (srcX >= 0 && srcX < bbbDest.Width) { + for (int wy = 0; wy < wlen; ++wy) { + int srcY = y + wy - r; + + if (srcY >= 0 && srcY < bbbDest.Height) { + int[] colors = bbbSrc.GetColorArrayAt(srcX, srcY); + int wp = w[wy]; + + waSums[wx] += wp; + wp *= colors[0] + (colors[0] >> 7); + wcSums[wx] += wp; + wp >>= 8; + + aSums[wx] += wp * colors[0]; + bSums[wx] += wp * colors[3]; + gSums[wx] += wp * colors[2]; + rSums[wx] += wp * colors[1]; + } + } + + int wwx = w[wx]; + waSum += wwx * waSums[wx]; + wcSum += wwx * wcSums[wx]; + aSum += wwx * aSums[wx]; + bSum += wwx * bSums[wx]; + gSum += wwx * gSums[wx]; + rSum += wwx * rSums[wx]; + } + } + + wcSum >>= 8; + + if (waSum == 0 || wcSum == 0) { + if (parentBounds.Contains(applyRect.Left, applyRect.Top + y) ^ invert) { + bbbDest.SetColorAt(0, y, nullColor); + } + } else { + int alpha = (int)(aSum / waSum); + int blue = (int)(bSum / wcSum); + int green = (int)(gSum / wcSum); + int red = (int)(rSum / wcSum); + if (parentBounds.Contains(applyRect.Left, applyRect.Top + y) ^ invert) { + bbbDest.SetColorAt(0, y, Color.FromArgb(alpha, red, green, blue)); + } + } + + for (int x = 1; x < applyRect.Width; ++x) { + for (int i = 0; i < wlen - 1; ++i) { + waSums[i] = waSums[i + 1]; + wcSums[i] = wcSums[i + 1]; + aSums[i] = aSums[i + 1]; + bSums[i] = bSums[i + 1]; + gSums[i] = gSums[i + 1]; + rSums[i] = rSums[i + 1]; + } + + waSum = 0; + wcSum = 0; + aSum = 0; + bSum = 0; + gSum = 0; + rSum = 0; + + int wx; + for (wx = 0; wx < wlen - 1; ++wx) { + long wwx = (long)w[wx]; + waSum += wwx * waSums[wx]; + wcSum += wwx * wcSums[wx]; + aSum += wwx * aSums[wx]; + bSum += wwx * bSums[wx]; + gSum += wwx * gSums[wx]; + rSum += wwx * rSums[wx]; + } + + wx = wlen - 1; + + waSums[wx] = 0; + wcSums[wx] = 0; + aSums[wx] = 0; + bSums[wx] = 0; + gSums[wx] = 0; + rSums[wx] = 0; + + int srcX = x + wx - r; + + if (srcX >= 0 && srcX < applyRect.Width) { + for (int wy = 0; wy < wlen; ++wy) { + int srcY = y + wy - r; + // only when in EDIT mode, ignore some pixels depending on preview quality + if ((export || rand.NextDouble() < previewQuality) && srcY >= 0 && srcY < applyRect.Height) { + int[] colors = bbbSrc.GetColorArrayAt(srcX, srcY); + int wp = w[wy]; + + waSums[wx] += wp; + wp *= colors[0] + (colors[0] >> 7); + wcSums[wx] += wp; + wp >>= 8; + + aSums[wx] += wp * (long)colors[0]; + bSums[wx] += wp * (long)colors[3]; + gSums[wx] += wp * (long)colors[2]; + rSums[wx] += wp * (long)colors[1]; + } + } + + int wr = w[wx]; + waSum += (long)wr * waSums[wx]; + wcSum += (long)wr * wcSums[wx]; + aSum += (long)wr * aSums[wx]; + bSum += (long)wr * bSums[wx]; + gSum += (long)wr * gSums[wx]; + rSum += (long)wr * rSums[wx]; + } + + wcSum >>= 8; + + if (waSum == 0 || wcSum == 0) { + if (parentBounds.Contains(applyRect.Left + x, applyRect.Top + y) ^ invert) { + bbbDest.SetColorAt(x, y, nullColor); + } + } else { + int alpha = (int)(aSum / waSum); + int blue = (int)(bSum / wcSum); + int green = (int)(gSum / wcSum); + int red = (int)(rSum / wcSum); + if (parentBounds.Contains(applyRect.Left + x, applyRect.Top + y) ^ invert) { + bbbDest.SetColorAt(x, y, Color.FromArgb(alpha, red, green, blue)); + } + } + } + } + } + bbbDest.DrawTo(targetGraphics, applyRect.Location); + } + } + + /** + * 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) { + myRect = new Rectangle(0, 0, applySize.Width, applySize.Height); + } else { + Rectangle applyRect = new Rectangle(0, 0, applySize.Width, applySize.Height); + myRect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); + myRect.Intersect(applyRect); + } + return myRect; + } + + /// + /// Create a new bitmap where the sourceBitmap has a shadow + /// + /// Bitmap to make a shadow on + /// How dark is the shadow + /// Size of the shadow + /// What pixel format must the returning bitmap have + /// How many pixels is the original image moved? + /// Bitmap with the shadow, is bigger than the sourceBitmap!! + public static Bitmap CreateShadow(Bitmap sourceBitmap, float darkness, int shadowSize, PixelFormat targetPixelformat, out Point offset) { + Bitmap newImage = new Bitmap(sourceBitmap.Width + (shadowSize * 2), sourceBitmap.Height + (shadowSize * 2), targetPixelformat); + + using (Graphics graphics = Graphics.FromImage(newImage)) { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + + if (Image.IsAlphaPixelFormat(targetPixelformat)) { + graphics.Clear(Color.Transparent); + } else { + graphics.Clear(Color.White); + } + ImageAttributes ia = new ImageAttributes(); + ColorMatrix cm = new ColorMatrix(); + cm.Matrix00 = 0; + cm.Matrix11 = 0; + cm.Matrix22 = 0; + cm.Matrix33 = darkness; + ia.SetColorMatrix(cm); + // Draw "shadow" offsetted + graphics.DrawImage(sourceBitmap, new Rectangle(new Point(shadowSize, shadowSize), sourceBitmap.Size), 0, 0, sourceBitmap.Width, sourceBitmap.Height, GraphicsUnit.Pixel, ia); + // blur "shadow", apply to whole new image + Rectangle applyRectangle = new Rectangle(Point.Empty, newImage.Size); + ApplyBlur(graphics, newImage, applyRectangle, true, shadowSize, 1d, false, applyRectangle); + // draw original + offset = new Point(shadowSize - 2, shadowSize - 2); + graphics.DrawImage(sourceBitmap, offset); + } + return newImage; } } }