# 从 Assets/gotify-mascot.png 生成多分辨率 ICO # 输出:Assets/gotify-mascot.ico param( [string]$Png = "$PSScriptRoot\gotify-mascot.png", [string]$Ico = "$PSScriptRoot\gotify-mascot.ico" ) Add-Type -AssemblyName System.Drawing $src = [System.Drawing.Image]::FromFile((Resolve-Path $Png)) $srcW = $src.Width $srcH = $src.Height # 多分辨率列表(像素) — 包含原始尺寸 $sizes = @(16, 24, 32, 48, 64, 128, 196) | Where-Object { $_ -le [math]::Max($srcW, $srcH) } if (($srcW, $srcH) -notin $sizes) { $sizes += ,($srcW, $srcH) | Out-Null } $sizes = $sizes | Sort-Object -Unique # 1) 把每个分辨率的位图渲染成 PNG 字节 $entries = @() foreach ($sz in $sizes) { $bmp = New-Object System.Drawing.Bitmap $sz, $sz, ([System.Drawing.Imaging.PixelFormat]::Format32bppArgb) $g = [System.Drawing.Graphics]::FromImage($bmp) $g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic $g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::HighQuality $g.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality $g.Clear([System.Drawing.Color]::Transparent) $g.DrawImage($src, 0, 0, $sz, $sz) $g.Dispose() $ms = New-Object System.IO.MemoryStream $bmp.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png) $pngBytes = $ms.ToArray() $ms.Dispose() $bmp.Dispose() $entries += [pscustomobject]@{ Width = $sz Height = $sz Bytes = $pngBytes } } $src.Dispose() # 2) 组装 ICO 文件 # ICONDIR (6 bytes) # ICONDIRENTRY * N (16 bytes each) # Image data $out = New-Object System.IO.MemoryStream $bw = New-Object System.IO.BinaryWriter $out # ICONDIR $bw.Write([uint16]0) # Reserved $bw.Write([uint16]1) # Type: 1 = ICO $bw.Write([uint16]$entries.Count) # Count # ICONDIRENTRY (16 bytes each) $dataOffset = 6 + 16 * $entries.Count foreach ($e in $entries) { $w = if ($e.Width -ge 256) { 0 } else { $e.Width } $h = if ($e.Height -ge 256) { 0 } else { $e.Height } $bw.Write([byte]$w) # Width $bw.Write([byte]$h) # Height $bw.Write([byte]0) # Color count (0 = >256 colors) $bw.Write([byte]0) # Reserved $bw.Write([uint16]1) # Color planes $bw.Write([uint16]32) # Bits per pixel $bw.Write([uint32]$e.Bytes.Length) $bw.Write([uint32]$dataOffset) $dataOffset += $e.Bytes.Length } # Image data foreach ($e in $entries) { $bw.Write($e.Bytes) } $bw.Flush() [System.IO.File]::WriteAllBytes($Ico, $out.ToArray()) $bw.Dispose() $out.Dispose() Write-Host "ICO built: $Ico ($((Get-Item $Ico).Length) bytes, $($entries.Count) sizes: $($sizes -join ','))"