在Perl中生成PDF报告?

13
所有Perl的PDF库似乎都有些过时,停留在20世纪80年代。您需要指定PostScript点来进行布局。Java有JasperReports,Ruby有Prawn,Python有ReportLab。是否有一个非绝迹的库/模块能够让我在不到一周的编码时间内制作出漂亮的PDF文件呢?(我对PDF::API2,PDF::Table等有点失望)。我不想生成HTML并将其转换成PDF。Perl非常适合报告,但主要的报告文件格式无法以可用的方式使用。人们使用哪些库呢?
我需要:
  • 表格
  • 图表(图片)
  • 颜色
  • 格式化(最好是自动的,而不是像素级别的)
  • 页眉/页脚
如果绝对必要,我可以稍微接受包装外部(非Perl)开源工具。但我并不真正对采用重度Java服务器方法感兴趣。对于赏金,我希望采用纯Perl方法,因为我要在一个不能添加除模块外更多内容的服务器上运行它。如果您有一个有效的公共示例,请指向它。

1
这是一个非常好的问题。我有同样的需求,尝试了CPAN中能找到的所有东西。最终放弃了,并学习了足够的Python来使用ReportLab。很想把它转回Perl。 - Bill Ruppert
ReportLab 可以通过 Inline::Python 使用吗? - Joel Berger
目前似乎没有人在维护Inline模块,但是Inline::Python确实可以工作,尽管Inline::Ruby没有通过最基本的测试--它是为Perl 5.5开发的,而我正在使用一个非常新的5。但还是谢谢,如果纯Perl失败了,ReportLab看起来是个好主意... - sventechie
3
@sventech,Inline模块非常独立,即使Inline::Ruby失败了,也不能说明太多关于Inline::Python。承担大部分工作的基本框架是Inline模块,该模块最近一次更新是在2011年2月。实际上,Inline::Python的更新时间是在2011年7月。我想没有必要担心。 - Joel Berger
@JoelBerger 是的,应该没问题。从我最初查看 CPAN 的情况来看,我认为它们是由同一个人开发的,并且没有更新。似乎谷歌搜索结果会指向旧版本。 - sventechie
3个回答

10
使用Perl生成LaTeX,可能使用Template::Toolkit,然后调用编译器,如TeXLive或MikTeX或您需要的任何发行版。有一个名为Template::LaTeX的扩展程序,但您可能不需要它,它管理构建过程。
LaTeX支持所有您需要的内容。表格有些有趣,但有一些现代表格包可以简化操作(我认为它被称为ltxtable)。对于图表(您是否指的是图表),有一个名为TikZ的子语言,非常强大。
这确实是一个非常简单的工作流程,特别是如果您希望结果每次都类似(即可以使用模板)。实际上,它真的与从模板创建HTML并将其提供给浏览器没有什么不同。
另一个好处是,模板(和准备好的源代码)将是可移植的,如果您需要在另一种语言中构建报告。

谢谢,Joel。我一直在考虑这个问题,因为我熟悉LaTeX,但它有很大的开销——我需要生成很多报告。 - sventechie
如果您已经熟悉LaTeX,那么我认为这绝对是正确的选择。每当我推荐这种工作流程时,我都担心LaTeX会成为障碍。 - Joel Berger
从类似问题的旧答案中得到启发:http://stackoverflow.com/questions/6017157/pdf-file-generation-in-perl-is-there-a-primer-to-get-one-started/6023730#6023730 我肯定会建议使用模板而不是我在那里所做的,但这是可能的。 - Joel Berger
我认为LaTeX在服务器环境下计算密集度太高了,而且我无法将其放在我想要运行代码的机器上。如果没有其他办法,我可能不得不请求他们安装它或其他软件。不过还是谢谢你。 - sventechie

5
如果LaTeX太大,可以使用Inline::Python来包装ReportLab,这是大家都非常喜欢的(我没有使用过,对Python也不是很熟练)。编辑3:这里是编辑2,但是采用了模块化的风格,如果人们喜欢它(并且它具有某种稳健性),那么我可以将其发布到CPAN。现在请将.pm文件放在类似于Inline/Python/ReportLab.pm的文件结构中,放在您的@INC中的某个位置(脚本自己的基本目录通常在@INC中)。
# Inline/Python/ReportLab.pm
package Inline::Python::ReportLab;

use strict;
use warnings;

use Carp;

use Inline::Python qw/py_eval/;
our @ISA = 'Inline::Python::Object';

sub import {
  py_eval('from reportlab.pdfgen.canvas import Canvas');
}

sub new {
  my $class = shift;
  my $filename = shift || croak "Must specify file name to contructor";
  return bless(Inline::Python::Object->new('__main__', 'Canvas', $filename), $class);
}

1;

然后,脚本可以是这样的:
#!/usr/bin/env perl

use strict;
use warnings;

use Inline::Python::ReportLab;

my $c = Inline::Python::ReportLab->new('hello.pdf');
$c->drawString(100,100,"Hello World");
$c->showPage();
$c->save();

编辑2: 虽然编辑1仍然有趣,但似乎(如果我错误了,请告诉我!)我已经找出如何创建“Canvas”的实例并直接公开其方法:

#!/usr/bin/env perl

use strict;
use warnings;

use Inline::Python qw/py_eval/;

py_eval('from reportlab.pdfgen.canvas import Canvas');

my $c = Inline::Python::Object->new('__main__', 'Canvas', 'hello.pdf');
$c->drawString(100,100,"Hello World");
$c->showPage();
$c->save();

编辑2/3:这部分内容是手动界面的示例。我认为编辑2/3提供了更好的界面,可以让原始的Python类承担重要任务,而不需要(太多)包装。

编辑1:我现在已经通过手动添加方法来公开一些功能。这意味着对于每个想要使用的方法,都必须添加一个包装器方法。虽然这已经是一个可行的解决方案,但我想知道是否有一种更简单的方法来公开整个Python“画布”类,但现在我只能到这里:

#!/usr/bin/env perl

use strict;
use warnings;

use Inline Python => <<END_PYTHON;
from reportlab.pdfgen import canvas

class Canvas:
  def __init__(self,filename):
    self.canvas = canvas.Canvas(filename)
  def drawString(self,x,y,text):
    self.canvas.drawString(x,y,text)
  def save(self):
    self.canvas.showPage()
    self.canvas.save()

END_PYTHON

my $c = Canvas->new('hello.pdf');
$c->drawString(100,100,"Hello World");
$c->save();

谢谢,Joel。这肯定是令人兴奋的。我仍然希望能有一个纯Perl的解决方案,但是您的想法似乎很有效。 - sventechie
感谢您的辛勤工作和创新,Joel。如果您只添加需要访问的主要对象,我相信将这样的东西放在CPAN上会非常有帮助。但对我来说,您的代码很可能是一个不错的解决方案。我将更仔细地研究它如何适合我的目的。 - sventechie
@sventech,哪些其他对象需要构造函数?我已经开始整理CPAN模块。 - Joel Berger
鸭嘴兽,lib,图形,rl_config - 不确定如何处理通过导入设置的页面大小、单位和样式... http://www.eecho.info/Echo/python/getting-started-with-reportlab-tutorial/ http://www.protocolostomy.com/2008/10/22/generating-reports-with-charts-using-python-reportlab/ - sventechie
假设您是来自达拉斯的唯一sventech,我已将您添加为新的GitHub项目的合作者。尽情发挥您的技能,也许我们可以一起让它实现。 - Joel Berger

0
经过深思熟虑和实验,我最终编写了大量的代码来包装 PDF::API2。不幸的是,这是公司内部项目,不会发布为开源,但坦率地说,我建议使用其他语言(Python/Ruby),或者通过 JSON 等方式传递数据。我的最终结果很有效,但它需要大量的编码工作。CPAN 上正在进行对 PDF::API2 的重构,但似乎已经停滞不前。

很有趣听到你的结果。如果你看了,你会发现我没有进一步实现我的想法,因为它太难以管理了。话虽如此,我已经做了一些工作,将Mojo::Template适应生成LaTeX。就个人而言,我认为LaTeX是任何语言生成PDF的真正答案。祝贺你。 - Joel Berger
1
另外,有时候一些公司会向Perl社区捐赠代码。如果您能够询问一下,我相信很多人都会受益!只是想说一下这个 :-) - Joel Berger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接