Browse Source

Phase 1: prepare new encoder options API

pull/2120/head
Dmitry Pentin 4 years ago
parent
commit
cad0ed017b
  1. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs
  2. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector.cs
  3. 7
      src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
  4. 2
      src/ImageSharp/Formats/Jpeg/Components/Encoder/JpegComponent.cs
  5. 26
      src/ImageSharp/Formats/Jpeg/Components/Encoder/JpegFrame.cs
  6. 9
      src/ImageSharp/Formats/Jpeg/JpegColorType.cs
  7. 76
      src/ImageSharp/Formats/Jpeg/JpegEncoder.cs
  8. 20
      src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs

2
src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs

@ -46,7 +46,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
protected override void ConvertCoreInplaceToRgb(in ComponentValues values) =>
FromCmykScalar.ConvertCoreInplace(values, this.MaximumValue);
protected override void ConvertCoreVectorizedInplaceFromRgb(in ComponentValues values) => throw new System.NotImplementedException();
protected override void ConvertCoreInplaceFromRgb(in ComponentValues values) => throw new System.NotImplementedException();
}
}

2
src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector.cs

@ -70,7 +70,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
protected override void ConvertCoreInplaceToRgb(in ComponentValues values) =>
FromYccKScalar.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue);
protected override void ConvertCoreVectorizedInplaceFromRgb(in ComponentValues values) => throw new System.NotImplementedException();
protected override void ConvertCoreInplaceFromRgb(in ComponentValues values) => throw new System.NotImplementedException();
}
}

7
src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs

@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
get => this.emitWriteIndex < (uint)this.emitBuffer.Length / 2;
}
public void EncodeScan<TPixel>(JpegFrame frame, Image<TPixel> image, Block8x8F[] quantTables, Configuration configuration, CancellationToken cancellationToken)
public void EncodeInterleavedScan<TPixel>(JpegFrame frame, Image<TPixel> image, Block8x8F[] quantTables, Configuration configuration, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
// DEBUG INITIALIZATION SETUP
@ -199,6 +199,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
this.FlushRemainingBytes();
}
public void EncodeSingleComponentScan<TPixel>(JpegFrame frame, Image<TPixel> image, Block8x8F[] quantTables, Configuration configuration, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
}
/// <summary>
/// Encodes the image with no subsampling.
/// </summary>

2
src/ImageSharp/Formats/Jpeg/Components/Encoder/JpegComponent.cs

@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
{
private readonly MemoryAllocator memoryAllocator;
public JpegComponent(MemoryAllocator memoryAllocator, int horizontalFactor, int verticalFactor, byte quantizationTableIndex)
public JpegComponent(MemoryAllocator memoryAllocator, int horizontalFactor, int verticalFactor, int quantizationTableIndex)
{
this.memoryAllocator = memoryAllocator;

26
src/ImageSharp/Formats/Jpeg/Components/Encoder/JpegFrame.cs

@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
/// </summary>
internal sealed class JpegFrame : IDisposable
{
public JpegFrame(MemoryAllocator allocator, Image image, Decoder.JpegColorSpace colorSpace)
public JpegFrame(Jpeg.JpegFrameConfig frameConfig, MemoryAllocator allocator, Image image, Decoder.JpegColorSpace colorSpace)
{
this.ColorSpace = colorSpace;
@ -19,21 +19,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
this.PixelHeight = image.Height;
// int componentCount = 3;
this.Components = new JpegComponent[]
var componentConfigs = frameConfig.Components;
this.Components = new JpegComponent[componentConfigs.Length];
for (int i = 0; i < this.Components.Length; i++)
{
// RGB
new JpegComponent(allocator, 1, 1, 0) { DcTableId = 0, AcTableId = 1 },
new JpegComponent(allocator, 1, 1, 0) { DcTableId = 0, AcTableId = 1 },
new JpegComponent(allocator, 1, 1, 0) { DcTableId = 0, AcTableId = 1 },
// YCbCr
//new JpegComponent(allocator, 1, 1, 0) { DcTableId = 0, AcTableId = 1 },
//new JpegComponent(allocator, 1, 1, 1) { DcTableId = 2, AcTableId = 3 },
//new JpegComponent(allocator, 1, 1, 1) { DcTableId = 2, AcTableId = 3 },
// Luminance
//new JpegComponent(allocator, 1, 1, 0) { DcTableId = 0, AcTableId = 1 }
};
var componentConfig = componentConfigs[i];
this.Components[i] = new JpegComponent(allocator, componentConfig.HorizontalSampleFactor, componentConfig.VerticalSampleFactor, componentConfig.QuantizatioTableIndex)
{
DcTableId = componentConfig.dcTableSelector,
AcTableId = componentConfig.acTableSelector,
};
}
}
public Decoder.JpegColorSpace ColorSpace { get; }

9
src/ImageSharp/Formats/Jpeg/JpegColorType.cs

@ -41,8 +41,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <summary>
/// YCbCr (luminance, blue chroma, red chroma) color as defined in the ITU-T T.871 specification.
/// This ratio uses half of the vertical and one-fourth the horizontal color resolutions.
///
/// Note: Not supported by the encoder.
/// </summary>
YCbCrRatio410 = 4,
@ -58,9 +56,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <summary>
/// CMYK colorspace (cyan, magenta, yellow, and key black) intended for printing.
///
/// Note: Not supported by the encoder.
/// </summary>
Cmyk = 7,
/// <summary>
/// YCCK colorspace.
/// </summary>
YccK = 8,
}
}

