/// <summary> /// Connects a callback function (<paramref name="callback"/>) to a signal on this object. /// </summary> /// <remarks> /// The callback will be triggered every time this signal is issued on this instance. /// </remarks> /// <param name="detailedSignal">A string of the form "signal-name::detail".</param> /// <param name="callback">The callback to connect.</param> /// <param name="data">Data to pass to handler calls.</param> /// <returns>The handler id.</returns> /// <exception cref="T:System.Exception">If it failed to connect the signal.</exception> public uint SignalConnect(string detailedSignal, Delegate callback, IntPtr data = default) { if (callback is Image.EvalDelegate evalDelegate) { void EvalMarshal(IntPtr imagePtr, IntPtr progressPtr, IntPtr userDataPtr) { if (progressPtr == IntPtr.Zero || imagePtr == IntPtr.Zero) { return; } using var image = new Image(imagePtr); image.ObjectRef(); var progressStruct = progressPtr.Dereference <VipsProgress>(); evalDelegate.Invoke(image, progressStruct); } callback = (VipsImage.EvalSignal)EvalMarshal; } // add a weak reference callback to ensure all handles are released on finalization if (_handles.Count == 0) { GWeakNotify notify = ReleaseDelegates; var notifyHandle = GCHandle.Alloc(notify); Internal.GObject.WeakRef(this, notify, GCHandle.ToIntPtr(notifyHandle)); } // prevent the delegate from being re-located or disposed of by the garbage collector var delegateHandle = GCHandle.Alloc(callback); _handles.Add(delegateHandle); // get the pointer for the delegate which can be passed to the native code var callbackPtr = Marshal.GetFunctionPointerForDelegate(callback); var ret = GSignal.ConnectData(this, detailedSignal, callbackPtr, data, null, default); if (ret == 0) { throw new Exception("Failed to connect signal."); } return(ret); }
/// <summary> /// Get the contents of a GValue. /// </summary> /// <remarks> /// The contents of the GValue are read out as a C# type. /// </remarks> /// <returns></returns> public object Get() { // logger.Debug($"Get: this = {this}"); var gtype = GetTypeOf(); var fundamental = GType.GTypeFundamental(gtype); object result; if (gtype == GBoolType) { result = Internal.GValue.GValueGetBoolean(ref Struct) != 0; } else if (gtype == GIntType) { result = Internal.GValue.GValueGetInt(ref Struct); } else if (gtype == GDoubleType) { result = Internal.GValue.GValueGetDouble(ref Struct); } else if (fundamental == GEnumType) { result = FromEnum(gtype, Internal.GValue.GValueGetEnum(ref Struct)); } else if (fundamental == GFlagsType) { result = Internal.GValue.GValueGetFlags(ref Struct); } else if (gtype == GStrType) { result = Internal.GValue.GValueGetString(ref Struct).ToUtf8String(); } else if (gtype == RefStrType) { // don't bother getting the size -- assume these are always // null-terminated C strings ulong psize = 0; result = VipsType.VipsValueGetRefString(ref Struct, ref psize).ToUtf8String(); } else if (gtype == ImageType) { // GValueGetObject() will not add a ref ... that is // held by the gvalue var vi = Internal.GObject.GValueGetObject(ref Struct); // we want a ref that will last with the life of the vimage: // this ref is matched by the unref that's attached to finalize // by GObject var image = new Image(vi); image.ObjectRef(); result = image; } else if (gtype == ArrayIntType) { var psize = 0; var intPtr = VipsType.VipsValueGetArrayInt(ref Struct, ref psize); var intArr = new int[psize]; Marshal.Copy(intPtr, intArr, 0, psize); result = intArr; } else if (gtype == ArrayDoubleType) { var psize = 0; var intPtr = VipsType.VipsValueGetArrayDouble(ref Struct, ref psize); var doubleArr = new double[psize]; Marshal.Copy(intPtr, doubleArr, 0, psize); result = doubleArr; } else if (gtype == ArrayImageType) { var psize = 0; var ptrArr = VipsImage.VipsValueGetArrayImage(ref Struct, ref psize); var images = new Image[psize]; for (var i = 0; i < psize; i++) { var vi = Marshal.ReadIntPtr(ptrArr, i * IntPtr.Size); images[i] = new Image(vi); images[i].ObjectRef(); } result = images; } else if (gtype == BlobType) { ulong psize = 0; var array = VipsType.VipsValueGetBlob(ref Struct, ref psize); // Blob types are returned as an array of bytes. var byteArr = new byte[psize]; Marshal.Copy(array, byteArr, 0, (int)psize); result = byteArr; } else { throw new Exception($"unsupported gtype for get {Base.TypeName(gtype)}"); } return(result); }
/// <summary> /// Make a <see cref="MutableImage"/> from a regular copied <see cref="Image"/>. /// </summary> /// <remarks> /// This is for internal use only. See <see cref="Image.Mutate"/> for the /// user-facing interface. /// </remarks> internal MutableImage(Image copiedImage) : base(copiedImage.ObjectRef()) { Image = copiedImage; }