Browse Source

Ensure PixelOperations.To(TPixel) uses scaling.

pull/2050/head
James Jackson-South 4 years ago
parent
commit
666ae9eb02
  1. 6
      src/ImageSharp/ImageFrame{TPixel}.cs
  2. 2
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.String.cs
  3. 4
      src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs
  4. 24
      src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
  5. 5
      tests/ImageSharp.Tests.ruleset
  6. 61
      tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs
  7. 18
      tests/ImageSharp.Tests/TestUtilities/TestPixel.cs

6
src/ImageSharp/ImageFrame{TPixel}.cs

@ -362,10 +362,8 @@ namespace SixLabors.ImageSharp
return;
}
this.PixelBuffer.FastMemoryGroup.TransformTo(destination, (s, d) =>
{
PixelOperations<TPixel>.Instance.To(this.GetConfiguration(), s, d);
});
this.PixelBuffer.FastMemoryGroup.TransformTo(destination, (s, d)
=> PixelOperations<TPixel>.Instance.To(this.GetConfiguration(), s, d));
}
/// <inheritdoc/>

2
src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.String.cs

@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
/// <summary>
/// Gets the MDFileUnits exif tag.
/// </summary>
public static ExifTag<string> MDFileUnits => new ExifTag<string>(ExifTagValue.MDFileUnits);
public static ExifTag<string> MDFileUnits { get; } = new ExifTag<string>(ExifTagValue.MDFileUnits);
/// <summary>
/// Gets the SEMInfo exif tag.

4
src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs

@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.PixelFormats
internal class PixelOperations : PixelOperations<RgbaVector>
{
private static readonly Lazy<PixelTypeInfo> LazyInfo =
new Lazy<PixelTypeInfo>(() => PixelTypeInfo.Create<RgbaVector>(PixelAlphaRepresentation.Unassociated), true);
new(() => PixelTypeInfo.Create<RgbaVector>(PixelAlphaRepresentation.Unassociated), true);
/// <inheritdoc />
public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value;
@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.PixelFormats
{
Span<Vector4> destinationVectors = MemoryMarshal.Cast<RgbaVector, Vector4>(destinationPixels);
PixelOperations<TSourcePixel>.Instance.ToVector4(configuration, sourcePixels, destinationVectors);
PixelOperations<TSourcePixel>.Instance.ToVector4(configuration, sourcePixels, destinationVectors, PixelConversionModifiers.Scale);
}
/// <inheritdoc />

24
src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs

@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats
public partial class PixelOperations<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private static readonly Lazy<PixelTypeInfo> LazyInfo = new Lazy<PixelTypeInfo>(() => PixelTypeInfo.Create<TPixel>(), true);
private static readonly Lazy<PixelTypeInfo> LazyInfo = new(() => PixelTypeInfo.Create<TPixel>(), true);
/// <summary>
/// Gets the global <see cref="PixelOperations{TPixel}"/> instance for the pixel type <typeparamref name="TPixel"/>
@ -116,29 +116,29 @@ namespace SixLabors.ImageSharp.PixelFormats
Span<TPixel> destinationPixels)
where TSourcePixel : unmanaged, IPixel<TSourcePixel>
{
const int SliceLength = 1024;
int numberOfSlices = sourcePixels.Length / SliceLength;
const int sliceLength = 1024;
int numberOfSlices = sourcePixels.Length / sliceLength;
using IMemoryOwner<Vector4> tempVectors = configuration.MemoryAllocator.Allocate<Vector4>(SliceLength);
using IMemoryOwner<Vector4> tempVectors = configuration.MemoryAllocator.Allocate<Vector4>(sliceLength);
Span<Vector4> vectorSpan = tempVectors.GetSpan();
for (int i = 0; i < numberOfSlices; i++)
{
int start = i * SliceLength;
ReadOnlySpan<TSourcePixel> s = sourcePixels.Slice(start, SliceLength);
Span<TPixel> d = destinationPixels.Slice(start, SliceLength);
PixelOperations<TSourcePixel>.Instance.ToVector4(configuration, s, vectorSpan);
this.FromVector4Destructive(configuration, vectorSpan, d);
int start = i * sliceLength;
ReadOnlySpan<TSourcePixel> s = sourcePixels.Slice(start, sliceLength);
Span<TPixel> d = destinationPixels.Slice(start, sliceLength);
PixelOperations<TSourcePixel>.Instance.ToVector4(configuration, s, vectorSpan, PixelConversionModifiers.Scale);
this.FromVector4Destructive(configuration, vectorSpan, d, PixelConversionModifiers.Scale);
}
int endOfCompleteSlices = numberOfSlices * SliceLength;
int endOfCompleteSlices = numberOfSlices * sliceLength;
int remainder = sourcePixels.Length - endOfCompleteSlices;
if (remainder > 0)
{
ReadOnlySpan<TSourcePixel> s = sourcePixels.Slice(endOfCompleteSlices);
Span<TPixel> d = destinationPixels.Slice(endOfCompleteSlices);
vectorSpan = vectorSpan.Slice(0, remainder);
PixelOperations<TSourcePixel>.Instance.ToVector4(configuration, s, vectorSpan);
this.FromVector4Destructive(configuration, vectorSpan, d);
PixelOperations<TSourcePixel>.Instance.ToVector4(configuration, s, vectorSpan, PixelConversionModifiers.Scale);
this.FromVector4Destructive(configuration, vectorSpan, d, PixelConversionModifiers.Scale);
}
}

