Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions src/ImageSharp/Advanced/AdvancedImageExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ public static class AdvancedImageExtensions
/// </summary>
/// <param name="source">The source image.</param>
/// <param name="filePath">The target file path to save the image to.</param>
/// <exception cref="ArgumentNullException">The file path is null.</exception>
/// <exception cref="NotSupportedException">No encoder available for provided path.</exception>
/// <returns>The matching <see cref="IImageEncoder"/>.</returns>
/// <exception cref="ArgumentNullException">The file path is null.</exception>
/// <exception cref="UnknownImageFormatException">No encoder available for provided path.</exception>
public static IImageEncoder DetectEncoder(this Image source, string filePath)
{
Guard.NotNull(filePath, nameof(filePath));
Expand All @@ -30,27 +30,27 @@ public static IImageEncoder DetectEncoder(this Image source, string filePath)
if (!source.GetConfiguration().ImageFormatsManager.TryFindFormatByFileExtension(ext, out IImageFormat? format))
{
StringBuilder sb = new();
sb.AppendLine(CultureInfo.InvariantCulture, $"No encoder was found for extension '{ext}'. Registered encoders include:");
sb = sb.AppendLine(CultureInfo.InvariantCulture, $"No encoder was found for extension '{ext}'. Registered encoders include:");
foreach (IImageFormat fmt in source.GetConfiguration().ImageFormats)
{
sb.AppendFormat(CultureInfo.InvariantCulture, " - {0} : {1}{2}", fmt.Name, string.Join(", ", fmt.FileExtensions), Environment.NewLine);
sb = sb.AppendFormat(CultureInfo.InvariantCulture, " - {0} : {1}{2}", fmt.Name, string.Join(", ", fmt.FileExtensions), Environment.NewLine);
}

throw new NotSupportedException(sb.ToString());
throw new UnknownImageFormatException(sb.ToString());
}

IImageEncoder? encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format);
IImageEncoder? encoder = source.GetConfiguration().ImageFormatsManager.GetEncoder(format);

if (encoder is null)
{
StringBuilder sb = new();
sb.AppendLine(CultureInfo.InvariantCulture, $"No encoder was found for extension '{ext}' using image format '{format.Name}'. Registered encoders include:");
sb = sb.AppendLine(CultureInfo.InvariantCulture, $"No encoder was found for extension '{ext}' using image format '{format.Name}'. Registered encoders include:");
foreach (KeyValuePair<IImageFormat, IImageEncoder> enc in source.GetConfiguration().ImageFormatsManager.ImageEncoders)
{
sb.AppendFormat(CultureInfo.InvariantCulture, " - {0} : {1}{2}", enc.Key, enc.Value.GetType().Name, Environment.NewLine);
sb = sb.AppendFormat(CultureInfo.InvariantCulture, " - {0} : {1}{2}", enc.Key, enc.Value.GetType().Name, Environment.NewLine);
}

throw new NotSupportedException(sb.ToString());
throw new UnknownImageFormatException(sb.ToString());
}

return encoder;
Expand Down
2 changes: 1 addition & 1 deletion src/ImageSharp/Formats/Bmp/BmpDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ private BmpDecoder()
public static BmpDecoder Instance { get; } = new();

/// <inheritdoc/>
protected override IImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
protected override ImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
Guard.NotNull(options, nameof(options));
Guard.NotNull(stream, nameof(stream));
Expand Down
2 changes: 1 addition & 1 deletion src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
}

/// <inheritdoc />
public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken)
public ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken)
{
this.ReadImageHeaders(stream, out _, out _);
return new ImageInfo(new PixelTypeInfo(this.infoHeader.BitsPerPixel), this.infoHeader.Width, this.infoHeader.Height, this.metadata);
Expand Down
2 changes: 1 addition & 1 deletion src/ImageSharp/Formats/Gif/GifDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ private GifDecoder()
public static GifDecoder Instance { get; } = new();

/// <inheritdoc/>
protected override IImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
protected override ImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
Guard.NotNull(options, nameof(options));
Guard.NotNull(stream, nameof(stream));
Expand Down
2 changes: 1 addition & 1 deletion src/ImageSharp/Formats/Gif/GifDecoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
}

/// <inheritdoc />
public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken)
public ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken)
{
try
{
Expand Down
6 changes: 3 additions & 3 deletions src/ImageSharp/Formats/IImageDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ public interface IImageDecoder
/// </summary>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <returns>The <see cref="IImageInfo"/> object.</returns>
/// <returns>The <see cref="ImageInfo"/> object.</returns>
/// <exception cref="ImageFormatException">Thrown if the encoded image contains errors.</exception>
public IImageInfo Identify(DecoderOptions options, Stream stream);
public ImageInfo Identify(DecoderOptions options, Stream stream);

/// <summary>
/// Reads the raw image information from the specified stream.
Expand All @@ -27,7 +27,7 @@ public interface IImageDecoder
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The <see cref="Task{IImageInfo}"/> object.</returns>
/// <exception cref="ImageFormatException">Thrown if the encoded image contains errors.</exception>
public Task<IImageInfo> IdentifyAsync(DecoderOptions options, Stream stream, CancellationToken cancellationToken = default);
public Task<ImageInfo> IdentifyAsync(DecoderOptions options, Stream stream, CancellationToken cancellationToken = default);

/// <summary>
/// Decodes the image from the specified stream to an <see cref="Image{TPixel}"/> of a specific pixel type.
Expand Down
4 changes: 2 additions & 2 deletions src/ImageSharp/Formats/IImageDecoderInternals.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken cancel
/// </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="IImageInfo"/>.</returns>
/// <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>
IImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken);
ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken);
}
115 changes: 83 additions & 32 deletions src/ImageSharp/Formats/ImageDecoder.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#nullable disable

