Skip to content

Commit c2d2ccb

Browse files
authored
Merge pull request #869 from SixLabors/af/pixel-conversion
Introduce extended pixel conversion
2 parents 45b7490 + 408e196 commit c2d2ccb

36 files changed

Lines changed: 827 additions & 379 deletions

ImageSharp.sln.DotSettings

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@
382382
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
383383
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
384384
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
385+
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
385386
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
386387
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAlwaysTreatStructAsNotReorderableMigration/@EntryIndexedValue">True</s:Boolean>
387388
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>

src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@ public static void Expand(Span<Vector4> vectors)
3030
for (int i = 0; i < vectors.Length; i++)
3131
{
3232
ref Vector4 v = ref Unsafe.Add(ref baseRef, i);
33-
v.X = Expand(v.X);
34-
v.Y = Expand(v.Y);
35-
v.Z = Expand(v.Z);
33+
Expand(ref v);
3634
}
3735
}
3836

@@ -48,27 +46,33 @@ public static void Compress(Span<Vector4> vectors)
4846
for (int i = 0; i < vectors.Length; i++)
4947
{
5048
ref Vector4 v = ref Unsafe.Add(ref baseRef, i);
51-
v.X = Compress(v.X);
52-
v.Y = Compress(v.Y);
53-
v.Z = Compress(v.Z);
49+
Compress(ref v);
5450
}
5551
}
5652

5753
/// <summary>
5854
/// Expands a companded vector to its linear equivalent with respect to the energy.
5955
/// </summary>
6056
/// <param name="vector">The vector.</param>
61-
/// <returns>The <see cref="Vector4"/> representing the linear channel values.</returns>
6257
[MethodImpl(InliningOptions.ShortMethod)]
63-
public static Vector4 Expand(Vector4 vector) => new Vector4(Expand(vector.X), Expand(vector.Y), Expand(vector.Z), vector.W);
58+
public static void Expand(ref Vector4 vector)
59+
{
60+
vector.X = Expand(vector.X);
61+
vector.Y = Expand(vector.Y);
62+
vector.Z = Expand(vector.Z);
63+
}
6464

6565
/// <summary>
6666
/// Compresses an uncompanded vector (linear) to its nonlinear equivalent.
6767
/// </summary>
6868
/// <param name="vector">The vector.</param>
69-
/// <returns>The <see cref="Vector4"/> representing the nonlinear channel values.</returns>
7069
[MethodImpl(InliningOptions.ShortMethod)]
71-
public static Vector4 Compress(Vector4 vector) => new Vector4(Compress(vector.X), Compress(vector.Y), Compress(vector.Z), vector.W);
70+
public static void Compress(ref Vector4 vector)
71+
{
72+
vector.X = Compress(vector.X);
73+
vector.Y = Compress(vector.Y);
74+
vector.Z = Compress(vector.Z);
75+
}
7276

7377
/// <summary>
7478
/// Expands a companded channel to its linear equivalent with respect to the energy.

src/ImageSharp/Common/Helpers/Guard.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,26 @@ public static void DestinationShouldNotBeTooShort<TSource, TDest>(
257257
}
258258
}
259259

260+
/// <summary>
261+
/// Verifies that the 'destination' span is not shorter than 'source'.
262+
/// </summary>
263+
/// <typeparam name="TSource">The source element type</typeparam>
264+
/// <typeparam name="TDest">The destination element type</typeparam>
265+
/// <param name="source">The source span</param>
266+
/// <param name="destination">The destination span</param>
267+
/// <param name="destinationParamName">The name of the argument for 'destination'</param>
268+
[MethodImpl(InliningOptions.ShortMethod)]
269+
public static void DestinationShouldNotBeTooShort<TSource, TDest>(
270+
Span<TSource> source,
271+
Span<TDest> destination,
272+
string destinationParamName)
273+
{
274+
if (destination.Length < source.Length)
275+
{
276+
ThrowArgumentException($"Destination span is too short!", destinationParamName);
277+
}
278+
}
279+
260280
/// <summary>
261281
/// Verifies, that the `source` span has the length of 'minLength', or longer.
262282
/// </summary>

src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ private void ConvertColorsInto<TPixel>(ImageFrame<TPixel> destination)
173173
Span<TPixel> destRow = destination.GetPixelRowSpan(yy);
174174

175175
// TODO: Investigate if slicing is actually necessary
176-
PixelOperations<TPixel>.Instance.FromVector4(this.configuration, this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow);
176+
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow);
177177
}
178178
}
179179
}

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

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -112,21 +112,15 @@ public void Blend<TPixelSrc>(
112112
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
113113
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
114114

115-
PixelOperations<TPixel>.Instance.ToScaledVector4(
116-
configuration,
117-
background.Slice(0, background.Length),
118-
backgroundSpan);
119-
PixelOperations<TPixelSrc>.Instance.ToScaledVector4(
120-
configuration,
121-
source.Slice(0, background.Length),
122-
sourceSpan);
115+
ReadOnlySpan<TPixel> sourcePixels = background.Slice(0, background.Length);
116+
PixelOperations<TPixel>.Instance.ToVector4(configuration, sourcePixels, backgroundSpan, PixelConversionModifiers.Scale);
117+
ReadOnlySpan<TPixelSrc> sourcePixels1 = source.Slice(0, background.Length);
118+
PixelOperations<TPixelSrc>.Instance.ToVector4(configuration, sourcePixels1, sourceSpan, PixelConversionModifiers.Scale);
123119

124120
this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount);
125121

