Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image position - stretching image #467

Closed
Trynex opened this issue Dec 20, 2017 · 22 comments
Closed

Image position - stretching image #467

Trynex opened this issue Dec 20, 2017 · 22 comments

Comments

@Trynex
Copy link

Trynex commented Dec 20, 2017

Hello everyone. I have a problem with images using exceljs. If I just run excel file through and save it, images are immediately deformed (stretched). I tried workaround and so I just removed images from original excel file and inserted them with add image. Again stretched. So I tried not to specify cells for image to include, but also other(more specific option):

{tl: { col: 1.2, row: 0.4 }, br: { col: 3.2, row: 0.9 }}

This worked when row number was not decimal. Because the example above didn't scale the image
from 0.4 to 0.9 of the cell, but rather deformed it .. Which is weird as the image started the position on 0.4. This for example worked fine:

{tl: { col: 1.2, row: 0.4 }, br: { col: 3.2, row: 1 }}

but any decimal number in br->row does weird things.

I also tried to specify editAs attribute and all its options, but no luck there.

Am I doing something wrong or is it a bug? Is there any workaround where I can specify the place where I want to include image without stretching image?

Thank you for your help!

@jwmann
Copy link
Contributor

jwmann commented Jan 17, 2018

I'm having a similar issue in where the row property isn't being respected.
In my case though, I want to resize the image.

  // Add the Header Image
  sheet.mergeCells('A1:E1');
  const imageRow = sheet.getRow(1);
  imageRow.height = 60;
  const headerImage = workbook.addImage({
    base64: headerImg,
    extension: 'png',
  });
  sheet.addImage( headerImage, {
    tl: { col: 0.1, row: 0.3},
    br: { col: 2.0, row: 0.99999999999}
  });

screen shot 2018-01-17 at 10 22 59

If I make br: { col: 2.0, row: 1} That pixelated image stretches ALL the way to the full height of Row 1.

Do you see the discrepancy here?
It's as if the height change is being ignored and row doesn't care. The col prop seems to work fine though.

@jwmann
Copy link
Contributor

jwmann commented Jan 17, 2018

I decided that maybe I could avoid this and pre-size my actual image first and use editAs: 'absolute' but that makes it stretch the image anyway.

There seems to be something fundamentally broken in this function.

@Trynex
Copy link
Author

Trynex commented Jan 17, 2018

Hi man. I know what you mean, I tried everything with this plugin but it didnt work. So I had to fork this package and fix it. Currently I'm not near PC but tomorrow I will write you how to use my modified version to make pictures scalable any way you want.

@jwmann
Copy link
Contributor

jwmann commented Jan 17, 2018

Sounds good, perhaps we could make a PR with these fixes too? :)

@Trynex
Copy link
Author

Trynex commented Jan 18, 2018

So as promised this is my fork of ExcelJS: https://github.com/Trynex/exceljs
The thing is that (after few hours debugging their code) I found they use fixed height and width of cells to calculate the position of your image. I had to break down excel (unzip it and look into the standard what is excel's structure) and I found out that first you have to specify where your image starts and ends (cell-wise: row and col property of model) and than colOff and rowOff is actuall stretching/position inside the cell of the image. This is what was calculated wrong and I didn't find any possibility to calculate colOff and rowOff easily and dynamically(since you would need to know the width and height of cells you insert the image into). So what I did is I added two new properties colOff and rowOff (obviously) for each of two existing tl and br properties. As you know from documentation tl is top left corner (cell wise) and br is bottom right. But now you need stretching right to specify like part of the cell where you want it.

(TLDR starts here:)

So basic example in original:
{
"tl": { "col": 1, "row": 0},
"br": { "col": 3, "row": 0},
"editAs" : "absolute"
}

But that stretches the wrong way as your cell width and height is not accounted for in calculation. So what you want to do here is to add specific position in the cell where these top left and bottom right corners will start in pixels.

Example with my fix:
{
"tl": { "col": 1, "row": 0, "colOff": 6, "rowOff": 14},
"br": { "col": 3, "row": 0, "colOff": 76, "rowOff": 55},
"editAs" : "absolute"
}

Try to play with it little and ask if you need any help.

@dmastag
Copy link

dmastag commented Feb 22, 2018

@Trynex interesting way of going around this issue.
Would it not be more practical to account the cell height and weight in the calculation or is this something that is not possible?

@robsco-git
Copy link

One can also use the sharp image processing library to add a transparent (or white) background to an image and scale the image whilst retaining it's aspect ratio. Then, placing this square image into a square cell will display it with the correct aspect ratio. Maybe an image is a simpler way of explaining:

screenshot from 2018-03-18 00-11-59

The ratio between width an height in this library seems to be 0.14291498 (IDK why?). In other words, one can set col.width = 10 * 1.429149798 and row.height = 100 to get a square cell. Then, you can use the following sharp snippet to scale the image, preserving the aspect ratio and adding a white background to the image in the places where extra space is needed to keep the image square.

sharp(image)
      .resize(scale, scale)
      .background({r: 255, g: 255, b: 255})
      .embed()
      .toBuffer()
      .then(data => {
        // do something
      })

One could use this snippet to use a transparent background

sharp(image)
      .resize(scale, scale)
      .background({r: 0, g: 0, b: 0, alpha: 0})
      .embed()
      .toFormat(sharp.format.png)
      .toBuffer()
      .then(data => {
        // do something
      })

Super duper hacky but I got a working solution for my use case. Whether or not this will help you depends on your use case.

@statzg
Copy link

statzg commented Apr 26, 2018

@Trynex: thanks for your fork. Now I can actually place images without or with only invisible stretch.

Just a quick info for everyone: rowOff and colOff in the open xml specification is not in pixel but actually in EMUs which supposedly stands for English Metric Unit. Here's an article on the topic. @Trynex implemented it so that when you use his code 1 unit in rowOff and colOff is actually 10000 EMU

The row height (as defined with row.height = 10;) is defined in pts. So in my case, where I knew row heights (since I defined it), I could calculate rowoff in pts and then had to multiply it with 1.27 to get 12700 EMUs per pt.

For colOff the thing is even more complex since column with is in some fucked-up font dependend unit. In my case, I got good results with multiplying the cell width (as defined with col.width = 15;) with 7.025 (when using arial).

So, Thanks Microsoft for making a "standard" thats so fucked up that you need to spend hours on just placing images. You could have at least used the same unit for x and y.

@jwmann
Copy link
Contributor

jwmann commented Apr 26, 2018

I'm just wondering why @Trynex's fix isn't pulled into master. It's an actual bug that editAs: 'absolute' doesn't actually do what it says.

@FelipeRobles92
Copy link

How to export excel ?
i ussed this code

workbook.xlsx.writeBuffer({
base64: true
}).then(buffer => FileSaver.saveAs(new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}), ${Date.now()}_feedback.xlsx)).catch(err => console.log('Error writing excel export', err))

