PhantomJS:将PDF导出到stdout

时间:2012-07-10 07:13:21

标签: pdf pipe file-descriptor phantomjs io-redirection

有没有办法在PhantomJS中触发PDF导出功能而不指定扩展名为.pdf的输出文件?我们想使用stdout输出PDF。

4 个答案:

答案 0 :(得分:20)

您可以直接输出到stdout而无需临时文件。

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

有关何时添加此内容的历史记录,请参阅here

如果您想从stdin获取HTML并将PDF输出到stdout,see here

答案 1 :(得分:19)

对于极长的回答感到抱歉;我有一种感觉,我生命中需要多次参考这种方法,所以我会写“一个答案来统治它们”。我首先会对文件,文件描述符,(命名)管道和输出重定向进行一些讨论,然后回答你的问题。


考虑这个简单的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(使用{{1 }})。我们可以使用以下任何一种方法来实现这一目标:

  • > 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是默认情况下分配给Unix进程的第三个文件描述符(在stderrstdin之后)

  • stdout,表示“使用您的第六个文件描述符,并将其重定向到(./write_to_file.o /dev/fd/5) 5> some_file

如果不清楚,我们使用的是Unix管道而不是实际文件(毕竟,一切都是Unix中的文件)。我们可以使用这个管道做各种奇特的事情:将它写入文件,或将其写入命名管道并在不同进程之间共享。


现在,让我们创建一个命名管道:

some_file

如果您现在输入mkfifo my_pipe ,您会看到:

ls -l

请注意第二行开头的 p 。这意味着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 是(命名)管道。

现在,让我们指定我们想要对管道做什么:

my_pipe

这意味着:gzip -c < my_pipe > out.gz & 我放在gzip内的内容并将结果写在my_pipe中。最后的out.gz要求shell在后台运行此命令。您将获得类似&的内容,然后控件返回终端。

然后,只需将C程序的输出重定向到此管道:

[1] 10449

或者

(./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个ed文件。它将被删除,并将创建一个新文件(gzip)。 out让我们:

cat out

这是我们的预期。

不要忘记用some text...

删除管道

现在回到PhantomJS。

这是一个简单的PhantomJS脚本(rm my_pipe,用CoffeeScript编写),它带有两个参数:URL和文件名。它加载URL,呈现它并将其写入给定的文件名:

render.coffee

现在在终端中输入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也是如此。

让我们重复我们之前在C程序中所做的事情:

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

它不起作用...... :(为什么?因为,如PhantomJS's manual所述:

  

渲染(fileName)

     

将网页呈现为图像缓冲区并保存   作为指定的文件。

     

目前,输出格式是根据文件自动设置的   延期。支持的格式为PNG,JPEG和PDF。

它失败了,只是因为(phantomjs render.coffee news.ycombinator.com /dev/fd/5) 5> hn.pdf /dev/fd/2都没有以/dev/stdout结尾等等。

但没有恐惧,命名管道可以帮助你!

创建另一个命名管道,但这次使用扩展名.PNG

.pdf

现在,告诉它只是mkfifo my_pipe.pdf 它对cat的输入:

hn.pdf

然后运行:

cat < my_pipe.pdf > hn.pdf &

看到美丽的phantomjs render.coffee news.ycombinator.com my_pipe.pdf

显然你想做一些更复杂的事情只是hn.pdf输出,但我确信现在你应该做什么了:)


TL; DR:

  1. 使用“.pdf”文件扩展名创建一个命名管道(因此它欺骗PhantomJS认为它是PDF文件):

    cat
  2. 对文件内容执行任何操作,例如:

    mkfifo my_pipe.pdf
    

    只需cat < my_pipe.pdf > hn.pdf cat

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

  4. 稍后,你应该删除管道:

    hn.pdf

答案 2 :(得分:13)

正如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文件的路径。

答案 3 :(得分:2)

我不知道它是否能解决您的问题,但您也可以检查添加到PhantomJS 1.6的新renderBase64()方法:https://github.com/ariya/phantomjs/blob/master/src/webpage.cpp#L623

不幸的是,该功能尚未记录在维基上:/