Пример #1
0
        protected static Bitmap GetBitmap(ImageClipStream ics, int width = 0)
        {
            TryReset(ics.Stream);
            using var ms = new MemoryStream();
            ics.Stream.CopyTo(ms);
            TryReset(ms);
            using var bitmapSource = SKBitmap.Decode(ms);
            using var bitmapDest   = new SKBitmap(bitmapSource.Width, bitmapSource.Height, SKColorType.Bgra8888, SKAlphaType.Unpremul);

            using var canvas = new SKCanvas(bitmapDest);

            var rect = ics.Circle ?
                       new SKRect(0, 0, bitmapSource.Width, bitmapSource.Height) :
                       new SKRect(ics.Left, ics.Top, ics.Right, ics.Bottom);
            var roundRect = ics.Circle ?
                            new SKRoundRect(rect, bitmapSource.Width / 2f, bitmapSource.Height / 2f) :
                            new SKRoundRect(rect, ics.Radius_X, ics.Radius_Y);

            canvas.ClipRoundRect(roundRect, antialias: true);

            canvas.DrawBitmap(bitmapSource, 0, 0);

            var stream = bitmapDest.Encode(SKEncodedImageFormat.Png, 100).AsStream();

            TryReset(stream);

            //var tempFilePath = Path.Combine(IOPath.CacheDirectory, Path.GetFileName(Path.GetTempFileName() + ".png"));
            //using (var fs = File.Create(tempFilePath))
            //{
            //    stream.CopyTo(fs);
            //    TryReset(stream);
            //}

            return(GetDecodeBitmap(stream, width));
        }
Пример #2
0
        void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
        {
            SKImageInfo info    = args.Info;
            SKSurface   surface = args.Surface;
            SKCanvas    canvas  = surface.Canvas;

            canvas.Clear();

            float dxShadow = SizeStroker / 2;


            if (ShowOut)
            {
                makeShadow(info, canvas, TypeShadow.down, dxShadow, dxShadow, Color.Black, BaseColor);
                makeShadow(info, canvas, TypeShadow.top, -dxShadow, -dxShadow, Color.White, BaseColor);
            }

            if (ShowInner)
            {
                var mask = makeBox(info, canvas, TypeShadow.top, -dxShadow, -dxShadow, Color.White, BaseColor);
                canvas.ClipRoundRect(mask, SKClipOperation.Intersect);

                makeInnerShadow(info, canvas, TypeShadow.down, -dxShadow, -dxShadow, Color.White, BaseColor);
                makeInnerShadow(info, canvas, TypeShadow.top, dxShadow, dxShadow, Color.Black, BaseColor);
            }
        }
Пример #3
0
        private void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
        {
            SKImageInfo info    = args.Info;
            SKSurface   surface = args.Surface;
            SKCanvas    canvas  = surface.Canvas;

            canvas.Clear();

            float size = 600;
            float posX = (info.Width - size) / 2;
            float posY = (info.Height - size) / 2;

            using (SKPath path = new SKPath())
            {
                var fillRect  = SKRect.Create(info.Width, info.Height);
                var codeRect  = SKRect.Create(posX, posY, size, size);
                var roundRect = new SKRoundRect(codeRect, 20);
                canvas.ClipRoundRect(roundRect, SKClipOperation.Difference, true);

                SKColor maskColor;
                SKColor.TryParse("003AB6", out maskColor);

                using (SKPaint paint = new SKPaint())
                {
                    paint.Style = SKPaintStyle.Fill;
                    paint.Color = maskColor;
                    canvas.DrawRect(fillRect, paint);
                }
            }
        }
Пример #4
0
        public static SKBitmap ClipRoundRect(this SKBitmap bitmap, int cornerRadius)
        {
            var rect     = new SKRoundRect(new SKRect(0, 0, bitmap.Width, bitmap.Height), cornerRadius);
            var skCanvas = new SKCanvas(bitmap);

            skCanvas.ClipRoundRect(rect);
            skCanvas.Flush();
            skCanvas.Save();
            return(bitmap);
        }
