internal static async void RenderImage(SocketUser user, ISocketMessageChannel channel) { RestUserMessage loader = await channel.SendMessageAsync("", false, LoadingMessage().Build()); // Place the bulk of the function in a try-catch block in case something fails and an error message needs to be sent try { // Grab the user's account information var account = UserInfoClasses.GetAccount(user); //Establish variables to write on the template string username = ""; //If the username is over 12 characters, replace the last parts with an ellipsis if (user.Username.Length > 12) { username = $"{username.Substring(0, 12)}..."; } else { username = $"{user.Username}"; } //Establish other variables of the user's data string level = $"{account.Level}"; string profile_picture = user.GetAvatarUrl(); string pmedals = $"{account.P_Medals}"; string proficiency_title = Core.LevelSystem.SocialStats.ProficiencyRankTitle(account.Proficiency_Rank); string diligence_title = Core.LevelSystem.SocialStats.DiligenceRankTitle(account.Diligence_Rank); string expression_title = Core.LevelSystem.SocialStats.ExpressionRankTitle(account.Expression_Rank); //Determine the Next Exp value int next_exp = 0; if (account.Level != 99) { next_exp = Core.LevelSystem.Leveling.CalculateExp(account.Level + 1) - account.Total_Exp; } //If the user doesn't have a profile picture, use a default one if (profile_picture == null) { profile_picture = "https://i.imgur.com/T0AjCLh.png"; } // Create a base bitmap to render all the elements on Bitmap p4_template = new Bitmap(1920, 1080); //Copy the P4 status background to a bitmap Bitmap base_layer = (Bitmap)System.Drawing.Image.FromFile($@"{AssetDirectoryConfig.assetDirectory.assetFolderPath}//Profile//StatusScreens//Default//P4//layer_1.png"); //Copy the P4 status info fields to a bitmap Bitmap info_layer = (Bitmap)System.Drawing.Image.FromFile($@"{AssetDirectoryConfig.assetDirectory.assetFolderPath}//Profile//StatusScreens//Default//P4//layer_2.png"); //Copy the plot point overlay to a bitmap Bitmap graph_overlay = (Bitmap)System.Drawing.Image.FromFile($@"{AssetDirectoryConfig.assetDirectory.assetFolderPath}//Profile//StatusScreens//Default//P4//layer_3.png"); //Copy the P-Medal icon to a bitmap Bitmap pmedal_icon = (Bitmap)System.Drawing.Image.FromFile($@"{AssetDirectoryConfig.assetDirectory.assetFolderPath}//Profile//StatusScreens//Default//P4//pmedal_icon.png"); //Use a graphics object to edit the bitmap using (Graphics graphics = Graphics.FromImage(p4_template)) { //Set text rendering to have antialiasing graphics.TextRenderingHint = TextRenderingHint.AntiAlias; // Draw the first bitmap layer to the template graphics.DrawImage(base_layer, 0, 0, base_layer.Width, base_layer.Height); //Draw the randomized elements to the template first graphics.DrawImage(RandomizeWaveAndWindow(), 0, 0, 1920, 1080); //Draw the information fields graphics.DrawImage(info_layer, 0, 0, 1920, 1080); //Using a font object, draw the user's username value to the template using (Font p4g_font = new Font("P4G", 37)) { graphics.DrawString(username, p4g_font, System.Drawing.Brushes.Black, new Point(276, 139)); } //Create text boxes to place the user's level and P-Medal values in Rectangle level_box = new Rectangle(70, 84, 210, 100); Rectangle pmedal_box = new Rectangle(50, 180, 210, 100); Rectangle next_exp_box = new Rectangle(575, 222, 1000, 100); //Create new colors to shade the level and P-Medal values with System.Drawing.Color level_color = System.Drawing.Color.FromArgb(255, 247, 130); System.Drawing.Color pmedal_color = System.Drawing.Color.FromArgb(225, 108, 1); //Create new brushes so that the colors can be used on a font object SolidBrush level_brush = new SolidBrush(level_color); SolidBrush pmedal_brush = new SolidBrush(pmedal_color); //Using a font object, draw the user's level value to the template using (Font p4g_stats_font = new Font("P4G Stats", 68)) { //Format the string so that its placement is on the right side of the text box StringFormat stringFormat = new StringFormat(); stringFormat.Alignment = StringAlignment.Far; graphics.DrawString(level, p4g_stats_font, level_brush, level_box, stringFormat); } //Draw P-Medal text and graphic information within this font object using (Font p4g_stats_font = new Font("P4G Stats", 48)) { //Format the string so that its placement is on the right side of the text box StringFormat stringFormat = new StringFormat(); stringFormat.Alignment = StringAlignment.Far; //If the user's P-Medal count has 2 or less digits, draw the P-Medal icon in a specific place if (pmedals.Length <= 2) { graphics.DrawImage(pmedal_icon, 85, 189, 72, 52); } //Else, if the user's P-Medal count has 3 digits, draw the P-Medal icon in a different place else if (pmedals.Length == 3) { graphics.DrawImage(pmedal_icon, 55, 189, 72, 52); } //Draw the user's P-Medal value to the screen graphics.DrawString(pmedals, p4g_stats_font, pmedal_brush, pmedal_box, stringFormat); } //Draw the user's next EXP value to the template within this font object using (Font p4g_stats_font = new Font("P4G Stats", 47)) { //Format the string so that its placement is on the left side of the text box StringFormat stringFormat = new StringFormat(); stringFormat.Alignment = StringAlignment.Near; graphics.DrawString($"{next_exp}", p4g_stats_font, System.Drawing.Brushes.Black, next_exp_box, stringFormat); } //Create text boxes to draw the social link rank titles Rectangle proficiency_title_box = new Rectangle(1163, 233, 309, 53); Rectangle diligence_title_box = new Rectangle(834, 860, 309, 53); Rectangle expression_title_box = new Rectangle(1493, 859, 309, 53); //Draw the rank titles onto the template using (Font p4g_font = new Font("P4G", 31)) { //Format the strings so that their placements are at the center of the text boxes StringFormat stringFormat = new StringFormat(); stringFormat.Alignment = StringAlignment.Center; graphics.DrawString(proficiency_title, p4g_font, System.Drawing.Brushes.White, proficiency_title_box, stringFormat); graphics.DrawString(diligence_title, p4g_font, System.Drawing.Brushes.White, diligence_title_box, stringFormat); graphics.DrawString(expression_title, p4g_font, System.Drawing.Brushes.White, expression_title_box, stringFormat); } //Create points that define radar chart Point proficiency_point = ProficiencyGraphPoint(account.Proficiency_Rank); Point diligence_point = DiligenceGraphPoint(account.Diligence_Rank); Point expression_point = ExpressionGraphPoint(account.Expression_Rank); //Create rectangles for large endpoints that emphasize where the radar points are Rectangle proficiency_endpoint = ProficiencyEndpoint(account.Proficiency_Rank); Rectangle diligence_endpoint = DiligenceEndpoint(account.Diligence_Rank); Rectangle expression_endpoint = ExpressionEndpoint(account.Expression_Rank); //Create a color for the radar chart SolidBrush orangeBrush = new SolidBrush(System.Drawing.Color.Orange); //Bind radar chart points Point[] curvePoints = { proficiency_point, diligence_point, expression_point }; //Draw radar chart to screen graphics.FillPolygon(orangeBrush, curvePoints); //Draw the plot point overlay to the template graphics.DrawImage(graph_overlay, 0, 0, 1920, 1080); //Create a black pen to draw large endpoints over the plot point overlay System.Drawing.Pen blackPen = new System.Drawing.Pen(System.Drawing.Color.Black, 10); //Draw the large endpoints to the template graphics.DrawEllipse(blackPen, proficiency_endpoint); graphics.DrawEllipse(blackPen, diligence_endpoint); graphics.DrawEllipse(blackPen, expression_endpoint); //Use a web client to download the user's profile picture and draw it to the template using (var wc = new WebClient()) { using (var imgStream = new MemoryStream(wc.DownloadData(profile_picture))) { using (var objImage = System.Drawing.Image.FromStream(imgStream)) { graphics.InterpolationMode = InterpolationMode.NearestNeighbor; graphics.DrawImage(objImage, 250, 447, 440, 440); } } } // If the user has ever reset their level, render a prestige counter to the template if (account.Level_Resets > 0) { graphics.DrawImage(RenderPrestigeCounter(account.Level_Resets), 0, 0, 1920, 1080); } } //Save the bitmap to a data stream MemoryStream memoryStream = new MemoryStream(); p4_template.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png); memoryStream.Seek(0, SeekOrigin.Begin); //Send the image await channel.SendFileAsync(memoryStream, $"status_{user.Id}_{DateTime.UtcNow}.png"); //Delete the loading message await loader.DeleteAsync(); } catch (Exception ex) { //Send an error message to the user _ = ErrorHandling.Scene_Upload_Failed(user, channel); Console.WriteLine(ex); //Delete the loading message await loader.DeleteAsync(); return; } }