From 50aa6e005ee8bb2a9223ea0ebed95840e4251927 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: Sun, 5 Mar 2023 23:02:07 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84group?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apidrawing.go | 18 ++++---- apishape.go | 4 +- structdrawing.go | 44 ++++++++++++------ structeffects.go | 111 ++++++++++++++++++++++++++++++++++++++++++++- structgroup.go | 105 +++++++++++++++++++++++++++++++++++++++--- structshape.go | 116 ++--------------------------------------------- 6 files changed, 257 insertions(+), 141 deletions(-) diff --git a/apidrawing.go b/apidrawing.go index b21c487..8567851 100644 --- a/apidrawing.go +++ b/apidrawing.go @@ -36,7 +36,8 @@ func (p *Paragraph) AddInlineDrawing(pic []byte) (*Run, error) { return nil, err } idn := int(atomic.AddUintptr(&p.file.docID, 1)) - id := strconv.Itoa(int(p.file.IncreaseID("图片"))) + id := int(p.file.IncreaseID("图片")) + ids := strconv.Itoa(id) rid := p.file.addImage(format, pic) w, h := int64(sz.Width), int64(sz.Height) if float64(w)/float64(h) > 1.2 { @@ -58,7 +59,7 @@ func (p *Paragraph) AddInlineDrawing(pic []byte) (*Run, error) { EffectExtent: &WPEffectExtent{}, DocPr: &WPDocPr{ ID: idn, - Name: "图片 " + id, + Name: "图片 " + ids, }, CNvGraphicFramePr: &WPCNvGraphicFramePr{ Locks: AGraphicFrameLocks{ @@ -72,9 +73,9 @@ func (p *Paragraph) AddInlineDrawing(pic []byte) (*Run, error) { Pic: &Picture{ XMLPIC: XMLNS_DRAWINGML_PICTURE, NonVisualPicProperties: &PICNonVisualPicProperties{ - NonVisualDrawingProperties: PICNonVisualDrawingProperties{ + NonVisualDrawingProperties: NonVisualProperties{ ID: id, - Name: "图片 " + id, + Name: "图片 " + ids, }, }, BlipFill: &PICBlipFill{ @@ -137,7 +138,8 @@ func (p *Paragraph) AddAnchorDrawing(pic []byte) (*Run, error) { return nil, err } idn := int(atomic.AddUintptr(&p.file.docID, 1)) - id := strconv.Itoa(int(p.file.IncreaseID("图片"))) + id := int(p.file.IncreaseID("图片")) + ids := strconv.Itoa(id) rid := p.file.addImage(format, pic) w, h := int64(sz.Width), int64(sz.Height) if float64(w)/float64(h) > 1.2 { @@ -168,7 +170,7 @@ func (p *Paragraph) AddAnchorDrawing(pic []byte) (*Run, error) { WrapNone: &struct{}{}, DocPr: &WPDocPr{ ID: idn, - Name: "图片 " + id, + Name: "图片 " + ids, }, CNvGraphicFramePr: &WPCNvGraphicFramePr{ Locks: AGraphicFrameLocks{ @@ -182,9 +184,9 @@ func (p *Paragraph) AddAnchorDrawing(pic []byte) (*Run, error) { Pic: &Picture{ XMLPIC: XMLNS_DRAWINGML_PICTURE, NonVisualPicProperties: &PICNonVisualPicProperties{ - NonVisualDrawingProperties: PICNonVisualDrawingProperties{ + NonVisualDrawingProperties: NonVisualProperties{ ID: id, - Name: "图片 " + id, + Name: "图片 " + ids, }, }, BlipFill: &PICBlipFill{ diff --git a/apishape.go b/apishape.go index 47701af..5ebcd49 100644 --- a/apishape.go +++ b/apishape.go @@ -49,7 +49,7 @@ func (p *Paragraph) AddInlineShape(w, h int64, name, bwMode, prst string, ln *AL CNvCnPr: &WPSCNvCnPr{ ConnShapeLocks: &struct{}{}, }, - SpPr: &WPSSpPr{ + SpPr: &ShapeProperties{ BWMode: bwMode, Xfrm: AXfrm{ @@ -116,7 +116,7 @@ func (p *Paragraph) AddAnchorShape(w, h int64, name, bwMode, prst string, ln *AL CNvCnPr: &WPSCNvCnPr{ ConnShapeLocks: &struct{}{}, }, - SpPr: &WPSSpPr{ + SpPr: &ShapeProperties{ BWMode: bwMode, Xfrm: AXfrm{ diff --git a/structdrawing.go b/structdrawing.go index fcf627e..745ce7b 100644 --- a/structdrawing.go +++ b/structdrawing.go @@ -417,15 +417,25 @@ func (a *AGraphic) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { type AGraphicData struct { XMLName xml.Name `xml:"a:graphicData,omitempty"` URI string `xml:"uri,attr"` - Pic *Picture - Shape *WordprocessingShape - Canvas *WordprocessingCanvas + + Pic *Picture + Shape *WordprocessingShape + Canvas *WordprocessingCanvas + Group *WordprocessingGroup file *Docx } // UnmarshalXML ... func (a *AGraphicData) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + for _, attr := range start.Attr { + switch attr.Name.Local { + case "uri": + a.URI = attr.Value + default: + // ignore other attributes + } + } for { t, err := d.Token() if err == io.EOF { @@ -461,6 +471,14 @@ func (a *AGraphicData) UnmarshalXML(d *xml.Decoder, start xml.StartElement) erro return err } a.Canvas = &value + case "wgp": + var value WordprocessingGroup + value.file = a.file + err = d.DecodeElement(&value, &tt) + if err != nil && !strings.HasPrefix(err.Error(), "expected") { + return err + } + a.Group = &value default: err = d.Skip() // skip unsupported tags if err != nil { @@ -530,8 +548,8 @@ func (p *Picture) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { // PICNonVisualPicProperties represents the non-visual properties of a picture in a Word document. type PICNonVisualPicProperties struct { - XMLName xml.Name `xml:"pic:nvPicPr,omitempty"` - NonVisualDrawingProperties PICNonVisualDrawingProperties + XMLName xml.Name `xml:"pic:nvPicPr,omitempty"` + NonVisualDrawingProperties NonVisualProperties `xml:"pic:cNvPr,omitempty"` CNvPicPr PicCNvPicPr } @@ -549,7 +567,14 @@ func (p *PICNonVisualPicProperties) UnmarshalXML(d *xml.Decoder, start xml.Start if tt, ok := t.(xml.StartElement); ok { switch tt.Name.Local { case "cNvPr": - p.NonVisualDrawingProperties.ID = getAtt(tt.Attr, "id") + v := getAtt(tt.Attr, "id") + if v == "" { + continue + } + p.NonVisualDrawingProperties.ID, err = strconv.Atoi(v) + if err != nil { + return err + } p.NonVisualDrawingProperties.Name = getAtt(tt.Attr, "name") case "cNvPicPr": err = d.DecodeElement(&p.CNvPicPr, &tt) @@ -618,13 +643,6 @@ type APicLocks struct { NoChangeAspect int `xml:"noChangeAspect,attr"` } -// PICNonVisualDrawingProperties represents the non-visual drawing properties of a picture in a Word document. -type PICNonVisualDrawingProperties struct { - XMLName xml.Name `xml:"pic:cNvPr,omitempty"` - ID string `xml:"id,attr"` - Name string `xml:"name,attr"` -} - // PICBlipFill represents the blip fill of a picture in a Word document. type PICBlipFill struct { XMLName xml.Name `xml:"pic:blipFill,omitempty"` diff --git a/structeffects.go b/structeffects.go index 2dc0ad8..a531de1 100644 --- a/structeffects.go +++ b/structeffects.go @@ -20,7 +20,12 @@ package docx -import "encoding/xml" +import ( + "encoding/xml" + "io" + "strconv" + "strings" +) // RunStyle contains styling for a run type RunStyle struct { @@ -162,3 +167,107 @@ type OverflowPunct struct { XMLName xml.Name `xml:"w:overflowPunct,omitempty"` Val int `xml:"w:val,attr"` } + +// ShapeProperties is a container element that represents the visual properties of a shape. +type ShapeProperties struct { + BWMode string `xml:"bwMode,attr"` + + Xfrm AXfrm + PrstGeom APrstGeom + SolidFill *ASolidFill + BlipFill *ABlipFill + NoFill *struct{} `xml:"a:noFill,omitempty"` + Line *ALine + + // EffectList struct{} `xml:"a:effectLst"` + // ExtList struct{} `xml:"a:extLst"` +} + +// UnmarshalXML ... +func (w *ShapeProperties) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + for _, attr := range start.Attr { + switch attr.Name.Local { + case "bwMode": + w.BWMode = attr.Value + default: + // ignore other attributes + } + } + for { + t, err := d.Token() + if err == io.EOF { + break + } + if err != nil { + return err + } + + if tt, ok := t.(xml.StartElement); ok { + switch tt.Name.Local { + case "xfrm": + err = d.DecodeElement(&w.Xfrm, &tt) + if err != nil && !strings.HasPrefix(err.Error(), "expected") { + return err + } + case "prstGeom": + w.PrstGeom.Prst = getAtt(tt.Attr, "prst") + case "solidFill": + var value ASolidFill + err = d.DecodeElement(&value, &tt) + if err != nil && !strings.HasPrefix(err.Error(), "expected") { + return err + } + w.SolidFill = &value + case "blipFill": + var value ABlipFill + err = d.DecodeElement(&value, &tt) + if err != nil && !strings.HasPrefix(err.Error(), "expected") { + return err + } + w.BlipFill = &value + case "noFill": + w.NoFill = &struct{}{} + case "ln": + var ln ALine + err = d.DecodeElement(&ln, &tt) + if err != nil && !strings.HasPrefix(err.Error(), "expected") { + return err + } + w.Line = &ln + default: + err = d.Skip() // skip unsupported tags + if err != nil { + return err + } + continue + } + } + } + return nil +} + +// NonVisualProperties is an element that represents the non-visual properties of a content control. +type NonVisualProperties struct { + ID int `xml:"id,attr"` + Name string `xml:"name,attr"` +} + +// UnmarshalXML ... +func (r *NonVisualProperties) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error) { + for _, attr := range start.Attr { + switch attr.Name.Local { + case "id": + r.ID, err = strconv.Atoi(attr.Value) + if err != nil { + return + } + case "name": + r.Name = attr.Value + default: + // ignore other attributes + } + } + // Consume the end element + _, err = d.Token() + return +} diff --git a/structgroup.go b/structgroup.go index dcd17ed..5941dca 100644 --- a/structgroup.go +++ b/structgroup.go @@ -30,8 +30,10 @@ import ( type WordprocessingGroup struct { XMLName xml.Name `xml:"wpg:wgp,omitempty"` CNvGrpSpPr *WPGcNvGrpSpPr - GroupShapeProperties *WPGGroupShapeProperties + GroupShapeProperties *ShapeProperties `xml:"wpg:grpSpPr,omitempty"` Elems []interface{} + + file *Docx } // UnmarshalXML ... @@ -55,7 +57,7 @@ func (w *WordprocessingGroup) UnmarshalXML(d *xml.Decoder, start xml.StartElemen } w.CNvGrpSpPr = &value case "grpSpPr": - var value WPGGroupShapeProperties + var value ShapeProperties err = d.DecodeElement(&value, &tt) if err != nil && !strings.HasPrefix(err.Error(), "expected") { return err @@ -70,6 +72,23 @@ func (w *WordprocessingGroup) UnmarshalXML(d *xml.Decoder, start xml.StartElemen w.Elems = append(w.Elems, &value) case "wsp": var value WordprocessingShape + value.file = w.file + err = d.DecodeElement(&value, &tt) + if err != nil && !strings.HasPrefix(err.Error(), "expected") { + return err + } + w.Elems = append(w.Elems, &value) + case "wpc": + var value WordprocessingCanvas + value.file = w.file + err = d.DecodeElement(&value, &tt) + if err != nil && !strings.HasPrefix(err.Error(), "expected") { + return err + } + w.Elems = append(w.Elems, &value) + case "grpSp": + var value WPGGroupShape + value.file = w.file err = d.DecodeElement(&value, &tt) if err != nil && !strings.HasPrefix(err.Error(), "expected") { return err @@ -129,8 +148,82 @@ type AGroupShapeLocks struct { XMLName xml.Name `xml:"a:grpSpLocks,omitempty"` } -// WPGGroupShapeProperties represents the properties applied to a group shape. -type WPGGroupShapeProperties struct { - XMLName xml.Name `xml:"wpg:grpSpPr,omitempty"` - Xfrm *AXfrm +// WPGGroupShape ... +type WPGGroupShape struct { + XMLName xml.Name `xml:"wpg:grpSp,omitempty"` + CNvPr *NonVisualProperties `xml:"wpg:cNvPr,omitempty"` + CNvGrpSpPr *WPGcNvGrpSpPr + GroupShapeProperties *ShapeProperties `xml:"wpg:grpSpPr,omitempty"` + Elems []interface{} + + file *Docx +} + +// UnmarshalXML ... +func (w *WPGGroupShape) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + for { + t, err := d.Token() + if err == io.EOF { + break + } + if err != nil { + return err + } + + if tt, ok := t.(xml.StartElement); ok { + switch tt.Name.Local { + case "cNvPr": + var value NonVisualProperties + err = d.DecodeElement(&value, &tt) + if err != nil && !strings.HasPrefix(err.Error(), "expected") { + return err + } + w.CNvPr = &value + case "cNvGrpSpPr": + var value WPGcNvGrpSpPr + err = d.DecodeElement(&value, &tt) + if err != nil && !strings.HasPrefix(err.Error(), "expected") { + return err + } + w.CNvGrpSpPr = &value + case "grpSpPr": + var value ShapeProperties + err = d.DecodeElement(&value, &tt) + if err != nil && !strings.HasPrefix(err.Error(), "expected") { + return err + } + w.GroupShapeProperties = &value + case "pic": + var value Picture + err = d.DecodeElement(&value, &tt) + if err != nil && !strings.HasPrefix(err.Error(), "expected") { + return err + } + w.Elems = append(w.Elems, &value) + case "wsp": + var value WordprocessingShape + value.file = w.file + err = d.DecodeElement(&value, &tt) + if err != nil && !strings.HasPrefix(err.Error(), "expected") { + return err + } + w.Elems = append(w.Elems, &value) + case "wpc": + var value WordprocessingCanvas + value.file = w.file + err = d.DecodeElement(&value, &tt) + if err != nil && !strings.HasPrefix(err.Error(), "expected") { + return err + } + w.Elems = append(w.Elems, &value) + default: + err = d.Skip() // skip unsupported tags + if err != nil { + return err + } + continue + } + } + } + return nil } diff --git a/structshape.go b/structshape.go index 1016e39..47c7bed 100644 --- a/structshape.go +++ b/structshape.go @@ -29,11 +29,11 @@ import ( // WordprocessingShape is a container for a WordprocessingML DrawingML shape. type WordprocessingShape struct { - XMLName xml.Name `xml:"wps:wsp,omitempty"` - CNvPr *WPSCNvPr + XMLName xml.Name `xml:"wps:wsp,omitempty"` + CNvPr *NonVisualProperties `xml:"wps:cNvPr,omitempty"` CNvCnPr *WPSCNvCnPr CNvSpPr *WPSCNvSpPr - SpPr *WPSSpPr + SpPr *ShapeProperties `xml:"wps:spPr,omitempty"` TextBox *WPSTextBox BodyPr *WPSBodyPr @@ -54,7 +54,7 @@ func (w *WordprocessingShape) UnmarshalXML(d *xml.Decoder, start xml.StartElemen if tt, ok := t.(xml.StartElement); ok { switch tt.Name.Local { case "cNvPr": - w.CNvPr = new(WPSCNvPr) + w.CNvPr = new(NonVisualProperties) err = d.DecodeElement(w.CNvPr, &tt) if err != nil && !strings.HasPrefix(err.Error(), "expected") { return err @@ -72,7 +72,7 @@ func (w *WordprocessingShape) UnmarshalXML(d *xml.Decoder, start xml.StartElemen return err } case "spPr": - w.SpPr = new(WPSSpPr) + w.SpPr = new(ShapeProperties) err = d.DecodeElement(w.SpPr, &tt) if err != nil && !strings.HasPrefix(err.Error(), "expected") { return err @@ -102,33 +102,6 @@ func (w *WordprocessingShape) UnmarshalXML(d *xml.Decoder, start xml.StartElemen return nil } -// WPSCNvPr is an element that represents the non-visual properties of a content control. -type WPSCNvPr struct { - XMLName xml.Name `xml:"wps:cNvPr,omitempty"` - ID int `xml:"id,attr"` - Name string `xml:"name,attr"` -} - -// UnmarshalXML ... -func (r *WPSCNvPr) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error) { - for _, attr := range start.Attr { - switch attr.Name.Local { - case "id": - r.ID, err = strconv.Atoi(attr.Value) - if err != nil { - return - } - case "name": - r.Name = attr.Value - default: - // ignore other attributes - } - } - // Consume the end element - _, err = d.Token() - return -} - // WPSCNvCnPr represents the non-visual drawing properties of a connector. type WPSCNvCnPr struct { XMLName xml.Name `xml:"wps:cNvCnPr,omitempty"` @@ -237,85 +210,6 @@ func (l *ASPLocks) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err err return err } -// WPSSpPr is a container element that represents the visual properties of a shape. -type WPSSpPr struct { - XMLName xml.Name `xml:"wps:spPr,omitempty"` - BWMode string `xml:"bwMode,attr"` - - Xfrm AXfrm - PrstGeom APrstGeom - SolidFill *ASolidFill - BlipFill *ABlipFill - NoFill *struct{} `xml:"a:noFill,omitempty"` - Line *ALine - - // EffectList struct{} `xml:"a:effectLst"` - // ExtList struct{} `xml:"a:extLst"` -} - -// UnmarshalXML ... -func (w *WPSSpPr) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { - for _, attr := range start.Attr { - switch attr.Name.Local { - case "bwMode": - w.BWMode = attr.Value - default: - // ignore other attributes - } - } - for { - t, err := d.Token() - if err == io.EOF { - break - } - if err != nil { - return err - } - - if tt, ok := t.(xml.StartElement); ok { - switch tt.Name.Local { - case "xfrm": - err = d.DecodeElement(&w.Xfrm, &tt) - if err != nil && !strings.HasPrefix(err.Error(), "expected") { - return err - } - case "prstGeom": - w.PrstGeom.Prst = getAtt(tt.Attr, "prst") - case "solidFill": - var value ASolidFill - err = d.DecodeElement(&value, &tt) - if err != nil && !strings.HasPrefix(err.Error(), "expected") { - return err - } - w.SolidFill = &value - case "blipFill": - var value ABlipFill - err = d.DecodeElement(&value, &tt) - if err != nil && !strings.HasPrefix(err.Error(), "expected") { - return err - } - w.BlipFill = &value - case "noFill": - w.NoFill = &struct{}{} - case "ln": - var ln ALine - err = d.DecodeElement(&ln, &tt) - if err != nil && !strings.HasPrefix(err.Error(), "expected") { - return err - } - w.Line = &ln - default: - err = d.Skip() // skip unsupported tags - if err != nil { - return err - } - continue - } - } - } - return nil -} - // ABlipFill represents a fill that contains a reference to an image. type ABlipFill struct { XMLName xml.Name `xml:"a:blipFill,omitempty"`