Behind the PowerShell Pipeline logo

Behind the PowerShell Pipeline

Subscribe
Archives
April 1, 2025

Creating Image Markup Tools

In the previous article in this series, I demonstrated how to use PowerShell and the .NET Framework to add a layer of text to an image. I eventually want to have a tool that I can use to customize the cover images in my MuseScore MP3 files. However, the real takeaway is the process I used to create the tool.

When we left off, I had demonstrated enough code to add a layer of text to an image.

Add-Type -AssemblyName System.Drawing
$Text = "Behind the PowerShell Pipeline"
$image = "C:\work\blue-robot-ps.jpg"
$imageObject = [System.Drawing.Image]::FromFile($image)
$rect = [System.Drawing.RectangleF]::new(0, 0, $imageObject.Width, $imageObject.Height)
$graphics = [System.Drawing.Graphics]::FromImage($imageObject)
$size = "36"
$font = "Cascadia Code"
$fontObject = New-Object System.Drawing.Font($font,$size)
$brush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::Black)
$graphics.DrawString($text, $fontObject, $brush, $rect, $format)
$output = "c:\temp\preview.jpg"
$imageObject.Save($output)

I am using Get-SpectreImage from the pwshSpectreConsole module to view the image in the PowerShell console.

Sample image
figure 1

> *I'll admit this isn't necessarily the best image to use. *

Formatting the Text

One step I'm missing is formatting the text. I would like to position the text in the image. I might also want to format the text to be bold or italic. Using the Get-TypeConstructor function from the PSScriptTools module, I can see there is a constructor for the Font class that takes a FontStyle object.

PS C:\> Get-TypeConstructor system.drawing.font

[System.Drawing.Font]::new([System.Drawing.Font]$Prototype),[System.Drawing.FontStyle]$newStyle))

[System.Drawing.Font]::new([System.Drawing.FontFamily]$Family),
                        [System.Single]$emSize),
                        [System.Drawing.FontStyle]$Style),
                        [System.Drawing.GraphicsUnit]$Unit))
                        ...

There is no default constructor for that class.

PS C:\> Get-TypeConstructor system.drawing.fontstyle
WARNING: No constructors found for FontStyle

I'll use Get-TypeMember to explore this class.

PS C:\> Get-TypeMember system.drawing.fontstyle

   Type: System.Drawing.FontStyle

Name      MemberType ResultType               IsStatic IsEnum
----      ---------- ----------               -------- ------
Bold      Field      System.Drawing.FontStyle     True
Italic    Field      System.Drawing.FontStyle     True
Regular   Field      System.Drawing.FontStyle     True
Strikeout Field      System.Drawing.FontStyle     True
Underline Field      System.Drawing.FontStyle     True
GetType   Method     Type
HasFlag   Method     Boolean
ToString  Method     String

When I see fields, that tells me that I can define a value like this:

[System.Drawing.FontStyle]$FontStyle = 'Italic'

This should let me define the font.

PS C:\> $FontObject = New-Object System.Drawing.Font($Font, $Size, $FontStyle)
PS C:\> $FontObject

Size             : 36
Style            : Italic
Bold             : False
Italic           : True
Strikeout        : False
Underline        : False
FontFamily       : [FontFamily: Name=Cascadia Code]
Name             : Cascadia Code
Unit             : Point
GdiCharSet       : 1
GdiVerticalFont  : False
OriginalFontName : Cascadia Code
SystemFontName   :
IsSystemFont     : False
Height           : 56
SizeInPoints     : 36

Next, I have to figure out how to position the text on the image. I am using the DrawString() method of the Graphics class. I'll look at the definitions again.

PS C:\> $graphics.DrawString.OverloadDefinitions
void DrawString(string s, System.Drawing.Font font, System.Drawing.Brush brush, float x, float y)
void DrawString(System.ReadOnlySpan[char] s, System.Drawing.Font font, System.Drawing.Brush brush, float x, float y)
void DrawString(string s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.PointF point)
void DrawString(System.ReadOnlySpan[char] s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.PointF point)
void DrawString(string s, System.Drawing.Font font, System.Drawing.Brush brush, float x, float y, System.Drawing.StringFormat format)
...
Want to read the full issue?
GitHub Bluesky LinkedIn About Jeff
This email brought to you by Buttondown, the easiest way to start and grow your newsletter.