mirror of https://github.com/SixLabors/ImageSharp
85 changed files with 788 additions and 792 deletions
@ -1,21 +0,0 @@ |
|||||
// Copyright (c) Six Labors and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
|
|
||||
using System; |
|
||||
using SixLabors.ImageSharp.PixelFormats; |
|
||||
|
|
||||
namespace SixLabors.ImageSharp.Advanced |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Allows access to the pixels as an area of contiguous memory in the given pixel format.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
|
|
||||
internal interface IPixelSource<TPixel> |
|
||||
where TPixel : struct, IPixel<TPixel> |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets the representation of the pixels as an area of contiguous memory in the given pixel format.
|
|
||||
/// </summary>
|
|
||||
Span<TPixel> Span { get; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,19 +0,0 @@ |
|||||
// Copyright (c) Six Labors and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
|
|
||||
using SixLabors.ImageSharp.Formats; |
|
||||
using SixLabors.ImageSharp.MetaData; |
|
||||
|
|
||||
namespace SixLabors.ImageSharp |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Encapsulates the basic properties and methods required to manipulate images.
|
|
||||
/// </summary>
|
|
||||
internal interface IImage : IImageBase |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets the meta data of the image.
|
|
||||
/// </summary>
|
|
||||
ImageMetaData MetaData { get; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,28 +0,0 @@ |
|||||
// Copyright (c) Six Labors and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
|
|
||||
using SixLabors.Primitives; |
|
||||
|
|
||||
namespace SixLabors.ImageSharp |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Encapsulates the basic properties and methods required to manipulate images.
|
|
||||
/// </summary>
|
|
||||
public interface IImageBase |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets the width in pixels.
|
|
||||
/// </summary>
|
|
||||
int Width { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the height in pixels.
|
|
||||
/// </summary>
|
|
||||
int Height { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the configuration providing initialization code which allows extending the library.
|
|
||||
/// </summary>
|
|
||||
Configuration Configuration { get; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,18 +1,50 @@ |
|||||
// Copyright (c) Six Labors and contributors.
|
// Copyright (c) Six Labors and contributors.
|
||||
// Licensed under the Apache License, Version 2.0.
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
using SixLabors.ImageSharp.Advanced; |
||||
|
using SixLabors.ImageSharp.Memory; |
||||
using SixLabors.ImageSharp.MetaData; |
using SixLabors.ImageSharp.MetaData; |
||||
|
using SixLabors.ImageSharp.PixelFormats; |
||||
|
|
||||
namespace SixLabors.ImageSharp |
namespace SixLabors.ImageSharp |
||||
{ |
{ |
||||
/// <summary>
|
/// <summary>
|
||||
/// Encapsulates the basic properties and methods required to manipulate images.
|
/// Encapsulates the basic properties and methods required to manipulate images.
|
||||
/// </summary>
|
/// </summary>
|
||||
internal interface IImageFrame : IImageBase |
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
|
||||
|
internal interface IImageFrame<TPixel> : IImageFrame |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets the parent.
|
||||
|
/// </summary>
|
||||
|
Image<TPixel> Parent { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the pixel buffer.
|
||||
|
/// </summary>
|
||||
|
Buffer2D<TPixel> PixelBuffer { get; } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Encapsulates the basic properties and methods required to manipulate images.
|
||||
|
/// </summary>
|
||||
|
public interface IImageFrame : IDisposable |
||||
{ |
{ |
||||
/// <summary>
|
/// <summary>
|
||||
/// Gets the meta data of the image.
|
/// Gets the meta data of the image.
|
||||
/// </summary>
|
/// </summary>
|
||||
ImageFrameMetaData MetaData { get; } |
ImageFrameMetaData MetaData { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the width.
|
||||
|
/// </summary>
|
||||
|
int Width { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the height.
|
||||
|
/// </summary>
|
||||
|
int Height { get; } |
||||
} |
} |
||||
} |
} |
||||
@ -1,333 +0,0 @@ |
|||||
// Copyright (c) Six Labors and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
|
|
||||
using System; |
|
||||
using System.Diagnostics; |
|
||||
using System.Runtime.CompilerServices; |
|
||||
using SixLabors.ImageSharp.Advanced; |
|
||||
using SixLabors.ImageSharp.Memory; |
|
||||
using SixLabors.ImageSharp.PixelFormats; |
|
||||
using SixLabors.ImageSharp.Processing; |
|
||||
using SixLabors.Primitives; |
|
||||
|
|
||||
namespace SixLabors.ImageSharp |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The base class of all images. Encapsulates the basic properties and methods required to manipulate
|
|
||||
/// images in different pixel formats.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|
||||
public abstract class ImageBase<TPixel> : IImageBase, IDisposable, IPixelSource<TPixel> |
|
||||
where TPixel : struct, IPixel<TPixel> |
|
||||
{ |
|
||||
#pragma warning disable SA1401 // Fields must be private
|
|
||||
/// <summary>
|
|
||||
/// The image pixels. Not private as Buffer2D requires an array in its constructor.
|
|
||||
/// </summary>
|
|
||||
internal TPixel[] PixelBuffer; |
|
||||
#pragma warning restore SA1401 // Fields must be private
|
|
||||
|
|
||||
/// <summary>
|
|
||||
/// A value indicating whether this instance of the given entity has been disposed.
|
|
||||
/// </summary>
|
|
||||
/// <value><see langword="true"/> if this instance has been disposed; otherwise, <see langword="false"/>.</value>
|
|
||||
/// <remarks>
|
|
||||
/// If the entity is disposed, it must not be disposed a second time. The isDisposed field is set the first time the entity
|
|
||||
/// is disposed. If the isDisposed field is true, then the Dispose() method will not dispose again. This help not to prolong the entity's
|
|
||||
/// life in the Garbage Collector.
|
|
||||
/// </remarks>
|
|
||||
private bool isDisposed; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="ImageBase{TPixel}"/> class.
|
|
||||
/// </summary>
|
|
||||
/// <param name="configuration">
|
|
||||
/// The configuration providing initialization code which allows extending the library.
|
|
||||
/// </param>
|
|
||||
protected ImageBase(Configuration configuration) |
|
||||
{ |
|
||||
this.Configuration = configuration ?? Configuration.Default; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="ImageBase{TPixel}"/> class.
|
|
||||
/// </summary>
|
|
||||
/// <param name="configuration">
|
|
||||
/// The configuration providing initialization code which allows extending the library.
|
|
||||
/// </param>
|
|
||||
/// <param name="width">The width of the image in pixels.</param>
|
|
||||
/// <param name="height">The height of the image in pixels.</param>
|
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
|
||||
/// Thrown if either <paramref name="width"/> or <paramref name="height"/> are less than or equal to 0.
|
|
||||
/// </exception>
|
|
||||
protected ImageBase(Configuration configuration, int width, int height) |
|
||||
: this(configuration) |
|
||||
{ |
|
||||
Guard.MustBeGreaterThan(width, 0, nameof(width)); |
|
||||
Guard.MustBeGreaterThan(height, 0, nameof(height)); |
|
||||
|
|
||||
this.Width = width; |
|
||||
this.Height = height; |
|
||||
this.RentPixels(); |
|
||||
this.ClearPixels(); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="ImageBase{TPixel}"/> class.
|
|
||||
/// </summary>
|
|
||||
/// <param name="other">
|
|
||||
/// The other <see cref="ImageBase{TPixel}"/> to create this instance from.
|
|
||||
/// </param>
|
|
||||
/// <exception cref="System.ArgumentNullException">
|
|
||||
/// Thrown if the given <see cref="ImageBase{TPixel}"/> is null.
|
|
||||
/// </exception>
|
|
||||
protected ImageBase(ImageBase<TPixel> other) |
|
||||
: this(other.Configuration) |
|
||||
{ |
|
||||
Guard.NotNull(other, nameof(other), "Other image cannot be null."); |
|
||||
|
|
||||
this.Width = other.Width; |
|
||||
this.Height = other.Height; |
|
||||
this.CopyProperties(other); |
|
||||
|
|
||||
// Rent then copy the pixels. Unsafe.CopyBlock gives us a nice speed boost here.
|
|
||||
this.RentPixels(); |
|
||||
|
|
||||
other.GetPixelSpan().CopyTo(this.GetPixelSpan()); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
Span<TPixel> IPixelSource<TPixel>.Span => new Span<TPixel>(this.PixelBuffer, 0, this.Width * this.Height); |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public int Width { get; private set; } |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public int Height { get; private set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the configuration providing initialization code which allows extending the library.
|
|
||||
/// </summary>
|
|
||||
public Configuration Configuration { get; private set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the pixel at the specified position.
|
|
||||
/// </summary>
|
|
||||
/// <param name="x">The x-coordinate of the pixel. Must be greater than or equal to zero and less than the width of the image.</param>
|
|
||||
/// <param name="y">The y-coordinate of the pixel. Must be greater than or equal to zero and less than the height of the image.</param>
|
|
||||
/// <returns>The <see typeparam="TPixel"/> at the specified position.</returns>
|
|
||||
public TPixel this[int x, int y] |
|
||||
{ |
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
||||
get |
|
||||
{ |
|
||||
this.CheckCoordinates(x, y); |
|
||||
return this.PixelBuffer[(y * this.Width) + x]; |
|
||||
} |
|
||||
|
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
||||
set |
|
||||
{ |
|
||||
this.CheckCoordinates(x, y); |
|
||||
this.PixelBuffer[(y * this.Width) + x] = value; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets a reference to the pixel at the specified position.
|
|
||||
/// </summary>
|
|
||||
/// <param name="x">The x-coordinate of the pixel. Must be greater than or equal to zero and less than the width of the image.</param>
|
|
||||
/// <param name="y">The y-coordinate of the pixel. Must be greater than or equal to zero and less than the height of the image.</param>
|
|
||||
/// <returns>The <see typeparam="TPixel"/> at the specified position.</returns>
|
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
||||
internal ref TPixel GetPixelReference(int x, int y) |
|
||||
{ |
|
||||
this.CheckCoordinates(x, y); |
|
||||
return ref this.PixelBuffer[(y * this.Width) + x]; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Clones the image
|
|
||||
/// </summary>
|
|
||||
/// <returns>A new items which is a clone of the original.</returns>
|
|
||||
public ImageBase<TPixel> Clone() |
|
||||
{ |
|
||||
return this.CloneImageBase(); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc />
|
|
||||
public void Dispose() |
|
||||
{ |
|
||||
this.Dispose(true); |
|
||||
|
|
||||
// This object will be cleaned up by the Dispose method.
|
|
||||
// Therefore, you should call GC.SuppressFinalize to
|
|
||||
// take this object off the finalization queue
|
|
||||
// and prevent finalization code for this object
|
|
||||
// from executing a second time.
|
|
||||
GC.SuppressFinalize(this); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Locks the image providing access to the pixels.
|
|
||||
/// <remarks>
|
|
||||
/// It is imperative that the accessor is correctly disposed off after use.
|
|
||||
/// </remarks>
|
|
||||
/// </summary>
|
|
||||
/// <returns>The <see cref="PixelAccessor{TPixel}"/></returns>
|
|
||||
internal PixelAccessor<TPixel> Lock() |
|
||||
{ |
|
||||
return new PixelAccessor<TPixel>(this); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Copies the pixels to another <see cref="PixelAccessor{TPixel}"/> of the same size.
|
|
||||
/// </summary>
|
|
||||
/// <param name="target">The target pixel buffer accessor.</param>
|
|
||||
internal void CopyTo(PixelAccessor<TPixel> target) |
|
||||
{ |
|
||||
SpanHelper.Copy(this.GetPixelSpan(), target.PixelBuffer.Span); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Switches the buffers used by the image and the PixelAccessor meaning that the Image will "own" the buffer from the PixelAccessor and the PixelAccessor will now own the Images buffer.
|
|
||||
/// </summary>
|
|
||||
/// <param name="pixelSource">The pixel source.</param>
|
|
||||
internal void SwapPixelsBuffers(PixelAccessor<TPixel> pixelSource) |
|
||||
{ |
|
||||
Guard.NotNull(pixelSource, nameof(pixelSource)); |
|
||||
|
|
||||
int newWidth = pixelSource.Width; |
|
||||
int newHeight = pixelSource.Height; |
|
||||
|
|
||||
// Push my memory into the accessor (which in turn unpins the old buffer ready for the images use)
|
|
||||
TPixel[] newPixels = pixelSource.ReturnCurrentColorsAndReplaceThemInternally(this.Width, this.Height, this.PixelBuffer); |
|
||||
this.Width = newWidth; |
|
||||
this.Height = newHeight; |
|
||||
this.PixelBuffer = newPixels; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Switches the buffers used by the image and the pixelSource meaning that the Image will "own" the buffer from the pixelSource and the pixelSource will now own the Images buffer.
|
|
||||
/// </summary>
|
|
||||
/// <param name="pixelSource">The pixel source.</param>
|
|
||||
internal void SwapPixelsData(ImageBase<TPixel> pixelSource) |
|
||||
{ |
|
||||
Guard.NotNull(pixelSource, nameof(pixelSource)); |
|
||||
|
|
||||
int newWidth = pixelSource.Width; |
|
||||
int newHeight = pixelSource.Height; |
|
||||
TPixel[] newPixels = pixelSource.PixelBuffer; |
|
||||
|
|
||||
pixelSource.PixelBuffer = this.PixelBuffer; |
|
||||
pixelSource.Width = this.Width; |
|
||||
pixelSource.Height = this.Height; |
|
||||
|
|
||||
this.Width = newWidth; |
|
||||
this.Height = newHeight; |
|
||||
this.PixelBuffer = newPixels; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Clones the image
|
|
||||
/// </summary>
|
|
||||
/// <returns>A new items which is a clone of the original.</returns>
|
|
||||
protected abstract ImageBase<TPixel> CloneImageBase(); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Copies the properties from the other <see cref="IImageBase"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="other">
|
|
||||
/// The other <see cref="IImageBase"/> to copy the properties from.
|
|
||||
/// </param>
|
|
||||
protected void CopyProperties(IImageBase other) |
|
||||
{ |
|
||||
DebugGuard.NotNull(other, nameof(other)); |
|
||||
|
|
||||
this.Configuration = other.Configuration; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Disposes the object and frees resources for the Garbage Collector.
|
|
||||
/// </summary>
|
|
||||
/// <param name="disposing">If true, the object gets disposed.</param>
|
|
||||
protected virtual void Dispose(bool disposing) |
|
||||
{ |
|
||||
if (this.isDisposed) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
if (disposing) |
|
||||
{ |
|
||||
this.ReturnPixels(); |
|
||||
} |
|
||||
|
|
||||
// Note disposing is done.
|
|
||||
this.isDisposed = true; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Rents the pixel array from the pool.
|
|
||||
/// </summary>
|
|
||||
private void RentPixels() |
|
||||
{ |
|
||||
this.PixelBuffer = PixelDataPool<TPixel>.Rent(this.Width * this.Height); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Returns the rented pixel array back to the pool.
|
|
||||
/// </summary>
|
|
||||
private void ReturnPixels() |
|
||||
{ |
|
||||
PixelDataPool<TPixel>.Return(this.PixelBuffer); |
|
||||
this.PixelBuffer = null; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Clears the pixel array.
|
|
||||
/// </summary>
|
|
||||
private void ClearPixels() |
|
||||
{ |
|
||||
Array.Clear(this.PixelBuffer, 0, this.Width * this.Height); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Checks the coordinates to ensure they are within bounds.
|
|
||||
/// </summary>
|
|
||||
/// <param name="y">The y-coordinate of the pixel. Must be greater than zero and less than the height of the image.</param>
|
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
|
||||
/// Thrown if the coordinates are not within the bounds of the image.
|
|
||||
/// </exception>
|
|
||||
[Conditional("DEBUG")] |
|
||||
private void CheckCoordinates(int y) |
|
||||
{ |
|
||||
if (y < 0 || y >= this.Height) |
|
||||
{ |
|
||||
throw new ArgumentOutOfRangeException(nameof(y), y, $"{y} is outwith the image bounds."); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Checks the coordinates to ensure they are within bounds.
|
|
||||
/// </summary>
|
|
||||
/// <param name="x">The x-coordinate of the pixel. Must be greater than zero and less than the width of the image.</param>
|
|
||||
/// <param name="y">The y-coordinate of the pixel. Must be greater than zero and less than the height of the image.</param>
|
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
|
||||
/// Thrown if the coordinates are not within the bounds of the image.
|
|
||||
/// </exception>
|
|
||||
[Conditional("DEBUG")] |
|
||||
private void CheckCoordinates(int x, int y) |
|
||||
{ |
|
||||
if (x < 0 || x >= this.Width) |
|
||||
{ |
|
||||
throw new ArgumentOutOfRangeException(nameof(x), x, $"{x} is outwith the image bounds."); |
|
||||
} |
|
||||
|
|
||||
if (y < 0 || y >= this.Height) |
|
||||
{ |
|
||||
throw new ArgumentOutOfRangeException(nameof(y), y, $"{y} is outwith the image bounds."); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,148 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Diagnostics; |
||||
|
using System.IO; |
||||
|
using System.Numerics; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
using SixLabors.ImageSharp.Formats; |
||||
|
using SixLabors.ImageSharp.MetaData; |
||||
|
using SixLabors.ImageSharp.PixelFormats; |
||||
|
using SixLabors.ImageSharp.Processing; |
||||
|
using SixLabors.Primitives; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Encapsulates an imaged collection of frames.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
|
||||
|
public sealed class ImageFrameCollection<TPixel> : IEnumerable<ImageFrame<TPixel>> |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
private IList<ImageFrame<TPixel>> frames = new List<ImageFrame<TPixel>>(); |
||||
|
private readonly Image<TPixel> parent; |
||||
|
|
||||
|
internal ImageFrameCollection(Image<TPixel> parent) |
||||
|
{ |
||||
|
this.parent = parent; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the count.
|
||||
|
/// </summary>
|
||||
|
public int Count { get => this.frames.Count; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the <see cref="ImageFrame{TPixel}"/> at the specified index.
|
||||
|
/// </summary>
|
||||
|
/// <value>
|
||||
|
/// The <see cref="ImageFrame{TPixel}"/>.
|
||||
|
/// </value>
|
||||
|
/// <param name="index">The index.</param>
|
||||
|
/// <returns>The <see cref="ImageFrame{TPixel}"/> at the specified index.</returns>
|
||||
|
public ImageFrame<TPixel> this[int index] |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
return this.frames[index]; |
||||
|
} |
||||
|
|
||||
|
set |
||||
|
{ |
||||
|
this.ValidateFrameSize(value); |
||||
|
this.frames[index] = value; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Determines the index of a specific <paramref name="frame"/> in the <seealso cref="Image{TPixel}"/>.
|
||||
|
/// </summary>
|
||||
|
/// <param name="frame">The <seealso cref="ImageFrame{TPixel}"/> to locate in the <seealso cref="Image{TPixel}"/>.</param>
|
||||
|
/// <returns>The index of item if found in the list; otherwise, -1.</returns>
|
||||
|
public int IndexOf(ImageFrame<TPixel> frame) => this.frames.IndexOf(frame); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Inserts the <paramref name="frame"/> to the <seealso cref="Image{TPixel}"/> at the specified <paramref name="index"/>.
|
||||
|
/// </summary>
|
||||
|
/// <param name="index"> The zero-based index at which item should be inserted..</param>
|
||||
|
/// <param name="frame">The <seealso cref="ImageFrame{TPixel}"/> to insert into the <seealso cref="Image{TPixel}"/>.</param>
|
||||
|
public void Insert(int index, ImageFrame<TPixel> frame) |
||||
|
{ |
||||
|
this.ValidateFrameSize(frame); |
||||
|
this.frames.Insert(index, frame); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Removes the <seealso cref="ImageFrame{TPixel}"/> from the <seealso cref="Image{TPixel}"/> at the specified index.
|
||||
|
/// </summary>
|
||||
|
/// <param name="index">The zero-based index of the item to remove.</param>
|
||||
|
/// <exception cref="InvalidOperationException">Cannot remove last frame.</exception>
|
||||
|
public void RemoveAt(int index) |
||||
|
{ |
||||
|
if (index > 0 || this.frames.Count > 1) |
||||
|
{ |
||||
|
this.frames.RemoveAt(index); |
||||
|
} |
||||
|
|
||||
|
throw new InvalidOperationException("Cannot remove last frame."); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Adds the specified frame.
|
||||
|
/// </summary>
|
||||
|
/// <param name="frame">The frame.</param>
|
||||
|
/// <exception cref="ArgumentException">Frame must have the same dimensions as the image - frame</exception>
|
||||
|
public void Add(ImageFrame<TPixel> frame) |
||||
|
{ |
||||
|
this.ValidateFrameSize(frame); |
||||
|
this.frames.Add(frame); |
||||
|
} |
||||
|
|
||||
|
private void ValidateFrameSize(ImageFrame<TPixel> frame) |
||||
|
{ |
||||
|
if (this.parent.Width != frame.Width || this.parent.Height != frame.Height) |
||||
|
{ |
||||
|
throw new ArgumentException("Frame must have the same dimensions as the image", nameof(frame)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Determines whether the <seealso cref="Image{TPixel}"/> contains the <paramref name="frame"/>.
|
||||
|
/// </summary>
|
||||
|
/// <param name="frame">The frame.</param>
|
||||
|
/// <returns>
|
||||
|
/// <c>true</c> if the <seealso cref="Image{TPixel}"/> the specified frame; otherwise, <c>false</c>.
|
||||
|
/// </returns>
|
||||
|
public bool Contains(ImageFrame<TPixel> frame) |
||||
|
{ |
||||
|
return this.frames.Contains(frame); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Removes the specified frame.
|
||||
|
/// </summary>
|
||||
|
/// <param name="frame">The frame.</param>
|
||||
|
/// <returns>true if item is found in the <seealso cref="Image{TPixel}"/>; otherwise,</returns>
|
||||
|
/// <exception cref="InvalidOperationException">Cannot remove last frame</exception>
|
||||
|
public bool Remove(ImageFrame<TPixel> frame) |
||||
|
{ |
||||
|
if (this.frames.Count == 1 && this.frames.Contains(frame)) |
||||
|
{ |
||||
|
throw new InvalidOperationException("Cannot remove last frame"); |
||||
|
} |
||||
|
|
||||
|
return this.frames.Remove(frame); |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
IEnumerator<ImageFrame<TPixel>> IEnumerable<ImageFrame<TPixel>>.GetEnumerator() => this.frames.GetEnumerator(); |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this.frames).GetEnumerator(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Diagnostics; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using System.Threading.Tasks; |
||||
|
using SixLabors.ImageSharp.Memory; |
||||
|
using SixLabors.ImageSharp.PixelFormats; |
||||
|
using Unsafe = System.Runtime.CompilerServices.Unsafe; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Helper methods fro acccess pixel accessors
|
||||
|
/// </summary>
|
||||
|
internal static class PixelAccessorExtensions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Locks the image providing access to the pixels.
|
||||
|
/// <remarks>
|
||||
|
/// It is imperative that the accessor is correctly disposed off after use.
|
||||
|
/// </remarks>
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
|
||||
|
/// <param name="frame">The frame.</param>
|
||||
|
/// <returns>
|
||||
|
/// The <see cref="PixelAccessor{TPixel}" />
|
||||
|
/// </returns>
|
||||
|
internal static PixelAccessor<TPixel> Lock<TPixel>(this IImageFrame<TPixel> frame) |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
return new PixelAccessor<TPixel>(frame); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue