【问题标题】:Convert PDF to Jpg with ghostscript from stdin(string) to stdout使用从标准输入(字符串)到标准输出的 ghostscript 将 PDF 转换为 Jpg
【发布时间】:2018-04-17 11:11:06
【问题描述】:

我正在尝试使用 php 中的 ghostscript 将多页 pdf 转换为 jpg。现在的命令看起来像这样:

gs -q -dBATCH -sDEVICE=jpeg -dNOPAUSE -dSAFER -dJPEGQ=100 -dGraphicsAlphaBits=4 -dTextAlphaBits=4 -r72 -sOutputFile=- some.pdf

我想要的是找到一种方法将 pdf 作为字符串输入,看起来像这样:'%PDF-1.4 %���� 1 0 obj endobj 2 0 obj endobj, etc.'并将所有页面输出到标准输出。为命令提供一个实际的 pdf 文件效果很好,但它返回一个页面。如果选择文件写入,则可以选择 p%03d.jpg 来获取所有页面,但我需要将其转储到临时/内存中。据我了解,您需要使用管道才能使其正常工作。我用 proc_open() 做了一些事情,但没有成功,因为我不知道如何将字符串传递给管道。

$args = [
    '-dBATCH',
    '-sDEVICE=jpeg',
    '-dNOPAUSE',
    '-dSAFER',
    '-dJPEGQ=100',
    '-dGraphicsAlphaBits=4',
    '-dTextAlphaBits=4',
    '-r72',
    '-sOutputFile=-',
    $path . '/some.pdf'// this shouold be passed as string stdin
];

$descr = [
    0 => ['pipe', 'r'],
    1 => ['pipe', 'w'],
    2 => ['pipe','w']
];
$pipes = array();
$args = implode(' ', $args);
$commd = "gs -q $args";

$process = proc_open($commd, $descr, $pipes);

$response = '';

if (is_resource($process)) {
    fputs($pipes[0], $pdf);
    fclose($pipes[0]);

    while ($f = fgets($pipes[1])) {
        $response .= $f;
    }

    fclose($pipes[1]);
    fclose($pipes[2]);
    proc_close($process);
}

echo '<img src="data:image/png;base64, ' . base64_encode($response) . '" />';

更新: 找到输入的解决方案。它是一个破折号,而不是代表输入文件的最后一个参数。多页输出仍然是个问题。

【问题讨论】:

  • Hello @Calin 不要自己实现,我强烈建议您使用抽象库,例如:ghostscript-PHP 用于 GhostScript 或 imagick
  • 嗨@Yanis-git。感谢您的回答。我想避免使用 Imagick,因为它在合理的分辨率上真的很慢,对于另一个它没有适应这个,它是非常基本的。

标签: php ghostscript


【解决方案1】:

您无法使用 Ghostscript 在内存中呈现 PDF 文件。

Ghostscript 仅处理磁盘中的 PDF 文件。如果您通过管道输入来自标准输入的所有内容,那么 Ghostscript 会创建一个临时文件,将 PDF 存储在其中,然后呈现该临时文件。这是因为 PDF 文件本质上需要能够在文件中随机查找。

实际上,通过标准输入发送文件,您只是将临时文件的创建转移到在 Ghostscript 中完成,而不是自己完成。如果您认为这样做会以某种方式提高性能,那您就大错特错了。

如果您将- (stdout) 指定为输出文件,则all 将输出发送到stdout。如果有不止一页,那么这两页都被发送到输出(它还能做什么?)。由您决定每个页面的结束位置并将其拆分。

如果您省略-q 并查看发送到stdout 的内容(例如通过将其重定向到文件),您将看到通常的Ghostscript 样板文件在开始时发送。如果您进一步省略-dNOPAUSE(请注意,您需要为每一页按“返回”并且不会提示您,因此只需敲击一下键)然后查看输出,您将看到每一页都是用

分隔
>>showpage, press <return> to continue<<

因此您可以看到每个页面都已发送,并且由您决定每个 JPEG 文件的结束位置。

鉴于您将多页输出发送到标准输出,我不确定您还期望发生什么。

【讨论】:

  • 感谢您提供此信息。写入临时文件就可以了。我不想显式创建实际的 pdf 并将其传递给 gs,这就是我选择 stdin 的原因(我不确定这是正确的表达方式)。所以我的标准输入问题解决了,但是关于标准输出我在输出中找不到任何 jpg "separator" >>showpage, ...除此之外,使用
  • 如果您想看到“showpage”消息,那么您需要从命令行中删除 -q 和 -dNOPAUSE,正如我所说的。正如我也说过的,如果您将所有内容都发送到标准输出,那么您将自行确定每个图像的结尾。所以你可以做你想做的事(将数据发送到 stdou),但你必须自己做一些工作来恢复单个图像。
  • 你能告诉我们通过基于实际命令输出的模式来处理输出字符串有多可靠吗,换句话说,输出是否有可能改变,不知道可能在更新版本?
  • 输出是 JPEG 图像,打包为 JFIF 文件,由您决定如何确定每张图像的开头和结尾。
  • 我设法做到了,它的工作就像一个魅力,但我担心ghostscript是否可以改变它的输出格式,因为如果是这样,我有第二个选项来临时存储图像并将它们转换为字符串这是可靠的,但这样做是无用的,字符串->图像->字符串。也许忘了提到我需要将响应作为 base64 编码字符串发送。无论如何,再次感谢您的帮助。
【解决方案2】:

我已在本地测试此代码并为我工作:

我正在使用passthru 直接输出答案,并使用output buffering 来捕获一个

<?php

$command = "/path/to/gs -dBATCH -sDEVICE=jpeg -dNOPAUSE -dSAFER -dJPEGQ=100 -dGraphicsAlphaBits=4 -dTextAlphaBits=4 -r72 -sOutputFile=- ./someFile.pdf";

// Capture output on buffer.
ob_start();

// Will automatically output answer of your command
passthru($command);
// you get buffered output.
$response = ob_get_contents();
// Flush buffer.
ob_end_clean();

echo '<img src="data:image/png;base64, ' . base64_encode($response) . '" />';

【讨论】:

  • 是的,如果您在磁盘上有文件,这可能是一个很好的解决方案,但如前所述,我想通过管道传递它。
  • 我不明白你想用管道实现什么
  • 我不能传递一个实际的文件,而是一个字符串,所以我必须通过管道传递它
  • 哦,我明白了,您是否可以将字符串临时存储在文件中,然后在完成特征后将其删除?
猜你喜欢
  • 2012-03-16
  • 2018-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-17
  • 2013-10-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多