私はc#を使ってフォトショップのようなペイントプロジェクトを作っています。描画にはGDI+を使用しました。残念ながら、必要な評判ポイントのスクリーンショットを投稿できません。編集:わかりました、写真をアップロードするのに十分な担当者を取得しました。
ブラシのサイズが大きくなると、マウスを使用した描画が遅れます。キャンバスパネルに描画されるcanvasBufferがあります
protected override void OnPaint(PaintEventArgs e)
{
if (canvasBuffer != null)
{
using (Graphics g = e.Graphics)
{
g.DrawImage(canvasBuffer, e.ClipRectangle, e.ClipRectangle, GraphicsUnit.Pixel);
}
}
}
そして、これは、ペイントが行われたときに起こることです。
- マウスドラッグイベントのポイントのリストを保存します。
- 記録した点を中心に点aから点bまで一連の円を描き、滑らかな線を描きます
- この描画は、レイヤークラスのストロークのリストに格納されているビットマップで行われます。この描画もCompositingMode.SourceCopyを使用して行われ、アルファ値の描画を実装します
- レイヤーの最終画像を保存するlayerBufferがあります。SourceCopy互換モードを使用して透明色の描画でクリアし、SourceOverを使用してストロークのリストにビットマップを描画することにより、ストロークの影響を受ける変更をこのlayerBufferに描画します。
- 私が実装しているレイヤリングシステムのため、すべてのレイヤバッファをpictureBufferに描画します。この画像バッファは、スケーリング変換を使用して最終的にcanvasBufferに描画されます。
注:キャンバスバッファーの影響を受ける領域は、レイヤーバッファーと同じ方法で実行されます。つまり、影響を受ける部分をクリアし、画像バッファーの影響を受ける部分全体を再度描画します。前の描画をクリアしないと、アルファ値での描画が期待どおりに機能しません。
このコードを最適化するのを手伝ってください。または、マウスを使用して描画する際のパフォーマンスを改善し、ラグを減らすための新しい方法を提案してください。また、描画コードとポイントの計算を分離し、スレッドを使用してバッファを描画することは役に立ちますか?
これがコードです。
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();
}