Browse Source

Simplify image processing by removing image enhancers

Bond_009 5 năm trước cách đây
mục cha
commit
ddf9b38799

+ 12 - 0
Emby.Drawing/Emby.Drawing.csproj

@@ -17,4 +17,16 @@
     <Compile Include="..\SharedVersion.cs" />
   </ItemGroup>
 
+  <!-- Code analysers-->
+  <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
+    <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
+    <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
+    <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
+    <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
+  </ItemGroup>
+
+  <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+    <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+
 </Project>

+ 34 - 315
Emby.Drawing/ImageProcessor.cs

@@ -3,7 +3,6 @@ using System.Collections.Generic;
 using System.Globalization;
 using System.IO;
 using System.Linq;
-using System.Threading;
 using System.Threading.Tasks;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller;
@@ -11,10 +10,8 @@ using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Net;
 using Microsoft.Extensions.Logging;
@@ -24,7 +21,7 @@ namespace Emby.Drawing
     /// <summary>
     /// Class ImageProcessor.
     /// </summary>
-    public class ImageProcessor : IImageProcessor, IDisposable
+    public sealed class ImageProcessor : IImageProcessor, IDisposable
     {
         // Increment this when there's a change requiring caches to be invalidated
         private const string Version = "3";
@@ -32,28 +29,24 @@ namespace Emby.Drawing
         private static readonly HashSet<string> _transparentImageTypes
             = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { ".png", ".webp", ".gif" };
 
-        /// <summary>
-        /// The _logger
-        /// </summary>
         private readonly ILogger _logger;
         private readonly IFileSystem _fileSystem;
         private readonly IServerApplicationPaths _appPaths;
-        private IImageEncoder _imageEncoder;
+        private readonly IImageEncoder _imageEncoder;
         private readonly Func<ILibraryManager> _libraryManager;
         private readonly Func<IMediaEncoder> _mediaEncoder;
 
-        private readonly Dictionary<string, LockInfo> _locks = new Dictionary<string, LockInfo>();
         private bool _disposed = false;
 
         /// <summary>
-        ///
+        /// Initializes a new instance of the <see cref="ImageProcessor"/> class.
         /// </summary>
-        /// <param name="logger"></param>
-        /// <param name="appPaths"></param>
-        /// <param name="fileSystem"></param>
-        /// <param name="imageEncoder"></param>
-        /// <param name="libraryManager"></param>
-        /// <param name="mediaEncoder"></param>
+        /// <param name="logger">The logger.</param>
+        /// <param name="appPaths">The server application paths.</param>
+        /// <param name="fileSystem">The filesystem.</param>
+        /// <param name="imageEncoder">The image encoder.</param>
+        /// <param name="libraryManager">The library manager.</param>
+        /// <param name="mediaEncoder">The media encoder.</param>
         public ImageProcessor(
             ILogger<ImageProcessor> logger,
             IServerApplicationPaths appPaths,
@@ -68,16 +61,10 @@ namespace Emby.Drawing
             _libraryManager = libraryManager;
             _mediaEncoder = mediaEncoder;
             _appPaths = appPaths;
-
-            ImageEnhancers = Array.Empty<IImageEnhancer>();
-
-            ImageHelper.ImageProcessor = this;
         }
 
         private string ResizedImageCachePath => Path.Combine(_appPaths.ImageCachePath, "resized-images");
 
-        private string EnhancedImageCachePath => Path.Combine(_appPaths.ImageCachePath, "enhanced-images");
-
         /// <inheritdoc />
         public IReadOnlyCollection<string> SupportedInputFormats =>
             new HashSet<string>(StringComparer.OrdinalIgnoreCase)
@@ -90,9 +77,7 @@ namespace Emby.Drawing
                 "aiff",
                 "cr2",
                 "crw",
-
-                // Remove until supported
-                //"nef",
+                "nef",
                 "orf",
                 "pef",
                 "arw",
@@ -111,19 +96,9 @@ namespace Emby.Drawing
                 "wbmp"
             };
 
-        /// <inheritdoc />
-        public IReadOnlyCollection<IImageEnhancer> ImageEnhancers { get; set; }
-
         /// <inheritdoc />
         public bool SupportsImageCollageCreation => _imageEncoder.SupportsImageCollageCreation;
 
-        /// <inheritdoc />
-        public IImageEncoder ImageEncoder
-        {
-            get => _imageEncoder;
-            set => _imageEncoder = value ?? throw new ArgumentNullException(nameof(value));
-        }
-
         /// <inheritdoc />
         public async Task ProcessImage(ImageProcessingOptions options, Stream toStream)
         {
@@ -151,6 +126,8 @@ namespace Emby.Drawing
                 throw new ArgumentNullException(nameof(options));
             }
 
+            var libraryManager = _libraryManager();
+
             ItemImageInfo originalImage = options.Image;
             BaseItem item = options.Item;
 
@@ -158,9 +135,10 @@ namespace Emby.Drawing
             {
                 if (item == null)
                 {
-                    item = _libraryManager().GetItemById(options.ItemId);
+                    item = libraryManager.GetItemById(options.ItemId);
                 }
-                originalImage = await _libraryManager().ConvertImageToLocal(item, originalImage, options.ImageIndex).ConfigureAwait(false);
+
+                originalImage = await libraryManager.ConvertImageToLocal(item, originalImage, options.ImageIndex).ConfigureAwait(false);
             }
 
             string originalImagePath = originalImage.Path;
@@ -187,27 +165,6 @@ namespace Emby.Drawing
             dateModified = supportedImageInfo.dateModified;
             bool requiresTransparency = _transparentImageTypes.Contains(Path.GetExtension(originalImagePath));
 
-            if (options.Enhancers.Count > 0)
-            {
-                if (item == null)
-                {
-                    item = _libraryManager().GetItemById(options.ItemId);
-                }
-
-                var tuple = await GetEnhancedImage(new ItemImageInfo
-                {
-                    DateModified = dateModified,
-                    Type = originalImage.Type,
-                    Path = originalImagePath
-                }, requiresTransparency, item, options.ImageIndex, options.Enhancers, CancellationToken.None).ConfigureAwait(false);
-
-                originalImagePath = tuple.path;
-                dateModified = tuple.dateModified;
-                requiresTransparency = tuple.transparent;
-                // TODO: Get this info
-                originalImageSize = null;
-            }
-
             bool autoOrient = false;
             ImageOrientation? orientation = null;
             if (item is Photo photo)
@@ -240,12 +197,6 @@ namespace Emby.Drawing
             ImageFormat outputFormat = GetOutputFormat(options.SupportedOutputFormats, requiresTransparency);
             string cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.Blur, options.BackgroundColor, options.ForegroundLayer);
 
-            CheckDisposed();
-
-            LockInfo lockInfo = GetLock(cacheFilePath);
-
-            await lockInfo.Lock.WaitAsync().ConfigureAwait(false);
-
             try
             {
                 if (!File.Exists(cacheFilePath))
@@ -271,10 +222,6 @@ namespace Emby.Drawing
                 _logger.LogError(ex, "Error encoding image");
                 return (originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
             }
-            finally
-            {
-                ReleaseLock(cacheFilePath, lockInfo);
-            }
         }
 
         private ImageFormat GetOutputFormat(IReadOnlyCollection<ImageFormat> clientSupportedFormats, bool requiresTransparency)
@@ -306,20 +253,18 @@ namespace Emby.Drawing
         }
 
         private string GetMimeType(ImageFormat format, string path)
-        {
-            switch(format)
-            {
-                case ImageFormat.Bmp:  return MimeTypes.GetMimeType("i.bmp");
-                case ImageFormat.Gif:  return MimeTypes.GetMimeType("i.gif");
-                case ImageFormat.Jpg:  return MimeTypes.GetMimeType("i.jpg");
-                case ImageFormat.Png:  return MimeTypes.GetMimeType("i.png");
-                case ImageFormat.Webp: return MimeTypes.GetMimeType("i.webp");
-                default:               return MimeTypes.GetMimeType(path);
-            }
-        }
+            => format switch
+            {
+                ImageFormat.Bmp => MimeTypes.GetMimeType("i.bmp"),
+                ImageFormat.Gif => MimeTypes.GetMimeType("i.gif"),
+                ImageFormat.Jpg => MimeTypes.GetMimeType("i.jpg"),
+                ImageFormat.Png => MimeTypes.GetMimeType("i.png"),
+                ImageFormat.Webp => MimeTypes.GetMimeType("i.webp"),
+                _ => MimeTypes.GetMimeType(path)
+            };
 
         /// <summary>
