mirror of https://github.com/SixLabors/ImageSharp
33 changed files with 266 additions and 301 deletions
@ -1,56 +0,0 @@ |
|||||
// Copyright (c) Six Labors.
|
|
||||
// Licensed under the Six Labors Split License.
|
|
||||
|
|
||||
using SixLabors.ImageSharp.Advanced; |
|
||||
using SixLabors.ImageSharp.PixelFormats; |
|
||||
|
|
||||
namespace SixLabors.ImageSharp.Formats; |
|
||||
|
|
||||
internal static class ImageEncoderUtilities |
|
||||
{ |
|
||||
public static async Task EncodeAsync<TPixel>( |
|
||||
this IImageEncoderInternals encoder, |
|
||||
Image<TPixel> image, |
|
||||
Stream stream, |
|
||||
CancellationToken cancellationToken) |
|
||||
where TPixel : unmanaged, IPixel<TPixel> |
|
||||
{ |
|
||||
Configuration configuration = image.GetConfiguration(); |
|
||||
if (stream.CanSeek) |
|
||||
{ |
|
||||
await DoEncodeAsync(stream).ConfigureAwait(false); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
using MemoryStream ms = new(); |
|
||||
await DoEncodeAsync(ms); |
|
||||
ms.Position = 0; |
|
||||
await ms.CopyToAsync(stream, configuration.StreamProcessingBufferSize, cancellationToken) |
|
||||
.ConfigureAwait(false); |
|
||||
} |
|
||||
|
|
||||
Task DoEncodeAsync(Stream innerStream) |
|
||||
{ |
|
||||
try |
|
||||
{ |
|
||||
encoder.Encode(image, innerStream, cancellationToken); |
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
catch (OperationCanceledException) |
|
||||
{ |
|
||||
return Task.FromCanceled(cancellationToken); |
|
||||
} |
|
||||
catch (Exception ex) |
|
||||
{ |
|
||||
return Task.FromException(ex); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public static void Encode<TPixel>( |
|
||||
this IImageEncoderInternals encoder, |
|
||||
Image<TPixel> image, |
|
||||
Stream stream) |
|
||||
where TPixel : unmanaged, IPixel<TPixel> |
|
||||
=> encoder.Encode(image, stream, default); |
|
||||
} |
|
||||
@ -0,0 +1,23 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
using SixLabors.ImageSharp.Processing; |
||||
|
using SixLabors.ImageSharp.Processing.Processors.Quantization; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Acts as a base class for all image encoders that allow color palette generation via quantization.
|
||||
|
/// </summary>
|
||||
|
public abstract class QuantizingImageEncoder : SynchronousImageEncoder |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets the quantizer used to generate the color palette.
|
||||
|
/// </summary>
|
||||
|
public IQuantizer Quantizer { get; init; } = KnownQuantizers.Octree; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the <see cref="IPixelSamplingStrategy"/> used for quantization when building color palettes.
|
||||
|
/// </summary>
|
||||
|
public IPixelSamplingStrategy PixelSamplingStrategy { get; init; } = new DefaultPixelSamplingStrategy(); |
||||
|
} |
||||
@ -0,0 +1,94 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
using SixLabors.ImageSharp.Advanced; |
||||
|
using SixLabors.ImageSharp.IO; |
||||
|
using SixLabors.ImageSharp.PixelFormats; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Acts as a base class for image encoders.
|
||||
|
/// Types that inherit this encoder are required to implement cancellable synchronous encoding operations only.
|
||||
|
/// </summary>
|
||||
|
public abstract class SynchronousImageEncoder : IImageEncoder |
||||
|
{ |
||||
|
/// <inheritdoc/>
|
||||
|
public bool SkipMetadata { get; init; } |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public void Encode<TPixel>(Image<TPixel> image, Stream stream) |
||||
|
where TPixel : unmanaged, IPixel<TPixel> |
||||
|
=> this.EncodeWithSeekableStream(image, stream, default); |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken) |
||||
|
where TPixel : unmanaged, IPixel<TPixel> |
||||
|
=> this.EncodeWithSeekableStreamAsync(image, stream, cancellationToken); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Encodes the image to the specified stream from the <see cref="Image{TPixel}" />.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// This method is designed to support the ImageSharp internal infrastructure and is not recommended for direct use.
|
||||
|
/// </remarks>
|
||||
|
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
||||
|
/// <param name="image">The <see cref="Image{TPixel}" /> to encode from.</param>
|
||||
|
/// <param name="stream">The <see cref="Stream" /> to encode the image data to.</param>
|
||||
|
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
|
||||
|
protected abstract void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken) |
||||
|
where TPixel : unmanaged, IPixel<TPixel>; |
||||
|
|
||||
|
private void EncodeWithSeekableStream<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken) |
||||
|
where TPixel : unmanaged, IPixel<TPixel> |
||||
|
{ |
||||
|
Configuration configuration = image.GetConfiguration(); |
||||
|
if (stream.CanSeek) |
||||
|
{ |
||||
|
this.Encode(image, stream, cancellationToken); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
using ChunkedMemoryStream ms = new(configuration.MemoryAllocator); |
||||
|
this.Encode(image, stream, cancellationToken); |
||||
|
ms.Position = 0; |
||||
|
ms.CopyTo(stream, configuration.StreamProcessingBufferSize); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private async Task EncodeWithSeekableStreamAsync<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken) |
||||
|
where TPixel : unmanaged, IPixel<TPixel> |
||||
|
{ |
||||
|
Configuration configuration = image.GetConfiguration(); |
||||
|
if (stream.CanSeek) |
||||
|
{ |
||||
|
await DoEncodeAsync(stream).ConfigureAwait(false); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
using ChunkedMemoryStream ms = new(configuration.MemoryAllocator); |
||||
|
await DoEncodeAsync(ms); |
||||
|
ms.Position = 0; |
||||
|
await ms.CopyToAsync(stream, configuration.StreamProcessingBufferSize, cancellationToken) |
||||
|
.ConfigureAwait(false); |
||||
|
} |
||||
|
|
||||
|
Task DoEncodeAsync(Stream innerStream) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
// TODO: Are synchronous IO writes OK? We avoid reads.
|
||||
|
this.Encode(image, innerStream, cancellationToken); |
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
catch (OperationCanceledException) |
||||
|
{ |
||||
|
return Task.FromCanceled(cancellationToken); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
return Task.FromException(ex); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue