mirror of https://github.com/SixLabors/ImageSharp
8 changed files with 347 additions and 75 deletions
@ -0,0 +1,47 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.PixelFormats |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Contains optimized implementations for conversion between pixel formats.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// Implementations are based on ideas in:
|
||||
|
/// https://github.com/dotnet/coreclr/blob/master/src/System.Private.CoreLib/shared/System/Buffers/Binary/Reader.cs#L84
|
||||
|
/// The JIT should be able to detect and optimize ROL and ROR patterns.
|
||||
|
/// </remarks>
|
||||
|
internal static class PixelConverter |
||||
|
{ |
||||
|
public static class Rgba32 |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Converts a packed <see cref="PixelFormats.Rgba32"/> to <see cref="Argb32"/>.
|
||||
|
/// </summary>
|
||||
|
[MethodImpl(InliningOptions.ShortMethod)] |
||||
|
public static uint ToArgb32(uint packedRgba) |
||||
|
{ |
||||
|
// packedRgba = [aa bb gg rr]
|
||||
|
// ROL(8, packedRgba):
|
||||
|
return (packedRgba << 8) | (packedRgba >> 24); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static class Argb32 |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Converts a packed <see cref="Argb32"/> to <see cref="PixelFormats.Rgba32"/>.
|
||||
|
/// </summary>
|
||||
|
[MethodImpl(InliningOptions.ShortMethod)] |
||||
|
public static uint ToRgba32(uint packedArgb) |
||||
|
{ |
||||
|
// packedArgb = [bb gg rr aa]
|
||||
|
// ROR(8, packedArgb):
|
||||
|
return (packedArgb >> 8) | (packedArgb << 24); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,150 @@ |
|||||
|
using SixLabors.ImageSharp.PixelFormats; |
||||
|
|
||||
|
using Xunit; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Tests.PixelFormats |
||||
|
{ |
||||
|
public class PixelConverterTests |
||||
|
{ |
||||
|
public static readonly TheoryData<byte, byte, byte, byte> RgbaData = |
||||
|
new TheoryData<byte, byte, byte, byte> |
||||
|
{ |
||||
|
{ 0, 0, 0, 0 }, |
||||
|
{ 0, 0, 0, 255 }, |
||||
|
{ 0, 0, 255, 0 }, |
||||
|
{ 0, 255, 0, 0 }, |
||||
|
{ 255, 0, 0, 0 }, |
||||
|
{ 255, 255, 255, 255 }, |
||||
|
{ 0, 0, 0, 1 }, |
||||
|
{ 0, 0, 1, 0 }, |
||||
|
{ 0, 1, 0, 0 }, |
||||
|
{ 1, 0, 0, 0 }, |
||||
|
{ 3, 5, 7, 11 }, |
||||
|
{ 67, 71, 101, 109 } |
||||
|
}; |
||||
|
|
||||
|
[Theory] |
||||
|
[MemberData(nameof(RgbaData))] |
||||
|
public void Rgba32ToArgb32(byte r, byte g, byte b, byte a) |
||||
|
{ |
||||
|
Rgba32 s = ReferenceImplementations.MakeRgba32(r, g, b, a); |
||||
|
|
||||
|
// Act:
|
||||
|
uint actualPacked = PixelConverter.Rgba32.ToArgb32(s.PackedValue); |
||||
|
|
||||
|
// Assert:
|
||||
|
uint expectedPacked = ReferenceImplementations.ToArgb32(s).PackedValue; |
||||
|
|
||||
|
Assert.Equal(expectedPacked, actualPacked); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[MemberData(nameof(RgbaData))] |
||||
|
public void Argb32ToRgba32(byte r, byte g, byte b, byte a) |
||||
|
{ |
||||
|
Argb32 s = ReferenceImplementations.MakeArgb32(r, g, b, a); |
||||
|
|
||||
|
// Act:
|
||||
|
uint actualPacked = PixelConverter.Argb32.ToRgba32(s.PackedValue); |
||||
|
|
||||
|
// Assert:
|
||||
|
uint expectedPacked = ReferenceImplementations.ToRgba32(s).PackedValue; |
||||
|
|
||||
|
Assert.Equal(expectedPacked, actualPacked); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
private static class ReferenceImplementations |
||||
|
{ |
||||
|
public static Rgba32 MakeRgba32(byte r, byte g, byte b, byte a) |
||||
|
{ |
||||
|
Rgba32 d = default; |
||||
|
d.R = r; |
||||
|
d.G = g; |
||||
|
d.B = b; |
||||
|
d.A = a; |
||||
|
return d; |
||||
|
} |
||||
|
|
||||
|
public static Argb32 MakeArgb32(byte r, byte g, byte b, byte a) |
||||
|
{ |
||||
|
Argb32 d = default; |
||||
|
d.R = r; |
||||
|
d.G = g; |
||||
|
d.B = b; |
||||
|
d.A = a; |
||||
|
return d; |
||||
|
} |
||||
|
|
||||
|
public static Bgra32 MakeBgra32(byte r, byte g, byte b, byte a) |
||||
|
{ |
||||
|
Bgra32 d = default; |
||||
|
d.R = r; |
||||
|
d.G = g; |
||||
|
d.B = b; |
||||
|
d.A = a; |
||||
|
return d; |
||||
|
} |
||||
|
|
||||
|
public static Argb32 ToArgb32(Rgba32 s) |
||||
|
{ |
||||
|
Argb32 d = default; |
||||
|
d.R = s.R; |
||||
|
d.G = s.G; |
||||
|
d.B = s.B; |
||||
|
d.A = s.A; |
||||
|
return d; |
||||
|
} |
||||
|
|
||||
|
public static Argb32 ToArgb32(Bgra32 s) |
||||
|
{ |
||||
|
Argb32 d = default; |
||||
|
d.R = s.R; |
||||
|
d.G = s.G; |
||||
|
d.B = s.B; |
||||
|
d.A = s.A; |
||||
|
return d; |
||||
|
} |
||||
|
|
||||
|
public static Rgba32 ToRgba32(Argb32 s) |
||||
|
{ |
||||
|
Rgba32 d = default; |
||||
|
d.R = s.R; |
||||
|
d.G = s.G; |
||||
|
d.B = s.B; |
||||
|
d.A = s.A; |
||||
|
return d; |
||||
|
} |
||||
|
|
||||
|
public static Rgba32 ToRgba32(Bgra32 s) |
||||
|
{ |
||||
|
Rgba32 d = default; |
||||
|
d.R = s.R; |
||||
|
d.G = s.G; |
||||
|
d.B = s.B; |
||||
|
d.A = s.A; |
||||
|
return d; |
||||
|
} |
||||
|
|
||||
|
public static Bgra32 ToBgra32(Rgba32 s) |
||||
|
{ |
||||
|
Bgra32 d = default; |
||||
|
d.R = s.R; |
||||
|
d.G = s.G; |
||||
|
d.B = s.B; |
||||
|
d.A = s.A; |
||||
|
return d; |
||||
|
} |
||||
|
|
||||
|
public static Bgra32 ToBgra32(Argb32 s) |
||||
|
{ |
||||
|
Bgra32 d = default; |
||||
|
d.R = s.R; |
||||
|
d.G = s.G; |
||||
|
d.B = s.B; |
||||
|
d.A = s.A; |
||||
|
return d; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue