【问题标题】:How to Render a PDF using Perl如何使用 Perl 渲染 PDF
【发布时间】:2014-03-05 03:28:53
【问题描述】:

是否可以使用 PERL 在浏览器中呈现 pdf?我拥有的是一个将渲染的 pdf 二进制文件发送到 perl 的 flash 应用程序。 pdf 是从 AlivePDF 生成的。

#!C:\Perl\bin\perl.exe
##
BEGIN { $ENV{PATH} = ''; delete @ENV{ 'IFS', 'CDPATH', 'ENV', 'BASH_ENV'}; }
use strict;
use warnings;
no warnings qw (redefine closure);
use CGI;
my $CGI = new CGI();

#name=generated.pdf&method=inline these are passed via the URL and are in the environmental variable QUERY_STRING
my %nv_pairs = map{my @tmp = split(/=/,$_);$tmp[0] => $tmp[1] }split(/&/,$ENV{QUERY_STRING});
my $name = $nv_pairs{name};
my $method = $nv_pairs{method};

#Raw Data is stored in the POST Parameter POSTDATA
my $pdf = $CGI->param('POSTDATA');

print "Content-Type: application/pdf\r\n";
print "Content-Length: " . length($pdf) . "\r\n";
print "Content-Disposition :$method\n\n";
print $pdf;

问题是我想实际渲染 pdf 的样子。我可以保存该二进制代码并在 Adob​​e Reader 中手动打开它并正确呈现。

我想让它在浏览器中呈现,但我不知道如何实现。

当前的输出(浏览器显示的内容)如下所示:

Content-Type: application/pdf
Content-Length: 432785
Content-disposition:inline; filename="test.pdf"

%PDF-1.5
1 0 obj
<</Type /Pages
/Kids [3 0 R 5 0 R]
/Count 2>>
endobj
3 0 obj
<</Type /Page
/Parent 1 0 R
/MediaBox [0 0 612.00 792.00]
/Resources 2 0 R

这只是显示文件的一部分,但我希望这会有所帮助。我不想显示代码,我希望它看起来像图形。如果我下载这个文件,并将扩展名更改为 .pdf,它就可以完美运行。

【问题讨论】:

  • 所以您想在不渲染 pdf 的情况下渲染 pdf 的样子?您不能只提供指向 pdf 本身的超链接吗?
  • 我不确定你的意思。我有创建 pdf 的代码,但我希望它能够呈现(看起来像图像)。我希望这是有道理的。
  • 令我困惑的是“看起来像图像”部分。让浏览器简单地显示 pdf 不是最好的吗?对我来说,您所说的听起来像是您希望将 pdf 显示为 jpg 或其他内容。
  • 我确实希望它显示 pdf。请查看我的编辑。
  • 为什么要手动解析QUERY_STRING?

标签: perl flash pdf alivepdf


【解决方案1】:

我没有在请求正文中创建 PDF 的 Flash 应用程序,但我根据具有相同响应标头的静态资源的输出对其进行了验证。 Content-Disposition 是关键。这在 Konqueror 中使用 Okular KPart 进行了测试并且可以正常工作,我完全希望其他浏览器/插件组合也可以工作。

#!/usr/bin/perl -T
# ↑↑↑↑↑
# on Windows you can just write …
#!perl -T
# … instead, using the Unix shebang however does no harm
use strict;
use warnings FATAL => 'all';
use CGI qw();
use IO::File qw();

# delete @ENV{qw(BASH_ENV CDPATH ENV IFS PATH)};
# ↑↑↑↑↑
# Cleaning path is required for taint-checked programs
# that want to run other programs. It does not affect anything here,
# so I commented it out.

my $c = CGI->new;

# untaint data coming from outside
my ($name) = defined $c->url_param('name') ?
    $c->url_param('name') =~ /\A ([a-zA-Z_-]{1,40}\.pdf) \z/msx : ();
my ($method) = defined $c->url_param('method') ?
    $c->url_param('method') =~ /\A (attachment|inline) \z/msx : ();
die 'invalid parameters' unless $name or $method;

# FIXME: untaint blindly because I don't know how to validate PDF
my ($pdf) = $c->param('POSTDATA') =~ /(.*)/msx;