Пример #5
0
 /// <summary>
 /// Clips the current drawing session.
 /// </summary>
 /// <param name="bounds">The bounds.</param>
 /// <param name="cornerRadius">The corner radius.</param>
 public void ClipRect(Rect bounds, CornerRadius cornerRadius)
 {
     if (cornerRadius.TopLeft > 0)
     {
         _canvas.ClipRoundRect(new SKRoundRect(bounds.ToSKRect(), cornerRadius.TopLeft.ToFloat(), cornerRadius.TopLeft.ToFloat()), SKClipOperation.Intersect, false);
     }
     else
     {
         _canvas.ClipRect(bounds.ToSKRect(), SKClipOperation.Intersect, false);
     }
 }
 public void DrawHole(SKCanvas canvas, SKRect rect, float scale = 1)
 {
     if (Roundness <= 0)
     {
         canvas.ClipRect(new SKRect(rect.Left, rect.Top, rect.Right, rect.Bottom), SKClipOperation.Difference);
     }
     else
     {
         canvas.ClipRoundRect(
             new SKRoundRect(new SKRect(rect.Left, rect.Top, rect.Right, rect.Bottom), Roundness, Roundness),
             SKClipOperation.Difference);
     }
 }
Пример #7
0
        private void PaintChessPattern(SKCanvas canvas, SliderLocation slider, SKSize canvasSize)
        {
            var    pickerRadiusPixels = GetPickerRadiusPixels();
            var    sliderTop          = slider.GetSliderOffset(pickerRadiusPixels);
            var    scale = pickerRadiusPixels / 3;
            SKPath path  = new SKPath();

            path.MoveTo(-1 * scale, -1 * scale);
            path.LineTo(0 * scale, -1 * scale);
            path.LineTo(0 * scale, 0 * scale);
            path.LineTo(1 * scale, 0 * scale);
            path.LineTo(1 * scale, 1 * scale);
            path.LineTo(0 * scale, 1 * scale);
            path.LineTo(0 * scale, 0 * scale);
            path.LineTo(-1 * scale, 0 * scale);
            path.LineTo(-1 * scale, -1 * scale);

            SKMatrix matrix = SKMatrix.MakeScale(2 * scale, 2 * scale);
            SKPaint  paint  = new SKPaint
            {
                PathEffect  = SKPathEffect.Create2DPath(matrix, path),
                Color       = Color.LightGray.ToSKColor(),
                IsAntialias = true
            };

            SKRect      patternRect;
            SKRect      clipRect;
            SKRoundRect clipRoundRect;

            if (Vertical)
            {
                patternRect = new SKRect(sliderTop - pickerRadiusPixels, pickerRadiusPixels
                                         , sliderTop + pickerRadiusPixels, canvasSize.Height - pickerRadiusPixels);
                clipRect = new SKRect(sliderTop - (pickerRadiusPixels * 0.65f), pickerRadiusPixels * 1.35f
                                      , sliderTop + (pickerRadiusPixels * 0.65f), canvasSize.Height - (pickerRadiusPixels * 1.35f));
                clipRoundRect = new SKRoundRect(clipRect, pickerRadiusPixels * 0.65f, pickerRadiusPixels * 0.65f);
            }
            else
            {
                patternRect = new SKRect(pickerRadiusPixels, sliderTop - pickerRadiusPixels
                                         , canvasSize.Width - pickerRadiusPixels, sliderTop + pickerRadiusPixels);
                clipRect = new SKRect(pickerRadiusPixels * 1.35f, sliderTop - (pickerRadiusPixels * 0.65f)
                                      , canvasSize.Width - (pickerRadiusPixels * 1.35f), sliderTop + (pickerRadiusPixels * 0.65f));
                clipRoundRect = new SKRoundRect(clipRect, pickerRadiusPixels * 0.65f, pickerRadiusPixels * 0.65f);
            }

            canvas.Save();
            canvas.ClipRoundRect(clipRoundRect);
            canvas.DrawRect(patternRect, paint);
            canvas.Restore();
        }