-        /// Gets the cache file path based on a set of parameters
+        /// Gets the cache file path based on a set of parameters.
         /// </summary>
         private string GetCacheFilePath(string originalPath, ImageDimensions outputSize, int quality, DateTime dateModified, ImageFormat format, bool addPlayedIndicator, double percentPlayed, int? unwatchedCount, int? blur, string backgroundColor, string foregroundLayer)
         {
@@ -401,11 +346,7 @@ namespace Emby.Drawing
 
         /// <inheritdoc />
         public string GetImageCacheTag(BaseItem item, ItemImageInfo image)
-        {
-            var supportedEnhancers = GetSupportedEnhancers(item, image.Type).ToArray();
-
-            return GetImageCacheTag(item, image, supportedEnhancers);
-        }
+            => (item.Path + image.DateModified.Ticks).GetMD5().ToString("N", CultureInfo.InvariantCulture);
 
         /// <inheritdoc />
         public string GetImageCacheTag(BaseItem item, ChapterInfo chapter)
@@ -425,26 +366,6 @@ namespace Emby.Drawing
             }
         }
 
-        /// <inheritdoc />
-        public string GetImageCacheTag(BaseItem item, ItemImageInfo image, IReadOnlyCollection<IImageEnhancer> imageEnhancers)
-        {
-            string originalImagePath = image.Path;
-            DateTime dateModified = image.DateModified;
-            ImageType imageType = image.Type;
-
-            // Optimization
-            if (imageEnhancers.Count == 0)
-            {
-                return (originalImagePath + dateModified.Ticks).GetMD5().ToString("N", CultureInfo.InvariantCulture);
-            }
-
-            // Cache name is created with supported enhancers combined with the last config change so we pick up new config changes
-            var cacheKeys = imageEnhancers.Select(i => i.GetConfigurationCacheKey(item, imageType)).ToList();
-            cacheKeys.Add(originalImagePath + dateModified.Ticks);
-
-            return string.Join("|", cacheKeys).GetMD5().ToString("N", CultureInfo.InvariantCulture);
-        }
-
         private async Task<(string path, DateTime dateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified)
         {
             var inputFormat = Path.GetExtension(originalImagePath)
@@ -488,154 +409,6 @@ namespace Emby.Drawing
             return (originalImagePath, dateModified);
         }
 
