Browse Source

Merge branch 'master' into jpeg-port

pull/298/head
James Jackson-South 9 years ago
parent
commit
cd72206cd6
  1. 4
      .editorconfig
  2. 1
      .gitignore
  3. 19
      ImageSharp.sln
  4. 12
      samples/AvatarWithRoundedCorner/AvatarWithRoundedCorner.csproj
  5. 70
      samples/AvatarWithRoundedCorner/Program.cs
  6. BIN
      samples/AvatarWithRoundedCorner/fb.jpg
  7. 2
      src/ImageSharp/Formats/Png/ImageExtensions.cs
  8. 4
      src/ImageSharp/Image/Image.FromBytes.cs
  9. 18
      src/ImageSharp/ImageSharp.csproj
  10. 16
      src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs
  11. 25
      src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs
  12. 62
      src/ImageSharp/PixelFormats/PixelBlenderMode.cs
  13. 57
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultAddPixelBlender{TPixel}.cs
  14. 57
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultDarkenPixelBlender{TPixel}.cs
  15. 57
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultHardLightPixelBlender{TPixel}.cs
  16. 57
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultLightenPixelBlender{TPixel}.cs
  17. 57
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultMultiplyPixelBlender{TPixel}.cs
  18. 57
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultNormalPixelBlender{TPixel}.cs
  19. 57
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultOverlayPixelBlender{TPixel}.cs
  20. 849
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs
  21. 118
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt
  22. 57
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultScreenPixelBlender{TPixel}.cs
  23. 57
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultSubstractPixelBlender{TPixel}.cs
  24. 451
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs
  25. 112
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt
  26. 67
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs
  27. 151
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions{TPixel}.cs
  28. 39
      src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs
  29. 4
      tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs
  30. 70
      tests/ImageSharp.Tests/Drawing/BlendedShapes.cs
  31. 14
      tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccReaderTests.cs
  32. 12
      tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccWriterTests.cs
  33. 18
      tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs
  34. 54
      tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs
  35. 66
      tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs
  36. 103
      tests/ImageSharp.Tests/TestDataIcc/IccTestDataProfiles.cs

4
.editorconfig

@ -14,3 +14,7 @@ dotnet_style_predefined_type_for_member_access = true:warning
dotnet_style_qualification_for_field = true:warning dotnet_style_qualification_for_field = true:warning
dotnet_style_qualification_for_method = true:warning dotnet_style_qualification_for_method = true:warning
dotnet_style_qualification_for_property = true:warning dotnet_style_qualification_for_property = true:warning
[*.tt]
indent_style = space
indent_size = 4

1
.gitignore

