using System ;
namespace UMC.ITME
{
using System ;
using System.Collections.Generic ;
using System.Diagnostics ;
using System.IO ;
using System.Runtime.InteropServices ;
using System.Threading.Tasks ;
/// <summary>
/// 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
/// </summary>
public static class AvifConverter
{
/// <summary>
/// Converts PNG/JPEG to AVIF format.
/// </summary>
public static Task < AvifConvertResult > 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 < string > list = new List < string > ( 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 < AvifConvertResult > RunEncodeProcessAsync ( string aviflibExe , string arguments )
{
TaskCompletionSource < AvifConvertResult > tcs = new TaskCompletionSource < AvifConvertResult > ( ) ;
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 ;
}
}
/// <summary>
/// Read more about options here:
/// https://github.com/kornelski/cavif-rs
/// </summary>
public class AvifConverterOptions
{
/// <summary>
/// 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.
/// </summary>
public int? Quality { get ; set ; }
/// <summary>
/// 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.
/// </summary>
public int? Speed { get ; set ; }
/// <summary>
/// Replace files if there's .avif already. By default the existing files are overwritten.
/// </summary>
public bool Overwrite { get ; set ; } = true ;
/// <summary>
/// Preserve RGB values of fully transparent pixels (not recommended). By default irrelevant color of transparent pixels is cleared to avoid wasting space.
/// </summary>
public bool? DirtyAlpha { get ; set ; }
/// <summary>
/// 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.
/// </summary>
public bool? ColorRgb { get ; set ; }
/// <summary>
/// Generate output message
/// </summary>
public bool EmitMesage { get ; set ; }
}
}