使用Perl处理PostScript和创建PDF文档
在编程领域,处理PostScript和创建PDF文档是常见的需求。本文将介绍如何使用Perl语言来完成这些任务,包括使用PostScript模块和 PDF::API2 模块。
1. 使用PostScript模块
在处理PostScript时,有几个关键的属性和方法值得关注。
-
linewidth和linetint属性 :这两个属性的功能与addArc()方法中的描述一致。 -
Write()方法 :$tb->Write()方法用于生成渲染添加到Elements对象中的线条、矩形或弧线的PostScript代码。该方法返回一个包含PostScript代码的字符串,可将其写入文件、传递给进程或追加到其他PostScript代码中。
此外,还有一些其他处理PostScript的模块未在本文详细介绍:
- Font::AFM 模块 :由Gisle Aas开发,提供解析Adobe字体度量文件格式的基本例程。可通过 http://search.cpan.org/search?module=Font::AFM 查找。
- PostScript::FontMetrics 模块 :由Johan Vromans开发,提供查询字体度量信息的强大接口。可通过 http://search.cpan.org/search?module=PostScript::FontMetrics 查找。
- PostScript::PrinterFontMetrics 模块 :允许查询打印机字体度量(PFM)。可通过 http://search.cpan.org/search?module=PostScript::PrinterFontMetrics 查找。
- PostScript::BasicTypesetter 模块 :同样由Johan Vromans开发,与本章描述的模块功能类似,但提供更具过程性的接口。可通过 http://search.cpan.org/search?module=PostScript::BasicTypesetter 查找。
2. 使用 PDF::API2 模块创建PDF文档
PDF::API2 模块可用于动态创建新的PDF文档或操作现有的PDF文档。不过,它不支持Perl 5.005系列发行版,需要Perl 5.6.x,并且需要预先安装 Compress::Zlib 、 Font::TTF 和 Text::PDF 模块。
2.1 PDF::API2 简介
顶级的 PDF::API2 对象维护一个内部数据结构,大致类似于PDF文档结构。该对象知道如何构建最终PDF文档的头部、主体和交叉引用部分。在构建文档时,需要创建对象并将其添加到顶级文档中。定义了三种类型的对象:结构对象、内容流对象和资源对象。
- 结构对象 :用于定义文档的页面、大纲和注释树。例如, Page 对象描述单个页面, Outlines 对象定义大纲条目的树根, Outline 对象定义单个大纲条目, Annotation 对象用于向页面添加浮动注释。
- 内容流对象 :用于在页面上绘制图形或文本。例如, Text 对象可用于在页面上绘制文本, Gfx 对象可用于绘制线条和形状。
下面是使用 Text 对象绘制“Hello World”字符串的示例代码:
#!/usr/bin/perl -w
#
# Example 12-1. Hello World
use strict;
use PDF::API2;
my $pdf=PDF::API2->new;
my $page=$pdf->page( ); # Add a new page
$page->mediabox(400, 200);
# Set the dimensions
my $text=$page->text( ); # Add the Text object
$text->translate(65, 75);
# Position the Text object
my $font = $pdf->corefont('Helvetica-Bold',1);
$text->font($font,48);
# Assign a font to the Text object
$text->text('Hello World');
# Draw the string
print $pdf->stringify( ); # Output the document as a PDF
$pdf->end;
# Destroy the PDF object
exit;
使用 Gfx 对象绘制随机大小圆圈的示例代码如下:
#!/usr/bin/perl -w
# Example 12-2. Hello World with graphics
use strict;
use PDF::API2;
my $pdf=PDF::API2->new;
my $page=$pdf->page( );
$page->mediabox(400, 200);
my $g = $page->gfx( ); # Add a Gfx object
$g->strokecolor("#FF0000");
# Set the stroke color
$g->fillcolor("#FF0000");
# Set the fill color
for my $i (0..10) {
for my $j (0..5) {
# Draw a circle with random radius
$g->circle($i*40, $j*40, rand(25)+1);
}
}
$g->fillstroke( ); # Fill and stroke
my $text=$page->text( );
$text->translate(65, 75);
$text->font($pdf->corefont('Helvetica-Bold',1),48);
$text->text('Hello World');
print $pdf->stringify( );
$pdf->end;
exit;
Gfx 对象还可用于绘制图像和裁剪路径。以下是插入JPEG图像并进行裁剪的示例代码:
#!/usr/bin/perl -w
# Example 12-3. Images and clipping paths
use strict;
use PDF::API2;
my $pdf=PDF::API2->new;
my $page=$pdf->page( );
$page->mediabox(300, 300);
my $gfx = $page->gfx( );
$gfx->circle(150, 150, 150); # Draw a circular path
$gfx->clip( ); # Make this path the clipping path
$gfx->stroke( ); # Draw the path
my $img = $pdf->image('scotty.jpg'); # Read a JPEG image
$gfx->image($img, 0, 0); # Add it to the page at the origin
print $pdf->stringify( );
$pdf->end;
exit;
2.2 创建地址标签
下面的示例将一个表示邮寄地址标签集合的XML文件格式化为多页PDF文档,可调整列和行之间的间距以适应不同样式的标签纸。该示例使用 XML::Simple 模块解析输入的XML文件。
#!/usr/bin/perl -w
#
# Use the PDF::API2 module to generate columns of
# text for printing names and addresses on labels.
use strict;
use PDF::API2; # Used to generate the PDF output
use XML::Simple; # Used to parse the XML input
my %font = ( ); # A hash holding plain and bold font styles
my ($rows, $columns) = (11,3); # Size of each label is calculated
my ($hspace, $vspace) = (6, 0); # Space between columns and rows
my ($tmargin, $bmargin, # The margins of the page
$lmargin, $rmargin) = (36, 36, 36, 36);
my ($width, $height) = (612, 792); # Dimensions of page
my $print_grid_lines = 1; # If true, print grid lines
# Calculate the width and height of each label
my $colwidth = ($width-$lmargin-$rmargin-
($columns-1)*$hspace)/$columns;
my $rowheight = ($height-$tmargin-$bmargin-
($rows-1)*$vspace)/$rows;
# Create a new top-level PDF document
# and initialize the font objects for later use
my $pdf=PDF::API2->new;
$font{'plain'} = $pdf->corefont('Helvetica',1);
$font{'bold'} = $pdf->corefont('Helvetica-Bold',1);
foreach (keys(%font)) {
$font{$_}->encode('latin1');
}
# Create a new simple XML parser.
# XML::Simple only implements two functions: XMLin and XMLout.
my $parser = new XML::Simple( );
my $data = $parser->XMLin($ARGV[0]);
my @labels = dereference($data->{'label'});
my ($page, $text, $label);
# Each element of @labels is a reference to a hash containing
# the parsed content of each name and address
PAGE: while (@labels) {
$page=$pdf->page( ); # Add a new page
$page->mediabox($width, $height); # Set the dimensions
# Add a new graphic state element to be used if
# $draw_grid_lines is true.
my $g = $page->gfx( );
$g->strokecolor("#FF0000");
if ($print_grid_lines) {
# Draw the bounding box
$g->rect($lmargin, $bmargin,
$width-$lmargin-$rmargin,
$height-$tmargin-$bmargin);
$g->stroke( );
$g->endpath( );
}
# Add a text block that holds all of the text on the page
$text=$page->text( );
# Loop through the columns
foreach my $c (0..$columns-1) {
my $x = $lmargin + $c * ($colwidth + $hspace);
if ($print_grid_lines && ($c>0)) {
# Print a vertical grid line
$g->move($x, 0);
$g->line($x, $height);
$g->move($x-$hspace, 0);
$g->line($x-$hspace, $height);
$g->stroke;
$g->endpath( );
}
# Loop through the rows
foreach my $r (0..$rows-1) {
my $y = $height - $tmargin - $r * ($rowheight + $vspace);
if ($print_grid_lines && ($r > 0)) {
# Print two horizontal grid lines
$g->move(0, $y);
$g->line($width, $y);
$g->move(0, $y+$vspace);
$g->line($width, $y+$vspace);
$g->stroke;
$g->endpath( );
}
# Add three lines: fullname, address, and city/state/zip
$text->translate($x+6, $y-16);
my $label = shift(@labels);
$text->font($font{'bold'},10);
$text->text($label->{'fullname'});
$text->cr(-16);
$text->font($font{'plain'},10);
$text->text($label->{'address'});
$text->cr(-16);
$text->text("$label->{'city'} $label->{'state'} ".
"$label->{'zip'}");
unless (@labels) {
last PAGE; # Jump out if no more labels
}
}
}
}
print $pdf->stringify( ); # Print the object as a string
$pdf->end;
exit;
sub dereference {
# We need this function if the input XML has only one element.
# If the parameter is an array reference, de-reference
# and return it. Otherwise return the parameter unchanged
my $ref = shift;
if (ref($ref) eq 'ARRAY') {
return (@$ref);
} else {
return ($ref);
}
}
所需的地址标签XML数据格式如下:
<labels>
<label>
<fullname>Buckminster Thomas</fullname>
<address>942 Scrofulous Dr.</address>
<city>Ashaway</city>
<state>KY</state>
<zip>28621</zip>
</label>
<label>
<fullname>Elizabeth O'Neill</fullname>
<address>426 Hollow Ct.</address>
<city>West Warwick</city>
<state>RI</state>
<zip>13858</zip>
</label>
...
</labels>
3. PDF::API2 模块的其他操作
除了上述功能, PDF::API2 模块还提供了一些其他方法。
| 方法 | 描述 |
|---|---|
clonepage(source, target) | 创建一个新页面,其内容是源页面的副本,页面编号为 target 。若 target 为 -1,则将副本页面插入到文档末尾。 |
corefont(fontname [, noembed]) | 使用14种“核心”PDF字体之一向文档添加字体字典。若 noembed 为 false ,则将字体的整个度量集嵌入文档。 |
end() | 销毁PDF对象中的所有数据,应在不再需要文档对象时调用。 |
image(filename) | 创建一个新的 Image 对象,该对象作为内容流块包含在PDF文档中。图像可以是JPEG、PNG或PNM格式的文件。 |
imagemask(image, file) | 为先前创建的图像对象添加遮罩。遮罩应为灰度JPG、PNG或PNM文件。灰度级别对应于每个像素处遮罩的不透明度,0表示透明,255表示不透明。 |
14种核心PDF字体如下:
| 字体名称 | 字体名称 |
| ---- | ---- |
| Courier | Courier-Bold |
| Courier-Oblique | Courier-BoldOblique |
| Times-Roman | Times-Bold |
| Times-Italic | Times-BoldItalic |
| Helvetica | Helvetica-Bold |
| Helvetica-Oblique | Helvetica-BoldOblique |
| Symbol | ZapfDingbats |
通过以上介绍,你可以使用Perl语言处理PostScript和创建PDF文档,实现诸如绘制图形、插入图像、创建地址标签等功能。希望这些内容对你有所帮助。
使用Perl处理PostScript和创建PDF文档
4. 向现有PDF文件添加内容
PDF::API2 对象代表一个顶级的PDF文档,既可以从头开始创建页面并添加 Gfx 或 Text 对象进行绘制,也可以读取现有的PDF文件。若要操作现有文件,在创建顶级 PDF 对象时使用 open() 方法。
以下示例展示了如何打开一个现有的PDF文件,并在每一页添加一个旋转的“Confidential”印章:
#!/usr/bin/perl -w
#
# Example 12-4. Add a stamp to an existing document.
use strict;
use PDF::API2; # Used to generate the PDF output
unless (defined($ARGV[0])) {
die "Please provide a filename.\n";
}
# Open the PDF file whose name was provided on the command line
my $pdf = PDF::API2->open($ARGV[0]) or
die "Couldn't open $ARGV[0]!\n";
# Initialize the font used to create the stamp
my $font = $pdf->corefont('Helvetica');
my ($page, $text);
# Loop through the pages
for (my $n=1; $n <= $pdf->pages( ); $n++) {
$page = $pdf->openpage($n);
# Create a new text block on the page, center and rotate it
$text = $page->text( );
$text->transform( -translate => [198, 306],
-rotate => 45);
# Set the font and fill color
$text->font($font, 36);
$text->fillcolor("#FF0000");
# Add a string of text to the text block
$text->text_center('C O N F I D E N T I A L');
}
# Update the original PDF file in-place
$pdf->update( );
$pdf->end;
exit;
操作步骤如下:
1. 检查输入 :确保命令行提供了要打开的PDF文件名。
2. 打开文件 :使用 open() 方法打开指定的PDF文件。
3. 初始化字体 :使用 corefont() 方法添加Helvetica字体。
4. 遍历页面 :使用 openpage() 方法获取每一页的 Page 对象。
5. 添加文本 :在每一页创建一个 Text 对象,设置其位置和旋转角度,设置字体和填充颜色,然后添加“Confidential”文本。
6. 更新文件 :使用 update() 方法将更改写回原文件。
7. 销毁对象 :使用 end() 方法销毁PDF对象。
5. 总结与操作流程梳理
通过上述内容,我们了解了使用Perl处理PostScript和创建、操作PDF文档的方法。下面是使用 PDF::API2 模块的主要操作流程:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
A([开始]):::startend --> B{选择操作类型}:::decision
B -->|创建新文档| C(创建顶级PDF对象: PDF::API2->new):::process
B -->|操作现有文档| D(打开现有PDF文件: PDF::API2->open):::process
C --> E(设置页面和字体等资源):::process
D --> E
E --> F{添加内容类型}:::decision
F -->|文本| G(添加Text对象并设置属性和内容):::process
F -->|图形| H(添加Gfx对象并绘制图形):::process
F -->|图像| I(添加Image对象并放置图像):::process
G --> J(继续添加其他内容?):::decision
H --> J
I --> J
J -->|是| F
J -->|否| K(输出文档: stringify()或update()):::process
K --> L([结束]):::startend
6. 注意事项
- 版本要求 :
PDF::API2模块不支持Perl 5.005系列发行版,需要Perl 5.6.x,并且需要预先安装Compress::Zlib、Font::TTF和Text::PDF模块。 - 字体嵌入 :使用
corefont()方法时,如果noembed参数为false,字体的整个度量集将嵌入文档,可能会增加文件大小。 - 文件路径 :使用
XML::Simple模块解析XML文件时,需要指定输入XML文件的完整路径。
通过掌握这些知识和操作方法,你可以使用Perl语言灵活地处理PostScript和创建、操作PDF文档,满足不同的业务需求。无论是简单的文本输出,还是复杂的图形和图像组合,都能轻松实现。希望本文能为你在相关领域的开发工作提供有价值的参考。
超级会员免费看
12

被折叠的 条评论
为什么被折叠?



