From 903929b3ee1fc1a50c83e33fb1fde0b6a72a2380 Mon Sep 17 00:00:00 2001 From: Jan Klass Date: Wed, 16 Jul 2025 00:25:38 +0200 Subject: [PATCH 1/3] Split off DrawGray method --- .../Drawing/Filters/GrayscaleFilter.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) 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 From 008fbe5faf6397810dfc1a6d2372ca6fd345446b Mon Sep 17 00:00:00 2001 From: Jan Klass Date: Wed, 16 Jul 2025 00:25:38 +0200 Subject: [PATCH 2/3] Use LINQ Cast --- src/Greenshot.Editor/Drawing/DrawableContainerList.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Greenshot.Editor/Drawing/DrawableContainerList.cs b/src/Greenshot.Editor/Drawing/DrawableContainerList.cs index ef30c037f..642c4ca05 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,10 @@ namespace Greenshot.Editor.Drawing return; } - foreach (var drawableContainer in this) + var drawableContainers = this.Cast(); + + foreach (var dc in drawableContainers) { - var dc = (DrawableContainer) drawableContainer; if (dc.Parent == null) { continue; From c4a531697483ec905a7d68c917ef9ef7beecbec1 Mon Sep 17 00:00:00 2001 From: Jan Klass Date: Wed, 16 Jul 2025 18:05:00 +0200 Subject: [PATCH 3/3] Combine multiple grayscale highlights --- .../Drawing/DrawableContainer.cs | 4 ++- .../Drawing/DrawableContainerList.cs | 26 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) 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 642c4ca05..a3027808e 100644 --- a/src/Greenshot.Editor/Drawing/DrawableContainerList.cs +++ b/src/Greenshot.Editor/Drawing/DrawableContainerList.cs @@ -331,6 +331,8 @@ namespace Greenshot.Editor.Drawing var drawableContainers = this.Cast(); + ApplyGrayscaleFilters(g, drawableContainers, bitmap); + foreach (var dc in drawableContainers) { if (dc.Parent == null) @@ -343,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); + } } ///