From 67d3b61e4739193d28a4140dd82e969743182a8d Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 19 Jun 2024 16:41:19 +0200 Subject: [PATCH] [PixImage] Cache delegates for dynamic creation --- .../PixImage/PixImage.cs | 90 ++++++++++++------- 1 file changed, 58 insertions(+), 32 deletions(-) diff --git a/src/Aardvark.Base.Tensors.CSharp/PixImage/PixImage.cs b/src/Aardvark.Base.Tensors.CSharp/PixImage/PixImage.cs index 5e275ee2..de0521c5 100644 --- a/src/Aardvark.Base.Tensors.CSharp/PixImage/PixImage.cs +++ b/src/Aardvark.Base.Tensors.CSharp/PixImage/PixImage.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.Concurrent; using System.IO; using System.Linq; using System.Reflection; @@ -319,6 +320,8 @@ public PixImage(Col.Format format) #region Static Tables and Methods + #region Format file extensions + private static readonly Dictionary s_formatOfExtension = new() { { ".tga", PixFileFormat.Targa }, @@ -362,39 +365,78 @@ protected static PixFileFormat GetFormatOfExtension(string filename) throw new ArgumentException("File name has unknown extension: " + ext); } + public static string GetPreferredExtensionOfFormat(PixFileFormat format) + { + return s_preferredExtensionOfFormat.Value[format]; + } + + #endregion + + #region Grayscale conversion + + private static void ToGray(PixImage src, object dst, Func toGray) + { + ((Matrix)dst).SetMap(src.AsPixImage().GetMatrix(), toGray); + } + + protected static readonly Dictionary<(Type, Type), Action> s_rgbToGrayMap = new() + { + { (typeof(byte), typeof(byte)), (src, dst) => ToGray(src, dst, Col.ToGrayByte) }, + { (typeof(ushort), typeof(ushort)), (src, dst) => ToGray(src, dst, Col.ToGrayUShort) }, + { (typeof(uint), typeof(uint)), (src, dst) => ToGray(src, dst, Col.ToGrayUInt) }, + { (typeof(float), typeof(float)), (src, dst) => ToGray(src, dst, Col.ToGrayFloat) }, + { (typeof(double), typeof(double)), (src, dst) => ToGray(src, dst, Col.ToGrayDouble) }, + }; + + #endregion + + #region Create dispatcher + // Helper class to create PixImage from given Type private static class Dispatch { + private delegate PixImage CreateDelegate(Col.Format format, long width, long height, long channels); + private delegate PixImage CreateArrayDelegate(Array data, Col.Format format, long width, long height, long channels); + private static class CreateDispatcher { - public static PixImage Create(Col.Format format, long x, long y, long channels) - => new PixImage(format, x, y, channels); + public static PixImage Create(Col.Format format, long width, long height, long channels) + => new PixImage(format, width, height, channels); - public static PixImage CreateArray(T[] data, Col.Format format, long x, long y, long channels) - => new PixImage(format, data.CreateImageVolume(new V3l(x, y, channels))); + public static PixImage CreateArray(Array data, Col.Format format, long width, long height, long channels) + => new PixImage(format, ((T[])data).CreateImageVolume(new V3l(width, height, channels))); } private const BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public; - private static readonly MethodInfo s_createMethod = typeof(CreateDispatcher).GetMethod("Create", flags); - private static readonly MethodInfo s_createArrayMethod = typeof(CreateDispatcher).GetMethod("CreateArray", flags); - public static PixImage Create(PixFormat format, long x, long y, long channels) + private static readonly MethodInfo s_createMethod = typeof(CreateDispatcher).GetMethod(nameof(CreateDispatcher.Create), flags); + private static readonly ConcurrentDictionary s_createDelegates = new(); + + private static readonly MethodInfo s_createArrayMethod = typeof(CreateDispatcher).GetMethod(nameof(CreateDispatcher.CreateArray), flags); + private static readonly ConcurrentDictionary s_createArrayDelegates = new(); + + public static PixImage Create(PixFormat format, long width, long height, long channels) { - var mi = s_createMethod.MakeGenericMethod(format.Type); - return (PixImage)mi.Invoke(null, new object[] { format.Format, x, y, channels }); + var create = s_createDelegates.GetOrAdd(format.Type, t => { + var mi = s_createMethod.MakeGenericMethod(t); + return (CreateDelegate)Delegate.CreateDelegate(typeof(CreateDelegate), mi); + }); + + return create(format.Format, width, height, channels); } - public static PixImage Create(Array array, Col.Format format, long x, long y, long channels) + public static PixImage Create(Array array, Col.Format format, long width, long height, long channels) { - var mi = s_createArrayMethod.MakeGenericMethod(array.GetType().GetElementType()); - return (PixImage)mi.Invoke(null, new object[] { array, format, x, y, channels }); + var create = s_createArrayDelegates.GetOrAdd(array.GetType().GetElementType(), t => { + var mi = s_createArrayMethod.MakeGenericMethod(t); + return (CreateArrayDelegate)Delegate.CreateDelegate(typeof(CreateArrayDelegate), mi); + }); + + return create(array, format, width, height, channels); } } - public static string GetPreferredExtensionOfFormat(PixFileFormat format) - { - return s_preferredExtensionOfFormat.Value[format]; - } + #endregion #endregion @@ -814,22 +856,6 @@ public static PixImageInfo GetInfoFromStream(Stream stream, IPixLoader loader = { (typeof(double), typeof(float)), v => ((Volume)v).ToFloatColor() }, { (typeof(double), typeof(double)), v => ((Volume)v).CopyWindow() }, }; - - private static void ToGray(PixImage src, object dst, Func toGray) - { - ((Matrix)dst).SetMap(src.AsPixImage().GetMatrix(), toGray); - } - - protected static Dictionary<(Type, Type), Action> s_rgbToGrayMap = - new Dictionary<(Type, Type), Action>() - { - { (typeof(byte), typeof(byte)), (src, dst) => ToGray(src, dst, Col.ToGrayByte) }, - { (typeof(ushort), typeof(ushort)), (src, dst) => ToGray(src, dst, Col.ToGrayUShort) }, - { (typeof(uint), typeof(uint)), (src, dst) => ToGray(src, dst, Col.ToGrayUInt) }, - { (typeof(float), typeof(float)), (src, dst) => ToGray(src, dst, Col.ToGrayFloat) }, - { (typeof(double), typeof(double)), (src, dst) => ToGray(src, dst, Col.ToGrayDouble) }, - }; - public abstract PixImage ToPixImage(); public abstract PixImage Transformed(ImageTrafo trafo);