Java使用PDFBOX操作pdf文件(一,加载和创建pdf)

2年前 (2022) 程序员胖胖胖虎阿
485 0 0

前言:
之前想学习使用Java操作pdf的时候看过了IText的文档。确实IText的文档很全,也有一个官网可以很方便的查找信息。但IText的开源协议为AGPL,使用者必须传染性的开源代码,商业使用必须付费获取商业许可。所以有一些风险。所以转而来学习使用PDFBOX。现在pdfbox的文档并不是很多,列出如下链接以做参考。
https://iowiki.com/pdfbox/pdfbox_quick_guide.html
如果需要源码进行研究,可以在https://www.apache.org/dyn/closer.lua/pdfbox/2.0.25/pdfbox-2.0.25-src.zip下载使用
有一些坑在网上的资料也比较少,也可以到https://issues.apache.org/jira/browse/PDFBOX-5103里查找相关的issue(英文),如果你找到了bug也可以往里提。

一.加载已有的pdf文件

1.加载全文/页的文本

	注意:PDFBOX依赖commons-logging,fontbox包,使用请确保fontbox与pdfbox的版本相同,不然可能会有兼容BUG(亲测)
	具体信息可以查看:https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox/2.0.25
	先准备一个pdf文件(有内容的),如下:

Java使用PDFBOX操作pdf文件(一,加载和创建pdf)
通过加载PDF文件获取文本内容:

public class LoadPDF {
	
	public static void main(String[] args) throws FileNotFoundException, IOException {
		//通过文件和输入流都可以加载pdf文件
		PDDocument doc = PDDocument.load(new FileInputStream("src/Target.pdf"));
		
		PDFTextStripper text = new PDFTextStripper();
		//获取全文件的所有文本
		String FinalText = text.getText(doc);
		
		System.out.println(FinalText);
		//关闭
		doc.close();
	}

}

运行:

邮政银行卡类型查询指引
方法一:拨打中国邮政储蓄银行电话“95580”查询。
方法二:携带本人身份证及银行卡至邮政银行网点查询。
方法三:手机网银查询,步骤如下图:
      打开手机APP<邮储银行>,点击”我的“,点击"银行卡",查看薪资卡类型。

这样便很容易通过正则表达式进行内容的提取了。比如常见的一些招聘模块,通常有上传pdf简历的功能,这样大致也可以实现,只是方法有些不同。

2.加载保存pdf中的图片信息

当然,我们也可以从PDF文件中读取图片信息。

		//打开PDF文件
		PDDocument doc = PDDocument.load(new FileInputStream("src/Target.pdf"));
		//获取第一页的数据
		PDPage pageOne = doc.getPage(0);
		//获取页面resources
		PDResources resources = pageOne.getResources();
		
		//获取COS对象的名字集合(如果不了解什么是COS对象,请参考这个链接
		//https://www.pdftron.com/documentation/cli/guides/pdf-cosedit/faq/#what-is-cos
		Iterable<COSName> xObjectNames = resources.getXObjectNames();
		
		//遍历COS对象
		xObjectNames.forEach(item->{
		    try {
				PDXObject xObject = resources.getXObject(item);
				System.out.println(item.getName());
				//如果为图片类型就调Java的图片处理接口,将其保存下来
				if(xObject instanceof PDImageXObject) {
					PDImageXObject imgobject = (PDImageXObject)xObject;
					BufferedImage image = imgobject.getImage();
					
					ImageIO.write(image, "png", new File("第"+Count+"张图片.png"));
					System.out.println("ImageSaved");
					Count++;
				}
			} catch (IOException e) {
				System.out.println("图片保存出错");
				e.printStackTrace();
			}
			
		});

运行:
Java使用PDFBOX操作pdf文件(一,加载和创建pdf)

二.创建普通的pdf文件

创建一个空的pdf非常的简单,只需要创建然后保存即可

PDDocument doc = new PDDocument();
doc.save(null);

如果要写入内容,需要使用PDFBOX提供的流对象进行写入。

写入英文

写入英文文本是不需要设置任何额外的东西,直接向流里面丢就可以了。

public static void main(String[] args) throws IOException {
	//创建文件,设置页码
	PDDocument doc = new PDDocument();
	PDPage pageOne = new PDPage(PDRectangle.A4);
	doc.addPage(pageOne);
	//创建页面内容流
	PDPageContentStream pageStream = new PDPageContentStream(doc, pageOne);
	//设置要使用的字体
	PDFont font =  PDType1Font.COURIER_BOLD_OBLIQUE;
	
	pageStream.setFont(font,18);
	pageStream.beginText();
	//直接写入内容即可
	pageStream.showText("hello pdfbox");
	pageStream.endText();
	//记得关闭流对象要不然是无法成功保存pdf文档的
	pageStream.close();
	doc.save(new File("src\\hello.pdf"));
	doc.close();
}

