Browse Source

Get rid of CreatePooled and ReturnPooled methods in JpegPixelArea to separate memory management.

pull/210/head
Mykhailo Matviiv 9 years ago
parent
commit
c97cbb6cd6
  1. 34
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegPixelArea.cs
  2. 18
      src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrImage.cs
  3. 40
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  4. 6
      tests/ImageSharp.Tests/Formats/Jpg/YCbCrImageTests.cs

34
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegPixelArea.cs

@ -24,6 +24,16 @@ namespace ImageSharp.Formats.Jpg
this.Offset = offset;
}
/// <summary>
/// Initializes a new instance of the <see cref="JpegPixelArea" /> struct from existing buffer.
/// <see cref="Stride"/> will be set to <see cref="Buffer2D{T}.Width"/> of <paramref name="pixels"/> and <see cref="Offset"/> will be set to 0.
/// </summary>
/// <param name="pixels">The pixel buffer</param>
public JpegPixelArea(Buffer2D<byte> pixels)
: this(pixels, pixels.Width, 0)
{
}
/// <summary>
/// Gets the pixels buffer.
/// </summary>
@ -64,30 +74,6 @@ namespace ImageSharp.Formats.Jpg
}
}
/// <summary>
/// Creates a new instance of the <see cref="JpegPixelArea" /> struct.
/// Pixel array will be handled by <see cref="Buffer2D{T}"/>, but
/// <see cref="ReturnPooled" /> can be called when the instance is no longer needed.
/// </summary>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <returns>A <see cref="JpegPixelArea" /> with pooled data</returns>
public static JpegPixelArea CreatePooled(int width, int height) => new JpegPixelArea(Buffer2D<byte>.CreateClean(width, height), width, 0);
/// <summary>
/// Dispose <see cref="Pixels" />.
/// </summary>
public void ReturnPooled()
{
if (this.Pixels == null)
{
return;
}
this.Pixels.Dispose();
this.Pixels = null;
}
/// <summary>
/// Gets the subarea that belongs to the Block8x8 defined by block indices
/// </summary>

18
src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrImage.cs

@ -17,17 +17,17 @@ namespace ImageSharp.Formats.Jpg
/// <summary>
/// Gets the luminance components channel as <see cref="JpegPixelArea" />.
/// </summary>
public JpegPixelArea YChannel;
public Buffer2D<byte> YChannel;
/// <summary>
/// Gets the blue chroma components channel as <see cref="JpegPixelArea" />.
/// </summary>
public JpegPixelArea CbChannel;
public Buffer2D<byte> CbChannel;
/// <summary>
/// Gets an offseted <see cref="JpegPixelArea" /> to the Cr channel
/// </summary>
public JpegPixelArea CrChannel;
public Buffer2D<byte> CrChannel;
#pragma warning restore SA1401
/// <summary>
@ -44,9 +44,9 @@ namespace ImageSharp.Formats.Jpg
this.YStride = width;
this.CStride = cSize.Width;
this.YChannel = JpegPixelArea.CreatePooled(width, height);
this.CbChannel = JpegPixelArea.CreatePooled(cSize.Width, cSize.Height);
this.CrChannel = JpegPixelArea.CreatePooled(cSize.Width, cSize.Height);
this.YChannel = Buffer2D<byte>.CreateClean(width, height);
this.CbChannel = Buffer2D<byte>.CreateClean(cSize.Width, cSize.Height);
this.CrChannel = Buffer2D<byte>.CreateClean(cSize.Width, cSize.Height);
}
/// <summary>
@ -106,9 +106,9 @@ namespace ImageSharp.Formats.Jpg
/// </summary>
public void Dispose()
{
this.YChannel.ReturnPooled();
this.CbChannel.ReturnPooled();
this.CrChannel.ReturnPooled();
this.YChannel.Dispose();
this.CbChannel.Dispose();
this.CrChannel.Dispose();
}
/// <summary>

40
src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

