已验证 提交 05689d6a 编写于 作者: xurime's avatar xurime

This closes #1694, using namespace prefix in workbook theme XML

- Improve compatibility with the viewer which doesn't support default theme part namespace
- ref #1690, support read background color style, and conditional format with default pattern type
- Update the unit tests
上级 b52db71d
......@@ -47,7 +47,7 @@ type File struct {
Sheet sync.Map
SheetCount int
Styles *xlsxStyleSheet
Theme *xlsxTheme
Theme *decodeTheme
DecodeVMLDrawing map[string]*decodeVmlDrawing
VMLDrawing map[string]*vmlDrawing
WorkBook *xlsxWorkbook
......
......@@ -191,13 +191,11 @@ func (f *File) writeToZip(zw *zip.Writer) error {
return err
}
var from io.Reader
from, err = stream.rawData.Reader()
if err != nil {
if from, err = stream.rawData.Reader(); err != nil {
_ = stream.rawData.Close()
return err
}
_, err = io.Copy(fi, from)
if err != nil {
if _, err = io.Copy(fi, from); err != nil {
return err
}
}
......@@ -210,8 +208,7 @@ func (f *File) writeToZip(zw *zip.Writer) error {
return true
}
var fi io.Writer
fi, err = zw.Create(path.(string))
if err != nil {
if fi, err = zw.Create(path.(string)); err != nil {
return false
}
_, err = fi.Write(content.([]byte))
......@@ -222,8 +219,7 @@ func (f *File) writeToZip(zw *zip.Writer) error {
return true
}
var fi io.Writer
fi, err = zw.Create(path.(string))
if err != nil {
if fi, err = zw.Create(path.(string)); err != nil {
return false
}
_, err = fi.Write(f.readBytes(path.(string)))
......
......@@ -129,8 +129,67 @@ func (f *File) styleSheetWriter() {
// themeWriter provides a function to save xl/theme/theme1.xml after serialize
// structure.
func (f *File) themeWriter() {
newColor := func(c *decodeCTColor) xlsxCTColor {
return xlsxCTColor{
ScrgbClr: c.ScrgbClr,
SrgbClr: c.SrgbClr,
HslClr: c.HslClr,
SysClr: c.SysClr,
SchemeClr: c.SchemeClr,
PrstClr: c.PrstClr,
}
}
newFontScheme := func(c *decodeFontCollection) xlsxFontCollection {
return xlsxFontCollection{
Latin: c.Latin,
Ea: c.Ea,
Cs: c.Cs,
Font: c.Font,
ExtLst: c.ExtLst,
}
}
if f.Theme != nil {
output, _ := xml.Marshal(f.Theme)
output, _ := xml.Marshal(xlsxTheme{
XMLNSa: NameSpaceDrawingML.Value,
XMLNSr: SourceRelationship.Value,
Name: f.Theme.Name,
ThemeElements: xlsxBaseStyles{
ClrScheme: xlsxColorScheme{
Name: f.Theme.ThemeElements.ClrScheme.Name,
Dk1: newColor(&f.Theme.ThemeElements.ClrScheme.Dk1),
Lt1: newColor(&f.Theme.ThemeElements.ClrScheme.Lt1),
Dk2: newColor(&f.Theme.ThemeElements.ClrScheme.Dk2),
Lt2: newColor(&f.Theme.ThemeElements.ClrScheme.Lt2),
Accent1: newColor(&f.Theme.ThemeElements.ClrScheme.Accent1),
Accent2: newColor(&f.Theme.ThemeElements.ClrScheme.Accent2),
Accent3: newColor(&f.Theme.ThemeElements.ClrScheme.Accent3),
Accent4: newColor(&f.Theme.ThemeElements.ClrScheme.Accent4),
Accent5: newColor(&f.Theme.ThemeElements.ClrScheme.Accent5),
Accent6: newColor(&f.Theme.ThemeElements.ClrScheme.Accent6),
Hlink: newColor(&f.Theme.ThemeElements.ClrScheme.Hlink),
FolHlink: newColor(&f.Theme.ThemeElements.ClrScheme.FolHlink),
ExtLst: f.Theme.ThemeElements.ClrScheme.ExtLst,
},
FontScheme: xlsxFontScheme{
Name: f.Theme.ThemeElements.FontScheme.Name,
MajorFont: newFontScheme(&f.Theme.ThemeElements.FontScheme.MajorFont),
MinorFont: newFontScheme(&f.Theme.ThemeElements.FontScheme.MinorFont),
ExtLst: f.Theme.ThemeElements.FontScheme.ExtLst,
},
FmtScheme: xlsxStyleMatrix{
Name: f.Theme.ThemeElements.FmtScheme.Name,
FillStyleLst: f.Theme.ThemeElements.FmtScheme.FillStyleLst,
LnStyleLst: f.Theme.ThemeElements.FmtScheme.LnStyleLst,
EffectStyleLst: f.Theme.ThemeElements.FmtScheme.EffectStyleLst,
BgFillStyleLst: f.Theme.ThemeElements.FmtScheme.BgFillStyleLst,
},
ExtLst: f.Theme.ThemeElements.ExtLst,
},
ObjectDefaults: f.Theme.ObjectDefaults,
ExtraClrSchemeLst: f.Theme.ExtraClrSchemeLst,
CustClrLst: f.Theme.CustClrLst,
ExtLst: f.Theme.ExtLst,
})
f.saveFileList(defaultXMLPathTheme, f.replaceNameSpaceBytes(defaultXMLPathTheme, output))
}
}
......@@ -1284,6 +1343,9 @@ func (f *File) extractFills(fl *xlsxFill, s *xlsxStyleSheet, style *Style) {
if fl.PatternFill != nil {
fill.Type = "pattern"
fill.Pattern = inStrSlice(styleFillPatterns, fl.PatternFill.PatternType, false)
if fl.PatternFill.BgColor != nil {
fill.Color = []string{f.getThemeColor(fl.PatternFill.BgColor)}
}
if fl.PatternFill.FgColor != nil {
fill.Color = []string{f.getThemeColor(fl.PatternFill.FgColor)}
}
......@@ -1507,6 +1569,10 @@ func (f *File) GetConditionalStyle(idx int) (*Style, error) {
}
style = &Style{}
xf := s.Dxfs.Dxfs[idx]
// The default pattern fill type of conditional format style is solid
if xf.Fill != nil && xf.Fill.PatternFill != nil && xf.Fill.PatternFill.PatternType == "" {
xf.Fill.PatternFill.PatternType = "solid"
}
f.extractFills(xf.Fill, s, style)
f.extractBorders(xf.Border, s, style)
f.extractFont(xf.Font, s, style)
......@@ -3078,11 +3144,11 @@ func getPaletteColor(color string) string {
// themeReader provides a function to get the pointer to the xl/theme/theme1.xml
// structure after deserialization.
func (f *File) themeReader() (*xlsxTheme, error) {
func (f *File) themeReader() (*decodeTheme, error) {
if _, ok := f.Pkg.Load(defaultXMLPathTheme); !ok {
return nil, nil
}
theme := xlsxTheme{XMLNSa: NameSpaceDrawingML.Value, XMLNSr: SourceRelationship.Value}
theme := decodeTheme{}
if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLPathTheme)))).
Decode(&theme); err != nil && err != io.EOF {
return &theme, err
......
......@@ -391,6 +391,18 @@ func TestConditionalStyle(t *testing.T) {
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
_, err = f.GetConditionalStyle(1)
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
f = NewFile()
// Test get conditional style with background color and empty pattern type
idx, err = f.NewConditionalStyle(&Style{Fill: Fill{Type: "pattern", Color: []string{"FEC7CE"}, Pattern: 1}})
assert.NoError(t, err)
f.Styles.Dxfs.Dxfs[0].Fill.PatternFill.PatternType = ""
f.Styles.Dxfs.Dxfs[0].Fill.PatternFill.FgColor = nil
f.Styles.Dxfs.Dxfs[0].Fill.PatternFill.BgColor = &xlsxColor{Theme: intPtr(6)}
style, err = f.GetConditionalStyle(idx)
assert.NoError(t, err)
assert.Equal(t, "pattern", style.Fill.Type)
assert.Equal(t, []string{"A5A5A5"}, style.Fill.Color)
}
func TestGetDefaultFont(t *testing.T) {
......@@ -436,7 +448,7 @@ func TestThemeReader(t *testing.T) {
f.Pkg.Store(defaultXMLPathTheme, MacintoshCyrillicCharset)
theme, err := f.themeReader()
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
assert.EqualValues(t, &xlsxTheme{XMLNSa: NameSpaceDrawingML.Value, XMLNSr: SourceRelationship.Value}, theme)
assert.EqualValues(t, &decodeTheme{}, theme)
}
func TestSetCellStyle(t *testing.T) {
......
......@@ -16,15 +16,15 @@ import "encoding/xml"
// xlsxTheme directly maps the theme element in the namespace
// http://schemas.openxmlformats.org/drawingml/2006/main
type xlsxTheme struct {
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/drawingml/2006/main theme"`
XMLName xml.Name `xml:"a:theme"`
XMLNSa string `xml:"xmlns:a,attr"`
XMLNSr string `xml:"xmlns:r,attr"`
Name string `xml:"name,attr"`
ThemeElements xlsxBaseStyles `xml:"themeElements"`
ObjectDefaults xlsxObjectDefaults `xml:"objectDefaults"`
ExtraClrSchemeLst xlsxExtraClrSchemeLst `xml:"extraClrSchemeLst"`
CustClrLst *xlsxInnerXML `xml:"custClrLst"`
ExtLst *xlsxExtLst `xml:"extLst"`
ThemeElements xlsxBaseStyles `xml:"a:themeElements"`
ObjectDefaults xlsxObjectDefaults `xml:"a:objectDefaults"`
ExtraClrSchemeLst xlsxExtraClrSchemeLst `xml:"a:extraClrSchemeLst"`
CustClrLst *xlsxInnerXML `xml:"a:custClrLst"`
ExtLst *xlsxExtLst `xml:"a:extLst"`
}
// xlsxBaseStyles defines the theme elements for a theme, and is the workhorse
......@@ -33,40 +33,40 @@ type xlsxTheme struct {
// scheme, a font scheme, and a style matrix (format scheme) that defines
// different formatting options for different pieces of a document.
type xlsxBaseStyles struct {
ClrScheme xlsxColorScheme `xml:"clrScheme"`
FontScheme xlsxFontScheme `xml:"fontScheme"`
FmtScheme xlsxStyleMatrix `xml:"fmtScheme"`
ExtLst *xlsxExtLst `xml:"extLst"`
ClrScheme xlsxColorScheme `xml:"a:clrScheme"`
FontScheme xlsxFontScheme `xml:"a:fontScheme"`
FmtScheme xlsxStyleMatrix `xml:"a:fmtScheme"`
ExtLst *xlsxExtLst `xml:"a:extLst"`
}
// xlsxCTColor holds the actual color values that are to be applied to a given
// diagram and how those colors are to be applied.
type xlsxCTColor struct {
ScrgbClr *xlsxInnerXML `xml:"scrgbClr"`
SrgbClr *attrValString `xml:"srgbClr"`
HslClr *xlsxInnerXML `xml:"hslClr"`
SysClr *xlsxSysClr `xml:"sysClr"`
SchemeClr *xlsxInnerXML `xml:"schemeClr"`
PrstClr *xlsxInnerXML `xml:"prstClr"`
ScrgbClr *xlsxInnerXML `xml:"a:scrgbClr"`
SrgbClr *attrValString `xml:"a:srgbClr"`
HslClr *xlsxInnerXML `xml:"a:hslClr"`
SysClr *xlsxSysClr `xml:"a:sysClr"`
SchemeClr *xlsxInnerXML `xml:"a:schemeClr"`
PrstClr *xlsxInnerXML `xml:"a:prstClr"`
}
// xlsxColorScheme defines a set of colors for the theme. The set of colors
// consists of twelve color slots that can each hold a color of choice.
type xlsxColorScheme struct {
Name string `xml:"name,attr"`
Dk1 xlsxCTColor `xml:"dk1"`
Lt1 xlsxCTColor `xml:"lt1"`
Dk2 xlsxCTColor `xml:"dk2"`
Lt2 xlsxCTColor `xml:"lt2"`
Accent1 xlsxCTColor `xml:"accent1"`
Accent2 xlsxCTColor `xml:"accent2"`
Accent3 xlsxCTColor `xml:"accent3"`
Accent4 xlsxCTColor `xml:"accent4"`
Accent5 xlsxCTColor `xml:"accent5"`
Accent6 xlsxCTColor `xml:"accent6"`
Hlink xlsxCTColor `xml:"hlink"`
FolHlink xlsxCTColor `xml:"folHlink"`
ExtLst *xlsxExtLst `xml:"extLst"`
Dk1 xlsxCTColor `xml:"a:dk1"`
Lt1 xlsxCTColor `xml:"a:lt1"`
Dk2 xlsxCTColor `xml:"a:dk2"`
Lt2 xlsxCTColor `xml:"a:lt2"`
Accent1 xlsxCTColor `xml:"a:accent1"`
Accent2 xlsxCTColor `xml:"a:accent2"`
Accent3 xlsxCTColor `xml:"a:accent3"`
Accent4 xlsxCTColor `xml:"a:accent4"`
Accent5 xlsxCTColor `xml:"a:accent5"`
Accent6 xlsxCTColor `xml:"a:accent6"`
Hlink xlsxCTColor `xml:"a:hlink"`
FolHlink xlsxCTColor `xml:"a:folHlink"`
ExtLst *xlsxExtLst `xml:"a:extLst"`
}
// objectDefaults element allows for the definition of default shape, line,
......@@ -95,11 +95,11 @@ type xlsxCTSupplementalFont struct {
// Asian, and complex script. On top of these three definitions, one can also
// define a font for use in a specific language or languages.
type xlsxFontCollection struct {
Latin *xlsxCTTextFont `xml:"latin"`
Ea *xlsxCTTextFont `xml:"ea"`
Cs *xlsxCTTextFont `xml:"cs"`
Font []xlsxCTSupplementalFont `xml:"font"`
ExtLst *xlsxExtLst `xml:"extLst"`
Latin *xlsxCTTextFont `xml:"a:latin"`
Ea *xlsxCTTextFont `xml:"a:ea"`
Cs *xlsxCTTextFont `xml:"a:cs"`
Font []xlsxCTSupplementalFont `xml:"a:font"`
ExtLst *xlsxExtLst `xml:"a:extLst"`
}
// xlsxFontScheme element defines the font scheme within the theme. The font
......@@ -109,9 +109,9 @@ type xlsxFontCollection struct {
// paragraph areas.
type xlsxFontScheme struct {
Name string `xml:"name,attr"`
MajorFont xlsxFontCollection `xml:"majorFont"`
MinorFont xlsxFontCollection `xml:"minorFont"`
ExtLst *xlsxExtLst `xml:"extLst"`
MajorFont xlsxFontCollection `xml:"a:majorFont"`
MinorFont xlsxFontCollection `xml:"a:minorFont"`
ExtLst *xlsxExtLst `xml:"a:extLst"`
}
// xlsxStyleMatrix defines a set of formatting options, which can be referenced
......@@ -121,10 +121,10 @@ type xlsxFontScheme struct {
// change when the theme is changed.
type xlsxStyleMatrix struct {
Name string `xml:"name,attr,omitempty"`
FillStyleLst xlsxFillStyleLst `xml:"fillStyleLst"`
LnStyleLst xlsxLnStyleLst `xml:"lnStyleLst"`
EffectStyleLst xlsxEffectStyleLst `xml:"effectStyleLst"`
BgFillStyleLst xlsxBgFillStyleLst `xml:"bgFillStyleLst"`
FillStyleLst xlsxFillStyleLst `xml:"a:fillStyleLst"`
LnStyleLst xlsxLnStyleLst `xml:"a:lnStyleLst"`
EffectStyleLst xlsxEffectStyleLst `xml:"a:effectStyleLst"`
BgFillStyleLst xlsxBgFillStyleLst `xml:"a:bgFillStyleLst"`
}
// xlsxFillStyleLst element defines a set of three fill styles that are used
......@@ -161,3 +161,85 @@ type xlsxSysClr struct {
Val string `xml:"val,attr"`
LastClr string `xml:"lastClr,attr"`
}
// decodeTheme defines the structure used to parse the a:theme element for the
// theme.
type decodeTheme struct {
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/drawingml/2006/main theme"`
Name string `xml:"name,attr"`
ThemeElements decodeBaseStyles `xml:"themeElements"`
ObjectDefaults xlsxObjectDefaults `xml:"objectDefaults"`
ExtraClrSchemeLst xlsxExtraClrSchemeLst `xml:"extraClrSchemeLst"`
CustClrLst *xlsxInnerXML `xml:"custClrLst"`
ExtLst *xlsxExtLst `xml:"extLst"`
}
// decodeBaseStyles defines the structure used to parse the theme elements for a
// theme, and is the workhorse of the theme.
type decodeBaseStyles struct {
ClrScheme decodeColorScheme `xml:"clrScheme"`
FontScheme decodeFontScheme `xml:"fontScheme"`
FmtScheme decodeStyleMatrix `xml:"fmtScheme"`
ExtLst *xlsxExtLst `xml:"extLst"`
}
// decodeColorScheme defines the structure used to parse a set of colors for the
// theme.
type decodeColorScheme struct {
Name string `xml:"name,attr"`
Dk1 decodeCTColor `xml:"dk1"`
Lt1 decodeCTColor `xml:"lt1"`
Dk2 decodeCTColor `xml:"dk2"`
Lt2 decodeCTColor `xml:"lt2"`
Accent1 decodeCTColor `xml:"accent1"`
Accent2 decodeCTColor `xml:"accent2"`
Accent3 decodeCTColor `xml:"accent3"`
Accent4 decodeCTColor `xml:"accent4"`
Accent5 decodeCTColor `xml:"accent5"`
Accent6 decodeCTColor `xml:"accent6"`
Hlink decodeCTColor `xml:"hlink"`
FolHlink decodeCTColor `xml:"folHlink"`
ExtLst *xlsxExtLst `xml:"extLst"`
}
// decodeFontScheme defines the structure used to parse font scheme within the
// theme.
type decodeFontScheme struct {
Name string `xml:"name,attr"`
MajorFont decodeFontCollection `xml:"majorFont"`
MinorFont decodeFontCollection `xml:"minorFont"`
ExtLst *xlsxExtLst `xml:"extLst"`
}
// decodeFontCollection defines the structure used to parse a major and minor
// font which is used in the font scheme.
type decodeFontCollection struct {
Latin *xlsxCTTextFont `xml:"latin"`
Ea *xlsxCTTextFont `xml:"ea"`
Cs *xlsxCTTextFont `xml:"cs"`
Font []xlsxCTSupplementalFont `xml:"font"`
ExtLst *xlsxExtLst `xml:"extLst"`
}
// decodeCTColor defines the structure used to parse the actual color values
// that are to be applied to a given diagram and how those colors are to be
// applied.
type decodeCTColor struct {
ScrgbClr *xlsxInnerXML `xml:"scrgbClr"`
SrgbClr *attrValString `xml:"srgbClr"`
HslClr *xlsxInnerXML `xml:"hslClr"`
SysClr *xlsxSysClr `xml:"sysClr"`
SchemeClr *xlsxInnerXML `xml:"schemeClr"`
PrstClr *xlsxInnerXML `xml:"prstClr"`
}
// decodeStyleMatrix defines the structure used to parse a set of formatting
// options, which can be referenced by documents that apply a certain style to
// a given part of an object.
type decodeStyleMatrix struct {
Name string `xml:"name,attr,omitempty"`
FillStyleLst xlsxFillStyleLst `xml:"fillStyleLst"`
LnStyleLst xlsxLnStyleLst `xml:"lnStyleLst"`
EffectStyleLst xlsxEffectStyleLst `xml:"effectStyleLst"`
BgFillStyleLst xlsxBgFillStyleLst `xml:"bgFillStyleLst"`
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册