31、使用Perl处理PostScript和创建PDF文档

使用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文档,满足不同的业务需求。无论是简单的文本输出,还是复杂的图形和图像组合,都能轻松实现。希望本文能为你在相关领域的开发工作提供有价值的参考。

【完美复现】面向配电网韧性提升的移动储能预布局与动态调度策略【IEEE33节点】(Matlab代码实现)内容概要:本文介绍了基于IEEE33节点的配电网韧性提升方法,重点研究了移动储能系统的预布局与动态调度策略。通过Matlab代码实现,提出了一种结合预配置动态调度的两阶段优化模型,旨在应对电网故障或极端事件时快速恢复供电能力。文中采用了多种智能优化算法(如PSO、MPSO、TACPSO、SOA、GA等)进行对比分析,验证所提策略的有效性优越性。研究不仅关注移动储能单元的初始部署位置,还深入探讨其在故障发生后的动态路径规划与电力支援过程,从而全面提升配电网的韧性水平。; 适合人群:具备电力系统基础知识Matlab编程能力的研究生、科研人员及从事智能电网、能源系统优化等相关领域的工程技术人员。; 使用场景及目标:①用于科研复现,特别是IEEE顶刊或SCI一区论文中关于配电网韧性、应急电源调度的研究;②支撑电力系统在灾害或故障条件下的恢复力优化设计,提升实际电网应对突发事件的能力;③为移动储能系统在智能配电网中的应用提供理论依据技术支持。; 阅读建议:建议读者结合提供的Matlab代码逐模块分析,重点关注目标函数建模、约束条件设置以及智能算法的实现细节。同时推荐参考文中提及的MPS预配置与动态调度上下两部分,系统掌握完整的技术路线,并可通过替换不同算法或测试系统进一步拓展研究。
先看效果: https://pan.quark.cn/s/3756295eddc9 在C#软件开发过程中,DateTimePicker组件被视为一种常见且关键的构成部分,它为用户提供了图形化的途径来选取日期与时间。 此类控件多应用于需要用户输入日期或时间数据的场景,例如日程管理、订单管理或时间记录等情境。 针对这一主题,我们将细致研究DateTimePicker的操作方法、具备的功能以及相关的C#编程理念。 DateTimePicker控件是由.NET Framework所支持的一种界面组件,适用于在Windows Forms应用程序中部署。 在构建阶段,程序员能够通过调整属性来设定其视觉形态及运作模式,诸如设定日期的显示格式、是否展现时间选项、预设的初始值等。 在执行阶段,用户能够通过点击日历图标的下拉列表来选定日期,或是在文本区域直接键入日期信息,随后按下Tab键或回车键以确认所选定的内容。 在C#语言中,DateTime结构是处理日期与时间数据的核心,而DateTimePicker控件的值则表现为DateTime类型的实例。 用户能够借助`Value`属性来读取或设定用户所选择的日期与时间。 例如,以下代码片段展示了如何为DateTimePicker设定初始的日期值:```csharpDateTimePicker dateTimePicker = new DateTimePicker();dateTimePicker.Value = DateTime.Now;```再者,DateTimePicker控件还内置了事件响应机制,比如`ValueChanged`事件,当用户修改日期或时间时会自动激活。 开发者可以注册该事件以执行特定的功能,例如进行输入验证或更新关联的数据:``...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值