// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) James South. // Licensed under the Apache License, Version 2.0. // // // The ImageProcessor bootstrapper. // // -------------------------------------------------------------------------------------------------------------------- namespace ImageProcessor.Configuration { using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using ImageProcessor.Common.Exceptions; using ImageProcessor.Common.Extensions; using ImageProcessor.Imaging.Formats; /// /// The ImageProcessor bootstrapper. /// public class ImageProcessorBootstrapper { /// /// A new instance Initializes a new instance of the class. /// with lazy initialization. /// private static readonly Lazy Lazy = new Lazy(() => new ImageProcessorBootstrapper()); /// /// Prevents a default instance of the class from being created. /// private ImageProcessorBootstrapper() { this.NativeBinaryFactory = new NativeBinaryFactory(); this.LoadSupportedImageFormats(); } /// /// Gets the current instance of the class. /// public static ImageProcessorBootstrapper Instance { get { return Lazy.Value; } } /// /// Gets the supported image formats. /// public IEnumerable SupportedImageFormats { get; private set; } /// /// Gets the native binary factory for registering embedded (unmanaged) binaries. /// public NativeBinaryFactory NativeBinaryFactory { get; private set; } /// /// Creates a list, using reflection, of supported image formats that ImageProcessor can run. /// private void LoadSupportedImageFormats() { if (this.SupportedImageFormats == null) { try { Type type = typeof(ISupportedImageFormat); HashSet found = new HashSet(); // Get any references and used assemblies. foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) { this.LoadReferencedAssemblies(found, assembly); } // Get any referenced but not used assemblies. Assembly executingAssembly = Assembly.GetExecutingAssembly(); string targetBasePath = Path.GetDirectoryName(new Uri(executingAssembly.Location).LocalPath); // ReSharper disable once AssignNullToNotNullAttribute FileInfo[] files = new DirectoryInfo(targetBasePath).GetFiles("*.dll", SearchOption.AllDirectories); foreach (FileInfo fileInfo in files) { AssemblyName assemblyName = AssemblyName.GetAssemblyName(fileInfo.FullName); if (!AppDomain.CurrentDomain.GetAssemblies() .Any(a => AssemblyName.ReferenceMatchesDefinition(assemblyName, a.GetName()))) { // In a web app, this assembly will automatically be bound from the // Asp.Net Temporary folder from where the site actually runs. this.LoadReferencedAssemblies(found, Assembly.Load(assemblyName)); } } List availableTypes = AppDomain.CurrentDomain .GetAssemblies() .SelectMany(a => a.GetLoadableTypes()) .Where(t => type.IsAssignableFrom(t) && t.IsClass && !t.IsAbstract) .ToList(); this.SupportedImageFormats = availableTypes .Select(f => (Activator.CreateInstance(f) as ISupportedImageFormat)).ToList(); } catch (Exception ex) { throw new ImageFormatException(ex.Message, ex.InnerException); } } } /// /// Loads any referenced assemblies into the current application domain. /// /// /// The collection containing the name of already found assemblies. /// /// /// The assembly to load from. /// private void LoadReferencedAssemblies(HashSet found, Assembly assembly) { // Used to avoid duplicates ArrayList results = new ArrayList(); // Resulting info Stack stack = new Stack(); // Stack of names // Store root assembly (level 0) directly into results list stack.Push(assembly.ToString()); // Do a preorder, non-recursive traversal while (stack.Count > 0) { string info = (string)stack.Pop(); // Get next assembly if (!found.Contains(info)) { found.Add(info); results.Add(info); // Store it to results ArrayList Assembly child = Assembly.Load(info); AssemblyName[] subchild = child.GetReferencedAssemblies(); for (int i = subchild.Length - 1; i >= 0; --i) { stack.Push(subchild[i].ToString()); } } } } } }