Merge pull request #3597 from barronpm/jellyfin-drawing-skia-cleanup

Jellyfin.Drawing.Skia Cleanup
This commit is contained in:
Anthony Lavado 2020-07-26 15:32:06 -07:00 committed by GitHub
commit 2f315bb0dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 270 additions and 448 deletions

View File

@ -19,22 +19,18 @@ namespace Jellyfin.Drawing.Skia
/// <param name="percent">The percentage played to display with the indicator.</param> /// <param name="percent">The percentage played to display with the indicator.</param>
public static void Process(SKCanvas canvas, ImageDimensions imageSize, double percent) public static void Process(SKCanvas canvas, ImageDimensions imageSize, double percent)
{ {
using (var paint = new SKPaint()) using var paint = new SKPaint();
{
var endX = imageSize.Width - 1; var endX = imageSize.Width - 1;
var endY = imageSize.Height - 1; var endY = imageSize.Height - 1;
paint.Color = SKColor.Parse("#99000000"); paint.Color = SKColor.Parse("#99000000");
paint.Style = SKPaintStyle.Fill; paint.Style = SKPaintStyle.Fill;
canvas.DrawRect(SKRect.Create(0, (float)endY - IndicatorHeight, (float)endX, (float)endY), paint); canvas.DrawRect(SKRect.Create(0, (float)endY - IndicatorHeight, endX, endY), paint);
double foregroundWidth = endX; double foregroundWidth = (endX * percent) / 100;
foregroundWidth *= percent;
foregroundWidth /= 100;
paint.Color = SKColor.Parse("#FF00A4DC"); paint.Color = SKColor.Parse("#FF00A4DC");
canvas.DrawRect(SKRect.Create(0, (float)endY - IndicatorHeight, Convert.ToInt32(foregroundWidth), (float)endY), paint); canvas.DrawRect(SKRect.Create(0, (float)endY - IndicatorHeight, Convert.ToInt32(foregroundWidth), endY), paint);
}
} }
} }
} }

View File

@ -22,18 +22,15 @@ namespace Jellyfin.Drawing.Skia
{ {
var x = imageSize.Width - OffsetFromTopRightCorner; var x = imageSize.Width - OffsetFromTopRightCorner;
using (var paint = new SKPaint()) using var paint = new SKPaint
{ {
paint.Color = SKColor.Parse("#CC00A4DC"); Color = SKColor.Parse("#CC00A4DC"),
paint.Style = SKPaintStyle.Fill; Style = SKPaintStyle.Fill
};
canvas.DrawCircle(x, OffsetFromTopRightCorner, 20, paint); canvas.DrawCircle(x, OffsetFromTopRightCorner, 20, paint);
}
using (var paint = new SKPaint())
{
paint.Color = new SKColor(255, 255, 255, 255); paint.Color = new SKColor(255, 255, 255, 255);
paint.Style = SKPaintStyle.Fill;
paint.TextSize = 30; paint.TextSize = 30;
paint.IsAntialias = true; paint.IsAntialias = true;
@ -49,4 +46,3 @@ namespace Jellyfin.Drawing.Skia
} }
} }
} }
}

View File

@ -12,7 +12,7 @@ namespace Jellyfin.Drawing.Skia
/// Initializes a new instance of the <see cref="SkiaCodecException" /> class. /// Initializes a new instance of the <see cref="SkiaCodecException" /> class.
/// </summary> /// </summary>
/// <param name="result">The non-successful codec result returned by Skia.</param> /// <param name="result">The non-successful codec result returned by Skia.</param>
public SkiaCodecException(SKCodecResult result) : base() public SkiaCodecException(SKCodecResult result)
{ {
CodecResult = result; CodecResult = result;
} }

View File

