From 90e06289dc8a9b97fc48ee136eade94616de1ad6 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 12 Nov 2015 14:26:02 -0500 Subject: [PATCH] update image encoding --- Emby.Drawing/GDI/GDIImageEncoder.cs | 12 +-- Emby.Drawing/IImageEncoder.cs | 3 +- .../ImageMagick/ImageMagickEncoder.cs | 35 +++++-- Emby.Drawing/ImageProcessor.cs | 96 +++++++++++++------ Emby.Drawing/NullImageEncoder.cs | 2 +- MediaBrowser.Api/Images/ImageService.cs | 91 ++++++------------ .../Drawing/IImageProcessor.cs | 11 ++- .../Drawing/ImageProcessingOptions.cs | 41 ++++++-- .../ApplicationHost.cs | 2 +- 9 files changed, 175 insertions(+), 118 deletions(-) diff --git a/Emby.Drawing/GDI/GDIImageEncoder.cs b/Emby.Drawing/GDI/GDIImageEncoder.cs index 5306137411..3df84cf112 100644 --- a/Emby.Drawing/GDI/GDIImageEncoder.cs +++ b/Emby.Drawing/GDI/GDIImageEncoder.cs @@ -32,7 +32,7 @@ namespace Emby.Drawing.GDI { using (var img = Image.FromStream(stream)) { - + } } _logger.Info("GDIImageEncoder started"); @@ -79,17 +79,17 @@ namespace Emby.Drawing.GDI { using (var croppedImage = image.CropWhitespace()) { - _fileSystem.CreateDirectory(Path.GetDirectoryName(outputPath)); + _fileSystem.CreateDirectory(Path.GetDirectoryName(outputPath)); using (var outputStream = _fileSystem.GetFileStream(outputPath, FileMode.Create, FileAccess.Write, FileShare.Read, false)) { croppedImage.Save(System.Drawing.Imaging.ImageFormat.Png, outputStream, 100); } - } + } } } - public void EncodeImage(string inputPath, string cacheFilePath, int width, int height, int quality, ImageProcessingOptions options) + public void EncodeImage(string inputPath, string cacheFilePath, int width, int height, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat) { var hasPostProcessing = !string.IsNullOrEmpty(options.BackgroundColor) || options.UnplayedCount.HasValue || options.AddPlayedIndicator || options.PercentPlayed > 0; @@ -98,8 +98,6 @@ namespace Emby.Drawing.GDI var newWidth = Convert.ToInt32(width); var newHeight = Convert.ToInt32(height); - var selectedOutputFormat = options.OutputFormat; - // Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here // Also, Webp only supports Format32bppArgb and Format32bppRgb var pixelFormat = selectedOutputFormat == ImageFormat.Webp @@ -133,7 +131,7 @@ namespace Emby.Drawing.GDI var outputFormat = GetOutputFormat(originalImage, selectedOutputFormat); - _fileSystem.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); + _fileSystem.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); // Save to the cache location using (var cacheFileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, false)) diff --git a/Emby.Drawing/IImageEncoder.cs b/Emby.Drawing/IImageEncoder.cs index 4469075a6d..bfd382bb7c 100644 --- a/Emby.Drawing/IImageEncoder.cs +++ b/Emby.Drawing/IImageEncoder.cs @@ -31,7 +31,8 @@ namespace Emby.Drawing /// The height. /// The quality. /// The options. - void EncodeImage(string inputPath, string outputPath, int width, int height, int quality, ImageProcessingOptions options); + /// The output format. + void EncodeImage(string inputPath, string outputPath, int width, int height, int quality, ImageProcessingOptions options, ImageFormat outputFormat); /// /// Creates the image collage. diff --git a/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs index ed0760ee33..64ddf7e884 100644 --- a/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs +++ b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs @@ -9,6 +9,7 @@ using System; using System.IO; using System.Linq; using CommonIO; +using MediaBrowser.Controller.Configuration; namespace Emby.Drawing.ImageMagick { @@ -18,13 +19,15 @@ namespace Emby.Drawing.ImageMagick private readonly IApplicationPaths _appPaths; private readonly IHttpClient _httpClient; private readonly IFileSystem _fileSystem; + private readonly IServerConfigurationManager _config; - public ImageMagickEncoder(ILogger logger, IApplicationPaths appPaths, IHttpClient httpClient, IFileSystem fileSystem) + public ImageMagickEncoder(ILogger logger, IApplicationPaths appPaths, IHttpClient httpClient, IFileSystem fileSystem, IServerConfigurationManager config) { _logger = logger; _appPaths = appPaths; _httpClient = httpClient; _fileSystem = fileSystem; + _config = config; LogVersion(); } @@ -87,7 +90,7 @@ namespace Emby.Drawing.ImageMagick wand.SaveImage(tmpPath); } } - catch + catch { //_logger.ErrorException("Error loading webp: ", ex); _webpAvailable = false; @@ -131,17 +134,21 @@ namespace Emby.Drawing.ImageMagick string.Equals(ext, ".webp", StringComparison.OrdinalIgnoreCase); } - public void EncodeImage(string inputPath, string outputPath, int width, int height, int quality, ImageProcessingOptions options) + public void EncodeImage(string inputPath, string outputPath, int width, int height, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat) { + // Even if the caller specified 100, don't use it because it takes forever + quality = Math.Min(quality, 99); + if (string.IsNullOrWhiteSpace(options.BackgroundColor) || !HasTransparency(inputPath)) { using (var originalImage = new MagickWand(inputPath)) { - originalImage.CurrentImage.ResizeImage(width, height); + ScaleImage(originalImage, width, height); DrawIndicator(originalImage, width, height, options); originalImage.CurrentImage.CompressionQuality = quality; + //originalImage.CurrentImage.StripImage(); originalImage.SaveImage(outputPath); } @@ -152,12 +159,13 @@ namespace Emby.Drawing.ImageMagick { using (var originalImage = new MagickWand(inputPath)) { - originalImage.CurrentImage.ResizeImage(width, height); + ScaleImage(originalImage, width, height); wand.CurrentImage.CompositeImage(originalImage, CompositeOperator.OverCompositeOp, 0, 0); DrawIndicator(wand, width, height, options); wand.CurrentImage.CompressionQuality = quality; + //wand.CurrentImage.StripImage(); wand.SaveImage(outputPath); } @@ -166,6 +174,19 @@ namespace Emby.Drawing.ImageMagick SaveDelay(); } + private void ScaleImage(MagickWand wand, int width, int height) + { + wand.CurrentImage.ResizeImage(width, height); + //if (_config.Configuration.EnableHighQualityImageScaling) + //{ + // wand.CurrentImage.ResizeImage(width, height); + //} + //else + //{ + // wand.CurrentImage.ScaleImage(width, height); + //} + } + /// /// Draws the indicator. /// @@ -231,8 +252,8 @@ namespace Emby.Drawing.ImageMagick private void SaveDelay() { // For some reason the images are not always getting released right away - var task = Task.Delay(300); - Task.WaitAll(task); + //var task = Task.Delay(300); + //Task.WaitAll(task); } public string Name diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index ec5d66cba4..e1b92bbffc 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -19,6 +19,7 @@ using System.Threading.Tasks; using CommonIO; using Emby.Drawing.Common; using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Net; namespace Emby.Drawing { @@ -152,7 +153,7 @@ namespace Emby.Drawing { var file = await ProcessImage(options).ConfigureAwait(false); - using (var fileStream = _fileSystem.GetFileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, true)) + using (var fileStream = _fileSystem.GetFileStream(file.Item1, FileMode.Open, FileAccess.Read, FileShare.Read, true)) { await fileStream.CopyToAsync(toStream).ConfigureAwait(false); } @@ -163,7 +164,7 @@ namespace Emby.Drawing return _imageEncoder.SupportedOutputFormats; } - public async Task ProcessImage(ImageProcessingOptions options) + public async Task> ProcessImage(ImageProcessingOptions options) { if (options == null) { @@ -181,13 +182,7 @@ namespace Emby.Drawing if (!_imageEncoder.SupportsImageEncoding) { - return originalImagePath; - } - - if (options.HasDefaultOptions(originalImagePath) && options.Enhancers.Count == 0 && !options.CropWhiteSpace) - { - // Just spit out the original file if all the options are default - return originalImagePath; + return new Tuple(originalImagePath, MimeTypes.GetMimeType(originalImagePath)); } var dateModified = originalImage.DateModified; @@ -214,19 +209,31 @@ namespace Emby.Drawing dateModified = tuple.Item2; } - var newSizeInfo = GetNewImageSize(originalImagePath, dateModified, options); - var newSize = newSizeInfo.Item1; - var isSizeChanged = newSizeInfo.Item2; + if (options.HasDefaultOptions(originalImagePath)) + { + // Just spit out the original file if all the options are default + return new Tuple(originalImagePath, MimeTypes.GetMimeType(originalImagePath)); + } - if (options.HasDefaultOptionsWithoutSize(originalImagePath) && !isSizeChanged && options.Enhancers.Count == 0) + ImageSize? originalImageSize; + try { - // Just spit out the original file if the new size equals the old - return originalImagePath; + originalImageSize = GetImageSize(originalImagePath, dateModified, true); + if (options.HasDefaultOptions(originalImagePath, originalImageSize.Value)) + { + // Just spit out the original file if all the options are default + return new Tuple(originalImagePath, MimeTypes.GetMimeType(originalImagePath)); + } + } + catch + { + originalImageSize = null; } - var quality = options.Quality ?? 90; + var newSize = GetNewImageSize(options, originalImageSize); + var quality = options.Quality; - var outputFormat = GetOutputFormat(options.OutputFormat); + var outputFormat = GetOutputFormat(options.SupportedOutputFormats[0]); var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.BackgroundColor); var semaphore = GetLock(cacheFilePath); @@ -250,8 +257,18 @@ namespace Emby.Drawing imageProcessingLockTaken = true; - _imageEncoder.EncodeImage(originalImagePath, cacheFilePath, newWidth, newHeight, quality, options); + _imageEncoder.EncodeImage(originalImagePath, cacheFilePath, newWidth, newHeight, quality, options, outputFormat); } + + return new Tuple(cacheFilePath, GetMimeType(outputFormat, cacheFilePath)); + } + catch (Exception ex) + { + // If it fails for whatever reason, return the original image + _logger.ErrorException("Error encoding image", ex); + + // Just spit out the original file if all the options are default + return new Tuple(originalImagePath, MimeTypes.GetMimeType(originalImagePath)); } finally { @@ -262,28 +279,47 @@ namespace Emby.Drawing semaphore.Release(); } - - return cacheFilePath; } - private Tuple GetNewImageSize(string originalImagePath, DateTime dateModified, ImageProcessingOptions options) + private string GetMimeType(ImageFormat format, string path) { - try + if (format == ImageFormat.Bmp) + { + return MimeTypes.GetMimeType("i.bmp"); + } + if (format == ImageFormat.Gif) + { + return MimeTypes.GetMimeType("i.gif"); + } + if (format == ImageFormat.Jpg) + { + return MimeTypes.GetMimeType("i.jpg"); + } + if (format == ImageFormat.Png) + { + return MimeTypes.GetMimeType("i.png"); + } + if (format == ImageFormat.Webp) { - var originalImageSize = GetImageSize(originalImagePath, dateModified, true); + return MimeTypes.GetMimeType("i.webp"); + } - // Determine the output size based on incoming parameters - var newSize = DrawingUtils.Resize(originalImageSize, options.Width, options.Height, options.MaxWidth, options.MaxHeight); + return MimeTypes.GetMimeType(path); + } - return new Tuple(newSize, !newSize.Equals(originalImageSize)); - } - catch + private ImageSize GetNewImageSize(ImageProcessingOptions options, ImageSize? originalImageSize) + { + if (originalImageSize.HasValue) { - return new Tuple(GetSizeEstimage(options), true); + // Determine the output size based on incoming parameters + var newSize = DrawingUtils.Resize(originalImageSize.Value, options.Width, options.Height, options.MaxWidth, options.MaxHeight); + + return newSize; } + return GetSizeEstimate(options); } - private ImageSize GetSizeEstimage(ImageProcessingOptions options) + private ImageSize GetSizeEstimate(ImageProcessingOptions options) { if (options.Width.HasValue && options.Height.HasValue) { diff --git a/Emby.Drawing/NullImageEncoder.cs b/Emby.Drawing/NullImageEncoder.cs index 30ea363290..1638a675ac 100644 --- a/Emby.Drawing/NullImageEncoder.cs +++ b/Emby.Drawing/NullImageEncoder.cs @@ -32,7 +32,7 @@ namespace Emby.Drawing throw new NotImplementedException(); } - public void EncodeImage(string inputPath, string outputPath, int width, int height, int quality, ImageProcessingOptions options) + public void EncodeImage(string inputPath, string outputPath, int width, int height, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat) { throw new NotImplementedException(); } diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 259789fd19..957d73c2d3 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -1,5 +1,4 @@ using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.IO; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -18,7 +17,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using CommonIO; -using MimeTypes = MediaBrowser.Model.Net.MimeTypes; namespace MediaBrowser.Api.Images { @@ -571,8 +569,7 @@ namespace MediaBrowser.Api.Images cropwhitespace = request.CropWhitespace.Value; } - var format = GetOutputFormat(request, imageInfo, cropwhitespace, supportedImageEnhancers); - var contentType = GetMimeType(format, imageInfo.Path); + var outputFormats = GetOutputFormats(request, imageInfo, cropwhitespace, supportedImageEnhancers); var cacheGuid = new Guid(_imageProcessor.GetImageCacheTag(item, imageInfo, supportedImageEnhancers)); @@ -593,9 +590,8 @@ namespace MediaBrowser.Api.Images request, imageInfo, cropwhitespace, - format, + outputFormats, supportedImageEnhancers, - contentType, cacheDuration, responseHeaders, isHeadRequest) @@ -606,9 +602,8 @@ namespace MediaBrowser.Api.Images ImageRequest request, ItemImageInfo image, bool cropwhitespace, - ImageFormat format, + List supportedFormats, List enhancers, - string contentType, TimeSpan? cacheDuration, IDictionary headers, bool isHeadRequest) @@ -623,16 +618,16 @@ namespace MediaBrowser.Api.Images Item = item, MaxHeight = request.MaxHeight, MaxWidth = request.MaxWidth, - Quality = request.Quality, + Quality = request.Quality ?? 100, Width = request.Width, AddPlayedIndicator = request.AddPlayedIndicator, PercentPlayed = request.PercentPlayed ?? 0, UnplayedCount = request.UnplayedCount, BackgroundColor = request.BackgroundColor, - OutputFormat = format + SupportedOutputFormats = supportedFormats }; - var file = await _imageProcessor.ProcessImage(options).ConfigureAwait(false); + var imageResult = await _imageProcessor.ProcessImage(options).ConfigureAwait(false); headers["Vary"] = "Accept"; @@ -640,20 +635,20 @@ namespace MediaBrowser.Api.Images { CacheDuration = cacheDuration, ResponseHeaders = headers, - ContentType = contentType, + ContentType = imageResult.Item2, IsHeadRequest = isHeadRequest, - Path = file + Path = imageResult.Item1 }); } - private ImageFormat GetOutputFormat(ImageRequest request, ItemImageInfo image, bool cropwhitespace, List enhancers) + private List GetOutputFormats(ImageRequest request, ItemImageInfo image, bool cropwhitespace, List enhancers) { if (!string.IsNullOrWhiteSpace(request.Format)) { ImageFormat format; if (Enum.TryParse(request.Format, true, out format)) { - return format; + return new List { format }; } } @@ -671,39 +666,30 @@ namespace MediaBrowser.Api.Images } var clientSupportedFormats = GetClientSupportedFormats(); - if (inputFormat.HasValue && clientSupportedFormats.Contains(inputFormat.Value) && enhancers.Count == 0) - { - if ((request.Quality ?? 100) == 100 && !request.Height.HasValue && !request.Width.HasValue && - !request.AddPlayedIndicator && !request.PercentPlayed.HasValue && !request.UnplayedCount.HasValue && string.IsNullOrWhiteSpace(request.BackgroundColor)) - { - // TODO: Allow this when specfying max width/height if the value is in range - if (!cropwhitespace && !request.MaxHeight.HasValue && !request.MaxWidth.HasValue) - { - return inputFormat.Value; - } - } - } var serverFormats = _imageProcessor.GetSupportedImageOutputFormats(); + var outputFormats = new List(); // Client doesn't care about format, so start with webp if supported if (serverFormats.Contains(ImageFormat.Webp) && clientSupportedFormats.Contains(ImageFormat.Webp)) { - return ImageFormat.Webp; + outputFormats.Add(ImageFormat.Webp); } if (enhancers.Count > 0) { - return ImageFormat.Png; + outputFormats.Add(ImageFormat.Png); } if (inputFormat.HasValue && inputFormat.Value == ImageFormat.Jpg) { - return ImageFormat.Jpg; + outputFormats.Add(ImageFormat.Jpg); } // We can't predict if there will be transparency or not, so play it safe - return ImageFormat.Png; + outputFormats.Add(ImageFormat.Png); + + return outputFormats; } private ImageFormat[] GetClientSupportedFormats() @@ -712,10 +698,21 @@ namespace MediaBrowser.Api.Images var userAgent = Request.UserAgent ?? string.Empty; - if (userAgent.IndexOf("crosswalk", StringComparison.OrdinalIgnoreCase) != -1 && - userAgent.IndexOf("android", StringComparison.OrdinalIgnoreCase) != -1) + if (!supportsWebP) { - supportsWebP = true; + if (string.Equals(Request.QueryString["accept"], "webp", StringComparison.OrdinalIgnoreCase)) + { + supportsWebP = true; + } + } + + if (!supportsWebP) + { + if (userAgent.IndexOf("crosswalk", StringComparison.OrdinalIgnoreCase) != -1 && + userAgent.IndexOf("android", StringComparison.OrdinalIgnoreCase) != -1) + { + supportsWebP = true; + } } if (supportsWebP) @@ -730,32 +727,6 @@ namespace MediaBrowser.Api.Images return new[] { ImageFormat.Jpg, ImageFormat.Png }; } - private string GetMimeType(ImageFormat format, string path) - { - if (format == ImageFormat.Bmp) - { - return MimeTypes.GetMimeType("i.bmp"); - } - if (format == ImageFormat.Gif) - { - return MimeTypes.GetMimeType("i.gif"); - } - if (format == ImageFormat.Jpg) - { - return MimeTypes.GetMimeType("i.jpg"); - } - if (format == ImageFormat.Png) - { - return MimeTypes.GetMimeType("i.png"); - } - if (format == ImageFormat.Webp) - { - return MimeTypes.GetMimeType("i.webp"); - } - - return MimeTypes.GetMimeType(path); - } - /// /// Gets the image path. /// diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index e1e98857ff..d42a04f2ee 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Entities; +using System; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Entities; @@ -18,7 +19,7 @@ namespace MediaBrowser.Controller.Drawing /// /// The supported input formats. string[] SupportedInputFormats { get; } - + /// /// Gets the image enhancers. /// @@ -38,7 +39,7 @@ namespace MediaBrowser.Controller.Drawing /// The path. /// ImageSize. ImageSize GetImageSize(string path); - + /// /// Adds the parts. /// @@ -77,13 +78,13 @@ namespace MediaBrowser.Controller.Drawing /// To stream. /// Task. Task ProcessImage(ImageProcessingOptions options, Stream toStream); - + /// /// Processes the image. /// /// The options. /// Task. - Task ProcessImage(ImageProcessingOptions options); + Task> ProcessImage(ImageProcessingOptions options); /// /// Gets the enhanced image. diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs index d8f5d52c3b..2b80b701e0 100644 --- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs +++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs @@ -4,6 +4,7 @@ using MediaBrowser.Model.Drawing; using System; using System.Collections.Generic; using System.IO; +using System.Linq; namespace MediaBrowser.Controller.Drawing { @@ -25,11 +26,11 @@ namespace MediaBrowser.Controller.Drawing public int? MaxHeight { get; set; } - public int? Quality { get; set; } + public int Quality { get; set; } public List Enhancers { get; set; } - public ImageFormat OutputFormat { get; set; } + public List SupportedOutputFormats { get; set; } public bool AddPlayedIndicator { get; set; } @@ -48,19 +49,47 @@ namespace MediaBrowser.Controller.Drawing !MaxHeight.HasValue; } + public bool HasDefaultOptions(string originalImagePath, ImageSize size) + { + if (!HasDefaultOptionsWithoutSize(originalImagePath)) + { + return false; + } + + if (Width.HasValue && !size.Width.Equals(Width.Value)) + { + return false; + } + if (Height.HasValue && !size.Height.Equals(Height.Value)) + { + return false; + } + if (MaxWidth.HasValue && size.Width > MaxWidth.Value) + { + return false; + } + if (MaxHeight.HasValue && size.Height > MaxHeight.Value) + { + return false; + } + + return true; + } + public bool HasDefaultOptionsWithoutSize(string originalImagePath) { - return (!Quality.HasValue || Quality.Value == 100) && - IsOutputFormatDefault(originalImagePath) && + return (Quality >= 90) && + IsFormatSupported(originalImagePath) && !AddPlayedIndicator && PercentPlayed.Equals(0) && !UnplayedCount.HasValue && string.IsNullOrEmpty(BackgroundColor); } - private bool IsOutputFormatDefault(string originalImagePath) + private bool IsFormatSupported(string originalImagePath) { - return string.Equals(Path.GetExtension(originalImagePath), "." + OutputFormat, StringComparison.OrdinalIgnoreCase); + var ext = Path.GetExtension(originalImagePath); + return SupportedOutputFormats.Any(outputFormat => string.Equals(ext, "." + outputFormat, StringComparison.OrdinalIgnoreCase)); } } } diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index aeafc1ede2..97a457a1b6 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -573,7 +573,7 @@ namespace MediaBrowser.Server.Startup.Common { try { - return new ImageMagickEncoder(LogManager.GetLogger("ImageMagick"), ApplicationPaths, HttpClient, FileSystemManager); + return new ImageMagickEncoder(LogManager.GetLogger("ImageMagick"), ApplicationPaths, HttpClient, FileSystemManager, ServerConfigurationManager); } catch (Exception ex) {