You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用PowerShell将网站PNG图标转高质量ICO用于桌面快捷方式

提升PowerShell转换PNG到ICO的质量问题

我需要用PowerShell从网站下载favicon.png,再转换成适合桌面快捷方式的favicon.ico文件。已经掌握用Invoke-WebRequest获取网站favicon.png的方法,但之前使用的转换脚本生成的ICO文件质量极低。脚本需通过Intune部署,无法依赖本地资源,否则会直接制作ICO文件托管。

之前使用的转换脚本:

function ConvertTo-Icon {
  param(
    [Parameter(Mandatory=$true)]
    $bitmapPath,
    $iconPath = "$env:temp\newicon.ico"
  )

Add-Type -AssemblyName System.Drawing

if (Test-Path $bitmapPath) {
    $b = [System.Drawing.Bitmap]::FromFile($bitmapPath)
    $icon = [System.Drawing.Icon]::FromHandle($b.GetHicon())
    $file = New-Object System.IO.FileStream($iconPath, 'OpenOrCreate') 
    $icon.Save($file)
    $file.Close()
    $icon.Dispose()

    explorer "/SELECT,$iconpath"
} else { Write-Warning "$BitmapPath does not exist" }
}

当前使用的完整代码:

param (
[string]$name, 
[string]$url, 
[string]$exe,
[string]$ptemp = "c:\temp\png",
[string]$icofold = "c:\Icons\",
[string]$s2url = "https://t2.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url="
)

#Append Icon URl if needed
if ($url.SubString(0,8) -like 'https://') {}
else { $url = $url.Insert(0,'https://')}
$iconurl = -join($s2url, $url, "&size=64")

#Verify temp directory and save .png
if (Test-Path $ptemp) {}
else { New-Item $ptemp -ItemType Directory}
$temppng = -join($ptemp, "/", $name, ".png")
Invoke-WebRequest -UseBasicParsing -uri $iconurl -outfile $temppng

#Verify Icon Folder exists
if (Test-Path $icofold) {}
else { New-Item $icofold -ItemType Directory}

#Convert to .ico and save
Add-Type -AssemblyName System.Drawing
$iconpath = -join($icofold, $name, ".ico")
    $img = [System.Drawing.Image]::FromFile($temppng)
    $img.Save($iconPath, [System.Drawing.Imaging.ImageFormat]::Icon)
    $img.Dispose()

#Create Shortcut on public Desktop
$desktopDir = Join-Path -Path $env:PUBLIC -ChildPath "Desktop"
$destinationPath = Join-Path -Path $desktopDir -ChildPath "$name.lnk"
$WshShell = New-Object -comObject WScript.Shell
$Shortcut = $WshShell.CreateShortcut($destinationPath)
$Shortcut.TargetPath = $exe
$Shortcut.Arguments = $url
$Shortcut.IconLocation = $iconpath
$Shortcut.Save()

#cleanup
remove-item $temppng

问题原因与解决方案

原脚本的问题在于:

  • 直接通过[System.Drawing.Icon]::FromHandle转换,仅生成单一尺寸的ICO,桌面快捷方式在不同场景下需要缩放该尺寸,导致模糊
  • 使用Image.Save直接转Icon格式,同样只保留单一尺寸,且未处理透明通道的优化

要生成高质量ICO,需创建包含多尺寸图标的ICO文件,让系统根据场景自动选择最合适的尺寸,避免缩放失真。以下是修改后的完整脚本:

修改后的完整脚本

param (
[string]$name, 
[string]$url, 
[string]$exe,
[string]$ptemp = "c:\temp\png",
[string]$icofold = "c:\Icons\",
[string]$s2url = "https://t2.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url="
)

#Append Icon URl if needed
if ($url.SubString(0,8) -like 'https://') {}
else { $url = $url.Insert(0,'https://')}
$iconurl = -join($s2url, $url, "&size=64")

#Verify temp directory and save .png
if (Test-Path $ptemp) {}
else { New-Item $ptemp -ItemType Directory}
$temppng = -join($ptemp, "/", $name, ".png")
Invoke-WebRequest -UseBasicParsing -uri $iconurl -outfile $temppng