using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.PixelFormats;
Expand All @@ -17,49 +16,85 @@ public abstract class ImageDecoder : IImageDecoder
/// <inheritdoc/>
public Image<TPixel> Decode<TPixel>(DecoderOptions options, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
=> WithSeekableStream(
options,
stream,
s => this.Decode<TPixel>(options, s, default));
{
Image<TPixel> image = WithSeekableStream(
options,
stream,
s => this.Decode<TPixel>(options, s, default));

this.SetDecoderFormat(options.Configuration, image);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rather than calling this at every overload... could this not just happen inside the Decode() call above? well instead of calling the abstract Decode<>() directly create a DecodeInternal<>() (name?) that calls the abstract method and sets the decoder rather than have to repeat the call on every overload.

Copy link
Member Author

@JimBobSquarePants JimBobSquarePants Jan 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not that I can see. Each of the sync/async calls are different calling the generic/non-generic versions. The overloads are the abstract methods.


return image;
}

/// <inheritdoc/>
public Image Decode(DecoderOptions options, Stream stream)
=> WithSeekableStream(
options,
stream,
s => this.Decode(options, s, default));
{
Image image = WithSeekableStream(
options,
stream,
s => this.Decode(options, s, default));

this.SetDecoderFormat(options.Configuration, image);

return image;
}

/// <inheritdoc/>
public Task<Image<TPixel>> DecodeAsync<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken = default)
public async Task<Image<TPixel>> DecodeAsync<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken = default)
where TPixel : unmanaged, IPixel<TPixel>
=> WithSeekableMemoryStreamAsync(
options,
stream,
(s, ct) => this.Decode<TPixel>(options, s, ct),
cancellationToken);
{
Image<TPixel> image = await WithSeekableMemoryStreamAsync(
options,
stream,
(s, ct) => this.Decode<TPixel>(options, s, ct),
cancellationToken).ConfigureAwait(false);

this.SetDecoderFormat(options.Configuration, image);

return image;
}

/// <inheritdoc/>
public Task<Image> DecodeAsync(DecoderOptions options, Stream stream, CancellationToken cancellationToken = default)
=> WithSeekableMemoryStreamAsync(
public async Task<Image> DecodeAsync(DecoderOptions options, Stream stream, CancellationToken cancellationToken = default)
{
Image image = await WithSeekableMemoryStreamAsync(
options,
stream,
(s, ct) => this.Decode(options, s, ct),
cancellationToken);
cancellationToken).ConfigureAwait(false);

this.SetDecoderFormat(options.Configuration, image);

return image;
}

/// <inheritdoc/>
public IImageInfo Identify(DecoderOptions options, Stream stream)
=> WithSeekableStream(
options,
stream,
s => this.Identify(options, s, default));
public ImageInfo Identify(DecoderOptions options, Stream stream)
{
ImageInfo info = WithSeekableStream(
options,
stream,
s => this.Identify(options, s, default));

this.SetDecoderFormat(options.Configuration, info);

return info;
}

/// <inheritdoc/>
public Task<IImageInfo> IdentifyAsync(DecoderOptions options, Stream stream, CancellationToken cancellationToken = default)
=> WithSeekableMemoryStreamAsync(
options,
stream,
(s, ct) => this.Identify(options, s, ct),
cancellationToken);
public async Task<ImageInfo> IdentifyAsync(DecoderOptions options, Stream stream, CancellationToken cancellationToken = default)
{
ImageInfo info = await WithSeekableMemoryStreamAsync(
options,
stream,
(s, ct) => this.Identify(options, s, ct),
cancellationToken).ConfigureAwait(false);

this.SetDecoderFormat(options.Configuration, info);

return info;
}

/// <summary>
/// Decodes the image from the specified stream to an <see cref="Image{TPixel}" /> of a specific pixel type.
Expand Down Expand Up @@ -98,9 +133,9 @@ protected abstract Image<TPixel> Decode<TPixel>(DecoderOptions options, Stream s
/// <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>
/// <returns>The <see cref="ImageInfo"/> object.</returns>
/// <exception cref="ImageFormatException">Thrown if the encoded image contains errors.</exception>
protected abstract IImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken);
protected abstract ImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken);

/// <summary>
/// Performs a scaling operation against the decoded image. If the target size is not set, or the image size
Expand All @@ -114,7 +149,7 @@ protected static void ScaleToTargetSize(DecoderOptions options, Image image)
{
ResizeOptions resizeOptions = new()
{
Size = options.TargetSize.Value,
Size = options.TargetSize!.Value,
Sampler = options.Sampler,
Mode = ResizeMode.Max
};
Expand Down Expand Up @@ -252,4 +287,20 @@ private static async Task<T> CopyToMemoryStreamAndActionAsync<T>(
memoryStream.Position = 0;
return await action(memoryStream, position, cancellationToken).ConfigureAwait(false);
}

internal void SetDecoderFormat(Configuration configuration, Image image)
{
if (configuration.ImageFormatsManager.TryFindFormatByDecoder(this, out IImageFormat? format))
{
image.Metadata.DecodedImageFormat = format;
}
}

internal void SetDecoderFormat(Configuration configuration, ImageInfo info)
{
if (configuration.ImageFormatsManager.TryFindFormatByDecoder(this, out IImageFormat? format))
{
info.Metadata.DecodedImageFormat = format;
}
}
}
2 changes: 1 addition & 1 deletion src/ImageSharp/Formats/ImageDecoderUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Formats;
/// </summary>
internal static class ImageDecoderUtilities
{
internal static IImageInfo Identify(
internal static ImageInfo Identify(
this IImageDecoderInternals decoder,
Configuration configuration,
Stream stream,
Expand Down
Loading