125 lines
4.5 KiB
PowerShell
125 lines
4.5 KiB
PowerShell
|
|
# SVG → multi-size .ico mittels WPF (Bordmittel, kein extra Tool nötig)
|
||
|
|
# Generiert logo.ico mit 16, 32, 48, 64, 128, 256 Pixeln
|
||
|
|
|
||
|
|
Add-Type -AssemblyName PresentationCore, PresentationFramework, WindowsBase
|
||
|
|
|
||
|
|
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||
|
|
$IcoPath = Join-Path $ScriptDir 'logo.ico'
|
||
|
|
|
||
|
|
function New-LogoBitmap {
|
||
|
|
param([int]$Size)
|
||
|
|
|
||
|
|
$dv = [System.Windows.Media.DrawingVisual]::new()
|
||
|
|
$dc = $dv.RenderOpen()
|
||
|
|
$scale = $Size / 256.0
|
||
|
|
|
||
|
|
# Hintergrund
|
||
|
|
$bgRect = [System.Windows.Rect]::new(8 * $scale, 8 * $scale, 240 * $scale, 240 * $scale)
|
||
|
|
$bgBrush = [System.Windows.Media.SolidColorBrush]::new(
|
||
|
|
[System.Windows.Media.Color]::FromRgb(0x1A, 0x1A, 0x1A))
|
||
|
|
$dc.DrawRoundedRectangle($bgBrush, $null, $bgRect, 40 * $scale, 40 * $scale)
|
||
|
|
|
||
|
|
# Blauer Gradient
|
||
|
|
$gradStart = [System.Windows.Media.Color]::FromRgb(0x00, 0x78, 0xD4)
|
||
|
|
$gradEnd = [System.Windows.Media.Color]::FromRgb(0x00, 0x5A, 0x9E)
|
||
|
|
$grad = [System.Windows.Media.LinearGradientBrush]::new($gradStart, $gradEnd, 90)
|
||
|
|
$grad.Freeze()
|
||
|
|
|
||
|
|
# Bildschirm-Rahmen
|
||
|
|
$screenRect = [System.Windows.Rect]::new(40 * $scale, 56 * $scale, 176 * $scale, 120 * $scale)
|
||
|
|
$screenPen = [System.Windows.Media.Pen]::new($grad, 6 * $scale)
|
||
|
|
$dc.DrawRoundedRectangle($null, $screenPen, $screenRect, 10 * $scale, 10 * $scale)
|
||
|
|
|
||
|
|
# Streaming-Wellen
|
||
|
|
$wavePen = [System.Windows.Media.Pen]::new($grad, 5 * $scale)
|
||
|
|
$wavePen.StartLineCap = 'Round'
|
||
|
|
$wavePen.EndLineCap = 'Round'
|
||
|
|
|
||
|
|
foreach ($wave in @(@(70, 140, 90, 110, 120, 110), @(70, 140, 100, 90, 145, 90), @(70, 140, 110, 70, 170, 70))) {
|
||
|
|
$geom = [System.Windows.Media.StreamGeometry]::new()
|
||
|
|
$ctx = $geom.Open()
|
||
|
|
$ctx.BeginFigure([System.Windows.Point]::new($wave[0] * $scale, $wave[1] * $scale), $false, $false)
|
||
|
|
$ctx.QuadraticBezierTo(
|
||
|
|
[System.Windows.Point]::new($wave[2] * $scale, $wave[3] * $scale),
|
||
|
|
[System.Windows.Point]::new($wave[4] * $scale, $wave[5] * $scale), $true, $false)
|
||
|
|
$ctx.Close()
|
||
|
|
$geom.Freeze()
|
||
|
|
$dc.DrawGeometry($null, $wavePen, $geom)
|
||
|
|
}
|
||
|
|
|
||
|
|
# Punkt am Ursprung
|
||
|
|
$dc.DrawEllipse($grad, $null,
|
||
|
|
[System.Windows.Point]::new(70 * $scale, 140 * $scale),
|
||
|
|
6 * $scale, 6 * $scale)
|
||
|
|
|
||
|
|
# Standfuß
|
||
|
|
$foot1 = [System.Windows.Rect]::new(100 * $scale, 184 * $scale, 56 * $scale, 8 * $scale)
|
||
|
|
$foot2 = [System.Windows.Rect]::new( 80 * $scale, 196 * $scale, 96 * $scale, 8 * $scale)
|
||
|
|
$dc.DrawRoundedRectangle($grad, $null, $foot1, 2 * $scale, 2 * $scale)
|
||
|
|
$dc.DrawRoundedRectangle($grad, $null, $foot2, 3 * $scale, 3 * $scale)
|
||
|
|
|
||
|
|
$dc.Close()
|
||
|
|
|
||
|
|
$rtb = [System.Windows.Media.Imaging.RenderTargetBitmap]::new(
|
||
|
|
$Size, $Size, 96, 96, [System.Windows.Media.PixelFormats]::Pbgra32)
|
||
|
|
$rtb.Render($dv)
|
||
|
|
return $rtb
|
||
|
|
}
|
||
|
|
|
||
|
|
function Get-PngBytes {
|
||
|
|
param($bitmap)
|
||
|
|
$encoder = [System.Windows.Media.Imaging.PngBitmapEncoder]::new()
|
||
|
|
$encoder.Frames.Add([System.Windows.Media.Imaging.BitmapFrame]::Create($bitmap))
|
||
|
|
$ms = [System.IO.MemoryStream]::new()
|
||
|
|
$encoder.Save($ms)
|
||
|
|
$bytes = $ms.ToArray()
|
||
|
|
$ms.Dispose()
|
||
|
|
return ,$bytes
|
||
|
|
}
|
||
|
|
|
||
|
|
# Generierung mit ArrayList damit Wrapping vorhersehbar ist
|
||
|
|
$sizes = @(16, 32, 48, 64, 128, 256)
|
||
|
|
$pngList = New-Object System.Collections.ArrayList
|
||
|
|
foreach ($size in $sizes) {
|
||
|
|
Write-Host " Rendere ${size}x${size}..."
|
||
|
|
$bmp = New-LogoBitmap -Size $size
|
||
|
|
$bytes = Get-PngBytes $bmp
|
||
|
|
[void]$pngList.Add($bytes)
|
||
|
|
Write-Host " PNG: $($bytes.Length) bytes"
|
||
|
|
}
|
||
|
|
|
||
|
|
# ICO bauen
|
||
|
|
$out = [System.IO.MemoryStream]::new()
|
||
|
|
$bw = [System.IO.BinaryWriter]::new($out)
|
||
|
|
$bw.Write([UInt16]0) # reserved
|
||
|
|
$bw.Write([UInt16]1) # type = ICO
|
||
|
|
$bw.Write([UInt16]$pngList.Count) # count
|
||
|
|
|
||
|
|
$dataOffset = 6 + ($pngList.Count * 16)
|
||
|
|
for ($i = 0; $i -lt $pngList.Count; $i++) {
|
||
|
|
$size = $sizes[$i]
|
||
|
|
$w = if ($size -eq 256) { 0 } else { $size }
|
||
|
|
$h = if ($size -eq 256) { 0 } else { $size }
|
||
|
|
$len = $pngList[$i].Length
|
||
|
|
$bw.Write([byte]$w)
|
||
|
|
$bw.Write([byte]$h)
|
||
|
|
$bw.Write([byte]0)
|
||
|
|
$bw.Write([byte]0)
|
||
|
|
$bw.Write([UInt16]1)
|
||
|
|
$bw.Write([UInt16]32)
|
||
|
|
$bw.Write([UInt32]$len)
|
||
|
|
$bw.Write([UInt32]$dataOffset)
|
||
|
|
$dataOffset += $len
|
||
|
|
}
|
||
|
|
for ($i = 0; $i -lt $pngList.Count; $i++) {
|
||
|
|
$bytes = $pngList[$i]
|
||
|
|
$bw.Write($bytes, 0, $bytes.Length)
|
||
|
|
}
|
||
|
|
$bw.Flush()
|
||
|
|
[System.IO.File]::WriteAllBytes($IcoPath, $out.ToArray())
|
||
|
|
$bw.Close()
|
||
|
|
$out.Dispose()
|
||
|
|
|
||
|
|
$icoSize = (Get-Item $IcoPath).Length
|
||
|
|
Write-Host "`nFertig: $IcoPath ($icoSize Bytes, $($pngList.Count) Größen)"
|