< Summary - Jellyfin

Information
Class: Jellyfin.Drawing.Skia.SplashscreenBuilder
Assembly: Jellyfin.Drawing.Skia
File(s): /srv/git/jellyfin/src/Jellyfin.Drawing.Skia/SplashscreenBuilder.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 56
Coverable lines: 56
Total lines: 147
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 12
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
GenerateSplash(...)100%210%
GenerateCollage(...)0%156120%
Transform3D(...)100%210%

File(s)

/srv/git/jellyfin/src/Jellyfin.Drawing.Skia/SplashscreenBuilder.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using SkiaSharp;
 4
 5namespace Jellyfin.Drawing.Skia;
 6
 7/// <summary>
 8/// Used to build the splashscreen.
 9/// </summary>
 10public class SplashscreenBuilder
 11{
 12    private const int FinalWidth = 1920;
 13    private const int FinalHeight = 1080;
 14    // generated collage resolution should be higher than the final resolution
 15    private const int WallWidth = FinalWidth * 3;
 16    private const int WallHeight = FinalHeight * 2;
 17    private const int Rows = 6;
 18    private const int Spacing = 20;
 19
 20    private readonly SkiaEncoder _skiaEncoder;
 21
 22    /// <summary>
 23    /// Initializes a new instance of the <see cref="SplashscreenBuilder"/> class.
 24    /// </summary>
 25    /// <param name="skiaEncoder">The SkiaEncoder.</param>
 26    public SplashscreenBuilder(SkiaEncoder skiaEncoder)
 27    {
 028        _skiaEncoder = skiaEncoder;
 029    }
 30
 31    /// <summary>
 32    /// Generate a splashscreen.
 33    /// </summary>
 34    /// <param name="posters">The poster paths.</param>
 35    /// <param name="backdrops">The landscape paths.</param>
 36    /// <param name="outputPath">The output path.</param>
 37    public void GenerateSplash(IReadOnlyList<string> posters, IReadOnlyList<string> backdrops, string outputPath)
 38    {
 039        using var wall = GenerateCollage(posters, backdrops);
 040        using var transformed = Transform3D(wall);
 41
 042        using var outputStream = new SKFileWStream(outputPath);
 043        using var pixmap = new SKPixmap(new SKImageInfo(FinalWidth, FinalHeight), transformed.GetPixels());
 044        pixmap.Encode(outputStream, StripCollageBuilder.GetEncodedFormat(outputPath), 90);
 045    }
 46
 47    /// <summary>
 48    /// Generates a collage of posters and landscape pictures.
 49    /// </summary>
 50    /// <param name="posters">The poster paths.</param>
 51    /// <param name="backdrops">The landscape paths.</param>
 52    /// <returns>The created collage as a bitmap.</returns>
 53    private SKBitmap GenerateCollage(IReadOnlyList<string> posters, IReadOnlyList<string> backdrops)
 54    {
 055        var posterIndex = 0;
 056        var backdropIndex = 0;
 57
 058        var bitmap = new SKBitmap(WallWidth, WallHeight);
 059        using var canvas = new SKCanvas(bitmap);
 060        canvas.Clear(SKColors.Black);
 61
 062        int posterHeight = WallHeight / 6;
 63
 064        for (int i = 0; i < Rows; i++)
 65        {
 066            int imageCounter = Random.Shared.Next(0, 5);
 067            int currentWidthPos = i * 75;
 068            int currentHeight = i * (posterHeight + Spacing);
 69
 070            while (currentWidthPos < WallWidth)
 71            {
 72                SKBitmap? currentImage;
 73
 74                switch (imageCounter)
 75                {
 76                    case 0:
 77                    case 2:
 78                    case 3:
 079                        currentImage = SkiaHelper.GetNextValidImage(_skiaEncoder, posters, posterIndex, out int newPoste
 080                        posterIndex = newPosterIndex;
 081                        break;
 82                    default:
 083                        currentImage = SkiaHelper.GetNextValidImage(_skiaEncoder, backdrops, backdropIndex, out int newB
 084                        backdropIndex = newBackdropIndex;
 85                        break;
 86                }
 87
 088                if (currentImage is null)
 89                {
 090                    throw new ArgumentException("Not enough valid pictures provided to create a splashscreen!");
 91                }
 92
 93                // resize to the same aspect as the original
 094                var imageWidth = Math.Abs(posterHeight * currentImage.Width / currentImage.Height);
 095                using var resizedBitmap = new SKBitmap(imageWidth, posterHeight);
 096                currentImage.ScalePixels(resizedBitmap, SKFilterQuality.High);
 97
 98                // draw on canvas
 099                canvas.DrawBitmap(resizedBitmap, currentWidthPos, currentHeight);
 100
 0101                currentWidthPos += imageWidth + Spacing;
 102
 0103                currentImage.Dispose();
 104
 0105                if (imageCounter >= 4)
 106                {
 0107                    imageCounter = 0;
 108                }
 109                else
 110                {
 0111                    imageCounter++;
 112                }
 113            }
 114        }
 115
 0116        return bitmap;
 0117    }
 118
 119    /// <summary>
 120    /// Transform the collage in 3D space.
 121    /// </summary>
 122    /// <param name="input">The bitmap to transform.</param>
 123    /// <returns>The transformed image.</returns>
 124    private SKBitmap Transform3D(SKBitmap input)
 125    {
 0126        var bitmap = new SKBitmap(FinalWidth, FinalHeight);
 0127        using var canvas = new SKCanvas(bitmap);
 0128        canvas.Clear(SKColors.Black);
 0129        var matrix = new SKMatrix
 0130        {
 0131            ScaleX = 0.324108899f,
 0132            ScaleY = 0.563934922f,
 0133            SkewX = -0.244337708f,
 0134            SkewY = 0.0377609022f,
 0135            TransX = 42.0407715f,
 0136            TransY = -198.104706f,
 0137            Persp0 = -9.08959337E-05f,
 0138            Persp1 = 6.85242048E-05f,
 0139            Persp2 = 0.988209724f
 0140        };
 141
 0142        canvas.SetMatrix(matrix);
 0143        canvas.DrawBitmap(input, 0, 0);
 144
 0145        return bitmap;
 0146    }
 147}