phantomjs pdf to stdout

mic*_*iuc 9 javascript pdf stdout phantomjs

我拼命想把phantomJS生成的PDF输出到这里的 stdout

我得到的是一个空的PDF文件,虽然它不是0大小,但它显示一个空白页面.

var page = require('webpage').create(),
system = require('system'),
address;

address = system.args[1];
page.paperSize = {format: 'A4'};

page.open(address, function (status) {
    if (status !== 'success') {
        console.log('Unable to load the address!');
        phantom.exit();
    } else {
        window.setTimeout(function () {
            page.render('/dev/stdout', { format: 'pdf' });
            phantom.exit();
        }, 1000);
    }
});
Run Code Online (Sandbox Code Playgroud)

我称之为: phantomjs rasterize.js http://google.com>test.pdf

我试图改变/dev/stdoutsystem.stdout,但不是运气.直接将PDF写入文件可以毫无问题地工作.

我正在寻找一个跨平台的实现,所以我希望这可以在非Linux系统上实现.

nic*_*k_w 15

在Windows 上/dev/stdout//dev/stderr/在Windows上写入输出时,请PhantomJS执行以下步骤(如\ phantomjs\src\webpage.cpp中的render方法所示):

  1. 在没有/dev/stdout//dev/stderr/临时文件的路径进行分配.
  2. renderPdf使用临时文件路径调用.
  3. 将网页渲染到此文件路径.
  4. 将此文件的内容读入QByteArray.
  5. 调用QString::fromAscii字节数组并写入stdoutstderr.
  6. 删除临时文件.

首先,我构建了源代码PhantomJS,但注释掉了文件删除.在下一次运行中,我能够检查它渲染的临时文件,结果证明是完全正常的.我也尝试过运行phantomjs.exe rasterize.js http://google.com > test.png相同的结果.这立即排除了渲染问题,或者与PDF有关的任何问题,这意味着问题必须与写入数据的方式有关stdout.

在这个阶段,我怀疑是否有一些文本编码恶作剧正在进行.从以前的运行中,我有同一个文件的有效和无效版本(在这种情况下是PNG).

使用一些C#代码,我运行了以下实验:

//Read the contents of the known good file.
byte[] bytesFromGoodFile = File.ReadAllBytes("valid_file.png");
//Read the contents of the known bad file.
byte[] bytesFromBadFile = File.ReadAllBytes("invalid_file.png");

//Take the bytes from the valid file and convert to a string
//using the Latin-1 encoding.
string iso88591String = Encoding.GetEncoding("iso-8859-1").GetString(bytesFromGoodFile);
//Take the Latin-1 encoded string and retrieve its bytes using the UTF-8 encoding.
byte[] bytesFromIso88591String = Encoding.UTF8.GetBytes(iso88591String);

//If the bytes from the Latin-1 string are all the same as the ones from the
//known bad file, we have an encoding problem.
Debug.Assert(bytesFromBadFile
    .Select((b, i) => b == bytesFromIso88591String[i])
    .All(c => c));
Run Code Online (Sandbox Code Playgroud)

请注意,我使用ISO-8859-1编码QT将其用作c-strings默认编码.事实证明,所有这些字节都是相同的.该练习的目的是看我是否可以模仿导致有效数据无效的编码步骤.

为了进一步证据,我调查了\ phantomjs\src\system.cpp\ phantomjs\src\filesystem.cpp.

  • system.cpp中,System类持有引用,除其他事项外,File对于对象stdout,stdin并且stderr,被设置为使用UTF-8的编码.
  • 写入时stdout,调用对象的write功能File.此函数支持写入文本和二进制文件,但由于System类初始化它们的方式,所有写入都将被视为文本文件.

所以问题归结为:我们需要执行二进制写操作stdout,但是我们的写操作最终被视为文本并且应用了编码,导致生成的文件无效.


