Skip to content

Commit a54d8b5

Browse files
Merge pull request #2050 from SixLabors/js/pixel-conversion-2048
Ensure PixelOperations.To(TPixel) uses scaling.
2 parents 8b2ebc5 + d1cfa8d commit a54d8b5

File tree

8 files changed

+81
-55
lines changed

8 files changed

+81
-55
lines changed

src/ImageSharp/ImageFrame{TPixel}.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -362,10 +362,8 @@ internal override void CopyPixelsTo<TDestinationPixel>(MemoryGroup<TDestinationP
362362
return;
363363
}
364364

365-
this.PixelBuffer.FastMemoryGroup.TransformTo(destination, (s, d) =>
366-
{
367-
PixelOperations<TPixel>.Instance.To(this.GetConfiguration(), s, d);
368-
});
365+
this.PixelBuffer.FastMemoryGroup.TransformTo(destination, (s, d)
366+
=> PixelOperations<TPixel>.Instance.To(this.GetConfiguration(), s, d));
369367
}
370368

371369
/// <inheritdoc/>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public abstract partial class ExifTag
9494
/// <summary>
9595
/// Gets the MDFileUnits exif tag.
9696
/// </summary>
97-
public static ExifTag<string> MDFileUnits => new ExifTag<string>(ExifTagValue.MDFileUnits);
97+
public static ExifTag<string> MDFileUnits { get; } = new ExifTag<string>(ExifTagValue.MDFileUnits);
9898

