mirror of https://github.com/SixLabors/ImageSharp
18 changed files with 222 additions and 269 deletions
@ -1,50 +0,0 @@ |
|||||
// Copyright (c) Six Labors.
|
|
||||
// Licensed under the Six Labors Split License.
|
|
||||
|
|
||||
using SixLabors.ImageSharp.IO; |
|
||||
using SixLabors.ImageSharp.PixelFormats; |
|
||||
|
|
||||
namespace SixLabors.ImageSharp.Formats; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Abstraction for shared internals for XXXDecoderCore implementations to be used with <see cref="ImageDecoderUtilities"/>.
|
|
||||
/// </summary>
|
|
||||
internal interface IImageDecoderInternals |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets the general decoder options.
|
|
||||
/// </summary>
|
|
||||
DecoderOptions Options { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the dimensions of the image being decoded.
|
|
||||
/// </summary>
|
|
||||
Size Dimensions { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Decodes the image from the specified stream.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|
||||
/// <param name="stream">The stream, where the image should be decoded from. Cannot be null.</param>
|
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
|
|
||||
/// <exception cref="ArgumentNullException"><paramref name="stream"/> is null.</exception>
|
|
||||
/// <returns>The decoded image.</returns>
|
|
||||
/// <remarks>
|
|
||||
/// Cancellable synchronous method. In case of cancellation,
|
|
||||
/// an <see cref="OperationCanceledException"/> shall be thrown which will be handled on the call site.
|
|
||||
/// </remarks>
|
|
||||
Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken cancellationToken) |
|
||||
where TPixel : unmanaged, IPixel<TPixel>; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Reads the raw image information from the specified stream.
|
|
||||
/// </summary>
|
|
||||
/// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
|
|
||||
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
|
|
||||
/// <returns>The <see cref="ImageInfo"/>.</returns>
|
|
||||
/// <remarks>
|
|
||||
/// Cancellable synchronous method. In case of cancellation,
|
|
||||
/// an <see cref="OperationCanceledException"/> shall be thrown which will be handled on the call site.
|
|
||||
/// </remarks>
|
|
||||
ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken); |
|
||||
} |
|
||||
@ -0,0 +1,127 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
using SixLabors.ImageSharp.IO; |
||||
|
using SixLabors.ImageSharp.Memory; |
||||
|
using SixLabors.ImageSharp.PixelFormats; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The base class for all stateful image decoders.
|
||||
|
/// </summary>
|
||||
|
internal abstract class ImageDecoderCore |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="ImageDecoderCore"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="options">The general decoder options.</param>
|
||||
|
protected ImageDecoderCore(DecoderOptions options) |
||||
|
=> this.Options = options; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the general decoder options.
|
||||
|
/// </summary>
|
||||
|
public DecoderOptions Options { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the dimensions of the image being decoded.
|
||||
|
/// </summary>
|
||||
|
public Size Dimensions { get; protected internal set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Reads the raw image information from the specified stream.
|
||||
|
/// </summary>
|
||||
|
/// <param name="configuration">The shared configuration.</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="ImageInfo" />.</returns>
|
||||
|
/// <exception cref="InvalidImageContentException">Thrown if the encoded image contains errors.</exception>
|
||||
|
public ImageInfo Identify( |
||||
|
Configuration configuration, |
||||
|
Stream stream, |
||||
|
CancellationToken cancellationToken) |
||||
|
{ |
||||
|
using BufferedReadStream bufferedReadStream = new(configuration, stream, cancellationToken); |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
return this.Identify(bufferedReadStream, cancellationToken); |
||||
|
} |
||||
|
catch (InvalidMemoryOperationException ex) |
||||
|
{ |
||||
|
throw new InvalidImageContentException(this.Dimensions, ex); |
||||
|
} |
||||
|
catch (Exception) |
||||
|
{ |
||||
|
throw; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <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="configuration">The shared configuration.</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="InvalidImageContentException">Thrown if the encoded image contains errors.</exception>
|
||||
|
public Image<TPixel> Decode<TPixel>( |
||||
|
Configuration configuration, |
||||
|
Stream stream, |
||||
|
CancellationToken cancellationToken) |
||||
|
where TPixel : unmanaged, IPixel<TPixel> |
||||
|
{ |
||||
|
// Test may pass a BufferedReadStream in order to monitor EOF hits, if so, use the existing instance.
|
||||
|
BufferedReadStream bufferedReadStream = |
||||
|
stream as BufferedReadStream ?? new BufferedReadStream(configuration, stream, cancellationToken); |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
return this.Decode<TPixel>(bufferedReadStream, cancellationToken); |
||||
|
} |
||||
|
catch (InvalidMemoryOperationException ex) |
||||
|
{ |
||||
|
throw new InvalidImageContentException(this.Dimensions, ex); |
||||
|
} |
||||
|
catch (Exception) |
||||
|
{ |
||||
|
throw; |
||||
|
} |
||||
|
finally |
||||
|
{ |
||||
|
if (bufferedReadStream != stream) |
||||
|
{ |
||||
|
bufferedReadStream.Dispose(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Reads the raw image information from the specified stream.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
|
||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
|
||||
|
/// <returns>The <see cref="ImageInfo"/>.</returns>
|
||||
|
/// <remarks>
|
||||
|
/// Cancellable synchronous method. In case of cancellation,
|
||||
|
/// an <see cref="OperationCanceledException"/> shall be thrown which will be handled on the call site.
|
||||
|
/// </remarks>
|
||||
|
protected abstract ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Decodes the image from the specified stream.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
||||
|
/// <param name="stream">The stream, where the image should be decoded from. Cannot be null.</param>
|
||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
|
||||
|
/// <exception cref="ArgumentNullException"><paramref name="stream"/> is null.</exception>
|
||||
|
/// <returns>The decoded image.</returns>
|
||||
|
/// <remarks>
|
||||
|
/// Cancellable synchronous method. In case of cancellation, an <see cref="OperationCanceledException"/> shall
|
||||
|
/// be thrown which will be handled on the call site.
|
||||
|
/// </remarks>
|
||||
|
protected abstract Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken cancellationToken) |
||||
|
where TPixel : unmanaged, IPixel<TPixel>; |
||||
|
} |
||||
@ -1,81 +0,0 @@ |
|||||
// Copyright (c) Six Labors.
|
|
||||
// Licensed under the Six Labors Split License.
|
|
||||
|
|
||||
using SixLabors.ImageSharp.IO; |
|
||||
using SixLabors.ImageSharp.Memory; |
|
||||
using SixLabors.ImageSharp.PixelFormats; |
|
||||
|
|
||||
namespace SixLabors.ImageSharp.Formats; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Utility methods for <see cref="IImageDecoderInternals"/>.
|
|
||||
/// </summary>
|
|
||||
internal static class ImageDecoderUtilities |
|
||||
{ |
|
||||
internal static ImageInfo Identify( |
|
||||
this IImageDecoderInternals decoder, |
|
||||
Configuration configuration, |
|
||||
Stream stream, |
|
||||
CancellationToken cancellationToken) |
|
||||
{ |
|
||||
using BufferedReadStream bufferedReadStream = new(configuration, stream, cancellationToken); |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
return decoder.Identify(bufferedReadStream, cancellationToken); |
|
||||
} |
|
||||
catch (InvalidMemoryOperationException ex) |
|
||||
{ |
|
||||
throw new InvalidImageContentException(decoder.Dimensions, ex); |
|
||||
} |
|
||||
catch (Exception) |
|
||||
{ |
|
||||
throw; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
internal static Image<TPixel> Decode<TPixel>( |
|
||||
this IImageDecoderInternals decoder, |
|
||||
Configuration configuration, |
|
||||
Stream stream, |
|
||||
CancellationToken cancellationToken) |
|
||||
where TPixel : unmanaged, IPixel<TPixel> |
|
||||
=> decoder.Decode<TPixel>(configuration, stream, DefaultLargeImageExceptionFactory, cancellationToken); |
|
||||
|
|
||||
internal static Image<TPixel> Decode<TPixel>( |
|
||||
this IImageDecoderInternals decoder, |
|
||||
Configuration configuration, |
|
||||
Stream stream, |
|
||||
Func<InvalidMemoryOperationException, Size, InvalidImageContentException> largeImageExceptionFactory, |
|
||||
CancellationToken cancellationToken) |
|
||||
where TPixel : unmanaged, IPixel<TPixel> |
|
||||
{ |
|
||||
// Test may pass a BufferedReadStream in order to monitor EOF hits, if so, use the existing instance.
|
|
||||
BufferedReadStream bufferedReadStream = stream as BufferedReadStream ?? new BufferedReadStream(configuration, stream, cancellationToken); |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
return decoder.Decode<TPixel>(bufferedReadStream, cancellationToken); |
|
||||
} |
|
||||
catch (InvalidMemoryOperationException ex) |
|
||||
{ |
|
||||
throw largeImageExceptionFactory(ex, decoder.Dimensions); |
|
||||
} |
|
||||
catch (Exception) |
|
||||
{ |
|
||||
throw; |
|
||||
} |
|
||||
finally |
|
||||
{ |
|
||||
if (bufferedReadStream != stream) |
|
||||
{ |
|
||||
bufferedReadStream.Dispose(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private static InvalidImageContentException DefaultLargeImageExceptionFactory( |
|
||||
InvalidMemoryOperationException memoryOperationException, |
|
||||
Size dimensions) => |
|
||||
new(dimensions, memoryOperationException); |
|
||||
} |
|
||||
Loading…
Reference in new issue