// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageSharp.Tests { using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Reflection; using ImageSharp.PixelFormats; /// /// Extension methods for TestUtilities /// public static class TestUtilityExtensions { private static readonly Dictionary ClrTypes2PixelTypes = new Dictionary(); private static readonly Assembly ImageSharpAssembly = typeof(Rgba32).GetTypeInfo().Assembly; private static readonly Dictionary PixelTypes2ClrTypes = new Dictionary(); private static readonly PixelTypes[] AllConcretePixelTypes = GetAllPixelTypes() .Except(new[] { PixelTypes.Undefined, PixelTypes.All }) .ToArray(); static TestUtilityExtensions() { // Add Rgba32 Our default. Type defaultPixelFormatType = typeof(Rgba32); PixelTypes2ClrTypes[PixelTypes.Rgba32] = defaultPixelFormatType; ClrTypes2PixelTypes[defaultPixelFormatType] = PixelTypes.Rgba32; // Add PixelFormat types string nameSpace = typeof(Alpha8).FullName; nameSpace = nameSpace.Substring(0, nameSpace.Length - typeof(Alpha8).Name.Length - 1); foreach (PixelTypes pt in AllConcretePixelTypes.Where(pt => pt != PixelTypes.Rgba32)) { string typeName = $"{nameSpace}.{pt}"; Type t = ImageSharpAssembly.GetType(typeName); PixelTypes2ClrTypes[pt] = t ?? throw new InvalidOperationException($"Could not find: {typeName}"); ClrTypes2PixelTypes[t] = pt; } } public static bool HasFlag(this PixelTypes pixelTypes, PixelTypes flag) => (pixelTypes & flag) == flag; public static bool IsEquivalentTo(this Image a, Image b, bool compareAlpha = true) where TPixel : struct, IPixel { if (a.Width != b.Width || a.Height != b.Height) { return false; } byte[] bytesA = new byte[3]; byte[] bytesB = new byte[3]; using (PixelAccessor pixA = a.Lock()) { using (PixelAccessor pixB = b.Lock()) { for (int y = 0; y < a.Height; y++) { for (int x = 0; x < a.Width; x++) { TPixel ca = pixA[x, y]; TPixel cb = pixB[x, y]; if (compareAlpha) { if (!ca.Equals(cb)) { return false; } } else { ca.ToXyzBytes(bytesA, 0); cb.ToXyzBytes(bytesB, 0); if (bytesA[0] != bytesB[0] || bytesA[1] != bytesB[1] || bytesA[2] != bytesB[2]) { return false; } } } } } } return true; } public static string ToCsv(this IEnumerable items, string separator = ",") { return string.Join(separator, items.Select(o => string.Format(CultureInfo.InvariantCulture, "{0}", o))); } public static Type GetClrType(this PixelTypes pixelType) => PixelTypes2ClrTypes[pixelType]; /// /// Returns the enumerations for the given type. /// /// /// public static PixelTypes GetPixelType(this Type colorStructClrType) => ClrTypes2PixelTypes[colorStructClrType]; public static IEnumerable> ExpandAllTypes(this PixelTypes pixelTypes) { if (pixelTypes == PixelTypes.Undefined) { return Enumerable.Empty>(); } else if (pixelTypes == PixelTypes.All) { // TODO: Need to return unknown types here without forcing CLR to load all types in ImageSharp assembly return PixelTypes2ClrTypes; } var result = new Dictionary(); foreach (PixelTypes pt in AllConcretePixelTypes) { if (pixelTypes.HasAll(pt)) { result[pt] = pt.GetClrType(); } } return result; } internal static bool HasAll(this PixelTypes pixelTypes, PixelTypes flagsToCheck) => (pixelTypes & flagsToCheck) == flagsToCheck; /// /// Enumerate all available -s /// /// The pixel types internal static PixelTypes[] GetAllPixelTypes() => (PixelTypes[])Enum.GetValues(typeof(PixelTypes)); } }