but i open excel file and crash, help pls

@Pipoupi
Copy link

Pipoupi commented Nov 9, 2018

@FelipeRobles92 It might be because you forgot to quote your file name

 workbook.xlsx.writeBuffer({
            base64: true
        }).then(buffer => FileSaver.saveAs(new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}), `${Date.now()}_feedback.xlsx`)).catch(err => console.log('Error writing excel export', err))
    });

@FelipeRobles92
Copy link

it just happens to me when export excel with image :(

@kaidoj
Copy link

kaidoj commented Nov 14, 2018

I can confirm. This issue is still there. Same problem as OP posted.
//Edited
I added PR for this. @Trynex fix worked for me.

@Siemienik
Copy link
Member

Siemienik commented Dec 1, 2018

@Trynex @jwmann @dmastag @kaidoj
Hello guys, i fix it in pull request #702,
comparing it to #691, i care about backward compatibility and write some test to ensure it works well.

if You need this changes quicly, i have build branch in my repo:
https://github.com/p3rio/exceljs/tree/build

npm:

    "dependencies": {
        "exceljs": "github:p3rio/exceljs#build"
    }

@kaidoj
Copy link

kaidoj commented Dec 8, 2018

@Siemienik as soon as i get back to that project where i used exceljs, i will try out your fix and see if that fixes my problem. Ofc its better to have tests etc. I just did it to fix my issue fast without going too deep into execeljs code.

Edit: I can now confirm that @Siemienik fix works for me too.
Edit2: This #702 fix did not actually work for me. Went back to my fork and that works in all excel reading applications.

@dogusev
Copy link
Contributor

dogusev commented Apr 8, 2019

@alubbe @guyonroche
Hi!
An issue, which was resolved after #702 merged - came back again. Something happened, and images again stretched

@Siemienik
Copy link
Member

An issue, which was resolved after #702 merged - came back again. Something happened, and images again stretched

any one found reason of that?

@dogusev
Copy link
Contributor

dogusev commented Apr 17, 2019

probably mess in installed dependencies. Can not reproduce it again

@Siemienik
Copy link
Member

So .. does the bug still exists or was it fixed?

@dogusev
Copy link
Contributor

dogusev commented Apr 18, 2019

as for me, i cannot reproduce it again. So i'd say it's fixed

@ShraddhaJ11
Copy link

"editAs" : "absolute"

So as promised this is my fork of ExcelJS: https://github.com/Trynex/exceljs
The thing is that (after few hours debugging their code) I found they use fixed height and width of cells to calculate the position of your image. I had to break down excel (unzip it and look into the standard what is excel's structure) and I found out that first you have to specify where your image starts and ends (cell-wise: row and col property of model) and than colOff and rowOff is actuall stretching/position inside the cell of the image. This is what was calculated wrong and I didn't find any possibility to calculate colOff and rowOff easily and dynamically(since you would need to know the width and height of cells you insert the image into). So what I did is I added two new properties colOff and rowOff (obviously) for each of two existing tl and br properties. As you know from documentation tl is top left corner (cell wise) and br is bottom right. But now you need stretching right to specify like part of the cell where you want it.

(TLDR starts here:)

So basic example in original:
{
"tl": { "col": 1, "row": 0},
"br": { "col": 3, "row": 0},
"editAs" : "absolute"
}

But that stretches the wrong way as your cell width and height is not accounted for in calculation. So what you want to do here is to add specific position in the cell where these top left and bottom right corners will start in pixels.

Example with my fix:
{
"tl": { "col": 1, "row": 0, "colOff": 6, "rowOff": 14},
"br": { "col": 3, "row": 0, "colOff": 76, "rowOff": 55},
"editAs" : "absolute"
}

Try to play with it little and ask if you need any help.

@Trynex How to calculate coloff and rowoff and what is the unit of coloff and rowoff ?

@sourvil
Copy link

sourvil commented Aug 31, 2020

still not working and calculating rowOff & colOff is not clear

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests