Private/New-GradientColorArray.ps1
|
function New-GradientColorArray { <# .SYNOPSIS Generates a gradient color array for character-by-character coloring .DESCRIPTION Interpolates colors evenly between 2 or more waypoint colors, one color per step, as RGB arrays (TrueColor) or ANSI 256-color codes (ANSI8). .PARAMETER Colors Array of gradient waypoints (minimum 2 colors). Accepts color names, hex codes, or RGB arrays. .PARAMETER Steps Number of colors to generate (typically total character count) .PARAMETER Mode Color mode: 'TrueColor' returns RGB arrays, 'ANSI8' returns ANSI 256-color codes .EXAMPLE New-GradientColorArray -Colors @("Red","Blue") -Steps 10 -Mode TrueColor Returns 10 RGB arrays interpolated from Red to Blue .EXAMPLE New-GradientColorArray -Colors @("#FF0000","#00FF00","#0000FF") -Steps 20 -Mode ANSI8 Returns 20 ANSI8 codes for a red-green-blue gradient .OUTPUTS System.Array Returns an array of color values matching the Steps count: - TrueColor mode: Array of RGB arrays @(R,G,B) - ANSI8 mode: Array of ANSI 256-color codes (integers 0-255) .NOTES Author: MarkusMcNugen License: MIT Requires: PowerShell 5.1 or later Write-ColorEX calls this private function for -Gradient. Each step's color is a linear interpolation between the two waypoints around it. A color name not in the color table and an invalid hex code are gray. .LINK https://github.com/MarkusMcNugen/PSWriteColorEX .LINK Write-ColorEX #> [CmdletBinding()] param( [Parameter(Mandatory)] [object[]]$Colors, [Parameter(Mandatory)] [ValidateRange(1, [int]::MaxValue)] [int]$Steps, [Parameter(Mandatory)] [ValidateSet('TrueColor', 'ANSI8')] [string]$Mode ) # Validate colors count if ($Colors.Count -lt 2) { throw "Gradient requires at least 2 colors (received $($Colors.Count))" } $gradientColors = [System.Collections.Generic.List[object]]::new($Steps) # Every waypoint as RGB $rgbColors = [System.Collections.Generic.List[array]]::new($Colors.Count) if ($null -eq $script:CachedColorTable) { $script:CachedColorTable = Get-ColorTableWithRGB } foreach ($color in $Colors) { if ($color -is [array] -and $color.Count -eq 3) { $null = $rgbColors.Add(@( [Math]::Max(0, [Math]::Min(255, [int]$color[0])), [Math]::Max(0, [Math]::Min(255, [int]$color[1])), [Math]::Max(0, [Math]::Min(255, [int]$color[2])) )) } elseif ($color -is [string] -and $color -match '^#|^0x') { $null = $rgbColors.Add((Convert-HexToRGB -Hex $color)) } else { $colorEntry = $script:CachedColorTable[$color] if ($colorEntry) { $null = $rgbColors.Add($colorEntry[4]) } else { $null = $rgbColors.Add(@(128, 128, 128)) } } } # One step is the first color if ($Steps -eq 1) { $rgb = $rgbColors[0] if ($Mode -eq 'ANSI8') { $null = $gradientColors.Add((Convert-RGBToANSI8 -RGB $rgb)) } else { $null = $gradientColors.Add($rgb) } return ,$gradientColors.ToArray() } if ($rgbColors.Count -eq 2) { $startRGB = $rgbColors[0] $endRGB = $rgbColors[1] for ($i = 0; $i -lt $Steps; $i++) { # Linear interpolation $ratio = $i / ($Steps - 1) $r = [int]($startRGB[0] + ($endRGB[0] - $startRGB[0]) * $ratio) $g = [int]($startRGB[1] + ($endRGB[1] - $startRGB[1]) * $ratio) $b = [int]($startRGB[2] + ($endRGB[2] - $startRGB[2]) * $ratio) if ($Mode -eq 'ANSI8') { $null = $gradientColors.Add((Convert-RGBToANSI8 -RGB @($r, $g, $b))) } else { $null = $gradientColors.Add(@($r, $g, $b)) } } } else { # Three or more waypoints: each step falls between the two waypoints around it $segmentCount = $rgbColors.Count - 1 for ($step = 0; $step -lt $Steps; $step++) { # Determine which color segment this step falls into $position = $step / ($Steps - 1) * $segmentCount $segmentIndex = [Math]::Min([int][Math]::Floor($position), $segmentCount - 1) $segmentProgress = $position - $segmentIndex $startRGB = $rgbColors[$segmentIndex] $endRGB = $rgbColors[$segmentIndex + 1] # Linear interpolation within segment $r = [int]($startRGB[0] + ($endRGB[0] - $startRGB[0]) * $segmentProgress) $g = [int]($startRGB[1] + ($endRGB[1] - $startRGB[1]) * $segmentProgress) $b = [int]($startRGB[2] + ($endRGB[2] - $startRGB[2]) * $segmentProgress) if ($Mode -eq 'ANSI8') { $null = $gradientColors.Add((Convert-RGBToANSI8 -RGB @($r, $g, $b))) } else { $null = $gradientColors.Add(@($r, $g, $b)) } } } # The comma keeps the array whole rather than unrolled into the pipeline return ,$gradientColors.ToArray() } |