0

The following method is part of a winform label inherited class. The goal is to make a halo or glow effect on text. So far the effect is actually an outline. Its worth keeping as its not bad but its not there yet.

protected override void OnPaint(PaintEventArgs e)
{
  if (this.Text.Length == 0) return;

  e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
  e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
  Rectangle rc = new Rectangle(ClientRectangle.X + Padding.Left,
                                ClientRectangle.Y + Padding.Top,
                                ClientRectangle.Width - (Padding.Left + Padding.Right),
                                ClientRectangle.Height - (Padding.Top + Padding.Bottom));
  StringFormat fmt = new StringFormat(StringFormat.GenericTypographic)
  {
    Alignment = TextAlign == ContentAlignment.TopLeft || TextAlign == ContentAlignment.MiddleLeft || TextAlign == ContentAlignment.BottomLeft
    ? StringAlignment.Near
    : TextAlign == ContentAlignment.TopCenter || TextAlign == ContentAlignment.MiddleCenter || TextAlign == ContentAlignment.BottomCenter
    ? StringAlignment.Center
    : StringAlignment.Far
  };

  if ((haloSize < 1) | (haloColor == Color.Transparent))
  {
    using (var brush = new SolidBrush(this.ForeColor))
    {
      e.Graphics.DrawString(Text, Font, brush, rc, fmt);
    }
  }
  else
  {
    using (var path = new GraphicsPath())
    using (var halopen = new Pen(new SolidBrush(this.haloColor), haloSize) { LineJoin = LineJoin.Round })
    using (var brush = new SolidBrush(ForeColor))
    {
      if (fmt.Alignment == StringAlignment.Center) rc.X += rc.Width / 2;
      if (fmt.Alignment == StringAlignment.Far) rc.X += rc.Width;
      path.AddString(Text, Font.FontFamily, (int)Font.Style, rc.Height, rc.Location, fmt);
      //path.AddString(Text, Font.FontFamily, (int)Font.Style, rc.Height, rc, fmt);
      e.Graphics.DrawPath(halopen, path);
      e.Graphics.FillPath(brush, path);
    }
  }
}

Two questions.

  1. Why does the line that is commented out using AddString with a Rectangle not work but it does work with a Point?
  2. The halo glow effect can be done with progressively smaller brush size and color change but that feels like inventing a new wheel. Is there an easy way to do this or an open source library with this already?
Neutone
  • 95
  • 1
  • 6
  • 2
    Setting the `StringAlignment`, you don't need to calculate the bounding rectangle: DrawString + StringFormat provide the alignment. `rc` is `this.ClientRectangle`. The Padding value is already included. If the `Text.Lenght + 2 * Pen.Size > rc.Width`, you need to decide what to do: clip the Text or inflate the Label's Size (generating a sort of AutoSize effect). You need to redefine the `Pen` and `SolidBrush`, using a semi-transparent Color. `path.AddString()` is using the wrong `em` size: don't use `rc.Height` as this measure. See [here](https://stackoverflow.com/a/53074638/7444103) about it. – Jimi Apr 05 '20 at 21:56
  • You may also want to take a look at this: [Creating different brush patterns](https://stackoverflow.com/a/49298313/7444103), if you want to add a *special look* to the *glowing* aspect. – Jimi Apr 05 '20 at 23:30

1 Answers1

0
  1. The original addstring was too big for the box. I think it canceled the draw because it was clipping.
  2. Multi-pass works and makes a gradient but it may not be fast enough to add a flicker effect in the glow.

The glow/halo effect provides good contrast for a background image that happens to match the text primary color. This is mostly on target but it does nothing for text that is too long for the label. I might add that later.

    protected override void OnPaint(PaintEventArgs e)
    {
      if (this.Text.Length == 0) return;

      e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
      e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
      e.Graphics.CompositingMode = CompositingMode.SourceOver;
      Rectangle rc = new Rectangle(ClientRectangle.X + Padding.Left,
                                    ClientRectangle.Y + Padding.Top,
                                    ClientRectangle.Width - (Padding.Left + Padding.Right),
                                    ClientRectangle.Height - (Padding.Top + Padding.Bottom));
      StringFormat fmt = new StringFormat(StringFormat.GenericTypographic)
      {
        Alignment = TextAlign == ContentAlignment.TopLeft || TextAlign == ContentAlignment.MiddleLeft || TextAlign == ContentAlignment.BottomLeft
        ? StringAlignment.Near
        : TextAlign == ContentAlignment.TopCenter || TextAlign == ContentAlignment.MiddleCenter || TextAlign == ContentAlignment.BottomCenter
        ? StringAlignment.Center
        : StringAlignment.Far
      };
      float EmSize = rc.Height * 0.70f //Font.SizeInPoints  disreguard fontsize and fit height of label
                     * (Font.FontFamily.GetCellAscent(Font.Style) + Font.FontFamily.GetCellDescent(Font.Style))
                     / Font.FontFamily.GetEmHeight(Font.Style);
      using (var path = new GraphicsPath())
      using (var brush = new SolidBrush(ForeColor))
      {
        path.AddString(Text, Font.FontFamily, (int)Font.Style, EmSize, rc, fmt);
        if ((haloSize > 0) & (haloColor != Color.Transparent))
        {
          using (var halopen = new Pen(new SolidBrush(Color.FromArgb(255 / (int)haloSize, haloColor)), haloSize) { LineJoin = LineJoin.Round })
          {
            for (int i = (int)haloSize; i > 0; --i)
            {
              halopen.Width = i;
              e.Graphics.DrawPath(halopen, path);
            }
          }
        }
        e.Graphics.FillPath(brush, path);
      }
    }
Neutone
  • 95
  • 1
  • 6