Skip to content

Commit cbc3fd2

Browse files
committed
Resolve qax-os#455, init delete picture from spreadsheet support
1 parent e2bd08c commit cbc3fd2

File tree

5 files changed

+80
-42
lines changed

5 files changed

+80
-42
lines changed

chart.go

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,8 @@
1010
package excelize
1111

1212
import (
13-
"bytes"
1413
"encoding/json"
1514
"errors"
16-
"fmt"
17-
"io"
1815
"strconv"
1916
"strings"
2017
)
@@ -766,7 +763,6 @@ func (f *File) AddChart(sheet, cell, format string, combo ...string) error {
766763
// DeleteChart provides a function to delete chart in XLSX by given worksheet
767764
// and cell name.
768765
func (f *File) DeleteChart(sheet, cell string) (err error) {
769-
var wsDr *xlsxWsDr
770766
col, row, err := CellNameToCoordinates(cell)
771767
if err != nil {
772768
return
@@ -781,38 +777,7 @@ func (f *File) DeleteChart(sheet, cell string) (err error) {
781777
return
782778
}
783779
drawingXML := strings.Replace(f.getSheetRelationshipsTargetByID(sheet, ws.Drawing.RID), "..", "xl", -1)
784-
wsDr, _ = f.drawingParser(drawingXML)
785-
for idx := 0; idx < len(wsDr.TwoCellAnchor); idx++ {
786-
if err = nil; wsDr.TwoCellAnchor[idx].From != nil && wsDr.TwoCellAnchor[idx].Pic == nil {
787-
if wsDr.TwoCellAnchor[idx].From.Col == col && wsDr.TwoCellAnchor[idx].From.Row == row {
788-
wsDr.TwoCellAnchor = append(wsDr.TwoCellAnchor[:idx], wsDr.TwoCellAnchor[idx+1:]...)
789-
idx--
790-
}
791-
}
792-
}
793-
return f.deleteChart(col, row, drawingXML, wsDr)
794-
}
795-
796-
// deleteChart provides a function to delete chart graphic frame by given by
797-
// given coordinates.
798-
func (f *File) deleteChart(col, row int, drawingXML string, wsDr *xlsxWsDr) (err error) {
799-
var deTwoCellAnchor *decodeTwoCellAnchor
800-
for idx := 0; idx < len(wsDr.TwoCellAnchor); idx++ {
801-
deTwoCellAnchor = new(decodeTwoCellAnchor)
802-
if err = f.xmlNewDecoder(bytes.NewReader([]byte("<decodeTwoCellAnchor>" + wsDr.TwoCellAnchor[idx].GraphicFrame + "</decodeTwoCellAnchor>"))).
803-
Decode(deTwoCellAnchor); err != nil && err != io.EOF {
804-
err = fmt.Errorf("xml decode error: %s", err)
805-
return
806-
}
807-
if err = nil; deTwoCellAnchor.From != nil && deTwoCellAnchor.Pic == nil {
808-
if deTwoCellAnchor.From.Col == col && deTwoCellAnchor.From.Row == row {
809-
wsDr.TwoCellAnchor = append(wsDr.TwoCellAnchor[:idx], wsDr.TwoCellAnchor[idx+1:]...)
810-
idx--
811-
}
812-
}
813-
}
814-
f.Drawings[drawingXML] = wsDr
815-
return err
780+
return f.deleteDrawing(col, row, drawingXML, "Chart")
816781
}
817782

818783
// countCharts provides a function to get chart files count storage in the

chart_test.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -217,12 +217,6 @@ func TestDeleteChart(t *testing.T) {
217217
assert.EqualError(t, f.DeleteChart("SheetN", "A1"), "sheet SheetN is not exist")
218218
// Test delete chart with invalid coordinates.
219219
assert.EqualError(t, f.DeleteChart("Sheet1", ""), `cannot convert cell "" to coordinates: invalid cell name ""`)
220-
// Test delete chart with unsupport charset.
221-
f, err = OpenFile(filepath.Join("test", "Book1.xlsx"))
222-
assert.NoError(t, err)
223-
delete(f.Sheet, "xl/drawings/drawing1.xml")
224-
f.XLSX["xl/drawings/drawing1.xml"] = MacintoshCyrillicCharset
225-
assert.EqualError(t, f.DeleteChart("Sheet1", "A1"), "xml decode error: XML syntax error on line 1: invalid UTF-8")
226220
// Test delete chart on no chart worksheet.
227221
assert.NoError(t, NewFile().DeleteChart("Sheet1", "A1"))
228222
}

drawing.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ package excelize
1212
import (
1313
"bytes"
1414
"encoding/xml"
15+
"fmt"
1516
"io"
1617
"log"
1718
"reflect"
@@ -1207,3 +1208,45 @@ func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rI
12071208
f.Drawings[drawingXML] = content
12081209
return err
12091210
}
1211+
1212+
// deleteDrawing provides a function to delete chart graphic frame by given by
1213+
// given coordinates and graphic type.
1214+
func (f *File) deleteDrawing(col, row int, drawingXML, drawingType string) (err error) {
1215+
var (
1216+
wsDr *xlsxWsDr
1217+
deTwoCellAnchor *decodeTwoCellAnchor
1218+
)
1219+
xdrCellAnchorFuncs := map[string]func(anchor *xdrCellAnchor) bool{
1220+
"Chart": func(anchor *xdrCellAnchor) bool { return anchor.Pic == nil },
1221+
"Pic": func(anchor *xdrCellAnchor) bool { return anchor.Pic != nil },
1222+
}
1223+
decodeTwoCellAnchorFuncs := map[string]func(anchor *decodeTwoCellAnchor) bool{
1224+
"Chart": func(anchor *decodeTwoCellAnchor) bool { return anchor.Pic == nil },
1225+
"Pic": func(anchor *decodeTwoCellAnchor) bool { return anchor.Pic != nil },
1226+
}
1227+
wsDr, _ = f.drawingParser(drawingXML)
1228+
for idx := 0; idx < len(wsDr.TwoCellAnchor); idx++ {
1229+
if err = nil; wsDr.TwoCellAnchor[idx].From != nil && xdrCellAnchorFuncs[drawingType](wsDr.TwoCellAnchor[idx]) {
1230+
if wsDr.TwoCellAnchor[idx].From.Col == col && wsDr.TwoCellAnchor[idx].From.Row == row {
1231+
wsDr.TwoCellAnchor = append(wsDr.TwoCellAnchor[:idx], wsDr.TwoCellAnchor[idx+1:]...)
1232+
idx--
1233+
}
1234+
}
1235+
}
1236+
for idx := 0; idx < len(wsDr.TwoCellAnchor); idx++ {
1237+
deTwoCellAnchor = new(decodeTwoCellAnchor)
1238+
if err = f.xmlNewDecoder(bytes.NewReader([]byte("<decodeTwoCellAnchor>" + wsDr.TwoCellAnchor[idx].GraphicFrame + "</decodeTwoCellAnchor>"))).
1239+
Decode(deTwoCellAnchor); err != nil && err != io.EOF {
1240+
err = fmt.Errorf("xml decode error: %s", err)
1241+
return
1242+
}
1243+
if err = nil; deTwoCellAnchor.From != nil && decodeTwoCellAnchorFuncs[drawingType](deTwoCellAnchor) {
1244+
if deTwoCellAnchor.From.Col == col && deTwoCellAnchor.From.Row == row {
1245+
wsDr.TwoCellAnchor = append(wsDr.TwoCellAnchor[:idx], wsDr.TwoCellAnchor[idx+1:]...)
1246+
idx--
1247+
}
1248+
}
1249+
}
1250+
f.Drawings[drawingXML] = wsDr
1251+
return err
1252+
}

picture.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,27 @@ func (f *File) GetPicture(sheet, cell string) (string, []byte, error) {
462462
return f.getPicture(row, col, drawingXML, drawingRelationships)
463463
}
464464

465+
// DeletePicture provides a function to delete chart in XLSX by given
466+
// worksheet and cell name. Note that the image file won't deleted from the
467+
// document currently.
468+
func (f *File) DeletePicture(sheet, cell string) (err error) {
469+
col, row, err := CellNameToCoordinates(cell)
470+
if err != nil {
471+
return
472+
}
473+
col--
474+
row--
475+
ws, err := f.workSheetReader(sheet)
476+
if err != nil {
477+
return
478+
}
479+
if ws.Drawing == nil {
480+
return
481+
}
482+
drawingXML := strings.Replace(f.getSheetRelationshipsTargetByID(sheet, ws.Drawing.RID), "..", "xl", -1)
483+
return f.deleteDrawing(col, row, drawingXML, "Pic")
484+
}
485+
465486
// getPicture provides a function to get picture base name and raw content
466487
// embed in XLSX by given coordinates and drawing relationships.
467488
func (f *File) getPicture(row, col int, drawingXML, drawingRelationships string) (ret string, buf []byte, err error) {

picture_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,3 +166,18 @@ func TestAddPictureFromBytes(t *testing.T) {
166166
assert.Equal(t, 1, imageCount, "Duplicate image should only be stored once.")
167167
assert.EqualError(t, f.AddPictureFromBytes("SheetN", fmt.Sprint("A", 1), "", "logo", ".png", imgFile), "sheet SheetN is not exist")
168168
}
169+
170+
func TestDeletePicture(t *testing.T) {
171+
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
172+
assert.NoError(t, err)
173+
assert.NoError(t, f.DeletePicture("Sheet1", "A1"))
174+
assert.NoError(t, f.AddPicture("Sheet1", "P1", filepath.Join("test", "images", "excel.jpg"), ""))
175+
assert.NoError(t, f.DeletePicture("Sheet1", "P1"))
176+
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDeletePicture.xlsx")))
177+
// Test delete picture on not exists worksheet.
178+
assert.EqualError(t, f.DeletePicture("SheetN", "A1"), "sheet SheetN is not exist")
179+
// Test delete picture with invalid coordinates.
180+
assert.EqualError(t, f.DeletePicture("Sheet1", ""), `cannot convert cell "" to coordinates: invalid cell name ""`)
181+
// Test delete picture on no chart worksheet.
182+
assert.NoError(t, NewFile().DeletePicture("Sheet1", "A1"))
183+
}

0 commit comments

Comments
 (0)