Creating Image Markup Tools Part 3
At the end of the last newsletter, I demonstrated my basic function for inserting text into an image.
Add-TextToImage c:\scripts\db.png -Text "FooFoo" -Size 25 -Color Black -FontStyle Bold -PreviewPath c:\temp\db-preview.png

I also demonstrated a process for thinking about function parameters. When creating a function, you want to make it as effortless as possible for the user to use it. That could even be you! Not only do you want to make it easy for them to pass parameter values, you want to validate those values.
Today I want to go a little further. There are a few things I can add that make it even easier to use the function. I also want to add value for the person who has to maintain or manage the function. It might be you today, but it might be someone else tomorrow. A good rule of thumb is to write code for your future self.
Auto Completion
I love tab completion. The less typing I have to do, the better. Tab completion almost always means the values are pre-validated. Some of my the function's parameter implicitly provide tab completion based on the parameter type.
[Parameter(HelpMessage = 'The vertical alignment of the text block on the image.')]
[alias('VAlign')]
[System.Drawing.StringAlignment]$VerticalAlign = 'Center'
Last time I also demonstrated how to use the ArgumentCompleter()
attribute to provide tab completion for a parameter.
[Parameter(HelpMessage = 'The color of the text.')]
[ArgumentCompleter({ [System.Drawing.Color].GetProperties().Where({ $_.PropertyType.Name -eq 'Color' }).Name})]
[Alias('Color')]
[System.Drawing.Color]$FontColor = 'CornSilk'
> You can also get tab completion using ValidateSet()
, although that doesn't apply to any of my parameters.
Another way to provide tab completion is to register an argument completer. This creates a mocked function to create values that will be used for auto completion. I like this approach because you can configure it it to use wildcards. For example, I when I autocomplete the FontColor
parameter, I want to be able to type -FontColor Bl
and get a list of colors that start with Bl
. I can do that by registering an argument completer.
Here's the basic format. I have this saved as a VSCode snippet so I can easily insert it into my code.
Register-ArgumentCompleter -CommandName CommandName -ParameterName ParamName -ScriptBlock {
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
#PowerShell code to populate $WordToComplete
Code |
ForEach-Object {
# completion text,listItem text,result type,Tooltip
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
}
}
I want to create a completer for the -FontColor
parameter that will not only give me wildcard support, but also display the color using the color! I know that I can use $PSStyle
to convert any RGB value.
PS C:\> $PSStyle.Foreground.FromRGB.OverloadDefinitions
string FromRgb(byte red, byte green, byte blue)
string FromRgb(int rgb)
> There is a FromConsoleColor()
method but that is for the colors we use with Write-Host
If I can identify the color, I can get necessary RGB value.
PS C:\> $c = [system.drawing.color]"Aqua"
PS C:\> $c
R : 0
G : 255
B : 255
A : 255
IsKnownColor : True
IsEmpty : False
IsNamedColor : True
IsSystemColor : False
Name : Aqua
PS C:\> $c.ToArgb()
-16711681
I can use this value as the PSStyle foreground value.
$PSStyle.Foreground.FromRGB(-16711681)
Here's the argument completer I created for the -FontColor
parameter.
Register-ArgumentCompleter -CommandName Add-TextToImage -ParameterName FontColor -ScriptBlock {
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
[System.Drawing.Color].GetProperties() |
Where-Object {$_.Name -ne 'Transparent' -AND ($_.PropertyType.Name -eq 'Color' -and $_.Name -like "$wordToComplete*") } |
ForEach-Object {
#show the color name using the color
[int]$rgb = ([system.drawing.color]$_.Name).toArgb()
$ansi = $PSStyle.Foreground.FromRGB($rgb)
[String]$show = "$ansi$($_.Name)$([char]27)[0m"
# completion text,listItem text,result type,Tooltip
[System.Management.Automation.CompletionResult]::new($_.Name, $show, 'ParameterValue', $_.name)}
}