Co-authored-by: liying05 <liying05@zhidemai.com>
This commit is contained in:
parent
dfaf418f34
commit
00d62590f4
11
calc.go
11
calc.go
|
@ -18640,3 +18640,14 @@ func (fn *formulaFuncs) DVAR(argsList *list.List) formulaArg {
|
|||
func (fn *formulaFuncs) DVARP(argsList *list.List) formulaArg {
|
||||
return fn.database("DVARP", argsList)
|
||||
}
|
||||
|
||||
// DISPIMG function calculates the Kingsoft WPS Office embedded image ID. The
|
||||
// syntax of the function is:
|
||||
//
|
||||
// DISPIMG(picture_name,display_mode)
|
||||
func (fn *formulaFuncs) DISPIMG(argsList *list.List) formulaArg {
|
||||
if argsList.Len() != 2 {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "DISPIMG requires 2 numeric arguments")
|
||||
}
|
||||
return argsList.Front().Value.(formulaArg)
|
||||
}
|
||||
|
|
|
@ -2236,6 +2236,8 @@ func TestCalcCellValue(t *testing.T) {
|
|||
// YIELDMAT
|
||||
"=YIELDMAT(\"01/01/2017\",\"06/30/2018\",\"06/01/2014\",5.5%,101)": "0.0419422478838651",
|
||||
"=YIELDMAT(\"01/01/2017\",\"06/30/2018\",\"06/01/2014\",5.5%,101,0)": "0.0419422478838651",
|
||||
// DISPIMG
|
||||
"=_xlfn.DISPIMG(\"ID_********************************\",1)": "ID_********************************",
|
||||
}
|
||||
for formula, expected := range mathCalc {
|
||||
f := prepareCalcData(cellData)
|
||||
|
@ -4609,6 +4611,8 @@ func TestCalcCellValue(t *testing.T) {
|
|||
"=YIELDMAT(\"01/01/2017\",\"06/30/2018\",\"06/01/2014\",-1,101,0)": {"#NUM!", "YIELDMAT requires rate >= 0"},
|
||||
"=YIELDMAT(\"01/01/2017\",\"06/30/2018\",\"06/01/2014\",1,0,0)": {"#NUM!", "YIELDMAT requires pr > 0"},
|
||||
"=YIELDMAT(\"01/01/2017\",\"06/30/2018\",\"06/01/2014\",5.5%,101,5)": {"#NUM!", "invalid basis"},
|
||||
// DISPIMG
|
||||
"=_xlfn.DISPIMG()": {"#VALUE!", "DISPIMG requires 2 numeric arguments"},
|
||||
}
|
||||
for formula, expected := range mathCalcError {
|
||||
f := prepareCalcData(cellData)
|
||||
|
|
10
chart.go
10
chart.go
|
@ -892,9 +892,9 @@ func (opts *Chart) parseTitle() {
|
|||
// The default width is 480, and height is 260.
|
||||
//
|
||||
// Set the bubble size in all data series for the bubble chart or 3D bubble
|
||||
// chart by 'BubbleSizes' property. The 'BubbleSizes' property is optional.
|
||||
// The default width is 100, and the value should be great than 0 and less or
|
||||
// equal than 300.
|
||||
// chart by 'BubbleSizes' property. The 'BubbleSizes' property is optional. The
|
||||
// default width is 100, and the value should be great than 0 and less or equal
|
||||
// than 300.
|
||||
//
|
||||
// Set the doughnut hole size in all data series for the doughnut chart by
|
||||
// 'HoleSize' property. The 'HoleSize' property is optional. The default width
|
||||
|
@ -932,7 +932,7 @@ func (opts *Chart) parseTitle() {
|
|||
// }
|
||||
// enable, disable := true, false
|
||||
// if err := f.AddChart("Sheet1", "E1", &excelize.Chart{
|
||||
// Type: "col",
|
||||
// Type: excelize.Col,
|
||||
// Series: []excelize.ChartSeries{
|
||||
// {
|
||||
// Name: "Sheet1!$A$2",
|
||||
|
@ -966,7 +966,7 @@ func (opts *Chart) parseTitle() {
|
|||
// ShowVal: true,
|
||||
// },
|
||||
// }, &excelize.Chart{
|
||||
// Type: "line",
|
||||
// Type: excelize.Line,
|
||||
// Series: []excelize.ChartSeries{
|
||||
// {
|
||||
// Name: "Sheet1!$A$4",
|
||||
|
|
|
@ -43,6 +43,7 @@ type File struct {
|
|||
Comments map[string]*xlsxComments
|
||||
ContentTypes *xlsxTypes
|
||||
DecodeVMLDrawing map[string]*decodeVmlDrawing
|
||||
DecodeCellImages *decodeCellImages
|
||||
Drawings sync.Map
|
||||
Path string
|
||||
Pkg sync.Map
|
||||
|
|
66
picture.go
66
picture.go
|
@ -15,6 +15,7 @@ import (
|
|||
"bytes"
|
||||
"encoding/xml"
|
||||
"image"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
@ -467,14 +468,22 @@ func (f *File) GetPictures(sheet, cell string) ([]Picture, error) {
|
|||
}
|
||||
f.mu.Unlock()
|
||||
if ws.Drawing == nil {
|
||||
return nil, err
|
||||
return f.getCellImages(sheet, cell)
|
||||
}
|
||||
target := f.getSheetRelationshipsTargetByID(sheet, ws.Drawing.RID)
|
||||
drawingXML := strings.TrimPrefix(strings.ReplaceAll(target, "..", "xl"), "/")
|
||||
drawingRelationships := strings.ReplaceAll(
|
||||
strings.ReplaceAll(target, "../drawings", "xl/drawings/_rels"), ".xml", ".xml.rels")
|
||||
|
||||
return f.getPicture(row, col, drawingXML, drawingRelationships)
|
||||
imgs, err := f.getCellImages(sheet, cell)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pics, err := f.getPicture(row, col, drawingXML, drawingRelationships)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append(imgs, pics...), err
|
||||
}
|
||||
|
||||
// GetPictureCells returns all picture cell references in a worksheet by a
|
||||
|
@ -741,3 +750,56 @@ func (f *File) getPictureCells(drawingXML, drawingRelationships string) ([]strin
|
|||
}
|
||||
return cells, err
|
||||
}
|
||||
|
||||
// cellImagesReader provides a function to get the pointer to the structure
|
||||
// after deserialization of xl/cellimages.xml.
|
||||
func (f *File) cellImagesReader() (*decodeCellImages, error) {
|
||||
if f.DecodeCellImages == nil {
|
||||
f.DecodeCellImages = new(decodeCellImages)
|
||||
if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLPathCellImages)))).
|
||||
Decode(f.DecodeCellImages); err != nil && err != io.EOF {
|
||||
return f.DecodeCellImages, err
|
||||
}
|
||||
}
|
||||
return f.DecodeCellImages, nil
|
||||
}
|
||||
|
||||
// getCellImages provides a function to get the Kingsoft WPS Office embedded
|
||||
// cell images by given worksheet name and cell reference.
|
||||
func (f *File) getCellImages(sheet, cell string) ([]Picture, error) {
|
||||
formula, err := f.GetCellFormula(sheet, cell)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !strings.HasPrefix(strings.TrimPrefix(strings.TrimPrefix(formula, "="), "_xlfn."), "DISPIMG") {
|
||||
return nil, err
|
||||
}
|
||||
imgID, err := f.CalcCellValue(sheet, cell)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cellImages, err := f.cellImagesReader()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rels, err := f.relsReader(defaultXMLPathCellImagesRels)
|
||||
if rels == nil {
|
||||
return nil, err
|
||||
}
|
||||
var pics []Picture
|
||||
for _, cellImg := range cellImages.CellImage {
|
||||
if cellImg.Pic.NvPicPr.CNvPr.Name == imgID {
|
||||
for _, r := range rels.Relationships {
|
||||
if r.ID == cellImg.Pic.BlipFill.Blip.Embed {
|
||||
pic := Picture{Extension: filepath.Ext(r.Target), Format: &GraphicOptions{}}
|
||||
if buffer, _ := f.Pkg.Load("xl/" + r.Target); buffer != nil {
|
||||
pic.File = buffer.([]byte)
|
||||
pic.Format.AltText = cellImg.Pic.NvPicPr.CNvPr.Descr
|
||||
pics = append(pics, pic)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return pics, err
|
||||
}
|
||||
|
|
|
@ -216,6 +216,7 @@ func TestGetPicture(t *testing.T) {
|
|||
cells, err := f.GetPictureCells("Sheet2")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{"K16"}, cells)
|
||||
assert.NoError(t, f.Close())
|
||||
|
||||
// Test get picture from none drawing worksheet
|
||||
f = NewFile()
|
||||
|
@ -229,11 +230,41 @@ func TestGetPicture(t *testing.T) {
|
|||
path := "xl/drawings/drawing1.xml"
|
||||
f.Drawings.Delete(path)
|
||||
f.Pkg.Store(path, MacintoshCyrillicCharset)
|
||||
_, err = f.GetPictures("Sheet1", "F21")
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
_, err = f.getPicture(20, 5, path, "xl/drawings/_rels/drawing2.xml.rels")
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
f.Drawings.Delete(path)
|
||||
_, err = f.getPicture(20, 5, path, "xl/drawings/_rels/drawing2.xml.rels")
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
assert.NoError(t, f.Close())
|
||||
|
||||
// Test get embedded cell pictures
|
||||
f, err = OpenFile(filepath.Join("test", "TestGetPicture.xlsx"))
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, f.SetCellFormula("Sheet1", "F21", "=_xlfn.DISPIMG(\"ID_********************************\",1)"))
|
||||
f.Pkg.Store(defaultXMLPathCellImages, []byte(`<etc:cellImages xmlns:etc="http://www.wps.cn/officeDocument/2017/etCustomData"><etc:cellImage><xdr:pic><xdr:nvPicPr><xdr:cNvPr id="1" name="ID_********************************" descr="CellImage1"/></xdr:nvPicPr><xdr:blipFill><a:blip r:embed="rId1"/></xdr:blipFill></xdr:pic></etc:cellImage></etc:cellImages>`))
|
||||
f.Pkg.Store(defaultXMLPathCellImagesRels, []byte(`<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/image1.jpeg"/></Relationships>`))
|
||||
pics, err = f.GetPictures("Sheet1", "F21")
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pics, 2)
|
||||
assert.Equal(t, "CellImage1", pics[0].Format.AltText)
|
||||
|
||||
// Test get embedded cell pictures with invalid formula
|
||||
assert.NoError(t, f.SetCellFormula("Sheet1", "A1", "=_xlfn.DISPIMG()"))
|
||||
_, err = f.GetPictures("Sheet1", "A1")
|
||||
assert.EqualError(t, err, "DISPIMG requires 2 numeric arguments")
|
||||
|
||||
// Test get embedded cell pictures with unsupported charset
|
||||
f.Relationships.Delete(defaultXMLPathCellImagesRels)
|
||||
f.Pkg.Store(defaultXMLPathCellImagesRels, MacintoshCyrillicCharset)
|
||||
_, err = f.GetPictures("Sheet1", "F21")
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
f.Pkg.Store(defaultXMLPathCellImages, MacintoshCyrillicCharset)
|
||||
f.DecodeCellImages = nil
|
||||
_, err = f.GetPictures("Sheet1", "F21")
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
assert.NoError(t, f.Close())
|
||||
}
|
||||
|
||||
func TestAddDrawingPicture(t *testing.T) {
|
||||
|
@ -394,3 +425,12 @@ func TestExtractDecodeCellAnchor(t *testing.T) {
|
|||
cb := func(a *decodeCellAnchor, r *xlsxRelationship) {}
|
||||
f.extractDecodeCellAnchor(&xdrCellAnchor{GraphicFrame: string(MacintoshCyrillicCharset)}, "", cond, cb)
|
||||
}
|
||||
|
||||
func TestGetCellImages(t *testing.T) {
|
||||
f := NewFile()
|
||||
f.Sheet.Delete("xl/worksheets/sheet1.xml")
|
||||
f.Pkg.Store("xl/worksheets/sheet1.xml", MacintoshCyrillicCharset)
|
||||
_, err := f.getCellImages("Sheet1", "A1")
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
assert.NoError(t, f.Close())
|
||||
}
|
||||
|
|
24
templates.go
24
templates.go
|
@ -266,17 +266,19 @@ var supportedChartDataLabelsPosition = map[ChartType][]ChartDataLabelPositionTyp
|
|||
}
|
||||
|
||||
const (
|
||||
defaultTempFileSST = "sharedStrings"
|
||||
defaultXMLPathCalcChain = "xl/calcChain.xml"
|
||||
defaultXMLPathContentTypes = "[Content_Types].xml"
|
||||
defaultXMLPathDocPropsApp = "docProps/app.xml"
|
||||
defaultXMLPathDocPropsCore = "docProps/core.xml"
|
||||
defaultXMLPathSharedStrings = "xl/sharedStrings.xml"
|
||||
defaultXMLPathStyles = "xl/styles.xml"
|
||||
defaultXMLPathTheme = "xl/theme/theme1.xml"
|
||||
defaultXMLPathVolatileDeps = "xl/volatileDependencies.xml"
|
||||
defaultXMLPathWorkbook = "xl/workbook.xml"
|
||||
defaultXMLPathWorkbookRels = "xl/_rels/workbook.xml.rels"
|
||||
defaultTempFileSST = "sharedStrings"
|
||||
defaultXMLPathCalcChain = "xl/calcChain.xml"
|
||||
defaultXMLPathCellImages = "xl/cellimages.xml"
|
||||
defaultXMLPathCellImagesRels = "xl/_rels/cellimages.xml.rels"
|
||||
defaultXMLPathContentTypes = "[Content_Types].xml"
|
||||
defaultXMLPathDocPropsApp = "docProps/app.xml"
|
||||
defaultXMLPathDocPropsCore = "docProps/core.xml"
|
||||
defaultXMLPathSharedStrings = "xl/sharedStrings.xml"
|
||||
defaultXMLPathStyles = "xl/styles.xml"
|
||||
defaultXMLPathTheme = "xl/theme/theme1.xml"
|
||||
defaultXMLPathVolatileDeps = "xl/volatileDependencies.xml"
|
||||
defaultXMLPathWorkbook = "xl/workbook.xml"
|
||||
defaultXMLPathWorkbookRels = "xl/_rels/workbook.xml.rels"
|
||||
)
|
||||
|
||||
// IndexedColorMapping is the table of default mappings from indexed color value
|
||||
|
|
|
@ -83,7 +83,7 @@ type decodeCNvSpPr struct {
|
|||
// changed after serialization and deserialization, two different structures
|
||||
// are defined. decodeWsDr just for deserialization.
|
||||
type decodeWsDr struct {
|
||||
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing wsDr,omitempty"`
|
||||
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing wsDr"`
|
||||
A string `xml:"xmlns a,attr"`
|
||||
Xdr string `xml:"xmlns xdr,attr"`
|
||||
R string `xml:"xmlns r,attr"`
|
||||
|
@ -242,3 +242,15 @@ type decodeClientData struct {
|
|||
FLocksWithSheet bool `xml:"fLocksWithSheet,attr"`
|
||||
FPrintsWithSheet bool `xml:"fPrintsWithSheet,attr"`
|
||||
}
|
||||
|
||||
// decodeCellImages directly maps the Kingsoft WPS Office embedded cell images.
|
||||
type decodeCellImages struct {
|
||||
XMLName xml.Name `xml:"http://www.wps.cn/officeDocument/2017/etCustomData cellImages"`
|
||||
CellImage []decodeCellImage `xml:"cellImage"`
|
||||
}
|
||||
|
||||
// decodeCellImage defines the structure used to deserialize the Kingsoft WPS
|
||||
// Office embedded cell images.
|
||||
type decodeCellImage struct {
|
||||
Pic decodePic `xml:"pic"`
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue