marcbachmann / node-html-pdf

This repo isn't maintained anymore as phantomjs got dreprecated a long time ago. Please migrate to headless chrome/puppeteer.
MIT License
3.56k stars 544 forks source link

The image is not show after convert to pdf #239

Open alatebloomer opened 7 years ago

alatebloomer commented 7 years ago

Below is my html code

<div>
  <img src="./cscps/images/aaa.bmp">
  <img src="./cscps/images/bbb.bmp">
  <img src="./cscps/images/ccc.bmp">
  <img src="./cscps/images/ddd.bmp">
</div>

and I set "base" option like below

var options = { 
format: 'Letter',
base: 'file://./cscps/images/' 

};

But still can not see any image in pdf file.

Anyone can help? I am using MAC system Thanks.

waila7 commented 7 years ago

Might help https://github.com/marcbachmann/node-html-pdf/issues/44

derouck commented 7 years ago

Calculate the full path on your server and put that as base. The src path should be aaa.bmp if your vase goes all the way down to images. Good luck.

marcbachmann commented 7 years ago

file://./cscps/images/ is a relative path from the phantomjs executable. This is wrong in most cases.

Please use base: 'file://' + __dirname + '/cscps/images/' for the base option and <img src="aaa.bmp"> to reference to an image.

ndevendh commented 7 years ago

Hi marcbachmann,

I set an svg image in header and it is not showing after converting it to pdf. But body elements are taking the images properly.

Please find the below and confirm that this is possible or not.

{ "format": "A4", "type": "pdf",
"base":"file://" + __dirname+"/template/images/", "header": { "height": "50px", "contents": '

' }, "footer": { "height": "30px", "contents": ''
} };

Also i set some dummy div for cache purpose.

Im using 2.1.0 latest version.

I have tried to set data uri of svg as well. That is not working too.

Please let me know if it is possible set image in header.

ndevendh commented 7 years ago

<div><img src="icon_logo.vg"/></div>

ndevendh commented 7 years ago

dummy div

<div class="dummy_img"><img src="icon_logo.vg"/></div>

Hardik21 commented 7 years ago

Still not working for me. My Code:

var pdf = require('html-pdf');
var html = fs.readFileSync('./Media/index.html', 'utf8');
var _basePath = 'file:///' + __dirname + '\\Media\\';
var options = {
    format: 'A4',
    base: _basePath
};

pdf.create(html, options).toFile('./Media/123.pdf', function (err, res) {
    if (err) return console.log(err);
    console.log(res); // { filename: '/app/businesscard.pdf' } 
});

HTML: <img src="logo.png" alt="Logo" />

nickvirden commented 6 years ago

It seems that for now the nesting an <img> tag inside a <div id="pageHeader"></div>, whether you actually have the HTML in your .html file or set the HTML in the header content option, doesn't render images. The best solution I've come up with after reading around a bit was what I have below. I used relative paths on images for the src attribute.

HTML

<div class="header-wrapper">
    <div>
        <img class="logo" src="/relative/path/to/header/image.png" />
    </div>
</div>

CSS

html, body {
    margin: 0;
    padding: 0;
    -webkit-print-color-adjust: exact;
}

.page {
    height: 100vh;
    page-break-after: always;
}

.page:last-of-type {
    page-break-after: auto
}

.page .header-wrapper {
    margin-top: 20px;
}

.page .header-wrapper > div {
    position: relative;
    width: 100%;
    text-align: center;
}

.page .header-wrapper > div .logo {
    width: 100%;
}

.page .page-body-wrapper {
    margin-top: 40px;
}

.page-body {
    font-family: Calibri, Candara, Segoe, Segoe UI, Optima, Arial, sans-serif;
    font-size: 10px;
}

Note: You must put the header on EVERY PAGE. If you don't, the image will not render on every page. Moreover, if you're turning the HTML file into a giant string on the server side, the image path should be relative to the HTML file in which you're trying to insert the image, NOT relative to the, say, server file that may be inserting the image dynamically into your HTML file.

Example folder structure:

app.js
app/
  pdf.html
  images/
     image-to-insert.jpg

What I did in app.js was the following:

const { body } = req,
        currentDir = `${__dirname}/`,
        template = `${currentDir}templates/pdf.html`;

let templateHtml = fs.readFileSync(template, 'utf8');

const headerImage = 'images/header.png';
    templateHtml = templateHtml.replace(/{{header}}/g, headerImage);

const baseFolder = './folder/',
    nameOfDocument = `PDF.pdf`,
    pdfDocument = `${baseFolder}/${nameOfDocument}`;

// If the folder doesn't exists, add it. Otherwise, skip it
if (!fs.existsSync(baseFolder)) { fs.mkdirSync(baseFolder); }

// Establish the base options for the PDF formatting
const options = {
    base: `file://${currentDir}`,
    // Height of document
    height: '11in',
    // Width of document
    width: '8in',
    // Border 'padding'
    border: {
        top: '0in',
        right: '0.5in',
        bottom: '0in',
        left: '0.5in'
    },
    header: {
        height: '0mm'
    },
    // Footer contents
    footer: {
        contents: '<div>This is a footer</div>'
    }
};

pdf.create(templateHtml, options).toFile(pdfDocument, (err, res) => {
    if (err) { return console.log(err); }
});

and in pdf.html, every page has the following

<style>
    html, body {
        margin: 0;
        padding: 0;
        -webkit-print-color-adjust: exact;
    }

    .page {
        height: 100vh;
        page-break-after: always;
    }

    .page:last-of-type {
        page-break-after: auto
    }

    .page .header-wrapper {
        margin-top: 20px;
    }

    .page .header-wrapper > div {
        position: relative;
        width: 100%;
        text-align: center;
    }

    .page .header-wrapper > div .logo {
        width: 100%;
    }

    .page .page-body-wrapper {
        margin-top: 40px;
    }

    .page-body {
        font-family: Calibri, Candara, Segoe, Segoe UI, Optima, Arial, sans-serif;
        font-size: 10px;
    }
</style>
<div class="page">
    <div class="header-wrapper">
        <div>
            <img class="logo" src="{{header}}" />
        </div>
    </div>
    <div class="page-body-wrapper">
        <div class="page-body">
           <p></p>
        </div>
    </div>
</div>
pushkertiwari commented 6 years ago

hello i have facing the issue that , i takes the same values for two different pdfs i creates the caching issue in it, is it any way to reinitialize the html variables

madve2 commented 6 years ago

After 2 hours of trying in vain, I ended up generating my source HTML with base64 encoded images embedded in it (instead of using paths), and that worked on first try. So, if you have control over the HTML file you're trying to convert, this might be actually a lot simpler than trying to figure out what's wrong with your paths (which, as other issues show, has many possible pitfalls).

rudrakshpathak commented 6 years ago

Your code should be

<div>
  <img src="aaa.bmp">
  <img src="bbb.bmp">
  <img src="ccc.bmp">
  <img src="ddd.bmp">
</div>
var options = { 
format: 'Letter',
base: 'file:///' + __dirname + '/images/'
}

Considering cscps is the root directory name.

amitcodefire commented 5 years ago

Image is not shown in pdf. Can anyone guide me? How can fix it?

Image Url :- https://www.codefire.org/sites/all/themes/codefire/img/logo.png

krinjalpatel commented 5 years ago

Hi, you need to convert the image into base64 image. Following is the solution for the same.

Using css + images

It takes css into account. The only problem I faced - it ignored my images. The solution I found was to replace url in src attrribute value by base64, e.g.

<img src="data:image/png;base64,iVBOR...kSuQmCC">

You can do it with your code or to use one of online converters, e.g. https://www.base64-image.de/

Reference Link: https://stackoverflow.com/questions/14552112/html-to-pdf-with-node-js/14552323

shahnad commented 2 years ago

i convert my image into base64 using online converter . and use src

<img class="invoice-logo" alt="img-logo" src="data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAABkAAD/4QMqaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgY" />

neenus commented 1 year ago

In my case following what @marcbachmann mentioned didn't work for some reason by setting a base property inside the options object maybe I messed up the path string! but what I did was I converted the images to a base64 strings with node and by using base64 instead is working like a charm.

if you have access to where the images are you can easily convert it with node without any additional libraries like so:

const convertImageToBase64 = imgPath => {
  const imgExtension = imgPath.split(".").pop();  \\ get image extension
  let image = `data:image/${imgExtenstion};base64`; \\ construct starting of the string needed by html img src
  image += fs.readFileSync(imgPath, 'base64'); \\ concat base64 string to the image string
  return image;
}