Update SkiaSharp to 2.80.1 and replace resize code.

This fixed the blurry resized images in the Web UI.
This commit is contained in:
Erwin de Haan 2020-07-31 21:20:05 +02:00
parent 9ec787e954
commit 7ce99aaf78
3 changed files with 46 additions and 15 deletions

View File

@ -20,9 +20,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="BlurHashSharp" Version="1.1.0" /> <PackageReference Include="BlurHashSharp" Version="1.1.0" />
<PackageReference Include="BlurHashSharp.SkiaSharp" Version="1.1.0" /> <PackageReference Include="BlurHashSharp.SkiaSharp" Version="1.1.0" />
<PackageReference Include="SkiaSharp" Version="1.68.3" /> <PackageReference Include="SkiaSharp" Version="2.80.1" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="1.68.3" /> <PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="2.80.1" />
<PackageReference Include="Jellyfin.SkiaSharp.NativeAssets.LinuxArm" Version="1.68.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -395,6 +395,42 @@ namespace Jellyfin.Drawing.Skia
return rotated; return rotated;
} }
/// <summary>
/// Resizes an image on the CPU, by utilizing a surface and canvas.
/// </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();
paint.FilterQuality = SKFilterQuality.High;
paint.IsAntialias = isAntialias;
paint.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/> /// <inheritdoc/>
public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat) public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
{ {
@ -436,9 +472,8 @@ namespace Jellyfin.Drawing.Skia
var width = newImageSize.Width; var width = newImageSize.Width;
var height = newImageSize.Height; var height = newImageSize.Height;
using var resizedBitmap = new SKBitmap(width, height, bitmap.ColorType, bitmap.AlphaType); // scale image (the FromImage creates a copy)
// scale image using var resizedBitmap = SKBitmap.FromImage(ResizeImage(bitmap, new SKImageInfo(width, height, bitmap.ColorType, bitmap.AlphaType, bitmap.ColorSpace)));
bitmap.ScalePixels(resizedBitmap, SKFilterQuality.High);
// If all we're doing is resizing then we can stop now // If all we're doing is resizing then we can stop now
if (!hasBackgroundColor && !hasForegroundColor && blur == 0 && !hasIndicator) if (!hasBackgroundColor && !hasForegroundColor && blur == 0 && !hasIndicator)
@ -446,7 +481,7 @@ namespace Jellyfin.Drawing.Skia
Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
using var outputStream = new SKFileWStream(outputPath); using var outputStream = new SKFileWStream(outputPath);
using var pixmap = new SKPixmap(new SKImageInfo(width, height), resizedBitmap.GetPixels()); using var pixmap = new SKPixmap(new SKImageInfo(width, height), resizedBitmap.GetPixels());
pixmap.Encode(outputStream, skiaOutputFormat, quality); resizedBitmap.Encode(outputStream, skiaOutputFormat, quality);
return outputPath; return outputPath;
} }

View File

@ -115,15 +115,13 @@ namespace Jellyfin.Drawing.Skia
// resize to the same aspect as the original // resize to the same aspect as the original
int iWidth = Math.Abs(iHeight * currentBitmap.Width / currentBitmap.Height); int iWidth = Math.Abs(iHeight * currentBitmap.Width / currentBitmap.Height);
using var resizeBitmap = new SKBitmap(iWidth, iHeight, currentBitmap.ColorType, currentBitmap.AlphaType); using var resizedImage = SkiaEncoder.ResizeImage(bitmap, new SKImageInfo(iWidth, iHeight, currentBitmap.ColorType, currentBitmap.AlphaType, currentBitmap.ColorSpace));
currentBitmap.ScalePixels(resizeBitmap, SKFilterQuality.High);
// crop image // crop image
int ix = Math.Abs((iWidth - iSlice) / 2); int ix = Math.Abs((iWidth - iSlice) / 2);
using var image = SKImage.FromBitmap(resizeBitmap); using var subset = resizedImage.Subset(SKRectI.Create(ix, 0, iSlice, iHeight));
using var subset = image.Subset(SKRectI.Create(ix, 0, iSlice, iHeight));
// draw image onto canvas // draw image onto canvas
canvas.DrawImage(subset ?? image, iSlice * i, 0); canvas.DrawImage(subset ?? resizedImage, iSlice * i, 0);
} }
return bitmap; return bitmap;
@ -177,9 +175,8 @@ namespace Jellyfin.Drawing.Skia
continue; continue;
} }
using var resizedBitmap = new SKBitmap(cellWidth, cellHeight, currentBitmap.ColorType, currentBitmap.AlphaType); // Scale image. The FromBitmap creates a copy
// scale image using var resizedBitmap = SKBitmap.FromImage(SkiaEncoder.ResizeImage(bitmap, new SKImageInfo(cellWidth, cellHeight, currentBitmap.ColorType, currentBitmap.AlphaType, currentBitmap.ColorSpace)));
currentBitmap.ScalePixels(resizedBitmap, SKFilterQuality.High);
// draw this image into the strip at the next position // draw this image into the strip at the next position
var xPos = x * cellWidth; var xPos = x * cellWidth;