namespace ImageSharp.Benchmarks.Image { using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Numerics; using BenchmarkDotNet.Attributes; using Image = ImageSharp.Image; public abstract class MultiImageBenchmarkBase : BenchmarkBase { protected Dictionary FileNamesToBytes = new Dictionary(); protected Dictionary FileNamesToImageSharpImages = new Dictionary(); protected Dictionary FileNamesToSystemDrawingImages = new Dictionary(); /// /// The values of this enum separate input files into categories /// public enum InputImageCategory { AllImages, SmallImagesOnly, LargeImagesOnly } [Params(InputImageCategory.AllImages, InputImageCategory.SmallImagesOnly, InputImageCategory.LargeImagesOnly)] public InputImageCategory InputCategory { get; set; } protected virtual string BaseFolder => "../ImageSharp.Tests/TestImages/Formats/"; protected virtual IEnumerable FileFilters => new[] { "*.*" }; /// /// Gets the file names containing these strings are substrings are not processed by the benchmark. /// protected IEnumerable ExcludeSubstringsInFileNames => new string[] { }; /// /// Enumerates folders containing files OR files to be processed by the benchmark. /// protected IEnumerable AllFoldersOrFiles => this.InputImageSubfoldersOrFiles.Select(f => Path.Combine(this.BaseFolder, f)); /// /// The images sized above this threshold will be included in /// protected virtual int LargeImageThresholdInBytes => 100000; protected IEnumerable> EnumeratePairsByBenchmarkSettings( Dictionary input, Predicate checkIfSmall) { switch (this.InputCategory) { case InputImageCategory.AllImages: return input; case InputImageCategory.SmallImagesOnly: return input.Where(kv => checkIfSmall(kv.Value)); case InputImageCategory.LargeImagesOnly: return input.Where(kv => !checkIfSmall(kv.Value)); default: throw new ArgumentOutOfRangeException(); } } protected IEnumerable> FileNames2Bytes => this.EnumeratePairsByBenchmarkSettings( this.FileNamesToBytes, arr => arr.Length < this.LargeImageThresholdInBytes); protected abstract IEnumerable InputImageSubfoldersOrFiles { get; } [Setup] public void ReadImages() { // Console.WriteLine("Vector.IsHardwareAccelerated: " + Vector.IsHardwareAccelerated); this.ReadImagesImpl(); } protected virtual void ReadImagesImpl() { foreach (string folder in this.AllFoldersOrFiles) { var allFiles = this.FileFilters.SelectMany( f => Directory.EnumerateFiles(folder, f, SearchOption.AllDirectories) .Where(fn => !this.ExcludeSubstringsInFileNames.Any(w => fn.ToLower().Contains(w)))).ToArray(); foreach (var fn in allFiles) { this.FileNamesToBytes[fn] = File.ReadAllBytes(fn); } } } protected void ForEachStream(Func operation) { foreach (var kv in this.FileNames2Bytes) { using (MemoryStream memoryStream = new MemoryStream(kv.Value)) { try { var obj = operation(memoryStream); (obj as IDisposable)?.Dispose(); } catch (Exception ex) { Console.WriteLine($"Operation on {kv.Key} failed with {ex.Message}"); } } } } public abstract class WithImagesPreloaded : MultiImageBenchmarkBase { protected override void ReadImagesImpl() { base.ReadImagesImpl(); foreach (var kv in this.FileNamesToBytes) { byte[] bytes = kv.Value; string fn = kv.Key; using (var ms1 = new MemoryStream(bytes)) { this.FileNamesToImageSharpImages[fn] = new Image(ms1); } this.FileNamesToSystemDrawingImages[fn] = new Bitmap(new MemoryStream(bytes)); } } protected IEnumerable> FileNames2ImageSharpImages => this.EnumeratePairsByBenchmarkSettings( this.FileNamesToImageSharpImages, img => img.Width * img.Height < this.LargeImageThresholdInPixels); protected IEnumerable> FileNames2SystemDrawingImages => this.EnumeratePairsByBenchmarkSettings( this.FileNamesToSystemDrawingImages, img => img.Width * img.Height < this.LargeImageThresholdInPixels); protected virtual int LargeImageThresholdInPixels => 700000; protected void ForEachImageSharpImage(Func operation) { foreach (var kv in this.FileNames2ImageSharpImages) { try { var obj = operation(kv.Value); (obj as IDisposable)?.Dispose(); } catch (Exception ex) { Console.WriteLine($"Operation on {kv.Key} failed with {ex.Message}"); } } } protected void ForEachSystemDrawingImage(Func operation) { foreach (var kv in this.FileNames2SystemDrawingImages) { try { var obj = operation(kv.Value); (obj as IDisposable)?.Dispose(); } catch (Exception ex) { Console.WriteLine($"Operation on {kv.Key} failed with {ex.Message}"); } } } } } }