From 0c3fd0223c784ddcc7d2442105b920587b970727 Mon Sep 17 00:00:00 2001 From: xuri Date: Fri, 13 May 2022 01:03:40 +0800 Subject: [PATCH] This closes #1225, allowing insert EMF format images --- picture.go | 29 +++++++++++++---------------- picture_test.go | 13 +++++++++++-- sheet.go | 2 +- test/images/excel.emf | Bin 0 -> 12020 bytes xmlDrawing.go | 3 ++- 5 files changed, 27 insertions(+), 20 deletions(-) create mode 100644 test/images/excel.emf diff --git a/picture.go b/picture.go index 5e8f6b8..f8133ca 100644 --- a/picture.go +++ b/picture.go @@ -113,7 +113,7 @@ func (f *File) AddPicture(sheet, cell, picture, format string) error { if _, err = os.Stat(picture); os.IsNotExist(err) { return err } - ext, ok := supportImageTypes[path.Ext(picture)] + ext, ok := supportedImageTypes[path.Ext(picture)] if !ok { return ErrImgExt } @@ -154,7 +154,7 @@ func (f *File) AddPicture(sheet, cell, picture, format string) error { func (f *File) AddPictureFromBytes(sheet, cell, format, name, extension string, file []byte) error { var drawingHyperlinkRID int var hyperlinkType string - ext, ok := supportImageTypes[extension] + ext, ok := supportedImageTypes[extension] if !ok { return ErrImgExt } @@ -366,23 +366,20 @@ func (f *File) addMedia(file []byte, ext string) string { // setContentTypePartImageExtensions provides a function to set the content // type for relationship parts and the Main Document part. func (f *File) setContentTypePartImageExtensions() { - imageTypes := map[string]bool{"jpeg": false, "png": false, "gif": false, "tiff": false} + imageTypes := map[string]string{"jpeg": "image/", "png": "image/", "gif": "image/", "tiff": "image/", "emf": "image/x-"} content := f.contentTypesReader() content.Lock() defer content.Unlock() - for _, v := range content.Defaults { - _, ok := imageTypes[v.Extension] - if ok { - imageTypes[v.Extension] = true + for _, file := range content.Defaults { + if _, ok := imageTypes[file.Extension]; ok { + delete(imageTypes, file.Extension) } } - for k, v := range imageTypes { - if !v { - content.Defaults = append(content.Defaults, xlsxDefault{ - Extension: k, - ContentType: "image/" + k, - }) - } + for extension, prefix := range imageTypes { + content.Defaults = append(content.Defaults, xlsxDefault{ + Extension: extension, + ContentType: prefix + extension, + }) } } @@ -576,7 +573,7 @@ func (f *File) getPicture(row, col int, drawingXML, drawingRelationships string) if err = nil; deTwoCellAnchor.From != nil && deTwoCellAnchor.Pic != nil { if deTwoCellAnchor.From.Col == col && deTwoCellAnchor.From.Row == row { drawRel = f.getDrawingRelationships(drawingRelationships, deTwoCellAnchor.Pic.BlipFill.Blip.Embed) - if _, ok = supportImageTypes[filepath.Ext(drawRel.Target)]; ok { + if _, ok = supportedImageTypes[filepath.Ext(drawRel.Target)]; ok { ret = filepath.Base(drawRel.Target) if buffer, _ := f.Pkg.Load(strings.Replace(drawRel.Target, "..", "xl", -1)); buffer != nil { buf = buffer.([]byte) @@ -605,7 +602,7 @@ func (f *File) getPictureFromWsDr(row, col int, drawingRelationships string, wsD if anchor.From.Col == col && anchor.From.Row == row { if drawRel = f.getDrawingRelationships(drawingRelationships, anchor.Pic.BlipFill.Blip.Embed); drawRel != nil { - if _, ok = supportImageTypes[filepath.Ext(drawRel.Target)]; ok { + if _, ok = supportedImageTypes[filepath.Ext(drawRel.Target)]; ok { ret = filepath.Base(drawRel.Target) if buffer, _ := f.Pkg.Load(strings.Replace(drawRel.Target, "..", "xl", -1)); buffer != nil { buf = buffer.([]byte) diff --git a/picture_test.go b/picture_test.go index fbbdf11..c548035 100644 --- a/picture_test.go +++ b/picture_test.go @@ -2,9 +2,11 @@ package excelize import ( "fmt" + "image" _ "image/gif" _ "image/jpeg" _ "image/png" + "io" "io/ioutil" "os" "path/filepath" @@ -66,7 +68,7 @@ func TestAddPicture(t *testing.T) { assert.NoError(t, f.AddPicture("Sheet1", "Q22", filepath.Join("test", "images", "excel.tif"), "")) // Test write file to given path. - assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddPicture.xlsx"))) + assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddPicture1.xlsx"))) assert.NoError(t, f.Close()) } @@ -89,7 +91,14 @@ func TestAddPictureErrors(t *testing.T) { // Test add picture to worksheet with invalid file data. err = f.AddPictureFromBytes("Sheet1", "G21", "", "Excel Logo", ".jpg", make([]byte, 1)) - assert.EqualError(t, err, "image: unknown format") + assert.EqualError(t, err, image.ErrFormat.Error()) + + // Test add picture with custom image decoder and encoder. + decode := func(r io.Reader) (image.Image, error) { return nil, nil } + decodeConfig := func(r io.Reader) (image.Config, error) { return image.Config{Height: 100, Width: 90}, nil } + image.RegisterFormat("emf", "", decode, decodeConfig) + assert.NoError(t, f.AddPicture("Sheet1", "Q1", filepath.Join("test", "images", "excel.emf"), "")) + assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddPicture2.xlsx"))) assert.NoError(t, f.Close()) } diff --git a/sheet.go b/sheet.go index 3986cd8..4665fd9 100644 --- a/sheet.go +++ b/sheet.go @@ -463,7 +463,7 @@ func (f *File) SetSheetBackground(sheet, picture string) error { if _, err = os.Stat(picture); os.IsNotExist(err) { return err } - ext, ok := supportImageTypes[path.Ext(picture)] + ext, ok := supportedImageTypes[path.Ext(picture)] if !ok { return ErrImgExt } diff --git a/test/images/excel.emf b/test/images/excel.emf new file mode 100644 index 0000000000000000000000000000000000000000..9daa6de8b2ffc18f05d94a66460a94a0fb119ae3 GIT binary patch literal 12020 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 K60?=~_5TA5L<>y- literal 0 HcmV?d00001 diff --git a/xmlDrawing.go b/xmlDrawing.go index d6d6135..7d0b2df 100644 --- a/xmlDrawing.go +++ b/xmlDrawing.go @@ -118,7 +118,8 @@ const ( pivotTableVersion = 3 ) -var supportImageTypes = map[string]string{".gif": ".gif", ".jpg": ".jpeg", ".jpeg": ".jpeg", ".png": ".png", ".tif": ".tiff", ".tiff": ".tiff"} +// supportedImageTypes defined supported image types. +var supportedImageTypes = map[string]string{".gif": ".gif", ".jpg": ".jpeg", ".jpeg": ".jpeg", ".png": ".png", ".tif": ".tiff", ".tiff": ".tiff", ".emf": ".emf"} // xlsxCNvPr directly maps the cNvPr (Non-Visual Drawing Properties). This // element specifies non-visual canvas properties. This allows for additional