Theme.WindowsTerminal.psm1
using namespace PoshCode.Pansies #Region '.\Private\FindProfile.ps1' 0 function FindProfile { [CmdletBinding()] param( # A collection of profiles to search by GUID $Profiles = @((GetLayeredConfig -FlattenDefaultProfile).profiles.list), # If the only thing we care about is the color scheme, we can take shortcuts [Switch]$ColorSchemeReadOnly, # The profile guid. Default value from Env:WT_PROFILE_ID $ProfileId = $Env:WT_PROFILE_ID ) if (!$ProfileId) { Write-Warning "ENV:WT_PROFILE_ID should always be set when you're in Windows Terminal. Without that, we cannot identify the current profile. Please ensure you're running Windows Terminal 0.11 or higher." } else { if (($P = $Profiles.Where({ $_.guid -eq $ProfileId }))) { $P } else { Write-Error "The ProfileId should be a guid set in ENV:WT_PROFILE_ID" } } } #EndRegion '.\Private\FindProfile.ps1' 24 #Region '.\Private\GetLayeredConfig.ps1' 0 function GetLayeredConfig { [CmdletBinding()] param( # If set, update the profiles with values from profiles.defaults [switch]$FlattenDefaultProfile ) # Hypothetically the file is in the first location, but if you're using a dev copy instead, it might be elsewhere: if (!$script:UserConfigFile -or !$script:DefaultConfig) { $wt = @(Get-Process WindowsTerminal -ErrorAction Ignore) if ($wt.count -eq 1) { $wtExecutable = $wt.Path } else { $ps = Get-Process -Id $Pid while ($ps.ProcessName -ne "WindowsTerminal" -and $ps.Parent) { $ps = $ps.Parent } if ($ps.ProcessName -eq "WindowsTerminal") { $wtExecutable = $ps.Path } } if ($wtExecutable) { $DefaultConfigFile = Get-ChildItem ($wtExecutable | Split-Path) -Filter defaults.json | Convert-Path if (!$DefaultConfigFile) { Write-Warning "Unable to locate Windows Terminal's default.json" } else { $script:DefaultConfig = if ($PSVersionTable.PSVersion.Major -gt 5) { ConvertFrom-Json (Get-Content $DefaultConfigFile -Raw) } else { # WindowsPowerShell's JSON can't handle comments ConvertFrom-Json (((Get-Content $DefaultConfigFile) -replace "^\s*//.*") -join "`n") } } } $ProductKey = switch -regex ($wtExecutable) { "Microsoft\.WindowsTerminalPreview_" { "Microsoft.WindowsTerminalPreview_8wekyb3d8bbwe" } "WindowsTerminalDev" { "WindowsTerminalDev_8wekyb3d8bbwe" } # "Microsoft\.WindowsTerminal_" { "Microsoft.WindowsTerminal_8wekyb3d8bbwe" } default { "Microsoft.WindowsTerminal_8wekyb3d8bbwe" } } $script:UserConfigFile = Get-ChildItem @( "$Env:LocalAppData/packages/$ProductKey/LocalState/settings.json" "$Env:AppData/Microsoft/Windows Terminal/settings.json" ) -ErrorAction Ignore | Select-Object -First 1 } if (!$UserConfigFile) { Write-Warning "Unable to locate Windows Terminal's settings.json" } else { $UserConfig = if ($PSVersionTable.PSVersion.Major -gt 5) { ConvertFrom-Json (Get-Content $UserConfigFile -Raw) } else { # WindowsPowerShell's JSON can't handle comments ConvertFrom-Json (((Get-Content $UserConfigFile) -replace "^\s*//.*") -join "`n") } } # The profiles are different in default, so we normalize that first ... # The only way to normalize it is to add the `default`: if (!(Get-Member Defaults -Input $UserConfig.Profiles)) { $UserConfig.profiles = [PSCustomObject]@{ defaults = [PSCustomObject]@{ } list = $UserConfig.profiles } } if (!(Get-Member Defaults -input $DefaultConfig.Profiles)) { $DefaultConfig.profiles = [PSCustomObject]@{ defaults = [PSCustomObject]@{ } list = $DefaultConfig.profiles } } # Update-Object doesn't handle arrays at all, so we need to deal with those manually for ($u = 0; $u -lt $UserConfig.profiles.list.Count; $u++) { if (($d = $DefaultConfig.profiles.list.guid.IndexOf($UserConfig.profiles.list[$u].guid)) -ge 0) { # Which is fine, because maybe we need to start with the default profile if ($FlattenDefaultProfile -and $UserConfig.profiles.defaults) { $UserConfig.profiles.list[$u] = $DefaultConfig.profiles.list[$d] | Update-Object ($UserConfig.profiles.defaults | Select-Object *) | Update-Object $UserConfig.profiles.list[$u] } else { $UserConfig.profiles.list[$u] = $DefaultConfig.profiles.list[$d] | Update-Object $UserConfig.profiles.list[$u] } } elseif ($FlattenDefaultProfile -and $UserConfig.profiles.defaults) { $UserConfig.profiles.list[$u] = $UserConfig.profiles.defaults | Select-Object * | Update-Object $UserConfig.profiles.list[$u] } } for ($u = 0; $u -lt $UserConfig.schemes.Count; $u++) { if (($d = $DefaultConfig.schemes.name.IndexOf($UserConfig.schemes[$u].name)) -ge 0) { $UserConfig.schemes[$u] = $DefaultConfig.schemes[$d] | Update-Object $UserConfig.schemes[$u] } } # Let's be honest, schemes that are in the default probably aren't in UserConfig, so copy them: $existing = $UserConfig.schemes.name $UserConfig.schemes += @($DefaultConfig.schemes).where{$_.name -notin $existing} # Finally, copy over everything else Update-Object -InputObject ($DefaultConfig | Select-Object *) -UpdateObject $UserConfig } #EndRegion '.\Private\GetLayeredConfig.ps1' 105 #Region '.\Private\GetSimpleConfig.ps1' 0 function GetSimpleConfig { [CmdletBinding()] param() # Hypothetically the file is in the first location, but if you're using a dev copy instead, it might be elsewhere: if (!$script:UserConfigFile) { $script:UserConfigFile = Get-ChildItem @( "$Env:LocalAppData/packages/Microsoft.WindowsTerminal_8wekyb3d8bbwe/LocalState/settings.json" "$Env:LocalAppData/packages/WindowsTerminalDev_8wekyb3d8bbwe/LocalState/settings.json" "$Env:AppData/Microsoft/Windows Terminal/settings.json" "$Env:LocalAppData/packages/Microsoft.WindowsTerminal_8wekyb3d8bbwe/LocalState/profile.json" "$Env:LocalAppData/packages/WindowsTerminalDev_8wekyb3d8bbwe/LocalState/profile.json" "$Env:AppData/Microsoft/Windows Terminal/profile.json" ) -ErrorAction Ignore | Select-Object -First 1 } if (!$UserConfigFile) { Write-Warning "Unable to locate Windows Terminal's settings.json" } else { Write-Verbose $UserConfigFile $UserConfig = ConvertFrom-Json (Get-Content $UserConfigFile -Raw) } # The profiles exist two different ways, so we have to normalize that first ... # The only way to normalize it is to add the `default`: if (!(Get-Member Defaults -Input $UserConfig.Profiles)) { $UserConfig.profiles = [PSCustomObject]@{ defaults = [PSCustomObject]@{ } list = $UserConfig.profiles } } $UserConfig } #EndRegion '.\Private\GetSimpleConfig.ps1' 35 #Region '.\Public\Copy-WindowsTerminalProfile.ps1' 0 function Copy-WindowsTerminalProfile { <# .SYNOPSIS Creates a new WindowsTerminalProfile based on another #> [Alias("cptp")] [CmdletBinding(DefaultParameterSetName="SimpleCopy")] param( # The name of the profile to copy. By default, copies the current profile [Parameter()] [string]$SourceProfileName, # The name of the new profile. If it already exists, it will be overwritten [Parameter(Mandatory, Position = 0)] [string]$NewProfileName, # A command-line to override the one in the source profle [Parameter(Position = 1)] [string]$CommandLine, # If set, creates a new tab immediately from the profile [switch]$CreateTab, # If set, creates a new tab and immediately removes the profile [switch]$AutoDelete, # If set, this text is written to the bottom right corner of the background image [Parameter(Position = 2, ParameterSetName = "WithText")] [string]$TextForBackground, [Parameter(ParameterSetName = "WithText")] [System.Drawing.Size]$ImageSize, # Number of pixels of padding for the text on the left. By default, 20 pixels. [Parameter(ParameterSetName = "WithText")] [int]$LeftPadding = 20, # Number of pixels of padding for the text on the top. By default, 20 pixels. [Parameter(ParameterSetName = "WithText")] [int]$TopPadding = 20, # Number of pixels of padding for the text on the right. By default, 20 pixels. [Parameter(ParameterSetName = "WithText")] [int]$RightPadding = 20, # Number of pixels of padding for the text on the bottom. By default, 20 pixels. [Parameter(ParameterSetName = "WithText")] [int]$BottomPadding = 20, # The font name (defaults to "Cascadia Code") [Parameter(ParameterSetName = "WithText")] [string]$FontName = "Cascadia Code", # The font size (defaults to 28) [Parameter(ParameterSetName = "WithText")] [int]$FontSize = 28, # The font style defaults to bold [Parameter(ParameterSetName = "WithText")] [System.Drawing.FontStyle]$FontStyle = "Bold", # The alignment relative to the background + bounds. # In a left-to-right layout, the far position is bottom, and the near position is top. [Parameter(ParameterSetName = "WithText")] [System.Drawing.StringAlignment]$VerticalAlignment = "Far", # The alignment relative to the background + bounds. # In a left-to-right layout, the far position is right, and the near position is left. # However, in a right-to-left layout, the far position is left. [Parameter(ParameterSetName = "WithText")] [System.Drawing.StringAlignment]$HorizontalAlignment = "Far", # The stroke color defaults to [System.Drawing.Brushes]::Black [Parameter(ParameterSetName = "WithText")] [System.Drawing.Brush]$StrokeBrush = [System.Drawing.Brushes]::Black, # The fill color defaults to [System.Drawing.Brushes]::White [Parameter(ParameterSetName = "WithText")] [System.Drawing.Brush]$FillBrush = [System.Drawing.Brushes]::White ) process { $LayeredConfig = GetLayeredConfig -FlattenDefaultProfile $Config = GetSimpleConfig if ($SourceProfileName) { $SourceProfile = @($LayeredConfig.profiles.list).Where({ $_.Name -eq $SourceProfileName }, "First", 1)[0] | Select-Object * } if (!$SourceProfile) { $SourceProfile = FindProfile $LayeredConfig.profiles.list } if (!($ActualProfile = @($Config.profiles.list).Where({ $_.Name -eq $SourceProfile.Name }, "First", 1)[0] | Select-Object * -ExcludeProperty "source", "hidden")) { $ActualProfile = $SourceProfile | Select-Object * -ExcludeProperty "source", "hidden" } $ActualProfile | Add-Member -NotePropertyName name $NewProfileName -force $ActualProfile | Add-Member -NotePropertyName guid ([guid]::NewGuid().ToString("b")) -force $ActualProfile | Add-Member -NotePropertyName commandline $CommandLine -force if ($TextForBackground) { # Make a copy of the PSBoundParameters that only has parameters from Write-TextOnImage $TextParameters = @{} + $PSBoundParameters $ParameterNames = (Get-Command Write-TextOnImage).Parameters.Keys @($PSBoundParameters.Keys. Where({ $_ -notin $ParameterNames })). ForEach({ $TextParameters.Remove($_) }) try { $TerminalTempState = Join-Path $Env:LocalAppData "packages/Microsoft.WindowsTerminal_8wekyb3d8bbwe/TempState" if ($SourceProfile.backgroundImage) { $TerminalRoamingState = Join-Path $Env:LocalAppData "packages/Microsoft.WindowsTerminal_8wekyb3d8bbwe/RoamingState/" $TerminalLocalState = Join-Path $Env:LocalAppData "packages/Microsoft.WindowsTerminal_8wekyb3d8bbwe/LocalState/" $Path = $SourceProfile.backgroundImage -replace "ms-appdata:///roaming/", $TerminalRoamingState -replace "ms-appdata:///local/", $TerminalLocalState Write-Verbose "Existing Background Image: $Path" $BackgroundFile = Write-TextOnImage -Path $Path -Text $TextForBackground @TextParameters $ActualProfile | Add-Member -NotePropertyName backgroundImage $BackgroundFile.FullName -Force } else { $Path = Join-Path $TerminalTempState (Get-Date -f "yyyyMMddhhmmss.pn\g") $BackgroundFile = Write-TextOnImage -NewPath $Path -ImageSize ([System.Drawing.Size]::new(256,256)) -Text $TextForBackground @TextParameters $ActualProfile | Add-Member -NotePropertyName backgroundImage $BackgroundFile.FullName -Force } } catch { Write-Error "Couldn't update the background image. You may need to use a full file path or ms-appdata:/// path." -ErrorAction Continue } } $Config.profiles.list += $ActualProfile Set-Content $UserConfigFile ($Config | ConvertTo-Json -Depth 10) if ($CreateTab -or $AutoDelete) { $DefaultProfile = $Config.defaultProfile $DefaultKeyBindings = $Config.keybindings $Config.defaultProfile = $ActualProfile.guid # Force the newTab hotkey to something $NewTab = @($LayeredConfig.keybindings).where({ $_.command -eq "newTab" }, "First", 1)[0] $NewTab.keys = @( "ctrl+t" ) $Config.keybindings = @($NewTab) Set-Content $UserConfigFile ($Config | ConvertTo-Json -Depth 10) Start-Sleep 1 # you have to wait for the terminal to _notice_ the config change # Create a new tab and then set the old default back Add-Type -AssemblyName System.Windows.Forms [System.Windows.Forms.SendKeys]::SendWait("^t") $Config.defaultProfile = $DefaultProfile $Config.keybindings = $DefaultKeyBindings if ($AutoDelete) { $Config.profiles.list = @($Config.profiles.list).Where{ $_.guid -ne $ActualProfile.guid } } Set-Content $UserConfigFile ($Config | ConvertTo-Json -Depth 10) } } } #EndRegion '.\Public\Copy-WindowsTerminalProfile.ps1' 157 #Region '.\Public\Get-WindowsTerminalTheme.ps1' 0 #using namespace PoshCode.Pansies function Get-WindowsTerminalTheme { <# .SYNOPSIS Returns an object representing the color scheme from the Windows Terminal settings .DESCRIPTION The expectation is that you call Get-WindowsTerminalTheme, modify the result, then pipe the modified value into Set-WindowsTerminalTheme. By default (without parameters), this function detects the current profile via Env:WT_PROFILE_ID and returns the color scheme associated with that profile. .LINK Set-WindowsTerminalTheme #> [CmdletBinding()] param( # If specified, returns the named color scheme instead of the one associated with the current profile [Parameter(ValueFromPipeline)] [string]$ColorScheme ) process { $Config = GetLayeredConfig -FlattenDefaultProfile if (!$ColorScheme) { $ActiveProfile = FindProfile $Config.profiles.list $ColorScheme = $ActiveProfile.ColorScheme } if ($ColorScheme) { $Result = @($Config.schemes).Where({ $_.name -eq $colorScheme })[0] $Result.PSTypeNames.Insert(0, "Terminal.ColorScheme") $Result.PSTypeNames.Insert(0, "WindowsTerminal.ColorScheme") if ($ActiveProfile) { # Update with overrides from the active profile if ($ActiveProfile.foreground) { # -and -not $Result.foreground Add-Member -InputObject $Result -NotePropertyMembers @{ foreground = $ActiveProfile.foreground } -Force } if ($ActiveProfile.background) { # -and -not $Result.background Add-Member -InputObject $Result -NotePropertyMembers @{ background = $ActiveProfile.background } -Force } if ($ActiveProfile.cursorColor) { # -and -not $Result.cursorColor Add-Member -InputObject $Result -NotePropertyMembers @{ cursorColor = $ActiveProfile.cursorColor } -Force } if (!$Result.cursorColor) { Add-Member -InputObject $Result -NotePropertyMembers @{ cursorColor = $Result.foreground } -Force } } # Since all the properties are colors, we cast them to RgbColor for display purposes foreach ($property in @(Get-Member -Input $Result -Type Properties).Where({$_.Name -ne "name"}).name) { $Result.$property = [RgbColor]$Result.$property } $Result } } } #EndRegion '.\Public\Get-WindowsTerminalTheme.ps1' 58 #Region '.\Public\Set-WindowsTerminalTheme.ps1' 0 #using namespace PoshCode.Pansies function Set-WindowsTerminalTheme { <# .SYNOPSIS Set the theme for Windows Terminal Has parameters for each color, including foreground, background, and cursorColor .DESCRIPTION The expectation is that you call Get-WindowsTerminalTheme and modify the result, then pipe the modified value into Set-WindowsTerminalTheme .LINK Get-WindowsTerminalTheme #> [CmdletBinding()] param( [Parameter(ValueFromPipelineByPropertyName)] [string]$Name = "EzTheme", [Parameter(ValueFromPipelineByPropertyName)] [RgbColor]$background = "#0C0C0C", [Parameter(ValueFromPipelineByPropertyName)] [RgbColor]$foreground = "#CCCCCC", [Parameter(ValueFromPipelineByPropertyName)] [RgbColor]$cursorColor = "#FFFFFF", [Parameter(ValueFromPipelineByPropertyName)] [RgbColor]$selectionBackground = "#FFFFFF", [Parameter(ValueFromPipelineByPropertyName)] [RgbColor]$black = "#0C0C0C", [Parameter(ValueFromPipelineByPropertyName)] [RgbColor]$red = "#C50F1F", [Parameter(ValueFromPipelineByPropertyName)] [RgbColor]$green = "#13A10E", [Parameter(ValueFromPipelineByPropertyName)] [RgbColor]$yellow = "#C19C00", [Parameter(ValueFromPipelineByPropertyName)] [RgbColor]$blue = "#0037DA", [Parameter(ValueFromPipelineByPropertyName)] [RgbColor]$purple = "#881798", [Parameter(ValueFromPipelineByPropertyName)] [RgbColor]$cyan = "#3A96DD", [Parameter(ValueFromPipelineByPropertyName)] [RgbColor]$white = "#CCCCCC", [Parameter(ValueFromPipelineByPropertyName)] [RgbColor]$brightBlack = "#767676", [Parameter(ValueFromPipelineByPropertyName)] [RgbColor]$brightRed = "#E74856", [Parameter(ValueFromPipelineByPropertyName)] [RgbColor]$brightGreen = "#16C60C", [Parameter(ValueFromPipelineByPropertyName)] [RgbColor]$brightYellow = "#F9F1A5", [Parameter(ValueFromPipelineByPropertyName)] [RgbColor]$brightBlue = "#3B78FF", [Parameter(ValueFromPipelineByPropertyName)] [RgbColor]$brightPurple = "#B4009E", [Parameter(ValueFromPipelineByPropertyName)] [RgbColor]$brightCyan = "#61D6D6", [Parameter(ValueFromPipelineByPropertyName)] [RgbColor]$brightWhite = "#F2F2F2" ) begin { $Config = GetLayeredConfig -FlattenDefaultProfile $CurrentProfile = FindProfile $Config.profiles.list } process { $UserConfig = ConvertFrom-Json (Get-Content $UserConfigFile -Raw) $SchemeIndex = $UserConfig.schemes.name.IndexOf($name) # Make sure we're using simple strings that match the json Windows Terminal needs $Scheme = [PSCustomObject]@{ name = "$Name" background = "$background" foreground = "$foreground" selectionBackground = "$selectionBackground" cursorColor = "$cursorColor" black = "$black" red = "$red" green = "$green" yellow = "$yellow" blue = "$blue" purple = "$purple" cyan = "$cyan" white = "$white" brightBlack = "$brightBlack" brightRed = "$brightRed" brightGreen = "$brightGreen" brightYellow = "$brightYellow" brightBlue = "$brightBlue" brightPurple = "$brightPurple" brightCyan = "$brightCyan" brightWhite = "$brightWhite" } if ($SchemeIndex -lt 0) { $UserConfig.schemes += $Scheme } else { $UserConfig.schemes[$SchemeIndex] = $Scheme } if (!($CurrentUserProfile = @($UserConfig.profiles.list).where({ $_.guid -eq $CurrentProfile.guid })[0])) { $CurrentUserProfile = @($UserConfig.profiles).where({ $_.guid -eq $CurrentProfile.guid })[0] } if ($CurrentUserProfile.colorScheme) { $CurrentUserProfile.colorScheme = $Scheme.name } elseif($UserConfig.profiles.defaults) { $UserConfig.profiles.defaults | Add-Member -NotePropertyName colorScheme -NotePropertyValue $Scheme.name -Force } else { $UserConfig.profiles.defaults = [PSCustomObject]@{ colorScheme = $Scheme.name } } Set-Content $UserConfigFile ($UserConfig | ConvertTo-Json -Depth 10) } } #EndRegion '.\Public\Set-WindowsTerminalTheme.ps1' 119 #Region '.\Public\Write-TextOnImage.ps1' 0 function Write-TextOnImage { <# .SYNOPSIS Writes text to an image. .DESCRIPTION Writes one or more lines of text onto a rectangle on an image. By default, it writes the computer name on the bottom right corner, with an outline around so you can read it regardless of the picture. .EXAMPLE Write-OutlineText "$Env:UserName`n$Env:ComputerName`n$Env:UserDnsDomain" -Path "~\Wallpaper.png" #> [CmdletBinding()] param( [Parameter(ParameterSetName = "OnExistingImageFile", Mandatory, ValueFromPipelineByPropertyName)] [ValidateScript({ if (!(Test-Path "$_")) { throw "The path must point to an existing image. Can't find '$_'" } $true })] [Alias("PSPath")] [string]$Path, [Parameter(ParameterSetName = "OnExistingImageFile")] [Parameter(ParameterSetName = "OnNewImageFile", Mandatory)] [Parameter(ParameterSetName = "OnExistingGraphics", ValueFromPipeline, Mandatory)] [string]$NewPath, [Parameter(ParameterSetName = "OnNewImageFile")] [System.Drawing.Size]$ImageSize, [Parameter(ParameterSetName = "OnExistingGraphics", ValueFromPipeline, Mandatory)] [System.Drawing.Graphics]$Graphics, # Number of pixels of padding on the left. By default, 20 pixels. [int]$LeftPadding = 20, # Number of pixels of padding on the top. By default, 20 pixels. [int]$TopPadding = 20, # Number of pixels of padding on the right. By default, 20 pixels. [int]$RightPadding = 20, # Number of pixels of padding on the bottom. By default, 60 pixels. [int]$BottomPadding = 60, [string]$Text = $Env:ComputerName, [string]$FontName = "Cascadia Code", [int]$FontSize = 38, [System.Drawing.FontStyle]$FontStyle = "Bold", # The alignment relative to the bounds. Note that in a left-to-right layout, the far position is bottom, and the near position is top. [System.Drawing.StringAlignment]$VerticalAlignment = "Far", # The alignment relative to the bounds. Note that in a left-to-right layout, the far position is right, and the near position is left. However, in a right-to-left layout, the far position is left. [System.Drawing.StringAlignment]$HorizontalAlignment = "Far", # The stroke color (defaults to [System.Drawing.Brushes]::Black) [System.Drawing.Brush]$StrokeBrush = [System.Drawing.Brushes]::Black, # The fill color (defaults to [System.Drawing.Brushes]::White) [System.Drawing.Brush]$FillBrush = [System.Drawing.Brushes]::White ) process { if ($PSCmdlet.ParameterSetName -eq "OnExistingImageFile") { $Source = [System.Drawing.Image]::FromFile((Convert-Path $Path)) $Graphics = [System.Drawing.Graphics]::FromImage($Source) Write-Verbose "Adding text to existing $($Graphics.VisibleClipBounds.Width) x $($Graphics.VisibleClipBounds.Height) image" } elseif($PSCmdlet.ParameterSetName -eq "OnNewImageFile") { $Source = [System.Drawing.Bitmap]::new($ImageSize.Width, $imageSize.Height) $Graphics = [System.Drawing.Graphics]::FromImage($Source) # $Graphics.Clear($StrokeBrush.Color) Write-Verbose "Adding text to blank $($ImageSize.Width) x $($ImageSize.Height) image" } else { Write-Verbose "Adding text to image from '$Path'" } # Save as png to avoid asking them, and dealing with image format as a parameter if ($Path -and -not $NewPath) { $NewPath = "{0}\{1}{2}" -f [IO.Path]::GetDirectoryName($Path), ([IO.Path]::GetFileNameWithoutExtension($Path) + '-' + ($Text -replace ("[" + [regex]::escape([io.path]::GetInvalidFileNameChars()) +"]"))), [IO.Path]::GetExtension($Path) } elseif ($Path -and -not (Split-Path $NewPath)) { $NewPath = Join-Path ([IO.Path]::GetDirectoryName($Path)) $NewPath Write-Verbose "Adding text to image: '$Path'" } try { $Bounds = [System.Drawing.RectangleF]::new( $Graphics.VisibleClipBounds.Location + [System.Drawing.SizeF]::new($LeftPadding, $TopPadding), $Graphics.VisibleClipBounds.Size - [System.Drawing.SizeF]::new($RightPadding + $LeftPadding, $TopPadding + $BottomPadding)) Write-Verbose "Using Bounds: $($Bounds.Top), $($Bounds.Left), $($Bounds.Bottom, $Bounds.Right)" $Font = try { [System.Drawing.FontFamily]::new($FontName) } catch { [System.Drawing.FontFamily]::GenericMonospace } Write-Verbose "Using FontFamily $Font" $StringFormat = [System.Drawing.StringFormat]::GenericTypographic $StringFormat.Alignment = $HorizontalAlignment $StringFormat.LineAlignment = $VerticalAlignment $GraphicsPath = [System.Drawing.Drawing2D.GraphicsPath]::new() $GraphicsPath.AddString( $Text, $Font, $FontStyle, ($Graphics.DpiY * $FontSize / 72), $Bounds, $StringFormat); Write-Verbose "Adding '$Text' to the image in $($FillBrush.Color) on $($StrokeBrush.Color)" $Graphics.FillPath($FillBrush, $GraphicsPath); $Graphics.DrawPath($StrokeBrush, $GraphicsPath); } catch { Write-Warning "Unhandled Error: $_" Write-Warning "Unhandled Error: $($_.ScriptStackTrace)" throw } finally { if ($PSCmdlet.ParameterSetName -ne "OnExistingGraphics") { $Graphics.Dispose() } try { if ($NewPath -and $Source) { $ImageFormat = switch ([IO.Path]::GetExtension($NewPath)) { ".png" { [System.Drawing.Imaging.ImageFormat]::Png } ".bmp" { [System.Drawing.Imaging.ImageFormat]::Bmp } ".jpg" { [System.Drawing.Imaging.ImageFormat]::Jpeg } } Write-Verbose "Writing a $([IO.Path]::GetExtension($NewPath)) to $NewPath" $Source.Save($NewPath, $ImageFormat) } Get-Item $NewPath } finally { if ($PSCmdlet.ParameterSetName -ne "OnExistingGraphics") { $Source.Dispose() } } } } } #EndRegion '.\Public\Write-TextOnImage.ps1' 145 #Region '.\postfix.ps1' 0 if (Get-Module EzTheme -ErrorAction SilentlyContinue) { Get-ModuleTheme | Set-WindowsTerminalTheme } #EndRegion '.\postfix.ps1' 4 |