mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
Update skiasharp monorepo (major) (#13369)
This commit is contained in:
parent
43659f011c
commit
cdbf4752b9
@ -10,15 +10,15 @@
|
|||||||
<PackageVersion Include="AutoFixture" Version="4.18.1" />
|
<PackageVersion Include="AutoFixture" Version="4.18.1" />
|
||||||
<PackageVersion Include="BDInfo" Version="0.8.0" />
|
<PackageVersion Include="BDInfo" Version="0.8.0" />
|
||||||
<PackageVersion Include="BitFaster.Caching" Version="2.5.3" />
|
<PackageVersion Include="BitFaster.Caching" Version="2.5.3" />
|
||||||
<PackageVersion Include="BlurHashSharp.SkiaSharp" Version="1.3.4" />
|
<PackageVersion Include="BlurHashSharp.SkiaSharp" Version="1.4.0-pre.1" />
|
||||||
<PackageVersion Include="BlurHashSharp" Version="1.3.4" />
|
<PackageVersion Include="BlurHashSharp" Version="1.4.0-pre.1" />
|
||||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||||
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
|
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
|
||||||
<PackageVersion Include="Diacritics" Version="3.3.29" />
|
<PackageVersion Include="Diacritics" Version="3.3.29" />
|
||||||
<PackageVersion Include="DiscUtils.Udf" Version="0.16.13" />
|
<PackageVersion Include="DiscUtils.Udf" Version="0.16.13" />
|
||||||
<PackageVersion Include="DotNet.Glob" Version="3.1.3" />
|
<PackageVersion Include="DotNet.Glob" Version="3.1.3" />
|
||||||
<PackageVersion Include="FsCheck.Xunit" Version="3.2.0" />
|
<PackageVersion Include="FsCheck.Xunit" Version="3.2.0" />
|
||||||
<PackageVersion Include="HarfBuzzSharp.NativeAssets.Linux" Version="7.3.0.3" />
|
<PackageVersion Include="HarfBuzzSharp.NativeAssets.Linux" Version="8.3.1.1" />
|
||||||
<PackageVersion Include="ICU4N.Transliterator" Version="60.1.0-alpha.356" />
|
<PackageVersion Include="ICU4N.Transliterator" Version="60.1.0-alpha.356" />
|
||||||
<PackageVersion Include="IDisposableAnalyzers" Version="4.0.8" />
|
<PackageVersion Include="IDisposableAnalyzers" Version="4.0.8" />
|
||||||
<PackageVersion Include="Ignore" Version="0.2.1" />
|
<PackageVersion Include="Ignore" Version="0.2.1" />
|
||||||
@ -67,12 +67,12 @@
|
|||||||
<PackageVersion Include="Serilog.Sinks.Graylog" Version="3.1.1" />
|
<PackageVersion Include="Serilog.Sinks.Graylog" Version="3.1.1" />
|
||||||
<PackageVersion Include="SerilogAnalyzer" Version="0.15.0" />
|
<PackageVersion Include="SerilogAnalyzer" Version="0.15.0" />
|
||||||
<PackageVersion Include="SharpFuzz" Version="2.2.0" />
|
<PackageVersion Include="SharpFuzz" Version="2.2.0" />
|
||||||
<PackageVersion Include="SkiaSharp" Version="2.88.9" />
|
<PackageVersion Include="SkiaSharp" Version="3.119.0" />
|
||||||
<PackageVersion Include="SkiaSharp.HarfBuzz" Version="2.88.9" />
|
<PackageVersion Include="SkiaSharp.HarfBuzz" Version="3.119.0" />
|
||||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
|
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="3.119.0" />
|
||||||
<PackageVersion Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" />
|
<PackageVersion Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" />
|
||||||
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
|
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
|
||||||
<PackageVersion Include="Svg.Skia" Version="2.0.0.8" />
|
<PackageVersion Include="Svg.Skia" Version="3.0.2" />
|
||||||
<PackageVersion Include="Swashbuckle.AspNetCore.ReDoc" Version="6.5.0" />
|
<PackageVersion Include="Swashbuckle.AspNetCore.ReDoc" Version="6.5.0" />
|
||||||
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.2.3" />
|
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.2.3" />
|
||||||
<PackageVersion Include="System.Globalization" Version="4.3.0" />
|
<PackageVersion Include="System.Globalization" Version="4.3.0" />
|
||||||
@ -89,4 +89,4 @@
|
|||||||
<PackageVersion Include="Xunit.SkippableFact" Version="1.5.23" />
|
<PackageVersion Include="Xunit.SkippableFact" Version="1.5.23" />
|
||||||
<PackageVersion Include="xunit" Version="2.9.3" />
|
<PackageVersion Include="xunit" Version="2.9.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -27,6 +27,16 @@ public class SkiaEncoder : IImageEncoder
|
|||||||
private static readonly SKImageFilter _imageFilter;
|
private static readonly SKImageFilter _imageFilter;
|
||||||
private static readonly SKTypeface[] _typefaces;
|
private static readonly SKTypeface[] _typefaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default sampling options, equivalent to old high quality filter settings when upscaling.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly SKSamplingOptions UpscaleSamplingOptions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The sampling options, used for downscaling images, equivalent to old high quality filter settings when not upscaling.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly SKSamplingOptions DefaultSamplingOptions;
|
||||||
|
|
||||||
#pragma warning disable CA1810
|
#pragma warning disable CA1810
|
||||||
static SkiaEncoder()
|
static SkiaEncoder()
|
||||||
#pragma warning restore CA1810
|
#pragma warning restore CA1810
|
||||||
@ -63,6 +73,11 @@ public class SkiaEncoder : IImageEncoder
|
|||||||
SKFontManager.Default.MatchCharacter(null, SKFontStyleWeight.Bold, SKFontStyleWidth.Normal, SKFontStyleSlant.Upright, null, 'ي'), // Arabic
|
SKFontManager.Default.MatchCharacter(null, SKFontStyleWeight.Bold, SKFontStyleWidth.Normal, SKFontStyleSlant.Upright, null, 'ي'), // Arabic
|
||||||
SKTypeface.FromFamilyName("sans-serif", SKFontStyleWeight.Bold, SKFontStyleWidth.Normal, SKFontStyleSlant.Upright) // Default font
|
SKTypeface.FromFamilyName("sans-serif", SKFontStyleWeight.Bold, SKFontStyleWidth.Normal, SKFontStyleSlant.Upright) // Default font
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// use cubic for upscaling
|
||||||
|
UpscaleSamplingOptions = new SKSamplingOptions(SKCubicResampler.Mitchell);
|
||||||
|
// use bilinear for everything else
|
||||||
|
DefaultSamplingOptions = new SKSamplingOptions(SKFilterMode.Linear, SKMipmapMode.Linear);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -441,7 +456,7 @@ public class SkiaEncoder : IImageEncoder
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
surface.DrawBitmap(bitmap, 0, 0);
|
surface.DrawBitmap(bitmap, 0, 0, DefaultSamplingOptions);
|
||||||
return rotated;
|
return rotated;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -467,18 +482,23 @@ public class SkiaEncoder : IImageEncoder
|
|||||||
{
|
{
|
||||||
using var surface = SKSurface.Create(targetInfo);
|
using var surface = SKSurface.Create(targetInfo);
|
||||||
using var canvas = surface.Canvas;
|
using var canvas = surface.Canvas;
|
||||||
using var paint = new SKPaint
|
using var paint = new SKPaint();
|
||||||
{
|
paint.IsAntialias = isAntialias;
|
||||||
FilterQuality = SKFilterQuality.High,
|
paint.IsDither = isDither;
|
||||||
IsAntialias = isAntialias,
|
|
||||||
IsDither = isDither
|
// Historically, kHigh implied cubic filtering, but only when upsampling.
|
||||||
};
|
// If specified kHigh, and were down-sampling, Skia used to switch back to kMedium (bilinear filtering plus mipmaps).
|
||||||
|
// With current skia API, passing Mitchell cubic when down-sampling will cause serious quality degradation.
|
||||||
|
var samplingOptions = source.Width > targetInfo.Width || source.Height > targetInfo.Height
|
||||||
|
? DefaultSamplingOptions
|
||||||
|
: UpscaleSamplingOptions;
|
||||||
|
|
||||||
paint.ImageFilter = _imageFilter;
|
paint.ImageFilter = _imageFilter;
|
||||||
canvas.DrawBitmap(
|
canvas.DrawBitmap(
|
||||||
source,
|
source,
|
||||||
SKRect.Create(0, 0, source.Width, source.Height),
|
SKRect.Create(0, 0, source.Width, source.Height),
|
||||||
SKRect.Create(0, 0, targetInfo.Width, targetInfo.Height),
|
SKRect.Create(0, 0, targetInfo.Width, targetInfo.Height),
|
||||||
|
samplingOptions,
|
||||||
paint);
|
paint);
|
||||||
|
|
||||||
return surface.Snapshot();
|
return surface.Snapshot();
|
||||||
@ -560,11 +580,10 @@ public class SkiaEncoder : IImageEncoder
|
|||||||
using var paint = new SKPaint();
|
using var paint = new SKPaint();
|
||||||
// Add blur if option is present
|
// Add blur if option is present
|
||||||
using var filter = blur > 0 ? SKImageFilter.CreateBlur(blur, blur) : null;
|
using var filter = blur > 0 ? SKImageFilter.CreateBlur(blur, blur) : null;
|
||||||
paint.FilterQuality = SKFilterQuality.High;
|
|
||||||
paint.ImageFilter = filter;
|
paint.ImageFilter = filter;
|
||||||
|
|
||||||
// create image from resized bitmap to apply blur
|
// create image from resized bitmap to apply blur
|
||||||
canvas.DrawBitmap(resizedBitmap, SKRect.Create(width, height), paint);
|
canvas.DrawBitmap(resizedBitmap, SKRect.Create(width, height), DefaultSamplingOptions, paint);
|
||||||
|
|
||||||
// If foreground layer present then draw
|
// If foreground layer present then draw
|
||||||
if (hasForegroundColor)
|
if (hasForegroundColor)
|
||||||
@ -690,7 +709,7 @@ public class SkiaEncoder : IImageEncoder
|
|||||||
throw new InvalidOperationException("Image height does not match first image height.");
|
throw new InvalidOperationException("Image height does not match first image height.");
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.DrawBitmap(img, x * imgWidth, y * imgHeight.Value);
|
canvas.DrawBitmap(img, x * imgWidth, y * imgHeight.Value, DefaultSamplingOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
58
src/Jellyfin.Drawing.Skia/SkiaExtensions.cs
Normal file
58
src/Jellyfin.Drawing.Skia/SkiaExtensions.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
using SkiaSharp;
|
||||||
|
|
||||||
|
namespace Jellyfin.Drawing.Skia;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The SkiaSharp extensions.
|
||||||
|
/// </summary>
|
||||||
|
public static class SkiaExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Draws an SKBitmap on the canvas with specified SkSamplingOptions.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="canvas">The SKCanvas to draw on.</param>
|
||||||
|
/// <param name="bitmap">The SKBitmap to draw.</param>
|
||||||
|
/// <param name="dest">The destination SKRect.</param>
|
||||||
|
/// <param name="options">The SKSamplingOptions to use for rendering.</param>
|
||||||
|
/// <param name="paint">Optional SKPaint to apply additional effects or styles.</param>
|
||||||
|
public static void DrawBitmap(this SKCanvas canvas, SKBitmap bitmap, SKRect dest, SKSamplingOptions options, SKPaint? paint = null)
|
||||||
|
{
|
||||||
|
using var image = SKImage.FromBitmap(bitmap);
|
||||||
|
canvas.DrawImage(image, dest, options, paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Draws an SKBitmap on the canvas at the specified coordinates with the given SkSamplingOptions.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="canvas">The SKCanvas to draw on.</param>
|
||||||
|
/// <param name="bitmap">The SKBitmap to draw.</param>
|
||||||
|
/// <param name="x">The x-coordinate where the bitmap will be drawn.</param>
|
||||||
|
/// <param name="y">The y-coordinate where the bitmap will be drawn.</param>
|
||||||
|
/// <param name="options">The SKSamplingOptions to use for rendering.</param>
|
||||||
|
/// <param name="paint">Optional SKPaint to apply additional effects or styles.</param>
|
||||||
|
public static void DrawBitmap(this SKCanvas canvas, SKBitmap bitmap, float x, float y, SKSamplingOptions options, SKPaint? paint = null)
|
||||||
|
{
|
||||||
|
using var image = SKImage.FromBitmap(bitmap);
|
||||||
|
canvas.DrawImage(image, x, y, options, paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Draws an SKBitmap on the canvas using a specified source rectangle, destination rectangle,
|
||||||
|
/// and optional paint, with the given SkSamplingOptions.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="canvas">The SKCanvas to draw on.</param>
|
||||||
|
/// <param name="bitmap">The SKBitmap to draw.</param>
|
||||||
|
/// <param name="source">
|
||||||
|
/// The source SKRect defining the portion of the bitmap to draw.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="dest">
|
||||||
|
/// The destination SKRect defining the area on the canvas where the bitmap will be drawn.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="options">The SKSamplingOptions to use for rendering.</param>
|
||||||
|
/// <param name="paint">Optional SKPaint to apply additional effects or styles.</param>
|
||||||
|
public static void DrawBitmap(this SKCanvas canvas, SKBitmap bitmap, SKRect source, SKRect dest, SKSamplingOptions options, SKPaint? paint = null)
|
||||||
|
{
|
||||||
|
using var image = SKImage.FromBitmap(bitmap);
|
||||||
|
canvas.DrawImage(image, source, dest, options, paint);
|
||||||
|
}
|
||||||
|
}
|
@ -101,10 +101,12 @@ public class SplashscreenBuilder
|
|||||||
{
|
{
|
||||||
var imageWidth = Math.Abs(posterHeight * currentImage.Width / currentImage.Height);
|
var imageWidth = Math.Abs(posterHeight * currentImage.Width / currentImage.Height);
|
||||||
using var resizedBitmap = new SKBitmap(imageWidth, posterHeight);
|
using var resizedBitmap = new SKBitmap(imageWidth, posterHeight);
|
||||||
currentImage.ScalePixels(resizedBitmap, SKFilterQuality.High);
|
var samplingOptions = currentImage.Width > imageWidth || currentImage.Height > posterHeight
|
||||||
|
? SkiaEncoder.DefaultSamplingOptions
|
||||||
|
: SkiaEncoder.UpscaleSamplingOptions;
|
||||||
|
currentImage.ScalePixels(resizedBitmap, samplingOptions);
|
||||||
// draw on canvas
|
// draw on canvas
|
||||||
canvas.DrawBitmap(resizedBitmap, currentWidthPos, currentHeight);
|
canvas.DrawBitmap(resizedBitmap, currentWidthPos, currentHeight, samplingOptions);
|
||||||
|
|
||||||
// resize to the same aspect as the original
|
// resize to the same aspect as the original
|
||||||
currentWidthPos += imageWidth + Spacing;
|
currentWidthPos += imageWidth + Spacing;
|
||||||
|
@ -111,38 +111,31 @@ public partial class StripCollageBuilder
|
|||||||
var backdropHeight = Math.Abs(width * backdrop.Height / backdrop.Width);
|
var backdropHeight = Math.Abs(width * backdrop.Height / backdrop.Width);
|
||||||
using var resizedBackdrop = SkiaEncoder.ResizeImage(backdrop, new SKImageInfo(width, backdropHeight, backdrop.ColorType, backdrop.AlphaType, backdrop.ColorSpace));
|
using var resizedBackdrop = SkiaEncoder.ResizeImage(backdrop, new SKImageInfo(width, backdropHeight, backdrop.ColorType, backdrop.AlphaType, backdrop.ColorSpace));
|
||||||
using var paint = new SKPaint();
|
using var paint = new SKPaint();
|
||||||
paint.FilterQuality = SKFilterQuality.High;
|
|
||||||
// draw the backdrop
|
// draw the backdrop
|
||||||
canvas.DrawImage(resizedBackdrop, 0, 0, paint);
|
canvas.DrawImage(resizedBackdrop, 0, 0, SkiaEncoder.DefaultSamplingOptions, paint);
|
||||||
|
|
||||||
// draw shadow rectangle
|
// draw shadow rectangle
|
||||||
using var paintColor = new SKPaint
|
using var paintColor = new SKPaint();
|
||||||
{
|
paintColor.Color = SKColors.Black.WithAlpha(0x78);
|
||||||
Color = SKColors.Black.WithAlpha(0x78),
|
paintColor.Style = SKPaintStyle.Fill;
|
||||||
Style = SKPaintStyle.Fill,
|
|
||||||
FilterQuality = SKFilterQuality.High
|
|
||||||
};
|
|
||||||
canvas.DrawRect(0, 0, width, height, paintColor);
|
canvas.DrawRect(0, 0, width, height, paintColor);
|
||||||
|
|
||||||
var typeFace = SkiaEncoder.DefaultTypeFace;
|
var typeFace = SkiaEncoder.DefaultTypeFace;
|
||||||
|
|
||||||
// draw library name
|
// draw library name
|
||||||
using var textPaint = new SKPaint
|
using var textFont = new SKFont();
|
||||||
{
|
textFont.Size = 112;
|
||||||
Color = SKColors.White,
|
textFont.Typeface = typeFace;
|
||||||
Style = SKPaintStyle.Fill,
|
using var textPaint = new SKPaint();
|
||||||
TextSize = 112,
|
textPaint.Color = SKColors.White;
|
||||||
TextAlign = SKTextAlign.Left,
|
textPaint.Style = SKPaintStyle.Fill;
|
||||||
Typeface = typeFace,
|
textPaint.IsAntialias = true;
|
||||||
IsAntialias = true,
|
|
||||||
FilterQuality = SKFilterQuality.High
|
|
||||||
};
|
|
||||||
|
|
||||||
// scale down text to 90% of the width if text is larger than 95% of the width
|
// scale down text to 90% of the width if text is larger than 95% of the width
|
||||||
var textWidth = textPaint.MeasureText(libraryName);
|
var textWidth = textFont.MeasureText(libraryName);
|
||||||
if (textWidth > width * 0.95)
|
if (textWidth > width * 0.95)
|
||||||
{
|
{
|
||||||
textPaint.TextSize = 0.9f * width * textPaint.TextSize / textWidth;
|
textFont.Size = 0.9f * width * textFont.Size / textWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(libraryName))
|
if (string.IsNullOrWhiteSpace(libraryName))
|
||||||
@ -150,23 +143,22 @@ public partial class StripCollageBuilder
|
|||||||
return bitmap;
|
return bitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
var realWidth = DrawText(null, 0, (height / 2f) + (textPaint.FontMetrics.XHeight / 2), libraryName, textPaint);
|
var realWidth = DrawText(null, 0, (height / 2f) + (textFont.Metrics.XHeight / 2), libraryName, textPaint, textFont);
|
||||||
if (realWidth > width * 0.95)
|
if (realWidth > width * 0.95)
|
||||||
{
|
{
|
||||||
textPaint.TextSize = 0.9f * width * textPaint.TextSize / realWidth;
|
textFont.Size = 0.9f * width * textFont.Size / realWidth;
|
||||||
realWidth = DrawText(null, 0, (height / 2f) + (textPaint.FontMetrics.XHeight / 2), libraryName, textPaint);
|
realWidth = DrawText(null, 0, (height / 2f) + (textFont.Metrics.XHeight / 2), libraryName, textPaint, textFont);
|
||||||
}
|
}
|
||||||
|
|
||||||
var padding = (width - realWidth) / 2;
|
var padding = (width - realWidth) / 2;
|
||||||
|
|
||||||
if (IsRtlTextRegex().IsMatch(libraryName))
|
if (IsRtlTextRegex().IsMatch(libraryName))
|
||||||
{
|
{
|
||||||
textPaint.TextAlign = SKTextAlign.Right;
|
DrawText(canvas, width - padding, (height / 2f) + (textFont.Metrics.XHeight / 2), libraryName, textPaint, textFont, true);
|
||||||
DrawText(canvas, width - padding, (height / 2f) + (textPaint.FontMetrics.XHeight / 2), libraryName, textPaint, true);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DrawText(canvas, padding, (height / 2f) + (textPaint.FontMetrics.XHeight / 2), libraryName, textPaint);
|
DrawText(canvas, padding, (height / 2f) + (textFont.Metrics.XHeight / 2), libraryName, textPaint, textFont);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bitmap;
|
return bitmap;
|
||||||
@ -196,12 +188,11 @@ public partial class StripCollageBuilder
|
|||||||
var imageInfo = new SKImageInfo(cellWidth, cellHeight, currentBitmap.ColorType, currentBitmap.AlphaType, currentBitmap.ColorSpace);
|
var imageInfo = new SKImageInfo(cellWidth, cellHeight, currentBitmap.ColorType, currentBitmap.AlphaType, currentBitmap.ColorSpace);
|
||||||
using var resizeImage = SkiaEncoder.ResizeImage(currentBitmap, imageInfo);
|
using var resizeImage = SkiaEncoder.ResizeImage(currentBitmap, imageInfo);
|
||||||
using var paint = new SKPaint();
|
using var paint = new SKPaint();
|
||||||
paint.FilterQuality = 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;
|
||||||
var yPos = y * cellHeight;
|
var yPos = y * cellHeight;
|
||||||
canvas.DrawImage(resizeImage, xPos, yPos, paint);
|
canvas.DrawImage(resizeImage, xPos, yPos, SkiaEncoder.DefaultSamplingOptions, paint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,11 +207,13 @@ public partial class StripCollageBuilder
|
|||||||
/// <param name="y">y position of the canvas to draw text.</param>
|
/// <param name="y">y position of the canvas to draw text.</param>
|
||||||
/// <param name="text">The text to draw.</param>
|
/// <param name="text">The text to draw.</param>
|
||||||
/// <param name="textPaint">The SKPaint to style the text.</param>
|
/// <param name="textPaint">The SKPaint to style the text.</param>
|
||||||
|
/// <param name="textFont">The SKFont to style the text.</param>
|
||||||
|
/// <param name="alignment">The alignment of the text. Default aligns to left.</param>
|
||||||
/// <returns>The width of the text.</returns>
|
/// <returns>The width of the text.</returns>
|
||||||
private static float MeasureAndDrawText(SKCanvas? canvas, float x, float y, string text, SKPaint textPaint)
|
private static float MeasureAndDrawText(SKCanvas? canvas, float x, float y, string text, SKPaint textPaint, SKFont textFont, SKTextAlign alignment = SKTextAlign.Left)
|
||||||
{
|
{
|
||||||
var width = textPaint.MeasureText(text);
|
var width = textFont.MeasureText(text);
|
||||||
canvas?.DrawShapedText(text, x, y, textPaint);
|
canvas?.DrawShapedText(text, x, y, alignment, textFont, textPaint);
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,16 +225,18 @@ public partial class StripCollageBuilder
|
|||||||
/// <param name="y">y position of the canvas to draw text.</param>
|
/// <param name="y">y position of the canvas to draw text.</param>
|
||||||
/// <param name="text">The text to draw.</param>
|
/// <param name="text">The text to draw.</param>
|
||||||
/// <param name="textPaint">The SKPaint to style the text.</param>
|
/// <param name="textPaint">The SKPaint to style the text.</param>
|
||||||
|
/// <param name="textFont">The SKFont to style the text.</param>
|
||||||
/// <param name="isRtl">If true, render from right to left.</param>
|
/// <param name="isRtl">If true, render from right to left.</param>
|
||||||
/// <returns>The width of the text.</returns>
|
/// <returns>The width of the text.</returns>
|
||||||
private static float DrawText(SKCanvas? canvas, float x, float y, string text, SKPaint textPaint, bool isRtl = false)
|
private static float DrawText(SKCanvas? canvas, float x, float y, string text, SKPaint textPaint, SKFont textFont, bool isRtl = false)
|
||||||
{
|
{
|
||||||
float width = 0;
|
float width = 0;
|
||||||
|
var alignment = isRtl ? SKTextAlign.Right : SKTextAlign.Left;
|
||||||
|
|
||||||
if (textPaint.ContainsGlyphs(text))
|
if (textFont.ContainsGlyphs(text))
|
||||||
{
|
{
|
||||||
// Current font can render all characters in text
|
// Current font can render all characters in text
|
||||||
return MeasureAndDrawText(canvas, x, y, text, textPaint);
|
return MeasureAndDrawText(canvas, x, y, text, textPaint, textFont, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over all text elements using TextElementEnumerator
|
// Iterate over all text elements using TextElementEnumerator
|
||||||
@ -254,7 +249,7 @@ public partial class StripCollageBuilder
|
|||||||
{
|
{
|
||||||
bool notAtEnd;
|
bool notAtEnd;
|
||||||
var textElement = enumerator.GetTextElement();
|
var textElement = enumerator.GetTextElement();
|
||||||
if (textPaint.ContainsGlyphs(textElement))
|
if (textFont.ContainsGlyphs(textElement))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -264,12 +259,12 @@ public partial class StripCollageBuilder
|
|||||||
if (start != enumerator.ElementIndex)
|
if (start != enumerator.ElementIndex)
|
||||||
{
|
{
|
||||||
var regularText = text.Substring(start, enumerator.ElementIndex - start);
|
var regularText = text.Substring(start, enumerator.ElementIndex - start);
|
||||||
width += MeasureAndDrawText(canvas, MoveX(x, width), y, regularText, textPaint);
|
width += MeasureAndDrawText(canvas, MoveX(x, width), y, regularText, textPaint, textFont, alignment);
|
||||||
start = enumerator.ElementIndex;
|
start = enumerator.ElementIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search for next point where current font can render the character there
|
// Search for next point where current font can render the character there
|
||||||
while ((notAtEnd = enumerator.MoveNext()) && !textPaint.ContainsGlyphs(enumerator.GetTextElement()))
|
while ((notAtEnd = enumerator.MoveNext()) && !textFont.ContainsGlyphs(enumerator.GetTextElement()))
|
||||||
{
|
{
|
||||||
// Do nothing, just move enumerator to the point where current font can render the character
|
// Do nothing, just move enumerator to the point where current font can render the character
|
||||||
}
|
}
|
||||||
@ -284,21 +279,21 @@ public partial class StripCollageBuilder
|
|||||||
|
|
||||||
if (fallback is not null)
|
if (fallback is not null)
|
||||||
{
|
{
|
||||||
|
using var fallbackTextFont = new SKFont();
|
||||||
|
fallbackTextFont.Size = textFont.Size;
|
||||||
|
fallbackTextFont.Typeface = fallback;
|
||||||
using var fallbackTextPaint = new SKPaint();
|
using var fallbackTextPaint = new SKPaint();
|
||||||
fallbackTextPaint.Color = textPaint.Color;
|
fallbackTextPaint.Color = textPaint.Color;
|
||||||
fallbackTextPaint.Style = textPaint.Style;
|
fallbackTextPaint.Style = textPaint.Style;
|
||||||
fallbackTextPaint.TextSize = textPaint.TextSize;
|
|
||||||
fallbackTextPaint.TextAlign = textPaint.TextAlign;
|
|
||||||
fallbackTextPaint.Typeface = fallback;
|
|
||||||
fallbackTextPaint.IsAntialias = textPaint.IsAntialias;
|
fallbackTextPaint.IsAntialias = textPaint.IsAntialias;
|
||||||
|
|
||||||
// Do the search recursively to select all possible fonts
|
// Do the search recursively to select all possible fonts
|
||||||
width += DrawText(canvas, MoveX(x, width), y, subtext, fallbackTextPaint, isRtl);
|
width += DrawText(canvas, MoveX(x, width), y, subtext, fallbackTextPaint, fallbackTextFont, isRtl);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Used up all fonts and no fonts can be found, just use current font
|
// Used up all fonts and no fonts can be found, just use current font
|
||||||
width += MeasureAndDrawText(canvas, MoveX(x, width), y, text[start..], textPaint);
|
width += MeasureAndDrawText(canvas, MoveX(x, width), y, text[start..], textPaint, textFont, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
start = notAtEnd ? enumerator.ElementIndex : text.Length;
|
start = notAtEnd ? enumerator.ElementIndex : text.Length;
|
||||||
@ -307,7 +302,7 @@ public partial class StripCollageBuilder
|
|||||||
// Render the remaining text that current fonts can render
|
// Render the remaining text that current fonts can render
|
||||||
if (start < text.Length)
|
if (start < text.Length)
|
||||||
{
|
{
|
||||||
width += MeasureAndDrawText(canvas, MoveX(x, width), y, text[start..], textPaint);
|
width += MeasureAndDrawText(canvas, MoveX(x, width), y, text[start..], textPaint, textFont, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
return width;
|
return width;
|
||||||
|
@ -34,10 +34,12 @@ public static class UnplayedCountIndicator
|
|||||||
Style = SKPaintStyle.Fill
|
Style = SKPaintStyle.Fill
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using var font = new SKFont();
|
||||||
|
|
||||||
canvas.DrawCircle(x, OffsetFromTopRightCorner, 20, paint);
|
canvas.DrawCircle(x, OffsetFromTopRightCorner, 20, paint);
|
||||||
|
|
||||||
paint.Color = new SKColor(255, 255, 255, 255);
|
paint.Color = new SKColor(255, 255, 255, 255);
|
||||||
paint.TextSize = 24;
|
font.Size = 24;
|
||||||
paint.IsAntialias = true;
|
paint.IsAntialias = true;
|
||||||
|
|
||||||
var y = OffsetFromTopRightCorner + 9;
|
var y = OffsetFromTopRightCorner + 9;
|
||||||
@ -55,9 +57,9 @@ public static class UnplayedCountIndicator
|
|||||||
{
|
{
|
||||||
x -= 15;
|
x -= 15;
|
||||||
y -= 2;
|
y -= 2;
|
||||||
paint.TextSize = 18;
|
font.Size = 18;
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.DrawText(text, x, y, paint);
|
canvas.DrawText(text, x, y, font, paint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user