STDOUT->binmode(':raw');
STDOUT->print($c->header(
    -Content_Type        => 'application/pdf',
    -Content_Length      => length($pdf),
    -Content_Disposition => qq($method; filename="$name"),
));
STDOUT->print($pdf);

请注意您是mixing GET and POST parameters。了解如何编写安全的 CGI 程序。

【讨论】:

  • 不过,这只是打印出纯文本而不是渲染的 pdf。有什么想法我可能做错了吗?
  • 您使用哪些浏览器/插件对此进行了测试?
  • 哪个插件?如果您没有在浏览器中设置 PDF 插件来拦截 MIME 类型,所有这些都无法正常工作。
  • 我不知道我是否有任何特定于 PDF 的插件。你能解释一下吗?
  • 只有当您拥有一个功能强大的插件时,您才能期望在浏览器中呈现 PDF!我认为这整个事件开始变成一场野鹅追逐。尝试前往about:plugins 获取信息(复制地址,粘贴到 URL 栏中)。
【解决方案2】:

您需要添加以下 HTTP 标头

print "Content-Transfer-Encoding: binary\n";

以下内容对我来说可以读取 pdf 文件并显示它:

use strict;
use warnings;

my $file = "discover.pdf"; # a pdf I happen to have
my $pdf;

open (my $fh, $file);
binmode $fh; # set the file handle to binary mode
while (<$fh>){ $pdf .= $_; } # read it all into a string;
close ($fh);

showPdf($pdf); # call the display function

sub showPdf {

        my $pdf = shift;
        my $file = shift || "new.pdf"; # if no name is given use this
        my $method = shift || "Content-disposition:inline; filename='$file'"; # default method
        my $size = length($pdf);

        print "Content-Type: application/pdf\n";
        print "Content-Length: $size\n";
        print "$method\n";
        print "Content-Transfer-Encoding: binary\n\n"; # blank line to separate headers

        print $pdf;

}

可以将相同的功能添加到原始代码中,并且应该像这样工作:

#!C:\Perl\bin\perl.exe
##
BEGIN { $ENV{PATH} = ''; delete @ENV{ 'IFS', 'CDPATH', 'ENV', 'BASH_ENV'}; }
use strict;
use warnings;
no warnings qw (redefine closure);
use CGI;
my $CGI = new CGI();

#name=generated.pdf&method=inline these are passed via the URL and are in the environmental variable QUERY_STRING
my %nv_pairs = map{my @tmp = split(/=/,$_);$tmp[0] => $tmp[1] }split(/&/,$ENV{QUERY_STRING});
my $name = $nv_pairs{name};
my $method = $nv_pairs{method};

#Raw Data is stored in the POST Parameter POSTDATA
my $pdf = $CGI->param('POSTDATA');

showPdf($pdf, $name, $method);

sub showPdf {

    my $pdf = shift;
    my $file = shift || "new.pdf"; # if no name is given use this
    my $method = shift || "Content-disposition:inline; filename='$file'"; # default method
    my $size = length($pdf);

    print "Content-Type: application/pdf\n";
    print "Content-Length: $size\n";
    print "$method\n";
    print "Content-Transfer-Encoding: binary\n\n"; # blank line to separate headers

    print $pdf;

}

【讨论】:

  • 在标题行中将 \r\n 更改为 \n\n。如果这不能解决它,您可以更新您当前获得的输出吗?
  • 那还是不行。输出仍然与我在上面的编辑中描述的一样。
  • 我使用我正在使用的概念验证脚本编辑了我的解决方案。是打印我建议的新标题吗?
  • 没有。现在我遇到了错误。我并没有像您一样使用“discover.pdf”打开文件,而是将参数作为字节传递。
  • 您遇到了什么错误?你说如果你写出一个文件,它就可以工作。您是否以相同的方式传递它并简单地将$CGI-&gt;param('POSTDATA'); 打印到文件中?如果是这样,那与将文件读入标量然后像我一样输出它之间应该没有区别。
猜你喜欢
  • 1970-01-01
  • 2010-10-05
  • 2019-02-13
  • 2014-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多