- Introduce new exported function GetPictureCells - Upgrade dependencies module golang.org/x/net from 0.16.0 to 0.17.0 - Update unit tests
This commit is contained in:
parent
f752f2ddf4
commit
27f1056929
2
go.mod
2
go.mod
|
@ -11,6 +11,6 @@ require (
|
|||
github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05
|
||||
golang.org/x/crypto v0.14.0
|
||||
golang.org/x/image v0.11.0
|
||||
golang.org/x/net v0.16.0
|
||||
golang.org/x/net v0.17.0
|
||||
golang.org/x/text v0.13.0
|
||||
)
|
||||
|
|
4
go.sum
4
go.sum
|
@ -33,8 +33,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
|||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos=
|
||||
golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
|
166
picture.go
166
picture.go
|
@ -478,6 +478,27 @@ func (f *File) GetPictures(sheet, cell string) ([]Picture, error) {
|
|||
return f.getPicture(row, col, drawingXML, drawingRelationships)
|
||||
}
|
||||
|
||||
// GetPictureCells returns all picture cell references in a worksheet by a
|
||||
// specific worksheet name.
|
||||
func (f *File) GetPictureCells(sheet string) ([]string, error) {
|
||||
f.mu.Lock()
|
||||
ws, err := f.workSheetReader(sheet)
|
||||
if err != nil {
|
||||
f.mu.Unlock()
|
||||
return nil, err
|
||||
}
|
||||
f.mu.Unlock()
|
||||
if ws.Drawing == nil {
|
||||
return nil, err
|
||||
}
|
||||
target := f.getSheetRelationshipsTargetByID(sheet, ws.Drawing.RID)
|
||||
drawingXML := strings.ReplaceAll(target, "..", "xl")
|
||||
drawingRelationships := strings.ReplaceAll(
|
||||
strings.ReplaceAll(target, "../drawings", "xl/drawings/_rels"), ".xml", ".xml.rels")
|
||||
|
||||
return f.getPictureCells(drawingXML, drawingRelationships)
|
||||
}
|
||||
|
||||
// DeletePicture provides a function to delete all pictures in a cell by given
|
||||
// worksheet name and cell reference.
|
||||
func (f *File) DeletePicture(sheet, cell string) error {
|
||||
|
@ -533,58 +554,52 @@ func (f *File) DeletePicture(sheet, cell string) error {
|
|||
// embed in spreadsheet by given coordinates and drawing relationships.
|
||||
func (f *File) getPicture(row, col int, drawingXML, drawingRelationships string) (pics []Picture, err error) {
|
||||
var (
|
||||
ok bool
|
||||
deWsDr *decodeWsDr
|
||||
deCellAnchor *decodeCellAnchor
|
||||
drawRel *xlsxRelationship
|
||||
wsDr *xlsxWsDr
|
||||
deWsDr = new(decodeWsDr)
|
||||
wsDr *xlsxWsDr
|
||||
)
|
||||
|
||||
if wsDr, _, err = f.drawingParser(drawingXML); err != nil {
|
||||
return
|
||||
}
|
||||
pics = f.getPicturesFromWsDr(row, col, drawingRelationships, wsDr)
|
||||
deWsDr = new(decodeWsDr)
|
||||
anchorCond := func(a *xdrCellAnchor) bool { return a.From.Col == col && a.From.Row == row }
|
||||
anchorCb := func(a *xdrCellAnchor, r *xlsxRelationship) {
|
||||
pic := Picture{Extension: filepath.Ext(r.Target), Format: &GraphicOptions{}}
|
||||
if buffer, _ := f.Pkg.Load(strings.ReplaceAll(r.Target, "..", "xl")); buffer != nil {
|
||||
pic.File = buffer.([]byte)
|
||||
pic.Format.AltText = a.Pic.NvPicPr.CNvPr.Descr
|
||||
pics = append(pics, pic)
|
||||
}
|
||||
}
|
||||
f.extractCellAnchor(drawingRelationships, wsDr, anchorCond, anchorCb)
|
||||
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(drawingXML)))).
|
||||
Decode(deWsDr); err != nil && err != io.EOF {
|
||||
return
|
||||
}
|
||||
err = nil
|
||||
extractAnchor := func(anchor *decodeCellAnchor) {
|
||||
deCellAnchor = new(decodeCellAnchor)
|
||||
if err := f.xmlNewDecoder(strings.NewReader("<decodeCellAnchor>" + anchor.Content + "</decodeCellAnchor>")).
|
||||
Decode(deCellAnchor); err != nil && err != io.EOF {
|
||||
return
|
||||
}
|
||||
if err = nil; deCellAnchor.From != nil && deCellAnchor.Pic != nil {
|
||||
if deCellAnchor.From.Col == col && deCellAnchor.From.Row == row {
|
||||
drawRel = f.getDrawingRelationships(drawingRelationships, deCellAnchor.Pic.BlipFill.Blip.Embed)
|
||||
if _, ok = supportedImageTypes[strings.ToLower(filepath.Ext(drawRel.Target))]; ok {
|
||||
pic := Picture{Extension: filepath.Ext(drawRel.Target), Format: &GraphicOptions{}}
|
||||
if buffer, _ := f.Pkg.Load(strings.ReplaceAll(drawRel.Target, "..", "xl")); buffer != nil {
|
||||
pic.File = buffer.([]byte)
|
||||
pic.Format.AltText = deCellAnchor.Pic.NvPicPr.CNvPr.Descr
|
||||
pics = append(pics, pic)
|
||||
}
|
||||
}
|
||||
}
|
||||
decodeAnchorCond := func(a *decodeCellAnchor) bool { return a.From.Col == col && a.From.Row == row }
|
||||
decodeAnchorCb := func(a *decodeCellAnchor, r *xlsxRelationship) {
|
||||
pic := Picture{Extension: filepath.Ext(r.Target), Format: &GraphicOptions{}}
|
||||
if buffer, _ := f.Pkg.Load(strings.ReplaceAll(r.Target, "..", "xl")); buffer != nil {
|
||||
pic.File = buffer.([]byte)
|
||||
pic.Format.AltText = a.Pic.NvPicPr.CNvPr.Descr
|
||||
pics = append(pics, pic)
|
||||
}
|
||||
}
|
||||
for _, anchor := range deWsDr.TwoCellAnchor {
|
||||
extractAnchor(anchor)
|
||||
f.extractDecodeCellAnchor(anchor, drawingRelationships, decodeAnchorCond, decodeAnchorCb)
|
||||
}
|
||||
for _, anchor := range deWsDr.OneCellAnchor {
|
||||
extractAnchor(anchor)
|
||||
f.extractDecodeCellAnchor(anchor, drawingRelationships, decodeAnchorCond, decodeAnchorCb)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// getPicturesFromWsDr provides a function to get picture base name and raw
|
||||
// content in worksheet drawing by given coordinates and drawing
|
||||
// relationships.
|
||||
func (f *File) getPicturesFromWsDr(row, col int, drawingRelationships string, wsDr *xlsxWsDr) (pics []Picture) {
|
||||
// extractCellAnchor extract drawing object from cell anchor by giving drawing
|
||||
// cell anchor, drawing relationships part path, conditional and callback
|
||||
// function.
|
||||
func (f *File) extractCellAnchor(drawingRelationships string, wsDr *xlsxWsDr,
|
||||
cond func(anchor *xdrCellAnchor) bool, cb func(anchor *xdrCellAnchor, rels *xlsxRelationship),
|
||||
) {
|
||||
var (
|
||||
ok bool
|
||||
anchor *xdrCellAnchor
|
||||
drawRel *xlsxRelationship
|
||||
)
|
||||
|
@ -592,22 +607,40 @@ func (f *File) getPicturesFromWsDr(row, col int, drawingRelationships string, ws
|
|||
defer wsDr.mu.Unlock()
|
||||
for _, anchor = range wsDr.TwoCellAnchor {
|
||||
if anchor.From != nil && anchor.Pic != nil {
|
||||
if anchor.From.Col == col && anchor.From.Row == row {
|
||||
if cond(anchor) {
|
||||
if drawRel = f.getDrawingRelationships(drawingRelationships,
|
||||
anchor.Pic.BlipFill.Blip.Embed); drawRel != nil {
|
||||
if _, ok = supportedImageTypes[strings.ToLower(filepath.Ext(drawRel.Target))]; ok {
|
||||
pic := Picture{Extension: filepath.Ext(drawRel.Target), Format: &GraphicOptions{}}
|
||||
if buffer, _ := f.Pkg.Load(strings.ReplaceAll(drawRel.Target, "..", "xl")); buffer != nil {
|
||||
pic.File = buffer.([]byte)
|
||||
pic.Format.AltText = anchor.Pic.NvPicPr.CNvPr.Descr
|
||||
pics = append(pics, pic)
|
||||
}
|
||||
if _, ok := supportedImageTypes[strings.ToLower(filepath.Ext(drawRel.Target))]; ok {
|
||||
cb(anchor, drawRel)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// extractDecodeCellAnchor extract drawing object from cell anchor by giving
|
||||
// decoded drawing cell anchor, drawing relationships part path, conditional and
|
||||
// callback function.
|
||||
func (f *File) extractDecodeCellAnchor(anchor *decodeCellAnchor, drawingRelationships string,
|
||||
cond func(anchor *decodeCellAnchor) bool, cb func(anchor *decodeCellAnchor, rels *xlsxRelationship),
|
||||
) {
|
||||
var (
|
||||
drawRel *xlsxRelationship
|
||||
deCellAnchor = new(decodeCellAnchor)
|
||||
)
|
||||
if err := f.xmlNewDecoder(strings.NewReader("<decodeCellAnchor>" + anchor.Content + "</decodeCellAnchor>")).
|
||||
Decode(deCellAnchor); err != nil && err != io.EOF {
|
||||
return
|
||||
}
|
||||
if deCellAnchor.From != nil && deCellAnchor.Pic != nil {
|
||||
if cond(deCellAnchor) {
|
||||
drawRel = f.getDrawingRelationships(drawingRelationships, deCellAnchor.Pic.BlipFill.Blip.Embed)
|
||||
if _, ok := supportedImageTypes[strings.ToLower(filepath.Ext(drawRel.Target))]; ok {
|
||||
cb(deCellAnchor, drawRel)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getDrawingRelationships provides a function to get drawing relationships
|
||||
|
@ -655,10 +688,7 @@ func (f *File) drawingResize(sheet, cell string, width, height float64, opts *Gr
|
|||
if inMergeCell {
|
||||
continue
|
||||
}
|
||||
if inMergeCell, err = f.checkCellInRangeRef(cell, mergeCell[0]); err != nil {
|
||||
return
|
||||
}
|
||||
if inMergeCell {
|
||||
if inMergeCell, err = f.checkCellInRangeRef(cell, mergeCell[0]); err == nil {
|
||||
rng, _ = cellRefsToCoordinates(mergeCell.GetStartAxis(), mergeCell.GetEndAxis())
|
||||
_ = sortCoordinates(rng)
|
||||
}
|
||||
|
@ -685,3 +715,47 @@ func (f *File) drawingResize(sheet, cell string, width, height float64, opts *Gr
|
|||
w, h = int(width*opts.ScaleX), int(height*opts.ScaleY)
|
||||
return
|
||||
}
|
||||
|
||||
// getPictureCells provides a function to get all picture cell references in a
|
||||
// worksheet by given drawing part path and drawing relationships path.
|
||||
func (f *File) getPictureCells(drawingXML, drawingRelationships string) ([]string, error) {
|
||||
var (
|
||||
cells []string
|
||||
err error
|
||||
deWsDr *decodeWsDr
|
||||
wsDr *xlsxWsDr
|
||||
)
|
||||
if wsDr, _, err = f.drawingParser(drawingXML); err != nil {
|
||||
return cells, err
|
||||
}
|
||||
anchorCond := func(a *xdrCellAnchor) bool { return true }
|
||||
anchorCb := func(a *xdrCellAnchor, r *xlsxRelationship) {
|
||||
if _, ok := f.Pkg.Load(strings.ReplaceAll(r.Target, "..", "xl")); ok {
|
||||
if cell, err := CoordinatesToCellName(a.From.Col+1, a.From.Row+1); err == nil && inStrSlice(cells, cell, true) == -1 {
|
||||
cells = append(cells, cell)
|
||||
}
|
||||
}
|
||||
}
|
||||
f.extractCellAnchor(drawingRelationships, wsDr, anchorCond, anchorCb)
|
||||
deWsDr = new(decodeWsDr)
|
||||
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(drawingXML)))).
|
||||
Decode(deWsDr); err != nil && err != io.EOF {
|
||||
return cells, err
|
||||
}
|
||||
err = nil
|
||||
decodeAnchorCond := func(a *decodeCellAnchor) bool { return true }
|
||||
decodeAnchorCb := func(a *decodeCellAnchor, r *xlsxRelationship) {
|
||||
if _, ok := f.Pkg.Load(strings.ReplaceAll(r.Target, "..", "xl")); ok {
|
||||
if cell, err := CoordinatesToCellName(a.From.Col+1, a.From.Row+1); err == nil && inStrSlice(cells, cell, true) == -1 {
|
||||
cells = append(cells, cell)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, anchor := range deWsDr.TwoCellAnchor {
|
||||
f.extractDecodeCellAnchor(anchor, drawingRelationships, decodeAnchorCond, decodeAnchorCb)
|
||||
}
|
||||
for _, anchor := range deWsDr.OneCellAnchor {
|
||||
f.extractDecodeCellAnchor(anchor, drawingRelationships, decodeAnchorCond, decodeAnchorCb)
|
||||
}
|
||||
return cells, err
|
||||
}
|
||||
|
|
|
@ -62,8 +62,8 @@ func TestAddPicture(t *testing.T) {
|
|||
// Test add picture to worksheet from bytes with illegal cell reference
|
||||
assert.EqualError(t, f.AddPictureFromBytes("Sheet1", "A", &Picture{Extension: ".png", File: file, Format: &GraphicOptions{AltText: "Excel Logo"}}), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
||||
|
||||
for cell, ext := range map[string]string{"Q8": "gif", "Q15": "jpg", "Q22": "tif", "Q28": "bmp"} {
|
||||
assert.NoError(t, f.AddPicture("Sheet1", cell, filepath.Join("test", "images", fmt.Sprintf("excel.%s", ext)), nil))
|
||||
for _, preset := range [][]string{{"Q8", "gif"}, {"Q15", "jpg"}, {"Q22", "tif"}, {"Q28", "bmp"}} {
|
||||
assert.NoError(t, f.AddPicture("Sheet1", preset[0], filepath.Join("test", "images", fmt.Sprintf("excel.%s", preset[1])), nil))
|
||||
}
|
||||
|
||||
// Test write file to given path
|
||||
|
@ -77,6 +77,32 @@ func TestAddPicture(t *testing.T) {
|
|||
pics, err := f.GetPictures("Sheet1", "A30")
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pics, 2)
|
||||
|
||||
// Test get picture cells
|
||||
cells, err := f.GetPictureCells("Sheet1")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{"A30", "F21", "B30", "Q1", "Q8", "Q15", "Q22", "Q28"}, cells)
|
||||
assert.NoError(t, f.Close())
|
||||
|
||||
f, err = OpenFile(filepath.Join("test", "TestAddPicture1.xlsx"))
|
||||
assert.NoError(t, err)
|
||||
path := "xl/drawings/drawing1.xml"
|
||||
f.Drawings.Delete(path)
|
||||
cells, err = f.GetPictureCells("Sheet1")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{"F21", "A30", "B30", "Q1", "Q8", "Q15", "Q22", "Q28"}, cells)
|
||||
// Test get picture cells with unsupported charset
|
||||
f.Pkg.Store(path, MacintoshCyrillicCharset)
|
||||
_, err = f.GetPictureCells("Sheet1")
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
assert.NoError(t, f.Close())
|
||||
|
||||
f, err = OpenFile(filepath.Join("test", "TestAddPicture1.xlsx"))
|
||||
assert.NoError(t, err)
|
||||
// Test get picture cells with unsupported charset
|
||||
f.Pkg.Store(path, MacintoshCyrillicCharset)
|
||||
_, err = f.GetPictureCells("Sheet1")
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
assert.NoError(t, f.Close())
|
||||
|
||||
// Test add picture with unsupported charset content types
|
||||
|
@ -185,6 +211,10 @@ func TestGetPicture(t *testing.T) {
|
|||
pics, err = f.GetPictures("Sheet2", "K16")
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pics, 1)
|
||||
// Try to get picture cells with one cell anchor
|
||||
cells, err := f.GetPictureCells("Sheet2")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{"K16"}, cells)
|
||||
|
||||
// Test get picture from none drawing worksheet
|
||||
f = NewFile()
|
||||
|
@ -344,3 +374,21 @@ func TestAddContentTypePart(t *testing.T) {
|
|||
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.addContentTypePart(0, "unknown"), "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestGetPictureCells(t *testing.T) {
|
||||
f := NewFile()
|
||||
// Test get picture cells on a worksheet which not contains any pictures
|
||||
cells, err := f.GetPictureCells("Sheet1")
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, cells)
|
||||
// Test get picture cells on not exists worksheet
|
||||
_, err = f.GetPictureCells("SheetN")
|
||||
assert.EqualError(t, err, "sheet SheetN does not exist")
|
||||
}
|
||||
|
||||
func TestExtractDecodeCellAnchor(t *testing.T) {
|
||||
f := NewFile()
|
||||
cond := func(a *decodeCellAnchor) bool { return true }
|
||||
cb := func(a *decodeCellAnchor, r *xlsxRelationship) {}
|
||||
f.extractDecodeCellAnchor(&decodeCellAnchor{Content: string(MacintoshCyrillicCharset)}, "", cond, cb)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue