Browse Source

Refactor jpeg decoder and general load

pull/2180/head
James Jackson-South 4 years ago
parent
commit
d53ad0efa0
  1. 24
      src/ImageSharp/Advanced/AotCompilerTools.cs
  2. 2
      src/ImageSharp/Formats/Bmp/BmpDecoderOptions.cs
  3. 9
      src/ImageSharp/Formats/DecoderOptions.cs
  4. 2
      src/ImageSharp/Formats/Gif/GifDecoderOptions.cs
  5. 12
      src/ImageSharp/Formats/IImageDecoder.cs
  6. 37
      src/ImageSharp/Formats/IImageDecoder2.cs
  7. 7
      src/ImageSharp/Formats/IImageInfoDetector.cs
  8. 24
      src/ImageSharp/Formats/IImageInfoDetector2.cs
  9. 2
      src/ImageSharp/Formats/ISpecializedDecoderOptions.cs
  10. 4
      src/ImageSharp/Formats/ImageDecoder{T}.cs
  11. 16
      src/ImageSharp/Formats/Jpeg/IJpegDecoderOptions.cs
  12. 78
      src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
  13. 90
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  14. 14
      src/ImageSharp/Formats/Jpeg/JpegDecoderOptions.cs
  15. 2
      src/ImageSharp/Formats/Pbm/PbmDecoderOptions.cs
  16. 2
      src/ImageSharp/Formats/Png/PngDecoderOptions.cs
  17. 2
      src/ImageSharp/Formats/Tga/TgaDecoderOptions.cs
  18. 20
      src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs
  19. 4
      src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs
  20. 4
      src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
  21. 2
      src/ImageSharp/Formats/Tiff/TiffDecoderOptions.cs
  22. 2
      src/ImageSharp/Formats/Webp/WebpDecoderOptions.cs
  23. 38
      src/ImageSharp/Image.Decode.cs
  24. 430
      src/ImageSharp/Image.FromBytes.cs
  25. 295
      src/ImageSharp/Image.FromFile.cs
  26. 333
      src/ImageSharp/Image.FromStream.cs
  27. 68
      src/ImageSharp/Image.LoadPixelData.cs
  28. 35
      tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs

24
src/ImageSharp/Advanced/AotCompilerTools.cs

@ -178,7 +178,7 @@ namespace SixLabors.ImageSharp.Advanced
img.CloneAs<Short2>(default);
img.CloneAs<Short4>(default);
ImageFrame.LoadPixelData<TPixel>(default, default(ReadOnlySpan<TPixel>), default, default);
ImageFrame.LoadPixelData(default, default(ReadOnlySpan<TPixel>), default, default);
ImageFrame.LoadPixelData<TPixel>(default, default(ReadOnlySpan<byte>), default, default);
}
@ -210,21 +210,21 @@ namespace SixLabors.ImageSharp.Advanced
}
/// <summary>
/// This method pre-seeds the all <see cref="IImageDecoderInternals"/> in the AoT compiler.
/// This method pre-seeds the all <see cref="IImageDecoderInternals{T}"/> in the AoT compiler.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
[Preserve]
private static void AotCompileImageDecoderInternals<TPixel>()
where TPixel : unmanaged, IPixel<TPixel>
{
default(WebpDecoderCore).Decode<TPixel>(default, default, default);
default(BmpDecoderCore).Decode<TPixel>(default, default, default);
default(GifDecoderCore).Decode<TPixel>(default, default, default);
default(JpegDecoderCore).Decode<TPixel>(default, default, default);
default(PbmDecoderCore).Decode<TPixel>(default, default, default);
default(PngDecoderCore).Decode<TPixel>(default, default, default);
default(TgaDecoderCore).Decode<TPixel>(default, default, default);
default(TiffDecoderCore).Decode<TPixel>(default, default, default);
default(WebpDecoderCore).Decode<TPixel>(default, default);
default(BmpDecoderCore).Decode<TPixel>(default, default);
default(GifDecoderCore).Decode<TPixel>(default, default);
default(JpegDecoderCore).Decode<TPixel>(default, default);
default(PbmDecoderCore).Decode<TPixel>(default, default);
default(PngDecoderCore).Decode<TPixel>(default, default);
default(TgaDecoderCore).Decode<TPixel>(default, default);
default(TiffDecoderCore).Decode<TPixel>(default, default);
}
/// <summary>
@ -286,9 +286,7 @@ namespace SixLabors.ImageSharp.Advanced
private static void AotCompileImageDecoder<TPixel, TDecoder>()
where TPixel : unmanaged, IPixel<TPixel>
where TDecoder : class, IImageDecoder
{
default(TDecoder).Decode<TPixel>(default, default, default);
}
=> default(TDecoder).Decode<TPixel>(default, default, default);
/// <summary>
/// This method pre-seeds the all <see cref="IImageProcessor" /> in the AoT compiler.

2
src/ImageSharp/Formats/Bmp/BmpDecoderOptions.cs

@ -1,5 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Bmp
{

9
src/ImageSharp/Formats/DecoderOptions.cs

@ -1,5 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
// Licensed under the Six Labors Split License.
using System;
@ -10,8 +10,15 @@ namespace SixLabors.ImageSharp.Formats
/// </summary>
public sealed class DecoderOptions
{
private static readonly Lazy<DecoderOptions> LazyOptions = new(() => new());
private uint maxFrames = int.MaxValue;
/// <summary>
/// Gets the shared default general decoder options instance.
/// </summary>
public static DecoderOptions Default { get; } = LazyOptions.Value;
/// <summary>
/// Gets or sets a custom Configuration instance to be used by the image processing pipeline.
/// </summary>

2
src/ImageSharp/Formats/Gif/GifDecoderOptions.cs

@ -1,5 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Gif
{

12
src/ImageSharp/Formats/IImageDecoder.cs

@ -16,22 +16,22 @@ namespace SixLabors.ImageSharp.Formats
/// Decodes the image from the specified stream to an <see cref="Image{TPixel}"/> of a specific pixel type.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="configuration">The configuration for the image.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
// TODO: Document ImageFormatExceptions (https://github.com/SixLabors/ImageSharp/issues/1110)
Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream, CancellationToken cancellationToken)
/// <exception cref="ImageFormatException">Thrown if the encoded image contains errors.</exception>
Image<TPixel> Decode<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>;
/// <summary>
/// Decodes the image from the specified stream to an <see cref="Image"/>.
/// </summary>
/// <param name="configuration">The configuration for the image.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The <see cref="Image"/>.</returns>
// TODO: Document ImageFormatExceptions (https://github.com/SixLabors/ImageSharp/issues/1110)
Image Decode(Configuration configuration, Stream stream, CancellationToken cancellationToken);
/// <exception cref="ImageFormatException">Thrown if the encoded image contains errors.</exception>
Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken);
}
}

37
src/ImageSharp/Formats/IImageDecoder2.cs

@ -1,37 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System.IO;
using System.Threading;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats
{
/// <summary>
/// Encapsulates properties and methods required for decoding an image from a stream.
/// </summary>
public interface IImageDecoder2
{
/// <summary>
/// Decodes the image from the specified stream to an <see cref="Image{TPixel}"/> of a specific pixel type.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <exception cref="ImageFormatException">Thrown if the encoded image contains errors.</exception>
Image<TPixel> Decode<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>;
/// <summary>
/// Decodes the image from the specified stream to an <see cref="Image"/>.
/// </summary>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The <see cref="Image"/>.</returns>
/// <exception cref="ImageFormatException">Thrown if the encoded image contains errors.</exception>
Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken);
}
}

7
src/ImageSharp/Formats/IImageInfoDetector.cs

@ -14,10 +14,11 @@ namespace SixLabors.ImageSharp.Formats
/// <summary>
/// Reads the raw image information from the specified stream.
/// </summary>
/// <param name="configuration">The configuration for the image.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The <see cref="PixelTypeInfo"/> object</returns>
IImageInfo Identify(Configuration configuration, Stream stream, CancellationToken cancellationToken);
/// <returns>The <see cref="IImageInfo"/> object.</returns>
/// <exception cref="ImageFormatException">Thrown if the encoded image contains errors.</exception>
IImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken);
}
}

24
src/ImageSharp/Formats/IImageInfoDetector2.cs

@ -1,24 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System.IO;
using System.Threading;
namespace SixLabors.ImageSharp.Formats
{
/// <summary>
/// Encapsulates methods used for detecting the raw image information without fully decoding it.
/// </summary>
public interface IImageInfoDetector2
{
/// <summary>
/// Reads the raw image information from the specified stream.
/// </summary>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The <see cref="IImageInfo"/> object.</returns>
/// <exception cref="ImageFormatException">Thrown if the encoded image contains errors.</exception>
IImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken);
}
}

2
src/ImageSharp/Formats/ISpecializedDecoderOptions.cs

