summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chart.go52
-rw-r--r--comment.go7
-rw-r--r--excelize.go4
-rw-r--r--excelize_test.go18
-rw-r--r--file.go4
-rw-r--r--picture.go104
-rw-r--r--shape.go9
7 files changed, 126 insertions, 72 deletions
diff --git a/chart.go b/chart.go
index 77a0125..f11fd55 100644
--- a/chart.go
+++ b/chart.go
@@ -1207,28 +1207,34 @@ func (f *File) drawPlotAreaTxPr() *cTxPr {
// the problem that the label structure is changed after serialization and
// deserialization, two different structures: decodeWsDr and encodeWsDr are
// defined.
-func (f *File) drawingParser(drawingXML string, content *xlsxWsDr) int {
+func (f *File) drawingParser(path string) (*xlsxWsDr, int) {
cNvPrID := 1
- _, ok := f.XLSX[drawingXML]
- if ok { // Append Model
- decodeWsDr := decodeWsDr{}
- _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(drawingXML)), &decodeWsDr)
- content.R = decodeWsDr.R
- cNvPrID = len(decodeWsDr.OneCellAnchor) + len(decodeWsDr.TwoCellAnchor) + 1
- for _, v := range decodeWsDr.OneCellAnchor {
- content.OneCellAnchor = append(content.OneCellAnchor, &xdrCellAnchor{
- EditAs: v.EditAs,
- GraphicFrame: v.Content,
- })
- }
- for _, v := range decodeWsDr.TwoCellAnchor {
- content.TwoCellAnchor = append(content.TwoCellAnchor, &xdrCellAnchor{
- EditAs: v.EditAs,
- GraphicFrame: v.Content,
- })
+ if f.Drawings[path] == nil {
+ content := xlsxWsDr{}
+ content.A = NameSpaceDrawingML
+ content.Xdr = NameSpaceDrawingMLSpreadSheet
+ _, ok := f.XLSX[path]
+ if ok { // Append Model
+ decodeWsDr := decodeWsDr{}
+ _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(path)), &decodeWsDr)
+ content.R = decodeWsDr.R
+ cNvPrID = len(decodeWsDr.OneCellAnchor) + len(decodeWsDr.TwoCellAnchor) + 1
+ for _, v := range decodeWsDr.OneCellAnchor {
+ content.OneCellAnchor = append(content.OneCellAnchor, &xdrCellAnchor{
+ EditAs: v.EditAs,
+ GraphicFrame: v.Content,
+ })
+ }
+ for _, v := range decodeWsDr.TwoCellAnchor {
+ content.TwoCellAnchor = append(content.TwoCellAnchor, &xdrCellAnchor{
+ EditAs: v.EditAs,
+ GraphicFrame: v.Content,
+ })
+ }
}
+ f.Drawings[path] = &content
}
- return cNvPrID
+ return f.Drawings[path], cNvPrID
}
// addDrawingChart provides a function to add chart graphic frame by given
@@ -1242,10 +1248,7 @@ func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rI
width = int(float64(width) * formatSet.XScale)
height = int(float64(height) * formatSet.YScale)
colStart, rowStart, _, _, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, col, row, formatSet.OffsetX, formatSet.OffsetY, width, height)
- content := xlsxWsDr{}
- content.A = NameSpaceDrawingML
- content.Xdr = NameSpaceDrawingMLSpreadSheet
- cNvPrID := f.drawingParser(drawingXML, &content)
+ content, cNvPrID := f.drawingParser(drawingXML)
twoCellAnchor := xdrCellAnchor{}
twoCellAnchor.EditAs = formatSet.Positioning
from := xlsxFrom{}
@@ -1286,6 +1289,5 @@ func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rI
FPrintsWithSheet: formatSet.FPrintsWithSheet,
}
content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
- output, _ := xml.Marshal(content)
- f.saveFileList(drawingXML, output)
+ f.Drawings[drawingXML] = content
}
diff --git a/comment.go b/comment.go
index 5db6312..c86e932 100644
--- a/comment.go
+++ b/comment.go
@@ -33,10 +33,7 @@ func parseFormatCommentsSet(formatSet string) (*formatComment, error) {
func (f *File) GetComments() (comments map[string][]Comment) {
comments = map[string][]Comment{}
for n := range f.sheetMap {
- c, ok := f.XLSX["xl"+strings.TrimPrefix(f.getSheetComments(f.GetSheetIndex(n)), "..")]
- if ok {
- d := xlsxComments{}
- xml.Unmarshal([]byte(c), &d)
+ if d := f.commentsReader("xl" + strings.TrimPrefix(f.getSheetComments(f.GetSheetIndex(n)), "..")); d != nil {
sheetComments := []Comment{}
for _, comment := range d.CommentList.Comment {
sheetComment := Comment{}
@@ -294,7 +291,7 @@ func (f *File) decodeVMLDrawingReader(path string) *decodeVmlDrawing {
return f.DecodeVMLDrawing[path]
}
-// vmlDrawingWriter provides a function to save xl/drawings/vmlDrawing%d.xml.
+// vmlDrawingWriter provides a function to save xl/drawings/vmlDrawing%d.xml
// after serialize structure.
func (f *File) vmlDrawingWriter() {
for path, vml := range f.VMLDrawing {
diff --git a/excelize.go b/excelize.go
index df3cd05..a2bec07 100644
--- a/excelize.go
+++ b/excelize.go
@@ -28,6 +28,8 @@ type File struct {
CalcChain *xlsxCalcChain
Comments map[string]*xlsxComments
ContentTypes *xlsxTypes
+ DrawingRels map[string]*xlsxWorkbookRels
+ Drawings map[string]*xlsxWsDr
Path string
SharedStrings *xlsxSST
Sheet map[string]*xlsxWorksheet
@@ -76,6 +78,8 @@ func OpenReader(r io.Reader) (*File, error) {
f := &File{
checked: make(map[string]bool),
Comments: make(map[string]*xlsxComments),
+ DrawingRels: make(map[string]*xlsxWorkbookRels),
+ Drawings: make(map[string]*xlsxWsDr),
Sheet: make(map[string]*xlsxWorksheet),
SheetCount: sheetCount,
DecodeVMLDrawing: make(map[string]*decodeVmlDrawing),
diff --git a/excelize_test.go b/excelize_test.go
index d621b87..ed6f073 100644
--- a/excelize_test.go
+++ b/excelize_test.go
@@ -817,6 +817,24 @@ func TestGetPicture(t *testing.T) {
xlsx.getDrawingRelationships("", "")
xlsx.getSheetRelationshipsTargetByID("", "")
xlsx.deleteSheetRelationships("", "")
+
+ // Try to get picture from a local storage file.
+ assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestGetPicture.xlsx")))
+ xlsx, err = OpenFile(filepath.Join("test", "TestGetPicture.xlsx"))
+ if !assert.NoError(t, err) {
+ t.FailNow()
+ }
+ file, raw = xlsx.GetPicture("Sheet1", "F21")
+ if file == "" {
+ err = ioutil.WriteFile(file, raw, 0644)
+ if !assert.NoError(t, err) {
+ t.FailNow()
+ }
+ }
+
+ // Try to get picture from a local storage file that doesn't contain an image.
+ file, raw = xlsx.GetPicture("Sheet1", "F22")
+ t.Log(file, len(raw))
}
func TestSheetVisibility(t *testing.T) {
diff --git a/file.go b/file.go
index b6bf57d..8d68851 100644
--- a/file.go
+++ b/file.go
@@ -42,6 +42,8 @@ func NewFile() *File {
f.CalcChain = f.calcChainReader()
f.Comments = make(map[string]*xlsxComments)
f.ContentTypes = f.contentTypesReader()
+ f.DrawingRels = make(map[string]*xlsxWorkbookRels)
+ f.Drawings = make(map[string]*xlsxWsDr)
f.Styles = f.stylesReader()
f.DecodeVMLDrawing = make(map[string]*decodeVmlDrawing)
f.VMLDrawing = make(map[string]*vmlDrawing)
@@ -94,6 +96,8 @@ func (f *File) WriteToBuffer() (*bytes.Buffer, error) {
f.calcChainWriter()
f.commentsWriter()
f.contentTypesWriter()
+ f.drawingRelsWriter()
+ f.drawingsWriter()
f.vmlDrawingWriter()
f.workbookWriter()
f.workbookRelsWriter()
diff --git a/picture.go b/picture.go
index 763d89a..2ad9db2 100644
--- a/picture.go
+++ b/picture.go
@@ -272,10 +272,7 @@ func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, he
width = int(float64(width) * formatSet.XScale)
height = int(float64(height) * formatSet.YScale)
colStart, rowStart, _, _, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, col, row, formatSet.OffsetX, formatSet.OffsetY, width, height)
- content := xlsxWsDr{}
- content.A = NameSpaceDrawingML
- content.Xdr = NameSpaceDrawingMLSpreadSheet
- cNvPrID := f.drawingParser(drawingXML, &content)
+ content, cNvPrID := f.drawingParser(drawingXML)
twoCellAnchor := xdrCellAnchor{}
twoCellAnchor.EditAs = formatSet.Positioning
from := xlsxFrom{}
@@ -311,8 +308,7 @@ func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, he
FPrintsWithSheet: formatSet.FPrintsWithSheet,
}
content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
- output, _ := xml.Marshal(content)
- f.saveFileList(drawingXML, output)
+ f.Drawings[drawingXML] = content
}
// addDrawingRelationships provides a function to add image part relationships
@@ -320,27 +316,25 @@ func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, he
// relationship type and target.
func (f *File) addDrawingRelationships(index int, relType, target, targetMode string) int {
var rels = "xl/drawings/_rels/drawing" + strconv.Itoa(index) + ".xml.rels"
- var drawingRels xlsxWorkbookRels
var rID = 1
var ID bytes.Buffer
ID.WriteString("rId")
ID.WriteString(strconv.Itoa(rID))
- _, ok := f.XLSX[rels]
- if ok {
- ID.Reset()
- _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(rels)), &drawingRels)
- rID = len(drawingRels.Relationships) + 1
- ID.WriteString("rId")
- ID.WriteString(strconv.Itoa(rID))
+ drawingRels := f.drawingRelsReader(rels)
+ if drawingRels == nil {
+ drawingRels = &xlsxWorkbookRels{}
}
+ ID.Reset()
+ rID = len(drawingRels.Relationships) + 1
+ ID.WriteString("rId")
+ ID.WriteString(strconv.Itoa(rID))
drawingRels.Relationships = append(drawingRels.Relationships, xlsxWorkbookRelation{
ID: ID.String(),
Type: relType,
Target: target,
TargetMode: targetMode,
})
- output, _ := xml.Marshal(drawingRels)
- f.saveFileList(rels, output)
+ f.DrawingRels[rels] = drawingRels
return rID
}
@@ -482,22 +476,30 @@ func (f *File) GetPicture(sheet, cell string) (string, []byte) {
}
target := f.getSheetRelationshipsTargetByID(sheet, xlsx.Drawing.RID)
drawingXML := strings.Replace(target, "..", "xl", -1)
-
- _, ok := f.XLSX[drawingXML]
- if !ok {
- return "", nil
- }
- decodeWsDr := decodeWsDr{}
- _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(drawingXML)), &decodeWsDr)
-
cell = strings.ToUpper(cell)
fromCol := string(strings.Map(letterOnlyMapF, cell))
fromRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, cell))
row := fromRow - 1
col := TitleToNumber(fromCol)
-
drawingRelationships := strings.Replace(strings.Replace(target, "../drawings", "xl/drawings/_rels", -1), ".xml", ".xml.rels", -1)
-
+ wsDr, _ := f.drawingParser(drawingXML)
+ for _, anchor := range wsDr.TwoCellAnchor {
+ if anchor.From != nil && anchor.Pic != nil {
+ if anchor.From.Col == col && anchor.From.Row == row {
+ xlsxWorkbookRelation := f.getDrawingRelationships(drawingRelationships, anchor.Pic.BlipFill.Blip.Embed)
+ _, ok := supportImageTypes[filepath.Ext(xlsxWorkbookRelation.Target)]
+ if ok {
+ return filepath.Base(xlsxWorkbookRelation.Target), []byte(f.XLSX[strings.Replace(xlsxWorkbookRelation.Target, "..", "xl", -1)])
+ }
+ }
+ }
+ }
+ _, ok := f.XLSX[drawingXML]
+ if !ok {
+ return "", nil
+ }
+ decodeWsDr := decodeWsDr{}
+ _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(drawingXML)), &decodeWsDr)
for _, anchor := range decodeWsDr.TwoCellAnchor {
decodeTwoCellAnchor := decodeTwoCellAnchor{}
_ = xml.Unmarshal([]byte("<decodeTwoCellAnchor>"+anchor.Content+"</decodeTwoCellAnchor>"), &decodeTwoCellAnchor)
@@ -518,16 +520,48 @@ func (f *File) GetPicture(sheet, cell string) (string, []byte) {
// from xl/drawings/_rels/drawing%s.xml.rels by given file name and
// relationship ID.
func (f *File) getDrawingRelationships(rels, rID string) *xlsxWorkbookRelation {
- _, ok := f.XLSX[rels]
- if !ok {
- return nil
- }
- var drawingRels xlsxWorkbookRels
- _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(rels)), &drawingRels)
- for _, v := range drawingRels.Relationships {
- if v.ID == rID {
- return &v
+ if drawingRels := f.drawingRelsReader(rels); drawingRels != nil {
+ for _, v := range drawingRels.Relationships {
+ if v.ID == rID {
+ return &v
+ }
}
}
return nil
}
+
+// drawingRelsReader provides a function to get the pointer to the structure
+// after deserialization of xl/drawings/_rels/drawing%d.xml.rels.
+func (f *File) drawingRelsReader(rel string) *xlsxWorkbookRels {
+ if f.DrawingRels[rel] == nil {
+ _, ok := f.XLSX[rel]
+ if ok {
+ d := xlsxWorkbookRels{}
+ _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(rel)), &d)
+ f.DrawingRels[rel] = &d
+ }
+ }
+ return f.DrawingRels[rel]
+}
+
+// drawingRelsWriter provides a function to save
+// xl/drawings/_rels/drawing%d.xml.rels after serialize structure.
+func (f *File) drawingRelsWriter() {
+ for path, d := range f.DrawingRels {
+ if d != nil {
+ v, _ := xml.Marshal(d)
+ f.saveFileList(path, v)
+ }
+ }
+}
+
+// drawingsWriter provides a function to save xl/drawings/drawing%d.xml after
+// serialize structure.
+func (f *File) drawingsWriter() {
+ for path, d := range f.Drawings {
+ if d != nil {
+ v, _ := xml.Marshal(d)
+ f.saveFileList(path, v)
+ }
+ }
+}
diff --git a/shape.go b/shape.go
index e2281a2..3cf09d8 100644
--- a/shape.go
+++ b/shape.go
@@ -11,7 +11,6 @@ package excelize
import (
"encoding/json"
- "encoding/xml"
"strconv"
"strings"
)
@@ -293,10 +292,7 @@ func (f *File) addDrawingShape(sheet, drawingXML, cell string, formatSet *format
width := int(float64(formatSet.Width) * formatSet.Format.XScale)
height := int(float64(formatSet.Height) * formatSet.Format.YScale)
colStart, rowStart, _, _, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, col, row, formatSet.Format.OffsetX, formatSet.Format.OffsetY, width, height)
- content := xlsxWsDr{}
- content.A = NameSpaceDrawingML
- content.Xdr = NameSpaceDrawingMLSpreadSheet
- cNvPrID := f.drawingParser(drawingXML, &content)
+ content, cNvPrID := f.drawingParser(drawingXML)
twoCellAnchor := xdrCellAnchor{}
twoCellAnchor.EditAs = formatSet.Format.Positioning
from := xlsxFrom{}
@@ -402,8 +398,7 @@ func (f *File) addDrawingShape(sheet, drawingXML, cell string, formatSet *format
FPrintsWithSheet: formatSet.Format.FPrintsWithSheet,
}
content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
- output, _ := xml.Marshal(content)
- f.saveFileList(drawingXML, output)
+ f.Drawings[drawingXML] = content
}
// setShapeRef provides a function to set color with hex model by given actual