aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua M. Boniface <joshua@boniface.me>2020-08-02 20:28:42 -0400
committerGitHub <noreply@github.com>2020-08-02 20:28:42 -0400
commit612d513d864a0ce2ad43ffbd8274bef7268d21d0 (patch)
treea901f6ecd78551328d0253d8e21fc984f04fd1f9
parent714a6f04ef328201b4ee8a1a9bc549ab22ba4987 (diff)
parent0f43780c8c50a6d933091056aaa523905f6e7b1a (diff)
Merge pull request #3772 from EraYaN/master
Updated SkiaSharp to 2.80.1 and replace resize code to fix bad quality
-rw-r--r--Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj5
-rw-r--r--Jellyfin.Drawing.Skia/SkiaEncoder.cs58
-rw-r--r--Jellyfin.Drawing.Skia/StripCollageBuilder.cs14
3 files changed, 62 insertions, 15 deletions
diff --git a/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj b/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj
index 65a439459..c71c76f08 100644
--- a/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj
+++ b/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj
@@ -20,9 +20,8 @@
<ItemGroup>
<PackageReference Include="BlurHashSharp" Version="1.1.0" />
<PackageReference Include="BlurHashSharp.SkiaSharp" Version="1.1.0" />
- <PackageReference Include="SkiaSharp" Version="1.68.3" />
- <PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="1.68.3" />
- <PackageReference Include="Jellyfin.SkiaSharp.NativeAssets.LinuxArm" Version="1.68.1" />
+ <PackageReference Include="SkiaSharp" Version="2.80.1" />
+ <PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="2.80.1" />
</ItemGroup>
<ItemGroup>
diff --git a/Jellyfin.Drawing.Skia/SkiaEncoder.cs b/Jellyfin.Drawing.Skia/SkiaEncoder.cs
index 1f7c43de8..a1caa751b 100644
--- a/Jellyfin.Drawing.Skia/SkiaEncoder.cs
+++ b/Jellyfin.Drawing.Skia/SkiaEncoder.cs
@@ -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;
}
diff --git a/Jellyfin.Drawing.Skia/StripCollageBuilder.cs b/Jellyfin.Drawing.Skia/StripCollageBuilder.cs
index e0ee4a342..b08c3750d 100644
--- a/Jellyfin.Drawing.Skia/StripCollageBuilder.cs
+++ b/Jellyfin.Drawing.Skia/StripCollageBuilder.cs
@@ -115,15 +115,13 @@ namespace Jellyfin.Drawing.Skia
// resize to the same aspect as the original
int iWidth = Math.Abs(iHeight * currentBitmap.Width / currentBitmap.Height);
- using var resizeBitmap = new SKBitmap(iWidth, iHeight, currentBitmap.ColorType, currentBitmap.AlphaType);
- currentBitmap.ScalePixels(resizeBitmap, SKFilterQuality.High);
+ using var resizedImage = SkiaEncoder.ResizeImage(bitmap, new SKImageInfo(iWidth, iHeight, currentBitmap.ColorType, currentBitmap.AlphaType, currentBitmap.ColorSpace));
// crop image
int ix = Math.Abs((iWidth - iSlice) / 2);
- using var image = SKImage.FromBitmap(resizeBitmap);
- using var subset = image.Subset(SKRectI.Create(ix, 0, iSlice, iHeight));
+ using var subset = resizedImage.Subset(SKRectI.Create(ix, 0, iSlice, iHeight));
// draw image onto canvas
- canvas.DrawImage(subset ?? image, iSlice * i, 0);
+ canvas.DrawImage(subset ?? resizedImage, iSlice * i, 0);
}
return bitmap;
@@ -177,9 +175,9 @@ namespace Jellyfin.Drawing.Skia
continue;
}
- using var resizedBitmap = new SKBitmap(cellWidth, cellHeight, currentBitmap.ColorType, currentBitmap.AlphaType);
- // scale image
- currentBitmap.ScalePixels(resizedBitmap, SKFilterQuality.High);
+ // Scale image. The FromBitmap creates a copy
+ var imageInfo = new SKImageInfo(cellWidth, cellHeight, currentBitmap.ColorType, currentBitmap.AlphaType, currentBitmap.ColorSpace);
+ using var resizedBitmap = SKBitmap.FromImage(SkiaEncoder.ResizeImage(bitmap, imageInfo));
// draw this image into the strip at the next position
var xPos = x * cellWidth;