public static Stream GetImage(string astronaut1, string astronaut2, string messageContent, bool debugRectangle = false) { MemoryStream stream = new MemoryStream(); FontCollection fonts = new FontCollection(); fonts.Install(Path.Combine(assetsFolder, "fonts", "arial.ttf")); Font captionFont = fonts.CreateFont("arial", 8); Rectangle messageContentRectangle = new Rectangle(150, 50, 450, 165); Font astronaut1Font = fonts.CreateFont("arial", 7); Rectangle astronaut1Rectangle = new Rectangle(350, 225, 150, 75); Font astronaut2Font = fonts.CreateFont("arial", 8); Rectangle astronaut2Rectangle = new Rectangle(625, 50, 250, 125); Font alwaysHasBeenFont = fonts.CreateFont("arial", 9); Rectangle alwaysHasBeenRectangle = new Rectangle(400, 0, 475, 50); using (Image img = Image.Load(Path.Combine(assetsFolder, "images", "wait-its-all-ohio.png"))) { img.Mutate(ctx => ctx.DrawBoxedText(astronaut1Font, astronaut1, Color.White, Color.Black, astronaut1Rectangle, VerticalAlignment.Center, debugRectangle)); img.Mutate(ctx => ctx.DrawBoxedText(astronaut2Font, astronaut2, Color.White, Color.Black, astronaut2Rectangle, VerticalAlignment.Center, debugRectangle)); img.Mutate(ctx => ctx.DrawBoxedText(captionFont, messageContent, Color.White, Color.Black, messageContentRectangle, VerticalAlignment.Bottom, debugRectangle)); img.Mutate(ctx => ctx.DrawBoxedText(alwaysHasBeenFont, "Always has been", Color.White, Color.Black, alwaysHasBeenRectangle, VerticalAlignment.Center, debugRectangle)); img.SaveAsPng(stream); } stream.Position = 0; return(stream); }
public async Task <RuntimeResult> ProfileAsync(SocketUser user = null) { //User Data var targetUser = user ?? Context.User; var record = await UserRepository.GetOrCreateProfileAsync(targetUser).ConfigureAwait(false); using (var profileBase = Image.Load("Resources/Profile/base.png")) using (var avatarFrame = Image.Load("Resources/Profile/avatarFrame.png")) using (var badge = Image.Load("Resources/Profile/badge.png")) using (var avatarStream = await WebHelper.GetFileStreamAsync(HttpClient, new Uri(targetUser.GetAvatarUrl())).ConfigureAwait(false)) using (var finalImage = new MemoryStream()) using (var avatar = Image.Load(avatarStream)) { //Fonts & text rendering var robotoItalic = new FontCollection().Install("Resources/Profile/Fonts/Roboto-Italic.ttf"); var roboto = new FontCollection().Install("Resources/Profile/Fonts/Roboto-Regular.ttf"); var textOptions = new TextGraphicsOptions { HorizontalAlignment = HorizontalAlignment.Center }; //Actual Image var final = profileBase.DrawImage(avatar.Resize(540, 540), new Size(), new Point(935, 134), GraphicsOptions.Default) .DrawImage(avatarFrame, new Size(), new Point(0, 0), GraphicsOptions.Default) .DrawText(targetUser.Username, robotoItalic.CreateFont(130), new Rgba32(106, 161, 196), new Point(profileBase.Width / 2, 690), textOptions) .DrawText($"Member Since {targetUser.CreatedAt:M/d/yy}", robotoItalic.CreateFont(73), new Rgba32(138, 145, 153), new Point(profileBase.Width / 2, 840), textOptions) .DrawText($"Balance: {record.Balance}", roboto.CreateFont(82), new Rgba32(138, 145, 153), new Point(profileBase.Width / 2, 930), textOptions) .DrawText("About Me:", robotoItalic.CreateFont(90), new Rgba32(106, 161, 196), new Point(340, 1130), TextGraphicsOptions.Default) .DrawText(Regex.Replace(record.Summary, ".{55}", "$0\n"), roboto.CreateFont(70), new Rgba32(138, 145, 153), new Point(340, 1250), TextGraphicsOptions.Default); //Verified Badge //TODO: Add some kind of verification system/reputation system? if (Config.Owners.Contains(targetUser.Id)) { final.DrawImage(badge, new Size(), new Point(0, 0), GraphicsOptions.Default).Resize(500, 500).SaveAsPng(finalImage); } else { final.Resize(500, 500).SaveAsPng(finalImage); } //Sending the image finalImage.Seek(0, SeekOrigin.Begin); await Context.Channel.SendFileAsync(finalImage, "profile.png", $"Profile card for `{targetUser}`").ConfigureAwait(false); } return(CommandRuntimeResult.FromSuccess()); }
public void Draw(Image image, FontCollection fonts, ICommandContext context, IMessage repliedMessage) { var font = fonts.CreateFont(FontName, FontSize); string labelText = GetLabelText(context, repliedMessage); image.Mutate(ctx => ctx.DrawBoxedText(font, labelText, MainColor, OutlineColor, Rectangle, VerticalAlignment, ShowRectangle)); }
/// <summary> /// Image process and writes to <paramref name="output"/> <see cref="Stream"/>. /// </summary> /// <param name="output">The output <see cref="Stream"/> to write to.</param> /// <param name="firstName">First name to use.</param> /// <param name="lastName">Last name to use.</param> /// <param name="size">Image size.</param> /// <param name="jpeg">Specifies whether the image has .jpg extension.</param> /// <param name="background">The background color to use.</param> public void Generate(Stream output, string firstName, string lastName, int size = 192, bool jpeg = false, string background = null) { var avatarText = string.Format("{0}{1}", firstName?.Length > 0 ? firstName[0] : ' ', lastName?.Length > 0 ? lastName[0] : ' ').ToUpper().RemoveDiacritics(); var randomIndex = $"{firstName}{lastName}".ToCharArray().Sum(x => x) % _backgroundColours.Length; var accentColor = _backgroundColours[randomIndex]; if (background != null) { accentColor = new AvatarColor(background); } using (var image = new Image <Rgba32>(size, size)) { image.Mutate(x => x.Fill(accentColor.Background)); var fonts = new FontCollection(); // For production application we would recomend you create a FontCollection singleton and manually install the ttf fonts yourself as using SystemFonts can be expensive and you risk font existing or not existing on a deployment by deployment basis. var font = _openSansFont.CreateFont("Open Sans", 70, FontStyle.Regular); // for scaling water mark size is largly ignored. // Measure the text size. var textSize = TextMeasurer.Measure(avatarText, new RendererOptions(font)); // Find out how much we need to scale the text to fill the space (up or down). var scalingFactor = Math.Min(image.Width * 0.6f / textSize.Width, image.Height * 0.6f / textSize.Height); // Create a new font. var scaledFont = new Font(font, scalingFactor * font.Size); var center = new PointF(image.Width / 2, image.Height / 2); var textGraphicOptions = new TextGraphicsOptions(true) { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center }; image.Mutate(x => x.DrawText(textGraphicOptions, avatarText, scaledFont, accentColor.Color, center)); image.Save(output, jpeg ? (IImageFormat)JpegFormat.Instance : PngFormat.Instance); } output.Seek(0, SeekOrigin.Begin); }
/// <summary> /// Transforms an image to add a watermark. /// </summary> /// <param name="input"></param> /// <param name="output"></param> /// <param name="waterMarkText"></param> public void TransformDownloadImage(string input, Stream output, string waterMarkText = null) { Logging.Log($" Running image transform for Watermark: {waterMarkText}"); using var img = Image.Load(input, out IImageFormat fmt); var opts = new ResizeOptions { Mode = ResizeMode.Max, Size = new Size { Height = 1600, Width = 1600 } }; // First rotate and resize. img.Mutate(x => x.AutoOrient().Resize(opts)); if (!string.IsNullOrEmpty(waterMarkText)) { // Apply the watermark if one's been specified. Font font = fontCollection.CreateFont("Arial", 10); if (!string.IsNullOrEmpty(waterMarkText)) { img.Mutate(context => ApplyWaterMark(context, font, waterMarkText, Color.White)); } } img.Save(output, fmt); }
public void DrawText(PointF position, string text, Font font, string color, int penWidth) { var p = ToPointF(position, world); commandQueue.Enqueue(ctx => { ctx.DrawText(text, fontCollection.CreateFont(font.Name, font.Size), Rgba32.FromHex(color), p, currentOption); }); }
public Function(ILogger <Function> logger) { _logger = logger; var configReader = new ConfigReader(logger); _outputBucket = configReader.Read("BUCKET"); _requestReader = new HttpRequestReader(logger); var fontCollection = new FontCollection(); fontCollection.Install("Arial.ttf"); _font = fontCollection.CreateFont("Arial", 10); }
private async Task DrawWelcomeScreen() { Image <Rgba32> image = new Image <Rgba32>(400, 300); FontCollection fc = new FontCollection(); fc.Install("DigitalDream.ttf"); var f = fc.CreateFont("Digital Dream", 18); GraphicsOptions options = new GraphicsOptions(false); image.Mutate((ctx) => { ctx.Fill(Rgba32.White); ctx.DrawText($"{GetCurrentIpv4Address()}:8800", f, Rgba32.Black, new PointF(0, 0), options); ctx.DrawText($"{DateTime.Now.ToString()}", f, Rgba32.Black, new PointF(0, 100), options); ctx.Dither(new SixLabors.ImageSharp.Dithering.FloydSteinbergDiffuser(), 0.5f); }); await Renderer.RenderAsync(image, Task.Factory.CancellationToken); }
public KomiPaperMemeGen(BotState state) { _botState = state; var fontCollection = new FontCollection(); fontCollection.Install(@"Fonts\mangat.ttf", out var fontDescription); _template = new MemeTemplate("KomiPaper.png", new TextBoundingBox() { TopLeft = new PointF(245, 479), TopRight = new PointF(708, 558), BottomLeft = new PointF(168, 728), BottomRight = new PointF(632, 810), CenterHeight = false, CenterWidth = false, Font = fontCollection.CreateFont(fontDescription.FontFamily, 20) }, new MultiBoundingBox(new ImageBoundingBox() { TopLeft = new PointF(245, 479), TopRight = new PointF(708, 558), BottomLeft = new PointF(94, 988), BottomRight = new PointF(557, 1067), LandscapeScalingMode = ImageScalingMode.FitWithLetterbox, PortraitScalingMode = ImageScalingMode.FillFit }) { Padding = 10, Masks = new List <Rectangle> { new Rectangle(0, 631, 186, 446), new Rectangle(666, 552, 50, 150), new Rectangle(0, 1065, 557, 205) } }); }
public static async Task <string> GenerateAsync(BannerOptions options, Profile profile, string subtext) { if (profile == null) { throw new ArgumentNullException(nameof(profile)); } // Avatar base url + avatar meta = rendered avatar url var avatarURL = $"{DevrantAvatarBaseURL}/{profile.Avatar.Image}"; const string outputDir = "generated"; const string avatarsDir = "avatars"; var outputFileName = $"{profile.Username}.png"; var workingDir = Directory.GetCurrentDirectory(); var outputPath = Path.Combine(workingDir, outputDir); var avatarPath = Path.Combine(workingDir, avatarsDir); Directory.CreateDirectory(outputPath); Directory.CreateDirectory(avatarPath); var avatarFile = Path.Combine(avatarPath, outputFileName); var outputFile = Path.Combine(outputPath, outputFileName); byte[] data; if (options.CacheAvatars && File.Exists(avatarFile)) { data = await File.ReadAllBytesAsync(avatarFile); } else { // Download rendered avatar var httpClient = new HttpClient(); using (var response = await httpClient.GetAsync(avatarURL)) { if (response.StatusCode == HttpStatusCode.NotFound) { throw new AvatarNotFoundException(profile.Username); } response.EnsureSuccessStatusCode(); data = await response.Content.ReadAsByteArrayAsync(); if (options.CacheAvatars) { await File.WriteAllBytesAsync(avatarFile, data); } } } using (var avatarImage = Image.Load(data)) using (var banner = new Image <Rgba32>(800, 192)) { var fontCollection = new FontCollection(); fontCollection.Install("fonts/Comfortaa-Regular.ttf"); var fontSizeUsername = 64; var fontSizeSubtext = fontSizeUsername / 2; var fontSizeDevrant = 16; var fontUsername = fontCollection.CreateFont("Comfortaa", fontSizeUsername, FontStyle.Bold); var fontSubtext = fontCollection.CreateFont("Comfortaa", fontSizeSubtext, FontStyle.Regular); var fontDevrant = fontCollection.CreateFont("Comfortaa", fontSizeDevrant, FontStyle.Regular); var avatarHeight = banner.Height; var avatarWidth = avatarHeight; var avatarSize = new Size(avatarWidth, avatarHeight); var avatarTargetX = 15; var avatarTargetY = 0; var avatarTarget = new Point(avatarTargetX, avatarTargetY); var usernameTargetX = banner.Width / 3; var usernameTartgetY = banner.Height / 4; var usernameTarget = new Point(usernameTargetX, usernameTartgetY); var subtextTargetX = usernameTarget.X; var subtextTartgetY = usernameTarget.Y + fontSizeUsername; var subtextTarget = new Point(subtextTargetX, subtextTartgetY); var subTextWidth = banner.Width - subtextTargetX - 15; var subTextHeight = fontSizeSubtext; var devrantTargetX = banner.Width - 108; var devrantTargetY = banner.Height - 4 - fontSizeDevrant; var devrantTarget = new Point(devrantTargetX, devrantTargetY); // Draw background banner.SetBGColor(Rgba32.FromHex(profile.Avatar.Background)); // Draw avatar banner.DrawImage(avatarImage, avatarSize, avatarTarget); // Draw username banner.DrawText(profile.Username, fontUsername, Rgba32.White, usernameTarget); // Scale font size to subtext fontSubtext = fontSubtext.ScaleToText(subtext, new SizeF(subTextWidth, subTextHeight)); // Draw subtext banner.DrawText(subtext, fontSubtext, Rgba32.White, subtextTarget); // Draw devrant text banner.DrawText("devrant.com", fontDevrant, Rgba32.White, devrantTarget, HorizontalAlignment.Left, VerticalAlignment.Top); banner.Save(outputFile, new PngEncoder()); } return(outputFile); }
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger <Startup> logger) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } logger.LogInformation("Service is starting..."); app.UseRouting(); var eventReader = new CloudEventReader(logger); var configReader = new ConfigReader(logger); var outputBucket = configReader.Read("BUCKET"); var fontCollection = new FontCollection(); fontCollection.Install("Arial.ttf"); var font = fontCollection.CreateFont("Arial", 10); app.UseEndpoints(endpoints => { endpoints.MapPost("/", async context => { try { var(bucket, name) = await eventReader.ReadCloudStorageData(context); using (var inputStream = new MemoryStream()) { var client = await StorageClient.CreateAsync(); await client.DownloadObjectAsync(bucket, name, inputStream); logger.LogInformation($"Downloaded '{name}' from bucket '{bucket}'"); using (var outputStream = new MemoryStream()) { inputStream.Position = 0; // Reset to read using (var image = Image.Load(inputStream)) { using (var imageProcessed = image.Clone(ctx => ApplyScalingWaterMarkSimple(ctx, font, Watermark, Color.DeepSkyBlue, 5))) { logger.LogInformation($"Added watermark to image '{name}'"); imageProcessed.SaveAsJpeg(outputStream); } } var outputObjectName = $"{Path.GetFileNameWithoutExtension(name)}-watermark.jpeg"; await client.UploadObjectAsync(outputBucket, outputObjectName, "image/jpeg", outputStream); logger.LogInformation($"Uploaded '{outputObjectName}' to bucket '{outputBucket}'"); } } } catch (Exception e) { logger.LogError($"Error processing: " + e.Message); throw e; } }); }); }
public static MemoryStream GenerateXpBar(Stream avatar, XpLevel xp, string rank, string username, string discriminator, DateTime date, bool doubleXp, bool fastXp) { using Image image = Image.Load("data/xp/roki_xp_half.png"); var transparentGray = new Rgba32(211, 211, 211, 220); var grayBackground = new RectangleF(PfpOutlineX + (PfpLength + 10) / 2, 7.5f, 680, 185); var pfpBackground = new RectangleF(PfpOutlineX, PfpOutlineY, PfpLength + 10, PfpLength + 10); var pfpOutline = new RectangleF(PfpOutlineX, PfpOutlineY, PfpLength + 10, PfpLength + 10); var xpBarOutline = new RectangleF(XpBarX, XpBarY, XpBarLength, XpBarHeight); image.Mutate(x => x .Fill(new Color(transparentGray), grayBackground) // profile pic .Fill(Color.White, pfpBackground) .Draw(Color.WhiteSmoke, 3.5f, pfpOutline) .Fill(Color.HotPink, new RectangleF(37, 25, 150, 150)) // profile pic // xp bar .Draw(Color.HotPink, 2.5f, xpBarOutline)); if (xp.TotalXp != 0) { var xpBarProgress = new RectangleF(XpBarX + 2.5f, XpBarY + 2.5f, (XpBarLength - 5) * ((float)xp.ProgressXp / xp.RequiredXp), XpBarHeight - 5); image.Mutate(x => x.Fill(Color.HotPink, xpBarProgress)); } using (Image pfp = Image.Load(avatar)) { pfp.Mutate(x => x.Resize(new Size(PfpLength, PfpLength))); image.Mutate(x => x.DrawImage(pfp, new Point(PfpOutlineX + 5, PfpOutlineY + 5), 1)); } var fonts = new FontCollection(); fonts.Install("data/xp/DIN_REG.ttf"); fonts.Install("data/xp/DIN_MED.ttf"); Font usernameFont = fonts.CreateFont("DIN", 30); Font discriminatorFont = fonts.CreateFont("DIN", 21); Font xpFont = fonts.CreateFont("DIN", 30); Font headerFont = fonts.CreateFont("DIN Medium", 20); Font bodyFont = fonts.CreateFont("DIN", 25); image.Mutate(x => x .DrawUsername(usernameFont, discriminatorFont, username, $"#{discriminator}", new PointF(XpBarX, 50)) // username + discrim .DrawText(new TextGraphicsOptions { TextOptions = { HorizontalAlignment = HorizontalAlignment.Center } }, $"XP: {xp.TotalXp:N0} / {xp.TotalRequiredXp:N0}", xpFont, Color.DarkSlateGray, new PointF(XpBarX + XpBarLength / 2, 66)) // xp progress .DrawStats(headerFont, bodyFont, $"#{rank}", xp.Level.ToString("N0"), (xp.TotalRequiredXp - xp.TotalXp).ToString("N0"), date) .DrawBoosts(doubleXp, fastXp)); var stream = new MemoryStream(); image.SaveAsPng(stream); stream.Position = 0; return(stream); }
public int GetFont(string family, float size) { return(add <Font>(fc.CreateFont(family, size))); }
/// <summary> /// Loads necesarry resouces for rendering /// </summary> /// <returns>true loading succeeded</returns> static bool LoadResources() { if (!String.IsNullOrWhiteSpace(Options.SystemFont)) { if (!SystemFonts.TryFind(Options.SystemFont, out var family)) { Log.Error("font '" + Options.SystemFont + " not found"); return(false); } SelectedFont = new Font(family, Options.FontSize, Options.StyleOfFont); //Log.Debug("FontInfo: " // +"\n\tAscender\t"+SelectedFont.Ascender // +"\n\tBold\t"+SelectedFont.Bold // +"\n\tDescender\t"+SelectedFont.Descender // +"\n\tEmSize\t"+SelectedFont.EmSize // +"\n\tFamily.Name\t"+SelectedFont.Family.Name // +"\n\tItalic\t"+SelectedFont.Italic // +"\n\tLineGap\t"+SelectedFont.LineGap // +"\n\tLineHeight\t"+SelectedFont.LineHeight // +"\n\tName\t"+SelectedFont.Name // +"\n\tSize\t"+SelectedFont.Size //); } else if (!String.IsNullOrWhiteSpace(Options.FontFile)) { if (!File.Exists(Options.FontFile)) { Log.Error("Cannot find font file '" + Options.FontFile + "'"); return(false); } var col = new FontCollection().Install(Options.FontFile); SelectedFont = col.CreateFont(Options.FontSize, Options.StyleOfFont); } else { Log.Error("no font specified"); return(false); } //Log.Debug("Options.WhichSet = "+Options.WhichSet); if (Options.WhichSet != CharSets.Set.None) { SelectedCharSet = CharSets.Get(Options.WhichSet); } else if (!String.IsNullOrWhiteSpace(Options.CharFile)) { if (!File.Exists(Options.CharFile)) { Log.Error("cannot find file " + Options.CharFile); return(false); } var uniqChars = new HashSet <char>(); const int buffLen = 256; using (var fs = File.Open(Options.CharFile, FileMode.Open, FileAccess.Read, FileShare.Read)) using (var sr = new StreamReader(fs)) { char[] buff = new char[buffLen]; int count = int.MaxValue; while (count >= buffLen) { count = sr.Read(buff, 0, buffLen); uniqChars.UnionWith(buff); } } SelectedCharSet = new char[uniqChars.Count]; uniqChars.CopyTo(SelectedCharSet); } else { Log.Error("char set not specified"); return(false); } if (!String.IsNullOrWhiteSpace(Options.InputName)) { if (!File.Exists(Options.InputName)) { Log.Error("cannot find file " + Options.InputName); return(false); } var data = File.ReadAllBytes(Options.InputName); SourceImage = Image.Load(data); } return(true); }
public static async Task <string> GenerateAsync(BannerOptions options, Profile profile, string subtext, int width = 800, int height = 192) { if (profile == null) { throw new ArgumentNullException(nameof(profile)); } var checkedWidth = CheckWidth(options, width); height = (int)(checkedWidth / options.WidthToHeightRatio); // Avatar base url + avatar meta = rendered avatar url var avatarURL = $"{DevrantAvatarBaseURL}/{profile.Avatar.Image}"; const string outputDir = "generated"; const string avatarsDir = "avatars"; var outputFileName = $"{profile.Username}.png"; var workingDir = Directory.GetCurrentDirectory(); var outputPath = Path.Combine(workingDir, outputDir); var avatarPath = Path.Combine(workingDir, avatarsDir); Directory.CreateDirectory(outputPath); Directory.CreateDirectory(avatarPath); var avatarFile = Path.Combine(avatarPath, outputFileName); var outputFile = Path.Combine(outputPath, outputFileName); byte[] data; if (options.CacheAvatars && File.Exists(avatarFile) && File.GetCreationTime(avatarFile) > DateTime.Now.AddMinutes(-options.MaxCacheAvatarAge)) { data = await File.ReadAllBytesAsync(avatarFile); } else { // Download rendered avatar var httpClient = new HttpClient(); using (var response = await httpClient.GetAsync(avatarURL)) { if (response.StatusCode == HttpStatusCode.NotFound) { throw new AvatarNotFoundException(profile.Username); } response.EnsureSuccessStatusCode(); data = await response.Content.ReadAsByteArrayAsync(); if (options.CacheAvatars) { await File.WriteAllBytesAsync(avatarFile, data); } } } using (var avatarImage = Image.Load(data)) using (var banner = new Image <Rgba32>(checkedWidth, height)) { var fontCollection = new FontCollection(); fontCollection.Install("fonts/Comfortaa-Regular.ttf"); var fontSizeUsername = (int)(banner.Width * 0.07); // original : 0.08 var fontSizeSubtext = (int)(banner.Width * 0.04); var fontSizeDevrant = (int)(banner.Width * 0.02); var fontUsername = fontCollection.CreateFont("Comfortaa", fontSizeUsername, FontStyle.Bold); var fontSubtext = fontCollection.CreateFont("Comfortaa", fontSizeSubtext, FontStyle.Regular); var fontDevrant = fontCollection.CreateFont("Comfortaa", fontSizeDevrant, FontStyle.Regular); var avatarHeight = banner.Height; var avatarWidth = avatarHeight; var avatarSize = new Size(avatarWidth, avatarHeight); var avatarTargetX = (int)(banner.Width * 0.01875); var avatarTargetY = 0; var avatarTarget = new Point(avatarTargetX, avatarTargetY); var usernameTargetX = banner.Width / 3; var usernameTargetY = (banner.Height / 4f) - (fontSizeUsername / 2f); var usernameTarget = new PointF(usernameTargetX, usernameTargetY); var subtextTargetX = usernameTarget.X; var subtextTargetY = usernameTarget.Y + fontSizeUsername; var subtextTarget = new PointF(subtextTargetX, subtextTargetY + (fontSizeSubtext / 2f)); var subTextWidth = banner.Width - subtextTargetX - (int)(banner.Width * 0.01875); var subTextHeight = fontSizeSubtext; var devrantTargetX = banner.Width - (int)(banner.Width * 0.130); var devrantTargetY = banner.Height - (int)(banner.Width * 0.03); var devrantTarget = new Point(devrantTargetX, devrantTargetY); var backgroundColor = Rgba32.FromHex(profile.Avatar.Background); var foregroundColor = GetForegroundColor(backgroundColor); // Draw background banner.SetBGColor(backgroundColor); // Draw avatar banner.DrawImage(avatarImage, avatarSize, avatarTarget); // Draw username banner.DrawText(profile.Username, fontUsername, foregroundColor, usernameTarget, verticalAlignment: VerticalAlignment.Top); // Scale font size to subtext fontSubtext = fontSubtext.ScaleToText(subtext, new SizeF(subTextWidth, subTextHeight), subTextWidth); // Add subtext word wrapping subtext = subtext.AddWrap(fontSubtext, subTextWidth, options.MaxSubtextWraps); // Draw subtext banner.DrawText(subtext, fontSubtext, foregroundColor, subtextTarget, verticalAlignment: VerticalAlignment.Top); // Draw devrant text banner.DrawText("devrant.com", fontDevrant, foregroundColor, devrantTarget, HorizontalAlignment.Left, VerticalAlignment.Top); banner.Save(outputFile, new PngEncoder()); } return(outputFile); }
public static string Generate(string avatarURL, string avatarBGColor, string username, string subtext) { var workingDir = Directory.GetCurrentDirectory(); var outputPath = $"{workingDir}/generated/{username}.png"; // Download rendered avatar var httpClient = new HttpClient(); var responseStream = httpClient.GetStreamAsync(avatarURL).Result; var avatarImage = Image.Load(responseStream); System.IO.Directory.CreateDirectory("generated"); using (Image <Rgba32> banner = new Image <Rgba32>(800, 192)) { var fontCollection = new FontCollection(); fontCollection.Install("fonts/Comfortaa-Regular.ttf"); var fontSizeUsername = 64; var fontSizeSubtext = fontSizeUsername / 2; var fontSizeDevrant = 16; var fontUsername = fontCollection.CreateFont("Comfortaa", fontSizeUsername, FontStyle.Bold); var fontSubtext = fontCollection.CreateFont("Comfortaa", fontSizeSubtext, FontStyle.Regular); var fontDevrant = fontCollection.CreateFont("Comfortaa", fontSizeDevrant, FontStyle.Regular); var avatarHeight = banner.Height; var avatarWidth = avatarHeight; var avatarSize = new Size(avatarWidth, avatarHeight); var avatarTargetX = 0; var avatarTargetY = 0; var avatarTarget = new Point(avatarTargetX, avatarTargetY); var usernameTargetX = banner.Width / 3; var usernameTartgetY = banner.Height / 4; var usernameTarget = new Point(usernameTargetX, usernameTartgetY); var subtextTargetX = usernameTarget.X; var subtextTartgetY = usernameTarget.Y + fontSizeUsername; var subtextTarget = new Point(subtextTargetX, subtextTartgetY); var devrantTargetX = banner.Width - 108; var devrantTargetY = banner.Height - 4 - fontSizeDevrant; var devrantTarget = new Point(devrantTargetX, devrantTargetY); // Draw background banner.Mutate(i => i.BackgroundColor(Rgba32.FromHex(avatarBGColor))); // Draw avatar banner.Mutate(i => i.DrawImage(avatarImage, 1, avatarSize, avatarTarget)); // Draw username banner.Mutate(i => i.DrawText(username, fontUsername, Rgba32.White, usernameTarget, new TextGraphicsOptions(true) { HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Center })); // Draw subtext banner.Mutate(i => i.DrawText(subtext, fontSubtext, Rgba32.White, subtextTarget, new TextGraphicsOptions(true) { HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Center })); // Draw devrant text banner.Mutate(i => i.DrawText("devrant.com", fontDevrant, Rgba32.White, devrantTarget, new TextGraphicsOptions(true) { HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top })); banner.Save(outputPath); } responseStream.Close(); return(outputPath); }
/// <summary> /// Create a font atlas with all registered <see cref="FontAtlasEntry"/> instances. /// </summary> /// <param name="dpi">Dots per inch to use. Usually 96 (Windows) or 72 (MacOS).</param> public FontAtlas CreateAtlas(Vector2?dpi = null) { var dpiVal = dpi ?? new Vector2(DefaultDpi); var characterSizes = new Size[_atlasEntries.Count][]; var characterRanges = new CharacterRange[_atlasEntries.Count][]; var characterBounds = new Rectangle[_atlasEntries.Count][]; var fonts = new Font[_atlasEntries.Count]; var packer = new MaxRectsBin(64, 64); // pad 1 pixel at all borders packer.PaddingWidth = 1; packer.PaddingHeight = 1; var sb = new StringBuilder(); for (var i = 0; i < _atlasEntries.Count; i++) { var e = _atlasEntries[i]; characterSizes[i] = new Size[e.GetCharacterCount()]; characterRanges[i] = new CharacterRange[e.CharacterRanges.Count]; Font font; if (e.IsSystemFont) { font = SystemFonts.CreateFont(e.Font.FamilyName, e.Font.Size, e.Font.Style); } else { font = _fontCollection.CreateFont(e.Font.FamilyName, e.Font.Size, e.Font.Style); } fonts[i] = font; var renderOptions = new RendererOptions(font, dpiVal.X, dpiVal.Y); var characterIndex = 0; for (var characterRangeIndex = 0; characterRangeIndex < e.CharacterRanges.Count; characterRangeIndex++) { // TODO reduce allocations var cr = e.CharacterRanges[characterRangeIndex]; characterRanges[i][characterRangeIndex] = new CharacterRange(cr, characterIndex); sb.Clear(); for (var c = cr.Start; c <= cr.End; c++) { sb.Append(char.ConvertFromUtf32(c)); } if (!TextMeasurer.TryMeasureCharacterBounds(sb.ToString().AsSpan(), renderOptions, out var glyphMetrics)) { continue; } foreach (var gm in glyphMetrics) { // we should round the size up so nothing gets lost characterSizes[i][characterIndex] = new Size((int)(gm.Bounds.Width + .9999f), (int)(gm.Bounds.Height + .9999f)); characterIndex++; } } } for (var i = 0; i < _atlasEntries.Count; i++) { characterBounds[i] = packer.Insert(characterSizes[i]); } var uw = (float)packer.UsedWidth; var uh = (float)packer.UsedHeight; var glyphMaps = new PixelGlyphMap[_atlasEntries.Count]; for (var i = 0; i < _atlasEntries.Count; i++) { var glyphData = new GlyphData[characterSizes[i].Length]; var gi = 0; foreach (var cr in characterRanges[i]) { foreach (var c in cr) { var rect = characterBounds[i][gi]; glyphData[gi] = new GlyphData(c, rect); gi++; } } glyphMaps[i] = new PixelGlyphMap(fonts[i], characterRanges[i], glyphData); } return(new FontAtlas(packer.UsedWidth, packer.UsedHeight, dpiVal, glyphMaps)); }