public static string GenerateFront(string name, Roles role, string filePath) { string hexcode = "#0B1133"; string border = "Cards/hero_frontoverlay.png"; if (role == Roles.Villain) { border = "Cards/villain_frontoverlay.png"; hexcode = "#670000"; } else if (role == Roles.Rogue) { border = "Cards/rogue_frontoverlay.png"; hexcode = "#350022"; } var fontCollection = new FontCollection(); var parentFont = fontCollection.Install("Cards/front.tff").CreateFont(50, FontStyle.Bold); var childFont = parentFont; using (Image <Rgba32> backgroundImage = Image.Load(filePath)) { using (Image <Rgba32> borderImage = Image.Load(border)) { int fontSize = 50; float textOffset = 0; while (true) { var size = TextMeasurer.Measure(name, new RendererOptions(childFont)); if (size.Width > 350) { fontSize -= 5; childFont = new Font(parentFont, fontSize); continue; } textOffset = 250 - size.Width / 2; break; } backgroundImage.Mutate(x => x.Resize(new ResizeOptions() { Mode = ResizeMode.Crop, Size = new Size(500, 700), Position = AnchorPositionMode.Top }).DrawImage(borderImage, 1).DrawText(name, childFont, Brushes.Solid(Rgba32.FromHex("#FFFFFF")), Pens.Solid(Rgba32.FromHex(hexcode), 8), new PointF(textOffset, 630)).DrawText(name, childFont, Brushes.Solid(Rgba32.FromHex("#FFFFFF")), new PointF(textOffset, 630))); backgroundImage.Save($"Cards/Done/front-{name}.png"); return($"Cards/Done/front-{name}.png"); } } }
public void Draw() { if (ImageWrapper != null) { var width = (int)ImageWrapper.ActualWidth; var height = (int)ImageWrapper.ActualHeight; using (image = new Image <Rgba32>(width, height)) { // Draw triangle image.Mutate((x) => { // Define pens and inks var sss = new Pen(Rgba32.ParseHex("#FFC0CB"), 10, new float[] { 2f, 6f, 8f }); var pinkPen = Pens.Solid(Rgba32.ParseHex("#FFC0CB"), 10); var greenPen = Pens.Solid(Rgba32.ParseHex("#228B22"), 10); var blackPen = Pens.Solid(Rgba32.ParseHex("#000000"), 10); var pinkBrush = Brushes.Solid(Rgba32.ParseHex("#C71585")); Image img = Image.Load("Resources\\cat.jpg"); img.Mutate((x) => { x.Resize( 128, (x.GetCurrentSize().Height / x.GetCurrentSize().Width) * 128); }); var CatBrush = new ImageBrush(img); // Draw a Line x.DrawLines(pinkPen, new PointF[] { new PointF(30, 30), new PointF(100, 30) }); // Draw a Triangle x.FillPolygon(CatBrush, new PointF[] { new PointF(50, 50), new PointF(500, 30), new PointF(555, 555), }); // Draw a star x y numberofcorners innerradius outerradius Star star = new Star(50, 50, 5, 50, 100); var staroutline = Outliner.GenerateOutline(star, 2, JointStyle.Round); x.Fill(CatBrush, star); // Draw an arc var arc = new Polygon(new CubicBezierLineSegment(new PointF[] { new PointF(10, 400), new PointF(30, 10), new PointF(240, 30), new PointF(300, 400) })); x.Draw(blackPen, arc); // Draw some Ellipse var sector = new EllipsePolygon(200, 200, 10, 20).Scale(5); x.Draw(blackPen, sector); }); // Set the source ImageControl.Source = Helpers.ImageToBitmap(image); } } }
public static Stream Render(string text, Image <Rgba32> image) { var words = text.Split(' '); var font = Arial.CreateFont(2, FontStyle.Regular); var canvasPoint = new PointF(image.Width * 0.125F, image.Height * 0.70F); var canvasSize = new SizeF(image.Width * 0.75F, image.Height * 0.3F); font = GetLargestFont(canvasSize, font, text); var render = new RendererOptions(font); foreach (var line in SplitTextForMaxWidth(canvasSize.Width, font, text)) { var textSize = TextMeasurer.Measure(line, render); var point = new PointF(canvasPoint.X + (canvasSize.Width - textSize.Width) / 2, canvasPoint.Y); image.Mutate(cl => cl.DrawText(line, font, Brushes.Solid(Color.WhiteSmoke), Pens.Solid(Color.Black, 1), point)); canvasPoint.Y += textSize.Height; } var str = new MemoryStream(); image.SaveAsJpeg(str); str.Seek(0, SeekOrigin.Begin); return(str); }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="source">Source image data.</param> /// <param name="destination">Destination image data.</param> /// <param name="rect">Image rectangle for processing by the filter.</param> /// protected override void ProcessFilter(Image <Rgb24> source, Image <L8> destination, Rectangle rect) { // processing start and stop X,Y positions int startX = rect.Left + 1; int startY = rect.Top + 1; int stopX = startX + rect.Width - 2; int stopY = startY + rect.Height - 2; int width = rect.Width - 2; int height = rect.Height - 2; int dstOffset = rect.Width + 2; int srcOffset = rect.Width + 2; // pixel's value and gradients int gx, gy; double orientation, toAngle = 180.0 / System.Math.PI; float leftPixel = 0, rightPixel = 0; // STEP 1 - blur image source.Mutate(x => x.ApplyProcessor(this.gaussianFilter)); var src = source.CloneAs <L8>(); // orientation array byte[] orients = new byte[width * height]; // gradients array float[,] gradients = new float[source.Width, source.Height]; float maxGradient = float.NegativeInfinity; // STEP 2 - calculate magnitude and edge orientation int p = 0; // for each line for (int y = startY; y < stopY; y++) { // for each pixel for (int x = startX; x < stopX; x++, p++) { gx = src[y - 1, x + 1].PackedValue + src[y, x + 1].PackedValue - src[y - 1, x - 1].PackedValue - src[y, x - 1].PackedValue + (2 * (src[y + 1, x].PackedValue - src[y - 1, x].PackedValue)); gy = src[y - 1, x - 1].PackedValue + src[y - 1, x + 1].PackedValue - src[y, x - 1].PackedValue - src[y, x + 1].PackedValue + (2 * (src[y - 1, x].PackedValue - src[y + 1, x].PackedValue)); // get gradient value gradients[x, y] = (float)Math.Sqrt((gx * gx) + (gy * gy)); if (gradients[x, y] > maxGradient) { maxGradient = gradients[x, y]; } // --- get orientation if (gx == 0) { // can not divide by zero orientation = (gy == 0) ? 0 : 90; } else { double div = (double)gy / gx; // handle angles of the 2nd and 4th quads if (div < 0) { orientation = 180 - (Math.Atan(-div) * toAngle); } // handle angles of the 1st and 3rd quads else { orientation = System.Math.Atan(div) * toAngle; } // get closest angle from 0, 45, 90, 135 set if (orientation < 22.5) { orientation = 0; } else if (orientation < 67.5) { orientation = 45; } else if (orientation < 112.5) { orientation = 90; } else if (orientation < 157.5) { orientation = 135; } else { orientation = 0; } } // save orientation orients[p] = (byte)orientation; } } // STEP 3 - suppres non maximums p = 0; // for each line for (int y = startY; y < stopY; y++) { // for each pixel for (int x = startX; x < stopX; x++, p++) { // get two adjacent pixels switch (orients[p]) { case 0: leftPixel = gradients[x - 1, y]; rightPixel = gradients[x + 1, y]; break; case 45: leftPixel = gradients[x - 1, y + 1]; rightPixel = gradients[x + 1, y - 1]; break; case 90: leftPixel = gradients[x, y + 1]; rightPixel = gradients[x, y - 1]; break; case 135: leftPixel = gradients[x + 1, y + 1]; rightPixel = gradients[x - 1, y - 1]; break; } // compare current pixels value with adjacent pixels if ((gradients[x, y] < leftPixel) || (gradients[x, y] < rightPixel)) { destination[startY, startX] = new L8(0); } else { var result = (byte)(gradients[x, y] / maxGradient * 255); destination[startY, startX] = new L8(result); } } } // STEP 4 - hysteresis // for each line for (int y = startY; y < stopY; y++) { // for each pixel for (int x = startX; x < stopX; x++) { if (destination[startY, startX].PackedValue < this.HighThreshold) { if (destination[startY, startX].PackedValue < this.LowThreshold) { // non edge destination[startY, startX] = new L8(0); } else { // check 8 neighboring pixels if ((destination[startY - 1, startX].PackedValue < this.HighThreshold) && (destination[startY + 1, startX].PackedValue < this.HighThreshold) && (destination[startY - 1, startX - 1].PackedValue < this.HighThreshold) && (destination[startY - 1, startX].PackedValue < this.HighThreshold) && (destination[startY - 1, startX + 1].PackedValue < this.HighThreshold) && (destination[startY + 1, startX - 1].PackedValue < this.HighThreshold) && (destination[startY + 1, startX].PackedValue < this.HighThreshold) && (destination[startY + 1, startX + 1].PackedValue < this.HighThreshold)) { destination[startY, startX] = new L8(0); } } } } } // STEP 5 - draw black rectangle to remove those pixels, which were not processed // (this needs to be done for those cases, when filter is applied "in place" - // source image is modified instead of creating new copy) RectangleF r = rect; destination.Mutate(x => x.Draw(Pens.Solid(Color.Black, 1), r)); }
private static void DrawWorld(World world) { var map = world.Map; var output = "cellmap.png"; var e = map.MapCells.Values.ElementAt(10); var highlight = new List <uint>() { e.Id }; highlight.AddRange(e.AdjacentMapCellIds); using (var image = new Image <Rgba32>(map.Width, map.Height)) { // Draw edges first to ensure any pixel gaps between polygons // will be filled in foreach (var cell in map.MapCells.Values) { if (cell.MapPoints.Count > 2) { var color = GetColor(cell, map.LandThreshold); image.Mutate(x => x .DrawLines(new Pen(color, 3f), cell.MapPoints.Select(p => new PointF(p.X, p.Y)).ToArray()) ); } } // Now draw map cell polygons foreach (var cell in map.MapCells.Values) { if (cell.MapPoints.Count > 2) { var color = GetColor(cell, map.LandThreshold); image.Mutate(x => x .FillPolygon(color, cell.MapPoints.Select(p => new PointF(p.X, p.Y)).ToArray()) ); } } var colors = new List <Color>() { Color.Red, Color.Orange, Color.Yellow, Color.GreenYellow, Color.Green, Color.DarkGreen, Color.DarkBlue, Color.Blue, Color.BlueViolet, Color.Violet, Color.PaleVioletRed }; colors.AddRange(Color.WebSafePalette.ToArray()); // Regions foreach (var territory in world.Territories.Values) { var color = colors.RemoveRandom(); if (color == null) { color = Color.White; } /* * foreach (var cell in territory.MapCells) * { * if (cell.MapPoints.Count > 2) * { * var centerX = cell.X; * var centerY = cell.Y; * * image.Mutate(x => x * .FillPolygon(color, cell.MapPoints.Select(p => new PointF(p.X, p.Y)).ToArray())); * } * }/**/ /* * image.Mutate(x => x * .DrawLines(new Pen(color, 2f), territory.ContainingMapPointIds.Select(id => new PointF(world.Map.MapPoints[id].X, world.Map.MapPoints[id].Y)).ToArray())); */ } // Now draw population centers foreach (var pop in world.PopulationCenters.Values) { image.Mutate(x => x .DrawLines(new Pen(Color.LightGray, 10f), new PointF(pop.MapCell.X, pop.MapCell.Y), new PointF(pop.MapCell.X, pop.MapCell.Y)) .DrawText(pop.Name, SmallFont, Color.White, new PointF(pop.MapCell.X + 10, pop.MapCell.Y + 10)) ); } // Show names of landmasses var textOptions = new TextOptions() { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center, }; var drawingOptions = new DrawingOptions() { TextOptions = textOptions }; foreach (var landmass in world.Landmasses.Values.Where(x => x.MapCells.Count > 2)) { if (landmass.MapCells.Count > 100) { image.Mutate(x => x .DrawText(drawingOptions, landmass.Name, BigFont, Brushes.Solid(Color.White), Pens.Solid(Color.Black, 2.5f), new PointF(landmass.X, landmass.Y)) ); } else if (landmass.MapCells.Count < 20) { /* * drawingOptions.TextOptions.VerticalAlignment = VerticalAlignment.Bottom; * * image.Mutate(x => x * .DrawText(drawingOptions, landmass.Name, SmallFont, Brushes.Solid(Color.Black), Pens.Solid(Color.Black, 1), new PointF(landmass.Center.X, landmass.Center.Y)) * ); * /**/ } else { image.Mutate(x => x .DrawText(drawingOptions, landmass.Name, NormalFont, Brushes.Solid(Color.Black), Pens.Solid(Color.Black, 0.5f), new PointF(landmass.X, landmass.Y)) ); } } using (var filestream = new FileStream(output, FileMode.Create)) { image.SaveAsPng(filestream); } } try { var process = new ProcessStartInfo(output) { UseShellExecute = true, Verb = "open" }; Process.Start(process); } catch (Exception ex) { Console.WriteLine(ex.Message); } }
/// <summary> /// Renderes the given historic coverages as PNG image. /// </summary> /// <param name="historicCoverages">The historic coverages.</param> /// <returns>The image in PNG format.</returns> public static byte[] RenderHistoryChart(IReadOnlyList <HistoricCoverage> historicCoverages) { using (Image <Rgba32> image = new Image <Rgba32>(1450, 150)) using (MemoryStream output = new MemoryStream()) { var grayPen = Pens.Dash(Color.LightGray, 1); var redPen = Pens.Solid(Color.ParseHex("cc0000"), 2); var bluePen = Pens.Solid(Color.ParseHex("1c2298"), 2); var redBrush = Brushes.Solid(Color.ParseHex("cc0000")); var blueBrush = Brushes.Solid(Color.ParseHex("1c2298")); int numberOfLines = historicCoverages.Count; if (numberOfLines == 1) { numberOfLines = 2; } float totalWidth = 1445 - 50; float width = totalWidth / (numberOfLines - 1); float totalHeight = 115 - 15; image.Mutate(ctx => { ctx.Fill(Color.White); ctx.DrawLines(grayPen, new PointF(50, 115), new PointF(1445, 115)); ctx.DrawLines(grayPen, new PointF(50, 90), new PointF(1445, 90)); ctx.DrawLines(grayPen, new PointF(50, 65), new PointF(1445, 65)); ctx.DrawLines(grayPen, new PointF(50, 40), new PointF(1445, 40)); ctx.DrawLines(grayPen, new PointF(50, 15), new PointF(1445, 15)); for (int i = 0; i < numberOfLines; i++) { ctx.DrawLines(grayPen, new PointF(50 + (i * width), 15), new PointF(50 + (i * width), 115)); } for (int i = 1; i < historicCoverages.Count; i++) { float x1 = 50 + ((i - 1) * width); float y1 = 15 + (((100 - (float)historicCoverages[i - 1].CoverageQuota.GetValueOrDefault()) * totalHeight) / 100); float x2 = 50 + (i * width); float y2 = 15 + (((100 - (float)historicCoverages[i].CoverageQuota.GetValueOrDefault()) * totalHeight) / 100); ctx.DrawLines(redPen, new PointF(x1, y1), new PointF(x2, y2)); } if (historicCoverages.Any(h => h.BranchCoverageQuota.HasValue)) { for (int i = 1; i < historicCoverages.Count; i++) { float x1 = 50 + ((i - 1) * width); float y1 = 15 + (((100 - (float)historicCoverages[i - 1].BranchCoverageQuota.GetValueOrDefault()) * totalHeight) / 100); float x2 = 50 + (i * width); float y2 = 15 + (((100 - (float)historicCoverages[i].BranchCoverageQuota.GetValueOrDefault()) * totalHeight) / 100); ctx.DrawLines(bluePen, new PointF(x1, y1), new PointF(x2, y2)); } } for (int i = 0; i < historicCoverages.Count; i++) { float x1 = 50 + (i * width); float y1 = 15 + (((100 - (float)historicCoverages[i].CoverageQuota.GetValueOrDefault()) * totalHeight) / 100); ctx.Fill(redBrush, new EllipsePolygon(x1, y1, 3)); } if (historicCoverages.Any(h => h.BranchCoverageQuota.HasValue)) { for (int i = 0; i < historicCoverages.Count; i++) { float x1 = 50 + (i * width); float y1 = 15 + (((100 - (float)historicCoverages[i].BranchCoverageQuota.GetValueOrDefault()) * totalHeight) / 100); ctx.Fill(blueBrush, new EllipsePolygon(x1, y1, 3)); } } try { var font = SystemFonts.CreateFont("Arial", 11, FontStyle.Regular); var textGraphicsOptions = new TextGraphicsOptions(); textGraphicsOptions.TextOptions.HorizontalAlignment = HorizontalAlignment.Right; ctx.DrawText(textGraphicsOptions, "100", font, Color.Gray, new PointF(38, 5)); ctx.DrawText(textGraphicsOptions, "75", font, Color.Gray, new PointF(38, 30)); ctx.DrawText(textGraphicsOptions, "50", font, Color.Gray, new PointF(38, 55)); ctx.DrawText(textGraphicsOptions, "25", font, Color.Gray, new PointF(38, 80)); ctx.DrawText(textGraphicsOptions, "0", font, Color.Gray, new PointF(38, 105)); } catch (SixLabors.Fonts.Exceptions.FontFamilyNotFoundException) { // Font 'Arial' may not be present on Linux } }); image.Save(output, new PngEncoder()); return(output.ToArray()); } }
public static IImageProcessingContext DrawBoxedText(this IImageProcessingContext processingContext, Font font, string text, Color mainColor, Color outlineColor, Rectangle rectangle, VerticalAlignment verticalAlignment, bool debugRectangle = false) { Size imgSize = processingContext.GetCurrentSize(); float targetWidth = rectangle.Width; float targetHeight = rectangle.Height; float targetMinHeight = (int)(targetHeight * 0.95); var scaledFont = font; FontRectangle s = new(0, 0, float.MaxValue, float.MaxValue); float scaleFactor = (scaledFont.Size / 2); int trapCount = (int)scaledFont.Size * 2; if (trapCount < 10) { trapCount = 10; } bool isTooSmall = false; while ((s.Height > targetHeight || s.Height < targetMinHeight) && trapCount > 0) { if (s.Height > targetHeight) { if (isTooSmall) { scaleFactor /= 2; } scaledFont = new Font(scaledFont, scaledFont.Size - scaleFactor); isTooSmall = false; } if (s.Height < targetMinHeight) { if (!isTooSmall) { scaleFactor /= 2; } scaledFont = new Font(scaledFont, scaledFont.Size + scaleFactor); isTooSmall = true; } trapCount--; s = TextMeasurer.Measure(text, new RendererOptions(scaledFont) { WrappingWidth = targetWidth }); } var textGraphicOptions = new TextGraphicsOptions() { TextOptions = { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = verticalAlignment, WrapTextWidth = targetWidth } }; var position = new PointF(rectangle.X, 0); switch (verticalAlignment) { case VerticalAlignment.Top: position.Y = rectangle.Y; break; case VerticalAlignment.Center: position.Y = rectangle.Y + rectangle.Height / 2; break; case VerticalAlignment.Bottom: position.Y = rectangle.Y + rectangle.Height; break; default: break; } if (debugRectangle) { PointF[] points = { new PointF(rectangle.X, rectangle.Y), new PointF(rectangle.X, rectangle.Y + rectangle.Height), new PointF(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height), new PointF(rectangle.X + rectangle.Width, rectangle.Y) }; processingContext = processingContext.DrawPolygon(new Pen(Color.Red, 5), points); } return(processingContext.DrawText(textGraphicOptions, text, scaledFont, Brushes.Solid(mainColor), Pens.Solid(outlineColor, font.Size / 10), position)); }
private static async Task <Stream> DrawText(Stream stream, string text) { if (stream is null) { throw new ArgumentNullException(nameof(stream)); } if (String.IsNullOrEmpty(text)) { throw new ArgumentNullException(nameof(text)); } var font = SystemFonts.CreateFont("Arial", 32); var options = new TextGraphicsOptions(true) { VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Center }; MemoryStream output = new MemoryStream(); using (Image image = Image.Load(stream, new JpegDecoder())) { var position = new PointF(image.Width / 2, image.Height - 30); image.Mutate(x => x.DrawText(options, text, font, Brushes.Solid(Rgba32.White), Pens.Solid(Rgba32.Black, 1), position)); image.Save(output, new JpegEncoder()); output.Position = 0; } return(output); }