有什么方法可以加快位图画布上的绘图速度吗?

时间:2015-11-01 00:11:18

标签: delphi canvas bitmap delphi-xe7

我的部分应用程序是绘制图形表单草稿,主要是用户输入表单,包含许多编辑框。我绘制位图并保存为PNG,报告过程的所有部分,因此没有任何内容被绘制到应用程序表单。 我绘制所有控件,编辑框,单选按钮,复选框......

绘图的最长部分当然是绘制编辑框,因为它们数量巨大。我有一个典型的过程,在大约70K表格上绘制1M编辑框。

我画了一个非常简单的编辑框:

  1. 基本矩形,笔宽= 1
  2. 添加左侧和顶部的其他行,以获得缩进控制的感觉。
  3. 如果需要,添加文字
  4. 我附上了简单编辑控件的屏幕截图,其中包含Zoomed,因此可以看到额外的左侧和顶部线条。

    enter image description here

    以下是DrawEdit的代码,它绘制了1M Edit框,需要20秒。 无论如何都要加快这个过程吗?

    procedure DrawEdit(myCanvas:TCanvas; vLeft, vTop, vWidth, vHeight: integer; const vText: string; vCenterText:boolean=false);
    begin
    
      // basic rectangle
      pPoint.x := vLeft; pPoint.Y := vTop;
      myCanvas.Pen.Width := 1;
      myCanvas.PenPos := pPoint;
      myCanvas.Pen.Color := $0099A8AC;
      myCanvas.LineTo(vLeft + vWidth, vTop);
      myCanvas.LineTo(vLeft + vWidth, vTop + 1);
      myCanvas.Pen.Color := $00E2EFF1;
      myCanvas.LineTo(vLeft + vWidth, vTop + vHeight - 1);
      myCanvas.LineTo(vLeft, vTop + vHeight - 1);
      myCanvas.Pen.Color := $0099A8AC;
      myCanvas.LineTo(vLeft, vTop);
    
      // again top border
      pPoint.x := vLeft + 1; pPoint.Y := vTop + 1;
      myCanvas.PenPos := ppoint;
      myCanvas.Pen.Color := $00646F71;
      myCanvas.LineTo(vLeft + vWidth, vTop + 1);
    
      // again left border
      ppoint.x := vLeft + 1; ppoint.Y := vTop + 1;
      myCanvas.PenPos := ppoint;
      myCanvas.Pen.Color := $00646F71;
      myCanvas.LineTo(vLeft + 1, vTop + vHeight - 1);
    
      if vText<>'' then
      begin
        // clear area for text - white background
        myCanvas.Font.Color := clblack;
        myCanvas.Brush.Color := clWhite;
        rRect.Left := vLeft + 2;
        rRect.Top := vTop + 2;
        rRect.Right := vLeft + myCanvas.TextWidth(vText);
        rRect.Bottom := vTop + myCanvas.TextHeight(vText);
        myCanvas.FillRect(rRect);
    
        If Not vCenterText Then
          Winapi.Windows.TextOut(myCanvas.Handle, vLeft + 4, vTop + 2, PChar(vText), Length(vText))
        else
          Winapi.Windows.TextOut(myCanvas.Handle, vLeft + (vWidth div 2) - (myCanvas.TextWidth(vText) div 2), vTop + (vHeight div 2) - (myCanvas.TextHeight(vText) div 2), PChar(vText), Length(vText));
      end;
    
    end;
    

    这是我使用的测试。测试不理想,因为真正的编辑框大小不同,但这是我测试不同的optimizatino选项的测试。

    procedure TForm1.Button3Click(Sender: TObject);
    var
      i, t1, t2: integer;
      myBitmap: TBitmap;
    begin
    
      myBitmap := TBitmap.Create;
      try
        myBitmap.SetSize(500, 500);
        myBitmap.PixelFormat := pf24bit;
    
        t1 := GetTickCount;
        for i := 1 to 1000000 do
          DrawEdit(myBitmap.Canvas, 10, 10, 100, 50, 'Edit box', true);
        t2 := GetTickCount;
    
      finally
        myBitmap.Free;
      end;
    
      button3.Caption := inttostr(t2 - t1);
    
    end;
    

2 个答案:

答案 0 :(得分:5)

GDI对于绘制到设备是有效的,但是,对于内存位图工作,它会带来很大的开销。

您最好避开GDI图层并直接对内存光栅图像执行此操作。我建议使用graphics32库。切换到那应该会产生非常显着的性能提升。

您可能要做的另一件事是将工作分成多个任务并利用多线程。您想要绘制到不同的位图,然后在最后拼接在一起。

答案 1 :(得分:2)

我使用Line在Graphics32上绘制TBitmap32,结果比在TBitmap上绘图快3倍.Canvas:

procedure DrawEdit32(BM32: TBitmap32; vLeft, vTop, vWidth, vHeight: integer; const vText: string; vCenterText: boolean = false);
begin

  // basic rectangle
  BM32.Line(vLeft, vTop, vWidth, vTop, $0099A8AC);
  BM32.Line(vWidth, vTop, vWidth, vTop + vHeight, $00E2EFF1);
  BM32.Line(vWidth, vTop + vHeight, vLeft, vTop + vHeight, $00E2EFF1);
  BM32.Line(vLeft, vTop + vHeight, vLeft, vTop, $0099A8AC);

   // again top border
  BM32.Line(vLeft + 1, vTop + 1, vWidth, vTop + 1, $00646F71);

  // again left border
  BM32.Line(vLeft + 1, vTop + 1, vLeft + 1, vTop + vHeight, $00646F71);

  if vText <> '' then
  begin
    // clear area for text - white background
    BM32.Font.Color := clblack;
    rRect.Left := vLeft + 2;
    rRect.Top := vTop + 2;
    rRect.Right := vLeft + BM32.TextWidth(vText);
    rRect.Bottom := vTop + BM32.TextHeight(vText);
    BM32.FillRect(rRect.Left,rRect.Top,rRect.Right,rRect.Bottom,clWhite);

    if not vCenterText then
      Winapi.Windows.TextOut(BM32.Handle, vLeft + 4, vTop + 2, PChar(vText), Length(vText))
    else
      Winapi.Windows.TextOut(BM32.Handle, vLeft + (vWidth div 2) - (BM32.TextWidth(vText) div 2), vTop + (vHeight div 2) - (BM32.TextHeight(vText) div 2), PChar(vText), Length(vText));
  end;
end;