diff --git a/chart_test.go b/chart_test.go
index dc2df7ae95..1527bc71e6 100644
--- a/chart_test.go
+++ b/chart_test.go
@@ -124,6 +124,11 @@ func TestDeleteDrawing(t *testing.T) {
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
f, err = OpenFile(filepath.Join("test", "Book1.xlsx"))
assert.NoError(t, err)
+ f.Drawings.Store(path, &xlsxWsDr{OneCellAnchor: []*xdrCellAnchor{{
+ GraphicFrame: string(MacintoshCyrillicCharset),
+ }}})
+ _, err = f.deleteDrawing(0, 0, path, "Chart")
+ assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
f.Drawings.Store(path, &xlsxWsDr{TwoCellAnchor: []*xdrCellAnchor{{
GraphicFrame: string(MacintoshCyrillicCharset),
}}})
diff --git a/drawing.go b/drawing.go
index 09f5800868..7241dac1f8 100644
--- a/drawing.go
+++ b/drawing.go
@@ -1484,13 +1484,14 @@ func (f *File) addSheetDrawingChart(drawingXML string, rID int, opts *GraphicOpt
// deleteDrawing provides a function to delete the chart graphic frame and
// returns deleted embed relationships ID (for unique picture cell anchor) by
// given coordinates and graphic type.
-func (f *File) deleteDrawing(col, row int, drawingXML, drawingType string) (string, error) {
+func (f *File) deleteDrawing(col, row int, drawingXML, drawingType string) ([]string, error) {
var (
- err error
- rID string
- rIDs []string
- wsDr *xlsxWsDr
- deTwoCellAnchor *decodeCellAnchor
+ err error
+ rID string
+ delRID, refRID []string
+ rIDMaps = map[string]int{}
+ wsDr *xlsxWsDr
+ deCellAnchor *decodeCellAnchor
)
xdrCellAnchorFuncs := map[string]func(anchor *xdrCellAnchor) bool{
"Chart": func(anchor *xdrCellAnchor) bool { return anchor.Pic == nil },
@@ -1502,54 +1503,70 @@ func (f *File) deleteDrawing(col, row int, drawingXML, drawingType string) (stri
}
onAnchorCell := func(c, r int) bool { return c == col && r == row }
if wsDr, _, err = f.drawingParser(drawingXML); err != nil {
- return rID, err
- }
- for idx := 0; idx < len(wsDr.TwoCellAnchor); idx++ {
- if err = nil; wsDr.TwoCellAnchor[idx].From != nil && xdrCellAnchorFuncs[drawingType](wsDr.TwoCellAnchor[idx]) {
- if onAnchorCell(wsDr.TwoCellAnchor[idx].From.Col, wsDr.TwoCellAnchor[idx].From.Row) {
- rID, _ = extractEmbedRID(wsDr.TwoCellAnchor[idx].Pic, nil, rIDs)
- wsDr.TwoCellAnchor = append(wsDr.TwoCellAnchor[:idx], wsDr.TwoCellAnchor[idx+1:]...)
- idx--
+ return delRID, err
+ }
+ deleteCellAnchor := func(ca []*xdrCellAnchor) ([]*xdrCellAnchor, error) {
+ for idx := 0; idx < len(ca); idx++ {
+ if err = nil; ca[idx].From != nil && xdrCellAnchorFuncs[drawingType](ca[idx]) {
+ rID = extractEmbedRID(ca[idx].Pic, nil)
+ rIDMaps[rID]++
+ if onAnchorCell(ca[idx].From.Col, ca[idx].From.Row) {
+ refRID = append(refRID, rID)
+ ca = append(ca[:idx], ca[idx+1:]...)
+ idx--
+ rIDMaps[rID]--
+ }
continue
}
- _, rIDs = extractEmbedRID(wsDr.TwoCellAnchor[idx].Pic, nil, rIDs)
- }
- }
- for idx := 0; idx < len(wsDr.TwoCellAnchor); idx++ {
- deTwoCellAnchor = new(decodeCellAnchor)
- if err = f.xmlNewDecoder(strings.NewReader("" + wsDr.TwoCellAnchor[idx].GraphicFrame + "")).
- Decode(deTwoCellAnchor); err != nil && err != io.EOF {
- return rID, err
- }
- if err = nil; deTwoCellAnchor.From != nil && decodeCellAnchorFuncs[drawingType](deTwoCellAnchor) {
- if onAnchorCell(deTwoCellAnchor.From.Col, deTwoCellAnchor.From.Row) {
- rID, _ = extractEmbedRID(nil, deTwoCellAnchor.Pic, rIDs)
- wsDr.TwoCellAnchor = append(wsDr.TwoCellAnchor[:idx], wsDr.TwoCellAnchor[idx+1:]...)
- idx--
- continue
+ deCellAnchor = new(decodeCellAnchor)
+ if err = f.xmlNewDecoder(strings.NewReader("" + ca[idx].GraphicFrame + "")).
+ Decode(deCellAnchor); err != nil && err != io.EOF {
+ return ca, err
+ }
+ if err = nil; deCellAnchor.From != nil && decodeCellAnchorFuncs[drawingType](deCellAnchor) {
+ rID = extractEmbedRID(nil, deCellAnchor.Pic)
+ rIDMaps[rID]++
+ if onAnchorCell(deCellAnchor.From.Col, deCellAnchor.From.Row) {
+ refRID = append(refRID, rID)
+ ca = append(ca[:idx], ca[idx+1:]...)
+ idx--
+ rIDMaps[rID]--
+ }
}
- _, rIDs = extractEmbedRID(nil, deTwoCellAnchor.Pic, rIDs)
}
+ return ca, err
}
- if inStrSlice(rIDs, rID, true) != -1 {
- rID = ""
+ if wsDr.OneCellAnchor, err = deleteCellAnchor(wsDr.OneCellAnchor); err != nil {
+ return delRID, err
+ }
+ if wsDr.TwoCellAnchor, err = deleteCellAnchor(wsDr.TwoCellAnchor); err != nil {
+ return delRID, err
}
f.Drawings.Store(drawingXML, wsDr)
- return rID, err
+ return getUnusedCellAnchorRID(delRID, refRID, rIDMaps), err
}
-// extractEmbedRID returns embed relationship ID and all relationship ID lists
-// for giving cell anchor.
-func extractEmbedRID(pic *xlsxPic, decodePic *decodePic, rIDs []string) (string, []string) {
+// extractEmbedRID returns embed relationship ID by giving cell anchor.
+func extractEmbedRID(pic *xlsxPic, decodePic *decodePic) string {
+ var rID string
if pic != nil {
- rIDs = append(rIDs, pic.BlipFill.Blip.Embed)
- return pic.BlipFill.Blip.Embed, rIDs
+ rID = pic.BlipFill.Blip.Embed
}
if decodePic != nil {
- rIDs = append(rIDs, decodePic.BlipFill.Blip.Embed)
- return decodePic.BlipFill.Blip.Embed, rIDs
+ rID = decodePic.BlipFill.Blip.Embed
+ }
+ return rID
+}
+
+// getUnusedCellAnchorRID returns relationship ID lists in the cell anchor which
+// for remove.
+func getUnusedCellAnchorRID(delRID, refRID []string, rIDMaps map[string]int) []string {
+ for _, rID := range refRID {
+ if rIDMaps[rID] == 0 && inStrSlice(delRID, rID, false) == -1 {
+ delRID = append(delRID, rID)
+ }
}
- return "", rIDs
+ return delRID
}
// deleteDrawingRels provides a function to delete relationships in
diff --git a/picture.go b/picture.go
index 48041683fb..3980df32cf 100644
--- a/picture.go
+++ b/picture.go
@@ -566,36 +566,41 @@ func (f *File) DeletePicture(sheet, cell string) error {
}
drawingXML := strings.ReplaceAll(f.getSheetRelationshipsTargetByID(sheet, ws.Drawing.RID), "..", "xl")
drawingRels := "xl/drawings/_rels/" + filepath.Base(drawingXML) + ".rels"
- rID, err := f.deleteDrawing(col, row, drawingXML, "Pic")
+ rIDs, err := f.deleteDrawing(col, row, drawingXML, "Pic")
if err != nil {
return err
}
- rels := f.getDrawingRelationships(drawingRels, rID)
- if rels == nil {
- return err
- }
- var used bool
- checkPicRef := func(k, v interface{}) bool {
- if strings.Contains(k.(string), "xl/drawings/_rels/drawing") {
- r, err := f.relsReader(k.(string))
- if err != nil {
- return true
- }
- for _, rel := range r.Relationships {
- if rel.ID != rels.ID && rel.Type == SourceRelationshipImage &&
- filepath.Base(rel.Target) == filepath.Base(rels.Target) {
- used = true
+ for _, rID := range rIDs {
+ rels := f.getDrawingRelationships(drawingRels, rID)
+ if rels == nil {
+ return err
+ }
+ var used bool
+ checkPicRef := func(k, v interface{}) bool {
+ if strings.Contains(k.(string), "xl/drawings/_rels/drawing") {
+ if k.(string) == drawingRels {
+ return true
+ }
+ r, err := f.relsReader(k.(string))
+ if err != nil {
+ return true
+ }
+ for _, rel := range r.Relationships {
+ if rel.Type == SourceRelationshipImage &&
+ filepath.Base(rel.Target) == filepath.Base(rels.Target) {
+ used = true
+ }
}
}
+ return true
}
- return true
- }
- f.Relationships.Range(checkPicRef)
- f.Pkg.Range(checkPicRef)
- if !used {
- f.Pkg.Delete(strings.Replace(rels.Target, "../", "xl/", -1))
+ f.Relationships.Range(checkPicRef)
+ f.Pkg.Range(checkPicRef)
+ if !used {
+ f.Pkg.Delete(strings.Replace(rels.Target, "../", "xl/", -1))
+ }
+ f.deleteDrawingRels(drawingRels, rID)
}
- f.deleteDrawingRels(drawingRels, rID)
return err
}
diff --git a/picture_test.go b/picture_test.go
index 9da63f99ba..2f5d4773c6 100644
--- a/picture_test.go
+++ b/picture_test.go
@@ -334,9 +334,9 @@ func TestDeletePicture(t *testing.T) {
f, err = OpenFile(filepath.Join("test", "TestDeletePicture.xlsx"))
assert.NoError(t, err)
// Test delete same picture on different worksheet, the images should be removed
- assert.NoError(t, f.DeletePicture("Sheet1", "F10"))
- assert.NoError(t, f.DeletePicture("Sheet2", "F1"))
+ assert.NoError(t, f.DeletePicture("Sheet1", "F20"))
assert.NoError(t, f.DeletePicture("Sheet1", "I20"))
+ assert.NoError(t, f.DeletePicture("Sheet2", "F1"))
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDeletePicture2.xlsx")))
// Test delete picture on not exists worksheet
@@ -364,6 +364,14 @@ func TestDeletePicture(t *testing.T) {
assert.NoError(t, f.DeletePicture("Sheet2", "F1"))
assert.NoError(t, f.Close())
+ f, err = OpenFile(filepath.Join("test", "TestDeletePicture.xlsx"))
+ assert.NoError(t, err)
+ // Test delete picture without drawing relationships
+ f.Relationships.Delete("xl/drawings/_rels/drawing1.xml.rels")
+ f.Pkg.Delete("xl/drawings/_rels/drawing1.xml.rels")
+ assert.NoError(t, f.DeletePicture("Sheet1", "I20"))
+ assert.NoError(t, f.Close())
+
f = NewFile()
assert.NoError(t, err)
assert.NoError(t, f.AddPicture("Sheet1", "A1", filepath.Join("test", "images", "excel.jpg"), nil))