diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 5e16cfccae..f61cb199ed 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -28,8 +28,17 @@ jobs:
     - name: Build
       run: go build -v .
 
+    - name: Build on ARM
+      if: runner.os == 'Linux'
+      run: |
+        GOARCH=arm GOARM=5 go build .
+        GOARCH=arm GOARM=6 go build .
+        GOARCH=arm GOARM=7 go build .
+        GOARCH=arm64 go build .
+        GOARCH=arm64 GOOS=android go build .
+
     - name: Test
-      run: env GO111MODULE=on go test -v -timeout 30m -race ./... -coverprofile='coverage.txt' -covermode=atomic
+      run: env GO111MODULE=on go test -v -timeout 50m -race ./... -coverprofile='coverage.txt' -covermode=atomic
 
     - name: Codecov
       uses: codecov/codecov-action@v5
diff --git a/adjust.go b/adjust.go
index 28e54e5809..38e6207689 100644
--- a/adjust.go
+++ b/adjust.go
@@ -38,10 +38,10 @@ var adjustHelperFunc = [9]func(*File, *xlsxWorksheet, string, adjustDirection, i
 		return f.adjustDataValidations(ws, sheet, dir, num, offset, sheetID)
 	},
 	func(f *File, ws *xlsxWorksheet, sheet string, dir adjustDirection, num, offset, sheetID int) error {
-		return f.adjustDefinedNames(ws, sheet, dir, num, offset, sheetID)
+		return f.adjustDefinedNames(sheet, dir, num, offset)
 	},
 	func(f *File, ws *xlsxWorksheet, sheet string, dir adjustDirection, num, offset, sheetID int) error {
-		return f.adjustDrawings(ws, sheet, dir, num, offset, sheetID)
+		return f.adjustDrawings(ws, sheet, dir, num, offset)
 	},
 	func(f *File, ws *xlsxWorksheet, sheet string, dir adjustDirection, num, offset, sheetID int) error {
 		return f.adjustMergeCells(ws, sheet, dir, num, offset, sheetID)
@@ -475,20 +475,15 @@ func transformParenthesesToken(token efp.Token) string {
 // adjustRangeSheetName returns replaced range reference by given source and
 // target sheet name.
 func adjustRangeSheetName(rng, source, target string) string {
+	source = escapeSheetName(source)
 	cellRefs := strings.Split(rng, ",")
 	for i, cellRef := range cellRefs {
 		rangeRefs := strings.Split(cellRef, ":")
 		for j, rangeRef := range rangeRefs {
 			parts := strings.Split(rangeRef, "!")
 			for k, part := range parts {
-				singleQuote := strings.HasPrefix(part, "'") && strings.HasSuffix(part, "'")
-				if singleQuote {
-					part = strings.TrimPrefix(strings.TrimSuffix(part, "'"), "'")
-				}
-				if part == source {
-					if part = target; singleQuote {
-						part = "'" + part + "'"
-					}
+				if strings.TrimPrefix(strings.TrimSuffix(part, "'"), "'") == source {
+					part = escapeSheetName(target)
 				}
 				parts[k] = part
 			}
@@ -1034,7 +1029,7 @@ func (from *xlsxFrom) adjustDrawings(dir adjustDirection, num, offset int, editA
 
 // adjustDrawings updates the ending anchor of the two cell anchor pictures
 // and charts object when inserting or deleting rows or columns.
-func (to *xlsxTo) adjustDrawings(dir adjustDirection, num, offset int, editAs string, ok bool) error {
+func (to *xlsxTo) adjustDrawings(dir adjustDirection, num, offset int, ok bool) error {
 	if dir == columns && to.Col+1 >= num && to.Col+offset >= 0 && ok {
 		if to.Col+offset >= MaxColumns {
 			return ErrColumnNumber
@@ -1054,32 +1049,38 @@ func (to *xlsxTo) adjustDrawings(dir adjustDirection, num, offset int, editAs st
 // inserting or deleting rows or columns.
 func (a *xdrCellAnchor) adjustDrawings(dir adjustDirection, num, offset int) error {
 	editAs := a.EditAs
-	if a.From == nil || a.To == nil || editAs == "absolute" {
+	if (a.From == nil && (a.To == nil || a.Ext == nil)) || editAs == "absolute" {
 		return nil
 	}
 	ok, err := a.From.adjustDrawings(dir, num, offset, editAs)
 	if err != nil {
 		return err
 	}
-	return a.To.adjustDrawings(dir, num, offset, editAs, ok || editAs == "")
+	if a.To != nil {
+		return a.To.adjustDrawings(dir, num, offset, ok || editAs == "")
+	}
+	return err
 }
 
 // adjustDrawings updates the existing two cell anchor pictures and charts
 // object when inserting or deleting rows or columns.
 func (a *xlsxCellAnchorPos) adjustDrawings(dir adjustDirection, num, offset int, editAs string) error {
-	if a.From == nil || a.To == nil || editAs == "absolute" {
+	if (a.From == nil && (a.To == nil || a.Ext == nil)) || editAs == "absolute" {
 		return nil
 	}
 	ok, err := a.From.adjustDrawings(dir, num, offset, editAs)
 	if err != nil {
 		return err
 	}
-	return a.To.adjustDrawings(dir, num, offset, editAs, ok || editAs == "")
+	if a.To != nil {
+		return a.To.adjustDrawings(dir, num, offset, ok || editAs == "")
+	}
+	return err
 }
 
 // adjustDrawings updates the pictures and charts object when inserting or
 // deleting rows or columns.
-func (f *File) adjustDrawings(ws *xlsxWorksheet, sheet string, dir adjustDirection, num, offset, sheetID int) error {
+func (f *File) adjustDrawings(ws *xlsxWorksheet, sheet string, dir adjustDirection, num, offset int) error {
 	if ws.Drawing == nil {
 		return nil
 	}
@@ -1128,12 +1129,17 @@ func (f *File) adjustDrawings(ws *xlsxWorksheet, sheet string, dir adjustDirecti
 			return err
 		}
 	}
+	for _, anchor := range wsDr.OneCellAnchor {
+		if err = anchorCb(anchor); err != nil {
+			return err
+		}
+	}
 	return nil
 }
 
 // adjustDefinedNames updates the cell reference of the defined names when
 // inserting or deleting rows or columns.
-func (f *File) adjustDefinedNames(ws *xlsxWorksheet, sheet string, dir adjustDirection, num, offset, sheetID int) error {
+func (f *File) adjustDefinedNames(sheet string, dir adjustDirection, num, offset int) error {
 	wb, err := f.workbookReader()
 	if err != nil {
 		return err
diff --git a/adjust_test.go b/adjust_test.go
index 0acc8bf2eb..07ccaa5e12 100644
--- a/adjust_test.go
+++ b/adjust_test.go
@@ -1206,7 +1206,7 @@ func TestAdjustDrawings(t *testing.T) {
 	assert.NoError(t, f.InsertRows("Sheet1", 15, 1))
 	cells, err := f.GetPictureCells("Sheet1")
 	assert.NoError(t, err)
-	assert.Equal(t, []string{"D3", "D13", "B21"}, cells)
+	assert.Equal(t, []string{"D3", "B21", "D13"}, cells)
 	wb := filepath.Join("test", "TestAdjustDrawings.xlsx")
 	assert.NoError(t, f.SaveAs(wb))
 
@@ -1215,7 +1215,7 @@ func TestAdjustDrawings(t *testing.T) {
 	assert.NoError(t, f.RemoveRow("Sheet1", 1))
 	cells, err = f.GetPictureCells("Sheet1")
 	assert.NoError(t, err)
-	assert.Equal(t, []string{"C2", "C12", "B21"}, cells)
+	assert.Equal(t, []string{"C2", "B21", "C12"}, cells)
 
 	// Test adjust existing pictures on inserting columns and rows
 	f, err = OpenFile(wb)
@@ -1227,7 +1227,7 @@ func TestAdjustDrawings(t *testing.T) {
 	assert.NoError(t, f.InsertRows("Sheet1", 16, 1))
 	cells, err = f.GetPictureCells("Sheet1")
 	assert.NoError(t, err)
-	assert.Equal(t, []string{"F4", "F15", "B21"}, cells)
+	assert.Equal(t, []string{"F4", "B21", "F15"}, cells)
 
 	// Test adjust drawings with unsupported charset
 	f, err = OpenFile(wb)
@@ -1267,6 +1267,11 @@ func TestAdjustDrawings(t *testing.T) {
 	assert.NoError(t, err)
 	f.Pkg.Store("xl/drawings/drawing1.xml", []byte(xml.Header+`<wsDr xmlns="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"><twoCellAnchor><from><col>0</col><colOff>0</colOff><row>0</row><rowOff>0</rowOff></from><to><col>1</col><colOff>0</colOff><row>1</row><rowOff>0</rowOff></to><mc:AlternateContent xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"></mc:AlternateContent><clientData/></twoCellAnchor></wsDr>`))
 	assert.NoError(t, f.InsertCols("Sheet1", "A", 1))
+
+	f, err = OpenFile(wb)
+	assert.NoError(t, err)
+	f.Pkg.Store("xl/drawings/drawing1.xml", []byte(xml.Header+fmt.Sprintf(`<wsDr xmlns="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"><oneCellAnchor><from><col>%d</col><row>0</row></from><mc:AlternateContent xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"></mc:AlternateContent><clientData/></oneCellAnchor></wsDr>`, MaxColumns)))
+	assert.EqualError(t, f.InsertCols("Sheet1", "A", 1), "the column number must be greater than or equal to 1 and less than or equal to 16384")
 }
 
 func TestAdjustDefinedNames(t *testing.T) {
@@ -1330,5 +1335,5 @@ func TestAdjustDefinedNames(t *testing.T) {
 	f = NewFile()
 	f.WorkBook = nil
 	f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
-	assert.EqualError(t, f.adjustDefinedNames(nil, "Sheet1", columns, 0, 0, 1), "XML syntax error on line 1: invalid UTF-8")
+	assert.EqualError(t, f.adjustDefinedNames("Sheet1", columns, 0, 0), "XML syntax error on line 1: invalid UTF-8")
 }
diff --git a/cell.go b/cell.go
index f2df30478c..af918555b5 100644
--- a/cell.go
+++ b/cell.go
@@ -17,6 +17,7 @@ import (
 	"math"
 	"os"
 	"reflect"
+	"sort"
 	"strconv"
 	"strings"
 	"time"
@@ -193,6 +194,7 @@ func (f *File) removeFormula(c *xlsxC, ws *xlsxWorksheet, sheet string) error {
 				for col, cell := range row.C {
 					if cell.F != nil && cell.F.Si != nil && *cell.F.Si == *si {
 						ws.SheetData.Row[r].C[col].F = nil
+						ws.formulaSI.Delete(si)
 						_ = f.deleteCalcChain(sheetID, cell.R)
 					}
 				}
@@ -689,7 +691,8 @@ func (f *File) getCellFormula(sheet, cell string, transformed bool) (string, err
 			return "", false, nil
 		}
 		if c.F.T == STCellFormulaTypeShared && c.F.Si != nil {
-			return getSharedFormula(x, *c.F.Si, c.R), true, nil
+			formula, err := getSharedFormula(x, *c.F.Si, c.R)
+			return formula, true, err
 		}
 		return c.F.Content, true, nil
 	})
@@ -793,6 +796,7 @@ func (f *File) SetCellFormula(sheet, cell, formula string, opts ...FormulaOpts)
 		return err
 	}
 	if formula == "" {
+		ws.deleteSharedFormula(c)
 		c.F = nil
 		return f.deleteCalcChain(f.getSheetID(sheet), cell)
 	}
@@ -815,7 +819,8 @@ func (f *File) SetCellFormula(sheet, cell, formula string, opts ...FormulaOpts)
 				}
 			}
 			if c.F.T == STCellFormulaTypeShared {
-				if err = ws.setSharedFormula(*opt.Ref); err != nil {
+				ws.deleteSharedFormula(c)
+				if err = ws.setSharedFormula(cell, *opt.Ref); err != nil {
 					return err
 				}
 			}
@@ -890,22 +895,28 @@ func (f *File) setArrayFormulaCells() error {
 }
 
 // setSharedFormula set shared formula for the cells.
-func (ws *xlsxWorksheet) setSharedFormula(ref string) error {
+func (ws *xlsxWorksheet) setSharedFormula(cell, ref string) error {
 	coordinates, err := rangeRefToCoordinates(ref)
 	if err != nil {
 		return err
 	}
 	_ = sortCoordinates(coordinates)
-	cnt := ws.countSharedFormula()
-	for c := coordinates[0]; c <= coordinates[2]; c++ {
-		for r := coordinates[1]; r <= coordinates[3]; r++ {
-			ws.prepareSheetXML(c, r)
-			cell := &ws.SheetData.Row[r-1].C[c-1]
-			if cell.F == nil {
-				cell.F = &xlsxF{}
+	si := ws.countSharedFormula()
+	for col := coordinates[0]; col <= coordinates[2]; col++ {
+		for rol := coordinates[1]; rol <= coordinates[3]; rol++ {
+			ws.prepareSheetXML(col, rol)
+			c := &ws.SheetData.Row[rol-1].C[col-1]
+			if c.F == nil {
+				c.F = &xlsxF{}
+			}
+			c.F.T = STCellFormulaTypeShared
+			if c.R == cell {
+				if c.F.Ref != "" {
+					si = *c.F.Si
+					continue
+				}
 			}
-			cell.F.T = STCellFormulaTypeShared
-			cell.F.Si = &cnt
+			c.F.Si = &si
 		}
 	}
 	return err
@@ -923,6 +934,23 @@ func (ws *xlsxWorksheet) countSharedFormula() (count int) {
 	return
 }
 
+// deleteSharedFormula delete shared formula cell from worksheet shared formula
+// index cache and remove all shared cells formula which refer to the cell which
+// containing the formula.
+func (ws *xlsxWorksheet) deleteSharedFormula(c *xlsxC) {
+	if c.F != nil && c.F.Si != nil && c.F.Ref != "" {
+		si := *c.F.Si
+		ws.formulaSI.Delete(si)
+		for r, row := range ws.SheetData.Row {
+			for c, cell := range row.C {
+				if cell.F != nil && cell.F.Si != nil && *cell.F.Si == si && cell.F.Ref == "" {
+					ws.SheetData.Row[r].C[c].F = nil
+				}
+			}
+		}
+	}
+}
+
 // GetCellHyperLink gets a cell hyperlink based on the given worksheet name and
 // cell reference. If the cell has a hyperlink, it will return 'true' and
 // the link address, otherwise it will return 'false' and an empty link
@@ -1471,16 +1499,22 @@ func (f *File) getCellStringFunc(sheet, cell string, fn func(x *xlsxWorksheet, c
 		return "", nil
 	}
 
-	for rowIdx := range ws.SheetData.Row {
-		rowData := &ws.SheetData.Row[rowIdx]
-		if rowData.R != row {
-			continue
+	idx, found := sort.Find(len(ws.SheetData.Row), func(i int) int {
+		if ws.SheetData.Row[i].R == row {
+			return 0
 		}
-		for colIdx := range rowData.C {
-			colData := &rowData.C[colIdx]
-			if cell != colData.R {
-				continue
-			}
+		if ws.SheetData.Row[i].R > row {
+			return -1
+		}
+		return 1
+	})
+	if !found {
+		return "", nil
+	}
+	rowData := ws.SheetData.Row[idx]
+	for colIdx := range rowData.C {
+		colData := &rowData.C[colIdx]
+		if cell == colData.R {
 			val, ok, err := fn(ws, colData)
 			if err != nil {
 				return "", err
@@ -1488,6 +1522,7 @@ func (f *File) getCellStringFunc(sheet, cell string, fn func(x *xlsxWorksheet, c
 			if ok {
 				return val, nil
 			}
+			break
 		}
 	}
 	return "", nil
@@ -1640,18 +1675,27 @@ func isOverlap(rect1, rect2 []int) bool {
 		cellInRange([]int{rect2[2], rect2[3]}, rect1)
 }
 
-// parseSharedFormula generate dynamic part of shared formula for target cell
-// by given column and rows distance and origin shared formula.
-func parseSharedFormula(dCol, dRow int, orig string) string {
+// convertSharedFormula creates a non shared formula from the shared formula
+// counterpart by given cell reference which not containing the formula.
+func (c *xlsxC) convertSharedFormula(cell string) (string, error) {
+	col, row, err := CellNameToCoordinates(cell)
+	if err != nil {
+		return "", err
+	}
+	sharedCol, sharedRow, err := CellNameToCoordinates(c.R)
+	if err != nil {
+		return "", err
+	}
+	dCol, dRow := col-sharedCol, row-sharedRow
 	ps := efp.ExcelParser()
-	tokens := ps.Parse(string(orig))
-	for i := 0; i < len(tokens); i++ {
+	tokens := ps.Parse(c.F.Content)
+	for i := range tokens {
 		token := tokens[i]
 		if token.TType == efp.TokenTypeOperand && token.TSubType == efp.TokenSubTypeRange {
 			tokens[i].TValue = shiftCell(token.TValue, dCol, dRow)
 		}
 	}
-	return ps.Render()
+	return ps.Render(), nil
 }
 
 // getSharedFormula find a cell contains the same formula as another cell,
@@ -1662,21 +1706,23 @@ func parseSharedFormula(dCol, dRow int, orig string) string {
 //
 // Note that this function not validate ref tag to check the cell whether in
 // allow range reference, and always return origin shared formula.
-func getSharedFormula(ws *xlsxWorksheet, si int, cell string) string {
-	for row := 0; row < len(ws.SheetData.Row); row++ {
+func getSharedFormula(ws *xlsxWorksheet, si int, cell string) (string, error) {
+	val, ok := ws.formulaSI.Load(si)
+
+	if ok {
+		return val.(*xlsxC).convertSharedFormula(cell)
+	}
+	for row := range ws.SheetData.Row {
 		r := &ws.SheetData.Row[row]
-		for column := 0; column < len(r.C); column++ {
+		for column := range r.C {
 			c := &r.C[column]
 			if c.F != nil && c.F.Ref != "" && c.F.T == STCellFormulaTypeShared && c.F.Si != nil && *c.F.Si == si {
-				col, row, _ := CellNameToCoordinates(cell)
-				sharedCol, sharedRow, _ := CellNameToCoordinates(c.R)
-				dCol := col - sharedCol
-				dRow := row - sharedRow
-				return parseSharedFormula(dCol, dRow, c.F.Content)
+				ws.formulaSI.Store(si, c)
+				return c.convertSharedFormula(cell)
 			}
 		}
 	}
-	return ""
+	return "", nil
 }
 
 // shiftCell returns the cell shifted according to dCol and dRow taking into
diff --git a/cell_test.go b/cell_test.go
index b9069a354e..88abb95c32 100644
--- a/cell_test.go
+++ b/cell_test.go
@@ -563,7 +563,7 @@ func TestGetValueFrom(t *testing.T) {
 	assert.NoError(t, err)
 	value, err := c.getValueFrom(f, sst, false)
 	assert.NoError(t, err)
-	assert.Equal(t, "", value)
+	assert.Empty(t, value)
 
 	c = xlsxC{T: "s", V: " 1 "}
 	value, err = c.getValueFrom(f, &xlsxSST{Count: 1, SI: []xlsxSI{{}, {T: &xlsxT{Val: "s"}}}}, false)
@@ -602,13 +602,17 @@ func TestGetCellFormula(t *testing.T) {
 		formula, err := f.GetCellFormula("Sheet1", "B3")
 		assert.NoError(t, err)
 		assert.Equal(t, expected, formula)
+		// Test get shared formula form cache
+		formula, err = f.GetCellFormula("Sheet1", "B3")
+		assert.NoError(t, err)
+		assert.Equal(t, expected, formula)
 	}
 
 	f.Sheet.Delete("xl/worksheets/sheet1.xml")
 	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(`<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData><row r="2"><c r="B2"><f t="shared" si="0"></f></c></row></sheetData></worksheet>`))
 	formula, err := f.GetCellFormula("Sheet1", "B2")
 	assert.NoError(t, err)
-	assert.Equal(t, "", formula)
+	assert.Empty(t, formula)
 
 	// Test get array formula with invalid cell range reference
 	f = NewFile()
@@ -628,6 +632,81 @@ func TestGetCellFormula(t *testing.T) {
 	f.Sheet.Delete("xl/worksheets/sheet1.xml")
 	f.Pkg.Store("xl/worksheets/sheet1.xml", MacintoshCyrillicCharset)
 	assert.EqualError(t, f.setArrayFormulaCells(), "XML syntax error on line 1: invalid UTF-8")
+
+	// Test get shared formula after updated refer cell formula, the shared
+	// formula cell reference range covered the previous.
+	f = NewFile()
+	formulaType, ref = STCellFormulaTypeShared, "C2:C6"
+	assert.NoError(t, f.SetCellFormula("Sheet1", "C2", "=A2+B2", FormulaOpts{Ref: &ref, Type: &formulaType}))
+	formula, err = f.GetCellFormula("Sheet1", "C2")
+	assert.NoError(t, err)
+	assert.Equal(t, "A2+B2", formula)
+	formula, err = f.GetCellFormula("Sheet1", "C6")
+	assert.NoError(t, err)
+	assert.Equal(t, "A6+B6", formula)
+
+	formulaType, ref = STCellFormulaTypeShared, "C2:C8"
+	assert.NoError(t, f.SetCellFormula("Sheet1", "C2", "=A2*B2", FormulaOpts{Ref: &ref, Type: &formulaType}))
+	formula, err = f.GetCellFormula("Sheet1", "C2")
+	assert.NoError(t, err)
+	assert.Equal(t, "A2*B2", formula)
+	formula, err = f.GetCellFormula("Sheet1", "C8")
+	assert.NoError(t, err)
+	assert.Equal(t, "A8*B8", formula)
+	assert.NoError(t, f.Close())
+
+	// Test get shared formula after updated refer cell formula, the shared
+	// formula cell reference range not over the previous.
+	f = NewFile()
+	formulaType, ref = STCellFormulaTypeShared, "C2:C6"
+	assert.NoError(t, f.SetCellFormula("Sheet1", "C2", "=A2+B2", FormulaOpts{Ref: &ref, Type: &formulaType}))
+	formula, err = f.GetCellFormula("Sheet1", "C2")
+	assert.NoError(t, err)
+	assert.Equal(t, "A2+B2", formula)
+	formula, err = f.GetCellFormula("Sheet1", "C6")
+	assert.NoError(t, err)
+	assert.Equal(t, "A6+B6", formula)
+
+	formulaType, ref = STCellFormulaTypeShared, "C2:C4"
+	assert.NoError(t, f.SetCellFormula("Sheet1", "C2", "=A2*B2", FormulaOpts{Ref: &ref, Type: &formulaType}))
+	formula, err = f.GetCellFormula("Sheet1", "C2")
+	assert.NoError(t, err)
+	assert.Equal(t, "A2*B2", formula)
+	formula, err = f.GetCellFormula("Sheet1", "C6")
+	assert.NoError(t, err)
+	assert.Empty(t, formula)
+
+	// Test get shared formula after remove refer cell formula
+	f = NewFile()
+	formulaType, ref = STCellFormulaTypeShared, "C2:C6"
+	assert.NoError(t, f.SetCellFormula("Sheet1", "C2", "=A2+B2", FormulaOpts{Ref: &ref, Type: &formulaType}))
+
+	assert.NoError(t, f.SetCellFormula("Sheet1", "C2", ""))
+
+	formula, err = f.GetCellFormula("Sheet1", "C2")
+	assert.NoError(t, err)
+	assert.Empty(t, formula)
+	formula, err = f.GetCellFormula("Sheet1", "C6")
+	assert.NoError(t, err)
+	assert.Empty(t, formula)
+
+	formulaType, ref = STCellFormulaTypeShared, "C2:C8"
+	assert.NoError(t, f.SetCellFormula("Sheet1", "C2", "=A2*B2", FormulaOpts{Ref: &ref, Type: &formulaType}))
+	formula, err = f.GetCellFormula("Sheet1", "C2")
+	assert.NoError(t, err)
+	assert.Equal(t, "A2*B2", formula)
+	formula, err = f.GetCellFormula("Sheet1", "C8")
+	assert.NoError(t, err)
+	assert.Equal(t, "A8*B8", formula)
+	assert.NoError(t, f.Close())
+}
+
+func TestConvertSharedFormula(t *testing.T) {
+	c := xlsxC{R: "A"}
+	_, err := c.convertSharedFormula("A")
+	assert.Equal(t, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")), err)
+	_, err = c.convertSharedFormula("A1")
+	assert.Equal(t, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")), err)
 }
 
 func ExampleFile_SetCellFloat() {
@@ -1186,3 +1265,14 @@ func TestSetCellIntFunc(t *testing.T) {
 func TestSIString(t *testing.T) {
 	assert.Empty(t, xlsxSI{}.String())
 }
+
+func TestGetCellStringFunc(t *testing.T) {
+	f := NewFile()
+	ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
+	assert.True(t, ok)
+	ws.(*xlsxWorksheet).SheetData.Row = []xlsxRow{{R: 2}}
+	val, err := f.GetCellValue("Sheet1", "A1")
+	assert.Empty(t, val)
+	assert.NoError(t, err)
+	assert.NoError(t, f.Close())
+}
diff --git a/chart.go b/chart.go
index 88df5c2f21..011fbd1c3c 100644
--- a/chart.go
+++ b/chart.go
@@ -863,6 +863,14 @@ func (opts *Chart) parseTitle() {
 // ShowCatName: Specifies that the category name shall be shown in the data
 // label. The 'ShowCatName' property is optional. The default value is true.
 //
+// ShowDataTable: Used for add data table under chart, depending on the chart
+// type, only available for area, bar, column and line series type charts. The
+// 'ShowDataTable' property is optional. The default value is false.
+//
+// ShowDataTableKeys: Used for add legend key in data table, only works on
+// 'ShowDataTable' is enabled. The 'ShowDataTableKeys' property is optional.
+// The default value is false.
+//
 // ShowLeaderLines: Specifies leader lines shall be shown for data labels. The
 // 'ShowLeaderLines' property is optional. The default value is false.
 //
diff --git a/chart_test.go b/chart_test.go
index 42e2a65764..989d9337d8 100644
--- a/chart_test.go
+++ b/chart_test.go
@@ -93,11 +93,8 @@ func TestChartSize(t *testing.T) {
 		t.FailNow()
 	}
 
-	if !assert.Equal(t, 14, anchor.To.Col, "Expected 'to' column 14") ||
-		!assert.Equal(t, 29, anchor.To.Row, "Expected 'to' row 29") {
-
-		t.FailNow()
-	}
+	assert.Equal(t, 14, anchor.To.Col, "Expected 'to' column 14")
+	assert.Equal(t, 29, anchor.To.Row, "Expected 'to' row 29")
 }
 
 func TestAddDrawingChart(t *testing.T) {
@@ -293,7 +290,7 @@ func TestAddChart(t *testing.T) {
 		{"I1", Doughnut, "Clustered Column - Doughnut Chart"},
 	}
 	for _, props := range clusteredColumnCombo {
-		assert.NoError(t, f.AddChart("Combo Charts", props[0].(string), &Chart{Type: Col, Series: series[:4], Format: format, Legend: legend, Title: []RichTextRun{{Text: props[2].(string)}}, PlotArea: ChartPlotArea{ShowBubbleSize: true, ShowCatName: false, ShowLeaderLines: false, ShowPercent: true, ShowSerName: true, ShowVal: true}}, &Chart{Type: props[1].(ChartType), Series: series[4:], Format: format, Legend: legend, PlotArea: ChartPlotArea{ShowBubbleSize: true, ShowCatName: false, ShowLeaderLines: false, ShowPercent: true, ShowSerName: true, ShowVal: true}, YAxis: ChartAxis{Secondary: true}}))
+		assert.NoError(t, f.AddChart("Combo Charts", props[0].(string), &Chart{Type: Col, Series: series[:4], Format: format, Legend: legend, Title: []RichTextRun{{Text: props[2].(string)}}, PlotArea: ChartPlotArea{ShowBubbleSize: true, ShowCatName: false, ShowDataTable: true, ShowDataTableKeys: true, ShowLeaderLines: false, ShowPercent: true, ShowSerName: true, ShowVal: true}}, &Chart{Type: props[1].(ChartType), Series: series[4:], Format: format, Legend: legend, PlotArea: ChartPlotArea{ShowBubbleSize: true, ShowCatName: false, ShowLeaderLines: false, ShowPercent: true, ShowSerName: true, ShowVal: true}, YAxis: ChartAxis{Secondary: true}}))
 	}
 	stackedAreaCombo := map[string][]interface{}{
 		"A16": {Line, "Stacked Area - Line Chart"},
diff --git a/col.go b/col.go
index 6608048a83..d8c3d0dbe9 100644
--- a/col.go
+++ b/col.go
@@ -14,7 +14,6 @@ package excelize
 import (
 	"bytes"
 	"encoding/xml"
-	"math"
 	"strconv"
 	"strings"
 
@@ -621,40 +620,35 @@ func flatCols(col xlsxCol, cols []xlsxCol, replacer func(fc, c xlsxCol) xlsxCol)
 //
 //	width           # Width of object frame.
 //	height          # Height of object frame.
-func (f *File) positionObjectPixels(sheet string, col, row, x1, y1, width, height int) (int, int, int, int, int, int) {
+func (f *File) positionObjectPixels(sheet string, col, row, width, height int, opts *GraphicOptions) (int, int, int, int, int, int, int, int) {
 	colIdx, rowIdx := col-1, row-1
-	// Adjust start column for offsets that are greater than the col width.
-	for x1 >= f.getColWidth(sheet, colIdx+1) {
-		colIdx++
-		x1 -= f.getColWidth(sheet, colIdx)
-	}
-
-	// Adjust start row for offsets that are greater than the row height.
-	for y1 >= f.getRowHeight(sheet, rowIdx+1) {
-		rowIdx++
-		y1 -= f.getRowHeight(sheet, rowIdx)
-	}
-
 	// Initialized end cell to the same as the start cell.
 	colEnd, rowEnd := colIdx, rowIdx
+	x1, y1, x2, y2 := opts.OffsetX, opts.OffsetY, width, height
+	if opts.Positioning != "oneCell" {
+		// Using a twoCellAnchor, the maximum possible offset is limited by the
+		// "from" cell dimensions. If these were to be exceeded the "toPoint" would
+		// be calculated incorrectly, since the requested "fromPoint" is not possible
+
+		x1 = min(x1, f.getColWidth(sheet, col))
+		y1 = min(y1, f.getRowHeight(sheet, row))
+
+		x2 += x1
+		y2 += y1
+		// Subtract the underlying cell widths to find end cell of the object.
+		for x2 >= f.getColWidth(sheet, colEnd+1) {
+			colEnd++
+			x2 -= f.getColWidth(sheet, colEnd)
+		}
 
-	width += x1
-	height += y1
-
-	// Subtract the underlying cell widths to find end cell of the object.
-	for width >= f.getColWidth(sheet, colEnd+1) {
-		colEnd++
-		width -= f.getColWidth(sheet, colEnd)
-	}
-
-	// Subtract the underlying cell heights to find end cell of the object.
-	for height >= f.getRowHeight(sheet, rowEnd+1) {
-		rowEnd++
-		height -= f.getRowHeight(sheet, rowEnd)
+		// Subtract the underlying cell heights to find end cell of the object.
+		for y2 >= f.getRowHeight(sheet, rowEnd+1) {
+			rowEnd++
+			y2 -= f.getRowHeight(sheet, rowEnd)
+		}
 	}
-
 	// The end vertices are whatever is left from the width and height.
-	return colIdx, rowIdx, colEnd, rowEnd, width, height
+	return colIdx, rowIdx, colEnd, rowEnd, x1, y1, x2, y2
 }
 
 // getColWidth provides a function to get column width in pixels by given
@@ -664,13 +658,14 @@ func (f *File) getColWidth(sheet string, col int) int {
 	ws.mu.Lock()
 	defer ws.mu.Unlock()
 	if ws.Cols != nil {
-		var width float64
+		width := -1.0
 		for _, v := range ws.Cols.Col {
 			if v.Min <= col && col <= v.Max && v.Width != nil {
 				width = *v.Width
+				break
 			}
 		}
-		if width != 0 {
+		if width != -1.0 {
 			return int(convertColWidthToPixels(width))
 		}
 	}
@@ -782,6 +777,7 @@ func (f *File) RemoveCol(sheet, col string) error {
 	if err != nil {
 		return err
 	}
+	ws.formulaSI.Clear()
 	for rowIdx := range ws.SheetData.Row {
 		rowData := &ws.SheetData.Row[rowIdx]
 		for colIdx := range rowData.C {
@@ -800,16 +796,11 @@ func (f *File) RemoveCol(sheet, col string) error {
 // pixel. If the width hasn't been set by the user we use the default value.
 // If the column is hidden it has a value of zero.
 func convertColWidthToPixels(width float64) float64 {
-	var padding float64 = 5
 	var pixels float64
-	var maxDigitWidth float64 = 7
+	var maxDigitWidth float64 = 8
 	if width == 0 {
 		return pixels
 	}
-	if width < 1 {
-		pixels = (width * 12) + 0.5
-		return math.Ceil(pixels)
-	}
-	pixels = (width*maxDigitWidth + 0.5) + padding
-	return math.Ceil(pixels)
+	pixels = (width*maxDigitWidth + 0.5)
+	return float64(int(pixels))
 }
diff --git a/col_test.go b/col_test.go
index 2e7aeb80c7..5c4bfc5559 100644
--- a/col_test.go
+++ b/col_test.go
@@ -396,7 +396,7 @@ func TestColWidth(t *testing.T) {
 	width, err = f.GetColWidth("Sheet1", "A")
 	assert.NoError(t, err)
 	assert.Equal(t, 10.0, width)
-	assert.Equal(t, 76, f.getColWidth("Sheet1", 1))
+	assert.Equal(t, 80, f.getColWidth("Sheet1", 1))
 
 	// Test set and get column width with illegal cell reference
 	width, err = f.GetColWidth("Sheet1", "*")
@@ -484,5 +484,5 @@ func TestRemoveCol(t *testing.T) {
 }
 
 func TestConvertColWidthToPixels(t *testing.T) {
-	assert.Equal(t, -11.0, convertColWidthToPixels(-1))
+	assert.Equal(t, -7.0, convertColWidthToPixels(-1))
 }
diff --git a/datavalidation.go b/datavalidation.go
index ab61931625..3b5a852dbc 100644
--- a/datavalidation.go
+++ b/datavalidation.go
@@ -12,9 +12,11 @@
 package excelize
 
 import (
+	"encoding/xml"
 	"fmt"
 	"io"
 	"math"
+	"slices"
 	"strings"
 	"unicode/utf16"
 )
@@ -361,9 +363,27 @@ func getDataValidations(dvs *xlsxDataValidations) []*DataValidation {
 }
 
 // DeleteDataValidation delete data validation by given worksheet name and
-// reference sequence. This function is concurrency safe.
-// All data validations in the worksheet will be deleted
-// if not specify reference sequence parameter.
+// reference sequence. This function is concurrency safe. All data validations
+// in the worksheet will be deleted if not specify reference sequence parameter.
+//
+// Example 1, delete data validation on Sheet1!A1:B2:
+//
+//	err := f.DeleteDataValidation("Sheet1", "A1:B2")
+//
+// Example 2, delete data validations on Sheet1 with multiple cell ranges
+// A1:B2 and C1:C3 with reference sequence slice:
+//
+//	err := f.DeleteDataValidation("Sheet1", []string{"A1:B2", "C1:C3"}...)
+//
+// Example 3, delete data validations on Sheet1 with multiple cell ranges
+// A1:B2 and C1:C3 with blank separated reference sequence string, the result
+// same as example 2:
+//
+//	err := f.DeleteDataValidation("Sheet1", "A1:B2 C1:C3")
+//
+// Example 4, delete all data validations on Sheet1:
+//
+//	err := f.DeleteDataValidation("Sheet1")
 func (f *File) DeleteDataValidation(sheet string, sqref ...string) error {
 	ws, err := f.workSheetReader(sheet)
 	if err != nil {
@@ -371,17 +391,31 @@ func (f *File) DeleteDataValidation(sheet string, sqref ...string) error {
 	}
 	ws.mu.Lock()
 	defer ws.mu.Unlock()
-	if ws.DataValidations == nil {
+	if ws.DataValidations == nil && ws.ExtLst == nil {
 		return nil
 	}
 	if sqref == nil {
 		ws.DataValidations = nil
 		return nil
 	}
-	delCells, err := flatSqref(sqref[0])
+	delCells, err := flatSqref(strings.Join(sqref, " "))
 	if err != nil {
 		return err
 	}
+	if ws.DataValidations != nil {
+		if err = f.deleteDataValidation(ws, delCells); err != nil {
+			return err
+		}
+	}
+	if ws.ExtLst != nil {
+		return f.deleteX14DataValidation(ws, sqref)
+	}
+	return nil
+}
+
+// deleteDataValidation deletes data validation by given worksheet and cell
+// reference list.
+func (f *File) deleteDataValidation(ws *xlsxWorksheet, delCells map[int][][]int) error {
 	dv := ws.DataValidations
 	for i := 0; i < len(dv.DataValidation); i++ {
 		var applySqref []string
@@ -413,6 +447,64 @@ func (f *File) DeleteDataValidation(sheet string, sqref ...string) error {
 	return nil
 }
 
+// deleteX14DataValidation deletes data validation in the extLst element by
+// given worksheet and cell reference list.
+func (f *File) deleteX14DataValidation(ws *xlsxWorksheet, sqref []string) error {
+	var (
+		decodeExtLst          = new(decodeExtLst)
+		decodeDataValidations *xlsxDataValidations
+		x14DataValidations    *xlsxX14DataValidations
+	)
+	if err := f.xmlNewDecoder(strings.NewReader("<extLst>" + ws.ExtLst.Ext + "</extLst>")).
+		Decode(decodeExtLst); err != nil && err != io.EOF {
+		return err
+	}
+	for i, ext := range decodeExtLst.Ext {
+		if ext.URI == ExtURIDataValidations {
+			decodeDataValidations = new(xlsxDataValidations)
+			x14DataValidations = new(xlsxX14DataValidations)
+			_ = f.xmlNewDecoder(strings.NewReader(ext.Content)).Decode(decodeDataValidations)
+			x14DataValidations.XMLNSXM = NameSpaceSpreadSheetExcel2006Main.Value
+			x14DataValidations.DisablePrompts = decodeDataValidations.DisablePrompts
+			x14DataValidations.XWindow = decodeDataValidations.XWindow
+			x14DataValidations.YWindow = decodeDataValidations.YWindow
+			for _, dv := range decodeDataValidations.DataValidation {
+				if inStrSlice(sqref, dv.XMSqref, false) == -1 {
+					x14DataValidations.DataValidation = append(x14DataValidations.DataValidation, &xlsxX14DataValidation{
+						AllowBlank:       dv.AllowBlank,
+						Error:            dv.Error,
+						ErrorStyle:       dv.ErrorStyle,
+						ErrorTitle:       dv.ErrorTitle,
+						Operator:         dv.Operator,
+						Prompt:           dv.Prompt,
+						PromptTitle:      dv.PromptTitle,
+						ShowDropDown:     dv.ShowDropDown,
+						ShowErrorMessage: dv.ShowErrorMessage,
+						ShowInputMessage: dv.ShowInputMessage,
+						Sqref:            dv.Sqref,
+						XMSqref:          dv.XMSqref,
+						Type:             dv.Type,
+						Formula1:         dv.Formula1,
+						Formula2:         dv.Formula2,
+					})
+				}
+			}
+			x14DataValidations.Count = len(x14DataValidations.DataValidation)
+			x14DataValidationsBytes, _ := xml.Marshal(x14DataValidations)
+			decodeExtLst.Ext[i] = &xlsxExt{
+				xmlns: []xml.Attr{{Name: xml.Name{Local: "xmlns:" + NameSpaceSpreadSheetX14.Name.Local}, Value: NameSpaceSpreadSheetX14.Value}},
+				URI:   ExtURIDataValidations, Content: string(x14DataValidationsBytes),
+			}
+			if x14DataValidations.Count == 0 {
+				decodeExtLst.Ext = slices.Delete(decodeExtLst.Ext, i, i+1)
+			}
+		}
+	}
+	extLstBytes, err := xml.Marshal(decodeExtLst)
+	ws.ExtLst = &xlsxExtLst{Ext: strings.TrimSuffix(strings.TrimPrefix(string(extLstBytes), "<extLst>"), "</extLst>")}
+	return err
+}
+
 // squashSqref generates cell reference sequence by given cells coordinates list.
 func squashSqref(cells [][]int) []string {
 	if len(cells) == 1 {
diff --git a/datavalidation_test.go b/datavalidation_test.go
index a5d2becaf3..a979e2bc4b 100644
--- a/datavalidation_test.go
+++ b/datavalidation_test.go
@@ -16,6 +16,7 @@ import (
 	"math"
 	"path/filepath"
 	"strings"
+	"sync"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
@@ -81,7 +82,7 @@ func TestDataValidation(t *testing.T) {
 		dv.Formula1 = ""
 		assert.NoError(t, dv.SetDropList(listValid),
 			"SetDropList failed for valid input %v", listValid)
-		assert.NotEqual(t, "", dv.Formula1,
+		assert.NotEmpty(t, dv.Formula1,
 			"Formula1 should not be empty for valid input %v", listValid)
 	}
 	assert.Equal(t, `"A&lt;,B&gt;,C"",D	,E',F"`, dv.Formula1)
@@ -242,4 +243,31 @@ func TestDeleteDataValidation(t *testing.T) {
 	// Test delete all data validations in the worksheet
 	assert.NoError(t, f.DeleteDataValidation("Sheet1"))
 	assert.Nil(t, ws.(*xlsxWorksheet).DataValidations)
+
+	t.Run("delete_data_validation_from_extLst", func(t *testing.T) {
+		f := NewFile()
+		f.Sheet.Delete("xl/worksheets/sheet1.xml")
+		f.Pkg.Store("xl/worksheets/sheet1.xml", fmt.Appendf(nil,
+			`<worksheet xmlns="%s"><sheetData/><extLst><ext xmlns:x14="%s" uri="%s"><x14:dataValidations xmlns:xm="%s" count="2"><x14:dataValidation allowBlank="true" showErrorMessage="true" showInputMessage="true" sqref="" type="list"><xm:sqref>A1:A2</xm:sqref><x14:formula1><xm:f>Sheet1!$A$2:$A$4</xm:f></x14:formula1></x14:dataValidation><x14:dataValidation allowBlank="true" showErrorMessage="true" showInputMessage="true" sqref="" type="list"><xm:sqref>B1:B2</xm:sqref><x14:formula1><xm:f>Sheet1!$B$2:$B$3</xm:f></x14:formula1></x14:dataValidation></x14:dataValidations></ext></extLst></worksheet>`,
+			NameSpaceSpreadSheet.Value, NameSpaceSpreadSheetExcel2006Main.Value,
+			ExtURIDataValidations, NameSpaceSpreadSheetExcel2006Main.Value))
+		f.checked = sync.Map{}
+		assert.NoError(t, f.DeleteDataValidation("Sheet1", "A1:A2"))
+		dvs, err := f.GetDataValidations("Sheet1")
+		assert.NoError(t, err)
+		assert.Len(t, dvs, 1)
+		assert.Equal(t, "B1:B2", dvs[0].Sqref)
+
+		assert.NoError(t, f.DeleteDataValidation("Sheet1", "B1:B2"))
+		dvs, err = f.GetDataValidations("Sheet1")
+		assert.NoError(t, err)
+		assert.Empty(t, dvs)
+	})
+
+	t.Run("delete_data_validation_failed_from_extLst", func(t *testing.T) {
+		f := NewFile()
+		assert.EqualError(t, f.deleteX14DataValidation(&xlsxWorksheet{
+			ExtLst: &xlsxExtLst{Ext: "<extLst><x14:dataValidations></x14:dataValidation></x14:dataValidations></ext></extLst>"},
+		}, nil), "XML syntax error on line 1: element <dataValidations> closed by </dataValidation>")
+	})
 }
diff --git a/drawing.go b/drawing.go
index c029fdf7d3..5f1c9dd4b0 100644
--- a/drawing.go
+++ b/drawing.go
@@ -169,6 +169,7 @@ func (f *File) addChart(opts *Chart, comboCharts []*Chart) {
 		xlsxChartSpace.Chart.Legend = nil
 	}
 	xlsxChartSpace.Chart.PlotArea.SpPr = f.drawShapeFill(opts.PlotArea.Fill, xlsxChartSpace.Chart.PlotArea.SpPr)
+	xlsxChartSpace.Chart.PlotArea.DTable = f.drawPlotAreaDTable(opts)
 	addChart := func(c, p *cPlotArea) {
 		immutable, mutable := reflect.ValueOf(c).Elem(), reflect.ValueOf(p).Elem()
 		for i := 0; i < mutable.NumField(); i++ {
@@ -1232,6 +1233,19 @@ func (f *File) drawPlotAreaTitles(runs []RichTextRun, vert string) *cTitle {
 	return title
 }
 
+// drawPlotAreaDTable provides a function to draw the c:dTable element.
+func (f *File) drawPlotAreaDTable(opts *Chart) *cDTable {
+	if _, ok := plotAreaChartGrouping[opts.Type]; ok && opts.PlotArea.ShowDataTable {
+		return &cDTable{
+			ShowHorzBorder: &attrValBool{Val: boolPtr(true)},
+			ShowVertBorder: &attrValBool{Val: boolPtr(true)},
+			ShowOutline:    &attrValBool{Val: boolPtr(true)},
+			ShowKeys:       &attrValBool{Val: boolPtr(opts.PlotArea.ShowDataTableKeys)},
+		}
+	}
+	return nil
+}
+
 // drawPlotAreaSpPr provides a function to draw the c:spPr element.
 func (f *File) drawPlotAreaSpPr() *cSpPr {
 	return &cSpPr{
@@ -1392,7 +1406,7 @@ func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rI
 	}
 	width = int(float64(width) * opts.ScaleX)
 	height = int(float64(height) * opts.ScaleY)
-	colStart, rowStart, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, col, row, opts.OffsetX, opts.OffsetY, width, height)
+	colStart, rowStart, colEnd, rowEnd, x1, y1, x2, y2 := f.positionObjectPixels(sheet, col, row, width, height, opts)
 	content, cNvPrID, err := f.drawingParser(drawingXML)
 	if err != nil {
 		return err
@@ -1401,9 +1415,9 @@ func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rI
 	twoCellAnchor.EditAs = opts.Positioning
 	from := xlsxFrom{}
 	from.Col = colStart
-	from.ColOff = opts.OffsetX * EMU
+	from.ColOff = x1 * EMU
 	from.Row = rowStart
-	from.RowOff = opts.OffsetY * EMU
+	from.RowOff = y1 * EMU
 	to := xlsxTo{}
 	to.Col = colEnd
 	to.ColOff = x2 * EMU
@@ -1452,7 +1466,7 @@ func (f *File) addSheetDrawingChart(drawingXML string, rID int, opts *GraphicOpt
 	absoluteAnchor := xdrCellAnchor{
 		EditAs: opts.Positioning,
 		Pos:    &xlsxPoint2D{},
-		Ext:    &aExt{},
+		Ext:    &xlsxPositiveSize2D{},
 	}
 
 	graphicFrame := xlsxGraphicFrame{
diff --git a/excelize.go b/excelize.go
index 8448999ab2..61bb6d3489 100644
--- a/excelize.go
+++ b/excelize.go
@@ -31,6 +31,7 @@ type File struct {
 	mu               sync.Mutex
 	checked          sync.Map
 	formulaChecked   bool
+	zip64Entries     []string
 	options          *Options
 	sharedStringItem [][]uint
 	sharedStringsMap map[string]int
diff --git a/excelize_test.go b/excelize_test.go
index 9684db2cd6..b88911e4c7 100644
--- a/excelize_test.go
+++ b/excelize_test.go
@@ -86,13 +86,13 @@ func TestOpenFile(t *testing.T) {
 
 	f.SetActiveSheet(2)
 	// Test get cell formula with given rows number
-	_, err = f.GetCellFormula("Sheet1", "B19")
+	formula, err := f.GetCellFormula("Sheet1", "B19")
 	assert.NoError(t, err)
+	assert.Equal(t, "SUM(Sheet2!D2,Sheet2!D11)", formula)
 	// Test get cell formula with illegal worksheet name
-	_, err = f.GetCellFormula("Sheet2", "B20")
-	assert.NoError(t, err)
-	_, err = f.GetCellFormula("Sheet1", "B20")
+	formula, err = f.GetCellFormula("Sheet2", "B20")
 	assert.NoError(t, err)
+	assert.Empty(t, formula)
 
 	// Test get cell formula with illegal rows number
 	_, err = f.GetCellFormula("Sheet1", "B")
@@ -1060,7 +1060,7 @@ func TestCopySheetError(t *testing.T) {
 
 func TestGetSheetComments(t *testing.T) {
 	f := NewFile()
-	assert.Equal(t, "", f.getSheetComments("sheet0"))
+	assert.Empty(t, f.getSheetComments("sheet0"))
 }
 
 func TestGetActiveSheetIndex(t *testing.T) {
@@ -1414,7 +1414,7 @@ func TestProtectSheet(t *testing.T) {
 	assert.NoError(t, f.UnprotectSheet(sheetName, "password"))
 	// Test protect worksheet with empty password
 	assert.NoError(t, f.ProtectSheet(sheetName, &SheetProtectionOptions{}))
-	assert.Equal(t, "", ws.SheetProtection.Password)
+	assert.Empty(t, ws.SheetProtection.Password)
 	// Test protect worksheet with password exceeds the limit length
 	assert.EqualError(t, f.ProtectSheet(sheetName, &SheetProtectionOptions{
 		AlgorithmName: "MD4",
diff --git a/file.go b/file.go
index aa0816c9c2..1ef8a8a5fb 100644
--- a/file.go
+++ b/file.go
@@ -14,8 +14,10 @@ package excelize
 import (
 	"archive/zip"
 	"bytes"
+	"encoding/binary"
 	"encoding/xml"
 	"io"
+	"math"
 	"os"
 	"path/filepath"
 	"sort"
@@ -85,22 +87,23 @@ func (f *File) SaveAs(name string, opts ...Options) error {
 
 // Close closes and cleanup the open temporary file for the spreadsheet.
 func (f *File) Close() error {
-	var err error
+	var firstErr error
 	if f.sharedStringTemp != nil {
-		if err := f.sharedStringTemp.Close(); err != nil {
-			return err
-		}
+		firstErr = f.sharedStringTemp.Close()
+		f.sharedStringTemp = nil
+	}
+	for _, stream := range f.streams {
+		_ = stream.rawData.Close()
 	}
+	f.streams = nil
 	f.tempFiles.Range(func(k, v interface{}) bool {
-		if err = os.Remove(v.(string)); err != nil {
-			return false
+		if err := os.Remove(v.(string)); err != nil && firstErr == nil {
+			firstErr = err
 		}
 		return true
 	})
-	for _, stream := range f.streams {
-		_ = stream.rawData.Close()
-	}
-	return err
+	f.tempFiles.Clear()
+	return firstErr
 }
 
 // Write provides a function to write to an io.Writer.
@@ -123,17 +126,11 @@ func (f *File) WriteTo(w io.Writer, opts ...Options) (int64, error) {
 			return 0, err
 		}
 	}
-	if f.options != nil && f.options.Password != "" {
-		buf, err := f.WriteToBuffer()
-		if err != nil {
-			return 0, err
-		}
-		return buf.WriteTo(w)
-	}
-	if err := f.writeDirectToWriter(w); err != nil {
+	buf, err := f.WriteToBuffer()
+	if err != nil {
 		return 0, err
 	}
-	return 0, nil
+	return buf.WriteTo(w)
 }
 
 // WriteToBuffer provides a function to get bytes.Buffer from the saved file,
@@ -143,32 +140,22 @@ func (f *File) WriteToBuffer() (*bytes.Buffer, error) {
 	zw := zip.NewWriter(buf)
 
 	if err := f.writeToZip(zw); err != nil {
-		return buf, zw.Close()
+		_ = zw.Close()
+		return buf, err
 	}
-
+	if err := zw.Close(); err != nil {
+		return buf, err
+	}
+	f.writeZip64LFH(buf)
 	if f.options != nil && f.options.Password != "" {
-		if err := zw.Close(); err != nil {
-			return buf, err
-		}
 		b, err := Encrypt(buf.Bytes(), f.options)
 		if err != nil {
 			return buf, err
 		}
 		buf.Reset()
 		buf.Write(b)
-		return buf, nil
 	}
-	return buf, zw.Close()
-}
-
-// writeDirectToWriter provides a function to write to io.Writer.
-func (f *File) writeDirectToWriter(w io.Writer) error {
-	zw := zip.NewWriter(w)
-	if err := f.writeToZip(zw); err != nil {
-		_ = zw.Close()
-		return err
-	}
-	return zw.Close()
+	return buf, nil
 }
 
 // writeToZip provides a function to write to zip.Writer
@@ -197,11 +184,16 @@ func (f *File) writeToZip(zw *zip.Writer) error {
 			_ = stream.rawData.Close()
 			return err
 		}
-		if _, err = io.Copy(fi, from); err != nil {
+		written, err := io.Copy(fi, from)
+		if err != nil {
 			return err
 		}
+		if written > math.MaxUint32 {
+			f.zip64Entries = append(f.zip64Entries, path)
+		}
 	}
 	var (
+		n                int
 		err              error
 		files, tempFiles []string
 	)
@@ -219,7 +211,9 @@ func (f *File) writeToZip(zw *zip.Writer) error {
 			break
 		}
 		content, _ := f.Pkg.Load(path)
-		_, err = fi.Write(content.([]byte))
+		if n, err = fi.Write(content.([]byte)); int64(n) > math.MaxUint32 {
+			f.zip64Entries = append(f.zip64Entries, path)
+		}
 	}
 	f.tempFiles.Range(func(path, content interface{}) bool {
 		if _, ok := f.Pkg.Load(path); ok {
@@ -234,7 +228,46 @@ func (f *File) writeToZip(zw *zip.Writer) error {
 		if fi, err = zw.Create(path); err != nil {
 			break
 		}
-		_, err = fi.Write(f.readBytes(path))
+		if n, err = fi.Write(f.readBytes(path)); int64(n) > math.MaxUint32 {
+			f.zip64Entries = append(f.zip64Entries, path)
+		}
 	}
 	return err
 }
+
+// writeZip64LFH function sets the ZIP version to 0x2D (45) in the Local File
+// Header (LFH). Excel strictly enforces ZIP64 format validation rules. When any
+// file within the workbook (OCP) exceeds 4GB in size, the ZIP64 format must be
+// used according to the PKZIP specification. However, ZIP files generated using
+// Go's standard archive/zip library always set the version in the local file
+// header to 20 (ZIP version 2.0) by default, as defined in the internal
+// 'writeHeader' function during ZIP creation. The archive/zip package only sets
+// the 'ReaderVersion' to 45 (ZIP64 version 4.5) in the central directory for
+// entries larger than 4GB. This results in a version mismatch between the
+// central directory and the local file header. As a result, opening the
+// generated workbook with spreadsheet application will prompt file corruption.
+func (f *File) writeZip64LFH(buf *bytes.Buffer) error {
+	if len(f.zip64Entries) == 0 {
+		return nil
+	}
+	data, offset := buf.Bytes(), 0
+	for offset < len(data) {
+		idx := bytes.Index(data[offset:], []byte{0x50, 0x4b, 0x03, 0x04})
+		if idx == -1 {
+			break
+		}
+		idx += offset
+		if idx+30 > len(data) {
+			break
+		}
+		filenameLen := int(binary.LittleEndian.Uint16(data[idx+26 : idx+28]))
+		if idx+30+filenameLen > len(data) {
+			break
+		}
+		if inStrSlice(f.zip64Entries, string(data[idx+30:idx+30+filenameLen]), true) != -1 {
+			binary.LittleEndian.PutUint16(data[idx+4:idx+6], 45)
+		}
+		offset = idx + 1
+	}
+	return nil
+}
diff --git a/file_test.go b/file_test.go
index 4272a7b4f1..58c9e4a265 100644
--- a/file_test.go
+++ b/file_test.go
@@ -3,8 +3,11 @@ package excelize
 import (
 	"bufio"
 	"bytes"
+	"encoding/binary"
+	"math"
 	"os"
 	"path/filepath"
+	"strconv"
 	"strings"
 	"sync"
 	"testing"
@@ -95,3 +98,91 @@ func TestClose(t *testing.T) {
 	f.tempFiles.Store("/d/", "/d/")
 	require.Error(t, f.Close())
 }
+
+func TestZip64(t *testing.T) {
+	f := NewFile()
+	_, err := f.NewSheet("Sheet2")
+	assert.NoError(t, err)
+	sw, err := f.NewStreamWriter("Sheet1")
+	assert.NoError(t, err)
+	for r := range 131 {
+		rowData := make([]interface{}, 1000)
+		for c := range 1000 {
+			rowData[c] = strings.Repeat("c", TotalCellChars)
+		}
+		cell, err := CoordinatesToCellName(1, r+1)
+		assert.NoError(t, err)
+		assert.NoError(t, sw.SetRow(cell, rowData))
+	}
+	assert.NoError(t, sw.Flush())
+	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestZip64.xlsx")))
+	assert.NoError(t, f.Close())
+
+	// Test with filename length overflow
+	f = NewFile()
+	f.zip64Entries = append(f.zip64Entries, defaultXMLPathSharedStrings)
+	buf := new(bytes.Buffer)
+	buf.Write([]byte{0x50, 0x4b, 0x03, 0x04})
+	buf.Write(make([]byte, 20))
+	assert.NoError(t, f.writeZip64LFH(buf))
+
+	// Test with file header less than the required 30 for the fixed header part
+	f = NewFile()
+	f.zip64Entries = append(f.zip64Entries, defaultXMLPathSharedStrings)
+	buf.Reset()
+	buf.Write([]byte{0x50, 0x4b, 0x03, 0x04})
+	buf.Write(make([]byte, 22))
+	binary.Write(buf, binary.LittleEndian, uint16(10))
+	buf.Write(make([]byte, 2))
+	buf.WriteString("test")
+	assert.NoError(t, f.writeZip64LFH(buf))
+
+	t.Run("for_save_zip64_with_in_memory_file_over_4GB", func(t *testing.T) {
+		// Test save workbook in ZIP64 format with in memory file with size over 4GB.
+		f := NewFile()
+		f.Sheet.Delete("xl/worksheets/sheet1.xml")
+		f.Pkg.Store("xl/worksheets/sheet1.xml", make([]byte, math.MaxUint32+1))
+		_, err := f.WriteToBuffer()
+		assert.NoError(t, err)
+		assert.NoError(t, f.Close())
+	})
+
+	t.Run("for_save_zip64_with_in_temporary_file_over_4GB", func(t *testing.T) {
+		// Test save workbook in ZIP64 format with temporary file with size over 4GB.
+		if os.Getenv("GITHUB_ACTIONS") == "true" {
+			t.Skip()
+		}
+		f := NewFile()
+		f.Pkg.Delete("xl/worksheets/sheet1.xml")
+		f.Sheet.Delete("xl/worksheets/sheet1.xml")
+		tmp, err := os.CreateTemp(os.TempDir(), "excelize-")
+		assert.NoError(t, err)
+		assert.NoError(t, tmp.Truncate(math.MaxUint32+1))
+		f.tempFiles.Store("xl/worksheets/sheet1.xml", tmp.Name())
+		assert.NoError(t, tmp.Close())
+		_, err = f.WriteToBuffer()
+		assert.NoError(t, err)
+		assert.NoError(t, f.Close())
+	})
+}
+
+func TestRemoveTempFiles(t *testing.T) {
+	tmp, err := os.CreateTemp("", "excelize-*")
+	if err != nil {
+		t.Fatal(err)
+	}
+	tmpName := tmp.Name()
+	tmp.Close()
+	f := NewFile()
+	// fill the tempFiles map with non-existing (erroring on Remove) "files"
+	for i := 0; i < 1000; i++ {
+		f.tempFiles.Store(strconv.Itoa(i), "/hopefully not existing")
+	}
+	f.tempFiles.Store("existing", tmpName)
+
+	require.Error(t, f.Close())
+	if _, err := os.Stat(tmpName); err == nil {
+		t.Errorf("temp file %q still exist", tmpName)
+		os.Remove(tmpName)
+	}
+}
diff --git a/go.mod b/go.mod
index 53b05c8e78..1a01180b1e 100644
--- a/go.mod
+++ b/go.mod
@@ -5,13 +5,13 @@ go 1.23.0
 require (
 	github.com/richardlehane/mscfb v1.0.4
 	github.com/stretchr/testify v1.10.0
-	github.com/tiendc/go-deepcopy v1.5.1
-	github.com/xuri/efp v0.0.0-20250227110027-3491fafc2b79
-	github.com/xuri/nfp v0.0.0-20250226145837-86d5fc24b2ba
-	golang.org/x/crypto v0.36.0
+	github.com/tiendc/go-deepcopy v1.6.0
+	github.com/xuri/efp v0.0.1
+	github.com/xuri/nfp v0.0.1
+	golang.org/x/crypto v0.38.0
 	golang.org/x/image v0.25.0
-	golang.org/x/net v0.38.0
-	golang.org/x/text v0.23.0
+	golang.org/x/net v0.40.0
+	golang.org/x/text v0.25.0
 )
 
 require (
diff --git a/go.sum b/go.sum
index e66a0ba3e4..0bb04b8cee 100644
--- a/go.sum
+++ b/go.sum
@@ -9,20 +9,20 @@ github.com/richardlehane/msoleps v1.0.4 h1:WuESlvhX3gH2IHcd8UqyCuFY5yiq/GR/yqaSM
 github.com/richardlehane/msoleps v1.0.4/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
 github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
 github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-github.com/tiendc/go-deepcopy v1.5.1 h1:5ymXIB8ReIywehne6oy3HgywC8LicXYucPBNnj5QQxE=
-github.com/tiendc/go-deepcopy v1.5.1/go.mod h1:toXoeQoUqXOOS/X4sKuiAoSk6elIdqc0pN7MTgOOo2I=
-github.com/xuri/efp v0.0.0-20250227110027-3491fafc2b79 h1:78nKszZqigiBRBVcoe/AuPzyLTWW5B+ltBaUX1rlIXA=
-github.com/xuri/efp v0.0.0-20250227110027-3491fafc2b79/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
-github.com/xuri/nfp v0.0.0-20250226145837-86d5fc24b2ba h1:DhIu6n3qU0joqG9f4IO6a/Gkerd+flXrmlJ+0yX2W8U=
-github.com/xuri/nfp v0.0.0-20250226145837-86d5fc24b2ba/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
-golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
-golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
+github.com/tiendc/go-deepcopy v1.6.0 h1:0UtfV/imoCwlLxVsyfUd4hNHnB3drXsfle+wzSCA5Wo=
+github.com/tiendc/go-deepcopy v1.6.0/go.mod h1:toXoeQoUqXOOS/X4sKuiAoSk6elIdqc0pN7MTgOOo2I=
+github.com/xuri/efp v0.0.1 h1:fws5Rv3myXyYni8uwj2qKjVaRP30PdjeYe2Y6FDsCL8=
+github.com/xuri/efp v0.0.1/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
+github.com/xuri/nfp v0.0.1 h1:MDamSGatIvp8uOmDP8FnmjuQpu90NzdJxo7242ANR9Q=
+github.com/xuri/nfp v0.0.1/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
+golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
+golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
 golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
 golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
-golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
-golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
-golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
-golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
+golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
+golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
+golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
+golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
diff --git a/lib.go b/lib.go
index e06e7f5105..113d574fbf 100644
--- a/lib.go
+++ b/lib.go
@@ -80,7 +80,7 @@ func (f *File) ReadZipReader(r *zip.Reader) (map[string][]byte, int, error) {
 // unzipToTemp unzip the zip entity to the system temporary directory and
 // returned the unzipped file path.
 func (f *File) unzipToTemp(zipFile *zip.File) (string, error) {
-	tmp, err := os.CreateTemp(os.TempDir(), "excelize-")
+	tmp, err := os.CreateTemp("", "excelize-")
 	if err != nil {
 		return "", err
 	}
diff --git a/lib_test.go b/lib_test.go
index f6bd94fe64..6a46f1ef1f 100644
--- a/lib_test.go
+++ b/lib_test.go
@@ -95,12 +95,12 @@ func TestColumnNumberToName_OK(t *testing.T) {
 func TestColumnNumberToName_Error(t *testing.T) {
 	out, err := ColumnNumberToName(-1)
 	if assert.Error(t, err) {
-		assert.Equal(t, "", out)
+		assert.Empty(t, out)
 	}
 
 	out, err = ColumnNumberToName(0)
 	if assert.Error(t, err) {
-		assert.Equal(t, "", out)
+		assert.Empty(t, out)
 	}
 
 	_, err = ColumnNumberToName(MaxColumns + 1)
diff --git a/merge_test.go b/merge_test.go
index fcdbcfd647..93a7ff7044 100644
--- a/merge_test.go
+++ b/merge_test.go
@@ -35,7 +35,7 @@ func TestMergeCell(t *testing.T) {
 	assert.NoError(t, err)
 	// Merged cell ref is single coordinate
 	value, err = f.GetCellValue("Sheet2", "A6")
-	assert.Equal(t, "", value)
+	assert.Empty(t, value)
 	assert.NoError(t, err)
 	value, err = f.GetCellFormula("Sheet1", "G12")
 	assert.Equal(t, "SUM(Sheet1!B19,Sheet1!C19)", value)
@@ -104,7 +104,7 @@ func TestMergeCellOverlap(t *testing.T) {
 	assert.Len(t, mc, 1)
 	assert.Equal(t, "A1", mc[0].GetStartAxis())
 	assert.Equal(t, "D3", mc[0].GetEndAxis())
-	assert.Equal(t, "", mc[0].GetCellValue())
+	assert.Empty(t, mc[0].GetCellValue())
 	assert.NoError(t, f.Close())
 }
 
diff --git a/picture.go b/picture.go
index de0d555870..c6c8c2bd8f 100644
--- a/picture.go
+++ b/picture.go
@@ -366,25 +366,29 @@ func (f *File) addDrawingPicture(sheet, drawingXML, cell, ext string, rID, hyper
 		width = int(float64(width) * opts.ScaleX)
 		height = int(float64(height) * opts.ScaleY)
 	}
-	colStart, rowStart, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, col, row, opts.OffsetX, opts.OffsetY, width, height)
+	colStart, rowStart, colEnd, rowEnd, x1, y1, x2, y2 := f.positionObjectPixels(sheet, col, row, width, height, opts)
 	content, cNvPrID, err := f.drawingParser(drawingXML)
 	if err != nil {
 		return err
 	}
-	twoCellAnchor := xdrCellAnchor{}
-	twoCellAnchor.EditAs = opts.Positioning
+	cellAnchor := xdrCellAnchor{}
 	from := xlsxFrom{}
 	from.Col = colStart
-	from.ColOff = opts.OffsetX * EMU
+	from.ColOff = x1 * EMU
 	from.Row = rowStart
-	from.RowOff = opts.OffsetY * EMU
-	to := xlsxTo{}
-	to.Col = colEnd
-	to.ColOff = x2 * EMU
-	to.Row = rowEnd
-	to.RowOff = y2 * EMU
-	twoCellAnchor.From = &from
-	twoCellAnchor.To = &to
+	from.RowOff = y1 * EMU
+	cellAnchor.From = &from
+
+	if opts.Positioning != "oneCell" {
+		to := xlsxTo{}
+		to.Col = colEnd
+		to.ColOff = x2 * EMU
+		to.Row = rowEnd
+		to.RowOff = y2 * EMU
+		cellAnchor.To = &to
+		cellAnchor.EditAs = opts.Positioning
+	}
+
 	pic := xlsxPic{}
 	pic.NvPicPr.CNvPicPr.PicLocks.NoChangeAspect = opts.LockAspectRatio
 	pic.NvPicPr.CNvPr.ID = cNvPrID
@@ -413,14 +417,29 @@ func (f *File) addDrawingPicture(sheet, drawingXML, cell, ext string, rID, hyper
 	}
 	pic.SpPr.PrstGeom.Prst = "rect"
 
-	twoCellAnchor.Pic = &pic
-	twoCellAnchor.ClientData = &xdrClientData{
+	if opts.Positioning == "oneCell" {
+		cx := x2 * EMU
+		cy := y2 * EMU
+		cellAnchor.Ext = &xlsxPositiveSize2D{
+			Cx: cx,
+			Cy: cy,
+		}
+		pic.SpPr.Xfrm.Ext.Cx = cx
+		pic.SpPr.Xfrm.Ext.Cy = cy
+	}
+
+	cellAnchor.Pic = &pic
+	cellAnchor.ClientData = &xdrClientData{
 		FLocksWithSheet:  *opts.Locked,
 		FPrintsWithSheet: *opts.PrintObject,
 	}
 	content.mu.Lock()
 	defer content.mu.Unlock()
-	content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
+	if opts.Positioning == "oneCell" {
+		content.OneCellAnchor = append(content.OneCellAnchor, &cellAnchor)
+	} else {
+		content.TwoCellAnchor = append(content.TwoCellAnchor, &cellAnchor)
+	}
 	f.Drawings.Store(drawingXML, content)
 	return err
 }
@@ -721,8 +740,10 @@ func (f *File) drawingsWriter() {
 	})
 }
 
-// drawingResize calculate the height and width after resizing.
-func (f *File) drawingResize(sheet, cell string, width, height float64, opts *GraphicOptions) (w, h, c, r int, err error) {
+// GetCellPixelsWithCoordinates returns the pixel dimensions of a specified cell within a given sheet,
+// accounting for merged cells. This function calculates the total pixel width and height
+// for individual or merged cells and provides the column and row index of the cell.
+func (f *File) GetCellPixelsWithCoordinates(sheet, cell string) (cellWidth, cellHeight, c, r int, err error) {
 	var mergeCells []MergeCell
 	mergeCells, err = f.GetMergeCells(sheet)
 	if err != nil {
@@ -733,7 +754,7 @@ func (f *File) drawingResize(sheet, cell string, width, height float64, opts *Gr
 	if c, r, err = CellNameToCoordinates(cell); err != nil {
 		return
 	}
-	cellWidth, cellHeight := f.getColWidth(sheet, c), f.getRowHeight(sheet, r)
+	cellWidth, cellHeight = f.getColWidth(sheet, c), f.getRowHeight(sheet, r)
 	for _, mergeCell := range mergeCells {
 		if inMergeCell {
 			continue
@@ -753,18 +774,21 @@ func (f *File) drawingResize(sheet, cell string, width, height float64, opts *Gr
 			cellHeight += f.getRowHeight(sheet, row)
 		}
 	}
-	if float64(cellWidth) < width {
-		asp := float64(cellWidth) / width
-		width, height = float64(cellWidth), height*asp
-	}
-	if float64(cellHeight) < height {
-		asp := float64(cellHeight) / height
-		height, width = float64(cellHeight), width*asp
+	return
+}
+
+// drawingResize calculate the height and width after resizing.
+func (f *File) drawingResize(sheet, cell string, width, height float64, opts *GraphicOptions) (w, h, c, r int, err error) {
+	cellWidth, cellHeight, c, r, err := f.GetCellPixelsWithCoordinates(sheet, cell)
+	if float64(cellWidth) < width || float64(cellHeight) < height {
+		aspWidth := float64(cellWidth) / width
+		aspHeight := float64(cellHeight) / height
+		asp := min(aspWidth, aspHeight)
+		width, height = width*asp, height*asp
 	}
 	if opts.AutoFitIgnoreAspect {
 		width, height = float64(cellWidth), float64(cellHeight)
 	}
-	width, height = width-float64(opts.OffsetX), height-float64(opts.OffsetY)
 	w, h = int(width*opts.ScaleX), int(height*opts.ScaleY)
 	return
 }
diff --git a/picture_test.go b/picture_test.go
index c0c9075583..38cd5df2dc 100644
--- a/picture_test.go
+++ b/picture_test.go
@@ -42,6 +42,16 @@ func TestAddPicture(t *testing.T) {
 	assert.NoError(t, f.AddPicture("Sheet1", "F21", filepath.Join("test", "images", "excel.jpg"),
 		&GraphicOptions{OffsetX: 10, OffsetY: 10, Hyperlink: "https://github.com/xuri/excelize", HyperlinkType: "External", Positioning: "oneCell"}))
 
+	// Test add pictures to single cell with offsets
+	assert.NoError(t, f.AddPicture("Sheet2", "K22", filepath.Join("test", "images", "excel.jpg"),
+		&GraphicOptions{Positioning: "oneCell"}))
+	assert.NoError(t, f.AddPicture("Sheet2", "K22", filepath.Join("test", "images", "excel.jpg"),
+		&GraphicOptions{OffsetX: 200, Positioning: "oneCell"}))
+	assert.NoError(t, f.AddPicture("Sheet2", "K22", filepath.Join("test", "images", "excel.jpg"),
+		&GraphicOptions{OffsetX: 400, Positioning: "oneCell"}))
+	assert.NoError(t, f.AddPicture("Sheet2", "K22", filepath.Join("test", "images", "excel.jpg"),
+		&GraphicOptions{OffsetX: 600, Positioning: "oneCell"}))
+
 	file, err := os.ReadFile(filepath.Join("test", "images", "excel.png"))
 	assert.NoError(t, err)
 
@@ -83,7 +93,7 @@ func TestAddPicture(t *testing.T) {
 	// Test get picture cells
 	cells, err := f.GetPictureCells("Sheet1")
 	assert.NoError(t, err)
-	assert.Equal(t, []string{"F21", "A30", "B30", "C30", "Q1", "Q8", "Q15", "Q22", "Q28"}, cells)
+	assert.Equal(t, []string{"A30", "B30", "C30", "Q1", "Q8", "Q15", "Q22", "Q28", "F21"}, cells)
 	assert.NoError(t, f.Close())
 
 	f, err = OpenFile(filepath.Join("test", "TestAddPicture1.xlsx"))
@@ -92,7 +102,7 @@ func TestAddPicture(t *testing.T) {
 	f.Drawings.Delete(path)
 	cells, err = f.GetPictureCells("Sheet1")
 	assert.NoError(t, err)
-	assert.Equal(t, []string{"F21", "A30", "B30", "C30", "Q1", "Q8", "Q15", "Q22", "Q28"}, cells)
+	assert.Equal(t, []string{"A30", "B30", "C30", "Q1", "Q8", "Q15", "Q22", "Q28", "F21"}, cells)
 	// Test get picture cells with unsupported charset
 	f.Drawings.Delete(path)
 	f.Pkg.Store(path, MacintoshCyrillicCharset)
diff --git a/rows.go b/rows.go
index 436a5d6abf..5dbfaf86ea 100644
--- a/rows.go
+++ b/rows.go
@@ -139,8 +139,10 @@ func (rows *Rows) Error() error {
 // Close closes the open worksheet XML file in the system temporary
 // directory.
 func (rows *Rows) Close() error {
-	if rows.tempFile != nil {
-		return rows.tempFile.Close()
+	tempFile := rows.tempFile
+	rows.tempFile = nil
+	if tempFile != nil {
+		return tempFile.Close()
 	}
 	return nil
 }
@@ -231,7 +233,7 @@ func (rows *Rows) rowXMLHandler(rowIterator *rowXMLIterator, xmlElement *xml.Sta
 	if rowIterator.inElement == "c" {
 		rowIterator.cellCol++
 		colCell := xlsxC{}
-		_ = rows.decoder.DecodeElement(&colCell, xmlElement)
+		colCell.cellXMLHandler(rows.decoder, xmlElement)
 		if colCell.R != "" {
 			if rowIterator.cellCol, _, rowIterator.err = CellNameToCoordinates(colCell.R); rowIterator.err != nil {
 				return
@@ -244,6 +246,63 @@ func (rows *Rows) rowXMLHandler(rowIterator *rowXMLIterator, xmlElement *xml.Sta
 	}
 }
 
+// cellXMLAttrHandler parse the cell XML element attributes of the worksheet.
+func (cell *xlsxC) cellXMLAttrHandler(start *xml.StartElement) error {
+	for _, attr := range start.Attr {
+		switch attr.Name.Local {
+		case "r":
+			cell.R = attr.Value
+		case "s":
+			val, err := strconv.ParseInt(attr.Value, 10, 64)
+			if err != nil {
+				return err
+			}
+			if math.MinInt <= val && val <= math.MaxInt {
+				cell.S = int(val)
+			}
+		case "t":
+			cell.T = attr.Value
+		default:
+		}
+	}
+	return nil
+}
+
+// cellXMLHandler parse the cell XML element of the worksheet.
+func (cell *xlsxC) cellXMLHandler(decoder *xml.Decoder, start *xml.StartElement) error {
+	cell.XMLName = start.Name
+	err := cell.cellXMLAttrHandler(start)
+	if err != nil {
+		return err
+	}
+	for {
+		tok, err := decoder.Token()
+		if err != nil {
+			return err
+		}
+		var se xml.StartElement
+		switch el := tok.(type) {
+		case xml.StartElement:
+			se = el
+			switch se.Name.Local {
+			case "v":
+				err = decoder.DecodeElement(&cell.V, &se)
+			case "f":
+				err = decoder.DecodeElement(&cell.F, &se)
+			case "is":
+				err = decoder.DecodeElement(&cell.IS, &se)
+			}
+			if err != nil {
+				return err
+			}
+		case xml.EndElement:
+			if el == start.End() {
+				return nil
+			}
+		}
+	}
+}
+
 // Rows returns a rows iterator, used for streaming reading data for a
 // worksheet with a large data. This function is concurrency safe. For
 // example:
@@ -309,7 +368,7 @@ func (f *File) getFromStringItem(index int) string {
 		}()
 	}
 	f.sharedStringItem = [][]uint{}
-	f.sharedStringTemp, _ = os.CreateTemp(os.TempDir(), "excelize-")
+	f.sharedStringTemp, _ = os.CreateTemp("", "excelize-")
 	f.tempFiles.Store(defaultTempFileSST, f.sharedStringTemp.Name())
 	var (
 		inElement string
@@ -393,12 +452,17 @@ func (f *File) getRowHeight(sheet string, row int) int {
 	ws, _ := f.workSheetReader(sheet)
 	ws.mu.Lock()
 	defer ws.mu.Unlock()
+	height := -1.0
 	for i := range ws.SheetData.Row {
 		v := &ws.SheetData.Row[i]
 		if v.R == row && v.Ht != nil {
-			return int(convertRowHeightToPixels(*v.Ht))
+			height = *v.Ht
+			break
 		}
 	}
+	if height != -1.0 {
+		return int(convertRowHeightToPixels(height))
+	}
 	if ws.SheetFormatPr != nil && ws.SheetFormatPr.DefaultRowHeight > 0 {
 		return int(convertRowHeightToPixels(ws.SheetFormatPr.DefaultRowHeight))
 	}
@@ -575,11 +639,22 @@ func (f *File) RemoveRow(sheet string, row int) error {
 	if err != nil {
 		return err
 	}
+	ws.formulaSI.Clear()
 	if row > len(ws.SheetData.Row) {
 		return f.adjustHelper(sheet, rows, row, -1)
 	}
+	for rowIdx := range ws.SheetData.Row {
+		v := &ws.SheetData.Row[rowIdx]
+		if v.R == row {
+			for _, c := range v.C {
+				if err := f.removeFormula(&c, ws, sheet); err != nil {
+					return err
+				}
+			}
+		}
+	}
 	keep := 0
-	for rowIdx := 0; rowIdx < len(ws.SheetData.Row); rowIdx++ {
+	for rowIdx := range ws.SheetData.Row {
 		v := &ws.SheetData.Row[rowIdx]
 		if v.R != row {
 			ws.SheetData.Row[keep] = *v
diff --git a/rows_test.go b/rows_test.go
index 01b20a0fcf..acc6105a6a 100644
--- a/rows_test.go
+++ b/rows_test.go
@@ -5,6 +5,7 @@ import (
 	"encoding/xml"
 	"fmt"
 	"path/filepath"
+	"strconv"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
@@ -314,41 +315,27 @@ func TestRemoveRow(t *testing.T) {
 	assert.EqualError(t, f.RemoveRow(sheet1, 0), newInvalidRowNumberError(0).Error())
 
 	assert.NoError(t, f.RemoveRow(sheet1, 4))
-	if !assert.Len(t, r.SheetData.Row, rowCount-1) {
-		t.FailNow()
-	}
+	assert.Len(t, r.SheetData.Row, rowCount-1)
 
 	assert.NoError(t, f.MergeCell(sheet1, "B3", "B5"))
 
 	assert.NoError(t, f.RemoveRow(sheet1, 2))
-	if !assert.Len(t, r.SheetData.Row, rowCount-2) {
-		t.FailNow()
-	}
+	assert.Len(t, r.SheetData.Row, rowCount-2)
 
 	assert.NoError(t, f.RemoveRow(sheet1, 4))
-	if !assert.Len(t, r.SheetData.Row, rowCount-3) {
-		t.FailNow()
-	}
+	assert.Len(t, r.SheetData.Row, rowCount-3)
 
 	err = f.AutoFilter(sheet1, "A2:A2", []AutoFilterOptions{{Column: "A", Expression: "x != blanks"}})
-	if !assert.NoError(t, err) {
-		t.FailNow()
-	}
+	assert.NoError(t, err)
 
 	assert.NoError(t, f.RemoveRow(sheet1, 1))
-	if !assert.Len(t, r.SheetData.Row, rowCount-4) {
-		t.FailNow()
-	}
+	assert.Len(t, r.SheetData.Row, rowCount-4)
 
 	assert.NoError(t, f.RemoveRow(sheet1, 2))
-	if !assert.Len(t, r.SheetData.Row, rowCount-5) {
-		t.FailNow()
-	}
+	assert.Len(t, r.SheetData.Row, rowCount-5)
 
 	assert.NoError(t, f.RemoveRow(sheet1, 1))
-	if !assert.Len(t, r.SheetData.Row, rowCount-6) {
-		t.FailNow()
-	}
+	assert.Len(t, r.SheetData.Row, rowCount-6)
 
 	assert.NoError(t, f.RemoveRow(sheet1, 10))
 	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestRemoveRow.xlsx")))
@@ -366,6 +353,14 @@ func TestRemoveRow(t *testing.T) {
 	assert.EqualError(t, f.RemoveRow("SheetN", 1), "sheet SheetN does not exist")
 	// Test remove row with invalid sheet name
 	assert.EqualError(t, f.RemoveRow("Sheet:1", 1), ErrSheetNameInvalid.Error())
+
+	f = NewFile()
+	formulaType, ref := STCellFormulaTypeShared, "C1:C5"
+	assert.NoError(t, f.SetCellFormula("Sheet1", "C1", "=A1+B1",
+		FormulaOpts{Ref: &ref, Type: &formulaType}))
+	f.CalcChain = nil
+	f.Pkg.Store(defaultXMLPathCalcChain, MacintoshCyrillicCharset)
+	assert.EqualError(t, f.RemoveRow("Sheet1", 1), "XML syntax error on line 1: invalid UTF-8")
 }
 
 func TestInsertRows(t *testing.T) {
@@ -382,19 +377,13 @@ func TestInsertRows(t *testing.T) {
 	assert.NoError(t, f.SetCellHyperLink(sheet1, "A5", "https://github.com/xuri/excelize", "External"))
 
 	assert.NoError(t, f.InsertRows(sheet1, 1, 1))
-	if !assert.Len(t, r.SheetData.Row, rowCount+1) {
-		t.FailNow()
-	}
+	assert.Len(t, r.SheetData.Row, rowCount+1)
 
 	assert.NoError(t, f.InsertRows(sheet1, 4, 1))
-	if !assert.Len(t, r.SheetData.Row, rowCount+2) {
-		t.FailNow()
-	}
+	assert.Len(t, r.SheetData.Row, rowCount+2)
 
 	assert.NoError(t, f.InsertRows(sheet1, 4, 2))
-	if !assert.Len(t, r.SheetData.Row, rowCount+4) {
-		t.FailNow()
-	}
+	assert.Len(t, r.SheetData.Row, rowCount+4)
 	// Test insert rows with invalid sheet name
 	assert.EqualError(t, f.InsertRows("Sheet:1", 1, 1), ErrSheetNameInvalid.Error())
 
@@ -585,16 +574,16 @@ func TestDuplicateRowZeroWithNoRows(t *testing.T) {
 
 		val, err := f.GetCellValue(sheet, "A1")
 		assert.NoError(t, err)
-		assert.Equal(t, "", val)
+		assert.Empty(t, val)
 		val, err = f.GetCellValue(sheet, "B1")
 		assert.NoError(t, err)
-		assert.Equal(t, "", val)
+		assert.Empty(t, val)
 		val, err = f.GetCellValue(sheet, "A2")
 		assert.NoError(t, err)
-		assert.Equal(t, "", val)
+		assert.Empty(t, val)
 		val, err = f.GetCellValue(sheet, "B2")
 		assert.NoError(t, err)
-		assert.Equal(t, "", val)
+		assert.Empty(t, val)
 
 		assert.NoError(t, err)
 		expect := map[string]string{
@@ -970,7 +959,7 @@ func TestGetValueFromInlineStr(t *testing.T) {
 	d := &xlsxSST{}
 	val, err := c.getValueFrom(f, d, false)
 	assert.NoError(t, err)
-	assert.Equal(t, "", val)
+	assert.Empty(t, val)
 }
 
 func TestGetValueFromNumber(t *testing.T) {
@@ -1157,6 +1146,66 @@ func TestNumberFormats(t *testing.T) {
 	assert.Equal(t, "2019/3/19", result, "A1")
 }
 
+func TestCellXMLHandler(t *testing.T) {
+	var (
+		content      = []byte(fmt.Sprintf(`<worksheet xmlns="%s"><sheetData><row r="1"><c r="A1" t="s"><v>10</v></c><c r="B1"><is><t>String</t></is></c></row><row r="2"><c r="A2" s="4" t="str"><f>2*A1</f><v>0</v></c><c r="C2" s="1"><f>A3</f><v>2422.3000000000002</v></c><c r="D2" t="d"><v>2022-10-22T15:05:29Z</v></c><c r="F2"></c><c r="G2"></c></row></sheetData></worksheet>`, NameSpaceSpreadSheet.Value))
+		expected, ws xlsxWorksheet
+		row          *xlsxRow
+	)
+	assert.NoError(t, xml.Unmarshal(content, &expected))
+	decoder := xml.NewDecoder(bytes.NewReader(content))
+	rows := Rows{decoder: decoder}
+	for {
+		token, _ := decoder.Token()
+		if token == nil {
+			break
+		}
+		switch element := token.(type) {
+		case xml.StartElement:
+			if element.Name.Local == "row" {
+				r, err := strconv.Atoi(element.Attr[0].Value)
+				assert.NoError(t, err)
+				ws.SheetData.Row = append(ws.SheetData.Row, xlsxRow{R: r})
+				row = &ws.SheetData.Row[len(ws.SheetData.Row)-1]
+			}
+			if element.Name.Local == "c" {
+				colCell := xlsxC{}
+				assert.NoError(t, colCell.cellXMLHandler(rows.decoder, &element))
+				row.C = append(row.C, colCell)
+			}
+		}
+	}
+	assert.Equal(t, expected.SheetData.Row, ws.SheetData.Row)
+
+	for _, rowXML := range []string{
+		`<row spans="1:17" r="1"><c r="A1" t="s" s="A"><v>10</v></c></row></sheetData></worksheet>`, // s need number
+		`<row spans="1:17" r="1"><c r="A1"><v>10</v>    </row></sheetData></worksheet>`,             // missing </c>
+		`<row spans="1:17" r="1"><c r="B1"><is><t>`,                                                 // incorrect data
+	} {
+		ws := xlsxWorksheet{}
+		content := []byte(fmt.Sprintf(`<worksheet xmlns="%s"><sheetData>%s</sheetData></worksheet>`, NameSpaceSpreadSheet.Value, rowXML))
+		expected := xml.Unmarshal(content, &ws)
+		assert.Error(t, expected)
+		decoder := xml.NewDecoder(bytes.NewReader(content))
+		rows := Rows{decoder: decoder}
+		for {
+			token, _ := decoder.Token()
+			if token == nil {
+				break
+			}
+			switch element := token.(type) {
+			case xml.StartElement:
+				if element.Name.Local == "c" {
+					colCell := xlsxC{}
+					err := colCell.cellXMLHandler(rows.decoder, &element)
+					assert.Error(t, err)
+					assert.Equal(t, expected, err)
+				}
+			}
+		}
+	}
+}
+
 func BenchmarkRows(b *testing.B) {
 	f, _ := OpenFile(filepath.Join("test", "Book1.xlsx"))
 	for i := 0; i < b.N; i++ {
diff --git a/shape.go b/shape.go
index 1bbf6964d6..b0228748a7 100644
--- a/shape.go
+++ b/shape.go
@@ -331,7 +331,7 @@ func (f *File) twoCellAnchorShape(sheet, drawingXML, cell string, width, height
 	}
 	w := int(float64(width) * format.ScaleX)
 	h := int(float64(height) * format.ScaleY)
-	colStart, rowStart, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, fromCol, fromRow, format.OffsetX, format.OffsetY, w, h)
+	colStart, rowStart, colEnd, rowEnd, x1, y1, x2, y2 := f.positionObjectPixels(sheet, fromCol, fromRow, w, h, &format)
 	content, cNvPrID, err := f.drawingParser(drawingXML)
 	if err != nil {
 		return content, nil, cNvPrID, err
@@ -340,9 +340,9 @@ func (f *File) twoCellAnchorShape(sheet, drawingXML, cell string, width, height
 	twoCellAnchor.EditAs = format.Positioning
 	from := xlsxFrom{}
 	from.Col = colStart
-	from.ColOff = format.OffsetX * EMU
+	from.ColOff = x1 * EMU
 	from.Row = rowStart
-	from.RowOff = format.OffsetY * EMU
+	from.RowOff = y1 * EMU
 	to := xlsxTo{}
 	to.Col = colEnd
 	to.ColOff = x2 * EMU
diff --git a/sheet_test.go b/sheet_test.go
index 48bb423447..d5cc4cfa7b 100644
--- a/sheet_test.go
+++ b/sheet_test.go
@@ -418,8 +418,8 @@ func TestGetSheetName(t *testing.T) {
 	assert.NoError(t, err)
 	assert.Equal(t, "Sheet1", f.GetSheetName(0))
 	assert.Equal(t, "Sheet2", f.GetSheetName(1))
-	assert.Equal(t, "", f.GetSheetName(-1))
-	assert.Equal(t, "", f.GetSheetName(2))
+	assert.Empty(t, f.GetSheetName(-1))
+	assert.Empty(t, f.GetSheetName(2))
 	assert.NoError(t, f.Close())
 }
 
@@ -481,6 +481,8 @@ func TestSetSheetName(t *testing.T) {
 	assert.Equal(t, "sheet1", f.GetSheetName(0))
 	// Test set sheet name with invalid sheet name
 	assert.Equal(t, f.SetSheetName("Sheet:1", "Sheet1"), ErrSheetNameInvalid)
+	_, err := f.NewSheet("Sheet 3")
+	assert.NoError(t, err)
 
 	// Test set worksheet name with existing defined name and auto filter
 	assert.NoError(t, f.AutoFilter("Sheet1", "A1:A2", nil))
@@ -496,8 +498,12 @@ func TestSetSheetName(t *testing.T) {
 		Name:     "Name3",
 		RefersTo: "Sheet1!$A$1:'Sheet1'!A1:Sheet1!$A$1,Sheet1!A1:Sheet3!A1,Sheet3!A1",
 	}))
-	assert.NoError(t, f.SetSheetName("Sheet1", "Sheet2"))
-	for i, expected := range []string{"'Sheet2'!$A$1:$A$2", "$B$2", "$A1$2:A2", "Sheet2!$A$1:'Sheet2'!A1:Sheet2!$A$1,Sheet2!A1:Sheet3!A1,Sheet3!A1"} {
+	assert.NoError(t, f.SetDefinedName(&DefinedName{
+		Name:     "Name4",
+		RefersTo: "'Sheet 3'!$A1$2:A2",
+	}))
+	assert.NoError(t, f.SetSheetName("Sheet1", "Sheet 2"))
+	for i, expected := range []string{"'Sheet 2'!$A$1:$A$2", "$B$2", "$A1$2:A2", "'Sheet 2'!$A$1:'Sheet 2'!A1:'Sheet 2'!$A$1,'Sheet 2'!A1:Sheet3!A1,Sheet3!A1", "'Sheet 3'!$A1$2:A2"} {
 		assert.Equal(t, expected, f.WorkBook.DefinedNames.DefinedName[i].Data)
 	}
 }
@@ -519,7 +525,7 @@ func TestWorksheetWriter(t *testing.T) {
 func TestGetWorkbookPath(t *testing.T) {
 	f := NewFile()
 	f.Pkg.Delete("_rels/.rels")
-	assert.Equal(t, "", f.getWorkbookPath())
+	assert.Empty(t, f.getWorkbookPath())
 }
 
 func TestGetWorkbookRelsPath(t *testing.T) {
@@ -786,7 +792,7 @@ func TestSheetDimension(t *testing.T) {
 	assert.NoError(t, err)
 	dimension, err = f.GetSheetDimension(sheetName)
 	assert.NoError(t, err)
-	assert.Equal(t, "", dimension)
+	assert.Empty(t, dimension)
 	// Test set the worksheet dimension
 	for _, excepted := range []string{"A1", "A1:D5", "A1:XFD1048576", "a1", "A1:d5"} {
 		err = f.SetSheetDimension(sheetName, excepted)
diff --git a/slicer.go b/slicer.go
index 8073cf72ff..c20b053571 100644
--- a/slicer.go
+++ b/slicer.go
@@ -612,7 +612,7 @@ func (f *File) addDrawingSlicer(sheet, slicerName string, ns xml.Attr, opts *Sli
 				Name: slicerName,
 			},
 		},
-		Xfrm: xlsxXfrm{Off: xlsxOff{}, Ext: aExt{}},
+		Xfrm: xlsxXfrm{Off: xlsxOff{}, Ext: xlsxPositiveSize2D{}},
 		Graphic: &xlsxGraphic{
 			GraphicData: &xlsxGraphicData{
 				URI: NameSpaceDrawingMLSlicer.Value,
@@ -632,7 +632,7 @@ func (f *File) addDrawingSlicer(sheet, slicerName string, ns xml.Attr, opts *Sli
 			},
 		},
 		SpPr: &xlsxSpPr{
-			Xfrm:      xlsxXfrm{Off: xlsxOff{X: 2914650, Y: 152400}, Ext: aExt{Cx: 1828800, Cy: 2238375}},
+			Xfrm:      xlsxXfrm{Off: xlsxOff{X: 2914650, Y: 152400}, Ext: xlsxPositiveSize2D{Cx: 1828800, Cy: 2238375}},
 			SolidFill: &xlsxInnerXML{Content: "<a:prstClr val=\"white\"/>"},
 			PrstGeom: xlsxPrstGeom{
 				Prst: "rect",
diff --git a/stream.go b/stream.go
index 89081b8dde..63309ff3bd 100644
--- a/stream.go
+++ b/stream.go
@@ -137,7 +137,7 @@ func (f *File) NewStreamWriter(sheet string) (*StreamWriter, error) {
 	f.streams[sheetXMLPath] = sw
 
 	_, _ = sw.rawData.WriteString(xml.Header + `<worksheet` + templateNamespaceIDMap)
-	bulkAppendFields(&sw.rawData, sw.worksheet, 2, 3)
+	bulkAppendFields(&sw.rawData, sw.worksheet, 3, 4)
 	return sw, err
 }
 
@@ -662,7 +662,7 @@ func writeCell(buf *bufferedWriter, c xlsxC) {
 // sheetData XML start element to the buffer.
 func (sw *StreamWriter) writeSheetData() {
 	if !sw.sheetWritten {
-		bulkAppendFields(&sw.rawData, sw.worksheet, 4, 5)
+		bulkAppendFields(&sw.rawData, sw.worksheet, 5, 6)
 		if sw.worksheet.Cols != nil {
 			_, _ = sw.rawData.WriteString("<cols>")
 			for _, col := range sw.worksheet.Cols.Col {
@@ -694,7 +694,7 @@ func (sw *StreamWriter) writeSheetData() {
 func (sw *StreamWriter) Flush() error {
 	sw.writeSheetData()
 	_, _ = sw.rawData.WriteString(`</sheetData>`)
-	bulkAppendFields(&sw.rawData, sw.worksheet, 8, 15)
+	bulkAppendFields(&sw.rawData, sw.worksheet, 9, 16)
 	mergeCells := strings.Builder{}
 	if sw.mergeCellsCount > 0 {
 		_, _ = mergeCells.WriteString(`<mergeCells count="`)
@@ -704,9 +704,9 @@ func (sw *StreamWriter) Flush() error {
 		_, _ = mergeCells.WriteString(`</mergeCells>`)
 	}
 	_, _ = sw.rawData.WriteString(mergeCells.String())
-	bulkAppendFields(&sw.rawData, sw.worksheet, 17, 38)
+	bulkAppendFields(&sw.rawData, sw.worksheet, 18, 39)
 	_, _ = sw.rawData.WriteString(sw.tableParts)
-	bulkAppendFields(&sw.rawData, sw.worksheet, 40, 40)
+	bulkAppendFields(&sw.rawData, sw.worksheet, 41, 41)
 	_, _ = sw.rawData.WriteString(`</worksheet>`)
 	if err := sw.rawData.Flush(); err != nil {
 		return err
@@ -775,7 +775,7 @@ func (bw *bufferedWriter) Sync() (err error) {
 		return nil
 	}
 	if bw.tmp == nil {
-		bw.tmp, err = os.CreateTemp(os.TempDir(), "excelize-")
+		bw.tmp, err = os.CreateTemp("", "excelize-")
 		if err != nil {
 			// can not use local storage
 			return nil
diff --git a/vml.go b/vml.go
index 08d54985d2..4ba0ded2d5 100644
--- a/vml.go
+++ b/vml.go
@@ -852,7 +852,7 @@ func (f *File) addDrawingVML(sheetID int, drawingVML string, opts *vmlOptions) e
 		leftOffset, vmlID = 0, 201
 		style = "position:absolute;73.5pt;width:108pt;height:59.25pt;z-index:1;mso-wrap-style:tight"
 	}
-	colStart, rowStart, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(opts.sheet, col, row, opts.Format.OffsetX, opts.Format.OffsetY, int(opts.FormControl.Width), int(opts.FormControl.Height))
+	colStart, rowStart, colEnd, rowEnd, _, _, x2, y2 := f.positionObjectPixels(opts.sheet, col, row, int(opts.FormControl.Width), int(opts.FormControl.Height), &opts.Format)
 	anchor := fmt.Sprintf("%d, %d, %d, 0, %d, %d, %d, %d", colStart, leftOffset, rowStart, colEnd, x2, rowEnd, y2)
 	if vml == nil {
 		vml = &vmlDrawing{
diff --git a/xmlChart.go b/xmlChart.go
index abb0e4adbe..629aa33d1a 100644
--- a/xmlChart.go
+++ b/xmlChart.go
@@ -215,6 +215,17 @@ type aRPr struct {
 	Cs         *aCs            `xml:"a:cs"`
 }
 
+// cDTable (Data Table) directly maps the dTable element.
+type cDTable struct {
+	ShowHorzBorder *attrValBool `xml:"showHorzBorder"`
+	ShowVertBorder *attrValBool `xml:"showVertBorder"`
+	ShowOutline    *attrValBool `xml:"showOutline"`
+	ShowKeys       *attrValBool `xml:"showKeys"`
+	SpPr           *cSpPr       `xml:"spPr"`
+	TxPr           *cTxPr       `xml:"txPr"`
+	ExtLst         *xlsxExtLst  `xml:"extLst"`
+}
+
 // cSpPr (Shape Properties) directly maps the spPr element. This element
 // specifies the visual shape properties that can be applied to a shape. These
 // properties include the shape fill, outline, geometry, effects, and 3D
@@ -319,6 +330,7 @@ type cPlotArea struct {
 	CatAx          []*cAxs    `xml:"catAx"`
 	ValAx          []*cAxs    `xml:"valAx"`
 	SerAx          []*cAxs    `xml:"serAx"`
+	DTable         *cDTable   `xml:"dTable"`
 	SpPr           *cSpPr     `xml:"spPr"`
 }
 
@@ -559,15 +571,17 @@ type ChartDimension struct {
 
 // ChartPlotArea directly maps the format settings of the plot area.
 type ChartPlotArea struct {
-	SecondPlotValues int
-	ShowBubbleSize   bool
-	ShowCatName      bool
-	ShowLeaderLines  bool
-	ShowPercent      bool
-	ShowSerName      bool
-	ShowVal          bool
-	Fill             Fill
-	NumFmt           ChartNumFmt
+	SecondPlotValues  int
+	ShowBubbleSize    bool
+	ShowCatName       bool
+	ShowDataTable     bool
+	ShowDataTableKeys bool
+	ShowLeaderLines   bool
+	ShowPercent       bool
+	ShowSerName       bool
+	ShowVal           bool
+	Fill              Fill
+	NumFmt            ChartNumFmt
 }
 
 // Chart directly maps the format settings of the chart.
diff --git a/xmlDecodeDrawing.go b/xmlDecodeDrawing.go
index 8a20c5d5c6..747352182e 100644
--- a/xmlDecodeDrawing.go
+++ b/xmlDecodeDrawing.go
@@ -21,6 +21,7 @@ type decodeCellAnchor struct {
 	EditAs           string                  `xml:"editAs,attr,omitempty"`
 	From             *decodeFrom             `xml:"from"`
 	To               *decodeTo               `xml:"to"`
+	Ext              *decodePositiveSize2D   `xml:"ext"`
 	Sp               *decodeSp               `xml:"sp"`
 	Pic              *decodePic              `xml:"pic"`
 	ClientData       *decodeClientData       `xml:"clientData"`
@@ -35,7 +36,7 @@ type decodeCellAnchorPos struct {
 	From             *xlsxFrom               `xml:"from"`
 	To               *xlsxTo                 `xml:"to"`
 	Pos              *xlsxInnerXML           `xml:"pos"`
-	Ext              *xlsxInnerXML           `xml:"ext"`
+	Ext              *xlsxPositiveSize2D     `xml:"ext"`
 	Sp               *xlsxSp                 `xml:"sp"`
 	GrpSp            *xlsxInnerXML           `xml:"grpSp"`
 	GraphicFrame     *xlsxInnerXML           `xml:"graphicFrame"`
@@ -85,9 +86,9 @@ type decodeSp struct {
 // shape. This allows for additional information that does not affect the
 // appearance of the shape to be stored.
 type decodeNvSpPr struct {
-	CNvPr   *decodeCNvPr   `xml:"cNvPr"`
-	ExtLst  *decodeAExt    `xml:"extLst"`
-	CNvSpPr *decodeCNvSpPr `xml:"cNvSpPr"`
+	CNvPr   *decodeCNvPr          `xml:"cNvPr"`
+	ExtLst  *decodePositiveSize2D `xml:"extLst"`
+	CNvSpPr *decodeCNvSpPr        `xml:"cNvSpPr"`
 }
 
 // decodeCNvSpPr (Connection Non-Visual Shape Properties) directly maps the
@@ -164,8 +165,8 @@ type decodeOff struct {
 	Y int `xml:"y,attr"`
 }
 
-// decodeAExt directly maps the a:ext element.
-type decodeAExt struct {
+// decodePositiveSize2D directly maps the a:ext element.
+type decodePositiveSize2D struct {
 	Cx int `xml:"cx,attr"`
 	Cy int `xml:"cy,attr"`
 }
@@ -183,8 +184,8 @@ type decodePrstGeom struct {
 // frame. This transformation is applied to the graphic frame just as it would
 // be for a shape or group shape.
 type decodeXfrm struct {
-	Off decodeOff  `xml:"off"`
-	Ext decodeAExt `xml:"ext"`
+	Off decodeOff            `xml:"off"`
+	Ext decodePositiveSize2D `xml:"ext"`
 }
 
 // decodeCNvPicPr directly maps the cNvPicPr (Non-Visual Picture Drawing
diff --git a/xmlDrawing.go b/xmlDrawing.go
index f363849014..89fe986cec 100644
--- a/xmlDrawing.go
+++ b/xmlDrawing.go
@@ -83,8 +83,8 @@ type xlsxOff struct {
 	Y int `xml:"y,attr"`
 }
 
-// aExt directly maps the a:ext element.
-type aExt struct {
+// xlsxPositiveSize2D directly maps the a:ext element.
+type xlsxPositiveSize2D struct {
 	Cx int `xml:"cx,attr"`
 	Cy int `xml:"cy,attr"`
 }
@@ -102,8 +102,8 @@ type xlsxPrstGeom struct {
 // 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 aExt    `xml:"a:ext"`
+	Off xlsxOff            `xml:"a:off"`
+	Ext xlsxPositiveSize2D `xml:"a:ext"`
 }
 
 // xlsxCNvPicPr directly maps the cNvPicPr (Non-Visual Picture Drawing
@@ -222,7 +222,7 @@ type xdrCellAnchor struct {
 	Pos              *xlsxPoint2D            `xml:"xdr:pos"`
 	From             *xlsxFrom               `xml:"xdr:from"`
 	To               *xlsxTo                 `xml:"xdr:to"`
-	Ext              *aExt                   `xml:"xdr:ext"`
+	Ext              *xlsxPositiveSize2D     `xml:"xdr:ext"`
 	Sp               *xdrSp                  `xml:"xdr:sp"`
 	Pic              *xlsxPic                `xml:"xdr:pic,omitempty"`
 	GraphicFrame     string                  `xml:",innerxml"`
@@ -237,7 +237,7 @@ type xlsxCellAnchorPos struct {
 	From             *xlsxFrom               `xml:"xdr:from"`
 	To               *xlsxTo                 `xml:"xdr:to"`
 	Pos              *xlsxInnerXML           `xml:"xdr:pos"`
-	Ext              *xlsxInnerXML           `xml:"xdr:ext"`
+	Ext              *xlsxPositiveSize2D     `xml:"xdr:ext"`
 	Sp               *xlsxSp                 `xml:"xdr:sp"`
 	GrpSp            *xlsxInnerXML           `xml:"xdr:grpSp"`
 	GraphicFrame     *xlsxInnerXML           `xml:"xdr:graphicFrame"`
diff --git a/xmlStyles.go b/xmlStyles.go
index 93ad33cce3..76826c1cc4 100644
--- a/xmlStyles.go
+++ b/xmlStyles.go
@@ -253,13 +253,13 @@ type xlsxDxfs struct {
 // xlsxDxf directly maps the dxf element. A single dxf record, expressing
 // incremental formatting to be applied.
 type xlsxDxf struct {
-	Font       *xlsxFont       `xml:"font"`
-	NumFmt     *xlsxNumFmt     `xml:"numFmt"`
-	Fill       *xlsxFill       `xml:"fill"`
-	Alignment  *xlsxAlignment  `xml:"alignment"`
-	Border     *xlsxBorder     `xml:"border"`
-	Protection *xlsxProtection `xml:"protection"`
-	ExtLst     *aExt           `xml:"extLst"`
+	Font       *xlsxFont           `xml:"font"`
+	NumFmt     *xlsxNumFmt         `xml:"numFmt"`
+	Fill       *xlsxFill           `xml:"fill"`
+	Alignment  *xlsxAlignment      `xml:"alignment"`
+	Border     *xlsxBorder         `xml:"border"`
+	Protection *xlsxProtection     `xml:"protection"`
+	ExtLst     *xlsxPositiveSize2D `xml:"extLst"`
 }
 
 // xlsxTableStyles directly maps the tableStyles element. This element
diff --git a/xmlWorksheet.go b/xmlWorksheet.go
index dab4caf321..f0f9e76128 100644
--- a/xmlWorksheet.go
+++ b/xmlWorksheet.go
@@ -20,6 +20,7 @@ import (
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main.
 type xlsxWorksheet struct {
 	mu                     sync.Mutex
+	formulaSI              sync.Map
 	XMLName                xml.Name                     `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main worksheet"`
 	SheetPr                *xlsxSheetPr                 `xml:"sheetPr"`
 	Dimension              *xlsxDimension               `xml:"dimension"`
@@ -427,7 +428,7 @@ type xlsxDataValidations struct {
 	DataValidation []*xlsxDataValidation `xml:"dataValidation"`
 }
 
-// DataValidation directly maps the single item of data validation defined
+// xlsxDataValidation directly maps the single item of data validation defined
 // on a range of the worksheet.
 type xlsxDataValidation struct {
 	AllowBlank       bool          `xml:"allowBlank,attr"`
@@ -447,6 +448,39 @@ type xlsxDataValidation struct {
 	Formula2         *xlsxInnerXML `xml:"formula2"`
 }
 
+// xlsxX14DataValidation directly maps the single item of data validation
+// defined on a extLst element of the worksheet.
+type xlsxX14DataValidation struct {
+	XMLName          xml.Name      `xml:"x14:dataValidation"`
+	AllowBlank       bool          `xml:"allowBlank,attr"`
+	Error            *string       `xml:"error,attr"`
+	ErrorStyle       *string       `xml:"errorStyle,attr"`
+	ErrorTitle       *string       `xml:"errorTitle,attr"`
+	Operator         string        `xml:"operator,attr,omitempty"`
+	Prompt           *string       `xml:"prompt,attr"`
+	PromptTitle      *string       `xml:"promptTitle,attr"`
+	ShowDropDown     bool          `xml:"showDropDown,attr,omitempty"`
+	ShowErrorMessage bool          `xml:"showErrorMessage,attr,omitempty"`
+	ShowInputMessage bool          `xml:"showInputMessage,attr,omitempty"`
+	Sqref            string        `xml:"sqref,attr"`
+	Type             string        `xml:"type,attr,omitempty"`
+	Formula1         *xlsxInnerXML `xml:"x14:formula1"`
+	Formula2         *xlsxInnerXML `xml:"x14:formula2"`
+	XMSqref          string        `xml:"xm:sqref,omitempty"`
+}
+
+// xlsxX14DataValidations expresses all data validation information for cells in
+// a sheet extLst element which have data validation features applied.
+type xlsxX14DataValidations struct {
+	XMLName        xml.Name `xml:"x14:dataValidations"`
+	XMLNSXM        string   `xml:"xmlns:xm,attr,omitempty"`
+	Count          int      `xml:"count,attr,omitempty"`
+	DisablePrompts bool     `xml:"disablePrompts,attr,omitempty"`
+	XWindow        int      `xml:"xWindow,attr,omitempty"`
+	YWindow        int      `xml:"yWindow,attr,omitempty"`
+	DataValidation []*xlsxX14DataValidation
+}
+
 // xlsxC collection represents a cell in the worksheet. Information about the
 // cell's location (reference), value, data type, formatting, and formula is
 // expressed here.