Resolve #455, init delete picture from spreadsheet support

formula
xuri 5 years ago
parent e2bd08c911
commit cbc3fd21b7
No known key found for this signature in database
GPG Key ID: BA5E5BB1C948EDF7

@ -10,11 +10,8 @@
package excelize package excelize
import ( import (
"bytes"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"io"
"strconv" "strconv"
"strings" "strings"
) )
@ -766,7 +763,6 @@ func (f *File) AddChart(sheet, cell, format string, combo ...string) error {
// DeleteChart provides a function to delete chart in XLSX by given worksheet // DeleteChart provides a function to delete chart in XLSX by given worksheet
// and cell name. // and cell name.
func (f *File) DeleteChart(sheet, cell string) (err error) { func (f *File) DeleteChart(sheet, cell string) (err error) {
var wsDr *xlsxWsDr
col, row, err := CellNameToCoordinates(cell) col, row, err := CellNameToCoordinates(cell)
if err != nil { if err != nil {
return return
@ -781,38 +777,7 @@ func (f *File) DeleteChart(sheet, cell string) (err error) {
return return
} }
drawingXML := strings.Replace(f.getSheetRelationshipsTargetByID(sheet, ws.Drawing.RID), "..", "xl", -1) drawingXML := strings.Replace(f.getSheetRelationshipsTargetByID(sheet, ws.Drawing.RID), "..", "xl", -1)
wsDr, _ = f.drawingParser(drawingXML) return f.deleteDrawing(col, row, drawingXML, "Chart")
for idx := 0; idx < len(wsDr.TwoCellAnchor); idx++ {
if err = nil; wsDr.TwoCellAnchor[idx].From != nil && wsDr.TwoCellAnchor[idx].Pic == nil {
if wsDr.TwoCellAnchor[idx].From.Col == col && wsDr.TwoCellAnchor[idx].From.Row == row {
wsDr.TwoCellAnchor = append(wsDr.TwoCellAnchor[:idx], wsDr.TwoCellAnchor[idx+1:]...)
idx--
}
}
}
return f.deleteChart(col, row, drawingXML, wsDr)
}
// deleteChart provides a function to delete chart graphic frame by given by
// given coordinates.
func (f *File) deleteChart(col, row int, drawingXML string, wsDr *xlsxWsDr) (err error) {
var deTwoCellAnchor *decodeTwoCellAnchor
for idx := 0; idx < len(wsDr.TwoCellAnchor); idx++ {
deTwoCellAnchor = new(decodeTwoCellAnchor)
if err = f.xmlNewDecoder(bytes.NewReader([]byte("<decodeTwoCellAnchor>" + wsDr.TwoCellAnchor[idx].GraphicFrame + "</decodeTwoCellAnchor>"))).
Decode(deTwoCellAnchor); err != nil && err != io.EOF {
err = fmt.Errorf("xml decode error: %s", err)
return
}
if err = nil; deTwoCellAnchor.From != nil && deTwoCellAnchor.Pic == nil {
if deTwoCellAnchor.From.Col == col && deTwoCellAnchor.From.Row == row {
wsDr.TwoCellAnchor = append(wsDr.TwoCellAnchor[:idx], wsDr.TwoCellAnchor[idx+1:]...)
idx--
}
}
}
f.Drawings[drawingXML] = wsDr
return err
} }
// countCharts provides a function to get chart files count storage in the // countCharts provides a function to get chart files count storage in the

@ -217,12 +217,6 @@ func TestDeleteChart(t *testing.T) {
assert.EqualError(t, f.DeleteChart("SheetN", "A1"), "sheet SheetN is not exist") assert.EqualError(t, f.DeleteChart("SheetN", "A1"), "sheet SheetN is not exist")
// Test delete chart with invalid coordinates. // Test delete chart with invalid coordinates.
assert.EqualError(t, f.DeleteChart("Sheet1", ""), `cannot convert cell "" to coordinates: invalid cell name ""`) assert.EqualError(t, f.DeleteChart("Sheet1", ""), `cannot convert cell "" to coordinates: invalid cell name ""`)
// Test delete chart with unsupport charset.
f, err = OpenFile(filepath.Join("test", "Book1.xlsx"))
assert.NoError(t, err)
delete(f.Sheet, "xl/drawings/drawing1.xml")
f.XLSX["xl/drawings/drawing1.xml"] = MacintoshCyrillicCharset
assert.EqualError(t, f.DeleteChart("Sheet1", "A1"), "xml decode error: XML syntax error on line 1: invalid UTF-8")
// Test delete chart on no chart worksheet. // Test delete chart on no chart worksheet.
assert.NoError(t, NewFile().DeleteChart("Sheet1", "A1")) assert.NoError(t, NewFile().DeleteChart("Sheet1", "A1"))
} }

@ -12,6 +12,7 @@ package excelize
import ( import (
"bytes" "bytes"
"encoding/xml" "encoding/xml"
"fmt"
"io" "io"
"log" "log"
"reflect" "reflect"
@ -1207,3 +1208,45 @@ func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rI
f.Drawings[drawingXML] = content f.Drawings[drawingXML] = content
return err return err
} }
// deleteDrawing provides a function to delete chart graphic frame by given by
// given coordinates and graphic type.
func (f *File) deleteDrawing(col, row int, drawingXML, drawingType string) (err error) {
var (
wsDr *xlsxWsDr
deTwoCellAnchor *decodeTwoCellAnchor
)
xdrCellAnchorFuncs := map[string]func(anchor *xdrCellAnchor) bool{
"Chart": func(anchor *xdrCellAnchor) bool { return anchor.Pic == nil },
"Pic": func(anchor *xdrCellAnchor) bool { return anchor.Pic != nil },
}
decodeTwoCellAnchorFuncs := map[string]func(anchor *decodeTwoCellAnchor) bool{
"Chart": func(anchor *decodeTwoCellAnchor) bool { return anchor.Pic == nil },
"Pic": func(anchor *decodeTwoCellAnchor) bool { return anchor.Pic != nil },
}
wsDr, _ = f.drawingParser(drawingXML)
for idx := 0; idx < len(wsDr.TwoCellAnchor); idx++ {
if err = nil; wsDr.TwoCellAnchor[idx].From != nil && xdrCellAnchorFuncs[drawingType](wsDr.TwoCellAnchor[idx]) {
if wsDr.TwoCellAnchor[idx].From.Col == col && wsDr.TwoCellAnchor[idx].From.Row == row {
wsDr.TwoCellAnchor = append(wsDr.TwoCellAnchor[:idx], wsDr.TwoCellAnchor[idx+1:]...)
idx--
}
}
}
for idx := 0; idx < len(wsDr.TwoCellAnchor); idx++ {
deTwoCellAnchor = new(decodeTwoCellAnchor)
if err = f.xmlNewDecoder(bytes.NewReader([]byte("<decodeTwoCellAnchor>" + wsDr.TwoCellAnchor[idx].GraphicFrame + "</decodeTwoCellAnchor>"))).
Decode(deTwoCellAnchor); err != nil && err != io.EOF {
err = fmt.Errorf("xml decode error: %s", err)
return
}
if err = nil; deTwoCellAnchor.From != nil && decodeTwoCellAnchorFuncs[drawingType](deTwoCellAnchor) {
if deTwoCellAnchor.From.Col == col && deTwoCellAnchor.From.Row == row {
wsDr.TwoCellAnchor = append(wsDr.TwoCellAnchor[:idx], wsDr.TwoCellAnchor[idx+1:]...)
idx--
}
}
}
f.Drawings[drawingXML] = wsDr
return err
}

@ -462,6 +462,27 @@ func (f *File) GetPicture(sheet, cell string) (string, []byte, error) {
return f.getPicture(row, col, drawingXML, drawingRelationships) return f.getPicture(row, col, drawingXML, drawingRelationships)
} }
// DeletePicture provides a function to delete chart in XLSX by given
// worksheet and cell name. Note that the image file won't deleted from the
// document currently.
func (f *File) DeletePicture(sheet, cell string) (err error) {
col, row, err := CellNameToCoordinates(cell)
if err != nil {
return
}
col--
row--
ws, err := f.workSheetReader(sheet)
if err != nil {
return
}
if ws.Drawing == nil {
return
}
drawingXML := strings.Replace(f.getSheetRelationshipsTargetByID(sheet, ws.Drawing.RID), "..", "xl", -1)
return f.deleteDrawing(col, row, drawingXML, "Pic")
}
// getPicture provides a function to get picture base name and raw content // getPicture provides a function to get picture base name and raw content
// embed in XLSX by given coordinates and drawing relationships. // embed in XLSX by given coordinates and drawing relationships.
func (f *File) getPicture(row, col int, drawingXML, drawingRelationships string) (ret string, buf []byte, err error) { func (f *File) getPicture(row, col int, drawingXML, drawingRelationships string) (ret string, buf []byte, err error) {

@ -166,3 +166,18 @@ func TestAddPictureFromBytes(t *testing.T) {
assert.Equal(t, 1, imageCount, "Duplicate image should only be stored once.") assert.Equal(t, 1, imageCount, "Duplicate image should only be stored once.")
assert.EqualError(t, f.AddPictureFromBytes("SheetN", fmt.Sprint("A", 1), "", "logo", ".png", imgFile), "sheet SheetN is not exist") assert.EqualError(t, f.AddPictureFromBytes("SheetN", fmt.Sprint("A", 1), "", "logo", ".png", imgFile), "sheet SheetN is not exist")
} }
func TestDeletePicture(t *testing.T) {
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
assert.NoError(t, err)
assert.NoError(t, f.DeletePicture("Sheet1", "A1"))
assert.NoError(t, f.AddPicture("Sheet1", "P1", filepath.Join("test", "images", "excel.jpg"), ""))
assert.NoError(t, f.DeletePicture("Sheet1", "P1"))
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDeletePicture.xlsx")))
// Test delete picture on not exists worksheet.
assert.EqualError(t, f.DeletePicture("SheetN", "A1"), "sheet SheetN is not exist")
// Test delete picture with invalid coordinates.
assert.EqualError(t, f.DeletePicture("Sheet1", ""), `cannot convert cell "" to coordinates: invalid cell name ""`)
// Test delete picture on no chart worksheet.
assert.NoError(t, NewFile().DeletePicture("Sheet1", "A1"))
}

Loading…
Cancel
Save