forked from p30928647/excelize
Resolve #274, performance optimization for add images, charts and shapes
This commit is contained in:
parent
1427027e38
commit
1aed1d744b
52
chart.go
52
chart.go
|
@ -1207,28 +1207,34 @@ func (f *File) drawPlotAreaTxPr() *cTxPr {
|
|||
// the problem that the label structure is changed after serialization and
|
||||
// deserialization, two different structures: decodeWsDr and encodeWsDr are
|
||||
// defined.
|
||||
func (f *File) drawingParser(drawingXML string, content *xlsxWsDr) int {
|
||||
func (f *File) drawingParser(path string) (*xlsxWsDr, int) {
|
||||
cNvPrID := 1
|
||||
_, ok := f.XLSX[drawingXML]
|
||||
if ok { // Append Model
|
||||
decodeWsDr := decodeWsDr{}
|
||||
_ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(drawingXML)), &decodeWsDr)
|
||||
content.R = decodeWsDr.R
|
||||
cNvPrID = len(decodeWsDr.OneCellAnchor) + len(decodeWsDr.TwoCellAnchor) + 1
|
||||
for _, v := range decodeWsDr.OneCellAnchor {
|
||||
content.OneCellAnchor = append(content.OneCellAnchor, &xdrCellAnchor{
|
||||
EditAs: v.EditAs,
|
||||
GraphicFrame: v.Content,
|
||||
})
|
||||
}
|
||||
for _, v := range decodeWsDr.TwoCellAnchor {
|
||||
content.TwoCellAnchor = append(content.TwoCellAnchor, &xdrCellAnchor{
|
||||
EditAs: v.EditAs,
|
||||
GraphicFrame: v.Content,
|
||||
})
|
||||
if f.Drawings[path] == nil {
|
||||
content := xlsxWsDr{}
|
||||
content.A = NameSpaceDrawingML
|
||||
content.Xdr = NameSpaceDrawingMLSpreadSheet
|
||||
_, ok := f.XLSX[path]
|
||||
if ok { // Append Model
|
||||
decodeWsDr := decodeWsDr{}
|
||||
_ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(path)), &decodeWsDr)
|
||||
content.R = decodeWsDr.R
|
||||
cNvPrID = len(decodeWsDr.OneCellAnchor) + len(decodeWsDr.TwoCellAnchor) + 1
|
||||
for _, v := range decodeWsDr.OneCellAnchor {
|
||||
content.OneCellAnchor = append(content.OneCellAnchor, &xdrCellAnchor{
|
||||
EditAs: v.EditAs,
|
||||
GraphicFrame: v.Content,
|
||||
})
|
||||
}
|
||||
for _, v := range decodeWsDr.TwoCellAnchor {
|
||||
content.TwoCellAnchor = append(content.TwoCellAnchor, &xdrCellAnchor{
|
||||
EditAs: v.EditAs,
|
||||
GraphicFrame: v.Content,
|
||||
})
|
||||
}
|
||||
}
|
||||
f.Drawings[path] = &content
|
||||
}
|
||||
return cNvPrID
|
||||
return f.Drawings[path], cNvPrID
|
||||
}
|
||||
|
||||
// addDrawingChart provides a function to add chart graphic frame by given
|
||||
|
@ -1242,10 +1248,7 @@ func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rI
|
|||
width = int(float64(width) * formatSet.XScale)
|
||||
height = int(float64(height) * formatSet.YScale)
|
||||
colStart, rowStart, _, _, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, col, row, formatSet.OffsetX, formatSet.OffsetY, width, height)
|
||||
content := xlsxWsDr{}
|
||||
content.A = NameSpaceDrawingML
|
||||
content.Xdr = NameSpaceDrawingMLSpreadSheet
|
||||
cNvPrID := f.drawingParser(drawingXML, &content)
|
||||
content, cNvPrID := f.drawingParser(drawingXML)
|
||||
twoCellAnchor := xdrCellAnchor{}
|
||||
twoCellAnchor.EditAs = formatSet.Positioning
|
||||
from := xlsxFrom{}
|
||||
|
@ -1286,6 +1289,5 @@ func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rI
|
|||
FPrintsWithSheet: formatSet.FPrintsWithSheet,
|
||||
}
|
||||
content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
|
||||
output, _ := xml.Marshal(content)
|
||||
f.saveFileList(drawingXML, output)
|
||||
f.Drawings[drawingXML] = content
|
||||
}
|
||||
|
|
|
@ -33,10 +33,7 @@ func parseFormatCommentsSet(formatSet string) (*formatComment, error) {
|
|||
func (f *File) GetComments() (comments map[string][]Comment) {
|
||||
comments = map[string][]Comment{}
|
||||
for n := range f.sheetMap {
|
||||
c, ok := f.XLSX["xl"+strings.TrimPrefix(f.getSheetComments(f.GetSheetIndex(n)), "..")]
|
||||
if ok {
|
||||
d := xlsxComments{}
|
||||
xml.Unmarshal([]byte(c), &d)
|
||||
if d := f.commentsReader("xl" + strings.TrimPrefix(f.getSheetComments(f.GetSheetIndex(n)), "..")); d != nil {
|
||||
sheetComments := []Comment{}
|
||||
for _, comment := range d.CommentList.Comment {
|
||||
sheetComment := Comment{}
|
||||
|
@ -294,7 +291,7 @@ func (f *File) decodeVMLDrawingReader(path string) *decodeVmlDrawing {
|
|||
return f.DecodeVMLDrawing[path]
|
||||
}
|
||||
|
||||
// vmlDrawingWriter provides a function to save xl/drawings/vmlDrawing%d.xml.
|
||||
// vmlDrawingWriter provides a function to save xl/drawings/vmlDrawing%d.xml
|
||||
// after serialize structure.
|
||||
func (f *File) vmlDrawingWriter() {
|
||||
for path, vml := range f.VMLDrawing {
|
||||
|
|
|
@ -28,6 +28,8 @@ type File struct {
|
|||
CalcChain *xlsxCalcChain
|
||||
Comments map[string]*xlsxComments
|
||||
ContentTypes *xlsxTypes
|
||||
DrawingRels map[string]*xlsxWorkbookRels
|
||||
Drawings map[string]*xlsxWsDr
|
||||
Path string
|
||||
SharedStrings *xlsxSST
|
||||
Sheet map[string]*xlsxWorksheet
|
||||
|
@ -76,6 +78,8 @@ func OpenReader(r io.Reader) (*File, error) {
|
|||
f := &File{
|
||||
checked: make(map[string]bool),
|
||||
Comments: make(map[string]*xlsxComments),
|
||||
DrawingRels: make(map[string]*xlsxWorkbookRels),
|
||||
Drawings: make(map[string]*xlsxWsDr),
|
||||
Sheet: make(map[string]*xlsxWorksheet),
|
||||
SheetCount: sheetCount,
|
||||
DecodeVMLDrawing: make(map[string]*decodeVmlDrawing),
|
||||
|
|
|
@ -817,6 +817,24 @@ func TestGetPicture(t *testing.T) {
|
|||
xlsx.getDrawingRelationships("", "")
|
||||
xlsx.getSheetRelationshipsTargetByID("", "")
|
||||
xlsx.deleteSheetRelationships("", "")
|
||||
|
||||
// Try to get picture from a local storage file.
|
||||
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestGetPicture.xlsx")))
|
||||
xlsx, err = OpenFile(filepath.Join("test", "TestGetPicture.xlsx"))
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
file, raw = xlsx.GetPicture("Sheet1", "F21")
|
||||
if file == "" {
|
||||
err = ioutil.WriteFile(file, raw, 0644)
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// Try to get picture from a local storage file that doesn't contain an image.
|
||||
file, raw = xlsx.GetPicture("Sheet1", "F22")
|
||||
t.Log(file, len(raw))
|
||||
}
|
||||
|
||||
func TestSheetVisibility(t *testing.T) {
|
||||
|
|
4
file.go
4
file.go
|
@ -42,6 +42,8 @@ func NewFile() *File {
|
|||
f.CalcChain = f.calcChainReader()
|
||||
f.Comments = make(map[string]*xlsxComments)
|
||||
f.ContentTypes = f.contentTypesReader()
|
||||
f.DrawingRels = make(map[string]*xlsxWorkbookRels)
|
||||
f.Drawings = make(map[string]*xlsxWsDr)
|
||||
f.Styles = f.stylesReader()
|
||||
f.DecodeVMLDrawing = make(map[string]*decodeVmlDrawing)
|
||||
f.VMLDrawing = make(map[string]*vmlDrawing)
|
||||
|
@ -94,6 +96,8 @@ func (f *File) WriteToBuffer() (*bytes.Buffer, error) {
|
|||
f.calcChainWriter()
|
||||
f.commentsWriter()
|
||||
f.contentTypesWriter()
|
||||
f.drawingRelsWriter()
|
||||
f.drawingsWriter()
|
||||
f.vmlDrawingWriter()
|
||||
f.workbookWriter()
|
||||
f.workbookRelsWriter()
|
||||
|
|
104
picture.go
104
picture.go
|
@ -272,10 +272,7 @@ func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, he
|
|||
width = int(float64(width) * formatSet.XScale)
|
||||
height = int(float64(height) * formatSet.YScale)
|
||||
colStart, rowStart, _, _, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, col, row, formatSet.OffsetX, formatSet.OffsetY, width, height)
|
||||
content := xlsxWsDr{}
|
||||
content.A = NameSpaceDrawingML
|
||||
content.Xdr = NameSpaceDrawingMLSpreadSheet
|
||||
cNvPrID := f.drawingParser(drawingXML, &content)
|
||||
content, cNvPrID := f.drawingParser(drawingXML)
|
||||
twoCellAnchor := xdrCellAnchor{}
|
||||
twoCellAnchor.EditAs = formatSet.Positioning
|
||||
from := xlsxFrom{}
|
||||
|
@ -311,8 +308,7 @@ func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, he
|
|||
FPrintsWithSheet: formatSet.FPrintsWithSheet,
|
||||
}
|
||||
content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
|
||||
output, _ := xml.Marshal(content)
|
||||
f.saveFileList(drawingXML, output)
|
||||
f.Drawings[drawingXML] = content
|
||||
}
|
||||
|
||||
// addDrawingRelationships provides a function to add image part relationships
|
||||
|
@ -320,27 +316,25 @@ func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, he
|
|||
// relationship type and target.
|
||||
func (f *File) addDrawingRelationships(index int, relType, target, targetMode string) int {
|
||||
var rels = "xl/drawings/_rels/drawing" + strconv.Itoa(index) + ".xml.rels"
|
||||
var drawingRels xlsxWorkbookRels
|
||||
var rID = 1
|
||||
var ID bytes.Buffer
|
||||
ID.WriteString("rId")
|
||||
ID.WriteString(strconv.Itoa(rID))
|
||||
_, ok := f.XLSX[rels]
|
||||
if ok {
|
||||
ID.Reset()
|
||||
_ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(rels)), &drawingRels)
|
||||
rID = len(drawingRels.Relationships) + 1
|
||||
ID.WriteString("rId")
|
||||
ID.WriteString(strconv.Itoa(rID))
|
||||
drawingRels := f.drawingRelsReader(rels)
|
||||
if drawingRels == nil {
|
||||
drawingRels = &xlsxWorkbookRels{}
|
||||
}
|
||||
ID.Reset()
|
||||
rID = len(drawingRels.Relationships) + 1
|
||||
ID.WriteString("rId")
|
||||
ID.WriteString(strconv.Itoa(rID))
|
||||
drawingRels.Relationships = append(drawingRels.Relationships, xlsxWorkbookRelation{
|
||||
ID: ID.String(),
|
||||
Type: relType,
|
||||
Target: target,
|
||||
TargetMode: targetMode,
|
||||
})
|
||||
output, _ := xml.Marshal(drawingRels)
|
||||
f.saveFileList(rels, output)
|
||||
f.DrawingRels[rels] = drawingRels
|
||||
return rID
|
||||
}
|
||||
|
||||
|
@ -482,22 +476,30 @@ func (f *File) GetPicture(sheet, cell string) (string, []byte) {
|
|||
}
|
||||
target := f.getSheetRelationshipsTargetByID(sheet, xlsx.Drawing.RID)
|
||||
drawingXML := strings.Replace(target, "..", "xl", -1)
|
||||
|
||||
cell = strings.ToUpper(cell)
|
||||
fromCol := string(strings.Map(letterOnlyMapF, cell))
|
||||
fromRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, cell))
|
||||
row := fromRow - 1
|
||||
col := TitleToNumber(fromCol)
|
||||
drawingRelationships := strings.Replace(strings.Replace(target, "../drawings", "xl/drawings/_rels", -1), ".xml", ".xml.rels", -1)
|
||||
wsDr, _ := f.drawingParser(drawingXML)
|
||||
for _, anchor := range wsDr.TwoCellAnchor {
|
||||
if anchor.From != nil && anchor.Pic != nil {
|
||||
if anchor.From.Col == col && anchor.From.Row == row {
|
||||
xlsxWorkbookRelation := f.getDrawingRelationships(drawingRelationships, anchor.Pic.BlipFill.Blip.Embed)
|
||||
_, ok := supportImageTypes[filepath.Ext(xlsxWorkbookRelation.Target)]
|
||||
if ok {
|
||||
return filepath.Base(xlsxWorkbookRelation.Target), []byte(f.XLSX[strings.Replace(xlsxWorkbookRelation.Target, "..", "xl", -1)])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_, ok := f.XLSX[drawingXML]
|
||||
if !ok {
|
||||
return "", nil
|
||||
}
|
||||
decodeWsDr := decodeWsDr{}
|
||||
_ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(drawingXML)), &decodeWsDr)
|
||||
|
||||
cell = strings.ToUpper(cell)
|
||||
fromCol := string(strings.Map(letterOnlyMapF, cell))
|
||||
fromRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, cell))
|
||||
row := fromRow - 1
|
||||
col := TitleToNumber(fromCol)
|
||||
|
||||
drawingRelationships := strings.Replace(strings.Replace(target, "../drawings", "xl/drawings/_rels", -1), ".xml", ".xml.rels", -1)
|
||||
|
||||
for _, anchor := range decodeWsDr.TwoCellAnchor {
|
||||
decodeTwoCellAnchor := decodeTwoCellAnchor{}
|
||||
_ = xml.Unmarshal([]byte("<decodeTwoCellAnchor>"+anchor.Content+"</decodeTwoCellAnchor>"), &decodeTwoCellAnchor)
|
||||
|
@ -518,16 +520,48 @@ func (f *File) GetPicture(sheet, cell string) (string, []byte) {
|
|||
// from xl/drawings/_rels/drawing%s.xml.rels by given file name and
|
||||
// relationship ID.
|
||||
func (f *File) getDrawingRelationships(rels, rID string) *xlsxWorkbookRelation {
|
||||
_, ok := f.XLSX[rels]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
var drawingRels xlsxWorkbookRels
|
||||
_ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(rels)), &drawingRels)
|
||||
for _, v := range drawingRels.Relationships {
|
||||
if v.ID == rID {
|
||||
return &v
|
||||
if drawingRels := f.drawingRelsReader(rels); drawingRels != nil {
|
||||
for _, v := range drawingRels.Relationships {
|
||||
if v.ID == rID {
|
||||
return &v
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// drawingRelsReader provides a function to get the pointer to the structure
|
||||
// after deserialization of xl/drawings/_rels/drawing%d.xml.rels.
|
||||
func (f *File) drawingRelsReader(rel string) *xlsxWorkbookRels {
|
||||
if f.DrawingRels[rel] == nil {
|
||||
_, ok := f.XLSX[rel]
|
||||
if ok {
|
||||
d := xlsxWorkbookRels{}
|
||||
_ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(rel)), &d)
|
||||
f.DrawingRels[rel] = &d
|
||||
}
|
||||
}
|
||||
return f.DrawingRels[rel]
|
||||
}
|
||||
|
||||
// drawingRelsWriter provides a function to save
|
||||
// xl/drawings/_rels/drawing%d.xml.rels after serialize structure.
|
||||
func (f *File) drawingRelsWriter() {
|
||||
for path, d := range f.DrawingRels {
|
||||
if d != nil {
|
||||
v, _ := xml.Marshal(d)
|
||||
f.saveFileList(path, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// drawingsWriter provides a function to save xl/drawings/drawing%d.xml after
|
||||
// serialize structure.
|
||||
func (f *File) drawingsWriter() {
|
||||
for path, d := range f.Drawings {
|
||||
if d != nil {
|
||||
v, _ := xml.Marshal(d)
|
||||
f.saveFileList(path, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
9
shape.go
9
shape.go
|
@ -11,7 +11,6 @@ package excelize
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
@ -293,10 +292,7 @@ func (f *File) addDrawingShape(sheet, drawingXML, cell string, formatSet *format
|
|||
width := int(float64(formatSet.Width) * formatSet.Format.XScale)
|
||||
height := int(float64(formatSet.Height) * formatSet.Format.YScale)
|
||||
colStart, rowStart, _, _, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, col, row, formatSet.Format.OffsetX, formatSet.Format.OffsetY, width, height)
|
||||
content := xlsxWsDr{}
|
||||
content.A = NameSpaceDrawingML
|
||||
content.Xdr = NameSpaceDrawingMLSpreadSheet
|
||||
cNvPrID := f.drawingParser(drawingXML, &content)
|
||||
content, cNvPrID := f.drawingParser(drawingXML)
|
||||
twoCellAnchor := xdrCellAnchor{}
|
||||
twoCellAnchor.EditAs = formatSet.Format.Positioning
|
||||
from := xlsxFrom{}
|
||||
|
@ -402,8 +398,7 @@ func (f *File) addDrawingShape(sheet, drawingXML, cell string, formatSet *format
|
|||
FPrintsWithSheet: formatSet.Format.FPrintsWithSheet,
|
||||
}
|
||||
content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
|
||||
output, _ := xml.Marshal(content)
|
||||
f.saveFileList(drawingXML, output)
|
||||
f.Drawings[drawingXML] = content
|
||||
}
|
||||
|
||||
// setShapeRef provides a function to set color with hex model by given actual
|
||||
|
|
Loading…
Reference in New Issue