mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-06-18 21:50:25 +01:00
Ensure Skia images are always disposed (#12786)
This commit is contained in:
@@ -269,14 +269,24 @@ public class SkiaEncoder : IImageEncoder
|
||||
}
|
||||
|
||||
// create the bitmap
|
||||
var bitmap = new SKBitmap(codec.Info.Width, codec.Info.Height, !requiresTransparencyHack);
|
||||
SKBitmap? bitmap = null;
|
||||
try
|
||||
{
|
||||
bitmap = new SKBitmap(codec.Info.Width, codec.Info.Height, !requiresTransparencyHack);
|
||||
|
||||
// decode
|
||||
_ = codec.GetPixels(bitmap.Info, bitmap.GetPixels());
|
||||
// decode
|
||||
_ = codec.GetPixels(bitmap.Info, bitmap.GetPixels());
|
||||
|
||||
origin = codec.EncodedOrigin;
|
||||
origin = codec.EncodedOrigin;
|
||||
|
||||
return bitmap;
|
||||
return bitmap!;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Detected intermediary error decoding image {0}", path);
|
||||
bitmap?.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
var resultBitmap = SKBitmap.Decode(NormalizePath(path));
|
||||
@@ -286,17 +296,26 @@ public class SkiaEncoder : IImageEncoder
|
||||
return Decode(path, true, orientation, out origin);
|
||||
}
|
||||
|
||||
// If we have to resize these they often end up distorted
|
||||
if (resultBitmap.ColorType == SKColorType.Gray8)
|
||||
try
|
||||
{
|
||||
using (resultBitmap)
|
||||
// If we have to resize these they often end up distorted
|
||||
if (resultBitmap.ColorType == SKColorType.Gray8)
|
||||
{
|
||||
return Decode(path, true, orientation, out origin);
|
||||
using (resultBitmap)
|
||||
{
|
||||
return Decode(path, true, orientation, out origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
origin = SKEncodedOrigin.TopLeft;
|
||||
return resultBitmap;
|
||||
origin = SKEncodedOrigin.TopLeft;
|
||||
return resultBitmap;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Detected intermediary error decoding image {0}", path);
|
||||
resultBitmap?.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private SKBitmap? GetBitmap(string path, bool autoOrient, ImageOrientation? orientation)
|
||||
@@ -335,58 +354,78 @@ public class SkiaEncoder : IImageEncoder
|
||||
var width = (int)Math.Round(svg.Drawable.Bounds.Width);
|
||||
var height = (int)Math.Round(svg.Drawable.Bounds.Height);
|
||||
|
||||
var bitmap = new SKBitmap(width, height);
|
||||
using var canvas = new SKCanvas(bitmap);
|
||||
canvas.DrawPicture(svg.Picture);
|
||||
canvas.Flush();
|
||||
canvas.Save();
|
||||
SKBitmap? bitmap = null;
|
||||
try
|
||||
{
|
||||
bitmap = new SKBitmap(width, height);
|
||||
using var canvas = new SKCanvas(bitmap);
|
||||
canvas.DrawPicture(svg.Picture);
|
||||
canvas.Flush();
|
||||
canvas.Save();
|
||||
|
||||
return bitmap;
|
||||
return bitmap!;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Detected intermediary error extracting image {0}", path);
|
||||
bitmap?.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private SKBitmap OrientImage(SKBitmap bitmap, SKEncodedOrigin origin)
|
||||
{
|
||||
var needsFlip = origin is SKEncodedOrigin.LeftBottom or SKEncodedOrigin.LeftTop or SKEncodedOrigin.RightBottom or 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)
|
||||
SKBitmap? rotated = null;
|
||||
try
|
||||
{
|
||||
case SKEncodedOrigin.TopRight:
|
||||
surface.Scale(-1, 1, midX, midY);
|
||||
break;
|
||||
case SKEncodedOrigin.BottomRight:
|
||||
surface.RotateDegrees(180, midX, midY);
|
||||
break;
|
||||
case SKEncodedOrigin.BottomLeft:
|
||||
surface.Scale(1, -1, midX, midY);
|
||||
break;
|
||||
case SKEncodedOrigin.LeftTop:
|
||||
surface.Translate(0, -rotated.Height);
|
||||
surface.Scale(1, -1, midX, midY);
|
||||
surface.RotateDegrees(-90);
|
||||
break;
|
||||
case SKEncodedOrigin.RightTop:
|
||||
surface.Translate(rotated.Width, 0);
|
||||
surface.RotateDegrees(90);
|
||||
break;
|
||||
case SKEncodedOrigin.RightBottom:
|
||||
surface.Translate(rotated.Width, 0);
|
||||
surface.Scale(1, -1, midX, midY);
|
||||
surface.RotateDegrees(90);
|
||||
break;
|
||||
case SKEncodedOrigin.LeftBottom:
|
||||
surface.Translate(0, rotated.Height);
|
||||
surface.RotateDegrees(-90);
|
||||
break;
|
||||
}
|
||||
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;
|
||||
|
||||
surface.DrawBitmap(bitmap, 0, 0);
|
||||
return rotated;
|
||||
switch (origin)
|
||||
{
|
||||
case SKEncodedOrigin.TopRight:
|
||||
surface.Scale(-1, 1, midX, midY);
|
||||
break;
|
||||
case SKEncodedOrigin.BottomRight:
|
||||
surface.RotateDegrees(180, midX, midY);
|
||||
break;
|
||||
case SKEncodedOrigin.BottomLeft:
|
||||
surface.Scale(1, -1, midX, midY);
|
||||
break;
|
||||
case SKEncodedOrigin.LeftTop:
|
||||
surface.Translate(0, -rotated.Height);
|
||||
surface.Scale(1, -1, midX, midY);
|
||||
surface.RotateDegrees(-90);
|
||||
break;
|
||||
case SKEncodedOrigin.RightTop:
|
||||
surface.Translate(rotated.Width, 0);
|
||||
surface.RotateDegrees(90);
|
||||
break;
|
||||
case SKEncodedOrigin.RightBottom:
|
||||
surface.Translate(rotated.Width, 0);
|
||||
surface.Scale(1, -1, midX, midY);
|
||||
surface.RotateDegrees(90);
|
||||
break;
|
||||
case SKEncodedOrigin.LeftBottom:
|
||||
surface.Translate(0, rotated.Height);
|
||||
surface.RotateDegrees(-90);
|
||||
break;
|
||||
}
|
||||
|
||||
surface.DrawBitmap(bitmap, 0, 0);
|
||||
return rotated;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Detected intermediary error rotating image");
|
||||
rotated?.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -562,7 +601,7 @@ public class SkiaEncoder : IImageEncoder
|
||||
// Only generate the splash screen if we have at least one poster and at least one backdrop/thumbnail.
|
||||
if (posters.Count > 0 && backdrops.Count > 0)
|
||||
{
|
||||
var splashBuilder = new SplashscreenBuilder(this);
|
||||
var splashBuilder = new SplashscreenBuilder(this, _logger);
|
||||
var outputPath = Path.Combine(_appPaths.DataPath, "splashscreen.png");
|
||||
splashBuilder.GenerateSplash(posters, backdrops, outputPath);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user