mirror of https://github.com/SixLabors/ImageSharp
8 changed files with 270 additions and 44 deletions
@ -0,0 +1,97 @@ |
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jpeg.Common |
|||
{ |
|||
using System.Diagnostics; |
|||
|
|||
/// <summary>
|
|||
/// Represents a Jpeg block with <see cref="short"/> coefficiens.
|
|||
/// </summary>
|
|||
// ReSharper disable once InconsistentNaming
|
|||
internal unsafe struct Block8x8 |
|||
{ |
|||
/// <summary>
|
|||
/// A number of scalar coefficients in a <see cref="Block8x8F"/>
|
|||
/// </summary>
|
|||
public const int Size = 64; |
|||
|
|||
private fixed short data[Size]; |
|||
|
|||
public Block8x8(Span<short> coefficients) |
|||
{ |
|||
ref byte selfRef = ref Unsafe.As<Block8x8, byte>(ref this); |
|||
ref byte sourceRef = ref coefficients.NonPortableCast<short, byte>().DangerousGetPinnableReference(); |
|||
Unsafe.CopyBlock(ref selfRef, ref sourceRef, Size * sizeof(short)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Pointer-based "Indexer" (getter part)
|
|||
/// </summary>
|
|||
/// <param name="blockPtr">Block pointer</param>
|
|||
/// <param name="idx">Index</param>
|
|||
/// <returns>The scaleVec value at the specified index</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static unsafe short GetScalarAt(Block8x8* blockPtr, int idx) |
|||
{ |
|||
GuardBlockIndex(idx); |
|||
|
|||
short* fp = (short*)blockPtr; |
|||
return fp[idx]; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Pointer-based "Indexer" (setter part)
|
|||
/// </summary>
|
|||
/// <param name="blockPtr">Block pointer</param>
|
|||
/// <param name="idx">Index</param>
|
|||
/// <param name="value">Value</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static unsafe void SetScalarAt(Block8x8* blockPtr, int idx, short value) |
|||
{ |
|||
GuardBlockIndex(idx); |
|||
|
|||
short* fp = (short*)blockPtr; |
|||
fp[idx] = value; |
|||
} |
|||
|
|||
|
|||
public short this[int idx] |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get |
|||
{ |
|||
GuardBlockIndex(idx); |
|||
ref short selfRef = ref Unsafe.As<Block8x8, short>(ref this); |
|||
return Unsafe.Add(ref selfRef, idx); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
set |
|||
{ |
|||
GuardBlockIndex(idx); |
|||
ref short selfRef = ref Unsafe.As<Block8x8, short>(ref this); |
|||
Unsafe.Add(ref selfRef, idx) = value; |
|||
} |
|||
} |
|||
|
|||
[Conditional("DEBUG")] |
|||
private static void GuardBlockIndex(int idx) |
|||
{ |
|||
DebugGuard.MustBeLessThan(idx, Size, nameof(idx)); |
|||
DebugGuard.MustBeGreaterThanOrEqualTo(idx, 0, nameof(idx)); |
|||
} |
|||
|
|||
public Block8x8F AsFloatBlock() |
|||
{ |
|||
// TODO: Optimize this
|
|||
var result = default(Block8x8F); |
|||
for (int i = 0; i < Size; i++) |
|||
{ |
|||
result[i] = this[i]; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,80 @@ |
|||
// ReSharper disable InconsistentNaming
|
|||
namespace SixLabors.ImageSharp.Tests |
|||
{ |
|||
using Moq; |
|||
|
|||
using SixLabors.ImageSharp.Formats.Jpeg.Common; |
|||
|
|||
using Xunit; |
|||
using Xunit.Abstractions; |
|||
|
|||
public class Block8x8Tests : JpegUtilityTestFixture |
|||
{ |
|||
public Block8x8Tests(ITestOutputHelper output) |
|||
: base(output) |
|||
{ |
|||
} |
|||
|
|||
[Fact] |
|||
public void Construct_And_Indexer_Get() |
|||
{ |
|||
short[] data = Create8x8ShortData(); |
|||
|
|||
var block = new Block8x8(data); |
|||
|
|||
for (int i = 0; i < Block8x8.Size; i++) |
|||
{ |
|||
Assert.Equal(data[i], block[i]); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public void Indexer_Set() |
|||
{ |
|||
var block = default(Block8x8); |
|||
|
|||
block[17] = 17; |
|||
block[42] = 42; |
|||
|
|||
Assert.Equal(0, block[0]); |
|||
Assert.Equal(17, block[17]); |
|||
Assert.Equal(42, block[42]); |
|||
} |
|||
|
|||
|
|||
[Fact] |
|||
public unsafe void Indexer_GetScalarAt_SetScalarAt() |
|||
{ |
|||
int sum = 0; |
|||
var block = default(Block8x8); |
|||
|
|||
for (int i = 0; i < Block8x8.Size; i++) |
|||
{ |
|||
Block8x8.SetScalarAt(&block, i, i); |
|||
} |
|||
|
|||
sum = 0; |
|||
for (int i = 0; i < Block8x8.Size; i++) |
|||
{ |
|||
sum += Block8x8.GetScalarAt(&block, i); |
|||
} |
|||
Assert.Equal(sum, 64 * 63 / 2); |
|||
} |
|||
|
|||
|
|||
[Fact] |
|||
public void AsFloatBlock() |
|||
{ |
|||
short[] data = Create8x8ShortData(); |
|||
|
|||
var source = new Block8x8(data); |
|||
|
|||
Block8x8F dest = source.AsFloatBlock(); |
|||
|
|||
for (int i = 0; i < Block8x8F.Size; i++) |
|||
{ |
|||
Assert.Equal((float)data[i], dest[i]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue