node js html to pdf




PhantomJS:將PDF導出到標準輸出 (3)

有沒有辦法在PhantomJS中觸發PDF導出功能,而不指定帶.pdf擴展名的輸出文件? 我們希望使用stdout來輸出PDF。


你可以直接輸出到標準輸出而不需要臨時文件。

page.render('/dev/stdout', { format: 'pdf' });

有關添加時的歷史記錄,請參閱此處

如果你想從stdin獲取HTML並輸出PDF到標準輸出, 請看這裡


對不起,答案非常長。 我有一種感覺,在我的生活中我需要參考這個方法幾十次,所以我會寫“一個統治所有的答案”。 我會先嘮叨一些關於文件,文件描述符,(命名)管道和輸出重定向,然後回答你的問題。

考慮一下這個簡單的C99程序:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{

  if (argc < 2) {
    printf("Usage: %s file_name\n", argv[0]);
    return 1;
  }

  FILE* file = fopen(argv[1], "w");
  if (!file) {
    printf("No such file: %s\n", argv[1]);
    return 2;
  }

  fprintf(file, "some text...");

  fclose(file); 

  return 0;
}

非常簡單。 它需要一個參數(一個文件名)並打印一些文本。 不能更簡單。

編譯它與clang write_to_file.c -o write_to_file.ogcc write_to_file.c -o write_to_file.o

現在運行./write_to_file.o some_file (打印到some_file )。 然後運行cat some_file 。 正如所料,結果是some text...

