- New function `AddPicture()` added, support to add picture into excel cell;

- go test updated;
- fix typo and `gofmt -s` formatted
This commit is contained in:
Ri Xu 2017-01-17 19:06:42 +08:00
parent 53d8c4bb3a
commit a99f0227b0
15 changed files with 581 additions and 37 deletions

View File

@ -1,5 +1,6 @@
Copyright (c) 2016, Ri Xu BSD 3-Clause License
All rights reserved.
Copyright (c) 2016 - 2017 Ri Xu All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:

View File

@ -106,6 +106,28 @@ func main() {
} }
``` ```
### Add pictures to XLSX files
```go
package main
import (
"fmt"
"os"
"github.com/Luxurioust/excelize"
)
func main() {
xlsx := excelize.CreateFile()
err := xlsx.AddPicture("Sheet1", "A2", "H9", "/tmp/image.jpg")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
```
## Contributing ## Contributing
Contributions are welcome! Open a pull request to fix a bug, or open an issue to discuss a new feature or change. Contributions are welcome! Open a pull request to fix a bug, or open an issue to discuss a new feature or change.

View File

@ -34,7 +34,7 @@ func OpenFile(filename string) (*File, error) {
}, nil }, nil
} }
// SetCellValue provide function to set int or string type value of a cell. // SetCellValue provides function to set int or string type value of a cell.
func (f *File) SetCellValue(sheet string, axis string, value interface{}) { func (f *File) SetCellValue(sheet string, axis string, value interface{}) {
switch t := value.(type) { switch t := value.(type) {
case int: case int:
@ -60,7 +60,7 @@ func (f *File) SetCellValue(sheet string, axis string, value interface{}) {
} }
} }
// SetCellInt provide function to set int type value of a cell. // SetCellInt provides function to set int type value of a cell.
func (f *File) SetCellInt(sheet string, axis string, value int) { func (f *File) SetCellInt(sheet string, axis string, value int) {
axis = strings.ToUpper(axis) axis = strings.ToUpper(axis)
var xlsx xlsxWorksheet var xlsx xlsxWorksheet
@ -69,7 +69,7 @@ func (f *File) SetCellInt(sheet string, axis string, value int) {
xAxis := row - 1 xAxis := row - 1
yAxis := titleToNumber(col) yAxis := titleToNumber(col)
name := `xl/worksheets/` + strings.ToLower(sheet) + `.xml` name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx) xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
rows := xAxis + 1 rows := xAxis + 1
@ -85,7 +85,7 @@ func (f *File) SetCellInt(sheet string, axis string, value int) {
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output))) f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
} }
// SetCellStr provide function to set string type value of a cell. // SetCellStr provides function to set string type value of a cell.
func (f *File) SetCellStr(sheet string, axis string, value string) { func (f *File) SetCellStr(sheet string, axis string, value string) {
axis = strings.ToUpper(axis) axis = strings.ToUpper(axis)
var xlsx xlsxWorksheet var xlsx xlsxWorksheet
@ -94,7 +94,7 @@ func (f *File) SetCellStr(sheet string, axis string, value string) {
xAxis := row - 1 xAxis := row - 1
yAxis := titleToNumber(col) yAxis := titleToNumber(col)
name := `xl/worksheets/` + strings.ToLower(sheet) + `.xml` name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx) xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
rows := xAxis + 1 rows := xAxis + 1
@ -103,36 +103,36 @@ func (f *File) SetCellStr(sheet string, axis string, value string) {
xlsx = completeRow(xlsx, rows, cell) xlsx = completeRow(xlsx, rows, cell)
xlsx = completeCol(xlsx, rows, cell) xlsx = completeCol(xlsx, rows, cell)
xlsx.SheetData.Row[xAxis].C[yAxis].T = `str` xlsx.SheetData.Row[xAxis].C[yAxis].T = "str"
xlsx.SheetData.Row[xAxis].C[yAxis].V = value xlsx.SheetData.Row[xAxis].C[yAxis].V = value
output, _ := xml.Marshal(xlsx) output, _ := xml.Marshal(xlsx)
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output))) f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
} }
// SetCellDefault provides function to set string type value of a cell as default format without escaping the cell // SetCellDefault provides function to set string type value of a cell as default format without escaping the cell.
func (f *File) SetCellDefault(sheet string, axis string, value string) { func (f *File) SetCellDefault(sheet string, axis string, value string) {
axis = strings.ToUpper(axis) axis = strings.ToUpper(axis)
var xlsx xlsxWorksheet var xlsx xlsxWorksheet
col := string(strings.Map(letterOnlyMapF, axis)) col := string(strings.Map(letterOnlyMapF, axis))
row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis)) row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
xAxis := row - 1 xAxis := row - 1
yAxis := titleToNumber(col) yAxis := titleToNumber(col)
name := `xl/worksheets/` + strings.ToLower(sheet) + `.xml` name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx) xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
rows := xAxis + 1 rows := xAxis + 1
cell := yAxis + 1 cell := yAxis + 1
xlsx = completeRow(xlsx, rows, cell) xlsx = completeRow(xlsx, rows, cell)
xlsx = completeCol(xlsx, rows, cell) xlsx = completeCol(xlsx, rows, cell)
xlsx.SheetData.Row[xAxis].C[yAxis].T = "" xlsx.SheetData.Row[xAxis].C[yAxis].T = ""
xlsx.SheetData.Row[xAxis].C[yAxis].V = value xlsx.SheetData.Row[xAxis].C[yAxis].V = value
output, _ := xml.Marshal(xlsx) output, _ := xml.Marshal(xlsx)
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output))) f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
} }
// Completion column element tags of XML in a sheet. // Completion column element tags of XML in a sheet.
@ -288,16 +288,17 @@ func checkRow(xlsx xlsxWorksheet) xlsxWorksheet {
// <f>SUM(Sheet2!D2,Sheet2!D11)</f> // <f>SUM(Sheet2!D2,Sheet2!D11)</f>
// </c> // </c>
// </row> // </row>
//
func (f *File) UpdateLinkedValue() { func (f *File) UpdateLinkedValue() {
for i := 1; i <= f.SheetCount; i++ { for i := 1; i <= f.SheetCount; i++ {
var xlsx xlsxWorksheet var xlsx xlsxWorksheet
name := `xl/worksheets/sheet` + strconv.Itoa(i) + `.xml` name := "xl/worksheets/sheet" + strconv.Itoa(i) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx) xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
for indexR, row := range xlsx.SheetData.Row { for indexR, row := range xlsx.SheetData.Row {
for indexC, col := range row.C { for indexC, col := range row.C {
if col.F != nil && col.V != `` { if col.F != nil && col.V != `` {
xlsx.SheetData.Row[indexR].C[indexC].V = `` xlsx.SheetData.Row[indexR].C[indexC].V = ""
xlsx.SheetData.Row[indexR].C[indexC].T = `` xlsx.SheetData.Row[indexR].C[indexC].T = ""
} }
} }
} }

View File

@ -22,8 +22,8 @@ func TestExcelize(t *testing.T) {
t.Log("\r\n") t.Log("\r\n")
} }
f1.UpdateLinkedValue() f1.UpdateLinkedValue()
f1.SetCellDefault("SHEET2", "A1", strconv.FormatFloat(float64(100.1588), 'f', -1, 32)) f1.SetCellDefault("SHEET2", "A1", strconv.FormatFloat(float64(100.1588), 'f', -1, 32))
f1.SetCellDefault("SHEET2", "A1", strconv.FormatFloat(float64(-100.1588), 'f', -1, 64)) f1.SetCellDefault("SHEET2", "A1", strconv.FormatFloat(float64(-100.1588), 'f', -1, 64))
f1.SetCellInt("SHEET2", "A1", 100) f1.SetCellInt("SHEET2", "A1", 100)
f1.SetCellStr("SHEET2", "C11", "Knowns") f1.SetCellStr("SHEET2", "C11", "Knowns")
f1.NewSheet(3, "Maximum 31 characters allowed in sheet title.") f1.NewSheet(3, "Maximum 31 characters allowed in sheet title.")
@ -49,8 +49,8 @@ func TestExcelize(t *testing.T) {
f1.SetCellValue("Sheet2", "F2", int16(42)) f1.SetCellValue("Sheet2", "F2", int16(42))
f1.SetCellValue("Sheet2", "F2", int32(42)) f1.SetCellValue("Sheet2", "F2", int32(42))
f1.SetCellValue("Sheet2", "F2", int64(42)) f1.SetCellValue("Sheet2", "F2", int64(42))
f1.SetCellValue("Sheet2", "F2", float32(42.65418)) f1.SetCellValue("Sheet2", "F2", float32(42.65418))
f1.SetCellValue("Sheet2", "F2", float64(-42.65418)) f1.SetCellValue("Sheet2", "F2", float64(-42.65418))
f1.SetCellValue("Sheet2", "F2", float32(42)) f1.SetCellValue("Sheet2", "F2", float32(42))
f1.SetCellValue("Sheet2", "F2", float64(42)) f1.SetCellValue("Sheet2", "F2", float64(42))
f1.SetCellValue("Sheet2", "G2", nil) f1.SetCellValue("Sheet2", "G2", nil)
@ -72,6 +72,34 @@ func TestExcelize(t *testing.T) {
if err != nil { if err != nil {
t.Log(err) t.Log(err)
} }
// Test add picture to sheet.
err = f1.AddPicture("Sheet2", "I1", "L10", "./test/images/excel.jpg")
if err != nil {
t.Log(err)
}
err = f1.AddPicture("Sheet1", "F21", "G25", "./test/images/excel.png")
if err != nil {
t.Log(err)
}
err = f1.AddPicture("Sheet2", "L1", "O10", "./test/images/excel.bmp")
if err != nil {
t.Log(err)
}
err = f1.AddPicture("Sheet1", "G21", "H25", "./test/images/excel.ico")
if err != nil {
t.Log(err)
}
// Test add picture to sheet with unsupport file type.
err = f1.AddPicture("Sheet1", "G21", "H25", "./test/images/excel.icon")
if err != nil {
t.Log(err)
}
// Test add picture to sheet with invalid file path.
err = f1.AddPicture("Sheet1", "G21", "H25", "./test/Workbook1.xlsx")
if err != nil {
t.Log(err)
}
// Test write file to given path. // Test write file to given path.
err = f1.WriteTo("./test/Workbook_2.xlsx") err = f1.WriteTo("./test/Workbook_2.xlsx")
if err != nil { if err != nil {
@ -102,6 +130,15 @@ func TestExcelize(t *testing.T) {
f3.SetCellInt("Sheet2", "A23", 56) f3.SetCellInt("Sheet2", "A23", 56)
f3.SetCellStr("SHEET1", "B20", "42") f3.SetCellStr("SHEET1", "B20", "42")
f3.SetActiveSheet(0) f3.SetActiveSheet(0)
// Test add picture to sheet.
err = f3.AddPicture("Sheet1", "H2", "K12", "./test/images/excel.gif")
if err != nil {
t.Log(err)
}
err = f3.AddPicture("Sheet1", "C2", "F12", "./test/images/excel.tif")
if err != nil {
t.Log(err)
}
err = f3.WriteTo("./test/Workbook_3.xlsx") err = f3.WriteTo("./test/Workbook_3.xlsx")
if err != nil { if err != nil {
t.Log(err) t.Log(err)

286
picture.go Normal file
View File

@ -0,0 +1,286 @@
package excelize
import (
"bytes"
"encoding/xml"
"errors"
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"strconv"
"strings"
)
// AddPicture provide the method to add picture in a sheet by given xAxis, yAxis and file path.
// For example:
//
// xlsx := excelize.CreateFile()
// err := xlsx.AddPicture("Sheet1", "A2", "H9", "./image.jpg")
// if err != nil {
// fmt.Println(err)
// os.Exit(1)
// }
//
func (f *File) AddPicture(sheet string, xAxis string, yAxis string, picture string) error {
var supportTypes = map[string]string{".bmp": ".jpeg", ".gif": ".gif", ".ico": ".png", ".tif": ".tiff", ".tiff": ".tiff", ".jpg": ".jpeg", ".jpeg": ".jpeg", ".png": ".png"}
var err error
// Check picture exists first.
if _, err = os.Stat(picture); os.IsNotExist(err) {
return err
}
ext, ok := supportTypes[path.Ext(picture)]
if !ok {
return errors.New("Unsupported image extension")
}
_, file := filepath.Split(picture)
// Read sheet data.
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
// Add first picture for given sheet, create xl/drawings/ and xl/drawings/_rels/ folder.
drawingID := f.countDrawings() + 1
pictureID := f.countMedia() + 1
drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
sheetRelationshipsDrawingXML := "../drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
var drawingRID int
if xlsx.Drawing != nil {
// The worksheet already has a picture 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 picture for given sheet.
rID := f.addSheetRelationships(sheet, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML)
f.addSheetDrawing(sheet, rID)
}
drawingRID = f.addDrawingRelationships(drawingID, SourceRelationshipImage, "../media/image"+strconv.Itoa(pictureID)+ext)
f.addDrawing(drawingXML, xAxis, yAxis, file, drawingRID)
f.addMedia(picture, ext)
f.addDrawingContentTypePart(drawingID)
return err
}
// addSheetRelationships provides function to add xl/worksheets/_rels/sheet%d.xml.rels by given
// sheet name, relationship type and target.
func (f *File) addSheetRelationships(sheet string, relType string, target string) int {
var rels = "xl/worksheets/_rels/" + strings.ToLower(sheet) + ".xml.rels"
var sheetRels 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([]byte(f.readXML(rels)), &sheetRels)
rID = len(sheetRels.Relationships) + 1
ID.WriteString("rId")
ID.WriteString(strconv.Itoa(rID))
}
sheetRels.Relationships = append(sheetRels.Relationships, xlsxWorkbookRelation{
ID: ID.String(),
Type: relType,
Target: target,
})
output, err := xml.Marshal(sheetRels)
if err != nil {
fmt.Println(err)
}
f.saveFileList(rels, string(output))
return rID
}
// addSheetDrawing provides function to add drawing element to xl/worksheets/sheet%d.xml by
// given sheet name and relationship index.
func (f *File) addSheetDrawing(sheet string, rID int) {
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
xlsx.Drawing = &xlsxDrawing{
RID: "rId" + strconv.Itoa(rID),
}
output, err := xml.Marshal(xlsx)
if err != nil {
fmt.Println(err)
}
f.saveFileList(name, string(output))
}
// countDrawings provides function to get drawing files count storage in the folder xl/drawings.
func (f *File) countDrawings() int {
count := 0
for k := range f.XLSX {
if strings.Contains(k, "xl/drawings/drawing") {
count++
}
}
return count
}
// addDrawing provides function to add picture by given drawingXML, xAxis, yAxis, file name
// and relationship index. In order to solve the problem that the label structure is changed
// after serialization and deserialization, two different structures: decodeWsDr and encodeWsDr
// are defined.
func (f *File) addDrawing(drawingXML string, xAxis string, yAxis string, file string, rID int) {
xAxis = strings.ToUpper(xAxis)
fromCol := string(strings.Map(letterOnlyMapF, xAxis))
fromRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, xAxis))
fromXAxis := fromRow - 1
fromYAxis := titleToNumber(fromCol)
yAxis = strings.ToUpper(yAxis)
ToCol := string(strings.Map(letterOnlyMapF, yAxis))
ToRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, yAxis))
ToXAxis := ToRow - 1
ToYAxis := titleToNumber(ToCol)
content := encodeWsDr{}
content.WsDr.A = NameSpaceDrawingML
content.WsDr.Xdr = NameSpaceSpreadSheetDrawing
cNvPrID := 1
_, ok := f.XLSX[drawingXML]
if ok { // Append Model
decodeWsDr := decodeWsDr{}
xml.Unmarshal([]byte(f.readXML(drawingXML)), &decodeWsDr)
cNvPrID = len(decodeWsDr.TwoCellAnchor) + 1
for _, v := range decodeWsDr.TwoCellAnchor {
content.WsDr.TwoCellAnchor = append(content.WsDr.TwoCellAnchor, &xlsxTwoCellAnchor{
EditAs: v.EditAs,
GraphicFrame: v.Content,
})
}
}
twoCellAnchor := xlsxTwoCellAnchor{}
twoCellAnchor.EditAs = "oneCell"
from := xlsxFrom{}
from.Col = fromYAxis
from.Row = fromXAxis
to := xlsxTo{}
to.Col = ToYAxis
to.Row = ToXAxis
twoCellAnchor.From = &from
twoCellAnchor.To = &to
pic := xlsxPic{}
pic.NvPicPr.CNvPicPr.PicLocks.NoChangeAspect = false
pic.NvPicPr.CNvPr.ID = cNvPrID
pic.NvPicPr.CNvPr.Descr = file
pic.NvPicPr.CNvPr.Name = "Picture " + strconv.Itoa(cNvPrID)
pic.BlipFill.Blip.R = SourceRelationship
pic.BlipFill.Blip.Embed = "rId" + strconv.Itoa(rID)
pic.SpPr.PrstGeom.Prst = "rect"
twoCellAnchor.Pic = &pic
twoCellAnchor.ClientData = &xlsxClientData{
FLocksWithSheet: false,
FPrintsWithSheet: false,
}
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)
}
// addDrawingRelationships provides function to add image part relationships in the file
// xl/drawings/_rels/drawing%d.xml.rels by given drawing index, relationship type and target.
func (f *File) addDrawingRelationships(index int, relType string, target 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([]byte(f.readXML(rels)), &drawingRels)
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,
})
output, err := xml.Marshal(drawingRels)
if err != nil {
fmt.Println(err)
}
f.saveFileList(rels, string(output))
return rID
}
// countMedia provides function to get media files count storage in the folder xl/media/image.
func (f *File) countMedia() int {
count := 0
for k := range f.XLSX {
if strings.Contains(k, "xl/media/image") {
count++
}
}
return count
}
// addMedia provides function to add picture into folder xl/media/image by given file
// name and extension name.
func (f *File) addMedia(file string, ext string) {
count := f.countMedia()
dat, _ := ioutil.ReadFile(file)
media := "xl/media/image" + strconv.Itoa(count+1) + ext
f.XLSX[media] = string(dat)
}
// addDrawingContentTypePart provides function to add image part relationships in
// http://purl.oclc.org/ooxml/officeDocument/relationships/image and appropriate content type.
func (f *File) addDrawingContentTypePart(index int) {
var imageTypes = map[string]bool{"jpeg": false, "png": false, "gif": false, "tiff": false}
var content xlsxTypes
xml.Unmarshal([]byte(f.readXML(`[Content_Types].xml`)), &content)
for _, v := range content.Defaults {
_, ok := imageTypes[v.Extension]
if ok {
imageTypes[v.Extension] = true
}
}
for k, v := range imageTypes {
if !v {
content.Defaults = append(content.Defaults, xlsxDefault{
Extension: k,
ContentType: "image/" + k,
})
}
}
for _, v := range content.Overrides {
if v.PartName == "/xl/drawings/drawing"+strconv.Itoa(index)+".xml" {
output, _ := xml.Marshal(content)
f.saveFileList(`[Content_Types].xml`, string(output))
return
}
}
content.Overrides = append(content.Overrides, xlsxOverride{
PartName: "/xl/drawings/drawing" + strconv.Itoa(index) + ".xml",
ContentType: "application/vnd.openxmlformats-officedocument.drawing+xml",
})
output, _ := xml.Marshal(content)
f.saveFileList(`[Content_Types].xml`, string(output))
}
// getSheetRelationshipsTargetByID provides function to get Target attribute value
// in xl/worksheets/_rels/sheet%d.xml.rels by given sheet name and relationship index.
func (f *File) getSheetRelationshipsTargetByID(sheet string, rID string) string {
var rels = "xl/worksheets/_rels/" + strings.ToLower(sheet) + ".xml.rels"
var sheetRels xlsxWorkbookRels
xml.Unmarshal([]byte(f.readXML(rels)), &sheetRels)
for _, v := range sheetRels.Relationships {
if v.ID == rID {
return v.Target
}
}
return ""
}

BIN
test/images/excel.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
test/images/excel.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
test/images/excel.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
test/images/excel.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
test/images/excel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
test/images/excel.tif Normal file

Binary file not shown.

View File

@ -1,5 +1,3 @@
// Some code of this file reference tealeg/xlsx.
package excelize package excelize
import "encoding/xml" import "encoding/xml"

21
xmlDecodeDrawing.go Normal file
View File

@ -0,0 +1,21 @@
package excelize
import "encoding/xml"
// decodeTwoCellAnchor directly maps the 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 decodeTwoCellAnchor struct {
EditAs string `xml:"editAs,attr,omitempty"`
Content string `xml:",innerxml"`
}
// decodeWsDr directly maps the root element for a part of this content type shall wsDr.
// In order to solve the problem that the label structure is changed after serialization
// and deserialization, two different structures are defined. decodeWsDr just for deserialization.
type decodeWsDr struct {
A string `xml:"xmlns a,attr"`
Xdr string `xml:"xmlns xdr,attr"`
TwoCellAnchor []*decodeTwoCellAnchor `xml:"twoCellAnchor,omitempty"`
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing wsDr,omitempty"`
}

180
xmlDrawing.go Normal file
View File

@ -0,0 +1,180 @@
package excelize
// Source relationship and namespace.
const (
SourceRelationship = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
SourceRelationshipImage = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
SourceRelationshipDrawingML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"
NameSpaceDrawingML = "http://schemas.openxmlformats.org/drawingml/2006/main"
NameSpaceSpreadSheetDrawing = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
)
// xlsxCNvPr directly maps the cNvPr (Non-Visual Drawing Properties).
// This element specifies non-visual canvas properties. This allows for
// additional information that does not affect the appearance of the
// picture to be stored.
type xlsxCNvPr struct {
ID int `xml:"id,attr"`
Name string `xml:"name,attr"`
Descr string `xml:"descr,attr"`
Title string `xml:"title,attr,omitempty"`
}
// xlsxPicLocks directly maps the picLocks (Picture Locks). This element
// specifies all locking properties for a graphic frame. These properties
// inform the generating application about specific properties that have
// been previously locked and thus should not be changed.
type xlsxPicLocks struct {
NoAdjustHandles bool `xml:"noAdjustHandles,attr,omitempty"`
NoChangeArrowheads bool `xml:"noChangeArrowheads,attr,omitempty"`
NoChangeAspect bool `xml:"noChangeAspect,attr"`
NoChangeShapeType bool `xml:"noChangeShapeType,attr,omitempty"`
NoCrop bool `xml:"noCrop,attr,omitempty"`
NoEditPoints bool `xml:"noEditPoints,attr,omitempty"`
NoGrp bool `xml:"noGrp,attr,omitempty"`
NoMove bool `xml:"noMove,attr,omitempty"`
NoResize bool `xml:"noResize,attr,omitempty"`
NoRot bool `xml:"noRot,attr,omitempty"`
NoSelect bool `xml:"noSelect,attr,omitempty"`
}
// xlsxBlip directly maps the blip element in the namespace
// http://purl.oclc.or g/ooxml/officeDoc ument/relationships -
// This element specifies the existence of an image (binary large image or
// picture) and contains a reference to the image data.
type xlsxBlip struct {
Embed string `xml:"r:embed,attr"`
Cstate string `xml:"cstate,attr,omitempty"`
R string `xml:"xmlns:r,attr"`
}
// xlsxStretch directly maps the stretch element. This element specifies
// that a BLIP should be stretched to fill the target rectangle. The other
// option is a tile where a BLIP is tiled to fill the available area.
type xlsxStretch struct {
FillRect string `xml:"a:fillRect"`
}
// xlsxOff directly maps the colOff and rowOff element. This element is used
// to specify the column offset within a cell.
type xlsxOff struct {
X int `xml:"x,attr"`
Y int `xml:"y,attr"`
}
// xlsxExt directly maps the ext element.
type xlsxExt struct {
Cx int `xml:"cx,attr"`
Cy int `xml:"cy,attr"`
}
// xlsxPrstGeom directly maps the prstGeom (Preset geometry). This element specifies
// when a preset geometric shape should be used instead of a custom geometric shape.
// The generating application should be able to render all preset geometries enumerated
// in the ST_ShapeType list.
type xlsxPrstGeom struct {
Prst string `xml:"prst,attr"`
}
// xlsxXfrm directly maps the xfrm (2D Transform for Graphic Frame). This element
// specifies the transform to be applied to the corresponding graphic frame. This
// transformation is applied to the graphic frame just as it would be for a shape
// or group shape.
type xlsxXfrm struct {
Off xlsxOff `xml:"a:off"`
Ext xlsxExt `xml:"a:ext"`
}
// xlsxCNvPicPr directly maps the cNvPicPr (Non-Visual Picture Drawing Properties).
// This element specifies the non-visual properties for the picture canvas. These
// properties are to be used by the generating application to determine how certain
// properties are to be changed for the picture object in question.
type xlsxCNvPicPr struct {
PicLocks xlsxPicLocks `xml:"a:picLocks"`
}
// directly maps the nvPicPr (Non-Visual Properties for a Picture). This element specifies
// all non-visual properties for a picture. This element is a container for the non-visual
// identification properties, shape properties and application properties that are to be
// associated with a picture. This allows for additional information that does not affect
// the appearance of the picture to be stored.
type xlsxNvPicPr struct {
CNvPr xlsxCNvPr `xml:"xdr:cNvPr"`
CNvPicPr xlsxCNvPicPr `xml:"xdr:cNvPicPr"`
}
// xlsxBlipFill directly maps the blipFill (Picture Fill). This element specifies the kind
// of picture fill that the picture object has. Because a picture has a picture fill already
// by default, it is possible to have two fills specified for a picture object.
type xlsxBlipFill struct {
Blip xlsxBlip `xml:"a:blip"`
Stretch xlsxStretch `xml:"a:stretch"`
}
// xlsxSpPr directly maps the spPr (Shape Properties). This element specifies the visual shape
// properties that can be applied to a picture. These are the same properties that are allowed
// to describe the visual properties of a shape but are used here to describe the visual
// appearance of a picture within a document.
type xlsxSpPr struct {
Xfrm xlsxXfrm `xml:"a:xfrm"`
PrstGeom xlsxPrstGeom `xml:"a:prstGeom"`
}
// xlsxPic elements encompass the definition of pictures within the DrawingML framework. While
// pictures are in many ways very similar to shapes they have specific properties that are unique
// in order to optimize for picture- specific scenarios.
type xlsxPic struct {
NvPicPr xlsxNvPicPr `xml:"xdr:nvPicPr"`
BlipFill xlsxBlipFill `xml:"xdr:blipFill"`
SpPr xlsxSpPr `xml:"xdr:spPr"`
}
// xlsxFrom specifies the starting anchor.
type xlsxFrom struct {
Col int `xml:"xdr:col"`
ColOff int `xml:"xdr:colOff"`
Row int `xml:"xdr:row"`
RowOff int `xml:"xdr:rowOff"`
}
// xlsxTo directly specifies the ending anchor.
type xlsxTo struct {
Col int `xml:"xdr:col"`
ColOff int `xml:"xdr:colOff"`
Row int `xml:"xdr:row"`
RowOff int `xml:"xdr:rowOff"`
}
// xlsxClientData 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 {
FLocksWithSheet bool `xml:"fLocksWithSheet,attr"`
FPrintsWithSheet bool `xml:"fPrintsWithSheet,attr"`
}
// xlsxTwoCellAnchor directly maps the 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 xlsxTwoCellAnchor 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"`
}
// xlsxWsDr directly maps the root element for a part of this content type shall wsDr.
type xlsxWsDr struct {
TwoCellAnchor []*xlsxTwoCellAnchor `xml:"xdr:twoCellAnchor"`
Xdr string `xml:"xmlns:xdr,attr"`
A string `xml:"xmlns:a,attr"`
}
// encodeWsDr directly maps the element xdr:wsDr.
type encodeWsDr struct {
WsDr xlsxWsDr `xml:"xdr:wsDr"`
}

View File

@ -1,5 +1,3 @@
// Some code of this file reference tealeg/xlsx.
package excelize package excelize
import "encoding/xml" import "encoding/xml"