Browse Source

Remove bounds checks during Emit

pull/1554/head
James Jackson-South 5 years ago
parent
commit
e47c8fcb90
  1. 77
      src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs

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

@ -6,6 +6,7 @@ using System.Buffers.Binary;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Formats.Jpeg.Components;
@ -313,7 +314,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// </summary> /// </summary>
/// <param name="bits">The packed bits.</param> /// <param name="bits">The packed bits.</param>
/// <param name="count">The number of bits</param> /// <param name="count">The number of bits</param>
private void Emit(uint bits, uint count) /// <param name="emitBufferBase">The reference to the emitBuffer.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Emit(uint bits, uint count, ref byte emitBufferBase)
{ {
count += this.bitCount; count += this.bitCount;
bits <<= (int)(32 - count); bits <<= (int)(32 - count);
@ -327,10 +330,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
while (count >= 8) while (count >= 8)
{ {
byte b = (byte)(bits >> 24); byte b = (byte)(bits >> 24);
this.emitBuffer[len++] = b; Unsafe.Add(ref emitBufferBase, len++) = b;
if (b == 0xff) if (b == byte.MaxValue)
{ {
this.emitBuffer[len++] = 0x00; Unsafe.Add(ref emitBufferBase, len++) = byte.MinValue;
} }
bits <<= 8; bits <<= 8;
@ -352,11 +355,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// </summary> /// </summary>
/// <param name="index">The index of the Huffman encoder</param> /// <param name="index">The index of the Huffman encoder</param>
/// <param name="value">The value to encode.</param> /// <param name="value">The value to encode.</param>
/// <param name="emitBufferBase">The reference to the emit buffer.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void EmitHuff(HuffIndex index, int value) private void EmitHuff(HuffIndex index, int value, ref byte emitBufferBase)
{ {
uint x = HuffmanLut.TheHuffmanLut[(int)index].Values[value]; uint x = HuffmanLut.TheHuffmanLut[(int)index].Values[value];
this.Emit(x & ((1 << 24) - 1), x >> 24); this.Emit(x & ((1 << 24) - 1), x >> 24, ref emitBufferBase);
} }
/// <summary> /// <summary>
@ -365,8 +369,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <param name="index">The index of the Huffman encoder</param> /// <param name="index">The index of the Huffman encoder</param>
/// <param name="runLength">The number of copies to encode.</param> /// <param name="runLength">The number of copies to encode.</param>
/// <param name="value">The value to encode.</param> /// <param name="value">The value to encode.</param>
/// <param name="emitBufferBase">The reference to the emit buffer.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void EmitHuffRLE(HuffIndex index, int runLength, int value) private void EmitHuffRLE(HuffIndex index, int runLength, int value, ref byte emitBufferBase)
{ {
int a = value; int a = value;
int b = value; int b = value;
@ -386,10 +391,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
bt = 8 + (uint)BitCountLut[a >> 8]; bt = 8 + (uint)BitCountLut[a >> 8];
} }
this.EmitHuff(index, (int)((uint)(runLength << 4) | bt)); this.EmitHuff(index, (int)((uint)(runLength << 4) | bt), ref emitBufferBase);
if (bt > 0) if (bt > 0)
{ {
this.Emit((uint)b & (uint)((1 << ((int)bt)) - 1), bt); this.Emit((uint)b & (uint)((1 << ((int)bt)) - 1), bt, ref emitBufferBase);
} }
} }
@ -399,7 +404,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="pixels">The pixel accessor providing access to the image pixels.</param> /// <param name="pixels">The pixel accessor providing access to the image pixels.</param>
/// <param name="cancellationToken">The token to monitor for cancellation.</param> /// <param name="cancellationToken">The token to monitor for cancellation.</param>
private void Encode444<TPixel>(Image<TPixel> pixels, CancellationToken cancellationToken) /// <param name="emitBufferBase">The reference to the emit buffer.</param>
private void Encode444<TPixel>(Image<TPixel> pixels, CancellationToken cancellationToken, ref byte emitBufferBase)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
// TODO: Need a JpegScanEncoder<TPixel> class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.) // TODO: Need a JpegScanEncoder<TPixel> class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.)
@ -436,7 +442,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
ref temp1, ref temp1,
ref temp2, ref temp2,
ref onStackLuminanceQuantTable, ref onStackLuminanceQuantTable,
ref unzig); ref unzig,
ref emitBufferBase);
prevDCCb = this.WriteBlock( prevDCCb = this.WriteBlock(
QuantIndex.Chrominance, QuantIndex.Chrominance,
prevDCCb, prevDCCb,
@ -444,7 +452,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
ref temp1, ref temp1,
ref temp2, ref temp2,
ref onStackChrominanceQuantTable, ref onStackChrominanceQuantTable,
ref unzig); ref unzig,
ref emitBufferBase);
prevDCCr = this.WriteBlock( prevDCCr = this.WriteBlock(
QuantIndex.Chrominance, QuantIndex.Chrominance,
prevDCCr, prevDCCr,
@ -452,7 +462,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
ref temp1, ref temp1,
ref temp2, ref temp2,
ref onStackChrominanceQuantTable, ref onStackChrominanceQuantTable,
ref unzig); ref unzig,
ref emitBufferBase);
} }
} }
} }
@ -518,9 +529,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <param name="tempDest2">Temporal block 2</param> /// <param name="tempDest2">Temporal block 2</param>
/// <param name="quant">Quantization table</param> /// <param name="quant">Quantization table</param>
/// <param name="unZig">The 8x8 Unzig block.</param> /// <param name="unZig">The 8x8 Unzig block.</param>
/// <returns> /// <param name="emitBufferBase">The reference to the emit buffer.</param>
/// The <see cref="int"/> /// <returns>The <see cref="int"/>.</returns>
/// </returns>
private int WriteBlock( private int WriteBlock(
QuantIndex index, QuantIndex index,
int prevDC, int prevDC,
@ -528,7 +538,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
ref Block8x8F tempDest1, ref Block8x8F tempDest1,
ref Block8x8F tempDest2, ref Block8x8F tempDest2,
ref Block8x8F quant, ref Block8x8F quant,
ref ZigZag unZig) ref ZigZag unZig,
ref byte emitBufferBase)
{ {
FastFloatingPointDCT.TransformFDCT(ref src, ref tempDest1, ref tempDest2); FastFloatingPointDCT.TransformFDCT(ref src, ref tempDest1, ref tempDest2);
@ -537,7 +548,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
int dc = (int)tempDest2[0]; int dc = (int)tempDest2[0];
// Emit the DC delta. // Emit the DC delta.
this.EmitHuffRLE((HuffIndex)((2 * (int)index) + 0), 0, dc - prevDC); this.EmitHuffRLE((HuffIndex)((2 * (int)index) + 0), 0, dc - prevDC, ref emitBufferBase);
// Emit the AC components. // Emit the AC components.
var h = (HuffIndex)((2 * (int)index) + 1); var h = (HuffIndex)((2 * (int)index) + 1);
@ -555,18 +566,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
{ {
while (runLength > 15) while (runLength > 15)
{ {
this.EmitHuff(h, 0xf0); this.EmitHuff(h, 0xf0, ref emitBufferBase);
runLength -= 16; runLength -= 16;
} }
this.EmitHuffRLE(h, runLength, ac); this.EmitHuffRLE(h, runLength, ac, ref emitBufferBase);
runLength = 0; runLength = 0;
} }
} }
if (runLength > 0) if (runLength > 0)
{ {
this.EmitHuff(h, 0x00); this.EmitHuff(h, 0x00, ref emitBufferBase);
} }
return dc; return dc;
@ -748,9 +759,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// </summary> /// </summary>
/// <param name="app1Length">The length of the data the app1 marker contains.</param> /// <param name="app1Length">The length of the data the app1 marker contains.</param>
private void WriteApp1Header(int app1Length) private void WriteApp1Header(int app1Length)
{ => this.WriteAppHeader(app1Length, JpegConstants.Markers.APP1);
this.WriteAppHeader(app1Length, JpegConstants.Markers.APP1);
}
/// <summary> /// <summary>
/// Writes a AppX header. /// Writes a AppX header.
@ -954,19 +963,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
// TODO: Need a JpegScanEncoder<TPixel> class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.) // TODO: Need a JpegScanEncoder<TPixel> class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.)
// TODO: We should allow grayscale writing. // TODO: We should allow grayscale writing.
this.outputStream.Write(SosHeaderYCbCr); this.outputStream.Write(SosHeaderYCbCr);
ref byte emitBufferBase = ref MemoryMarshal.GetReference<byte>(this.emitBuffer);
switch (this.subsample) switch (this.subsample)
{ {
case JpegSubsample.Ratio444: case JpegSubsample.Ratio444:
this.Encode444(image, cancellationToken); this.Encode444(image, cancellationToken, ref emitBufferBase);
break; break;
case JpegSubsample.Ratio420: case JpegSubsample.Ratio420:
this.Encode420(image, cancellationToken); this.Encode420(image, cancellationToken, ref emitBufferBase);
break; break;
} }
// Pad the last byte with 1's. // Pad the last byte with 1's.
this.Emit(0x7f, 7); this.Emit(0x7f, 7, ref emitBufferBase);
} }
/// <summary> /// <summary>
@ -976,7 +985,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="pixels">The pixel accessor providing access to the image pixels.</param> /// <param name="pixels">The pixel accessor providing access to the image pixels.</param>
/// <param name="cancellationToken">The token to monitor for cancellation.</param> /// <param name="cancellationToken">The token to monitor for cancellation.</param>
private void Encode420<TPixel>(Image<TPixel> pixels, CancellationToken cancellationToken) /// <param name="emitBufferBase">The reference to the emit buffer.</param>
private void Encode420<TPixel>(Image<TPixel> pixels, CancellationToken cancellationToken, ref byte emitBufferBase)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
// TODO: Need a JpegScanEncoder<TPixel> class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.) // TODO: Need a JpegScanEncoder<TPixel> class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.)
@ -1023,7 +1033,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
ref temp1, ref temp1,
ref temp2, ref temp2,
ref onStackLuminanceQuantTable, ref onStackLuminanceQuantTable,
ref unzig); ref unzig,
ref emitBufferBase);
} }
Block8x8F.Scale16X16To8X8(ref b, cb); Block8x8F.Scale16X16To8X8(ref b, cb);
@ -1034,7 +1045,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
ref temp1, ref temp1,
ref temp2, ref temp2,
ref onStackChrominanceQuantTable, ref onStackChrominanceQuantTable,
ref unzig); ref unzig,
ref emitBufferBase);
Block8x8F.Scale16X16To8X8(ref b, cr); Block8x8F.Scale16X16To8X8(ref b, cr);
prevDCCr = this.WriteBlock( prevDCCr = this.WriteBlock(
@ -1044,7 +1056,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
ref temp1, ref temp1,
ref temp2, ref temp2,
ref onStackChrominanceQuantTable, ref onStackChrominanceQuantTable,
ref unzig); ref unzig,
ref emitBufferBase);
} }
} }
} }

Loading…
Cancel
Save