Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Struct-valued custom enumerator for pixel offsets #1171

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Pinta.Core/Algorithms/ColorDifference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
21 changes: 0 additions & 21 deletions Pinta.Core/Algorithms/Utility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,6 @@ public static double Magnitude (this PointI point)
public static double Distance (this PointD origin, in PointD dest)
=> Magnitude (origin - dest);

/// <returns>
/// Offsets of pixels, if we consider all pixels in a canvas of
/// size <paramref name="canvasSize"/> to be sequential in memory
/// (from left to right, and top to bottom)
/// </returns>
public static IEnumerable<PixelOffset> 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,
Expand Down
86 changes: 86 additions & 0 deletions Pinta.Core/Enumeration/PixelOffsetEnumeration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using System.Collections;
using System.Collections.Generic;

namespace Pinta.Core;

public readonly struct PixelOffsetEnumerable : IEnumerable<PixelOffset>
{
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<PixelOffset> IEnumerable<PixelOffset>.GetEnumerator () => GetEnumerator ();
}

public struct PixelOffsetEnumerator : IEnumerator<PixelOffset>
{
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;
}
12 changes: 12 additions & 0 deletions Pinta.Core/Extensions/Tiling.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Pinta.Core;

public static class Tiling
{
/// <returns>
/// Offsets of pixels, if we consider all pixels in a canvas of
/// size <paramref name="canvasSize"/> to be sequential in memory
/// (from left to right, and top to bottom)
/// </returns>
public static PixelOffsetEnumerable GeneratePixelOffsets (this RectangleI bounds, Size canvasSize)
=> new (bounds, canvasSize);
}
2 changes: 1 addition & 1 deletion Pinta.Effects/Effects/AddNoiseEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion Pinta.Effects/Effects/BulgeEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion Pinta.Effects/Effects/DentsEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public override void Render (ImageSurface src, ImageSurface dst, ReadOnlySpan<Re
Span<ColorBgra> dst_data = dst.GetPixelData ();
ReadOnlySpan<ColorBgra> 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,
Expand Down
2 changes: 1 addition & 1 deletion Pinta.Effects/Effects/DitheringEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion Pinta.Effects/Effects/FragmentEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ protected override void Render (
FragmentSettings settings = CreateSettings (source);
ReadOnlySpan<ColorBgra> sourceData = source.GetReadOnlyPixelData ();
Span<ColorBgra> 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,
Expand Down
2 changes: 1 addition & 1 deletion Pinta.Effects/Effects/JuliaFractalEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public override void Render (ImageSurface src, ImageSurface dst, ReadOnlySpan<Re
JuliaSettings settings = CreateSettings (dst);
Span<ColorBgra> 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);
}

Expand Down
2 changes: 1 addition & 1 deletion Pinta.Effects/Effects/MandelbrotFractalEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public override void Render (ImageSurface src, ImageSurface dst, ReadOnlySpan<Re
MandelbrotSettings settings = CreateSettings (dst);
Span<ColorBgra> 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)
Expand Down
2 changes: 1 addition & 1 deletion Pinta.Effects/Effects/MotionBlurEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public override void Render (
Span<ColorBgra> 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);
Expand Down
2 changes: 1 addition & 1 deletion Pinta.Effects/Effects/OilPaintingEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ protected override void Render (
OilPaintingSettings settings = CreateSettings (source);
ReadOnlySpan<ColorBgra> src_data = source.GetReadOnlyPixelData ();
Span<ColorBgra> 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,
Expand Down
2 changes: 1 addition & 1 deletion Pinta.Effects/Effects/PencilSketchEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public override void Render (ImageSurface src, ImageSurface dest, ReadOnlySpan<R
Size canvasSize = src.GetSize ();

foreach (RectangleI roi in rois) {
foreach (var pixel in Utility.GeneratePixelOffsets (roi, canvasSize)) {
foreach (var pixel in Tiling.GeneratePixelOffsets (roi, canvasSize)) {
ColorBgra srcGrey = desaturate_op.Apply (src_data[pixel.memoryOffset]);
dst_data[pixel.memoryOffset] = color_dodge_op.Apply (srcGrey, dst_data[pixel.memoryOffset]);
}
Expand Down
2 changes: 1 addition & 1 deletion Pinta.Effects/Effects/PolarInversionEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public override void Render (ImageSurface src, ImageSurface dst, ReadOnlySpan<Re
Span<ColorBgra> dst_data = dst.GetPixelData ();
ReadOnlySpan<ColorBgra> 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,
Expand Down
2 changes: 1 addition & 1 deletion Pinta.Effects/Effects/RadialBlurEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public override void Render (ImageSurface source, ImageSurface destination, Read
Span<ColorBgra> 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,
Expand Down
2 changes: 1 addition & 1 deletion Pinta.Effects/Effects/SoftenPortraitEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public override void Render (ImageSurface src, ImageSurface dest, ReadOnlySpan<R
Span<ColorBgra> 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));
Expand Down
2 changes: 1 addition & 1 deletion Pinta.Effects/Effects/TileEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ protected override void Render (
TileSettings settings = CreateSettings (source);
ReadOnlySpan<ColorBgra> sourceData = source.GetReadOnlyPixelData ();
Span<ColorBgra> 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,
Expand Down
2 changes: 1 addition & 1 deletion Pinta.Effects/Effects/TwistEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ protected override void Render (
TwistSettings settings = CreateSettings ();
ReadOnlySpan<ColorBgra> sourceData = source.GetReadOnlyPixelData ();
Span<ColorBgra> 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,
Expand Down
2 changes: 1 addition & 1 deletion Pinta.Effects/Effects/VignetteEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ protected override void Render (
VignetteSettings settings = CreateSettings (source);
ReadOnlySpan<ColorBgra> sourceData = source.GetReadOnlyPixelData ();
Span<ColorBgra> 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);
}

Expand Down
2 changes: 1 addition & 1 deletion Pinta.Effects/Effects/ZoomBlurEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ protected override void Render (
ZoomBlurSettings settings = CreateSettings (source);
ReadOnlySpan<ColorBgra> sourceData = source.GetReadOnlyPixelData ();
Span<ColorBgra> 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,
Expand Down
Loading