@ -1,5 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats
{

4
src/ImageSharp/Formats/ImageDecoder{T}.cs

@ -1,5 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
// Licensed under the Six Labors Split License.
using System.IO;
using System.Threading;
@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Formats
/// The base class for all image decoders.
/// </summary>
/// <typeparam name="T">The type of specialized decoder options.</typeparam>
public abstract class ImageDecoder<T> : IImageInfoDetector2, IImageDecoder2
public abstract class ImageDecoder<T> : IImageInfoDetector, IImageDecoder
where T : ISpecializedDecoderOptions, new()
{
/// <inheritdoc/>

16
src/ImageSharp/Formats/Jpeg/IJpegDecoderOptions.cs

@ -1,16 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Jpeg
{
/// <summary>
/// Image decoder for generating an image out of a jpg stream.
/// </summary>
internal interface IJpegDecoderOptions
{
/// <summary>
/// Gets a value indicating whether the metadata should be ignored when the image is being decoded.
/// </summary>
bool IgnoreMetadata { get; }
}
}

78
src/ImageSharp/Formats/Jpeg/JpegDecoder.cs

@ -3,77 +3,45 @@
using System.IO;
using System.Threading;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Jpeg
{
/// <summary>
/// Image decoder for generating an image out of a jpg stream.
/// Decoder for generating an image out of a jpeg encoded stream.
/// </summary>
public sealed class JpegDecoder : IImageDecoder, IJpegDecoderOptions, IImageInfoDetector
public sealed class JpegDecoder : ImageDecoder<JpegDecoderOptions>
{
/// <inheritdoc/>
public bool IgnoreMetadata { get; set; }
/// <inheritdoc/>
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
/// <remarks>
/// Unlike <see cref="IImageDecoder.Decode{TPixel}(DecoderOptions, Stream, CancellationToken)"/>, when
/// <see cref="DecoderOptions.TargetSize"/> is passed, the codec may not be able to scale efficiently to
/// the exact scale factor requested, so returns a size that approximates that scale.
/// Upscaling is not supported, so the original size will be returned.
/// </remarks>
public override Image<TPixel> DecodeSpecialized<TPixel>(JpegDecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
Guard.NotNull(stream, nameof(stream));
using var decoder = new JpegDecoderCore(configuration, this);
return decoder.Decode<TPixel>(configuration, stream, cancellationToken);
using JpegDecoderCore decoder = new(options);
return decoder.Decode<JpegDecoderOptions, TPixel>(options.GeneralOptions.Configuration, stream, cancellationToken);
}
/// <inheritdoc />
public Image Decode(Configuration configuration, Stream stream, CancellationToken cancellationToken)
=> this.Decode<Rgb24>(configuration, stream, cancellationToken);
/// <summary>
/// Placeholder summary.
/// </summary>
/// <param name="configuration">Placeholder2</param>
/// <param name="stream">Placeholder3</param>
/// <param name="targetSize">Placeholder4</param>
/// <param name="cancellationToken">Placeholder5</param>
/// <returns>Placeholder6</returns>
internal Image DecodeInto(Configuration configuration, Stream stream, Size targetSize, CancellationToken cancellationToken)
=> this.DecodeInto<Rgb24>(configuration, stream, targetSize, cancellationToken);
/// <summary>
/// Decodes and downscales the image from the specified stream if possible.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="configuration">Configuration.</param>
/// <param name="stream">Stream.</param>
/// <param name="targetSize">Target size.</param>
/// <param name="cancellationToken">Cancellation token.</param>
internal Image<TPixel> DecodeInto<TPixel>(Configuration configuration, Stream stream, Size targetSize, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(stream, nameof(stream));
using var decoder = new JpegDecoderCore(configuration, this);
using var bufferedReadStream = new BufferedReadStream(configuration, stream);
try
{
return decoder.DecodeInto<TPixel>(bufferedReadStream, targetSize, cancellationToken);
}
catch (InvalidMemoryOperationException ex)
{
throw new InvalidImageContentException(((IImageDecoderInternals)decoder).Dimensions, ex);
}
}
/// <inheritdoc/>
/// <remarks>
/// Unlike <see cref="IImageDecoder.Decode(DecoderOptions, Stream, CancellationToken)"/>, when
/// <see cref="DecoderOptions.TargetSize"/> is passed, the codec may not be able to scale efficiently to
/// the exact scale factor requested, so returns a size that approximates that scale.
/// Upscaling is not supported, so the original size will be returned.
/// </remarks>
public override Image DecodeSpecialized(JpegDecoderOptions options, Stream stream, CancellationToken cancellationToken)
=> this.DecodeSpecialized<Rgb24>(options, stream, cancellationToken);
/// <inheritdoc/>
public IImageInfo Identify(Configuration configuration, Stream stream, CancellationToken cancellationToken)
public override IImageInfo IdentifySpecialized(JpegDecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
Guard.NotNull(stream, nameof(stream));
using var decoder = new JpegDecoderCore(configuration, this);
return decoder.Identify(configuration, stream, cancellationToken);
using JpegDecoderCore decoder = new(options);
return decoder.Identify(options.GeneralOptions.Configuration, stream, cancellationToken);
}
}
}

90
src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// Originally ported from <see href="https://github.com/mozilla/pdf.js/blob/master/src/core/jpg.js"/>
/// with additional fixes for both performance and common encoding errors.
/// </summary>
internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals<JpegDecoderOptions>
{
/// <summary>
/// The only supported precision
@ -116,31 +116,36 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
private int? resetInterval;
/// <summary>
/// Initializes a new instance of the <see cref="JpegDecoderCore" /> class.
/// The global configuration.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The options.</param>
public JpegDecoderCore(Configuration configuration, IJpegDecoderOptions options)
{
this.Configuration = configuration ?? Configuration.Default;
this.IgnoreMetadata = options.IgnoreMetadata;
}
private readonly Configuration configuration;
/// <inheritdoc />
public Configuration Configuration { get; }
/// <summary>
/// Whether to skip metadata during decode.
/// </summary>
private readonly bool skipMetadata;
/// <summary>
/// Gets the frame
/// Initializes a new instance of the <see cref="JpegDecoderCore"/> class.
/// </summary>
public JpegFrame Frame { get; private set; }
/// <param name="options">The decoder options.</param>
public JpegDecoderCore(JpegDecoderOptions options)
{
this.Options = options;
this.configuration = options.GeneralOptions.Configuration;
this.skipMetadata = options.GeneralOptions.SkipMetadata;
}
/// <inheritdoc />
public JpegDecoderOptions Options { get; }
/// <inheritdoc/>
Size IImageDecoderInternals.Dimensions => this.Frame.PixelSize;
public Size Dimensions => this.Frame.PixelSize;
/// <summary>
/// Gets a value indicating whether the metadata should be ignored when the image is being decoded.
/// Gets the frame
/// </summary>
public bool IgnoreMetadata { get; }
public JpegFrame Frame { get; private set; }
/// <summary>
/// Gets the <see cref="ImageMetadata"/> decoded by this decoder instance.
@ -201,48 +206,33 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <inheritdoc/>
public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
=> this.Decode<TPixel>(stream, targetSize: null, cancellationToken);
/// <inheritdoc/>
public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken)
{
this.ParseStream(stream, spectralConverter: null, cancellationToken);
using var spectralConverter = new SpectralConverter<TPixel>(this.configuration, this.Options.GeneralOptions.TargetSize);
this.ParseStream(stream, spectralConverter, cancellationToken);
this.InitExifProfile();
this.InitIccProfile();
this.InitIptcProfile();
this.InitXmpProfile();
this.InitDerivedMetadataProperties();
Size pixelSize = this.Frame.PixelSize;
return new ImageInfo(new PixelTypeInfo(this.Frame.BitsPerPixel), pixelSize.Width, pixelSize.Height, this.Metadata);
return new Image<TPixel>(
this.configuration,
spectralConverter.GetPixelBuffer(cancellationToken),
this.Metadata);
}
/// <summary>
/// Decodes and downscales the image from the specified stream if possible.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="stream">Stream.</param>
/// <param name="targetSize">Target size.</param>
/// <param name="cancellationToken">Cancellation token.</param>
internal Image<TPixel> DecodeInto<TPixel>(BufferedReadStream stream, Size targetSize, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
=> this.Decode<TPixel>(stream, targetSize, cancellationToken);
private Image<TPixel> Decode<TPixel>(BufferedReadStream stream, Size? targetSize, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
/// <inheritdoc/>
public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken)
{
using var spectralConverter = new SpectralConverter<TPixel>(this.Configuration, targetSize);
this.ParseStream(stream, spectralConverter, cancellationToken);
this.ParseStream(stream, spectralConverter: null, cancellationToken);
this.InitExifProfile();
this.InitIccProfile();
this.InitIptcProfile();
this.InitXmpProfile();
this.InitDerivedMetadataProperties();
return new Image<TPixel>(
this.Configuration,
spectralConverter.GetPixelBuffer(cancellationToken),
this.Metadata);
Size pixelSize = this.Frame.PixelSize;
return new ImageInfo(new PixelTypeInfo(this.Frame.BitsPerPixel), pixelSize.Width, pixelSize.Height, this.Metadata);
}
/// <summary>
@ -262,7 +252,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
}
using var ms = new MemoryStream(tableBytes);
using var stream = new BufferedReadStream(this.Configuration, ms);
using var stream = new BufferedReadStream(this.configuration, ms);
// Check for the Start Of Image marker.
int bytesRead = stream.Read(this.markerBuffer, 0, 2);
@ -809,7 +799,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
{
const int ExifMarkerLength = 6;
const int XmpMarkerLength = 29;
if (remaining < ExifMarkerLength || this.IgnoreMetadata)
if (remaining < ExifMarkerLength || this.skipMetadata)
{
// Skip the application header length.
stream.Skip(remaining);
@ -847,7 +837,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
if (ProfileResolver.IsProfile(this.temp, ProfileResolver.XmpMarker.Slice(0, ExifMarkerLength)))
{
const int remainingXmpMarkerBytes = XmpMarkerLength - ExifMarkerLength;
if (remaining < remainingXmpMarkerBytes || this.IgnoreMetadata)
if (remaining < remainingXmpMarkerBytes || this.skipMetadata)
{
// Skip the application header length.
stream.Skip(remaining);
@ -889,7 +879,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
{
// Length is 14 though we only need to check 12.
const int Icclength = 14;
if (remaining < Icclength || this.IgnoreMetadata)
if (remaining < Icclength || this.skipMetadata)
{
stream.Skip(remaining);
return;
@ -930,7 +920,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <param name="remaining">The remaining bytes in the segment block.</param>
private void ProcessApp13Marker(BufferedReadStream stream, int remaining)
{
if (remaining < ProfileResolver.AdobePhotoshopApp13Marker.Length || this.IgnoreMetadata)
if (remaining < ProfileResolver.AdobePhotoshopApp13Marker.Length || this.skipMetadata)
{
stream.Skip(remaining);
return;
@ -1310,8 +1300,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
}
IJpegComponent component = decodingComponentType is ComponentType.Huffman ?
new JpegComponent(this.Configuration.MemoryAllocator, this.Frame, componentId, h, v, quantTableIndex, i) :
new ArithmeticDecodingComponent(this.Configuration.MemoryAllocator, this.Frame, componentId, h, v, quantTableIndex, i);
new JpegComponent(this.configuration.MemoryAllocator, this.Frame, componentId, h, v, quantTableIndex, i) :
new ArithmeticDecodingComponent(this.configuration.MemoryAllocator, this.Frame, componentId, h, v, quantTableIndex, i);
this.Frame.Components[i] = (JpegComponent)component;
this.Frame.ComponentIds[i] = componentId;
@ -1348,7 +1338,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
}
int length = remaining;
using (IMemoryOwner<byte> buffer = this.Configuration.MemoryAllocator.Allocate<byte>(totalBufferSize))
using (IMemoryOwner<byte> buffer = this.configuration.MemoryAllocator.Allocate<byte>(totalBufferSize))
{
Span<byte> bufferSpan = buffer.GetSpan();
Span<byte> huffmanLengthsSpan = bufferSpan.Slice(0, codeLengthsByteSize);

14
src/ImageSharp/Formats/Jpeg/JpegDecoderOptions.cs

@ -0,0 +1,14 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Jpeg
{
/// <summary>
/// Configuration options for decoding Jpeg images.
/// </summary>
public sealed class JpegDecoderOptions : ISpecializedDecoderOptions
{
/// <inheritdoc/>
public DecoderOptions GeneralOptions { get; set; } = new();
}
}

2
src/ImageSharp/Formats/Pbm/PbmDecoderOptions.cs

@ -1,5 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Pbm
{

2
src/ImageSharp/Formats/Png/PngDecoderOptions.cs

@ -1,5 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Png
{

2
src/ImageSharp/Formats/Tga/TgaDecoderOptions.cs

@ -1,5 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Tga
{

20
src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs

@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
/// </summary>
internal sealed class JpegTiffCompression : TiffBaseDecompressor
{
private readonly Configuration configuration;
private readonly JpegDecoderOptions options;
private readonly byte[] jpegTables;
@ -27,14 +27,14 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
/// <summary>
/// Initializes a new instance of the <see cref="JpegTiffCompression"/> class.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The specialized jpeg decoder options.</param>
/// <param name="memoryAllocator">The memoryAllocator to use for buffer allocations.</param>
/// <param name="width">The image width.</param>
/// <param name="bitsPerPixel">The bits per pixel.</param>
/// <param name="jpegTables">The JPEG tables containing the quantization and/or Huffman tables.</param>
/// <param name="photometricInterpretation">The photometric interpretation.</param>
public JpegTiffCompression(
Configuration configuration,
JpegDecoderOptions options,
MemoryAllocator memoryAllocator,
int width,
int bitsPerPixel,
@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
TiffPhotometricInterpretation photometricInterpretation)
: base(memoryAllocator, width, bitsPerPixel)
{
this.configuration = configuration;
this.options = options;
this.jpegTables = jpegTables;
this.photometricInterpretation = photometricInterpretation;
}
@ -52,14 +52,14 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{
if (this.jpegTables != null)
{
using var jpegDecoder = new JpegDecoderCore(this.configuration, new JpegDecoder());
using var jpegDecoder = new JpegDecoderCore(this.options);
Configuration configuration = this.options.GeneralOptions.Configuration;
switch (this.photometricInterpretation)
{
case TiffPhotometricInterpretation.BlackIsZero:
case TiffPhotometricInterpretation.WhiteIsZero:
{
using SpectralConverter<L8> spectralConverterGray = new GrayJpegSpectralConverter<L8>(this.configuration);
using SpectralConverter<L8> spectralConverterGray = new GrayJpegSpectralConverter<L8>(configuration);
var scanDecoderGray = new HuffmanScanDecoder(stream, spectralConverterGray, CancellationToken.None);
jpegDecoder.LoadTables(this.jpegTables, scanDecoderGray);
jpegDecoder.ParseStream(stream, spectralConverterGray, CancellationToken.None);
@ -73,8 +73,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
case TiffPhotometricInterpretation.YCbCr:
case TiffPhotometricInterpretation.Rgb:
{
using SpectralConverter<Rgb24> spectralConverter = this.photometricInterpretation == TiffPhotometricInterpretation.YCbCr ?
new RgbJpegSpectralConverter<Rgb24>(this.configuration) : new SpectralConverter<Rgb24>(this.configuration);
using SpectralConverter<Rgb24> spectralConverter = this.photometricInterpretation == TiffPhotometricInterpretation.YCbCr
? new RgbJpegSpectralConverter<Rgb24>(this.options.GeneralOptions.Configuration)
: new SpectralConverter<Rgb24>(this.options.GeneralOptions.Configuration);
var scanDecoder = new HuffmanScanDecoder(stream, spectralConverter, CancellationToken.None);
jpegDecoder.LoadTables(this.jpegTables, scanDecoder);
jpegDecoder.ParseStream(stream, spectralConverter, CancellationToken.None);

4
src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs

@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
internal static class TiffDecompressorsFactory
{
public static TiffBaseDecompressor Create(
Configuration configuration,
DecoderOptions options,
TiffDecoderCompressionType method,
MemoryAllocator allocator,
TiffPhotometricInterpretation photometricInterpretation,
@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
case TiffDecoderCompressionType.Jpeg:
DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
return new JpegTiffCompression(configuration, allocator, width, bitsPerPixel, jpegTables, photometricInterpretation);
return new JpegTiffCompression(new() { GeneralOptions = options }, allocator, width, bitsPerPixel, jpegTables, photometricInterpretation);
default:
throw TiffThrowHelper.NotSupportedDecompressor(nameof(method));

4
src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs

@ -373,7 +373,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
}
using TiffBaseDecompressor decompressor = TiffDecompressorsFactory.Create(
this.configuration,
this.Options.GeneralOptions,
this.CompressionType,
this.memoryAllocator,
this.PhotometricInterpretation,
@ -453,7 +453,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
Buffer2D<TPixel> pixels = frame.PixelBuffer;
using TiffBaseDecompressor decompressor = TiffDecompressorsFactory.Create(
this.configuration,
this.Options.GeneralOptions,
this.CompressionType,
this.memoryAllocator,
this.PhotometricInterpretation,

2
src/ImageSharp/Formats/Tiff/TiffDecoderOptions.cs

@ -1,5 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Tiff
{

2
src/ImageSharp/Formats/Webp/WebpDecoderOptions.cs

@ -1,5 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Webp
{

38
src/ImageSharp/Image.Decode.cs

@ -44,14 +44,14 @@ namespace SixLabors.ImageSharp
/// <summary>
/// By reading the header on the provided stream this calculates the images format.
/// </summary>
/// <param name="configuration">The general configuration.</param>
/// <param name="stream">The image stream to read the header from.</param>
/// <param name="config">The configuration.</param>
/// <returns>The mime type or null if none found.</returns>
private static IImageFormat InternalDetectFormat(Stream stream, Configuration config)
private static IImageFormat InternalDetectFormat(Configuration configuration, Stream stream)
{
// We take a minimum of the stream length vs the max header size and always check below
// to ensure that only formats that headers fit within the given buffer length are tested.
int headerSize = (int)Math.Min(config.MaxHeaderSize, stream.Length);
int headerSize = (int)Math.Min(configuration.MaxHeaderSize, stream.Length);
if (headerSize <= 0)
{
return null;
@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp
// and does that data match the format specification?
// Individual formats should still check since they are public.
IImageFormat format = null;
foreach (IImageFormatDetector formatDetector in config.ImageFormatsManager.FormatDetectors)
foreach (IImageFormatDetector formatDetector in configuration.ImageFormatsManager.FormatDetectors)
{
if (formatDetector.HeaderSize <= headerSize)
{
@ -98,73 +98,73 @@ namespace SixLabors.ImageSharp
/// <summary>
/// By reading the header on the provided stream this calculates the images format.
/// </summary>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The image stream to read the header from.</param>
/// <param name="config">The configuration.</param>
/// <param name="format">The IImageFormat.</param>
/// <returns>The image format or null if none found.</returns>
private static IImageDecoder DiscoverDecoder(Stream stream, Configuration config, out IImageFormat format)
private static IImageDecoder DiscoverDecoder(DecoderOptions options, Stream stream, out IImageFormat format)
{
format = InternalDetectFormat(stream, config);
format = InternalDetectFormat(options.Configuration, stream);
return format != null
? config.ImageFormatsManager.FindDecoder(format)
? options.Configuration.ImageFormatsManager.FindDecoder(format)
: null;
}
/// <summary>
/// Decodes the image stream to the current image.
/// </summary>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream.</param>
/// <param name="config">the configuration.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>
/// A new <see cref="Image{TPixel}"/>.
/// </returns>
private static (Image<TPixel> Image, IImageFormat Format) Decode<TPixel>(Stream stream, Configuration config, CancellationToken cancellationToken = default)
private static (Image<TPixel> Image, IImageFormat Format) Decode<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken = default)
where TPixel : unmanaged, IPixel<TPixel>
{
IImageDecoder decoder = DiscoverDecoder(stream, config, out IImageFormat format);
IImageDecoder decoder = DiscoverDecoder(options, stream, out IImageFormat format);
if (decoder is null)
{
return (null, null);
}
Image<TPixel> img = decoder.Decode<TPixel>(config, stream, cancellationToken);
Image<TPixel> img = decoder.Decode<TPixel>(options, stream, cancellationToken);
return (img, format);
}
private static (Image Image, IImageFormat Format) Decode(Stream stream, Configuration config, CancellationToken cancellationToken = default)
private static (Image Image, IImageFormat Format) Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken = default)
{
IImageDecoder decoder = DiscoverDecoder(stream, config, out IImageFormat format);
IImageDecoder decoder = DiscoverDecoder(options, stream, out IImageFormat format);
if (decoder is null)
{
return (null, null);
}
Image img = decoder.Decode(config, stream, cancellationToken);
Image img = decoder.Decode(options, stream, cancellationToken);
return (img, format);
}
/// <summary>
/// Reads the raw image information from the specified stream.
/// </summary>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream.</param>
/// <param name="config">the configuration.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>
/// The <see cref="IImageInfo"/> or null if a suitable info detector is not found.
/// </returns>
private static (IImageInfo ImageInfo, IImageFormat Format) InternalIdentity(Stream stream, Configuration config, CancellationToken cancellationToken = default)
private static (IImageInfo ImageInfo, IImageFormat Format) InternalIdentity(DecoderOptions options, Stream stream, CancellationToken cancellationToken = default)
{
IImageDecoder decoder = DiscoverDecoder(stream, config, out IImageFormat format);
IImageDecoder decoder = DiscoverDecoder(options, stream, out IImageFormat format);
if (decoder is not IImageInfoDetector detector)
{
return (null, null);
}
IImageInfo info = detector?.Identify(config, stream, cancellationToken);
IImageInfo info = detector?.Identify(options, stream, cancellationToken);
return (info, format);
}
}

430
src/ImageSharp/Image.FromBytes.cs

@ -9,232 +9,30 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp
{
/// <content>
/// Adds static methods allowing the creation of new image from a byte array.
/// Adds static methods allowing the creation of new image from a byte span.
/// </content>
public abstract partial class Image
{
/// <summary>
/// By reading the header on the provided byte array this calculates the images format.
/// </summary>
/// <param name="data">The byte array containing encoded image data to read the header from.</param>
/// <exception cref="ArgumentNullException">The data is null.</exception>
/// <returns>The format or null if none found.</returns>
public static IImageFormat DetectFormat(byte[] data)
=> DetectFormat(Configuration.Default, data);
/// <summary>
/// By reading the header on the provided byte array this calculates the images format.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="data">The byte array containing encoded image data to read the header from.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The data is null.</exception>
/// <returns>The mime type or null if none found.</returns>
public static IImageFormat DetectFormat(Configuration configuration, byte[] data)
{
Guard.NotNull(data, nameof(data));
using (var stream = new MemoryStream(data, 0, data.Length, false, true))
{
return DetectFormat(configuration, stream);
}
}
/// <summary>
/// Reads the raw image information from the specified stream without fully decoding it.
/// </summary>
/// <param name="data">The byte array containing encoded image data to read the header from.</param>
/// <exception cref="ArgumentNullException">The data is null.</exception>
/// <exception cref="NotSupportedException">The data is not readable.</exception>
/// <returns>
/// The <see cref="IImageInfo"/> or null if suitable info detector not found.
/// </returns>
public static IImageInfo Identify(byte[] data) => Identify(data, out IImageFormat _);
/// <summary>
/// Reads the raw image information from the specified stream without fully decoding it.
/// </summary>
/// <param name="data">The byte array containing encoded image data to read the header from.</param>
/// <param name="format">The format type of the decoded image.</param>
/// <exception cref="ArgumentNullException">The data is null.</exception>
/// <exception cref="NotSupportedException">The data is not readable.</exception>
/// <returns>
/// The <see cref="IImageInfo"/> or null if suitable info detector not found.
/// </returns>
public static IImageInfo Identify(byte[] data, out IImageFormat format) => Identify(Configuration.Default, data, out format);
/// <summary>
/// Reads the raw image information from the specified stream without fully decoding it.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="data">The byte array containing encoded image data to read the header from.</param>
/// <param name="format">The format type of the decoded image.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The data is null.</exception>
/// <exception cref="NotSupportedException">The data is not readable.</exception>
/// <returns>
/// The <see cref="IImageInfo"/> or null if suitable info detector is not found.
/// </returns>
public static IImageInfo Identify(Configuration configuration, byte[] data, out IImageFormat format)
{
Guard.NotNull(data, nameof(data));
using (var stream = new MemoryStream(data, 0, data.Length, false, true))
{
return Identify(configuration, stream, out format);
}
}
/// <summary>
/// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte array.
/// </summary>
/// <param name="data">The byte array containing image data.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The data is null.</exception>
/// <returns>A new <see cref="Image"/>.</returns>
public static Image Load(byte[] data)
=> Load(Configuration.Default, data);
/// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array.
/// </summary>
/// <param name="data">The byte array containing encoded image data.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <exception cref="ArgumentNullException">The data is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(byte[] data)
where TPixel : unmanaged, IPixel<TPixel>
=> Load<TPixel>(Configuration.Default, data);
/// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array.
/// </summary>
/// <param name="data">The byte array containing image data.</param>
/// <param name="format">The mime type of the decoded image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <exception cref="ArgumentNullException">The data is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(byte[] data, out IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel>
=> Load<TPixel>(Configuration.Default, data, out format);
/// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array.
/// </summary>
/// <param name="configuration">The configuration options.</param>
/// <param name="data">The byte array containing encoded image data.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The data is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration configuration, byte[] data)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(data, nameof(data));
using (var stream = new MemoryStream(data, 0, data.Length, false, true))
{
return Load<TPixel>(configuration, stream);
}
}
/// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array.
/// </summary>
/// <param name="configuration">The configuration options.</param>
/// <param name="data">The byte array containing encoded image data.</param>
/// <param name="format">The <see cref="IImageFormat"/> of the decoded image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The data is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration configuration, byte[] data, out IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(data, nameof(data));
using (var stream = new MemoryStream(data, 0, data.Length, false, true))
{
return Load<TPixel>(configuration, stream, out format);
}
}
/// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array.
/// </summary>
/// <param name="data">The byte array containing encoded image data.</param>
/// <param name="decoder">The decoder.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <exception cref="ArgumentNullException">The data is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(byte[] data, IImageDecoder decoder)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(data, nameof(data));
using (var stream = new MemoryStream(data, 0, data.Length, false, true))
{
return Load<TPixel>(stream, decoder);
}
}
/// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array.
/// </summary>
/// <param name="configuration">The Configuration.</param>
/// <param name="data">The byte array containing encoded image data.</param>
/// <param name="decoder">The decoder.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The data is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration configuration, byte[] data, IImageDecoder decoder)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(data, nameof(data));
using (var stream = new MemoryStream(data, 0, data.Length, false, true))
{
return Load<TPixel>(configuration, stream, decoder);
}
}
/// <summary>
/// By reading the header on the provided byte span this calculates the images format.
/// </summary>
/// <param name="data">The byte span containing encoded image data to read the header from.</param>
/// <returns>The format or null if none found.</returns>
public static IImageFormat DetectFormat(ReadOnlySpan<byte> data) => DetectFormat(Configuration.Default, data);
public static IImageFormat DetectFormat(ReadOnlySpan<byte> data)
=> DetectFormat(DecoderOptions.Default, data);
/// <summary>
/// By reading the header on the provided byte span this calculates the images format.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="data">The byte span containing encoded image data to read the header from.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <returns>The mime type or null if none found.</returns>
public static IImageFormat DetectFormat(Configuration configuration, ReadOnlySpan<byte> data)
public static IImageFormat DetectFormat(DecoderOptions options, ReadOnlySpan<byte> data)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.NotNull(options, nameof(options.Configuration));
Configuration configuration = options.Configuration;
int maxHeaderSize = configuration.MaxHeaderSize;
if (maxHeaderSize <= 0)
{
@ -265,7 +63,7 @@ namespace SixLabors.ImageSharp
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(ReadOnlySpan<byte> data)
where TPixel : unmanaged, IPixel<TPixel>
=> Load<TPixel>(Configuration.Default, data);
=> Load<TPixel>(DecoderOptions.Default, data);
/// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span.
@ -279,177 +77,51 @@ namespace SixLabors.ImageSharp
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(ReadOnlySpan<byte> data, out IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel>
=> Load<TPixel>(Configuration.Default, data, out format);
=> Load<TPixel>(DecoderOptions.Default, data, out format);
/// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span.
/// </summary>
/// <param name="options">The general decoder options.</param>
/// <param name="data">The byte span containing encoded image data.</param>
/// <param name="decoder">The decoder.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(ReadOnlySpan<byte> data, IImageDecoder decoder)
where TPixel : unmanaged, IPixel<TPixel>
=> Load<TPixel>(Configuration.Default, data, decoder);
/// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span.
/// </summary>
/// <param name="configuration">The configuration options.</param>
/// <param name="data">The byte span containing encoded image data.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static unsafe Image<TPixel> Load<TPixel>(Configuration configuration, ReadOnlySpan<byte> data)
where TPixel : unmanaged, IPixel<TPixel>
{
fixed (byte* ptr = &data.GetPinnableReference())
{
using (var stream = new UnmanagedMemoryStream(ptr, data.Length))
{
return Load<TPixel>(configuration, stream);
}
}
}
/// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span.
/// </summary>
/// <param name="configuration">The Configuration.</param>
/// <param name="data">The byte span containing image data.</param>
/// <param name="decoder">The decoder.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static unsafe Image<TPixel> Load<TPixel>(
Configuration configuration,
ReadOnlySpan<byte> data,
IImageDecoder decoder)
public static unsafe Image<TPixel> Load<TPixel>(DecoderOptions options, ReadOnlySpan<byte> data)
where TPixel : unmanaged, IPixel<TPixel>
{
fixed (byte* ptr = &data.GetPinnableReference())
{
using (var stream = new UnmanagedMemoryStream(ptr, data.Length))
{
return Load<TPixel>(configuration, stream, decoder);
}
using var stream = new UnmanagedMemoryStream(ptr, data.Length);
return Load<TPixel>(options, stream);
}
}
/// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span.
/// </summary>
/// <param name="configuration">The configuration options.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="data">The byte span containing image data.</param>
/// <param name="format">The <see cref="IImageFormat"/> of the decoded image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static unsafe Image<TPixel> Load<TPixel>(
Configuration configuration,
DecoderOptions options,
ReadOnlySpan<byte> data,
out IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel>
{
fixed (byte* ptr = &data.GetPinnableReference())
{
using (var stream = new UnmanagedMemoryStream(ptr, data.Length))
{
return Load<TPixel>(configuration, stream, out format);
}
}
}
/// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte array.
/// </summary>
/// <param name="data">The byte array containing image data.</param>
/// <param name="format">The detected format.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The data is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(byte[] data, out IImageFormat format)
=> Load(Configuration.Default, data, out format);
/// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte array.
/// </summary>
/// <param name="data">The byte array containing encoded image data.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="ArgumentNullException">The data is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(byte[] data, IImageDecoder decoder)
=> Load(Configuration.Default, data, decoder);
/// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte array.
/// </summary>
/// <param name="configuration">The configuration for the decoder.</param>
/// <param name="data">The byte array containing encoded image data.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The data is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Configuration configuration, byte[] data)
=> Load(configuration, data, out _);
/// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte array.
/// </summary>
/// <param name="configuration">The configuration for the decoder.</param>
/// <param name="data">The byte array containing image data.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The data is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Configuration configuration, byte[] data, IImageDecoder decoder)
{
using (var stream = new MemoryStream(data, 0, data.Length, false, true))
{
return Load(configuration, stream, decoder);
}
}
/// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte array.
/// </summary>
/// <param name="configuration">The configuration for the decoder.</param>
/// <param name="data">The byte array containing image data.</param>
/// <param name="format">The mime type of the decoded image.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The data is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Configuration configuration, byte[] data, out IImageFormat format)
{
using (var stream = new MemoryStream(data, 0, data.Length, false, true))
{
return Load(configuration, stream, out format);
using var stream = new UnmanagedMemoryStream(ptr, data.Length);
return Load<TPixel>(options, stream, out format);
}
}
@ -462,21 +134,7 @@ namespace SixLabors.ImageSharp
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(ReadOnlySpan<byte> data)
=> Load(Configuration.Default, data);
/// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte span.
/// </summary>
/// <param name="data">The byte span containing image data.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="ArgumentNullException">The data is null.</exception>
/// <exception cref="ArgumentNullException">The decoder is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(ReadOnlySpan<byte> data, IImageDecoder decoder)
=> Load(Configuration.Default, data, decoder);
=> Load(DecoderOptions.Default, data);
/// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte array.
@ -489,65 +147,37 @@ namespace SixLabors.ImageSharp
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(ReadOnlySpan<byte> data, out IImageFormat format)
=> Load(Configuration.Default, data, out format);
=> Load(DecoderOptions.Default, data, out format);
/// <summary>
/// Decodes a new instance of <see cref="Image"/> from the given encoded byte span.
/// </summary>
/// <param name="configuration">The configuration options.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="data">The byte span containing image data.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Configuration configuration, ReadOnlySpan<byte> data)
=> Load(configuration, data, out _);
public static Image Load(DecoderOptions options, ReadOnlySpan<byte> data)
=> Load(options, data, out _);
/// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte span.
/// </summary>
/// <param name="configuration">The Configuration.</param>
/// <param name="data">The byte span containing image data.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The decoder is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>The <see cref="Image"/>.</returns>
public static unsafe Image Load(
Configuration configuration,
ReadOnlySpan<byte> data,
IImageDecoder decoder)
{
fixed (byte* ptr = &data.GetPinnableReference())
{
using (var stream = new UnmanagedMemoryStream(ptr, data.Length))
{
return Load(configuration, stream, decoder);
}
}
}
/// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte span.
/// </summary>
/// <param name="configuration">The configuration options.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="data">The byte span containing image data.</param>
/// <param name="format">The <see cref="IImageFormat"/> of the decoded image.</param>>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <returns>The <see cref="Image"/>.</returns>
public static unsafe Image Load(
Configuration configuration,
DecoderOptions options,
ReadOnlySpan<byte> data,
out IImageFormat format)
{
fixed (byte* ptr = &data.GetPinnableReference())
{
using (var stream = new UnmanagedMemoryStream(ptr, data.Length))
{
return Load(configuration, stream, out format);
}
using var stream = new UnmanagedMemoryStream(ptr, data.Length);
return Load(options, stream, out format);
}
}
}

295
src/ImageSharp/Image.FromFile.cs

@ -21,23 +21,21 @@ namespace SixLabors.ImageSharp
/// <param name="filePath">The image file to open and to read the header from.</param>
/// <returns>The mime type or null if none found.</returns>
public static IImageFormat DetectFormat(string filePath)
=> DetectFormat(Configuration.Default, filePath);
=> DetectFormat(DecoderOptions.Default, filePath);
/// <summary>
/// By reading the header on the provided file this calculates the images mime type.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="filePath">The image file to open and to read the header from.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <returns>The mime type or null if none found.</returns>
public static IImageFormat DetectFormat(Configuration configuration, string filePath)
public static IImageFormat DetectFormat(DecoderOptions options, string filePath)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.NotNull(options, nameof(options));
using (Stream file = configuration.FileSystem.OpenRead(filePath))
{
return DetectFormat(configuration, file);
}
using Stream file = options.Configuration.FileSystem.OpenRead(filePath);
return DetectFormat(options, file);
}
/// <summary>
@ -59,25 +57,23 @@ namespace SixLabors.ImageSharp
/// The <see cref="IImageInfo"/> or null if suitable info detector not found.
/// </returns>
public static IImageInfo Identify(string filePath, out IImageFormat format)
=> Identify(Configuration.Default, filePath, out format);
=> Identify(DecoderOptions.Default, filePath, out format);
/// <summary>
/// Reads the raw image information from the specified stream without fully decoding it.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="filePath">The image file to open and to read the header from.</param>
/// <param name="format">The format type of the decoded image.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <returns>
/// The <see cref="IImageInfo"/> or null if suitable info detector is not found.
/// </returns>
public static IImageInfo Identify(Configuration configuration, string filePath, out IImageFormat format)
public static IImageInfo Identify(DecoderOptions options, string filePath, out IImageFormat format)
{
Guard.NotNull(configuration, nameof(configuration));
using (Stream file = configuration.FileSystem.OpenRead(filePath))
{
return Identify(configuration, file, out format);
}
Guard.NotNull(options, nameof(options));
using Stream file = options.Configuration.FileSystem.OpenRead(filePath);
return Identify(options, file, out format);
}
/// <summary>
@ -91,12 +87,12 @@ namespace SixLabors.ImageSharp
/// <see cref="IImageInfo"/> property set to null if suitable info detector is not found.
/// </returns>
public static Task<IImageInfo> IdentifyAsync(string filePath, CancellationToken cancellationToken = default)
=> IdentifyAsync(Configuration.Default, filePath, cancellationToken);
=> IdentifyAsync(DecoderOptions.Default, filePath, cancellationToken);
/// <summary>
/// Reads the raw image information from the specified stream without fully decoding it.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="filePath">The image file to open and to read the header from.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
@ -105,12 +101,12 @@ namespace SixLabors.ImageSharp
/// <see cref="IImageInfo"/> property set to null if suitable info detector is not found.
/// </returns>
public static async Task<IImageInfo> IdentifyAsync(
Configuration configuration,
DecoderOptions options,
string filePath,
CancellationToken cancellationToken = default)
{
(IImageInfo ImageInfo, IImageFormat Format) res = await IdentifyWithFormatAsync(configuration, filePath, cancellationToken)
.ConfigureAwait(false);
(IImageInfo ImageInfo, IImageFormat Format) res =
await IdentifyWithFormatAsync(options, filePath, cancellationToken).ConfigureAwait(false);
return res.ImageInfo;
}
@ -127,12 +123,12 @@ namespace SixLabors.ImageSharp
public static Task<(IImageInfo ImageInfo, IImageFormat Format)> IdentifyWithFormatAsync(
string filePath,
CancellationToken cancellationToken = default)
=> IdentifyWithFormatAsync(Configuration.Default, filePath, cancellationToken);
=> IdentifyWithFormatAsync(DecoderOptions.Default, filePath, cancellationToken);
/// <summary>
/// Reads the raw image information from the specified stream without fully decoding it.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="filePath">The image file to open and to read the header from.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
@ -141,13 +137,13 @@ namespace SixLabors.ImageSharp
/// <see cref="IImageInfo"/> property set to null if suitable info detector is not found.
/// </returns>
public static async Task<(IImageInfo ImageInfo, IImageFormat Format)> IdentifyWithFormatAsync(
Configuration configuration,
DecoderOptions options,
string filePath,
CancellationToken cancellationToken = default)
{
Guard.NotNull(configuration, nameof(configuration));
using Stream stream = configuration.FileSystem.OpenRead(filePath);
return await IdentifyWithFormatAsync(configuration, stream, cancellationToken)
Guard.NotNull(options, nameof(options));
using Stream stream = options.Configuration.FileSystem.OpenRead(filePath);
return await IdentifyWithFormatAsync(options, stream, cancellationToken)
.ConfigureAwait(false);
}
@ -160,7 +156,7 @@ namespace SixLabors.ImageSharp
/// </exception>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(string path)
=> Load(Configuration.Default, path);
=> Load(DecoderOptions.Default, path);
/// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file.
@ -172,12 +168,12 @@ namespace SixLabors.ImageSharp
/// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image Load(string path, out IImageFormat format)
=> Load(Configuration.Default, path, out format);
=> Load(DecoderOptions.Default, path, out format);
/// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file.
/// </summary>
/// <param name="configuration">The configuration for the decoder.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="path">The file path to the image.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The path is null.</exception>
@ -185,13 +181,13 @@ namespace SixLabors.ImageSharp
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Configuration configuration, string path)
=> Load(configuration, path, out _);
public static Image Load(DecoderOptions options, string path)
=> Load(options, path, out _);
/// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file.
/// </summary>
/// <param name="configuration">The configuration for the decoder.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="path">The file path to the image.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
@ -201,40 +197,16 @@ namespace SixLabors.ImageSharp
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
public static async Task<Image> LoadAsync(
Configuration configuration,
DecoderOptions options,
string path,
CancellationToken cancellationToken = default)
{
using Stream stream = configuration.FileSystem.OpenRead(path);
(Image img, _) = await LoadWithFormatAsync(configuration, stream, cancellationToken)
using Stream stream = options.Configuration.FileSystem.OpenRead(path);
(Image img, _) = await LoadWithFormatAsync(options, stream, cancellationToken)
.ConfigureAwait(false);
return img;
}
/// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file.
/// </summary>
/// <param name="configuration">The Configuration.</param>
/// <param name="path">The file path to the image.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="ArgumentNullException">The decoder is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Configuration configuration, string path, IImageDecoder decoder)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.NotNull(path, nameof(path));
using (Stream stream = configuration.FileSystem.OpenRead(path))
{
return Load(configuration, stream, decoder);
}
}
/// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file.
/// </summary>
@ -248,99 +220,7 @@ namespace SixLabors.ImageSharp
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
public static Task<Image> LoadAsync(string path, CancellationToken cancellationToken = default)
=> LoadAsync(Configuration.Default, path, cancellationToken);
/// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file.
/// </summary>
/// <param name="path">The file path to the image.</param>
/// <param name="decoder">The decoder.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="ArgumentNullException">The decoder is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
public static Task<Image> LoadAsync(string path, IImageDecoder decoder, CancellationToken cancellationToken = default)
=> LoadAsync(Configuration.Default, path, decoder, cancellationToken);
/// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file.
/// </summary>
/// <param name="path">The file path to the image.</param>
/// <param name="decoder">The decoder.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="ArgumentNullException">The decoder is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
public static Task<Image<TPixel>> LoadAsync<TPixel>(string path, IImageDecoder decoder, CancellationToken cancellationToken = default)
where TPixel : unmanaged, IPixel<TPixel>
=> LoadAsync<TPixel>(Configuration.Default, path, decoder, cancellationToken);
/// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file.
/// </summary>
/// <param name="configuration">The Configuration.</param>
/// <param name="path">The file path to the image.</param>
/// <param name="decoder">The decoder.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="ArgumentNullException">The decoder is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
public static async Task<Image> LoadAsync(
Configuration configuration,
string path,
IImageDecoder decoder,
CancellationToken cancellationToken = default)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.NotNull(path, nameof(path));
using Stream stream = configuration.FileSystem.OpenRead(path);
return await LoadAsync(configuration, stream, decoder, cancellationToken)
.ConfigureAwait(false);
}
/// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file.
/// </summary>
/// <param name="configuration">The Configuration.</param>
/// <param name="path">The file path to the image.</param>
/// <param name="decoder">The decoder.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="ArgumentNullException">The decoder is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
public static async Task<Image<TPixel>> LoadAsync<TPixel>(
Configuration configuration,
string path,
IImageDecoder decoder,
CancellationToken cancellationToken = default)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(configuration, nameof(configuration));
Guard.NotNull(path, nameof(path));
using Stream stream = configuration.FileSystem.OpenRead(path);
return await LoadAsync<TPixel>(configuration, stream, decoder, cancellationToken)
.ConfigureAwait(false);
}
=> LoadAsync(DecoderOptions.Default, path, cancellationToken);
/// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file.
@ -356,12 +236,12 @@ namespace SixLabors.ImageSharp
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
public static Task<Image<TPixel>> LoadAsync<TPixel>(string path, CancellationToken cancellationToken = default)
where TPixel : unmanaged, IPixel<TPixel>
=> LoadAsync<TPixel>(Configuration.Default, path, cancellationToken);
=> LoadAsync<TPixel>(DecoderOptions.Default, path, cancellationToken);
/// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file.
/// </summary>
/// <param name="configuration">The configuration for the decoder.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="path">The file path to the image.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
@ -372,31 +252,19 @@ namespace SixLabors.ImageSharp
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
public static async Task<Image<TPixel>> LoadAsync<TPixel>(
Configuration configuration,
DecoderOptions options,
string path,
CancellationToken cancellationToken = default)
where TPixel : unmanaged, IPixel<TPixel>
{
using Stream stream = configuration.FileSystem.OpenRead(path);
(Image<TPixel> img, _) = await LoadWithFormatAsync<TPixel>(configuration, stream, cancellationToken)
.ConfigureAwait(false);
Guard.NotNull(options, nameof(options));
using Stream stream = options.Configuration.FileSystem.OpenRead(path);
(Image<TPixel> img, _) =
await LoadWithFormatAsync<TPixel>(options, stream, cancellationToken).ConfigureAwait(false);
return img;
}
/// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file.
/// </summary>
/// <param name="path">The file path to the image.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="ArgumentNullException">The decoder is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(string path, IImageDecoder decoder)
=> Load(Configuration.Default, path, decoder);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
/// </summary>
@ -409,7 +277,7 @@ namespace SixLabors.ImageSharp
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(string path)
where TPixel : unmanaged, IPixel<TPixel>
=> Load<TPixel>(Configuration.Default, path);
=> Load<TPixel>(DecoderOptions.Default, path);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
@ -424,12 +292,12 @@ namespace SixLabors.ImageSharp
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(string path, out IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel>
=> Load<TPixel>(Configuration.Default, path, out format);
=> Load<TPixel>(DecoderOptions.Default, path, out format);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
/// </summary>
/// <param name="configuration">The configuration options.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="path">The file path to the image.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The path is null.</exception>
@ -438,22 +306,20 @@ namespace SixLabors.ImageSharp
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration configuration, string path)
public static Image<TPixel> Load<TPixel>(DecoderOptions options, string path)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(configuration, nameof(configuration));
Guard.NotNull(options, nameof(options));
Guard.NotNull(path, nameof(path));
using (Stream stream = configuration.FileSystem.OpenRead(path))
{
return Load<TPixel>(configuration, stream);
}
using Stream stream = options.Configuration.FileSystem.OpenRead(path);
return Load<TPixel>(options, stream);
}
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
/// </summary>
/// <param name="configuration">The configuration options.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="path">The file path to the image.</param>
/// <param name="format">The mime type of the decoded image.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
@ -463,23 +329,21 @@ namespace SixLabors.ImageSharp
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration configuration, string path, out IImageFormat format)
public static Image<TPixel> Load<TPixel>(DecoderOptions options, string path, out IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(configuration, nameof(configuration));
Guard.NotNull(options, nameof(options));
Guard.NotNull(path, nameof(path));
using (Stream stream = configuration.FileSystem.OpenRead(path))
{
return Load<TPixel>(configuration, stream, out format);
}
using Stream stream = options.Configuration.FileSystem.OpenRead(path);
return Load<TPixel>(options, stream, out format);
}
/// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file.
/// The pixel type is selected by the decoder.
/// </summary>
/// <param name="configuration">The configuration options.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="path">The file path to the image.</param>
/// <param name="format">The mime type of the decoded image.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
@ -488,56 +352,13 @@ namespace SixLabors.ImageSharp
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image Load(Configuration configuration, string path, out IImageFormat format)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.NotNull(path, nameof(path));
using (Stream stream = configuration.FileSystem.OpenRead(path))
{
return Load(configuration, stream, out format);
}
}
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
/// </summary>
/// <param name="path">The file path to the image.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(string path, IImageDecoder decoder)
where TPixel : unmanaged, IPixel<TPixel>
=> Load<TPixel>(Configuration.Default, path, decoder);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
/// </summary>
/// <param name="configuration">The Configuration.</param>
/// <param name="path">The file path to the image.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="ArgumentNullException">The decoder is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration configuration, string path, IImageDecoder decoder)
where TPixel : unmanaged, IPixel<TPixel>
public static Image Load(DecoderOptions options, string path, out IImageFormat format)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.NotNull(options, nameof(options));
Guard.NotNull(path, nameof(path));
using (Stream stream = configuration.FileSystem.OpenRead(path))
{
return Load<TPixel>(configuration, stream, decoder);
}
using Stream stream = options.Configuration.FileSystem.OpenRead(path);
return Load(options, stream, out format);
}
}
}

333
src/ImageSharp/Image.FromStream.cs

@ -26,19 +26,19 @@ namespace SixLabors.ImageSharp
/// <exception cref="NotSupportedException">The stream is not readable.</exception>
/// <returns>The format type or null if none found.</returns>
public static IImageFormat DetectFormat(Stream stream)
=> DetectFormat(Configuration.Default, stream);
=> DetectFormat(DecoderOptions.Default, stream);
/// <summary>
/// By reading the header on the provided stream this calculates the images format type.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The image stream to read the header from.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable.</exception>
/// <returns>The format type or null if none found.</returns>
public static IImageFormat DetectFormat(Configuration configuration, Stream stream)
=> WithSeekableStream(configuration, stream, s => InternalDetectFormat(s, configuration));
public static IImageFormat DetectFormat(DecoderOptions options, Stream stream)
=> WithSeekableStream(options, stream, s => InternalDetectFormat(options.Configuration, s));
/// <summary>
/// By reading the header on the provided stream this calculates the images format type.
@ -49,23 +49,23 @@ namespace SixLabors.ImageSharp
/// <exception cref="NotSupportedException">The stream is not readable.</exception>
/// <returns>A <see cref="Task{IImageFormat}"/> representing the asynchronous operation or null if none is found.</returns>
public static Task<IImageFormat> DetectFormatAsync(Stream stream, CancellationToken cancellationToken = default)
=> DetectFormatAsync(Configuration.Default, stream, cancellationToken);
=> DetectFormatAsync(DecoderOptions.Default, stream, cancellationToken);
/// <summary>
/// By reading the header on the provided stream this calculates the images format type.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The image stream to read the header from.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable.</exception>
/// <returns>A <see cref="Task{IImageFormat}"/> representing the asynchronous operation.</returns>
public static Task<IImageFormat> DetectFormatAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken = default)
public static Task<IImageFormat> DetectFormatAsync(DecoderOptions options, Stream stream, CancellationToken cancellationToken = default)
=> WithSeekableStreamAsync(
configuration,
options,
stream,
(s, _) => InternalDetectFormat(s, configuration),
(s, _) => InternalDetectFormat(options.Configuration, s),
cancellationToken);
/// <summary>
@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp
/// a suitable detector is not found.
/// </returns>
public static Task<IImageInfo> IdentifyAsync(Stream stream, CancellationToken cancellationToken = default)
=> IdentifyAsync(Configuration.Default, stream, cancellationToken);
=> IdentifyAsync(DecoderOptions.Default, stream, cancellationToken);
/// <summary>
/// Reads the raw image information from the specified stream without fully decoding it.
@ -108,30 +108,30 @@ namespace SixLabors.ImageSharp
/// The <see cref="IImageInfo"/> or null if a suitable info detector is not found.
/// </returns>
public static IImageInfo Identify(Stream stream, out IImageFormat format)
=> Identify(Configuration.Default, stream, out format);
=> Identify(DecoderOptions.Default, stream, out format);
/// <summary>
/// Reads the raw image information from the specified stream without fully decoding it.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The image stream to read the information from.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>
/// The <see cref="IImageInfo"/> or null if a suitable info detector is not found.
/// </returns>
public static IImageInfo Identify(Configuration configuration, Stream stream)
=> Identify(configuration, stream, out _);
public static IImageInfo Identify(DecoderOptions options, Stream stream)
=> Identify(options, stream, out _);
/// <summary>
/// Reads the raw image information from the specified stream without fully decoding it.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The image stream to read the information from.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
@ -140,30 +140,30 @@ namespace SixLabors.ImageSharp
/// a suitable detector is not found.
/// </returns>
public static async Task<IImageInfo> IdentifyAsync(
Configuration configuration,
DecoderOptions options,
Stream stream,
CancellationToken cancellationToken = default)
{
(IImageInfo ImageInfo, IImageFormat Format) res = await IdentifyWithFormatAsync(configuration, stream, cancellationToken).ConfigureAwait(false);
(IImageInfo ImageInfo, IImageFormat Format) res = await IdentifyWithFormatAsync(options, stream, cancellationToken).ConfigureAwait(false);
return res.ImageInfo;
}
/// <summary>
/// Reads the raw image information from the specified stream without fully decoding it.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The image stream to read the information from.</param>
/// <param name="format">The format type of the decoded image.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>
/// The <see cref="IImageInfo"/> or null if a suitable info detector is not found.
/// </returns>
public static IImageInfo Identify(Configuration configuration, Stream stream, out IImageFormat format)
public static IImageInfo Identify(DecoderOptions options, Stream stream, out IImageFormat format)
{
(IImageInfo ImageInfo, IImageFormat Format) data = WithSeekableStream(configuration, stream, s => InternalIdentity(s, configuration ?? Configuration.Default));
(IImageInfo ImageInfo, IImageFormat Format) data = WithSeekableStream(options, stream, s => InternalIdentity(options, s));
format = data.Format;
return data.ImageInfo;
@ -174,7 +174,7 @@ namespace SixLabors.ImageSharp
/// </summary>
/// <param name="stream">The image stream to read the information from.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
@ -185,15 +185,15 @@ namespace SixLabors.ImageSharp
public static Task<(IImageInfo ImageInfo, IImageFormat Format)> IdentifyWithFormatAsync(
Stream stream,
CancellationToken cancellationToken = default)
=> IdentifyWithFormatAsync(Configuration.Default, stream, cancellationToken);
=> IdentifyWithFormatAsync(DecoderOptions.Default, stream, cancellationToken);
/// <summary>
/// Reads the raw image information from the specified stream without fully decoding it.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The image stream to read the information from.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
@ -202,13 +202,13 @@ namespace SixLabors.ImageSharp
/// <see cref="IImageInfo"/> property set to null if suitable info detector is not found.
/// </returns>
public static Task<(IImageInfo ImageInfo, IImageFormat Format)> IdentifyWithFormatAsync(
Configuration configuration,
DecoderOptions options,
Stream stream,
CancellationToken cancellationToken = default)
=> WithSeekableStreamAsync(
configuration,
options,
stream,
(s, ct) => InternalIdentity(s, configuration ?? Configuration.Default, ct),
(s, ct) => InternalIdentity(options, s, ct),
cancellationToken);
/// <summary>
@ -223,7 +223,7 @@ namespace SixLabors.ImageSharp
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Stream stream, out IImageFormat format)
=> Load(Configuration.Default, stream, out format);
=> Load(DecoderOptions.Default, stream, out format);
/// <summary>
/// Decode a new instance of the <see cref="Image"/> class from the given stream.
@ -237,7 +237,7 @@ namespace SixLabors.ImageSharp
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A <see cref="Task{ValueTuple}"/> representing the asynchronous operation.</returns>
public static Task<(Image Image, IImageFormat Format)> LoadWithFormatAsync(Stream stream, CancellationToken cancellationToken = default)
=> LoadWithFormatAsync(Configuration.Default, stream, cancellationToken);
=> LoadWithFormatAsync(DecoderOptions.Default, stream, cancellationToken);
/// <summary>
/// Decode a new instance of the <see cref="Image"/> class from the given stream.
@ -249,7 +249,7 @@ namespace SixLabors.ImageSharp
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Stream stream) => Load(Configuration.Default, stream);
public static Image Load(Stream stream) => Load(DecoderOptions.Default, stream);
/// <summary>
/// Decode a new instance of the <see cref="Image"/> class from the given stream.
@ -263,116 +263,37 @@ namespace SixLabors.ImageSharp
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
public static Task<Image> LoadAsync(Stream stream, CancellationToken cancellationToken = default)
=> LoadAsync(Configuration.Default, stream, cancellationToken);
=> LoadAsync(DecoderOptions.Default, stream, cancellationToken);
/// <summary>
/// Decode a new instance of the <see cref="Image"/> class from the given stream.
/// The pixel format is selected by the decoder.
/// </summary>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="ArgumentNullException">The decoder is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Stream stream, IImageDecoder decoder)
=> Load(Configuration.Default, stream, decoder);
/// <summary>
/// Decode a new instance of the <see cref="Image"/> class from the given stream.
/// The pixel format is selected by the decoder.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="decoder">The decoder.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="ArgumentNullException">The decoder is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
public static Task<Image> LoadAsync(Stream stream, IImageDecoder decoder, CancellationToken cancellationToken = default)
=> LoadAsync(Configuration.Default, stream, decoder, cancellationToken);
/// <summary>
/// Decode a new instance of the <see cref="Image"/> class from the given stream.
/// The pixel format is selected by the decoder.
/// </summary>
/// <param name="configuration">The configuration for the decoder.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="ArgumentNullException">The decoder is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A new <see cref="Image"/>.</returns>
public static Image Load(Configuration configuration, Stream stream, IImageDecoder decoder)
{
Guard.NotNull(decoder, nameof(decoder));
return WithSeekableStream(configuration, stream, s => decoder.Decode(configuration, s, default));
}
public static Image Load(DecoderOptions options, Stream stream)
=> Load(options, stream, out _);
/// <summary>
/// Decode a new instance of the <see cref="Image"/> class from the given stream.
/// The pixel format is selected by the decoder.
/// </summary>
/// <param name="configuration">The configuration for the decoder.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="decoder">The decoder.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="ArgumentNullException">The decoder is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
public static Task<Image> LoadAsync(
Configuration configuration,
Stream stream,
IImageDecoder decoder,
CancellationToken cancellationToken = default)
public static async Task<Image> LoadAsync(DecoderOptions options, Stream stream, CancellationToken cancellationToken = default)
{
Guard.NotNull(decoder, nameof(decoder));
return WithSeekableStreamAsync(
configuration,
stream,
(s, ct) => decoder.Decode(configuration, s, ct),
cancellationToken);
}
/// <summary>
/// Decode a new instance of the <see cref="Image"/> class from the given stream.
/// </summary>
/// <param name="configuration">The configuration for the decoder.</param>
/// <param name="stream">The stream containing image information.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A new <see cref="Image"/>.</returns>
public static Image Load(Configuration configuration, Stream stream) => Load(configuration, stream, out _);
/// <summary>
/// Decode a new instance of the <see cref="Image"/> class from the given stream.
/// </summary>
/// <param name="configuration">The configuration for the decoder.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
public static async Task<Image> LoadAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken = default)
{
(Image Image, IImageFormat Format) fmt = await LoadWithFormatAsync(configuration, stream, cancellationToken)
(Image Image, IImageFormat Format) fmt = await LoadWithFormatAsync(options, stream, cancellationToken)
.ConfigureAwait(false);
return fmt.Image;
}
@ -389,7 +310,7 @@ namespace SixLabors.ImageSharp
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
=> Load<TPixel>(Configuration.Default, stream);
=> Load<TPixel>(DecoderOptions.Default, stream);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
@ -404,7 +325,7 @@ namespace SixLabors.ImageSharp
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
public static Task<Image<TPixel>> LoadAsync<TPixel>(Stream stream, CancellationToken cancellationToken = default)
where TPixel : unmanaged, IPixel<TPixel>
=> LoadAsync<TPixel>(Configuration.Default, stream, cancellationToken);
=> LoadAsync<TPixel>(DecoderOptions.Default, stream, cancellationToken);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
@ -419,7 +340,7 @@ namespace SixLabors.ImageSharp
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Stream stream, out IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel>
=> Load<TPixel>(Configuration.Default, stream, out format);
=> Load<TPixel>(DecoderOptions.Default, stream, out format);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
@ -434,119 +355,41 @@ namespace SixLabors.ImageSharp
/// <returns>A <see cref="Task{ValueTuple}"/> representing the asynchronous operation.</returns>
public static Task<(Image<TPixel> Image, IImageFormat Format)> LoadWithFormatAsync<TPixel>(Stream stream, CancellationToken cancellationToken = default)
where TPixel : unmanaged, IPixel<TPixel>
=> LoadWithFormatAsync<TPixel>(Configuration.Default, stream, cancellationToken);
=> LoadWithFormatAsync<TPixel>(DecoderOptions.Default, stream, cancellationToken);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Stream stream, IImageDecoder decoder)
public static Image<TPixel> Load<TPixel>(DecoderOptions options, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
=> WithSeekableStream(Configuration.Default, stream, s => decoder.Decode<TPixel>(Configuration.Default, s, default));
=> Load<TPixel>(options, stream, out IImageFormat _);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="decoder">The decoder.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static Task<Image<TPixel>> LoadAsync<TPixel>(Stream stream, IImageDecoder decoder, CancellationToken cancellationToken = default)
where TPixel : unmanaged, IPixel<TPixel>
=> WithSeekableStreamAsync(
Configuration.Default,
stream,
(s, ct) => decoder.Decode<TPixel>(Configuration.Default, s, ct),
cancellationToken);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary>
/// <param name="configuration">The Configuration.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration configuration, Stream stream, IImageDecoder decoder)
where TPixel : unmanaged, IPixel<TPixel>
=> WithSeekableStream(configuration, stream, s => decoder.Decode<TPixel>(configuration, s, default));
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary>
/// <param name="configuration">The Configuration.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="decoder">The decoder.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static Task<Image<TPixel>> LoadAsync<TPixel>(
Configuration configuration,
Stream stream,
IImageDecoder decoder,
CancellationToken cancellationToken = default)
where TPixel : unmanaged, IPixel<TPixel>
=> WithSeekableStreamAsync(
configuration,
stream,
(s, ct) => decoder.Decode<TPixel>(configuration, s, ct),
cancellationToken);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary>
/// <param name="configuration">The configuration options.</param>
/// <param name="stream">The stream containing image information.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration configuration, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
=> Load<TPixel>(configuration, stream, out IImageFormat _);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary>
/// <param name="configuration">The configuration options.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="format">The format type of the decoded image.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static Image<TPixel> Load<TPixel>(Configuration configuration, Stream stream, out IImageFormat format)
public static Image<TPixel> Load<TPixel>(DecoderOptions options, Stream stream, out IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel>
{
(Image<TPixel> Image, IImageFormat Format) data = WithSeekableStream(configuration, stream, s => Decode<TPixel>(s, configuration));
(Image<TPixel> Image, IImageFormat Format) data = WithSeekableStream(options, stream, s => Decode<TPixel>(options, s));
format = data.Format;
@ -558,7 +401,7 @@ namespace SixLabors.ImageSharp
var sb = new StringBuilder();
sb.AppendLine("Image cannot be loaded. Available decoders:");
foreach (KeyValuePair<IImageFormat, IImageDecoder> val in configuration.ImageFormatsManager.ImageDecoders)
foreach (KeyValuePair<IImageFormat, IImageDecoder> val in options.Configuration.ImageFormatsManager.ImageDecoders)
{
sb.AppendFormat(" - {0} : {1}{2}", val.Key.Name, val.Value.GetType().Name, Environment.NewLine);
}
@ -569,24 +412,24 @@ namespace SixLabors.ImageSharp
/// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given stream.
/// </summary>
/// <param name="configuration">The configuration options.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A <see cref="Task{ValueTuple}"/> representing the asynchronous operation.</returns>
public static async Task<(Image Image, IImageFormat Format)> LoadWithFormatAsync(
Configuration configuration,
DecoderOptions options,
Stream stream,
CancellationToken cancellationToken = default)
{
(Image Image, IImageFormat Format) data = await WithSeekableStreamAsync(
configuration,
options,
stream,
(s, ct) => Decode(s, configuration, ct),
(s, ct) => Decode(options, s, ct),
cancellationToken)
.ConfigureAwait(false);
@ -598,7 +441,7 @@ namespace SixLabors.ImageSharp
var sb = new StringBuilder();
sb.AppendLine("Image cannot be loaded. Available decoders:");
foreach (KeyValuePair<IImageFormat, IImageDecoder> val in configuration.ImageFormatsManager.ImageDecoders)
foreach (KeyValuePair<IImageFormat, IImageDecoder> val in options.Configuration.ImageFormatsManager.ImageDecoders)
{
sb.AppendFormat(" - {0} : {1}{2}", val.Key.Name, val.Value.GetType().Name, Environment.NewLine);
}
@ -609,10 +452,10 @@ namespace SixLabors.ImageSharp
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary>
/// <param name="configuration">The configuration options.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
@ -620,16 +463,16 @@ namespace SixLabors.ImageSharp
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A <see cref="Task{ValueTuple}"/> representing the asynchronous operation.</returns>
public static async Task<(Image<TPixel> Image, IImageFormat Format)> LoadWithFormatAsync<TPixel>(
Configuration configuration,
DecoderOptions options,
Stream stream,
CancellationToken cancellationToken = default)
where TPixel : unmanaged, IPixel<TPixel>
{
(Image<TPixel> Image, IImageFormat Format) data =
await WithSeekableStreamAsync(
configuration,
options,
stream,
(s, ct) => Decode<TPixel>(s, configuration, ct),
(s, ct) => Decode<TPixel>(options, s, ct),
cancellationToken)
.ConfigureAwait(false);
@ -641,7 +484,7 @@ namespace SixLabors.ImageSharp
var sb = new StringBuilder();
sb.AppendLine("Image cannot be loaded. Available decoders:");
foreach (KeyValuePair<IImageFormat, IImageDecoder> val in configuration.ImageFormatsManager.ImageDecoders)
foreach (KeyValuePair<IImageFormat, IImageDecoder> val in options.Configuration.ImageFormatsManager.ImageDecoders)
{
sb.AppendFormat(" - {0} : {1}{2}", val.Key.Name, val.Value.GetType().Name, Environment.NewLine);
}
@ -652,10 +495,10 @@ namespace SixLabors.ImageSharp
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary>
/// <param name="configuration">The configuration options.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
@ -663,12 +506,12 @@ namespace SixLabors.ImageSharp
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static async Task<Image<TPixel>> LoadAsync<TPixel>(
Configuration configuration,
DecoderOptions options,
Stream stream,
CancellationToken cancellationToken = default)
where TPixel : unmanaged, IPixel<TPixel>
{
(Image<TPixel> img, _) = await LoadWithFormatAsync<TPixel>(configuration, stream, cancellationToken)
(Image<TPixel> img, _) = await LoadWithFormatAsync<TPixel>(options, stream, cancellationToken)
.ConfigureAwait(false);
return img;
}
@ -677,30 +520,30 @@ namespace SixLabors.ImageSharp
/// Decode a new instance of the <see cref="Image"/> class from the given stream.
/// The pixel format is selected by the decoder.
/// </summary>
/// <param name="configuration">The configuration options.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="format">The format type of the decoded image.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image Load(Configuration configuration, Stream stream, out IImageFormat format)
public static Image Load(DecoderOptions options, Stream stream, out IImageFormat format)
{
(Image Img, IImageFormat Format) data = WithSeekableStream(configuration, stream, s => Decode(s, configuration));
(Image img, IImageFormat fmt) = WithSeekableStream(options, stream, s => Decode(options, s));
format = data.Format;
format = fmt;
if (data.Img != null)
if (img != null)
{
return data.Img;
return img;
}
var sb = new StringBuilder();
sb.AppendLine("Image cannot be loaded. Available decoders:");
foreach (KeyValuePair<IImageFormat, IImageDecoder> val in configuration.ImageFormatsManager.ImageDecoders)
foreach (KeyValuePair<IImageFormat, IImageDecoder> val in options.Configuration.ImageFormatsManager.ImageDecoders)
{
sb.AppendFormat(" - {0} : {1}{2}", val.Key.Name, val.Value.GetType().Name, Environment.NewLine);
}
@ -712,16 +555,16 @@ namespace SixLabors.ImageSharp
/// Performs the given action against the stream ensuring that it is seekable.
/// </summary>
/// <typeparam name="T">The type of object returned from the action.</typeparam>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The input stream.</param>
/// <param name="action">The action to perform.</param>
/// <returns>The <typeparamref name="T"/>.</returns>
private static T WithSeekableStream<T>(
Configuration configuration,
DecoderOptions options,
Stream stream,
Func<Stream, T> action)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.NotNull(options, nameof(options));
Guard.NotNull(stream, nameof(stream));
if (!stream.CanRead)
@ -729,6 +572,7 @@ namespace SixLabors.ImageSharp
throw new NotSupportedException("Cannot read from the stream.");
}
Configuration configuration = options.Configuration;
if (stream.CanSeek)
{
if (configuration.ReadOrigin == ReadOrigin.Begin)
@ -751,18 +595,18 @@ namespace SixLabors.ImageSharp
/// Performs the given action asynchronously against the stream ensuring that it is seekable.
/// </summary>
/// <typeparam name="T">The type of object returned from the action.</typeparam>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The input stream.</param>
/// <param name="action">The action to perform.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The <see cref="Task{T}"/>.</returns>
private static async Task<T> WithSeekableStreamAsync<T>(
Configuration configuration,
DecoderOptions options,
Stream stream,
Func<Stream, CancellationToken, T> action,
CancellationToken cancellationToken)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.NotNull(options, nameof(options));
Guard.NotNull(stream, nameof(stream));
if (!stream.CanRead)
@ -770,6 +614,7 @@ namespace SixLabors.ImageSharp
throw new NotSupportedException("Cannot read from the stream.");
}
Configuration configuration = options.Configuration;
if (stream.CanSeek)
{
if (configuration.ReadOrigin == ReadOrigin.Begin)

68
src/ImageSharp/Image.LoadPixelData.cs

@ -16,20 +16,7 @@ namespace SixLabors.ImageSharp
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the raw <typeparamref name="TPixel"/> data.
/// </summary>
/// <param name="data">The byte array containing image data.</param>
/// <param name="width">The width of the final image.</param>
/// <param name="height">The height of the final image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <exception cref="ArgumentException">The data length is incorrect.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> LoadPixelData<TPixel>(TPixel[] data, int width, int height)
where TPixel : unmanaged, IPixel<TPixel>
=> LoadPixelData(Configuration.Default, data, width, height);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the raw <typeparamref name="TPixel"/> data.
/// </summary>
/// <param name="data">The byte array containing image data.</param>
/// <param name="data">The readonly span of bytes containing image data.</param>
/// <param name="width">The width of the final image.</param>
/// <param name="height">The height of the final image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
@ -40,22 +27,9 @@ namespace SixLabors.ImageSharp
=> LoadPixelData(Configuration.Default, data, width, height);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array in <typeparamref name="TPixel"/> format.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given readonly span of bytes in <typeparamref name="TPixel"/> format.
/// </summary>
/// <param name="data">The byte array containing image data.</param>
/// <param name="width">The width of the final image.</param>
/// <param name="height">The height of the final image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <exception cref="ArgumentException">The data length is incorrect.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> LoadPixelData<TPixel>(byte[] data, int width, int height)
where TPixel : unmanaged, IPixel<TPixel>
=> LoadPixelData<TPixel>(Configuration.Default, data, width, height);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array in <typeparamref name="TPixel"/> format.
/// </summary>
/// <param name="data">The byte array containing image data.</param>
/// <param name="data">The readonly span of bytes containing image data.</param>
/// <param name="width">The width of the final image.</param>
/// <param name="height">The height of the final image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
@ -66,25 +40,10 @@ namespace SixLabors.ImageSharp
=> LoadPixelData<TPixel>(Configuration.Default, data, width, height);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array in <typeparamref name="TPixel"/> format.
/// </summary>
/// <param name="configuration">The configuration for the decoder.</param>
/// <param name="data">The byte array containing image data.</param>
/// <param name="width">The width of the final image.</param>
/// <param name="height">The height of the final image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentException">The data length is incorrect.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> LoadPixelData<TPixel>(Configuration configuration, byte[] data, int width, int height)
where TPixel : unmanaged, IPixel<TPixel>
=> LoadPixelData(configuration, MemoryMarshal.Cast<byte, TPixel>(new ReadOnlySpan<byte>(data)), width, height);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array in <typeparamref name="TPixel"/> format.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given readonly span of bytes in <typeparamref name="TPixel"/> format.
/// </summary>
/// <param name="configuration">The configuration for the decoder.</param>
/// <param name="data">The byte array containing image data.</param>
/// <param name="data">The readonly span of bytes containing image data.</param>
/// <param name="width">The width of the final image.</param>
/// <param name="height">The height of the final image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
@ -99,22 +58,7 @@ namespace SixLabors.ImageSharp
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the raw <typeparamref name="TPixel"/> data.
/// </summary>
/// <param name="configuration">The configuration for the decoder.</param>
/// <param name="data">The Span containing the image Pixel data.</param>
/// <param name="width">The width of the final image.</param>
/// <param name="height">The height of the final image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentException">The data length is incorrect.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> LoadPixelData<TPixel>(Configuration configuration, TPixel[] data, int width, int height)
where TPixel : unmanaged, IPixel<TPixel>
=> LoadPixelData(configuration, new ReadOnlySpan<TPixel>(data), width, height);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the raw <typeparamref name="TPixel"/> data.
/// </summary>
/// <param name="configuration">The configuration for the decoder.</param>
/// <param name="data">The Span containing the image Pixel data.</param>
/// <param name="data">The readonly span containing the image pixel data.</param>
/// <param name="width">The width of the final image.</param>
/// <param name="height">The height of the final image.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>

35
tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs

@ -13,6 +13,7 @@ using System.Runtime.InteropServices;
using System.Threading.Tasks;
using ImageMagick;
using PhotoSauce.MagicScaler;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Tests;
@ -157,7 +158,7 @@ namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
this.TotalProcessedMegapixels += pixels / 1_000_000.0;
}
private string OutputPath(string inputPath, [CallerMemberName]string postfix = null) =>
private string OutputPath(string inputPath, [CallerMemberName] string postfix = null) =>
Path.Combine(
this.outputDirectory,
Path.GetFileNameWithoutExtension(inputPath) + "-" + postfix + Path.GetExtension(inputPath));
@ -208,18 +209,15 @@ namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
using FileStream outputStream = File.Open(this.OutputPath(input), FileMode.Create);
// Resize it to fit a 150x150 square
var targetSize = new ImageSharpSize(this.ThumbnailSize, this.ThumbnailSize);
DecoderOptions options = new()
{
TargetSize = new ImageSharpSize(this.ThumbnailSize, this.ThumbnailSize)
};
var decoder = new JpegDecoder();
using ImageSharpImage image = decoder.DecodeInto(Configuration.Default, inputStream, targetSize, default);
using ImageSharpImage image = decoder.Decode(options, inputStream, default);
this.LogImageProcessed(image.Width, image.Height);
image.Mutate(i => i.Resize(new ResizeOptions
{
Size = targetSize,
Mode = ResizeMode.Max,
Sampler = KnownResamplers.Box
}));
// Reduce the size of the file
image.Metadata.ExifProfile = null;
image.Metadata.XmpProfile = null;
@ -235,18 +233,19 @@ namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
using FileStream output = File.Open(this.OutputPath(input), FileMode.Create);
// Resize it to fit a 150x150 square.
using ImageSharpImage image = await ImageSharpImage.LoadAsync(input);
this.LogImageProcessed(image.Width, image.Height);
// Resize checks whether image size and target sizes are equal
image.Mutate(i => i.Resize(new ResizeOptions
DecoderOptions options = new()
{
Size = new ImageSharpSize(this.ThumbnailSize, this.ThumbnailSize),
Mode = ResizeMode.Max
}));
TargetSize = new ImageSharpSize(this.ThumbnailSize, this.ThumbnailSize)
};
using ImageSharpImage image = await ImageSharpImage.LoadAsync(options, input);
this.LogImageProcessed(image.Width, image.Height);
// Reduce the size of the file
image.Metadata.ExifProfile = null;
image.Metadata.XmpProfile = null;
image.Metadata.IccProfile = null;
image.Metadata.IptcProfile = null;
// Save the results
await image.SaveAsync(output, this.imageSharpJpegEncoder);

Loading…
Cancel
Save