Skip to content

Commit

Permalink
add AddInlineDrawingFrom
Browse files Browse the repository at this point in the history
  • Loading branch information
fumiama committed Feb 20, 2023
1 parent f07b5dd commit 292a298
Show file tree
Hide file tree
Showing 27 changed files with 635 additions and 131 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
docxlib
.vscode/
*.docx
/*.xml
/*.xml
.DS_Store
96 changes: 92 additions & 4 deletions apidrawing.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,95 @@
package docxlib

// AddDrawing adds drawing to paragraph
func (p *Paragraph) AddDrawing(pic []byte) *Run {
//TODO: finish add drawing
return nil
import (
"bytes"
"fmt"
"math/rand"
"os"
"strconv"
"sync/atomic"

"github.com/fumiama/imgsz"
)

// AddInlineDrawing adds inline drawing to paragraph
func (p *Paragraph) AddInlineDrawing(pic []byte) (*Run, error) {
sz, format, err := imgsz.DecodeSize(bytes.NewReader(pic))
if err != nil {
return nil, err
}
id := strconv.Itoa(int(atomic.AddUintptr(&p.file.imageId, 1)))
rId := p.file.addImage(Media{Name: "image" + id + "." + format, Data: pic})
w, h := sz.Width, 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{
Inline: &WPInline{
AnchorID: fmt.Sprintf("%08X", rand.Uint32()),
EditID: fmt.Sprintf("%08X", rand.Uint32()),

Extent: &WPExtent{
CX: w,
CY: h,
},
EffectExtent: &WPEffectExtent{},
DocPr: &WPDocPr{
ID: id,
Name: "图片 " + id,
},
CNvGraphicFramePr: &WPCNvGraphicFramePr{
Locks: &AGraphicFrameLocks{
NoChangeAspect: 1,
},
},
Graphic: &AGraphic{
GraphicData: &AGraphicData{
URI: XMLNS_PICTURE,
Pic: &PICPic{
NonVisualPicProperties: &PICNonVisualPicProperties{
NonVisualDrawingProperties: PICNonVisualDrawingProperties{
ID: 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) AddInlineDrawingFrom(file string) (*Run, error) {
data, err := os.ReadFile(file)
if err != nil {
return nil, err
}
return p.AddInlineDrawing(data)
}
19 changes: 0 additions & 19 deletions apilink.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,9 @@
package docxlib

import (
"strconv"
"sync/atomic"
)

const (
HYPERLINK_STYLE = "a1"
)

// when adding an hyperlink we need to store a reference in the relationship field
func (f *Docx) addLinkRelation(link string) string {
rel := &Relationship{
ID: "rId" + strconv.Itoa(int(atomic.AddUintptr(&f.rId, 1))),
Type: REL_HYPERLINK,
Target: link,
TargetMode: REL_TARGETMODE,
}

f.DocRelation.Relationships = append(f.DocRelation.Relationships, rel)

return rel.ID
}

// AddLink adds an hyperlink to paragraph
func (p *Paragraph) AddLink(text string, link string) *Hyperlink {
rId := p.file.addLinkRelation(link)
Expand Down
29 changes: 0 additions & 29 deletions apitext.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package docxlib

import "strings"

// AddText adds text to paragraph
func (p *Paragraph) AddText(text string) *Run {
t := &Text{
Expand All @@ -17,30 +15,3 @@ func (p *Paragraph) AddText(text string) *Run {

return run
}

func (p *Paragraph) String() string {
sb := strings.Builder{}
for _, c := range p.Children {
switch {
case c.Link != nil:
id := c.Link.ID
text := c.Link.Run.InstrText
link, err := p.file.Refer(id)
sb.WriteString(text)
sb.WriteByte('(')
if err != nil {
sb.WriteString(id)
} else {
sb.WriteString(link)
}
sb.WriteByte(')')
case c.Run != nil:
sb.WriteString("run") //TODO: implement
case c.Properties != nil:
sb.WriteString("prop") //TODO: implement
default:
continue
}
}
return sb.String()
}
4 changes: 2 additions & 2 deletions cmd/getstructure/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ 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.DistT) // TODO: replace to refid
fmt.Printf("\tWe've found a new run with the drawing ->%d\n", child.Run.Drawing.Inline.DistT) // TODO: replace to refid
}
}
if child.Link != nil {
id := child.Link.ID
text := child.Link.Run.InstrText
link, err := doc.Refer(id)
link, err := doc.ReferHref(id)
if err != nil {
fmt.Printf("\tWe found a link with id %s and text %s without target\n", id, text)
} else {
Expand Down
17 changes: 14 additions & 3 deletions cmd/main/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ func main() {
nextPara := w.AddParagraph()
nextPara.AddLink("google", `http://google.com`)

para3 := w.AddParagraph()
// add text
para3.AddText("直接粘贴 inline")

para4 := w.AddParagraph()
para4.AddInlineDrawingFrom("testdata/fumiama.JPG")
para4.AddInlineDrawingFrom("testdata/fumiama2x.webp")

para5 := w.AddParagraph()
para5.AddInlineDrawingFrom("testdata/fumiamayoko.png")

f, err := os.Create(*fileLocation)
if err != nil {
panic(err)
Expand Down Expand Up @@ -66,13 +77,13 @@ 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.DistT) // TODO: replace to refid
fmt.Printf("\tWe've found a new run with the drawing ->%d\n", child.Run.Drawing.Inline.DistT) // TODO: replace to refid
}
}
if child.Link != nil {
id := child.Link.ID
text := child.Link.Run.InstrText
link, err := doc.Refer(id)
link, err := doc.ReferHref(id)
if err != nil {
fmt.Printf("\tWe found a link with id %s and text %s without target\n", id, text)
} else {
Expand All @@ -83,7 +94,7 @@ func main() {
}
fmt.Print("End of paragraph\n\n")
}
f, err = os.Create("tmp.docx")
f, err = os.Create("unmarshal_" + *fileLocation)
if err != nil {
panic(err)
}
Expand Down
18 changes: 5 additions & 13 deletions docxlib.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ type Docx struct {
Document Document
DocRelation Relationships

rId uintptr
media []Media
mediaNameIdx map[string]int

rId uintptr
imageId uintptr

buf *bytes.Buffer
isbufempty bool
Expand Down Expand Up @@ -93,15 +97,3 @@ func (f *Docx) Read(p []byte) (n int, err error) {
f.isbufempty = false
return f.buf.Read(p)
}

// Refer gets the url for a reference
func (f *Docx) Refer(id string) (href string, err error) {
for _, a := range f.DocRelation.Relationships {
if a.ID == id {
href = a.Target
return
}
}
err = ErrRefIDNotFound
return
}
6 changes: 4 additions & 2 deletions empty.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ func newEmptyFile() *Docx {
},
},
},
rId: 3,
buf: bytes.NewBuffer(make([]byte, 0, 1024*1024*4)),
media: make([]Media, 0, 64),
mediaNameIdx: make(map[string]int, 64),
rId: 3,
buf: bytes.NewBuffer(make([]byte, 0, 1024*1024*4)),
}
docx.Document.file = docx
return docx
Expand Down
File renamed without changes.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module github.com/fumiama/docxlib

go 1.16

require github.com/fumiama/imgsz v0.0.2
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/fumiama/imgsz v0.0.2 h1:fAkC0FnIscdKOXwAxlyw3EUba5NzxZdSxGaq3Uyfxak=
github.com/fumiama/imgsz v0.0.2/go.mod h1:dR71mI3I2O5u6+PCpd47M9TZptzP+39tRBcbdIkoqM4=
7 changes: 7 additions & 0 deletions image.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package docxlib

// addImage add image to docx and return its rId
func (f *Docx) addImage(m Media) string {
f.addMedia(m)
return f.addImageRelation(m)
}
51 changes: 51 additions & 0 deletions link.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package docxlib

import (
"strconv"
"sync/atomic"
)

// when adding an hyperlink we need to store a reference in the relationship field
//
// this func is not thread-safe
func (f *Docx) addLinkRelation(link string) string {
rel := &Relationship{
ID: "rId" + strconv.Itoa(int(atomic.AddUintptr(&f.rId, 1))),
Type: REL_HYPERLINK,
Target: link,
TargetMode: REL_TARGETMODE,
}

f.DocRelation.Relationships = append(f.DocRelation.Relationships, rel)

return rel.ID
}

// when adding an image we need to store a reference in the relationship field
//
// this func is not thread-safe
func (f *Docx) addImageRelation(m Media) string {
rel := &Relationship{
ID: "rId" + strconv.Itoa(int(atomic.AddUintptr(&f.rId, 1))),
Type: REL_IMAGE,
Target: "media/" + m.Name,
}

f.DocRelation.Relationships = append(f.DocRelation.Relationships, rel)

return rel.ID
}

// ReferHref gets the url for a reference
func (f *Docx) ReferHref(id string) (href string, err error) {
f.DocRelation.mu.RLock()
defer f.DocRelation.mu.RUnlock()
for _, a := range f.DocRelation.Relationships {
if a.ID == id {
href = a.Target
return
}
}
err = ErrRefIDNotFound
return
}
29 changes: 29 additions & 0 deletions media.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package docxlib

const MEDIA_FOLDER = `word/media/`

// Media is in word/media
type Media struct {
Name string // Name is for word/media/Name
Data []byte // Data is data of this media
}

// String is the full path of the media
func (m *Media) String() string {
return MEDIA_FOLDER + m.Name
}

// Media get media struct pointer (or nil on notfound) by name
func (f *Docx) Media(name string) *Media {
i, ok := f.mediaNameIdx[name]
if !ok {
return nil
}
return &f.media[i]
}

// addMedia append the media to docx's media list
func (f *Docx) addMedia(m Media) {
f.mediaNameIdx[m.Name] = len(f.media)
f.media = append(f.media, m)
}
7 changes: 6 additions & 1 deletion pack.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package docxlib

import (
"archive/zip"
"bytes"
"encoding/xml"
"io"
"os"
Expand All @@ -27,9 +28,13 @@ func (f *Docx) pack(zipWriter *zip.Writer) (err error) {
return
}
}
files["word/_rels/document.xml.rels"] = marshaller{data: f.DocRelation}
files["word/_rels/document.xml.rels"] = marshaller{data: &f.DocRelation}
files["word/document.xml"] = marshaller{data: f.Document}

for _, m := range f.media {
files[m.String()] = bytes.NewReader(m.Data)
}

for path, r := range files {
w, err := zipWriter.Create(path)
if err != nil {
Expand Down
Loading

0 comments on commit 292a298

Please sign in to comment.