// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests { /// /// Utility class to provide information about the test image & the test case for the test code, /// and help managing IO. /// public class ImagingTestCaseUtility { /// /// Name of the TPixel in the owner /// public string PixelTypeName { get; set; } = string.Empty; /// /// The name of the file which is provided by /// Or a short string describing the image in the case of a non-file based image provider. /// public string SourceFileOrDescription { get; set; } = string.Empty; /// /// By default this is the name of the test class, but it's possible to change it /// public string TestGroupName { get; set; } = string.Empty; /// /// The name of the test case (by default) /// public string TestName { get; set; } = string.Empty; private string GetTestOutputFileNameImpl(string extension, string details, bool appendPixelTypeToFileName) { string fn = string.Empty; if (string.IsNullOrWhiteSpace(extension)) { extension = null; } fn = Path.GetFileNameWithoutExtension(this.SourceFileOrDescription); if (string.IsNullOrWhiteSpace(extension)) { extension = Path.GetExtension(this.SourceFileOrDescription); } if (string.IsNullOrWhiteSpace(extension)) { extension = ".bmp"; } extension = extension.ToLower(); if (extension[0] != '.') { extension = '.' + extension; } if (fn != string.Empty) fn = '_' + fn; string pixName = ""; if (appendPixelTypeToFileName) { pixName = this.PixelTypeName; if (pixName != string.Empty) { pixName = '_' + pixName; } } details = details ?? string.Empty; if (details != string.Empty) { details = '_' + details; } return $"{this.GetTestOutputDir()}/{this.TestName}{pixName}{fn}{details}{extension}"; } /// /// Gets the recommended file name for the output of the test /// /// The required extension /// The settings modifying the output path /// A boolean indicating whether to append the pixel type to output file name. /// The file test name public string GetTestOutputFileName(string extension = null, object testOutputDetails = null, bool appendPixelTypeToFileName = true) { string detailsString = null; string s = testOutputDetails as string; if (s != null) { detailsString = s; } else if (testOutputDetails != null) { Type type = testOutputDetails.GetType(); TypeInfo info = type.GetTypeInfo(); if (info.IsPrimitive || info.IsEnum || type == typeof(decimal)) { detailsString = testOutputDetails.ToString(); } else { IEnumerable properties = testOutputDetails.GetType().GetRuntimeProperties(); detailsString = String.Join("_", properties.ToDictionary(x => x.Name, x => x.GetValue(testOutputDetails)).Select(x => $"{x.Key}-{x.Value}")); } } return this.GetTestOutputFileNameImpl(extension, detailsString, appendPixelTypeToFileName); } /// /// Encodes image by the format matching the required extension, than saves it to the recommended output file. /// /// The pixel format of the image /// The image instance /// The requested extension /// Optional encoder public string SaveTestOutputFile( Image image, string extension = null, IImageEncoder encoder = null, object testOutputDetails = null, bool appendPixelTypeToFileName = true) where TPixel : struct, IPixel { string path = this.GetTestOutputFileName(extension, testOutputDetails, appendPixelTypeToFileName); encoder = encoder ?? TestEnvironment.GetReferenceEncoder(path); using (FileStream stream = File.OpenWrite(path)) { image.Save(stream, encoder); } return path; } internal string GetReferenceOutputFileName( string extension, object settings, bool appendPixelTypeToFileName) { return TestEnvironment.GetReferenceOutputFileName( this.GetTestOutputFileName(extension, settings, appendPixelTypeToFileName) ); } internal void Init(string typeName, string methodName) { this.TestGroupName = typeName; this.TestName = methodName; } internal void Init(MethodInfo method) { this.Init(method.DeclaringType.Name, method.Name); } //private static IImageEncoder GetEncoderByExtension(string extension, bool grayscale) //{ // extension = extension?.TrimStart('.'); // var format = Configuration.Default.FindFormatByFileExtension(extension); // IImageEncoder encoder = Configuration.Default.FindEncoder(format); // PngEncoder pngEncoder = encoder as PngEncoder; // if (pngEncoder != null) // { // pngEncoder = new PngEncoder(); // encoder = pngEncoder; // pngEncoder.CompressionLevel = 9; // if (grayscale) // { // pngEncoder.PngColorType = PngColorType.Grayscale; // } // } // return encoder; //} internal string GetTestOutputDir() { string testGroupName = Path.GetFileNameWithoutExtension(this.TestGroupName); return TestEnvironment.CreateOutputDirectory(testGroupName); } public static void ModifyPixel(Image img, int x, int y, byte perChannelChange) where TPixel : struct, IPixel { ModifyPixel((ImageFrame)img, x, y, perChannelChange); } public static void ModifyPixel(ImageFrame img, int x, int y, byte perChannelChange) where TPixel : struct, IPixel { TPixel pixel = img[x, y]; var rgbaPixel = default(Rgba32); pixel.ToRgba32(ref rgbaPixel); if (rgbaPixel.R + perChannelChange <= 255) { rgbaPixel.R += perChannelChange; } else { rgbaPixel.R -= perChannelChange; } if (rgbaPixel.G + perChannelChange <= 255) { rgbaPixel.G += perChannelChange; } else { rgbaPixel.G -= perChannelChange; } if (rgbaPixel.B + perChannelChange <= 255) { rgbaPixel.B += perChannelChange; } else { rgbaPixel.B -= perChannelChange; } if (rgbaPixel.A + perChannelChange <= 255) { rgbaPixel.A += perChannelChange; } else { rgbaPixel.A -= perChannelChange; } pixel.PackFromRgba32(rgbaPixel); img[x, y] = pixel; } } }