|  | @@ -19,6 +19,7 @@ using MediaBrowser.Controller.Configuration;
 | 
	
		
			
				|  |  |  using MediaBrowser.Controller.MediaEncoding;
 | 
	
		
			
				|  |  |  using MediaBrowser.MediaEncoding.Probing;
 | 
	
		
			
				|  |  |  using MediaBrowser.Model.Dlna;
 | 
	
		
			
				|  |  | +using MediaBrowser.Model.Drawing;
 | 
	
		
			
				|  |  |  using MediaBrowser.Model.Dto;
 | 
	
		
			
				|  |  |  using MediaBrowser.Model.Entities;
 | 
	
		
			
				|  |  |  using MediaBrowser.Model.Globalization;
 | 
	
	
		
			
				|  | @@ -478,17 +479,17 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
	
		
			
				|  |  |                  Protocol = MediaProtocol.File
 | 
	
		
			
				|  |  |              };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            return ExtractImage(path, null, null, imageStreamIndex, mediaSource, true, null, null, ".jpg", cancellationToken);
 | 
	
		
			
				|  |  | +            return ExtractImage(path, null, null, imageStreamIndex, mediaSource, true, null, null, ImageFormat.Jpg, cancellationToken);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          public Task<string> ExtractVideoImage(string inputFile, string container, MediaSourceInfo mediaSource, MediaStream videoStream, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            return ExtractImage(inputFile, container, videoStream, null, mediaSource, false, threedFormat, offset, ".jpg", cancellationToken);
 | 
	
		
			
				|  |  | +            return ExtractImage(inputFile, container, videoStream, null, mediaSource, false, threedFormat, offset, ImageFormat.Jpg, cancellationToken);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        public Task<string> ExtractVideoImage(string inputFile, string container, MediaSourceInfo mediaSource, MediaStream imageStream, int? imageStreamIndex, string outputExtension, CancellationToken cancellationToken)
 | 
	
		
			
				|  |  | +        public Task<string> ExtractVideoImage(string inputFile, string container, MediaSourceInfo mediaSource, MediaStream imageStream, int? imageStreamIndex, ImageFormat? targetFormat, CancellationToken cancellationToken)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            return ExtractImage(inputFile, container, imageStream, imageStreamIndex, mediaSource, false, null, null, outputExtension, cancellationToken);
 | 
	
		
			
				|  |  | +            return ExtractImage(inputFile, container, imageStream, imageStreamIndex, mediaSource, false, null, null, targetFormat, cancellationToken);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          private async Task<string> ExtractImage(
 | 
	
	
		
			
				|  | @@ -500,7 +501,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
	
		
			
				|  |  |              bool isAudio,
 | 
	
		
			
				|  |  |              Video3DFormat? threedFormat,
 | 
	
		
			
				|  |  |              TimeSpan? offset,
 | 
	
		
			
				|  |  | -            string outputExtension,
 | 
	
		
			
				|  |  | +            ImageFormat? targetFormat,
 | 
	
		
			
				|  |  |              CancellationToken cancellationToken)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              var inputArgument = GetInputArgument(inputFile, mediaSource);
 | 
	
	
		
			
				|  | @@ -510,7 +511,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
	
		
			
				|  |  |                  // The failure of HDR extraction usually occurs when using custom ffmpeg that does not contain the zscale filter.
 | 
	
		
			
				|  |  |                  try
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, true, true, outputExtension, cancellationToken).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +                    return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, true, true, targetFormat, cancellationToken).ConfigureAwait(false);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |                  catch (ArgumentException)
 | 
	
		
			
				|  |  |                  {
 | 
	
	
		
			
				|  | @@ -523,7 +524,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  try
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, false, true, outputExtension, cancellationToken).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +                    return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, false, true, targetFormat, cancellationToken).ConfigureAwait(false);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |                  catch (ArgumentException)
 | 
	
		
			
				|  |  |                  {
 | 
	
	
		
			
				|  | @@ -536,7 +537,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  try
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, true, false, outputExtension, cancellationToken).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +                    return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, true, false, targetFormat, cancellationToken).ConfigureAwait(false);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |                  catch (ArgumentException)
 | 
	
		
			
				|  |  |                  {
 | 
	
	
		
			
				|  | @@ -548,24 +549,25 @@ namespace MediaBrowser.MediaEncoding.Encoder
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, false, false, outputExtension, cancellationToken).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +            return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, false, false, targetFormat, cancellationToken).ConfigureAwait(false);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        private async Task<string> ExtractImageInternal(string inputPath, string container, MediaStream videoStream, int? imageStreamIndex, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, bool allowTonemap, string outputExtension, CancellationToken cancellationToken)
 | 
	
		
			
				|  |  | +        private async Task<string> ExtractImageInternal(string inputPath, string container, MediaStream videoStream, int? imageStreamIndex, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, bool allowTonemap, ImageFormat? targetFormat, CancellationToken cancellationToken)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              if (string.IsNullOrEmpty(inputPath))
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  throw new ArgumentNullException(nameof(inputPath));
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            if (string.IsNullOrEmpty(outputExtension))
 | 
	
		
			
				|  |  | +            var outputExtension = targetFormat switch
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | -                outputExtension = ".jpg";
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            else if (outputExtension[0] != '.')
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                outputExtension = "." + outputExtension;
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | +                ImageFormat.Bmp => ".bmp",
 | 
	
		
			
				|  |  | +                ImageFormat.Gif => ".gif",
 | 
	
		
			
				|  |  | +                ImageFormat.Jpg => ".jpg",
 | 
	
		
			
				|  |  | +                ImageFormat.Png => ".png",
 | 
	
		
			
				|  |  | +                ImageFormat.Webp => ".webp",
 | 
	
		
			
				|  |  | +                _ => ".jpg"
 | 
	
		
			
				|  |  | +            };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              var tempExtractPath = Path.Combine(_configurationManager.ApplicationPaths.TempDirectory, Guid.NewGuid() + outputExtension);
 | 
	
		
			
				|  |  |              Directory.CreateDirectory(Path.GetDirectoryName(tempExtractPath));
 |