From c9e9857c00ae1f88e42c2863ebc00aaa5646a3d8 Mon Sep 17 00:00:00 2001 From: xuri Date: Sun, 17 May 2020 17:36:53 +0800 Subject: [PATCH] Merge pull request #410 --- picture.go | 53 +++++++++++++++++++++++++++++++++++++++++++++++-- picture_test.go | 21 ++++++++++++++++++++ rows.go | 3 ++- xmlDrawing.go | 1 + 4 files changed, 75 insertions(+), 3 deletions(-) diff --git a/picture.go b/picture.go index 306a582230b..71c3b8e9ecd 100644 --- a/picture.go +++ b/picture.go @@ -32,6 +32,7 @@ func parseFormatPictureSet(formatSet string) (*formatPicture, error) { FPrintsWithSheet: true, FLocksWithSheet: false, NoChangeAspect: false, + Autofit: false, OffsetX: 0, OffsetY: 0, XScale: 1.0, @@ -244,8 +245,12 @@ func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, he if err != nil { return err } - width = int(float64(width) * formatSet.XScale) - height = int(float64(height) * formatSet.YScale) + if formatSet.Autofit { + width, height, col, row, err = f.drawingResize(sheet, cell, float64(width), float64(height), formatSet) + if err != nil { + return err + } + } col-- row-- colStart, rowStart, _, _, colEnd, rowEnd, x2, y2 := @@ -578,3 +583,47 @@ func (f *File) drawingsWriter() { } } } + +// drawingResize calculate the height and width after resizing. +func (f *File) drawingResize(sheet string, cell string, width, height float64, formatSet *formatPicture) (w, h, c, r int, err error) { + var mergeCells []MergeCell + mergeCells, err = f.GetMergeCells(sheet) + if err != nil { + return + } + var rng []int + var inMergeCell bool + if c, r, err = CellNameToCoordinates(cell); err != nil { + return + } + cellWidth, cellHeight := f.getColWidth(sheet, c), f.getRowHeight(sheet, r) + for _, mergeCell := range mergeCells { + if inMergeCell, err = f.checkCellInArea(cell, mergeCell[0]); err != nil { + return + } + if inMergeCell { + rng, _ = areaRangeToCoordinates(mergeCell.GetStartAxis(), mergeCell.GetEndAxis()) + sortCoordinates(rng) + } + } + if inMergeCell { + c, r = rng[0], rng[1] + for col := rng[0] - 1; col < rng[2]; col++ { + cellWidth += f.getColWidth(sheet, col) + } + for row := rng[1] - 1; row < rng[3]; row++ { + cellHeight += f.getRowHeight(sheet, row) + } + } + if float64(cellWidth) < width { + asp := float64(cellWidth) / width + width, height = float64(cellWidth), height*asp + } + if float64(cellHeight) < height { + asp := float64(cellHeight) / height + height, width = float64(cellHeight), width*asp + } + width, height = width-float64(formatSet.OffsetX), height-float64(formatSet.OffsetY) + w, h = int(width*formatSet.XScale), int(height*formatSet.YScale) + return +} diff --git a/picture_test.go b/picture_test.go index fdc6f0db026..015d8540b72 100644 --- a/picture_test.go +++ b/picture_test.go @@ -47,6 +47,15 @@ func TestAddPicture(t *testing.T) { file, err := ioutil.ReadFile(filepath.Join("test", "images", "excel.png")) assert.NoError(t, err) + // Test add picture to worksheet with autofit. + assert.NoError(t, f.AddPicture("Sheet1", "A30", filepath.Join("test", "images", "excel.jpg"), `{"autofit": true}`)) + assert.NoError(t, f.AddPicture("Sheet1", "B30", filepath.Join("test", "images", "excel.jpg"), `{"x_offset": 10, "y_offset": 10, "autofit": true}`)) + f.NewSheet("AddPicture") + assert.NoError(t, f.SetRowHeight("AddPicture", 10, 30)) + assert.NoError(t, f.MergeCell("AddPicture", "B3", "D9")) + assert.NoError(t, f.AddPicture("AddPicture", "C6", filepath.Join("test", "images", "excel.jpg"), `{"autofit": true}`)) + assert.NoError(t, f.AddPicture("AddPicture", "A1", filepath.Join("test", "images", "excel.jpg"), `{"autofit": true}`)) + // Test add picture to worksheet from bytes. assert.NoError(t, f.AddPictureFromBytes("Sheet1", "Q1", "", "Excel Logo", ".png", file)) // Test add picture to worksheet from bytes with illegal cell coordinates. @@ -181,3 +190,15 @@ func TestDeletePicture(t *testing.T) { // Test delete picture on no chart worksheet. assert.NoError(t, NewFile().DeletePicture("Sheet1", "A1")) } + +func TestDrawingResize(t *testing.T) { + f := NewFile() + // Test calculate drawing resize on not exists worksheet. + _, _, _, _, err := f.drawingResize("SheetN", "A1", 1, 1, nil) + assert.EqualError(t, err, "sheet SheetN is not exist") + // Test calculate drawing resize with invalid coordinates. + _, _, _, _, err = f.drawingResize("Sheet1", "", 1, 1, nil) + assert.EqualError(t, err, `cannot convert cell "" to coordinates: invalid cell name ""`) + f.Sheet["xl/worksheets/sheet1.xml"].MergeCells = &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: "A:A"}}} + assert.EqualError(t, f.AddPicture("Sheet1", "A1", filepath.Join("test", "images", "excel.jpg"), `{"autofit": true}`), `cannot convert cell "A" to coordinates: invalid cell name "A"`) +} diff --git a/rows.go b/rows.go index 6a676727ed4..17216df24bc 100644 --- a/rows.go +++ b/rows.go @@ -148,7 +148,8 @@ func (err ErrSheetNotExist) Error() string { return fmt.Sprintf("sheet %s is not exist", string(err.SheetName)) } -// Rows return a rows iterator. For example: +// Rows returns a rows iterator, used for streaming reading data for a +// worksheet with a large data. For example: // // rows, err := f.Rows("Sheet1") // if err != nil { diff --git a/xmlDrawing.go b/xmlDrawing.go index a5e43a1cbc7..808bed5499b 100644 --- a/xmlDrawing.go +++ b/xmlDrawing.go @@ -419,6 +419,7 @@ type formatPicture struct { FPrintsWithSheet bool `json:"print_obj"` FLocksWithSheet bool `json:"locked"` NoChangeAspect bool `json:"lock_aspect_ratio"` + Autofit bool `json:"autofit"` OffsetX int `json:"x_offset"` OffsetY int `json:"y_offset"` XScale float64 `json:"x_scale"`