1
0
mirror of https://github.com/fumiama/go-docx.git synced 2026-06-27 06:30:24 +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 {
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
}
}

View File

@@ -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 {

View File

@@ -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)

View File

@@ -111,7 +111,7 @@ const drawing_doc = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:noProof/>
</w:rPr>
<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:effectExtent l="0" t="0" r="0" b="0"/>
<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:rPr>
<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:effectExtent l="0" t="0" r="0" b="4445"/>
<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:rPr>
<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:effectExtent l="0" t="0" r="0" b="4445"/>
<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:Choice Requires="wpg">
<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:effectExtent l="0" t="0" r="0" b="4445"/>
<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:rPr>
<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:positionH relativeFrom="column">
<wp:posOffset>2935605</wp:posOffset>
@@ -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")
}*/
}
}

View File

@@ -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 <a:ext> 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 <a:prstGeom> 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"`
}

View File

@@ -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
}

View File

@@ -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:

View File

@@ -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 {