| 
					
				 | 
			
			
				@@ -13,6 +13,9 @@ using static Jellyfin.Drawing.Skia.SkiaHelper; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 namespace Jellyfin.Drawing.Skia 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// Image encoder that uses <see cref="SkiaSharp"/> to manipulate images. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     public class SkiaEncoder : IImageEncoder 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private readonly ILogger _logger; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -22,6 +25,12 @@ namespace Jellyfin.Drawing.Skia 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private static readonly HashSet<string> _transparentImageTypes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { ".png", ".gif", ".webp" }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Initializes a new instance of the <see cref="SkiaEncoder"/> class. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="logger">The application logger.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="appPaths">The application paths.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="localizationManager">The application localization manager.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public SkiaEncoder( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             ILogger<SkiaEncoder> logger, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             IApplicationPaths appPaths, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -32,12 +41,16 @@ namespace Jellyfin.Drawing.Skia 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _localizationManager = localizationManager; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public string Name => "Skia"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public bool SupportsImageCollageCreation => true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public bool SupportsImageEncoding => true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public IReadOnlyCollection<string> SupportedInputFormats => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             new HashSet<string>(StringComparer.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -65,11 +78,12 @@ namespace Jellyfin.Drawing.Skia 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 "arw" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public IReadOnlyCollection<ImageFormat> SupportedOutputFormats 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             => new HashSet<ImageFormat>() { ImageFormat.Webp, ImageFormat.Jpg, ImageFormat.Png }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// Test to determine if the native lib is available 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Test to determine if the native lib is available. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public static void TestSkia() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -80,6 +94,11 @@ namespace Jellyfin.Drawing.Skia 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private static bool IsTransparent(SKColor color) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             => (color.Red == 255 && color.Green == 255 && color.Blue == 255) || color.Alpha == 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Convert a <see cref="ImageFormat"/> to a <see cref="SKEncodedImageFormat"/>. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="selectedFormat">The format to convert.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <returns>The converted format.</returns> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public static SKEncodedImageFormat GetImageFormat(ImageFormat selectedFormat) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             switch (selectedFormat) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -186,6 +205,9 @@ namespace Jellyfin.Drawing.Skia 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <inheritdoc /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <exception cref="ArgumentNullException">The path is null.</exception> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <exception cref="FileNotFoundException">The path is not valid.</exception> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <exception cref="SkiaCodecException">The file at the specified path could not be used to generate a codec.</exception> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public ImageDimensions GetImageSize(string path) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (path == null) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -269,6 +291,14 @@ namespace Jellyfin.Drawing.Skia 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Decode an image. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="path">The filepath of the image to decode.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="forceCleanBitmap">Whether to force clean the bitmap.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="orientation">The orientation of the image.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="origin">The detected origin of the image.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <returns>The resulting bitmap of the image.</returns> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         internal SKBitmap Decode(string path, bool forceCleanBitmap, ImageOrientation? orientation, out SKEncodedOrigin origin) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (!File.Exists(path)) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -358,16 +388,6 @@ namespace Jellyfin.Drawing.Skia 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private SKBitmap OrientImage(SKBitmap bitmap, SKEncodedOrigin origin) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            //var transformations = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            //    2: { rotate: 0, flip: true}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            //    3: { rotate: 180, flip: false}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            //    4: { rotate: 180, flip: true}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            //    5: { rotate: 90, flip: true}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            //    6: { rotate: 90, flip: false}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            //    7: { rotate: 270, flip: true}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            //    8: { rotate: 270, flip: false}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            //} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             switch (origin) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 case SKEncodedOrigin.TopRight: 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -497,6 +517,7 @@ namespace Jellyfin.Drawing.Skia 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (string.IsNullOrWhiteSpace(inputPath)) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -520,7 +541,7 @@ namespace Jellyfin.Drawing.Skia 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 if (bitmap == null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    throw new ArgumentOutOfRangeException(string.Format("Skia unable to read image {0}", inputPath)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    throw new ArgumentOutOfRangeException($"Skia unable to read image {inputPath}"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 var originalImageSize = new ImageDimensions(bitmap.Width, bitmap.Height); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -556,7 +577,7 @@ namespace Jellyfin.Drawing.Skia 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     // create bitmap to use for canvas drawing used to draw into bitmap 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    using (var saveBitmap = new SKBitmap(width, height))//, bitmap.ColorType, bitmap.AlphaType)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    using (var saveBitmap = new SKBitmap(width, height)) // , bitmap.ColorType, bitmap.AlphaType)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     using (var canvas = new SKCanvas(saveBitmap)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         // set background color if present 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -609,9 +630,11 @@ namespace Jellyfin.Drawing.Skia 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return outputPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public void CreateImageCollage(ImageCollageOptions options) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             double ratio = (double)options.Width / options.Height; 
			 |