@ -217,3 +217,4 @@ artifacts/
#CodeCoverage #CodeCoverage
**/CodeCoverage/* **/CodeCoverage/*
docs/ docs/
/samples/AvatarWithRoundedCorner/output

19
ImageSharp.sln

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio 15
VisualStudioVersion = 15.0.26403.7 VisualStudioVersion = 15.0.26430.6
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
@ -45,6 +45,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Benchmarks", "te
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Sandbox46", "tests\ImageSharp.Sandbox46\ImageSharp.Sandbox46.csproj", "{96188137-5FA6-4924-AB6E-4EFF79C6E0BB}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Sandbox46", "tests\ImageSharp.Sandbox46\ImageSharp.Sandbox46.csproj", "{96188137-5FA6-4924-AB6E-4EFF79C6E0BB}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{7CC6D57E-B916-43B8-B315-A0BB92F260A2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AvatarWithRoundedCorner", "samples\AvatarWithRoundedCorner\AvatarWithRoundedCorner.csproj", "{844FC582-4E78-4371-847D-EFD4D1103578}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -127,6 +131,18 @@ Global
{96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x64.Build.0 = Release|Any CPU {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x64.Build.0 = Release|Any CPU
{96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x86.ActiveCfg = Release|Any CPU {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x86.ActiveCfg = Release|Any CPU
{96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x86.Build.0 = Release|Any CPU {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x86.Build.0 = Release|Any CPU
{844FC582-4E78-4371-847D-EFD4D1103578}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{844FC582-4E78-4371-847D-EFD4D1103578}.Debug|Any CPU.Build.0 = Debug|Any CPU
{844FC582-4E78-4371-847D-EFD4D1103578}.Debug|x64.ActiveCfg = Debug|Any CPU
{844FC582-4E78-4371-847D-EFD4D1103578}.Debug|x64.Build.0 = Debug|Any CPU
{844FC582-4E78-4371-847D-EFD4D1103578}.Debug|x86.ActiveCfg = Debug|Any CPU
{844FC582-4E78-4371-847D-EFD4D1103578}.Debug|x86.Build.0 = Debug|Any CPU
{844FC582-4E78-4371-847D-EFD4D1103578}.Release|Any CPU.ActiveCfg = Release|Any CPU
{844FC582-4E78-4371-847D-EFD4D1103578}.Release|Any CPU.Build.0 = Release|Any CPU
{844FC582-4E78-4371-847D-EFD4D1103578}.Release|x64.ActiveCfg = Release|Any CPU
{844FC582-4E78-4371-847D-EFD4D1103578}.Release|x64.Build.0 = Release|Any CPU
{844FC582-4E78-4371-847D-EFD4D1103578}.Release|x86.ActiveCfg = Release|Any CPU
{844FC582-4E78-4371-847D-EFD4D1103578}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -139,5 +155,6 @@ Global
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC}
{2BF743D8-2A06-412D-96D7-F448F00C5EA5} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {2BF743D8-2A06-412D-96D7-F448F00C5EA5} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC}
{96188137-5FA6-4924-AB6E-4EFF79C6E0BB} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {96188137-5FA6-4924-AB6E-4EFF79C6E0BB} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC}
{844FC582-4E78-4371-847D-EFD4D1103578} = {7CC6D57E-B916-43B8-B315-A0BB92F260A2}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

12
samples/AvatarWithRoundedCorner/AvatarWithRoundedCorner.csproj

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\ImageSharp.Drawing\ImageSharp.Drawing.csproj" />
</ItemGroup>
</Project>

70
samples/AvatarWithRoundedCorner/Program.cs

@ -0,0 +1,70 @@

namespace AvatarWithRoundedCorner
{
using System;
using System.Numerics;
using ImageSharp;
using SixLabors.Shapes;
class Program
{
static void Main(string[] args)
{
System.IO.Directory.CreateDirectory("output");
GenerateAvatar("fb.jpg", "output/fb.png", new ImageSharp.Size(200, 200), 20);
GenerateAvatar("fb.jpg", "output/fb-round.png", new ImageSharp.Size(200, 200), 100);
GenerateAvatar("fb.jpg", "output/fb-rounder.png", new ImageSharp.Size(200, 200), 150);
}
private static void GenerateAvatar(string source, string destination, ImageSharp.Size size, float cornerRadius)
{
using (var image = Image.Load(source))
{
image.Resize(new ImageSharp.Processing.ResizeOptions
{
Size = size,
Mode = ImageSharp.Processing.ResizeMode.Crop
});
ApplyRoundedCourners(image, cornerRadius);
image.Save(destination);
}
}
public static void ApplyRoundedCourners(Image<Rgba32> img, float cornerRadius)
{
var corners = BuildCorners(img.Width, img.Height, cornerRadius);
// now we have our corners time to draw them
img.Fill(Rgba32.Transparent, corners, new GraphicsOptions(true)
{
BlenderMode = ImageSharp.PixelFormats.PixelBlenderMode.Src // enforces that any part of this shape that has color is punched out of the background
});
}
public static IPathCollection BuildCorners(int imageWidth, int imageHeight, float cornerRadius)
{
// first create a square
var rect = new SixLabors.Shapes.Rectangle(-0.5f, -0.5f, cornerRadius, cornerRadius);
// then cut out of the square a circle so we are left with a corner
var cornerToptLeft = rect.Clip(new SixLabors.Shapes.Ellipse(cornerRadius-0.5f, cornerRadius - 0.5f, cornerRadius));
// corner is now a corner shape positions top left
//lets make 3 more positioned correctly, we cando that by translating the orgional artound the center of the image
var center = new Vector2(imageWidth / 2, imageHeight / 2);
var angle = Math.PI / 2f;
float rightPos = imageWidth - cornerToptLeft.Bounds.Width +1;
float bottomPos = imageHeight - cornerToptLeft.Bounds.Height + 1;
// move it across the widthof the image - the width of the shape
var cornerTopRight = cornerToptLeft.RotateDegree(90).Translate(rightPos, 0);
var cornerBottomLeft = cornerToptLeft.RotateDegree(-90).Translate(0, bottomPos);
var cornerBottomRight = cornerToptLeft.RotateDegree(180).Translate(rightPos, bottomPos);
return new PathCollection(cornerToptLeft, cornerBottomLeft, cornerTopRight, cornerBottomRight);
}
}
}

BIN
samples/AvatarWithRoundedCorner/fb.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

2
src/ImageSharp/Formats/Png/ImageExtensions.cs

@ -46,7 +46,7 @@ namespace ImageSharp
public static Image<TPixel> SaveAsPng<TPixel>(this Image<TPixel> source, Stream stream, IPngEncoderOptions options) public static Image<TPixel> SaveAsPng<TPixel>(this Image<TPixel> source, Stream stream, IPngEncoderOptions options)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
PngEncoder encoder = new PngEncoder(); var encoder = new PngEncoder();
encoder.Encode(source, stream, options); encoder.Encode(source, stream, options);
return source; return source;

4
src/ImageSharp/Image/Image.FromBytes.cs

@ -126,7 +126,7 @@ namespace ImageSharp
public static Image<TPixel> Load<TPixel>(Configuration config, byte[] data, IDecoderOptions options) public static Image<TPixel> Load<TPixel>(Configuration config, byte[] data, IDecoderOptions options)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
using (MemoryStream ms = new MemoryStream(data)) using (var ms = new MemoryStream(data))
{ {
return Load<TPixel>(config, ms, options); return Load<TPixel>(config, ms, options);
} }
@ -143,7 +143,7 @@ namespace ImageSharp
public static Image<TPixel> Load<TPixel>(byte[] data, IImageDecoder decoder, IDecoderOptions options) public static Image<TPixel> Load<TPixel>(byte[] data, IImageDecoder decoder, IDecoderOptions options)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
using (MemoryStream ms = new MemoryStream(data)) using (var ms = new MemoryStream(data))
{ {
return Load<TPixel>(ms, decoder, options); return Load<TPixel>(ms, decoder, options);
} }

18
src/ImageSharp/ImageSharp.csproj

@ -63,6 +63,14 @@
<Generator>TextTemplatingFileGenerator</Generator> <Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Rgba32.PixelOperations.Generated.cs</LastGenOutput> <LastGenOutput>Rgba32.PixelOperations.Generated.cs</LastGenOutput>
</None> </None>
<None Update="PixelFormats\PixelBlenders\PorterDuffFunctions.Generated.tt">
<LastGenOutput>PorterDuffFunctions.Generated.cs</LastGenOutput>
<Generator>TextTemplatingFileGenerator</Generator>
</None>
<None Update="PixelFormats\PixelBlenders\DefaultPixelBlenders.Generated.tt">
<LastGenOutput>DefaultPixelBlenders.Generated.cs</LastGenOutput>
<Generator>TextTemplatingFileGenerator</Generator>
</None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" /> <Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
@ -83,5 +91,15 @@
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DependentUpon>Rgba32.PixelOperations.Generated.tt</DependentUpon> <DependentUpon>Rgba32.PixelOperations.Generated.tt</DependentUpon>
</Compile> </Compile>
<Compile Update="PixelFormats\PixelBlenders\DefaultPixelBlenders.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>DefaultPixelBlenders.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\PixelBlenders\PorterDuffFunctions.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>PorterDuffFunctions.Generated.tt</DependentUpon>
</Compile>
</ItemGroup> </ItemGroup>
</Project> </Project>

16
src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs

@ -5,6 +5,8 @@
namespace ImageSharp namespace ImageSharp
{ {
using System.Collections.Generic;
/// <summary> /// <summary>
/// Reads and parses ICC data from a byte array /// Reads and parses ICC data from a byte array
/// </summary> /// </summary>
@ -85,9 +87,21 @@ namespace ImageSharp
{ {
IccTagTableEntry[] tagTable = this.ReadTagTable(reader); IccTagTableEntry[] tagTable = this.ReadTagTable(reader);
IccTagDataEntry[] entries = new IccTagDataEntry[tagTable.Length]; IccTagDataEntry[] entries = new IccTagDataEntry[tagTable.Length];
var store = new Dictionary<uint, IccTagDataEntry>();
for (int i = 0; i < tagTable.Length; i++) for (int i = 0; i < tagTable.Length; i++)
{ {
IccTagDataEntry entry = reader.ReadTagDataEntry(tagTable[i]); IccTagDataEntry entry;
uint offset = tagTable[i].Offset;
if (store.ContainsKey(offset))
{
entry = store[offset];
}
else
{
entry = reader.ReadTagDataEntry(tagTable[i]);
store.Add(offset, entry);
}
entry.TagSignature = tagTable[i].Signature; entry.TagSignature = tagTable[i].Signature;
entries[i] = entry; entries[i] = entry;
} }

25
src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs

@ -5,6 +5,7 @@
namespace ImageSharp namespace ImageSharp
{ {
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -76,30 +77,18 @@ namespace ImageSharp
private IccTagTableEntry[] WriteTagData(IccDataWriter writer, List<IccTagDataEntry> entries) private IccTagTableEntry[] WriteTagData(IccDataWriter writer, List<IccTagDataEntry> entries)
{ {
var inData = new List<IccTagDataEntry>(entries); IEnumerable<IGrouping<IccTagDataEntry, IccTagDataEntry>> grouped = entries.GroupBy(t => t);
var dupData = new List<IccTagDataEntry[]>();
while (inData.Count > 0)
{
IccTagDataEntry[] items = inData.Where(t => inData[0].Equals(t)).ToArray();
dupData.Add(items);
foreach (IccTagDataEntry item in items)
{
inData.Remove(item);
}
}
var table = new List<IccTagTableEntry>();
// (Header size) + (entry count) + (nr of entries) * (size of table entry) // (Header size) + (entry count) + (nr of entries) * (size of table entry)
writer.SetIndex(128 + 4 + (entries.Count * 12)); writer.SetIndex(128 + 4 + (entries.Count * 12));
foreach (IccTagDataEntry[] entry in dupData) var table = new List<IccTagTableEntry>();
foreach (IGrouping<IccTagDataEntry, IccTagDataEntry> group in grouped)
{ {
writer.WriteTagDataEntry(entry[0], out IccTagTableEntry tentry); writer.WriteTagDataEntry(group.Key, out IccTagTableEntry tableEntry);
foreach (IccTagDataEntry item in entry) foreach (IccTagDataEntry item in group)
{ {
table.Add(new IccTagTableEntry(item.TagSignature, tentry.Offset, tentry.DataSize)); table.Add(new IccTagTableEntry(item.TagSignature, tableEntry.Offset, tableEntry.DataSize));
} }
} }

62
src/ImageSharp/PixelFormats/PixelBlenderMode.cs

@ -57,6 +57,66 @@ namespace ImageSharp.PixelFormats
/// <summary> /// <summary>
/// Multiplies or screens the colors, depending on the source value. /// Multiplies or screens the colors, depending on the source value.
/// </summary> /// </summary>
HardLight HardLight,
/// <summary>
/// returns the source colors
/// </summary>
Src,
/// <summary>
/// returns the source over the destination
/// </summary>
Atop,
/// <summary>
/// returns the detination over the source
/// </summary>
Over,
/// <summary>
/// the source where the desitnation and source overlap
/// </summary>
In,
/// <summary>
/// the destination where the desitnation and source overlap
/// </summary>
Out,
/// <summary>
/// the destination where the source does not overlap it
/// </summary>
Dest,
/// <summary>
/// the source where they dont overlap othersie dest in overlapping parts
/// </summary>
DestAtop,
/// <summary>
/// the destnation over the source
/// </summary>
DestOver,
/// <summary>
/// the destination where the desitnation and source overlap
/// </summary>
DestIn,
/// <summary>
/// the source where the desitnation and source overlap
/// </summary>
DestOut,
/// <summary>
/// the clear.
/// </summary>
Clear,
/// <summary>
/// clear where they overlap
/// </summary>
Xor
} }
} }

57
src/ImageSharp/PixelFormats/PixelBlenders/DefaultAddPixelBlender{TPixel}.cs

@ -1,57 +0,0 @@
// <copyright file="DefaultAddPixelBlender{TPixel}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
/// Applies an "Add" blending to pixels.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel</typeparam>
internal class DefaultAddPixelBlender<TPixel> : PixelBlender<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DefaultAddPixelBlender<TPixel> Instance { get; } = new DefaultAddPixelBlender<TPixel>();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions<TPixel>.AddFunction(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.AddFunction(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
}

57
src/ImageSharp/PixelFormats/PixelBlenders/DefaultDarkenPixelBlender{TPixel}.cs

@ -1,57 +0,0 @@
// <copyright file="DefaultDarkenPixelBlender{TPixel}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
/// Applies an "Darken" blending to pixels.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel</typeparam>
internal class DefaultDarkenPixelBlender<TPixel> : PixelBlender<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DefaultDarkenPixelBlender<TPixel> Instance { get; } = new DefaultDarkenPixelBlender<TPixel>();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions<TPixel>.DarkenFunction(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.DarkenFunction(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
}

57
src/ImageSharp/PixelFormats/PixelBlenders/DefaultHardLightPixelBlender{TPixel}.cs

@ -1,57 +0,0 @@
// <copyright file="DefaultHardLightPixelBlender{TPixel}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
/// Applies an "Hard Light" blending to pixels.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel</typeparam>
internal class DefaultHardLightPixelBlender<TPixel> : PixelBlender<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DefaultHardLightPixelBlender<TPixel> Instance { get; } = new DefaultHardLightPixelBlender<TPixel>();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions<TPixel>.HardLightFunction(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.HardLightFunction(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
}

57
src/ImageSharp/PixelFormats/PixelBlenders/DefaultLightenPixelBlender{TPixel}.cs

@ -1,57 +0,0 @@
// <copyright file="DefaultLightenPixelBlender{TPixel}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
/// Applies an "Lighten" blending to pixels.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel</typeparam>
internal class DefaultLightenPixelBlender<TPixel> : PixelBlender<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DefaultLightenPixelBlender<TPixel> Instance { get; } = new DefaultLightenPixelBlender<TPixel>();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions<TPixel>.LightenFunction(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.LightenFunction(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
}

57
src/ImageSharp/PixelFormats/PixelBlenders/DefaultMultiplyPixelBlender{TPixel}.cs

@ -1,57 +0,0 @@
// <copyright file="DefaultMultiplyPixelBlender{TPixel}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
/// Applies an "Multiply" blending to pixels.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel</typeparam>
internal class DefaultMultiplyPixelBlender<TPixel> : PixelBlender<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DefaultMultiplyPixelBlender<TPixel> Instance { get; } = new DefaultMultiplyPixelBlender<TPixel>();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions<TPixel>.MultiplyFunction(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.MultiplyFunction(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
}

57
src/ImageSharp/PixelFormats/PixelBlenders/DefaultNormalPixelBlender{TPixel}.cs

@ -1,57 +0,0 @@
// <copyright file="DefaultNormalPixelBlender{TPixel}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
/// Applies a "Normal" otherwise nown as "Alpha Blending" blending to pixels.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel</typeparam>
internal class DefaultNormalPixelBlender<TPixel> : PixelBlender<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DefaultNormalPixelBlender<TPixel> Instance { get; } = new DefaultNormalPixelBlender<TPixel>();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions<TPixel>.NormalBlendFunction(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.NormalBlendFunction(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
}

57
src/ImageSharp/PixelFormats/PixelBlenders/DefaultOverlayPixelBlender{TPixel}.cs

@ -1,57 +0,0 @@
// <copyright file="DefaultOverlayPixelBlender{TPixel}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
/// Applies an "Overlay" blending to pixels.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel</typeparam>
internal class DefaultOverlayPixelBlender<TPixel> : PixelBlender<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DefaultOverlayPixelBlender<TPixel> Instance { get; } = new DefaultOverlayPixelBlender<TPixel>();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions<TPixel>.OverlayFunction(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.OverlayFunction(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
}

849
src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs

@ -0,0 +1,849 @@
// <autogenerated />
// <copyright file="PorterDuffFunctions.Generated.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
/// <summary>
/// Collection of Porter Duff alpha blending functions applying different composition models.
/// </summary>
/// <remarks>
/// These functions are designed to be a general solution for all color cases,
/// that is, they take in account the alpha value of both the backdrop
/// and source, and there's no need to alpha-premultiply neither the backdrop
/// nor the source.
/// Note there are faster functions for when the backdrop color is known
/// to be opaque
/// </remarks>
internal static class DefaultPixelBlenders<TPixel>
where TPixel : struct, IPixel<TPixel>
{
internal class Normal : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Normal Instance { get; } = new Normal();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Normal(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Normal(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Multiply : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Multiply Instance { get; } = new Multiply();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Multiply(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Multiply(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Add : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Add Instance { get; } = new Add();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Add(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Add(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Substract : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Substract Instance { get; } = new Substract();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Substract(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Substract(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Screen : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Screen Instance { get; } = new Screen();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Screen(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Screen(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Darken : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Darken Instance { get; } = new Darken();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Darken(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Darken(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Lighten : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Lighten Instance { get; } = new Lighten();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Lighten(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Lighten(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Overlay : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Overlay Instance { get; } = new Overlay();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Overlay(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Overlay(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class HardLight : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static HardLight Instance { get; } = new HardLight();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.HardLight(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.HardLight(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Src : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Src Instance { get; } = new Src();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Src(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Src(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Atop : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Atop Instance { get; } = new Atop();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Atop(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Atop(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Over : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Over Instance { get; } = new Over();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Over(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Over(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class In : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static In Instance { get; } = new In();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.In(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.In(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Out : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Out Instance { get; } = new Out();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Out(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Out(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Dest : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Dest Instance { get; } = new Dest();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Dest(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Dest(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class DestAtop : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DestAtop Instance { get; } = new DestAtop();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.DestAtop(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.DestAtop(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class DestOver : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DestOver Instance { get; } = new DestOver();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.DestOver(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.DestOver(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class DestIn : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DestIn Instance { get; } = new DestIn();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.DestIn(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.DestIn(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class DestOut : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DestOut Instance { get; } = new DestOut();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.DestOut(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.DestOut(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Clear : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Clear Instance { get; } = new Clear();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Clear(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Clear(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Xor : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Xor Instance { get; } = new Xor();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Xor(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Xor(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
}
}

118
src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt

@ -0,0 +1,118 @@
<#
// <copyright file="DefaultPixelBlenders.Generated.tt" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
#>
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
// <autogenerated />
// <copyright file="PorterDuffFunctions.Generated.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
/// <summary>
/// Collection of Porter Duff alpha blending functions applying different composition models.
/// </summary>
/// <remarks>
/// These functions are designed to be a general solution for all color cases,
/// that is, they take in account the alpha value of both the backdrop
/// and source, and there's no need to alpha-premultiply neither the backdrop
/// nor the source.
/// Note there are faster functions for when the backdrop color is known
/// to be opaque
/// </remarks>
internal static class DefaultPixelBlenders<TPixel>
where TPixel : struct, IPixel<TPixel>
{
<#
string[] blenders = new []{
"Normal",
"Multiply",
"Add",
"Substract",
"Screen",
"Darken",
"Lighten",
"Overlay",
"HardLight",
"Src" ,
"Atop" ,
"Over" ,
"In" ,
"Out" ,
"Dest" ,
"DestAtop" ,
"DestOver" ,
"DestIn" ,
"DestOut" ,
"Clear" ,
"Xor" ,
};
foreach(var blender in blenders) {
#>
internal class <#=blender#> : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static <#=blender#> Instance { get; } = new <#=blender#>();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.<#=blender#>(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.<#=blender#>(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
<#
}
#>
}
}

57
src/ImageSharp/PixelFormats/PixelBlenders/DefaultScreenPixelBlender{TPixel}.cs

@ -1,57 +0,0 @@
// <copyright file="DefaultScreenPixelBlender{TPixel}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
/// Applies an "Screen" blending to pixels.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel</typeparam>
internal class DefaultScreenPixelBlender<TPixel> : PixelBlender<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DefaultScreenPixelBlender<TPixel> Instance { get; } = new DefaultScreenPixelBlender<TPixel>();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions<TPixel>.ScreenFunction(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.ScreenFunction(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
}

57
src/ImageSharp/PixelFormats/PixelBlenders/DefaultSubstractPixelBlender{TPixel}.cs

@ -1,57 +0,0 @@
// <copyright file="DefaultSubstractPixelBlender{TPixel}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
/// Applies an "Subtract" blending to pixels.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel</typeparam>
internal class DefaultSubstractPixelBlender<TPixel> : PixelBlender<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DefaultSubstractPixelBlender<TPixel> Instance { get; } = new DefaultSubstractPixelBlender<TPixel>();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions<TPixel>.SubstractFunction(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.SubstractFunction(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
}

451
src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs

@ -0,0 +1,451 @@
// <autogenerated />
// <copyright file="PorterDuffFunctions.Generated.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System.Numerics;
using System.Runtime.CompilerServices;
internal static partial class PorterDuffFunctions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Src(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
source.W *= opacity;
Vector4 xform = source;
// calculate weights
float xw = Vector4.Zero.W * source.W;
float bw = Vector4.Zero.W - xw;
float sw = source.W - xw;
// calculate final alpha
float a = xw + bw + sw;
// calculate final value
xform = ((xform * xw) + (Vector4.Zero * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon);
return Vector4.Lerp(backdrop, xform, opacity);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Atop(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
Vector4 xform = source;
// calculate weights
float xw = backdrop.W * Vector4.Zero.W;
float bw = backdrop.W - xw;
float sw = Vector4.Zero.W - xw;
// calculate final alpha
float a = xw + bw + sw;
// calculate final value
xform = ((xform * xw) + (backdrop * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon);
return Vector4.Lerp(backdrop, xform, opacity);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Over(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
source.W *= opacity;
Vector4 xform = source;
// calculate weights
float xw = backdrop.W * source.W;
float bw = backdrop.W - xw;
float sw = source.W - xw;
// calculate final alpha
float a = xw + bw + sw;
// calculate final value
xform = ((xform * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon);
return Vector4.Lerp(backdrop, xform, opacity);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 In(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
Vector4 xform = source;
// calculate weights
float xw = Vector4.Zero.W * Vector4.Zero.W;
float bw = Vector4.Zero.W - xw;
float sw = Vector4.Zero.W - xw;
// calculate final alpha
float a = xw + bw + sw;
// calculate final value
xform = ((xform * xw) + (Vector4.Zero * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon);
return Vector4.Lerp(backdrop, xform, opacity);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Out(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
source.W *= opacity;
Vector4 xform = Vector4.Zero;
// calculate weights
float xw = Vector4.Zero.W * source.W;
float bw = Vector4.Zero.W - xw;
float sw = source.W - xw;
// calculate final alpha
float a = xw + bw + sw;
// calculate final value
xform = ((xform * xw) + (Vector4.Zero * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon);
return Vector4.Lerp(backdrop, xform, opacity);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Dest(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
Vector4 xform = backdrop;
// calculate weights
float xw = backdrop.W * Vector4.Zero.W;
float bw = backdrop.W - xw;
float sw = Vector4.Zero.W - xw;
// calculate final alpha
float a = xw + bw + sw;
// calculate final value
xform = ((xform * xw) + (backdrop * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon);
return Vector4.Lerp(backdrop, xform, opacity);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 DestAtop(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
source.W *= opacity;
Vector4 xform = backdrop;
// calculate weights
float xw = Vector4.Zero.W * source.W;
float bw = Vector4.Zero.W - xw;
float sw = source.W - xw;
// calculate final alpha
float a = xw + bw + sw;
// calculate final value
xform = ((xform * xw) + (Vector4.Zero * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon);
return Vector4.Lerp(backdrop, xform, opacity);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 DestOver(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
source.W *= opacity;
Vector4 xform = backdrop;
// calculate weights
float xw = backdrop.W * source.W;
float bw = backdrop.W - xw;
float sw = source.W - xw;
// calculate final alpha
float a = xw + bw + sw;
// calculate final value
xform = ((xform * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon);
return Vector4.Lerp(backdrop, xform, opacity);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 DestIn(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
Vector4 xform = backdrop;
// calculate weights
float xw = Vector4.Zero.W * Vector4.Zero.W;
float bw = Vector4.Zero.W - xw;
float sw = Vector4.Zero.W - xw;
// calculate final alpha
float a = xw + bw + sw;
// calculate final value
xform = ((xform * xw) + (Vector4.Zero * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon);
return Vector4.Lerp(backdrop, xform, opacity);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 DestOut(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
Vector4 xform = Vector4.Zero;
// calculate weights
float xw = backdrop.W * Vector4.Zero.W;
float bw = backdrop.W - xw;
float sw = Vector4.Zero.W - xw;
// calculate final alpha
float a = xw + bw + sw;
// calculate final value
xform = ((xform * xw) + (backdrop * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon);
return Vector4.Lerp(backdrop, xform, opacity);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Clear(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
Vector4 xform = Vector4.Zero;
// calculate weights
float xw = Vector4.Zero.W * Vector4.Zero.W;
float bw = Vector4.Zero.W - xw;
float sw = Vector4.Zero.W - xw;
// calculate final alpha
float a = xw + bw + sw;
// calculate final value
xform = ((xform * xw) + (Vector4.Zero * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon);
return Vector4.Lerp(backdrop, xform, opacity);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Xor(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
source.W *= opacity;
Vector4 xform = Vector4.Zero;
// calculate weights
float xw = backdrop.W * source.W;
float bw = backdrop.W - xw;
float sw = source.W - xw;
// calculate final alpha
float a = xw + bw + sw;
// calculate final value
xform = ((xform * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon);
return Vector4.Lerp(backdrop, xform, opacity);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Normal<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Normal(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Multiply<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Multiply(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Add<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Add(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Substract<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Substract(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Screen<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Screen(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Darken<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Darken(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Lighten<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Lighten(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Overlay<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Overlay(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel HardLight<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(HardLight(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Src<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Src(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Atop<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Atop(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Over<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Over(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel In<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(In(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Out<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Out(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Dest<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Dest(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel DestAtop<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(DestAtop(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel DestOver<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(DestOver(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel DestIn<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(DestIn(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel DestOut<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(DestOut(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Clear<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Clear(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Xor<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Xor(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
}
}

112
src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt

@ -0,0 +1,112 @@
<#
// <copyright file="PorterDuffFunctions.Generated.tt" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
#>
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
// <autogenerated />
// <copyright file="PorterDuffFunctions.Generated.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System.Numerics;
using System.Runtime.CompilerServices;
internal static partial class PorterDuffFunctions
{
<#
void GeneratePixelBlender (string blender)
{
#>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel <#=blender#><TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(<#=blender#>(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
<#
}
void GenerateVectorCompositor(string name, string sourceVar, string destVar, string blendVar)
{
#>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 <#=name#>(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
<# if(sourceVar != "Vector4.Zero" ) { #>
source.W *= opacity;
<# } #>
Vector4 xform = <#=blendVar#>;
// calculate weights
float xw = <#=destVar#>.W * <#=sourceVar#>.W;
float bw = <#=destVar#>.W - xw;
float sw = <#=sourceVar#>.W - xw;
// calculate final alpha
float a = xw + bw + sw;
// calculate final value
xform = ((xform * xw) + (<#=destVar#> * bw) + (<#=sourceVar#> * sw)) / MathF.Max(a, Constants.Epsilon);
return Vector4.Lerp(backdrop, xform, opacity);
}
<#
}
GenerateVectorCompositor("Src", "source", "Vector4.Zero", "source");
GenerateVectorCompositor("Atop", "Vector4.Zero", "backdrop", "source");
GenerateVectorCompositor("Over", "source", "backdrop", "source");
GenerateVectorCompositor("In", "Vector4.Zero", "Vector4.Zero", "source");
GenerateVectorCompositor("Out", "source", "Vector4.Zero", "Vector4.Zero");
GenerateVectorCompositor("Dest", "Vector4.Zero", "backdrop", "backdrop");
GenerateVectorCompositor("DestAtop", "source", "Vector4.Zero", "backdrop");
GenerateVectorCompositor("DestOver", "source", "backdrop", "backdrop");
GenerateVectorCompositor("DestIn", "Vector4.Zero", "Vector4.Zero", "backdrop");
GenerateVectorCompositor("DestOut", "Vector4.Zero", "backdrop", "Vector4.Zero");
GenerateVectorCompositor("Clear", "Vector4.Zero", "Vector4.Zero", "Vector4.Zero");
GenerateVectorCompositor("Xor", "source", "backdrop", "Vector4.Zero");
GeneratePixelBlender("Normal");
GeneratePixelBlender("Multiply");
GeneratePixelBlender("Add");
GeneratePixelBlender("Substract");
GeneratePixelBlender("Screen");
GeneratePixelBlender("Darken");
GeneratePixelBlender("Lighten");
GeneratePixelBlender("Overlay");
GeneratePixelBlender("HardLight");
GeneratePixelBlender("Src");
GeneratePixelBlender("Atop");
GeneratePixelBlender("Over");
GeneratePixelBlender("In");
GeneratePixelBlender("Out");
GeneratePixelBlender("Dest");
GeneratePixelBlender("DestAtop");
GeneratePixelBlender("DestOver");
GeneratePixelBlender("DestIn");
GeneratePixelBlender("DestOut");
GeneratePixelBlender("Clear");
GeneratePixelBlender("Xor");
#>
}
}

67
src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs

@ -29,14 +29,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
/// <param name="opacity">Opacity applied to Source Alpha</param> /// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns> /// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 NormalBlendFunction(Vector4 backdrop, Vector4 source, float opacity) public static Vector4 Normal(Vector4 backdrop, Vector4 source, float opacity)
{ {
source.W *= opacity; source.W *= opacity;
if (source.W == 0)
{
return backdrop;
}
return Compose(backdrop, source, source); return Compose(backdrop, source, source);
} }
@ -48,14 +43,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
/// <param name="opacity">Opacity applied to Source Alpha</param> /// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns> /// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 MultiplyFunction(Vector4 backdrop, Vector4 source, float opacity) public static Vector4 Multiply(Vector4 backdrop, Vector4 source, float opacity)
{ {
source.W *= opacity; source.W *= opacity;
if (source.W == 0)
{
return backdrop;
}
return Compose(backdrop, source, backdrop * source); return Compose(backdrop, source, backdrop * source);
} }
@ -67,14 +57,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
/// <param name="opacity">Opacity applied to Source Alpha</param> /// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns> /// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 AddFunction(Vector4 backdrop, Vector4 source, float opacity) public static Vector4 Add(Vector4 backdrop, Vector4 source, float opacity)
{ {
source.W *= opacity; source.W *= opacity;
if (source.W == 0)
{
return backdrop;
}
return Compose(backdrop, source, Vector4.Min(Vector4.One, backdrop + source)); return Compose(backdrop, source, Vector4.Min(Vector4.One, backdrop + source));
} }
@ -86,14 +71,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
/// <param name="opacity">Opacity applied to Source Alpha</param> /// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns> /// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 SubstractFunction(Vector4 backdrop, Vector4 source, float opacity) public static Vector4 Substract(Vector4 backdrop, Vector4 source, float opacity)
{ {
source.W *= opacity; source.W *= opacity;
if (source.W == 0)
{
return backdrop;
}
return Compose(backdrop, source, Vector4.Max(Vector4.Zero, backdrop - source)); return Compose(backdrop, source, Vector4.Max(Vector4.Zero, backdrop - source));
} }
@ -105,14 +85,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
/// <param name="opacity">Opacity applied to Source Alpha</param> /// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns> /// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 ScreenFunction(Vector4 backdrop, Vector4 source, float opacity) public static Vector4 Screen(Vector4 backdrop, Vector4 source, float opacity)
{ {
source.W *= opacity; source.W *= opacity;
if (source.W == 0)
{
return backdrop;
}
return Compose(backdrop, source, Vector4.One - ((Vector4.One - backdrop) * (Vector4.One - source))); return Compose(backdrop, source, Vector4.One - ((Vector4.One - backdrop) * (Vector4.One - source)));
} }
@ -124,14 +99,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
/// <param name="opacity">Opacity applied to Source Alpha</param> /// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns> /// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 DarkenFunction(Vector4 backdrop, Vector4 source, float opacity) public static Vector4 Darken(Vector4 backdrop, Vector4 source, float opacity)
{ {
source.W *= opacity; source.W *= opacity;
if (source.W == 0)
{
return backdrop;
}
return Compose(backdrop, source, Vector4.Min(backdrop, source)); return Compose(backdrop, source, Vector4.Min(backdrop, source));
} }
@ -143,14 +113,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
/// <param name="opacity">Opacity applied to Source Alpha</param> /// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns> /// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 LightenFunction(Vector4 backdrop, Vector4 source, float opacity) public static Vector4 Lighten(Vector4 backdrop, Vector4 source, float opacity)
{ {
source.W *= opacity; source.W *= opacity;
if (source.W == 0)
{
return backdrop;
}
return Compose(backdrop, source, Vector4.Max(backdrop, source)); return Compose(backdrop, source, Vector4.Max(backdrop, source));
} }
@ -162,14 +127,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
/// <param name="opacity">Opacity applied to Source Alpha</param> /// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns> /// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 OverlayFunction(Vector4 backdrop, Vector4 source, float opacity) public static Vector4 Overlay(Vector4 backdrop, Vector4 source, float opacity)
{ {
source.W *= opacity; source.W *= opacity;
if (source.W == 0)
{
return backdrop;
}
float cr = OverlayValueFunction(backdrop.X, source.X); float cr = OverlayValueFunction(backdrop.X, source.X);
float cg = OverlayValueFunction(backdrop.Y, source.Y); float cg = OverlayValueFunction(backdrop.Y, source.Y);
float cb = OverlayValueFunction(backdrop.Z, source.Z); float cb = OverlayValueFunction(backdrop.Z, source.Z);
@ -185,14 +145,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
/// <param name="opacity">Opacity applied to Source Alpha</param> /// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns> /// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 HardLightFunction(Vector4 backdrop, Vector4 source, float opacity) public static Vector4 HardLight(Vector4 backdrop, Vector4 source, float opacity)
{ {
source.W *= opacity; source.W *= opacity;
if (source.W == 0)
{
return backdrop;
}
float cr = OverlayValueFunction(source.X, backdrop.X); float cr = OverlayValueFunction(source.X, backdrop.X);
float cg = OverlayValueFunction(source.Y, backdrop.Y); float cg = OverlayValueFunction(source.Y, backdrop.Y);
float cb = OverlayValueFunction(source.Z, backdrop.Z); float cb = OverlayValueFunction(source.Z, backdrop.Z);
@ -222,8 +177,6 @@ namespace ImageSharp.PixelFormats.PixelBlenders
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector4 Compose(Vector4 backdrop, Vector4 source, Vector4 xform) private static Vector4 Compose(Vector4 backdrop, Vector4 source, Vector4 xform)
{ {
DebugGuard.MustBeGreaterThan(source.W, 0, nameof(source.W));
// calculate weights // calculate weights
float xw = backdrop.W * source.W; float xw = backdrop.W * source.W;
float bw = backdrop.W - xw; float bw = backdrop.W - xw;
@ -233,7 +186,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
float a = xw + bw + sw; float a = xw + bw + sw;
// calculate final value // calculate final value
xform = ((xform * xw) + (backdrop * bw) + (source * sw)) / a; xform = ((xform * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon);
xform.W = a; xform.W = a;
return xform; return xform;

151
src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions{TPixel}.cs

@ -1,151 +0,0 @@
// <copyright file="PorterDuffFunctions.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System.Numerics;
using System.Runtime.CompilerServices;
/// <summary>
/// Collection of Porter Duff alpha blending functions
/// </summary>
/// <typeparam name="TPixel">Pixel Format</typeparam>
/// <remarks>
/// These functions are designed to be a general solution for all color cases,
/// that is, they take in account the alpha value of both the backdrop
/// and source, and there's no need to alpha-premultiply neither the backdrop
/// nor the source.
/// Note there are faster functions for when the backdrop color is known
/// to be opaque
/// </remarks>
internal static class PorterDuffFunctions<TPixel>
where TPixel : IPixel
{
/// <summary>
/// Source over backdrop
/// </summary>
/// <param name="backdrop">Backgrop color</param>
/// <param name="source">Source color</param>
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel NormalBlendFunction(TPixel backdrop, TPixel source, float opacity)
{
return ToPixel(PorterDuffFunctions.NormalBlendFunction(backdrop.ToVector4(), source.ToVector4(), opacity));
}
/// <summary>
/// Source multiplied by backdrop
/// </summary>
/// <param name="backdrop">Backgrop color</param>
/// <param name="source">Source color</param>
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel MultiplyFunction(TPixel backdrop, TPixel source, float opacity)
{
return ToPixel(PorterDuffFunctions.MultiplyFunction(backdrop.ToVector4(), source.ToVector4(), opacity));
}
/// <summary>
/// Source added to backdrop
/// </summary>
/// <param name="backdrop">Backgrop color</param>
/// <param name="source">Source color</param>
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel AddFunction(TPixel backdrop, TPixel source, float opacity)
{
return ToPixel(PorterDuffFunctions.AddFunction(backdrop.ToVector4(), source.ToVector4(), opacity));
}
/// <summary>
/// Source substracted from backdrop
/// </summary>
/// <param name="backdrop">Backgrop color</param>
/// <param name="source">Source color</param>
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel SubstractFunction(TPixel backdrop, TPixel source, float opacity)
{
return ToPixel(PorterDuffFunctions.SubstractFunction(backdrop.ToVector4(), source.ToVector4(), opacity));
}
/// <summary>
/// Complement of source multiplied by the complement of backdrop
/// </summary>
/// <param name="backdrop">Backgrop color</param>
/// <param name="source">Source color</param>
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ScreenFunction(TPixel backdrop, TPixel source, float opacity)
{
return ToPixel(PorterDuffFunctions.ScreenFunction(backdrop.ToVector4(), source.ToVector4(), opacity));
}
/// <summary>
/// Per element, chooses the smallest value of source and backdrop
/// </summary>
/// <param name="backdrop">Backgrop color</param>
/// <param name="source">Source color</param>
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel DarkenFunction(TPixel backdrop, TPixel source, float opacity)
{
return ToPixel(PorterDuffFunctions.DarkenFunction(backdrop.ToVector4(), source.ToVector4(), opacity));
}
/// <summary>
/// Per element, chooses the largest value of source and backdrop
/// </summary>
/// <param name="backdrop">Backgrop color</param>
/// <param name="source">Source color</param>
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel LightenFunction(TPixel backdrop, TPixel source, float opacity)
{
return ToPixel(PorterDuffFunctions.LightenFunction(backdrop.ToVector4(), source.ToVector4(), opacity));
}
/// <summary>
/// Overlays source over backdrop
/// </summary>
/// <param name="backdrop">Backgrop color</param>
/// <param name="source">Source color</param>
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel OverlayFunction(TPixel backdrop, TPixel source, float opacity)
{
return ToPixel(PorterDuffFunctions.OverlayFunction(backdrop.ToVector4(), source.ToVector4(), opacity));
}
/// <summary>
/// Hard light effect
/// </summary>
/// <param name="backdrop">Backgrop color</param>
/// <param name="source">Source color</param>
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel HardLightFunction(TPixel backdrop, TPixel source, float opacity)
{
return ToPixel(PorterDuffFunctions.HardLightFunction(backdrop.ToVector4(), source.ToVector4(), opacity));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static TPixel ToPixel(Vector4 vector)
{
TPixel p = default(TPixel);
p.PackFromVector4(vector);
return p;
}
}
}

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

@ -22,25 +22,30 @@ namespace ImageSharp.PixelFormats
{ {
switch (mode) switch (mode)
{ {
case PixelBlenderMode.Multiply: case PixelBlenderMode.Multiply: return DefaultPixelBlenders<TPixel>.Multiply.Instance;
return DefaultMultiplyPixelBlender<TPixel>.Instance; case PixelBlenderMode.Add: return DefaultPixelBlenders<TPixel>.Add.Instance;
case PixelBlenderMode.Add: case PixelBlenderMode.Substract: return DefaultPixelBlenders<TPixel>.Substract.Instance;
return DefaultAddPixelBlender<TPixel>.Instance; case PixelBlenderMode.Screen: return DefaultPixelBlenders<TPixel>.Screen.Instance;
case PixelBlenderMode.Substract: case PixelBlenderMode.Darken: return DefaultPixelBlenders<TPixel>.Darken.Instance;
return DefaultSubstractPixelBlender<TPixel>.Instance; case PixelBlenderMode.Lighten: return DefaultPixelBlenders<TPixel>.Lighten.Instance;
case PixelBlenderMode.Screen: case PixelBlenderMode.Overlay: return DefaultPixelBlenders<TPixel>.Overlay.Instance;
return DefaultScreenPixelBlender<TPixel>.Instance; case PixelBlenderMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLight.Instance;
case PixelBlenderMode.Darken: case PixelBlenderMode.Src: return DefaultPixelBlenders<TPixel>.Src.Instance;
return DefaultDarkenPixelBlender<TPixel>.Instance; case PixelBlenderMode.Atop: return DefaultPixelBlenders<TPixel>.Atop.Instance;
case PixelBlenderMode.Lighten: case PixelBlenderMode.Over: return DefaultPixelBlenders<TPixel>.Over.Instance;
return DefaultLightenPixelBlender<TPixel>.Instance; case PixelBlenderMode.In: return DefaultPixelBlenders<TPixel>.In.Instance;
case PixelBlenderMode.Overlay: case PixelBlenderMode.Out: return DefaultPixelBlenders<TPixel>.Out.Instance;
return DefaultOverlayPixelBlender<TPixel>.Instance; case PixelBlenderMode.Dest: return DefaultPixelBlenders<TPixel>.Dest.Instance;
case PixelBlenderMode.HardLight: case PixelBlenderMode.DestAtop: return DefaultPixelBlenders<TPixel>.DestAtop.Instance;
return DefaultHardLightPixelBlender<TPixel>.Instance; case PixelBlenderMode.DestOver: return DefaultPixelBlenders<TPixel>.DestOver.Instance;
case PixelBlenderMode.DestIn: return DefaultPixelBlenders<TPixel>.DestIn.Instance;
case PixelBlenderMode.DestOut: return DefaultPixelBlenders<TPixel>.DestOut.Instance;
case PixelBlenderMode.Clear: return DefaultPixelBlenders<TPixel>.Clear.Instance;
case PixelBlenderMode.Xor: return DefaultPixelBlenders<TPixel>.Xor.Instance;
case PixelBlenderMode.Normal: case PixelBlenderMode.Normal:
default: default:
return DefaultNormalPixelBlender<TPixel>.Instance; return DefaultPixelBlenders<TPixel>.Normal.Instance;
} }
} }
} }

4
tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs

@ -35,7 +35,7 @@ namespace ImageSharp.Benchmarks
for (int i = 0; i < destination.Length; i++) for (int i = 0; i < destination.Length; i++)
{ {
destinationSpan[i] = PorterDuffFunctions.NormalBlendFunction(backgroundSpan[i], sourceSpan[i], amount[i]); destinationSpan[i] = PorterDuffFunctions.Normal(backgroundSpan[i], sourceSpan[i], amount[i]);
} }
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
@ -50,7 +50,7 @@ namespace ImageSharp.Benchmarks
for (int i = 0; i < destination.Length; i++) for (int i = 0; i < destination.Length; i++)
{ {
destination[i] = PorterDuffFunctions<TPixel>.NormalBlendFunction(destination[i], source[i], amount[i]); destination[i] = PorterDuffFunctions.Normal(destination[i], source[i], amount[i]);
} }
} }

70
tests/ImageSharp.Tests/Drawing/BlendedShapes.cs

@ -18,14 +18,16 @@ namespace ImageSharp.Tests.Drawing
.Select(x=> new object[] { x }); .Select(x=> new object[] { x });
[Theory] [Theory]
[WithBlankImages(nameof(modes), 100, 100, PixelTypes.Rgba32)] [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)]
public void DrawBlendedValues<TPixel>(TestImageProvider<TPixel> provider, PixelBlenderMode mode) public void DrawBlendedValues<TPixel>(TestImageProvider<TPixel> provider, PixelBlenderMode mode)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
using (var img = provider.GetImage()) using (var img = provider.GetImage())
{ {
img.Fill(NamedColors<TPixel>.DarkBlue, new Rectangle(0, 40, 100, 20)); var scaleX = (img.Width / 100);
img.Fill(NamedColors<TPixel>.HotPink, new Rectangle(40, 0, 20, 100), new ImageSharp.GraphicsOptions(true) var scaleY = (img.Height / 100);
img.Fill(NamedColors<TPixel>.DarkBlue, new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY));
img.Fill(NamedColors<TPixel>.HotPink, new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY), new ImageSharp.GraphicsOptions(true)
{ {
BlenderMode = mode BlenderMode = mode
}); });
@ -34,18 +36,72 @@ namespace ImageSharp.Tests.Drawing
} }
[Theory] [Theory]
[WithBlankImages(nameof(modes), 100, 100, PixelTypes.Rgba32)] [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)]
public void DrawBlendedValues_transparent<TPixel>(TestImageProvider<TPixel> provider, PixelBlenderMode mode) public void DrawBlendedValues_transparent<TPixel>(TestImageProvider<TPixel> provider, PixelBlenderMode mode)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
using (var img = provider.GetImage()) using (var img = provider.GetImage())
{ {
img.Fill(NamedColors<TPixel>.DarkBlue, new Rectangle(0, 40, 100, 20)); var scaleX = (img.Width / 100);
img.Fill(NamedColors<TPixel>.HotPink, new Rectangle(20, 0, 40, 100), new ImageSharp.GraphicsOptions(true) var scaleY = (img.Height / 100);
img.Fill(NamedColors<TPixel>.DarkBlue, new Rectangle(0* scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY));
img.Fill(NamedColors<TPixel>.HotPink, new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY), new ImageSharp.GraphicsOptions(true)
{ {
BlenderMode = mode BlenderMode = mode
}); });
img.Fill(NamedColors<TPixel>.Transparent, new Rectangle(40, 0, 20, 100), new ImageSharp.GraphicsOptions(true) img.Fill(NamedColors<TPixel>.Transparent, new SixLabors.Shapes.Ellipse(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY), new ImageSharp.GraphicsOptions(true)
{
BlenderMode = mode
});
img.DebugSave(provider, new { mode });
}
}
[Theory]
[WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)]
public void DrawBlendedValues_transparent50Percent<TPixel>(TestImageProvider<TPixel> provider, PixelBlenderMode mode)
where TPixel : struct, IPixel<TPixel>
{
using (var img = provider.GetImage())
{
var scaleX = (img.Width / 100);
var scaleY = (img.Height / 100);
img.Fill(NamedColors<TPixel>.DarkBlue, new Rectangle(0 * scaleX, 40, 100 * scaleX, 20* scaleY));
img.Fill(NamedColors<TPixel>.HotPink, new Rectangle(20 * scaleX, 0, 30 * scaleX, 100 * scaleY), new ImageSharp.GraphicsOptions(true)
{
BlenderMode = mode
});
var c = NamedColors<TPixel>.Red.ToVector4();
c.W *= 0.5f;
TPixel pixel = default(TPixel);
pixel.PackFromVector4(c);
img.Fill(pixel, new SixLabors.Shapes.Ellipse(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY), new ImageSharp.GraphicsOptions(true)
{
BlenderMode = mode
});
img.DebugSave(provider, new { mode });
}
}
[Theory]
[WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)]
public void DrawBlendedValues_doldidEllips<TPixel>(TestImageProvider<TPixel> provider, PixelBlenderMode mode)
where TPixel : struct, IPixel<TPixel>
{
using (var img = provider.GetImage())
{
var scaleX = (img.Width / 100);
var scaleY = (img.Height / 100);
img.Fill(NamedColors<TPixel>.DarkBlue, new Rectangle(0 * scaleX, 40* scaleY, 100 * scaleX, 20 * scaleY));
//img.Fill(NamedColors<TPixel>.HotPink, new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY), new ImageSharp.GraphicsOptions(true)
//{
// BlenderMode = mode
//});
img.Fill(NamedColors<TPixel>.Black, new SixLabors.Shapes.Ellipse(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY), new ImageSharp.GraphicsOptions(true)
{ {
BlenderMode = mode BlenderMode = mode
}); });

14
tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccReaderTests.cs

@ -10,7 +10,7 @@ namespace ImageSharp.Tests.Icc
public class IccReaderTests public class IccReaderTests
{ {
[Fact] [Fact]
public void ReadProfile() public void ReadProfile_NoEntries()
{ {
IccReader reader = CreateReader(); IccReader reader = CreateReader();
@ -40,6 +40,18 @@ namespace ImageSharp.Tests.Icc
Assert.Equal(header.Version, expected.Version); Assert.Equal(header.Version, expected.Version);
} }
[Fact]
public void ReadProfile_DuplicateEntry()
{
IccReader reader = CreateReader();
IccProfile output = reader.Read(IccTestDataProfiles.Profile_Random_Array);
Assert.Equal(2, output.Entries.Count);
Assert.True(ReferenceEquals(output.Entries[0], output.Entries[1]));
}
private IccReader CreateReader() private IccReader CreateReader()
{ {
return new IccReader(); return new IccReader();

12
tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccWriterTests.cs

@ -10,7 +10,7 @@ namespace ImageSharp.Tests.Icc
public class IccWriterTests public class IccWriterTests
{ {
[Fact] [Fact]
public void WriteProfile() public void WriteProfile_NoEntries()
{ {
IccWriter writer = CreateWriter(); IccWriter writer = CreateWriter();
@ -23,6 +23,16 @@ namespace ImageSharp.Tests.Icc
Assert.Equal(IccTestDataProfiles.Header_Random_Array, output); Assert.Equal(IccTestDataProfiles.Header_Random_Array, output);
} }
[Fact]
public void WriteProfile_DuplicateEntry()
{
IccWriter writer = CreateWriter();
byte[] output = writer.Write(IccTestDataProfiles.Profile_Random_Val);
Assert.Equal(IccTestDataProfiles.Profile_Random_Array, output);
}
private IccWriter CreateWriter() private IccWriter CreateWriter()
{ {
return new IccWriter(); return new IccWriter();

18
tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs

@ -24,7 +24,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
[MemberData(nameof(NormalBlendFunctionData))] [MemberData(nameof(NormalBlendFunctionData))]
public void NormalBlendFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) public void NormalBlendFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
{ {
Vector4 actual = PorterDuffFunctions.NormalBlendFunction(back, source, amount); Vector4 actual = PorterDuffFunctions.Normal((Vector4)back, source, amount);
Assert.Equal(expected, actual); Assert.Equal(expected, actual);
} }
@ -43,7 +43,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
[MemberData(nameof(MultiplyFunctionData))] [MemberData(nameof(MultiplyFunctionData))]
public void MultiplyFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) public void MultiplyFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
{ {
Vector4 actual = PorterDuffFunctions.MultiplyFunction(back, source, amount); Vector4 actual = PorterDuffFunctions.Multiply((Vector4)back, source, amount);
VectorAssert.Equal(expected, actual, 5); VectorAssert.Equal(expected, actual, 5);
} }
@ -62,7 +62,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
[MemberData(nameof(AddFunctionData))] [MemberData(nameof(AddFunctionData))]
public void AddFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) public void AddFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
{ {
Vector4 actual = PorterDuffFunctions.MultiplyFunction(back, source, amount); Vector4 actual = PorterDuffFunctions.Multiply((Vector4)back, source, amount);
VectorAssert.Equal(expected, actual, 5); VectorAssert.Equal(expected, actual, 5);
} }
@ -81,7 +81,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
[MemberData(nameof(SubstractFunctionData))] [MemberData(nameof(SubstractFunctionData))]
public void SubstractFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) public void SubstractFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
{ {
Vector4 actual = PorterDuffFunctions.SubstractFunction(back, source, amount); Vector4 actual = PorterDuffFunctions.Substract((Vector4)back, source, amount);
VectorAssert.Equal(expected, actual, 5); VectorAssert.Equal(expected, actual, 5);
} }
@ -100,7 +100,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
[MemberData(nameof(ScreenFunctionData))] [MemberData(nameof(ScreenFunctionData))]
public void ScreenFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) public void ScreenFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
{ {
Vector4 actual = PorterDuffFunctions.ScreenFunction(back, source, amount); Vector4 actual = PorterDuffFunctions.Screen((Vector4)back, source, amount);
VectorAssert.Equal(expected, actual, 5); VectorAssert.Equal(expected, actual, 5);
} }
@ -119,7 +119,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
[MemberData(nameof(DarkenFunctionData))] [MemberData(nameof(DarkenFunctionData))]
public void DarkenFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) public void DarkenFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
{ {
Vector4 actual = PorterDuffFunctions.DarkenFunction(back, source, amount); Vector4 actual = PorterDuffFunctions.Darken((Vector4)back, source, amount);
VectorAssert.Equal(expected, actual, 5); VectorAssert.Equal(expected, actual, 5);
} }
@ -138,7 +138,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
[MemberData(nameof(LightenFunctionData))] [MemberData(nameof(LightenFunctionData))]
public void LightenFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) public void LightenFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
{ {
Vector4 actual = PorterDuffFunctions.LightenFunction(back, source, amount); Vector4 actual = PorterDuffFunctions.Lighten((Vector4)back, source, amount);
VectorAssert.Equal(expected, actual, 5); VectorAssert.Equal(expected, actual, 5);
} }
@ -157,7 +157,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
[MemberData(nameof(OverlayFunctionData))] [MemberData(nameof(OverlayFunctionData))]
public void OverlayFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) public void OverlayFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
{ {
Vector4 actual = PorterDuffFunctions.OverlayFunction(back, source, amount); Vector4 actual = PorterDuffFunctions.Overlay((Vector4)back, source, amount);
VectorAssert.Equal(expected, actual, 5); VectorAssert.Equal(expected, actual, 5);
} }
@ -176,7 +176,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
[MemberData(nameof(HardLightFunctionData))] [MemberData(nameof(HardLightFunctionData))]
public void HardLightFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) public void HardLightFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
{ {
Vector4 actual = PorterDuffFunctions.HardLightFunction(back, source, amount); Vector4 actual = PorterDuffFunctions.HardLight((Vector4)back, source, amount);
VectorAssert.Equal(expected, actual, 5); VectorAssert.Equal(expected, actual, 5);
} }
} }

54
tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs

@ -32,7 +32,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void NormalBlendFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected) public void NormalBlendFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel actual = PorterDuffFunctions<TPixel>.NormalBlendFunction(back, source, amount); TPixel actual = PorterDuffFunctions.Normal((TPixel)(TPixel)back, source, amount);
VectorAssert.Equal(expected, actual, 2); VectorAssert.Equal(expected, actual, 2);
} }
@ -41,7 +41,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void NormalBlendFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected) public void NormalBlendFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel actual = new DefaultNormalPixelBlender<TPixel>().Blend(back, source, amount); TPixel actual = new DefaultPixelBlenders<TPixel>.Normal().Blend(back, source, amount);
VectorAssert.Equal(expected, actual, 2); VectorAssert.Equal(expected, actual, 2);
} }
@ -51,7 +51,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
Span<TPixel> dest = new Span<TPixel>(new TPixel[1]); Span<TPixel> dest = new Span<TPixel>(new TPixel[1]);
new DefaultNormalPixelBlender<TPixel>().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); new DefaultPixelBlenders<TPixel>.Normal().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2); VectorAssert.Equal(expected, dest[0], 2);
} }
@ -71,7 +71,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void MultiplyFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected) public void MultiplyFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel actual = PorterDuffFunctions<TPixel>.MultiplyFunction(back, source, amount); TPixel actual = PorterDuffFunctions.Multiply((TPixel)back, source, amount);
VectorAssert.Equal(expected, actual, 2); VectorAssert.Equal(expected, actual, 2);
} }
@ -80,7 +80,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void MultiplyFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected) public void MultiplyFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel actual = new DefaultMultiplyPixelBlender<TPixel>().Blend(back, source, amount); TPixel actual = new DefaultPixelBlenders<TPixel>.Multiply().Blend(back, source, amount);
VectorAssert.Equal(expected, actual, 2); VectorAssert.Equal(expected, actual, 2);
} }
@ -90,7 +90,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
Span<TPixel> dest = new Span<TPixel>(new TPixel[1]); Span<TPixel> dest = new Span<TPixel>(new TPixel[1]);
new DefaultMultiplyPixelBlender<TPixel>().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); new DefaultPixelBlenders<TPixel>.Multiply().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2); VectorAssert.Equal(expected, dest[0], 2);
} }
@ -110,7 +110,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void AddFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected) public void AddFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel actual = PorterDuffFunctions<TPixel>.AddFunction(back, source, amount); TPixel actual = PorterDuffFunctions.Add((TPixel)back, source, amount);
VectorAssert.Equal(expected, actual, 2); VectorAssert.Equal(expected, actual, 2);
} }
@ -119,7 +119,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void AddFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected) public void AddFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel actual = new DefaultAddPixelBlender<TPixel>().Blend(back, source, amount); TPixel actual = new DefaultPixelBlenders<TPixel>.Add().Blend(back, source, amount);
VectorAssert.Equal(expected, actual, 2); VectorAssert.Equal(expected, actual, 2);
} }
@ -129,7 +129,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
Span<TPixel> dest = new Span<TPixel>(new TPixel[1]); Span<TPixel> dest = new Span<TPixel>(new TPixel[1]);
new DefaultAddPixelBlender<TPixel>().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); new DefaultPixelBlenders<TPixel>.Add().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2); VectorAssert.Equal(expected, dest[0], 2);
} }
@ -149,7 +149,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void SubstractFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected) public void SubstractFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel actual = PorterDuffFunctions<TPixel>.SubstractFunction(back, source, amount); TPixel actual = PorterDuffFunctions.Substract((TPixel)back, source, amount);
VectorAssert.Equal(expected, actual, 2); VectorAssert.Equal(expected, actual, 2);
} }
@ -158,7 +158,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void SubstractFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected) public void SubstractFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel actual = new DefaultSubstractPixelBlender<TPixel>().Blend(back, source, amount); TPixel actual = new DefaultPixelBlenders<TPixel>.Substract().Blend(back, source, amount);
VectorAssert.Equal(expected, actual, 2); VectorAssert.Equal(expected, actual, 2);
} }
@ -168,7 +168,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
Span<TPixel> dest = new Span<TPixel>(new TPixel[1]); Span<TPixel> dest = new Span<TPixel>(new TPixel[1]);
new DefaultSubstractPixelBlender<TPixel>().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); new DefaultPixelBlenders<TPixel>.Substract().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2); VectorAssert.Equal(expected, dest[0], 2);
} }
@ -188,7 +188,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void ScreenFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected) public void ScreenFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel actual = PorterDuffFunctions<TPixel>.ScreenFunction(back, source, amount); TPixel actual = PorterDuffFunctions.Screen((TPixel)back, source, amount);
VectorAssert.Equal(expected, actual, 2); VectorAssert.Equal(expected, actual, 2);
} }
@ -197,7 +197,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void ScreenFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected) public void ScreenFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel actual = new DefaultScreenPixelBlender<TPixel>().Blend(back, source, amount); TPixel actual = new DefaultPixelBlenders<TPixel>.Screen().Blend(back, source, amount);
VectorAssert.Equal(expected, actual, 2); VectorAssert.Equal(expected, actual, 2);
} }
@ -207,7 +207,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
Span<TPixel> dest = new Span<TPixel>(new TPixel[1]); Span<TPixel> dest = new Span<TPixel>(new TPixel[1]);
new DefaultScreenPixelBlender<TPixel>().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); new DefaultPixelBlenders<TPixel>.Screen().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2); VectorAssert.Equal(expected, dest[0], 2);
} }
@ -227,7 +227,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void DarkenFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected) public void DarkenFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel actual = PorterDuffFunctions<TPixel>.DarkenFunction(back, source, amount); TPixel actual = PorterDuffFunctions.Darken((TPixel)back, source, amount);
VectorAssert.Equal(expected, actual, 2); VectorAssert.Equal(expected, actual, 2);
} }
@ -236,7 +236,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void DarkenFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected) public void DarkenFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel actual = new DefaultDarkenPixelBlender<TPixel>().Blend(back, source, amount); TPixel actual = new DefaultPixelBlenders<TPixel>.Darken().Blend(back, source, amount);
VectorAssert.Equal(expected, actual, 2); VectorAssert.Equal(expected, actual, 2);
} }
@ -246,7 +246,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
Span<TPixel> dest = new Span<TPixel>(new TPixel[1]); Span<TPixel> dest = new Span<TPixel>(new TPixel[1]);
new DefaultDarkenPixelBlender<TPixel>().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); new DefaultPixelBlenders<TPixel>.Darken().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2); VectorAssert.Equal(expected, dest[0], 2);
} }
@ -266,7 +266,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void LightenFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected) public void LightenFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel actual = PorterDuffFunctions<TPixel>.LightenFunction(back, source, amount); TPixel actual = PorterDuffFunctions.Lighten((TPixel)back, source, amount);
VectorAssert.Equal(expected, actual, 2); VectorAssert.Equal(expected, actual, 2);
} }
@ -275,7 +275,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void LightenFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected) public void LightenFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel actual = new DefaultLightenPixelBlender<TPixel>().Blend(back, source, amount); TPixel actual = new DefaultPixelBlenders<TPixel>.Lighten().Blend(back, source, amount);
VectorAssert.Equal(expected, actual, 2); VectorAssert.Equal(expected, actual, 2);
} }
@ -285,7 +285,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
Span<TPixel> dest = new Span<TPixel>(new TPixel[1]); Span<TPixel> dest = new Span<TPixel>(new TPixel[1]);
new DefaultLightenPixelBlender<TPixel>().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); new DefaultPixelBlenders<TPixel>.Lighten().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2); VectorAssert.Equal(expected, dest[0], 2);
} }
@ -305,7 +305,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void OverlayFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected) public void OverlayFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel actual = PorterDuffFunctions<TPixel>.OverlayFunction(back, source, amount); TPixel actual = PorterDuffFunctions.Overlay((TPixel)back, source, amount);
VectorAssert.Equal(expected, actual, 2); VectorAssert.Equal(expected, actual, 2);
} }
@ -314,7 +314,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void OverlayFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected) public void OverlayFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel actual = new DefaultOverlayPixelBlender<TPixel>().Blend(back, source, amount); TPixel actual = new DefaultPixelBlenders<TPixel>.Overlay().Blend(back, source, amount);
VectorAssert.Equal(expected, actual, 2); VectorAssert.Equal(expected, actual, 2);
} }
@ -324,7 +324,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
Span<TPixel> dest = new Span<TPixel>(new TPixel[1]); Span<TPixel> dest = new Span<TPixel>(new TPixel[1]);
new DefaultOverlayPixelBlender<TPixel>().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); new DefaultPixelBlenders<TPixel>.Overlay().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2); VectorAssert.Equal(expected, dest[0], 2);
} }
@ -344,7 +344,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void HardLightFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected) public void HardLightFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel actual = PorterDuffFunctions<TPixel>.HardLightFunction(back, source, amount); TPixel actual = PorterDuffFunctions.HardLight((TPixel)back, source, amount);
VectorAssert.Equal(expected, actual, 2); VectorAssert.Equal(expected, actual, 2);
} }
@ -353,7 +353,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void HardLightFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected) public void HardLightFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel actual = new DefaultHardLightPixelBlender<TPixel>().Blend(back, source, amount); TPixel actual = new DefaultPixelBlenders<TPixel>.HardLight().Blend(back, source, amount);
VectorAssert.Equal(expected, actual, 2); VectorAssert.Equal(expected, actual, 2);
} }
@ -363,7 +363,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
Span<TPixel> dest = new Span<TPixel>(new TPixel[1]); Span<TPixel> dest = new Span<TPixel>(new TPixel[1]);
new DefaultHardLightPixelBlender<TPixel>().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); new DefaultPixelBlenders<TPixel>.HardLight().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2); VectorAssert.Equal(expected, dest[0], 2);
} }
} }

66
tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs

@ -15,27 +15,55 @@ namespace ImageSharp.Tests.PixelFormats
public partial class PixelOperationsTests public partial class PixelOperationsTests
{ {
public static TheoryData<object, Type, PixelBlenderMode> BlenderMappings = new TheoryData<object, Type, PixelBlenderMode>() public static TheoryData<object, Type, PixelBlenderMode> BlenderMappings = new TheoryData<object, Type, PixelBlenderMode>()
{ {
{ new TestPixel<Rgba32>(), typeof(DefaultNormalPixelBlender<Rgba32>), PixelBlenderMode.Normal }, { new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Normal), PixelBlenderMode.Normal },
{ new TestPixel<Rgba32>(), typeof(DefaultScreenPixelBlender<Rgba32>), PixelBlenderMode.Screen }, { new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Screen), PixelBlenderMode.Screen },
{ new TestPixel<Rgba32>(), typeof(DefaultHardLightPixelBlender<Rgba32>), PixelBlenderMode.HardLight }, { new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.HardLight), PixelBlenderMode.HardLight },
{ new TestPixel<Rgba32>(), typeof(DefaultOverlayPixelBlender<Rgba32>), PixelBlenderMode.Overlay }, { new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Overlay), PixelBlenderMode.Overlay },
{ new TestPixel<Rgba32>(), typeof(DefaultDarkenPixelBlender<Rgba32>), PixelBlenderMode.Darken }, { new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Darken), PixelBlenderMode.Darken },
{ new TestPixel<Rgba32>(), typeof(DefaultLightenPixelBlender<Rgba32>), PixelBlenderMode.Lighten }, { new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Lighten), PixelBlenderMode.Lighten },
{ new TestPixel<Rgba32>(), typeof(DefaultAddPixelBlender<Rgba32>), PixelBlenderMode.Add }, { new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Add), PixelBlenderMode.Add },
{ new TestPixel<Rgba32>(), typeof(DefaultSubstractPixelBlender<Rgba32>), PixelBlenderMode.Substract }, { new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Substract), PixelBlenderMode.Substract },
{ new TestPixel<Rgba32>(), typeof(DefaultMultiplyPixelBlender<Rgba32>), PixelBlenderMode.Multiply }, { new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Multiply), PixelBlenderMode.Multiply },
{ new TestPixel<RgbaVector>(), typeof(DefaultNormalPixelBlender<RgbaVector>), PixelBlenderMode.Normal }, { new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Src), PixelBlenderMode.Src },
{ new TestPixel<RgbaVector>(), typeof(DefaultScreenPixelBlender<RgbaVector>), PixelBlenderMode.Screen }, { new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Atop), PixelBlenderMode.Atop },
{ new TestPixel<RgbaVector>(), typeof(DefaultHardLightPixelBlender<RgbaVector>), PixelBlenderMode.HardLight }, { new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Over), PixelBlenderMode.Over },
{ new TestPixel<RgbaVector>(), typeof(DefaultOverlayPixelBlender<RgbaVector>), PixelBlenderMode.Overlay }, { new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.In), PixelBlenderMode.In },
{ new TestPixel<RgbaVector>(), typeof(DefaultDarkenPixelBlender<RgbaVector>), PixelBlenderMode.Darken }, { new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Out), PixelBlenderMode.Out },
{ new TestPixel<RgbaVector>(), typeof(DefaultLightenPixelBlender<RgbaVector>), PixelBlenderMode.Lighten }, { new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Dest), PixelBlenderMode.Dest },
{ new TestPixel<RgbaVector>(), typeof(DefaultAddPixelBlender<RgbaVector>), PixelBlenderMode.Add }, { new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.DestAtop), PixelBlenderMode.DestAtop },
{ new TestPixel<RgbaVector>(), typeof(DefaultSubstractPixelBlender<RgbaVector>), PixelBlenderMode.Substract }, { new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.DestOver), PixelBlenderMode.DestOver },
{ new TestPixel<RgbaVector>(), typeof(DefaultMultiplyPixelBlender<RgbaVector>), PixelBlenderMode.Multiply }, { new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.DestIn), PixelBlenderMode.DestIn },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.DestOut), PixelBlenderMode.DestOut },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Clear), PixelBlenderMode.Clear },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Xor), PixelBlenderMode.Xor },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Normal), PixelBlenderMode.Normal },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Screen), PixelBlenderMode.Screen },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.HardLight), PixelBlenderMode.HardLight },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Overlay), PixelBlenderMode.Overlay },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Darken), PixelBlenderMode.Darken },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Lighten), PixelBlenderMode.Lighten },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Add), PixelBlenderMode.Add },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Substract), PixelBlenderMode.Substract },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Multiply), PixelBlenderMode.Multiply },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Src), PixelBlenderMode.Src },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Atop), PixelBlenderMode.Atop },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Over), PixelBlenderMode.Over },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.In), PixelBlenderMode.In },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Out), PixelBlenderMode.Out },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Dest), PixelBlenderMode.Dest },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.DestAtop), PixelBlenderMode.DestAtop },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.DestOver), PixelBlenderMode.DestOver },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.DestIn), PixelBlenderMode.DestIn },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.DestOut), PixelBlenderMode.DestOut },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Clear), PixelBlenderMode.Clear },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Xor), PixelBlenderMode.Xor },
}; };
[Theory] [Theory]

103
tests/ImageSharp.Tests/TestDataIcc/IccTestDataProfiles.cs

@ -10,28 +10,31 @@ namespace ImageSharp.Tests
{ {
internal static class IccTestDataProfiles internal static class IccTestDataProfiles
{ {
public static readonly IccProfileHeader Header_Random_Write = new IccProfileHeader public static readonly IccProfileHeader Header_Random_Write = CreateHeaderRandomValue(
562, // should be overwritten
new IccProfileId(1, 2, 3, 4), // should be overwritten
"ijkl"); // should be overwritten to "acsp"
public static readonly IccProfileHeader Header_Random_Read = CreateHeaderRandomValue(132,
#if !NETSTANDARD1_1
new IccProfileId(2931428592, 418415738, 3086756963, 2237536530),
#else
IccProfileId.Zero,
#endif
"acsp");
public static readonly byte[] Header_Random_Array = CreateHeaderRandomArray(132, 0, new byte[]
{ {
Class = IccProfileClass.DisplayDevice, #if !NETSTANDARD1_1
CmmType = "abcd", 0xAE, 0xBA, 0x0C, 0xF0, 0x18, 0xF0, 0x84, 0x7A, 0xB7, 0xFC, 0x2C, 0x63, 0x85, 0x5E, 0x19, 0x12,
CreationDate = new DateTime(1990, 11, 26, 7, 21, 42), #else
CreatorSignature = "dcba", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
DataColorSpace = IccColorSpaceType.Rgb, #endif
DeviceAttributes = IccDeviceAttribute.ChromaBlackWhite | IccDeviceAttribute.OpacityTransparent, });
DeviceManufacturer = 123456789u,
DeviceModel = 987654321u,
FileSignature = "ijkl", // should be overwritten to "acsp"
Flags = IccProfileFlag.Embedded | IccProfileFlag.Independent,
Id = new IccProfileId(1, 2, 3, 4), // should be overwritten
PcsIlluminant = new Vector3(4, 5, 6),
PrimaryPlatformSignature = IccPrimaryPlatformType.MicrosoftCorporation,
ProfileConnectionSpace = IccColorSpaceType.CieXyz,
RenderingIntent = IccRenderingIntent.AbsoluteColorimetric,
Size = 562, // should be overwritten
Version = new Version(4, 3, 0),
};
public static readonly IccProfileHeader Header_Random_Read = new IccProfileHeader public static IccProfileHeader CreateHeaderRandomValue(uint size, IccProfileId id, string fileSignature)
{
return new IccProfileHeader
{ {
Class = IccProfileClass.DisplayDevice, Class = IccProfileClass.DisplayDevice,
CmmType = "abcd", CmmType = "abcd",
@ -52,13 +55,17 @@ namespace ImageSharp.Tests
PrimaryPlatformSignature = IccPrimaryPlatformType.MicrosoftCorporation, PrimaryPlatformSignature = IccPrimaryPlatformType.MicrosoftCorporation,
ProfileConnectionSpace = IccColorSpaceType.CieXyz, ProfileConnectionSpace = IccColorSpaceType.CieXyz,
RenderingIntent = IccRenderingIntent.AbsoluteColorimetric, RenderingIntent = IccRenderingIntent.AbsoluteColorimetric,
Size = 132, Size = size,
Version = new Version(4, 3, 0), Version = new Version(4, 3, 0),
}; };
}
public static readonly byte[] Header_Random_Array = public static byte[] CreateHeaderRandomArray(uint size, uint nrOfEntries, byte[] profileId)
{
return ArrayHelper.Concat(
new byte[]
{ {
0x00, 0x00, 0x00, 0x84, // Size (132) (byte)(size >> 24), (byte)(size >> 16), (byte)(size >> 8), (byte)size, // Size
0x61, 0x62, 0x63, 0x64, // CmmType 0x61, 0x62, 0x63, 0x64, // CmmType
0x04, 0x30, 0x00, 0x00, // Version 0x04, 0x30, 0x00, 0x00, // Version
0x6D, 0x6E, 0x74, 0x72, // Class 0x6D, 0x6E, 0x74, 0x72, // Class
@ -74,19 +81,53 @@ namespace ImageSharp.Tests
0x00, 0x00, 0x00, 0x03, // RenderingIntent 0x00, 0x00, 0x00, 0x03, // RenderingIntent
0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, // PcsIlluminant 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, // PcsIlluminant
0x64, 0x63, 0x62, 0x61, // CreatorSignature 0x64, 0x63, 0x62, 0x61, // CreatorSignature
},
#if !NETSTANDARD1_1 profileId,
0xAE, 0xBA, 0x0C, 0xF0, 0x18, 0xF0, 0x84, 0x7A, 0xB7, 0xFC, 0x2C, 0x63, 0x85, 0x5E, 0x19, 0x12, // Id new byte[]
#else {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Id
#endif
// Padding // Padding
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Nr of tag table entries (0) // Nr of tag table entries (0)
0x00, 0x00, 0x00, 0x00, (byte)(nrOfEntries >> 24), (byte)(nrOfEntries >> 16), (byte)(nrOfEntries >> 8), (byte)nrOfEntries
}; });
}
public static byte[] Profile_Random_Array = ArrayHelper.Concat(CreateHeaderRandomArray(168, 2, new byte[]
{
#if !NETSTANDARD1_1
0xA9, 0x71, 0x8F, 0xC1, 0x1E, 0x2D, 0x64, 0x1B, 0x10, 0xF4, 0x7D, 0x6A, 0x5B, 0xF6, 0xAC, 0xB9
#else
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
#endif
}),
new byte[]
{
0x00, 0x00, 0x00, 0x00, // tag signature (Unknown)
0x00, 0x00, 0x00, 0x9C, // tag offset (156)
0x00, 0x00, 0x00, 0x0C, // tag size (12)
0x00, 0x00, 0x00, 0x00, // tag signature (Unknown)
0x00, 0x00, 0x00, 0x9C, // tag offset (156)
0x00, 0x00, 0x00, 0x0C, // tag size (12)
},
IccTestDataTagDataEntry.TagDataEntryHeader_UnknownArr,
IccTestDataTagDataEntry.Unknown_Arr
);
public static IccProfile Profile_Random_Val = new IccProfile(CreateHeaderRandomValue(168,
#if !NETSTANDARD1_1
new IccProfileId(0xA9718FC1, 0x1E2D641B, 0x10F47D6A, 0x5BF6ACB9),
#else
IccProfileId.Zero,
#endif
"acsp"),
new IccTagDataEntry[]
{
IccTestDataTagDataEntry.Unknown_Val,
IccTestDataTagDataEntry.Unknown_Val
});
} }
} }

Loading…
Cancel
Save