@ -29,9 +29,7 @@ namespace Jellyfin.Drawing.Skia
/// </summary> /// </summary>
/// <param name="logger">The application logger.</param> /// <param name="logger">The application logger.</param>
/// <param name="appPaths">The application paths.</param> /// <param name="appPaths">The application paths.</param>
public SkiaEncoder( public SkiaEncoder(ILogger<SkiaEncoder> logger, IApplicationPaths appPaths)
ILogger<SkiaEncoder> logger,
IApplicationPaths appPaths)
{ {
_logger = logger; _logger = logger;
_appPaths = appPaths; _appPaths = appPaths;
@ -102,19 +100,14 @@ namespace Jellyfin.Drawing.Skia
/// <returns>The converted format.</returns> /// <returns>The converted format.</returns>
public static SKEncodedImageFormat GetImageFormat(ImageFormat selectedFormat) public static SKEncodedImageFormat GetImageFormat(ImageFormat selectedFormat)
{ {
switch (selectedFormat) return selectedFormat switch
{ {
case ImageFormat.Bmp: ImageFormat.Bmp => SKEncodedImageFormat.Bmp,
return SKEncodedImageFormat.Bmp; ImageFormat.Jpg => SKEncodedImageFormat.Jpeg,
case ImageFormat.Jpg: ImageFormat.Gif => SKEncodedImageFormat.Gif,
return SKEncodedImageFormat.Jpeg; ImageFormat.Webp => SKEncodedImageFormat.Webp,
case ImageFormat.Gif: _ => SKEncodedImageFormat.Png
return SKEncodedImageFormat.Gif; };
case ImageFormat.Webp:
return SKEncodedImageFormat.Webp;
default:
return SKEncodedImageFormat.Png;
}
} }
private static bool IsTransparentRow(SKBitmap bmp, int row) private static bool IsTransparentRow(SKBitmap bmp, int row)
@ -146,64 +139,35 @@ namespace Jellyfin.Drawing.Skia
private SKBitmap CropWhiteSpace(SKBitmap bitmap) private SKBitmap CropWhiteSpace(SKBitmap bitmap)
{ {
var topmost = 0; var topmost = 0;
for (int row = 0; row < bitmap.Height; ++row) while (topmost < bitmap.Height && IsTransparentRow(bitmap, topmost))
{ {
if (IsTransparentRow(bitmap, row)) topmost++;
{
topmost = row + 1;
}
else
{
break;
}
} }
int bottommost = bitmap.Height; int bottommost = bitmap.Height;
for (int row = bitmap.Height - 1; row >= 0; --row) while (bottommost >= 0 && IsTransparentRow(bitmap, bottommost - 1))
{ {
if (IsTransparentRow(bitmap, row)) bottommost--;
{
bottommost = row;
}
else
{
break;
}
} }
int leftmost = 0, rightmost = bitmap.Width; var leftmost = 0;
for (int col = 0; col < bitmap.Width; ++col) while (leftmost < bitmap.Width && IsTransparentColumn(bitmap, leftmost))
{ {
if (IsTransparentColumn(bitmap, col)) leftmost++;
{
leftmost = col + 1;
}
else
{
break;
}
} }
for (int col = bitmap.Width - 1; col >= 0; --col) var rightmost = bitmap.Width;
while (rightmost >= 0 && IsTransparentColumn(bitmap, rightmost - 1))
{ {
if (IsTransparentColumn(bitmap, col)) rightmost--;
{
rightmost = col;
}
else
{
break;
}
} }
var newRect = SKRectI.Create(leftmost, topmost, rightmost - leftmost, bottommost - topmost); var newRect = SKRectI.Create(leftmost, topmost, rightmost - leftmost, bottommost - topmost);
using (var image = SKImage.FromBitmap(bitmap)) using var image = SKImage.FromBitmap(bitmap);
using (var subset = image.Subset(newRect)) using var subset = image.Subset(newRect);
{
return SKBitmap.FromImage(subset); return SKBitmap.FromImage(subset);
} }
}
/// <inheritdoc /> /// <inheritdoc />
/// <exception cref="ArgumentNullException">The path is null.</exception> /// <exception cref="ArgumentNullException">The path is null.</exception>
@ -216,15 +180,13 @@ namespace Jellyfin.Drawing.Skia
throw new FileNotFoundException("File not found", path); throw new FileNotFoundException("File not found", path);
} }
using (var codec = SKCodec.Create(path, out SKCodecResult result)) using var codec = SKCodec.Create(path, out SKCodecResult result);
{
EnsureSuccess(result); EnsureSuccess(result);
var info = codec.Info; var info = codec.Info;
return new ImageDimensions(info.Width, info.Height); return new ImageDimensions(info.Width, info.Height);
} }
}
/// <inheritdoc /> /// <inheritdoc />
/// <exception cref="ArgumentNullException">The path is null.</exception> /// <exception cref="ArgumentNullException">The path is null.</exception>
@ -253,12 +215,7 @@ namespace Jellyfin.Drawing.Skia
} }
} }
if (HasDiacritics(path)) return HasDiacritics(path);
{
return true;
}
return false;
} }
private string NormalizePath(string path) private string NormalizePath(string path)
@ -283,25 +240,17 @@ namespace Jellyfin.Drawing.Skia
return SKEncodedOrigin.TopLeft; return SKEncodedOrigin.TopLeft;
} }
switch (orientation.Value) return orientation.Value switch
{ {
case ImageOrientation.TopRight: ImageOrientation.TopRight => SKEncodedOrigin.TopRight,
return SKEncodedOrigin.TopRight; ImageOrientation.RightTop => SKEncodedOrigin.RightTop,
case ImageOrientation.RightTop: ImageOrientation.RightBottom => SKEncodedOrigin.RightBottom,
return SKEncodedOrigin.RightTop; ImageOrientation.LeftTop => SKEncodedOrigin.LeftTop,
case ImageOrientation.RightBottom: ImageOrientation.LeftBottom => SKEncodedOrigin.LeftBottom,
return SKEncodedOrigin.RightBottom; ImageOrientation.BottomRight => SKEncodedOrigin.BottomRight,
case ImageOrientation.LeftTop: ImageOrientation.BottomLeft => SKEncodedOrigin.BottomLeft,
return SKEncodedOrigin.LeftTop; _ => SKEncodedOrigin.TopLeft
case ImageOrientation.LeftBottom: };
return SKEncodedOrigin.LeftBottom;
case ImageOrientation.BottomRight:
return SKEncodedOrigin.BottomRight;
case ImageOrientation.BottomLeft:
return SKEncodedOrigin.BottomLeft;
default:
return SKEncodedOrigin.TopLeft;
}
} }
/// <summary> /// <summary>
@ -323,8 +272,7 @@ namespace Jellyfin.Drawing.Skia
if (requiresTransparencyHack || forceCleanBitmap) if (requiresTransparencyHack || forceCleanBitmap)
{ {
using (var codec = SKCodec.Create(NormalizePath(path))) using var codec = SKCodec.Create(NormalizePath(path));
{
if (codec == null) if (codec == null)
{ {
origin = GetSKEncodedOrigin(orientation); origin = GetSKEncodedOrigin(orientation);
@ -341,7 +289,6 @@ namespace Jellyfin.Drawing.Skia
return bitmap; return bitmap;
} }
}
var resultBitmap = SKBitmap.Decode(NormalizePath(path)); var resultBitmap = SKBitmap.Decode(NormalizePath(path));
@ -367,15 +314,8 @@ namespace Jellyfin.Drawing.Skia
{ {
if (cropWhitespace) if (cropWhitespace)
{ {
using (var bitmap = Decode(path, forceAnalyzeBitmap, orientation, out origin)) using var bitmap = Decode(path, forceAnalyzeBitmap, orientation, out origin);
{ return bitmap == null ? null : CropWhiteSpace(bitmap);
if (bitmap == null)
{
return null;
}
return CropWhiteSpace(bitmap);
}
} }
return Decode(path, forceAnalyzeBitmap, orientation, out origin); return Decode(path, forceAnalyzeBitmap, orientation, out origin);
@ -403,135 +343,57 @@ namespace Jellyfin.Drawing.Skia
private SKBitmap OrientImage(SKBitmap bitmap, SKEncodedOrigin origin) private SKBitmap OrientImage(SKBitmap bitmap, SKEncodedOrigin origin)
{ {
if (origin == SKEncodedOrigin.Default)
{
return bitmap;
}
var needsFlip = origin == SKEncodedOrigin.LeftBottom
|| origin == SKEncodedOrigin.LeftTop
|| origin == SKEncodedOrigin.RightBottom
|| origin == SKEncodedOrigin.RightTop;
var rotated = needsFlip
? new SKBitmap(bitmap.Height, bitmap.Width)
: new SKBitmap(bitmap.Width, bitmap.Height);
using var surface = new SKCanvas(rotated);
var midX = (float)rotated.Width / 2;
var midY = (float)rotated.Height / 2;
switch (origin) switch (origin)
{ {
case SKEncodedOrigin.TopRight: case SKEncodedOrigin.TopRight:
{ surface.Scale(-1, 1, midX, midY);
var rotated = new SKBitmap(bitmap.Width, bitmap.Height); break;
using (var surface = new SKCanvas(rotated))
{
surface.Translate(rotated.Width, 0);
surface.Scale(-1, 1);
surface.DrawBitmap(bitmap, 0, 0);
}
return rotated;
}
case SKEncodedOrigin.BottomRight: case SKEncodedOrigin.BottomRight:
{ surface.RotateDegrees(180, midX, midY);
var rotated = new SKBitmap(bitmap.Width, bitmap.Height); break;
using (var surface = new SKCanvas(rotated))
{
float px = (float)bitmap.Width / 2;
float py = (float)bitmap.Height / 2;
surface.RotateDegrees(180, px, py);
surface.DrawBitmap(bitmap, 0, 0);
}
return rotated;
}
case SKEncodedOrigin.BottomLeft: case SKEncodedOrigin.BottomLeft:
{ surface.Scale(1, -1, midX, midY);
var rotated = new SKBitmap(bitmap.Width, bitmap.Height); break;
using (var surface = new SKCanvas(rotated))
{
float px = (float)bitmap.Width / 2;
float py = (float)bitmap.Height / 2;
surface.Translate(rotated.Width, 0);
surface.Scale(-1, 1);
surface.RotateDegrees(180, px, py);
surface.DrawBitmap(bitmap, 0, 0);
}
return rotated;
}
case SKEncodedOrigin.LeftTop: case SKEncodedOrigin.LeftTop:
{ surface.Translate(0, -rotated.Height);
// TODO: Remove dual canvases, had trouble with flipping surface.Scale(1, -1, midX, midY);
using (var rotated = new SKBitmap(bitmap.Height, bitmap.Width)) surface.RotateDegrees(-90);
{ break;
using (var surface = new SKCanvas(rotated))
{
surface.Translate(rotated.Width, 0);
surface.RotateDegrees(90);
surface.DrawBitmap(bitmap, 0, 0);
}
var flippedBitmap = new SKBitmap(rotated.Width, rotated.Height);
using (var flippedCanvas = new SKCanvas(flippedBitmap))
{
flippedCanvas.Translate(flippedBitmap.Width, 0);
flippedCanvas.Scale(-1, 1);
flippedCanvas.DrawBitmap(rotated, 0, 0);
}
return flippedBitmap;
}
}
case SKEncodedOrigin.RightTop: case SKEncodedOrigin.RightTop:
{
var rotated = new SKBitmap(bitmap.Height, bitmap.Width);
using (var surface = new SKCanvas(rotated))
{
surface.Translate(rotated.Width, 0); surface.Translate(rotated.Width, 0);
surface.RotateDegrees(90); surface.RotateDegrees(90);
surface.DrawBitmap(bitmap, 0, 0); break;
}
return rotated;
}
case SKEncodedOrigin.RightBottom: case SKEncodedOrigin.RightBottom:
{ surface.Translate(rotated.Width, 0);
// TODO: Remove dual canvases, had trouble with flipping surface.Scale(1, -1, midX, midY);
using (var rotated = new SKBitmap(bitmap.Height, bitmap.Width)) surface.RotateDegrees(90);
{ break;
using (var surface = new SKCanvas(rotated))
{
surface.Translate(0, rotated.Height);
surface.RotateDegrees(270);
surface.DrawBitmap(bitmap, 0, 0);
}
var flippedBitmap = new SKBitmap(rotated.Width, rotated.Height);
using (var flippedCanvas = new SKCanvas(flippedBitmap))
{
flippedCanvas.Translate(flippedBitmap.Width, 0);
flippedCanvas.Scale(-1, 1);
flippedCanvas.DrawBitmap(rotated, 0, 0);
}
return flippedBitmap;
}
}
case SKEncodedOrigin.LeftBottom: case SKEncodedOrigin.LeftBottom:
{
var rotated = new SKBitmap(bitmap.Height, bitmap.Width);
using (var surface = new SKCanvas(rotated))
{
surface.Translate(0, rotated.Height); surface.Translate(0, rotated.Height);
surface.RotateDegrees(270); surface.RotateDegrees(-90);
break;
}
surface.DrawBitmap(bitmap, 0, 0); surface.DrawBitmap(bitmap, 0, 0);
}
return rotated; return rotated;
} }
default: return bitmap;
}
}
/// <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)
{ {
@ -552,8 +414,7 @@ namespace Jellyfin.Drawing.Skia
var blur = options.Blur ?? 0; var blur = options.Blur ?? 0;
var hasIndicator = options.AddPlayedIndicator || options.UnplayedCount.HasValue || !options.PercentPlayed.Equals(0); var hasIndicator = options.AddPlayedIndicator || options.UnplayedCount.HasValue || !options.PercentPlayed.Equals(0);
using (var bitmap = GetBitmap(inputPath, options.CropWhiteSpace, autoOrient, orientation)) using var bitmap = GetBitmap(inputPath, options.CropWhiteSpace, autoOrient, orientation);
{
if (bitmap == null) if (bitmap == null)
{ {
throw new InvalidDataException($"Skia unable to read image {inputPath}"); throw new InvalidDataException($"Skia unable to read image {inputPath}");
@ -574,8 +435,7 @@ namespace Jellyfin.Drawing.Skia
var width = newImageSize.Width; var width = newImageSize.Width;
var height = newImageSize.Height; var height = newImageSize.Height;
using (var resizedBitmap = new SKBitmap(width, height, bitmap.ColorType, bitmap.AlphaType)) using var resizedBitmap = new SKBitmap(width, height, bitmap.ColorType, bitmap.AlphaType);
{
// scale image // scale image
bitmap.ScalePixels(resizedBitmap, SKFilterQuality.High); bitmap.ScalePixels(resizedBitmap, SKFilterQuality.High);
@ -583,18 +443,15 @@ namespace Jellyfin.Drawing.Skia
if (!hasBackgroundColor && !hasForegroundColor && blur == 0 && !hasIndicator) if (!hasBackgroundColor && !hasForegroundColor && blur == 0 && !hasIndicator)
{ {
Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
using (var outputStream = new SKFileWStream(outputPath)) using var outputStream = new SKFileWStream(outputPath);
using (var pixmap = new SKPixmap(new SKImageInfo(width, height), resizedBitmap.GetPixels())) using var pixmap = new SKPixmap(new SKImageInfo(width, height), resizedBitmap.GetPixels());
{
pixmap.Encode(outputStream, skiaOutputFormat, quality); pixmap.Encode(outputStream, skiaOutputFormat, quality);
return outputPath; return outputPath;
} }
}
// create bitmap to use for canvas drawing used to draw into bitmap // create bitmap to use for canvas drawing used to draw into bitmap
using (var saveBitmap = new SKBitmap(width, height)) // , bitmap.ColorType, bitmap.AlphaType)) using var saveBitmap = new SKBitmap(width, height);
using (var canvas = new SKCanvas(saveBitmap)) using var canvas = new SKCanvas(saveBitmap);
{
// set background color if present // set background color if present
if (hasBackgroundColor) if (hasBackgroundColor)
{ {
@ -605,13 +462,11 @@ namespace Jellyfin.Drawing.Skia
if (blur > 0) if (blur > 0)
{ {
// create image from resized bitmap to apply blur // create image from resized bitmap to apply blur
using (var paint = new SKPaint()) using var paint = new SKPaint();
using (var filter = SKImageFilter.CreateBlur(blur, blur)) using var filter = SKImageFilter.CreateBlur(blur, blur);
{
paint.ImageFilter = filter; paint.ImageFilter = filter;
canvas.DrawBitmap(resizedBitmap, SKRect.Create(width, height), paint); canvas.DrawBitmap(resizedBitmap, SKRect.Create(width, height), paint);
} }
}
else else
{ {
// draw resized bitmap onto canvas // draw resized bitmap onto canvas
@ -642,9 +497,6 @@ namespace Jellyfin.Drawing.Skia
pixmap.Encode(outputStream, skiaOutputFormat, quality); pixmap.Encode(outputStream, skiaOutputFormat, quality);
} }
} }
}
}
}
return outputPath; return outputPath;
} }

View File

@ -10,7 +10,7 @@ namespace Jellyfin.Drawing.Skia
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="SkiaException"/> class. /// Initializes a new instance of the <see cref="SkiaException"/> class.
/// </summary> /// </summary>
public SkiaException() : base() public SkiaException()
{ {
} }

View File

@ -69,13 +69,11 @@ namespace Jellyfin.Drawing.Skia
/// <param name="height">The desired height of the collage.</param> /// <param name="height">The desired height of the collage.</param>
public void BuildSquareCollage(string[] paths, string outputPath, int width, int height) public void BuildSquareCollage(string[] paths, string outputPath, int width, int height)
{ {
using (var bitmap = BuildSquareCollageBitmap(paths, width, height)) using var bitmap = BuildSquareCollageBitmap(paths, width, height);
using (var outputStream = new SKFileWStream(outputPath)) using var outputStream = new SKFileWStream(outputPath);
using (var pixmap = new SKPixmap(new SKImageInfo(width, height), bitmap.GetPixels())) using var pixmap = new SKPixmap(new SKImageInfo(width, height), bitmap.GetPixels());
{
pixmap.Encode(outputStream, GetEncodedFormat(outputPath), 90); pixmap.Encode(outputStream, GetEncodedFormat(outputPath), 90);
} }
}
/// <summary> /// <summary>
/// Create a thumb collage. /// Create a thumb collage.
@ -86,20 +84,17 @@ namespace Jellyfin.Drawing.Skia
/// <param name="height">The desired height of the collage.</param> /// <param name="height">The desired height of the collage.</param>
public void BuildThumbCollage(string[] paths, string outputPath, int width, int height) public void BuildThumbCollage(string[] paths, string outputPath, int width, int height)
{ {
using (var bitmap = BuildThumbCollageBitmap(paths, width, height)) using var bitmap = BuildThumbCollageBitmap(paths, width, height);
using (var outputStream = new SKFileWStream(outputPath)) using var outputStream = new SKFileWStream(outputPath);
using (var pixmap = new SKPixmap(new SKImageInfo(width, height), bitmap.GetPixels())) using var pixmap = new SKPixmap(new SKImageInfo(width, height), bitmap.GetPixels());
{
pixmap.Encode(outputStream, GetEncodedFormat(outputPath), 90); pixmap.Encode(outputStream, GetEncodedFormat(outputPath), 90);
} }
}
private SKBitmap BuildThumbCollageBitmap(string[] paths, int width, int height) private SKBitmap BuildThumbCollageBitmap(string[] paths, int width, int height)
{ {
var bitmap = new SKBitmap(width, height); var bitmap = new SKBitmap(width, height);
using (var canvas = new SKCanvas(bitmap)) using var canvas = new SKCanvas(bitmap);
{
canvas.Clear(SKColors.Black); canvas.Clear(SKColors.Black);
// number of images used in the thumbnail // number of images used in the thumbnail
@ -111,8 +106,7 @@ namespace Jellyfin.Drawing.Skia
int imageIndex = 0; int imageIndex = 0;
for (int i = 0; i < iCount; i++) for (int i = 0; i < iCount; i++)
{ {
using (var currentBitmap = GetNextValidImage(paths, imageIndex, out int newIndex)) using var currentBitmap = GetNextValidImage(paths, imageIndex, out int newIndex);
{
imageIndex = newIndex; imageIndex = newIndex;
if (currentBitmap == null) if (currentBitmap == null)
{ {
@ -121,22 +115,16 @@ namespace Jellyfin.Drawing.Skia
// resize to the same aspect as the original // resize to the same aspect as the original
int iWidth = 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 = 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));
{
// draw image onto canvas // draw image onto canvas
canvas.DrawImage(subset ?? image, iSlice * i, 0); canvas.DrawImage(subset ?? image, iSlice * i, 0);
} }
}
}
}
}
return bitmap; return bitmap;
} }
@ -176,14 +164,12 @@ namespace Jellyfin.Drawing.Skia
var cellWidth = width / 2; var cellWidth = width / 2;
var cellHeight = height / 2; var cellHeight = height / 2;
using (var canvas = new SKCanvas(bitmap)) using var canvas = new SKCanvas(bitmap);
{
for (var x = 0; x < 2; x++) for (var x = 0; x < 2; x++)
{ {
for (var y = 0; y < 2; y++) for (var y = 0; y < 2; y++)
{ {
using (var currentBitmap = GetNextValidImage(paths, imageIndex, out int newIndex)) using var currentBitmap = GetNextValidImage(paths, imageIndex, out int newIndex);
{
imageIndex = newIndex; imageIndex = newIndex;
if (currentBitmap == null) if (currentBitmap == null)
@ -191,8 +177,7 @@ namespace Jellyfin.Drawing.Skia
continue; continue;
} }
using (var resizedBitmap = new SKBitmap(cellWidth, cellHeight, currentBitmap.ColorType, currentBitmap.AlphaType)) using var resizedBitmap = new SKBitmap(cellWidth, cellHeight, currentBitmap.ColorType, currentBitmap.AlphaType);
{
// scale image // scale image
currentBitmap.ScalePixels(resizedBitmap, SKFilterQuality.High); currentBitmap.ScalePixels(resizedBitmap, SKFilterQuality.High);
@ -202,9 +187,6 @@ namespace Jellyfin.Drawing.Skia
canvas.DrawBitmap(resizedBitmap, xPos, yPos); canvas.DrawBitmap(resizedBitmap, xPos, yPos);
} }
} }
}
}
}
return bitmap; return bitmap;
} }

View File

@ -28,18 +28,15 @@ namespace Jellyfin.Drawing.Skia
var x = imageSize.Width - OffsetFromTopRightCorner; var x = imageSize.Width - OffsetFromTopRightCorner;
var text = count.ToString(CultureInfo.InvariantCulture); var text = count.ToString(CultureInfo.InvariantCulture);
using (var paint = new SKPaint()) using var paint = new SKPaint
{ {
paint.Color = SKColor.Parse("#CC00A4DC"); Color = SKColor.Parse("#CC00A4DC"),
paint.Style = SKPaintStyle.Fill; Style = SKPaintStyle.Fill
};
canvas.DrawCircle(x, OffsetFromTopRightCorner, 20, paint); canvas.DrawCircle(x, OffsetFromTopRightCorner, 20, paint);
}
using (var paint = new SKPaint())
{
paint.Color = new SKColor(255, 255, 255, 255); paint.Color = new SKColor(255, 255, 255, 255);
paint.Style = SKPaintStyle.Fill;
paint.TextSize = 24; paint.TextSize = 24;
paint.IsAntialias = true; paint.IsAntialias = true;
@ -65,4 +62,3 @@ namespace Jellyfin.Drawing.Skia
} }
} }
} }
}