9999
/// <summary>
100100
/// Gets the SEMInfo exif tag.

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public partial struct RgbaVector
2121
internal class PixelOperations : PixelOperations<RgbaVector>
2222
{
2323
private static readonly Lazy<PixelTypeInfo> LazyInfo =
24-
new Lazy<PixelTypeInfo>(() => PixelTypeInfo.Create<RgbaVector>(PixelAlphaRepresentation.Unassociated), true);
24+
new(() => PixelTypeInfo.Create<RgbaVector>(PixelAlphaRepresentation.Unassociated), true);
2525

2626
/// <inheritdoc />
2727
public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value;
@@ -34,7 +34,7 @@ public override void From<TSourcePixel>(
3434
{
3535
Span<Vector4> destinationVectors = MemoryMarshal.Cast<RgbaVector, Vector4>(destinationPixels);
3636

37-
PixelOperations<TSourcePixel>.Instance.ToVector4(configuration, sourcePixels, destinationVectors);
37+
PixelOperations<TSourcePixel>.Instance.ToVector4(configuration, sourcePixels, destinationVectors, PixelConversionModifiers.Scale);
3838
}
3939

4040
/// <inheritdoc />

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats
1919
public partial class PixelOperations<TPixel>
2020
where TPixel : unmanaged, IPixel<TPixel>
2121
{
22-
private static readonly Lazy<PixelTypeInfo> LazyInfo = new Lazy<PixelTypeInfo>(() => PixelTypeInfo.Create<TPixel>(), true);
22+
private static readonly Lazy<PixelTypeInfo> LazyInfo = new(() => PixelTypeInfo.Create<TPixel>(), true);
2323

2424
/// <summary>
2525
/// Gets the global <see cref="PixelOperations{TPixel}"/> instance for the pixel type <typeparamref name="TPixel"/>
@@ -116,29 +116,29 @@ public virtual void From<TSourcePixel>(
116116
Span<TPixel> destinationPixels)
117117
where TSourcePixel : unmanaged, IPixel<TSourcePixel>
118118
{
119-
const int SliceLength = 1024;
120-
int numberOfSlices = sourcePixels.Length / SliceLength;
119+
const int sliceLength = 1024;
120+
int numberOfSlices = sourcePixels.Length / sliceLength;
121121

122-
using IMemoryOwner<Vector4> tempVectors = configuration.MemoryAllocator.Allocate<Vector4>(SliceLength);
122+
using IMemoryOwner<Vector4> tempVectors = configuration.MemoryAllocator.Allocate<Vector4>(sliceLength);
123123
Span<Vector4> vectorSpan = tempVectors.GetSpan();
124124
for (int i = 0; i < numberOfSlices; i++)
125125
{
126-
int start = i * SliceLength;
127-
ReadOnlySpan<TSourcePixel> s = sourcePixels.Slice(start, SliceLength);
128-
Span<TPixel> d = destinationPixels.Slice(start, SliceLength);
129-
PixelOperations<TSourcePixel>.Instance.ToVector4(configuration, s, vectorSpan);
130-
this.FromVector4Destructive(configuration, vectorSpan, d);
126+
int start = i * sliceLength;
127+
ReadOnlySpan<TSourcePixel> s = sourcePixels.Slice(start, sliceLength);
128+
Span<TPixel> d = destinationPixels.Slice(start, sliceLength);
129+
PixelOperations<TSourcePixel>.Instance.ToVector4(configuration, s, vectorSpan, PixelConversionModifiers.Scale);
130+
this.FromVector4Destructive(configuration, vectorSpan, d, PixelConversionModifiers.Scale);
131131
}
132132

133-
int endOfCompleteSlices = numberOfSlices * SliceLength;
133+
int endOfCompleteSlices = numberOfSlices * sliceLength;
134134
int remainder = sourcePixels.Length - endOfCompleteSlices;
135135
if (remainder > 0)
136136
{
137137
ReadOnlySpan<TSourcePixel> s = sourcePixels.Slice(endOfCompleteSlices);
138138
Span<TPixel> d = destinationPixels.Slice(endOfCompleteSlices);
139139
vectorSpan = vectorSpan.Slice(0, remainder);
140-
PixelOperations<TSourcePixel>.Instance.ToVector4(configuration, s, vectorSpan);
141-
this.FromVector4Destructive(configuration, vectorSpan, d);
140+
PixelOperations<TSourcePixel>.Instance.ToVector4(configuration, s, vectorSpan, PixelConversionModifiers.Scale);
141+
this.FromVector4Destructive(configuration, vectorSpan, d, PixelConversionModifiers.Scale);
142142
}
143143
}
144144

tests/ImageSharp.Tests.ruleset

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<RuleSet Name="ImageSharp.Tests" ToolsVersion="16.0">
2+
<RuleSet Name="ImageSharp.Tests" ToolsVersion="17.0">
33
<Include Path="..\shared-infrastructure\sixlabors.tests.ruleset" Action="Default" />
4+
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
5+
<Rule Id="SA1313" Action="None" />
6+
</Rules>
47
<Rules AnalyzerId="xunit.analyzers" RuleNamespace="xunit.analyzers">
58
<Rule Id="xUnit1004" Action="None" />
69
<Rule Id="xUnit1013" Action="None" />

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

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -320,30 +320,51 @@ public void ToVector4(int count)
320320
(s, d) => this.Operations.ToVector4(this.Configuration, s, d.GetSpan()));
321321
}
322322

323-
public static readonly TheoryData<object> Generic_To_Data = new TheoryData<object>
323+
public static readonly TheoryData<object> Generic_To_Data = new()
324324
{
325+
new TestPixel<A8>(),
325326
new TestPixel<Abgr32>(),
326-
new TestPixel<Rgba32>(),
327+
new TestPixel<Argb32>(),
328+
new TestPixel<Bgr24>(),
329+
new TestPixel<Bgr565>(),
327330
new TestPixel<Bgra32>(),
328-
new TestPixel<Rgb24>(),
329-
new TestPixel<L8>(),
331+
new TestPixel<Bgra4444>(),
332+
new TestPixel<Bgra5551>(),
333+
new TestPixel<Byte4>(),
334+
new TestPixel<HalfSingle>(),
335+
new TestPixel<HalfVector2>(),
336+
new TestPixel<HalfVector4>(),
330337
new TestPixel<L16>(),
338+
new TestPixel<L8>(),
339+
new TestPixel<La16>(),
340+
new TestPixel<La32>(),
341+
new TestPixel<NormalizedByte2>(),
342+
new TestPixel<NormalizedByte4>(),
343+
new TestPixel<NormalizedShort2>(),
344+
new TestPixel<NormalizedShort4>(),
345+
new TestPixel<Rg32>(),
346+
new TestPixel<Rgb24>(),
331347
new TestPixel<Rgb48>(),
332-
new TestPixel<Rgba64>()
348+
new TestPixel<Rgba1010102>(),
349+
new TestPixel<Rgba32>(),
350+
new TestPixel<Rgba64>(),
351+
new TestPixel<RgbaVector>(),
352+
new TestPixel<Short2>(),
353+
new TestPixel<Short4>(),
333354
};
334355

335356
[Theory]
336357
[MemberData(nameof(Generic_To_Data))]
337-
public void Generic_To<TDestPixel>(TestPixel<TDestPixel> dummy)
358+
public void Generic_To<TDestPixel>(TestPixel<TDestPixel> _)
338359
where TDestPixel : unmanaged, IPixel<TDestPixel>
339360
{
340-
const int Count = 2134;
341-
TPixel[] source = CreatePixelTestData(Count);
342-
var expected = new TDestPixel[Count];
361+
const int count = 2134;
362+
TPixel[] source = CreatePixelTestData(count);
363+
var expected = new TDestPixel[count];
343364

344365
PixelConverterTests.ReferenceImplementations.To<TPixel, TDestPixel>(this.Configuration, source, expected);
345366

346-
TestOperation(source, expected, (s, d) => this.Operations.To(this.Configuration, s, d.GetSpan()));
367+
TestOperation(source, expected, (s, d) => this.Operations.To(this.Configuration, s, d.GetSpan()), false);
347368
}
348369

349370
[Theory]
@@ -1234,23 +1255,11 @@ public void Verify()
12341255
}
12351256

