Browse Source

Make color tables mutable

pull/2500/head
James Jackson-South 3 years ago
parent
commit
43aaad1d49
  1. 4
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  2. 8
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  3. 8
      src/ImageSharp/Formats/Gif/GifFrameMetadata.cs
  4. 10
      src/ImageSharp/Formats/Gif/GifMetadata.cs
  5. 10
      tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs
  6. 8
      tests/ImageSharp.Tests/Formats/Gif/GifFrameMetadataTests.cs
  7. 10
      tests/ImageSharp.Tests/Formats/Gif/GifMetadataTests.cs
  8. 2
      tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs
  9. 4
      tests/ImageSharp.Tests/Metadata/ImageFrameMetadataTests.cs
  10. 2
      tests/ImageSharp.Tests/TestImages.cs

4
src/ImageSharp/Formats/Gif/GifDecoderCore.cs

@ -716,7 +716,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
colorTable[i] = new Color(Unsafe.Add(ref localBase, (uint)i));
}
gifMeta.DecodedLocalColorTable = colorTable;
gifMeta.LocalColorTable = colorTable;
}
// Graphics control extensions is optional.
@ -793,7 +793,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
colorTable[i] = new Color(Unsafe.Add(ref globalBase, (uint)i));
}
this.gifMetadata.DecodedGlobalColorTable = colorTable;
this.gifMetadata.GlobalColorTable = colorTable;
}
}
}

8
src/ImageSharp/Formats/Gif/GifEncoderCore.cs

