From c97cbb6cd647c79c2decb8e3bad0e2875e8ed7bd Mon Sep 17 00:00:00 2001 From: Mykhailo Matviiv Date: Sun, 7 May 2017 14:29:42 +0300 Subject: [PATCH] Get rid of CreatePooled and ReturnPooled methods in JpegPixelArea to separate memory management. --- .../Jpeg/Components/Decoder/JpegPixelArea.cs | 34 +++++----------- .../Jpeg/Components/Decoder/YCbCrImage.cs | 18 ++++----- .../Formats/Jpeg/JpegDecoderCore.cs | 40 ++++++++++--------- .../Formats/Jpg/YCbCrImageTests.cs | 6 +-- 4 files changed, 43 insertions(+), 55 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegPixelArea.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegPixelArea.cs index e46994c32..920457a0c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegPixelArea.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegPixelArea.cs @@ -24,6 +24,16 @@ namespace ImageSharp.Formats.Jpg this.Offset = offset; } + /// + /// Initializes a new instance of the struct from existing buffer. + /// will be set to of and will be set to 0. + /// + /// The pixel buffer + public JpegPixelArea(Buffer2D pixels) + : this(pixels, pixels.Width, 0) + { + } + /// /// Gets the pixels buffer. /// @@ -64,30 +74,6 @@ namespace ImageSharp.Formats.Jpg } } - /// - /// Creates a new instance of the struct. - /// Pixel array will be handled by , but - /// can be called when the instance is no longer needed. - /// - /// The width. - /// The height. - /// A with pooled data - public static JpegPixelArea CreatePooled(int width, int height) => new JpegPixelArea(Buffer2D.CreateClean(width, height), width, 0); - - /// - /// Dispose . - /// - public void ReturnPooled() - { - if (this.Pixels == null) - { - return; - } - - this.Pixels.Dispose(); - this.Pixels = null; - } - /// /// Gets the subarea that belongs to the Block8x8 defined by block indices /// diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrImage.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrImage.cs index a5ca9796b..86192318b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrImage.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrImage.cs @@ -17,17 +17,17 @@ namespace ImageSharp.Formats.Jpg /// /// Gets the luminance components channel as . /// - public JpegPixelArea YChannel; + public Buffer2D YChannel; /// /// Gets the blue chroma components channel as . /// - public JpegPixelArea CbChannel; + public Buffer2D CbChannel; /// /// Gets an offseted to the Cr channel /// - public JpegPixelArea CrChannel; + public Buffer2D CrChannel; #pragma warning restore SA1401 /// @@ -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.CreateClean(width, height); + this.CbChannel = Buffer2D.CreateClean(cSize.Width, cSize.Height); + this.CrChannel = Buffer2D.CreateClean(cSize.Width, cSize.Height); } /// @@ -106,9 +106,9 @@ namespace ImageSharp.Formats.Jpg /// public void Dispose() { - this.YChannel.ReturnPooled(); - this.CbChannel.ReturnPooled(); - this.CrChannel.ReturnPooled(); + this.YChannel.Dispose(); + this.CbChannel.Dispose(); + this.CrChannel.Dispose(); } /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index da519a6ac..92607883d 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/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(); } /// @@ -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 buffer = Buffer2D.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 buffer = Buffer2D.CreateClean(8 * h3 * this.MCUCountX, 8 * v3 * this.MCUCountY); + this.blackImage = new JpegPixelArea(buffer); } } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/YCbCrImageTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/YCbCrImageTests.cs index ee38f500b..ba55665ca 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/YCbCrImageTests.cs +++ b/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); } }