首页 > 代码库 > 抛弃Adobe Reader——用ICEpdf来打开你的PDF

抛弃Adobe Reader——用ICEpdf来打开你的PDF

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源码

刚才也说了ICEpdf是纯Java编写的,且提供了免费的开源版本供我们使用,下载地址:http://www.icesoft.org/java/downloads/icepdf-downloads.jsf 

注意这里有2种免费版本,一种带有字体引擎的而另一种不带,具体区别也就是不带字体引擎的在渲染中文字符的时候可能会有一些问题

至少在官网上摆着的demo上,没有使用字体引擎的ICEpdf渲染出来的中文都是乱码~

但是我试了貌似还是可以用的,我的猜想可能是它在渲染的时候首先找系统本地是否存在这个字体,然后再去字体引擎中找,所以我这里本地有中文字体的支持,那么它就不会渲染出乱码了。另外还需要说的一点是,带有字体引擎的ICEpdf是试用版本,所以生成出来的pdf会有红色的水印,其实我们用刚刚那个不带字体殷勤的版本就好了。

好吧~其实这一块已经是生成PDF的内容了。下面还是先说说ICEpdf作为PDF阅读器的功能。


作为PDF阅读器

下载了源码之后,那么就可以开始使用了~源码包里是有example的,我下面的代码也是从example中扣出来的,直接就可以运行。

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

下面我们再来试试用ICEpdf打印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();
		}
	}

官网的example中有一个问题,已经被我注释掉了
		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);
lookupMutiDocPrintServices是寻找系统中支持MutiDoc的打印机的方法,那么若系统中不存在该类打印机,那么msps[0]就会报空指针错误。

我猜想这类打印机应该就是那种可以直接支持打印PDF的打印机吧,这里我们将这些代码注释掉就可以使用了。

打印过程主要是通过PrintHelper这个类来封装的,最后具体实现还是使用Java Print Service来完成的。所以我们可以指定docAttributes和printAttributes,这两个属性是Java打印服务的内容,具体可以参考这里

			PrintHelper printHelper = new PrintHelper(null, pdf.getPageTree(),
					0f, MediaSizeName.NA_LEGAL, PrintQuality.DRAFT);

这行代码就简单的设定了打印纸张的尺寸和打印的质量。

另外这里的纸张大小定义不允许宽度大于长度,如果要连打的话貌似没办法搞啊,所以最后还是换成了调用GSview来打印~


貌似最后有些跑题~不过只是为了记录些知识点,另外,热爱Java的朋友可以加QQ群385193998一起交流~

抛弃Adobe Reader——用ICEpdf来打开你的PDF