# # 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 $_ } }