-        /// <inheritdoc />
-        public async Task<string> GetEnhancedImage(BaseItem item, ImageType imageType, int imageIndex)
-        {
-            var enhancers = GetSupportedEnhancers(item, imageType).ToArray();
-
-            ItemImageInfo imageInfo = item.GetImageInfo(imageType, imageIndex);
-
-            bool inputImageSupportsTransparency = SupportsTransparency(imageInfo.Path);
-
-            var result = await GetEnhancedImage(imageInfo, inputImageSupportsTransparency, item, imageIndex, enhancers, CancellationToken.None);
-
-            return result.path;
-        }
-
-        private async Task<(string path, DateTime dateModified, bool transparent)> GetEnhancedImage(
-            ItemImageInfo image,
-            bool inputImageSupportsTransparency,
-            BaseItem item,
-            int imageIndex,
-            IReadOnlyCollection<IImageEnhancer> enhancers,
-            CancellationToken cancellationToken)
-        {
-            var originalImagePath = image.Path;
-            var dateModified = image.DateModified;
-            var imageType = image.Type;
-
-            try
-            {
-                var cacheGuid = GetImageCacheTag(item, image, enhancers);
-
-                // Enhance if we have enhancers
-                var enhancedImageInfo = await GetEnhancedImageInternal(originalImagePath, item, imageType, imageIndex, enhancers, cacheGuid, cancellationToken).ConfigureAwait(false);
-
-                string enhancedImagePath = enhancedImageInfo.path;
-
-                // If the path changed update dateModified
-                if (!string.Equals(enhancedImagePath, originalImagePath, StringComparison.OrdinalIgnoreCase))
-                {
-                    var treatmentRequiresTransparency = enhancedImageInfo.transparent;
-
-                    return (enhancedImagePath, _fileSystem.GetLastWriteTimeUtc(enhancedImagePath), treatmentRequiresTransparency);
-                }
-            }
-            catch (Exception ex)
-            {
-                _logger.LogError(ex, "Error enhancing image");
-            }
-
-            return (originalImagePath, dateModified, inputImageSupportsTransparency);
-        }
-
-        /// <summary>
-        /// Gets the enhanced image internal.
-        /// </summary>
-        /// <param name="originalImagePath">The original image path.</param>
-        /// <param name="item">The item.</param>
-        /// <param name="imageType">Type of the image.</param>
-        /// <param name="imageIndex">Index of the image.</param>
-        /// <param name="supportedEnhancers">The supported enhancers.</param>
-        /// <param name="cacheGuid">The cache unique identifier.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task&lt;System.String&gt;.</returns>
-        /// <exception cref="ArgumentNullException">
-        /// originalImagePath
-        /// or
-        /// item
-        /// </exception>
-        private async Task<(string path, bool transparent)> GetEnhancedImageInternal(
-            string originalImagePath,
-            BaseItem item,
-            ImageType imageType,
-            int imageIndex,
-            IReadOnlyCollection<IImageEnhancer> supportedEnhancers,
-            string cacheGuid,
-            CancellationToken cancellationToken = default)
-        {
-            if (string.IsNullOrEmpty(originalImagePath))
-            {
-                throw new ArgumentNullException(nameof(originalImagePath));
-            }
-
-            if (item == null)
-            {
-                throw new ArgumentNullException(nameof(item));
-            }
-
-            var treatmentRequiresTransparency = false;
-            foreach (var enhancer in supportedEnhancers)
-            {
-                if (!treatmentRequiresTransparency)
-                {
-                    treatmentRequiresTransparency = enhancer.GetEnhancedImageInfo(item, originalImagePath, imageType, imageIndex).RequiresTransparency;
-                }
-            }
-
-            // All enhanced images are saved as png to allow transparency
-            string cacheExtension = _imageEncoder.SupportedOutputFormats.Contains(ImageFormat.Webp) ?
-                ".webp" :
-                (treatmentRequiresTransparency ? ".png" : ".jpg");
-
-            string enhancedImagePath = GetCachePath(EnhancedImageCachePath, cacheGuid + cacheExtension);
-
-            LockInfo lockInfo = GetLock(enhancedImagePath);
-
-            await lockInfo.Lock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
-            try
-            {
-                // Check again in case of contention
-                if (File.Exists(enhancedImagePath))
-                {
-                    return (enhancedImagePath, treatmentRequiresTransparency);
-                }
-
-                Directory.CreateDirectory(Path.GetDirectoryName(enhancedImagePath));
-
-                await ExecuteImageEnhancers(supportedEnhancers, originalImagePath, enhancedImagePath, item, imageType, imageIndex).ConfigureAwait(false);
-
-                return (enhancedImagePath, treatmentRequiresTransparency);
-            }
-            finally
-            {
-                ReleaseLock(enhancedImagePath, lockInfo);
-            }
-        }
-
-        /// <summary>
-        /// Executes the image enhancers.
-        /// </summary>
-        /// <param name="imageEnhancers">The image enhancers.</param>
-        /// <param name="inputPath">The input path.</param>
-        /// <param name="outputPath">The output path.</param>
-        /// <param name="item">The item.</param>
-        /// <param name="imageType">Type of the image.</param>
-        /// <param name="imageIndex">Index of the image.</param>
-        /// <returns>Task{EnhancedImage}.</returns>
-        private static async Task ExecuteImageEnhancers(IEnumerable<IImageEnhancer> imageEnhancers, string inputPath, string outputPath, BaseItem item, ImageType imageType, int imageIndex)
-        {
-            // Run the enhancers sequentially in order of priority
-            foreach (var enhancer in imageEnhancers)
-            {
-                await enhancer.EnhanceImageAsync(item, inputPath, outputPath, imageType, imageIndex).ConfigureAwait(false);
-
-                // Feed the output into the next enhancer as input
-                inputPath = outputPath;
-            }
-        }
-
         /// <summary>
         /// Gets the cache path.
         /// </summary>
@@ -648,7 +421,7 @@ namespace Emby.Drawing
         /// or
         /// uniqueName
         /// or
-        /// fileExtension
+        /// fileExtension.
         /// </exception>
         public string GetCachePath(string path, string uniqueName, string fileExtension)
         {
@@ -681,7 +454,7 @@ namespace Emby.Drawing
         /// <exception cref="ArgumentNullException">
         /// path
         /// or
-        /// filename
+        /// filename.
         /// </exception>
         public string GetCachePath(string path, string filename)
         {
@@ -689,6 +462,7 @@ namespace Emby.Drawing
             {
                 throw new ArgumentNullException(nameof(path));
             }
+
             if (string.IsNullOrEmpty(filename))
             {
                 throw new ArgumentNullException(nameof(filename));
@@ -710,74 +484,19 @@ namespace Emby.Drawing
         }
 
         /// <inheritdoc />
-        public IEnumerable<IImageEnhancer> GetSupportedEnhancers(BaseItem item, ImageType imageType)
-        {
-            foreach (var i in ImageEnhancers)
-            {
-                if (i.Supports(item, imageType))
-                {
-                    yield return i;
-                }
-            }
-        }
-
-
-        private class LockInfo
-        {
-            public SemaphoreSlim Lock = new SemaphoreSlim(1, 1);
-            public int Count = 1;
-        }
-
-        private LockInfo GetLock(string key)
-        {
-            lock (_locks)
-            {
-                if (_locks.TryGetValue(key, out LockInfo info))
-                {
-                    info.Count++;
-                }
-                else
-                {
-                    info = new LockInfo();
-                    _locks[key] = info;
-                }
-                return info;
-            }
-        }
-
-        private void ReleaseLock(string key, LockInfo info)
+        public void Dispose()
         {
-            info.Lock.Release();
-
-            lock (_locks)
+            if (_disposed)
             {
-                info.Count--;
-                if (info.Count <= 0)
-                {
-                    _locks.Remove(key);
-                    info.Lock.Dispose();
-                }
+                return;
             }
-        }
-
-        /// <inheritdoc />
-        public void Dispose()
-        {
-            _disposed = true;
 
-            var disposable = _imageEncoder as IDisposable;
-            if (disposable != null)
+            if (_imageEncoder is IDisposable disposable)
             {
                 disposable.Dispose();
             }
-        }
 
-        private void CheckDisposed()
-        {
-            if (_disposed)
-            {
-                throw new ObjectDisposedException(GetType().Name);
-            }
+            _disposed = true;
         }
     }
 }

+ 0 - 2
Emby.Server.Implementations/ApplicationHost.cs

@@ -1074,8 +1074,6 @@ namespace Emby.Server.Implementations
                 GetExports<IMetadataSaver>(),
                 GetExports<IExternalId>());
 
-            ImageProcessor.ImageEnhancers = GetExports<IImageEnhancer>();
-
             LiveTvManager.AddParts(GetExports<ILiveTvService>(), GetExports<ITunerHost>(), GetExports<IListingsProvider>());
 
             SubtitleManager.AddParts(GetExports<ISubtitleProvider>());

+ 12 - 35
Emby.Server.Implementations/Dto/DtoService.cs

@@ -1362,56 +1362,33 @@ namespace Emby.Server.Implementations.Dto
                 return null;
             }
 
-            var supportedEnhancers = _imageProcessor.GetSupportedEnhancers(item, ImageType.Primary).ToArray();
-
             ImageDimensions size;
 
             var defaultAspectRatio = item.GetDefaultPrimaryImageAspectRatio();
 
             if (defaultAspectRatio > 0)
             {
-                if (supportedEnhancers.Length == 0)
-                {
-                    return defaultAspectRatio;
-                }
+                return defaultAspectRatio;
+            }
 
-                int dummyWidth = 200;
-                int dummyHeight = Convert.ToInt32(dummyWidth / defaultAspectRatio);
-                size = new ImageDimensions(dummyWidth, dummyHeight);
+            if (!imageInfo.IsLocalFile)
+            {
+                return null;
             }
-            else
+
+            try
             {
-                if (!imageInfo.IsLocalFile)
-                {
-                    return null;
-                }
+                size = _imageProcessor.GetImageDimensions(item, imageInfo);
 
-                try
+                if (size.Width <= 0 || size.Height <= 0)
                 {
-                    size = _imageProcessor.GetImageDimensions(item, imageInfo);
-
-                    if (size.Width <= 0 || size.Height <= 0)
-                    {
-                        return null;
-                    }
-                }
-                catch (Exception ex)
-                {
-                    _logger.LogError(ex, "Failed to determine primary image aspect ratio for {0}", imageInfo.Path);
                     return null;
                 }
             }
-
-            foreach (var enhancer in supportedEnhancers)
+            catch (Exception ex)
             {
-                try
-                {
-                    size = enhancer.GetEnhancedImageSize(item, ImageType.Primary, 0, size);
-                }
-                catch (Exception ex)
-                {
-                    _logger.LogError(ex, "Error in image enhancer: {0}", enhancer.GetType().Name);
-                }
+                _logger.LogError(ex, "Failed to determine primary image aspect ratio for {0}", imageInfo.Path);
+                return null;
             }
 
             var width = size.Width;

+ 9 - 11
Jellyfin.Drawing.Skia/SkiaEncoder.cs

@@ -6,7 +6,6 @@ using MediaBrowser.Common.Configuration;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Extensions;
 using MediaBrowser.Model.Drawing;
-using MediaBrowser.Model.Globalization;
 using Microsoft.Extensions.Logging;
 using SkiaSharp;
 using static Jellyfin.Drawing.Skia.SkiaHelper;
