diff --git a/src/Greenshot.Editor/Drawing/DrawableContainer.cs b/src/Greenshot.Editor/Drawing/DrawableContainer.cs index cac23dc3a..bed1d7618 100644 --- a/src/Greenshot.Editor/Drawing/DrawableContainer.cs +++ b/src/Greenshot.Editor/Drawing/DrawableContainer.cs @@ -410,7 +410,9 @@ namespace Greenshot.Editor.Drawing { if (clipRectangle.Width != 0 && clipRectangle.Height != 0) { - foreach (IFilter filter in Filters) + // GrayscaleFilter is an inverted filter. Combining two makes the entire image greyscale. + // Skip any GrayscaleFilter here so outer drawing logic can handle them to combine multiple + foreach (IFilter filter in Filters.Where(x => x is not GrayscaleFilter)) { if (filter.Invert) { diff --git a/src/Greenshot.Editor/Drawing/DrawableContainerList.cs b/src/Greenshot.Editor/Drawing/DrawableContainerList.cs index ef30c037f..a3027808e 100644 --- a/src/Greenshot.Editor/Drawing/DrawableContainerList.cs +++ b/src/Greenshot.Editor/Drawing/DrawableContainerList.cs @@ -34,6 +34,7 @@ using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Configuration; using Greenshot.Editor.Drawing.Fields; +using Greenshot.Editor.Drawing.Filters; using Greenshot.Editor.Forms; using Greenshot.Editor.Memento; @@ -328,9 +329,12 @@ namespace Greenshot.Editor.Drawing return; } - foreach (var drawableContainer in this) + var drawableContainers = this.Cast(); + + ApplyGrayscaleFilters(g, drawableContainers, bitmap); + + foreach (var dc in drawableContainers) { - var dc = (DrawableContainer) drawableContainer; if (dc.Parent == null) { continue; @@ -341,6 +345,30 @@ namespace Greenshot.Editor.Drawing dc.DrawContent(g, bitmap, renderMode, clipRectangle); } } + + // To support multiple grayscale filters we merge them before applying them + static void ApplyGrayscaleFilters(Graphics g, IEnumerable drawableContainers, Bitmap bitmap) + { + if (bitmap is null) return; + + var grayFilters = drawableContainers.SelectMany(x => x.Filters.Where(filter => filter is GrayscaleFilter).Cast()); + // These rects shall not be grayed out + var rects = grayFilters.Select(x => x.Parent.Bounds); + + // full bitmap size because the GrayscaleFilter is an inverted filter covering the full bitmap + var applyRect = new NativeRect(0, 0, bitmap.Width, bitmap.Height); + + GraphicsState state = g.Save(); + // Set a clipping region and then exclude the highlight areas so only "everything else" gets greyed out + g.SetClip(applyRect); + foreach (var rect in rects) + { + g.ExcludeClip(rect); + } + GrayscaleFilter.DrawGray(g, bitmap, applyRect); + + g.Restore(state); + } } /// diff --git a/src/Greenshot.Editor/Drawing/Filters/GrayscaleFilter.cs b/src/Greenshot.Editor/Drawing/Filters/GrayscaleFilter.cs index 441102980..ab540f4e0 100644 --- a/src/Greenshot.Editor/Drawing/Filters/GrayscaleFilter.cs +++ b/src/Greenshot.Editor/Drawing/Filters/GrayscaleFilter.cs @@ -56,6 +56,13 @@ namespace Greenshot.Editor.Drawing.Filters graphics.ExcludeClip(rect); } + DrawGray(graphics, applyBitmap, applyRect); + + graphics.Restore(state); + } + + public static void DrawGray(Graphics graphics, Bitmap applyBitmap, NativeRect applyRect) + { ColorMatrix grayscaleMatrix = new ColorMatrix(new[] { new[] @@ -83,9 +90,7 @@ namespace Greenshot.Editor.Drawing.Filters { ia.SetColorMatrix(grayscaleMatrix); graphics.DrawImage(applyBitmap, applyRect, applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height, GraphicsUnit.Pixel, ia); - } - - graphics.Restore(state); + } } } } \ No newline at end of file