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