-
Notifications
You must be signed in to change notification settings - Fork 275
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
Feature proposal: Dithering #457
Merged
cameronwhite
merged 110 commits into
PintaProject:master
from
Lehonti:feature/error_diffusion_dithering
Jan 14, 2024
Merged
Changes from all commits
Commits
Show all changes
110 commits
Select commit
Hold shift + click to select a range
bf62d01
Feature proposal: Dithering
68b14c3
Fixed spelling mistakes to make the spell checker happy
39d1a29
Fixed more spelling mistakes to make the spell checker happy
00bfc1d
changed name to variable and used clamping functions in `Utility`
c66b6c9
Put new effect in `Pinta.Effects` namespace
9a181d7
Removed unnecessary comment
499a054
Added a new default palette
e35ceea
Corrected overflow that happened when creating web-safe color cube
186b28c
Overridden `LaunchConfiguration`, as a reminder in the code that it s…
33474f6
`ForwardErrorDiffusionDitheringData` now has enum-typed fields, so th…
39a3c1c
Added old ms paint palette
6dcb04b
Launches simple effect dialog
7739ae2
Debugged in Ubuntu and fixed indexing issues that prevented any pixel…
cc78400
Fixed formatting
39c44dd
Removed unnecessary class qualification
01b27a7
Started re-writing the algorithm
8636a6d
Fixed formatting
c2b5899
Another attempt, separating it into a 'working surface' and the desti…
400d18c
Fixed formatting
e351f9e
I finally understood how the ROIs are being passed as an argument. Th…
d4a8f50
Finally dithering works
19db393
Fixed formatting
6f54ffa
Formatting
87df8cb
Removed `DiffusionMatrixElement` and inheritors
1a15f18
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti f1e02ae
Added missing property
6a25aae
Added properties for dithering
832410b
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 2df07ec
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 9e0da4a
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 19ea99b
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti d43748b
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 7188947
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 7c8b13c
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti ab162d2
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 8716b29
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti b0a24a3
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti df31596
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 3afb1ee
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti f171294
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti e3992ce
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti c96ee62
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 64c845f
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti a9c8b66
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 836ca27
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 91b9e19
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 137c3fa
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 2ec8999
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti cbe0974
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti dca995d
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 5ab1109
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 089ecd8
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 91fbff0
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 379106b
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 74d4067
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti bc58a71
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti f35e299
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 71fddbb
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti dee5e3b
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 874a482
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 09f4850
Refactoring
Lehonti 0235ed4
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti f2450a7
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti aa85be5
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti d8fa12e
Changed method that was overridden
Lehonti 213f0bf
Inlined method
Lehonti d45393d
formatting
Lehonti 2b8b831
Assigning known settings to variables at the beginning of `Render` me…
Lehonti cbb23c0
`FindClosestPaletteColor` method made `static`
Lehonti d6dee49
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 08611b3
Extracted settings
Lehonti 4fe3095
Formatting
Lehonti f041ea6
Removed unused property
Lehonti 51393fe
Moved comment to a place that makes it more readable
Lehonti 4c6f8c5
Formatting and making some calculations more efficient (by removing u…
Lehonti 494e4f6
Corrected naming
Lehonti dc24b89
Removed conditional compilation
Lehonti 00e6f54
Added tests
Lehonti 4fdd7d5
Do the tests succeed if I remove this?
Lehonti 64208a8
Revert "Do the tests succeed if I remove this?"
Lehonti c539dd4
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 13ad130
Renamed dithering effect and extracted some classes into their own files
Lehonti 947858e
Copying to dst_data first, just to make sure
Lehonti 2bfc006
fixed compilation errors
Lehonti 702592d
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 1fb54c8
Changed test picture `dithering2.png`
Lehonti 1c4d1db
Ordered `using`s
Lehonti fdc8c52
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti f1c64a0
Added checks so that when the diffusion matrix is being applied is st…
Lehonti b2fa05f
Changed test files
Lehonti 5a73b5b
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 7f88f7c
Expanded selection of color palettes
Lehonti 9819be8
Sorted lines in `PaletteHelper`
Lehonti 3a3cfb2
Expanded palette selection further
Lehonti 6a725f9
Added another palette
Lehonti 6468687
Added another palette
Lehonti 4606508
Local refactoring
Lehonti adfd3e1
Removed WebSafe, as it was repeated
Lehonti 2dc1247
Created `ColorCube` method to bring many of those palettes together
Lehonti f66b20d
Formatting
Lehonti a6d126e
Made name more specific
Lehonti 7875e19
Added `Rgb12Bit` palette
Lehonti 37d6749
"Compressed" the logic even further
Lehonti d618420
Made code even more compact
Lehonti 5858023
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 86a6123
Implemented suggested changes
Lehonti b15875a
Changed label
Lehonti 733be7c
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 1f80229
Merge branch 'PintaProject:master' into feature/error_diffusion_dithe…
Lehonti 1372f7b
Added comments for translators
Lehonti File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.ComponentModel; | ||
using System.Linq; | ||
using Pinta.Gui.Widgets; | ||
|
||
namespace Pinta.Effects; | ||
|
||
public enum PredefinedDiffusionMatrices | ||
{ | ||
// Translators: Image dithering matrix named after Frankie Sierra | ||
[Caption ("Sierra")] | ||
Sierra, | ||
|
||
// Translators: Image dithering matrix named after Frankie Sierra | ||
[Caption ("Two-Row Sierra")] | ||
TwoRowSierra, | ||
|
||
// Translators: Image dithering matrix named after Frankie Sierra | ||
[Caption ("Sierra Lite")] | ||
SierraLite, | ||
|
||
// Translators: Image dithering matrix named after Daniel Burkes | ||
[Caption ("Burkes")] | ||
Burkes, | ||
|
||
// Translators: Image dithering matrix named after Bill Atkinson | ||
[Caption ("Atkinson")] | ||
Atkinson, | ||
|
||
// Translators: Image dithering matrix named after Peter Stucki | ||
[Caption ("Stucki")] | ||
Stucki, | ||
|
||
// Translators: Image dithering matrix named after J. F. Jarvis, C. N. Judice, and W. H. Ninke | ||
[Caption ("Jarvis-Judice-Ninke")] | ||
JarvisJudiceNinke, | ||
|
||
// Translators: Image dithering matrix named after Robert W. Floyd and Louis Steinberg | ||
[Caption ("Floyd-Steinberg")] | ||
FloydSteinberg, | ||
|
||
// Translators: Image dithering matrix named after Robert W. Floyd and Louis Steinberg. Some software may use it and call it Floyd-Steinberg, but it's not the actual Floyd-Steinberg matrix | ||
[Caption ("Floyd-Steinberg Lite")] | ||
FalseFloydSteinberg, | ||
} | ||
|
||
/// <summary> | ||
/// Represents the matrix that is used by the dithering algorithm | ||
/// in order to propagate the error (defined as the difference | ||
/// between a pixel's color and the color in a certain palette that is | ||
/// closest to it) forward. | ||
/// </summary> | ||
internal sealed class ErrorDiffusionMatrix | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please also add some doc comments for this class There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just added a doc comment with basic explanation |
||
{ | ||
public static ErrorDiffusionMatrix GetPredefined (PredefinedDiffusionMatrices choice) | ||
{ | ||
return choice switch { | ||
PredefinedDiffusionMatrices.Sierra => Predefined.Sierra, | ||
PredefinedDiffusionMatrices.TwoRowSierra => Predefined.TwoRowSierra, | ||
PredefinedDiffusionMatrices.SierraLite => Predefined.SierraLite, | ||
PredefinedDiffusionMatrices.Burkes => Predefined.Burkes, | ||
PredefinedDiffusionMatrices.Atkinson => Predefined.Atkinson, | ||
PredefinedDiffusionMatrices.Stucki => Predefined.Stucki, | ||
PredefinedDiffusionMatrices.JarvisJudiceNinke => Predefined.JarvisJudiceNinke, | ||
PredefinedDiffusionMatrices.FloydSteinberg => Predefined.FloydSteinberg, | ||
PredefinedDiffusionMatrices.FalseFloydSteinberg => Predefined.FakeFloydSteinberg, | ||
_ => throw new InvalidEnumArgumentException (nameof (choice), (int) choice, typeof (PredefinedDiffusionMatrices)), | ||
}; | ||
} | ||
|
||
public static class Predefined | ||
{ | ||
public static ErrorDiffusionMatrix Sierra { get; } = new ErrorDiffusionMatrix (DefaultMatrixArrays.Sierra, 2); | ||
public static ErrorDiffusionMatrix TwoRowSierra { get; } = new ErrorDiffusionMatrix (DefaultMatrixArrays.TwoRowSierra, 2); | ||
public static ErrorDiffusionMatrix SierraLite { get; } = new ErrorDiffusionMatrix (DefaultMatrixArrays.SierraLite, 1); | ||
public static ErrorDiffusionMatrix Burkes { get; } = new ErrorDiffusionMatrix (DefaultMatrixArrays.Burkes, 2); | ||
public static ErrorDiffusionMatrix Atkinson { get; } = new ErrorDiffusionMatrix (DefaultMatrixArrays.Atkinson, 1); | ||
public static ErrorDiffusionMatrix Stucki { get; } = new ErrorDiffusionMatrix (DefaultMatrixArrays.Stucki, 2); | ||
public static ErrorDiffusionMatrix JarvisJudiceNinke { get; } = new ErrorDiffusionMatrix (DefaultMatrixArrays.JarvisJudiceNinke, 2); | ||
public static ErrorDiffusionMatrix FloydSteinberg { get; } = new ErrorDiffusionMatrix (DefaultMatrixArrays.FloydSteinberg, 1); | ||
public static ErrorDiffusionMatrix FakeFloydSteinberg { get; } = new ErrorDiffusionMatrix (DefaultMatrixArrays.FakeFloydSteinberg, 0); | ||
} | ||
|
||
private static class DefaultMatrixArrays | ||
{ | ||
public static int[,] Sierra { get; } = { | ||
{ 0, 0, 0, 5, 3, }, | ||
{ 2, 4, 5, 4, 2, }, | ||
{ 0, 2, 3, 2, 0, }, | ||
}; | ||
|
||
public static int[,] TwoRowSierra { get; } = { | ||
{ 0, 0, 0, 4, 3, }, | ||
{ 1, 2, 3, 2, 1, }, | ||
}; | ||
|
||
public static int[,] SierraLite { get; } = { | ||
{ 0, 0, 2, }, | ||
{ 1, 1, 0, }, | ||
}; | ||
|
||
public static int[,] Burkes { get; } = { | ||
{ 0, 0, 0, 8, 4, }, | ||
{ 2, 4, 8, 4, 2, }, | ||
}; | ||
|
||
public static int[,] Atkinson { get; } = { | ||
{ 0, 0, 1, 1, }, | ||
{ 1, 1, 1, 0, }, | ||
{ 0, 1, 0, 0, }, | ||
}; | ||
|
||
public static int[,] Stucki { get; } = { | ||
{ 0, 0, 0, 8, 4, }, | ||
{ 2, 4, 8, 4, 2, }, | ||
{ 1, 2, 4, 2, 1, }, | ||
}; | ||
|
||
public static int[,] JarvisJudiceNinke { get; } = { | ||
{ 0, 0, 0, 7, 5, }, | ||
{ 3, 5, 7, 5, 3, }, | ||
{ 1, 3, 5, 3, 1, }, | ||
}; | ||
|
||
public static int[,] FloydSteinberg { get; } = { | ||
{ 0, 0, 7, }, | ||
{ 3, 5, 1, } | ||
}; | ||
|
||
public static int[,] FakeFloydSteinberg { get; } = { | ||
{ 0, 3, }, | ||
{ 3, 2, } | ||
}; | ||
} | ||
|
||
private readonly int[,] array_2_d; | ||
public int Columns { get; } | ||
public int Rows { get; } | ||
public int TotalWeight { get; } | ||
public int ColumnsToLeft { get; } | ||
public int ColumnsToRight { get; } | ||
public int RowsBelow { get; } | ||
public int this[int row, int column] => array_2_d[row, column]; | ||
public ErrorDiffusionMatrix (int[,] array2D, int pixelColumn) | ||
{ | ||
var clone = (int[,]) array2D.Clone (); | ||
var rows = clone.GetLength (0); | ||
if (rows <= 0) throw new ArgumentException ("Array has to have a strictly positive number of rows", nameof (array2D)); | ||
var columns = clone.GetLength (1); | ||
if (columns <= 0) throw new ArgumentException ("Array has to have a strictly positive number of rows", nameof (array2D)); | ||
if (pixelColumn < 0) throw new ArgumentException ("Argument has to refer to a valid column offset", nameof (pixelColumn)); | ||
if (pixelColumn >= columns) throw new ArgumentException ("Argument has to refer to a valid column offset", nameof (pixelColumn)); | ||
if (clone[0, pixelColumn] != 0) throw new ArgumentException ("Target pixel cannot have a nonzero weight"); | ||
var flattened = Flatten2DArray (clone); | ||
if (flattened.Any (w => w < 0)) throw new ArgumentException ("No negative weights", nameof (array2D)); | ||
if (flattened.Take (pixelColumn).Any (w => w != 0)) throw new ArgumentException ("Pixels previous to target cannot have nonzero weights"); | ||
ColumnsToLeft = pixelColumn; | ||
ColumnsToRight = columns - 1 - pixelColumn; | ||
TotalWeight = flattened.Sum (); | ||
Columns = columns; | ||
Rows = rows; | ||
RowsBelow = rows - 1; | ||
array_2_d = clone; | ||
} | ||
|
||
private static IEnumerable<T> Flatten2DArray<T> (T[,] array) | ||
{ | ||
for (int i = 0; i < array.GetLength (0); i++) | ||
for (int j = 0; j < array.GetLength (1); j++) | ||
yield return array[i, j]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
using System; | ||
using System.Collections.Immutable; | ||
using Cairo; | ||
using Pinta.Core; | ||
using Pinta.Gui.Widgets; | ||
|
||
namespace Pinta.Effects; | ||
|
||
public sealed class DitheringEffect : BaseEffect | ||
{ | ||
public override string Name => Translations.GetString ("Dithering"); | ||
public override bool IsConfigurable => true; | ||
// TODO: Icon | ||
public override string EffectMenuCategory => Translations.GetString ("Color"); | ||
public DitheringData Data => (DitheringData) EffectData!; // NRT - Set in constructor | ||
|
||
public override bool IsTileable => false; | ||
|
||
public DitheringEffect () | ||
{ | ||
EffectData = new DitheringData (); | ||
} | ||
|
||
public override void LaunchConfiguration () | ||
{ | ||
EffectHelper.LaunchSimpleEffectDialog (this); | ||
} | ||
|
||
private sealed record DitheringSettings ( | ||
ErrorDiffusionMatrix diffusionMatrix, | ||
ImmutableArray<ColorBgra> palette, | ||
int sourceWidth, | ||
int sourceHeight); | ||
|
||
private DitheringSettings CreateSettings (ImageSurface src) | ||
=> new ( | ||
diffusionMatrix: ErrorDiffusionMatrix.GetPredefined (Data.ErrorDiffusionMethod), | ||
palette: PaletteHelper.GetPredefined (Data.PaletteChoice), | ||
sourceWidth: src.Width, | ||
sourceHeight: src.Height | ||
); | ||
|
||
protected override void Render (ImageSurface src, ImageSurface dest, RectangleI roi) | ||
{ | ||
DitheringSettings settings = CreateSettings (src); | ||
|
||
ReadOnlySpan<ColorBgra> src_data = src.GetReadOnlyPixelData (); | ||
Span<ColorBgra> dst_data = dest.GetPixelData (); | ||
|
||
for (int y = roi.Top; y <= roi.Bottom; y++) { | ||
for (int x = roi.Left; x <= roi.Right; x++) { | ||
int currentIndex = y * settings.sourceWidth + x; | ||
dst_data[currentIndex] = src_data[currentIndex]; | ||
} | ||
} | ||
|
||
for (int y = roi.Top; y <= roi.Bottom; y++) { | ||
|
||
for (int x = roi.Left; x <= roi.Right; x++) { | ||
|
||
int currentIndex = y * settings.sourceWidth + x; | ||
ColorBgra originalPixel = dst_data[currentIndex]; | ||
ColorBgra closestColor = FindClosestPaletteColor (settings.palette, originalPixel); | ||
|
||
dst_data[currentIndex] = closestColor; | ||
|
||
int errorRed = originalPixel.R - closestColor.R; | ||
int errorGreen = originalPixel.G - closestColor.G; | ||
int errorBlue = originalPixel.B - closestColor.B; | ||
|
||
for (int r = 0; r < settings.diffusionMatrix.Rows; r++) { | ||
|
||
for (int c = 0; c < settings.diffusionMatrix.Columns; c++) { | ||
|
||
var weight = settings.diffusionMatrix[r, c]; | ||
|
||
if (weight <= 0) | ||
continue; | ||
|
||
PointI thisItem = new ( | ||
X: x + c - settings.diffusionMatrix.ColumnsToLeft, | ||
Y: y + r | ||
); | ||
|
||
if (thisItem.X < roi.Left || thisItem.X >= roi.Right) | ||
continue; | ||
|
||
if (thisItem.Y < roi.Top || thisItem.Y >= roi.Bottom) | ||
continue; | ||
|
||
int idx = (thisItem.Y * settings.sourceWidth) + thisItem.X; | ||
|
||
double factor = ((double) weight) / settings.diffusionMatrix.TotalWeight; | ||
|
||
dst_data[idx] = AddError (dst_data[idx], factor, errorRed, errorGreen, errorBlue); | ||
} | ||
} | ||
|
||
} | ||
} | ||
} | ||
|
||
private static ColorBgra AddError (ColorBgra color, double factor, int errorRed, int errorGreen, int errorBlue) | ||
=> ColorBgra.FromBgra ( | ||
b: Utility.ClampToByte (color.B + (int) (factor * errorBlue)), | ||
g: Utility.ClampToByte (color.G + (int) (factor * errorGreen)), | ||
r: Utility.ClampToByte (color.R + (int) (factor * errorRed)), | ||
a: 255 | ||
); | ||
|
||
private static ColorBgra FindClosestPaletteColor (ImmutableArray<ColorBgra> palette, ColorBgra original) | ||
{ | ||
if (palette.IsDefault) throw new ArgumentException ("Palette not initialized", nameof (palette)); | ||
if (palette.Length == 0) throw new ArgumentException ("Palette cannot be empty", nameof (palette)); | ||
if (palette.Length == 1) return palette[0]; | ||
double minDistance = double.MaxValue; | ||
ColorBgra closestColor = ColorBgra.FromBgra (0, 0, 0, 1); | ||
foreach (var paletteColor in palette) { | ||
double distance = CalculateSquaredDistance (original, paletteColor); | ||
if (distance >= minDistance) continue; | ||
minDistance = distance; | ||
closestColor = paletteColor; | ||
} | ||
return closestColor; | ||
} | ||
|
||
private static double CalculateSquaredDistance (ColorBgra color1, ColorBgra color2) | ||
{ | ||
double deltaR = color1.R - color2.R; | ||
double deltaG = color1.G - color2.G; | ||
double deltaB = color1.B - color2.B; | ||
return deltaR * deltaR + deltaG * deltaG + deltaB * deltaB; | ||
} | ||
|
||
public sealed class DitheringData : EffectData | ||
{ | ||
[Caption ("Error Diffusion Method")] | ||
public PredefinedDiffusionMatrices ErrorDiffusionMethod { get; set; } = PredefinedDiffusionMatrices.FloydSteinberg; | ||
|
||
[Caption ("Palette")] | ||
public PredefinedPalettes PaletteChoice { get; set; } = PredefinedPalettes.OldWindows16; | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should probably get Caption attributes added, e.g.
Floyd-Steinberg
should have a hyphen in it from what I see online, along with explanations for translatorsIt would also be good to see if there are any more descriptive names for users, e.g. "Fake" Floyd-Steinberg might not help a user understand what it does
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. I added a
CaptionAttribute
to those values that have hyphens or spaces; and I labeled the matrix you mentioned as "Floyd-Steinberg Lite"There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks - since these captions will also show up as translatable strings, also adding some
Translators: ...
comments would be good to explain to translators that these are algorithms named after peopleThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. I just added comments for translators making it clear that the matrices were named after people