PhantomJS:导出PDF到标准输出

PhantomJS:导出PDF到标准输出,pdf,pipe,file-descriptor,phantomjs,io-redirection,Pdf,Pipe,File Descriptor,Phantomjs,Io Redirection,有没有一种方法可以在不指定扩展名为.PDF的输出文件的情况下触发PhantomJS中的PDF导出功能?我们想使用标准输出输出PDF。很抱歉回答太长;我有一种感觉,在我的一生中,我需要参考这个方法几十次,所以我会写“一个答案来统治所有人”。我将首先对文件、文件描述符、(命名的)管道和输出重定向进行一些讨论,然后回答您的问题 考虑一下这个简单的C99程序: #包括 #包括 int main(int argc,char*argv[]) { 如果(argc一些文件。我们要求程序写入其标准输出(而不是常

有没有一种方法可以在不指定扩展名为.PDF的输出文件的情况下触发PhantomJS中的PDF导出功能?我们想使用标准输出输出PDF。

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


考虑一下这个简单的C99程序:

#包括
#包括
int main(int argc,char*argv[])
{
如果(argc<2){
printf(“用法:%s文件名\n”,argv[0]);
返回1;
}
FILE*FILE=fopen(argv[1],“w”);
如果(!文件){
printf(“没有这样的文件:%s\n”,argv[1]);
返回2;
}
fprintf(文件,“一些文本…”);
fclose(文件);
返回0;
}
非常简单。它接受一个参数(文件名)并在其中打印一些文本。再简单不过了


clangwrite_to_file.c-o write_to_file.o
gcc write_to_file.c-o write_to_file.o
编译它

现在,运行
/write_to_file.o some_file
(它将打印到
some_file
)。然后运行
cat some_file
。正如预期的那样,结果是
一些文本…

现在让我们来想象一下。在终端中键入
(./write_to_file.o/dev/stdout)>一些文件
。我们要求程序写入其标准输出(而不是常规文件),然后将
stdout
重定向到
some_文件
(使用
>some_文件
)。我们本可以使用以下任何一项来实现这一点:

  • (/write_to_file.o/dev/stdout)>一些文件
    ,意思是“使用
    stdout

  • (/write_to_file.o/dev/stderr)2>一些文件
    ,意思是“使用
    stderr
    ,并使用
    2>重定向它。”

  • (/write_to_file.o/dev/fd/2)2>一些文件
    ,与上面相同
    stderr
    是默认情况下分配给Unix进程的第三个文件描述符(在
    stdin
    stdout
    之后)

  • (/write_to_file.o/dev/fd/5)5>一些文件
    ,意思是“使用第六个文件描述符,并将其重定向到
    一些文件

如果不清楚,我们使用的是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 &

你会得到

[1]+  Done                    gzip -c < my_pipe > out.gz
我们已经成功地
gzip
ed了我们的文本

执行
gzip-d out.gz
解压此
gzip
ed文件。它将被删除,并将创建一个新文件(
out
)<代码>禁止进入
获取我们:

some text...
这正是我们所期望的

不要忘记用
rm my_pipe
移除管道


现在回到幻影

这是一个简单的PhantomJS脚本(
render.coffee
,用CoffeeScript编写),它包含两个参数:URL和文件名。它加载URL、呈现URL并将其写入给定的文件名:

system=需要“系统”
renderUrlToFile=(url、文件、回调)->
page=require('webpage')。create()
page.viewportSize={宽度:1024,高度:800}
page.settings.userAgent='Phantom.js bot'
page.open url,(状态)->
如果状态不是“成功”
console.log“无法呈现“#{url}”
其他的
page.render文件
删除页面
回调url,文件
url=system.args[1]
文件名=system.args[2]
console.log“将呈现到#{file_name}”
renderUrlToFile“http://{url}”,文件名,(url,文件)->
console.log“将“#{url}”呈现为“#{file}”
幻影。退出()
现在,在终端中键入
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
它不起作用了…:(为什么?因为,如上所述:

渲染(文件名)

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

当前,输出格式是根据文件自动设置的 支持的格式有PNG、JPEG和PDF

它失败了,仅仅是因为
/dev/fd/2
/dev/stdout
都不是以
.PNG
结尾,等等

但不用担心,命名管道可以帮助你

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

mkfifo my_pipe.pdf
cat < my_pipe.pdf > hn.pdf &
现在,让它简单地
cat
它的inout to
hn.pdf

mkfifo my_pipe.pdf
cat < my_pipe.pdf > hn.pdf &
看看美丽的
hn.pdf

显然,您想做一些更复杂的事情,只需
cat
ing输出,但我相信现在您应该做的事情已经很清楚了:)


TL;医生:
  • 使用“.pdf”文件扩展名创建一个命名管道(因此它愚弄了PhantomJS,使其认为它是pdf文件):

  • 对文件内容执行任何操作,如:

    cat < my_pipe.pdf > hn.pdf
    

  • 我不知道它是否能解决您的问题,但您也可以检查添加到PhantomJS 1.6中的新
    renderBase64()
    方法:


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

    正如Niko所指出的,您可以使用
    renderBase64()
    将网页渲染到图像缓冲区,并将结果作为base64编码字符串返回。
    但目前这只适用于PNG、JP
    phantomjs render.coffee news.ycombinator.com my_pipe.pdf 
    
    mkfifo my_pipe.pdf
    
    cat < my_pipe.pdf > hn.pdf
    
    rm my_pipe.pdf
    
    var base64image = page.renderBase64('PNG');
    var fs = require("fs");
    fs.write("/dev/stdout", base64image, "w");
    
    page.render(output);
    var fs = require("fs");
    var pdf = fs.read(output);
    fs.write("/dev/stdout", pdf, "w");
    fs.remove(output);