5
tests/ImageSharp.Tests.ruleset

@ -1,6 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="ImageSharp.Tests" ToolsVersion="16.0">
<RuleSet Name="ImageSharp.Tests" ToolsVersion="17.0">
<Include Path="..\shared-infrastructure\sixlabors.tests.ruleset" Action="Default" />
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
<Rule Id="SA1313" Action="None" />
</Rules>
<Rules AnalyzerId="xunit.analyzers" RuleNamespace="xunit.analyzers">
<Rule Id="xUnit1004" Action="None" />
<Rule Id="xUnit1013" Action="None" />

61
tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs

@ -320,30 +320,51 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations
(s, d) => this.Operations.ToVector4(this.Configuration, s, d.GetSpan()));
}
public static readonly TheoryData<object> Generic_To_Data = new TheoryData<object>
public static readonly TheoryData<object> Generic_To_Data = new()
{
new TestPixel<A8>(),
new TestPixel<Abgr32>(),
new TestPixel<Rgba32>(),
new TestPixel<Argb32>(),
new TestPixel<Bgr24>(),
new TestPixel<Bgr565>(),
new TestPixel<Bgra32>(),
new TestPixel<Rgb24>(),
new TestPixel<L8>(),
new TestPixel<Bgra4444>(),
new TestPixel<Bgra5551>(),
new TestPixel<Byte4>(),
new TestPixel<HalfSingle>(),
new TestPixel<HalfVector2>(),
new TestPixel<HalfVector4>(),
new TestPixel<L16>(),
new TestPixel<L8>(),
new TestPixel<La16>(),
new TestPixel<La32>(),
new TestPixel<NormalizedByte2>(),
new TestPixel<NormalizedByte4>(),
new TestPixel<NormalizedShort2>(),
new TestPixel<NormalizedShort4>(),
new TestPixel<Rg32>(),
new TestPixel<Rgb24>(),
new TestPixel<Rgb48>(),
new TestPixel<Rgba64>()
new TestPixel<Rgba1010102>(),
new TestPixel<Rgba32>(),
new TestPixel<Rgba64>(),
new TestPixel<RgbaVector>(),
new TestPixel<Short2>(),
new TestPixel<Short4>(),
};
[Theory]
[MemberData(nameof(Generic_To_Data))]
public void Generic_To<TDestPixel>(TestPixel<TDestPixel> dummy)
public void Generic_To<TDestPixel>(TestPixel<TDestPixel> _)
where TDestPixel : unmanaged, IPixel<TDestPixel>
{
const int Count = 2134;
TPixel[] source = CreatePixelTestData(Count);
var expected = new TDestPixel[Count];
const int count = 2134;
TPixel[] source = CreatePixelTestData(count);
var expected = new TDestPixel[count];
PixelConverterTests.ReferenceImplementations.To<TPixel, TDestPixel>(this.Configuration, source, expected);
TestOperation(source, expected, (s, d) => this.Operations.To(this.Configuration, s, d.GetSpan()));
TestOperation(source, expected, (s, d) => this.Operations.To(this.Configuration, s, d.GetSpan()), false);
}
[Theory]
@ -1234,23 +1255,11 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations
}
// TODO: We really need a PixelTypeInfo.BitsPerComponent property!!
private static bool IsComplexPixel()
private static bool IsComplexPixel() => default(TDest) switch
{
switch (default(TDest))
{
case HalfSingle _:
case HalfVector2 _:
case L16 _:
case La32 _:
case NormalizedShort2 _:
case Rg32 _:
case Short2 _:
return true;
default:
return Unsafe.SizeOf<TDest>() > sizeof(int);
}
}
HalfSingle or HalfVector2 or L16 or La32 or NormalizedShort2 or Rg32 or Short2 => true,
_ => Unsafe.SizeOf<TDest>() > sizeof(int),
};
}
}
}

18
tests/ImageSharp.Tests/TestUtilities/TestPixel.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using SixLabors.ImageSharp.PixelFormats;
using Xunit.Abstractions;
@ -16,6 +17,11 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities
public TestPixel(float red, float green, float blue, float alpha)
{
Guard.MustBeBetweenOrEqualTo(red, 0F, 1F, nameof(red));
Guard.MustBeBetweenOrEqualTo(green, 0F, 1F, nameof(green));
Guard.MustBeBetweenOrEqualTo(blue, 0F, 1F, nameof(blue));
Guard.MustBeBetweenOrEqualTo(alpha, 0F, 1F, nameof(alpha));
this.Red = red;
this.Green = green;
this.Blue = blue;
@ -33,14 +39,11 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities
public TPixel AsPixel()
{
var pix = default(TPixel);
pix.FromVector4(new System.Numerics.Vector4(this.Red, this.Green, this.Blue, this.Alpha));
pix.FromScaledVector4(new Vector4(this.Red, this.Green, this.Blue, this.Alpha));
return pix;
}
internal Span<TPixel> AsSpan()
{
return new Span<TPixel>(new[] { this.AsPixel() });
}
internal Span<TPixel> AsSpan() => new(new[] { this.AsPixel() });
public void Deserialize(IXunitSerializationInfo info)
{
@ -58,9 +61,6 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities
info.AddValue("alpha", this.Alpha);
}
public override string ToString()
{
return $"{typeof(TPixel).Name}{this.AsPixel().ToString()}";
}
public override string ToString() => $"{typeof(TPixel).Name}{this.AsPixel()}";
}
}

Loading…
Cancel
Save