diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/DecodedBlockMemento.cs b/src/ImageSharp.Formats.Jpeg/Components/Decoder/DecodedBlockMemento.cs new file mode 100644 index 000000000..4c3c7689f --- /dev/null +++ b/src/ImageSharp.Formats.Jpeg/Components/Decoder/DecodedBlockMemento.cs @@ -0,0 +1,31 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats.Jpg +{ + using System.Buffers; + + internal struct DecodedBlockMemento + { + /// + /// The used to pool data in . + /// Should always clean arrays when returning! + /// + public static readonly ArrayPool ArrayPool = ArrayPool.Create(); + + public int Bx; + + public int By; + + public Block8x8F Block; + + public static void Store(DecodedBlockMemento[] blockArray, int index, int bx, int by, ref Block8x8F block) + { + blockArray[index].Bx = bx; + blockArray[index].By = by; + blockArray[index].Block = block; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs b/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs index 70c4402e8..a1fe6444b 100644 --- a/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs +++ b/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs @@ -136,7 +136,7 @@ namespace ImageSharp.Formats.Jpg /// 3 4 5 /// /// The instance - public void ProcessBlocks(JpegDecoderCore decoder) + public void ReadBlocks(JpegDecoderCore decoder) { int blockCount = 0; int mcu = 0; @@ -213,6 +213,26 @@ namespace ImageSharp.Formats.Jpg } } + /// + /// Dequantize, perform the inverse DCT and store the block to the into the corresponding instances. + /// + /// The instance + public void ProcessBlock(JpegDecoderCore decoder) + { + int qtIndex = decoder.ComponentArray[this.componentIndex].Selector; + this.data.QuantiazationTable = decoder.QuantizationTables[qtIndex]; + + Block8x8F* b = this.pointers.Block; + + Block8x8F.UnZig(b, this.pointers.QuantiazationTable, this.pointers.Unzig); + + DCT.TransformIDCT(ref *b, ref *this.pointers.Temp1, ref *this.pointers.Temp2); + + var destChannel = decoder.GetDestinationChannel(this.componentIndex); + var destArea = destChannel.GetOffsetedSubAreaForBlock(this.bx, this.by); + destArea.LoadColorsFrom(this.pointers.Temp1, this.pointers.Temp2); + } + private void ResetDc() { Unsafe.InitBlock(this.pointers.Dc, default(byte), sizeof(int) * JpegDecoderCore.MaxComponents); @@ -248,7 +268,7 @@ namespace ImageSharp.Formats.Jpg for (int i = 0; i < this.componentScanCount; i++) { - this.ProcessScanImpl(decoder, i, ref this.pointers.ComponentScan[i], ref totalHv); + this.InitComponentScan(decoder, i, ref this.pointers.ComponentScan[i], ref totalHv); } // Section B.2.3 states that if there is more than one component then the @@ -293,7 +313,7 @@ namespace ImageSharp.Formats.Jpg private void ReadBlock(JpegDecoderCore decoder, int scanIndex) { int blockIndex = this.GetBlockIndex(decoder); - this.data.Block = decoder.DecodedBlocks[this.componentIndex][blockIndex]; + this.data.Block = decoder.DecodedBlocks[this.componentIndex][blockIndex].Block; var b = this.pointers.Block; DecoderErrorCode errorCode; @@ -379,31 +399,13 @@ namespace ImageSharp.Formats.Jpg } } - decoder.DecodedBlocks[this.componentIndex][blockIndex] = this.data.Block; + DecodedBlockMemento[] blocks = decoder.DecodedBlocks[this.componentIndex]; + DecodedBlockMemento.Store(blocks, blockIndex, this.bx, this.by, ref *b); } private bool IsProgressiveBlockFinished(JpegDecoderCore decoder) => decoder.IsProgressive && (this.zigEnd != Block8x8F.ScalarCount - 1 || this.al != 0); - /// - /// Dequantize, perform the inverse DCT and store the block to the into the corresponding instances. - /// - /// The instance - private void ProcessBlock(JpegDecoderCore decoder) - { - int qtIndex = decoder.ComponentArray[this.componentIndex].Selector; - this.data.QuantiazationTable = decoder.QuantizationTables[qtIndex]; - - Block8x8F* b = this.pointers.Block; - - Block8x8F.UnZig(b, this.pointers.QuantiazationTable, this.pointers.Unzig); - - DCT.TransformIDCT(ref *b, ref *this.pointers.Temp1, ref *this.pointers.Temp2); - - var destChannel = decoder.GetDestinationChannel(this.componentIndex); - var destArea = destChannel.GetOffsetedSubAreaForBlock(this.bx, this.by); - destArea.LoadColorsFrom(this.pointers.Temp1, this.pointers.Temp2); - } private DecoderErrorCode DecodeEobRun(int count, JpegDecoderCore decoder) { @@ -428,7 +430,7 @@ namespace ImageSharp.Formats.Jpg return ((this.by * decoder.MCUCountX) * this.hi) + this.bx; } - private void ProcessScanImpl(JpegDecoderCore decoder, int i, ref ComponentScan currentComponentScan, ref int totalHv) + private void InitComponentScan(JpegDecoderCore decoder, int i, ref ComponentScan currentComponentScan, ref int totalHv) { // Component selector. int cs = decoder.Temp[1 + (2 * i)]; @@ -649,5 +651,7 @@ namespace ImageSharp.Formats.Jpg return zig; } + + } } \ No newline at end of file diff --git a/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs b/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs index 1e1210387..30367e93e 100644 --- a/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs @@ -40,11 +40,7 @@ namespace ImageSharp.Formats public Bytes Bytes; #pragma warning restore SA401 - /// - /// The used to pool data in . - /// Should always clean arrays when returning! - /// - private static readonly ArrayPool BlockPool = ArrayPool.Create(); + /// /// The App14 marker color-space @@ -95,7 +91,7 @@ namespace ImageSharp.Formats this.QuantizationTables = new Block8x8F[MaxTq + 1]; this.Temp = new byte[2 * Block8x8F.ScalarCount]; this.ComponentArray = new Component[MaxComponents]; - this.DecodedBlocks = new Block8x8F[MaxComponents][]; + this.DecodedBlocks = new DecodedBlockMemento[MaxComponents][]; this.Bits = default(Bits); this.Bytes = Bytes.Create(); } @@ -114,7 +110,7 @@ namespace ImageSharp.Formats /// Gets the saved state between progressive-mode scans. /// TODO: Also save non-progressive data here. (Helps splitting and parallelizing JpegScanDecoder-s loop) /// - public Block8x8F[][] DecodedBlocks { get; } + public DecodedBlockMemento[][] DecodedBlocks { get; } /// /// Gets the quantization tables, in zigzag order. @@ -413,12 +409,11 @@ namespace ImageSharp.Formats this.HuffmanTrees[i].Dispose(); } - for (int i = 0; i < this.DecodedBlocks.Length; i++) + foreach (DecodedBlockMemento[] blockArray in this.DecodedBlocks) { - Block8x8F[] blockArray = this.DecodedBlocks[i]; if (blockArray != null) { - BlockPool.Return(blockArray, true); + DecodedBlockMemento.ArrayPool.Return(blockArray, true); } } @@ -1443,7 +1438,7 @@ namespace ImageSharp.Formats { int size = this.TotalMCUCount * this.ComponentArray[i].HorizontalFactor * this.ComponentArray[i].VerticalFactor; - this.DecodedBlocks[i] = BlockPool.Rent(size); + this.DecodedBlocks[i] = DecodedBlockMemento.ArrayPool.Rent(size); } } @@ -1461,7 +1456,7 @@ namespace ImageSharp.Formats JpegScanDecoder.Init(&scan, this, remaining); this.Bits = default(Bits); this.MakeImage(); - scan.ProcessBlocks(this); + scan.ReadBlocks(this); } /// diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index b02f99be1..37aff8338 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -41,5 +41,30 @@ namespace ImageSharp.Tests provider.Utility.SaveTestOutputFile(image, "bmp"); } + unsafe struct Buzisag + { + public int Value; + + public delegate void BlockAction(Buzisag* b); + + public static void Foo(Buzisag* buzisag) + { + Bar(buzisag, b => b->Value++); + } + + public static void Bar(Buzisag* buzisag, BlockAction action) + { + action(buzisag); + } + } + + [Fact] + public unsafe void Kabbe() + { + Buzisag b = default(Buzisag); + Buzisag.Foo(&b); + + Assert.Equal(1, b.Value); + } } } \ No newline at end of file