Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xuri
excelize
提交
00d62590
excelize
项目概览
xuri
/
excelize
通知
13
Star
2
Fork
4
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
excelize
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
未验证
提交
00d62590
编写于
12月 15, 2023
作者:
L
li
提交者:
GitHub
12月 15, 2023
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
This closes #664, support get embedded cell images (#1759)
Co-authored-by:
N
liying05
<
liying05@zhidemai.com
>
上级
dfaf418f
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
151 addition
and
19 deletion
+151
-19
calc.go
calc.go
+11
-0
calc_test.go
calc_test.go
+4
-0
chart.go
chart.go
+5
-5
excelize.go
excelize.go
+1
-0
picture.go
picture.go
+64
-2
picture_test.go
picture_test.go
+40
-0
templates.go
templates.go
+13
-11
xmlDecodeDrawing.go
xmlDecodeDrawing.go
+13
-1
未找到文件。
calc.go
浏览文件 @
00d62590
...
...
@@ -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)
}
calc_test.go
浏览文件 @
00d62590
...
...
@@ -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
)
...
...
chart.go
浏览文件 @
00d62590
...
...
@@ -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",
...
...
excelize.go
浏览文件 @
00d62590
...
...
@@ -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
...
...
picture.go
浏览文件 @
00d62590
...
...
@@ -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
}
picture_test.go
浏览文件 @
00d62590
...
...
@@ -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
())
}
templates.go
浏览文件 @
00d62590
...
...
@@ -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
...
...
xmlDecodeDrawing.go
浏览文件 @
00d62590
...
...
@@ -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"`
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录