// 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}";
}
private static string Inv(FormattableString formattable) => System.FormattableString.Invariant(formattable);
///
/// 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 = Inv($"{testOutputDetails}");
}
else
{
IEnumerable properties = testOutputDetails.GetType().GetRuntimeProperties();
detailsString = string.Join(
"_",
properties.ToDictionary(x => x.Name, x => x.GetValue(testOutputDetails))
.Select(x => Inv($"{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;
}
}
}