فهرست منبع

Initial support for themes

Right now this is only used to color cells that use theme colors
Brian Smith 10 سال پیش
والد
کامیت
be4c70439f
9فایلهای تغییر یافته به همراه388 افزوده شده و 19 حذف شده
  1. 2 1
      file.go
  2. 145 0
      hsl.go
  3. 29 3
      lib.go
  4. 4 4
      sheet_test.go
  5. 47 0
      theme.go
  6. 83 0
      theme_test.go
  7. 17 5
      xmlStyle.go
  8. 6 6
      xmlStyle_test.go
  9. 55 0
      xmlTheme.go

+ 2 - 1
file.go

@@ -18,6 +18,7 @@ type File struct {
 	styles         *xlsxStyleSheet
 	Sheets         []*Sheet
 	Sheet          map[string]*Sheet
+	theme          *theme
 }
 
 // Create a new File
@@ -170,7 +171,7 @@ func (f *File) MarshallParts() (map[string]string, error) {
 	sheetIndex := 1
 
 	if f.styles == nil {
-		f.styles = newXlsxStyleSheet()
+		f.styles = newXlsxStyleSheet(f.theme)
 	}
 	f.styles.reset()
 	for _, sheet := range f.Sheets {

+ 145 - 0
hsl.go

@@ -0,0 +1,145 @@
+/*
+Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+	 * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+	 * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+	 * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package xlsx
+
+import (
+	"image/color"
+	"math"
+)
+
+// HSLModel converts any color.Color to a HSL color.
+var HSLModel = color.ModelFunc(hslModel)
+
+// HSL represents a cylindrical coordinate of points in an RGB color model.
+//
+// Values are in the range 0 to 1.
+type HSL struct {
+	H, S, L float64
+}
+
+// RGBA returns the alpha-premultiplied red, green, blue and alpha values
+// for the HSL.
+func (c HSL) RGBA() (uint32, uint32, uint32, uint32) {
+	r, g, b := HSLToRGB(c.H, c.S, c.L)
+	return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff
+}
+
+// hslModel converts a color.Color to HSL.
+func hslModel(c color.Color) color.Color {
+	if _, ok := c.(HSL); ok {
+		return c
+	}
+	r, g, b, _ := c.RGBA()
+	h, s, l := RGBToHSL(uint8(r>>8), uint8(g>>8), uint8(b>>8))
+	return HSL{h, s, l}
+}
+
+// RGBToHSL converts an RGB triple to a HSL triple.
+//
+// Ported from http://goo.gl/Vg1h9
+func RGBToHSL(r, g, b uint8) (h, s, l float64) {
+	fR := float64(r) / 255
+	fG := float64(g) / 255
+	fB := float64(b) / 255
+	max := math.Max(math.Max(fR, fG), fB)
+	min := math.Min(math.Min(fR, fG), fB)
+	l = (max + min) / 2
+	if max == min {
+		// Achromatic.
+		h, s = 0, 0
+	} else {
+		// Chromatic.
+		d := max - min
+		if l > 0.5 {
+			s = d / (2.0 - max - min)
+		} else {
+			s = d / (max + min)
+		}
+		switch max {
+		case fR:
+			h = (fG - fB) / d
+			if fG < fB {
+				h += 6
+			}
+		case fG:
+			h = (fB-fR)/d + 2
+		case fB:
+			h = (fR-fG)/d + 4
+		}
+		h /= 6
+	}
+	return
+}
+
+// HSLToRGB converts an HSL triple to a RGB triple.
+//
+// Ported from http://goo.gl/Vg1h9
+func HSLToRGB(h, s, l float64) (r, g, b uint8) {
+	var fR, fG, fB float64
+	if s == 0 {
+		fR, fG, fB = l, l, l
+	} else {
+		var q float64
+		if l < 0.5 {
+			q = l * (1 + s)
+		} else {
+			q = l + s - s*l
+		}
+		p := 2*l - q
+		fR = hueToRGB(p, q, h+1.0/3)
+		fG = hueToRGB(p, q, h)
+		fB = hueToRGB(p, q, h-1.0/3)
+	}
+	r = uint8((fR * 255) + 0.5)
+	g = uint8((fG * 255) + 0.5)
+	b = uint8((fB * 255) + 0.5)
+	return
+}
+
+// hueToRGB is a helper function for HSLToRGB.
+func hueToRGB(p, q, t float64) float64 {
+	if t < 0 {
+		t += 1
+	}
+	if t > 1 {
+		t -= 1
+	}
+	if t < 1.0/6 {
+		return p + (q-p)*6*t
+	}
+	if t < 0.5 {
+		return q
+	}
+	if t < 2.0/3 {
+		return p + (q-p)*(2.0/3-t)*6
+	}
+	return p
+}

+ 29 - 3
lib.go

@@ -651,7 +651,7 @@ func readSharedStringsFromZipFile(f *zip.File) (*RefTable, error) {
 // readStylesFromZipFile() is an internal helper function to
 // extract a style table from the style.xml file within
 // the XLSX zip file.
-func readStylesFromZipFile(f *zip.File) (*xlsxStyleSheet, error) {
+func readStylesFromZipFile(f *zip.File, theme *theme) (*xlsxStyleSheet, error) {
 	var style *xlsxStyleSheet
 	var error error
 	var rc io.ReadCloser
@@ -660,7 +660,7 @@ func readStylesFromZipFile(f *zip.File) (*xlsxStyleSheet, error) {
 	if error != nil {
 		return nil, error
 	}
-	style = newXlsxStyleSheet()
+	style = newXlsxStyleSheet(theme)
 	decoder = xml.NewDecoder(rc)
 	error = decoder.Decode(style)
 	if error != nil {
@@ -677,6 +677,21 @@ func buildNumFmtRefTable(style *xlsxStyleSheet) {
 	}
 }
 
+func readThemeFromZipFile(f *zip.File) (*theme, error) {
+	rc, err := f.Open()
+	if err != nil {
+		return nil, err
+	}
+
+	var themeXml xlsxTheme
+	err = xml.NewDecoder(rc).Decode(&themeXml)
+	if err != nil {
+		return nil, err
+	}
+
+	return newTheme(themeXml), nil
+}
+
 type WorkBookRels map[string]string
 
 func (w *WorkBookRels) MakeXLSXWorkbookRels() xlsxWorkbookRels {
@@ -769,6 +784,7 @@ func ReadZipReader(r *zip.Reader) (*File, error) {
 	var sheets []*Sheet
 	var style *xlsxStyleSheet
 	var styles *zip.File
+	var themeFile *zip.File
 	var v *zip.File
 	var workbook *zip.File
 	var workbookRels *zip.File
@@ -787,6 +803,8 @@ func ReadZipReader(r *zip.Reader) (*File, error) {
 			workbookRels = v
 		case "xl/styles.xml":
 			styles = v
+		case "xl/theme/theme1.xml":
+			themeFile = v
 		default:
 			if len(v.Name) > 14 {
 				if v.Name[0:13] == "xl/worksheets" {
@@ -805,8 +823,16 @@ func ReadZipReader(r *zip.Reader) (*File, error) {
 		return nil, err
 	}
 	file.referenceTable = reftable
+	if themeFile != nil {
+		theme, err := readThemeFromZipFile(themeFile)
+		if err != nil {
+			return nil, err
+		}
+
+		file.theme = theme
+	}
 	if styles != nil {
-		style, err = readStylesFromZipFile(styles)
+		style, err = readStylesFromZipFile(styles, file.theme)
 		if err != nil {
 			return nil, err
 		}

+ 4 - 4
sheet_test.go

@@ -28,7 +28,7 @@ func (s *SheetSuite) TestMakeXLSXSheetFromRows(c *C) {
 	cell := row.AddCell()
 	cell.Value = "A cell!"
 	refTable := NewSharedStringRefTable()
-	styles := newXlsxStyleSheet()
+	styles := newXlsxStyleSheet(nil)
 	xSheet := sheet.makeXLSXSheet(refTable, styles)
 	c.Assert(xSheet.Dimension.Ref, Equals, "A1")
 	c.Assert(xSheet.SheetData.Row, HasLen, 1)
@@ -74,7 +74,7 @@ func (s *SheetSuite) TestMakeXLSXSheetAlsoPopulatesXLSXSTyles(c *C) {
 	cell2.SetStyle(style2)
 
 	refTable := NewSharedStringRefTable()
-	styles := newXlsxStyleSheet()
+	styles := newXlsxStyleSheet(nil)
 	worksheet := sheet.makeXLSXSheet(refTable, styles)
 
 	c.Assert(styles.Fonts.Count, Equals, 1)
@@ -116,7 +116,7 @@ func (s *SheetSuite) TestMarshalSheet(c *C) {
 	cell := row.AddCell()
 	cell.Value = "A cell!"
 	refTable := NewSharedStringRefTable()
-	styles := newXlsxStyleSheet()
+	styles := newXlsxStyleSheet(nil)
 	xSheet := sheet.makeXLSXSheet(refTable, styles)
 
 	output := bytes.NewBufferString(xml.Header)
@@ -139,7 +139,7 @@ func (s *SheetSuite) TestMarshalSheetWithMultipleCells(c *C) {
 	cell = row.AddCell()
 	cell.Value = "A cell (with value 2)!"
 	refTable := NewSharedStringRefTable()
-	styles := newXlsxStyleSheet()
+	styles := newXlsxStyleSheet(nil)
 	xSheet := sheet.makeXLSXSheet(refTable, styles)
 
 	output := bytes.NewBufferString(xml.Header)

+ 47 - 0
theme.go

@@ -0,0 +1,47 @@
+package xlsx
+
+import (
+	"fmt"
+	"strconv"
+)
+
+type theme struct {
+	colors []string
+}
+
+func newTheme(themeXml xlsxTheme) *theme {
+	clrMap := map[string]string{}
+	clrSchemes := themeXml.ThemeElements.ClrScheme.Children
+	for _, scheme := range clrSchemes {
+		var rgbColor string
+		if scheme.SysClr != nil {
+			rgbColor = scheme.SysClr.LastClr
+		} else {
+			rgbColor = scheme.SrgbClr.Val
+		}
+		clrMap[scheme.XMLName.Local] = rgbColor
+	}
+	colors := []string{clrMap["lt1"], clrMap["dk1"], clrMap["lt2"], clrMap["dk2"], clrMap["accent1"],
+					   clrMap["accent2"], clrMap["accent3"], clrMap["accent4"], clrMap["accent5"],
+					   clrMap["accent6"], clrMap["hlink"], clrMap["folHlink"]}
+	return &theme{colors}
+}
+
+func (t *theme) themeColor(index int64, tint float64) string {
+	baseColor := t.colors[index]
+	if tint == 0 {
+		return "FF" + baseColor
+	} else {
+		r, _ := strconv.ParseInt(baseColor[0:2], 16, 64)
+		g, _ := strconv.ParseInt(baseColor[2:4], 16, 64)
+		b, _ := strconv.ParseInt(baseColor[4:6], 16, 64)
+		h, s, l := RGBToHSL(uint8(r), uint8(g), uint8(b))
+		if tint < 0 {
+			l *= (1 + tint)
+		} else {
+			l = l*(1 - tint) + (1 - (1 - tint))
+		}
+		br, bg, bb := HSLToRGB(h, s, l)
+		return fmt.Sprintf("FF%02X%02X%02X", br, bg, bb)
+	}
+}

+ 83 - 0
theme_test.go

@@ -0,0 +1,83 @@
+package xlsx
+
+import (
+	"bytes"
+	"encoding/xml"
+
+	. "gopkg.in/check.v1"
+)
+
+type ThemeSuite struct{}
+
+var _ = Suite(&ThemeSuite{})
+
+func (s *ThemeSuite) TestThemeColors(c *C) {
+	themeXmlBytes := bytes.NewBufferString(`
+<?xml version="1.0"?>
+<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Office Theme">
+<a:themeElements>
+  <a:clrScheme name="Office">
+    <a:dk1>
+      <a:sysClr val="windowText" lastClr="000000"/>
+    </a:dk1>
+    <a:lt1>
+      <a:sysClr val="window" lastClr="FFFFFF"/>
+    </a:lt1>
+    <a:dk2>
+      <a:srgbClr val="1F497D"/>
+    </a:dk2>
+    <a:lt2>
+      <a:srgbClr val="EEECE1"/>
+    </a:lt2>
+    <a:accent1>
+      <a:srgbClr val="4F81BD"/>
+    </a:accent1>
+    <a:accent2>
+      <a:srgbClr val="C0504D"/>
+    </a:accent2>
+    <a:accent3>
+      <a:srgbClr val="9BBB59"/>
+    </a:accent3>
+    <a:accent4>
+      <a:srgbClr val="8064A2"/>
+    </a:accent4>
+    <a:accent5>
+      <a:srgbClr val="4BACC6"/>
+    </a:accent5>
+    <a:accent6>
+      <a:srgbClr val="F79646"/>
+    </a:accent6>
+    <a:hlink>
+      <a:srgbClr val="0000FF"/>
+    </a:hlink>
+    <a:folHlink>
+      <a:srgbClr val="800080"/>
+    </a:folHlink>
+  </a:clrScheme>
+</a:themeElements>
+</a:theme>
+	`)
+	var themeXml xlsxTheme
+	err := xml.NewDecoder(themeXmlBytes).Decode(&themeXml)
+	c.Assert(err, IsNil)
+
+	clrSchemes := themeXml.ThemeElements.ClrScheme.Children
+	c.Assert(len(clrSchemes), Equals, 12)
+
+	dk1Scheme := clrSchemes[0]
+	c.Assert(dk1Scheme.XMLName.Local, Equals, "dk1")
+	c.Assert(dk1Scheme.SrgbClr, IsNil)
+	c.Assert(dk1Scheme.SysClr, NotNil)
+	c.Assert(dk1Scheme.SysClr.Val, Equals, "windowText")
+	c.Assert(dk1Scheme.SysClr.LastClr, Equals, "000000")
+
+	dk2Scheme := clrSchemes[2]
+	c.Assert(dk2Scheme.XMLName.Local, Equals, "dk2")
+	c.Assert(dk2Scheme.SysClr, IsNil)
+	c.Assert(dk2Scheme.SrgbClr, NotNil)
+	c.Assert(dk2Scheme.SrgbClr.Val, Equals, "1F497D")
+
+	theme := newTheme(themeXml)
+	c.Assert(theme.themeColor(0, 0), Equals, "FFFFFFFF")
+	c.Assert(theme.themeColor(2, 0), Equals, "FFEEECE1")
+}

+ 17 - 5
xmlStyle.go

@@ -29,13 +29,15 @@ type xlsxStyleSheet struct {
 	CellXfs      xlsxCellXfs      `xml:"cellXfs,omitempty"`
 	NumFmts      xlsxNumFmts      `xml:"numFmts,omitempty"`
 
+	theme      *theme
 	styleCache map[int]*Style // `-`
 	numFmtRefTable map[int]xlsxNumFmt `xml:"-"`
 	lock       *sync.RWMutex
 }
 
-func newXlsxStyleSheet() *xlsxStyleSheet {
+func newXlsxStyleSheet(t *theme) *xlsxStyleSheet {
 	stylesheet := new(xlsxStyleSheet)
+	stylesheet.theme = t
 	stylesheet.styleCache = make(map[int]*Style)
 	stylesheet.lock = new(sync.RWMutex)
 	return stylesheet
@@ -91,8 +93,8 @@ func (styles *xlsxStyleSheet) getStyle(styleIndex int) (style *Style) {
 		if xf.FillId > -1 && xf.FillId < styles.Fills.Count {
 			xFill := styles.Fills.Fill[xf.FillId]
 			style.Fill.PatternType = xFill.PatternFill.PatternType
-			style.Fill.FgColor = xFill.PatternFill.FgColor.RGB
-			style.Fill.BgColor = xFill.PatternFill.BgColor.RGB
+			style.Fill.FgColor = styles.argbValue(xFill.PatternFill.FgColor)
+			style.Fill.BgColor = styles.argbValue(xFill.PatternFill.BgColor)
 		}
 
 		if xf.FontId > -1 && xf.FontId < styles.Fonts.Count {
@@ -101,7 +103,7 @@ func (styles *xlsxStyleSheet) getStyle(styleIndex int) (style *Style) {
 			style.Font.Name = xfont.Name.Val
 			style.Font.Family, _ = strconv.Atoi(xfont.Family.Val)
 			style.Font.Charset, _ = strconv.Atoi(xfont.Charset.Val)
-			style.Font.Color = xfont.Color.RGB
+			style.Font.Color = styles.argbValue(xfont.Color)
 
 			if xfont.B != nil {
 				style.Font.Bold = true
@@ -123,6 +125,14 @@ func (styles *xlsxStyleSheet) getStyle(styleIndex int) (style *Style) {
 	return style
 }
 
+func (styles *xlsxStyleSheet) argbValue(color xlsxColor) string {
+	if color.Theme != nil && styles.theme != nil {
+		return styles.theme.themeColor(int64(*color.Theme), color.Tint)
+	} else {
+		return color.RGB
+	}
+}
+
 // Excel styles can reference number formats that are built-in, all of which
 // have an id less than 164. This is a possibly incomplete list comprised of as
 // many of them as I could find.
@@ -577,7 +587,9 @@ func (patternFill *xlsxPatternFill) Marshal() (result string, err error) {
 // currently I have not checked it for completeness - it does as much
 // as I need.
 type xlsxColor struct {
-	RGB string `xml:"rgb,attr,omitempty"`
+	RGB   string  `xml:"rgb,attr,omitempty"`
+	Theme *int    `xml:"theme,attr,omitempty"`
+	Tint  float64 `xml:"tint,attr,omitempty"`
 }
 
 func (color *xlsxColor) Equals(other xlsxColor) bool {

+ 6 - 6
xmlStyle_test.go

@@ -10,7 +10,7 @@ var _ = Suite(&XMLStyleSuite{})
 
 // Test we produce valid output for an empty style file.
 func (x *XMLStyleSuite) TestMarshalEmptyXlsxStyleSheet(c *C) {
-	styles := newXlsxStyleSheet()
+	styles := newXlsxStyleSheet(nil)
 	result, err := styles.Marshal()
 	c.Assert(err, IsNil)
 	c.Assert(string(result), Equals, `<?xml version="1.0" encoding="UTF-8"?>
@@ -19,7 +19,7 @@ func (x *XMLStyleSuite) TestMarshalEmptyXlsxStyleSheet(c *C) {
 
 // Test we produce valid output for a style file with one font definition.
 func (x *XMLStyleSuite) TestMarshalXlsxStyleSheetWithAFont(c *C) {
-	styles := newXlsxStyleSheet()
+	styles := newXlsxStyleSheet(nil)
 	styles.Fonts = xlsxFonts{}
 	styles.Fonts.Count = 1
 	styles.Fonts.Font = make([]xlsxFont, 1)
@@ -37,7 +37,7 @@ func (x *XMLStyleSuite) TestMarshalXlsxStyleSheetWithAFont(c *C) {
 
 // Test we produce valid output for a style file with one fill definition.
 func (x *XMLStyleSuite) TestMarshalXlsxStyleSheetWithAFill(c *C) {
-	styles := newXlsxStyleSheet()
+	styles := newXlsxStyleSheet(nil)
 	styles.Fills = xlsxFills{}
 	styles.Fills.Count = 1
 	styles.Fills.Fill = make([]xlsxFill, 1)
@@ -58,7 +58,7 @@ func (x *XMLStyleSuite) TestMarshalXlsxStyleSheetWithAFill(c *C) {
 
 // Test we produce valid output for a style file with one border definition.
 func (x *XMLStyleSuite) TestMarshalXlsxStyleSheetWithABorder(c *C) {
-	styles := newXlsxStyleSheet()
+	styles := newXlsxStyleSheet(nil)
 	styles.Borders = xlsxBorders{}
 	styles.Borders.Count = 1
 	styles.Borders.Border = make([]xlsxBorder, 1)
@@ -76,7 +76,7 @@ func (x *XMLStyleSuite) TestMarshalXlsxStyleSheetWithABorder(c *C) {
 
 // Test we produce valid output for a style file with one cellStyleXf definition.
 func (x *XMLStyleSuite) TestMarshalXlsxStyleSheetWithACellStyleXf(c *C) {
-	styles := newXlsxStyleSheet()
+	styles := newXlsxStyleSheet(nil)
 	styles.CellStyleXfs = xlsxCellStyleXfs{}
 	styles.CellStyleXfs.Count = 1
 	styles.CellStyleXfs.Xf = make([]xlsxXf, 1)
@@ -109,7 +109,7 @@ func (x *XMLStyleSuite) TestMarshalXlsxStyleSheetWithACellStyleXf(c *C) {
 // Test we produce valid output for a style file with one cellXf
 // definition.
 func (x *XMLStyleSuite) TestMarshalXlsxStyleSheetWithACellXf(c *C) {
-	styles := newXlsxStyleSheet()
+	styles := newXlsxStyleSheet(nil)
 	styles.CellXfs = xlsxCellXfs{}
 	styles.CellXfs.Count = 1
 	styles.CellXfs.Xf = make([]xlsxXf, 1)

+ 55 - 0
xmlTheme.go

@@ -0,0 +1,55 @@
+package xlsx
+
+import "encoding/xml"
+
+// xlsxTheme directly maps the theme element in the namespace
+// http://schemas.openxmlformats.org/drawingml/2006/main -
+// currently I have not checked it for completeness - it does as much
+// as I need.
+type xlsxTheme struct {
+	ThemeElements xlsxThemeElements `xml:"themeElements"`
+}
+
+// xlsxThemeElements directly maps the themeElements element in the namespace
+// http://schemas.openxmlformats.org/drawingml/2006/main -
+// currently I have not checked it for completeness - it does as much
+// as I need.
+type xlsxThemeElements struct {
+	ClrScheme xlsxClrScheme `xml:"clrScheme"`
+}
+
+// xlsxClrScheme directly maps the clrScheme element in the namespace
+// http://schemas.openxmlformats.org/drawingml/2006/main -
+// currently I have not checked it for completeness - it does as much
+// as I need.
+type xlsxClrScheme struct {
+	Name     string            `xml:"name,attr"`
+	Children []xlsxClrSchemeEl `xml:",any"`
+}
+
+// xlsxClrScheme maps to children of the clrScheme element in the namespace
+// http://schemas.openxmlformats.org/drawingml/2006/main -
+// currently I have not checked it for completeness - it does as much
+// as I need.
+type xlsxClrSchemeEl struct {
+	XMLName xml.Name
+	SysClr  *xlsxSysClr  `xml:"sysClr"`
+	SrgbClr *xlsxSrgbClr `xml:"srgbClr"`
+}
+
+// xlsxSysClr directly maps the sysClr element in the namespace
+// http://schemas.openxmlformats.org/drawingml/2006/main -
+// currently I have not checked it for completeness - it does as much
+// as I need.
+type xlsxSysClr struct {
+	Val     string `xml:"val,attr"`
+	LastClr string `xml:"lastClr,attr"`
+}
+
+// xlsxSrgbClr directly maps the srgbClr element in the namespace
+// http://schemas.openxmlformats.org/drawingml/2006/main -
+// currently I have not checked it for completeness - it does as much
+// as I need.
+type xlsxSrgbClr struct {
+	Val string `xml:"val,attr"`
+}