HTML в PDF за допомогою Node.js


77

Я хочу створити pdfверсію веб-сторінок веб-сайту для друку . Щось на зразок express.render()лише відобразити сторінку якpdf

Хтось знає модуль вузла, який це робить?

Якщо ні, як би ви взялися за його реалізацію? Я бачив, як деякі методи говорять про використання безголового браузера phantom.js, але не впевнений, що це за потік.


Сподіваюся, це все ще буде актуальним, але зараз на сайті simpe.li є цей сайт, який має кілька заздалегідь визначених шаблонів, які ви можете вибрати та використовувати. Може бути корисним у деяких ситуаціях.
Девід Гатті

Відповіді:


87

Продовжуючи відповідь Мустафи.

A) Встановіть http://phantomjs.org/, а потім

Б) встановіть модуль фантомного вузла https://github.com/amir20/phantomjs-node

введіть тут опис зображення

В) Ось приклад надання 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


24
Це також завантажує CSS? Коли я відображаю сторінку, відображається текст, але немає CSS.

3
Однією з проблем цього рішення є те, що ви не отримаєте посилань, які можна натиснути, які є на веб-сторінці. Це те саме, що зробити знімок екрана та вбудувати зображення у PDF. Якщо це працює для вас, то це чудове рішення.
psuhas

Цей модуль phantomjs-nodeне існує на NPM, використовувати npm install phantom@2 -Sдля node v менше 5,0 або npm install phantom -Sдля версії версії 5,0 або новішої
TetraDev

Коли я перетворюю html у pdf, у HTML є 4-5 сторінок. Я хочу використовувати розрив сторінки між двома сторінками. Це моя URL-адреса, яку я хочу перетворити в PDF. " ishtech.xyz//web/#/reports_view?StartDate=11/14/… "
Хардік Манданкаа

3
PhantomJS більше не є активним проектом
Скотт

22

Phantom.js - це безголовий сервер webkit, і він буде завантажувати будь-яку веб-сторінку та відображати її в пам'яті, хоча, можливо, ви не зможете її побачити, є функція Screen Capture, за допомогою якої ви можете експортувати поточний вигляд у форматі PNG, PDF , JPEG та GIF. Погляньте на цей приклад із документації phantom.js


18

Якщо ви хочете експортувати HTML у PDF. У вас є багато варіантів. без вузла навіть

Варіант 1: На вашій сторінці html є кнопка, яка викликає функцію window.print (). скористатися власним браузером html у форматі pdf. використовуйте медіа-запити, щоб ваша HTML-сторінка добре виглядала у форматі PDF. а також у вас є друк до і після подій, які ви можете використовувати для внесення змін на свою сторінку до друку.

Варіант 2. htmltocanvas або rasterizeHTML . перетворіть свій html на полотно, а потім зателефонуйте toDataURL () на об'єкті полотна, щоб отримати зображення. і скористайтеся бібліотекою JavaScript, як jsPDF, щоб додати це зображення у файл PDF. Недоліком цього підходу є те, що pdf не стає доступним для редагування. Якщо вам потрібні дані, витягнуті з PDF, для цього існують різні способи.

Варіант 3. Відповідь @Jozzhard


Які браузери мають вбудований параметр html to pdf? На даний момент я бачу це лише в Chrome.
mwotton

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
Абсолютно приголомшливо. Він також працює із зовнішніми URL-адресами, якщо ви поєднуєте його з requestify.
TetraDev

2
Це враховує css? класи?
gabrielAnzaldo

1
@ gabodev77, так, це так.
зворотний дзвінок

його тег стилю підтримки чи ні?
Яш

2
FYI - цей пакет не оновлювався з 2017 року і має критичну вразливість npmjs.com/advisories/1095 Ймовірно, найкраще вибрати інший варіант :)
Д. Гіббс,

10

Спробуйте використовувати Puppeteer для створення PDF з HTML

Приклад звідси https://github.com/chuongtrh/html_to_pdf

Або https://github.com/GoogleChrome/puppeteer


5
лялькар зараз має більше сенсу, ніж фантом, оскільки останній вже застарів, а перший має набагато кращий і стабільніший apis.
Гулат

Puppeteer - єдиний спосіб створити PDF з HTML, використовуючи сучасну розмітку.
Олександр Кім

5

Створіть PDF із зовнішньої URL-адреси

Ось адаптація попередніх відповідей, яка використовує 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іноді приносить
TetraDev

Як би ви відтворили створений PDF безпосередньо у браузері, не маючи необхідності зберігати файл спочатку?
MartinWebb

