mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-11-03 19:17:24 -05:00 
			
		
		
		
	update image encoding
This commit is contained in:
		
							parent
							
								
									4da6275de1
								
							
						
					
					
						commit
						90e06289dc
					
				@ -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))
 | 
			
		||||
 | 
			
		||||
@ -31,7 +31,8 @@ namespace Emby.Drawing
 | 
			
		||||
        /// <param name="height">The height.</param>
 | 
			
		||||
        /// <param name="quality">The quality.</param>
 | 
			
		||||
        /// <param name="options">The options.</param>
 | 
			
		||||
        void EncodeImage(string inputPath, string outputPath, int width, int height, int quality, ImageProcessingOptions options);
 | 
			
		||||
        /// <param name="outputFormat">The output format.</param>
 | 
			
		||||
        void EncodeImage(string inputPath, string outputPath, int width, int height, int quality, ImageProcessingOptions options, ImageFormat outputFormat);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Creates the image collage.
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
            //}
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Draws the indicator.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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<string> ProcessImage(ImageProcessingOptions options)
 | 
			
		||||
        public async Task<Tuple<string, string>> 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<string, string>(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.HasDefaultOptionsWithoutSize(originalImagePath) && !isSizeChanged && options.Enhancers.Count == 0)
 | 
			
		||||
            if (options.HasDefaultOptions(originalImagePath))
 | 
			
		||||
            {
 | 
			
		||||
                // Just spit out the original file if the new size equals the old
 | 
			
		||||
                return originalImagePath;
 | 
			
		||||
                // Just spit out the original file if all the options are default
 | 
			
		||||
                return new Tuple<string, string>(originalImagePath, MimeTypes.GetMimeType(originalImagePath));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var quality = options.Quality ?? 90;
 | 
			
		||||
            ImageSize? originalImageSize;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                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<string, string>(originalImagePath, MimeTypes.GetMimeType(originalImagePath));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                originalImageSize = null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var outputFormat = GetOutputFormat(options.OutputFormat);
 | 
			
		||||
            var newSize = GetNewImageSize(options, originalImageSize);
 | 
			
		||||
            var quality = options.Quality;
 | 
			
		||||
 | 
			
		||||
            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<string, string>(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<string, string>(originalImagePath, MimeTypes.GetMimeType(originalImagePath));
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
@ -262,28 +279,47 @@ namespace Emby.Drawing
 | 
			
		||||
 | 
			
		||||
                semaphore.Release();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return cacheFilePath;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Tuple<ImageSize, bool> GetNewImageSize(string originalImagePath, DateTime dateModified, ImageProcessingOptions options)
 | 
			
		||||
        private string GetMimeType(ImageFormat format, string path)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            if (format == ImageFormat.Bmp)
 | 
			
		||||
            {
 | 
			
		||||
                var originalImageSize = GetImageSize(originalImagePath, dateModified, true);
 | 
			
		||||
 | 
			
		||||
                // Determine the output size based on incoming parameters
 | 
			
		||||
                var newSize = DrawingUtils.Resize(originalImageSize, options.Width, options.Height, options.MaxWidth, options.MaxHeight);
 | 
			
		||||
 | 
			
		||||
                return new Tuple<ImageSize, bool>(newSize, !newSize.Equals(originalImageSize));
 | 
			
		||||
                return MimeTypes.GetMimeType("i.bmp");
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            if (format == ImageFormat.Gif)
 | 
			
		||||
            {
 | 
			
		||||
                return new Tuple<ImageSize, bool>(GetSizeEstimage(options), true);
 | 
			
		||||
                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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private ImageSize GetSizeEstimage(ImageProcessingOptions options)
 | 
			
		||||
        private ImageSize GetNewImageSize(ImageProcessingOptions options, ImageSize? originalImageSize)
 | 
			
		||||
        {
 | 
			
		||||
            if (originalImageSize.HasValue)
 | 
			
		||||
            {
 | 
			
		||||
                // 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 GetSizeEstimate(ImageProcessingOptions options)
 | 
			
		||||
        {
 | 
			
		||||
            if (options.Width.HasValue && options.Height.HasValue)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
@ -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();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -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<ImageFormat> supportedFormats,
 | 
			
		||||
            List<IImageEnhancer> enhancers,
 | 
			
		||||
            string contentType,
 | 
			
		||||
            TimeSpan? cacheDuration,
 | 
			
		||||
            IDictionary<string, string> 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<IImageEnhancer> enhancers)
 | 
			
		||||
        private List<ImageFormat> GetOutputFormats(ImageRequest request, ItemImageInfo image, bool cropwhitespace, List<IImageEnhancer> enhancers)
 | 
			
		||||
        {
 | 
			
		||||
            if (!string.IsNullOrWhiteSpace(request.Format))
 | 
			
		||||
            {
 | 
			
		||||
                ImageFormat format;
 | 
			
		||||
                if (Enum.TryParse(request.Format, true, out format))
 | 
			
		||||
                {
 | 
			
		||||
                    return format;
 | 
			
		||||
                    return new List<ImageFormat> { 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<ImageFormat>();
 | 
			
		||||
 | 
			
		||||
            // 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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the image path.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <value>The supported input formats.</value>
 | 
			
		||||
        string[] SupportedInputFormats { get; }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the image enhancers.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
@ -38,7 +39,7 @@ namespace MediaBrowser.Controller.Drawing
 | 
			
		||||
        /// <param name="path">The path.</param>
 | 
			
		||||
        /// <returns>ImageSize.</returns>
 | 
			
		||||
        ImageSize GetImageSize(string path);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Adds the parts.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
@ -77,13 +78,13 @@ namespace MediaBrowser.Controller.Drawing
 | 
			
		||||
        /// <param name="toStream">To stream.</param>
 | 
			
		||||
        /// <returns>Task.</returns>
 | 
			
		||||
        Task ProcessImage(ImageProcessingOptions options, Stream toStream);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Processes the image.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="options">The options.</param>
 | 
			
		||||
        /// <returns>Task.</returns>
 | 
			
		||||
        Task<string> ProcessImage(ImageProcessingOptions options);
 | 
			
		||||
        Task<Tuple<string, string>> ProcessImage(ImageProcessingOptions options);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the enhanced image.
 | 
			
		||||
 | 
			
		||||
@ -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<IImageEnhancer> Enhancers { get; set; }
 | 
			
		||||
 | 
			
		||||
        public ImageFormat OutputFormat { get; set; }
 | 
			
		||||
        public List<ImageFormat> 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));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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)
 | 
			
		||||
                {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user