using System;
using System.Buffers;
using System.Runtime.InteropServices;
using System.Text;
using NetVips.Internal;
namespace NetVips;
///
/// Useful extension methods that we use in our codebase.
///
internal static class ExtensionMethods
{
///
/// Removes the element with the specified key from the
/// and retrieves the value to .
///
/// The to remove from.
/// >The key of the element to remove.
/// The target to retrieve the value to.
/// if the element is successfully removed; otherwise, .
internal static bool Remove(this VOption self, string key, out object target)
{
self.TryGetValue(key, out target);
return self.Remove(key);
}
///
/// Merges 2 s.
///
/// The to merge into.
/// The to merge from.
internal static void Merge(this VOption self, VOption merge)
{
foreach (var item in merge)
{
self[item.Key] = item.Value;
}
}
///
/// Call a libvips operation.
///
/// A used as guide.
/// Operation name.
/// A new object.
internal static object Call(this Image image, string operationName) =>
Operation.Call(operationName, null, image);
///
/// Call a libvips operation.
///
/// A used as guide.
/// Operation name.
/// An arbitrary number and variety of arguments.
/// A new object.
internal static object Call(this Image image, string operationName, params object[] args) =>
Operation.Call(operationName, null, image, args);
///
/// Call a libvips operation.
///
/// A used as guide.
/// Operation name.
/// Optional arguments.
/// A new object.
internal static object Call(this Image image, string operationName, VOption kwargs) =>
Operation.Call(operationName, kwargs, image);
///
/// Call a libvips operation.
///
/// A used as guide.
/// Operation name.
/// Optional arguments.
/// An arbitrary number and variety of arguments.
/// A new object.
internal static object Call(this Image image, string operationName, VOption kwargs, params object[] args) =>
Operation.Call(operationName, kwargs, image, args);
///
/// Prepends to .
///
/// The array.
/// The to prepend to .
/// A new object array.
internal static object[] PrependImage(this T[] args, Image image)
{
if (args == null)
{
return new object[] { image };
}
var newValues = new object[args.Length + 1];
newValues[0] = image;
Array.Copy(args, 0, newValues, 1, args.Length);
return newValues;
}
///
/// Marshals a GLib UTF8 char* to a managed string.
///
/// Pointer to the GLib string.
/// If set to , free the GLib string.
/// Size of the GLib string, use 0 to read until the null character.
/// The managed string.
internal static string ToUtf8String(this nint utf8Str, bool freePtr = false, int size = 0)
{
if (utf8Str == IntPtr.Zero)
{
return null;
}
if (size == 0)
{
while (Marshal.ReadByte(utf8Str, size) != 0)
{
++size;
}
}
if (size == 0)
{
if (freePtr)
{
GLib.GFree(utf8Str);
}
return string.Empty;
}
var bytes = ArrayPool.Shared.Rent(size);
try
{
Marshal.Copy(utf8Str, bytes, 0, size);
return Encoding.UTF8.GetString(bytes, 0, size);
}
finally
{
ArrayPool.Shared.Return(bytes);
if (freePtr)
{
GLib.GFree(utf8Str);
}
}
}
///
/// Convert bytes to human readable format.
///
/// The number of bytes.
/// The readable format of the bytes.
internal static string ToReadableBytes(this ulong value)
{
string[] sizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
var i = 0;
decimal dValue = value;
while (Math.Round(dValue, 2) >= 1000)
{
dValue /= 1024;
i++;
}
return $"{dValue:n2} {sizeSuffixes[i]}";
}
///
/// Negate all elements in an array.
///
/// An array of doubles.
/// The negated array.
internal static double[] Negate(this double[] array)
{
for (var i = 0; i < array.Length; i++)
{
array[i] *= -1;
}
return array;
}
///
/// Negate all elements in an array.
///
///
/// It will output an array of doubles instead of integers.
///
/// An array of integers.
/// The negated array.
internal static double[] Negate(this int[] array)
{
var doubles = new double[array.Length];
for (var i = 0; i < array.Length; i++)
{
ref var value = ref doubles[i];
value = array[i] * -1;
}
return doubles;
}
///
/// Invert all elements in an array.
///
/// An array of doubles.
/// The inverted array.
internal static double[] Invert(this double[] array)
{
for (var i = 0; i < array.Length; i++)
{
array[i] = 1.0 / array[i];
}
return array;
}
///
/// Invert all elements in an array.
///
///
/// It will output an array of doubles instead of integers.
///
/// An array of integers.
/// The inverted array.
internal static double[] Invert(this int[] array)
{
var doubles = new double[array.Length];
for (var i = 0; i < array.Length; i++)
{
ref var value = ref doubles[i];
value = 1.0 / array[i];
}
return doubles;
}
///
/// Compatibility method to call loaders with the enum.
///
/// The optional arguments for the loader.
/// The optional parameter.
internal static void AddFailOn(this VOption options, Enums.FailOn? failOn = null)
{
if (!failOn.HasValue)
{
return;
}
if (NetVips.AtLeastLibvips(8, 12))
{
options.Add("fail_on", failOn);
}
else
{
// The deprecated "fail" param was at the highest sensitivity (>= warning),
// but for compat it would be more correct to set this to true only when
// a non-permissive enum is given (> none).
options.Add("fail", failOn > Enums.FailOn.None);
}
}
///
/// Compatibility method to call savers with the enum.
///
/// The optional arguments for the saver.
/// The optional parameter.
/// Whether this operation is -like.
internal static void AddForeignKeep(this VOption options, Enums.ForeignKeep? keep = null, bool isDzsave = false)
{
if (!keep.HasValue)
{
return;
}
if (NetVips.AtLeastLibvips(8, 15))
{
options.Add(nameof(keep), keep);
}
else if (isDzsave)
{
options.Add("no_strip", keep != Enums.ForeignKeep.None);
}
else
{
options.Add("strip", keep == Enums.ForeignKeep.None);
}
}
}