@ -223,8 +223,8 @@ namespace ImageSharp.Formats
this.ycbcrImage?.Dispose();
this.InputProcessor.Dispose();
this.grayImage.ReturnPooled();
this.blackImage.ReturnPooled();
this.grayImage.Pixels?.Dispose();
this.blackImage.Pixels?.Dispose();
}
/// <summary>
@ -243,11 +243,11 @@ namespace ImageSharp.Formats
switch (compIndex)
{
case 0:
return this.ycbcrImage.YChannel;
return new JpegPixelArea(this.ycbcrImage.YChannel);
case 1:
return this.ycbcrImage.CbChannel;
return new JpegPixelArea(this.ycbcrImage.CbChannel);
case 2:
return this.ycbcrImage.CrChannel;
return new JpegPixelArea(this.ycbcrImage.CrChannel);
case 3:
return this.blackImage;
default:
@ -586,9 +586,9 @@ namespace ImageSharp.Formats
for (int x = 0; x < image.Width; x++)
{
byte cyan = this.ycbcrImage.YChannel.Pixels[yo + x];
byte magenta = this.ycbcrImage.CbChannel.Pixels[co + (x / scale)];
byte yellow = this.ycbcrImage.CrChannel.Pixels[co + (x / scale)];
byte cyan = this.ycbcrImage.YChannel[yo + x];
byte magenta = this.ycbcrImage.CbChannel[co + (x / scale)];
byte yellow = this.ycbcrImage.CrChannel[co + (x / scale)];
TPixel packed = default(TPixel);
this.PackCmyk(ref packed, cyan, magenta, yellow, x, y);
@ -655,9 +655,9 @@ namespace ImageSharp.Formats
for (int x = 0; x < image.Width; x++)
{
byte red = this.ycbcrImage.YChannel.Pixels[yo + x];
byte green = this.ycbcrImage.CbChannel.Pixels[co + (x / scale)];
byte blue = this.ycbcrImage.CrChannel.Pixels[co + (x / scale)];
byte red = this.ycbcrImage.YChannel[yo + x];
byte green = this.ycbcrImage.CbChannel[co + (x / scale)];
byte blue = this.ycbcrImage.CrChannel[co + (x / scale)];
TPixel packed = default(TPixel);
packed.PackFromBytes(red, green, blue, 255);
@ -687,9 +687,9 @@ namespace ImageSharp.Formats
y =>
{
// TODO. This Parallel loop doesn't give us the boost it should.
ref byte ycRef = ref this.ycbcrImage.YChannel.Pixels[0];
ref byte cbRef = ref this.ycbcrImage.CbChannel.Pixels[0];
ref byte crRef = ref this.ycbcrImage.CrChannel.Pixels[0];
ref byte ycRef = ref this.ycbcrImage.YChannel[0];
ref byte cbRef = ref this.ycbcrImage.CbChannel[0];
ref byte crRef = ref this.ycbcrImage.CrChannel[0];
fixed (YCbCrToRgbTables* tables = &yCbCrToRgbTables)
{
// TODO: Simplify + optimize + share duplicate code across converter methods
@ -737,9 +737,9 @@ namespace ImageSharp.Formats
for (int x = 0; x < image.Width; x++)
{
byte yy = this.ycbcrImage.YChannel.Pixels[yo + x];
byte cb = this.ycbcrImage.CbChannel.Pixels[co + (x / scale)];
byte cr = this.ycbcrImage.CrChannel.Pixels[co + (x / scale)];
byte yy = this.ycbcrImage.YChannel[yo + x];
byte cb = this.ycbcrImage.CbChannel[co + (x / scale)];
byte cr = this.ycbcrImage.CrChannel[co + (x / scale)];
TPixel packed = default(TPixel);
this.PackYcck(ref packed, yy, cb, cr, x, y);
@ -787,7 +787,8 @@ namespace ImageSharp.Formats
if (this.ComponentCount == 1)
{
this.grayImage = JpegPixelArea.CreatePooled(8 * this.MCUCountX, 8 * this.MCUCountY);
Buffer2D<byte> buffer = Buffer2D<byte>.CreateClean(8 * this.MCUCountX, 8 * this.MCUCountY);
this.grayImage = new JpegPixelArea(buffer);
}
else
{
@ -826,7 +827,8 @@ namespace ImageSharp.Formats
int h3 = this.ComponentArray[3].HorizontalFactor;
int v3 = this.ComponentArray[3].VerticalFactor;
this.blackImage = JpegPixelArea.CreatePooled(8 * h3 * this.MCUCountX, 8 * v3 * this.MCUCountY);
Buffer2D<byte> buffer = Buffer2D<byte>.CreateClean(8 * h3 * this.MCUCountX, 8 * v3 * this.MCUCountY);
this.blackImage = new JpegPixelArea(buffer);
}
}
}

6
tests/ImageSharp.Tests/Formats/Jpg/YCbCrImageTests.cs

@ -61,9 +61,9 @@ namespace ImageSharp.Tests
//this.PrintChannel("Cb", img.CbChannel);
//this.PrintChannel("Cr", img.CrChannel);
Assert.Equal(img.YChannel.Stride, 400);
Assert.Equal(img.CbChannel.Stride, 400 / expectedCStrideDiv);
Assert.Equal(img.CrChannel.Stride, 400 / expectedCStrideDiv);
Assert.Equal(img.YChannel.Width, 400);
Assert.Equal(img.CbChannel.Width, 400 / expectedCStrideDiv);
Assert.Equal(img.CrChannel.Width, 400 / expectedCStrideDiv);
}
}

Loading…
Cancel
Save