From 65caa860c821771ecdd153bd648c55497b41abe8 Mon Sep 17 00:00:00 2001
From: Lehonti Ramos <17771375+Lehonti@users.noreply.github.com>
Date: Sat, 30 Nov 2024 03:47:56 +0100
Subject: [PATCH] Struct-valued enumerator for pixel offsets
---
Pinta.Core/Algorithms/ColorDifference.cs | 2 +-
Pinta.Core/Algorithms/Utility.cs | 21 -----
.../Enumeration/PixelOffsetEnumeration.cs | 86 +++++++++++++++++++
Pinta.Core/Extensions/Tiling.cs | 12 +++
Pinta.Effects/Effects/AddNoiseEffect.cs | 2 +-
Pinta.Effects/Effects/BulgeEffect.cs | 2 +-
Pinta.Effects/Effects/DentsEffect.cs | 2 +-
Pinta.Effects/Effects/DitheringEffect.cs | 2 +-
Pinta.Effects/Effects/FragmentEffect.cs | 2 +-
Pinta.Effects/Effects/JuliaFractalEffect.cs | 2 +-
.../Effects/MandelbrotFractalEffect.cs | 2 +-
Pinta.Effects/Effects/MotionBlurEffect.cs | 2 +-
Pinta.Effects/Effects/OilPaintingEffect.cs | 2 +-
Pinta.Effects/Effects/PencilSketchEffect.cs | 2 +-
Pinta.Effects/Effects/PolarInversionEffect.cs | 2 +-
Pinta.Effects/Effects/RadialBlurEffect.cs | 2 +-
Pinta.Effects/Effects/SoftenPortraitEffect.cs | 2 +-
Pinta.Effects/Effects/TileEffect.cs | 2 +-
Pinta.Effects/Effects/TwistEffect.cs | 2 +-
Pinta.Effects/Effects/VignetteEffect.cs | 2 +-
Pinta.Effects/Effects/ZoomBlurEffect.cs | 2 +-
21 files changed, 116 insertions(+), 39 deletions(-)
create mode 100644 Pinta.Core/Enumeration/PixelOffsetEnumeration.cs
create mode 100644 Pinta.Core/Extensions/Tiling.cs
diff --git a/Pinta.Core/Algorithms/ColorDifference.cs b/Pinta.Core/Algorithms/ColorDifference.cs
index e3fc6b908..255890896 100644
--- a/Pinta.Core/Algorithms/ColorDifference.cs
+++ b/Pinta.Core/Algorithms/ColorDifference.cs
@@ -35,7 +35,7 @@ public static void RenderColorDifferenceEffect (
foreach (RectangleI rect in rois) {
- foreach (var pixel in Utility.GeneratePixelOffsets (rect, source.GetSize ())) {
+ foreach (var pixel in Tiling.GeneratePixelOffsets (rect, source.GetSize ())) {
destinationData[pixel.memoryOffset] = GetFinalPixelColor (
weights,
diff --git a/Pinta.Core/Algorithms/Utility.cs b/Pinta.Core/Algorithms/Utility.cs
index 4f5efa265..b580f77bd 100644
--- a/Pinta.Core/Algorithms/Utility.cs
+++ b/Pinta.Core/Algorithms/Utility.cs
@@ -38,27 +38,6 @@ public static double Magnitude (this PointI point)
public static double Distance (this PointD origin, in PointD dest)
=> Magnitude (origin - dest);
- ///
- /// Offsets of pixels, if we consider all pixels in a canvas of
- /// size to be sequential in memory
- /// (from left to right, and top to bottom)
- ///
- public static IEnumerable GeneratePixelOffsets (
- this RectangleI roi,
- Size canvasSize)
- {
- if (roi.Left < 0 || roi.Right >= canvasSize.Width || roi.Top < 0 || roi.Bottom >= canvasSize.Height)
- throw new ArgumentException ($"Rectangle is out of size bounds");
-
- for (int y = roi.Top; y <= roi.Bottom; y++) {
- int rowOffset = y * canvasSize.Width;
- for (int x = roi.Left; x <= roi.Right; x++)
- yield return new (
- coordinates: new (x, y),
- memoryOffset: rowOffset + x);
- }
- }
-
public static PointD Lerp (
PointD from,
PointD to,
diff --git a/Pinta.Core/Enumeration/PixelOffsetEnumeration.cs b/Pinta.Core/Enumeration/PixelOffsetEnumeration.cs
new file mode 100644
index 000000000..337741b06
--- /dev/null
+++ b/Pinta.Core/Enumeration/PixelOffsetEnumeration.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Pinta.Core;
+
+public readonly struct PixelOffsetEnumerable : IEnumerable
+{
+ private readonly RectangleI roi_bounds;
+ private readonly Size canvas_size;
+ internal PixelOffsetEnumerable (in RectangleI roiBounds, in Size canvasSize)
+ {
+ if (roiBounds.Left < 0 || roiBounds.Right >= canvasSize.Width || roiBounds.Top < 0 || roiBounds.Bottom >= canvasSize.Height)
+ throw new ArgumentException ($"Rectangle is out of size bounds");
+ roi_bounds = roiBounds;
+ canvas_size = canvasSize;
+ }
+
+ public PixelOffsetEnumerator GetEnumerator ()
+ => new (roi_bounds, canvas_size);
+
+ IEnumerator IEnumerable.GetEnumerator () => GetEnumerator ();
+ IEnumerator IEnumerable.GetEnumerator () => GetEnumerator ();
+}
+
+public struct PixelOffsetEnumerator : IEnumerator
+{
+ private readonly Size canvas_size;
+ private readonly int left;
+ private readonly int right;
+ private readonly int top;
+ private readonly int bottom;
+ private int x;
+ private int y;
+ private int row_offset;
+ private bool has_more_rows;
+ internal PixelOffsetEnumerator (in RectangleI roiBounds, in Size canvasSize)
+ {
+ int l = roiBounds.Left;
+ int r = roiBounds.Right;
+ int t = roiBounds.Top;
+ int b = roiBounds.Bottom;
+
+ // --- Read-only
+ canvas_size = canvasSize;
+ left = l;
+ right = r;
+ top = t;
+ bottom = b;
+
+ // --- Mutable
+ x = l - 1; // Initialize to just before the first x
+ y = t;
+ row_offset = t * canvasSize.Width;
+ has_more_rows = t <= b;
+ }
+
+ public readonly PixelOffset Current => new (
+ coordinates: new PointI (x, y),
+ memoryOffset: row_offset + x);
+
+ public bool MoveNext ()
+ {
+ if (!has_more_rows) return false;
+ x++;
+ if (x <= right) return true;
+ x = left;
+ y++;
+ row_offset += canvas_size.Width;
+ if (y <= bottom) return true;
+ has_more_rows = false;
+ return false;
+ }
+
+ public void Reset ()
+ {
+ x = left - 1; // Initialize to just before the first x
+ y = top;
+ row_offset = top * canvas_size.Width;
+ has_more_rows = top <= bottom;
+ }
+
+ public void Dispose () { }
+
+ readonly object IEnumerator.Current => Current;
+}
diff --git a/Pinta.Core/Extensions/Tiling.cs b/Pinta.Core/Extensions/Tiling.cs
new file mode 100644
index 000000000..9bc38a897
--- /dev/null
+++ b/Pinta.Core/Extensions/Tiling.cs
@@ -0,0 +1,12 @@
+namespace Pinta.Core;
+
+public static class Tiling
+{
+ ///
+ /// Offsets of pixels, if we consider all pixels in a canvas of
+ /// size to be sequential in memory
+ /// (from left to right, and top to bottom)
+ ///
+ public static PixelOffsetEnumerable GeneratePixelOffsets (this RectangleI bounds, Size canvasSize)
+ => new (bounds, canvasSize);
+}
diff --git a/Pinta.Effects/Effects/AddNoiseEffect.cs b/Pinta.Effects/Effects/AddNoiseEffect.cs
index 196f9c4c6..7d2babf45 100644
--- a/Pinta.Effects/Effects/AddNoiseEffect.cs
+++ b/Pinta.Effects/Effects/AddNoiseEffect.cs
@@ -129,7 +129,7 @@ protected override void Render (
// being used to render the effect, but will change if the effect is tiled differently.
Random rand = new (settings.seed.GetValueForRegion (rect));
- foreach (var pixel in Utility.GeneratePixelOffsets (rect, settings.size))
+ foreach (var pixel in Tiling.GeneratePixelOffsets (rect, settings.size))
destinationData[pixel.memoryOffset] = GetFinalPixelColor (
settings,
rand,
diff --git a/Pinta.Effects/Effects/BulgeEffect.cs b/Pinta.Effects/Effects/BulgeEffect.cs
index b9e4f5eb0..bec4f3686 100644
--- a/Pinta.Effects/Effects/BulgeEffect.cs
+++ b/Pinta.Effects/Effects/BulgeEffect.cs
@@ -76,7 +76,7 @@ public override void Render (
foreach (RectangleI rect in rois) {
- foreach (var pixel in Utility.GeneratePixelOffsets (rect, new Size (settings.sourceWidth, settings.sourceHeight))) {
+ foreach (var pixel in Tiling.GeneratePixelOffsets (rect, new Size (settings.sourceWidth, settings.sourceHeight))) {
destinationData[pixel.memoryOffset] = GetFinalPixelColor (
settings,
diff --git a/Pinta.Effects/Effects/DentsEffect.cs b/Pinta.Effects/Effects/DentsEffect.cs
index 1df517a71..aeabfa3b6 100644
--- a/Pinta.Effects/Effects/DentsEffect.cs
+++ b/Pinta.Effects/Effects/DentsEffect.cs
@@ -82,7 +82,7 @@ public override void Render (ImageSurface src, ImageSurface dst, ReadOnlySpan dst_data = dst.GetPixelData ();
ReadOnlySpan src_data = src.GetReadOnlyPixelData ();
foreach (RectangleI rect in rois) {
- foreach (var pixel in Utility.GeneratePixelOffsets (rect, src.GetSize ())) {
+ foreach (var pixel in Tiling.GeneratePixelOffsets (rect, src.GetSize ())) {
dst_data[pixel.memoryOffset] = Warp.GetPixelColor (
settings,
InverseTransform,
diff --git a/Pinta.Effects/Effects/DitheringEffect.cs b/Pinta.Effects/Effects/DitheringEffect.cs
index e6677c0aa..519ce9aa0 100644
--- a/Pinta.Effects/Effects/DitheringEffect.cs
+++ b/Pinta.Effects/Effects/DitheringEffect.cs
@@ -56,7 +56,7 @@ protected override void Render (ImageSurface src, ImageSurface dest, RectangleI
}
}
- foreach (var pixel in Utility.GeneratePixelOffsets (roi, dest.GetSize ())) {
+ foreach (var pixel in Tiling.GeneratePixelOffsets (roi, dest.GetSize ())) {
ColorBgra originalPixel = dst_data[pixel.memoryOffset];
ColorBgra closestColor = FindClosestPaletteColor (settings.palette, originalPixel);
diff --git a/Pinta.Effects/Effects/FragmentEffect.cs b/Pinta.Effects/Effects/FragmentEffect.cs
index caac82bea..9a309a99f 100644
--- a/Pinta.Effects/Effects/FragmentEffect.cs
+++ b/Pinta.Effects/Effects/FragmentEffect.cs
@@ -76,7 +76,7 @@ protected override void Render (
FragmentSettings settings = CreateSettings (source);
ReadOnlySpan sourceData = source.GetReadOnlyPixelData ();
Span dst_data = destination.GetPixelData ();
- foreach (var pixel in Utility.GeneratePixelOffsets (roi, settings.sourceSize))
+ foreach (var pixel in Tiling.GeneratePixelOffsets (roi, settings.sourceSize))
dst_data[pixel.memoryOffset] = GetFinalPixelColor (
settings,
source,
diff --git a/Pinta.Effects/Effects/JuliaFractalEffect.cs b/Pinta.Effects/Effects/JuliaFractalEffect.cs
index 1d505fea2..5be3ad19f 100644
--- a/Pinta.Effects/Effects/JuliaFractalEffect.cs
+++ b/Pinta.Effects/Effects/JuliaFractalEffect.cs
@@ -75,7 +75,7 @@ public override void Render (ImageSurface src, ImageSurface dst, ReadOnlySpan dst_data = dst.GetPixelData ();
foreach (RectangleI rect in rois)
- foreach (var pixel in Utility.GeneratePixelOffsets (rect, settings.canvasSize))
+ foreach (var pixel in Tiling.GeneratePixelOffsets (rect, settings.canvasSize))
dst_data[pixel.memoryOffset] = GetPixelColor (settings, pixel.coordinates);
}
diff --git a/Pinta.Effects/Effects/MandelbrotFractalEffect.cs b/Pinta.Effects/Effects/MandelbrotFractalEffect.cs
index 77fc9107b..2d011c379 100644
--- a/Pinta.Effects/Effects/MandelbrotFractalEffect.cs
+++ b/Pinta.Effects/Effects/MandelbrotFractalEffect.cs
@@ -132,7 +132,7 @@ public override void Render (ImageSurface src, ImageSurface dst, ReadOnlySpan dst_data = dst.GetPixelData ();
foreach (RectangleI rect in rois)
- foreach (var pixel in Utility.GeneratePixelOffsets (rect, settings.canvasSize))
+ foreach (var pixel in Tiling.GeneratePixelOffsets (rect, settings.canvasSize))
dst_data[pixel.memoryOffset] = GetPixelColor (settings, pixel.coordinates);
if (settings.invertColors)
diff --git a/Pinta.Effects/Effects/MotionBlurEffect.cs b/Pinta.Effects/Effects/MotionBlurEffect.cs
index 50881bdd3..0d0f61c0c 100644
--- a/Pinta.Effects/Effects/MotionBlurEffect.cs
+++ b/Pinta.Effects/Effects/MotionBlurEffect.cs
@@ -99,7 +99,7 @@ public override void Render (
Span dst_data = dst.GetPixelData ();
foreach (var rect in rois) {
- foreach (var pixel in Utility.GeneratePixelOffsets (rect, settings.canvasSize)) {
+ foreach (var pixel in Tiling.GeneratePixelOffsets (rect, settings.canvasSize)) {
int sampleCount = 0;
for (int j = 0; j < settings.points.Length; ++j) {
PointD pt = new (settings.points[j].X + pixel.coordinates.X, settings.points[j].Y + pixel.coordinates.Y);
diff --git a/Pinta.Effects/Effects/OilPaintingEffect.cs b/Pinta.Effects/Effects/OilPaintingEffect.cs
index 0ea45cf80..c0efd8de1 100644
--- a/Pinta.Effects/Effects/OilPaintingEffect.cs
+++ b/Pinta.Effects/Effects/OilPaintingEffect.cs
@@ -54,7 +54,7 @@ protected override void Render (
OilPaintingSettings settings = CreateSettings (source);
ReadOnlySpan src_data = source.GetReadOnlyPixelData ();
Span dst_data = destination.GetPixelData ();
- foreach (var pixel in Utility.GeneratePixelOffsets (roi, settings.canvasSize))
+ foreach (var pixel in Tiling.GeneratePixelOffsets (roi, settings.canvasSize))
dst_data[pixel.memoryOffset] = GetFinalColor (
settings,
src_data,
diff --git a/Pinta.Effects/Effects/PencilSketchEffect.cs b/Pinta.Effects/Effects/PencilSketchEffect.cs
index c672c83fc..d70958d8f 100644
--- a/Pinta.Effects/Effects/PencilSketchEffect.cs
+++ b/Pinta.Effects/Effects/PencilSketchEffect.cs
@@ -72,7 +72,7 @@ public override void Render (ImageSurface src, ImageSurface dest, ReadOnlySpan dst_data = dst.GetPixelData ();
ReadOnlySpan src_data = src.GetReadOnlyPixelData ();
foreach (RectangleI rect in rois) {
- foreach (var pixel in Utility.GeneratePixelOffsets (rect, src.GetSize ())) {
+ foreach (var pixel in Tiling.GeneratePixelOffsets (rect, src.GetSize ())) {
dst_data[pixel.memoryOffset] = Warp.GetPixelColor (
settings,
InverseTransform,
diff --git a/Pinta.Effects/Effects/RadialBlurEffect.cs b/Pinta.Effects/Effects/RadialBlurEffect.cs
index 1df748f12..44f0132ce 100644
--- a/Pinta.Effects/Effects/RadialBlurEffect.cs
+++ b/Pinta.Effects/Effects/RadialBlurEffect.cs
@@ -86,7 +86,7 @@ public override void Render (ImageSurface source, ImageSurface destination, Read
Span destinationData = destination.GetPixelData ();
foreach (RectangleI rect in rois)
- foreach (var pixel in Utility.GeneratePixelOffsets (rect, settings.canvasSize))
+ foreach (var pixel in Tiling.GeneratePixelOffsets (rect, settings.canvasSize))
destinationData[pixel.memoryOffset] = GetFinalPixelColor (
settings,
sourceData,
diff --git a/Pinta.Effects/Effects/SoftenPortraitEffect.cs b/Pinta.Effects/Effects/SoftenPortraitEffect.cs
index 8aee43911..cc7a8888b 100644
--- a/Pinta.Effects/Effects/SoftenPortraitEffect.cs
+++ b/Pinta.Effects/Effects/SoftenPortraitEffect.cs
@@ -100,7 +100,7 @@ public override void Render (ImageSurface src, ImageSurface dest, ReadOnlySpan dst_data = dest.GetPixelData ();
foreach (var roi in rois) {
- foreach (var pixel in Utility.GeneratePixelOffsets (roi, src.GetSize ())) {
+ foreach (var pixel in Tiling.GeneratePixelOffsets (roi, src.GetSize ())) {
ColorBgra srcGrey = desaturate_op.Apply (src_data[pixel.memoryOffset]);
srcGrey.R = Utility.ClampToByte ((int) (srcGrey.R * settings.redAdjust));
srcGrey.B = Utility.ClampToByte ((int) (srcGrey.B * settings.blueAdjust));
diff --git a/Pinta.Effects/Effects/TileEffect.cs b/Pinta.Effects/Effects/TileEffect.cs
index 7c3ac4ff0..50ecd0e72 100644
--- a/Pinta.Effects/Effects/TileEffect.cs
+++ b/Pinta.Effects/Effects/TileEffect.cs
@@ -125,7 +125,7 @@ protected override void Render (
TileSettings settings = CreateSettings (source);
ReadOnlySpan sourceData = source.GetReadOnlyPixelData ();
Span destinationData = destination.GetPixelData ();
- foreach (var pixel in Utility.GeneratePixelOffsets (roi, source.GetSize ()))
+ foreach (var pixel in Tiling.GeneratePixelOffsets (roi, source.GetSize ()))
destinationData[pixel.memoryOffset] = GetFinalPixelColor (
source,
settings,
diff --git a/Pinta.Effects/Effects/TwistEffect.cs b/Pinta.Effects/Effects/TwistEffect.cs
index 77c776209..cebfc0a69 100644
--- a/Pinta.Effects/Effects/TwistEffect.cs
+++ b/Pinta.Effects/Effects/TwistEffect.cs
@@ -51,7 +51,7 @@ protected override void Render (
TwistSettings settings = CreateSettings ();
ReadOnlySpan sourceData = source.GetReadOnlyPixelData ();
Span destinationData = destination.GetPixelData ();
- foreach (var pixel in Utility.GeneratePixelOffsets (roi, source.GetSize ()))
+ foreach (var pixel in Tiling.GeneratePixelOffsets (roi, source.GetSize ()))
destinationData[pixel.memoryOffset] = GetFinalPixelColor (
settings,
source,
diff --git a/Pinta.Effects/Effects/VignetteEffect.cs b/Pinta.Effects/Effects/VignetteEffect.cs
index da47d18ca..5bffac71a 100644
--- a/Pinta.Effects/Effects/VignetteEffect.cs
+++ b/Pinta.Effects/Effects/VignetteEffect.cs
@@ -98,7 +98,7 @@ protected override void Render (
VignetteSettings settings = CreateSettings (source);
ReadOnlySpan sourceData = source.GetReadOnlyPixelData ();
Span destinationData = destination.GetPixelData ();
- foreach (var pixel in Utility.GeneratePixelOffsets (roi, settings.canvasSize))
+ foreach (var pixel in Tiling.GeneratePixelOffsets (roi, settings.canvasSize))
destinationData[pixel.memoryOffset] = GetFinalPixelColor (settings, sourceData, pixel);
}
diff --git a/Pinta.Effects/Effects/ZoomBlurEffect.cs b/Pinta.Effects/Effects/ZoomBlurEffect.cs
index 7719ce567..a2ab03a16 100644
--- a/Pinta.Effects/Effects/ZoomBlurEffect.cs
+++ b/Pinta.Effects/Effects/ZoomBlurEffect.cs
@@ -76,7 +76,7 @@ protected override void Render (
ZoomBlurSettings settings = CreateSettings (source);
ReadOnlySpan sourceData = source.GetReadOnlyPixelData ();
Span destinationData = destination.GetPixelData ();
- foreach (var pixel in Utility.GeneratePixelOffsets (roi, settings.size))
+ foreach (var pixel in Tiling.GeneratePixelOffsets (roi, settings.size))
destinationData[pixel.memoryOffset] = GetFinalPixelColor (
source,
settings,