mirror of
https://github.com/dfinke/ImportExcel.git
synced 2025-12-06 00:23:20 +00:00
Compare commits
2 Commits
copilot/fi
...
copilot/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d823761970 | ||
|
|
5b4ae76394 |
152
GRADIENT_GUIDE.md
Normal file
152
GRADIENT_GUIDE.md
Normal file
@@ -0,0 +1,152 @@
|
||||
# Working with Gradient Fills in ImportExcel
|
||||
|
||||
## Overview
|
||||
|
||||
ImportExcel now provides enhanced support for working with Excel gradient fills through three new functions that address EPPlus 4.x limitations with gradient color reading.
|
||||
|
||||
## The Issue
|
||||
|
||||
In EPPlus 4.x (used by ImportExcel), while gradient colors can be set using `SetColor()`, they cannot be read back via properties like `Rgb`, `Top`, `Bottom`, `Left`, `Right`. This prevents copying gradients between cells.
|
||||
|
||||
## The Solution
|
||||
|
||||
Three new functions provide a complete gradient workflow:
|
||||
|
||||
### Set-ExcelGradientFill
|
||||
Sets gradient fill properties for Excel ranges.
|
||||
|
||||
```powershell
|
||||
# Basic linear gradient
|
||||
Set-ExcelGradientFill -Range $ws.Cells["A1"] -Type Linear -Degree 90 -Color1 Blue -Color2 Green
|
||||
|
||||
# Path gradient
|
||||
Set-ExcelGradientFill -Range $ws.Cells["B1"] -Type Path -Color1 Red -Color2 Yellow
|
||||
|
||||
# Advanced linear gradient with positioning
|
||||
Set-ExcelGradientFill -Range $ws.Cells["C1"] -Type Linear -Degree 45 -Color1 Purple -Color2 Orange -Top 0.1 -Bottom 0.9
|
||||
```
|
||||
|
||||
### Get-ExcelGradientFill
|
||||
Reads gradient properties that can be reliably extracted from EPPlus.
|
||||
|
||||
```powershell
|
||||
$gradient = Get-ExcelGradientFill -Range $ws.Cells["A1"]
|
||||
# Returns: Type, Degree, Top, Bottom, Left, Right
|
||||
# Note: Color1 and Color2 are null due to EPPlus limitations
|
||||
```
|
||||
|
||||
### Copy-ExcelGradientFill
|
||||
Copies gradient fills between ranges using two approaches:
|
||||
|
||||
#### Approach 1: Copy Geometric Properties Only
|
||||
```powershell
|
||||
# Copies Type, Degree, and positioning but warns about colors
|
||||
Copy-ExcelGradientFill -SourceRange $ws.Cells["A1"] -TargetRange $ws.Cells["B1"]
|
||||
```
|
||||
|
||||
#### Approach 2: Complete Gradient Definition
|
||||
```powershell
|
||||
# Create a complete gradient definition
|
||||
$gradientDef = @{
|
||||
Type = "Linear"
|
||||
Degree = 45
|
||||
Color1 = [System.Drawing.Color]::Blue
|
||||
Color2 = [System.Drawing.Color]::Green
|
||||
Top = 0.2
|
||||
Bottom = 0.8
|
||||
}
|
||||
|
||||
Copy-ExcelGradientFill -TargetRange $ws.Cells["C1:E3"] -GradientDefinition $gradientDef
|
||||
```
|
||||
|
||||
## Complete Example
|
||||
|
||||
```powershell
|
||||
Import-Module ImportExcel
|
||||
|
||||
$xl = Open-ExcelPackage -Path "gradients.xlsx" -Create
|
||||
$ws = Add-WorkSheet -ExcelPackage $xl -WorksheetName "Gradients"
|
||||
|
||||
# Set original gradient
|
||||
Set-ExcelGradientFill -Range $ws.Cells["A1"] -Type Linear -Degree 90 -Color1 Blue -Color2 Green
|
||||
|
||||
# Get gradient properties (geometric only)
|
||||
$gradientInfo = Get-ExcelGradientFill -Range $ws.Cells["A1"]
|
||||
|
||||
# Create complete definition for copying
|
||||
$completeDef = @{
|
||||
Type = $gradientInfo.Type
|
||||
Degree = $gradientInfo.Degree
|
||||
Top = $gradientInfo.Top
|
||||
Bottom = $gradientInfo.Bottom
|
||||
Left = $gradientInfo.Left
|
||||
Right = $gradientInfo.Right
|
||||
Color1 = [System.Drawing.Color]::Blue # Must specify colors
|
||||
Color2 = [System.Drawing.Color]::Green
|
||||
}
|
||||
|
||||
# Copy to other cells
|
||||
Copy-ExcelGradientFill -TargetRange $ws.Cells["B1:D3"] -GradientDefinition $completeDef
|
||||
|
||||
Close-ExcelPackage -ExcelPackage $xl -SaveAs "gradients.xlsx"
|
||||
```
|
||||
|
||||
## Migration from Direct EPPlus Access
|
||||
|
||||
### Before (Limited by EPPlus 4.x):
|
||||
```powershell
|
||||
# Setting worked
|
||||
$Sheet.Cells["A1"].Style.Fill.Gradient.Color1.SetColor("BLUE")
|
||||
$Sheet.Cells["A1"].Style.Fill.Gradient.Color2.SetColor("GREEN")
|
||||
|
||||
# Reading failed - returned empty values
|
||||
$rgb = $Sheet.Cells["A1"].Style.Fill.Gradient.Color1.Rgb # Empty!
|
||||
```
|
||||
|
||||
### After (Using ImportExcel functions):
|
||||
```powershell
|
||||
# Setting is easier and more robust
|
||||
Set-ExcelGradientFill -Range $Sheet.Cells["A1"] -Type Linear -Degree 90 -Color1 Blue -Color2 Green
|
||||
|
||||
# Reading works for geometric properties
|
||||
$gradient = Get-ExcelGradientFill -Range $Sheet.Cells["A1"]
|
||||
# $gradient.Type, $gradient.Degree work; colors need to be specified separately
|
||||
|
||||
# Copying now possible with complete definitions
|
||||
$gradientDef = @{
|
||||
Type = $gradient.Type
|
||||
Degree = $gradient.Degree
|
||||
Color1 = [System.Drawing.Color]::Blue
|
||||
Color2 = [System.Drawing.Color]::Green
|
||||
}
|
||||
Copy-ExcelGradientFill -TargetRange $Sheet.Cells["B1"] -GradientDefinition $gradientDef
|
||||
```
|
||||
|
||||
## Parameters Reference
|
||||
|
||||
### Set-ExcelGradientFill Parameters
|
||||
- **Range**: Target Excel range (required)
|
||||
- **Type**: "Linear" or "Path" (required)
|
||||
- **Degree**: Angle for linear gradients (0-360, default 90)
|
||||
- **Color1**: First color - Color object or string name (required)
|
||||
- **Color2**: Second color - Color object or string name (required)
|
||||
- **Top/Bottom/Left/Right**: Position values (0-1, optional)
|
||||
|
||||
### Copy-ExcelGradientFill Parameters
|
||||
- **SourceRange**: Source range (for copying geometric properties)
|
||||
- **TargetRange**: Target range (required)
|
||||
- **GradientDefinition**: Hashtable with gradient properties (alternative to SourceRange)
|
||||
|
||||
## Limitations
|
||||
|
||||
- Color properties cannot be read from existing gradients due to EPPlus 4.x limitations
|
||||
- When copying gradients, colors must be specified manually in the gradient definition
|
||||
- Functions provide warnings when color limitations affect operations
|
||||
|
||||
## Benefits
|
||||
|
||||
- Clean, PowerShell-friendly interface for gradient operations
|
||||
- Comprehensive parameter validation
|
||||
- Clear error messages and warnings
|
||||
- Supports both string color names and Color objects
|
||||
- Enables gradient copying workflows that weren't possible before
|
||||
@@ -46,6 +46,7 @@ Check out the How To Videos https://www.youtube.com/watch?v=U3Ne_yX4tYo&list=PL5
|
||||
'ConvertFrom-ExcelSheet',
|
||||
'ConvertFrom-ExcelToSQLInsert',
|
||||
'ConvertTo-ExcelXlsx',
|
||||
'Copy-ExcelGradientFill',
|
||||
'Copy-ExcelWorksheet',
|
||||
'DoChart',
|
||||
'Enable-ExcelAutoFilter',
|
||||
@@ -56,6 +57,7 @@ Check out the How To Videos https://www.youtube.com/watch?v=U3Ne_yX4tYo&list=PL5
|
||||
'Get-ExcelColumnName',
|
||||
'Get-ExcelFileSchema',
|
||||
'Get-ExcelFileSummary',
|
||||
'Get-ExcelGradientFill',
|
||||
'Get-ExcelSheetDimensionAddress',
|
||||
'Get-ExcelSheetInfo',
|
||||
'Get-ExcelWorkbookInfo',
|
||||
@@ -92,6 +94,7 @@ Check out the How To Videos https://www.youtube.com/watch?v=U3Ne_yX4tYo&list=PL5
|
||||
'Set-CellComment',
|
||||
'Set-CellStyle',
|
||||
'Set-ExcelColumn',
|
||||
'Set-ExcelGradientFill',
|
||||
'Set-ExcelRange',
|
||||
'Set-ExcelRow',
|
||||
'Set-WorksheetProtection',
|
||||
|
||||
@@ -113,57 +113,6 @@ function Add-ExcelChart {
|
||||
if ($null -ne $XMinValue) { $chart.XAxis.MinValue = $XMinValue }
|
||||
if ($null -ne $XMaxValue) { $chart.XAxis.MaxValue = $XMaxValue }
|
||||
if ($XAxisNumberformat) { $chart.XAxis.Format = (Expand-NumberFormat $XAxisNumberformat) }
|
||||
|
||||
# Fix for category axis (used in line charts, etc.): EPPlus doesn't serialize MajorUnit/MinorUnit to XML for category axes
|
||||
# We need to manually add these elements to the XML if they were specified
|
||||
if ($XMajorUnit -or $XMinorUnit) {
|
||||
$chartXml = $chart.ChartXml
|
||||
$nsManager = New-Object System.Xml.XmlNamespaceManager($chartXml.NameTable)
|
||||
$null = $nsManager.AddNamespace("c", "http://schemas.openxmlformats.org/drawingml/2006/chart")
|
||||
$catAx = $chartXml.SelectSingleNode("//c:catAx", $nsManager)
|
||||
|
||||
if ($catAx) {
|
||||
# Category axis exists - need to add majorUnit/minorUnit elements
|
||||
if ($XMajorUnit) {
|
||||
$existingMajorUnit = $catAx.SelectSingleNode("c:majorUnit", $nsManager)
|
||||
if (-not $existingMajorUnit) {
|
||||
$majorUnitElement = $chartXml.CreateElement("c", "majorUnit", "http://schemas.openxmlformats.org/drawingml/2006/chart")
|
||||
$null = $majorUnitElement.SetAttribute("val", $XMajorUnit)
|
||||
# Insert after scaling element or at the beginning
|
||||
$scalingNode = $catAx.SelectSingleNode("c:scaling", $nsManager)
|
||||
if ($scalingNode) {
|
||||
$null = $catAx.InsertAfter($majorUnitElement, $scalingNode)
|
||||
} else {
|
||||
$null = $catAx.PrependChild($majorUnitElement)
|
||||
}
|
||||
} else {
|
||||
$null = $existingMajorUnit.SetAttribute("val", $XMajorUnit)
|
||||
}
|
||||
}
|
||||
|
||||
if ($XMinorUnit) {
|
||||
$existingMinorUnit = $catAx.SelectSingleNode("c:minorUnit", $nsManager)
|
||||
if (-not $existingMinorUnit) {
|
||||
$minorUnitElement = $chartXml.CreateElement("c", "minorUnit", "http://schemas.openxmlformats.org/drawingml/2006/chart")
|
||||
$null = $minorUnitElement.SetAttribute("val", $XMinorUnit)
|
||||
# Insert after majorUnit if it exists, otherwise after scaling
|
||||
$majorUnitNode = $catAx.SelectSingleNode("c:majorUnit", $nsManager)
|
||||
if ($majorUnitNode) {
|
||||
$null = $catAx.InsertAfter($minorUnitElement, $majorUnitNode)
|
||||
} else {
|
||||
$scalingNode = $catAx.SelectSingleNode("c:scaling", $nsManager)
|
||||
if ($scalingNode) {
|
||||
$null = $catAx.InsertAfter($minorUnitElement, $scalingNode)
|
||||
} else {
|
||||
$null = $catAx.PrependChild($minorUnitElement)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$null = $existingMinorUnit.SetAttribute("val", $XMinorUnit)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($YAxisTitleText) {
|
||||
$chart.YAxis.Title.Text = $YAxisTitleText
|
||||
|
||||
119
Public/Copy-ExcelGradientFill.ps1
Normal file
119
Public/Copy-ExcelGradientFill.ps1
Normal file
@@ -0,0 +1,119 @@
|
||||
function Copy-ExcelGradientFill {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Copies gradient fill settings from one Excel range to another.
|
||||
|
||||
.DESCRIPTION
|
||||
Due to limitations in EPPlus 4.x, gradient color properties cannot be read directly.
|
||||
This function provides a workaround by storing gradient definitions and applying them
|
||||
to target ranges.
|
||||
|
||||
.PARAMETER SourceRange
|
||||
The source range with the gradient fill to copy.
|
||||
|
||||
.PARAMETER TargetRange
|
||||
The target range where the gradient fill should be applied.
|
||||
|
||||
.PARAMETER GradientDefinition
|
||||
A hashtable containing gradient definition with properties:
|
||||
- Type: Linear or Path
|
||||
- Degree: Angle for linear gradients (0-360)
|
||||
- Top, Bottom, Left, Right: Position values (0-1)
|
||||
- Color1: First color (System.Drawing.Color or color name)
|
||||
- Color2: Second color (System.Drawing.Color or color name)
|
||||
|
||||
.EXAMPLE
|
||||
# Copy gradient from A1 to B1:C2
|
||||
Copy-ExcelGradientFill -SourceRange $ws.Cells["A1"] -TargetRange $ws.Cells["B1:C2"]
|
||||
|
||||
.EXAMPLE
|
||||
# Apply a custom gradient definition
|
||||
$gradient = @{
|
||||
Type = "Linear"
|
||||
Degree = 45
|
||||
Color1 = [System.Drawing.Color]::Blue
|
||||
Color2 = [System.Drawing.Color]::Green
|
||||
Top = 0
|
||||
Bottom = 1
|
||||
Left = 0
|
||||
Right = 1
|
||||
}
|
||||
Copy-ExcelGradientFill -TargetRange $ws.Cells["A1:B2"] -GradientDefinition $gradient
|
||||
|
||||
.NOTES
|
||||
This function works around EPPlus 4.x limitations with gradient color reading.
|
||||
#>
|
||||
[CmdletBinding(DefaultParameterSetName = 'CopyFromSource')]
|
||||
param(
|
||||
[Parameter(ParameterSetName = 'CopyFromSource', Mandatory)]
|
||||
$SourceRange,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
$TargetRange,
|
||||
|
||||
[Parameter(ParameterSetName = 'ApplyDefinition', Mandatory)]
|
||||
[hashtable]$GradientDefinition
|
||||
)
|
||||
|
||||
if ($PSCmdlet.ParameterSetName -eq 'CopyFromSource') {
|
||||
# Extract gradient properties from source
|
||||
$sourceGradient = $SourceRange.Style.Fill.Gradient
|
||||
|
||||
# Create gradient definition from source
|
||||
$GradientDefinition = @{
|
||||
Type = $sourceGradient.Type
|
||||
Degree = $sourceGradient.Degree
|
||||
Top = $sourceGradient.Top
|
||||
Bottom = $sourceGradient.Bottom
|
||||
Left = $sourceGradient.Left
|
||||
Right = $sourceGradient.Right
|
||||
}
|
||||
|
||||
# Note: Colors cannot be copied due to EPPlus limitation
|
||||
Write-Warning "Gradient colors cannot be copied due to EPPlus 4.x limitations. Only geometric properties (Type, Degree, positioning) are copied. Please use Set-ExcelGradientFill to set colors."
|
||||
}
|
||||
|
||||
# Apply gradient definition to target
|
||||
$targetGradient = $TargetRange.Style.Fill.Gradient
|
||||
|
||||
if ($GradientDefinition.Type) {
|
||||
$targetGradient.Type = [OfficeOpenXml.Style.ExcelFillGradientType]::$($GradientDefinition.Type)
|
||||
}
|
||||
|
||||
if ($GradientDefinition.ContainsKey('Degree')) {
|
||||
$targetGradient.Degree = $GradientDefinition.Degree
|
||||
}
|
||||
|
||||
if ($GradientDefinition.ContainsKey('Top')) {
|
||||
$targetGradient.Top = $GradientDefinition.Top
|
||||
}
|
||||
|
||||
if ($GradientDefinition.ContainsKey('Bottom')) {
|
||||
$targetGradient.Bottom = $GradientDefinition.Bottom
|
||||
}
|
||||
|
||||
if ($GradientDefinition.ContainsKey('Left')) {
|
||||
$targetGradient.Left = $GradientDefinition.Left
|
||||
}
|
||||
|
||||
if ($GradientDefinition.ContainsKey('Right')) {
|
||||
$targetGradient.Right = $GradientDefinition.Right
|
||||
}
|
||||
|
||||
# Set colors if provided
|
||||
if ($GradientDefinition.Color1) {
|
||||
$color1 = $GradientDefinition.Color1
|
||||
if ($color1 -is [string]) {
|
||||
$color1 = [System.Drawing.Color]::$color1
|
||||
}
|
||||
$targetGradient.Color1.SetColor($color1)
|
||||
}
|
||||
|
||||
if ($GradientDefinition.Color2) {
|
||||
$color2 = $GradientDefinition.Color2
|
||||
if ($color2 -is [string]) {
|
||||
$color2 = [System.Drawing.Color]::$color2
|
||||
}
|
||||
$targetGradient.Color2.SetColor($color2)
|
||||
}
|
||||
}
|
||||
52
Public/Get-ExcelGradientFill.ps1
Normal file
52
Public/Get-ExcelGradientFill.ps1
Normal file
@@ -0,0 +1,52 @@
|
||||
function Get-ExcelGradientFill {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Gets gradient fill properties from an Excel range.
|
||||
|
||||
.DESCRIPTION
|
||||
This function extracts gradient fill properties that can be reliably read from EPPlus 4.x.
|
||||
Due to EPPlus limitations, gradient colors cannot be read directly and will return $null.
|
||||
|
||||
.PARAMETER Range
|
||||
The Excel range to read gradient properties from.
|
||||
|
||||
.EXAMPLE
|
||||
# Get gradient properties from a cell
|
||||
$gradientInfo = Get-ExcelGradientFill -Range $ws.Cells["A1"]
|
||||
|
||||
.EXAMPLE
|
||||
# Get gradient properties and use them to copy to another range
|
||||
$gradient = Get-ExcelGradientFill -Range $ws.Cells["A1"]
|
||||
# Add colors since they can't be read
|
||||
$gradient.Color1 = [System.Drawing.Color]::Blue
|
||||
$gradient.Color2 = [System.Drawing.Color]::Green
|
||||
Copy-ExcelGradientFill -TargetRange $ws.Cells["B1:C2"] -GradientDefinition $gradient
|
||||
|
||||
.NOTES
|
||||
Due to EPPlus 4.x limitations, Color1 and Color2 properties will always be $null.
|
||||
This function is provided for completeness and to work with Copy-ExcelGradientFill.
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory, ValueFromPipeline)]
|
||||
$Range
|
||||
)
|
||||
|
||||
process {
|
||||
$gradient = $Range.Style.Fill.Gradient
|
||||
|
||||
$result = [PSCustomObject]@{
|
||||
Type = $gradient.Type
|
||||
Degree = $gradient.Degree
|
||||
Top = $gradient.Top
|
||||
Bottom = $gradient.Bottom
|
||||
Left = $gradient.Left
|
||||
Right = $gradient.Right
|
||||
Color1 = $null # Cannot be read due to EPPlus 4.x limitation
|
||||
Color2 = $null # Cannot be read due to EPPlus 4.x limitation
|
||||
ColorLimitationNote = "Color properties cannot be read due to EPPlus 4.x limitations"
|
||||
}
|
||||
|
||||
return $result
|
||||
}
|
||||
}
|
||||
128
Public/Set-ExcelGradientFill.ps1
Normal file
128
Public/Set-ExcelGradientFill.ps1
Normal file
@@ -0,0 +1,128 @@
|
||||
function Set-ExcelGradientFill {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Sets gradient fill properties for an Excel range.
|
||||
|
||||
.DESCRIPTION
|
||||
This function provides a complete interface for setting gradient fills in Excel ranges,
|
||||
working around EPPlus 4.x limitations with gradient handling.
|
||||
|
||||
.PARAMETER Range
|
||||
The Excel range to apply the gradient fill to.
|
||||
|
||||
.PARAMETER Type
|
||||
The gradient type: Linear or Path.
|
||||
|
||||
.PARAMETER Degree
|
||||
The angle for linear gradients (0-360 degrees).
|
||||
|
||||
.PARAMETER Color1
|
||||
The first gradient color. Can be a System.Drawing.Color object or color name.
|
||||
|
||||
.PARAMETER Color2
|
||||
The second gradient color. Can be a System.Drawing.Color object or color name.
|
||||
|
||||
.PARAMETER Top
|
||||
The top position for gradient positioning (0-1).
|
||||
|
||||
.PARAMETER Bottom
|
||||
The bottom position for gradient positioning (0-1).
|
||||
|
||||
.PARAMETER Left
|
||||
The left position for gradient positioning (0-1).
|
||||
|
||||
.PARAMETER Right
|
||||
The right position for gradient positioning (0-1).
|
||||
|
||||
.EXAMPLE
|
||||
# Set a simple blue to green linear gradient
|
||||
Set-ExcelGradientFill -Range $ws.Cells["A1"] -Type Linear -Degree 90 -Color1 Blue -Color2 Green
|
||||
|
||||
.EXAMPLE
|
||||
# Set a more complex gradient with positioning
|
||||
Set-ExcelGradientFill -Range $ws.Cells["A1:C3"] -Type Linear -Degree 45 -Color1 ([System.Drawing.Color]::Red) -Color2 ([System.Drawing.Color]::Yellow) -Top 0.2 -Bottom 0.8
|
||||
|
||||
.EXAMPLE
|
||||
# Set a path gradient
|
||||
Set-ExcelGradientFill -Range $ws.Cells["B1:D3"] -Type Path -Color1 "DarkBlue" -Color2 "LightBlue"
|
||||
|
||||
.NOTES
|
||||
This function addresses the EPPlus 4.x limitation where gradient colors cannot be read back.
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Does not change system state')]
|
||||
param(
|
||||
[Parameter(Mandatory, ValueFromPipeline)]
|
||||
$Range,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[ValidateSet('Linear', 'Path')]
|
||||
[string]$Type,
|
||||
|
||||
[Parameter()]
|
||||
[ValidateRange(0, 360)]
|
||||
[double]$Degree = 90,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
$Color1,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
$Color2,
|
||||
|
||||
[Parameter()]
|
||||
[ValidateRange(0, 1)]
|
||||
[double]$Top,
|
||||
|
||||
[Parameter()]
|
||||
[ValidateRange(0, 1)]
|
||||
[double]$Bottom,
|
||||
|
||||
[Parameter()]
|
||||
[ValidateRange(0, 1)]
|
||||
[double]$Left,
|
||||
|
||||
[Parameter()]
|
||||
[ValidateRange(0, 1)]
|
||||
[double]$Right
|
||||
)
|
||||
|
||||
process {
|
||||
$gradient = $Range.Style.Fill.Gradient
|
||||
|
||||
# Set gradient type
|
||||
$gradient.Type = [OfficeOpenXml.Style.ExcelFillGradientType]::$Type
|
||||
|
||||
# Set degree for linear gradients
|
||||
if ($Type -eq 'Linear') {
|
||||
$gradient.Degree = $Degree
|
||||
}
|
||||
|
||||
# Set positioning if provided
|
||||
if ($PSBoundParameters.ContainsKey('Top')) {
|
||||
$gradient.Top = $Top
|
||||
}
|
||||
|
||||
if ($PSBoundParameters.ContainsKey('Bottom')) {
|
||||
$gradient.Bottom = $Bottom
|
||||
}
|
||||
|
||||
if ($PSBoundParameters.ContainsKey('Left')) {
|
||||
$gradient.Left = $Left
|
||||
}
|
||||
|
||||
if ($PSBoundParameters.ContainsKey('Right')) {
|
||||
$gradient.Right = $Right
|
||||
}
|
||||
|
||||
# Set colors
|
||||
if ($Color1 -is [string]) {
|
||||
$Color1 = [System.Drawing.Color]::$Color1
|
||||
}
|
||||
$gradient.Color1.SetColor($Color1)
|
||||
|
||||
if ($Color2 -is [string]) {
|
||||
$Color2 = [System.Drawing.Color]::$Color2
|
||||
}
|
||||
$gradient.Color2.SetColor($Color2)
|
||||
}
|
||||
}
|
||||
10
README.md
10
README.md
@@ -191,4 +191,14 @@ ForEach-Object { $_.Value | Export-Csv ($_.key + '.csv') }
|
||||
## Contributing
|
||||
Contributions are welcome! Open a pull request to fix a bug, or open an issue to discuss a new feature or change.
|
||||
|
||||
## New Features
|
||||
|
||||
### Gradient Fill Support
|
||||
ImportExcel now includes enhanced gradient fill support with three new functions:
|
||||
- `Set-ExcelGradientFill` - Apply gradient fills to Excel ranges
|
||||
- `Get-ExcelGradientFill` - Read gradient properties from ranges
|
||||
- `Copy-ExcelGradientFill` - Copy gradients between ranges
|
||||
|
||||
These functions work around EPPlus 4.x limitations with gradient color reading. See [GRADIENT_GUIDE.md](GRADIENT_GUIDE.md) for detailed usage examples.
|
||||
|
||||
Original [README.md](./README.original.md)
|
||||
@@ -1,135 +0,0 @@
|
||||
# Test for X-Axis configuration on line charts
|
||||
# This test verifies that XMajorUnit and XMinorUnit parameters work correctly for line charts
|
||||
|
||||
Describe "X-Axis Configuration for Line Charts" {
|
||||
BeforeAll {
|
||||
$path = "TestDrive:\xaxis_test.xlsx"
|
||||
}
|
||||
|
||||
Context "X-Axis MajorUnit and MinorUnit on Line Charts" {
|
||||
BeforeAll {
|
||||
# Create test data
|
||||
$excel = 1..7 | ForEach-Object {
|
||||
[pscustomobject][ordered]@{
|
||||
XValue = @(5, 10, 15, 20, 25, 30, 35)[$_ - 1]
|
||||
YValue = @(18, 11, 23, 17, 12, 32, 12)[$_ - 1]
|
||||
}
|
||||
} | Export-Excel -Path $path -WorksheetName "Test" -PassThru -AutoNameRange
|
||||
|
||||
# Add chart with X-axis configuration
|
||||
Add-ExcelChart -Worksheet $excel.Workbook.Worksheets["Test"] `
|
||||
-ChartType Line `
|
||||
-XRange "XValue" `
|
||||
-YRange "YValue" `
|
||||
-Title "Test Chart" `
|
||||
-XMinValue 0 `
|
||||
-XMaxValue 40 `
|
||||
-XMajorUnit 10 `
|
||||
-XMinorUnit 5 `
|
||||
-YMinValue 0 `
|
||||
-YMaxValue 40 `
|
||||
-YMajorUnit 10 `
|
||||
-YMinorUnit 5
|
||||
|
||||
Close-ExcelPackage $excel
|
||||
|
||||
# Reopen to verify
|
||||
$excel = Open-ExcelPackage -Path $path
|
||||
$ws = $excel.Workbook.Worksheets["Test"]
|
||||
$chart = $ws.Drawings[0]
|
||||
}
|
||||
|
||||
It "Set XAxis.MinValue correctly" {
|
||||
$chart.XAxis.MinValue | Should -Be 0
|
||||
}
|
||||
|
||||
It "Set XAxis.MaxValue correctly" {
|
||||
$chart.XAxis.MaxValue | Should -Be 40
|
||||
}
|
||||
|
||||
It "Set XAxis.MajorUnit correctly" {
|
||||
$chart.XAxis.MajorUnit | Should -Be 10
|
||||
}
|
||||
|
||||
It "Set XAxis.MinorUnit correctly" {
|
||||
$chart.XAxis.MinorUnit | Should -Be 5
|
||||
}
|
||||
|
||||
It "Added MajorUnit to category axis XML" {
|
||||
$xml = $chart.ChartXml
|
||||
$nsmgr = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
|
||||
$nsmgr.AddNamespace("c", "http://schemas.openxmlformats.org/drawingml/2006/chart")
|
||||
$catAx = $xml.SelectSingleNode("//c:catAx", $nsmgr)
|
||||
$majorUnit = $catAx.SelectSingleNode("c:majorUnit", $nsmgr)
|
||||
|
||||
$majorUnit | Should -Not -BeNullOrEmpty
|
||||
$majorUnit.val | Should -Be "10"
|
||||
}
|
||||
|
||||
It "Added MinorUnit to category axis XML" {
|
||||
$xml = $chart.ChartXml
|
||||
$nsmgr = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
|
||||
$nsmgr.AddNamespace("c", "http://schemas.openxmlformats.org/drawingml/2006/chart")
|
||||
$catAx = $xml.SelectSingleNode("//c:catAx", $nsmgr)
|
||||
$minorUnit = $catAx.SelectSingleNode("c:minorUnit", $nsmgr)
|
||||
|
||||
$minorUnit | Should -Not -BeNullOrEmpty
|
||||
$minorUnit.val | Should -Be "5"
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
Close-ExcelPackage $excel -NoSave
|
||||
}
|
||||
}
|
||||
|
||||
Context "X-Axis without MajorUnit and MinorUnit" {
|
||||
BeforeAll {
|
||||
$path2 = "TestDrive:\xaxis_test2.xlsx"
|
||||
# Create test data without X-axis units
|
||||
$excel2 = 1..7 | ForEach-Object {
|
||||
[pscustomobject][ordered]@{
|
||||
XValue = @(5, 10, 15, 20, 25, 30, 35)[$_ - 1]
|
||||
YValue = @(18, 11, 23, 17, 12, 32, 12)[$_ - 1]
|
||||
}
|
||||
} | Export-Excel -Path $path2 -WorksheetName "Test" -PassThru -AutoNameRange
|
||||
|
||||
# Add chart WITHOUT X-axis MajorUnit/MinorUnit
|
||||
Add-ExcelChart -Worksheet $excel2.Workbook.Worksheets["Test"] `
|
||||
-ChartType Line `
|
||||
-XRange "XValue" `
|
||||
-YRange "YValue" `
|
||||
-Title "Test Chart"
|
||||
|
||||
Close-ExcelPackage $excel2
|
||||
|
||||
# Reopen to verify
|
||||
$excel2 = Open-ExcelPackage -Path $path2
|
||||
$ws2 = $excel2.Workbook.Worksheets["Test"]
|
||||
$chart2 = $ws2.Drawings[0]
|
||||
}
|
||||
|
||||
It "Should not add MajorUnit to category axis XML when not specified" {
|
||||
$xml = $chart2.ChartXml
|
||||
$nsmgr = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
|
||||
$nsmgr.AddNamespace("c", "http://schemas.openxmlformats.org/drawingml/2006/chart")
|
||||
$catAx = $xml.SelectSingleNode("//c:catAx", $nsmgr)
|
||||
$majorUnit = $catAx.SelectSingleNode("c:majorUnit", $nsmgr)
|
||||
|
||||
$majorUnit | Should -BeNullOrEmpty
|
||||
}
|
||||
|
||||
It "Should not add MinorUnit to category axis XML when not specified" {
|
||||
$xml = $chart2.ChartXml
|
||||
$nsmgr = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
|
||||
$nsmgr.AddNamespace("c", "http://schemas.openxmlformats.org/drawingml/2006/chart")
|
||||
$catAx = $xml.SelectSingleNode("//c:catAx", $nsmgr)
|
||||
$minorUnit = $catAx.SelectSingleNode("c:minorUnit", $nsmgr)
|
||||
|
||||
$minorUnit | Should -BeNullOrEmpty
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
Close-ExcelPackage $excel2 -NoSave
|
||||
}
|
||||
}
|
||||
}
|
||||
219
__tests__/GradientFill.tests.ps1
Normal file
219
__tests__/GradientFill.tests.ps1
Normal file
@@ -0,0 +1,219 @@
|
||||
Describe "Gradient Fill Functions" {
|
||||
BeforeAll {
|
||||
$script:testPath = "TestDrive:\GradientTest.xlsx"
|
||||
Remove-Item -Path $testPath -ErrorAction SilentlyContinue
|
||||
|
||||
# Import the module
|
||||
Import-Module "$PSScriptRoot\..\ImportExcel.psd1" -Force
|
||||
}
|
||||
|
||||
Context "Set-ExcelGradientFill Tests" {
|
||||
BeforeEach {
|
||||
$script:xl = Open-ExcelPackage -Path $testPath -Create
|
||||
$script:ws = Add-WorkSheet -ExcelPackage $xl -WorksheetName "GradientTest"
|
||||
}
|
||||
|
||||
AfterEach {
|
||||
Close-ExcelPackage -ExcelPackage $xl
|
||||
Remove-Item -Path $testPath -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
It "Should set linear gradient with basic properties" {
|
||||
Set-ExcelGradientFill -Range $ws.Cells["A1"] -Type Linear -Degree 90 -Color1 Blue -Color2 Green
|
||||
|
||||
$gradient = $ws.Cells["A1"].Style.Fill.Gradient
|
||||
$gradient.Type | Should -Be "Linear"
|
||||
$gradient.Degree | Should -Be 90
|
||||
}
|
||||
|
||||
It "Should set path gradient" {
|
||||
Set-ExcelGradientFill -Range $ws.Cells["A1"] -Type Path -Color1 Red -Color2 Yellow
|
||||
|
||||
$gradient = $ws.Cells["A1"].Style.Fill.Gradient
|
||||
$gradient.Type | Should -Be "Path"
|
||||
}
|
||||
|
||||
It "Should set linear gradient with positioning" {
|
||||
Set-ExcelGradientFill -Range $ws.Cells["A1"] -Type Linear -Degree 45 -Color1 Blue -Color2 Green -Top 0.2 -Bottom 0.8 -Left 0.1 -Right 0.9
|
||||
|
||||
$gradient = $ws.Cells["A1"].Style.Fill.Gradient
|
||||
$gradient.Type | Should -Be "Linear"
|
||||
$gradient.Degree | Should -Be 45
|
||||
$gradient.Top | Should -Be 0.2
|
||||
$gradient.Bottom | Should -Be 0.8
|
||||
$gradient.Left | Should -Be 0.1
|
||||
$gradient.Right | Should -Be 0.9
|
||||
}
|
||||
|
||||
It "Should accept System.Drawing.Color objects" {
|
||||
Set-ExcelGradientFill -Range $ws.Cells["A1"] -Type Linear -Color1 ([System.Drawing.Color]::Red) -Color2 ([System.Drawing.Color]::Blue)
|
||||
|
||||
$gradient = $ws.Cells["A1"].Style.Fill.Gradient
|
||||
$gradient.Type | Should -Be "Linear"
|
||||
}
|
||||
|
||||
It "Should work with ranges" {
|
||||
Set-ExcelGradientFill -Range $ws.Cells["A1:C3"] -Type Linear -Degree 135 -Color1 "Purple" -Color2 "Orange"
|
||||
|
||||
$gradient = $ws.Cells["A1"].Style.Fill.Gradient
|
||||
$gradient.Type | Should -Be "Linear"
|
||||
$gradient.Degree | Should -Be 135
|
||||
}
|
||||
|
||||
It "Should validate degree range" {
|
||||
{ Set-ExcelGradientFill -Range $ws.Cells["A1"] -Type Linear -Degree 400 -Color1 Blue -Color2 Green } | Should -Throw
|
||||
}
|
||||
|
||||
It "Should validate position range" {
|
||||
{ Set-ExcelGradientFill -Range $ws.Cells["A1"] -Type Linear -Color1 Blue -Color2 Green -Top 1.5 } | Should -Throw
|
||||
}
|
||||
}
|
||||
|
||||
Context "Get-ExcelGradientFill Tests" {
|
||||
BeforeEach {
|
||||
$script:xl = Open-ExcelPackage -Path $testPath -Create
|
||||
$script:ws = Add-WorkSheet -ExcelPackage $xl -WorksheetName "GradientTest"
|
||||
}
|
||||
|
||||
AfterEach {
|
||||
Close-ExcelPackage -ExcelPackage $xl
|
||||
Remove-Item -Path $testPath -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
It "Should get gradient properties that can be read" {
|
||||
# Set a gradient first
|
||||
Set-ExcelGradientFill -Range $ws.Cells["A1"] -Type Linear -Degree 45 -Color1 Blue -Color2 Green -Top 0.3 -Bottom 0.7
|
||||
|
||||
$result = Get-ExcelGradientFill -Range $ws.Cells["A1"]
|
||||
|
||||
$result.Type | Should -Be "Linear"
|
||||
$result.Degree | Should -Be 45
|
||||
$result.Top | Should -Be 0.3
|
||||
$result.Bottom | Should -Be 0.7
|
||||
$result.Color1 | Should -BeNullOrEmpty
|
||||
$result.Color2 | Should -BeNullOrEmpty
|
||||
$result.ColorLimitationNote | Should -Match "EPPlus.*limitation"
|
||||
}
|
||||
|
||||
It "Should return PSCustomObject with expected properties" {
|
||||
Set-ExcelGradientFill -Range $ws.Cells["A1"] -Type Path -Color1 Red -Color2 Blue
|
||||
|
||||
$result = Get-ExcelGradientFill -Range $ws.Cells["A1"]
|
||||
|
||||
$result | Should -BeOfType [PSCustomObject]
|
||||
$result.PSObject.Properties.Name | Should -Contain "Type"
|
||||
$result.PSObject.Properties.Name | Should -Contain "Degree"
|
||||
$result.PSObject.Properties.Name | Should -Contain "Color1"
|
||||
$result.PSObject.Properties.Name | Should -Contain "Color2"
|
||||
$result.PSObject.Properties.Name | Should -Contain "ColorLimitationNote"
|
||||
}
|
||||
}
|
||||
|
||||
Context "Copy-ExcelGradientFill Tests" {
|
||||
BeforeEach {
|
||||
$script:xl = Open-ExcelPackage -Path $testPath -Create
|
||||
$script:ws = Add-WorkSheet -ExcelPackage $xl -WorksheetName "GradientTest"
|
||||
}
|
||||
|
||||
AfterEach {
|
||||
Close-ExcelPackage -ExcelPackage $xl
|
||||
Remove-Item -Path $testPath -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
It "Should copy gradient geometric properties from source to target" {
|
||||
# Set up source
|
||||
Set-ExcelGradientFill -Range $ws.Cells["A1"] -Type Linear -Degree 60 -Color1 Blue -Color2 Green -Top 0.1 -Bottom 0.9
|
||||
|
||||
# Copy to target (should warn about colors)
|
||||
$warningVar = $null
|
||||
Copy-ExcelGradientFill -SourceRange $ws.Cells["A1"] -TargetRange $ws.Cells["B1"] -WarningVariable warningVar
|
||||
|
||||
$targetGradient = $ws.Cells["B1"].Style.Fill.Gradient
|
||||
$targetGradient.Type | Should -Be "Linear"
|
||||
$targetGradient.Degree | Should -Be 60
|
||||
$targetGradient.Top | Should -Be 0.1
|
||||
$targetGradient.Bottom | Should -Be 0.9
|
||||
|
||||
$warningVar | Should -Match "cannot be copied"
|
||||
}
|
||||
|
||||
It "Should apply custom gradient definition" {
|
||||
$gradientDef = @{
|
||||
Type = "Linear"
|
||||
Degree = 120
|
||||
Color1 = [System.Drawing.Color]::Purple
|
||||
Color2 = [System.Drawing.Color]::Yellow
|
||||
Top = 0.25
|
||||
Bottom = 0.75
|
||||
Left = 0.2
|
||||
Right = 0.8
|
||||
}
|
||||
|
||||
Copy-ExcelGradientFill -TargetRange $ws.Cells["C1"] -GradientDefinition $gradientDef
|
||||
|
||||
$gradient = $ws.Cells["C1"].Style.Fill.Gradient
|
||||
$gradient.Type | Should -Be "Linear"
|
||||
$gradient.Degree | Should -Be 120
|
||||
$gradient.Top | Should -Be 0.25
|
||||
$gradient.Bottom | Should -Be 0.75
|
||||
$gradient.Left | Should -Be 0.2
|
||||
$gradient.Right | Should -Be 0.8
|
||||
}
|
||||
|
||||
It "Should apply gradient definition with string colors" {
|
||||
$gradientDef = @{
|
||||
Type = "Path"
|
||||
Color1 = "Red"
|
||||
Color2 = "Blue"
|
||||
}
|
||||
|
||||
Copy-ExcelGradientFill -TargetRange $ws.Cells["D1:F3"] -GradientDefinition $gradientDef
|
||||
|
||||
$gradient = $ws.Cells["D1"].Style.Fill.Gradient
|
||||
$gradient.Type | Should -Be "Path"
|
||||
}
|
||||
}
|
||||
|
||||
Context "Integration Tests" {
|
||||
BeforeEach {
|
||||
$script:xl = Open-ExcelPackage -Path $testPath -Create
|
||||
$script:ws = Add-WorkSheet -ExcelPackage $xl -WorksheetName "GradientTest"
|
||||
}
|
||||
|
||||
AfterEach {
|
||||
Close-ExcelPackage -ExcelPackage $xl
|
||||
Remove-Item -Path $testPath -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
It "Should work with the original issue scenario" {
|
||||
# Reproduce the original issue scenario but with new functions
|
||||
Set-ExcelGradientFill -Range $ws.Cells["A1"] -Type Linear -Degree 90 -Color1 Blue -Color2 Green
|
||||
|
||||
# Get gradient info (which will have limited color info)
|
||||
$gradientInfo = Get-ExcelGradientFill -Range $ws.Cells["A1"]
|
||||
|
||||
# Should be able to copy geometric properties
|
||||
$gradientInfo.Type | Should -Be "Linear"
|
||||
$gradientInfo.Degree | Should -Be 90
|
||||
|
||||
# Should be able to create a complete gradient definition for copying
|
||||
$completeDef = @{
|
||||
Type = $gradientInfo.Type
|
||||
Degree = $gradientInfo.Degree
|
||||
Top = $gradientInfo.Top
|
||||
Bottom = $gradientInfo.Bottom
|
||||
Left = $gradientInfo.Left
|
||||
Right = $gradientInfo.Right
|
||||
Color1 = [System.Drawing.Color]::Blue # Need to specify colors
|
||||
Color2 = [System.Drawing.Color]::Green
|
||||
}
|
||||
|
||||
# Should be able to copy to another cell
|
||||
Copy-ExcelGradientFill -TargetRange $ws.Cells["B1"] -GradientDefinition $completeDef
|
||||
|
||||
$targetGradient = $ws.Cells["B1"].Style.Fill.Gradient
|
||||
$targetGradient.Type | Should -Be "Linear"
|
||||
$targetGradient.Degree | Should -Be 90
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user