Browse Source

introduced DecodedBlockMemento

af/merge-core
Anton Firszov 9 years ago
parent
commit
8df425c630
  1. 31
      src/ImageSharp.Formats.Jpeg/Components/Decoder/DecodedBlockMemento.cs
  2. 52
      src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs
  3. 19
      src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs
  4. 25
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs

31
src/ImageSharp.Formats.Jpeg/Components/Decoder/DecodedBlockMemento.cs

@ -0,0 +1,31 @@
// <copyright file="DecodedBlockMemento.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats.Jpg
{
using System.Buffers;
internal struct DecodedBlockMemento
{
/// <summary>
/// The <see cref="ArrayPool{T}"/> used to pool data in <see cref="JpegDecoderCore.DecodedBlocks"/>.
/// Should always clean arrays when returning!
/// </summary>
public static readonly ArrayPool<DecodedBlockMemento> ArrayPool = ArrayPool<DecodedBlockMemento>.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;
}
}
}

52
src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs

@ -136,7 +136,7 @@ namespace ImageSharp.Formats.Jpg
/// 3 4 5
/// </summary>
/// <param name="decoder">The <see cref="JpegDecoderCore"/> instance</param>
public void ProcessBlocks(JpegDecoderCore decoder)
public void ReadBlocks(JpegDecoderCore decoder)
{
int blockCount = 0;
int mcu = 0;
@ -213,6 +213,26 @@ namespace ImageSharp.Formats.Jpg
}
}
/// <summary>
/// Dequantize, perform the inverse DCT and store the block to the into the corresponding <see cref="JpegPixelArea"/> instances.
/// </summary>
/// <param name="decoder">The <see cref="JpegDecoderCore"/> instance</param>
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);
/// <summary>
/// Dequantize, perform the inverse DCT and store the block to the into the corresponding <see cref="JpegPixelArea"/> instances.
/// </summary>
/// <param name="decoder">The <see cref="JpegDecoderCore"/> instance</param>
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;
}
}
}

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

@ -40,11 +40,7 @@ namespace ImageSharp.Formats
public Bytes Bytes;
#pragma warning restore SA401
/// <summary>
/// The <see cref="ArrayPool{T}"/> used to pool data in <see cref="DecodedBlocks"/>.
/// Should always clean arrays when returning!
/// </summary>
private static readonly ArrayPool<Block8x8F> BlockPool = ArrayPool<Block8x8F>.Create();
/// <summary>
/// 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)
/// </summary>
public Block8x8F[][] DecodedBlocks { get; }
public DecodedBlockMemento[][] DecodedBlocks { get; }
/// <summary>
/// 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);
}
/// <summary>

25
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);
}
}
}
Loading…
Cancel
Save