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 545 forks source link

Images in header and footer getting removed #12

Open Kop4lyf opened 9 years ago

Kop4lyf commented 9 years ago

I am trying to add header and footer containing images/logo, but when the pdf is getting generated, it is removing the images from the header and footer. The image src is base 64 encoded string and shows up when I put that in the main content. Only it is getting removed from header and footer.

Thanks.

marcbachmann commented 9 years ago

Sorry, I've only tested the headers with svgs but it should work (especially base64). What file type do you use and what sizes? Is it possible that the image dimensions are too large so it won't show up? Do you have an example to ensure that you embedded it correctly?

rojuvamshi commented 9 years ago

I am facing the same issue, Here i am using direct image path to src where it's located,The image type is PNG and the size is 5KB.

Thanks.

marcbachmann commented 9 years ago

You're right. It isn't working for the options.header.contents string. The script can already extract the headers from the html body if they are present. So images in the header are working using this html:

<body>
  <div id="pageHeader">
    <img src="https://www.google.com/images/srpr/logo11w.png">
  </div>
  some other content that shows on the pdf.
</body>

I can update the phantom script to inject the header & footer html into the html body. Therefore this can work after an update.

There's also an issue in the phantom project concerning this issue: https://github.com/ariya/phantomjs/issues/10735

Lichtjaeger commented 9 years ago

This is because header and footer is printed into pdf in a synchronous way. This mean any asynchronous request like getting image won't finish in time. This is current limitation of phantom.js

Solution: Add the same image to template content and hide it with style display:none. Then you can add it to the header and it will show up because it is already cached and no asynchronous request is needed. This is required to do for both image referenced with url as well for Data URI scheme base64 image.

marcbachmann commented 9 years ago

@Lichtjaeger That's what the script is doing when you use

<body>
  <div id="pageHeader">
    <img src="https://www.google.com/images/srpr/logo11w.png">
  </div>
  <div id="pageContent">
    some other content that shows on the pdf.
  </div>
  <div id="pageFooter">
    some other content
    <img src="https://www.google.com/images/srpr/logo11w.png">
  </div>
</body>

It renders the whole body and the header & footer get moved into the page header & footer I think that's still undocumented. Sorry for that. I'll have to improve it.

piermariacosina commented 9 years ago

we have tried this solution but images still don't shows up any suggestion?

asessa commented 9 years ago

@piermariacosina check this full example: https://gist.github.com/asessa/bf389070d76aaaf3987b

frapontillo commented 9 years ago

@asessa's solution works just fine, can it be integrated into the module?

stevenmhunt commented 9 years ago

Something else to keep in mind is that your images won't load if you're downloading them over https and your SSL certificate isn't configured properly.

morficus commented 8 years ago

The trick of using a div with id="pageHeader" in the content works great. But things brings up another point... I didn't see any documentation about #pageHeader and #pageFooter being parsed out of the content if they were present.

lekhnath commented 8 years ago

Image in #pageHeader not showing in pdf. However this image (https://www.google.com/images/srpr/logo11w.png) form goolge is showing but not from my localhost (http://localhost:3500/images/logo11w.png)

SFWDhaval commented 8 years ago

I am getting same issue, Image in #pageHeader div not showing in PDF header of each and every PDF pages. Image displayed only in first page of PDF.

linusbrolin commented 8 years ago

Same issue for me. The google image is showing, but if I use an image from my webserver (full http url, not https) then the image will not show in the pageHeader. It will show in pageContent though.

Edit: I also noticed that any linked stylesheet will not work in pageHeader

kenkogi commented 7 years ago

I had exactly the same issue. I looked to see the difference in how the two images were being served. I noticed the image being served from my server had a response header cache-control:private, max-age=0 while the google one cache-control:private, max-age=31536000. I served mine as google is being served and that saved the day.

Hopefully that helps someone.

marcbachmann commented 7 years ago

oh, wow. 😕 very weird. Does phantomjs have a local cache?

josepfdc commented 7 years ago

as kenkogi mentioned it , that resolve the problem in nodejs. I work with nodejs and express inside tmp folder there is 2 images

tmp
   logo.jpg
   img/foto2.jpg

app.js

var cacheTime=31536000;
app.use(express.static(__dirname + '/tmp',{ maxAge: cacheTime }));

prova.html

<body>
  <div id="pageHeader">
    <img src="http://localhost:3000/img/foto2.jpg"  >
    header
  </div>
  <div id="pageContent">
        COMIENZO DE CONTENIDO.
        <div><img src="http://localhost:3000/logo.jpg" alt="Smiley face" height="42" width="42" /></div>
        FIN DE CONTENIDO
  </div>
  <div id="pageFooter">
    footer
    <img src="http://localhost:3000/logo.jpg">
  </div>
</body>

index.js

var express = require('express');
var router = express.Router();
var libreria = require('../routes/libs/libreria');
var fs = require('fs');
var pdf = require('html-pdf');
var html = fs.readFileSync('./prova.html', 'utf8');
config = { 
  "format": "A4",        // allowed units: A3, A4, A5, Legal, Letter, Tabloid 
  "orientation": "portrait", // portrait or landscape 
  "border": {
    "top": "2in",            // default is 0, units: mm, cm, in, px 
    "right": "1in",
    "bottom": "2in",
    "left": "1.5in"
  },
  "header": {
    "height": "45mm"
  },
  "footer": {
    "height": "28mm"
  },
  "zoomFactor": "1", // default is 1 
  "type": "pdf",             // allowed file types: png, jpeg, pdf 
  "quality": "75",           // only used for types png & jpeg 
} 
/* GET home page. */
router.get('/', function(req, res, next) {

  pdf.create(html, config).toFile('./demo.pdf', function(err, res) {
    if (err) return console.log(err);
    console.log(res); // { filename: '/app/businesscard.pdf' } 
  });
  res.render('index', { title: 'Express' });
});

module.exports = router;

I hope , this help.

archer747 commented 7 years ago

I have my image in Google Cloud Storage. When I accessed directly from gcloud it displayed the image. But when I download same image from my Loopbackjs API it does not display. @kenkogi I added the cache-control:private, max-age=31536000 to my API response but still does not work.

Any other suggestions please?

kenkogi commented 7 years ago

@mugbomah, I don't know of any other methods to solve this. Maybe a look at the API code or a URL to the image may help.

moparlakci commented 6 years ago

My solution was to use the fullpath in the pageHeader section

const header = {
    type: 'div',
    attributes: {
        id: 'pageHeader',
    },
    content: [ 
        {
            type: 'img', 
            attributes: {
                src: 'file://' + path.resolve('./static/images') + '/logo.png'
            },
        }
    ]
}   
raulneis commented 5 years ago

Header/footer images load correctly if you load the same image on the body, with display:none

mcmino commented 5 years ago

This is because header and footer is printed into pdf in a synchronous way. This mean any asynchronous request like getting image won't finish in time. This is current limitation of phantom.js

Solution: Add the same image to template content and hide it with style display:none. Then you can add it to the header and it will show up because it is already cached and no asynchronous request is needed. This is required to do for both image referenced with url as well for Data URI scheme base64 image.

This worked for me, thanks!!

munganyendesandrine commented 3 years ago

Thanks to kenkogi and josepfdc's comments, I've got the solution. Copy these 2 lines in your server.js and replace /tmp with the folder that contains your image ex: /public var cacheTime=31536000; app.use(express.static(__dirname + '/tmp',{ maxAge: cacheTime }));