鉴于上述问题,我无法在不更改PhantomJS代码的情况下以任何方式在Windows上以您希望的方式工作.所以他们在这里:

第一个更改将提供一个函数,我们可以调用File对象来显式执行二进制写入.

在以下位置添加以下函数原型\phantomjs\src\filesystem.h:

bool binaryWrite(const QString &data);
Run Code Online (Sandbox Code Playgroud)

并将其定义放在\phantomjs\src\filesystem.cpp(此方法的代码来自write此文件中的方法):

bool File::binaryWrite(const QString &data)
{
    if ( !m_file->isWritable() ) {
        qDebug() << "File::write - " << "Couldn't write:" << m_file->fileName();
        return true;
    }

    QByteArray bytes(data.size(), Qt::Uninitialized);
    for(int i = 0; i < data.size(); ++i) {
        bytes[i] = data.at(i).toAscii();
    }
    return m_file->write(bytes);
}
Run Code Online (Sandbox Code Playgroud)

在第920行左右,\phantomjs\src\webpage.cpp你会看到一段代码如下:

    if( fileName == STDOUT_FILENAME ){
#ifdef Q_OS_WIN32
        _setmode(_fileno(stdout), O_BINARY);            
#endif      

        ((File *)system->_stderr())->write(QString::fromAscii(name.constData(), name.size()));

#ifdef Q_OS_WIN32
        _setmode(_fileno(stdout), O_TEXT);
#endif          
    }
Run Code Online (Sandbox Code Playgroud)

把它改成这个:

   if( fileName == STDOUT_FILENAME ){
#ifdef Q_OS_WIN32
        _setmode(_fileno(stdout), O_BINARY);
        ((File *)system->_stdout())->binaryWrite(QString::fromAscii(ba.constData(), ba.size()));
#elif            
        ((File *)system->_stderr())->write(QString::fromAscii(name.constData(), name.size()));
#endif      

#ifdef Q_OS_WIN32
        _setmode(_fileno(stdout), O_TEXT);
#endif          
    }
Run Code Online (Sandbox Code Playgroud)

那么代码替换所做的就是调用我们的新binaryWrite函数,但是这样做是由一个#ifdef Q_OS_WIN32块来保护的.我这样做是为了保留非Windows系统上的旧功能,这些系统似乎没有出现这个问题(或者他们呢?).请注意,此修复仅适用于写入stdout- 如果您愿意,您可以始终应用它,stderr但在这种情况下可能无关紧要.

如果您只想要一个预先构建的二进制文件(谁不会?),您可以phantomjs.exe在我的SkyDrive上找到这些修复程序.我的版本大约是19MB,而我之前下载的版本只有大约6MB,虽然我按照这里的说明进行操作,所以应该没问题.


Pin*_*chy 8

是的,这是正确的ISO-8859-1是QT的默认编码,因此您需要将所需参数添加到命令行--output-encoding = ISO-8859-1,以便pdf输出不会被破坏

phantomjs.exe rasterize.js --output-encoding = ISO-8859-1 <input.html> output.pdf

和rasterize.js看起来像这样(经测试,适用于Unix和Windows)

var page = require('webpage').create(),
system = require('system');

page.viewportSize = {width: 600, height: 600};
page.paperSize = {format: 'A4', orientation: system.args[1], margin: '1cm'};

page.content = system.stdin.read();

window.setTimeout(function () {
    try {
        page.render('/dev/stdout', {format: 'pdf'});
    }
    catch (e) {
        console.log(e.message + ';;' + output_file);
    }
    phantom.exit();
}, 1000);
Run Code Online (Sandbox Code Playgroud)

或者您可以使用stdout设置编码,如果您正在读取UTF-8流,那么您可能还必须为stdin设置编码;

system.stdout.setEncoding('ISO-8859-1');
system.stdin.setEncoding('UTF-8');
page.content = system.stdin.read();
Run Code Online (Sandbox Code Playgroud)