@@ -18,27 +17,23 @@ namespace Jellyfin.Drawing.Skia
     /// </summary>
     public class SkiaEncoder : IImageEncoder
     {
-        private readonly ILogger _logger;
-        private readonly IApplicationPaths _appPaths;
-        private readonly ILocalizationManager _localizationManager;
-
         private static readonly HashSet<string> _transparentImageTypes
             = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { ".png", ".gif", ".webp" };
 
+        private readonly ILogger _logger;
+        private readonly IApplicationPaths _appPaths;
+
         /// <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,
-            ILocalizationManager localizationManager)
+            IApplicationPaths appPaths)
         {
             _logger = logger;
             _appPaths = appPaths;
-            _localizationManager = localizationManager;
         }
 
         /// <inheritdoc/>
@@ -235,9 +230,12 @@ namespace Jellyfin.Drawing.Skia
 
         private bool RequiresSpecialCharacterHack(string path)
         {
-            if (_localizationManager.HasUnicodeCategory(path, UnicodeCategory.OtherLetter))
+            for (int i = 0; i < path.Length; i++)
             {
-                return true;
+                if (char.GetUnicodeCategory(path[i]) == UnicodeCategory.OtherLetter)
+                {
+                    return true;
+                }
             }
 
             if (HasDiacritics(path))

+ 3 - 8
Jellyfin.Server/Program.cs

@@ -169,7 +169,7 @@ namespace Jellyfin.Server
                 _loggerFactory,
                 options,
                 new ManagedFileSystem(_loggerFactory.CreateLogger<ManagedFileSystem>(), appPaths),
-                new NullImageEncoder(),
+                GetImageEncoder(appPaths),
                 new NetworkManager(_loggerFactory.CreateLogger<NetworkManager>()),
                 appConfig);
             try
@@ -193,8 +193,6 @@ namespace Jellyfin.Server
                     throw;
                 }
 
-                appHost.ImageProcessor.ImageEncoder = GetImageEncoder(appPaths, appHost.LocalizationManager);
-
                 await appHost.RunStartupTasksAsync().ConfigureAwait(false);
 
                 stopWatch.Stop();
@@ -494,9 +492,7 @@ namespace Jellyfin.Server
             }
         }
 