76
src/ImageSharp/Formats/Jpeg/JpegEncoder.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
@ -19,6 +20,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <inheritdoc/>
public JpegColorType? ColorType { get; set; }
public JpegFrameConfig JpegFrameConfig { get; set; }
/// <summary>
/// Encodes the image to the specified stream from the <see cref="Image{TPixel}"/>.
/// </summary>
@ -28,7 +31,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
var encoder = new JpegEncoderCore(this);
var encoder = new JpegEncoderCore(this, this.JpegFrameConfig);
encoder.Encode(image, stream);
}
@ -43,8 +46,77 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
public Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
var encoder = new JpegEncoderCore(this);
var encoder = new JpegEncoderCore(this, this.JpegFrameConfig);
return encoder.EncodeAsync(image, stream, cancellationToken);
}
}
public class JpegFrameConfig
{
public JpegFrameConfig(JpegColorType colorType, int precision)
{
this.ColorType = colorType;
this.Precision = precision;
int componentCount = GetComponentCountFromColorType(colorType);
this.Components = new JpegComponentConfig[componentCount];
static int GetComponentCountFromColorType(JpegColorType colorType)
{
switch (colorType)
{
case JpegColorType.Luminance:
return 1;
case JpegColorType.YCbCrRatio444:
case JpegColorType.YCbCrRatio422:
case JpegColorType.YCbCrRatio420:
case JpegColorType.YCbCrRatio411:
case JpegColorType.YCbCrRatio410:
case JpegColorType.Rgb:
return 3;
case JpegColorType.Cmyk:
case JpegColorType.YccK:
return 4;
default:
throw new ArgumentException($"Unknown jpeg color space: {colorType}");
}
}
}
public JpegColorType ColorType { get; }
public int Precision { get; }
public JpegComponentConfig[] Components { get; }
public JpegFrameConfig PopulateComponent(int index, int id, int hsf, int vsf, int quantIndex, int dcIndex, int acIndex)
{
this.Components[index] = new JpegComponentConfig
{
Id = id,
HorizontalSampleFactor = hsf,
VerticalSampleFactor = vsf,
QuantizatioTableIndex = quantIndex,
dcTableSelector = dcIndex,
acTableSelector = acIndex,
};
return this;
}
}
public class JpegComponentConfig
{
public int Id { get; set; }
public int HorizontalSampleFactor { get; set; }
public int VerticalSampleFactor { get; set; }
public int QuantizatioTableIndex { get; set; }
public int dcTableSelector { get; set; }
public int acTableSelector { get; set; }
}
}

20
src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs

@ -44,6 +44,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// </summary>
private JpegColorType? colorType;
private JpegFrameConfig frameConfig;
/// <summary>
/// The output stream. All attempted writes after the first error become no-ops.
/// </summary>
@ -53,14 +55,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// Initializes a new instance of the <see cref="JpegEncoderCore"/> class.
/// </summary>
/// <param name="options">The options.</param>
public JpegEncoderCore(IJpegEncoderOptions options)
public JpegEncoderCore(IJpegEncoderOptions options, JpegFrameConfig frameConfig)
{
this.quality = options.Quality;
if (IsSupportedColorType(options.ColorType))
{
this.colorType = options.ColorType;
}
this.frameConfig = frameConfig;
this.colorType = frameConfig.ColorType;
}
/// <summary>
@ -87,12 +87,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
ImageMetadata metadata = image.Metadata;
JpegMetadata jpegMetadata = metadata.GetJpegMetadata();
// If the color type was not specified by the user, preserve the color type of the input image.
if (!this.colorType.HasValue)
{
this.colorType = GetFallbackColorType(image);
}
// Compute number of components based on color type in options.
int componentCount = (this.colorType == JpegColorType.Luminance) ? 1 : 3;
ReadOnlySpan<byte> componentIds = this.GetComponentIds();
@ -131,9 +125,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
// Write the scan header.
this.WriteStartOfScan(componentCount, componentIds);
var frame = new Components.Encoder.JpegFrame(Configuration.Default.MemoryAllocator, image, GetTargetColorSpace(this.colorType.Value));
var frame = new Components.Encoder.JpegFrame(this.frameConfig, Configuration.Default.MemoryAllocator, image, GetTargetColorSpace(this.frameConfig.ColorType));
var quantTables = new Block8x8F[] { luminanceQuantTable, chrominanceQuantTable };
new HuffmanScanEncoder(3, stream).EncodeScan(frame, image, quantTables, Configuration.Default, cancellationToken);
new HuffmanScanEncoder(3, stream).EncodeInterleavedScan(frame, image, quantTables, Configuration.Default, cancellationToken);
// Write the End Of Image marker.
this.WriteEndOfImageMarker();

Loading…
Cancel
Save