12361257
// TODO: We really need a PixelTypeInfo.BitsPerComponent property!!
1237-
private static bool IsComplexPixel()
1258+
private static bool IsComplexPixel() => default(TDest) switch
12381259
{
1239-
switch (default(TDest))
1240-
{
1241-
case HalfSingle _:
1242-
case HalfVector2 _:
1243-
case L16 _:
1244-
case La32 _:
1245-
case NormalizedShort2 _:
1246-
case Rg32 _:
1247-
case Short2 _:
1248-
return true;
1249-
1250-
default:
1251-
return Unsafe.SizeOf<TDest>() > sizeof(int);
1252-
}
1253-
}
1260+
HalfSingle or HalfVector2 or L16 or La32 or NormalizedShort2 or Rg32 or Short2 => true,
1261+
_ => Unsafe.SizeOf<TDest>() > sizeof(int),
1262+
};
12541263
}
12551264
}
12561265
}

tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,5 +189,21 @@ public void RgbaVector_FromGrey8()
189189
// assert
190190
Assert.Equal(expected, rgba.ToScaledVector4());
191191
}
192+
193+
[Fact]
194+
public void Issue2048()
195+
{
196+
// https://github.com/SixLabors/ImageSharp/issues/2048
197+
RgbaVector green = Color.Green.ToPixel<RgbaVector>();
198+
using Image<RgbaVector> source = new(Configuration.Default, 1, 1, green);
199+
using Image<HalfVector4> clone = source.CloneAs<HalfVector4>();
200+
201+
Rgba32 srcColor = default;
202+
Rgba32 cloneColor = default;
203+
source[0, 0].ToRgba32(ref srcColor);
204+
clone[0, 0].ToRgba32(ref cloneColor);
205+
206+
Assert.Equal(srcColor, cloneColor);
207+
}
192208
}
193209
}

tests/ImageSharp.Tests/TestUtilities/TestPixel.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the Apache License, Version 2.0.
33

44
using System;
5+
using System.Numerics;
56
using SixLabors.ImageSharp.PixelFormats;
67
using Xunit.Abstractions;
78

@@ -16,6 +17,11 @@ public TestPixel()
1617

1718
public TestPixel(float red, float green, float blue, float alpha)
1819
{
20+
Guard.MustBeBetweenOrEqualTo(red, 0F, 1F, nameof(red));
21+
Guard.MustBeBetweenOrEqualTo(green, 0F, 1F, nameof(green));
22+
Guard.MustBeBetweenOrEqualTo(blue, 0F, 1F, nameof(blue));
23+
Guard.MustBeBetweenOrEqualTo(alpha, 0F, 1F, nameof(alpha));
24+
1925
this.Red = red;
2026
this.Green = green;
2127
this.Blue = blue;
@@ -33,14 +39,11 @@ public TestPixel(float red, float green, float blue, float alpha)
3339
public TPixel AsPixel()
3440
{
3541
var pix = default(TPixel);
36-
pix.FromVector4(new System.Numerics.Vector4(this.Red, this.Green, this.Blue, this.Alpha));
42+
pix.FromScaledVector4(new Vector4(this.Red, this.Green, this.Blue, this.Alpha));
3743
return pix;
3844
}
3945

40-
internal Span<TPixel> AsSpan()
41-
{
42-
return new Span<TPixel>(new[] { this.AsPixel() });
43-
}
46+
internal Span<TPixel> AsSpan() => new(new[] { this.AsPixel() });
4447

4548
public void Deserialize(IXunitSerializationInfo info)
4649
{
@@ -58,9 +61,6 @@ public void Serialize(IXunitSerializationInfo info)
5861
info.AddValue("alpha", this.Alpha);
5962
}
6063

61-
public override string ToString()
62-
{
63-
return $"{typeof(TPixel).Name}{this.AsPixel().ToString()}";
64-
}
64+
public override string ToString() => $"{typeof(TPixel).Name}{this.AsPixel()}";
6565
}
6666
}

0 commit comments

Comments
 (0)