2
我正在使用c#制作类似photoshop的绘画项目。 我已经使用GDI +绘图。可悲的是,我无法发布所需声望点的屏幕截图。 编辑:好吧,我有足够的代表上传图片。 为绘画应用程序优化绘图c#
当笔刷尺寸增加时,使用鼠标的绘图滞后。 我有被吸引到画布面板
protected override void OnPaint(PaintEventArgs e)
{
if (canvasBuffer != null)
{
using (Graphics g = e.Graphics)
{
g.DrawImage(canvasBuffer, e.ClipRectangle, e.ClipRectangle, GraphicsUnit.Pixel);
}
}
}
一个canvasBuffer这是当任何绘画完成后会发生什么。
- 我存储鼠标拖动事件的点列表。
- 我画了一系列从点a到点b的圆,并以记录点为中心画出一条平滑线
- 这张图是在存储在图层类的笔划列表中的位图上完成的。 此图也是用CompositingMode.SourceCopy完成的,用于实现alpha值图纸
- 我有一个layerBuffer存储图层的最终图像。我通过使用SourceCopy兼容模式使用透明颜色绘制清理绘图,将受该笔划影响的更改绘制到此图层缓冲区,然后使用SourceOver在笔划列表中绘制位图。由于我正在实施的分层系统,我将所有图层缓冲区绘制到一个pictureBuffer。 这张图缓冲区最终通过缩放变换被拖拽到canvasBuffer。
注意:画布缓冲区的受影响区域与图层缓冲区的完成方式相同,即清除受影响的部分并重新绘制图片缓冲区的整个受影响部分。 如果我不清除以前的绘图,使用alpha值绘图不能按预期工作。
请帮助我优化此代码或提出一些新方法来提高性能并减少使用鼠标绘图时的延迟。 此外,将使用线程帮助分离绘图代码和缓冲区的点和绘图的计算?
这是代码。
public void PSF_Painted(PSF_PaintEvent e)
{
Layer SelectedLayer = psf.Layers[0];//Get selected layer here
if ((BrushTool)getActiveTool() != null)
{
//getting the pen attributes from the brush tool
BrushTool brushTool = (BrushTool)getActiveTool();
Pen pen = brushTool.getPen();
Brush brush = pen.Brush;
int brushSize = (int)pen.Width;
//loading points data
List<Point> recordedPoints = null;
Point currentPoint = new Point(0, 0);
Point previousPoint = new Point(0, 0);
if (e.RecordedPoints != null)
{
recordedPoints = e.RecordedPoints;
if (recordedPoints.Count > 1)
{
currentPoint = recordedPoints[recordedPoints.Count - 1];
previousPoint = recordedPoints[recordedPoints.Count - 2];
}
else if (recordedPoints.Count == 1)
{
currentPoint = recordedPoints[0];
previousPoint = currentPoint;
}
}
if (e.PaintEventType == PSF_PaintEvent.StrokeStarted)
{
//Console.WriteLine("StrokeStarted");
SelectedLayer.Strokes.Add(new Bitmap(SelectedLayer.Width, SelectedLayer.Height));
}
else if (e.PaintEventType == PSF_PaintEvent.Painting)
{
//Draw the drawing in the bitmap of the layer's stroke data
using (Graphics g = Graphics.FromImage(SelectedLayer.Strokes[SelectedLayer.Strokes.Count - 1]))
{
List<Point> points = Global.GetPointsOnLine(previousPoint.X, previousPoint.Y, currentPoint.X, currentPoint.Y);
for (int i = 0; i < points.Count; i++)
{
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
if (pen.Width == 1)
{
g.FillRectangle(brush, new Rectangle(points[i].X, points[i].Y, brushSize, brushSize));
}
else
{
g.FillEllipse(brush, new Rectangle(points[i].X, points[i].Y, brushSize, brushSize));
}
int xt, xb, yt, yb;
xt = points[i].X;
xb = points[i].X + brushSize;
yt = points[i].Y;
yb = points[i].Y + brushSize;
if (xt < 0) xt = 0;
if (xb > psf.Width) xb = SelectedLayer.Width;
if (yt < 0) yt = 0;
if (yb > psf.Height) yb = SelectedLayer.Height;
//Refresh changes to the affected part of the canvas buffer
Rectangle affectedRect = new Rectangle(xt, yt, xb - xt, yb - yt);
float zf = psf.ZoomFactor;
Rectangle canvasAffectedRect = new Rectangle((int)(affectedRect.X * zf), (int)(affectedRect.Y * zf), (int)(affectedRect.Size.Width * zf), (int)(affectedRect.Size.Height * zf));
SelectedLayer.invalidateLayerBuffer(affectedRect);
invalidateCanvasBuffer(canvasAffectedRect);
}
}
}
else if (e.PaintEventType == PSF_PaintEvent.StrokeCompleted)
{
//Console.WriteLine("StrokeCompleted");
}
}
this.Invalidate();
}
感谢Daniel编辑! – 2012-04-12 15:43:07
你如何触发你的刷新?你是否在MouseMove处理程序中调用Refresh?如何以及何时打电话给PSF_Painted? – Brannon 2012-04-12 17:25:39
@Brannon:我在mouseclick,mouseUp,mouseDown和mouseMove之后触发了PSF_Painted。 另外,我在每个PSF_Painted被触发之后使作为面板控件的画布无效。 – 2012-04-12 17:50:31