Skip to content

Commit

Permalink
Added support for performing an Fx operation on a MagickImageCollecti…
Browse files Browse the repository at this point in the history
…on (#1616).
  • Loading branch information
dlemstra committed Jul 15, 2024
1 parent f9f32fe commit f3f8261
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 5 deletions.
17 changes: 17 additions & 0 deletions src/Magick.NET.Core/IMagickImageCollection{TQuantumType}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,23 @@ public partial interface IMagickImageCollection<TQuantumType> : IMagickImageColl
/// <exception cref="MagickException">Thrown when an error is raised by ImageMagick.</exception>
IMagickImage<TQuantumType> Flatten(IMagickColor<TQuantumType> backgroundColor);

/// <summary>
/// Applies a mathematical expression to the images and returns the result.
/// </summary>
/// <param name="expression">The expression to apply.</param>
/// <returns>The resulting image of the fx operation.</returns>
/// <exception cref="MagickException">Thrown when an error is raised by ImageMagick.</exception>
IMagickImage<TQuantumType> Fx(string expression);

/// <summary>
/// Applies a mathematical expression to the images and returns the result.
/// </summary>
/// <param name="expression">The expression to apply.</param>
/// <param name="channels">The channel(s) to apply the expression to.</param>
/// <returns>The resulting image of the fx operation.</returns>
/// <exception cref="MagickException">Thrown when an error is raised by ImageMagick.</exception>
IMagickImage<TQuantumType> Fx(string expression, Channels channels);

/// <summary>
/// Remap image colors with closest color from reference image.
/// </summary>
Expand Down
8 changes: 7 additions & 1 deletion src/Magick.NET/MagickImage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3016,7 +3016,7 @@ public void Fx(string expression, Channels channels)
{
Throw.IfNullOrEmpty(nameof(expression), expression);

_nativeInstance.Fx(expression, channels);
_nativeInstance.Instance = NativeMagickImage.Fx(_nativeInstance.Instance, expression, channels);
}

/// <summary>
Expand Down Expand Up @@ -7327,6 +7327,12 @@ internal static IReadOnlyCollection<IMagickImage<QuantumType>> CreateList(IntPtr
return result;
}

internal static IMagickImage<QuantumType> Fx(IMagickImage<QuantumType> image, string expression, Channels channels)
{
var result = NativeMagickImage.Fx(GetInstance(image), expression, channels);
return Create(result, GetSettings(image));
}

internal static IntPtr GetInstance(IMagickImage? image)
{
if (image is null)
Expand Down
24 changes: 24 additions & 0 deletions src/Magick.NET/MagickImageCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,30 @@ public IMagickImage<QuantumType> Flatten(IMagickColor<QuantumType> backgroundCol
}
}

/// <summary>
/// Applies a mathematical expression to the images and returns the result.
/// </summary>
/// <param name="expression">The expression to apply.</param>
/// <returns>The resulting image of the fx operation.</returns>
/// <exception cref="MagickException">Thrown when an error is raised by ImageMagick.</exception>
public IMagickImage<QuantumType> Fx(string expression)
=> Fx(expression, Channels.Undefined);

/// <summary>
/// Applies a mathematical expression to the images and returns the result.
/// </summary>
/// <param name="expression">The expression to apply.</param>
/// <param name="channels">The channel(s) to apply the expression to.</param>
/// <returns>The resulting image of the fx operation.</returns>
/// <exception cref="MagickException">Thrown when an error is raised by ImageMagick.</exception>
public IMagickImage<QuantumType> Fx(string expression, Channels channels)
{
Throw.IfNullOrEmpty(nameof(expression), expression);

using var imageAttacher = new TemporaryImageAttacher(_images);
return MagickImage.Fx(_images[0], expression, channels);
}

/// <summary>
/// Returns an enumerator that iterates through the images.
/// </summary>
Expand Down
8 changes: 4 additions & 4 deletions src/Magick.NET/Native/MagickImage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ private unsafe sealed partial class NativeMagickImage : NativeInstance
[Cleanup(Name = nameof(DisposeInstance))]
public static partial NativeMagickImage Create(IMagickSettings<QuantumType>? settings);

[Throws]
[Cleanup(Name = nameof(DisposeInstance))]
public static partial IntPtr Fx(IntPtr image, string expression, Channels channels);

public static partial IntPtr GetNext(IntPtr image);

public partial nuint AnimationDelay_Get();
Expand Down Expand Up @@ -459,10 +463,6 @@ private unsafe sealed partial class NativeMagickImage : NativeInstance
[SetInstance]
public partial void Frame(MagickRectangle geometry);

[Throws]
[SetInstance]
public partial void Fx(string expression, Channels channels);

[Throws]
public partial void GammaCorrect(double gamma, Channels channels);

Expand Down
59 changes: 59 additions & 0 deletions tests/Magick.NET.Tests/MagickImageCollectionTests/TheFxMethod.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright Dirk Lemstra https://github.com/dlemstra/Magick.NET.
// Licensed under the Apache License, Version 2.0.

using System;
using ImageMagick;
using Xunit;

namespace Magick.NET.Tests;

public partial class MagickImageCollectionTests
{
public class TheFxMethod
{
[Fact]
public void ShouldThrowExceptionWhenExpressionIsNull()
{
using var images = new MagickImageCollection();

Assert.Throws<ArgumentNullException>("expression", () => images.Fx(null));
}

[Fact]
public void ShouldThrowExceptionWhenExpressionIsEmpty()
{
using var images = new MagickImageCollection();

Assert.Throws<ArgumentException>("expression", () => images.Fx(string.Empty));
}

[Fact]
public void ShouldThrowExceptionWhenExpressionIsInvalid()
{
using var images = new MagickImageCollection
{
new MagickImage(MagickColors.Purple, 1, 1),
};

Assert.Throws<MagickOptionErrorException>(() => images.Fx("foobar"));
}

[Fact]
public void ShouldEvaluateTheExpression()
{
using var images = new MagickImageCollection();

var logo = new MagickImage(Files.Builtin.Logo);
images.Add(logo);

var floppedLogo = logo.Clone();
floppedLogo.Flop();
images.Add(floppedLogo);

using var result = images.Fx("(u+v)/2", Channels.Green);

ColorAssert.Equal(new MagickColor("#ff9fff"), result, 250, 375);
ColorAssert.Equal(new MagickColor("#229f92"), result, 375, 375);
}
}
}

0 comments on commit f3f8261

Please sign in to comment.