NanoXLSX.Reader 3.2.1
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 : IDocumentReader
27 {
28
29 private Stream stream;
30
31 #region properties
35 public virtual string DocumentType { get { return @"http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"; } }
36
40 public Workbook Workbook { get; set; }
44 public IOptions Options { get; set; }
48 public Action<Stream, Workbook, string, IOptions, int?> InlinePluginHandler { get; set; }
49 #endregion
50
51 #region constructors
55 internal ThemeReader()
56 {
57 }
58 #endregion
59
60 #region methods
68 public void Init(Stream stream, Workbook workbook, IOptions readerOptions, Action<Stream, Workbook, string, IOptions, int?> inlinePluginHandler)
69 {
70 this.stream = stream;
71 this.Workbook = workbook;
72 this.Options = readerOptions;
73 this.InlinePluginHandler = inlinePluginHandler;
74 }
75
80 public void Execute()
81 {
82 try
83 {
84 using (stream) // Close after processing
85 {
86 ColorScheme colorScheme = null;
87 using (XmlReader reader = XmlReader.Create(stream, XmlStreamUtils.CreateSettings()))
88 {
89 while (reader.Read())
90 {
91 if (reader.NodeType != XmlNodeType.Element)
92 {
93 continue;
94 }
95 if (XmlStreamUtils.IsElement(reader, "theme") && colorScheme == null)
96 {
97 string themeName = reader.GetAttribute("name");
98 Workbook.WorkbookTheme = new Theme(themeName);
99 colorScheme = new ColorScheme();
100 Workbook.WorkbookTheme.Colors = colorScheme;
101 }
102 else if (XmlStreamUtils.IsElement(reader, "clrScheme") && colorScheme != null)
103 {
104 ReadClrScheme(reader, colorScheme);
105 }
106 }
107 InlinePluginHandler?.Invoke(stream, Workbook, PlugInUUID.ThemeInlineReader, Options, null);
108 }
109 }
110 }
111 catch (Exception ex)
112 {
113 throw new IOException("The XML entry could not be read from the input stream. Please see the inner exception:", ex);
114 }
115 }
116
121 private static void ReadClrScheme(XmlReader reader, ColorScheme colorScheme)
122 {
123 colorScheme.Name = reader.GetAttribute("name") ?? string.Empty;
124 using (XmlReader subtree = reader.ReadSubtree())
125 {
126 subtree.Read(); // consume the <clrScheme> open tag
127 while (subtree.Read())
128 {
129 if (subtree.NodeType != XmlNodeType.Element)
130 {
131 continue;
132 }
133 string slot = subtree.LocalName;
134 IColor color = ReadColorEntry(subtree);
135 switch (slot)
136 {
137 case "dk1":
138 colorScheme.Dark1 = color;
139 break;
140 case "lt1":
141 colorScheme.Light1 = color;
142 break;
143 case "dk2":
144 colorScheme.Dark2 = color;
145 break;
146 case "lt2":
147 colorScheme.Light2 = color;
148 break;
149 case "accent1":
150 colorScheme.Accent1 = color;
151 break;
152 case "accent2":
153 colorScheme.Accent2 = color;
154 break;
155 case "accent3":
156 colorScheme.Accent3 = color;
157 break;
158 case "accent4":
159 colorScheme.Accent4 = color;
160 break;
161 case "accent5":
162 colorScheme.Accent5 = color;
163 break;
164 case "accent6":
165 colorScheme.Accent6 = color;
166 break;
167 case "hlink":
168 colorScheme.Hyperlink = color;
169 break;
170 case "folHlink":
171 colorScheme.FollowedHyperlink = color;
172 break;
173 }
174 }
175 }
176 }
177
183 private static IColor ReadColorEntry(XmlReader reader)
184 {
185 if (reader.IsEmptyElement)
186 {
187 return null;
188 }
189 int slotDepth = reader.Depth;
190 while (reader.Read())
191 {
192 if (reader.Depth == slotDepth)
193 {
194 break; // at the slot's end element — caller's Read() moves to next sibling
195 }
196 if (reader.NodeType == XmlNodeType.Element)
197 {
198 if (reader.LocalName.Equals("sysClr", StringComparison.OrdinalIgnoreCase))
199 {
200 string val = reader.GetAttribute("val");
201 SystemColor systemColor = new SystemColor
202 {
203 ColorValue = ParseSystemColor(val)
204 };
205 string lastColor = reader.GetAttribute("lastClr");
206 if (lastColor != null)
207 {
208 systemColor.LastColor = lastColor;
209 }
210 reader.Skip(); // advance past sysClr to the slot's end element
211 return systemColor;
212 }
213 else if (reader.LocalName.Equals("srgbClr", StringComparison.OrdinalIgnoreCase))
214 {
215 SrgbColor color = new SrgbColor
216 {
217 ColorValue = reader.GetAttribute("val")
218 };
219 reader.Skip(); // advance past srgbClr to the slot's end element
220 return color;
221 }
222 }
223 }
224 return null;
225 }
226
233 private static SystemColor.Value ParseSystemColor(string value)
234 {
235 if (string.IsNullOrEmpty(value))
236 {
237 throw new IOException("The system color entry was null or empty");
238 }
239 try
240 {
241 return SystemColor.MapStringToValue(value);
242 }
243 catch (Exception ex)
244 {
245 throw new IOException("The system color entry '" + value + "' could not be parsed", ex);
246 }
247 }
248 #endregion
249 }
250}
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).
virtual string DocumentType
Gets the relationship type URI of a theme document.
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