За допомогою двійкового потоку це можна зробити. Теоретично він не зберігається, просто надходить безпосередньо до браузера. Хоча я працював з вузлом, я міг змусити його працювати лише спочатку збереживши тимчасовий pdf, потім отримавши двійковий потік, завантаживши двійковий потік, потім видаливши тимчасовий pdf.
TetraDev

Я отримую повідомлення про помилку з html-pdf - ReferenceError: Не вдається знайти змінну $. Чи може це статися через те, що сторінка, яку я завантажую, має javascript, який потрібно виконати? Будь-які ідеї були б корисними.
MindWire

@TetraDev: мені потрібно розподілити, щоб сформувати 1 сторінку pdf, які будуть зміни?
Шива

5

Пакет

Я використовував html-pdf

Простий у використанні і дозволяє не лише зберігати PDF у вигляді файлу, але й передавати вміст PDF до WriteStream (щоб я міг передати його прямо в Google Storage, щоб там зберігати свої звіти).

Використання css + зображень

Це враховує css. Єдина проблема, з якою я зіткнувся - це ігнорування моїх зображень. Рішенням, яке я знайшов, було замінити url у srcзначенні атрибута base64, наприклад

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

Ви можете зробити це за допомогою коду або скористатися одним із онлайн-конвертерів, наприклад https://www.base64-image.de/

Скомпілюйте дійсний HTML-код з HTML-фрагмента + CSS

  1. Мені довелося отримати фрагмент мого htmlдокумента (я щойно застосував метод .html () у селекторі jQuery).
  2. Потім я прочитав вміст відповідного cssфайлу.

Використовуючи ці два значення (що зберігаються у змінних htmlі cssвідповідно), я склав дійсний html-код за допомогою рядка Template

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

і передав його в createметод html-pdf .


Чи можна html-pdf завантажити з недійсних URL-адрес, наприклад із розширень Google Chrome / gtar.html?
Малкольм Сальвадор,

як ви очікуєте, що будь-яка система отримає що-небудь із недійсної URL-адреси?
user1990962

Зображення можна завантажити з файлу, лише правильне розташування має бути встановлене з file://префіксом. Отже, ви говорите в шаблоні <img src="static/logo.png">, то перед перетворенням підготуйте шаблон за допомогою префіксаconst html = htmlOrig.replace(new RegExp('<img src="', 'g'), `<img src="${base}`);
Володимир Вуканаць

4

Для тих, хто не хоче встановлювати PhantomJS разом із екземпляром Chrome / Firefox на своєму сервері - або тому, що проект PhantomJS в даний час призупинено , ось альтернатива.

Ви можете екстерналізувати перетворення на API, щоб виконати цю роботу. Багато існує та варіюється, але те, що ви отримаєте, - це надійна послуга з сучасними функціями (я думаю, що сумісні CSS3, веб-шрифти, 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
    }
);

1

На мій погляд, найкращий спосіб зробити це за допомогою 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 локально або у власній інфраструктурі, якщо хочете.


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

Якщо ви приїдете сюди і шукаєте спосіб зробити PDF із шаблонів подання в Express, ми з колегою зробили express-template-to-pdf

що дозволяє генерувати PDF з будь-яких шаблонів, які ви використовуєте в Express - Pug, Nunjucks, будь-що.

Це залежить від 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

На додаток до @Jozzhart Answer, ви можете створити локальний html; подавати його експрес; і використовувати фантом для створення PDF з нього; щось на зразок цього:

const exp = require('express');
const app = exp();
const pth = require("path");
const phantom = require('phantom');
const ip = require("ip");

const PORT = 3000;
const PDF_SOURCE = "index"; //index.html
const PDF_OUTPUT = "out"; //out.pdf

const source = pth.join(__dirname, "", `${PDF_SOURCE}.html`);
const output = pth.join(__dirname, "", `${PDF_OUTPUT}.pdf`);

app.use("/" + PDF_SOURCE, exp.static(source));
app.use("/" + PDF_OUTPUT, exp.static(output));

app.listen(PORT);

let makePDF = async (fn) => {
    let local = `http://${ip.address()}:${PORT}/${PDF_SOURCE}`;
    phantom.create().then((ph) => {
        ph.createPage().then((page) => {
            page.open(local).then(() =>
                page.render(output).then(() => { ph.exit(); fn() })
            );
        });
    });
}

makePDF(() => {
    console.log("PDF Created From Local File");
    console.log("PDF is downloadable from link:");
    console.log(`http://${ip.address()}:${PORT}/${PDF_OUTPUT}`);
});

та index.html може бути будь-яким:

<h1>PDF HEAD</h1>
<a href="#">LINK</a>

результат:

введіть тут опис зображення


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.