#Verify Icon Folder exists
if (Test-Path $icofold) {}
else { New-Item $icofold -ItemType Directory}

#Convert to .ico and save (优化后的转换逻辑)
Add-Type -AssemblyName System.Drawing
$iconpath = -join($icofold, $name, ".ico")

$originalBitmap = [System.Drawing.Bitmap]::FromFile($temppng)
# 定义ICO需要包含的常用尺寸(覆盖桌面快捷方式的不同显示场景)
$iconSizes = @(16, 32, 48, 64)

# 创建内存流存储多尺寸ICO
$memoryStream = New-Object System.IO.MemoryStream
$iconWriter = New-Object System.BinaryWriter($memoryStream)

# ICO文件头
$iconWriter.Write([byte]0)
$iconWriter.Write([byte]0)
$iconWriter.Write([int16]1) # 图标类型
$iconWriter.Write([int16]$iconSizes.Count) # 图标数量

$iconDataOffsets = @()
$iconDataList = @()

# 先写入每个图标的目录项,再收集图标数据
foreach ($size in $iconSizes) {
    # 缩放位图到目标尺寸,使用高质量插值
    $scaledBitmap = New-Object System.Drawing.Bitmap($size, $size)
    $graphics = [System.Drawing.Graphics]::FromImage($scaledBitmap)
    $graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
    $graphics.DrawImage($originalBitmap, 0, 0, $size, $size)
    $graphics.Dispose()

    # 将缩放后的位图转成Icon并获取其数据
    $icon = [System.Drawing.Icon]::FromHandle($scaledBitmap.GetHicon())
    $tempStream = New-Object System.IO.MemoryStream
    $icon.Save($tempStream)
    $iconData = $tempStream.ToArray()
    $iconDataList += $iconData

    # 记录数据偏移(目录项之后的位置)
    $iconDataOffsets += $memoryStream.Position + (16 * $iconSizes.Count)

    # 写入目录项
    $iconWriter.Write([byte]$size) # 宽度
    $iconWriter.Write([byte]$size) # 高度
    $iconWriter.Write([byte]0) # 颜色数(0表示真彩色)
    $iconWriter.Write([byte]0) # 保留位
    $iconWriter.Write([int16]1) # 平面数
    $iconWriter.Write([int16]32) # 每像素位数(支持透明)
    $iconWriter.Write([int32]$iconData.Length) # 数据长度
    $iconWriter.Write([int32]$iconDataOffsets[-1]) # 数据偏移

    # 释放临时资源
    $tempStream.Dispose()
    $icon.Dispose()
    $scaledBitmap.Dispose()
}

# 写入所有图标数据
foreach ($data in $iconDataList) {
    $iconWriter.Write($data)
}

# 保存到文件
$fileStream = New-Object System.IO.FileStream($iconPath, [System.IO.FileMode]::Create)
$memoryStream.Seek(0, [System.IO.SeekOrigin]::Begin) | Out-Null
$memoryStream.CopyTo($fileStream)

# 释放所有资源
$fileStream.Dispose()
$memoryStream.Dispose()
$originalBitmap.Dispose()

#Create Shortcut on public Desktop
$desktopDir = Join-Path -Path $env:PUBLIC -ChildPath "Desktop"
$destinationPath = Join-Path -Path $desktopDir -ChildPath "$name.lnk"
$WshShell = New-Object -comObject WScript.Shell
$Shortcut = $WshShell.CreateShortcut($destinationPath)
$Shortcut.TargetPath = $exe
$Shortcut.Arguments = $url
$Shortcut.IconLocation = $iconpath
$Shortcut.Save()

#cleanup
remove-item $temppng

优化说明

  1. 多尺寸支持:生成16x16、32x32、48x48、64x64四种常用尺寸,覆盖桌面快捷方式的小图标、大图标、任务栏显示等场景
  2. 高质量缩放:使用HighQualityBicubic插值模式缩放位图,减少缩放失真
  3. 透明通道保留:指定32位色深,确保PNG的透明效果在ICO中正常显示
  4. 标准ICO结构:手动构建符合规范的ICO文件头和目录项,确保系统能正确识别多尺寸图标

内容的提问来源于stack exchange,提问作者iamsquash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 12:48:22