1
0
mirror of https://github.com/fumiama/go-docx.git synced 2026-06-17 15:30:27 +08:00

feat: add shade effect

This commit is contained in:
源文雨
2023-02-26 15:01:17 +08:00
parent 592c7b5d13
commit 0e18f8a163
11 changed files with 154 additions and 80 deletions

View File

@@ -25,7 +25,6 @@ func (r *Run) Color(color string) *Run {
r.RunProperties.Color = &Color{ r.RunProperties.Color = &Color{
Val: color, Val: color,
} }
return r return r
} }
@@ -34,7 +33,16 @@ func (r *Run) Size(size string) *Run {
r.RunProperties.Size = &Size{ r.RunProperties.Size = &Size{
Val: size, Val: size,
} }
return r
}
// Shade allows to set run shade
func (r *Run) Shade(val, color, fill string) *Run {
r.RunProperties.Shade = &Shade{
Val: val,
Color: color,
Fill: fill,
}
return r return r
} }

View File

@@ -158,3 +158,13 @@ func (w *WTableRow) Justification(val string) *WTableRow {
w.TableRowProperties.Justification.Val = val w.TableRowProperties.Justification.Val = val
return w return w
} }
// Shade allows to set cell's shade
func (c *WTableCell) Shade(val, color, fill string) *WTableCell {
c.TableCellProperties.Shade = &Shade{
Val: val,
Color: color,
Fill: fill,
}
return c
}

View File

@@ -51,9 +51,10 @@ func main() {
r.Children[0].(*docx.Drawing).Anchor.PositionH.PosOffset = r.Children[0].(*docx.Drawing).Anchor.Extent.CX r.Children[0].(*docx.Drawing).Anchor.PositionH.PosOffset = r.Children[0].(*docx.Drawing).Anchor.Extent.CX
r.Children[0].(*docx.Drawing).Anchor.Graphic.GraphicData.Pic.BlipFill.Blip.AlphaModFix = &docx.AAlphaModFix{Amount: 50000} r.Children[0].(*docx.Drawing).Anchor.Graphic.GraphicData.Pic.BlipFill.Blip.AlphaModFix = &docx.AAlphaModFix{Amount: 50000}
// add text // add text
para1.AddText("test") para1.AddText("test").AddTab()
para1.AddText("test font size").Size("44") para1.AddText("test font size").Size("44").AddTab()
para1.AddText("test color").Color("808080") para1.AddText("test color").Color("808080").AddTab()
para1.AddText("test shade").Shade("clear", "auto", "E7E6E6").AddTab()
para2 := w.AddParagraph().Justification("end") para2 := w.AddParagraph().Justification("end")
para2.AddText("test font size and color").Size("44").Color("ff0000") para2.AddText("test font size and color").Size("44").Color("ff0000")
@@ -88,10 +89,16 @@ func main() {
panic(err) panic(err)
} }
tbl1 := w.AddTable(3, 2) w.AddParagraph()
tbl1 := w.AddTable(9, 9)
for x, r := range tbl1.TableRows { for x, r := range tbl1.TableRows {
red := (x + 1) * 28
for y, c := range r.TableCells { for y, c := range r.TableCells {
c.AddParagraph().AddText(fmt.Sprintf("(%d, %d)", x, y)) green := ((y + 1) / 3) * 85
blue := (y%3 + 1) * 85
v := fmt.Sprintf("%02X%02X%02X", red, green, blue)
c.Shade("clear", "auto", v).AddParagraph().AddText(v).Size("18")
} }
} }
@@ -105,6 +112,7 @@ func main() {
c.AddParagraph().Justification("center").AddText(fmt.Sprintf("(%d, %d)", x, y)) c.AddParagraph().Justification("center").AddText(fmt.Sprintf("(%d, %d)", x, y))
} }
} }
tbl2.TableRows[0].TableCells[0].Shade("clear", "auto", "E7E6E6")
f, err := os.Create(*fileLocation) f, err := os.Create(*fileLocation)
if err != nil { if err != nil {

View File

@@ -236,10 +236,7 @@ func (r *WPExtent) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
} }
// Consume the end element // Consume the end element
_, err = d.Token() _, err = d.Token()
if err != nil { return err
return err
}
return nil
} }
// WPEffectExtent represents the effect extent of a drawing in a Word document. // WPEffectExtent represents the effect extent of a drawing in a Word document.
@@ -280,10 +277,7 @@ func (r *WPEffectExtent) UnmarshalXML(d *xml.Decoder, start xml.StartElement) er
} }
// Consume the end element // Consume the end element
_, err = d.Token() _, err = d.Token()
if err != nil { return err
return err
}
return nil
} }
// WPDocPr represents the document properties of a drawing in a Word document. // WPDocPr represents the document properties of a drawing in a Word document.
@@ -312,10 +306,7 @@ func (r *WPDocPr) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
} }
// Consume the end element // Consume the end element
_, err := d.Token() _, err := d.Token()
if err != nil { return err
return err
}
return nil
} }
// WPCNvGraphicFramePr represents the non-visual properties of a graphic frame. // WPCNvGraphicFramePr represents the non-visual properties of a graphic frame.

