Browse Source

Ensure frame metadata is a deep copy.

pull/707/head
James Jackson-South 8 years ago
parent
commit
48d9d7713b
  1. 23
      src/ImageSharp/Formats/Gif/GifFrameMetaData.cs
  2. 31
      src/ImageSharp/IDeepCloneable.cs
  3. 4
      src/ImageSharp/ImageFrame{TPixel}.cs
  4. 20
      src/ImageSharp/MetaData/ImageFrameMetaData.cs
  5. 2
      src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs
  6. 2
      src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs
  7. 2
      src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs
  8. 2
      src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs

23
src/ImageSharp/Formats/Gif/GifFrameMetaData.cs

@ -6,8 +6,26 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary>
/// Provides Gif specific metadata information for the image frame.
/// </summary>
public class GifFrameMetaData
public class GifFrameMetaData : IDeepCloneable
{
/// <summary>
/// Initializes a new instance of the <see cref="GifFrameMetaData"/> class.
/// </summary>
public GifFrameMetaData()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="GifFrameMetaData"/> class.
/// </summary>
/// <param name="other">The metadata to create an instance from.</param>
internal GifFrameMetaData(GifFrameMetaData other)
{
this.ColorTableLength = other.ColorTableLength;
this.FrameDelay = other.FrameDelay;
this.DisposalMethod = other.DisposalMethod;
}
/// <summary>
/// Gets or sets the length of the color table for paletted images.
/// If not 0, then this field indicates the maximum number of colors to use when quantizing the
@ -29,5 +47,8 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// be treated after being displayed.
/// </summary>
public GifDisposalMethod DisposalMethod { get; set; }
/// <inheritdoc/>
public IDeepCloneable DeepClone() => new GifFrameMetaData(this);
}
}

31
src/ImageSharp/IDeepCloneable.cs

@ -0,0 +1,31 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp
{
/// <summary>
/// A generic interface for a deeply cloneable type.
/// </summary>
/// <typeparam name="T">The type of object to clone.</typeparam>
public interface IDeepCloneable<T>
where T : class, IDeepCloneable<T>
{
/// <summary>
/// Creates a new <typeparamref name="T"/> that is a deep copy of the current instance.
/// </summary>
/// <returns>The <typeparamref name="T"/>.</returns>
T DeepClone();
}
/// <summary>
/// An interface for objects that can be cloned. This creates a deep copy of the object.
/// </summary>
public interface IDeepCloneable
{
/// <summary>
/// Creates a new object that is a deep copy of the current instance.
/// </summary>
/// <returns>The <see cref="IDeepCloneable"/>.</returns>
IDeepCloneable DeepClone();
}
}

4
src/ImageSharp/ImageFrame{TPixel}.cs

