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; 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> /// <summary>
/// Gets the pixels buffer. /// Gets the pixels buffer.
/// </summary> /// </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> /// <summary>
/// Gets the subarea that belongs to the Block8x8 defined by block indices /// Gets the subarea that belongs to the Block8x8 defined by block indices
/// </summary> /// </summary>

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

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

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

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

Loading…
Cancel
Save