|
|
|
@ -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);
|
|
|
|
|