Рисование границы точек вокруг TBitmap?

Я написал процедуру, которая должна добавить пунктирную границу к растровому изображению:

procedure AddDottedBorderToBitmap(aBM: Vcl.Graphics.TBitmap);
var
  c: TCanvas;
begin
  c := aBM.Canvas;
  c.Pen.Color := clBlack;
  c.Pen.Mode  := pmXor;
  c.Pen.Style := psDot;

  c.MoveTo(0, 0);
  c.LineTo(0, aBM.Height - 1);
  c.LineTo(aBM.Width - 1, aBM.Height - 1);
  c.LineTo(aBM.Width - 1, 0);
  c.LineTo(0, 0);
end;

Но при увеличении результата полученная граница вместо точек кажется сделанной из маленьких штрихов:

введите описание изображения здесь

Это правильно? Если нет, как я могу получить реальные точки вместо черточек?

2 ответа

Решение

DrawFocusRect - это вызов Windows API, который создает необходимую вам границу.

procedure AddDottedBorderToBitmap(aBM: Vcl.Graphics.TBitmap);
begin
  DrawFocusRect(aBM.canvas.Handle,Rect(0,0,aBM.Width,aBM.Height));
end;

Это может показаться простым в использовании DrawFocusRect, но если вам нужно нарисовать что-то еще, кроме прямоугольников, вы можете прочитать вперед.

Стиль ручки psDot не означает, что каждый второй пиксель окрашен, а другой очищен. Если подумать, чем выше разрешение, тем сложнее будет увидеть разницу между пунктирной и серой сплошными частями f.ex. Существует еще один стиль пера psAlternate который чередует пиксели. Документы говорят:

psAlternate

Ручка устанавливает каждый второй пиксель. (Этот стиль применим только для косметических перьев.) Этот стиль действителен только для перьев, созданных с помощью функции API ExtCreatePen. (См. Документы MS Windows SDK.) Это относится как к VCL, так и к VCL.NET.

Чтобы определить перо и использовать его, мы делаем следующее

var
  c: TCanvas;
  oldpenh, newpenh: HPEN; // pen handles
  lbrush: TLogBrush;      // logical brush

...

  c := pbx.Canvas; // pbx is a TPintBox, but can be anything with a canvas

  lbrush.lbStyle := BS_SOLID;
  lbrush.lbColor := clBlack;
  lbrush.lbHatch := 0;

  // create the pen
  newpenh := ExtCreatePen(PS_COSMETIC or PS_ALTERNATE, 1, lbrush, 0, nil);
  try
    // select it
    oldpenh := SelectObject(c.Handle, newpenh);

    // use the pen
    c.MoveTo(0, 0);
    c.LineTo(0, pbx.Height - 1);
    c.LineTo(pbx.Width - 1, pbx.Height - 1);
    c.LineTo(pbx.Width - 1, 0);
    c.LineTo(0, 0);

    c.Ellipse(3, 3, pbx.width-3, pbx.Height-3);

    // revert to the old pen
    SelectObject(c.Handle, oldpenh);
 finally
    // delete the pen
    DeleteObject(newpenh);
 end;

И, наконец, как это выглядит (лупа в х 10)

введите описание изображения здесь

Другие вопросы по тегам