97 lines
3.1 KiB
PowerShell
97 lines
3.1 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Converts a PNG into a multi-resolution Windows icon with ImageMagick.
|
|
|
|
.EXAMPLE
|
|
.\scripts\convert-png-to-ico.ps1 .\input.png .\output.ico
|
|
|
|
.EXAMPLE
|
|
.\scripts\convert-png-to-ico.ps1 .\input.png .\output.ico -PaddingPercent 0 -Force
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory, Position = 0)]
|
|
[string] $InputPath,
|
|
|
|
[Parameter(Position = 1)]
|
|
[string] $OutputPath,
|
|
|
|
[ValidateNotNullOrEmpty()]
|
|
[int[]] $Sizes = @(256, 128, 64, 48, 44, 40, 36, 32, 28, 24, 20, 16),
|
|
|
|
[ValidateRange(0, 25)]
|
|
[double] $PaddingPercent = 3,
|
|
|
|
[switch] $Force
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$magick = Get-Command magick -ErrorAction SilentlyContinue
|
|
if (-not $magick) {
|
|
throw 'ImageMagick was not found. Install it and make sure magick.exe is available on PATH.'
|
|
}
|
|
|
|
$resolvedInput = (Resolve-Path -LiteralPath $InputPath).Path
|
|
if (-not $OutputPath) {
|
|
$OutputPath = [System.IO.Path]::ChangeExtension($resolvedInput, '.ico')
|
|
}
|
|
|
|
$resolvedOutput = [System.IO.Path]::GetFullPath($OutputPath)
|
|
if ([System.IO.Path]::GetExtension($resolvedOutput) -ne '.ico') {
|
|
throw "The output path must have an .ico extension: $resolvedOutput"
|
|
}
|
|
if ((Test-Path -LiteralPath $resolvedOutput) -and -not $Force) {
|
|
throw "The output file already exists. Pass -Force to replace it: $resolvedOutput"
|
|
}
|
|
|
|
$outputDirectory = Split-Path -Parent $resolvedOutput
|
|
if (-not (Test-Path -LiteralPath $outputDirectory)) {
|
|
New-Item -ItemType Directory -Path $outputDirectory | Out-Null
|
|
}
|
|
|
|
$normalizedSizes = @($Sizes | Where-Object { $_ -ge 16 -and $_ -le 256 } | Sort-Object -Descending -Unique)
|
|
if ($normalizedSizes.Count -eq 0) {
|
|
throw 'Sizes must contain at least one value from 16 through 256.'
|
|
}
|
|
if ($normalizedSizes.Count -ne $Sizes.Count) {
|
|
throw 'Sizes must be unique values from 16 through 256.'
|
|
}
|
|
|
|
$dimensions = (& $magick.Source identify -format '%w %h' $resolvedInput).Trim() -split '\s+'
|
|
if ($LASTEXITCODE -ne 0 -or $dimensions.Count -ne 2) {
|
|
throw "ImageMagick could not read the input image dimensions: $resolvedInput"
|
|
}
|
|
|
|
$width = [int] $dimensions[0]
|
|
$height = [int] $dimensions[1]
|
|
$longestSide = [Math]::Max($width, $height)
|
|
$contentRatio = 1 - (2 * $PaddingPercent / 100)
|
|
$canvasSize = [int] [Math]::Ceiling($longestSide / $contentRatio)
|
|
$sizeList = $normalizedSizes -join ','
|
|
|
|
Write-Host "Input: $resolvedInput ($width x $height)"
|
|
Write-Host "Canvas: $canvasSize x $canvasSize ($PaddingPercent% padding per side)"
|
|
Write-Host "Frames: $sizeList"
|
|
|
|
& $magick.Source `
|
|
$resolvedInput `
|
|
-background none `
|
|
-gravity center `
|
|
-extent "${canvasSize}x${canvasSize}" `
|
|
-filter Lanczos `
|
|
-define "icon:auto-resize=$sizeList" `
|
|
$resolvedOutput
|
|
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "ImageMagick failed to create the icon: $resolvedOutput"
|
|
}
|
|
|
|
$actualSizes = @(& $magick.Source identify -format '%wx%h ' $resolvedOutput).Trim() -split '\s+'
|
|
if ($LASTEXITCODE -ne 0 -or $actualSizes.Count -ne $normalizedSizes.Count) {
|
|
throw "The icon was created, but its frames could not be verified: $resolvedOutput"
|
|
}
|
|
|
|
Write-Host "Created: $resolvedOutput"
|
|
Write-Host "Verified frames: $($actualSizes -join ', ')"
|