terminal/res/terminal/Generate-TerminalAssets.ps1
Dustin L. Howett 5a1c931f77
Update WT's icon at runtime to match high-contrast as applicable (#7971)
This commit introduces 8 more variants of the .ICO file, embeds the
right ones into WindowsTerminal.exe, and adds code that will select the
most appropriate icon at runtime.

Since we're a Centennial application, the "application" icon inside our
package isn't used by the shell for the taskbar thumbnails or the
Alt-Tab window.

To quote J. Tippet,
> I believe there are two possible fixes:
>
> 1. Fix the OS shell to prefer the MRT icon instead of preferring the
>    win32 icon
> 2. Add alternate versions of /res/terminal.ico
> The 1st fix is clearly better, since it benefits any hybrid app. But
> the 2nd fix is much easier, since it'd just take about an hour to gin up
> a new .ico file and hack the .RC file to refer to it when building the
> preview flavor.

... and to quote Michael Ratanapintha,

> Basically, if your MSIX-packaged desktop app's image resources are
> separate files or even separate MSIX packages, they may be loaded by
> MRT. If they're embedded in the .exe, they're the old-fashioned Win32
> resources Mr. Tippet is referring to.

This is the "2nd fix."

Fixes #6777

Co-authored-by: Jeffrey Tippet <jtippet@ntdev.microsoft.com>
2020-10-28 00:39:38 +00:00

208 lines
8.1 KiB
PowerShell