126-
PixelOperations<TPixel>.Instance.FromScaledVector4(
127-
configuration,
128-
destinationSpan.Slice(0, background.Length),
129-
destination);
122+
Span<Vector4> sourceVectors = destinationSpan.Slice(0, background.Length);
123+
PixelOperations<TPixel>.Instance.FromVector4Destructive(configuration, sourceVectors, destination, PixelConversionModifiers.Scale);
130124
}
131125
}
132126

@@ -161,21 +155,15 @@ public void Blend<TPixelSrc>(
161155
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
162156
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
163157

164-
PixelOperations<TPixel>.Instance.ToScaledVector4(
165-
configuration,
166-
background.Slice(0, background.Length),
167-
backgroundSpan);
168-
PixelOperations<TPixelSrc>.Instance.ToScaledVector4(
169-
configuration,
170-
source.Slice(0, background.Length),
171-
sourceSpan);
158+
ReadOnlySpan<TPixel> sourcePixels = background.Slice(0, background.Length);
159+
PixelOperations<TPixel>.Instance.ToVector4(configuration, sourcePixels, backgroundSpan, PixelConversionModifiers.Scale);
160+
ReadOnlySpan<TPixelSrc> sourcePixels1 = source.Slice(0, background.Length);
161+
PixelOperations<TPixelSrc>.Instance.ToVector4(configuration, sourcePixels1, sourceSpan, PixelConversionModifiers.Scale);
172162

173163
this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount);
174164

175-
PixelOperations<TPixel>.Instance.FromScaledVector4(
176-
configuration,
177-
destinationSpan.Slice(0, background.Length),
178-
destination);
165+
Span<Vector4> sourceVectors = destinationSpan.Slice(0, background.Length);
166+
PixelOperations<TPixel>.Instance.FromVector4Destructive(configuration, sourceVectors, destination, PixelConversionModifiers.Scale);
179167
}
180168
}
181169
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright (c) Six Labors and contributors.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
using System;
5+
6+
using SixLabors.ImageSharp.ColorSpaces.Companding;
7+
8+
namespace SixLabors.ImageSharp.PixelFormats
9+
{
10+
/// <summary>
11+
/// Flags responsible to select additional operations which could be effitiently applied in
12+
/// <see cref="PixelOperations{TPixel}.ToVector4(SixLabors.ImageSharp.Configuration,System.ReadOnlySpan{TPixel},System.Span{System.Numerics.Vector4},SixLabors.ImageSharp.PixelFormats.PixelConversionModifiers)"/>
13+
/// or
14+
/// <see cref="PixelOperations{TPixel}.FromVector4Destructive(SixLabors.ImageSharp.Configuration,System.Span{System.Numerics.Vector4},System.Span{TPixel},SixLabors.ImageSharp.PixelFormats.PixelConversionModifiers)"/>
15+
/// knowing the pixel type.
16+
/// </summary>
17+
[Flags]
18+
internal enum PixelConversionModifiers
19+
{
20+
/// <summary>
21+
/// No special operation is selected
22+
/// </summary>
23+
None = 0,
24+
25+
/// <summary>
26+
/// Select <see cref="IPixel.ToScaledVector4"/> and <see cref="IPixel.FromScaledVector4"/> instead the standard (non scaled) variants.
27+
/// </summary>
28+
Scale = 1 << 0,
29+
30+
/// <summary>
31+
/// Enable alpha premultiplication / unpremultiplication
32+
/// </summary>
33+
Premultiply = 1 << 1,
34+
35+
/// <summary>
36+
/// Enable SRGB companding (defined in <see cref="SRgbCompanding"/>).
37+
/// </summary>
38+
SRgbCompand = 1 << 2,
39+
}
40+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) Six Labors and contributors.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
using System.Runtime.CompilerServices;
5+
6+
namespace SixLabors.ImageSharp.PixelFormats
7+
{
8+
internal static class PixelConversionModifiersExtensions
9+
{
10+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
11+
public static bool IsDefined(this PixelConversionModifiers modifiers, PixelConversionModifiers expected) =>
12+
(modifiers & expected) == expected;
13+
14+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
15+
public static PixelConversionModifiers Remove(
16+
this PixelConversionModifiers modifiers,
17+
PixelConversionModifiers removeThis) =>
18+
modifiers & ~removeThis;
19+
}
20+
}

