Created
January 29, 2025 13:03
-
-
Save futuremotiondev/407fbe99ccfb2b0836924d66921bc93b to your computer and use it in GitHub Desktop.
Problems with converting multiple PNGs to 32-Bit ICO using ImageMagick in PowerShell.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using namespace System.Collections.Generic | |
using namespace System.Collections.Concurrent | |
using namespace System.IO | |
function Convert-SVGToICOWorking { | |
[CmdletBinding(DefaultParameterSetName = "Path")] | |
param ( | |
[Parameter( | |
Mandatory, | |
Position = 0, | |
ValueFromPipeline, | |
ValueFromPipelineByPropertyName, | |
ParameterSetName = "Path", | |
HelpMessage="Path to one or more SVG files." | |
)] | |
[SupportsWildcards()] | |
[ValidateNotNullOrEmpty()] | |
[String[]] $Path, | |
[Parameter( | |
Mandatory, | |
Position = 0, | |
ValueFromPipelineByPropertyName, | |
ParameterSetName = "LiteralPath", | |
HelpMessage="Literal path to one or more SVG files." | |
)] | |
[ValidateScript({$_ -notmatch '[\?\*]'}, | |
ErrorMessage = "Wildcard characters *, ? are not acceptable with -LiteralPath")] | |
[ValidateScript({[System.IO.Path]::IsPathRooted($_)}, | |
ErrorMessage = "Relative paths are not allowed in -LiteralPath.")] | |
[Alias('PSPath')] | |
[ValidateNotNullOrEmpty()] | |
[String[]] $LiteralPath, | |
[Parameter(HelpMessage = "If set, ICO files will be placed in a subfolder of the SVGs containing directory.")] | |
[Switch] $OutputInSubfolder, | |
[Parameter(HelpMessage = "The name of the subfolder to place ICO files if -OutputInSubfolder is set.")] | |
[String] $SubfolderName = 'ICO Conversion', | |
[Parameter(HelpMessage = "The number of simultaneous threads to use during conversion.")] | |
[Int32] $MaxThreads = 20 | |
) | |
begin { | |
$rsvgCmd = Get-Command rsvg-convert.exe -EA 0 | |
if(-not$rsvgCmd){ | |
Write-Error "rsvg-convert.exe cannot be found in PATH. Aborting" | |
return | |
} | |
$magickCmd = Get-Command magick.exe -EA 0 | |
if(-not$magickCmd){ | |
Write-Error "magick.exe (ImageMagick) cannot be found in PATH. Aborting" | |
return | |
} | |
$svgList = [List[FileInfo]]@() | |
} | |
process { | |
$resolvedPaths = if($PSBoundParameters['Path']) { | |
$Path | Get-Item -Force | |
} elseif($PSBoundParameters['LiteralPath']) { | |
Get-Item -LiteralPath $LiteralPath -Force | |
} | |
$resolvedPaths | % { | |
$fileName = $_.FullName | |
if (Test-Path -LiteralPath $fileName -PathType Container) { | |
$gciSplat = @{ | |
LiteralPath = $fileName | |
Force = $true | |
Recurse = $true | |
ErrorAction = 'SilentlyContinue' | |
File = -File | |
Filter = '*.svg' | |
} | |
$childItems = Get-ChildItem @gciSplat | |
if($childItems){ | |
foreach ($item in $childItems) { | |
$null = $svgList.Add($item) | |
} | |
} | |
} elseif(Test-Path -LiteralPath $fileName -PathType Leaf) { | |
if($_.Extension -eq '.svg'){ | |
$null = $svgList.Add($_) | |
} | |
} | |
} | |
} | |
end { | |
$tempDirDict = [ConcurrentDictionary[String,String]]::new() | |
if($PSBoundParameters['OutputInSubfolder']){ | |
$tempDirName = $SubfolderName | |
} else { | |
$tempDirName = ((New-Guid).Guid) | |
} | |
$svgList | ForEach-Object -Parallel { | |
$curSvg = $_.FullName | |
$curSvgBaseName = $_.BaseName | |
$curSvgDir = $_.Directory | |
$tempDirName = $Using:tempDirName | |
$tempDirDict = $using:tempDirDict | |
$rsvgCmd = $Using:rsvgCmd | |
$magickCmd = $Using:magickCmd | |
$tempFolder = Join-Path -Path $curSvgDir -ChildPath $tempDirName | |
if(-not($tempFolder | Test-Path -PathType Container)){ | |
New-Item -Path $tempFolder -ItemType Directory -Force | Out-Null | |
} | |
$icoSizes = @(16, 20, 24, 32, 48, 64, 96, 128, 256) | |
foreach ($size in $icoSizes) { | |
$rsvgParams = "-a", "-w", $size, "-h", $size, "-f", "png", $curSvg, "-o", "$tempFolder\$curSvgBaseName-$size.png" | |
& $rsvgCmd $rsvgParams | Out-Null | |
} | |
$magickCmd = Get-Command magick.exe -CommandType Application | |
$printArgs = Get-Command print_argv.exe -CommandType Application | |
# COMMAND 1: Works but throws error: magick.exe: Cannot write image with defined | |
# png:bit-depth or png:color-type. `' @ warning/png.c/MagickPNGWarningHandler/1526. | |
& $printArgs $($icoSizes.ForEach{"$tempFolder\$curSvgBaseName-$_.png"}) "$tempFolder\$curSvgBaseName.ico" | |
& $magickCmd $($icoSizes.ForEach{"$tempFolder\$curSvgBaseName-$_.png"}) "$tempFolder\$curSvgBaseName.ico" | |
# COMMAND 2: Works but throws Inkscape errors: (org.inkscape.Inkscape:13820): | |
# WARNING **: 06:50:22.942: Failed to find resource file 'svg2ico.py'. Looked in: | |
# C:\Users\username\AppData\Roaming\inkscape\extensions\svg2ico.py | |
# & $printArgs -background none $curSvg -define icon:auto-resize="16,20,24,32,48,64,96,128,256" -depth 32 "$tempFolder\$curSvgBaseName.ico" | |
# & $magickCmd -background none $curSvg -define icon:auto-resize="16,20,24,32,48,64,96,128,256" -depth 32 "$tempFolder\$curSvgBaseName.ico" | |
if (-not ($tempDirDict.Values -contains $tempFolder)) { | |
$null = $tempDirDict.TryAdd($((New-Guid).Guid), $tempFolder) | Out-Null | |
} | |
} -ThrottleLimit $MaxThreads | |
$tempDirDict.GetEnumerator() | % { | |
$tempDir = Get-Item -LiteralPath $($_.Value) -Force | |
$tempDirFull = $tempDir.FullName | |
$tempDirParent = $tempDir.Parent | |
Get-ChildItem $tempDirFull -Filter '*.png' -Recurse -Force | Remove-Item -Force | |
if(-not($PSBoundParameters['OutputInSubfolder'])){ | |
$icoFiles = Get-ChildItem -LiteralPath $tempDirFull -Filter '*.ico' -Recurse -Force | |
$icoFiles | % { | |
$curIcoFullname = $_.FullName | |
$icoDestPath = [System.IO.Path]::Combine($tempDirParent, $_.Name) | |
$icoDestPath = Get-UniqueNameIfDuplicate -LiteralPath $icoDestPath | |
Move-Item -LiteralPath $curIcoFullname -Destination $icoDestPath -Force | Out-Null | |
} | |
Remove-Item -LiteralPath $tempDirFull -Recurse -Force | Out-Null | |
} | |
} | |
} | |
} | |
Convert-SVGToICOWorking -LiteralPath "C:\Icons\00 Apps\Chrome\00 Source\FM Chrome Light Black 03.svg" -OutputInSubfolder |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment