ICEpdf简介
ICEpdf是一个开源的PDF引擎。它可以用来阅读、打印和注释PDF文档。并且它是100%纯Java写的,特点是轻量、快捷、效率和易用。
你可以把ICEpdf只当做PDF阅读器来使用,但是这点浪费,由于它是纯Java编写的,所以可以轻易地与任何Java应用无缝对接。另外它还可以捕获PDF文档。除了PDF文档渲染外,ICEpdf在另外的“领域”也相当全面,它可以用来在多方面进行创新,包括:PDF转换成图像、PDF注释、PDF中文字和图像的提取、对PDF中的内容进行查询、PDF打印
你还可以用ICEpdf来注释你的PDF文档,比如划个重点啊,写个备注之类的,这也是大多数PDF阅读器都具有的这么一个功能。
你可以从官网上获得更多关于ICEpdf的信息:http://www.icesoft.org/java/home.jsf
下载ICEpdf源码
注意这里有2种免费版本,一种带有字体引擎的而另一种不带,具体区别也就是不带字体引擎的在渲染中文字符的时候可能会有一些问题
至少在官网上摆着的demo上,没有使用字体引擎的ICEpdf渲染出来的中文都是乱码~
但是我试了貌似还是可以用的,我的猜想可能是它在渲染的时候首先找系统本地是否存在这个字体,然后再去字体引擎中找,所以我这里本地有中文字体的支持,那么它就不会渲染出乱码了。另外还需要说的一点是,带有字体引擎的ICEpdf是试用版本,所以生成出来的pdf会有红色的水印,其实我们用刚刚那个不带字体殷勤的版本就好了。
好吧~其实这一块已经是生成PDF的内容了。下面还是先说说ICEpdf作为PDF阅读器的功能。
作为PDF阅读器
public class ViewerComponentExample {
public static void main(String[] args) {
// Get a file from the command line to open
String filePath = args[0];
// build a component controller
SwingController controller = new SwingController();
controller.setIsEmbeddedComponent(true);
PropertiesManager properties = new PropertiesManager(System
.getProperties(), ResourceBundle
.getBundle(PropertiesManager.DEFAULT_MESSAGE_BUNDLE));
properties.set(PropertiesManager.PROPERTY_DEFAULT_ZOOM_LEVEL, "1.75");
SwingViewBuilder factory = new SwingViewBuilder(controller, properties);
// add interactive mouse link annotation support via callback
controller.getDocumentViewController().setAnnotationCallback(
new org.icepdf.ri.common.MyAnnotationCallback(controller
.getDocumentViewController()));
JPanel viewerComponentPanel = factory.buildViewerPanel();
JFrame applicationFrame = new JFrame();
applicationFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
applicationFrame.getContentPane().add(viewerComponentPanel);
// Now that the GUI is all in place, we can try openning a PDF
controller.openDocument(filePath);
// show the component
applicationFrame.pack();
applicationFrame.setVisible(true);
}
}
通过这些代码可以简单分析一下:
1、需要传入一个待打开的pdf文件的位置
2、ICEpdf阅读器的界面是用Swing来呈现的
3、SwingController应该是ICEpdf阅读器的核心控制器
4、SwingViewBuilder根据properties的设置来产生相应视图
运行之后的效果如下:
看的出,功能还是蛮强大的!可以将该工程导出后并关联到PDF文件,那么以后就可以抛弃Adobe Reader啦~
打印PDF
还记得前面我们说过普通打印机是无法解释PDF文档的,所以需要通过别的方式,比如通过渲染成图片再打印出来
ICEpdf使用的就是这种先将PDF渲染成图片的方式来打印PDF文档的,具体的操作细节已经封装好了,我们需要做的就是学习example来满足我们的需求:
/**
* Attempts to Print PDF documents which are specified as application
* arguments.
*
* @param args
* list of files which should be printed by the application
*/
public static void main(String[] args) {
// setup for input from command line
BufferedReader stdin = new BufferedReader(new InputStreamReader(
System.in));
/**
* Find Available printers
*/
PrintService[] services = PrintServiceLookup.lookupPrintServices(
DocFlavor.SERVICE_FORMATTED.PAGEABLE, null);
// MultiDocPrintService mdps[] = PrintServiceLookup
// .lookupMultiDocPrintServices(null, null);
// MultiDocPrintService mdps[] = PrintServiceLookup
// .lookupMultiDocPrintServices(
// new DocFlavor[] { DocFlavor.SERVICE_FORMATTED.PAGEABLE },
// null);
// MultiDocPrintJob mdpj = mdps[0].createMultiDocPrintJob();
// System.out.println(mdpj);
int selectedPrinter = 0;
// ask the user which printer they want, only quite when they type
// q, otherwise just keep asking them which printer to use.
while (!(selectedPrinter > 0 && selectedPrinter <= services.length)) {
System.out
.println("Please select the printer number your wish to print to (q to quit):");
int printerIndex = 1;
for (int i = 0, max = services.length - 1; i <= max; i++) {
System.out.println(" " + printerIndex++ + ". "
+ services[i].getName());
}
System.out.print("Printer selection? ");
String input = "";
// get users choice
try {
input = stdin.readLine();
} catch (IOException e) {
// purposely left empty;
}
if (input.length() == 0) {
System.out.println("Please select a valid printer number.");
System.out.println();
} else if (input.toLowerCase().equals("q")) {
System.exit(0);
} else {
try {
selectedPrinter = Integer.parseInt(input);
if ((selectedPrinter > 0 && selectedPrinter <= services.length)) {
break;
}
} catch (NumberFormatException e) {
// ignore error.
}
System.out.println("Please select a valid printer number.");
System.out.println();
}
}
/**
* Selected Printer, via user input
*/
PrintService selectedService = services[selectedPrinter - 1];
/**
* Show selected Printer default attributes.
*/
System.out.println("Supported Job Properties for printer: "
+ selectedService.getName());
Class[] supportedAttributes = selectedService
.getSupportedAttributeCategories();
for (Class supportedAttribute : supportedAttributes) {
System.out.println(" "
+ supportedAttribute.getName()
+ ":= "
+ selectedService
.getDefaultAttributeValue(supportedAttribute));
}
// Open the document, create a PrintHelper and finally print the
// document
Document pdf = new Document();
try {
// load the file specified by the command line
String filePath;
if (args.length > 0) {
filePath = args[0];
} else {
throw new FileNotFoundException("Specify a PDF document.");
}
pdf.setFile(filePath);
// create a new print helper with a specified paper size and print
// quality
PrintHelper printHelper = new PrintHelper(null, pdf.getPageTree(),
0f, MediaSizeName.NA_LEGAL, PrintQuality.DRAFT);
// try and print pages 1 - 10, 1 copy, scale to fit paper.
printHelper.setupPrintService(selectedService, 0, 0, 1, true);
// print the document
printHelper.print();
} catch (FileNotFoundException e) {
logger.log(Level.WARNING, "PDF file not found.", e);
} finally {
pdf.dispose();
}
}
MultiDocPrintService mdps[] = PrintServiceLookup
.lookupMultiDocPrintServices(null, null);
MultiDocPrintService mdps[] = PrintServiceLookup
.lookupMultiDocPrintServices(
new DocFlavor[] { DocFlavor.SERVICE_FORMATTED.PAGEABLE },
null);
MultiDocPrintJob mdpj = mdps[0].createMultiDocPrintJob();
System.out.println(mdpj);
我猜想这类打印机应该就是那种可以直接支持打印PDF的打印机吧,这里我们将这些代码注释掉就可以使用了。
打印过程主要是通过PrintHelper这个类来封装的,最后具体实现还是使用Java Print Service来完成的。所以我们可以指定docAttributes和printAttributes,这两个属性是Java打印服务的内容,具体可以参考这里
PrintHelper printHelper = new PrintHelper(null, pdf.getPageTree(),
0f, MediaSizeName.NA_LEGAL, PrintQuality.DRAFT);
另外这里的纸张大小定义不允许宽度大于长度,如果要连打的话貌似没办法搞啊,所以最后还是换成了调用GSview来打印~