diff --git a/excelize.go b/excelize.go
index 1bf0248..8b1b763 100644
--- a/excelize.go
+++ b/excelize.go
@@ -601,6 +601,17 @@ func (f *File) metadataReader() (*xlsxMetadata, error) {
return &mataData, nil
}
+// richValueReader provides a function to get the pointer to the structure after
+// deserialization of xl/richData/richvalue.xml.
+func (f *File) richValueReader() (*xlsxRichValueData, error) {
+ var richValue xlsxRichValueData
+ if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataRichValue)))).
+ Decode(&richValue); err != nil && err != io.EOF {
+ return &richValue, err
+ }
+ return &richValue, nil
+}
+
// richValueRelReader provides a function to get the pointer to the structure
// after deserialization of xl/richData/richValueRel.xml.
func (f *File) richValueRelReader() (*xlsxRichValueRels, error) {
diff --git a/picture.go b/picture.go
index d784079..a52bbc3 100644
--- a/picture.go
+++ b/picture.go
@@ -450,7 +450,8 @@ func (f *File) addMedia(file []byte, ext string) string {
// GetPictures provides a function to get picture meta info and raw content
// embed in spreadsheet by given worksheet and cell name. This function
// returns the image contents as []byte data types. This function is
-// concurrency safe. For example:
+// concurrency safe. Note that, this function doesn't support getting cell image
+// inserted by IMAGE formula function currently. For example:
//
// f, err := excelize.OpenFile("Book1.xlsx")
// if err != nil {
@@ -506,7 +507,8 @@ func (f *File) GetPictures(sheet, cell string) ([]Picture, error) {
}
// GetPictureCells returns all picture cell references in a worksheet by a
-// specific worksheet name.
+// specific worksheet name. Note that, this function doesn't support getting
+// cell image inserted by IMAGE formula function currently.
func (f *File) GetPictureCells(sheet string) ([]string, error) {
f.mu.Lock()
ws, err := f.workSheetReader(sheet)
@@ -790,7 +792,7 @@ func (f *File) cellImagesReader() (*decodeCellImages, error) {
return f.DecodeCellImages, nil
}
-// getImageCells returns all the Microsoft 365 cell images and the Kingsoft WPS
+// getImageCells returns all the cell images and the Kingsoft WPS
// Office embedded image cells reference by given worksheet name.
func (f *File) getImageCells(sheet string) ([]string, error) {
var (
@@ -823,7 +825,29 @@ func (f *File) getImageCells(sheet string) ([]string, error) {
return cells, err
}
-// getImageCellRel returns the Microsoft 365 cell image relationship.
+// getImageCellRichValueIdx returns index of the cell image rich value by given
+// cell value meta index and meta blocks.
+func (f *File) getImageCellRichValueIdx(vm uint, blocks *xlsxMetadataBlocks) (int, error) {
+ richValueIdx := blocks.Bk[vm-1].Rc[0].V
+ richValue, err := f.richValueReader()
+ if err != nil {
+ return -1, err
+ }
+ if richValueIdx >= len(richValue.Rv) {
+ return -1, err
+ }
+ rv := richValue.Rv[richValueIdx].V
+ if len(rv) != 2 || rv[1] != "5" {
+ return -1, err
+ }
+ richValueRelIdx, err := strconv.Atoi(rv[0])
+ if err != nil {
+ return -1, err
+ }
+ return richValueRelIdx, err
+}
+
+// getImageCellRel returns the cell image relationship.
func (f *File) getImageCellRel(c *xlsxC) (*xlsxRelationship, error) {
var r *xlsxRelationship
if c.Vm == nil || c.V != formulaErrorVALUE {
@@ -837,21 +861,25 @@ func (f *File) getImageCellRel(c *xlsxC) (*xlsxRelationship, error) {
if vmd == nil || int(*c.Vm) > len(vmd.Bk) || len(vmd.Bk[*c.Vm-1].Rc) == 0 {
return r, err
}
+ richValueRelIdx, err := f.getImageCellRichValueIdx(*c.Vm, vmd)
+ if err != nil || richValueRelIdx == -1 {
+ return r, err
+ }
richValueRel, err := f.richValueRelReader()
if err != nil {
return r, err
}
- if vmd.Bk[*c.Vm-1].Rc[0].V >= len(richValueRel.Rels) {
+ if richValueRelIdx >= len(richValueRel.Rels) {
return r, err
}
- rID := richValueRel.Rels[vmd.Bk[*c.Vm-1].Rc[0].V].ID
+ rID := richValueRel.Rels[richValueRelIdx].ID
if r = f.getRichDataRichValueRelRelationships(rID); r != nil && r.Type != SourceRelationshipImage {
return nil, err
}
return r, err
}
-// getCellImages provides a function to get the Microsoft 365 cell images and
+// getCellImages provides a function to get the cell images and
// the Kingsoft WPS Office embedded cell images by given worksheet name and cell
// reference.
func (f *File) getCellImages(sheet, cell string) ([]Picture, error) {
diff --git a/picture_test.go b/picture_test.go
index 7d08b8d..bb90634 100644
--- a/picture_test.go
+++ b/picture_test.go
@@ -452,17 +452,22 @@ func TestGetCellImages(t *testing.T) {
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
assert.NoError(t, f.Close())
- // Test get the Microsoft 365 cell images
- f = NewFile()
- assert.NoError(t, f.AddPicture("Sheet1", "A1", filepath.Join("test", "images", "excel.png"), nil))
- f.Pkg.Store(defaultXMLMetadata, []byte(``))
- f.Pkg.Store(defaultXMLRichDataRichValueRel, []byte(``))
- f.Pkg.Store(defaultXMLRichDataRichValueRelRels, []byte(fmt.Sprintf(``, SourceRelationshipImage)))
- f.Sheet.Store("xl/worksheets/sheet1.xml", &xlsxWorksheet{
- SheetData: xlsxSheetData{Row: []xlsxRow{
- {R: 1, C: []xlsxC{{R: "A1", T: "e", V: formulaErrorVALUE, Vm: uintPtr(1)}}},
- }},
- })
+ // Test get the cell images
+ prepareWorkbook := func() *File {
+ f := NewFile()
+ assert.NoError(t, f.AddPicture("Sheet1", "A1", filepath.Join("test", "images", "excel.png"), nil))
+ f.Pkg.Store(defaultXMLMetadata, []byte(``))
+ f.Pkg.Store(defaultXMLRichDataRichValue, []byte(`05`))
+ f.Pkg.Store(defaultXMLRichDataRichValueRel, []byte(``))
+ f.Pkg.Store(defaultXMLRichDataRichValueRelRels, []byte(fmt.Sprintf(``, SourceRelationshipImage)))
+ f.Sheet.Store("xl/worksheets/sheet1.xml", &xlsxWorksheet{
+ SheetData: xlsxSheetData{Row: []xlsxRow{
+ {R: 1, C: []xlsxC{{R: "A1", T: "e", V: formulaErrorVALUE, Vm: uintPtr(1)}}},
+ }},
+ })
+ return f
+ }
+ f = prepareWorkbook()
pics, err := f.GetPictures("Sheet1", "A1")
assert.NoError(t, err)
assert.Equal(t, 1, len(pics))
@@ -471,41 +476,64 @@ func TestGetCellImages(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, []string{"A1"}, cells)
- // Test get the Microsoft 365 cell images without image relationships parts
+ // Test get the cell images without image relationships parts
f.Relationships.Delete(defaultXMLRichDataRichValueRelRels)
f.Pkg.Store(defaultXMLRichDataRichValueRelRels, []byte(fmt.Sprintf(``, SourceRelationshipHyperLink)))
pics, err = f.GetPictures("Sheet1", "A1")
assert.NoError(t, err)
assert.Empty(t, pics)
- // Test get the Microsoft 365 cell images with unsupported charset rich data rich value relationships
+ // Test get the cell images with unsupported charset rich data rich value relationships
f.Relationships.Delete(defaultXMLRichDataRichValueRelRels)
f.Pkg.Store(defaultXMLRichDataRichValueRelRels, MacintoshCyrillicCharset)
pics, err = f.GetPictures("Sheet1", "A1")
assert.NoError(t, err)
assert.Empty(t, pics)
- // Test get the Microsoft 365 cell images with unsupported charset rich data rich value
+ // Test get the cell images with unsupported charset rich data rich value
f.Pkg.Store(defaultXMLRichDataRichValueRel, MacintoshCyrillicCharset)
_, err = f.GetPictures("Sheet1", "A1")
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
- // Test get the Microsoft 365 image cells without block of metadata records
+ // Test get the image cells without block of metadata records
cells, err = f.GetPictureCells("Sheet1")
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
assert.Empty(t, cells)
- // Test get the Microsoft 365 cell images with rich data rich value relationships
+ // Test get the cell images with rich data rich value relationships
f.Pkg.Store(defaultXMLMetadata, []byte(``))
f.Pkg.Store(defaultXMLRichDataRichValueRel, []byte(``))
pics, err = f.GetPictures("Sheet1", "A1")
assert.NoError(t, err)
assert.Empty(t, pics)
- // Test get the Microsoft 365 cell images with unsupported charset meta data
+ // Test get the cell images with unsupported charset meta data
f.Pkg.Store(defaultXMLMetadata, MacintoshCyrillicCharset)
_, err = f.GetPictures("Sheet1", "A1")
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
- // Test get the Microsoft 365 cell images without block of metadata records
+ // Test get the cell images without block of metadata records
f.Pkg.Store(defaultXMLMetadata, []byte(``))
pics, err = f.GetPictures("Sheet1", "A1")
assert.NoError(t, err)
assert.Empty(t, pics)
+
+ f = prepareWorkbook()
+ // Test get the cell images with empty image cell rich value
+ f.Pkg.Store(defaultXMLRichDataRichValue, []byte(`5`))
+ pics, err = f.GetPictures("Sheet1", "A1")
+ assert.EqualError(t, err, "strconv.Atoi: parsing \"\": invalid syntax")
+ assert.Empty(t, pics)
+ // Test get the cell images without image cell rich value
+ f.Pkg.Store(defaultXMLRichDataRichValue, []byte(`01`))
+ pics, err = f.GetPictures("Sheet1", "A1")
+ assert.NoError(t, err)
+ assert.Empty(t, pics)
+ // Test get the cell images with unsupported charset rich value
+ f.Pkg.Store(defaultXMLRichDataRichValue, MacintoshCyrillicCharset)
+ _, err = f.GetPictures("Sheet1", "A1")
+ assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
+
+ f = prepareWorkbook()
+ // Test get the cell images with invalid rich value index
+ f.Pkg.Store(defaultXMLMetadata, []byte(``))
+ pics, err = f.GetPictures("Sheet1", "A1")
+ assert.NoError(t, err)
+ assert.Empty(t, pics)
}
func TestGetImageCells(t *testing.T) {
diff --git a/templates.go b/templates.go
index e097e81..7d72e3b 100644
--- a/templates.go
+++ b/templates.go
@@ -280,6 +280,7 @@ const (
defaultXMLPathVolatileDeps = "xl/volatileDependencies.xml"
defaultXMLPathWorkbook = "xl/workbook.xml"
defaultXMLPathWorkbookRels = "xl/_rels/workbook.xml.rels"
+ defaultXMLRichDataRichValue = "xl/richData/rdrichvalue.xml"
defaultXMLRichDataRichValueRel = "xl/richData/richValueRel.xml"
defaultXMLRichDataRichValueRelRels = "xl/richData/_rels/richValueRel.xml.rels"
)
diff --git a/xmlMetaData.go b/xmlMetaData.go
index e8cf7db..b3f97b6 100644
--- a/xmlMetaData.go
+++ b/xmlMetaData.go
@@ -68,6 +68,23 @@ type xlsxMetadataRecord struct {
V int `xml:"v,attr"`
}
+// xlsxRichValueData directly maps the rvData element that specifies rich value
+// data.
+type xlsxRichValueData struct {
+ XMLName xml.Name `xml:"rvData"`
+ Count int `xml:"count,attr,omitempty"`
+ Rv []xlsxRichValue `xml:"rv"`
+ ExtLst *xlsxInnerXML `xml:"extLst"`
+}
+
+// xlsxRichValue directly maps the rv element that specifies rich value data
+// information for a single rich value
+type xlsxRichValue struct {
+ S int `xml:"s,attr"`
+ V []string `xml:"v"`
+ Fb *xlsxInnerXML `xml:"fb"`
+}
+
// xlsxRichValueRels directly maps the richValueRels element. This element that
// specifies a list of rich value relationships.
type xlsxRichValueRels struct {