From 9f0dbc43d1ef39badd5dbe501c00e6f409c34c9d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?=
<41315874+fumiama@users.noreply.github.com>
Date: Wed, 22 Feb 2023 17:09:04 +0800
Subject: [PATCH] add: anchor drawing & some attrs
---
apidrawing.go | 117 +++++++++-
cmd/main/main.go | 17 +-
structdoc.go | 2 +-
structdoc_test.go | 43 ++--
structdrawing.go | 532 ++++++++++++++++++++++++++++++++++++++++------
structlink.go | 2 +-
structpara.go | 8 +-
structrun.go | 8 +-
8 files changed, 617 insertions(+), 112 deletions(-)
diff --git a/apidrawing.go b/apidrawing.go
index b496d13..3219b88 100644
--- a/apidrawing.go
+++ b/apidrawing.go
@@ -15,9 +15,10 @@ func (p *Paragraph) AddInlineDrawing(pic []byte) (*Run, error) {
if err != nil {
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})
- w, h := sz.Width, sz.Height
+ 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
@@ -36,7 +37,7 @@ func (p *Paragraph) AddInlineDrawing(pic []byte) (*Run, error) {
},
EffectExtent: &WPEffectExtent{},
DocPr: &WPDocPr{
- ID: id,
+ ID: idn,
Name: "图片 " + id,
},
CNvGraphicFramePr: &WPCNvGraphicFramePr{
@@ -96,7 +97,7 @@ func (p *Paragraph) AddInlineDrawingFrom(file string) (*Run, error) {
}
// 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 {
in.Extent.CX = w
in.Extent.CY = h
@@ -106,3 +107,111 @@ func (in *WPInline) Size(w, h int) {
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
+ }
+}
diff --git a/cmd/main/main.go b/cmd/main/main.go
index f178bd5..528e043 100644
--- a/cmd/main/main.go
+++ b/cmd/main/main.go
@@ -20,6 +20,14 @@ func main() {
w := docxlib.NewA4()
// add new paragraph
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
para1.AddText("test")
para1.AddText("test font size").Size("44")
@@ -36,7 +44,7 @@ func main() {
para3.AddText("一行2个 inline").Size("44")
para4 := w.AddParagraph().Justification("center")
- r, err := para4.AddInlineDrawingFrom("testdata/fumiama.JPG")
+ r, err = para4.AddInlineDrawingFrom("testdata/fumiama.JPG")
if err != nil {
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)
}
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 {
diff --git a/structdoc.go b/structdoc.go
index 286b111..771e52c 100644
--- a/structdoc.go
+++ b/structdoc.go
@@ -60,7 +60,7 @@ func (doc *Document) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
case "body":
case "p":
var value Paragraph
- d.DecodeElement(&value, &start)
+ d.DecodeElement(&value, &tt)
if len(value.Children) > 0 {
value.file = doc.file
doc.Body.Paragraphs = append(doc.Body.Paragraphs, &value)
diff --git a/structdoc_test.go b/structdoc_test.go
index f647a69..3e76fa4 100644
--- a/structdoc_test.go
+++ b/structdoc_test.go
@@ -111,7 +111,7 @@ const drawing_doc = `
-
+
@@ -175,7 +175,7 @@ const drawing_doc = `
-
+
@@ -221,7 +221,7 @@ const drawing_doc = `
-
+
@@ -288,7 +288,7 @@ const drawing_doc = `
-
+
@@ -447,7 +447,7 @@ const drawing_doc = `
-
+
2935605
@@ -543,34 +543,26 @@ func TestUnmarshalDrawingStructure(t *testing.T) {
if child.Run != nil && child.Run.Drawing != nil {
t.Log("fild drawing at aragraph", i, ", child", j)
if child.Run.Drawing.Inline != nil {
- /*anchor := "mock-anchor-p" + string(rune('0'+i)) + "-c" + string(rune('0'+j))
- edit := "mock-edit-p" + string(rune('0'+i)) + "-c" + string(rune('0'+j))
- if anchor != child.Run.Drawing.Inline.AnchorID {
- t.Fatal("expect", anchor, "but got", child.Run.Drawing.Inline.AnchorID)
+ 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 {
+ t.Fatal("unexpected inline dist")
}
- 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()
// add new paragraph
para1 := w.AddParagraph()
// add text
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.AddInlineDrawingFrom("testdata/fumiama.JPG")
para2.AddTab().AddTab().AppendTab().AppendTab()
@@ -579,7 +571,7 @@ func TestMarshalDrawingStructure(t *testing.T) {
para3 := w.AddParagraph()
para3.AddInlineDrawingFrom("testdata/fumiamayoko.png")
- f, err := os.Create("TestMarshalDrawingStructure_Marshal.xml")
+ f, err := os.Create("TestMarshalInlineDrawingStructure.xml")
if err != nil {
t.Fatal(err)
}
@@ -597,7 +589,7 @@ func TestMarshalDrawingStructure(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- f1, err := os.Create("TestMarshalDrawingStructure_Unmarshal.xml")
+ f1, err := os.Create("TestUnmarshalInlineDrawingStructure.xml")
if err != nil {
t.Fatal(err)
}
@@ -628,8 +620,5 @@ func TestMarshalDrawingStructure(t *testing.T) {
md52 := h.Sum64()
if md51 != md52 {
t.Fail()
- } /* else {
- _ = os.Remove("TestMarshalDrawingStructure_Marshal.xml")
- _ = os.Remove("TestMarshalDrawingStructure_Unmarshal.xml")
- }*/
+ }
}
diff --git a/structdrawing.go b/structdrawing.go
index 7d49921..7402bb1 100644
--- a/structdrawing.go
+++ b/structdrawing.go
@@ -20,6 +20,7 @@ const (
type Drawing struct {
XMLName xml.Name `xml:"w:drawing,omitempty"`
Inline *WPInline
+ Anchor *WPAnchor
}
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 {
case "inline":
r.Inline = new(WPInline)
- r.Inline.DistT, err = strconv.Atoi(getAtt(tt.Attr, "distT"))
- if err != nil {
- return err
- }
- 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)
+ d.DecodeElement(r.Inline, &tt)
+ case "anchor":
+ r.Anchor = new(WPAnchor)
+ d.DecodeElement(r.Anchor, &tt)
default:
continue
}
@@ -69,10 +55,10 @@ func (r *Drawing) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
// WPInline wp:inline
type WPInline struct {
XMLName xml.Name `xml:"wp:inline,omitempty"`
- DistT int `xml:"distT,attr"`
- DistB int `xml:"distB,attr"`
- DistL int `xml:"distL,attr"`
- DistR int `xml:"distR,attr"`
+ DistT int64 `xml:"distT,attr"`
+ DistB int64 `xml:"distB,attr"`
+ DistL int64 `xml:"distL,attr"`
+ DistR int64 `xml:"distR,attr"`
// AnchorID string `xml:"wp14:anchorId,attr,omitempty"`
// EditID string `xml:"wp14:editId,attr,omitempty"`
@@ -83,7 +69,33 @@ type WPInline struct {
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 {
t, err := d.Token()
if err == io.EOF {
@@ -98,46 +110,42 @@ func (r *WPInline) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
switch tt.Name.Local {
case "extent":
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 {
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 {
return err
}
case "effectExtent":
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 {
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 {
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 {
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 {
return err
}
case "docPr":
r.DocPr = new(WPDocPr)
- r.DocPr.ID = getAtt(tt.Attr, "id")
- r.DocPr.Name = getAtt(tt.Attr, "name")
- r.DocPr.Macro = getAtt(tt.Attr, "macro")
- r.DocPr.Hidden = getAtt(tt.Attr, "hidden")
+ d.DecodeElement(r.DocPr, &tt)
case "cNvGraphicFramePr":
var value WPCNvGraphicFramePr
- d.DecodeElement(&value, &start)
+ d.DecodeElement(&value, &tt)
r.CNvGraphicFramePr = &value
case "graphic":
var value AGraphic
- d.DecodeElement(&value, &start)
- value.XMLA = getAtt(tt.Attr, "a")
+ d.DecodeElement(&value, &tt)
r.Graphic = &value
default:
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
type WPExtent struct {
XMLName xml.Name `xml:"wp:extent,omitempty"`
- CX int `xml:"cx,attr"`
- CY int `xml:"cy,attr"`
+ CX int64 `xml:"cx,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.
type WPEffectExtent struct {
XMLName xml.Name `xml:"wp:effectExtent,omitempty"`
- L int `xml:"l,attr"`
- T int `xml:"t,attr"`
- R int `xml:"r,attr"`
- B int `xml:"b,attr"`
+ L int64 `xml:"l,attr"`
+ T int64 `xml:"t,attr"`
+ R int64 `xml:"r,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.
type WPDocPr struct {
XMLName xml.Name `xml:"wp:docPr,omitempty"`
- ID string `xml:"id,attr"`
+ ID int `xml:"id,attr"`
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.
@@ -197,7 +285,7 @@ func (w *WPCNvGraphicFramePr) UnmarshalXML(d *xml.Decoder, start xml.StartElemen
switch tt.Name.Local {
case "graphicFrameLocks":
var value AGraphicFrameLocks
- d.DecodeElement(&value, &start)
+ d.DecodeElement(&value, &tt)
value.NoChangeAspect, err = strconv.Atoi(getAtt(tt.Attr, "noChangeAspect"))
if err != nil {
return err
@@ -226,6 +314,14 @@ type AGraphic struct {
}
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 {
t, err := d.Token()
if err == io.EOF {
@@ -240,7 +336,7 @@ func (a *AGraphic) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
switch tt.Name.Local {
case "graphicData":
var value AGraphicData
- d.DecodeElement(&value, &start)
+ d.DecodeElement(&value, &tt)
value.URI = getAtt(tt.Attr, "uri")
a.GraphicData = &value
default:
@@ -274,7 +370,7 @@ func (a *AGraphicData) UnmarshalXML(d *xml.Decoder, start xml.StartElement) erro
switch tt.Name.Local {
case "pic":
var value PICPic
- d.DecodeElement(&value, &start)
+ d.DecodeElement(&value, &tt)
value.XMLPIC = getAtt(tt.Attr, "pic")
a.Pic = &value
default:
@@ -310,15 +406,15 @@ func (p *PICPic) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
switch tt.Name.Local {
case "nvPicPr":
var value PICNonVisualPicProperties
- d.DecodeElement(&value, &start)
+ d.DecodeElement(&value, &tt)
p.NonVisualPicProperties = &value
case "blipFill":
var value PICBlipFill
- d.DecodeElement(&value, &start)
+ d.DecodeElement(&value, &tt)
p.BlipFill = &value
case "spPr":
var value PICSpPr
- d.DecodeElement(&value, &start)
+ d.DecodeElement(&value, &tt)
p.SpPr = &value
default:
continue
@@ -389,10 +485,9 @@ func (p *PICBlipFill) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
case xml.StartElement:
switch tt.Name.Local {
case "blip":
- p.Blip.Embed = getAtt(tt.Attr, "embed")
- p.Blip.Cstate = getAtt(tt.Attr, "cstate")
+ d.DecodeElement(&p.Blip, &tt)
case "stretch":
- d.DecodeElement(&p.Stretch, &start)
+ d.DecodeElement(&p.Stretch, &tt)
default:
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.
type ABlip struct {
- XMLName xml.Name `xml:"a:blip,omitempty"`
- Embed string `xml:"r:embed,attr"`
- Cstate string `xml:"cstate,attr"`
+ XMLName xml.Name `xml:"a:blip,omitempty"`
+ Embed string `xml:"r:embed,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 ...
@@ -442,9 +582,9 @@ func (p *PICSpPr) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
case xml.StartElement:
switch tt.Name.Local {
case "xfrm":
- d.DecodeElement(&p.Xfrm, &start)
+ d.DecodeElement(&p.Xfrm, &tt)
case "prstGeom":
- d.DecodeElement(&p.PrstGeom, &start)
+ d.DecodeElement(&p.PrstGeom, &tt)
p.PrstGeom.Prst = getAtt(tt.Attr, "prst")
default:
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.
type AXfrm struct {
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
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 {
t, err := d.Token()
if err == io.EOF {
@@ -477,20 +641,20 @@ func (a *AXfrm) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
case xml.StartElement:
switch tt.Name.Local {
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 {
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 {
return err
}
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 {
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 {
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.
type AOff struct {
XMLName xml.Name `xml:"a:off,omitempty"`
- X int `xml:"x,attr"`
- Y int `xml:"y,attr"`
+ X int64 `xml:"x,attr"`
+ Y int64 `xml:"y,attr"`
}
// AExt is a struct representing the element in OpenXML,
// which describes the size of a shape.
type AExt struct {
XMLName xml.Name `xml:"a:ext,omitempty"`
- CX int `xml:"cx,attr"`
- CY int `xml:"cy,attr"`
+ CX int64 `xml:"cx,attr"`
+ CY int64 `xml:"cy,attr"`
}
// APrstGeom is a struct representing the element in OpenXML,
@@ -566,3 +730,233 @@ func (a *AAvLst) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error
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"`
+}
diff --git a/structlink.go b/structlink.go
index 0f63296..4720fb8 100644
--- a/structlink.go
+++ b/structlink.go
@@ -25,7 +25,7 @@ func (r *Hyperlink) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
switch tt := t.(type) {
case xml.StartElement:
if tt.Name.Local == "r" {
- d.DecodeElement(&r.Run, &start)
+ d.DecodeElement(&r.Run, &tt)
} else {
continue
}
diff --git a/structpara.go b/structpara.go
index 6b5887a..2806518 100644
--- a/structpara.go
+++ b/structpara.go
@@ -121,7 +121,7 @@ func (p *Paragraph) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
switch tt.Name.Local {
case "hyperlink":
var value Hyperlink
- d.DecodeElement(&value, &start)
+ d.DecodeElement(&value, &tt)
id := getAtt(tt.Attr, "id")
anchor := getAtt(tt.Attr, "anchor")
if id != "" {
@@ -133,15 +133,15 @@ func (p *Paragraph) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
elem.Link = &value
case "r":
var value Run
- d.DecodeElement(&value, &start)
+ d.DecodeElement(&value, &tt)
elem.Run = &value
case "rPr":
var value RunProperties
- d.DecodeElement(&value, &start)
+ d.DecodeElement(&value, &tt)
elem.Properties = &value
case "pPr":
var value ParagraphProperties
- d.DecodeElement(&value, &start)
+ d.DecodeElement(&value, &tt)
p.Properties = &value
continue
default:
diff --git a/structrun.go b/structrun.go
index cefca80..396bf67 100644
--- a/structrun.go
+++ b/structrun.go
@@ -36,19 +36,19 @@ func (r *Run) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
switch tt.Name.Local {
case "rPr":
var value RunProperties
- d.DecodeElement(&value, &start)
+ d.DecodeElement(&value, &tt)
r.RunProperties = &value
case "instrText":
var value string
- d.DecodeElement(&value, &start)
+ d.DecodeElement(&value, &tt)
r.InstrText = value
case "t":
var value Text
- d.DecodeElement(&value, &start)
+ d.DecodeElement(&value, &tt)
r.Text = &value
case "drawing":
var value Drawing
- d.DecodeElement(&value, &start)
+ d.DecodeElement(&value, &tt)
r.Drawing = &value
case "tab":
if r.InstrText == "" && r.Text == nil && r.Drawing == nil {