Browse Source

Implemented non-interleaved encoding

pull/2120/head
Dmitry Pentin 4 years ago
parent
commit
97dc60d171
  1. 47
      src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
  2. 12
      src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs

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

@ -155,18 +155,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
this.FlushRemainingBytes(); this.FlushRemainingBytes();
} }
public void EncodeScanBaselineSingleComponent<TPixel>(JpegFrame frame, SpectralConverter<TPixel> converter, CancellationToken cancellationToken) public void EncodeScanBaselineSingleComponent<TPixel>(JpegComponent component, SpectralConverter<TPixel> converter, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
JpegComponent component = frame.Components[0]; int h = component.HeightInBlocks;
int mcuLines = frame.McusPerColumn;
int w = component.WidthInBlocks; int w = component.WidthInBlocks;
ref HuffmanLut dcHuffmanTable = ref this.dcHuffmanTables[component.DcTableId]; ref HuffmanLut dcHuffmanTable = ref this.dcHuffmanTables[component.DcTableId];
ref HuffmanLut acHuffmanTable = ref this.acHuffmanTables[component.AcTableId]; ref HuffmanLut acHuffmanTable = ref this.acHuffmanTables[component.AcTableId];
for (int i = 0; i < mcuLines; i++) for (int i = 0; i < h; i++)
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
@ -193,6 +191,40 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
} }
} }
public void EncodeScanBaseline(JpegComponent component, CancellationToken cancellationToken)
{
int h = component.HeightInBlocks;
int w = component.WidthInBlocks;
ref HuffmanLut dcHuffmanTable = ref this.dcHuffmanTables[component.DcTableId];
ref HuffmanLut acHuffmanTable = ref this.acHuffmanTables[component.AcTableId];
for (int i = 0; i < h; i++)
{
cancellationToken.ThrowIfCancellationRequested();
// Encode spectral to binary
Span<Block8x8> blockSpan = component.SpectralBlocks.DangerousGetRowSpan(y: i);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (int k = 0; k < w; k++)
{
this.WriteBlock(
component,
ref Unsafe.Add(ref blockRef, k),
ref dcHuffmanTable,
ref acHuffmanTable);
if (this.IsStreamFlushNeeded)
{
this.FlushToStream();
}
}
}
this.FlushRemainingBytes();
}
private void EncodeScanBaselineInterleavedArbitrarySampling<TPixel>(JpegFrame frame, SpectralConverter<TPixel> converter, CancellationToken cancellationToken) private void EncodeScanBaselineInterleavedArbitrarySampling<TPixel>(JpegFrame frame, SpectralConverter<TPixel> converter, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
@ -608,6 +640,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
// Flush cached bytes to the output stream with padding bits // Flush cached bytes to the output stream with padding bits
int lastByteIndex = (this.emitWriteIndex * 4) - valuableBytesCount; int lastByteIndex = (this.emitWriteIndex * 4) - valuableBytesCount;
this.FlushToStream(lastByteIndex); this.FlushToStream(lastByteIndex);
// Clean huffman register
// This is needed for for images with multiples scans
this.bitCount = 0;
this.accumulatedBits = 0;
} }
} }
} }

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

@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
frame.AllocateComponents(fullScan: false); frame.AllocateComponents(fullScan: false);
this.WriteStartOfScan(this.frameConfig.Components); this.WriteStartOfScan(this.frameConfig.Components);
this.scanEncoder.EncodeScanBaselineSingleComponent(frame, spectralConverter, cancellationToken); this.scanEncoder.EncodeScanBaselineSingleComponent(frame.Components[0], spectralConverter, cancellationToken);
} }
else if (this.interleaved ?? jpegMetadata.Interleaved ?? true) else if (this.interleaved ?? jpegMetadata.Interleaved ?? true)
{ {
@ -139,7 +139,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
} }
else else
{ {
throw new NotImplementedException(); frame.AllocateComponents(fullScan: true);
spectralConverter.ConvertFull();
Span<JpegComponentConfig> components = this.frameConfig.Components;
for (int i = 0; i < frame.Components.Length; i++)
{
this.WriteStartOfScan(components.Slice(i, 1));
this.scanEncoder.EncodeScanBaseline(frame.Components[i], cancellationToken);
}
} }
// Write the End Of Image marker. // Write the End Of Image marker.

Loading…
Cancel
Save