-
Notifications
You must be signed in to change notification settings - Fork 538
/
SKElement.cs
129 lines (102 loc) · 3.24 KB
/
SKElement.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using SkiaSharp.Views.Desktop;
namespace SkiaSharp.Views.WPF
{
[DefaultEvent("PaintSurface")]
[DefaultProperty("Name")]
public class SKElement : FrameworkElement
{
private const double BitmapDpi = 96.0;
private readonly bool designMode;
private WriteableBitmap bitmap;
private bool ignorePixelScaling;
public SKElement()
{
designMode = DesignerProperties.GetIsInDesignMode(this);
}
public SKSize CanvasSize { get; private set; }
public bool IgnorePixelScaling
{
get => ignorePixelScaling;
set
{
ignorePixelScaling = value;
InvalidateVisual();
}
}
[Category("Appearance")]
public event EventHandler<SKPaintSurfaceEventArgs> PaintSurface;
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
if (designMode)
return;
if (Visibility != Visibility.Visible || PresentationSource.FromVisual(this) == null)
return;
var size = CreateSize(out var unscaledSize, out var scaleX, out var scaleY);
var userVisibleSize = IgnorePixelScaling ? unscaledSize : size;
CanvasSize = userVisibleSize;
if (size.Width <= 0 || size.Height <= 0)
return;
var info = new SKImageInfo(size.Width, size.Height, SKImageInfo.PlatformColorType, SKAlphaType.Premul);
// reset the bitmap if the size has changed
if (bitmap == null || info.Width != bitmap.PixelWidth || info.Height != bitmap.PixelHeight)
{
bitmap = new WriteableBitmap(info.Width, size.Height, BitmapDpi * scaleX, BitmapDpi * scaleY, PixelFormats.Pbgra32, null);
}
// draw on the bitmap
bitmap.Lock();
using (var surface = SKSurface.Create(info, bitmap.BackBuffer, bitmap.BackBufferStride))
{
if (IgnorePixelScaling)
{
var canvas = surface.Canvas;
canvas.Scale(scaleX, scaleY);
canvas.Save();
}
OnPaintSurface(new SKPaintSurfaceEventArgs(surface, info.WithSize(userVisibleSize), info));
}
// draw the bitmap to the screen
bitmap.AddDirtyRect(new Int32Rect(0, 0, info.Width, size.Height));
bitmap.Unlock();
drawingContext.DrawImage(bitmap, new Rect(0, 0, ActualWidth, ActualHeight));
}
protected virtual void OnPaintSurface(SKPaintSurfaceEventArgs e)
{
// invoke the event
PaintSurface?.Invoke(this, e);
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
InvalidateVisual();
}
private SKSizeI CreateSize(out SKSizeI unscaledSize, out float scaleX, out float scaleY)
{
unscaledSize = SKSizeI.Empty;
scaleX = 1.0f;
scaleY = 1.0f;
var w = ActualWidth;
var h = ActualHeight;
if (!IsPositive(w) || !IsPositive(h))
return SKSizeI.Empty;
unscaledSize = new SKSizeI((int)w, (int)h);
var m = PresentationSource.FromVisual(this).CompositionTarget.TransformToDevice;
scaleX = (float)m.M11;
scaleY = (float)m.M22;
return new SKSizeI((int)(w * scaleX), (int)(h * scaleY));
bool IsPositive(double value)
{
return !double.IsNaN(value) && !double.IsInfinity(value) && value > 0;
}
}
}
}