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

add: anchor drawing & some attrs

This commit is contained in:
源文雨
2023-02-22 17:09:04 +08:00
parent d2666ec617
commit 9f0dbc43d1
8 changed files with 617 additions and 112 deletions

View File

@@ -15,9 +15,10 @@ func (p *Paragraph) AddInlineDrawing(pic []byte) (*Run, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
id := strconv.Itoa(int(atomic.AddUintptr(&p.file.imageId, 1))) idn := int(atomic.AddUintptr(&p.file.imageId, 1))
id := strconv.Itoa(idn)
rId := p.file.addImage(Media{Name: "image" + id + "." + format, Data: pic}) rId := p.file.addImage(Media{Name: "image" + id + "." + format, Data: pic})
w, h := sz.Width, sz.Height w, h := int64(sz.Width), int64(sz.Height)
if float64(w)/float64(h) > 1.2 { if float64(w)/float64(h) > 1.2 {
h = A4_EMU_MAX_WIDTH * h / w h = A4_EMU_MAX_WIDTH * h / w
w = A4_EMU_MAX_WIDTH w = A4_EMU_MAX_WIDTH
@@ -36,7 +37,7 @@ func (p *Paragraph) AddInlineDrawing(pic []byte) (*Run, error) {
}, },
EffectExtent: &WPEffectExtent{}, EffectExtent: &WPEffectExtent{},
DocPr: &WPDocPr{ DocPr: &WPDocPr{
ID: id, ID: idn,
Name: "图片 " + id, Name: "图片 " + id,
}, },
CNvGraphicFramePr: &WPCNvGraphicFramePr{ CNvGraphicFramePr: &WPCNvGraphicFramePr{
@@ -96,7 +97,7 @@ func (p *Paragraph) AddInlineDrawingFrom(file string) (*Run, error) {
} }
// Size of the inline drawing by EMU // Size of the inline drawing by EMU
func (in *WPInline) Size(w, h int) { func (in *WPInline) Size(w, h int64) {
if in.Extent != nil { if in.Extent != nil {
in.Extent.CX = w in.Extent.CX = w
in.Extent.CY = h in.Extent.CY = h
@@ -106,3 +107,111 @@ func (in *WPInline) Size(w, h int) {
in.Graphic.GraphicData.Pic.SpPr.Xfrm.Ext.CY = h in.Graphic.GraphicData.Pic.SpPr.Xfrm.Ext.CY = h
} }
} }
// AddAnchorDrawing adds inline drawing to paragraph
func (p *Paragraph) AddAnchorDrawing(pic []byte) (*Run, error) {
sz, format, err := imgsz.DecodeSize(bytes.NewReader(pic))
if err != nil {
return nil, err
}
idn := int(atomic.AddUintptr(&p.file.imageId, 1))
id := strconv.Itoa(idn)
rId := p.file.addImage(Media{Name: "image" + id + "." + format, Data: pic})
w, h := int64(sz.Width), int64(sz.Height)
if float64(w)/float64(h) > 1.2 {
h = A4_EMU_MAX_WIDTH * h / w
w = A4_EMU_MAX_WIDTH
} else {
h = A4_EMU_MAX_WIDTH * h / w / 2
w = A4_EMU_MAX_WIDTH / 2
}
d := &Drawing{
Anchor: &WPAnchor{
LayoutInCell: 1,
AllowOverlap: 1,
SimplePosXY: &WPSimplePos{},
PositionH: &WPPositionH{
RelativeFrom: "column",
},
PositionV: &WPPositionV{
RelativeFrom: "paragraph",
},
Extent: &WPExtent{
CX: w,
CY: h,
},
EffectExtent: &WPEffectExtent{},
WrapNone: &struct{}{},
DocPr: &WPDocPr{
ID: idn,
Name: "图片 " + id,
},
CNvGraphicFramePr: &WPCNvGraphicFramePr{
Locks: &AGraphicFrameLocks{
NoChangeAspect: 1,
},
},
Graphic: &AGraphic{
XMLA: XMLNS_DRAWINGML_MAIN,
GraphicData: &AGraphicData{
URI: XMLNS_PICTURE,
Pic: &PICPic{
XMLPIC: XMLNS_DRAWINGML_PICTURE,
NonVisualPicProperties: &PICNonVisualPicProperties{
NonVisualDrawingProperties: PICNonVisualDrawingProperties{
ID: id,
Name: "图片 " + id,
},
},
BlipFill: &PICBlipFill{
Blip: ABlip{
Embed: rId,
Cstate: "print",
},
},
SpPr: &PICSpPr{
Xfrm: AXfrm{
Ext: AExt{
CX: w,
CY: h,
},
},
PrstGeom: APrstGeom{
Prst: "rect",
},
},
},
},
},
},
}
run := &Run{
Drawing: d,
RunProperties: &RunProperties{},
}
p.Children = append(p.Children, ParagraphChild{Run: run})
return run, nil
}
// AddInlineDrawingFrom adds drawing from file to paragraph
func (p *Paragraph) AddAnchorDrawingFrom(file string) (*Run, error) {
data, err := os.ReadFile(file)
if err != nil {
return nil, err
}
return p.AddAnchorDrawing(data)
}
// Size of the anchor drawing by EMU
func (a *WPAnchor) Size(w, h int64) {
if a.Extent != nil {
a.Extent.CX = w
a.Extent.CY = h
}
if a.Graphic != nil && a.Graphic.GraphicData != nil && a.Graphic.GraphicData.Pic != nil && a.Graphic.GraphicData.Pic.SpPr != nil {
a.Graphic.GraphicData.Pic.SpPr.Xfrm.Ext.CX = w
a.Graphic.GraphicData.Pic.SpPr.Xfrm.Ext.CY = h
}
}

View File

@@ -20,6 +20,14 @@ func main() {
w := docxlib.NewA4() w := docxlib.NewA4()
// add new paragraph // add new paragraph
para1 := w.AddParagraph().Justification("distribute") para1 := w.AddParagraph().Justification("distribute")
r, err := para1.AddAnchorDrawingFrom("testdata/fumiama.JPG")
if err != nil {
panic(err)
}
r.Drawing.Anchor.Size(r.Drawing.Anchor.Extent.CX/4, r.Drawing.Anchor.Extent.CY/4)
r.Drawing.Anchor.BehindDoc = 1
r.Drawing.Anchor.PositionH.PosOffset = r.Drawing.Anchor.Extent.CX
r.Drawing.Anchor.Graphic.GraphicData.Pic.BlipFill.Blip.AlphaModFix = &docxlib.AAlphaModFix{Amount: 50000}
// add text // add text
para1.AddText("test") para1.AddText("test")
para1.AddText("test font size").Size("44") para1.AddText("test font size").Size("44")
@@ -36,7 +44,7 @@ func main() {
para3.AddText("一行2个 inline").Size("44") para3.AddText("一行2个 inline").Size("44")
para4 := w.AddParagraph().Justification("center") para4 := w.AddParagraph().Justification("center")
r, err := para4.AddInlineDrawingFrom("testdata/fumiama.JPG") r, err = para4.AddInlineDrawingFrom("testdata/fumiama.JPG")
if err != nil { if err != nil {
panic(err) panic(err)
} }
@@ -93,7 +101,12 @@ func main() {
fmt.Printf("\tWe've found a new run with the text ->%s\n", child.Run.Text.Text) fmt.Printf("\tWe've found a new run with the text ->%s\n", child.Run.Text.Text)
} }
if child.Run.Drawing != nil { if child.Run.Drawing != nil {
fmt.Printf("\tWe've found a new run with the drawing ->%s\n", child.Run.Drawing.Inline.DocPr.Name) // TODO: replace to refid if child.Run.Drawing.Inline != nil {
fmt.Printf("\tWe've found a new run with the inline drawing ->%s\n", child.Run.Drawing.Inline.DocPr.Name)
}
if child.Run.Drawing.Anchor != nil {
fmt.Printf("\tWe've found a new run with the anchor drawing ->%s\n", child.Run.Drawing.Anchor.DocPr.Name)
}
} }
} }
if child.Link != nil { if child.Link != nil {

View File

@@ -60,7 +60,7 @@ func (doc *Document) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
case "body": case "body":
case "p": case "p":
var value Paragraph var value Paragraph
d.DecodeElement(&value, &start) d.DecodeElement(&value, &tt)
if len(value.Children) > 0 { if len(value.Children) > 0 {
value.file = doc.file value.file = doc.file
doc.Body.Paragraphs = append(doc.Body.Paragraphs, &value) doc.Body.Paragraphs = append(doc.Body.Paragraphs, &value)

View File

@@ -111,7 +111,7 @@ const drawing_doc = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:noProof/> <w:noProof/>
</w:rPr> </w:rPr>
<w:drawing> <w:drawing>
<wp:inline distT="0" distB="0" distL="0" distR="0" wp14:anchorId="mock-anchor-p1-c0" wp14:editId="mock-edit-p1-c0"> <wp:inline distT="0" distB="1" distL="2" distR="3" wp14:anchorId="mock-anchor-p1-c0" wp14:editId="mock-edit-p1-c0">
<wp:extent cx="5274310" cy="3369310"/> <wp:extent cx="5274310" cy="3369310"/>
<wp:effectExtent l="0" t="0" r="0" b="0"/> <wp:effectExtent l="0" t="0" r="0" b="0"/>
<wp:docPr id="1" name="图片 1"/> <wp:docPr id="1" name="图片 1"/>
@@ -175,7 +175,7 @@ const drawing_doc = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:noProof/> <w:noProof/>
</w:rPr> </w:rPr>
<w:drawing> <w:drawing>
<wp:inline distT="0" distB="0" distL="0" distR="0" wp14:anchorId="mock-anchor-p3-c0" wp14:editId="mock-edit-p3-c0"> <wp:inline distT="0" distB="1" distL="2" distR="3" wp14:anchorId="mock-anchor-p3-c0" wp14:editId="mock-edit-p3-c0">
<wp:extent cx="2339163" cy="1494293"/> <wp:extent cx="2339163" cy="1494293"/>
<wp:effectExtent l="0" t="0" r="0" b="4445"/> <wp:effectExtent l="0" t="0" r="0" b="4445"/>
<wp:docPr id="2" name="图片 2"/> <wp:docPr id="2" name="图片 2"/>
@@ -221,7 +221,7 @@ const drawing_doc = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:noProof/> <w:noProof/>
</w:rPr> </w:rPr>
<w:drawing> <w:drawing>
<wp:inline distT="0" distB="0" distL="0" distR="0" wp14:anchorId="mock-anchor-p3-c1" wp14:editId="mock-edit-p3-c1"> <wp:inline distT="0" distB="1" distL="2" distR="3" wp14:anchorId="mock-anchor-p3-c1" wp14:editId="mock-edit-p3-c1">
<wp:extent cx="2339163" cy="1494293"/> <wp:extent cx="2339163" cy="1494293"/>
<wp:effectExtent l="0" t="0" r="0" b="4445"/> <wp:effectExtent l="0" t="0" r="0" b="4445"/>
<wp:docPr id="4" name="图片 4"/> <wp:docPr id="4" name="图片 4"/>
@@ -288,7 +288,7 @@ const drawing_doc = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<mc:AlternateContent> <mc:AlternateContent>
<mc:Choice Requires="wpg"> <mc:Choice Requires="wpg">
<w:drawing> <w:drawing>
<wp:inline distT="0" distB="0" distL="0" distR="0" wp14:anchorId="mock-anchor-p5-c0" wp14:editId="mock-edit-p5-c0"> <wp:inline distT="0" distB="1" distL="2" distR="3" wp14:anchorId="mock-anchor-p5-c0" wp14:editId="mock-edit-p5-c0">
<wp:extent cx="4677868" cy="1494155"/> <wp:extent cx="4677868" cy="1494155"/>
<wp:effectExtent l="0" t="0" r="0" b="4445"/> <wp:effectExtent l="0" t="0" r="0" b="4445"/>
<wp:docPr id="7" name="组合 7"/> <wp:docPr id="7" name="组合 7"/>
@@ -447,7 +447,7 @@ const drawing_doc = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:noProof/> <w:noProof/>
</w:rPr> </w:rPr>
<w:drawing> <w:drawing>
<wp:anchor distT="0" distB="0" distL="114300" distR="114300" simplePos="0" relativeHeight="251658240" behindDoc="0" locked="0" layoutInCell="1" allowOverlap="1" wp14:anchorId="mock-anchor-px-cx" wp14:editId="mock-edit-px-cx"> <wp:anchor distT="0" distB="1" distL="2" distR="3" simplePos="0" relativeHeight="251658240" behindDoc="0" locked="0" layoutInCell="1" allowOverlap="1" wp14:anchorId="mock-anchor-px-cx" wp14:editId="mock-edit-px-cx">
<wp:simplePos x="0" y="0"/> <wp:simplePos x="0" y="0"/>
<wp:positionH relativeFrom="column"> <wp:positionH relativeFrom="column">
<wp:posOffset>2935605</wp:posOffset> <wp:posOffset>2935605</wp:posOffset>
@@ -543,34 +543,26 @@ func TestUnmarshalDrawingStructure(t *testing.T) {
if child.Run != nil && child.Run.Drawing != nil { if child.Run != nil && child.Run.Drawing != nil {
t.Log("fild drawing at aragraph", i, ", child", j) t.Log("fild drawing at aragraph", i, ", child", j)
if child.Run.Drawing.Inline != nil { if child.Run.Drawing.Inline != nil {
/*anchor := "mock-anchor-p" + string(rune('0'+i)) + "-c" + string(rune('0'+j)) if child.Run.Drawing.Inline.DistT != 0 || child.Run.Drawing.Inline.DistB != 1 || child.Run.Drawing.Inline.DistL != 2 || child.Run.Drawing.Inline.DistR != 3 {
edit := "mock-edit-p" + string(rune('0'+i)) + "-c" + string(rune('0'+j)) t.Fatal("unexpected inline dist")
if anchor != child.Run.Drawing.Inline.AnchorID {
t.Fatal("expect", anchor, "but got", child.Run.Drawing.Inline.AnchorID)
} }
if edit != child.Run.Drawing.Inline.EditID {
t.Fatal("expect", edit, "but got", child.Run.Drawing.Inline.EditID)
}*/
if child.Run.Drawing.Inline.Graphic != nil && child.Run.Drawing.Inline.Graphic.GraphicData != nil {
t.Log(child.Run.Drawing.Inline.Graphic.GraphicData.URI)
if child.Run.Drawing.Inline.Graphic.GraphicData.Pic != nil {
t.Log(child.Run.Drawing.Inline.Graphic.GraphicData.Pic.NonVisualPicProperties.NonVisualDrawingProperties.ID, child.Run.Drawing.Inline.Graphic.GraphicData.Pic.BlipFill.Blip.Embed)
}
}
} }
} }
} }
} }
} }
func TestMarshalDrawingStructure(t *testing.T) { func TestInlineDrawingStructure(t *testing.T) {
w := NewA4() w := NewA4()
// add new paragraph // add new paragraph
para1 := w.AddParagraph() para1 := w.AddParagraph()
// add text // add text
para1.AddText("直接粘贴 inline").AddTab() para1.AddText("直接粘贴 inline").AddTab()
r, err := para1.AddAnchorDrawingFrom("testdata/fumiama.JPG")
if err != nil {
t.Fatal(err)
}
r.Drawing.Anchor.Graphic.GraphicData.Pic.BlipFill.Blip.AlphaModFix = &AAlphaModFix{Amount: 50000}
para2 := w.AddParagraph().Justification("center") para2 := w.AddParagraph().Justification("center")
para2.AddInlineDrawingFrom("testdata/fumiama.JPG") para2.AddInlineDrawingFrom("testdata/fumiama.JPG")
para2.AddTab().AddTab().AppendTab().AppendTab() para2.AddTab().AddTab().AppendTab().AppendTab()
@@ -579,7 +571,7 @@ func TestMarshalDrawingStructure(t *testing.T) {
para3 := w.AddParagraph() para3 := w.AddParagraph()
para3.AddInlineDrawingFrom("testdata/fumiamayoko.png") para3.AddInlineDrawingFrom("testdata/fumiamayoko.png")
f, err := os.Create("TestMarshalDrawingStructure_Marshal.xml") f, err := os.Create("TestMarshalInlineDrawingStructure.xml")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -597,7 +589,7 @@ func TestMarshalDrawingStructure(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
f1, err := os.Create("TestMarshalDrawingStructure_Unmarshal.xml") f1, err := os.Create("TestUnmarshalInlineDrawingStructure.xml")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -628,8 +620,5 @@ func TestMarshalDrawingStructure(t *testing.T) {
md52 := h.Sum64() md52 := h.Sum64()
if md51 != md52 { if md51 != md52 {
t.Fail() t.Fail()
} /* else { }
_ = os.Remove("TestMarshalDrawingStructure_Marshal.xml")
_ = os.Remove("TestMarshalDrawingStructure_Unmarshal.xml")
}*/
} }

View File

@@ -20,6 +20,7 @@ const (
type Drawing struct { type Drawing struct {
XMLName xml.Name `xml:"w:drawing,omitempty"` XMLName xml.Name `xml:"w:drawing,omitempty"`
Inline *WPInline Inline *WPInline
Anchor *WPAnchor
} }
func (r *Drawing) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { func (r *Drawing) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
@@ -37,25 +38,10 @@ func (r *Drawing) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
switch tt.Name.Local { switch tt.Name.Local {
case "inline": case "inline":
r.Inline = new(WPInline) r.Inline = new(WPInline)
r.Inline.DistT, err = strconv.Atoi(getAtt(tt.Attr, "distT")) d.DecodeElement(r.Inline, &tt)
if err != nil { case "anchor":
return err r.Anchor = new(WPAnchor)
} d.DecodeElement(r.Anchor, &tt)
r.Inline.DistB, err = strconv.Atoi(getAtt(tt.Attr, "distB"))
if err != nil {
return err
}
r.Inline.DistL, err = strconv.Atoi(getAtt(tt.Attr, "distL"))
if err != nil {
return err
}
r.Inline.DistR, err = strconv.Atoi(getAtt(tt.Attr, "distR"))
if err != nil {
return err
}
// r.Inline.AnchorID = getAtt(tt.Attr, "anchorId")
// r.Inline.EditID = getAtt(tt.Attr, "editId")
d.DecodeElement(r.Inline, &start)
default: default:
continue continue
} }
@@ -69,10 +55,10 @@ func (r *Drawing) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
// WPInline wp:inline // WPInline wp:inline
type WPInline struct { type WPInline struct {
XMLName xml.Name `xml:"wp:inline,omitempty"` XMLName xml.Name `xml:"wp:inline,omitempty"`
DistT int `xml:"distT,attr"` DistT int64 `xml:"distT,attr"`
DistB int `xml:"distB,attr"` DistB int64 `xml:"distB,attr"`
DistL int `xml:"distL,attr"` DistL int64 `xml:"distL,attr"`
DistR int `xml:"distR,attr"` DistR int64 `xml:"distR,attr"`
// AnchorID string `xml:"wp14:anchorId,attr,omitempty"` // AnchorID string `xml:"wp14:anchorId,attr,omitempty"`
// EditID string `xml:"wp14:editId,attr,omitempty"` // EditID string `xml:"wp14:editId,attr,omitempty"`
@@ -83,7 +69,33 @@ type WPInline struct {
Graphic *AGraphic Graphic *AGraphic
} }
func (r *WPInline) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { func (r *WPInline) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error) {
for _, attr := range start.Attr {
switch attr.Name.Local {
case "distT":
r.DistT, err = strconv.ParseInt(attr.Value, 10, 64)
if err != nil {
return
}
case "distB":
r.DistB, err = strconv.ParseInt(attr.Value, 10, 64)
if err != nil {
return
}
case "distL":
r.DistL, err = strconv.ParseInt(attr.Value, 10, 64)
if err != nil {
return
}
case "distR":
r.DistR, err = strconv.ParseInt(attr.Value, 10, 64)
if err != nil {
return
}
default:
// ignore other attributes
}
}
for { for {
t, err := d.Token() t, err := d.Token()
if err == io.EOF { if err == io.EOF {
@@ -98,46 +110,42 @@ func (r *WPInline) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
switch tt.Name.Local { switch tt.Name.Local {
case "extent": case "extent":
r.Extent = new(WPExtent) r.Extent = new(WPExtent)
r.Extent.CX, err = strconv.Atoi(getAtt(tt.Attr, "cx")) r.Extent.CX, err = strconv.ParseInt(getAtt(tt.Attr, "cx"), 10, 64)
if err != nil { if err != nil {
return err return err
} }
r.Extent.CY, err = strconv.Atoi(getAtt(tt.Attr, "cy")) r.Extent.CY, err = strconv.ParseInt(getAtt(tt.Attr, "cy"), 10, 64)
if err != nil { if err != nil {
return err return err
} }
case "effectExtent": case "effectExtent":
r.EffectExtent = new(WPEffectExtent) r.EffectExtent = new(WPEffectExtent)
r.EffectExtent.L, err = strconv.Atoi(getAtt(tt.Attr, "l")) r.EffectExtent.L, err = strconv.ParseInt(getAtt(tt.Attr, "l"), 10, 64)
if err != nil { if err != nil {
return err return err
} }
r.EffectExtent.T, err = strconv.Atoi(getAtt(tt.Attr, "t")) r.EffectExtent.T, err = strconv.ParseInt(getAtt(tt.Attr, "t"), 10, 64)
if err != nil { if err != nil {
return err return err
} }
r.EffectExtent.R, err = strconv.Atoi(getAtt(tt.Attr, "r")) r.EffectExtent.R, err = strconv.ParseInt(getAtt(tt.Attr, "r"), 10, 64)
if err != nil { if err != nil {
return err return err
} }
r.EffectExtent.B, err = strconv.Atoi(getAtt(tt.Attr, "b")) r.EffectExtent.B, err = strconv.ParseInt(getAtt(tt.Attr, "b"), 10, 64)
if err != nil { if err != nil {
return err return err
} }
case "docPr": case "docPr":
r.DocPr = new(WPDocPr) r.DocPr = new(WPDocPr)
r.DocPr.ID = getAtt(tt.Attr, "id") d.DecodeElement(r.DocPr, &tt)
r.DocPr.Name = getAtt(tt.Attr, "name")
r.DocPr.Macro = getAtt(tt.Attr, "macro")
r.DocPr.Hidden = getAtt(tt.Attr, "hidden")
case "cNvGraphicFramePr": case "cNvGraphicFramePr":
var value WPCNvGraphicFramePr var value WPCNvGraphicFramePr
d.DecodeElement(&value, &start) d.DecodeElement(&value, &tt)
r.CNvGraphicFramePr = &value r.CNvGraphicFramePr = &value
case "graphic": case "graphic":
var value AGraphic var value AGraphic
d.DecodeElement(&value, &start) d.DecodeElement(&value, &tt)
value.XMLA = getAtt(tt.Attr, "a")
r.Graphic = &value r.Graphic = &value
default: default:
continue continue
@@ -154,26 +162,106 @@ func (r *WPInline) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
// CX CY 's unit is English Metric Units, which is 1/914400 inch // CX CY 's unit is English Metric Units, which is 1/914400 inch
type WPExtent struct { type WPExtent struct {
XMLName xml.Name `xml:"wp:extent,omitempty"` XMLName xml.Name `xml:"wp:extent,omitempty"`
CX int `xml:"cx,attr"` CX int64 `xml:"cx,attr"`
CY int `xml:"cy,attr"` CY int64 `xml:"cy,attr"`
}
func (r *WPExtent) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
var err error
for _, attr := range start.Attr {
switch attr.Name.Local {
case "cx":
r.CX, err = strconv.ParseInt(attr.Value, 10, 64)
if err != nil {
return err
}
case "cy":
r.CY, err = strconv.ParseInt(attr.Value, 10, 64)
if err != nil {
return err
}
}
}
// Consume the end element
_, err = d.Token()
if err != nil {
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.
type WPEffectExtent struct { type WPEffectExtent struct {
XMLName xml.Name `xml:"wp:effectExtent,omitempty"` XMLName xml.Name `xml:"wp:effectExtent,omitempty"`
L int `xml:"l,attr"` L int64 `xml:"l,attr"`
T int `xml:"t,attr"` T int64 `xml:"t,attr"`
R int `xml:"r,attr"` R int64 `xml:"r,attr"`
B int `xml:"b,attr"` B int64 `xml:"b,attr"`
}
func (r *WPEffectExtent) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
var err error
for _, attr := range start.Attr {
switch attr.Name.Local {
case "l":
r.L, err = strconv.ParseInt(attr.Value, 10, 64)
if err != nil {
return err
}
case "t":
r.T, err = strconv.ParseInt(attr.Value, 10, 64)
if err != nil {
return err
}
case "r":
r.R, err = strconv.ParseInt(attr.Value, 10, 64)
if err != nil {
return err
}
case "b":
r.B, err = strconv.ParseInt(attr.Value, 10, 64)
if err != nil {
return err
}
}
}
// Consume the end element
_, err = d.Token()
if err != nil {
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.
type WPDocPr struct { type WPDocPr struct {
XMLName xml.Name `xml:"wp:docPr,omitempty"` XMLName xml.Name `xml:"wp:docPr,omitempty"`
ID string `xml:"id,attr"` ID int `xml:"id,attr"`
Name string `xml:"name,attr,omitempty"` Name string `xml:"name,attr,omitempty"`
Macro string `xml:"macro,attr,omitempty"` }
Hidden string `xml:"hidden,attr,omitempty"`
func (r *WPDocPr) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
for _, attr := range start.Attr {
switch attr.Name.Local {
case "id":
id, err := strconv.Atoi(attr.Value)
if err != nil {
return err
}
r.ID = id
case "name":
r.Name = attr.Value
default:
// ignore other attributes
}
}
// Consume the end element
_, err := d.Token()
if err != nil {
return err
}
return nil
} }
// WPCNvGraphicFramePr represents the non-visual properties of a graphic frame. // WPCNvGraphicFramePr represents the non-visual properties of a graphic frame.
@@ -197,7 +285,7 @@ func (w *WPCNvGraphicFramePr) UnmarshalXML(d *xml.Decoder, start xml.StartElemen
switch tt.Name.Local { switch tt.Name.Local {
case "graphicFrameLocks": case "graphicFrameLocks":
var value AGraphicFrameLocks var value AGraphicFrameLocks
d.DecodeElement(&value, &start) d.DecodeElement(&value, &tt)
value.NoChangeAspect, err = strconv.Atoi(getAtt(tt.Attr, "noChangeAspect")) value.NoChangeAspect, err = strconv.Atoi(getAtt(tt.Attr, "noChangeAspect"))
if err != nil { if err != nil {
return err return err
@@ -226,6 +314,14 @@ type AGraphic struct {
} }
func (a *AGraphic) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { func (a *AGraphic) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
for _, attr := range start.Attr {
switch attr.Name.Local {
case "a":
a.XMLA = attr.Value
default:
// ignore other attributes
}
}
for { for {
t, err := d.Token() t, err := d.Token()
if err == io.EOF { if err == io.EOF {
@@ -240,7 +336,7 @@ func (a *AGraphic) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
switch tt.Name.Local { switch tt.Name.Local {
case "graphicData": case "graphicData":
var value AGraphicData var value AGraphicData
d.DecodeElement(&value, &start) d.DecodeElement(&value, &tt)
value.URI = getAtt(tt.Attr, "uri") value.URI = getAtt(tt.Attr, "uri")
a.GraphicData = &value a.GraphicData = &value
default: default:
@@ -274,7 +370,7 @@ func (a *AGraphicData) UnmarshalXML(d *xml.Decoder, start xml.StartElement) erro
switch tt.Name.Local { switch tt.Name.Local {
case "pic": case "pic":
var value PICPic var value PICPic
d.DecodeElement(&value, &start) d.DecodeElement(&value, &tt)
value.XMLPIC = getAtt(tt.Attr, "pic") value.XMLPIC = getAtt(tt.Attr, "pic")
a.Pic = &value a.Pic = &value
default: default:
@@ -310,15 +406,15 @@ func (p *PICPic) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
switch tt.Name.Local { switch tt.Name.Local {
case "nvPicPr": case "nvPicPr":
var value PICNonVisualPicProperties var value PICNonVisualPicProperties
d.DecodeElement(&value, &start) d.DecodeElement(&value, &tt)
p.NonVisualPicProperties = &value p.NonVisualPicProperties = &value
case "blipFill": case "blipFill":
var value PICBlipFill var value PICBlipFill
d.DecodeElement(&value, &start) d.DecodeElement(&value, &tt)
p.BlipFill = &value p.BlipFill = &value
case "spPr": case "spPr":
var value PICSpPr var value PICSpPr
d.DecodeElement(&value, &start) d.DecodeElement(&value, &tt)
p.SpPr = &value p.SpPr = &value
default: default:
continue continue
@@ -389,10 +485,9 @@ func (p *PICBlipFill) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
case xml.StartElement: case xml.StartElement:
switch tt.Name.Local { switch tt.Name.Local {
case "blip": case "blip":
p.Blip.Embed = getAtt(tt.Attr, "embed") d.DecodeElement(&p.Blip, &tt)
p.Blip.Cstate = getAtt(tt.Attr, "cstate")
case "stretch": case "stretch":
d.DecodeElement(&p.Stretch, &start) d.DecodeElement(&p.Stretch, &tt)
default: default:
continue continue
} }
@@ -404,9 +499,54 @@ func (p *PICBlipFill) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
// ABlip represents the blip of a picture in a Word document. // ABlip represents the blip of a picture in a Word document.
type ABlip struct { type ABlip struct {
XMLName xml.Name `xml:"a:blip,omitempty"` XMLName xml.Name `xml:"a:blip,omitempty"`
Embed string `xml:"r:embed,attr"` Embed string `xml:"r:embed,attr"`
Cstate string `xml:"cstate,attr"` Cstate string `xml:"cstate,attr"`
AlphaModFix *AAlphaModFix
}
func (a *ABlip) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
for _, attr := range start.Attr {
switch attr.Name.Local {
case "embed":
a.Embed = attr.Value
case "cstate":
a.Cstate = attr.Value
default:
// ignore other attributes
}
}
for {
t, err := d.Token()
if err == io.EOF {
break
}
if err != nil {
return err
}
switch tt := t.(type) {
case xml.StartElement:
switch tt.Name.Local {
case "alphaModFix":
var value AAlphaModFix
value.Amount, err = strconv.Atoi(getAtt(tt.Attr, "amt"))
if err != nil {
return err
}
a.AlphaModFix = &value
default:
continue
}
}
}
return nil
}
type AAlphaModFix struct {
XMLName xml.Name `xml:"a:alphaModFix,omitempty"`
Amount int `xml:"amt,attr"`
} }
// AStretch ... // AStretch ...
@@ -442,9 +582,9 @@ func (p *PICSpPr) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
case xml.StartElement: case xml.StartElement:
switch tt.Name.Local { switch tt.Name.Local {
case "xfrm": case "xfrm":
d.DecodeElement(&p.Xfrm, &start) d.DecodeElement(&p.Xfrm, &tt)
case "prstGeom": case "prstGeom":
d.DecodeElement(&p.PrstGeom, &start) d.DecodeElement(&p.PrstGeom, &tt)
p.PrstGeom.Prst = getAtt(tt.Attr, "prst") p.PrstGeom.Prst = getAtt(tt.Attr, "prst")
default: default:
continue continue
@@ -459,11 +599,35 @@ func (p *PICSpPr) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
// which describes the position and size of a shape. // which describes the position and size of a shape.
type AXfrm struct { type AXfrm struct {
XMLName xml.Name `xml:"a:xfrm,omitempty"` XMLName xml.Name `xml:"a:xfrm,omitempty"`
Rot int64 `xml:"rot,attr,omitempty"`
FlipH int `xml:"flipH,attr,omitempty"`
FlipV int `xml:"flipV,attr,omitempty"`
Off AOff Off AOff
Ext AExt Ext AExt
} }
func (a *AXfrm) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { func (a *AXfrm) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error) {
for _, attr := range start.Attr {
switch attr.Name.Local {
case "rot":
a.Rot, err = strconv.ParseInt(attr.Value, 10, 64)
if err != nil {
return err
}
case "flipH":
a.FlipH, err = strconv.Atoi(attr.Value)
if err != nil {
return err
}
case "flipV":
a.FlipV, err = strconv.Atoi(attr.Value)
if err != nil {
return err
}
default:
// ignore other attributes
}
}
for { for {
t, err := d.Token() t, err := d.Token()
if err == io.EOF { if err == io.EOF {
@@ -477,20 +641,20 @@ func (a *AXfrm) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
case xml.StartElement: case xml.StartElement:
switch tt.Name.Local { switch tt.Name.Local {
case "off": case "off":
a.Off.X, err = strconv.Atoi(getAtt(tt.Attr, "x")) a.Off.X, err = strconv.ParseInt(getAtt(tt.Attr, "x"), 10, 64)
if err != nil { if err != nil {
return err return err
} }
a.Off.Y, err = strconv.Atoi(getAtt(tt.Attr, "y")) a.Off.Y, err = strconv.ParseInt(getAtt(tt.Attr, "y"), 10, 64)
if err != nil { if err != nil {
return err return err
} }
case "ext": case "ext":
a.Ext.CX, err = strconv.Atoi(getAtt(tt.Attr, "cx")) a.Ext.CX, err = strconv.ParseInt(getAtt(tt.Attr, "cx"), 10, 64)
if err != nil { if err != nil {
return err return err
} }
a.Ext.CY, err = strconv.Atoi(getAtt(tt.Attr, "cy")) a.Ext.CY, err = strconv.ParseInt(getAtt(tt.Attr, "cy"), 10, 64)
if err != nil { if err != nil {
return err return err
} }
@@ -507,16 +671,16 @@ func (a *AXfrm) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
// which describes the offset of a shape from its original position. // which describes the offset of a shape from its original position.
type AOff struct { type AOff struct {
XMLName xml.Name `xml:"a:off,omitempty"` XMLName xml.Name `xml:"a:off,omitempty"`
X int `xml:"x,attr"` X int64 `xml:"x,attr"`
Y int `xml:"y,attr"` Y int64 `xml:"y,attr"`
} }
// AExt is a struct representing the <a:ext> element in OpenXML, // AExt is a struct representing the <a:ext> element in OpenXML,
// which describes the size of a shape. // which describes the size of a shape.
type AExt struct { type AExt struct {
XMLName xml.Name `xml:"a:ext,omitempty"` XMLName xml.Name `xml:"a:ext,omitempty"`
CX int `xml:"cx,attr"` CX int64 `xml:"cx,attr"`
CY int `xml:"cy,attr"` CY int64 `xml:"cy,attr"`
} }
// APrstGeom is a struct representing the <a:prstGeom> element in OpenXML, // APrstGeom is a struct representing the <a:prstGeom> element in OpenXML,
@@ -566,3 +730,233 @@ func (a *AAvLst) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error
return nil return nil
} }
// WPAnchor wp:anchor
type WPAnchor struct {
XMLName xml.Name `xml:"wp:anchor,omitempty"`
DistT int64 `xml:"distT,attr"`
DistB int64 `xml:"distB,attr"`
DistL int64 `xml:"distL,attr"`
DistR int64 `xml:"distR,attr"`
SimplePos int `xml:"simplePos,attr"`
RelativeHeight int `xml:"relativeHeight,attr"`
BehindDoc int `xml:"behindDoc,attr"`
Locked int `xml:"locked,attr"`
LayoutInCell int `xml:"layoutInCell,attr"`
AllowOverlap int `xml:"allowOverlap,attr"`
SimplePosXY *WPSimplePos
PositionH *WPPositionH
PositionV *WPPositionV
Extent *WPExtent
EffectExtent *WPEffectExtent
WrapNone *struct{} `xml:"wp:wrapNone,omitempty"`
WrapSquare *WPWrapSquare
DocPr *WPDocPr
CNvGraphicFramePr *WPCNvGraphicFramePr
Graphic *AGraphic
}
func (r *WPAnchor) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error) {
for _, tt := range start.Attr {
switch tt.Name.Local {
case "distT":
r.DistT, err = strconv.ParseInt(tt.Value, 10, 64)
if err != nil {
return err
}
case "distB":
r.DistB, err = strconv.ParseInt(tt.Value, 10, 64)
if err != nil {
return err
}
case "distL":
r.DistL, err = strconv.ParseInt(tt.Value, 10, 64)
if err != nil {
return err
}
case "distR":
r.DistR, err = strconv.ParseInt(tt.Value, 10, 64)
if err != nil {
return err
}
case "simplePos":
r.SimplePos, err = strconv.Atoi(tt.Value)
if err != nil {
return err
}
case "relativeHeight":
r.RelativeHeight, err = strconv.Atoi(tt.Value)
if err != nil {
return err
}
case "behindDoc":
r.BehindDoc, err = strconv.Atoi(tt.Value)
if err != nil {
return err
}
case "locked":
r.Locked, err = strconv.Atoi(tt.Value)
if err != nil {
return err
}
case "layoutInCell":
r.LayoutInCell, err = strconv.Atoi(tt.Value)
if err != nil {
return err
}
case "allowOverlap":
r.AllowOverlap, err = strconv.Atoi(tt.Value)
if err != nil {
return err
}
}
}
for {
t, err := d.Token()
if err == io.EOF {
break
}
if err != nil {
return err
}
switch tt := t.(type) {
case xml.StartElement:
switch tt.Name.Local {
case "simplePos":
r.SimplePosXY = new(WPSimplePos)
r.SimplePosXY.X, err = strconv.ParseInt(getAtt(tt.Attr, "x"), 10, 64)
if err != nil {
return err
}
r.SimplePosXY.Y, err = strconv.ParseInt(getAtt(tt.Attr, "y"), 10, 64)
if err != nil {
return err
}
case "positionH":
r.PositionH = new(WPPositionH)
// r.PositionH.RelativeFrom = getAtt(tt.Attr, "relativeFrom")
d.DecodeElement(&r.PositionH, &tt)
case "positionV":
r.PositionV = new(WPPositionV)
// r.PositionV.RelativeFrom = getAtt(tt.Attr, "relativeFrom")
d.DecodeElement(&r.PositionV, &tt)
case "extent":
r.Extent = new(WPExtent)
d.DecodeElement(&r.Extent, &tt)
case "effectExtent":
r.EffectExtent = new(WPEffectExtent)
d.DecodeElement(&r.EffectExtent, &tt)
case "wrapNone":
r.WrapNone = &struct{}{}
case "wrapSquare":
r.WrapSquare = new(WPWrapSquare)
r.WrapSquare.WrapText = getAtt(tt.Attr, "wrapText")
case "docPr":
r.DocPr = new(WPDocPr)
d.DecodeElement(r.DocPr, &tt)
case "cNvGraphicFramePr":
r.CNvGraphicFramePr = new(WPCNvGraphicFramePr)
d.DecodeElement(r.CNvGraphicFramePr, &tt)
case "graphic":
r.Graphic = new(AGraphic)
d.DecodeElement(&r.Graphic, &tt)
default:
continue
}
}
}
return nil
}
// WPSimplePos represents the position of an object in a Word document.
type WPSimplePos struct {
XMLName xml.Name `xml:"wp:simplePos,omitempty"`
X int64 `xml:"x,attr"`
Y int64 `xml:"y,attr"`
}
// WPPositionH represents the horizontal position of an object in a Word document.
type WPPositionH struct {
XMLName xml.Name `xml:"wp:positionH,omitempty"`
RelativeFrom string `xml:"relativeFrom,attr"`
PosOffset int64 `xml:"wp:posOffset"`
}
func (r *WPPositionH) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
for _, attr := range start.Attr {
switch attr.Name.Local {
case "relativeFrom":
r.RelativeFrom = attr.Value
}
}
for {
t, err := d.Token()
if err == io.EOF {
break
}
if err != nil {
return err
}
switch tt := t.(type) {
case xml.StartElement:
switch tt.Name.Local {
case "posOffset":
err = d.DecodeElement(&r.PosOffset, &tt)
if err != nil {
return err
}
default:
continue
}
}
}
return nil
}
// WPPositionV represents the vertical position of an object in a Word document.
type WPPositionV struct {
XMLName xml.Name `xml:"wp:positionV,omitempty"`
RelativeFrom string `xml:"relativeFrom,attr"`
PosOffset int64 `xml:"wp:posOffset"`
}
func (r *WPPositionV) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
for _, attr := range start.Attr {
switch attr.Name.Local {
case "relativeFrom":
r.RelativeFrom = attr.Value
}
}
for {
t, err := d.Token()
if err == io.EOF {
break
}
if err != nil {
return err
}
switch tt := t.(type) {
case xml.StartElement:
switch tt.Name.Local {
case "posOffset":
err = d.DecodeElement(&r.PosOffset, &tt)
if err != nil {
return err
}
default:
continue
}
}
}
return nil
}
// WPWrapSquare represents the square wrapping of an object in a Word document.
type WPWrapSquare struct {
XMLName xml.Name `xml:"wp:wrapSquare,omitempty"`
WrapText string `xml:"wrapText,attr"`
}

View File

@@ -25,7 +25,7 @@ func (r *Hyperlink) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
switch tt := t.(type) { switch tt := t.(type) {
case xml.StartElement: case xml.StartElement:
if tt.Name.Local == "r" { if tt.Name.Local == "r" {
d.DecodeElement(&r.Run, &start) d.DecodeElement(&r.Run, &tt)
} else { } else {
continue continue
} }

View File

@@ -121,7 +121,7 @@ func (p *Paragraph) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
switch tt.Name.Local { switch tt.Name.Local {
case "hyperlink": case "hyperlink":
var value Hyperlink var value Hyperlink
d.DecodeElement(&value, &start) d.DecodeElement(&value, &tt)
id := getAtt(tt.Attr, "id") id := getAtt(tt.Attr, "id")
anchor := getAtt(tt.Attr, "anchor") anchor := getAtt(tt.Attr, "anchor")
if id != "" { if id != "" {
@@ -133,15 +133,15 @@ func (p *Paragraph) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
elem.Link = &value elem.Link = &value
case "r": case "r":
var value Run var value Run
d.DecodeElement(&value, &start) d.DecodeElement(&value, &tt)
elem.Run = &value elem.Run = &value
case "rPr": case "rPr":
var value RunProperties var value RunProperties
d.DecodeElement(&value, &start) d.DecodeElement(&value, &tt)
elem.Properties = &value elem.Properties = &value
case "pPr": case "pPr":
var value ParagraphProperties var value ParagraphProperties
d.DecodeElement(&value, &start) d.DecodeElement(&value, &tt)
p.Properties = &value p.Properties = &value
continue continue
default: default:

View File

@@ -36,19 +36,19 @@ func (r *Run) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
switch tt.Name.Local { switch tt.Name.Local {
case "rPr": case "rPr":
var value RunProperties var value RunProperties
d.DecodeElement(&value, &start) d.DecodeElement(&value, &tt)
r.RunProperties = &value r.RunProperties = &value
case "instrText": case "instrText":
var value string var value string
d.DecodeElement(&value, &start) d.DecodeElement(&value, &tt)
r.InstrText = value r.InstrText = value
case "t": case "t":
var value Text var value Text
d.DecodeElement(&value, &start) d.DecodeElement(&value, &tt)
r.Text = &value r.Text = &value
case "drawing": case "drawing":
var value Drawing var value Drawing
d.DecodeElement(&value, &start) d.DecodeElement(&value, &tt)
r.Drawing = &value r.Drawing = &value
case "tab": case "tab":
if r.InstrText == "" && r.Text == nil && r.Drawing == nil { if r.InstrText == "" && r.Text == nil && r.Drawing == nil {