Font Anti-Aliasing in PowerShell GUIs


The text on winform projects may seem blocky sometimes, particularly at larger font sizes. It never seems to look as polished as those we see with Microsoft products.

Here’s a standard form using Segio 24pt in white. It’s pretty blocky, especially around letters such as ‘S’ and ‘P’. Click on the image below to see it in normal size to get an idea how this looks.


Text without Anti-Aliasing

In order to make our text smoother and more, anti-aliasing will need to be used.

What’s Anti-Aliasing?

Anti-aliasing is the name given to actions which aim to minimise this type of blockiness. It works by shading the pixels along the borders of an image. In order to achieve this for ourselves, we need to dig into some .NET methods and events.

This post shows how we do just that for our fonts in PowerShell Studio, but can be applied in whatever way you develop your GUI apps.

Create a Project

Create a new forms project, making the form a good size. Now, drag a PictureBox control onto the form, and set the size of it close to the size of the form itself.

Set the properties for the PictureBox as follows :

Dock = ‘Top’
BackColour = 1;3;86

Create Positioning Functions

Because we’re going to be working with graphics, we need to define placement based on a horizontal and vertical basis. Whilst we could use absolute positioning, where we manually specify a fixed location, this style is rendered invalid if we make changes to size of the control or the graphic itself. Its relative positioning is changed.

Instead, if we use calculations for positioning, it gives us the flexibility to change control and graphic sizes after the code has been written without having to modify it later.

Thinking about this, there are several things we need to do :

  • Get the midpoint of the control (our picture box)
  • Get the midpoint of the graphic (our drawn string)
  • Get the position for placement of the graphic on the control

Picture Box Control

In this function, we simply pass in the PictureBox control, and work out its center point by adding the left most point with its width, and then divide by two. This gives us the horizontal (aka x) location. Similarly, we add the control’s top most point with it’s height and divide by two to get its vertical center point. These values are then returned as an object.

function Get-PictureboxMidPoint
        [Parameter(Mandatory = $True)][System.Windows.Forms.PictureBox]$PictureBox
    $objPictureBoxMidPoint = New-Object -TypeName System.Object | Select-Object -Property x, y
    $objPictureBoxMidPoint.x = ([int32] (($PictureBox.Left + $PictureBox.Width) /2))
    $objPictureBoxMidPoint.y = ([int32] (($PictureBox.Top + $PictureBox.Height) /2))

Drawn String

We’re working in a similar manner to the above function, but require to do a bit more calculation. We pass in a graphics object, previously instantiated, the string to be drawn, and the font itself. The MeasureString method of the grahpics control is then invoked, using the other two parameters we’ve just mentioned. Once that is completed, we obtain the horizontal and vertical midpoints.

function Get-TextMidPoint
        [Parameter(Mandatory = $True)][System.Drawing.Graphics]$Graphics,
        [Parameter(Mandatory = $True)][String]$Text,
        [Parameter(Mandatory = $True)][System.Drawing.Font]$Font
    $TextSize = $Graphics.MeasureString($Text, $Font)
    [single]$x = [int32] ($TextSize.Width / 2)
    [single]$y = [int32] ($TextSize.Height/ 2)
    $TextMiddlePoint = New-Object -TypeName System.Object | Select-Object -Property x, y
    $TextMiddlePoint.x = $x
    $TextMiddlePoint.y = $y

Position from Drawn String

Now that we have our two sets of midpoints, we can calculate where the drawn string should be placed. This is done by subtracting the result of the latter function from the former for both x and y positions, and returning the results.

function Get-TextPosition
        [Parameter(Mandatory = $True)][System.Object]$MiddlePoint,
        [Parameter(Mandatory = $True)][System.Object]$TextSize
    [int32]$x = ($MiddlePoint.X - $TextSize.X)
    [int32]$y = ($MiddlePoint.Y - $TextSize.Y)
    $textPosition = New-Object -TypeName System.Object | Select-Object -Property X, y
    $textPosition.x = $x
    $textPosition.y = $y

Create Event Code

Now that we’ve defined out functions, we can setup the event action and code.

The Paint event occurs when a control requires repainting. This can happen as a result of other actions on a form or control, such as scrolling to the bottom of a form at to the top again.
Go to the Paint event of the PictureBox in the properties panel, and double click on it. Insert the following :

#Event Argument: $_ = [System.Windows.Forms.PaintEventArgs]
    $g = $_.Graphics
    $picturebox1.Dock = 'Top'
    $picturebox1.BackColor = '1,36,86'
    $drawString = 'PowerShell Studio'
    $white = [System.Drawing.Color]::White
    $drawfont = New-Object -TypeName System.Drawing.Font -Args ('Segoe UI', 84)
    $drawBrush = New-Object -TypeName System.Drawing.SolidBrush -Args ($white)
    $middlePoint = Get-PictureboxMidPoint -PictureBox $picturebox1
    $middleText = Get-TextMidPoint -Graphics $g -Text $drawString -Font $drawfont
    $textposition = Get-TextPosition -MiddlePoint $middlePoint -TextSize $middleText
    $drawpoint = New-Object -TypeName System.Drawing.PointF -Args ($textposition.x, $textposition.y)
    $g.TextRenderingHint = 'AntiAliasGridFit'
    $g.DrawString($drawString, $drawfont, $drawBrush, $drawpoint)

Code explanation

What happens in this code is the following:

  • We obtain the Graphics properties from the event data and assigning it to a variable $g.
  • We define some of the properties of the picturebox control.
  • A Font type variable is created using Sergoe UI typeface in size 84 as the supplied parameters
  • A SoldBrush object is created. This is the drawing style we use, just like in the Paint application.
  • The functions mentioned previously are then used
  • With the above completed, we define a floating point coordinate object
  • We also set the type of anti-alias rendering to be carried out. Several options are available. See the links at the bottom of this page to get more information on these
  • We now run the DrawString method to create and position the anti aliased rendering of the font.

View the New Results

Now run the project to see a much smoother version.


Text with Anti-Aliasing

I’d recommend taking a look at the System.Drawing namespaces documentation on MSDN to get more information on the methods, properties, and enumerations used in this code, which will explain in more detail about each.

You can find the Project code and exported code (for those not using PSStudio) at my GitHub repository, and also a video of this in action on my YouTube channel.