1+ using System ;
2+ using DocumentFormat . OpenXml ;
3+ using DocumentFormat . OpenXml . Spreadsheet ;
4+
5+ namespace Openize . Cells
6+ {
7+ /// <summary>
8+ /// Provides extension methods for managing worksheet tab colors in Excel workbooks.
9+ /// </summary>
10+ public static class WorksheetColorExtensions
11+ {
12+ /// <summary>
13+ /// Sets the tab color for a worksheet using RGB values.
14+ /// </summary>
15+ /// <param name="worksheet">The worksheet to set the tab color for.</param>
16+ /// <param name="red">The red component (0-255).</param>
17+ /// <param name="green">The green component (0-255).</param>
18+ /// <param name="blue">The blue component (0-255).</param>
19+ /// <exception cref="ArgumentNullException">Thrown when worksheet is null.</exception>
20+ /// <exception cref="ArgumentOutOfRangeException">Thrown when color components are outside the valid range.</exception>
21+ public static void SetTabColor ( this Worksheet worksheet , byte red , byte green , byte blue )
22+ {
23+ if ( worksheet == null )
24+ throw new ArgumentNullException ( nameof ( worksheet ) ) ;
25+
26+ string hexColor = $ "{ red : X2} { green : X2} { blue : X2} ";
27+ SetTabColorByHex ( worksheet , hexColor ) ;
28+ }
29+
30+ /// <summary>
31+ /// Sets the tab color for a worksheet using an HTML-style hex color code.
32+ /// </summary>
33+ /// <param name="worksheet">The worksheet to set the tab color for.</param>
34+ /// <param name="hexColor">The hex color code (e.g., "FF0000" for red).</param>
35+ /// <exception cref="ArgumentNullException">Thrown when worksheet is null.</exception>
36+ /// <exception cref="ArgumentException">Thrown when hexColor is null, empty, or invalid.</exception>
37+ public static void SetTabColorByHex ( this Worksheet worksheet , string hexColor )
38+ {
39+ if ( worksheet == null )
40+ throw new ArgumentNullException ( nameof ( worksheet ) ) ;
41+
42+ if ( string . IsNullOrEmpty ( hexColor ) )
43+ throw new ArgumentException ( "Hex color cannot be null or empty." , nameof ( hexColor ) ) ;
44+
45+ // Strip # if present
46+ if ( hexColor . StartsWith ( "#" ) )
47+ hexColor = hexColor . Substring ( 1 ) ;
48+
49+ // Validate hex color format
50+ if ( ! IsValidHexColor ( hexColor ) )
51+ throw new ArgumentException ( "Invalid hex color format. Expected format: RRGGBB" , nameof ( hexColor ) ) ;
52+
53+ // Get access to the internal OpenXML worksheet
54+ var openXmlWorksheetPart = GetOpenXmlWorksheetPart ( worksheet ) ;
55+ if ( openXmlWorksheetPart == null )
56+ return ;
57+
58+ var openXmlWorksheet = openXmlWorksheetPart . Worksheet ;
59+
60+ // Get or create the SheetProperties element
61+ SheetProperties sheetProperties = openXmlWorksheet . GetFirstChild < SheetProperties > ( ) ;
62+ if ( sheetProperties == null )
63+ {
64+ sheetProperties = new SheetProperties ( ) ;
65+ openXmlWorksheet . InsertAt ( sheetProperties , 0 ) ;
66+ }
67+
68+ // Get or create the TabColor element
69+ TabColor tabColor = sheetProperties . GetFirstChild < TabColor > ( ) ;
70+ if ( tabColor == null )
71+ {
72+ tabColor = new TabColor ( ) ;
73+ sheetProperties . AppendChild ( tabColor ) ;
74+ }
75+
76+ // Set the RGB value
77+ tabColor . Rgb = hexColor ;
78+
79+ // Save the changes
80+ openXmlWorksheet . Save ( ) ;
81+ }
82+
83+ /// <summary>
84+ /// Gets the tab color of a worksheet as RGB values.
85+ /// </summary>
86+ /// <param name="worksheet">The worksheet to get the tab color from.</param>
87+ /// <param name="red">Output parameter to receive the red component.</param>
88+ /// <param name="green">Output parameter to receive the green component.</param>
89+ /// <param name="blue">Output parameter to receive the blue component.</param>
90+ /// <returns>True if a tab color is set; otherwise, false.</returns>
91+ /// <exception cref="ArgumentNullException">Thrown when worksheet is null.</exception>
92+ public static bool GetTabColor ( this Worksheet worksheet , out byte red , out byte green , out byte blue )
93+ {
94+ red = 0 ;
95+ green = 0 ;
96+ blue = 0 ;
97+
98+ if ( worksheet == null )
99+ throw new ArgumentNullException ( nameof ( worksheet ) ) ;
100+
101+ string hexColor = GetTabColorAsHex ( worksheet ) ;
102+ if ( string . IsNullOrEmpty ( hexColor ) )
103+ return false ;
104+
105+ // Parse the hex color
106+ red = Convert . ToByte ( hexColor . Substring ( 0 , 2 ) , 16 ) ;
107+ green = Convert . ToByte ( hexColor . Substring ( 2 , 2 ) , 16 ) ;
108+ blue = Convert . ToByte ( hexColor . Substring ( 4 , 2 ) , 16 ) ;
109+
110+ return true ;
111+ }
112+
113+ /// <summary>
114+ /// Gets the tab color of a worksheet as a hex color code.
115+ /// </summary>
116+ /// <param name="worksheet">The worksheet to get the tab color from.</param>
117+ /// <returns>The tab color as a hex color code, or null if no tab color is set.</returns>
118+ /// <exception cref="ArgumentNullException">Thrown when worksheet is null.</exception>
119+ public static string GetTabColorAsHex ( this Worksheet worksheet )
120+ {
121+ if ( worksheet == null )
122+ throw new ArgumentNullException ( nameof ( worksheet ) ) ;
123+
124+ // Get access to the internal OpenXML worksheet
125+ var openXmlWorksheetPart = GetOpenXmlWorksheetPart ( worksheet ) ;
126+ if ( openXmlWorksheetPart == null )
127+ return null ;
128+
129+ var openXmlWorksheet = openXmlWorksheetPart . Worksheet ;
130+
131+ // Check if tab color is set
132+ SheetProperties sheetProperties = openXmlWorksheet . GetFirstChild < SheetProperties > ( ) ;
133+ if ( sheetProperties == null )
134+ return null ;
135+
136+ TabColor tabColor = sheetProperties . GetFirstChild < TabColor > ( ) ;
137+ if ( tabColor == null || string . IsNullOrEmpty ( tabColor . Rgb ) )
138+ return null ;
139+
140+ return tabColor . Rgb ;
141+ }
142+
143+ /// <summary>
144+ /// Removes the tab color from a worksheet.
145+ /// </summary>
146+ /// <param name="worksheet">The worksheet to remove the tab color from.</param>
147+ /// <exception cref="ArgumentNullException">Thrown when worksheet is null.</exception>
148+ public static void RemoveTabColor ( this Worksheet worksheet )
149+ {
150+ if ( worksheet == null )
151+ throw new ArgumentNullException ( nameof ( worksheet ) ) ;
152+
153+ // Get access to the internal OpenXML worksheet
154+ var openXmlWorksheetPart = GetOpenXmlWorksheetPart ( worksheet ) ;
155+ if ( openXmlWorksheetPart == null )
156+ return ;
157+
158+ var openXmlWorksheet = openXmlWorksheetPart . Worksheet ;
159+
160+ // Check if tab color is set
161+ SheetProperties sheetProperties = openXmlWorksheet . GetFirstChild < SheetProperties > ( ) ;
162+ if ( sheetProperties == null )
163+ return ;
164+
165+ TabColor tabColor = sheetProperties . GetFirstChild < TabColor > ( ) ;
166+ if ( tabColor != null )
167+ {
168+ tabColor . Remove ( ) ;
169+ openXmlWorksheet . Save ( ) ;
170+ }
171+ }
172+
173+ /// <summary>
174+ /// Validates a hex color code.
175+ /// </summary>
176+ /// <param name="hexColor">The hex color code to validate.</param>
177+ /// <returns>True if the hex color code is valid; otherwise, false.</returns>
178+ private static bool IsValidHexColor ( string hexColor )
179+ {
180+ if ( string . IsNullOrEmpty ( hexColor ) )
181+ return false ;
182+
183+ // Standard hex color format is either RRGGBB or AARRGGBB
184+ return System . Text . RegularExpressions . Regex . IsMatch ( hexColor , "^[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?$" ) ;
185+ }
186+
187+ /// <summary>
188+ /// Gets the OpenXML worksheet part from a Worksheet object.
189+ /// </summary>
190+ /// <param name="worksheet">The worksheet to get the OpenXML part from.</param>
191+ /// <returns>The OpenXML worksheet part, or null if not available.</returns>
192+ private static DocumentFormat . OpenXml . Packaging . WorksheetPart GetOpenXmlWorksheetPart ( Worksheet worksheet )
193+ {
194+ // Use reflection to access the _worksheetPart field from the Worksheet class
195+ var fieldInfo = worksheet . GetType ( ) . GetField ( "_worksheetPart" , System . Reflection . BindingFlags . NonPublic | System . Reflection . BindingFlags . Instance ) ;
196+ if ( fieldInfo == null )
197+ return null ;
198+
199+ return fieldInfo . GetValue ( worksheet ) as DocumentFormat . OpenXml . Packaging . WorksheetPart ;
200+ }
201+ }
202+ }
0 commit comments