mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-06-23 15:30:56 -04:00
Merge pull request #2771 from Bond-009/nullable4
Enable nullabe reference types for Emby.Drawing and Jellyfin.Drawing.Skia
This commit is contained in:
commit
aa6d52277d
@ -1,3 +1,4 @@
|
|||||||
|
#nullable enable
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -116,11 +116,6 @@ namespace Emby.Drawing
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<(string path, string mimeType, DateTime dateModified)> ProcessImage(ImageProcessingOptions options)
|
public async Task<(string path, string mimeType, DateTime dateModified)> ProcessImage(ImageProcessingOptions options)
|
||||||
{
|
{
|
||||||
if (options == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(options));
|
|
||||||
}
|
|
||||||
|
|
||||||
ItemImageInfo originalImage = options.Image;
|
ItemImageInfo originalImage = options.Image;
|
||||||
BaseItem item = options.Item;
|
BaseItem item = options.Item;
|
||||||
|
|
||||||
@ -325,19 +320,12 @@ namespace Emby.Drawing
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string GetImageCacheTag(BaseItem item, ChapterInfo chapter)
|
public string GetImageCacheTag(BaseItem item, ChapterInfo chapter)
|
||||||
{
|
{
|
||||||
try
|
return GetImageCacheTag(item, new ItemImageInfo
|
||||||
{
|
{
|
||||||
return GetImageCacheTag(item, new ItemImageInfo
|
Path = chapter.ImagePath,
|
||||||
{
|
Type = ImageType.Chapter,
|
||||||
Path = chapter.ImagePath,
|
DateModified = chapter.ImageDateModified
|
||||||
Type = ImageType.Chapter,
|
});
|
||||||
DateModified = chapter.ImageDateModified
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<(string path, DateTime dateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified)
|
private async Task<(string path, DateTime dateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified)
|
||||||
|
@ -1990,7 +1990,14 @@ namespace Emby.Server.Implementations.Data
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(chapter.ImagePath))
|
if (!string.IsNullOrEmpty(chapter.ImagePath))
|
||||||
{
|
{
|
||||||
chapter.ImageTag = _imageProcessor.GetImageCacheTag(item, chapter);
|
try
|
||||||
|
{
|
||||||
|
chapter.ImageTag = _imageProcessor.GetImageCacheTag(item, chapter);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError(ex, "Failed to create image cache tag.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -26,7 +26,7 @@ namespace Jellyfin.Drawing.Skia
|
|||||||
{
|
{
|
||||||
paint.Color = SKColor.Parse("#CC00A4DC");
|
paint.Color = SKColor.Parse("#CC00A4DC");
|
||||||
paint.Style = SKPaintStyle.Fill;
|
paint.Style = SKPaintStyle.Fill;
|
||||||
canvas.DrawCircle((float)x, OffsetFromTopRightCorner, 20, paint);
|
canvas.DrawCircle(x, OffsetFromTopRightCorner, 20, paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var paint = new SKPaint())
|
using (var paint = new SKPaint())
|
||||||
@ -39,16 +39,13 @@ namespace Jellyfin.Drawing.Skia
|
|||||||
|
|
||||||
// or:
|
// or:
|
||||||
// var emojiChar = 0x1F680;
|
// var emojiChar = 0x1F680;
|
||||||
var text = "✔️";
|
const string Text = "✔️";
|
||||||
var emojiChar = StringUtilities.GetUnicodeCharacterCode(text, SKTextEncoding.Utf32);
|
var emojiChar = StringUtilities.GetUnicodeCharacterCode(Text, SKTextEncoding.Utf32);
|
||||||
|
|
||||||
// ask the font manager for a font with that character
|
// ask the font manager for a font with that character
|
||||||
var fontManager = SKFontManager.Default;
|
paint.Typeface = SKFontManager.Default.MatchCharacter(emojiChar);
|
||||||
var emojiTypeface = fontManager.MatchCharacter(emojiChar);
|
|
||||||
|
|
||||||
paint.Typeface = emojiTypeface;
|
canvas.DrawText(Text, (float)x - 20, OffsetFromTopRightCorner + 12, paint);
|
||||||
|
|
||||||
canvas.DrawText(text, (float)x - 20, OffsetFromTopRightCorner + 12, paint);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,11 +214,6 @@ namespace Jellyfin.Drawing.Skia
|
|||||||
/// <exception cref="SkiaCodecException">The file at the specified path could not be used to generate a codec.</exception>
|
/// <exception cref="SkiaCodecException">The file at the specified path could not be used to generate a codec.</exception>
|
||||||
public ImageDimensions GetImageSize(string path)
|
public ImageDimensions GetImageSize(string path)
|
||||||
{
|
{
|
||||||
if (path == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!File.Exists(path))
|
if (!File.Exists(path))
|
||||||
{
|
{
|
||||||
throw new FileNotFoundException("File not found", path);
|
throw new FileNotFoundException("File not found", path);
|
||||||
@ -306,7 +301,7 @@ namespace Jellyfin.Drawing.Skia
|
|||||||
/// <param name="orientation">The orientation of the image.</param>
|
/// <param name="orientation">The orientation of the image.</param>
|
||||||
/// <param name="origin">The detected origin of the image.</param>
|
/// <param name="origin">The detected origin of the image.</param>
|
||||||
/// <returns>The resulting bitmap of the image.</returns>
|
/// <returns>The resulting bitmap of the image.</returns>
|
||||||
internal SKBitmap Decode(string path, bool forceCleanBitmap, ImageOrientation? orientation, out SKEncodedOrigin origin)
|
internal SKBitmap? Decode(string path, bool forceCleanBitmap, ImageOrientation? orientation, out SKEncodedOrigin origin)
|
||||||
{
|
{
|
||||||
if (!File.Exists(path))
|
if (!File.Exists(path))
|
||||||
{
|
{
|
||||||
@ -357,12 +352,17 @@ namespace Jellyfin.Drawing.Skia
|
|||||||
return resultBitmap;
|
return resultBitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SKBitmap GetBitmap(string path, bool cropWhitespace, bool forceAnalyzeBitmap, ImageOrientation? orientation, out SKEncodedOrigin origin)
|
private SKBitmap? GetBitmap(string path, bool cropWhitespace, bool forceAnalyzeBitmap, ImageOrientation? orientation, out SKEncodedOrigin origin)
|
||||||
{
|
{
|
||||||
if (cropWhitespace)
|
if (cropWhitespace)
|
||||||
{
|
{
|
||||||
using (var bitmap = Decode(path, forceAnalyzeBitmap, orientation, out origin))
|
using (var bitmap = Decode(path, forceAnalyzeBitmap, orientation, out origin))
|
||||||
{
|
{
|
||||||
|
if (bitmap == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return CropWhiteSpace(bitmap);
|
return CropWhiteSpace(bitmap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -370,13 +370,11 @@ namespace Jellyfin.Drawing.Skia
|
|||||||
return Decode(path, forceAnalyzeBitmap, orientation, out origin);
|
return Decode(path, forceAnalyzeBitmap, orientation, out origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SKBitmap GetBitmap(string path, bool cropWhitespace, bool autoOrient, ImageOrientation? orientation)
|
private SKBitmap? GetBitmap(string path, bool cropWhitespace, bool autoOrient, ImageOrientation? orientation)
|
||||||
{
|
{
|
||||||
SKEncodedOrigin origin;
|
|
||||||
|
|
||||||
if (autoOrient)
|
if (autoOrient)
|
||||||
{
|
{
|
||||||
var bitmap = GetBitmap(path, cropWhitespace, true, orientation, out origin);
|
var bitmap = GetBitmap(path, cropWhitespace, true, orientation, out var origin);
|
||||||
|
|
||||||
if (bitmap != null && origin != SKEncodedOrigin.TopLeft)
|
if (bitmap != null && origin != SKEncodedOrigin.TopLeft)
|
||||||
{
|
{
|
||||||
@ -389,7 +387,7 @@ namespace Jellyfin.Drawing.Skia
|
|||||||
return bitmap;
|
return bitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetBitmap(path, cropWhitespace, false, orientation, out origin);
|
return GetBitmap(path, cropWhitespace, false, orientation, out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SKBitmap OrientImage(SKBitmap bitmap, SKEncodedOrigin origin)
|
private SKBitmap OrientImage(SKBitmap bitmap, SKEncodedOrigin origin)
|
||||||
@ -526,14 +524,14 @@ namespace Jellyfin.Drawing.Skia
|
|||||||
/// <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)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(inputPath))
|
if (inputPath.Length == 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(inputPath));
|
throw new ArgumentException("String can't be empty.", nameof(inputPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(inputPath))
|
if (outputPath.Length == 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(outputPath));
|
throw new ArgumentException("String can't be empty.", nameof(outputPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
var skiaOutputFormat = GetImageFormat(selectedOutputFormat);
|
var skiaOutputFormat = GetImageFormat(selectedOutputFormat);
|
||||||
@ -547,7 +545,7 @@ namespace Jellyfin.Drawing.Skia
|
|||||||
{
|
{
|
||||||
if (bitmap == null)
|
if (bitmap == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException($"Skia unable to read image {inputPath}");
|
throw new InvalidDataException($"Skia unable to read image {inputPath}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var originalImageSize = new ImageDimensions(bitmap.Width, bitmap.Height);
|
var originalImageSize = new ImageDimensions(bitmap.Width, bitmap.Height);
|
||||||
|
@ -120,13 +120,13 @@ namespace Jellyfin.Drawing.Skia
|
|||||||
}
|
}
|
||||||
|
|
||||||
// resize to the same aspect as the original
|
// resize to the same aspect as the original
|
||||||
int iWidth = (int)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 resizeBitmap = new SKBitmap(iWidth, iHeight, currentBitmap.ColorType, currentBitmap.AlphaType))
|
||||||
{
|
{
|
||||||
currentBitmap.ScalePixels(resizeBitmap, SKFilterQuality.High);
|
currentBitmap.ScalePixels(resizeBitmap, SKFilterQuality.High);
|
||||||
|
|
||||||
// crop image
|
// crop image
|
||||||
int ix = (int)Math.Abs((iWidth - iSlice) / 2);
|
int ix = Math.Abs((iWidth - iSlice) / 2);
|
||||||
using (var image = SKImage.FromBitmap(resizeBitmap))
|
using (var image = SKImage.FromBitmap(resizeBitmap))
|
||||||
using (var subset = image.Subset(SKRectI.Create(ix, 0, iSlice, iHeight)))
|
using (var subset = image.Subset(SKRectI.Create(ix, 0, iSlice, iHeight)))
|
||||||
{
|
{
|
||||||
@ -141,10 +141,10 @@ namespace Jellyfin.Drawing.Skia
|
|||||||
return bitmap;
|
return bitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SKBitmap GetNextValidImage(string[] paths, int currentIndex, out int newIndex)
|
private SKBitmap? GetNextValidImage(string[] paths, int currentIndex, out int newIndex)
|
||||||
{
|
{
|
||||||
var imagesTested = new Dictionary<int, int>();
|
var imagesTested = new Dictionary<int, int>();
|
||||||
SKBitmap bitmap = null;
|
SKBitmap? bitmap = null;
|
||||||
|
|
||||||
while (imagesTested.Count < paths.Length)
|
while (imagesTested.Count < paths.Length)
|
||||||
{
|
{
|
||||||
@ -153,7 +153,7 @@ namespace Jellyfin.Drawing.Skia
|
|||||||
currentIndex = 0;
|
currentIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bitmap = _skiaEncoder.Decode(paths[currentIndex], false, null, out var origin);
|
bitmap = _skiaEncoder.Decode(paths[currentIndex], false, null, out _);
|
||||||
|
|
||||||
imagesTested[currentIndex] = 0;
|
imagesTested[currentIndex] = 0;
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ namespace Jellyfin.Drawing.Skia
|
|||||||
{
|
{
|
||||||
paint.Color = SKColor.Parse("#CC00A4DC");
|
paint.Color = SKColor.Parse("#CC00A4DC");
|
||||||
paint.Style = SKPaintStyle.Fill;
|
paint.Style = SKPaintStyle.Fill;
|
||||||
canvas.DrawCircle((float)x, OffsetFromTopRightCorner, 20, paint);
|
canvas.DrawCircle(x, OffsetFromTopRightCorner, 20, paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var paint = new SKPaint())
|
using (var paint = new SKPaint())
|
||||||
@ -61,7 +61,7 @@ namespace Jellyfin.Drawing.Skia
|
|||||||
paint.TextSize = 18;
|
paint.TextSize = 18;
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.DrawText(text, (float)x, y, paint);
|
canvas.DrawText(text, x, y, paint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#nullable enable
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user