Prechádzať zdrojové kódy

Resolve #455, init delete picture from spreadsheet support

xuri 5 rokov pred
rodič
commit
cbc3fd21b7
5 zmenil súbory, kde vykonal 80 pridanie a 42 odobranie
  1. 1 36
      chart.go
  2. 0 6
      chart_test.go
  3. 43 0
      drawing.go
  4. 21 0
      picture.go
  5. 15 0
      picture_test.go

+ 1 - 36
chart.go

@@ -10,11 +10,8 @@
 package excelize
 
 import (
-	"bytes"
 	"encoding/json"
 	"errors"
-	"fmt"
-	"io"
 	"strconv"
 	"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
 // and cell name.
 func (f *File) DeleteChart(sheet, cell string) (err error) {
-	var wsDr *xlsxWsDr
 	col, row, err := CellNameToCoordinates(cell)
 	if err != nil {
 		return
@@ -781,38 +777,7 @@ func (f *File) DeleteChart(sheet, cell string) (err error) {
 		return
 	}
 	drawingXML := strings.Replace(f.getSheetRelationshipsTargetByID(sheet, ws.Drawing.RID), "..", "xl", -1)
-	wsDr, _ = f.drawingParser(drawingXML)
-	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
+	return f.deleteDrawing(col, row, drawingXML, "Chart")
 }
 
 // countCharts provides a function to get chart files count storage in the

+ 0 - 6
chart_test.go

@@ -217,12 +217,6 @@ func TestDeleteChart(t *testing.T) {
 	assert.EqualError(t, f.DeleteChart("SheetN", "A1"), "sheet SheetN is not exist")
 	// Test delete chart with invalid coordinates.
 	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.
 	assert.NoError(t, NewFile().DeleteChart("Sheet1", "A1"))
 }

+ 43 - 0
drawing.go

@@ -12,6 +12,7 @@ package excelize
 import (
 	"bytes"
 	"encoding/xml"
+	"fmt"
 	"io"
 	"log"
 	"reflect"
@@ -1207,3 +1208,45 @@ func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rI
 	f.Drawings[drawingXML] = content
 	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
+}

+ 21 - 0
picture.go

@@ -462,6 +462,27 @@ func (f *File) GetPicture(sheet, cell string) (string, []byte, error) {
 	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
 // 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) {

+ 15 - 0
picture_test.go

@@ -166,3 +166,18 @@ func TestAddPictureFromBytes(t *testing.T) {
 	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")
 }
+
+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"))
+}