aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCody Robibero <cody@robibe.ro>2022-06-16 07:14:56 -0600
committerJoshua Boniface <joshua@boniface.me>2022-06-29 01:26:14 -0400
commit7f1223016df0c9b55d89992b612648ed35a636dc (patch)
treeb931e84cf77b0394cbffea0437a893bf1f26c352
parenta168040cc8c0067c35801ec0469af80729c03487 (diff)
Merge pull request #7946 from cvium/svg
(cherry picked from commit 4ebe70cf6a12be4f4eae0b815a269a483ee238bb) Signed-off-by: Joshua Boniface <joshua@boniface.me>
-rw-r--r--Emby.Drawing/ImageProcessor.cs83
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs13
-rw-r--r--Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj1
-rw-r--r--Jellyfin.Drawing.Skia/SkiaEncoder.cs48
-rw-r--r--Jellyfin.Drawing.Skia/SkiaHelper.cs13
-rw-r--r--MediaBrowser.Controller/Drawing/IImageProcessor.cs8
6 files changed, 98 insertions, 68 deletions
diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs
index 18b413964..11256dafd 100644
--- a/Emby.Drawing/ImageProcessor.cs
+++ b/Emby.Drawing/ImageProcessor.cs
@@ -395,7 +395,13 @@ namespace Emby.Drawing
public string GetImageBlurHash(string path)
{
var size = GetImageDimensions(path);
- if (size.Width <= 0 || size.Height <= 0)
+ return GetImageBlurHash(path, size);
+ }
+
+ /// <inheritdoc />
+ public string GetImageBlurHash(string path, ImageDimensions imageDimensions)
+ {
+ if (imageDimensions.Width <= 0 || imageDimensions.Height <= 0)
{
return string.Empty;
}
@@ -403,8 +409,8 @@ namespace Emby.Drawing
// We want tiles to be as close to square as possible, and to *mostly* keep under 16 tiles for performance.
// One tile is (width / xComp) x (height / yComp) pixels, which means that ideally yComp = xComp * height / width.
// See more at https://github.com/woltapp/blurhash/#how-do-i-pick-the-number-of-x-and-y-components
- float xCompF = MathF.Sqrt(16.0f * size.Width / size.Height);
- float yCompF = xCompF * size.Height / size.Width;
+ float xCompF = MathF.Sqrt(16.0f * imageDimensions.Width / imageDimensions.Height);
+ float yCompF = xCompF * imageDimensions.Height / imageDimensions.Width;
int xComp = Math.Min((int)xCompF + 1, 9);
int yComp = Math.Min((int)yCompF + 1, 9);
@@ -439,47 +445,46 @@ namespace Emby.Drawing
.ToString("N", CultureInfo.InvariantCulture);
}
- private async Task<(string Path, DateTime DateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified)
+ private Task<(string Path, DateTime DateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified)
{
- var inputFormat = Path.GetExtension(originalImagePath)
- .TrimStart('.')
- .Replace("jpeg", "jpg", StringComparison.OrdinalIgnoreCase);
+ var inputFormat = Path.GetExtension(originalImagePath.AsSpan()).TrimStart('.').ToString();
// These are just jpg files renamed as tbn
if (string.Equals(inputFormat, "tbn", StringComparison.OrdinalIgnoreCase))
{
- return (originalImagePath, dateModified);
- }
-
- if (!_imageEncoder.SupportedInputFormats.Contains(inputFormat))
- {
- try
- {
- string filename = (originalImagePath + dateModified.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("N", CultureInfo.InvariantCulture);
-
- string cacheExtension = _mediaEncoder.SupportsEncoder("libwebp") ? ".webp" : ".png";
- var outputPath = Path.Combine(_appPaths.ImageCachePath, "converted-images", filename + cacheExtension);
-
- var file = _fileSystem.GetFileInfo(outputPath);
- if (!file.Exists)
- {
- await _mediaEncoder.ConvertImage(originalImagePath, outputPath).ConfigureAwait(false);
- dateModified = _fileSystem.GetLastWriteTimeUtc(outputPath);
- }
- else
- {
- dateModified = file.LastWriteTimeUtc;
- }
-
- originalImagePath = outputPath;
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Image conversion failed for {Path}", originalImagePath);
- }
- }
-
- return (originalImagePath, dateModified);
+ return Task.FromResult((originalImagePath, dateModified));
+ }
+
+ // TODO _mediaEncoder.ConvertImage is not implemented
+ // if (!_imageEncoder.SupportedInputFormats.Contains(inputFormat))
+ // {
+ // try
+ // {
+ // string filename = (originalImagePath + dateModified.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("N", CultureInfo.InvariantCulture);
+ //
+ // string cacheExtension = _mediaEncoder.SupportsEncoder("libwebp") ? ".webp" : ".png";
+ // var outputPath = Path.Combine(_appPaths.ImageCachePath, "converted-images", filename + cacheExtension);
+ //
+ // var file = _fileSystem.GetFileInfo(outputPath);
+ // if (!file.Exists)
+ // {
+ // await _mediaEncoder.ConvertImage(originalImagePath, outputPath).ConfigureAwait(false);
+ // dateModified = _fileSystem.GetLastWriteTimeUtc(outputPath);
+ // }
+ // else
+ // {
+ // dateModified = file.LastWriteTimeUtc;
+ // }
+ //
+ // originalImagePath = outputPath;
+ // }
+ // catch (Exception ex)
+ // {
+ // _logger.LogError(ex, "Image conversion failed for {Path}", originalImagePath);
+ // }
+ // }
+
+ return Task.FromResult((originalImagePath, dateModified));
}
/// <summary>
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index d6754ad4a..c54945c93 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -1860,7 +1860,9 @@ namespace Emby.Server.Implementations.Library
throw new ArgumentNullException(nameof(item));
}
- var outdated = forceUpdate ? item.ImageInfos.Where(i => i.Path != null).ToArray() : item.ImageInfos.Where(ImageNeedsRefresh).ToArray();
+ var outdated = forceUpdate
+ ? item.ImageInfos.Where(i => i.Path != null).ToArray()
+ : item.ImageInfos.Where(ImageNeedsRefresh).ToArray();
// Skip image processing if current or live tv source
if (outdated.Length == 0 || item.SourceType != SourceType.Library)
{
@@ -1883,7 +1885,7 @@ namespace Emby.Server.Implementations.Library
_logger.LogWarning("Cannot get image index for {ImagePath}", img.Path);
continue;
}
- catch (Exception ex) when (ex is InvalidOperationException || ex is IOException)
+ catch (Exception ex) when (ex is InvalidOperationException or IOException)
{
_logger.LogWarning(ex, "Cannot fetch image from {ImagePath}", img.Path);
continue;
@@ -1895,23 +1897,24 @@ namespace Emby.Server.Implementations.Library
}
}
+ ImageDimensions size;
try
{
- ImageDimensions size = _imageProcessor.GetImageDimensions(item, image);
+ size = _imageProcessor.GetImageDimensions(item, image);
image.Width = size.Width;
image.Height = size.Height;
}
catch (Exception ex)
{
_logger.LogError(ex, "Cannot get image dimensions for {ImagePath}", image.Path);
+ size = new ImageDimensions(0, 0);
image.Width = 0;
image.Height = 0;
- continue;
}
try
{
- image.BlurHash = _imageProcessor.GetImageBlurHash(image.Path);
+ image.BlurHash = _imageProcessor.GetImageBlurHash(image.Path, size);
}
catch (Exception ex)
{
diff --git a/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj b/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj
index 495c5b860..4de4b231d 100644
--- a/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj
+++ b/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj
@@ -20,6 +20,7 @@
<PackageReference Include="BlurHashSharp.SkiaSharp" Version="1.2.0" />
<PackageReference Include="SkiaSharp" Version="2.88.1-preview.1" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="2.88.1-preview.1" />
+ <PackageReference Include="SkiaSharp.Svg" Version="1.60.0" />
</ItemGroup>
<ItemGroup>
diff --git a/Jellyfin.Drawing.Skia/SkiaEncoder.cs b/Jellyfin.Drawing.Skia/SkiaEncoder.cs
index 2358fe623..687528231 100644
--- a/Jellyfin.Drawing.Skia/SkiaEncoder.cs
+++ b/Jellyfin.Drawing.Skia/SkiaEncoder.cs
@@ -10,7 +10,7 @@ using MediaBrowser.Controller.Drawing;
using MediaBrowser.Model.Drawing;
using Microsoft.Extensions.Logging;
using SkiaSharp;
-using static Jellyfin.Drawing.Skia.SkiaHelper;
+using SKSvg = SkiaSharp.Extended.Svg.SKSvg;
namespace Jellyfin.Drawing.Skia
{
@@ -19,8 +19,7 @@ namespace Jellyfin.Drawing.Skia
/// </summary>
public class SkiaEncoder : IImageEncoder
{
- private static readonly HashSet<string> _transparentImageTypes
- = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { ".png", ".gif", ".webp" };
+ private static readonly HashSet<string> _transparentImageTypes = new(StringComparer.OrdinalIgnoreCase) { ".png", ".gif", ".webp" };
private readonly ILogger<SkiaEncoder> _logger;
private readonly IApplicationPaths _appPaths;
@@ -71,7 +70,7 @@ namespace Jellyfin.Drawing.Skia
/// <inheritdoc/>
public IReadOnlyCollection<ImageFormat> SupportedOutputFormats
- => new HashSet<ImageFormat>() { ImageFormat.Webp, ImageFormat.Jpg, ImageFormat.Png };
+ => new HashSet<ImageFormat> { ImageFormat.Webp, ImageFormat.Jpg, ImageFormat.Png };
/// <summary>
/// Check if the native lib is available.
@@ -109,9 +108,7 @@ namespace Jellyfin.Drawing.Skia
}
/// <inheritdoc />
- /// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="FileNotFoundException">The path is not valid.</exception>
- /// <exception cref="SkiaCodecException">The file at the specified path could not be used to generate a codec.</exception>
public ImageDimensions GetImageSize(string path)
{
if (!File.Exists(path))
@@ -119,12 +116,27 @@ namespace Jellyfin.Drawing.Skia
throw new FileNotFoundException("File not found", path);
}
- using var codec = SKCodec.Create(path, out SKCodecResult result);
- EnsureSuccess(result);
-
- var info = codec.Info;
+ var extension = Path.GetExtension(path.AsSpan());
+ if (extension.Equals(".svg", StringComparison.OrdinalIgnoreCase))
+ {
+ var svg = new SKSvg();
+ svg.Load(path);
+ return new ImageDimensions(Convert.ToInt32(svg.Picture.CullRect.Width), Convert.ToInt32(svg.Picture.CullRect.Height));
+ }
- return new ImageDimensions(info.Width, info.Height);
+ using var codec = SKCodec.Create(path, out SKCodecResult result);
+ switch (result)
+ {
+ case SKCodecResult.Success:
+ var info = codec.Info;
+ return new ImageDimensions(info.Width, info.Height);
+ case SKCodecResult.Unimplemented:
+ _logger.LogDebug("Image format not supported: {FilePath}", path);
+ return new ImageDimensions(0, 0);
+ default:
+ _logger.LogError("Unable to determine image dimensions for {FilePath}: {SkCodecResult}", path, result);
+ return new ImageDimensions(0, 0);
+ }
}
/// <inheritdoc />
@@ -138,6 +150,13 @@ namespace Jellyfin.Drawing.Skia
throw new ArgumentNullException(nameof(path));
}
+ var extension = Path.GetExtension(path.AsSpan()).TrimStart('.');
+ if (!SupportedInputFormats.Contains(extension, StringComparison.OrdinalIgnoreCase))
+ {
+ _logger.LogDebug("Unable to compute blur hash due to unsupported format: {ImagePath}", path);
+ return string.Empty;
+ }
+
// Any larger than 128x128 is too slow and there's no visually discernible difference
return BlurHashEncoder.Encode(xComp, yComp, path, 128, 128);
}
@@ -378,6 +397,13 @@ namespace Jellyfin.Drawing.Skia
throw new ArgumentException("String can't be empty.", nameof(outputPath));
}
+ var inputFormat = Path.GetExtension(inputPath.AsSpan()).TrimStart('.');
+ if (!SupportedInputFormats.Contains(inputFormat, StringComparison.OrdinalIgnoreCase))
+ {
+ _logger.LogDebug("Unable to encode image due to unsupported format: {ImagePath}", inputPath);
+ return inputPath;
+ }
+
var skiaOutputFormat = GetImageFormat(outputFormat);
var hasBackgroundColor = !string.IsNullOrWhiteSpace(options.BackgroundColor);
diff --git a/Jellyfin.Drawing.Skia/SkiaHelper.cs b/Jellyfin.Drawing.Skia/SkiaHelper.cs
index 35dcebdab..c001c32b8 100644
--- a/Jellyfin.Drawing.Skia/SkiaHelper.cs
+++ b/Jellyfin.Drawing.Skia/SkiaHelper.cs
@@ -9,19 +9,6 @@ namespace Jellyfin.Drawing.Skia
public static class SkiaHelper
{
/// <summary>
- /// Ensures the result is a success
- /// by throwing an exception when that's not the case.
- /// </summary>
- /// <param name="result">The result returned by Skia.</param>
- public static void EnsureSuccess(SKCodecResult result)
- {
- if (result != SKCodecResult.Success)
- {
- throw new SkiaCodecException(result);
- }
- }
-
- /// <summary>
/// Gets the next valid image as a bitmap.
/// </summary>
/// <param name="skiaEncoder">The current skia encoder.</param>
diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
index 03882a0b9..e5ce0aa21 100644
--- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs
+++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
@@ -51,6 +51,14 @@ namespace MediaBrowser.Controller.Drawing
string GetImageBlurHash(string path);
/// <summary>
+ /// Gets the blurhash of the image.
+ /// </summary>
+ /// <param name="path">Path to the image file.</param>
+ /// <param name="imageDimensions">The image dimensions.</param>
+ /// <returns>BlurHash.</returns>
+ string GetImageBlurHash(string path, ImageDimensions imageDimensions);
+
+ /// <summary>
/// Gets the image cache tag.
/// </summary>
/// <param name="item">The item.</param>