Пример #8
0
        protected override void DrawInternal(SKCanvas canvas)
        {
            const float radius = 10;

            canvas.DrawRoundRect(BoundsLocal, radius, radius, Paint);

            if (Background != null)
            {
                using (new SKAutoCanvasRestore(canvas))
                {
                    canvas.ClipRoundRect(new SKRoundRect(BoundsLocal, radius), antialias: true);
                    DrawBackgroundInternal(canvas);
                }
            }

            Content.Draw(canvas);
        }
Пример #9
0
        private SKBitmap DrawBitmapIcon(byte[] imageData, bool isSvg,
                                        SKSizeI pictureSize, SKSizeI backgroundSize,
                                        SKColor?imageMaskColor = null, SKColor?backgroundColor = null,
                                        float?cornerRadius     = null)
        {
            var bitmap = GetSKBitmap(imageData, isSvg, pictureSize);

            if (imageMaskColor != null)
            {
                bitmap = bitmap.ApplyMask(imageMaskColor.Value);
            }
            var result = new SKBitmap(
                backgroundSize.Width,
                backgroundSize.Height);
            var skCanvas = new SKCanvas(result);
            var xRadius  = cornerRadius == null ?
                           0 :
                           backgroundSize.Width / 2.0f * cornerRadius.Value;
            var yRadius = cornerRadius == null ?
                          0 :
                          backgroundSize.Height / 2.0f * cornerRadius.Value;
            var rect = new SKRoundRect(
                new SKRect(0, 0, backgroundSize.Width, backgroundSize.Height),
                xRadius, yRadius);

            skCanvas.ClipRoundRect(rect, SKClipOperation.Intersect, true);
            skCanvas.Clear(backgroundColor ?? SKColors.Transparent);
            skCanvas.DrawBitmap(bitmap,
                                (backgroundSize.Width - pictureSize.Width) / 2.0f,
                                (backgroundSize.Height - pictureSize.Height) / 2.0f);
            skCanvas.Flush();
            skCanvas.Save();
            var skData = SKImage.FromBitmap(result).Encode(
                SKEncodedImageFormat.Png, 100);
            var data = skData.ToArray();

            return(SKBitmap.Decode(data));
        }