@ -102,10 +102,10 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
if (this.quantizer is null)
{
// Is this a gif with color information. If so use that, otherwise use octree.
if (gifMetadata.ColorTableMode == GifColorTableMode.Global && gifMetadata.DecodedGlobalColorTable.Length > 0)
if (gifMetadata.ColorTableMode == GifColorTableMode.Global && gifMetadata.GlobalColorTable?.Length > 0)
{
// We avoid dithering by default to preserve the original colors.
this.quantizer = new PaletteQuantizer(gifMetadata.DecodedGlobalColorTable, new() { Dither = null });
this.quantizer = new PaletteQuantizer(gifMetadata.GlobalColorTable.Value, new() { Dither = null });
}
else
{
@ -234,11 +234,11 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
if (useLocal)
{
// Reassign using the current frame and details.
if (metadata?.DecodedLocalColorTable.Length > 0)
if (metadata?.LocalColorTable?.Length > 0)
{
// We can use the color data from the decoded metadata here.
// We avoid dithering by default to preserve the original colors.
PaletteQuantizer localQuantizer = new(metadata.DecodedLocalColorTable, new() { Dither = null });
PaletteQuantizer localQuantizer = new(metadata.LocalColorTable.Value, new() { Dither = null });
using IQuantizer<TPixel> frameQuantizer = localQuantizer.CreatePixelSpecificQuantizer<TPixel>(this.configuration, localQuantizer.Options);
quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(frame, frame.Bounds());
}

8
src/ImageSharp/Formats/Gif/GifFrameMetadata.cs

@ -25,9 +25,9 @@ public class GifFrameMetadata : IDeepCloneable
this.FrameDelay = other.FrameDelay;
this.DisposalMethod = other.DisposalMethod;
if (other.DecodedLocalColorTable.Length > 0)
if (other.LocalColorTable?.Length > 0)
{
this.DecodedLocalColorTable = other.DecodedLocalColorTable.ToArray();
this.LocalColorTable = other.LocalColorTable.Value.ToArray();
}
this.HasTransparency = other.HasTransparency;
@ -40,9 +40,9 @@ public class GifFrameMetadata : IDeepCloneable
public GifColorTableMode ColorTableMode { get; set; }
/// <summary>
/// Gets the decoded global color table, if any.
/// Gets or sets the local color table, if any.
/// </summary>
public ReadOnlyMemory<Color> DecodedLocalColorTable { get; internal set; }
public ReadOnlyMemory<Color>? LocalColorTable { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the frame has transparency

10
src/ImageSharp/Formats/Gif/GifMetadata.cs

@ -25,9 +25,9 @@ public class GifMetadata : IDeepCloneable
this.ColorTableMode = other.ColorTableMode;
this.BackgroundColor = other.BackgroundColor;
if (other.DecodedGlobalColorTable.Length > 0)
if (other.GlobalColorTable?.Length > 0)
{
this.DecodedGlobalColorTable = other.DecodedGlobalColorTable.ToArray();
this.GlobalColorTable = other.GlobalColorTable.Value.ToArray();
}
for (int i = 0; i < other.Comments.Count; i++)
@ -50,12 +50,12 @@ public class GifMetadata : IDeepCloneable
public GifColorTableMode ColorTableMode { get; set; }
/// <summary>
/// Gets the decoded global color table, if any.
/// Gets or sets the global color table, if any.
/// </summary>
public ReadOnlyMemory<Color> DecodedGlobalColorTable { get; internal set; }
public ReadOnlyMemory<Color>? GlobalColorTable { get; set; }
/// <summary>
/// Gets or sets the index at the <see cref="DecodedGlobalColorTable"/> for the background color.
/// Gets or sets the index at the <see cref="GlobalColorTable"/> for the background color.
/// The background color is the color used for those pixels on the screen that are not covered by an image.
/// </summary>
public byte BackgroundColor { get; set; }

10
tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs

@ -175,11 +175,11 @@ public class GifEncoderTests
int maxColors;
if (colorMode == GifColorTableMode.Global)
{
maxColors = metaData.DecodedGlobalColorTable.Length;
maxColors = metaData.GlobalColorTable.Value.Length;
}
else
{
maxColors = frameMetadata.DecodedLocalColorTable.Length;
maxColors = frameMetadata.LocalColorTable.Value.Length;
}
GifEncoder encoder = new()
@ -201,11 +201,11 @@ public class GifEncoderTests
colorMode = cloneMetadata.ColorTableMode;
if (colorMode == GifColorTableMode.Global)
{
maxColors = metaData.DecodedGlobalColorTable.Length;
maxColors = metaData.GlobalColorTable.Value.Length;
}
else
{
maxColors = frameMetadata.DecodedLocalColorTable.Length;
maxColors = frameMetadata.LocalColorTable.Value.Length;
}
Assert.Equal(64, maxColors);
@ -217,7 +217,7 @@ public class GifEncoderTests
if (iMeta.ColorTableMode == GifColorTableMode.Local)
{
Assert.Equal(iMeta.DecodedLocalColorTable.Length, cMeta.DecodedLocalColorTable.Length);
Assert.Equal(iMeta.LocalColorTable.Value.Length, cMeta.LocalColorTable.Value.Length);
}
Assert.Equal(iMeta.FrameDelay, cMeta.FrameDelay);

8
tests/ImageSharp.Tests/Formats/Gif/GifFrameMetadataTests.cs

@ -15,18 +15,18 @@ public class GifFrameMetadataTests
{
FrameDelay = 1,
DisposalMethod = GifDisposalMethod.RestoreToBackground,
DecodedLocalColorTable = new[] { Color.Black, Color.White }
LocalColorTable = new[] { Color.Black, Color.White }
};
GifFrameMetadata clone = (GifFrameMetadata)meta.DeepClone();
clone.FrameDelay = 2;
clone.DisposalMethod = GifDisposalMethod.RestoreToPrevious;
clone.DecodedLocalColorTable = new[] { Color.Black };
clone.LocalColorTable = new[] { Color.Black };
Assert.False(meta.FrameDelay.Equals(clone.FrameDelay));
Assert.False(meta.DisposalMethod.Equals(clone.DisposalMethod));
Assert.False(meta.DecodedLocalColorTable.Length == clone.DecodedLocalColorTable.Length);
Assert.Equal(1, clone.DecodedLocalColorTable.Length);
Assert.False(meta.LocalColorTable.Value.Length == clone.LocalColorTable.Value.Length);
Assert.Equal(1, clone.LocalColorTable.Value.Length);
}
}

10
tests/ImageSharp.Tests/Formats/Gif/GifMetadataTests.cs

@ -34,7 +34,7 @@ public class GifMetadataTests
{
RepeatCount = 1,
ColorTableMode = GifColorTableMode.Global,
DecodedGlobalColorTable = new[] { Color.Black, Color.White },
GlobalColorTable = new[] { Color.Black, Color.White },
Comments = new List<string> { "Foo" }
};
@ -42,12 +42,12 @@ public class GifMetadataTests
clone.RepeatCount = 2;
clone.ColorTableMode = GifColorTableMode.Local;
clone.DecodedGlobalColorTable = new[] { Color.Black };
clone.GlobalColorTable = new[] { Color.Black };
Assert.False(meta.RepeatCount.Equals(clone.RepeatCount));
Assert.False(meta.ColorTableMode.Equals(clone.ColorTableMode));
Assert.False(meta.DecodedGlobalColorTable.Length == clone.DecodedGlobalColorTable.Length);
Assert.Equal(1, clone.DecodedGlobalColorTable.Length);
Assert.False(meta.GlobalColorTable.Value.Length == clone.GlobalColorTable.Value.Length);
Assert.Equal(1, clone.GlobalColorTable.Value.Length);
Assert.False(meta.Comments.Equals(clone.Comments));
Assert.True(meta.Comments.SequenceEqual(clone.Comments));
}
@ -208,7 +208,7 @@ public class GifMetadataTests
if (colorTableMode == GifColorTableMode.Global)
{
Assert.Equal(globalColorTableLength, gifMetadata.DecodedGlobalColorTable.Length);
Assert.Equal(globalColorTableLength, gifMetadata.GlobalColorTable.Value.Length);
}
Assert.Equal(frameDelay, gifFrameMetadata.FrameDelay);

2
tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs

@ -318,7 +318,7 @@ public abstract partial class ImageFrameCollectionTests
if (aData.ColorTableMode == GifColorTableMode.Local && bData.ColorTableMode == GifColorTableMode.Local)
{
Assert.Equal(aData.DecodedLocalColorTable.Length, bData.DecodedLocalColorTable.Length);
Assert.Equal(aData.LocalColorTable.Value.Length, bData.LocalColorTable.Value.Length);
}
}
}