View File

@@ -33,7 +33,7 @@ func TestDrawingStructure(t *testing.T) {
// add new paragraph // add new paragraph
para1 := w.AddParagraph() para1 := w.AddParagraph()
// add text // add text
para1.AddText("直接粘贴 inline").AddTab() para1.AddText("直接粘贴 inline").Shade("clear", "auto", "E7E6E6").AddTab()
r, err := para1.AddAnchorDrawingFrom("testdata/fumiama.JPG") r, err := para1.AddAnchorDrawingFrom("testdata/fumiama.JPG")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

74
structeffects.go Normal file
View File

@@ -0,0 +1,74 @@
package docx
import "encoding/xml"
// RunStyle contains styling for a run
type RunStyle struct {
XMLName xml.Name `xml:"w:rStyle,omitempty"`
Val string `xml:"w:val,attr"`
}
// Style contains styling for a paragraph
type Style struct {
XMLName xml.Name `xml:"w:pStyle,omitempty"`
Val string `xml:"w:val,attr"`
}
// Color contains the sound of music. :D
// I'm kidding. It contains the color
type Color struct {
XMLName xml.Name `xml:"w:color,omitempty"`
Val string `xml:"w:val,attr"`
}
// Size contains the font size
type Size struct {
XMLName xml.Name `xml:"w:sz,omitempty"`
Val string `xml:"w:val,attr"`
}
// Justification contains the way of the horizonal alignment
//
// w:jc 属性的取值可以是以下之一:
// start左对齐。
// center居中对齐。
// end右对齐。
// both两端对齐。
// distribute分散对齐。
type Justification struct {
XMLName xml.Name `xml:"w:jc,omitempty"`
Val string `xml:"w:val,attr"`
}
// Shade is an element that represents a shading pattern applied to a document element.
type Shade struct {
XMLName xml.Name `xml:"w:shd,omitempty"`
Val string `xml:"w:val,attr,omitempty"`
Color string `xml:"w:color,attr,omitempty"`
Fill string `xml:"w:fill,attr,omitempty"`
ThemeFill string `xml:"w:themeFill,attr,omitempty"`
ThemeFillTint string `xml:"w:themeFillTint,attr,omitempty"`
}
// UnmarshalXML ...
func (s *Shade) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
for _, attr := range start.Attr {
switch attr.Name.Local {
case "val":
s.Val = attr.Value
case "color":
s.Color = attr.Value
case "fill":
s.Fill = attr.Value
case "themeFill":
s.ThemeFill = attr.Value
case "themeFillTint":
s.ThemeFillTint = attr.Value
default:
// ignore other attributes
}
}
// Consume the end element
_, err := d.Token()
return err
}

View File

