diff --git a/src/Oh.My.Stitcher/NetVips/GObjectHacks.cs b/src/Oh.My.Stitcher/NetVips/GObjectHacks.cs new file mode 100644 index 0000000..cb363c9 --- /dev/null +++ b/src/Oh.My.Stitcher/NetVips/GObjectHacks.cs @@ -0,0 +1,38 @@ +using System.Runtime.InteropServices; +using System.Security; +using NetVips.Internal; +using GObjectManaged = NetVips.GObject; + +namespace Oh.My.Stitcher.NetVips; + + +internal static unsafe class GObjectHacks +{ + internal static void SetProperty(GObjectManaged gObject, string name, ReadOnlySpan value) + { + var gvStruct = new GValue.Struct(); + + try + { + GValue.Init(ref gvStruct, 16 << 2); + fixed( byte* pValue = value ) + { + GValueHacks.SetString(ref gvStruct, pValue); + } + + GObject.SetProperty(gObject, name, in gvStruct); + } + finally + { + GValue.Unset(ref gvStruct); + } + } +} + +internal static unsafe class GValueHacks +{ + [SuppressUnmanagedCodeSecurity] + [DllImport("libgobject-2.0.so.0", CallingConvention = CallingConvention.Cdecl, + EntryPoint = "g_value_set_string")] + internal static extern void SetString(ref GValue.Struct value, byte* vString); +} diff --git a/src/Oh.My.Stitcher/NetVips/OperationHacks.cs b/src/Oh.My.Stitcher/NetVips/OperationHacks.cs new file mode 100644 index 0000000..f73894a --- /dev/null +++ b/src/Oh.My.Stitcher/NetVips/OperationHacks.cs @@ -0,0 +1,34 @@ +using NetVips; +using NetVips.Internal; +using VipsObject = NetVips.Internal.VipsObject; + +namespace Oh.My.Stitcher.NetVips; + +public static class OperationHacks +{ + public static object Call(string operationName, ReadOnlySpan arg) + { + var intro = Introspect.Get(operationName); + if (intro.RequiredInput.Count != 1) + throw new ArgumentException($"unable to call {operationName}"); + + nint vop; + using( var op = Operation.NewFromName(operationName) ) + { + Introspect.Argument requiredArg = intro.RequiredInput[0]; + GObjectHacks.SetProperty(op, requiredArg.Name, arg); + vop = VipsOperation.Build(op); + if (vop == IntPtr.Zero) + { + VipsObject.UnrefOutputs(op); + throw new VipsException($"unable to call {operationName}"); + } + } + using (var op = new Operation(vop)) + { + object? result = op.Get(intro.RequiredOutput[0].Name); + VipsObject.UnrefOutputs(op); + return result; + } + } +}