param( [string]$OutputPath = (Join-Path $PSScriptRoot "..\Zcbot.WindowsNode\Assets\zcbot.ico") ) $ErrorActionPreference = "Stop" Add-Type -AssemblyName System.Drawing function New-RoundedRectanglePath { param( [System.Drawing.RectangleF]$Bounds, [float]$Radius ) $diameter = $Radius * 2 $path = [System.Drawing.Drawing2D.GraphicsPath]::new() $path.AddArc($Bounds.Left, $Bounds.Top, $diameter, $diameter, 180, 90) $path.AddArc($Bounds.Right - $diameter, $Bounds.Top, $diameter, $diameter, 270, 90) $path.AddArc($Bounds.Right - $diameter, $Bounds.Bottom - $diameter, $diameter, $diameter, 0, 90) $path.AddArc($Bounds.Left, $Bounds.Bottom - $diameter, $diameter, $diameter, 90, 90) $path.CloseFigure() return $path } function New-IconPngBytes { param([int]$Size) $bitmap = [System.Drawing.Bitmap]::new( $Size, $Size, [System.Drawing.Imaging.PixelFormat]::Format32bppArgb ) $graphics = [System.Drawing.Graphics]::FromImage($bitmap) $graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias $graphics.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality $graphics.Clear([System.Drawing.Color]::Transparent) $margin = $Size * 0.035 $radius = $Size * 0.22 $bounds = [System.Drawing.RectangleF]::new( $margin, $margin, $Size - 2 * $margin, $Size - 2 * $margin ) $shape = New-RoundedRectanglePath -Bounds $bounds -Radius $radius $background = [System.Drawing.SolidBrush]::new( [System.Drawing.Color]::FromArgb(255, 14, 40, 36) ) $logo = [System.Drawing.SolidBrush]::new( [System.Drawing.Color]::FromArgb(255, 153, 246, 228) ) $graphics.FillPath($background, $shape) $points = [System.Drawing.PointF[]]@( [System.Drawing.PointF]::new($Size * 0.265, $Size * 0.245), [System.Drawing.PointF]::new($Size * 0.735, $Size * 0.245), [System.Drawing.PointF]::new($Size * 0.735, $Size * 0.36), [System.Drawing.PointF]::new($Size * 0.455, $Size * 0.655), [System.Drawing.PointF]::new($Size * 0.735, $Size * 0.655), [System.Drawing.PointF]::new($Size * 0.735, $Size * 0.755), [System.Drawing.PointF]::new($Size * 0.265, $Size * 0.755), [System.Drawing.PointF]::new($Size * 0.265, $Size * 0.645), [System.Drawing.PointF]::new($Size * 0.545, $Size * 0.35), [System.Drawing.PointF]::new($Size * 0.265, $Size * 0.35) ) $graphics.FillPolygon($logo, $points) $stream = [System.IO.MemoryStream]::new() $bitmap.Save($stream, [System.Drawing.Imaging.ImageFormat]::Png) $bytes = $stream.ToArray() $stream.Dispose() $logo.Dispose() $background.Dispose() $shape.Dispose() $graphics.Dispose() $bitmap.Dispose() return ,$bytes } $sizes = @(16, 24, 32, 48, 64, 128, 256) $images = @($sizes | ForEach-Object { New-IconPngBytes -Size $_ }) $outputDirectory = Split-Path -Parent $OutputPath [System.IO.Directory]::CreateDirectory($outputDirectory) | Out-Null $stream = [System.IO.MemoryStream]::new() $writer = [System.IO.BinaryWriter]::new($stream) $writer.Write([uint16]0) $writer.Write([uint16]1) $writer.Write([uint16]$images.Count) $offset = 6 + 16 * $images.Count for ($index = 0; $index -lt $images.Count; $index++) { $size = $sizes[$index] $image = $images[$index] $writer.Write([byte]$(if ($size -eq 256) { 0 } else { $size })) $writer.Write([byte]$(if ($size -eq 256) { 0 } else { $size })) $writer.Write([byte]0) $writer.Write([byte]0) $writer.Write([uint16]1) $writer.Write([uint16]32) $writer.Write([uint32]$image.Length) $writer.Write([uint32]$offset) $offset += $image.Length } foreach ($image in $images) { $writer.Write([byte[]]$image) } $writer.Flush() [System.IO.File]::WriteAllBytes($OutputPath, $stream.ToArray()) $writer.Dispose() $stream.Dispose() Write-Output "[OK] Generated $OutputPath"