Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' Add-Type -AssemblyName System.Drawing function New-RoundedRectPath { param( [System.Drawing.RectangleF] $Rect, [float] $Radius ) $diameter = $Radius * 2.0 $path = New-Object System.Drawing.Drawing2D.GraphicsPath if ($diameter -le 0.0) { $path.AddRectangle($Rect) return $path } $path.AddArc($Rect.X, $Rect.Y, $diameter, $diameter, 180, 90) $path.AddArc($Rect.Right - $diameter, $Rect.Y, $diameter, $diameter, 270, 90) $path.AddArc($Rect.Right - $diameter, $Rect.Bottom - $diameter, $diameter, $diameter, 0, 90) $path.AddArc($Rect.X, $Rect.Bottom - $diameter, $diameter, $diameter, 90, 90) $path.CloseFigure() return $path } function New-Color { param( [int] $A, [int] $R, [int] $G, [int] $B ) return [System.Drawing.Color]::FromArgb($A, $R, $G, $B) } function Add-ShadowRoundedRect { param( [System.Drawing.Graphics] $Graphics, [System.Drawing.RectangleF] $Rect, [float] $Radius, [int] $Layers, [float] $OffsetX, [float] $OffsetY ) for ($layer = $Layers; $layer -ge 1; $layer--) { $inflate = [float]($layer * 2.2) $shadowRect = [System.Drawing.RectangleF]::new( $Rect.X + $OffsetX - ($inflate / 2.0), $Rect.Y + $OffsetY - ($inflate / 2.0), $Rect.Width + $inflate, $Rect.Height + $inflate) $shadowPath = New-RoundedRectPath -Rect $shadowRect -Radius ($Radius + ($inflate / 3.5)) try { $alpha = [Math]::Min(80, [int](5 + ($layer * 2.8))) $brush = New-Object System.Drawing.SolidBrush (New-Color -A $alpha -R 0 -G 0 -B 0) try { $Graphics.FillPath($brush, $shadowPath) } finally { $brush.Dispose() } } finally { $shadowPath.Dispose() } } } function Add-ShadowEllipse { param( [System.Drawing.Graphics] $Graphics, [System.Drawing.RectangleF] $Rect, [int] $Layers, [float] $OffsetX, [float] $OffsetY ) for ($layer = $Layers; $layer -ge 1; $layer--) { $inflate = [float]($layer * 1.8) $alpha = [Math]::Min(65, [int](4 + ($layer * 2.0))) $brush = New-Object System.Drawing.SolidBrush (New-Color -A $alpha -R 0 -G 0 -B 0) try { $Graphics.FillEllipse( $brush, $Rect.X + $OffsetX - ($inflate / 2.0), $Rect.Y + $OffsetY - ($inflate / 2.0), $Rect.Width + $inflate, $Rect.Height + $inflate) } finally { $brush.Dispose() } } } function Draw-Line { param( [System.Drawing.Graphics] $Graphics, [System.Drawing.Color] $Color, [float] $Width, [float] $X1, [float] $Y1, [float] $X2, [float] $Y2, [System.Drawing.Drawing2D.LineCap] $StartCap = [System.Drawing.Drawing2D.LineCap]::Round, [System.Drawing.Drawing2D.LineCap] $EndCap = [System.Drawing.Drawing2D.LineCap]::Round ) $pen = New-Object System.Drawing.Pen($Color, $Width) try { $pen.StartCap = $StartCap $pen.EndCap = $EndCap $Graphics.DrawLine($pen, $X1, $Y1, $X2, $Y2) } finally { $pen.Dispose() } } function Save-MultiSizeIcon { param( [System.Drawing.Bitmap] $MasterBitmap, [string] $OutputPath, [int[]] $Sizes ) $tempFiles = New-Object System.Collections.Generic.List[string] try { foreach ($size in $Sizes) { $scaled = New-Object System.Drawing.Bitmap($size, $size) try { $graphics = [System.Drawing.Graphics]::FromImage($scaled) try { $graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::HighQuality $graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic $graphics.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality $graphics.CompositingQuality = [System.Drawing.Drawing2D.CompositingQuality]::HighQuality $graphics.Clear([System.Drawing.Color]::Transparent) $graphics.DrawImage($MasterBitmap, 0, 0, $size, $size) } finally { $graphics.Dispose() } $tempFile = [System.IO.Path]::ChangeExtension([System.IO.Path]::GetTempFileName(), '.png') $scaled.Save($tempFile, [System.Drawing.Imaging.ImageFormat]::Png) $tempFiles.Add($tempFile) } finally { $scaled.Dispose() } } $stream = [System.IO.File]::Create($OutputPath) try { $writer = New-Object System.IO.BinaryWriter($stream) try { $writer.Write([UInt16]0) $writer.Write([UInt16]1) $writer.Write([UInt16]$Sizes.Length) $dataOffset = 6 + (16 * $Sizes.Length) $imageBlobs = @() for ($index = 0; $index -lt $Sizes.Length; $index++) { $size = $Sizes[$index] $pngBytes = [System.IO.File]::ReadAllBytes($tempFiles[$index]) $imageBlobs += ,$pngBytes $writer.Write([byte]($(if ($size -ge 256) { 0 } else { $size }))) $writer.Write([byte]($(if ($size -ge 256) { 0 } else { $size }))) $writer.Write([byte]0) $writer.Write([byte]0) $writer.Write([UInt16]1) $writer.Write([UInt16]32) $writer.Write([UInt32]$pngBytes.Length) $writer.Write([UInt32]$dataOffset) $dataOffset += $pngBytes.Length } foreach ($blob in $imageBlobs) { $writer.Write($blob) } } finally { $writer.Dispose() } } finally { $stream.Dispose() } } finally { foreach ($tempFile in $tempFiles) { if ([System.IO.File]::Exists($tempFile)) { Remove-Item $tempFile -Force } } } } $root = Split-Path -Parent $PSScriptRoot $assetsDir = Join-Path $root 'Assets' $previewPath = Join-Path $assetsDir 'XlabAppIconPreview.png' $iconPath = Join-Path $assetsDir 'XlabApp.ico' $size = 1024 $bitmap = New-Object System.Drawing.Bitmap($size, $size) try { $graphics = [System.Drawing.Graphics]::FromImage($bitmap) try { $graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias $graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic $graphics.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality $graphics.CompositingQuality = [System.Drawing.Drawing2D.CompositingQuality]::HighQuality $graphics.Clear([System.Drawing.Color]::Transparent) $tileRect = [System.Drawing.RectangleF]::new(86, 86, 852, 852) $tileRadius = 194.0 Add-ShadowRoundedRect -Graphics $graphics -Rect $tileRect -Radius $tileRadius -Layers 14 -OffsetX 8 -OffsetY 18 $tilePath = New-RoundedRectPath -Rect $tileRect -Radius $tileRadius try { $tileBrush = New-Object System.Drawing.Drawing2D.LinearGradientBrush( $tileRect, (New-Color -A 255 -R 12 -G 28 -B 52), (New-Color -A 255 -R 20 -G 96 -B 132), 48.0) try { $graphics.FillPath($tileBrush, $tilePath) } finally { $tileBrush.Dispose() } $glowEllipse = New-Object System.Drawing.Drawing2D.GraphicsPath try { $glowEllipse.AddEllipse([System.Drawing.RectangleF]::new(198, 154, 486, 350)) $glowBrush = New-Object System.Drawing.Drawing2D.PathGradientBrush($glowEllipse) try { $glowBrush.CenterColor = New-Color -A 90 -R 255 -G 255 -B 255 $glowBrush.SurroundColors = @((New-Color -A 0 -R 255 -G 255 -B 255)) $graphics.FillPath($glowBrush, $glowEllipse) } finally { $glowBrush.Dispose() } } finally { $glowEllipse.Dispose() } $radialCore = New-Object System.Drawing.Drawing2D.GraphicsPath try { $radialCore.AddEllipse([System.Drawing.RectangleF]::new(232, 232, 560, 560)) $radialBrush = New-Object System.Drawing.Drawing2D.PathGradientBrush($radialCore) try { $radialBrush.CenterColor = New-Color -A 64 -R 68 -G 226 -B 255 $radialBrush.SurroundColors = @((New-Color -A 0 -R 68 -G 226 -B 255)) $graphics.FillPath($radialBrush, $radialCore) } finally { $radialBrush.Dispose() } } finally { $radialCore.Dispose() } $rimPen = New-Object System.Drawing.Pen((New-Color -A 80 -R 98 -G 219 -B 255), 8.0) try { $graphics.DrawPath($rimPen, $tilePath) } finally { $rimPen.Dispose() } $innerPath = New-RoundedRectPath -Rect ([System.Drawing.RectangleF]::new(116, 116, 792, 792)) -Radius 170.0 try { $innerPen = New-Object System.Drawing.Pen((New-Color -A 42 -R 255 -G 255 -B 255), 3.0) try { $graphics.DrawPath($innerPen, $innerPath) } finally { $innerPen.Dispose() } } finally { $innerPath.Dispose() } } finally { $tilePath.Dispose() } $orbitRect = [System.Drawing.RectangleF]::new(250, 252, 524, 524) $orbitShadowPen = New-Object System.Drawing.Pen((New-Color -A 42 -R 0 -G 0 -B 0), 18.0) try { $graphics.DrawEllipse($orbitShadowPen, 268, 272, 524, 524) } finally { $orbitShadowPen.Dispose() } $orbitPen = New-Object System.Drawing.Pen((New-Color -A 76 -R 206 -G 241 -B 255), 14.0) try { $graphics.DrawEllipse($orbitPen, $orbitRect) } finally { $orbitPen.Dispose() } $center = 512.0 $bladeRect = [System.Drawing.RectangleF]::new(-64, -286, 128, 356) $bladeRadius = 64.0 $bladeDefinitions = @( @{ Angle = -18.0; Start = (New-Color -A 255 -R 88 -G 240 -B 255); End = (New-Color -A 255 -R 28 -G 144 -B 218); Highlight = (New-Color -A 120 -R 255 -G 255 -B 255) }, @{ Angle = 102.0; Start = (New-Color -A 255 -R 109 -G 246 -B 198); End = (New-Color -A 255 -R 30 -G 179 -B 133); Highlight = (New-Color -A 110 -R 244 -G 255 -B 250) }, @{ Angle = 222.0; Start = (New-Color -A 255 -R 255 -G 190 -B 98); End = (New-Color -A 255 -R 240 -G 120 -B 52); Highlight = (New-Color -A 100 -R 255 -G 242 -B 218) } ) foreach ($blade in $bladeDefinitions) { $shadowState = $graphics.Save() try { $graphics.TranslateTransform($center + 14.0, $center + 18.0) $graphics.RotateTransform([float]$blade.Angle) $shadowPath = New-RoundedRectPath -Rect $bladeRect -Radius $bladeRadius try { $shadowBrush = New-Object System.Drawing.SolidBrush (New-Color -A 72 -R 0 -G 0 -B 0) try { $graphics.FillPath($shadowBrush, $shadowPath) } finally { $shadowBrush.Dispose() } } finally { $shadowPath.Dispose() } } finally { $graphics.Restore($shadowState) } $state = $graphics.Save() try { $graphics.TranslateTransform($center, $center) $graphics.RotateTransform([float]$blade.Angle) $path = New-RoundedRectPath -Rect $bladeRect -Radius $bladeRadius try { $bladeBrush = New-Object System.Drawing.Drawing2D.LinearGradientBrush( $bladeRect, $blade.Start, $blade.End, 90.0) try { $graphics.FillPath($bladeBrush, $path) } finally { $bladeBrush.Dispose() } $shinePath = New-RoundedRectPath -Rect ([System.Drawing.RectangleF]::new(-44, -270, 34, 316)) -Radius 18.0 try { $shineBrush = New-Object System.Drawing.Drawing2D.LinearGradientBrush( ([System.Drawing.RectangleF]::new(-44, -270, 34, 316)), $blade.Highlight, (New-Color -A 0 -R 255 -G 255 -B 255), 90.0) try { $graphics.FillPath($shineBrush, $shinePath) } finally { $shineBrush.Dispose() } } finally { $shinePath.Dispose() } $edgePen = New-Object System.Drawing.Pen((New-Color -A 86 -R 255 -G 255 -B 255), 4.0) try { $graphics.DrawPath($edgePen, $path) } finally { $edgePen.Dispose() } } finally { $path.Dispose() } } finally { $graphics.Restore($state) } } $innerShadowBrush = New-Object System.Drawing.SolidBrush (New-Color -A 70 -R 0 -G 0 -B 0) try { $graphics.FillEllipse($innerShadowBrush, 404, 406, 216, 216) } finally { $innerShadowBrush.Dispose() } $innerRingRect = [System.Drawing.RectangleF]::new(394, 392, 216, 216) $innerRingBrush = New-Object System.Drawing.Drawing2D.LinearGradientBrush( $innerRingRect, (New-Color -A 255 -R 250 -G 252 -B 255), (New-Color -A 255 -R 204 -G 214 -B 226), 125.0) try { $graphics.FillEllipse($innerRingBrush, $innerRingRect) } finally { $innerRingBrush.Dispose() } $innerCorePath = New-Object System.Drawing.Drawing2D.GraphicsPath try { $innerCorePath.AddEllipse([System.Drawing.RectangleF]::new(428, 426, 148, 148)) $innerCoreBrush = New-Object System.Drawing.Drawing2D.PathGradientBrush($innerCorePath) try { $innerCoreBrush.CenterColor = New-Color -A 255 -R 14 -G 46 -B 82 $innerCoreBrush.SurroundColors = @((New-Color -A 255 -R 25 -G 93 -B 138)) $graphics.FillPath($innerCoreBrush, $innerCorePath) } finally { $innerCoreBrush.Dispose() } } finally { $innerCorePath.Dispose() } $coreGlowPath = New-Object System.Drawing.Drawing2D.GraphicsPath try { $coreGlowPath.AddEllipse([System.Drawing.RectangleF]::new(444, 442, 116, 116)) $coreGlowBrush = New-Object System.Drawing.Drawing2D.PathGradientBrush($coreGlowPath) try { $coreGlowBrush.CenterColor = New-Color -A 255 -R 92 -G 227 -B 255 $coreGlowBrush.SurroundColors = @((New-Color -A 0 -R 92 -G 227 -B 255)) $graphics.FillPath($coreGlowBrush, $coreGlowPath) } finally { $coreGlowBrush.Dispose() } } finally { $coreGlowPath.Dispose() } $coreRingPen = New-Object System.Drawing.Pen((New-Color -A 112 -R 255 -G 255 -B 255), 6.0) try { $graphics.DrawEllipse($coreRingPen, $innerRingRect) } finally { $coreRingPen.Dispose() } $sparkPath = New-Object System.Drawing.Drawing2D.GraphicsPath try { $sparkPath.AddEllipse([System.Drawing.RectangleF]::new(672, 248, 74, 74)) $sparkBrush = New-Object System.Drawing.Drawing2D.PathGradientBrush($sparkPath) try { $sparkBrush.CenterColor = New-Color -A 190 -R 255 -G 255 -B 255 $sparkBrush.SurroundColors = @((New-Color -A 0 -R 255 -G 255 -B 255)) $graphics.FillPath($sparkBrush, $sparkPath) } finally { $sparkBrush.Dispose() } } finally { $sparkPath.Dispose() } Draw-Line -Graphics $graphics -Color (New-Color -A 86 -R 255 -G 255 -B 255) -Width 10.0 -X1 708.0 -Y1 216.0 -X2 708.0 -Y2 282.0 Draw-Line -Graphics $graphics -Color (New-Color -A 86 -R 255 -G 255 -B 255) -Width 10.0 -X1 675.0 -Y1 249.0 -X2 741.0 -Y2 249.0 $bitmap.Save($previewPath, [System.Drawing.Imaging.ImageFormat]::Png) Save-MultiSizeIcon -MasterBitmap $bitmap -OutputPath $iconPath -Sizes @(16, 24, 32, 48, 64, 128, 256) } finally { $graphics.Dispose() } } finally { $bitmap.Dispose() } Write-Host "Generated:" Write-Host " $previewPath" Write-Host " $iconPath"