2012-04-12 9 views
2

私はPhotoshopのような塗料プロジェクトをC#で作成しています。 私は図面にGDI +を使用しました。残念ながら、私は必要な評判ポイントのスクリーンショットを掲載することはできません。 編集:私は写真をアップロードするのに十分な担当者を持っています。 enter image description here塗装アプリケーション用に図面を最適化する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を持っており、これはどんな絵が行われたときに何が起こるかです。

  1. 私はマウスドラッグイベントのポイントのリストを保存します。
  2. 記録された点を中心として点aから点bまでの一連の円を描きます。
  3. この描画は、レイヤークラスのストロークのリストに格納されたビットマップで行われます。 この描画は、アルファ値の描画を実装するCompositingMode.SourceCopyでも行われます。
  4. レイヤの最終イメージを格納するlayerBufferがあります。ストロークの影響を受けた変更をこのレイヤーバッファーに描画するには、SourceCopy互換モードを使用して透過カラーの描画をクリアし、SourceOverを使用してストロークのリストにビットマップを描画します。
  5. 私が実装するレイヤーシステムのため、すべてのレイヤバッファを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(); 
    } 
+0

編集のためのダニエルに感謝します! –

+0

リフレッシュをどのように誘発していますか? MouseMoveハンドラでRefreshを呼び出していますか?いつ、どのようにPSF_Paintedを呼びますか? – Brannon

+0

@Brannon:マウスクリック、mouseUp、mouseDown、mouseMoveでPSF_Paintedを起動します。 また、PSF_Paintedが起動するたびにパネルコントロールであるキャンバスを無効にします。 –

答えて

0

私はこの最適化のための解決策を見つけました。 ブラシの大きさの1/5を超えたポイントだけを記録しました。 私は非常に完璧なラインは必要ないと気付きました。したがって、パフォーマンスのための回線の品質の妥協点を交換することができます。