@@ -30,8 +30,9 @@ import (
// ParagraphProperties <w:pPr> // ParagraphProperties <w:pPr>
type ParagraphProperties struct { type ParagraphProperties struct {
XMLName xml.Name `xml:"w:pPr,omitempty"` XMLName xml.Name `xml:"w:pPr,omitempty"`
Justification *Justification `xml:"w:jc,omitempty"` Justification *Justification
Shade *Shade
} }
// UnmarshalXML ... // UnmarshalXML ...
@@ -48,6 +49,13 @@ func (p *ParagraphProperties) UnmarshalXML(d *xml.Decoder, start xml.StartElemen
switch tt.Name.Local { switch tt.Name.Local {
case "jc": case "jc":
p.Justification = &Justification{Val: getAtt(tt.Attr, "val")} p.Justification = &Justification{Val: getAtt(tt.Attr, "val")}
case "shd":
var value Shade
err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
p.Shade = &value
default: default:
err = d.Skip() // skip unsupported tags err = d.Skip() // skip unsupported tags
if err != nil { if err != nil {

View File

@@ -106,11 +106,12 @@ type WTab struct {
// RunProperties encapsulates visual properties of a run // RunProperties encapsulates visual properties of a run
type RunProperties struct { type RunProperties struct {
XMLName xml.Name `xml:"w:rPr,omitempty"` XMLName xml.Name `xml:"w:rPr,omitempty"`
Color *Color `xml:"w:color,omitempty"` Color *Color
Size *Size `xml:"w:sz,omitempty"` Size *Size
RunStyle *RunStyle `xml:"w:rStyle,omitempty"` RunStyle *RunStyle
Style *Style `xml:"w:pStyle,omitempty"` Style *Style
Shade *Shade
} }
// UnmarshalXML ... // UnmarshalXML ...
@@ -142,6 +143,13 @@ func (r *RunProperties) UnmarshalXML(d *xml.Decoder, start xml.StartElement) err
var value Style var value Style
value.Val = getAtt(tt.Attr, "val") value.Val = getAtt(tt.Attr, "val")
r.Style = &value r.Style = &value
case "shd":
var value Shade
err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
r.Shade = &value
default: default:
err = d.Skip() // skip unsupported tags err = d.Skip() // skip unsupported tags
if err != nil { if err != nil {
@@ -154,41 +162,3 @@ func (r *RunProperties) UnmarshalXML(d *xml.Decoder, start xml.StartElement) err
return nil return nil
} }
// RunStyle contains styling for a run
type RunStyle struct {
XMLName xml.Name `xml:"w:rStyle,omitempty"`
Val string `xml:"w:val,attr"`
}
// Style contains styling for a paragraph
type Style struct {
XMLName xml.Name `xml:"w:pStyle,omitempty"`
Val string `xml:"w:val,attr"`
}
// Color contains the sound of music. :D
// I'm kidding. It contains the color
type Color struct {
XMLName xml.Name `xml:"w:color"`
Val string `xml:"w:val,attr"`
}
// Size contains the font size
type Size struct {
XMLName xml.Name `xml:"w:sz"`
Val string `xml:"w:val,attr"`
}
// Justification contains the way of the horizonal alignment
//
// w:jc 属性的取值可以是以下之一:
// start左对齐。
// center居中对齐。
// end右对齐。
// both两端对齐。
// distribute分散对齐。
type Justification struct {
// XMLName xml.Name `xml:"w:jc"`
Val string `xml:"w:val,attr"`
}

View File

@@ -307,10 +307,7 @@ func (t *WTableLook) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
} }
// Consume the end element // Consume the end element
_, err := d.Token() _, err := d.Token()
if err != nil { return err
return err
}
return nil
} }
// WTableGrid is a structure that represents the table grid of a Word document. // WTableGrid is a structure that represents the table grid of a Word document.
@@ -382,6 +379,7 @@ func (g *WGridCol) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err err
type WTableRow struct { type WTableRow struct {
XMLName xml.Name `xml:"w:tr,omitempty"` XMLName xml.Name `xml:"w:tr,omitempty"`
RsidR string `xml:"w:rsidR,attr,omitempty"` RsidR string `xml:"w:rsidR,attr,omitempty"`
RsidRPr string `xml:"w:rsidRPr,attr,omitempty"`
RsidTr string `xml:"w:rsidTr,attr,omitempty"` RsidTr string `xml:"w:rsidTr,attr,omitempty"`
TableRowProperties *WTableRowProperties TableRowProperties *WTableRowProperties
TableCells []*WTableCell TableCells []*WTableCell
@@ -395,6 +393,8 @@ func (w *WTableRow) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
switch attr.Name.Local { switch attr.Name.Local {
case "rsidR": case "rsidR":
w.RsidR = attr.Value w.RsidR = attr.Value
case "rsidRPr":
w.RsidRPr = attr.Value
case "rsidTr": case "rsidTr":
w.RsidTr = attr.Value w.RsidTr = attr.Value
default: default:
@@ -443,7 +443,7 @@ func (w *WTableRow) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
type WTableRowProperties struct { type WTableRowProperties struct {
XMLName xml.Name `xml:"w:trPr,omitempty"` XMLName xml.Name `xml:"w:trPr,omitempty"`
TableRowHeight *WTableRowHeight TableRowHeight *WTableRowHeight
Justification *Justification `xml:"w:jc,omitempty"` Justification *Justification
} }
// UnmarshalXML ... // UnmarshalXML ...
@@ -462,12 +462,14 @@ func (t *WTableRowProperties) UnmarshalXML(d *xml.Decoder, start xml.StartElemen
case "trHeight": case "trHeight":
th := new(WTableRowHeight) th := new(WTableRowHeight)
for _, attr := range tt.Attr { for _, attr := range tt.Attr {
if attr.Name.Local == "val" { switch attr.Name.Local {
case "val":
th.Val, err = strconv.ParseInt(attr.Value, 10, 64) th.Val, err = strconv.ParseInt(attr.Value, 10, 64)
if err != nil { if err != nil {
return err return err
} }
break case "hRule":
th.Rule = attr.Value
} }
} }
t.TableRowHeight = th t.TableRowHeight = th
@@ -502,6 +504,7 @@ func (t *WTableRowProperties) UnmarshalXML(d *xml.Decoder, start xml.StartElemen
// WTableRowHeight represents the height of a row within a table. // WTableRowHeight represents the height of a row within a table.
type WTableRowHeight struct { type WTableRowHeight struct {
XMLName xml.Name `xml:"w:trHeight,omitempty"` XMLName xml.Name `xml:"w:trHeight,omitempty"`
Rule string `xml:"w:hRule,omitempty"`
Val int64 `xml:"w:val,attr"` Val int64 `xml:"w:val,attr"`
} }
@@ -563,6 +566,7 @@ type WTableCellProperties struct {
GridSpan *WGridSpan GridSpan *WGridSpan
VAlign *WVerticalAlignment VAlign *WVerticalAlignment
TableBorders *WTableBorders `xml:"w:tcBorders"` TableBorders *WTableBorders `xml:"w:tcBorders"`
Shade *Shade
} }
// UnmarshalXML ... // UnmarshalXML ...
@@ -608,6 +612,13 @@ func (r *WTableCellProperties) UnmarshalXML(d *xml.Decoder, start xml.StartEleme
if err != nil && !strings.HasPrefix(err.Error(), "expected") { if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err return err
} }
case "shd":
var value Shade
err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
r.Shade = &value
default: default:
err = d.Skip() // skip unsupported tags err = d.Skip() // skip unsupported tags
if err != nil { if err != nil {
@@ -743,10 +754,7 @@ func (t *WTableBorder) UnmarshalXML(d *xml.Decoder, start xml.StartElement) erro
} }
// Consume the end element // Consume the end element
_, err := d.Token() _, err := d.Token()
if err != nil { return err
return err
}
return nil
} }
// WGridSpan represents the number of grid columns this cell should span. // WGridSpan represents the number of grid columns this cell should span.

View File

@@ -36,7 +36,7 @@ func TestTableStructure(t *testing.T) {
para1.AddText("table") para1.AddText("table")
tab1 := w.AddTable(4, 3).Justification("center") tab1 := w.AddTable(4, 3).Justification("center")
tab1.TableProperties.Position = &WTablePositioningProperties{LeftFromText: 2333} tab1.TableProperties.Position = &WTablePositioningProperties{LeftFromText: 2333}
para2 := tab1.TableRows[3].Justification("center").TableCells[2].AddParagraph() para2 := tab1.TableRows[3].Justification("center").TableCells[2].Shade("clear", "auto", "E7E6E6").AddParagraph()
r, err := para2.AddAnchorDrawingFrom("testdata/fumiama.JPG") r, err := para2.AddAnchorDrawingFrom("testdata/fumiama.JPG")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View File

@@ -87,10 +87,7 @@ func (f *Docx) parseDocument(file *zip.File) error {
f.Document.Body.file = f f.Document.Body.file = f
err = xml.NewDecoder(zf).Decode(&f.Document) err = xml.NewDecoder(zf).Decode(&f.Document)
if err != nil { return err
return err
}
return nil
} }
// parseDocRelation processes one of the relevant files, the one with the relationships // parseDocRelation processes one of the relevant files, the one with the relationships