NanoXLSX.Reader 3.1.0
Loading...
Searching...
No Matches
ThemeReader.cs
1/*
2 * NanoXLSX is a small .NET library to generate and read XLSX (Microsoft Excel 2007 or newer) files in an easy and native way
3 * Copyright Raphael Stoeckli © 2026
4 * This library is licensed under the MIT License.
5 * You find a copy of the license in project folder or on: http://opensource.org/licenses/MIT
6 */
7
8using System;
9using System.IO;
10using System.Xml;
11using NanoXLSX.Colors;
12using NanoXLSX.Interfaces;
13using NanoXLSX.Interfaces.Reader;
14using NanoXLSX.Registry;
15using NanoXLSX.Registry.Attributes;
16using NanoXLSX.Themes;
17using NanoXLSX.Utils.Xml;
18using IOException = NanoXLSX.Exceptions.IOException;
19
21{
25 [NanoXlsxPlugIn(PlugInUUID = PlugInUUID.ThemeReader)]
26 public class ThemeReader : IPluginBaseReader
27 {
28
29 private Stream stream;
30
31 #region properties
35 public Workbook Workbook { get; set; }
39 public IOptions Options { get; set; }
43 public Action<Stream, Workbook, string, IOptions, int?> InlinePluginHandler { get; set; }
44 #endregion
45
46 #region constructors
50 internal ThemeReader()
51 {
52 }
53 #endregion
54
55 #region methods
63 public void Init(Stream stream, Workbook workbook, IOptions readerOptions, Action<Stream, Workbook, string, IOptions, int?> inlinePluginHandler)
64 {
65 this.stream = stream;
66 this.Workbook = workbook;
67 this.Options = readerOptions;
68 this.InlinePluginHandler = inlinePluginHandler;
69 }
70
75 public void Execute()
76 {
77 try
78 {
79 using (stream) // Close after processing
80 {
81 ColorScheme colorScheme = null;
82 using (XmlReader reader = XmlReader.Create(stream, XmlStreamUtils.CreateSettings()))
83 {
84 while (reader.Read())
85 {
86 if (reader.NodeType != XmlNodeType.Element)
87 {
88 continue;
89 }
90 if (XmlStreamUtils.IsElement(reader, "theme") && colorScheme == null)
91 {
92 string themeName = reader.GetAttribute("name");
93 Workbook.WorkbookTheme = new Theme(themeName);
94 colorScheme = new ColorScheme();
95 Workbook.WorkbookTheme.Colors = colorScheme;
96 }
97 else if (XmlStreamUtils.IsElement(reader, "clrScheme") && colorScheme != null)
98 {
99 ReadClrScheme(reader, colorScheme);
100 }
101 }
102 InlinePluginHandler?.Invoke(stream, Workbook, PlugInUUID.ThemeInlineReader, Options, null);
103 }
104 }
105 }
106 catch (Exception ex)
107 {
108 throw new IOException("The XML entry could not be read from the input stream. Please see the inner exception:", ex);
109 }
110 }
111
116 private static void ReadClrScheme(XmlReader reader, ColorScheme colorScheme)
117 {
118 colorScheme.Name = reader.GetAttribute("name") ?? string.Empty;
119 using (XmlReader subtree = reader.ReadSubtree())
120 {
121 subtree.Read(); // consume the <clrScheme> open tag
122 while (subtree.Read())
123 {
124 if (subtree.NodeType != XmlNodeType.Element)
125 {
126 continue;
127 }
128 string slot = subtree.LocalName;
129 IColor color = ReadColorEntry(subtree);
130 switch (slot)
131 {
132 case "dk1":
133 colorScheme.Dark1 = color;
134 break;
135 case "lt1":
136 colorScheme.Light1 = color;
137 break;
138 case "dk2":
139 colorScheme.Dark2 = color;
140 break;
141 case "lt2":
142 colorScheme.Light2 = color;
143 break;
144 case "accent1":
145 colorScheme.Accent1 = color;
146 break;
147 case "accent2":
148 colorScheme.Accent2 = color;
149 break;
150 case "accent3":
151 colorScheme.Accent3 = color;
152 break;
153 case "accent4":
154 colorScheme.Accent4 = color;
155 break;
156 case "accent5":
157 colorScheme.Accent5 = color;
158 break;
159 case "accent6":
160 colorScheme.Accent6 = color;
161 break;
162 case "hlink":
163 colorScheme.Hyperlink = color;
164 break;
165 case "folHlink":
166 colorScheme.FollowedHyperlink = color;
167 break;
168 }
169 }
170 }
171 }
172
178 private static IColor ReadColorEntry(XmlReader reader)
179 {
180 if (reader.IsEmptyElement)
181 {
182 return null;
183 }
184 int slotDepth = reader.Depth;
185 while (reader.Read())
186 {
187 if (reader.Depth == slotDepth)
188 {
189 break; // at the slot's end element — caller's Read() moves to next sibling
190 }
191 if (reader.NodeType == XmlNodeType.Element)
192 {
193 if (reader.LocalName.Equals("sysClr", StringComparison.OrdinalIgnoreCase))
194 {
195 string val = reader.GetAttribute("val");
196 SystemColor systemColor = new SystemColor
197 {
198 ColorValue = ParseSystemColor(val)
199 };
200 string lastColor = reader.GetAttribute("lastClr");
201 if (lastColor != null)
202 {
203 systemColor.LastColor = lastColor;
204 }
205 reader.Skip(); // advance past sysClr to the slot's end element
206 return systemColor;
207 }
208 else if (reader.LocalName.Equals("srgbClr", StringComparison.OrdinalIgnoreCase))
209 {
210 SrgbColor color = new SrgbColor
211 {
212 ColorValue = reader.GetAttribute("val")
213 };
214 reader.Skip(); // advance past srgbClr to the slot's end element
215 return color;
216 }
217 }
218 }
219 return null;
220 }
221
228 private static SystemColor.Value ParseSystemColor(string value)
229 {
230 if (string.IsNullOrEmpty(value))
231 {
232 throw new IOException("The system color entry was null or empty");
233 }
234 try
235 {
236 return SystemColor.MapStringToValue(value);
237 }
238 catch (Exception ex)
239 {
240 throw new IOException("The system color entry '" + value + "' could not be parsed", ex);
241 }
242 }
243 #endregion
244 }
245}
Class representing a reader for theme definitions of XLSX files.
void Init(Stream stream, Workbook workbook, IOptions readerOptions, Action< Stream, Workbook, string, IOptions, int?> inlinePluginHandler)
Initialization method (interface implementation).
void Execute()
Method to execute the main logic of the plug-in (interface implementation).
Workbook Workbook
Workbook reference where read data is stored (should not be null).
Action< Stream, Workbook, string, IOptions, int?> InlinePluginHandler
Reference to the ReaderPlugInHandler, to be used for post operations in the Execute method.
IOptions Options
Reader options.
Exceptions.IOException IOException