Пример #10
0
        /// <inheritdoc />
        public void DrawRectangle(IBrush brush, IPen pen, RoundedRect rect, BoxShadows boxShadows = default)
        {
            if (rect.Rect.Height <= 0 || rect.Rect.Width <= 0)
            {
                return;
            }
            // Arbitrary chosen values
            // On OSX Skia breaks OpenGL context when asked to draw, e. g. (0, 0, 623, 6666600) rect
            if (rect.Rect.Height > 8192 || rect.Rect.Width > 8192)
            {
                boxShadows = default;
            }

            var rc            = rect.Rect.ToSKRect();
            var isRounded     = rect.IsRounded;
            var needRoundRect = rect.IsRounded || (boxShadows.HasInsetShadows);

            using var skRoundRect = needRoundRect ? new SKRoundRect() : null;
            if (needRoundRect)
            {
                skRoundRect.SetRectRadii(rc,
                                         new[]
                {
                    rect.RadiiTopLeft.ToSKPoint(), rect.RadiiTopRight.ToSKPoint(),
                    rect.RadiiBottomRight.ToSKPoint(), rect.RadiiBottomLeft.ToSKPoint(),
                });
            }

            foreach (var boxShadow in boxShadows)
            {
                if (!boxShadow.IsEmpty && !boxShadow.IsInset)
                {
                    using (var shadow = BoxShadowFilter.Create(_boxShadowPaint, boxShadow, _currentOpacity))
                    {
                        var spread = (float)boxShadow.Spread;
                        if (boxShadow.IsInset)
                        {
                            spread = -spread;
                        }

                        Canvas.Save();
                        if (isRounded)
                        {
                            using var shadowRect = new SKRoundRect(skRoundRect);
                            if (spread != 0)
                            {
                                shadowRect.Inflate(spread, spread);
                            }
                            Canvas.ClipRoundRect(skRoundRect,
                                                 shadow.ClipOperation, true);

                            var oldTransform = Transform;
                            Transform = oldTransform * Matrix.CreateTranslation(boxShadow.OffsetX, boxShadow.OffsetY);
                            Canvas.DrawRoundRect(shadowRect, shadow.Paint);
                            Transform = oldTransform;
                        }
                        else
                        {
                            var shadowRect = rc;
                            if (spread != 0)
                            {
                                shadowRect.Inflate(spread, spread);
                            }
                            Canvas.ClipRect(rc, shadow.ClipOperation);
                            var oldTransform = Transform;
                            Transform = oldTransform * Matrix.CreateTranslation(boxShadow.OffsetX, boxShadow.OffsetY);
                            Canvas.DrawRect(shadowRect, shadow.Paint);
                            Transform = oldTransform;
                        }

                        Canvas.Restore();
                    }
                }
            }

            if (brush != null)
            {
                using (var paint = CreatePaint(_fillPaint, brush, rect.Rect.Size))
                {
                    if (isRounded)
                    {
                        Canvas.DrawRoundRect(skRoundRect, paint.Paint);
                    }
                    else
                    {
                        Canvas.DrawRect(rc, paint.Paint);
                    }
                }
            }

            foreach (var boxShadow in boxShadows)
            {
                if (!boxShadow.IsEmpty && boxShadow.IsInset)
                {
                    using (var shadow = BoxShadowFilter.Create(_boxShadowPaint, boxShadow, _currentOpacity))
                    {
                        var spread    = (float)boxShadow.Spread;
                        var offsetX   = (float)boxShadow.OffsetX;
                        var offsetY   = (float)boxShadow.OffsetY;
                        var outerRect = AreaCastingShadowInHole(rc, (float)boxShadow.Blur, spread, offsetX, offsetY);

                        Canvas.Save();
                        using var shadowRect = new SKRoundRect(skRoundRect);
                        if (spread != 0)
                        {
                            shadowRect.Deflate(spread, spread);
                        }
                        Canvas.ClipRoundRect(skRoundRect,
                                             shadow.ClipOperation, true);

                        var oldTransform = Transform;
                        Transform = oldTransform * Matrix.CreateTranslation(boxShadow.OffsetX, boxShadow.OffsetY);
                        using (var outerRRect = new SKRoundRect(outerRect))
                            Canvas.DrawRoundRectDifference(outerRRect, shadowRect, shadow.Paint);
                        Transform = oldTransform;
                        Canvas.Restore();
                    }
                }
            }

            if (pen?.Brush != null)
            {
                using (var paint = CreatePaint(_strokePaint, pen, rect.Rect.Size))
                {
                    if (isRounded)
                    {
                        Canvas.DrawRoundRect(skRoundRect, paint.Paint);
                    }
                    else
                    {
                        Canvas.DrawRect(rc, paint.Paint);
                    }
                }
            }
        }