現在讓我們變得更加奇特。 在終端中鍵入(./write_to_file.o /dev/stdout) > some_file 。 我們要求程序寫入其標準輸出 (而不是常規文件),然後我們將該stdout重定向到some_file (使用> some_file )。 我們可以使用下面的任何一個來達到這個目的:

  • (./write_to_file.o /dev/stdout) > some_file ,意思是“使用stdout

  • (./write_to_file.o /dev/stderr) 2> some_file ,意思是“使用stderr ,並使用2>重定向”

  • (./write_to_file.o /dev/fd/2) 2> some_file ,與上面相同; stderr是默認分配給Unix進程的第三個文件描述符(在stdinstdout

  • (./write_to_file.o /dev/fd/5) 5> some_file ,意思是“使用你的第六個文件描述符,並將其重定向到some_file

如果不清楚的話,我們使用的是Unix管道而不是實際的文件(畢竟,所有的東西都是Unix中的文件)。 我們可以用這個管道做各種奇特的事情:把它寫到一個文件中,或者把它寫到一個命名的管道,並在不同的進程之間共享它。

現在,我們來創建一個命名管道:

mkfifo my_pipe

如果你現在輸入ls -l ,你會看到:

total 32
prw-r--r--  1 pooriaazimi  staff     0 Jul 15 09:12 my_pipe
-rw-r--r--  1 pooriaazimi  staff   336 Jul 15 08:29 write_to_file.c
-rwxr-xr-x  1 pooriaazimi  staff  8832 Jul 15 08:34 write_to_file.o

注意第二行開頭的p 。 這意味著my_pipe是一個(命名)管道。

現在,讓我們指定我們想用我們的管道做什麼:

gzip -c < my_pipe > out.gz &

這意味著: gzip把我放在my_pipe裡面,並把結果寫在out.gz&最後要求shell在後台運行這個命令。 你會得到類似於[1] 10449 ,然後控制回到終端。

然後,只需將我們的C程序的輸出重定向到這個管道:

(./write_to_file.o /dev/fd/5) 5> my_pipe

要么

./write_to_file.o my_pipe

你會得到

[1]+  Done                    gzip -c < my_pipe > out.gz

這意味著gzip命令已經完成。

現在,再做一個ls -l

total 40
prw-r--r--  1 pooriaazimi  staff     0 Jul 15 09:14 my_pipe
-rw-r--r--  1 pooriaazimi  staff    32 Jul 15 09:14 out.gz
-rw-r--r--  1 pooriaazimi  staff   336 Jul 15 08:29 write_to_file.c
-rwxr-xr-x  1 pooriaazimi  staff  8832 Jul 15 08:34 write_to_file.o

我們已經成功地gzip我們的文本!

執行gzip -d out.gz解壓縮這個gzip文件。 它將被刪除並創建一個新文件( out )。 cat out了:

some text...

這是我們的預期。

不要忘記用rm my_pipe刪除管道!

現在回到PhantomJS。

這是一個簡單的PhantomJS腳本( render.coffee ,用CoffeeScript編寫),它有兩個參數:一個URL和一個文件名。 它加載URL,渲染並將其寫入給定的文件名:

system = require 'system'

renderUrlToFile = (url, file, callback) ->
  page = require('webpage').create()
  page.viewportSize = { width: 1024, height : 800 }
  page.settings.userAgent = 'Phantom.js bot'

  page.open url, (status) ->
    if status isnt 'success'
      console.log "Unable to render '#{url}'"
    else
      page.render file

    delete page
    callback url, file


url         = system.args[1]
file_name   = system.args[2]

console.log "Will render to #{file_name}"
renderUrlToFile "http://#{url}", file_name, (url, file) ->
  console.log "Rendered '#{url}' to '#{file}'"
  phantom.exit()

現在在終端中輸入phantomjs render.coffee news.ycombinator.com hn.png ,將黑客新聞首頁顯示到文件hn.png 。 它按預期工作。 那麼phantomjs render.coffee news.ycombinator.com hn.pdf

讓我們重複我們之前用C程序做的事情:

(phantomjs render.coffee news.ycombinator.com /dev/fd/5) 5> hn.pdf

它不工作... :(為什麼?因為,如PhantomJS手冊中所述

渲染(文件名)

將網頁渲染到圖像緩衝區,並將其保存為指定的文件。

目前輸出格式是基於文件擴展名自動設置的。 支持的格式是PNG,JPEG和PDF。

它失敗了,只是因為/dev/fd/2/dev/stdout都不以.PNG結尾

但沒有恐懼,命名管道可以幫助你!

創建另一個命名管道,但是這次使用擴展名.pdf

mkfifo my_pipe.pdf

現在,告訴它簡單地把它inout到hn.pdf

cat < my_pipe.pdf > hn.pdf &

然後運行:

phantomjs render.coffee news.ycombinator.com my_pipe.pdf 

hn.pdf美麗的hn.pdf

顯然你想做更複雜的事情,只是輸出,但我相信現在很清楚你應該做什麼:)

TL; DR:

  1. 創建一個命名管道,使用“.pdf”文件擴展名(所以它愚弄PhantomJS認為這是一個PDF文件):

    mkfifo my_pipe.pdf
    
  2. 做任何你想做的事情與文件的內容,如:

    cat < my_pipe.pdf > hn.pdf
    

    這只是cathn.pdf

  3. 在PhantomJS中,渲染到這個文件/管道。

  4. 稍後,您應該刪除管道:

    rm my_pipe.pdf
    

正如Niko所指出的那樣,你可以使用renderBase64()把網頁渲染到圖像緩衝區,並以base64編碼的字符串的形式返回結果。
但現在這只適用於PNG,JPEG和GIF。

要從phantomjs腳本寫入stdout,只需使用文件系統API。

我使用這樣的圖像:

var base64image = page.renderBase64('PNG');
var fs = require("fs");
fs.write("/dev/stdout", base64image, "w");

我不知道renderBase64()的PDF格式是否將在未來版本的phanthomjs中,但作為解決方法,沿著這些線路的東西可能適合你:

page.render(output);
var fs = require("fs");
var pdf = fs.read(output);
fs.write("/dev/stdout", pdf, "w");
fs.remove(output);

其中output是PDF文件的路徑。





io-redirection