@ -135,7 +135,7 @@ namespace SixLabors.ImageSharp
this.MemoryAllocator = configuration.MemoryAllocator;
this.PixelBuffer = this.MemoryAllocator.Allocate2D<TPixel>(source.PixelBuffer.Width, source.PixelBuffer.Height);
source.PixelBuffer.GetSpan().CopyTo(this.PixelBuffer.GetSpan());
this.MetaData = source.MetaData.Clone();
this.MetaData = source.MetaData.DeepClone();
}
/// <summary>
@ -260,7 +260,7 @@ namespace SixLabors.ImageSharp
return this.Clone() as ImageFrame<TPixel2>;
}
var target = new ImageFrame<TPixel2>(this.configuration, this.Width, this.Height, this.MetaData.Clone());
var target = new ImageFrame<TPixel2>(this.configuration, this.Width, this.Height, this.MetaData.DeepClone());
ParallelFor.WithTemporaryBuffer(
0,

20
src/ImageSharp/MetaData/ImageFrameMetaData.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Collections.Generic;
using SixLabors.ImageSharp.Formats;
@ -10,9 +9,9 @@ namespace SixLabors.ImageSharp.MetaData
/// <summary>
/// Encapsulates the metadata of an image frame.
/// </summary>
public sealed class ImageFrameMetaData
public sealed class ImageFrameMetaData : IDeepCloneable<ImageFrameMetaData>
{
private readonly Dictionary<IImageFormat, object> formatMetaData = new Dictionary<IImageFormat, object>();
private readonly Dictionary<IImageFormat, IDeepCloneable> formatMetaData = new Dictionary<IImageFormat, IDeepCloneable>();
/// <summary>
/// Initializes a new instance of the <see cref="ImageFrameMetaData"/> class.
@ -32,17 +31,14 @@ namespace SixLabors.ImageSharp.MetaData
{
DebugGuard.NotNull(other, nameof(other));
foreach (KeyValuePair<IImageFormat, object> meta in other.formatMetaData)
foreach (KeyValuePair<IImageFormat, IDeepCloneable> meta in other.formatMetaData)
{
this.formatMetaData.Add(meta.Key, meta.Value);
this.formatMetaData.Add(meta.Key, meta.Value.DeepClone());
}
}
/// <summary>
/// Clones this ImageFrameMetaData.
/// </summary>
/// <returns>The cloned instance.</returns>
public ImageFrameMetaData Clone() => new ImageFrameMetaData(this);
/// <inheritdoc/>
public ImageFrameMetaData DeepClone() => new ImageFrameMetaData(this);
/// <summary>
/// Gets the metadata value associated with the specified key.
@ -55,9 +51,9 @@ namespace SixLabors.ImageSharp.MetaData
/// </returns>
public TFormatFrameMetaData GetFormatMetaData<TFormatMetaData, TFormatFrameMetaData>(IImageFormat<TFormatMetaData, TFormatFrameMetaData> key)
where TFormatMetaData : class
where TFormatFrameMetaData : class
where TFormatFrameMetaData : class, IDeepCloneable
{
if (this.formatMetaData.TryGetValue(key, out object meta))
if (this.formatMetaData.TryGetValue(key, out IDeepCloneable meta))
{
return (TFormatFrameMetaData)meta;
}

2
src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs

@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
// We will always be creating the clone even for mutate because we may need to resize the canvas
IEnumerable<ImageFrame<TPixel>> frames =
source.Frames.Select(x => new ImageFrame<TPixel>(source.GetConfiguration(), this.TargetDimensions, x.MetaData.Clone()));
source.Frames.Select(x => new ImageFrame<TPixel>(source.GetConfiguration(), this.TargetDimensions, x.MetaData.DeepClone()));
// Use the overload to prevent an extra frame being added
return new Image<TPixel>(source.GetConfiguration(), source.MetaData.Clone(), frames);

2
src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs

@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
protected override Image<TPixel> CreateDestination(Image<TPixel> source, Rectangle sourceRectangle)
{
// We will always be creating the clone even for mutate because we may need to resize the canvas
IEnumerable<ImageFrame<TPixel>> frames = source.Frames.Select(x => new ImageFrame<TPixel>(source.GetConfiguration(), this.CropRectangle.Width, this.CropRectangle.Height, x.MetaData.Clone()));
IEnumerable<ImageFrame<TPixel>> frames = source.Frames.Select(x => new ImageFrame<TPixel>(source.GetConfiguration(), this.CropRectangle.Width, this.CropRectangle.Height, x.MetaData.DeepClone()));
// Use the overload to prevent an extra frame being added
return new Image<TPixel>(source.GetConfiguration(), source.MetaData.Clone(), frames);

2
src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs

@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
// We will always be creating the clone even for mutate because we may need to resize the canvas
IEnumerable<ImageFrame<TPixel>> frames =
source.Frames.Select(x => new ImageFrame<TPixel>(source.GetConfiguration(), this.TargetDimensions.Width, this.TargetDimensions.Height, x.MetaData.Clone()));
source.Frames.Select(x => new ImageFrame<TPixel>(source.GetConfiguration(), this.TargetDimensions.Width, this.TargetDimensions.Height, x.MetaData.DeepClone()));
// Use the overload to prevent an extra frame being added
return new Image<TPixel>(source.GetConfiguration(), source.MetaData.Clone(), frames);

2
src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs

@ -215,7 +215,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
protected override Image<TPixel> CreateDestination(Image<TPixel> source, Rectangle sourceRectangle)
{
// We will always be creating the clone even for mutate because we may need to resize the canvas
IEnumerable<ImageFrame<TPixel>> frames = source.Frames.Select(x => new ImageFrame<TPixel>(source.GetConfiguration(), this.Width, this.Height, x.MetaData.Clone()));
IEnumerable<ImageFrame<TPixel>> frames = source.Frames.Select(x => new ImageFrame<TPixel>(source.GetConfiguration(), this.Width, this.Height, x.MetaData.DeepClone()));
// Use the overload to prevent an extra frame being added
return new Image<TPixel>(source.GetConfiguration(), source.MetaData.Clone(), frames);

Loading…
Cancel
Save