看一下效果
Java使用PDFBOX操作pdf文件(一,加载和创建pdf)
内容是写上去了,但感觉位置如果不指定的话是随机的,下一节应该学习一下如下指定文字及图片绘制的位置。

写入中文

中文的写入则更加复杂。
如果直接把上述代码的写入字符串变成中文,则会出现如下异常

pageStream.showText("想要写入一些中文,但是会报错");

异常的详细信息:

Exception in thread "main" java.lang.IllegalArgumentException: U+6BD4 ('.notdef') is not available in this font Courier-BoldOblique encoding: WinAnsiEncoding
	at org.apache.pdfbox.pdmodel.font.PDType1Font.encode(PDType1Font.java:428)
	at org.apache.pdfbox.pdmodel.font.PDFont.encode(PDFont.java:333)
	at org.apache.pdfbox.pdmodel.PDAbstractContentStream.showTextInternal(PDAbstractContentStream.java:300)
	at org.apache.pdfbox.pdmodel.PDAbstractContentStream.showText(PDAbstractContentStream.java:254)
	at org.apache.pdfbox.pdmodel.PDPageContentStream.showText(PDPageContentStream.java:37)
	at PDFBOX3.MainTest.main(MainTest.java:35)

这是因为在pdf的14种原生的字体中并不支持中文(在PDFType1Font中可以通过静态属性列出),
如果需要写入中文,可以通过嵌入中文字体文件(支持中文的.ttf文件)或者直接从本地导入。
所以请先自备中文字体。(或者可以直接去C盘里找,路径为C:/Windows/Fonts)
Java使用PDFBOX操作pdf文件(一,加载和创建pdf)
现在,先加载中文字体就好了。

	private static final float MARGIN_LEFT = 0.8f * 72; // 0.8 inch
	private static final float MARGIN_TOP = 0.4f * 72; // 0.4 inch
	private static final float LOGO_WIDTH = 72;
	private static final float LOGO_MARGIN = 18;

	private static final float FONT_SIZE_TITLE = 24;
	private static final float FONT_SIZE_SMALL = 10;

	private static final float LINE_OFFSET_FACTOR = -1.8f;

	/**
	 * @param args
	 * @throws IOException
	 */
	public static void main(String[] args) throws IOException {
		//创建文档和页面
		PDDocument document = new PDDocument();
		PDPage page = new PDPage(PDRectangle.A4);
		document.addPage(page);
		
		@SuppressWarnings("resource")
		PDPageContentStream contentStream = new PDPageContentStream(document, page);
			PDRectangle boundingBox = page.getBBox();
			contentStream.beginText();
			//加载字体文件
			contentStream.setFont(PDType0Font.load(document, MainTest.class.getResourceAsStream("SimHei.ttf")),
					24);
			
			
			contentStream.newLineAtOffset(MARGIN_LEFT + LOGO_WIDTH + LOGO_MARGIN,
					boundingBox.getHeight() - MARGIN_TOP - FONT_SIZE_TITLE);
			//写入中文		
			contentStream.showText("中国你好!");

			contentStream.newLineAtOffset(0, LINE_OFFSET_FACTOR * FONT_SIZE_SMALL);
			contentStream.showText("RiderKick");

			contentStream.endText();
		contentStream.close();

		
		document.save(new File("Chinese.pdf"));
		document.close();
	}

Java使用PDFBOX操作pdf文件(一,加载和创建pdf)

写入图片

写入图片和写入文字一样,只需要将图片加载到PDImageXObject里,然后再从对象流中写入文档即可
以下图为例Java使用PDFBOX操作pdf文件(一,加载和创建pdf)

public static void main(String[] args) throws IOException {
		PDDocument doc = new PDDocument();
		PDPage pageOne = new PDPage(PDRectangle.A4);
		doc.addPage(pageOne);
		
		PDPageContentStream pageStream = new PDPageContentStream(doc, pageOne);
		PDFont font =  PDType1Font.COURIER_BOLD_OBLIQUE;
		
		PDImageXObject img = PDImageXObject.createFromFile("src/PDFBOX3/AutoFac.png", doc);
		
		pageStream.setFont(font,18);
		pageStream.beginText();
		pageStream.showText("hi this is AutoFac");
		pageStream.endText();
		
		pageStream.drawImage(img, 50, 50);
		pageStream.close();
		doc.save(new File("src\\hello.pdf"));
		doc.close();
	}

Java使用PDFBOX操作pdf文件(一,加载和创建pdf)

相关文章

暂无评论

暂无评论...