using ImageMagick; using PosterMaker.Interfaces.Services; using PosterMaker.Models; using PosterMaker.Models.Enums; namespace PosterMaker.Services; public class SeriesPosterMakerService : ISeriesPosterMakerService { private static readonly string RefDir = Path.Combine("Resources", "Series"); private static readonly string RefDirectory = Path.Combine(Directory.GetCurrentDirectory(), RefDir); private static readonly string Font = Path.Combine(RefDirectory, "Arial Bold.ttf"); private static readonly string SeasonFont = Path.Combine(RefDirectory, "Proxima Nova Semibold.ttf"); private static readonly string Frame = Path.Combine(RefDirectory, "frame.png"); private static readonly string Gradient = Path.Combine(RefDirectory, "gradient.png"); private const string FontColor = "white"; private const float FontSize = 1.0F; private readonly IMovieLogoService _movieLogoService; public SeriesPosterMakerService(IMovieLogoService movieLogoService) { _movieLogoService = movieLogoService; } public byte[] CreatePoster(string file, ImageProperties imageProperties) { using var image = new MagickImage(file); var resizeGeometry = new MagickGeometry(1892, 2892) { FillArea = true }; image.Resize(resizeGeometry); image.Extent(2000, 3000, Gravity.Center); ApplyGradient(image); using var frame = new MagickImage(Frame); frame.BackgroundColor = new MagickColor("transparent"); image.Composite(frame, Gravity.Center, CompositeOperator.Over); AddStudioLogo(image, imageProperties.Logo, imageProperties.LogoOption); AddNetworkLogo(image, imageProperties.NetworkLogo, imageProperties.LogoOption); AddTitle(image, imageProperties); return image.ToByteArray(); } private static void ApplyGradient(MagickImage image) { using var gradient = new MagickImage(Gradient); image.Composite(gradient, Gravity.Center, CompositeOperator.Multiply); } private void AddStudioLogo(MagickImage image, MovieLogoEnum? logo, LogoOptionEnum? logoOptionEnum) { if (logo == null) return; var logoFile = _movieLogoService.GetMovieLogo(logo); var gravity = _movieLogoService.GetLogoGravity(logo); var readSettings = new MagickReadSettings { TextGravity = Gravity.Center, BackgroundColor = MagickColors.Transparent }; using var logoImage = new MagickImage(logoFile, readSettings); logoImage.Resize(new MagickGeometry(500, 250)); switch (logoOptionEnum) { case LogoOptionEnum.White: logoImage.Colorize(MagickColors.White, new Percentage(100)); break; case LogoOptionEnum.Black: logoImage.Colorize(MagickColors.Black, new Percentage(100)); break; } var offset = gravity == Gravity.Northwest ? 100 : 0; image.Composite(logoImage, gravity, offset, 100, CompositeOperator.Atop); } private void AddNetworkLogo(MagickImage image, NetworkLogoEnum? logo, LogoOptionEnum? logoOptionEnum) { if (logo == null) return; var logoFile = _movieLogoService.GetNetworkLogo(logo); var readSettings = new MagickReadSettings { TextGravity = Gravity.Center, BackgroundColor = MagickColors.Transparent }; using var logoImage = new MagickImage(logoFile, readSettings); var networkLogoHeight = _movieLogoService.GetNetworkLogoHeight(logo); logoImage.Resize(new MagickGeometry(networkLogoHeight * 2, networkLogoHeight)); switch (logoOptionEnum) { case LogoOptionEnum.White: logoImage.Colorize(MagickColors.White, new Percentage(100)); break; case LogoOptionEnum.Black: logoImage.Colorize(MagickColors.Black, new Percentage(100)); break; } var shadow = new MagickImage(logoImage); shadow.Shadow(2, 2,3, new Percentage(80)); switch (logoOptionEnum) { case LogoOptionEnum.White: shadow.Colorize(MagickColors.Black, new Percentage(100)); break; case LogoOptionEnum.Black: shadow.Colorize(MagickColors.White, new Percentage(100)); break; } image.Composite(shadow, Gravity.Northwest, 100, 100, CompositeOperator.Atop); image.Composite(logoImage, Gravity.Northwest, 100, 100, CompositeOperator.Atop); } private void AddTitle(MagickImage image, ImageProperties properties) { if (string.IsNullOrEmpty(properties.TopSubtitle) && string.IsNullOrEmpty(properties.Title) && string.IsNullOrEmpty(properties.Subtitle) && string.IsNullOrEmpty(properties.Season)) return; var readSettings = new MagickReadSettings { BackgroundColor = MagickColors.Transparent, FillColor = new MagickColor(FontColor), Font = Font, Debug = true }; var labelImages = new MagickImageCollection(); if (!string.IsNullOrEmpty(properties.TopSubtitle)) { readSettings.FontPointsize = 95 * FontSize; readSettings.TextGravity = Gravity.Center; labelImages.Add(new MagickImage($"label:{properties.TopSubtitle.ToUpper()}", readSettings)); } if (!string.IsNullOrEmpty(properties.Title)) { readSettings.FontPointsize = 190 * FontSize; readSettings.TextKerning = 0.7; readSettings.TextInterlineSpacing = -44.5; readSettings.TextInterwordSpacing = 55; readSettings.TextGravity = Gravity.Center; labelImages.Add(new MagickImage($"label:{properties.Title.ToUpper()}", readSettings)); } if (!string.IsNullOrEmpty(properties.Title2)) { readSettings.FontPointsize = 190 * FontSize; readSettings.TextKerning = 0.7; readSettings.TextInterlineSpacing = -44.5; readSettings.TextInterwordSpacing = 55; readSettings.TextGravity = Gravity.Center; labelImages.Add(new MagickImage($"label:{properties.Title2.ToUpper()}", readSettings)); } if (!string.IsNullOrEmpty(properties.Subtitle)) { readSettings.FontPointsize = 95 * FontSize; readSettings.TextInterwordSpacing = 18; readSettings.TextKerning = 0.5; readSettings.TextGravity = Gravity.Center; labelImages.Add(new MagickImage($"label:{properties.Subtitle.ToUpper()}", readSettings)); } using var labels = labelImages.SmushVertical(30); var seasonImages = new MagickImageCollection(); var image2 = new MagickImage(); if (!string.IsNullOrEmpty(properties.Season) && ((properties.LimitedSeries != null && properties.LimitedSeries != true) || properties.LimitedSeries == null)) { seasonImages.Add(labels); readSettings.TextInterlineSpacing = 150; readSettings.FontPointsize = 66 * FontSize; readSettings.TextGravity = Gravity.Center; readSettings.TextKerning = 50; readSettings.TextInterwordSpacing = 20; readSettings.Font = SeasonFont; var seasonImage = new MagickImage($"label:SEASON {properties.Season.ToUpper()}", readSettings); seasonImages.Add(seasonImage); var offset = string.IsNullOrEmpty(properties.Subtitle) ? 150 : 75; using var imageWithSeason = seasonImages.SmushVertical(offset); image2 = new MagickImage(imageWithSeason); } if (properties.LimitedSeries == true) { seasonImages.Add(labels); readSettings.TextInterlineSpacing = 150; readSettings.FontPointsize = 66 * FontSize; readSettings.TextGravity = Gravity.Center; readSettings.TextKerning = 50; readSettings.TextInterwordSpacing = 20; readSettings.Font = SeasonFont; var seasonImage = new MagickImage($"label:LIMITED SERIES", readSettings); seasonImages.Add(seasonImage); using var imageWithSeason = seasonImages.SmushVertical(150); image2 = new MagickImage(imageWithSeason); } var titleHeight = !string.IsNullOrEmpty(properties.Season) || properties.LimitedSeries == true ? 85 : 262; if (!string.IsNullOrEmpty(properties.Subtitle) && properties.LimitedSeries is not true && string.IsNullOrWhiteSpace(properties.Season)) { titleHeight = 200; } image.Composite(string.IsNullOrEmpty(properties.Season) && properties.LimitedSeries != true ? labels : image2, Gravity.South, 0, titleHeight, CompositeOperator.Atop); } }