Пример #11
0
        private void SkiaOverlay_PaintSurface(object sender, SkiaSharp.Views.Forms.SKPaintSurfaceEventArgs e)
        {
            SKImageInfo info    = e.Info;
            SKSurface   surface = e.Surface;
            SKCanvas    canvas  = surface.Canvas;

            canvas.Clear();

            float paddingPx = (float)padding * (float)_density;

            float left   = paddingPx;
            float top    = (float)(anim[AnimationKey.Cell].Current * _density) + paddingPx;
            float right  = info.Width - paddingPx;
            float bottom = top + (float)(cellHeight * _density) - paddingPx;

            // adjust the cutout based on the expand animation
            float expandValue = (float)(anim[AnimationKey.Expand].Current * _density);

            if (expandValue > 0)
            {
                // change the values
                left -= expandValue;
                if (left < 0)
                {
                    left = 0;
                }

                right += expandValue;
                if (right > info.Width)
                {
                    right = info.Width;
                }

                top -= expandValue;
                if (top < 0)
                {
                    top = 0;
                }

                bottom += expandValue;
                if (bottom > info.Height)
                {
                    bottom = info.Height;
                }
            }

            // create a cutout
            var cornerRadius = (paddingPx * 2) - expandValue;

            // store the state of the canvas
            using (new SKAutoCanvasRestore(canvas))
            {
                var cutoutRect = new SKRect(left, top, right, bottom);
                canvas.ClipRoundRect(new SKRoundRect(cutoutRect, cornerRadius, cornerRadius),
                                     SKClipOperation.Difference, true);

                // draw the background
                SKRect backgroundRect = new SKRect(0, 0, info.Width, info.Height);
                canvas.DrawBitmap(mapbackground, backgroundRect, BitmapStretch.AspectFill);
            }

            // draw the flyup - but only when it should be
            float flyupPos     = (float)(anim[AnimationKey.FlyUp].Current * _density);
            float circleRadius = (float)(anim[AnimationKey.Circle].Current * _density);


            if (flyupPos < info.Height)
            {
                SKPoint circleCenter = new SKPoint(info.Width / 2, flyupPos);

                // draw the center circle
                canvas.DrawCircle(circleCenter, circleRadius - (float)(10 * _density), centerCirclePaint);

                // add the aircraft image
                float  aircraftScale = .6f;
                float  aircraftSize  = (circleRadius * 2f) * aircraftScale;
                SKRect aircraftRect  = new SKRect(0, 0, aircraftSize, aircraftSize);
                aircraftRect.Location = new SKPoint((info.Width / 2) - (aircraftSize / 2),
                                                    flyupPos - (aircraftSize / 2));
                canvas.DrawBitmap(aircraftImage, aircraftRect, BitmapStretch.AspectFit);

                // create a circle clip
                SKPath circlePath = new SKPath();
                circlePath.AddCircle(info.Width / 2, flyupPos, circleRadius);
                canvas.ClipPath(circlePath, SKClipOperation.Difference, true);

                SKRect flyupRect = new SKRect(0, flyupPos, info.Width, info.Height);
                canvas.DrawRect(flyupRect, flyupPaint);
            }
        }
