瀏覽代碼

- Initialize shape support: new function `AddShape()` added. Relate issue #38;
- Drawing `nvPicPr` element ID property calculation changed;
- go test updated

Ri Xu 8 年之前
父節點
當前提交
7f30a6c943
共有 10 個文件被更改,包括 670 次插入215 次删除
  1. 6 6
      README.md
  2. 132 143
      chart.go
  3. 13 0
      excelize_test.go
  4. 19 32
      picture.go
  5. 375 0
      shape.go
  6. 1 1
      sheet.go
  7. 0 3
      table.go
  8. 二進制
      test/Workbook1.xlsx
  9. 9 8
      xmlChart.go
  10. 115 22
      xmlDrawing.go

+ 6 - 6
README.md

@@ -45,7 +45,7 @@ func main() {
     // Set active sheet of the workbook.
     xlsx.SetActiveSheet(2)
     // Save xlsx file by the given path.
-    err := xlsx.WriteTo("/tmp/Workbook.xlsx")
+    err := xlsx.WriteTo("./Workbook.xlsx")
     if err != nil {
         fmt.Println(err)
         os.Exit(1)
@@ -69,7 +69,7 @@ import (
 )
 
 func main() {
-    xlsx, err := excelize.OpenFile("/tmp/Workbook.xlsx")
+    xlsx, err := excelize.OpenFile("./Workbook.xlsx")
     if err != nil {
         fmt.Println(err)
         os.Exit(1)
@@ -142,23 +142,23 @@ import (
 )
 
 func main() {
-    xlsx, err := excelize.OpenFile("/tmp/Workbook.xlsx")
+    xlsx, err := excelize.OpenFile("./Workbook.xlsx")
     if err != nil {
         fmt.Println(err)
         os.Exit(1)
     }
     // Insert a picture.
-    err = xlsx.AddPicture("Sheet1", "A2", "/tmp/image1.gif", "")
+    err = xlsx.AddPicture("Sheet1", "A2", "./image1.gif", "")
     if err != nil {
         fmt.Println(err)
     }
     // Insert a picture to sheet with scaling.
-    err = xlsx.AddPicture("Sheet1", "D2", "/tmp/image2.jpg", `{"x_scale": 0.5, "y_scale": 0.5}`)
+    err = xlsx.AddPicture("Sheet1", "D2", "./image2.jpg", `{"x_scale": 0.5, "y_scale": 0.5}`)
     if err != nil {
         fmt.Println(err)
     }
     // Insert a picture offset in the cell with printing support.
-    err = xlsx.AddPicture("Sheet1", "H2", "/tmp/image3.gif", `{"x_offset": 15, "y_offset": 10, "print_obj": true, "lock_aspect_ratio": false, "locked": false}`)
+    err = xlsx.AddPicture("Sheet1", "H2", "./image3.gif", `{"x_offset": 15, "y_offset": 10, "print_obj": true, "lock_aspect_ratio": false, "locked": false}`)
     if err != nil {
         fmt.Println(err)
     }

+ 132 - 143
chart.go

@@ -3,7 +3,6 @@ package excelize
 import (
 	"encoding/json"
 	"encoding/xml"
-	"fmt"
 	"strconv"
 	"strings"
 )
@@ -57,8 +56,8 @@ func parseFormatChartSet(formatSet string) *formatChart {
 
 // AddChart provides the method to add chart in a sheet by given chart format
 // set (such as offset, scale, aspect ratio setting and print settings) and
-// properties set. Only support "pie" and "3Dpie" type chart currently. For
-// example, create 3D bar chart with data Sheet1!$A$29:$D$32:
+// properties set. For example, create 3D bar chart with data
+// Sheet1!$A$29:$D$32:
 //
 //    package main
 //
@@ -81,7 +80,7 @@ func parseFormatChartSet(formatSet string) *formatChart {
 //        }
 //        xlsx.AddChart("SHEET1", "F2", `{"type":"bar3D","series":[{"name":"=Sheet1!$A$30","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$30:$D$30"},{"name":"=Sheet1!$A$31","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$31:$D$31"},{"name":"=Sheet1!$A$32","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"bottom","show_legend_key":false},"title":{"name":"Fruit Line Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`)
 //        // Save xlsx file by the given path.
-//        err := xlsx.WriteTo("./tmp/Workbook.xlsx")
+//        err := xlsx.WriteTo("./Workbook.xlsx")
 //        if err != nil {
 //            fmt.Println(err)
 //            os.Exit(1)
@@ -235,128 +234,126 @@ func (f *File) addChartContentTypePart(index int) {
 func (f *File) addChart(formatSet *formatChart) {
 	count := f.countCharts()
 	xlsxChartSpace := xlsxChartSpace{
-		ChartSpace: cChartSpace{
-			XMLNSc:         NameSpaceDrawingMLChart,
-			XMLNSa:         NameSpaceDrawingML,
-			XMLNSr:         SourceRelationship,
-			XMLNSc16r2:     SourceRelationshipChart201506,
-			Date1904:       &attrValBool{Val: false},
-			Lang:           &attrValString{Val: "en-US"},
-			RoundedCorners: &attrValBool{Val: false},
-			Chart: cChart{
-				Title: &cTitle{
-					Tx: cTx{
-						Rich: &cRich{
-							P: aP{
-								PPr: aPPr{
-									DefRPr: aDefRPr{
-										Kern:   1200,
-										Strike: "noStrike",
-										U:      "none",
-										Sz:     1400,
-										SolidFill: &aSolidFill{
-											SchemeClr: &aSchemeClr{
-												Val: "tx1",
-												LumMod: &attrValInt{
-													Val: 65000,
-												},
-												LumOff: &attrValInt{
-													Val: 35000,
-												},
+		XMLNSc:         NameSpaceDrawingMLChart,
+		XMLNSa:         NameSpaceDrawingML,
+		XMLNSr:         SourceRelationship,
+		XMLNSc16r2:     SourceRelationshipChart201506,
+		Date1904:       &attrValBool{Val: false},
+		Lang:           &attrValString{Val: "en-US"},
+		RoundedCorners: &attrValBool{Val: false},
+		Chart: cChart{
+			Title: &cTitle{
+				Tx: cTx{
+					Rich: &cRich{
+						P: aP{
+							PPr: &aPPr{
+								DefRPr: aDefRPr{
+									Kern:   1200,
+									Strike: "noStrike",
+									U:      "none",
+									Sz:     1400,
+									SolidFill: &aSolidFill{
+										SchemeClr: &aSchemeClr{
+											Val: "tx1",
+											LumMod: &attrValInt{
+												Val: 65000,
+											},
+											LumOff: &attrValInt{
+												Val: 35000,
 											},
-										},
-										Ea: &aEa{
-											Typeface: "+mn-ea",
-										},
-										Cs: &aCs{
-											Typeface: "+mn-cs",
-										},
-										Latin: &aLatin{
-											Typeface: "+mn-lt",
 										},
 									},
-								},
-								R: &aR{
-									RPr: aRPr{
-										Lang:    "en-US",
-										AltLang: "en-US",
+									Ea: &aEa{
+										Typeface: "+mn-ea",
+									},
+									Cs: &aCs{
+										Typeface: "+mn-cs",
+									},
+									Latin: &aLatin{
+										Typeface: "+mn-lt",
 									},
-									T: formatSet.Title.Name,
 								},
 							},
-						},
-					},
-					TxPr: cTxPr{
-						P: aP{
-							PPr: aPPr{
-								DefRPr: aDefRPr{
-									Kern:   1200,
-									U:      "none",
-									Sz:     14000,
-									Strike: "noStrike",
+							R: &aR{
+								RPr: aRPr{
+									Lang:    "en-US",
+									AltLang: "en-US",
 								},
-							},
-							EndParaRPr: &aEndParaRPr{
-								Lang: "en-US",
+								T: formatSet.Title.Name,
 							},
 						},
 					},
 				},
-				View3D: &cView3D{
-					RotX:         &attrValInt{Val: chartView3DRotX[formatSet.Type]},
-					RotY:         &attrValInt{Val: chartView3DRotY[formatSet.Type]},
-					DepthPercent: &attrValInt{Val: chartView3DDepthPercent[formatSet.Type]},
-					RAngAx:       &attrValInt{Val: chartView3DRAngAx[formatSet.Type]},
-				},
-				Floor: &cThicknessSpPr{
-					Thickness: &attrValInt{Val: 0},
-				},
-				SideWall: &cThicknessSpPr{
-					Thickness: &attrValInt{Val: 0},
-				},
-				BackWall: &cThicknessSpPr{
-					Thickness: &attrValInt{Val: 0},
-				},
-				PlotArea: &cPlotArea{},
-				Legend: &cLegend{
-					LegendPos: &attrValString{Val: chartLegendPosition[formatSet.Legend.Position]},
-					Overlay:   &attrValBool{Val: false},
+				TxPr: cTxPr{
+					P: aP{
+						PPr: &aPPr{
+							DefRPr: aDefRPr{
+								Kern:   1200,
+								U:      "none",
+								Sz:     14000,
+								Strike: "noStrike",
+							},
+						},
+						EndParaRPr: &aEndParaRPr{
+							Lang: "en-US",
+						},
+					},
 				},
+			},
+			View3D: &cView3D{
+				RotX:         &attrValInt{Val: chartView3DRotX[formatSet.Type]},
+				RotY:         &attrValInt{Val: chartView3DRotY[formatSet.Type]},
+				DepthPercent: &attrValInt{Val: chartView3DDepthPercent[formatSet.Type]},
+				RAngAx:       &attrValInt{Val: chartView3DRAngAx[formatSet.Type]},
+			},
+			Floor: &cThicknessSpPr{
+				Thickness: &attrValInt{Val: 0},
+			},
+			SideWall: &cThicknessSpPr{
+				Thickness: &attrValInt{Val: 0},
+			},
+			BackWall: &cThicknessSpPr{
+				Thickness: &attrValInt{Val: 0},
+			},
+			PlotArea: &cPlotArea{},
+			Legend: &cLegend{
+				LegendPos: &attrValString{Val: chartLegendPosition[formatSet.Legend.Position]},
+				Overlay:   &attrValBool{Val: false},
+			},
 
-				PlotVisOnly:      &attrValBool{Val: false},
-				DispBlanksAs:     &attrValString{Val: formatSet.ShowBlanksAs},
-				ShowDLblsOverMax: &attrValBool{Val: false},
+			PlotVisOnly:      &attrValBool{Val: false},
+			DispBlanksAs:     &attrValString{Val: formatSet.ShowBlanksAs},
+			ShowDLblsOverMax: &attrValBool{Val: false},
+		},
+		SpPr: &cSpPr{
+			SolidFill: &aSolidFill{
+				SchemeClr: &aSchemeClr{Val: "bg1"},
 			},
-			SpPr: &cSpPr{
+			Ln: &aLn{
+				W:    9525,
+				Cap:  "flat",
+				Cmpd: "sng",
+				Algn: "ctr",
 				SolidFill: &aSolidFill{
-					SchemeClr: &aSchemeClr{Val: "bg1"},
-				},
-				Ln: &aLn{
-					W:    9525,
-					Cap:  "flat",
-					Cmpd: "sng",
-					Algn: "ctr",
-					SolidFill: &aSolidFill{
-						SchemeClr: &aSchemeClr{Val: "tx1",
-							LumMod: &attrValInt{
-								Val: 15000,
-							},
-							LumOff: &attrValInt{
-								Val: 85000,
-							},
+					SchemeClr: &aSchemeClr{Val: "tx1",
+						LumMod: &attrValInt{
+							Val: 15000,
+						},
+						LumOff: &attrValInt{
+							Val: 85000,
 						},
 					},
 				},
 			},
-			PrintSettings: &cPrintSettings{
-				PageMargins: &cPageMargins{
-					B:      0.75,
-					L:      0.7,
-					R:      0.7,
-					T:      0.7,
-					Header: 0.3,
-					Footer: 0.3,
-				},
+		},
+		PrintSettings: &cPrintSettings{
+			PageMargins: &cPageMargins{
+				B:      0.75,
+				L:      0.7,
+				R:      0.7,
+				T:      0.7,
+				Header: 0.3,
+				Footer: 0.3,
 			},
 		},
 	}
@@ -370,11 +367,11 @@ func (f *File) addChart(formatSet *formatChart) {
 		Radar:    f.drawRadarChart,
 		Scatter:  f.drawScatterChart,
 	}
-	xlsxChartSpace.ChartSpace.Chart.PlotArea = plotAreaFunc[formatSet.Type](formatSet)
+	xlsxChartSpace.Chart.PlotArea = plotAreaFunc[formatSet.Type](formatSet)
 
 	chart, _ := xml.Marshal(xlsxChartSpace)
 	media := "xl/charts/chart" + strconv.Itoa(count+1) + ".xml"
-	f.saveFileList(media, string(chart[16:len(chart)-17]))
+	f.saveFileList(media, string(chart))
 }
 
 // drawBarChart provides function to draw the c:plotArea element for bar chart
@@ -809,7 +806,7 @@ func (f *File) drawPlotAreaTxPr() *cTxPr {
 			AnchorCtr:        true,
 		},
 		P: aP{
-			PPr: aPPr{
+			PPr: &aPPr{
 				DefRPr: aDefRPr{
 					Sz:       900,
 					B:        false,
@@ -846,29 +843,29 @@ 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 := encodeWsDr{}
-	content.WsDr.A = NameSpaceDrawingML
-	content.WsDr.Xdr = NameSpaceDrawingMLSpreadSheet
+	content := xlsxWsDr{}
+	content.A = NameSpaceDrawingML
+	content.Xdr = NameSpaceDrawingMLSpreadSheet
 	cNvPrID := 1
 	_, ok := f.XLSX[drawingXML]
 	if ok { // Append Model
 		decodeWsDr := decodeWsDr{}
 		xml.Unmarshal([]byte(f.readXML(drawingXML)), &decodeWsDr)
-		cNvPrID = len(decodeWsDr.TwoCellAnchor) + 1
+		cNvPrID = len(decodeWsDr.OneCellAnchor) + len(decodeWsDr.TwoCellAnchor) + 1
 		for _, v := range decodeWsDr.OneCellAnchor {
-			content.WsDr.OneCellAnchor = append(content.WsDr.OneCellAnchor, &xlsxCellAnchor{
+			content.OneCellAnchor = append(content.OneCellAnchor, &xdrCellAnchor{
 				EditAs:       v.EditAs,
 				GraphicFrame: v.Content,
 			})
 		}
 		for _, v := range decodeWsDr.TwoCellAnchor {
-			content.WsDr.TwoCellAnchor = append(content.WsDr.TwoCellAnchor, &xlsxCellAnchor{
+			content.TwoCellAnchor = append(content.TwoCellAnchor, &xdrCellAnchor{
 				EditAs:       v.EditAs,
 				GraphicFrame: v.Content,
 			})
 		}
 	}
-	twoCellAnchor := xlsxCellAnchor{}
+	twoCellAnchor := xdrCellAnchor{}
 	twoCellAnchor.EditAs = "oneCell"
 	from := xlsxFrom{}
 	from.Col = colStart
@@ -883,39 +880,31 @@ func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rI
 	twoCellAnchor.From = &from
 	twoCellAnchor.To = &to
 
-	graphicFrame := graphicFrame{
-		GraphicFrame: &xlsxGraphicFrame{
-			NvGraphicFramePr: xlsxNvGraphicFramePr{
-				CNvPr: &xlsxCNvPr{
-					ID:   cNvPrID,
-					Name: "Chart " + strconv.Itoa(cNvPrID),
-				},
+	graphicFrame := xlsxGraphicFrame{
+		NvGraphicFramePr: xlsxNvGraphicFramePr{
+			CNvPr: &xlsxCNvPr{
+				ID:   f.countCharts() + f.countMedia() + 1,
+				Name: "Chart " + strconv.Itoa(cNvPrID),
 			},
-			Graphic: &xlsxGraphic{
-				GraphicData: &xlsxGraphicData{
-					URI: NameSpaceDrawingMLChart,
-					Chart: &xlsxChart{
-						C:   NameSpaceDrawingMLChart,
-						R:   SourceRelationship,
-						RID: "rId" + strconv.Itoa(rID),
-					},
+		},
+		Graphic: &xlsxGraphic{
+			GraphicData: &xlsxGraphicData{
+				URI: NameSpaceDrawingMLChart,
+				Chart: &xlsxChart{
+					C:   NameSpaceDrawingMLChart,
+					R:   SourceRelationship,
+					RID: "rId" + strconv.Itoa(rID),
 				},
 			},
 		},
 	}
 	graphic, _ := xml.Marshal(graphicFrame)
-	twoCellAnchor.GraphicFrame = string(graphic[14 : len(graphic)-15])
-	twoCellAnchor.ClientData = &xlsxClientData{
+	twoCellAnchor.GraphicFrame = string(graphic)
+	twoCellAnchor.ClientData = &xdrClientData{
 		FLocksWithSheet:  formatSet.FLocksWithSheet,
 		FPrintsWithSheet: formatSet.FPrintsWithSheet,
 	}
-	content.WsDr.TwoCellAnchor = append(content.WsDr.TwoCellAnchor, &twoCellAnchor)
-	output, err := xml.Marshal(content)
-	if err != nil {
-		fmt.Println(err)
-	}
-	// Create replacer with pairs as arguments and replace all pairs.
-	r := strings.NewReplacer("<encodeWsDr>", "", "</encodeWsDr>", "")
-	result := r.Replace(string(output))
-	f.saveFileList(drawingXML, result)
+	content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
+	output, _ := xml.Marshal(content)
+	f.saveFileList(drawingXML, string(output))
 }

+ 13 - 0
excelize_test.go

@@ -486,6 +486,19 @@ func TestAddTable(t *testing.T) {
 	}
 }
 
+func TestAddShape(t *testing.T) {
+	xlsx, err := OpenFile("./test/Workbook_2.xlsx")
+	if err != nil {
+		t.Log(err)
+	}
+	xlsx.AddShape("Sheet1", "A30", `{"type":"rect","text":"Rectangle Shape"}`)
+	xlsx.AddShape("Sheet3", "H1", `{"type":"ellipseRibbon", "color":{"line":"#4286f4","fill":"#8eb9ff"}, "height": 90}`)
+	err = xlsx.Save()
+	if err != nil {
+		t.Log(err)
+	}
+}
+
 func TestAddChart(t *testing.T) {
 	xlsx, err := OpenFile("./test/Workbook1.xlsx")
 	if err != nil {

+ 19 - 32
picture.go

@@ -5,7 +5,6 @@ import (
 	"encoding/json"
 	"encoding/xml"
 	"errors"
-	"fmt"
 	"image"
 	"io/ioutil"
 	"os"
@@ -50,21 +49,21 @@ func parseFormatPictureSet(formatSet string) *formatPicture {
 //    func main() {
 //        xlsx := excelize.CreateFile()
 //        // Insert a picture.
-//        err := xlsx.AddPicture("Sheet1", "A2", "/tmp/image1.jpg", "")
+//        err := xlsx.AddPicture("Sheet1", "A2", "./image1.jpg", "")
 //        if err != nil {
 //            fmt.Println(err)
 //        }
 //        // Insert a picture to sheet with scaling.
-//        err = xlsx.AddPicture("Sheet1", "D2", "/tmp/image1.png", `{"x_scale": 0.5, "y_scale": 0.5}`)
+//        err = xlsx.AddPicture("Sheet1", "D2", "./image1.png", `{"x_scale": 0.5, "y_scale": 0.5}`)
 //        if err != nil {
 //            fmt.Println(err)
 //        }
 //        // Insert a picture offset in the cell with printing support.
-//        err = xlsx.AddPicture("Sheet1", "H2", "/tmp/image3.gif", `{"x_offset": 15, "y_offset": 10, "print_obj": true, "lock_aspect_ratio": false, "locked": false}`)
+//        err = xlsx.AddPicture("Sheet1", "H2", "./image3.gif", `{"x_offset": 15, "y_offset": 10, "print_obj": true, "lock_aspect_ratio": false, "locked": false}`)
 //        if err != nil {
 //            fmt.Println(err)
 //        }
-//        err = xlsx.WriteTo("/tmp/Workbook.xlsx")
+//        err = xlsx.WriteTo("./Workbook.xlsx")
 //        if err != nil {
 //            fmt.Println(err)
 //            os.Exit(1)
@@ -135,10 +134,7 @@ func (f *File) addSheetRelationships(sheet, relType, target, targetMode string)
 		Target:     target,
 		TargetMode: targetMode,
 	})
-	output, err := xml.Marshal(sheetRels)
-	if err != nil {
-		fmt.Println(err)
-	}
+	output, _ := xml.Marshal(sheetRels)
 	f.saveFileList(rels, string(output))
 	return rID
 }
@@ -187,29 +183,29 @@ 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 := encodeWsDr{}
-	content.WsDr.A = NameSpaceDrawingML
-	content.WsDr.Xdr = NameSpaceDrawingMLSpreadSheet
+	content := xlsxWsDr{}
+	content.A = NameSpaceDrawingML
+	content.Xdr = NameSpaceDrawingMLSpreadSheet
 	cNvPrID := 1
 	_, ok := f.XLSX[drawingXML]
 	if ok { // Append Model
 		decodeWsDr := decodeWsDr{}
 		xml.Unmarshal([]byte(f.readXML(drawingXML)), &decodeWsDr)
-		cNvPrID = len(decodeWsDr.TwoCellAnchor) + 1
+		cNvPrID = len(decodeWsDr.OneCellAnchor) + len(decodeWsDr.TwoCellAnchor) + 1
 		for _, v := range decodeWsDr.OneCellAnchor {
-			content.WsDr.OneCellAnchor = append(content.WsDr.OneCellAnchor, &xlsxCellAnchor{
+			content.OneCellAnchor = append(content.OneCellAnchor, &xdrCellAnchor{
 				EditAs:       v.EditAs,
 				GraphicFrame: v.Content,
 			})
 		}
 		for _, v := range decodeWsDr.TwoCellAnchor {
-			content.WsDr.TwoCellAnchor = append(content.WsDr.TwoCellAnchor, &xlsxCellAnchor{
+			content.TwoCellAnchor = append(content.TwoCellAnchor, &xdrCellAnchor{
 				EditAs:       v.EditAs,
 				GraphicFrame: v.Content,
 			})
 		}
 	}
-	twoCellAnchor := xlsxCellAnchor{}
+	twoCellAnchor := xdrCellAnchor{}
 	twoCellAnchor.EditAs = "oneCell"
 	from := xlsxFrom{}
 	from.Col = colStart
@@ -225,7 +221,7 @@ func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, he
 	twoCellAnchor.To = &to
 	pic := xlsxPic{}
 	pic.NvPicPr.CNvPicPr.PicLocks.NoChangeAspect = formatSet.NoChangeAspect
-	pic.NvPicPr.CNvPr.ID = cNvPrID
+	pic.NvPicPr.CNvPr.ID = f.countCharts() + f.countMedia() + 1
 	pic.NvPicPr.CNvPr.Descr = file
 	pic.NvPicPr.CNvPr.Name = "Picture " + strconv.Itoa(cNvPrID)
 	pic.BlipFill.Blip.R = SourceRelationship
@@ -233,19 +229,13 @@ func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, he
 	pic.SpPr.PrstGeom.Prst = "rect"
 
 	twoCellAnchor.Pic = &pic
-	twoCellAnchor.ClientData = &xlsxClientData{
+	twoCellAnchor.ClientData = &xdrClientData{
 		FLocksWithSheet:  formatSet.FLocksWithSheet,
 		FPrintsWithSheet: formatSet.FPrintsWithSheet,
 	}
-	content.WsDr.TwoCellAnchor = append(content.WsDr.TwoCellAnchor, &twoCellAnchor)
-	output, err := xml.Marshal(content)
-	if err != nil {
-		fmt.Println(err)
-	}
-	// Create replacer with pairs as arguments and replace all pairs.
-	r := strings.NewReplacer("<encodeWsDr>", "", "</encodeWsDr>", "")
-	result := r.Replace(string(output))
-	f.saveFileList(drawingXML, result)
+	content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
+	output, _ := xml.Marshal(content)
+	f.saveFileList(drawingXML, string(output))
 }
 
 // addDrawingRelationships provides function to add image part relationships in
@@ -271,10 +261,7 @@ func (f *File) addDrawingRelationships(index int, relType string, target string)
 		Type:   relType,
 		Target: target,
 	})
-	output, err := xml.Marshal(drawingRels)
-	if err != nil {
-		fmt.Println(err)
-	}
+	output, _ := xml.Marshal(drawingRels)
 	f.saveFileList(rels, string(output))
 	return rID
 }
@@ -356,7 +343,7 @@ func (f *File) getSheetRelationshipsTargetByID(sheet string, rID string) string
 // in XLSX by given worksheet and cell name. This function returns the file name
 // in XLSX and file contents as []byte data types. For example:
 //
-//    xlsx, err := excelize.OpenFile("/tmp/Workbook.xlsx")
+//    xlsx, err := excelize.OpenFile("./Workbook.xlsx")
 //    if err != nil {
 //        fmt.Println(err)
 //        os.Exit(1)

+ 375 - 0
shape.go

@@ -0,0 +1,375 @@
+package excelize
+
+import (
+	"encoding/json"
+	"encoding/xml"
+	"strconv"
+	"strings"
+)
+
+// parseFormatShapeSet provides function to parse the format settings of the
+// shape with default value.
+func parseFormatShapeSet(formatSet string) *formatShape {
+	format := formatShape{
+		Width:  160,
+		Height: 160,
+		Format: formatPicture{
+			FPrintsWithSheet: true,
+			FLocksWithSheet:  false,
+			NoChangeAspect:   false,
+			OffsetX:          0,
+			OffsetY:          0,
+			XScale:           1.0,
+			YScale:           1.0,
+		},
+		Text: " ",
+	}
+	json.Unmarshal([]byte(formatSet), &format)
+	return &format
+}
+
+// AddShape provides the method to add shape in a sheet by given worksheet
+// index, shape format set (such as offset, scale, aspect ratio setting and
+// print settings) and properties set. For example, add text box (rect shape) in
+// Sheet1:
+//
+//    xlsx.AddShape("Sheet1", "G6", `{"type":"rect", "text":"Rectangle Shape", "color":{"line":"#4286F4","fill":"#8eb9ff"}, "width": 180, "height": 90}`)
+//
+// The following shows the type of chart supported by excelize:
+//
+//    accentBorderCallout1 (Callout 1 with Border and Accent Shape)
+//    accentBorderCallout2 (Callout 2 with Border and Accent Shape)
+//    accentBorderCallout3 (Callout 3 with Border and Accent Shape)
+//    accentCallout1 (Callout 1 Shape)
+//    accentCallout2 (Callout 2 Shape)
+//    accentCallout3 (Callout 3 Shape)
+//    actionButtonBackPrevious (Back or Previous Button Shape)
+//    actionButtonBeginning (Beginning Button Shape)
+//    actionButtonBlank (Blank Button Shape)
+//    actionButtonDocument (Document Button Shape)
+//    actionButtonEnd (End Button Shape)
+//    actionButtonForwardNext (Forward or Next Button Shape)
+//    actionButtonHelp (Help Button Shape)
+//    actionButtonHome (Home Button Shape)
+//    actionButtonInformation (Information Button Shape)
+//    actionButtonMovie (Movie Button Shape)
+//    actionButtonReturn (Return Button Shape)
+//    actionButtonSound (Sound Button Shape)
+//    arc (Curved Arc Shape)
+//    bentArrow (Bent Arrow Shape)
+//    bentConnector2 (Bent Connector 2 Shape)
+//    bentConnector3 (Bent Connector 3 Shape)
+//    bentConnector4 (Bent Connector 4 Shape)
+//    bentConnector5 (Bent Connector 5 Shape)
+//    bentUpArrow (Bent Up Arrow Shape)
+//    bevel (Bevel Shape)
+//    blockArc (Block Arc Shape)
+//    borderCallout1 (Callout 1 with Border Shape)
+//    borderCallout2 (Callout 2 with Border Shape)
+//    borderCallout3 (Callout 3 with Border Shape)
+//    bracePair (Brace Pair Shape)
+//    bracketPair (Bracket Pair Shape)
+//    callout1 (Callout 1 Shape)
+//    callout2 (Callout 2 Shape)
+//    callout3 (Callout 3 Shape)
+//    can (Can Shape)
+//    chartPlus (Chart Plus Shape)
+//    chartStar (Chart Star Shape)
+//    chartX (Chart X Shape)
+//    chevron (Chevron Shape)
+//    chord (Chord Shape)
+//    circularArrow (Circular Arrow Shape)
+//    cloud (Cloud Shape)
+//    cloudCallout (Callout Cloud Shape)
+//    corner (Corner Shape)
+//    cornerTabs (Corner Tabs Shape)
+//    cube (Cube Shape)
+//    curvedConnector2 (Curved Connector 2 Shape)
+//    curvedConnector3 (Curved Connector 3 Shape)
+//    curvedConnector4 (Curved Connector 4 Shape)
+//    curvedConnector5 (Curved Connector 5 Shape)
+//    curvedDownArrow (Curved Down Arrow Shape)
+//    curvedLeftArrow (Curved Left Arrow Shape)
+//    curvedRightArrow (Curved Right Arrow Shape)
+//    curvedUpArrow (Curved Up Arrow Shape)
+//    decagon (Decagon Shape)
+//    diagStripe (Diagonal Stripe Shape)
+//    diamond (Diamond Shape)
+//    dodecagon (Dodecagon Shape)
+//    donut (Donut Shape)
+//    doubleWave (Double Wave Shape)
+//    downArrow (Down Arrow Shape)
+//    downArrowCallout (Callout Down Arrow Shape)
+//    ellipse (Ellipse Shape)
+//    ellipseRibbon (Ellipse Ribbon Shape)
+//    ellipseRibbon2 (Ellipse Ribbon 2 Shape)
+//    flowChartAlternateProcess (Alternate Process Flow Shape)
+//    flowChartCollate (Collate Flow Shape)
+//    flowChartConnector (Connector Flow Shape)
+//    flowChartDecision (Decision Flow Shape)
+//    flowChartDelay (Delay Flow Shape)
+//    flowChartDisplay (Display Flow Shape)
+//    flowChartDocument (Document Flow Shape)
+//    flowChartExtract (Extract Flow Shape)
+//    flowChartInputOutput (Input Output Flow Shape)
+//    flowChartInternalStorage (Internal Storage Flow Shape)
+//    flowChartMagneticDisk (Magnetic Disk Flow Shape)
+//    flowChartMagneticDrum (Magnetic Drum Flow Shape)
+//    flowChartMagneticTape (Magnetic Tape Flow Shape)
+//    flowChartManualInput (Manual Input Flow Shape)
+//    flowChartManualOperation (Manual Operation Flow Shape)
+//    flowChartMerge (Merge Flow Shape)
+//    flowChartMultidocument (Multi-Document Flow Shape)
+//    flowChartOfflineStorage (Offline Storage Flow Shape)
+//    flowChartOffpageConnector (Off-Page Connector Flow Shape)
+//    flowChartOnlineStorage (Online Storage Flow Shape)
+//    flowChartOr (Or Flow Shape)
+//    flowChartPredefinedProcess (Predefined Process Flow Shape)
+//    flowChartPreparation (Preparation Flow Shape)
+//    flowChartProcess (Process Flow Shape)
+//    flowChartPunchedCard (Punched Card Flow Shape)
+//    flowChartPunchedTape (Punched Tape Flow Shape)
+//    flowChartSort (Sort Flow Shape)
+//    flowChartSummingJunction (Summing Junction Flow Shape)
+//    flowChartTerminator (Terminator Flow Shape)
+//    foldedCorner (Folded Corner Shape)
+//    frame (Frame Shape)
+//    funnel (Funnel Shape)
+//    gear6 (Gear 6 Shape)
+//    gear9 (Gear 9 Shape)
+//    halfFrame (Half Frame Shape)
+//    heart (Heart Shape)
+//    heptagon (Heptagon Shape)
+//    hexagon (Hexagon Shape)
+//    homePlate (Home Plate Shape)
+//    horizontalScroll (Horizontal Scroll Shape)
+//    irregularSeal1 (Irregular Seal 1 Shape)
+//    irregularSeal2 (Irregular Seal 2 Shape)
+//    leftArrow (Left Arrow Shape)
+//    leftArrowCallout (Callout Left Arrow Shape)
+//    leftBrace (Left Brace Shape)
+//    leftBracket (Left Bracket Shape)
+//    leftCircularArrow (Left Circular Arrow Shape)
+//    leftRightArrow (Left Right Arrow Shape)
+//    leftRightArrowCallout (Callout Left Right Arrow Shape)
+//    leftRightCircularArrow (Left Right Circular Arrow Shape)
+//    leftRightRibbon (Left Right Ribbon Shape)
+//    leftRightUpArrow (Left Right Up Arrow Shape)
+//    leftUpArrow (Left Up Arrow Shape)
+//    lightningBolt (Lightning Bolt Shape)
+//    line (Line Shape)
+//    lineInv (Line Inverse Shape)
+//    mathDivide (Divide Math Shape)
+//    mathEqual (Equal Math Shape)
+//    mathMinus (Minus Math Shape)
+//    mathMultiply (Multiply Math Shape)
+//    mathNotEqual (Not Equal Math Shape)
+//    mathPlus (Plus Math Shape)
+//    moon (Moon Shape)
+//    nonIsoscelesTrapezoid (Non-Isosceles Trapezoid Shape)
+//    noSmoking (No Smoking Shape)
+//    notchedRightArrow (Notched Right Arrow Shape)
+//    octagon (Octagon Shape)
+//    parallelogram (Parallelogram Shape)
+//    pentagon (Pentagon Shape)
+//    pie (Pie Shape)
+//    pieWedge (Pie Wedge Shape)
+//    plaque (Plaque Shape)
+//    plaqueTabs (Plaque Tabs Shape)
+//    plus (Plus Shape)
+//    quadArrow (Quad-Arrow Shape)
+//    quadArrowCallout (Callout Quad-Arrow Shape)
+//    rect (Rectangle Shape)
+//    ribbon (Ribbon Shape)
+//    ribbon2 (Ribbon 2 Shape)
+//    rightArrow (Right Arrow Shape)
+//    rightArrowCallout (Callout Right Arrow Shape)
+//    rightBrace (Right Brace Shape)
+//    rightBracket (Right Bracket Shape)
+//    round1Rect (One Round Corner Rectangle Shape)
+//    round2DiagRect (Two Diagonal Round Corner Rectangle Shape)
+//    round2SameRect (Two Same-side Round Corner Rectangle Shape)
+//    roundRect (Round Corner Rectangle Shape)
+//    rtTriangle (Right Triangle Shape)
+//    smileyFace (Smiley Face Shape)
+//    snip1Rect (One Snip Corner Rectangle Shape)
+//    snip2DiagRect (Two Diagonal Snip Corner Rectangle Shape)
+//    snip2SameRect (Two Same-side Snip Corner Rectangle Shape)
+//    snipRoundRect (One Snip One Round Corner Rectangle Shape)
+//    squareTabs (Square Tabs Shape)
+//    star10 (Ten Pointed Star Shape)
+//    star12 (Twelve Pointed Star Shape)
+//    star16 (Sixteen Pointed Star Shape)
+//    star24 (Twenty Four Pointed Star Shape)
+//    star32 (Thirty Two Pointed Star Shape)
+//    star4 (Four Pointed Star Shape)
+//    star5 (Five Pointed Star Shape)
+//    star6 (Six Pointed Star Shape)
+//    star7 (Seven Pointed Star Shape)
+//    star8 (Eight Pointed Star Shape)
+//    straightConnector1 (Straight Connector 1 Shape)
+//    stripedRightArrow (Striped Right Arrow Shape)
+//    sun (Sun Shape)
+//    swooshArrow (Swoosh Arrow Shape)
+//    teardrop (Teardrop Shape)
+//    trapezoid (Trapezoid Shape)
+//    triangle (Triangle Shape)
+//    upArrow (Up Arrow Shape)
+//    upArrowCallout (Callout Up Arrow Shape)
+//    upDownArrow (Up Down Arrow Shape)
+//    upDownArrowCallout (Callout Up Down Arrow Shape)
+//    uturnArrow (U-Turn Arrow Shape)
+//    verticalScroll (Vertical Scroll Shape)
+//    wave (Wave Shape)
+//    wedgeEllipseCallout (Callout Wedge Ellipse Shape)
+//    wedgeRectCallout (Callout Wedge Rectangle Shape)
+//    wedgeRoundRectCallout (Callout Wedge Round Rectangle Shape)
+//
+func (f *File) AddShape(sheet, cell, format string) {
+	formatSet := parseFormatShapeSet(format)
+	// Read sheet data.
+	xlsx := f.workSheetReader(sheet)
+	// Add first shape for given sheet, create xl/drawings/ and xl/drawings/_rels/ folder.
+	drawingID := f.countDrawings() + 1
+	drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
+	sheetRelationshipsDrawingXML := "../drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
+
+	if xlsx.Drawing != nil {
+		// The worksheet already has a shape or chart relationships, use the relationships drawing ../drawings/drawing%d.xml.
+		sheetRelationshipsDrawingXML = f.getSheetRelationshipsTargetByID(sheet, xlsx.Drawing.RID)
+		drawingID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingXML, "../drawings/drawing"), ".xml"))
+		drawingXML = strings.Replace(sheetRelationshipsDrawingXML, "..", "xl", -1)
+	} else {
+		// Add first shape for given sheet.
+		rID := f.addSheetRelationships(sheet, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "")
+		f.addSheetDrawing(sheet, rID)
+	}
+	f.addDrawingShape(sheet, drawingXML, cell, formatSet)
+	f.addDrawingContentTypePart(drawingID)
+}
+
+// addDrawingShape
+func (f *File) addDrawingShape(sheet, drawingXML, cell string, formatSet *formatShape) {
+	cell = strings.ToUpper(cell)
+	fromCol := string(strings.Map(letterOnlyMapF, cell))
+	fromRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, cell))
+	row := fromRow - 1
+	col := titleToNumber(fromCol)
+	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 := 1
+	_, ok := f.XLSX[drawingXML]
+	if ok { // Append Model
+		decodeWsDr := decodeWsDr{}
+		xml.Unmarshal([]byte(f.readXML(drawingXML)), &decodeWsDr)
+		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,
+			})
+		}
+	}
+	twoCellAnchor := xdrCellAnchor{}
+	twoCellAnchor.EditAs = "oneCell"
+	from := xlsxFrom{}
+	from.Col = colStart
+	from.ColOff = formatSet.Format.OffsetX * EMU
+	from.Row = rowStart
+	from.RowOff = formatSet.Format.OffsetY * EMU
+	to := xlsxTo{}
+	to.Col = colEnd
+	to.ColOff = x2 * EMU
+	to.Row = rowEnd
+	to.RowOff = y2 * EMU
+	twoCellAnchor.From = &from
+	twoCellAnchor.To = &to
+	shape := xdrSp{
+		NvSpPr: &xdrNvSpPr{
+			CNvPr: &xlsxCNvPr{
+				ID:   cNvPrID,
+				Name: "Shape " + strconv.Itoa(cNvPrID),
+			},
+			CNvSpPr: &xdrCNvSpPr{
+				TxBox: true,
+			},
+		},
+		SpPr: &xlsxSpPr{
+			PrstGeom: xlsxPrstGeom{
+				Prst: formatSet.Type,
+			},
+		},
+		Style: &xdrStyle{
+			LnRef:     setShapeRef(formatSet.Color.Line, 2),
+			FillRef:   setShapeRef(formatSet.Color.Fill, 1),
+			EffectRef: setShapeRef(formatSet.Color.Effect, 0),
+			FontRef: &aFontRef{
+				Idx: "minor",
+				SchemeClr: &attrValString{
+					Val: "tx1",
+				},
+			},
+		},
+		TxBody: &xdrTxBody{
+			BodyPr: &aBodyPr{
+				VertOverflow: "clip",
+				HorzOverflow: "clip",
+				Wrap:         "none",
+				RtlCol:       false,
+				Anchor:       "t",
+			},
+			P: &aP{
+				R: &aR{
+					RPr: aRPr{
+						Lang:    "en-US",
+						AltLang: "en-US",
+						Sz:      1100,
+					},
+					T: formatSet.Text,
+				},
+				EndParaRPr: &aEndParaRPr{
+					Lang: "en-US",
+				},
+			},
+		},
+	}
+	twoCellAnchor.Sp = &shape
+	twoCellAnchor.ClientData = &xdrClientData{
+		FLocksWithSheet:  formatSet.Format.FLocksWithSheet,
+		FPrintsWithSheet: formatSet.Format.FPrintsWithSheet,
+	}
+	content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
+	output, _ := xml.Marshal(content)
+	f.saveFileList(drawingXML, string(output))
+}
+
+// setShapeRef provides function to set color with hex model by given actual
+// color value.
+func setShapeRef(color string, i int) *aRef {
+	if color == "" {
+		return &aRef{
+			Idx: 0,
+			ScrgbClr: &aScrgbClr{
+				R: 0,
+				G: 0,
+				B: 0,
+			},
+		}
+	}
+	return &aRef{
+		Idx: i,
+		SrgbClr: &attrValString{
+			Val: strings.Replace(strings.ToUpper(color), "#", "", -1),
+		},
+	}
+}

+ 1 - 1
sheet.go

@@ -291,7 +291,7 @@ func (f *File) GetSheetIndex(name string) int {
 
 // GetSheetMap provides function to get sheet map of XLSX. For example:
 //
-//    xlsx, err := excelize.OpenFile("/tmp/Workbook.xlsx")
+//    xlsx, err := excelize.OpenFile("./Workbook.xlsx")
 //    if err != nil {
 //        fmt.Println(err)
 //        os.Exit(1)

+ 0 - 3
table.go

@@ -52,11 +52,9 @@ func (f *File) AddTable(sheet, hcell, vcell, format string) {
 	vyAxis := vrow - 1
 	vxAxis := titleToNumber(vcol)
 	if vxAxis < hxAxis {
-		hcell, vcell = vcell, hcell
 		vxAxis, hxAxis = hxAxis, vxAxis
 	}
 	if vyAxis < hyAxis {
-		hcell, vcell = vcell, hcell
 		vyAxis, hyAxis = hyAxis, vyAxis
 	}
 	tableID := f.countTables() + 1
@@ -156,7 +154,6 @@ func (f *File) addTable(sheet, tableXML string, hxAxis, hyAxis, vxAxis, vyAxis,
 // addTableContentTypePart provides function to add image part relationships
 // in the file [Content_Types].xml by given drawing index.
 func (f *File) addTableContentTypePart(index int) {
-	f.setContentTypePartImageExtensions()
 	content := f.contentTypesReader()
 	for _, v := range content.Overrides {
 		if v.PartName == "/xl/tables/table"+strconv.Itoa(index)+".xml" {

二進制
test/Workbook1.xlsx


+ 9 - 8
xmlChart.go

@@ -1,14 +1,12 @@
 package excelize
 
-// chartSpace directly maps the xlsxChart element.
-type xlsxChartSpace struct {
-	ChartSpace cChartSpace `xml:"c:chartSpace"`
-}
+import "encoding/xml"
 
-// cChartSpace directly maps the c:chartSpace element. The chart namespace in
+// xlsxChartSpace directly maps the c:chartSpace element. The chart namespace in
 // DrawingML is for representing visualizations of numeric data with column
 // charts, pie charts, scatter charts, or other types of charts.
-type cChartSpace struct {
+type xlsxChartSpace struct {
+	XMLName        xml.Name        `xml:"c:chartSpace"`
 	XMLNSc         string          `xml:"xmlns:c,attr"`
 	XMLNSa         string          `xml:"xmlns:a,attr"`
 	XMLNSr         string          `xml:"xmlns:r,attr"`
@@ -98,7 +96,7 @@ type aBodyPr struct {
 // aP (Paragraph) directly maps the a:p element. This element specifies a
 // paragraph of content in the document.
 type aP struct {
-	PPr        aPPr         `xml:"a:pPr"`
+	PPr        *aPPr        `xml:"a:pPr"`
 	R          *aR          `xml:"a:r"`
 	EndParaRPr *aEndParaRPr `xml:"a:endParaRPr"`
 }
@@ -210,6 +208,7 @@ type aR struct {
 type aRPr struct {
 	Lang    string `xml:"lang,attr,omitempty"`
 	AltLang string `xml:"altLang,attr,omitempty"`
+	Sz      int    `xml:"sz,attr,omitempty"`
 }
 
 // cSpPr (Shape Properties) directly maps the c:spPr element. This element
@@ -271,7 +270,9 @@ type cTxPr struct {
 // element be specified at the end of the list of text runs within the paragraph
 // so that an orderly list is maintained.
 type aEndParaRPr struct {
-	Lang string `xml:"lang,attr"`
+	Lang    string `xml:"lang,attr"`
+	AltLang string `xml:"altLang,attr,omitempty"`
+	Sz      int    `xml:"sz,attr,omitempty"`
 }
 
 // cAutoTitleDeleted (Auto Title Is Deleted) directly maps the

+ 115 - 22
xmlDrawing.go

@@ -1,5 +1,7 @@
 package excelize
 
+import "encoding/xml"
+
 // Source relationship and namespace.
 const (
 	SourceRelationship              = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
@@ -162,42 +164,40 @@ type xlsxTo struct {
 	RowOff int `xml:"xdr:rowOff"`
 }
 
-// xlsxClientData directly maps the clientData element. An empty element which
+// xdrClientData directly maps the clientData element. An empty element which
 // specifies (via attributes) certain properties related to printing and
 // selection of the drawing object. The fLocksWithSheet attribute (either true
 // or false) determines whether to disable selection when the sheet is
 // protected, and fPrintsWithSheet attribute (either true or false) determines
 // whether the object is printed when the sheet is printed.
-type xlsxClientData struct {
+type xdrClientData struct {
 	FLocksWithSheet  bool `xml:"fLocksWithSheet,attr"`
 	FPrintsWithSheet bool `xml:"fPrintsWithSheet,attr"`
 }
 
-// xlsxCellAnchor directly maps the oneCellAnchor (One Cell Anchor Shape Size)
+// xdrCellAnchor directly maps the oneCellAnchor (One Cell Anchor Shape Size)
 // and twoCellAnchor (Two Cell Anchor Shape Size). This element specifies a two
 // cell anchor placeholder for a group, a shape, or a drawing element. It moves
 // with cells and its extents are in EMU units.
-type xlsxCellAnchor struct {
-	EditAs       string          `xml:"editAs,attr,omitempty"`
-	From         *xlsxFrom       `xml:"xdr:from"`
-	To           *xlsxTo         `xml:"xdr:to"`
-	Pic          *xlsxPic        `xml:"xdr:pic,omitempty"`
-	GraphicFrame string          `xml:",innerxml"`
-	ClientData   *xlsxClientData `xml:"xdr:clientData"`
+type xdrCellAnchor struct {
+	EditAs       string         `xml:"editAs,attr,omitempty"`
+	From         *xlsxFrom      `xml:"xdr:from"`
+	To           *xlsxTo        `xml:"xdr:to"`
+	Ext          *xlsxExt       `xml:"xdr:ext"`
+	Sp           *xdrSp         `xml:"xdr:sp"`
+	Pic          *xlsxPic       `xml:"xdr:pic,omitempty"`
+	GraphicFrame string         `xml:",innerxml"`
+	ClientData   *xdrClientData `xml:"xdr:clientData"`
 }
 
 // xlsxWsDr directly maps the root element for a part of this content type shall
 // wsDr.
 type xlsxWsDr struct {
-	OneCellAnchor []*xlsxCellAnchor `xml:"xdr:oneCellAnchor"`
-	TwoCellAnchor []*xlsxCellAnchor `xml:"xdr:twoCellAnchor"`
-	Xdr           string            `xml:"xmlns:xdr,attr"`
-	A             string            `xml:"xmlns:a,attr"`
-}
-
-// graphicFrame (Graphic Frame) directly maps the graphicFrame element.
-type graphicFrame struct {
-	GraphicFrame *xlsxGraphicFrame `xml:"xdr:graphicFrame"`
+	XMLName       xml.Name         `xml:"xdr:wsDr"`
+	OneCellAnchor []*xdrCellAnchor `xml:"xdr:oneCellAnchor"`
+	TwoCellAnchor []*xdrCellAnchor `xml:"xdr:twoCellAnchor"`
+	Xdr           string           `xml:"xmlns:xdr,attr"`
+	A             string           `xml:"xmlns:a,attr"`
 }
 
 // xlsxGraphicFrame (Graphic Frame) directly maps the xdr:graphicFrame element.
@@ -205,6 +205,7 @@ type graphicFrame struct {
 // a graphic that was generated by an external source and needs a container in
 // which to be displayed on the slide surface.
 type xlsxGraphicFrame struct {
+	XMLName          xml.Name             `xml:"xdr:graphicFrame"`
 	Macro            string               `xml:"macro,attr"`
 	NvGraphicFramePr xlsxNvGraphicFramePr `xml:"xdr:nvGraphicFramePr"`
 	Xfrm             xlsxXfrm             `xml:"xdr:xfrm"`
@@ -248,9 +249,85 @@ type xlsxChart struct {
 	R   string `xml:"xmlns:r,attr"`
 }
 
-// encodeWsDr directly maps the element xdr:wsDr.
-type encodeWsDr struct {
-	WsDr xlsxWsDr `xml:"xdr:wsDr"`
+// xdrSp (Shape) directly maps the xdr:sp element. This element specifies the
+// existence of a single shape. A shape can either be a preset or a custom
+// geometry, defined using the SpreadsheetDrawingML framework. In addition to a
+// geometry each shape can have both visual and non-visual properties attached.
+// Text and corresponding styling information can also be attached to a shape.
+// This shape is specified along with all other shapes within either the shape
+// tree or group shape elements.
+type xdrSp struct {
+	Macro    string     `xml:"macro,attr"`
+	Textlink string     `xml:"textlink,attr"`
+	NvSpPr   *xdrNvSpPr `xml:"xdr:nvSpPr"`
+	SpPr     *xlsxSpPr  `xml:"xdr:spPr"`
+	Style    *xdrStyle  `xml:"xdr:style"`
+	TxBody   *xdrTxBody `xml:"xdr:txBody"`
+}
+
+// xdrNvSpPr (Non-Visual Properties for a Shape) directly maps the xdr:nvSpPr
+// element. This element specifies all non-visual properties for a shape. This
+// element is a container for the non-visual identification properties, shape
+// properties and application properties that are to be associated with a shape.
+// This allows for additional information that does not affect the appearance of
+// the shape to be stored.
+type xdrNvSpPr struct {
+	CNvPr   *xlsxCNvPr  `xml:"xdr:cNvPr"`
+	CNvSpPr *xdrCNvSpPr `xml:"xdr:cNvSpPr"`
+}
+
+// xdrCNvSpPr (Connection Non-Visual Shape Properties) directly maps the
+// xdr:cNvSpPr element. This element specifies the set of non-visual properties
+// for a connection shape. These properties specify all data about the
+// connection shape which do not affect its display within a spreadsheet.
+type xdrCNvSpPr struct {
+	TxBox bool `xml:"txBox,attr"`
+}
+
+// xdrStyle (Shape Style) directly maps the xdr:style element. The element
+// specifies the style that is applied to a shape and the corresponding
+// references for each of the style components such as lines and fills.
+type xdrStyle struct {
+	LnRef     *aRef     `xml:"a:lnRef"`
+	FillRef   *aRef     `xml:"a:fillRef"`
+	EffectRef *aRef     `xml:"a:effectRef"`
+	FontRef   *aFontRef `xml:"a:fontRef"`
+}
+
+// aRef directly maps the a:lnRef, a:fillRef and a:effectRef element.
+type aRef struct {
+	Idx       int            `xml:"idx,attr"`
+	ScrgbClr  *aScrgbClr     `xml:"a:scrgbClr"`
+	SchemeClr *attrValString `xml:"a:schemeClr"`
+	SrgbClr   *attrValString `xml:"a:srgbClr"`
+}
+
+// aScrgbClr (RGB Color Model - Percentage Variant) directly maps the a:scrgbClr
+// element. This element specifies a color using the red, green, blue RGB color
+// model. Each component, red, green, and blue is expressed as a percentage from
+// 0% to 100%. A linear gamma of 1.0 is assumed.
+type aScrgbClr struct {
+	R float64 `xml:"r,attr"`
+	G float64 `xml:"g,attr"`
+	B float64 `xml:"b,attr"`
+}
+
+// aFontRef (Font Reference) directly maps the a:fontRef element. This element
+// represents a reference to a themed font. When used it specifies which themed
+// font to use along with a choice of color.
+type aFontRef struct {
+	Idx       string         `xml:"idx,attr"`
+	SchemeClr *attrValString `xml:"a:schemeClr"`
+}
+
+// xdrTxBody (Shape Text Body) directly maps the xdr:txBody element. This
+// element specifies the existence of text to be contained within the
+// corresponding shape. All visible text and visible text related properties are
+// contained within this element. There can be multiple paragraphs and within
+// paragraphs multiple runs of text.
+type xdrTxBody struct {
+	BodyPr *aBodyPr `xml:"a:bodyPr"`
+	P      *aP      `xml:"a:p"`
 }
 
 // formatPicture directly maps the format settings of the picture.
@@ -263,3 +340,19 @@ type formatPicture struct {
 	XScale           float64 `json:"x_scale"`
 	YScale           float64 `json:"y_scale"`
 }
+
+// formatShape directly maps the format settings of the shape.
+type formatShape struct {
+	Type   string           `json:"type"`
+	Width  int              `json:"width"`
+	Height int              `json:"height"`
+	Format formatPicture    `json:"format"`
+	Text   string           `json:"text"`
+	Color  formatShapeColor `json:"color"`
+}
+
+type formatShapeColor struct {
+	Line   string `json:"line"`
+	Fill   string `json:"fill"`
+	Effect string `json:"effect"`
+}