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 https://jdhitsoluti…
Powered by Buttondown, the easiest way to start and grow your newsletter.