src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,29 +42,16 @@ internal override void ToArgb32(Configuration configuration, ReadOnlySpan<Argb32
4242
}
4343

4444
/// <inheritdoc />
45-
internal override void FromVector4(Configuration configuration, ReadOnlySpan<Vector4> sourceVectors, Span<Argb32> destPixels)
45+
internal override void FromVector4Destructive(Configuration configuration, Span<Vector4> sourceVectors, Span<Argb32> destPixels, PixelConversionModifiers modifiers)
4646
{
47-
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false);
47+
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, modifiers.Remove(PixelConversionModifiers.Scale));
4848
}
4949

5050
/// <inheritdoc />
51-
internal override void ToVector4(Configuration configuration, ReadOnlySpan<Argb32> sourcePixels, Span<Vector4> destVectors)
51+
internal override void ToVector4(Configuration configuration, ReadOnlySpan<Argb32> sourcePixels, Span<Vector4> destVectors, PixelConversionModifiers modifiers)
5252
{
53-
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false);
53+
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale));
5454
}
55-
56-
/// <inheritdoc />
57-
internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan<Vector4> sourceVectors, Span<Argb32> destPixels)
58-
{
59-
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true);
60-
}
61-
62-
/// <inheritdoc />
63-
internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan<Argb32> sourcePixels, Span<Vector4> destVectors)
64-
{
65-
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true);
66-
}
67-
6855
/// <inheritdoc />
6956
internal override void ToRgba32(Configuration configuration, ReadOnlySpan<Argb32> sourcePixels, Span<Rgba32> destPixels)
7057
{

src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,30 +42,17 @@ internal override void ToBgr24(Configuration configuration, ReadOnlySpan<Bgr24>
4242
}
4343

4444
/// <inheritdoc />
45-
internal override void FromVector4(Configuration configuration, ReadOnlySpan<Vector4> sourceVectors, Span<Bgr24> destPixels)
45+
internal override void FromVector4Destructive(Configuration configuration, Span<Vector4> sourceVectors, Span<Bgr24> destPixels, PixelConversionModifiers modifiers)
4646
{
47-
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false);
47+
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, modifiers.Remove(PixelConversionModifiers.Scale | PixelConversionModifiers.Premultiply));
4848
}
4949

5050
/// <inheritdoc />
51-
internal override void ToVector4(Configuration configuration, ReadOnlySpan<Bgr24> sourcePixels, Span<Vector4> destVectors)
51+
internal override void ToVector4(Configuration configuration, ReadOnlySpan<Bgr24> sourcePixels, Span<Vector4> destVectors, PixelConversionModifiers modifiers)
5252
{
53-
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false);
53+
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale | PixelConversionModifiers.Premultiply));
5454
}
5555

56-
/// <inheritdoc />
57-
internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan<Vector4> sourceVectors, Span<Bgr24> destPixels)
58-
{
59-
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true);
60-
}
61-
62-
/// <inheritdoc />
63-
internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan<Bgr24> sourcePixels, Span<Vector4> destVectors)
64-
{
65-
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true);
66-
}
67-
68-
6956
/// <inheritdoc />
7057
internal override void ToArgb32(Configuration configuration, ReadOnlySpan<Bgr24> sourcePixels, Span<Argb32> destPixels)
7158
{

src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,29 +42,16 @@ internal override void ToBgra32(Configuration configuration, ReadOnlySpan<Bgra32
4242
}
4343

4444
/// <inheritdoc />
45-
internal override void FromVector4(Configuration configuration, ReadOnlySpan<Vector4> sourceVectors, Span<Bgra32> destPixels)
45+
internal override void FromVector4Destructive(Configuration configuration, Span<Vector4> sourceVectors, Span<Bgra32> destPixels, PixelConversionModifiers modifiers)
4646
{
47-
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false);
47+
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, modifiers.Remove(PixelConversionModifiers.Scale));
4848
}
4949

5050
/// <inheritdoc />
51-
internal override void ToVector4(Configuration configuration, ReadOnlySpan<Bgra32> sourcePixels, Span<Vector4> destVectors)
51+
internal override void ToVector4(Configuration configuration, ReadOnlySpan<Bgra32> sourcePixels, Span<Vector4> destVectors, PixelConversionModifiers modifiers)
5252
{
53-
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false);
53+
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale));
5454
}
55-
56-
/// <inheritdoc />
57-
internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan<Vector4> sourceVectors, Span<Bgra32> destPixels)
58-
{
59-
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true);
60-
}
61-
62-
/// <inheritdoc />
63-
internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan<Bgra32> sourcePixels, Span<Vector4> destVectors)
64-
{
65-
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true);
66-
}
67-
6855
/// <inheritdoc />
6956
internal override void ToRgba32(Configuration configuration, ReadOnlySpan<Bgra32> sourcePixels, Span<Rgba32> destPixels)
7057
{

0 commit comments

Comments
 (0)