4
tests/ImageSharp.Tests/Metadata/ImageFrameMetadataTests.cs

@ -26,14 +26,14 @@ public class ImageFrameMetadataTests
ImageFrameMetadata metaData = new();
GifFrameMetadata gifFrameMetadata = metaData.GetGifMetadata();
gifFrameMetadata.FrameDelay = frameDelay;
gifFrameMetadata.DecodedLocalColorTable = Enumerable.Repeat(Color.HotPink, colorTableLength).ToArray();
gifFrameMetadata.LocalColorTable = Enumerable.Repeat(Color.HotPink, colorTableLength).ToArray();
gifFrameMetadata.DisposalMethod = disposalMethod;
ImageFrameMetadata clone = new(metaData);
GifFrameMetadata cloneGifFrameMetadata = clone.GetGifMetadata();
Assert.Equal(frameDelay, cloneGifFrameMetadata.FrameDelay);
Assert.Equal(colorTableLength, cloneGifFrameMetadata.DecodedLocalColorTable.Length);
Assert.Equal(colorTableLength, cloneGifFrameMetadata.LocalColorTable.Value.Length);
Assert.Equal(disposalMethod, cloneGifFrameMetadata.DisposalMethod);
}

2
tests/ImageSharp.Tests/TestImages.cs

@ -482,6 +482,8 @@ public static class TestImages
public const string Issue2288_B = "Gif/issues/issue_2288_2.gif";
public const string Issue2288_C = "Gif/issues/issue_2288_3.gif";
public const string Issue2288_D = "Gif/issues/issue_2288_4.gif";
public const string Issue2450 = "Gif/issues/issue_2450.gif";
public const string Issue2198 = "Gif/issues/issue_2198.gif";
}
public static readonly string[] All = { Rings, Giphy, Cheers, Trans, Kumin, Leo, Ratio4x1, Ratio1x4 };

Loading…
Cancel
Save