Пример #12
0
        private async Task <byte[]> GenerateDiagram(CommandContext ctx, IEnumerable <IGrouping <long, Slavereports> > groupedReports, TimeSpan timespan)
        {
            if (groupedReports.Count() > 5)
            {
                throw new ArgumentOutOfRangeException("Maximum allowed number of users in a diagram is 5");
            }

            const int ImageWidth           = 1024;
            const int ImageHeight          = 800;
            const int DiagramSpacingLeft   = 90;           // Spacing on the left of the Y line
            const int DiagramSpacingBottom = 120;          // Spacing below the X line

            SKBitmap bmp = new SKBitmap(ImageWidth, ImageHeight);

            using SKCanvas canvas = new SKCanvas(bmp);

            // Set black background
            canvas.Clear(new SKColor(47, 49, 54));

            // Create all colors and strokes needed later on
            SKPaint diagramPaint = new SKPaint()
            {
                Color       = new SKColor(200, 200, 230),
                StrokeWidth = 3,
                IsAntialias = true,
            };

            SKPaint diagramPaintThicc = new SKPaint()
            {
                Color       = new SKColor(200, 200, 230),
                StrokeWidth = 6,
                IsAntialias = true
            };

            SKPaint textPaint = new SKPaint()
            {
                Color                = new SKColor(200, 200, 230),
                TextSize             = 18f,
                TextAlign            = SKTextAlign.Center,
                IsAntialias          = true,
                IsEmbeddedBitmapText = true
            };

            SKPaint leftTextPaint = new SKPaint()
            {
                Color                = new SKColor(200, 200, 230),
                TextSize             = 18f,
                TextAlign            = SKTextAlign.Right,
                IsAntialias          = true,
                IsEmbeddedBitmapText = true
            };

            // Draw X and Y lines
            canvas.DrawLine(new SKPoint(DiagramSpacingLeft, 0), new SKPoint(DiagramSpacingLeft, ImageHeight), diagramPaint);
            canvas.DrawLine(new SKPoint(0, ImageHeight - DiagramSpacingBottom), new SKPoint(ImageWidth, ImageHeight - DiagramSpacingBottom), diagramPaint);

            const int rows = 8;

            // max and min time of all reports
            var maxTime = groupedReports.Max(g => g.Max(r => r.TimeSpan));
            var minTime = groupedReports.Min(g => g.Min(r => r.TimeSpan));

            var timeDiff                = TimeSpan.FromTicks(maxTime - minTime);
            var individualTime          = TimeSpan.FromTicks(maxTime / rows);
            var individualRowSpacing    = Convert.ToInt32((ImageHeight - DiagramSpacingBottom * 1.4f) / rows);
            var individualColumnSpacing = Convert.ToInt32((ImageWidth - DiagramSpacingLeft * 1.4f) / (timespan.TotalDays + 1));

            for (int i = 1; i <= rows; i++)
            {
                var y = ImageHeight - DiagramSpacingBottom - individualRowSpacing * i;
                canvas.DrawLine(new SKPoint(DiagramSpacingLeft - 10, y), new SKPoint(DiagramSpacingLeft + 10, y), diagramPaintThicc);
                canvas.DrawText((individualTime * i).ToString("hh\\:mm\\:ss"), new SKPoint(DiagramSpacingLeft - 10, y - 10), leftTextPaint);
            }

            var xLineHeight = ImageHeight - DiagramSpacingBottom;

            for (int i = 1; i <= timespan.TotalDays + 2; i++)
            {
                var x = DiagramSpacingLeft + individualColumnSpacing * i;
                canvas.DrawLine(new SKPoint(x, xLineHeight - 10), new SKPoint(x, xLineHeight + 10), diagramPaintThicc);
                canvas.DrawText((DateTime.Now - timespan + TimeSpan.FromDays(1) + TimeSpan.FromDays(i - 1)).ToString("dd.MM."), new SKPoint(x, xLineHeight + 30), textPaint);
            }

            // Create a color for each user
            SKColor[] userColors = new SKColor[]
            {
                new SKColor(36, 123, 160),
                new SKColor(112, 193, 179),
                new SKColor(178, 219, 191),
                new SKColor(243, 255, 189),
                new SKColor(225, 22, 84)
            };

            for (int i = 0; i < groupedReports.Count(); i++)
            {
                var group       = groupedReports.ElementAt(i);
                var color       = userColors[i];
                var colorBright = new SKColor((byte)(color.Red + 100 > 255 ? 255 : color.Red + 100), (byte)(color.Green + 100 > 255 ? 255 : color.Green + 100), (byte)(color.Blue + 100 > 255 ? 255 : color.Blue + 100));

                var paint = new SKPaint()
                {
                    Color                = color,
                    StrokeWidth          = 3,
                    TextSize             = 18f,
                    TextAlign            = SKTextAlign.Center,
                    IsAntialias          = true,
                    IsEmbeddedBitmapText = true
                };

                var paintBright = new SKPaint()
                {
                    Color                = colorBright,
                    StrokeWidth          = 3,
                    TextSize             = 18f,
                    TextAlign            = SKTextAlign.Center,
                    IsAntialias          = true,
                    IsEmbeddedBitmapText = true
                };

                SKPoint lastCoord = SKPoint.Empty;

                var user = await ctx.Client.GetUserAsync(Convert.ToUInt64(group.Key));

                var spacePerUser = (ImageWidth - DiagramSpacingLeft) / 5;

                // Get the avatar
                HttpClient httpClient      = new HttpClient();
                var        userImgResponse = await httpClient.GetAsync(user.AvatarUrl);

                // Only add the user avatar if it can be downloaded
                if (userImgResponse.IsSuccessStatusCode)
                {
                    DiscordMember member = null;
                    try
                    {
                        member = await ctx.Channel.Guild.GetMemberAsync(user.Id);
                    }
                    catch (Exception)
                    { }

                    var antialiasedPaint = new SKPaint()
                    {
                        IsAntialias = true
                    };

                    textPaint.GetFontMetrics(out SKFontMetrics metrics);
                    var textSpacing = Convert.ToInt32(metrics.XMax + (metrics.XMax / 4));

                    var x         = DiagramSpacingLeft + 5 + spacePerUser * i;
                    var y         = ImageHeight - DiagramSpacingBottom + textSpacing;
                    var fullSpace = DiagramSpacingBottom - textSpacing < spacePerUser ? DiagramSpacingBottom : spacePerUser;
                    var halfSpace = fullSpace / 2;

                    var left = halfSpace / 4 * 1;
                    var top  = halfSpace / 4 * 1;
                    var size = halfSpace / 4 * 3;

                    var baseBmp    = new SKBitmap(spacePerUser, fullSpace - Convert.ToInt32(textSpacing));
                    var baseCanvas = new SKCanvas(baseBmp);
                    baseCanvas.Clear(color);

                    var      userImgBmp    = SKBitmap.Decode(await userImgResponse.Content.ReadAsStreamAsync());
                    var      clippedBmp    = new SKBitmap(userImgBmp.Width, userImgBmp.Height);
                    SKCanvas userImgCanvas = new SKCanvas(clippedBmp);
                    userImgCanvas.ClipRoundRect(new SKRoundRect(new SKRect(0, 0, userImgBmp.Width, userImgBmp.Height), 100, 100));
                    userImgCanvas.DrawBitmap(userImgBmp, 0, 0, antialiasedPaint);
                    userImgCanvas.Flush();

                    baseCanvas.DrawBitmap(clippedBmp, new SKRect(left, top, left + size, top + size), antialiasedPaint);

                    SKPaint namePaint = new SKPaint()
                    {
                        Color                = new SKColor(47, 49, 54),
                        TextAlign            = SKTextAlign.Left,
                        TextSize             = 18,
                        IsAntialias          = true,
                        IsEmbeddedBitmapText = true,
                    };

                    DrawTextArea(baseCanvas, namePaint, left * 2 + size, top * 2, spacePerUser - left * 2 + size, 15, member?.Nickname ?? user.Username);

                    canvas.DrawBitmap(baseBmp, new SKPoint(x, y), antialiasedPaint);
                }

                foreach (var report in group)
                {
                    var minDate             = (DateTime.Now - timespan).Date;
                    var maxDate             = (DateTime.Now + TimeSpan.FromDays(1)).Date;
                    var totalSpace          = individualColumnSpacing * (timespan.TotalDays + 1);
                    var percentPointPerTick = (float)totalSpace / (maxDate - minDate).Ticks;
                    var x     = DiagramSpacingLeft + (percentPointPerTick * (report.TimeOfReport - minDate).Ticks);                 //Subtract the time of the report from the mindate, to get the time relative from the beginning of the graph. multiply by percentagepoint of a tick on the graph. add spacing,
                    var y     = ImageHeight - DiagramSpacingBottom - ((ImageHeight - (DiagramSpacingBottom * 1.4f)) / Convert.ToSingle(maxTime) * report.TimeSpan);
                    var coord = new SKPoint(x, y);
                    canvas.DrawCircle(coord, 8, paint);
                    canvas.DrawText(TimeSpan.FromTicks(report.TimeSpan).ToString(), new SKPoint(coord.X, coord.Y - 10), paintBright);
                    //canvas.DrawText(report.TimeOfReport.ToString(), new SKPoint(coord.X, coord.Y + 15), paintBright);

                    if (lastCoord != SKPoint.Empty)
                    {
                        canvas.DrawLine(lastCoord, coord, paint);
                    }

                    lastCoord = coord;
                }
            }

            using var ms = new MemoryStream();
            using SKManagedWStream skStream = new SKManagedWStream(ms);
            if (SKPixmap.Encode(skStream, bmp, SKEncodedImageFormat.Png, 100))
            {
                return(ms.ToArray());
            }

            return(Array.Empty <byte>());
        }