#
# Generate-TerminalAssets.ps1
#
# Typical usage:
# .\Generate-TerminalAssets.ps1 -Path .\Terminal.svg -HighContrastPath .\Terminal_HC.svg -Destination .\images
# .\Generate-TerminalAssets.ps1 -Path .\Terminal_Pre.svg -HighContrastPath .\Terminal_Pre_HC.svg -Destination .\images-Pre
# .\Generate-TerminalAssets.ps1 -Path .\Terminal_Dev.svg -HighContrastPath .\Terminal_Dev_HC.svg -Destination .\images-Dev
#
# Some icons benefit from manual hints. The most efficient way to do that is to run the script twice:
#
# 1. Run .\Generate-TerminalAssets.ps1 ...args... -Destination .\images -KeepIntermediates
# 2. Manually hint the intermediate images under .\images\_intermediate*.png
# 3. Run .\Generate-TerminalAssets.ps1 ...args... -Destination .\images -UseExistingIntermediates
#
# Hinting the intermediate files minimizes the number of times you'll have to
# hint the same image. You may want to hint just the _intermediate.*.png and
# _intermediate.black.*.png files, and delete _intermediate.white.*.png. The
# script will then automatically derive _intermediate.white.*.png from
# _intermediate.black.*.png.
#
Param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
[string]$Path,
[string]$Destination,
[int[]]$Altforms = (16, 20, 24, 30, 32, 36, 40, 48, 60, 64, 72, 80, 96, 256),
[int[]]$Win32IconSizes = (16, 20, 24, 32, 48, 64, 256),
[switch]$Unplated = $true,
[float[]]$Scales = (1.0, 1.25, 1.5, 2.0, 4.0),
[string]$HighContrastPath = "",
[switch]$UseExistingIntermediates = $false,
[switch]$KeepIntermediates = $false
)
$assetTypes = @(
[pscustomobject]@{Name="LargeTile"; W=310; H=310; IconSize=96}
[pscustomobject]@{Name="LockScreenLogo"; W=24; H=24; IconSize=24}
[pscustomobject]@{Name="SmallTile"; W=71; H=71; IconSize=36}
[pscustomobject]@{Name="SplashScreen"; W=620; H=300; IconSize=96}
[pscustomobject]@{Name="Square44x44Logo"; W=44; H=44; IconSize=32}
[pscustomobject]@{Name="Square150x150Logo"; W=150; H=150; IconSize=48}
[pscustomobject]@{Name="StoreLogo"; W=50; H=50; IconSize=36}
[pscustomobject]@{Name="Wide310x150Logo"; W=310; H=150; IconSize=48}
)
function CeilToEven ([int]$i) { if ($i % 2 -eq 0) { [int]($i) } else { [int]($i + 1) } }
$inflatedAssetSizes = $assetTypes | ForEach-Object {
$as = $_;
$scales | ForEach-Object {
[pscustomobject]@{
Name = $as.Name + ".scale-$($_*100)"
W = [math]::Round($as.W * $_, [System.MidpointRounding]::ToPositiveInfinity)
H = [math]::Round($as.H * $_, [System.MidpointRounding]::ToPositiveInfinity)
IconSize = CeilToEven ($as.IconSize * $_)
}
}
}
$allAssetSizes = $inflatedAssetSizes + ($Altforms | ForEach-Object {
[pscustomobject]@{
Name = "Square44x44Logo.targetsize-${_}"
W = [int]$_
H = [int]$_
IconSize = [int]$_
}
If ($Unplated) {
[pscustomobject]@{
Name = "Square44x44Logo.targetsize-${_}_altform-unplated"
W = [int]$_
H = [int]$_
IconSize = [int]$_
}
}
})
# Cross product with the 3 high contrast modes
$allAssetSizes = $allAssetSizes | ForEach-Object {
$asset = $_
("standard", "black", "white") | ForEach-Object {
$contrast = $_
$name = $asset.Name
If ($contrast -Ne "standard") {
If ($HighContrastPath -Eq "") {
# "standard" is the default, so we can omit it in filenames
return
}
$name += "_contrast-" + $contrast
}
[pscustomobject]@{
Name = $name
W = $asset.W
H = $asset.H
IconSize = $asset.IconSize
Contrast = $_
}
}
}
$allSizes = $allAssetSizes.IconSize | Group-Object | Select-Object -Expand Name
$TranslatedSVGPath = & wsl wslpath -u ((Get-Item $Path -ErrorAction:Stop).FullName -Replace "\\","/")
$TranslatedSVGContrastPath = $null
If ($HighContrastPath -Ne "") {
$TranslatedSVGContrastPath = & wsl wslpath -u ((Get-Item $HighContrastPath -ErrorAction:Stop).FullName -Replace "\\","/")
}
& wsl which inkscape | Out-Null
If ($LASTEXITCODE -Ne 0) { throw "Inkscape is not installed in WSL" }
& wsl which convert | Out-Null
If ($LASTEXITCODE -Ne 0) { throw "imagemagick is not installed in WSL" }
If (-Not [string]::IsNullOrEmpty($Destination)) {
New-Item -Type Directory $Destination -EA:Ignore
$TranslatedOutDir = & wsl wslpath -u ((Get-Item $Destination -EA:Stop).FullName -Replace "\\","/")
} Else {
$TranslatedOutDir = "."
}
$intermediates = [System.Collections.Concurrent.ConcurrentBag[PSCustomObject]]::new()
$intermediateFiles = [System.Collections.Concurrent.ConcurrentBag[string]]::new()
# Generate the base icons
$allSizes | ForEach-Object -Parallel {
$sz = $_;
$destinationNt = $using:Destination
$destinationWsl = $using:TranslatedOutDir
$svgStandardWsl = $using:TranslatedSVGPath
$svgContrastWsl = $using:TranslatedSVGContrastPath
$intermediateStandardNt = "$destinationNt\_intermediate.standard.$($sz).png"
$intermediateStandardWsl = "$destinationWsl/_intermediate.standard.$($sz).png"
If (($using:UseExistingIntermediates -Eq $false) -Or (-Not (Test-Path $intermediateStandardNt))) {
wsl inkscape -z -e "$intermediateStandardWsl" -w $sz -h $sz $svgStandardWsl
} Else {
Write-Host "Using existing $intermediateStandardNt"
}
($using:intermediateFiles).Add($intermediateStandardNt)
($using:intermediates).Add([PSCustomObject]@{
Contrast = "standard"
Size = $sz
PathWSL = $intermediateStandardWsl
})
If ($svgContrastWsl -Ne $null) {
$intermediateBlackNt = "$destinationNt\_intermediate.black.$($sz).png"
$intermediateWhiteNt = "$destinationNt\_intermediate.white.$($sz).png"
$intermediateBlackWsl = "$destinationWsl/_intermediate.black.$($sz).png"
$intermediateWhiteWsl = "$destinationWsl/_intermediate.white.$($sz).png"
If (($using:UseExistingIntermediates -Eq $false) -Or (-Not (Test-Path $intermediateBlackNt))) {
wsl inkscape -z -e "$intermediateBlackWsl" -w $sz -h $sz $svgContrastWsl
} Else {
Write-Host "Using existing $intermediateBlackNt"
}
If (($using:UseExistingIntermediates -Eq $false) -Or (-Not (Test-Path $intermediateWhiteNt))) {
# The HC white icon is just a negative image of the HC black one
wsl convert "$intermediateBlackWsl" -channel RGB -negate "$intermediateWhiteWsl"
} Else {
Write-Host "Using existing $intermediateWhiteNt"
}
($using:intermediateFiles).Add($intermediateBlackNt)
($using:intermediateFiles).Add($intermediateWhiteNt)
($using:intermediates).Add([PSCustomObject]@{
Contrast = "black"
Size = $sz
PathWSL = $intermediateBlackWsl
})
($using:intermediates).Add([PSCustomObject]@{
Contrast = "white"
Size = $sz
PathWSL = $intermediateWhiteWsl
})
}
}
$intermediates | ? { $_.Size -In $Win32IconSizes } | Group-Object Contrast | ForEach-Object -Parallel {
$assetName = "terminal.ico"
If ($_.Name -Ne "standard") {
$assetName = "terminal_contrast-$($_.Name).ico"
}
Write-Host "Producing win32 .ico for contrast=$($_.Name) as $assetName"
wsl convert $_.Group.PathWSL "$($using:TranslatedOutDir)/$assetName"
}
# Once the base icons are done, splat them into the middles of larger canvases.
$allAssetSizes | ForEach-Object -Parallel {
$asset = $_
If ($asset.W -Eq $asset.H -And $asset.IconSize -eq $asset.W) {
Write-Host "Copying base icon for size=$($asset.IconSize), contrast=$($asset.Contrast) to $($asset.Name)"
Copy-Item "${using:Destination}\_intermediate.$($asset.Contrast).$($asset.IconSize).png" "${using:Destination}\$($asset.Name).png" -Force
} Else {
wsl convert "$($using:TranslatedOutDir)/_intermediate.$($asset.Contrast).$($asset.IconSize).png" -gravity center -background transparent -extent "$($asset.W)x$($asset.H)" "$($using:TranslatedOutDir)/$($asset.Name).png"
}
}
If ($KeepIntermediates -Eq $false) {
$intermediateFiles | ForEach-Object {
Write-Host "Cleaning up intermediate file $_"
Remove-Item $_
}
}