技术开发 频道

从Flex 应用程序创建PDF文档

【IT168技术资讯】有三种方法可以从 Adobe Flex 应用程序创建 PDF 文档:

    (1)通过使用 forms/LiveCycle设计器——这个过程具有详细的记录,要求创建 XDP form(一种 Acrobat XML Data Package文件)和数据模型,并创建同步Flex应用程序和 LiveCycle 的过程;
    
    (2)通过将 PDF 打印作为 Flex 应用程序的一个功能,无缝提供打印功能(使用或不使用 LiveCycle Designer);

    (3)通过使用 LCDS 中的 Snapshots,它使用位图表示 Flash 内容。

    虽然第一种过程可保证质量和可预测的结果,但是它也需要付出双倍的努力来开发 XDP 和 Flex form,而且引入了与应用程序域无关的模型和通信。

    由于屏幕快照使用较低的 DPI,第三种打印类型适合仅用于屏幕显示的 PDF。Flex 3 应该提供对 DPI 分辨率的控制。

    当文档结构是动态的时(比如终端用户可自定义的报告或表格),第二种过程更适合。它通常使用当前版本的 LiveCycle Data Services ES(以前为 Flex Data Services)Flex,该过程通常生成更好的打印质量。其思想是,不向服务器发送用于与表单合并的数据,而是以包含数据和格式的 XDP 格式发送已经合并的压缩文档。在这种情况下,LCDS 层只需使用 XDPXFAHelper 类处理它,并将其以PDF流返回到浏览器进行显示。
下一个代码示例是 JavaServer Page (createPDF.jsp) 的服务器端部分。注意,您需要 LCDS 的商业许可版本,因为其 Express 版本不支持 PDF 生成。

 

<%@ page language="java"
import="java.io.IOException,
javax.servlet.http.HttpServletRequest,
flex.acrobat.pdf.XDPXFAHelper,
java.util.zip.Inflater,
java.util.zip.InflaterInputStream"
%>
<jsp:directive.page import="java.io.InputStream"/>
<jsp:directive.page import="java.io.ByteArrayInputStream"/>
<jsp:directive.page import="java.io.FileInputStream"/>
<jsp:directive.page import="java.io.FileOutputStream"/>
<%
//Load compressed XDP stream (received from client)
//into a byte array
byte[] result = new byte[5000000];
int resultLength =0 ;
try {
Inflater decompresser = new Inflater( );
byte[] ba = new byte[500000];
ServletInputStream si = request.getInputStream();
int k = 0;
int i = 0;
while (true ) {
k = si.read(ba, i, 500000);
i +=k;
if (k<=0) break;
}
try {//Uncompress data into result
decompresser.setInput(ba);
resultLength = decompresser.inflate(result);
} catch (Exception e) {
System.out.println(e.getMessage());
}
} catch (IOException e) {
throw new ServletException(e);
}

//The next line won’t work unless you have a commercial
// LCDS. It’s not available in Express edition
XDPXFAHelper helper = new XDPXFAHelper();

try { //load the input into PDF convertor
helper.openFromByteArray( result );
} catch (Exception e) {
e.printStackTrace();
}

// Save new PDF as a byte array
byte[] bytes = helper.saveToByteArray();

//Send PDF to the client(GZIP compression can be
// provided by an external filter)
ServletOutputStream out2 = response.getOutputStream();
response.setContentType("application/pdf");
response.setContentLength(bytes.length);
out2.write(bytes);
out2.flush();
out2.close();
%>

    在客户端(Flex)一侧需要一些简单的类。首先需要一个 ActionScript 类,该类将生成的 XDP 发送到服务器,并打开浏览器页来显示进入的 PDF。
 

import flash.net.*;
import flash.utils.ByteArray;

