mirror of https://github.com/SixLabors/ImageSharp
12 changed files with 480 additions and 33 deletions
@ -0,0 +1,42 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Common.Helpers; |
|||
|
|||
/// <summary>
|
|||
/// Dictionary of <see cref="IDisposable"/> objects, which is itself <see cref="IDisposable"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="TKey">The type of the key.</typeparam>
|
|||
/// <typeparam name="TValue">Tye type of value, needs to implement <see cref="IDisposable"/>.</typeparam>
|
|||
public sealed class DisposableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IDisposable |
|||
where TKey : notnull |
|||
where TValue : IDisposable |
|||
{ |
|||
private bool disposedValue; |
|||
|
|||
/// <inheritdoc />
|
|||
public void Dispose() |
|||
{ |
|||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
|||
this.Dispose(disposing: true); |
|||
GC.SuppressFinalize(this); |
|||
} |
|||
|
|||
private void Dispose(bool disposing) |
|||
{ |
|||
if (!this.disposedValue) |
|||
{ |
|||
if (disposing) |
|||
{ |
|||
foreach (KeyValuePair<TKey, TValue> pair in this) |
|||
{ |
|||
pair.Value?.Dispose(); |
|||
} |
|||
} |
|||
|
|||
this.Clear(); |
|||
this.disposedValue = true; |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Common.Helpers; |
|||
|
|||
/// <summary>
|
|||
/// List of <see cref="IDisposable"/> objects, which is itself <see cref="IDisposable"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="TValue">Tye type of value, needs to implement <see cref="IDisposable"/>.</typeparam>
|
|||
public sealed class DisposableList<TValue> : List<TValue>, IDisposable |
|||
where TValue : IDisposable |
|||
{ |
|||
private bool disposedValue; |
|||
|
|||
/// <inheritdoc />
|
|||
public void Dispose() |
|||
{ |
|||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
|||
this.Dispose(disposing: true); |
|||
GC.SuppressFinalize(this); |
|||
} |
|||
|
|||
private void Dispose(bool disposing) |
|||
{ |
|||
if (!this.disposedValue) |
|||
{ |
|||
if (disposing) |
|||
{ |
|||
foreach (TValue item in this) |
|||
{ |
|||
item?.Dispose(); |
|||
} |
|||
} |
|||
|
|||
this.Clear(); |
|||
this.disposedValue = true; |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using SixLabors.ImageSharp.Formats.Heif.Av1; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif; |
|||
|
|||
/// <summary>
|
|||
/// Decoder for a single <see cref="HeifItem"/> into a AVIF image.
|
|||
/// </summary>
|
|||
internal class Av1HeifItemDecoder<TPixel> : IHeifItemDecoder<TPixel> |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the item type this decoder decodes, which is <see cref="Heif4CharCode.Av01"/>.
|
|||
/// </summary>
|
|||
public Heif4CharCode Type => Heif4CharCode.Av01; |
|||
|
|||
/// <summary>
|
|||
/// Gets the compression method this doceder uses, which is <see cref="HeifCompressionMethod.Av1"/>.
|
|||
/// </summary>
|
|||
public HeifCompressionMethod CompressionMethod => HeifCompressionMethod.Av1; |
|||
|
|||
/// <summary>
|
|||
/// Decode the specified item as AVIF.
|
|||
/// </summary>
|
|||
public Image<TPixel> DecodeItemData(Configuration configuration, HeifItem item, Span<byte> data) |
|||
{ |
|||
Av1Decoder decoder = new(configuration); |
|||
return decoder.Decode<TPixel>(data); |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif; |
|||
|
|||
/// <summary>
|
|||
/// Factory for item decoders inside the HEIF container format.
|
|||
/// </summary>
|
|||
internal class HeifCompressionFactory |
|||
{ |
|||
/// <summary>
|
|||
/// Get a decoder implementation.
|
|||
/// </summary>
|
|||
public static IHeifItemDecoder<TPixel>? GetDecoder<TPixel>(Heif4CharCode type) |
|||
where TPixel : unmanaged, IPixel<TPixel> => type switch |
|||
{ |
|||
Heif4CharCode.Jpeg => new JpegHeifItemDecoder<TPixel>(), |
|||
Heif4CharCode.Av01 => new Av1HeifItemDecoder<TPixel>(), |
|||
_ => null |
|||
}; |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif; |
|||
|
|||
internal class HeifLocationComparer : IComparer<HeifLocation> |
|||
{ |
|||
private readonly long positionOfMediaData; |
|||
private readonly long positionOfItem; |
|||
|
|||
public HeifLocationComparer(long positionOfMediaData, long positionOfItem) |
|||
{ |
|||
this.positionOfMediaData = positionOfMediaData; |
|||
this.positionOfItem = positionOfItem; |
|||
} |
|||
|
|||
public int Compare(HeifLocation? x, HeifLocation? y) |
|||
{ |
|||
if (x == null) |
|||
{ |
|||
if (y == null) |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
if (y == null) |
|||
{ |
|||
return -1; |
|||
} |
|||
|
|||
long xPos = x.GetStreamPosition(this.positionOfMediaData, this.positionOfItem); |
|||
long yPos = y.GetStreamPosition(this.positionOfMediaData, this.positionOfItem); |
|||
|
|||
return Math.Sign(xPos - yPos); |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif; |
|||
|
|||
/// <summary>
|
|||
/// Decoder for a single <see cref="HeifItem"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel type to use.</typeparam>
|
|||
internal interface IHeifItemDecoder<TPixel> |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the type of item this decoder can decode.
|
|||
/// </summary>
|
|||
public Heif4CharCode Type { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the <see cref="HeifCompressionMethod"/> tis decoder uses.
|
|||
/// </summary>
|
|||
public HeifCompressionMethod CompressionMethod { get; } |
|||
|
|||
/// <summary>
|
|||
/// Decode the specified item, given encoded data.
|
|||
/// </summary>
|
|||
/// <param name="configuration">The configuration to used.</param>
|
|||
/// <param name="item">The item to decode.</param>
|
|||
/// <param name="data">The encoded data.</param>
|
|||
/// <returns>The decoded image.</returns>
|
|||
public Image<TPixel> DecodeItemData(Configuration configuration, HeifItem item, Span<byte> data); |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif; |
|||
|
|||
/// <summary>
|
|||
/// Decoder for a single <see cref="HeifItem"/> into a JPEG image.
|
|||
/// </summary>
|
|||
internal class JpegHeifItemDecoder<TPixel> : IHeifItemDecoder<TPixel> |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the item type this decoder decodes, which is <see cref="Heif4CharCode.Jpeg"/>.
|
|||
/// </summary>
|
|||
public Heif4CharCode Type => Heif4CharCode.Jpeg; |
|||
|
|||
/// <summary>
|
|||
/// Gets the compression method this doceder uses, which is <see cref="HeifCompressionMethod.LegacyJpeg"/>.
|
|||
/// </summary>
|
|||
public HeifCompressionMethod CompressionMethod => HeifCompressionMethod.LegacyJpeg; |
|||
|
|||
/// <summary>
|
|||
/// Decode the specified item as JPEG.
|
|||
/// </summary>
|
|||
public Image<TPixel> DecodeItemData(Configuration configuration, HeifItem item, Span<byte> data) |
|||
{ |
|||
Image<TPixel> image = Image.Load<TPixel>(data); |
|||
return image; |
|||
} |
|||
} |
|||
@ -0,0 +1,116 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using SixLabors.ImageSharp.Formats.Heif; |
|||
|
|||
namespace SixLabors.ImageSharp.Tests.Formats.Heif; |
|||
|
|||
[Trait("Format", "Heif")] |
|||
public class HeifLocationTests |
|||
{ |
|||
[Fact] |
|||
public void CheckSameLocationFromDifferentOrigin() |
|||
{ |
|||
// Arrange
|
|||
const int dataPosition = 50; |
|||
const int itemPosition = 100; |
|||
HeifLocation fromItem = new(HeifLocationOffsetOrigin.ItemOffset, 0, 10, 42); |
|||
HeifLocation fromFile = new(HeifLocationOffsetOrigin.FileOffset, 0, 110, 42); |
|||
HeifLocation fromData = new(HeifLocationOffsetOrigin.ItemDataOffset, 0, 60, 42); |
|||
|
|||
// Act
|
|||
long itemActual = fromItem.GetStreamPosition(dataPosition, itemPosition); |
|||
long fileActual = fromFile.GetStreamPosition(dataPosition, itemPosition); |
|||
long dataActual = fromData.GetStreamPosition(dataPosition, itemPosition); |
|||
|
|||
// Assert
|
|||
Assert.Equal(110, itemActual); |
|||
Assert.Equal(110, fileActual); |
|||
Assert.Equal(110, dataActual); |
|||
} |
|||
|
|||
[Fact] |
|||
public void CheckSameLocationFromDifferentOriginWithBaseOffset() |
|||
{ |
|||
// Arrange
|
|||
const int dataPosition = 50; |
|||
const int itemPosition = 100; |
|||
HeifLocation fromItem = new(HeifLocationOffsetOrigin.ItemOffset, 40, 10, 42); |
|||
HeifLocation fromFile = new(HeifLocationOffsetOrigin.FileOffset, 40, 110, 42); |
|||
HeifLocation fromData = new(HeifLocationOffsetOrigin.ItemDataOffset, 40, 60, 42); |
|||
|
|||
// Act
|
|||
long itemActual = fromItem.GetStreamPosition(dataPosition, itemPosition); |
|||
long fileActual = fromFile.GetStreamPosition(dataPosition, itemPosition); |
|||
long dataActual = fromData.GetStreamPosition(dataPosition, itemPosition); |
|||
|
|||
// Assert
|
|||
Assert.Equal(150, itemActual); |
|||
Assert.Equal(150, fileActual); |
|||
Assert.Equal(150, dataActual); |
|||
} |
|||
|
|||
[Fact] |
|||
public void CheckComparerOnSameLocation() |
|||
{ |
|||
// Arrange
|
|||
const int dataPosition = 50; |
|||
const int itemPosition = 100; |
|||
HeifLocation fromItem = new(HeifLocationOffsetOrigin.ItemOffset, 0, 50, 42); |
|||
HeifLocation fromFile = new(HeifLocationOffsetOrigin.FileOffset, 30, 120, 42); |
|||
HeifLocation fromData = new(HeifLocationOffsetOrigin.ItemDataOffset, 40, 60, 42); |
|||
HeifLocationComparer comparer = new(dataPosition, itemPosition); |
|||
|
|||
// Act
|
|||
int item2Data = comparer.Compare(fromItem, fromData); |
|||
int item2File = comparer.Compare(fromItem, fromFile); |
|||
int file2Data = comparer.Compare(fromFile, fromData); |
|||
int data2File = comparer.Compare(fromData, fromFile); |
|||
|
|||
// Assert
|
|||
Assert.Equal(0, item2Data); |
|||
Assert.Equal(0, item2File); |
|||
Assert.Equal(0, file2Data); |
|||
Assert.Equal(0, data2File); |
|||
} |
|||
|
|||
[Fact] |
|||
public void CheckComparerOnLowerLocation() |
|||
{ |
|||
// Arrange
|
|||
const int dataPosition = 50; |
|||
const int itemPosition = 100; |
|||
HeifLocation fromItem = new(HeifLocationOffsetOrigin.ItemOffset, 0, 50, 42); |
|||
HeifLocation fromFile = new(HeifLocationOffsetOrigin.FileOffset, 30, 150, 42); |
|||
HeifLocation fromData = new(HeifLocationOffsetOrigin.ItemDataOffset, 40, 80, 42); |
|||
HeifLocationComparer comparer = new(dataPosition, itemPosition); |
|||
|
|||
// Act
|
|||
int item2Data = comparer.Compare(fromItem, fromData); |
|||
int item2File = comparer.Compare(fromItem, fromFile); |
|||
|
|||
// Assert
|
|||
Assert.Equal(-1, item2Data); |
|||
Assert.Equal(-1, item2File); |
|||
} |
|||
|
|||
[Fact] |
|||
public void CheckComparerOnHigherLocation() |
|||
{ |
|||
// Arrange
|
|||
const int dataPosition = 50; |
|||
const int itemPosition = 100; |
|||
HeifLocation fromItem = new(HeifLocationOffsetOrigin.ItemOffset, 10, 50, 42); |
|||
HeifLocation fromFile = new(HeifLocationOffsetOrigin.FileOffset, 30, 120, 42); |
|||
HeifLocation fromData = new(HeifLocationOffsetOrigin.ItemDataOffset, 40, 60, 42); |
|||
HeifLocationComparer comparer = new(dataPosition, itemPosition); |
|||
|
|||
// Act
|
|||
int item2Data = comparer.Compare(fromItem, fromData); |
|||
int item2File = comparer.Compare(fromItem, fromFile); |
|||
|
|||
// Assert
|
|||
Assert.Equal(1, item2Data); |
|||
Assert.Equal(1, item2File); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue