使用Node.js将HTML转换为PDF


77

我正在寻找创建pdf我网站网页的可打印版本。诸如express.render()仅将页面呈现为pdf

有人知道这样做的节点模块吗?

如果没有,您将如何实施?我已经看到一些关于使用无头浏览器的方法,例如phantom.js,但是不确定流程如何。


我希望这仍然有用,但是现在有这个站点simpe.li,其中包含一些预定义的模板供您选择和使用。在某些情况下可能有用。
David Gatti

Answers:


87

扩展穆斯塔法的答案。

A)安装http://phantomjs.org/,然后

B)安装幻象节点模块https://github.com/amir20/phantomjs-node

在此处输入图片说明

C)这是呈现pdf的示例

var phantom = require('phantom');   

phantom.create().then(function(ph) {
    ph.createPage().then(function(page) {
        page.open("http://www.google.com").then(function(status) {
            page.render('google.pdf').then(function() {
                console.log('Page Rendered');
                ph.exit();
            });
        });
    });
});

PDF的输出:

在此处输入图片说明

编辑: 静默打印该PDF

java -jar pdfbox-app-2.0.2.jar PrintPDF -silentPrint C:\print_mypdf.pdf


23
这还会加载CSS吗?当我渲染页面时,会显示文本,但是没有CSS。

3
该解决方案的问题之一是,您将不会获得网页上的可点击链接。这与拍摄屏幕快照并将图像嵌入到PDF中相同。如果这对您有用,那么这是一个很好的解决方案。
psuhas

该模块phantomjs-node在NPM上不存在,npm install phantom@2 -S用于节点v小于5.0或npm install phantom -S节点版本5.0或更高版本
TetraDev

当我将html转换为pdf时,html中有4-5页。我想在两个页面之间使用分页符。这是我要转换为pdf的URL链接。“ ishtech.xyz//web/#/reports_view?StartDate=11/14/…
Hardik Mandankaa

3
PhantomJS不再是一个活跃的项目
Scott Stensland '19

22

Phantom.js是一个无头Webkit服务器,它将加载任何网页并将其呈现在内存中,尽管您可能看不到它,但是它具有屏幕捕获功能,您可以在其中将当前视图导出为PNG,PDF ,JPEG和GIF。看看phantom.js文档中的这个例子


17

如果要将HTML导出为PDF。您有很多选择。甚至没有节点

选项1:在html页面上有一个调用window.print()函数的按钮。使用浏览器的本地html到pdf。使用媒体查询使您的html页面在pdf上看起来不错。并且还具有事件之前和之后的打印结果,可用于在打印之前更改页面。

选项2. htmltocanvasrasterizeHTML。将您的html转换为canvas,然后在canvas对象上调用toDataURL()以获取图像。并使用jsPDF之类的JavaScript库将该图像添加到PDF文件中。这种方法的缺点是pdf不会变得可编辑。如果要从PDF提取数据,则有不同的方法。

选项3. @Jozzhard答案


哪些浏览器具有内置的html至pdf选项?目前,我只能在Chrome中看到它。
mwotton 2015年

11

我发现最好的解决方案是html-pdf。这很简单,可以处理大型html。

https://www.npmjs.com/package/html-pdf

就这么简单:

    pdf.create(htm, options).toFile('./pdfname.pdf', function(err, res) {
        if (err) {
          console.log(err);
        }
    });

1
绝对棒 如果将它与requestify结合使用,它也适用于外部URL。
2016年

2
它考虑了css吗?上课?
gabrielAnzaldo

1
@ gabodev77,是的。
回调

是否支持样式标记?
Yash

2
仅供参考-该软件包自2017年以来未进行更新,并且具有严重漏洞npmjs.com/advisories/1095最好与另一个选项一起使用:)
D. Gibbs


5

从外部URL创建PDF

这是对先前答案的改编,其中利用了html-pdf,但也将其与结合使用,requestify因此可以与外部URL结合使用:

安装你的依赖

npm i -S html-pdf requestify

然后,创建脚本:

//MakePDF.js

var pdf = require('html-pdf');
var requestify = require('requestify');
var externalURL= 'http://www.google.com';

requestify.get(externalURL).then(function (response) {
   // Get the raw HTML response body
   var html = response.body; 
   var config = {format: 'A4'}; // or format: 'letter' - see https://github.com/marcbachmann/node-html-pdf#options

// Create the PDF
   pdf.create(html, config).toFile('pathtooutput/generated.pdf', function (err, res) {
      if (err) return console.log(err);
      console.log(res); // { filename: '/pathtooutput/generated.pdf' }
   });
});

然后,您只需从命令行运行:

node MakePDF.js

观看为您创建的美化像素完美PDF(免费!)


有一个问题导致html-pdf有时只能成功制作PDF-github.com/marcbachmann/node-html-pdf/issues/181
TetraDev

您如何将创建的PDF直接呈现给浏览器,而不必先存储文件?
MartinWebb

使用二进制流可以做到。从理论上讲,它不会被保存,只是直接通过管道传输到浏览器。尽管使用节点,但我只能先保存临时pdf,然后获取二进制流,下载二进制流,然后删除临时pdf,才能使其正常工作。
TetraDev

我从html-pdf收到错误-ReferenceError:找不到变量$。发生这种情况是因为我正在加载的页面具有需要执行的javascript吗?任何想法都会有所帮助。
MindWire

@TetraDev:我需要严格限制以生成1页pdf,这会有什么变化?
湿婆

5

我用html-pdf

易于使用,不仅可以将pdf保存为文件,还可以将pdf内容通过管道传输到WriteStream(这样我就可以将其直接流式传输到Google Storage,以将报告保存在那里)。

使用CSS +图像

它考虑了CSS。我面临的唯一问题-它忽略了我的图像。我发现的解决方案是src用base64替换attrribute值中的url ,例如

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

您可以使用您的代码进行操作,也可以使用在线转换器之一,例如https://www.base64-image.de/

从html片段+ CSS编译有效的html代码

  1. 我必须得到我的html文档的一部分(我只是在jQuery选择器上应用了.html()方法)。
  2. 然后,我阅读了相关css文件的内容。

使用该两个值(存储在变量中html,并css因此)我编译使用有效的HTML代码模板字符串

var htmlContent = `
<!DOCTYPE html>
<html>
  <head>
    <style>
      ${css}
    </style>
  </head>
  <body id=direct-sellers-bill>
    ${html}
  </body>
</html>`

并将其传递给html-pdf的create方法。


可以从无效的url(例如Google Chrome扩展程序/ gtar.html页面)下载html-pdf吗?
马尔科姆·萨尔瓦多

您如何期望任何系统从无效的URL获取任何信息?
user1990962

4

对于那些不想在服务器上安装PhantomJS以及Chrome / Firefox实例的用户-或因为PhantomJS项目当前已暂停,这是一个替代方案。

您可以将转换外部化为API来完成这项工作。许多存在并且各不相同,但是您将获得的是具有最新功能的可靠服务(我认为CSS3,Web字体,SVG,Canvas兼容)。

例如,使用PDFShift(免责声明,我是创始人),您可以简单地通过使用以下request程序包来做到这一点:

const request = require('request')
request.post(
    'https://api.pdfshift.io/v2/convert/',
    {
        'auth': {'user': 'your_api_key'},
        'json': {'source': 'https://www.google.com'},
        'encoding': null
    },
    (error, response, body) => {
        if (response === undefined) {
            return reject({'message': 'Invalid response from the server.', 'code': 0, 'response': response})
        }
        if (response.statusCode == 200) {
            // Do what you want with `body`, that contains the binary PDF
            // Like returning it to the client - or saving it as a file locally or on AWS S3
            return True
        }

        // Handle any errors that might have occured
    }
);

0

使用html-pdf

var fs = require('fs');
var pdf = require('html-pdf');
var html = fs.readFileSync('./test/businesscard.html', 'utf8');
var options = { format: 'Letter' };

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

0

如果您到达这里,是想寻找一种从Express的同事的视图模板制作PDF的方法,而我则做了express-template-to-pdf

这使您可以从Express中使用的任何模板(Pug,Nunjucks等)生成PDF。

它取决于html-pdf,并且被编写为在路由中使用,就像使用res.render一样:

const pdfRenderer = require('@ministryofjustice/express-template-to-pdf')

app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'pug')

app.use(pdfRenderer())

如果您使用过res.render,那么使用它应该看起来很明显:

app.use('/pdf', (req, res) => {
    res.renderPDF('helloWorld', { message: 'Hello World!' });
})

您可以将选项传递给html-pdf以控制PDF文档的页面大小等

仅依靠他人的出色工作。


0

我认为,最好的方法是通过API,这样您就不会在运行非托管代码的应用程序中添加大型且复杂的依赖项,而该依赖项需要经常更新。

这是一个简单的方法,每月可免费使用800个请求:

var CloudmersiveConvertApiClient = require('cloudmersive-convert-api-client');
var defaultClient = CloudmersiveConvertApiClient.ApiClient.instance;

// Configure API key authorization: Apikey
var Apikey = defaultClient.authentications['Apikey'];
Apikey.apiKey = 'YOUR API KEY';



var apiInstance = new CloudmersiveConvertApiClient.ConvertWebApi();

var input = new CloudmersiveConvertApiClient.HtmlToPdfRequest(); // HtmlToPdfRequest | HTML to PDF request parameters
input.Html = "<b>Hello, world!</b>";


var callback = function(error, data, response) {
  if (error) {
    console.error(error);
  } else {
    console.log('API called successfully. Returned data: ' + data);
  }
};
apiInstance.convertWebHtmlToPdf(input, callback);

通过上述方法,您还可以根据需要在本地或自己的基础结构上安装API。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.