-        private static IImageEncoder GetImageEncoder(
-            IApplicationPaths appPaths,
-            ILocalizationManager localizationManager)
+        private static IImageEncoder GetImageEncoder(IApplicationPaths appPaths)
         {
             try
             {
@@ -505,8 +501,7 @@ namespace Jellyfin.Server
 
                 return new SkiaEncoder(
                     _loggerFactory.CreateLogger<SkiaEncoder>(),
-                    appPaths,
-                    localizationManager);
+                    appPaths);
             }
             catch (Exception ex)
             {

+ 5 - 21
MediaBrowser.Api/Images/ImageService.cs

@@ -24,7 +24,7 @@ using Microsoft.Net.Http.Headers;
 namespace MediaBrowser.Api.Images
 {
     /// <summary>
-    /// Class GetItemImage
+    /// Class GetItemImage.
     /// </summary>
     [Route("/Items/{Id}/Images", "GET", Summary = "Gets information about an item's images")]
     [Authenticated]
@@ -558,21 +558,6 @@ namespace MediaBrowser.Api.Images
                 throw new ResourceNotFoundException(string.Format("{0} does not have an image of type {1}", displayText, request.Type));
             }
 
-            IImageEnhancer[] supportedImageEnhancers;
-            if (_imageProcessor.ImageEnhancers.Count > 0)
-            {
-                if (item == null)
-                {
-                    item = _libraryManager.GetItemById(itemId);
-                }
-
-                supportedImageEnhancers = request.EnableImageEnhancers ? _imageProcessor.GetSupportedEnhancers(item, request.Type).ToArray() : Array.Empty<IImageEnhancer>();
-            }
-            else
-            {
-                supportedImageEnhancers = Array.Empty<IImageEnhancer>();
-            }
-
             bool cropwhitespace;
             if (request.CropWhitespace.HasValue)
             {
@@ -598,25 +583,25 @@ namespace MediaBrowser.Api.Images
                 {"realTimeInfo.dlna.org", "DLNA.ORG_TLAG=*"}
             };
 
-            return GetImageResult(item,
+            return GetImageResult(
+                item,
                 itemId,
                 request,
                 imageInfo,
                 cropwhitespace,
                 outputFormats,
-                supportedImageEnhancers,
                 cacheDuration,
                 responseHeaders,
                 isHeadRequest);
         }
 
-        private async Task<object> GetImageResult(BaseItem item,
+        private async Task<object> GetImageResult(
+            BaseItem item,
             Guid itemId,
             ImageRequest request,
             ItemImageInfo image,
             bool cropwhitespace,
             IReadOnlyCollection<ImageFormat> supportedFormats,
-            IReadOnlyCollection<IImageEnhancer> enhancers,
             TimeSpan? cacheDuration,
             IDictionary<string, string> headers,
             bool isHeadRequest)
@@ -624,7 +609,6 @@ namespace MediaBrowser.Api.Images
             var options = new ImageProcessingOptions
             {
                 CropWhiteSpace = cropwhitespace,
-                Enhancers = enhancers,
                 Height = request.Height,
                 ImageIndex = request.Index ?? 0,
                 Image = image,

+ 0 - 35
MediaBrowser.Controller/Drawing/IImageProcessor.cs

@@ -3,7 +3,6 @@ using System.Collections.Generic;
 using System.IO;
 using System.Threading.Tasks;
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Entities;
 
@@ -20,20 +19,12 @@ namespace MediaBrowser.Controller.Drawing
         /// <value>The supported input formats.</value>
         IReadOnlyCollection<string> SupportedInputFormats { get; }
 
-        /// <summary>
-        /// Gets the image enhancers.
-        /// </summary>
-        /// <value>The image enhancers.</value>
-        IReadOnlyCollection<IImageEnhancer> ImageEnhancers { get; set; }
-
         /// <summary>
         /// Gets a value indicating whether [supports image collage creation].
         /// </summary>
         /// <value><c>true</c> if [supports image collage creation]; otherwise, <c>false</c>.</value>
         bool SupportsImageCollageCreation { get; }
 
-        IImageEncoder ImageEncoder { get; set; }
-
         /// <summary>
         /// Gets the dimensions of the image.
         /// </summary>
@@ -58,14 +49,6 @@ namespace MediaBrowser.Controller.Drawing
         /// <returns>ImageDimensions</returns>
         ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info, bool updateItem);
 
-        /// <summary>
-        /// Gets the supported enhancers.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="imageType">Type of the image.</param>
-        /// <returns>IEnumerable{IImageEnhancer}.</returns>
-        IEnumerable<IImageEnhancer> GetSupportedEnhancers(BaseItem item, ImageType imageType);
-
         /// <summary>
         /// Gets the image cache tag.
         /// </summary>
@@ -75,15 +58,6 @@ namespace MediaBrowser.Controller.Drawing
         string GetImageCacheTag(BaseItem item, ItemImageInfo image);
         string GetImageCacheTag(BaseItem item, ChapterInfo info);
 
-        /// <summary>
-        /// Gets the image cache tag.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="image">The image.</param>
-        /// <param name="imageEnhancers">The image enhancers.</param>
-        /// <returns>Guid.</returns>
-        string GetImageCacheTag(BaseItem item, ItemImageInfo image, IReadOnlyCollection<IImageEnhancer> imageEnhancers);
-
         /// <summary>
         /// Processes the image.
         /// </summary>
@@ -99,15 +73,6 @@ namespace MediaBrowser.Controller.Drawing
         /// <returns>Task.</returns>
         Task<(string path, string mimeType, DateTime dateModified)> ProcessImage(ImageProcessingOptions options);
 
-        /// <summary>
-        /// Gets the enhanced image.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="imageType">Type of the image.</param>
-        /// <param name="imageIndex">Index of the image.</param>
-        /// <returns>Task{System.String}.</returns>
-        Task<string> GetEnhancedImage(BaseItem item, ImageType imageType, int imageIndex);
-
         /// <summary>
         /// Gets the supported image output formats.
         /// </summary>

+ 0 - 2
MediaBrowser.Controller/Drawing/ImageHelper.cs

@@ -19,8 +19,6 @@ namespace MediaBrowser.Controller.Drawing
             return GetSizeEstimate(options);
         }
 
-        public static IImageProcessor ImageProcessor { get; set; }
-
         private static ImageDimensions GetSizeEstimate(ImageProcessingOptions options)
         {
             if (options.Width.HasValue && options.Height.HasValue)

+ 0 - 3
MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs

@@ -3,7 +3,6 @@ using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Drawing;
 
 namespace MediaBrowser.Controller.Drawing
@@ -34,8 +33,6 @@ namespace MediaBrowser.Controller.Drawing
 
         public int Quality { get; set; }
 
-        public IReadOnlyCollection<IImageEnhancer> Enhancers { get; set; }
-
         public IReadOnlyCollection<ImageFormat> SupportedOutputFormats { get; set; }
 
         public bool AddPlayedIndicator { get; set; }

+ 2 - 10
MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs

@@ -316,11 +316,7 @@ namespace MediaBrowser.Controller.MediaEncoding
             {
                 if (VideoStream != null && VideoStream.Width.HasValue && VideoStream.Height.HasValue)
                 {
-                    var size = new ImageDimensions
-                    {
-                        Width = VideoStream.Width.Value,
-                        Height = VideoStream.Height.Value
-                    };
+                    var size = new ImageDimensions(VideoStream.Width.Value, VideoStream.Height.Value);
 
                     var newSize = DrawingUtils.Resize(size,
                         BaseRequest.Width ?? 0,
@@ -346,11 +342,7 @@ namespace MediaBrowser.Controller.MediaEncoding
             {
                 if (VideoStream != null && VideoStream.Width.HasValue && VideoStream.Height.HasValue)
                 {
-                    var size = new ImageDimensions
-                    {
-                        Width = VideoStream.Width.Value,
-                        Height = VideoStream.Height.Value
-                    };
+                    var size = new ImageDimensions(VideoStream.Width.Value, VideoStream.Height.Value);
 
                     var newSize = DrawingUtils.Resize(size,
                         BaseRequest.Width ?? 0,

+ 0 - 61
MediaBrowser.Controller/Providers/IImageEnhancer.cs

@@ -1,61 +0,0 @@
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Drawing;
-using MediaBrowser.Model.Entities;
-
-namespace MediaBrowser.Controller.Providers
-{
-    public interface IImageEnhancer
-    {
-        /// <summary>
-        /// Return true only if the given image for the given item will be enhanced by this enhancer.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="imageType">Type of the image.</param>
-        /// <returns><c>true</c> if this enhancer will enhance the supplied image for the supplied item, <c>false</c> otherwise</returns>
-        bool Supports(BaseItem item, ImageType imageType);
-
-        /// <summary>
-        /// Gets the priority or order in which this enhancer should be run.
-        /// </summary>
-        /// <value>The priority.</value>
-        MetadataProviderPriority Priority { get; }
-
-        /// <summary>
-        /// Return a key incorporating all configuration information related to this item
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="imageType">Type of the image.</param>
-        /// <returns>Cache key relating to the current state of this item and configuration</returns>
-        string GetConfigurationCacheKey(BaseItem item, ImageType imageType);
-
-        /// <summary>
-        /// Gets the size of the enhanced image.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="imageType">Type of the image.</param>
-        /// <param name="imageIndex">Index of the image.</param>
-        /// <param name="originalImageSize">Size of the original image.</param>
-        /// <returns>ImageSize.</returns>
-        ImageDimensions GetEnhancedImageSize(BaseItem item, ImageType imageType, int imageIndex, ImageDimensions originalImageSize);
-
-        EnhancedImageInfo GetEnhancedImageInfo(BaseItem item, string inputFile, ImageType imageType, int imageIndex);
-
-        /// <summary>
-        /// Enhances the image async.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="inputFile">The input file.</param>
-        /// <param name="outputFile">The output file.</param>
-        /// <param name="imageType">Type of the image.</param>
-        /// <param name="imageIndex">Index of the image.</param>
-        /// <returns>Task{Image}.</returns>
-        /// <exception cref="System.ArgumentNullException"></exception>
-        Task EnhanceImageAsync(BaseItem item, string inputFile, string outputFile, ImageType imageType, int imageIndex);
-    }
-
-    public class EnhancedImageInfo
-    {
-        public bool RequiresTransparency { get; set; }
-    }
-}

+ 19 - 12
MediaBrowser.Model/Drawing/ImageDimensions.cs

@@ -1,36 +1,43 @@
+using System.Globalization;
+
 namespace MediaBrowser.Model.Drawing
 {
     /// <summary>
     /// Struct ImageDimensions
     /// </summary>
-    public struct ImageDimensions
+    public readonly struct ImageDimensions
     {
+        public ImageDimensions(int width, int height)
+        {
+            Width = width;
+            Height = height;
+        }
+
         /// <summary>
-        /// Gets or sets the height.
+        /// Gets the height.
         /// </summary>
         /// <value>The height.</value>
-        public int Height { get; set; }
+        public int Height { get; }
 
         /// <summary>
-        /// Gets or sets the width.
+        /// Gets the width.
         /// </summary>
         /// <value>The width.</value>
-        public int Width { get; set; }
+        public int Width { get; }
 
         public bool Equals(ImageDimensions size)
         {
             return Width.Equals(size.Width) && Height.Equals(size.Height);
         }
 
+        /// <inheritdoc />
         public override string ToString()
         {
-            return string.Format("{0}-{1}", Width, Height);
-        }
-
-        public ImageDimensions(int width, int height)
-        {
-            Width = width;
-            Height = height;
+            return string.Format(
+                CultureInfo.InvariantCulture,
+                "{0}-{1}",
+                Width,
+                Height);
         }
     }
 }