diff --git a/cmd/main/main.go b/cmd/main/main.go index 02703e0..883b280 100644 --- a/cmd/main/main.go +++ b/cmd/main/main.go @@ -46,7 +46,7 @@ func main() { if !*analyzeOnly { fmt.Printf("Preparing new document to write at %s\n", *fileLocation) - w = docx.New().WithDefaultTheme() + w = docx.New().WithDefaultTheme().WithA4Page() // add new paragraph para1 := w.AddParagraph().Justification("distribute") r, err := para1.AddAnchorDrawingFrom("testdata/fumiama.JPG") @@ -254,7 +254,7 @@ func main() { if err != nil { panic(err) } - newFile := docx.New().WithDefaultTheme() + newFile := docx.New().WithDefaultTheme().WithA4Page() for i := 0; i < int(*dupnum); i++ { newFile.AppendFile(doc) } diff --git a/pack.go b/pack.go index 1927976..b864691 100644 --- a/pack.go +++ b/pack.go @@ -36,7 +36,7 @@ func (f *Docx) pack(zipWriter *zip.Writer) (err error) { if f.template != "" { for _, name := range f.tmpfslst { - files[name], err = TemplateXMLFS.Open("xml/" + f.template + "/" + name) + files[name], err = f.tmplfs.Open("xml/" + f.template + "/" + name) if err != nil { return } diff --git a/structdoc.go b/structdoc.go index 91cc0a5..4265fa4 100644 --- a/structdoc.go +++ b/structdoc.go @@ -90,6 +90,13 @@ func (b *Body) UnmarshalXML(d *xml.Decoder, _ xml.StartElement) error { return err } b.Items = append(b.Items, &value) + case "sectPr": + var value SectPr + err = d.DecodeElement(&value, &tt) + if err != nil && !strings.HasPrefix(err.Error(), "expected") { + return err + } + b.Items = append(b.Items, &value) default: err = d.Skip() // skip unsupported tags if err != nil { diff --git a/structdoc_test.go b/structdoc_test.go index fa1a840..f1eb2e8 100644 --- a/structdoc_test.go +++ b/structdoc_test.go @@ -33,8 +33,8 @@ func TestUnmarshalPlainStructure(t *testing.T) { content string numParagraphs int }{ - {decoded_doc_1, 5}, - {decoded_doc_2, 14}, + {decoded_doc_1, 6}, + {decoded_doc_2, 15}, } for _, tc := range testCases { doc := Document{ @@ -50,16 +50,22 @@ func TestUnmarshalPlainStructure(t *testing.T) { t.Fatalf("We expected %d paragraphs, we got %d", tc.numParagraphs, len(doc.Body.Items)) } for i, it := range doc.Body.Items { - p := it.(*Paragraph) - if len(p.Children) == 0 { - t.Fatalf("We were not able to parse paragraph %d", i) - } - for _, child := range p.Children { - if child == nil { - t.Fatalf("There are Paragraph children with all fields nil") + switch v := it.(type) { + case *Paragraph: + if len(v.Children) == 0 { + t.Fatalf("We were not able to parse paragraph %d", i) } - if o, ok := child.(*Hyperlink); ok && o.ID == "" { - t.Fatalf("We have a link without ID") + for _, child := range v.Children { + if child == nil { + t.Fatalf("There are Paragraph children with all fields nil") + } + if o, ok := child.(*Hyperlink); ok && o.ID == "" { + t.Fatalf("We have a link without ID") + } + } + case *SectPr: + if v.PgSz.W.Value != "11906" || v.PgSz.H.Value != "16838" { + t.Fatalf("We were not able to parse sectPr") } } } diff --git a/structsect.go b/structsect.go new file mode 100644 index 0000000..f200cd3 --- /dev/null +++ b/structsect.go @@ -0,0 +1,85 @@ +/* + Copyright (c) 2024 mabiao0525 (马飚) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package docx + +import ( + "encoding/xml" + "io" + "strings" +) + +// SectPr show the properties of the document, like paper size +type SectPr struct { + XMLName xml.Name `xml:"w:sectPr,omitempty"` // properties of the document, including paper size + PgSz *PgSz `xml:"w:pgSz,omitempty"` +} + +// PgSz show the paper size +type PgSz struct { + W xml.Attr `xml:"w:w,attr"` // width of paper + H xml.Attr `xml:"w:h,attr"` // high of paper +} + +// UnmarshalXML ... +func (sect *SectPr) UnmarshalXML(d *xml.Decoder, _ 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 "pgSz": + var value PgSz + err = d.DecodeElement(&value, &tt) + if err != nil && !strings.HasPrefix(err.Error(), "expected") { + return err + } + sect.PgSz = &value + default: + err = d.Skip() // skip unsupported tags + if err != nil { + return err + } + } + } + } + return nil +} + +// UnmarshalXML ... +func (pgsz *PgSz) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + var err error + + for _, attr := range start.Attr { + switch attr.Name.Local { + case "w": + pgsz.W = xml.Attr{Name: xml.Name{Local: "w:w"}, Value: attr.Value} + case "h": + pgsz.H = xml.Attr{Name: xml.Name{Local: "w:w"}, Value: attr.Value} + default: + //ignore other attributes now + } + } + // Consume the end element + _, err = d.Token() + return err +} diff --git a/theme.go b/theme.go index 6748b49..000c0a9 100644 --- a/theme.go +++ b/theme.go @@ -20,7 +20,10 @@ package docx -import "io/fs" +import ( + "encoding/xml" + "io/fs" +) // UseTemplate will replace template files func (f *Docx) UseTemplate(template string, tmpfslst []string, tmplfs fs.FS) *Docx { @@ -34,3 +37,27 @@ func (f *Docx) UseTemplate(template string, tmpfslst []string, tmplfs fs.FS) *Do func (f *Docx) WithDefaultTheme() *Docx { return f.UseTemplate("default", DefaultTemplateFilesList, TemplateXMLFS) } + +// WithA3Page use A3 PageSize +func (f *Docx) WithA3Page() *Docx { + sectpr := &SectPr{ + PgSz: &PgSz{ + W: xml.Attr{Name: xml.Name{Local: "w:w"}, Value: "16838"}, + H: xml.Attr{Name: xml.Name{Local: "w:h"}, Value: "23811"}, + }, + } + f.Document.Body.Items = append(f.Document.Body.Items, sectpr) + return f +} + +// WithA4Page use A4 PageSize +func (f *Docx) WithA4Page() *Docx { + sectpr := &SectPr{ + PgSz: &PgSz{ + W: xml.Attr{Name: xml.Name{Local: "w:w"}, Value: "11906"}, + H: xml.Attr{Name: xml.Name{Local: "w:h"}, Value: "16838"}, + }, + } + f.Document.Body.Items = append(f.Document.Body.Items, sectpr) + return f +}