|  | @@ -395,6 +395,56 @@ namespace Jellyfin.Drawing.Skia
 | 
	
		
			
				|  |  |              return rotated;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        /// <summary>
 | 
	
		
			
				|  |  | +        /// Resizes an image on the CPU, by utilizing a surface and canvas.
 | 
	
		
			
				|  |  | +        ///
 | 
	
		
			
				|  |  | +        /// The convolutional matrix kernel used in this resize function gives a (light) sharpening effect.
 | 
	
		
			
				|  |  | +        /// This technique is similar to effect that can be created using for example the [Convolution matrix filter in GIMP](https://docs.gimp.org/2.10/en/gimp-filter-convolution-matrix.html).
 | 
	
		
			
				|  |  | +        /// </summary>
 | 
	
		
			
				|  |  | +        /// <param name="source">The source bitmap.</param>
 | 
	
		
			
				|  |  | +        /// <param name="targetInfo">This specifies the target size and other information required to create the surface.</param>
 | 
	
		
			
				|  |  | +        /// <param name="isAntialias">This enables anti-aliasing on the SKPaint instance.</param>
 | 
	
		
			
				|  |  | +        /// <param name="isDither">This enables dithering on the SKPaint instance.</param>
 | 
	
		
			
				|  |  | +        /// <returns>The resized image.</returns>
 | 
	
		
			
				|  |  | +        internal static SKImage ResizeImage(SKBitmap source, SKImageInfo targetInfo, bool isAntialias = false, bool isDither = false)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            using var surface = SKSurface.Create(targetInfo);
 | 
	
		
			
				|  |  | +            using var canvas = surface.Canvas;
 | 
	
		
			
				|  |  | +            using var paint = new SKPaint
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                FilterQuality = SKFilterQuality.High,
 | 
	
		
			
				|  |  | +                IsAntialias = isAntialias,
 | 
	
		
			
				|  |  | +                IsDither = isDither
 | 
	
		
			
				|  |  | +            };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var kernel = new float[9]
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                0,    -.1f,    0,
 | 
	
		
			
				|  |  | +                -.1f, 1.4f, -.1f,
 | 
	
		
			
				|  |  | +                0,    -.1f,    0,
 | 
	
		
			
				|  |  | +            };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var kernelSize = new SKSizeI(3, 3);
 | 
	
		
			
				|  |  | +            var kernelOffset = new SKPointI(1, 1);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            paint.ImageFilter = SKImageFilter.CreateMatrixConvolution(
 | 
	
		
			
				|  |  | +                kernelSize,
 | 
	
		
			
				|  |  | +                kernel,
 | 
	
		
			
				|  |  | +                1f,
 | 
	
		
			
				|  |  | +                0f,
 | 
	
		
			
				|  |  | +                kernelOffset,
 | 
	
		
			
				|  |  | +                SKShaderTileMode.Clamp,
 | 
	
		
			
				|  |  | +                false);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            canvas.DrawBitmap(
 | 
	
		
			
				|  |  | +                source,
 | 
	
		
			
				|  |  | +                SKRect.Create(0, 0, source.Width, source.Height),
 | 
	
		
			
				|  |  | +                SKRect.Create(0, 0, targetInfo.Width, targetInfo.Height),
 | 
	
		
			
				|  |  | +                paint);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return surface.Snapshot();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          /// <inheritdoc/>
 | 
	
		
			
				|  |  |          public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
 | 
	
		
			
				|  |  |          {
 | 
	
	
		
			
				|  | @@ -436,9 +486,9 @@ namespace Jellyfin.Drawing.Skia
 | 
	
		
			
				|  |  |              var width = newImageSize.Width;
 | 
	
		
			
				|  |  |              var height = newImageSize.Height;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            using var resizedBitmap = new SKBitmap(width, height, bitmap.ColorType, bitmap.AlphaType);
 | 
	
		
			
				|  |  | -            // scale image
 | 
	
		
			
				|  |  | -            bitmap.ScalePixels(resizedBitmap, SKFilterQuality.High);
 | 
	
		
			
				|  |  | +            // scale image (the FromImage creates a copy)
 | 
	
		
			
				|  |  | +            var imageInfo = new SKImageInfo(width, height, bitmap.ColorType, bitmap.AlphaType, bitmap.ColorSpace);
 | 
	
		
			
				|  |  | +            using var resizedBitmap = SKBitmap.FromImage(ResizeImage(bitmap, imageInfo));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              // If all we're doing is resizing then we can stop now
 | 
	
		
			
				|  |  |              if (!hasBackgroundColor && !hasForegroundColor && blur == 0 && !hasIndicator)
 | 
	
	
		
			
				|  | @@ -446,7 +496,7 @@ namespace Jellyfin.Drawing.Skia
 | 
	
		
			
				|  |  |                  Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
 | 
	
		
			
				|  |  |                  using var outputStream = new SKFileWStream(outputPath);
 | 
	
		
			
				|  |  |                  using var pixmap = new SKPixmap(new SKImageInfo(width, height), resizedBitmap.GetPixels());
 | 
	
		
			
				|  |  | -                pixmap.Encode(outputStream, skiaOutputFormat, quality);
 | 
	
		
			
				|  |  | +                resizedBitmap.Encode(outputStream, skiaOutputFormat, quality);
 | 
	
		
			
				|  |  |                  return outputPath;
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 |