/// <summary> /// Take a path provided by a user, draw it as a maptile. Potentially useful for exercise trackers. Resulting file must not be saved to the server as that would be user tracking. /// </summary> /// <param name="pointListAsString">a string of points separate by , and | </param> /// <returns>the png file with the path drawn over the mapdata in the area.</returns> public byte[] DrawUserPath(string pointListAsString) { //String is formatted as Lat,Lon~Lat,Lon~ repeating. Characters chosen to not be percent-encoded if submitted as part of the URL. //first, convert this to a list of latlon points string[] pointToConvert = pointListAsString.Split("|"); List <Coordinate> coords = pointToConvert.Select(p => new Coordinate(double.Parse(p.Split(',')[0]), double.Parse(p.Split(',')[1]))).ToList(); var mapBuffer = resolutionCell8 / 2; //Leave some area around the edges of where they went. GeoArea mapToDraw = new GeoArea(coords.Min(c => c.Y) - mapBuffer, coords.Min(c => c.X) - mapBuffer, coords.Max(c => c.Y) + mapBuffer, coords.Max(c => c.X) + mapBuffer); ImageStats info = new ImageStats(mapToDraw, 1024, 1024); LineString line = new LineString(coords.ToArray()); var drawableLine = PolygonToDrawingLine(line, mapToDraw, info.degreesPerPixelX, info.degreesPerPixelY); //Now, draw that path on the map. var places = GetPlaces(mapToDraw); var baseImage = DrawAreaAtSize(info, places); Image <Rgba32> image = new Image <Rgba32>(info.imageSizeX, info.imageSizeY); Rgba32 strokeColor = Rgba32.ParseHex("000000"); image.Mutate(x => x.Draw(strokeColor, 4, new SixLabors.ImageSharp.Drawing.Path(drawableLine))); image.Mutate(x => x.Flip(FlipMode.Vertical)); //Plus codes are south-to-north, so invert the image to make it correct. var ms = new MemoryStream(); image.SaveAsPng(ms); return(ms.ToArray()); }
private static IPen SetPenForGameTile(StylePaint tpe) { //These pens are saved with a fixed drawing width to match game tiles. int imgX = 0, imgY = 0; MapTileSupport.GetPlusCodeImagePixelSize("22334455", out imgX, out imgY); var info = new ImageStats(OpenLocationCode.DecodeValid("22334455"), imgX, imgY); var widthMod = resolutionCell11Lon * IMapTiles.GameTileScale; string htmlColor = tpe.HtmlColorCode; if (htmlColor.Length == 8) { htmlColor = htmlColor.Substring(2, 6) + htmlColor.Substring(0, 2); } Pen p; if (String.IsNullOrWhiteSpace(tpe.LinePattern) || tpe.LinePattern == "solid") { p = new Pen(Rgba32.ParseHex(htmlColor), tpe.LineWidthDegrees * (float)info.pixelsPerDegreeX); } else { float[] linesAndGaps = tpe.LinePattern.Split('|').Select(t => float.Parse(t)).ToArray(); p = new Pen(Rgba32.ParseHex(htmlColor), tpe.LineWidthDegrees * (float)info.pixelsPerDegreeX, linesAndGaps); } return(p); }
public object ReadYaml(IParser parser, Type type) { var scalar = parser.Consume <Scalar>(); var result = Rgba32.ParseHex(scalar.Value); return(result); }
public EncodeImageBenchmark() { _image1 = new Image <Rgba32>(4096, 4096); _image1.Mutate(x => x.BackgroundColor(Rgba32.ParseHex("FF6347"))); _image2 = Image.Load(Path.Combine("sample-files", "pexels-naushil-ansari-638738.jpg")); _image3 = Image.Load(Path.Combine("sample-files", "pexels-pok-rie-5696873.jpg")); }
public void CanCreateBlankImage(int width, int height, string color) { Console.WriteLine($"Vector.IsHardwareAccelerated: {Vector.IsHardwareAccelerated}"); var image = ImageUtils.GenerateSolidImage(width, height, Rgba32.ParseHex(color)); Assert.NotNull(image); Assert.NotNull(image.Contents); }
public void Color_Types_From_Hex_Produce_Equal_Scaled_Component_OutPut() { var color = Rgba32.ParseHex("183060C0"); var colorVector = RgbaVector.FromHex("183060C0"); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); Assert.Equal(color.B, (byte)(colorVector.B * 255)); Assert.Equal(color.A, (byte)(colorVector.A * 255)); }
public ColorPalette(string _name, params string[] hexcodes) { name = _name; firstColorHex = hexcodes[0]; colors = new Rgba32[hexcodes.Length]; for (int i = 0; i < hexcodes.Length; i++) { colors[i] = Rgba32.ParseHex(hexcodes[i]); } }
static void ParseArgs(string[] args) { foreach (string arg in args) { Console.WriteLine(arg); } // args: // GogoImageProcess --bordersize 5 --onColor ff000000 --offcolor 00000000 --gma2path for (int i = 0; i < args.Length;) { // if we're at the start of an argument definition if (args[i].StartsWith("--")) { string argument = args[i].Substring(2).ToLower(); switch (argument) { case "bordersize": case "b": bool success = int.TryParse(args[i + 1], out borderSize); if (!success) { throw new Exception("invalid following argument to --bordersize: " + args[i + 1]); } else { i += 2; } break; case "oncolor": case "on": onPixel = Rgba32.ParseHex(args[i + 1]); i += 2; break; case "offcolor": case "off": offPixel = Rgba32.ParseHex(args[i + 1]); i += 2; break; case "gma2path": case "v": Paths.ma2General = args[i + 1]; i += 2; break; default: Console.WriteLine("unrecognized argument: " + args[i]); i++; break; } } } }
public async Task EncodeSimpleImageAsync() { using var image = new Image <Rgba32>(20, 20); image.Mutate(x => x.BackgroundColor(Rgba32.ParseHex("FF6347"))); await using var ms = new MemoryStream(); await image.SaveAsync(ms, new WebPEncoder()); Assert.True(ms.Length > 0, "Output stream should not be empty."); Assert.InRange(ms.Length, 30, 50); }
public void Draw() { if (ImageWrapper != null) { // Get size of the image var width = (int)ImageWrapper.ActualWidth; var height = (int)ImageWrapper.ActualHeight; using (image = new Image <Rgba32>(width, height)) { // Draw triangle image.Mutate((ctx) => { offset = new PointF(width / 2, height / 2); // Define pens and inks var pinkPen = Pens.Solid(Rgba32.ParseHex("#FFC0CB"), 1); var greenPen = Pens.Solid(Rgba32.ParseHex("#228B22"), 1); var blackPen = Pens.Solid(Rgba32.ParseHex("#000000"), 1); var blackTransPen = Pens.Solid(Rgba32.ParseHex("#00005050"), 1); var pinkBrush = Brushes.Solid(Rgba32.ParseHex("#C71585")); var points = new List <PointF>(); for (int i = 1; i < width; i++) { var x = ScreenToX(i); var y = MathF.Pow(x, 2) * MathF.Exp(x); // Draw to screen PointF point = new PointF(i, YToScreen(y)); // Eliminate out of bounds exception if ( !float.IsInfinity(y) && MathF.Abs(y) < height * 10 ) { points.Add(point); } } DrawAxis(ctx, width, height); ctx.DrawLines(blackPen, points.ToArray()); }); // Set the source ImageControl.Source = Helpers.ImageToBitmap(image); } } }
// Create a title screen. That is text that fades in on a black background. async Task <List <string> > CreateTitleScreenAsync(int width, int height) { List <string> titleFramesFileNames = new List <string>(); TextGraphicsOptions textOptions = new TextGraphicsOptions() { TextOptions = new TextOptions() { WrapTextWidth = width, HorizontalAlignment = HorizontalAlignment.Center }, GraphicsOptions = new GraphicsOptions() { Antialias = true } }; const int fadeFramesCount = FramesPerSecond; // The text in in title screens will fade in in one second. for (int i = 1; i <= fadeFramesCount; i++) { using (var image = new Image <Rgba32>(width, height, Rgba32.ParseHex("000000"))) { // Calculate the color. The first will be very transparent, the last not. Color fontColor = Color.FromRgba(255, 255, 255, (byte)(255.0f * i / fadeFramesCount)); Font titlefont = MyFontFamily.CreateFont(height / 200.0f * 32, FontStyle.Regular); string title = Title; image.Mutate(x => x.DrawText(textOptions, title, titlefont, fontColor, new PointF(0, height / 3))); Font subtitlefont = MyFontFamily.CreateFont(height / 200.0f * 20, FontStyle.Regular); string subtitle = SubTitle; image.Mutate(x => x.DrawText(textOptions, subtitle, subtitlefont, fontColor, new PointF(0, height / 100 * 55))); string fullname = Path.Combine(TitleFramesPath, @$ "{i:000}.png"); await image.SaveAsPngAsync(fullname); titleFramesFileNames.Add(fullname); } } // We should have more frames where the nothing changes. // We are just reusing that last images seveal times. for (int i = 0; i < FramesPerSecond; i++) { titleFramesFileNames.Add(titleFramesFileNames.Last()); } return(titleFramesFileNames); }
public void AreNotEqual() { var color1 = new Rgba32(255, 0, 0, 255); var color2 = new Rgba32(0, 0, 0, 255); var color3 = Rgba32.ParseHex("#000"); var color4 = Rgba32.ParseHex("#000000"); var color5 = Rgba32.ParseHex("#FF000000"); Assert.NotEqual(color1, color2); Assert.NotEqual(color1, color3); Assert.NotEqual(color1, color4); Assert.NotEqual(color1, color5); }
// Get the original images to use. // In real life you will probably just do something like this: // // return Directory.EnumerateFiles(OriginalImagesPath, "*.jpg", enumerationOptions: new EnumerationOptions() // { // RecurseSubdirectories = true // }).OrderBy(a => a).ToList(); // // But since this is just demo code, we will create some images // instead with an advanced animation. private async Task <List <string> > GetOriginalImagesAsync() { List <string> originalImages = new List <string>(); int width = 320; int height = 200; Color objectsColor = Color.ParseHex("191D7C"); for (int i = 0; i < FramesPerSecond * 10; i++) { using (var image = new Image <Rgba32>(width, height, Rgba32.ParseHex("6D8AFF"))) { SixLabors.ImageSharp.Drawing.IPath yourPolygon = new SixLabors.ImageSharp.Drawing.Star ( width - height * 0.15f, height * 0.85f, prongs: 4, innerRadii: height * 0.05f, outerRadii: height * 0.10f, (float)-(Math.PI * 2 * i / FramesPerSecond / 6) );; image.Mutate(x => x.Fill(objectsColor, yourPolygon)); int objectWidth = width / 3; // Math is fun! const int framesToPassTheScreen = FramesPerSecond * 2; int x = -objectWidth + (width + objectWidth) * ((i + 1) % framesToPassTheScreen) / framesToPassTheScreen; if (x > -objectWidth) { var rectangle = new Rectangle(x, height / 3, objectWidth, height / 3); image.Mutate(x => x.Fill(objectsColor, rectangle)); } string fullFileName = Path.Combine(OriginalImagesPath, $@"{i:0000000}.png"); await image.SaveAsPngAsync(fullFileName); originalImages.Add(fullFileName); } } return(originalImages); }
public void AreEqual() { var color1 = new Rgba32(0, 0, 0); var color2 = new Rgba32(0, 0, 0, 1F); var color3 = Rgba32.ParseHex("#000"); var color4 = Rgba32.ParseHex("#000F"); var color5 = Rgba32.ParseHex("#000000"); var color6 = Rgba32.ParseHex("#000000FF"); Assert.Equal(color1, color2); Assert.Equal(color1, color3); Assert.Equal(color1, color4); Assert.Equal(color1, color5); Assert.Equal(color1, color6); }
/// <summary> /// Draws grid lines to match boundaries for 10 character PlusCodes. /// </summary> /// <param name="totalArea">the GeoArea to draw lines in</param> /// <returns>the byte array for the maptile png file</returns> public byte[] DrawCell10GridLines(GeoArea totalArea) { int imageSizeX = IMapTiles.SlippyTileSizeSquare; int imageSizeY = IMapTiles.SlippyTileSizeSquare; Image <Rgba32> image = new Image <Rgba32>(imageSizeX, imageSizeY); var bgColor = Rgba32.ParseHex("00000000"); image.Mutate(x => x.Fill(bgColor)); var lineColor = Rgba32.ParseHex("00CCFF"); var StrokeWidth = 1; double degreesPerPixelX = totalArea.LongitudeWidth / imageSizeX; double degreesPerPixelY = totalArea.LatitudeHeight / imageSizeY; //This is hardcoded to Cell 10 spaced gridlines. var imageLeft = totalArea.WestLongitude; var spaceToFirstLineLeft = (imageLeft % resolutionCell10); var imageBottom = totalArea.SouthLatitude; var spaceToFirstLineBottom = (imageBottom % resolutionCell10); double lonLineTrackerDegrees = imageLeft - spaceToFirstLineLeft; //This is degree coords while (lonLineTrackerDegrees <= totalArea.EastLongitude + resolutionCell10) //This means we should always draw at least 2 lines, even if they're off-canvas. { var geoLine = new LineString(new Coordinate[] { new Coordinate(lonLineTrackerDegrees, 90), new Coordinate(lonLineTrackerDegrees, -90) }); var points = PolygonToDrawingLine(geoLine, totalArea, degreesPerPixelX, degreesPerPixelY); image.Mutate(x => x.Draw(lineColor, StrokeWidth, new SixLabors.ImageSharp.Drawing.Path(points))); lonLineTrackerDegrees += resolutionCell10; } double latLineTrackerDegrees = imageBottom - spaceToFirstLineBottom; //This is degree coords while (latLineTrackerDegrees <= totalArea.NorthLatitude + resolutionCell10) //This means we should always draw at least 2 lines, even if they're off-canvas. { var geoLine = new LineString(new Coordinate[] { new Coordinate(180, latLineTrackerDegrees), new Coordinate(-180, latLineTrackerDegrees) }); var points = PolygonToDrawingLine(geoLine, totalArea, degreesPerPixelX, degreesPerPixelY); image.Mutate(x => x.Draw(lineColor, StrokeWidth, new SixLabors.ImageSharp.Drawing.Path(points))); latLineTrackerDegrees += resolutionCell10; } image.Mutate(x => x.Flip(FlipMode.Vertical)); //Plus codes are south-to-north, so invert the image to make it correct. var ms = new MemoryStream(); image.SaveAsPng(ms); return(ms.ToArray()); }
public async Task <byte[]> GenerateAvatar(string name, string formatExtension, Int32 squareSize, CancellationToken cancellationToken) { name = AvatarHelpers.CleanName(name); var backgroundColor = await _paletteProvider.GetColorForString(name, cancellationToken); var generator = _avatarGenerators.FirstOrDefault(p => p.Extension.Equals(formatExtension, StringComparison.OrdinalIgnoreCase)); if (generator == null) { throw new InvalidOperationException("No generator found for extension " + formatExtension); } var buffer = await generator.GenerateAvatar(name, squareSize, Rgba32.ParseHex("fff"), backgroundColor, cancellationToken); return(buffer); }
public async static Task <byte[, , ]> VoxelColorsByCsvUri(string csvUri, Palette palette, Logger logger) { logger.LogTechState("Downloading document..."); using (WebClient wc = new WebClient()) { byte[] data = await wc.DownloadDataTaskAsync(csvUri); logger.LogTechInfo("Document is downloaded"); logger.LogTechState("Converting..."); using (MemoryStream stream = new MemoryStream(data)) { using (StreamReader reader = new StreamReader(stream)) { List <int> dim = reader.ReadLine().Split(',').Select(int.Parse).ToList(); int sx = dim[0], sy = dim[2], sz = dim[1]; byte[,,] res = new byte[sx, sy, sz]; Dictionary <string, byte> knownColors = new Dictionary <string, byte>(); for (int z = sz - 1; z >= 0; z--) { for (int y = 0; y < sy; y++) { string[] rowHex = reader.ReadLine().Split(','); for (int x = 0; x < sx; x++) { string hex = rowHex[x]; if (hex.EndsWith("FF")) { if (!knownColors.TryGetValue(hex, out byte colorCode)) { Rgba32 color = Rgba32.ParseHex(hex); knownColors[hex] = colorCode = palette.ClosestAvailable(color); } res[x, y, z] = colorCode; } } } reader.ReadLine(); } return(res); } } } }
public async Task OutputsCorrectNumberFormats(string culture) { Thread.CurrentThread.CurrentCulture = new CultureInfo(culture); var fontProvider = new DefaultFontProvider(); var generator = new SvgAvatarGenerator(fontProvider); var bytes = await generator.GenerateAvatar("SX", 512, Rgba32.ParseHex("fff"), Rgba32.ParseHex("000")); var xml = Encoding.UTF8.GetString(bytes); var control = Input.FromString("<?xml version=\"1.0\" encoding=\"utf-8\"?><svg width=\"512\" height=\"512\" xmlns=\"http://www.w3.org/2000/svg\"><rect width=\"100%\" height=\"100%\" fill=\"#000000\" /><path stroke=\"#FFFFFF\" fill=\"#FFFFFF\" d=\"M254.4875 266.8625L 254.4875 266.8625C 231.84583 260.3542 215.36874 252.35625 205.05624 242.86874L 205.05624 242.86874L 205.05624 242.86874C 194.74374 233.38124 189.5875 221.67084 189.5875 207.7375L 189.5875 207.7375L 189.5875 207.7375C 189.5875 191.97083 195.88957 178.93124 208.49374 168.61874L 208.49374 168.61874L 208.49374 168.61874C 221.09792 158.30624 237.48334 153.15 257.65 153.15L 257.65 153.15L 257.65 153.15C 271.4 153.15 283.66043 155.80832 294.43127 161.125L 294.43127 161.125L 294.43127 161.125C 305.2021 166.44165 313.54376 173.775 319.45624 183.125L 319.45624 183.125L 319.45624 183.125C 325.36877 192.47499 328.325 202.69583 328.325 213.78749L 328.325 213.78749L 301.7875 213.78749L 301.7875 213.78749C 301.7875 201.6875 297.9375 192.17708 290.2375 185.25624L 290.2375 185.25624L 290.2375 185.25624C 282.5375 178.3354 271.675 174.87498 257.65 174.87498L 257.65 174.87498L 257.65 174.87498C 244.63333 174.87498 234.48125 177.73956 227.19376 183.46875L 227.19376 183.46875L 227.19376 183.46875C 219.90625 189.1979 216.2625 197.15 216.2625 207.325L 216.2625 207.325L 216.2625 207.325C 216.2625 215.48334 219.72292 222.38126 226.64375 228.01874L 226.64375 228.01874L 226.64375 228.01874C 233.56459 233.65625 245.34375 238.81248 261.98126 243.48749L 261.98126 243.48749L 261.98126 243.48749C 278.61877 248.16249 291.63544 253.31876 301.03125 258.95624L 301.03125 258.95624L 301.03125 258.95624C 310.42706 264.59375 317.39374 271.17084 321.93127 278.6875L 321.93127 278.6875L 321.93127 278.6875C 326.46875 286.20416 328.7375 295.05 328.7375 305.225L 328.7375 305.225L 328.7375 305.225C 328.7375 321.45 322.4125 334.44376 309.7625 344.20624L 309.7625 344.20624L 309.7625 344.20624C 297.1125 353.96875 280.2 358.85 259.025 358.85L 259.025 358.85L 259.025 358.85C 245.275 358.85 232.44167 356.2146 220.525 350.94376L 220.525 350.94376L 220.525 350.94376C 208.60834 345.6729 199.41875 338.45416 192.95625 329.2875L 192.95625 329.2875L 192.95625 329.2875C 186.49374 320.12085 183.2625 309.71667 183.2625 298.075L 183.2625 298.075L 209.8 298.075L 209.8 298.075C 209.8 310.175 214.26875 319.73126 223.20625 326.74377L 223.20625 326.74377L 223.20625 326.74377C 232.14375 333.75626 244.08334 337.2625 259.025 337.2625L 259.025 337.2625L 259.025 337.2625C 272.95834 337.2625 283.6375 334.42084 291.0625 328.73752L 291.0625 328.73752L 291.0625 328.73752C 298.48752 323.0542 302.2 315.30835 302.2 305.5L 302.2 305.5L 302.2 305.5C 302.2 295.69165 298.7625 288.10626 291.8875 282.74377L 291.8875 282.74377L 291.8875 282.74377C 285.0125 277.38126 272.54584 272.08752 254.4875 266.8625\" /></svg>").Build(); var test = Input.FromByteArray(bytes).Build(); var diff = new DOMDifferenceEngine(); diff.DifferenceListener += (comparison, outcome) => { Assert.True(false, "found a difference: " + comparison); }; diff.Compare(control, test); }
public void FromAndToHex() { // 8 digit hex matches css4 spec. RRGGBBAA var color = Rgba32.ParseHex("#AABBCCDD"); // 170, 187, 204, 221 Assert.Equal(170, color.R); Assert.Equal(187, color.G); Assert.Equal(204, color.B); Assert.Equal(221, color.A); Assert.Equal("AABBCCDD", color.ToHex()); color.R = 0; Assert.Equal("00BBCCDD", color.ToHex()); color.A = 255; Assert.Equal("00BBCCFF", color.ToHex()); }
/// <summary> /// Create the Brush object for each style and store it for later use. /// </summary> /// <param name="tpe">the TagParserPaint object to populate</param> private static IBrush SetPaintForTPP(StylePaint tpe) { //SkiaSharp now implements rounding line ends, but they're only for Pens //(which only work on lines), and my stuff all currently uses a Brush. //It's possible that I want pens instead of brushes for lines with patterns? string htmlColor = tpe.HtmlColorCode; if (htmlColor.Length == 8) { htmlColor = htmlColor.Substring(2, 6) + htmlColor.Substring(0, 2); } IBrush paint = new SolidBrush(Rgba32.ParseHex(htmlColor)); if (!string.IsNullOrEmpty(tpe.FileName)) { paint = new ImageBrush(cachedBitmaps[tpe.FileName]); } return(paint); }
/// <summary> /// Draw square boxes around each area to approximate how they would behave in an offline app /// </summary> /// <param name="info">the image information for drawing</param> /// <param name="items">the elements to draw.</param> /// <returns>byte array of the generated .png tile image</returns> public byte[] DrawOfflineEstimatedAreas(ImageStats info, List <DbTables.Place> items) { //TODO retest this. var image = new Image <Rgba32>(info.imageSizeX, info.imageSizeY); var bgColor = Rgba32.ParseHex("00000000"); image.Mutate(x => x.Fill(bgColor)); var fillColor = Rgba32.ParseHex("000000"); var strokeColor = Rgba32.ParseHex("000000"); var placeInfo = Standalone.Standalone.GetPlaceInfo(items.Where(i => i.IsGameElement ).ToList()); //this is for rectangles. foreach (var pi in placeInfo) { var rect = PlaceInfoToRect(pi, info); fillColor = Rgba32.ParseHex(TagParser.PickStaticColorForArea(pi.Name)); image.Mutate(x => x.Fill(fillColor, rect)); image.Mutate(x => x.Draw(strokeColor, 3, rect)); } image.Mutate(x => x.Flip(FlipMode.Vertical));; //inverts the inverted image again! foreach (var pi in placeInfo) { //NOTE: would be better to load fonts once and share that for the app's lifetime. var fonts = new SixLabors.Fonts.FontCollection(); var family = fonts.Add("fontHere.ttf"); var font = family.CreateFont(12, FontStyle.Regular); var rect = PlaceInfoToRect(pi, info); image.Mutate(x => x.DrawText(pi.Name, font, strokeColor, new PointF((float)(pi.lonCenter * info.pixelsPerDegreeX), (float)(pi.latCenter * info.pixelsPerDegreeY)))); } image.Mutate(x => x.Flip(FlipMode.Vertical)); //Plus codes are south-to-north, so invert the image to make it correct. var ms = new MemoryStream(); image.SaveAsPng(ms); return(ms.ToArray()); }
public MemoryStream MakeCaptchaImage(string text) { RendererOptions ro = new RendererOptions(font) { VerticalAlignment = VerticalAlignment.Center, TabWidth = 10 }; var rect = TextMeasurer.MeasureBounds(text, ro); MemoryStream ms; using (Image <Rgba32> img = new Image <Rgba32>((int)rect.Width + 10, (int)rect.Height + 6)) { var textGraphicsOptions = new TextGraphicsOptions() { TextOptions = new TextOptions() { VerticalAlignment = VerticalAlignment.Center, TabWidth = 10 } }; PointF[] points = { new PointF(2, img.Height / 2), new PointF(img.Width - 2, img.Height / 2) }; img.Mutate <Rgba32>(ctx => ctx .Fill(Rgba32.ParseHex("f0f4c3")) // white background image .DrawLines(Color.Black, 3, points) .DrawText(textGraphicsOptions, text, font, Color.Black, new PointF(0, img.Height / 2))); ms = new MemoryStream(); img.Save(ms, new JpegEncoder()); } ms.Seek(0, SeekOrigin.Begin); return(ms); }
public async Task Header(string parameter, string optional = "") { HeaderUtils.InterpretParameters(parameter); if (optional != "") { HeaderUtils.InterpretOptionalParameters(optional); } await Util.File.DownloadLastAttachmentAsync(Context, Path.GetTempPath() + "text-overlay", true); string type = Path.GetExtension(Util.File.ReturnLastAttachmentUrl(Context)); font = new Font(fontCollect.Find("Roboto"), Size); using (var img = await SLImage.LoadAsync(Path.GetTempPath() + "text-overlay" + type)) using (Image <Rgba32> container = new Image <Rgba32>(img.Width, img.Height + HeaderHeight)) { // forced parameters X = lrMargin; Y = tbMargin; Wraparound = img.Width - 2 * lrMargin; container.Mutate(mut => mut.Fill(Rgba32.ParseHex("FFFFFF"))); container.Mutate(mut => mut.DrawImage(img, new Point(0, HeaderHeight), PixelColorBlendingMode.Normal, 1.0F)); if (optional != "") { container.Mutate(mut => mut.DrawText(Text, font, new Rgba32(R / 255, G / 255, B / 255), new PointF(X, Y))); } else { container.Mutate(mut => mut.DrawText(Text, font, Rgba32.ParseHex("000000"), new PointF(X, Y))); } await container.SaveAsync(Path.GetTempPath() + "text-overlay_new" + type); } await Context.Channel.SendFileAsync(Path.GetTempPath() + "text-overlay_new" + type); }
public static void GenerateQRCode(this Stream file, string content) { try { var qrCodeWriter = new BarcodeWriterPixelData { Format = BarcodeFormat.QR_CODE, Options = new EncodingOptions { Margin = 0, Height = 250, Width = 250 } }; var pixelData = qrCodeWriter.Write(content); using (Image <Rgba32> image = new Image <Rgba32>(pixelData.Width, pixelData.Height)) { var ms = new MemoryStream(); byte[] pixels = pixelData.Pixels; int index = 0; for (int i = 0; i < pixelData.Height; i++) { for (int j = 0; j < pixelData.Width; j++) { image[i, j] = pixels[index * 4] == byte.MinValue ? Rgba32.ParseHex("#000000"): Rgba32.ParseHex("#FFFFFF"); index += 1; } } image.SaveAsPng(file); } } catch (Exception) { throw; } }
public async Task Direct(string parameter, string optional = "") { DirectUtils.InterpretParameters(parameter); if (optional != "") { DirectUtils.InterpretOptionalParameters(optional); } await Util.File.DownloadLastAttachmentAsync(Context, Path.GetTempPath() + "text-overlay", true); string type = Path.GetExtension(Util.File.ReturnLastAttachmentUrl(Context)); font = new Font(fontCollect.Find("Roboto"), Size); using (var img = await SLImage.LoadAsync(Path.GetTempPath() + "text-overlay" + type)) using (Image <Rgba32> container = new Image <Rgba32>(img.Width * 5, img.Height * 5)) { container.Mutate(mut => mut.DrawImage(img, new Point(img.Width * 2, img.Height * 2), PixelColorBlendingMode.Normal, 1.0F)); if (optional != "") { container.Mutate(mut => mut.DrawText(Text, font, new Rgba32(R / 255, G / 255, B / 255), new PointF(img.Width * 2 + X, img.Height * 2 + Y))); } else { container.Mutate(mut => mut.DrawText(Text, font, Rgba32.ParseHex("000000"), new PointF(img.Width * 2 + X, img.Height * 2 + Y))); } // proper cropping container.Mutate(mut => mut.Crop(new Rectangle(img.Width * 2, img.Height * 2, img.Width, img.Height))); // produces a "bts" result scaled down // container.Mutate(mut => mut.Resize(new ResizeOptions() { Mode = ResizeMode.Crop, Size = new Size(img.Width, img.Height) })); await container.SaveAsync(Path.GetTempPath() + "text-overlay_new" + type); } await Context.Channel.SendFileAsync(Path.GetTempPath() + "text-overlay_new" + type); }
private void DrawingEnText(Image img, string text, string[] colorHexArr, Font[] fonts) { if (string.IsNullOrEmpty(text) == false) { Random random = new Random(); var textWidth = (_imageWidth / text.Length); var img2Size = Math.Min(textWidth, _imageHeight); var fontMiniSize = (int)(img2Size * 0.8); var fontMaxSize = (int)(img2Size * 1); Array fontStyleArr = Enum.GetValues(typeof(FontStyle)); for (int i = 0; i < text.Length; i++) { using (Image <Rgba32> img2 = new Image <Rgba32>(img2Size, img2Size)) { Font scaledFont = new Font(fonts[random.Next(0, fonts.Length)], random.Next(fontMiniSize, fontMaxSize), (FontStyle)fontStyleArr.GetValue(random.Next(fontStyleArr.Length))); var point = new Point(i * textWidth, (_imageHeight - img2.Height) / 2); var colorHex = colorHexArr[random.Next(0, colorHexArr.Length)]; var textGraphicsOptions = new TextGraphicsOptions() { TextOptions = new TextOptions() { HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top } }; img2.Mutate(ctx => ctx .DrawText(textGraphicsOptions, text[i].ToString(), scaledFont, Rgba32.ParseHex(colorHex), new Point(0, 0)) ); DrawingGrid(img2, Rgba32.ParseHex(colorHexArr[new Random().Next(0, colorHexArr.Length)]), 6, 1); img2.Mutate(ctx => ctx.Rotate(random.Next(-30, 30))); img.Mutate(ctx => ctx.DrawImage(img2, point, 1)); } } } }
public IActionResult All([FromQuery] string hexColor = null) { var files = Directory.EnumerateFiles("wwwroot\\images"); var result = files.Select(file => { using var stream = System.IO.File.OpenRead(file); var colors = ColorExtractor.GetCached(stream, Path.GetFileName(file)); return(colors); }); if (!string.IsNullOrWhiteSpace(hexColor)) { var color = Rgba32.ParseHex(hexColor); var(hue, saturation, value) = ColorExtractor.ColorToHsv(color); const double hueRange = 255 * .15d; const double saturationRange = .15d; const double valueRange = .15d; result = result.Where(image => { foreach (var imageColor in image.Colors) { var hsv = imageColor.Hsv; imageColor.MatchedColor = hsv.H - hueRange <hue && hsv.H + hueRange> hue && hsv.S - saturationRange <saturation && hsv.S + saturationRange> saturation && hsv.V - valueRange <value && hsv.V + valueRange> value; } return(image.Colors.Any(x => x.MatchedColor)); }); } return(Ok(result)); }
static void Main(string[] rawArgs) { #region Argument parsing (string[] switches, string[] files) = rawArgs.ParseArgs(); if (files.Length == 0) goto Help; if (switches.Length == 0) goto Help; // Variables string input = files[0]; // Input file string output = Path.GetFileNameWithoutExtension(files[0]) +" modified"; // Output file List<Task<Rgba32[]>> conversionTasks = null; Image<Rgba32> image = null; // The input file Image<Rgba32> borderImage = null; // The secondary image Image<Rgba32> borderCanvas = null; // The border canvas Image<Rgba32> gifCanvas = null; // used for stitching together gifs Random RNG = new Random(); int borderWidth = 50; int innerBorderWidth = 15; int rgbOffset = RNG.Next(0, 90); int frameCount = 24; int animationSpeed = 1; float blurStrength = 5f; float backgroundDim = 1f; Rgba32? borderColor = null; bool discardPixels = false; bool animated = false; bool reversedAnimation = false; #endregion #region Jump logic // Sometimes if-statements and gotos do it better if (switches.Contains("n")) goto Brighten; else if (switches.Contains("f")) goto Funkyfy; else if (switches.Contains("b")) goto Border; else if (switches.Contains("c")) goto CircularBorder; else goto Help; #endregion #region Help Help: Console.WriteLine("Help menu"); Console.WriteLine(new string('-', Console.WindowWidth)); Console.WriteLine("Usage"); Console.WriteLine("executable [FILE] [SWITCH] [PARAMETERS]"); Console.WriteLine("Switches"); Console.WriteLine("-n\tBrightness normalization"); Console.WriteLine("-f\tApply some effects to get a cool-looking image"); Console.WriteLine("-b\tAdd a cool border around the image"); Console.WriteLine("-c\tAdd a cool circular border around the image"); Console.WriteLine(); Console.WriteLine("Parameters"); Console.WriteLine("\t-p:w=\tWidth in pixels (example -p:w=5 [must be positive])"); Console.WriteLine("\t-p:r=\tInner width (example -p:w=5)"); Console.WriteLine("\t-p:c=\tColor in hex (example -p:c=12345678 [the last two digits are optional])"); Console.WriteLine("\t-p:i=\tBorder image (example -p:i=image.png)"); Console.WriteLine("\t-p:a=\tBlur amount (example -p:a=1,2)"); Console.WriteLine("\t-p:b=\tBackground dim [for images with transparency] (example -p:a=0,5 [from 0 to 1])"); Console.WriteLine("\t-p:d\tDiscard excess pixels [only effective for circular borders]"); Console.WriteLine("\t-p:an\tAnimate border [only effective for circular borders]"); Console.WriteLine("\t-p:f=\tTotal frame count [only effective for animated borders] (example -p:f=24)"); Console.WriteLine("\t-p:s=\tAnimation speed [only effective for animated borders] (example -p:s=1)"); Console.WriteLine("\t-p:in\tInvert animation direction [only effective for animated borders]"); Console.WriteLine(new string('-', Console.WindowWidth)); Console.WriteLine("Image manipulator - GermanBread#9077"); return; #endregion #region Brightness normalisation Brighten: Console.WriteLine("==> Normalising brightness"); try { image = Image.Load<Rgba32>(input); } catch { Console.WriteLine("Failed loading the image!"); return; } // Figure out the highest brightness value int highestPixelValue = 0; Console.WriteLine("==> Analyzing image"); Console.WriteLine("Analysing \"{0}\".", input); for (int row = 0; row < image.Height; row++) { for (int column = 0; column < image.Width; column++) { // We want to figure out the highest value if (image[column, row].R > highestPixelValue) highestPixelValue = image[column, row].R; if (image[column, row].G > highestPixelValue) highestPixelValue = image[column, row].G; if (image[column, row].B > highestPixelValue) highestPixelValue = image[column, row].B; } } Console.WriteLine("Highest pixel value was \"{0}\".", highestPixelValue); Console.WriteLine("Pixel color values need to be increased by ~{0}%.", Math.Round(100f / (highestPixelValue / 255f))); Console.WriteLine("==> Normalising image"); Console.WriteLine("Converting \"{0}\".", input); for (int row = 0; row < image.Height; row++) { for (int column = 0; column < image.Width; column++) { // Get the pixel we're processing Rgba32 _pixel = image[column, row]; // Calculate the factor float _factor = 1 / (highestPixelValue / 255f); // Adjust the Pixel _pixel.R = (byte)Math.Round(_pixel.R * _factor); _pixel.G = (byte)Math.Round(_pixel.G * _factor); _pixel.B = (byte)Math.Round(_pixel.B * _factor); // Now overwrite the original pixel with the new one image[column, row] = _pixel; } } // Save output to disk Console.WriteLine("==> Saving modified image"); image.SaveAsPng(output + ".png"); Console.WriteLine("\"{0}\" got saved to \"{1}\"", input, output + ".png"); goto Cleanup; #endregion #region Funkyfying Funkyfy: Console.WriteLine("==> Funkyfying image"); try { image = Image.Load<Rgba32>(input); } catch { Console.WriteLine("Failed loading the image!"); return; } conversionTasks = new List<Task<Rgba32[]>>(); Console.WriteLine("Spawning tasks.", input); for (int row = 0; row < image.Height; row++) { conversionTasks.Add(Funkyfy(row)); } Console.WriteLine("Converting {0}.", input); Task.WaitAll(conversionTasks.ToArray()); Console.WriteLine("Merging results.", input); for (int row = 0; row < conversionTasks.Count; row++) { Rgba32[] conversionResult = conversionTasks[row].Result; for (int column = 0; column < conversionResult.Length; column++) { image[column, row] = conversionResult[column]; } } // Save output to disk Console.WriteLine("==> Saving modified image"); image.SaveAsPng(output + ".png"); Console.WriteLine("\"{0}\" got saved to \"{1}\"", input, output + ".png"); goto Cleanup; async Task<Rgba32[]> Funkyfy(int row) { // Create an array for the output Rgba32[] output = new Rgba32[image.Width]; // Modify the pixels for (int column = 0; column < image.Width; column++) { // Get the pixel we're processing Rgba32 _pixel = image[column, row]; // Do more fancy stuff here _pixel.R = (byte)Math.Pow(_pixel.R, 2); _pixel.G = (byte)Math.Pow(_pixel.G, 2); _pixel.B = (byte)Math.Pow(_pixel.B, 2); // Now overwrite the original pixel with the new one output[column] = _pixel; } // Return the result await Task.Delay(0); return output; } #endregion #region Border Border: Console.WriteLine("==> Adding border to image"); try { image = Image.Load<Rgba32>(input); } catch { Console.WriteLine("Failed loading the image!"); return; } conversionTasks = new List<Task<Rgba32[]>>(); // Parse the color foreach (var arg in switches.Where(x => x.StartsWith("p:")).ToArray()) { try { if (arg.StartsWith("p:w=")) borderWidth = int.Parse(new string(arg.Skip(4).ToArray())); } catch { Console.WriteLine("Failed to parse width parameter!"); } try { if (arg.StartsWith("p:r=")) innerBorderWidth = int.Parse(new string(arg.Skip(4).ToArray())); } catch { Console.WriteLine("Failed to parse inner width parameter!"); } try { if (arg.StartsWith("p:c=")) borderColor = Rgba32.ParseHex(new string(arg.Skip(4).ToArray())); } catch { Console.WriteLine("Failed to parse color parameter!"); } try { if (arg.StartsWith("p:i=")) borderImage = Image.Load<Rgba32>(new string(arg.Skip(4).ToArray())); } catch { Console.WriteLine("Failed to load image!"); } try { if (arg.StartsWith("p:a=")) blurStrength = float.Parse(new string(arg.Skip(4).ToArray())); } catch { Console.WriteLine("Failed parse blur amount!"); } try { if (arg.StartsWith("p:b=")) backgroundDim = Math.Clamp(float.Parse(new string(arg.Skip(4).ToArray())), 0, 1); } catch { Console.WriteLine("Failed to parse background-dim parameter!"); } } borderCanvas = new Image<Rgba32>(image.Width + borderWidth * 2, image.Height + borderWidth * 2, new Rgba32(255, 0, 255, 255)); // If a border image was specified, modify that image if (borderImage != null) { // Stretch the image to fit the screen Console.WriteLine("Resizing border image."); borderImage.Mutate(img => img.Resize(new Size(borderCanvas.Width, borderCanvas.Height))); // Apply a blur effect if (blurStrength > 0) borderImage.Mutate(img => img.GaussianBlur(blurStrength)); } Console.WriteLine("Spawning tasks."); for (int row = 0; row < borderCanvas.Height; row++) { conversionTasks.Add(AddBorder(row)); } Console.WriteLine("Converting \"{0}\".", input); Task.WaitAll(conversionTasks.ToArray()); Console.WriteLine("Merging results."); for (int row = 0; row < conversionTasks.Count; row++) { Rgba32[] conversionResult = conversionTasks[row].Result; for (int column = 0; column < conversionResult.Length; column++) { borderCanvas[column, row] = conversionResult[column]; } } // Save output to disk Console.WriteLine("==> Saving modified image"); borderCanvas.SaveAsPng(output + ".png"); Console.WriteLine("\"{0}\" got saved to \"{1}\"", input, output + ".png"); goto Cleanup; async Task<Rgba32[]> AddBorder(int row) { // Create an array for the output Rgba32[] output = new Rgba32[borderCanvas.Width]; // Modify the pixels for (int column = 0; column < borderCanvas.Width; column++) { // Get the pixel we're processing Rgba32 pixel = borderCanvas[column, row]; // Image border if (borderImage != null) { if ((column >= borderWidth - innerBorderWidth && column <= image.Width + borderWidth + innerBorderWidth) && (row >= borderWidth - innerBorderWidth && row <= image.Height + borderWidth + innerBorderWidth) && innerBorderWidth > 0) { // This gets displayed on the border of the main image pixel = borderImage[column, row]; } else { Rgba32 _imagePixel = borderImage[column, row]; byte _red = (byte)((_imagePixel.R / 255f) * 200f); byte _green = (byte)((_imagePixel.G / 255f) * 200f); byte _blue = (byte)((_imagePixel.B / 255f) * 200f); // This is the color-rotating border, but a bit darker pixel = new Rgba32(_red, _green, _blue, _imagePixel.A); } } // Color border else if (borderColor != null) { if ((column >= borderWidth - innerBorderWidth && column <= image.Width + borderWidth + innerBorderWidth) && (row >= borderWidth - innerBorderWidth && row <= image.Height + borderWidth + innerBorderWidth) && innerBorderWidth > 0) { // This gets displayed on the border of the main image pixel = borderColor.Value; } else { byte _red = (byte)((borderColor.Value.R / 255f) * 200f); byte _green = (byte)((borderColor.Value.G / 255f) * 200f); byte _blue = (byte)((borderColor.Value.B / 255f) * 200f); // This is a bit darker pixel = new Rgba32(_red, _green, _blue, 255); } } // If no border color was provided else { if ((column >= borderWidth - innerBorderWidth && column <= image.Width + borderWidth + innerBorderWidth) && (row >= borderWidth - innerBorderWidth && row <= image.Height + borderWidth + innerBorderWidth)) { byte _red = (byte)Math.Abs(Math.Sin(rgbOffset + (float)column / borderCanvas.Width * 3) * 255); byte _green = (byte)Math.Abs(Math.Sin(rgbOffset + (float)column / borderCanvas.Width * 3 - 45) * 255); byte _blue = (byte)Math.Abs(Math.Sin(rgbOffset + (float)column / borderCanvas.Width * 3 - 90) * 255); // This gets displayed on the border of the main image pixel = new Rgba32(_red, _green, _blue, 255); } else { byte _red = (byte)Math.Abs(Math.Sin(rgbOffset + (float)column / borderCanvas.Width * 3) * 100); byte _green = (byte)Math.Abs(Math.Sin(rgbOffset + (float)column / borderCanvas.Width * 3 - 45) * 100); byte _blue = (byte)Math.Abs(Math.Sin(rgbOffset + (float)column / borderCanvas.Width * 3 - 90) * 100); // This is the color-rotating border, but a bit darker pixel = new Rgba32(_red, _green, _blue, 255); } } // Copy the pixel from the original image if ((column > borderWidth && column < image.Width + borderWidth) && (row > borderWidth && row < image.Height + borderWidth)) { // Get the pixel of the image Rgba32 imagePixel = image[column - borderWidth, row - borderWidth]; // Get the pixel of the border image Rgba32 borderImagePixel; if (borderImage != null) borderImagePixel = borderImage[column, row]; else // Fallback if the border image was not specified borderImagePixel = pixel; // Do some blending magic pixel = new Rgba32( (imagePixel.R / 255f) * (imagePixel.A / 255f) + (borderImagePixel.R / 255f) * (1 - imagePixel.A / 255f) * backgroundDim, (imagePixel.G / 255f) * (imagePixel.A / 255f) + (borderImagePixel.G / 255f) * (1 - imagePixel.A / 255f) * backgroundDim, (imagePixel.B / 255f) * (imagePixel.A / 255f) + (borderImagePixel.B / 255f) * (1 - imagePixel.A / 255f) * backgroundDim, 1 ); } // Now overwrite result to the array output[column] = pixel; } // Return the result await Task.Delay(0); return output; } #endregion #region CircularBorder CircularBorder: Console.WriteLine("==> Adding border to image"); conversionTasks = new List<Task<Rgba32[]>>(); // Parse the color foreach (var arg in switches.Where(x => x.StartsWith("p:")).ToArray()) { try { if (arg.StartsWith("p:w=")) borderWidth = int.Parse(new string(arg.Skip(4).ToArray())); } catch { Console.WriteLine("Failed to parse width parameter!"); } try { if (arg.StartsWith("p:r=")) innerBorderWidth = int.Parse(new string(arg.Skip(4).ToArray())); } catch { Console.WriteLine("Failed to parse inner width parameter!"); } try { if (arg.StartsWith("p:c=")) borderColor = Rgba32.ParseHex(new string(arg.Skip(4).ToArray())); } catch { Console.WriteLine("Failed to parse color parameter!"); } try { if (arg.StartsWith("p:i=")) borderImage = Image.Load<Rgba32>(new string(arg.Skip(4).ToArray())); } catch { Console.WriteLine("Failed to load image!"); } try { if (arg.StartsWith("p:a=")) blurStrength = float.Parse(new string(arg.Skip(4).ToArray())); } catch { Console.WriteLine("Failed parse blur amount!"); } try { if (arg.StartsWith("p:b=")) backgroundDim = Math.Clamp(float.Parse(new string(arg.Skip(4).ToArray())), 0, 1); } catch { Console.WriteLine("Failed to parse background-dim parameter!"); } if (arg.StartsWith("p:d")) discardPixels = true; if (arg.StartsWith("p:an")) animated = true; try { if (arg.StartsWith("p:f=")) frameCount = int.Parse(new string(arg.Skip(4).ToArray())); } catch { Console.WriteLine("Failed to parse frame-count parameter!"); } try { if (arg.StartsWith("p:s=")) animationSpeed = int.Parse(new string(arg.Skip(4).ToArray())); } catch { Console.WriteLine("Failed to parse animation speed parameter!"); } if (arg.StartsWith("p:in")) reversedAnimation = true; } try { image = Image.Load<Rgba32>(input); if (animated) image.Mutate(x => x.Resize(new Size(1024))); } catch { Console.WriteLine("Failed loading the image!"); return; } borderCanvas = new Image<Rgba32>(image.Width + borderWidth * 2, image.Height + borderWidth * 2, new Rgba32(255, 0, 255, 255)); // If a border image was specified, modify that image if (borderImage != null) { // Stretch the image to fit the screen Console.WriteLine("Resizing border image."); borderImage.Mutate(img => img.Resize(new Size(borderCanvas.Width, borderCanvas.Height))); // Apply a blur effect if (blurStrength > 0) borderImage.Mutate(img => img.GaussianBlur(blurStrength)); } // If the border is not animated, fall through async Task SpawnTasks() { if (animated) goto Animated; Console.WriteLine("Spawning tasks."); for (int row = 0; row < borderCanvas.Height; row++) { Task<Rgba32[]> tsk = AddCircularBorder(row); conversionTasks.Add(tsk); } // Skip the animation part await Task.Delay(0); return; Animated: for (float i = 0; i < frameCount; i++) { Console.WriteLine("Spawning tasks for frame {0}.", i + 1); for (int row = 0; row < borderCanvas.Height; row++) { float rot = (MathF.Abs(i / frameCount - (reversedAnimation ? 1 : 0)) * 180f) / (180f / MathF.PI); Task<Rgba32[]> tsk = AddCircularBorderFrame(row, rot); conversionTasks.Add(tsk); } } await Task.Delay(0); return; } SpawnTasks().Wait(); Console.WriteLine("Waiting for conversion tasks to finish"); Task.WaitAll(conversionTasks.ToArray()); Console.WriteLine("Merging results."); if (animated) goto AnimatedMerge; for (int row = 0; row < conversionTasks.Count; row++) { Rgba32[] conversionResult = conversionTasks[row].Result; for (int column = 0; column < conversionResult.Length; column++) { borderCanvas[column, row] = conversionResult[column]; } } goto SavePng; AnimatedMerge: // Before we do anything, resize the canvas gifCanvas = new Image<Rgba32>(borderCanvas.Width, borderCanvas.Height); for (int frame = 0; frame < frameCount; frame++) { Console.WriteLine("Merging frame {0} out of {1}.", frame + 1, frameCount); Image<Rgba32> gifFrame = new Image<Rgba32>(borderCanvas.Width, borderCanvas.Height); for (int row = 0; row < conversionTasks.Count / frameCount; row++) { Rgba32[] conversionResult = conversionTasks[row + frame * (conversionTasks.Count / frameCount)].Result; for (int column = 0; column < conversionResult.Length; column++) { gifFrame[column, row] = conversionResult[column]; } } gifFrame.Mutate(x => x.Resize(new Size(gifCanvas.Width, gifCanvas.Height))); gifCanvas.Frames.AddFrame(gifFrame.Frames[0]); gifFrame.Dispose(); } // Remove the first, invisible frame gifCanvas.Frames.RemoveFrame(0); // Save output to disk Console.WriteLine("==> Saving animated image"); gifCanvas.Metadata.GetGifMetadata().RepeatCount = 0; gifCanvas.SaveAsGif(output + ".gif"); Console.WriteLine("\"{0}\" got saved to \"{1}\"", input, output + ".gif"); goto Cleanup; SavePng: // Save output to disk Console.WriteLine("==> Saving modified image"); borderCanvas.SaveAsPng(output + ".png"); Console.WriteLine("\"{0}\" got saved to \"{1}\"", input, output + ".png"); goto Cleanup; async Task<Rgba32[]> AddCircularBorder(int row) { // Create an array for the output Rgba32[] output = new Rgba32[borderCanvas.Width]; float maxDistanceToCenter = borderCanvas.Width / 2; // Modify the pixels for (int column = 0; column < borderCanvas.Width; column++) { float distanceToCenter = Vector2.Distance(new Vector2(column, row), new Vector2(borderCanvas.Width / 2f, borderCanvas.Height / 2f)); Vector2 directionVector = Vector2.Normalize(Vector2.Subtract(new Vector2(column, row), new Vector2(borderCanvas.Width / 2f, borderCanvas.Height / 2f))); float angleFromTop = MathF.Atan2(directionVector.Y, directionVector.X); // Get the pixel we're processing Rgba32 pixel = borderCanvas[column, row]; // If the pixel is too far away, we kcan skip this code and just set the pixel in question transparent if (distanceToCenter > maxDistanceToCenter && discardPixels) { pixel = new Rgba32(0, 0, 0, 0); // We don't want to waste processing time, do we? goto SkipBorders; } // Image border if (borderImage != null) { if (distanceToCenter + (borderWidth - innerBorderWidth) < maxDistanceToCenter && innerBorderWidth > 0) { // This gets displayed on the border of the main image pixel = borderImage[column, row]; } else { Rgba32 _imagePixel = borderImage[column, row]; byte _red = (byte)((_imagePixel.R / 255f) * 200f); byte _green = (byte)((_imagePixel.G / 255f) * 200f); byte _blue = (byte)((_imagePixel.B / 255f) * 200f); pixel = new Rgba32(_red, _green, _blue, _imagePixel.A); } } // Color border else if (borderColor != null) { if (distanceToCenter + (borderWidth - innerBorderWidth) < maxDistanceToCenter && innerBorderWidth > 0) { // This gets displayed on the border of the main image pixel = borderColor.Value; } else { byte _red = (byte)((borderColor.Value.R / 255f) * 200f); byte _green = (byte)((borderColor.Value.G / 255f) * 200f); byte _blue = (byte)((borderColor.Value.B / 255f) * 200f); // This is a bit darker pixel = new Rgba32(_red, _green, _blue, 255); } } // If no border color was provided else { if (distanceToCenter + (borderWidth - innerBorderWidth) < maxDistanceToCenter && innerBorderWidth > 0) { byte _red = (byte)Math.Abs(Math.Sin(rgbOffset + angleFromTop / 2) * 255); byte _green = (byte)Math.Abs(Math.Sin(rgbOffset + angleFromTop / 2 - 45) * 255); byte _blue = (byte)Math.Abs(Math.Sin(rgbOffset + angleFromTop / 2 - 90) * 255); // This gets displayed on the border of the main image pixel = new Rgba32(_red, _green, _blue, 255); } else { byte _red = (byte)Math.Abs(Math.Sin(rgbOffset + angleFromTop / 2) * 100); byte _green = (byte)Math.Abs(Math.Sin(rgbOffset + angleFromTop / 2 - 45) * 100); byte _blue = (byte)Math.Abs(Math.Sin(rgbOffset + angleFromTop / 2 - 90) * 100); // This is the color-rotating border, but a bit darker pixel = new Rgba32(_red, _green, _blue, 255); } } // To avoid some spaghetti SkipBorders: // Copy the pixel from the original image if (distanceToCenter < image.Width / 2) { // Get the pixel of the image Rgba32 imagePixel = image[column - borderWidth, row - borderWidth]; // Get the pixel of the border image Rgba32 borderImagePixel; if (borderImage != null) borderImagePixel = borderImage[column, row]; else // Fallback if the border image was not specified borderImagePixel = pixel; // Do some blending magic pixel = new Rgba32( (imagePixel.R / 255f) * (imagePixel.A / 255f) + (borderImagePixel.R / 255f) * (1 - imagePixel.A / 255f) * backgroundDim, (imagePixel.G / 255f) * (imagePixel.A / 255f) + (borderImagePixel.G / 255f) * (1 - imagePixel.A / 255f) * backgroundDim, (imagePixel.B / 255f) * (imagePixel.A / 255f) + (borderImagePixel.B / 255f) * (1 - imagePixel.A / 255f) * backgroundDim, 1 ); } // Now overwrite result to the array output[column] = pixel; } // Return the result await Task.Delay(0); return output; } async Task<Rgba32[]> AddCircularBorderFrame(int row, float frame) { // Create an array for the output Rgba32[] output = new Rgba32[borderCanvas.Width]; float maxDistanceToCenter = borderCanvas.Width / 2; // Modify the pixels for (int column = 0; column < borderCanvas.Width; column++) { float distanceToCenter = Vector2.Distance(new Vector2(column, row), new Vector2(borderCanvas.Width / 2f, borderCanvas.Height / 2f)); Vector2 directionVector = Vector2.Normalize(Vector2.Subtract(new Vector2(column, row), new Vector2(borderCanvas.Width / 2f, borderCanvas.Height / 2f))); float angleFromTop = MathF.Atan2(directionVector.Y, directionVector.X); // Get the pixel we're processing Rgba32 pixel = borderCanvas[column, row]; // If the pixel is too far away, we kcan skip this code and just set the pixel in question transparent if (distanceToCenter > maxDistanceToCenter && discardPixels) { pixel = new Rgba32(0, 0, 0, 0); // We don't want to waste processing time, do we? goto SkipBorders; } // Image border if (borderImage != null) { if (distanceToCenter + (borderWidth - innerBorderWidth) < maxDistanceToCenter && innerBorderWidth > 0) { // This gets displayed on the border of the main image pixel = borderImage[column, row]; } else { Rgba32 _imagePixel = borderImage[column, row]; byte _red = (byte)((_imagePixel.R / 255f) * 200f); byte _green = (byte)((_imagePixel.G / 255f) * 200f); byte _blue = (byte)((_imagePixel.B / 255f) * 200f); pixel = new Rgba32(_red, _green, _blue, _imagePixel.A); } } // Color border else if (borderColor != null) { if (distanceToCenter + (borderWidth - innerBorderWidth) < maxDistanceToCenter && innerBorderWidth > 0) { // This gets displayed on the border of the main image pixel = borderColor.Value; } else { byte _red = (byte)((borderColor.Value.R / 255f) * 200f); byte _green = (byte)((borderColor.Value.G / 255f) * 200f); byte _blue = (byte)((borderColor.Value.B / 255f) * 200f); // This is a bit darker pixel = new Rgba32(_red, _green, _blue, 255); } } // If no border color was provided else { if (distanceToCenter + (borderWidth - innerBorderWidth) < maxDistanceToCenter && innerBorderWidth > 0) { byte _red = (byte)Math.Abs(Math.Sin(frame + rgbOffset + angleFromTop / 2) * 255); byte _green = (byte)Math.Abs(Math.Sin(frame + rgbOffset + angleFromTop / 2 - 45) * 255); byte _blue = (byte)Math.Abs(Math.Sin(frame + rgbOffset + angleFromTop / 2 - 90) * 255); // This gets displayed on the border of the main image pixel = new Rgba32(_red, _green, _blue, 255); } else { byte _red = (byte)Math.Abs(Math.Sin(frame + rgbOffset + angleFromTop / 2) * 100); byte _green = (byte)Math.Abs(Math.Sin(frame + rgbOffset + angleFromTop / 2 - 45) * 100); byte _blue = (byte)Math.Abs(Math.Sin(frame + rgbOffset + angleFromTop / 2 - 90) * 100); // This is the color-rotating border, but a bit darker pixel = new Rgba32(_red, _green, _blue, 255); } } // To avoid some spaghetti SkipBorders: // Copy the pixel from the original image if (distanceToCenter < image.Width / 2) { // Get the pixel of the image Rgba32 imagePixel; try { imagePixel = image[column - borderWidth, row - borderWidth]; } catch { imagePixel = pixel; } // Get the pixel of the border image Rgba32 borderImagePixel; if (borderImage != null) borderImagePixel = borderImage[column, row]; else // Fallback if the border image was not specified borderImagePixel = pixel; // Do some blending magic pixel = new Rgba32( (imagePixel.R / 255f) * (imagePixel.A / 255f) + (borderImagePixel.R / 255f) * (1 - imagePixel.A / 255f) * backgroundDim, (imagePixel.G / 255f) * (imagePixel.A / 255f) + (borderImagePixel.G / 255f) * (1 - imagePixel.A / 255f) * backgroundDim, (imagePixel.B / 255f) * (imagePixel.A / 255f) + (borderImagePixel.B / 255f) * (1 - imagePixel.A / 255f) * backgroundDim, 1 ); } // Now overwrite result to the array output[column] = pixel; } // Return the result await Task.Delay(0); return output; } #endregion #region Memory cleanup code Cleanup: // Dispose the image we've processed, we won't need it anymore, this value cannot be null image.Dispose(); // Check if these two values are not null, then dispose them if (borderImage != null) borderImage.Dispose(); // Value is not null when a image parameter has been provided if (borderCanvas != null) borderCanvas.Dispose(); // Value is not null when a border has been added to the image if (gifCanvas != null) gifCanvas.Dispose(); // Value is not null when a gif has been generated // We want to free up the memory used by each Task (thousands get created and they take memory) if (conversionTasks == null) return; foreach (Task completedTask in conversionTasks) { completedTask.Dispose(); } return; #endregion }
public void Draw() { if (ImageWrapper != null) { // Get size of the image var width = (int)ImageWrapper.ActualWidth; var height = (int)ImageWrapper.ActualHeight; using (image = new Image <Rgba32>(width, height)) { // Draw triangle image.Mutate((ctx) => { offset = new PointF(width / 2, height / 2); // Define pens and inks var pinkPen = Pens.Solid(Rgba32.ParseHex("#C0C0FF"), 2); var greenPen = Pens.Solid(Rgba32.ParseHex("#228B22"), 1); var blackPen = Pens.Solid(Rgba32.ParseHex("#000000"), 1); var blackTransPen = Pens.Solid(Rgba32.ParseHex("#00005050"), 1); var pinkBrush = Brushes.Solid(Rgba32.ParseHex("#C71585")); var points = new List <PointF>(); try { // Get parameter a float a = float.Parse(ParamA.Text); // Quality and scale float quality = (float)ParamB.Value; scale = (float)ScaleSlider.Value; if (AxisCheckbox.IsChecked == true) { DrawAxis(ctx, width, height); } for (float i = -MathF.PI; i < MathF.PI; i += quality) { // x = a(t^2 - 1) / (t^2 + 1), y = at(t^2 - 1) / (t^2 + 1), t- infinite, а > 0 // t = i var t = i; // Find coords var x = (a * (MathF.Pow(t, 2) - 1)) / (MathF.Pow(t, 2) + 1); var y = a * t * (MathF.Pow(t, 2) - 1) / (MathF.Pow(t, 2) + 1); // Convert to screen space x = XToScreen(x); y = YToScreen(y); // Draw on the screen PointF point = new PointF(x, y); // Eliminate out of bounds exception if ( !float.IsInfinity(y) && MathF.Abs(y) < height && !float.IsInfinity(x) && MathF.Abs(x) < width ) { points.Add(point); } } ctx.DrawLines(pinkPen, points.ToArray()); } catch (Exception err) { } }); // Set the source ImageControl.Source = Helpers.ImageToBitmap(image); } } }
public void DrawAxis(IImageProcessingContext ctx, float width, float height) { var font = SystemFonts.CreateFont("Arial", 20, SixLabors.Fonts.FontStyle.Regular); var blackPen = Pens.Solid(Rgba32.ParseHex("#000000"), 1); var blackTransPen = Pens.Solid(Rgba32.ParseHex("#00005050"), 1); // Scale the cell size up until it's sane var cellSize = 1; while (cellSize * scale < 50) { cellSize++; } // Draw other thing for (int i = 1; i < width; i++) { var x = ScreenToX(i); // Draws every thing if (x % cellSize == 0) { ctx.DrawLines(blackTransPen, new PointF[] { new PointF(i, 0), new PointF(i, height) }); ctx.DrawText(x.ToString(), font, new Rgba32(22, 33, 45, 66), new PointF(i, YToScreen(0))); } } // Draw other thing for (int i = 1; i < height; i++) { var y = ScreenToY(i); if (y % cellSize == 0) { ctx.DrawLines(blackTransPen, new PointF[] { new PointF(0, i), new PointF(width, i) }); // skip drawing 0 twice if (y != 0) { ctx.DrawText(y.ToString(), font, new Rgba32(22, 33, 45, 66), new PointF(XToScreen(0), i)); } } } // Draw x line for (int i = 1; i < width; i++) { var x = ScreenToX(i); if (x == 0) { ctx.DrawLines(blackPen, new PointF[] { new PointF(i, 0), new PointF(i, height) }); } } // Draw other thing for (int i = 1; i < height; i++) { var y = ScreenToY(i); if (y == 0) { ctx.DrawLines(blackPen, new PointF[] { new PointF(0, i), new PointF(width, i) }); } } }