diff --git a/LICENSE b/LICENSE index 3ee17235..b765fe66 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,6 @@ -Copyright (c) 2016, Ri Xu -All rights reserved. +BSD 3-Clause License + +Copyright (c) 2016 - 2017 Ri Xu All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/README.md b/README.md index 3d0d24c2..1c77058c 100644 --- a/README.md +++ b/README.md @@ -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 Contributions are welcome! Open a pull request to fix a bug, or open an issue to discuss a new feature or change. diff --git a/excelize.go b/excelize.go index ca76c098..d7e08d5e 100644 --- a/excelize.go +++ b/excelize.go @@ -34,7 +34,7 @@ func OpenFile(filename string) (*File, error) { }, 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{}) { switch t := value.(type) { 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) { axis = strings.ToUpper(axis) var xlsx xlsxWorksheet @@ -69,7 +69,7 @@ func (f *File) SetCellInt(sheet string, axis string, value int) { xAxis := row - 1 yAxis := titleToNumber(col) - name := `xl/worksheets/` + strings.ToLower(sheet) + `.xml` + name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml" xml.Unmarshal([]byte(f.readXML(name)), &xlsx) rows := xAxis + 1 @@ -85,7 +85,7 @@ func (f *File) SetCellInt(sheet string, axis string, value int) { 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) { axis = strings.ToUpper(axis) var xlsx xlsxWorksheet @@ -94,7 +94,7 @@ func (f *File) SetCellStr(sheet string, axis string, value string) { xAxis := row - 1 yAxis := titleToNumber(col) - name := `xl/worksheets/` + strings.ToLower(sheet) + `.xml` + name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml" xml.Unmarshal([]byte(f.readXML(name)), &xlsx) rows := xAxis + 1 @@ -103,36 +103,36 @@ func (f *File) SetCellStr(sheet string, axis string, value string) { xlsx = completeRow(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 output, _ := xml.Marshal(xlsx) 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) { - axis = strings.ToUpper(axis) - var xlsx xlsxWorksheet - col := string(strings.Map(letterOnlyMapF, axis)) - row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis)) - xAxis := row - 1 - yAxis := titleToNumber(col) + axis = strings.ToUpper(axis) + var xlsx xlsxWorksheet + col := string(strings.Map(letterOnlyMapF, axis)) + row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis)) + xAxis := row - 1 + yAxis := titleToNumber(col) - name := `xl/worksheets/` + strings.ToLower(sheet) + `.xml` - xml.Unmarshal([]byte(f.readXML(name)), &xlsx) + name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml" + xml.Unmarshal([]byte(f.readXML(name)), &xlsx) - rows := xAxis + 1 - cell := yAxis + 1 + rows := xAxis + 1 + cell := yAxis + 1 - xlsx = completeRow(xlsx, rows, cell) - xlsx = completeCol(xlsx, rows, cell) + xlsx = completeRow(xlsx, rows, cell) + xlsx = completeCol(xlsx, rows, cell) - xlsx.SheetData.Row[xAxis].C[yAxis].T = "" - xlsx.SheetData.Row[xAxis].C[yAxis].V = value + xlsx.SheetData.Row[xAxis].C[yAxis].T = "" + xlsx.SheetData.Row[xAxis].C[yAxis].V = value - output, _ := xml.Marshal(xlsx) - f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output))) + output, _ := xml.Marshal(xlsx) + f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output))) } // Completion column element tags of XML in a sheet. @@ -288,16 +288,17 @@ func checkRow(xlsx xlsxWorksheet) xlsxWorksheet { // SUM(Sheet2!D2,Sheet2!D11) // // +// func (f *File) UpdateLinkedValue() { for i := 1; i <= f.SheetCount; i++ { 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) for indexR, row := range xlsx.SheetData.Row { for indexC, col := range row.C { if col.F != nil && col.V != `` { - xlsx.SheetData.Row[indexR].C[indexC].V = `` - xlsx.SheetData.Row[indexR].C[indexC].T = `` + xlsx.SheetData.Row[indexR].C[indexC].V = "" + xlsx.SheetData.Row[indexR].C[indexC].T = "" } } } diff --git a/excelize_test.go b/excelize_test.go index cd03cff5..e1bd4c79 100644 --- a/excelize_test.go +++ b/excelize_test.go @@ -21,9 +21,9 @@ func TestExcelize(t *testing.T) { } t.Log("\r\n") } - 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, 64)) + 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, 64)) f1.SetCellInt("SHEET2", "A1", 100) f1.SetCellStr("SHEET2", "C11", "Knowns") 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", int32(42)) f1.SetCellValue("Sheet2", "F2", int64(42)) - f1.SetCellValue("Sheet2", "F2", float32(42.65418)) - f1.SetCellValue("Sheet2", "F2", float64(-42.65418)) + f1.SetCellValue("Sheet2", "F2", float32(42.65418)) + f1.SetCellValue("Sheet2", "F2", float64(-42.65418)) f1.SetCellValue("Sheet2", "F2", float32(42)) f1.SetCellValue("Sheet2", "F2", float64(42)) f1.SetCellValue("Sheet2", "G2", nil) @@ -72,6 +72,34 @@ func TestExcelize(t *testing.T) { if err != nil { 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. err = f1.WriteTo("./test/Workbook_2.xlsx") if err != nil { @@ -102,6 +130,15 @@ func TestExcelize(t *testing.T) { f3.SetCellInt("Sheet2", "A23", 56) f3.SetCellStr("SHEET1", "B20", "42") 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") if err != nil { t.Log(err) diff --git a/picture.go b/picture.go new file mode 100644 index 00000000..62054fc1 --- /dev/null +++ b/picture.go @@ -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("", "", "", "") + 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 "" +} diff --git a/test/images/excel.bmp b/test/images/excel.bmp new file mode 100644 index 00000000..424619c5 Binary files /dev/null and b/test/images/excel.bmp differ diff --git a/test/images/excel.gif b/test/images/excel.gif new file mode 100644 index 00000000..1a34a180 Binary files /dev/null and b/test/images/excel.gif differ diff --git a/test/images/excel.ico b/test/images/excel.ico new file mode 100644 index 00000000..9bb8d6c9 Binary files /dev/null and b/test/images/excel.ico differ diff --git a/test/images/excel.jpg b/test/images/excel.jpg new file mode 100644 index 00000000..67c84f35 Binary files /dev/null and b/test/images/excel.jpg differ diff --git a/test/images/excel.png b/test/images/excel.png new file mode 100644 index 00000000..cbf36469 Binary files /dev/null and b/test/images/excel.png differ diff --git a/test/images/excel.tif b/test/images/excel.tif new file mode 100644 index 00000000..4eba87d2 Binary files /dev/null and b/test/images/excel.tif differ diff --git a/xmlContentTypes.go b/xmlContentTypes.go index 65e85bc2..4e185a0f 100644 --- a/xmlContentTypes.go +++ b/xmlContentTypes.go @@ -1,5 +1,3 @@ -// Some code of this file reference tealeg/xlsx. - package excelize import "encoding/xml" diff --git a/xmlDecodeDrawing.go b/xmlDecodeDrawing.go new file mode 100644 index 00000000..7965a14d --- /dev/null +++ b/xmlDecodeDrawing.go @@ -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"` +} diff --git a/xmlDrawing.go b/xmlDrawing.go new file mode 100644 index 00000000..75f6c03e --- /dev/null +++ b/xmlDrawing.go @@ -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"` +} diff --git a/xmlSharedStrings.go b/xmlSharedStrings.go index 059ed60a..03d1ed4b 100644 --- a/xmlSharedStrings.go +++ b/xmlSharedStrings.go @@ -1,5 +1,3 @@ -// Some code of this file reference tealeg/xlsx. - package excelize import "encoding/xml"