如何在像素艺术编辑器中优化绘制区域

我有像素艺术创作者程序,我在canvas上有一个矩形(像素?)。 这是很好的解决方案,不是很大的(例如128×128)。 如果我想在canvas上创建1024×1024矩形,这个过程非常长,ram使用量约为1-2 gb,之后程序运行速度非常慢。 如何优化这一点,或创造更好的解决方案?

使用Rectangle来表示每个像素是错误的方法。 作为FrameworkElement ,每个矩形都参与布局和输入命中测试。 这种方法太重,无法扩展。 现在放弃它。

我建议直接绘制到WriteableBitmap并使用自定义表面在用户绘制时呈现位图。

以下是允许简单绘制单一颜色的最低概念certificate。 它需要可从NuGet获得的WriteableBitmapEx库。

 public class PixelEditor : FrameworkElement { private readonly Surface _surface; private readonly Visual _gridLines; public int PixelWidth { get; } = 128; public int PixelHeight { get; } = 128; public int Magnification { get; } = 10; public PixelEditor() { _surface = new Surface(this); _gridLines = CreateGridLines(); Cursor = Cursors.Pen; AddVisualChild(_surface); AddVisualChild(_gridLines); } protected override int VisualChildrenCount => 2; protected override Visual GetVisualChild(int index) { return index == 0 ? _surface : _gridLines; } private void Draw() { var p = Mouse.GetPosition(_surface); var magnification = Magnification; var surfaceWidth = PixelWidth * magnification; var surfaceHeight = PixelHeight * magnification; if (pX < 0 || pX >= surfaceWidth || pY < 0 || pY >= surfaceHeight) return; _surface.SetColor( (int)(pX / magnification), (int)(pY / magnification), Colors.DodgerBlue); _surface.InvalidateVisual(); } protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if (e.LeftButton == MouseButtonState.Pressed && IsMouseCaptured) Draw(); } protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) { base.OnMouseLeftButtonDown(e); CaptureMouse(); Draw(); } protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) { base.OnMouseLeftButtonUp(e); ReleaseMouseCapture(); } protected override Size MeasureOverride(Size availableSize) { var magnification = Magnification; var size = new Size(PixelWidth* magnification, PixelHeight * magnification); _surface.Measure(size); return size; } protected override Size ArrangeOverride(Size finalSize) { _surface.Arrange(new Rect(finalSize)); return finalSize; } private Visual CreateGridLines() { var dv = new DrawingVisual(); var dc = dv.RenderOpen(); var w = PixelWidth; var h = PixelHeight; var m = Magnification; var d = -0.5d; // snap gridlines to device pixels var pen = new Pen(new SolidColorBrush(Color.FromArgb(63, 63, 63, 63)), 1d); pen.Freeze(); for (var x = 1; x < w; x++) dc.DrawLine(pen, new Point(x * m + d, 0), new Point(x * m + d, h * m)); for (var y = 1; y < h; y++) dc.DrawLine(pen, new Point(0, y * m + d), new Point(w * m, y * m + d)); dc.Close(); return dv; } private sealed class Surface : FrameworkElement { private readonly PixelEditor _owner; private readonly WriteableBitmap _bitmap; public Surface(PixelEditor owner) { _owner = owner; _bitmap = BitmapFactory.New(owner.PixelWidth, owner.PixelHeight); _bitmap.Clear(Colors.White); RenderOptions.SetBitmapScalingMode(this, BitmapScalingMode.NearestNeighbor); } protected override void OnRender(DrawingContext dc) { base.OnRender(dc); var magnification = _owner.Magnification; var width = _bitmap.PixelWidth * magnification; var height = _bitmap.PixelHeight * magnification; dc.DrawImage(_bitmap, new Rect(0, 0, width, height)); } internal void SetColor(int x, int y, Color color) { _bitmap.SetPixel(x, y, color); } } } 

只需将其导入您的Xaml,最好是在ScrollViewer

      

显然,这与function齐全的像素艺术编辑器相差甚远,但它function齐全,足以让你走上正轨。 编辑128x128图像与1024x1024之间的内存使用量差异约为30mb。 启动并查看它的运行情况:

Pixel Art Editor的屏幕截图

嘿,这很有趣! 谢谢你的转移。

只是为了改进Mike Strobel解决方案,将网格线捕捉到设备像素。

 var d = -0.5d; // snap gridlines to device pixels using (DrawingContext dc = _dv.RenderOpen()) { GuidelineSet guidelineSet = new GuidelineSet(); guidelineSet.GuidelinesX.Add(0.5); guidelineSet.GuidelinesY.Add(0.5); dc.PushGuidelineSet(guidelineSet); // Draw grid }