public class FormRenderer
{
public static function openPdf(xdp:String,
target:String="_blank"):void
{
var req:URLRequest = new URLRequest("/createPDF.jsp"); req.method = URLRequestMethod.POST;
var ba :ByteArray = new ByteArray();;
ba.writeMultiByte(xdp, "iso-8859-1");
ba.compress();
ba.position = 0;
req.data = ba;
navigateToURL(req, target);
}
}
}

    现在我们需要的只是一个具有数据和显示的 XDP 文件。虽然让一个 XDP 文件可编程是可行的,但我们一般建议首先在(随 Acrobat Professional 提供的)LiveCycle Designer 中创建空模板,该模板匹配打印机的 paper size/corporate stationary。XDP 文档是 XML 对象,EcmaScript for XML (e4x) 使Flex中的 XDP 构建过程非常容易。例如:

    1. 声明一个 XML 类型的变量,并使用 e4x 语法读取匹配文档和页面大小的 XDP 模板。下面是一个 XDP 模板的片段:
 

<?xml version="1.0" encoding="UTF-8"?>
<?xfa generator="AdobeLiveCycleDesigner_V8.0" APIVersion="2.5.6290.0"?>
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/" timeStamp="2007-01-25T10:40:38Z" uuid="784f469b-2fd0-4555-a905-6a2d173d0ee1">
<template xmlns="http://www.xfa.org/schema/xfa-template/2.5/">
<subform name="form1" layout="tb" restoreState="auto" locale="en_US">
<pageSet>
<pageArea name="Page1" id="Page1">
<contentArea x="0.25in" y="0.25in" w="8in" h="10.5in"/>
<medium stock="letter" short="8.5in" long="11in"/>
<?templateDesigner expand 1?></pageArea>
<?templateDesigner expand 1?></pageSet>
<subform w="8in" h="10.5in" name="YourPageAttachedHere"/>
<proto/>
<desc>
<text name="version">8.0.1291.1.339988.308172</text>
</desc>
</subform>
</template>


    2. 选择一个要打印的 Flex 容器或控件,例如 Panel、DataGrid 等。

    3. 从第 2 步查找该对象,获得其属性和子项,并创建准备此对象以便进行打印的 XML。将该 XML 作为一个页面附加到模板。如果您拥有自己的显示框架,所有组件可以实现您自己的界面(以下代码显示了只有一个 gette r 函数 xmlContent 的 IXdpContent ),该界面允许遍历屏幕上 XDP 内容的元素列表。您也可以拥有一个提供标准类的 XML 的处理器。下面是一般 DataGridItemRenderer 的实现,说明了如何准备打印一个 datagrid 单元:
 

package printing
{
import com.theriabook.controls.superGridClasses.DataGridItemRenderer;

public class DataGridItemRendererXdp extends DataGridItemRenderer
implements IXdpElement
{
public function get xmlContent():Object
{
var o:XML = <draw x={convert(x)} w={convert(width)}
h={convert(height)}>
<ui>
<textEdit>
</textEdit>
</ui>
<value><text>{text}</text></value>
<font typeface={getStyle("fontFamily")}
size={(getStyle("fontSize")*4/5)+"pt"}
weight={getStyle("fontWeight")}
posture={getStyle("fontStyle")}
underline={getStyle("textDecoration")=="normal"?1:0}
>
<fill>
<color value={rgb(getStyle("color"))}/>
</fill>
</font>
<margin topInset="0.5mm" bottomInset="0.5mm" leftInset="0.5mm" rightInset="0.5mm"/>

<border>
<edge presence="hidden"/>
<edge presence="visible"/>
<edge presence="hidden"/>
<edge presence="hidden"/>
</border>
</draw>;

return o;
}
private function convert(val:Number) : String {
return val/96 + "in"; //convert 96 dpi to inches
}
private function rgb(val:Number) : String {

return (val >> 16 & 255) + "," + (val >> 8 & 255) + "," + (val & 255);
}

}
}

    4. 重复使用 E4X 将 XML 附加到 XDP 模板的过程,直到所有打印页就绪。

    在我看来,这种从 Flex 打印的方法需要更少的报告努力。它还可能提供更好的打印质量,并且更易于在打印文档中搜索。

0
相关文章