Best way to write thousands of strokes in WPF canvas

牧云@^-^@ 提交于 2020-01-24 21:14:08

问题


I have to implement writing by touch on Wacom tablet ( like on paper) and I need to render up to 200 strokes per second in WPF Canvas. The problem is that after about 20s of constant writing it gets a bit laggs and the laggs grows. I store all strokes in HashSet. I thought about taking screen shoot when HashSet contains over 600 elements and set it as a background image and clear the HashSet, but after ~30 screen shoots it gets a bit blurred. Do you have any idea how to make it better?


回答1:


You can use WriteableBitmap. This is very fast, but it works by writing individual bytes to bitmap, so if you need to apply effects to the drawing, then you have to write them yourself. This is an example of how you can use WriteableBitmap. It takes ~100 ms in debug mode to draw 1000 lines (each made out of 1600 points) on 1600 x 1200 px image on my computer, but I'm sure this can be optimized.

I'm just randomly drawing lines, but you can get events from Canvas and capture positions of stylus and pass them after each stroke.

public partial class MainWindow : Window
{
    private WriteableBitmap _bitmap;
    private readonly Random _random = new Random();
    private readonly Stopwatch _stopwatch = new Stopwatch();
    private const int White = 0x00000000;
    private const int Red = 0x00FF0000;

    private int _width;
    private int _height;

    public MainWindow()
    {
        InitializeComponent();
        CanvasImage.Loaded += OnLoaded;
    }

    private async void OnLoaded(object sender, RoutedEventArgs e)
    {
        _width = (int)DrawableCanvas.ActualWidth;
        _height = (int)DrawableCanvas.ActualHeight;
        _bitmap = new WriteableBitmap(_width, _height, 96, 96, PixelFormats.Bgr32, null);
        CanvasImage.Source = _bitmap;

        while (true)
        {
            unsafe
            {
                for (var index = 0; index < _width * _height; index++)
                    *((int*)_bitmap.BackBuffer + index) = White;
            }

            _stopwatch.Start();

            for (var index = 0; index < 1000; index++)
            {
                var start = _random.Next(0, _width);
                var points = Enumerable.Range(0, _width).Select(x => new Point((x + start) % _width, x % _height));
                UpdateImage(points);
            }

            Debug.WriteLine($"Last 1000 draws took: {_stopwatch.ElapsedMilliseconds} ms");
            _stopwatch.Reset();

            await Task.Delay(300);
        }
    }

    private void UpdateImage(IEnumerable<Point> points)
    {
        _bitmap.Lock();

        foreach (var point in points)
        {
            var x = (int)point.X;
            var y = (int)point.Y;
            var offset = _width * y + x;
            unsafe
            {
                *((int*)_bitmap.BackBuffer + offset) = Red;
            }
        }

        _bitmap.AddDirtyRect(new Int32Rect(0, 0, _width, _height));
        _bitmap.Unlock();
    }
}

And view:

<Grid>
    <Border Width="1604" Height="1204" BorderThickness="2" BorderBrush="Blue">
        <Canvas x:Name="DrawableCanvas">
            <Image x:Name="CanvasImage"></Image>
        </Canvas>
    </Border>
</Grid>


来源:https://stackoverflow.com/questions/50948912/best-way-to-write-thousands-of-strokes-in-wpf-canvas

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!