using System; namespace UMC.Proxy { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Threading.Tasks; /// /// A executer for `cavif` which is a Encoder/converter for AVIF images. /// Please have the native `cavif` libraries next to your application. /// Grab prebuilt `cavif` from here: https://github.com/kornelski/cavif-rs/releases /// public static class AvifConverter { /// /// Converts PNG/JPEG to AVIF format. /// public static Task EncodeImage(string imageFile, string outputImageFile = null, AvifConverterOptions options = null) { string converterPath = GetConverterPath(); string arguments = GenerateArgument(imageFile, outputImageFile, options); return RunEncodeProcessAsync(converterPath, arguments); } private static string GenerateArgument(string imageFile, string outputImage = null, AvifConverterOptions options = null) { List list = new List(8); if (options != null) { if (!options!.EmitMesage) { list.Add("--quiet"); } if (options!.Overwrite) { list.Add("--overwrite"); } if (options!.Speed.HasValue) { list.Add("--speed " + options!.Speed.Value); } if (options!.Quality.HasValue) { list.Add("--quality " + options!.Quality.Value); } if (options!.ColorRgb == true) { list.Add("--color rgb"); } if (options!.DirtyAlpha == true) { list.Add("--dirty-alpha"); } } else { list.Add("--quiet"); list.Add("--overwrite"); } if (outputImage != null) { list.Add("-o \"" + outputImage + "\""); } list.Add("\"" + imageFile + "\""); return string.Join(" ", list); } private static string GetConverterPath() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { return ".\\native\\cavif.exe"; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { return "./native/cavif"; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { return "./native/cavif"; } else { throw new PlatformNotSupportedException(); } } private static Task RunEncodeProcessAsync(string aviflibExe, string arguments) { TaskCompletionSource tcs = new TaskCompletionSource(); try { Process process = new Process { StartInfo = { FileName = aviflibExe, Arguments = arguments, WindowStyle = ProcessWindowStyle.Hidden, UseShellExecute = false, RedirectStandardOutput = true, CreateNoWindow = true }, EnableRaisingEvents = true }; process.Exited += delegate { string text = ""; while (!process.StandardOutput.EndOfStream) { text = text + process.StandardOutput.ReadLine() + Environment.NewLine; } bool success = process.ExitCode == 0; tcs.SetResult(new AvifConvertResult(success, text)); process.Dispose(); }; process.Start(); } catch (Exception ex) { return Task.FromResult(new AvifConvertResult(success: false, ex.Message)); } return tcs.Task; } } public class AvifConvertResult { public bool Success { get; } public string Message { get; } = string.Empty; public AvifConvertResult() { } public AvifConvertResult(bool success) { Success = success; } public AvifConvertResult(bool success, string message) { Success = success; Message = message; } } /// /// Read more about options here: /// https://github.com/kornelski/cavif-rs /// public class AvifConverterOptions { /// /// Quality from 1 (worst) to 100 (best), the default value is 80. The numbers have different meaning than JPEG's quality scale. Beware when comparing codecs. There is no lossless compression support. /// public int? Quality { get; set; } /// /// Encoding speed between 1 (best, but slowest) and 10 (fastest, but a blurry mess), the default value is 4. Speeds 1 and 2 are unbelievably slow, but make files ~3-5% smaller. Speeds 7 and above degrade compression significantly, and are not recommended. /// public int? Speed { get; set; } /// /// Replace files if there's .avif already. By default the existing files are overwritten. /// public bool Overwrite { get; set; } = true; /// /// Preserve RGB values of fully transparent pixels (not recommended). By default irrelevant color of transparent pixels is cleared to avoid wasting space. /// public bool? DirtyAlpha { get; set; } /// /// Encode using RGB instead of YCbCr color space. Makes colors closer to lossless, but makes files larger. Use only if you need to avoid even smallest color shifts. /// public bool? ColorRgb { get; set; } /// /// Generate output message /// public bool EmitMesage { get; set; } } }