ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

PDFBOX替换文本(pdfbox版本2.0.24)

2021-11-25 09:06:18  阅读:429  来源: 互联网

标签:24 getName newTokens token 字体 PDFont new 2.0 PDFBOX


之前替换PDFBOX文本一直替换不了,查看到网上很多案例全都是直接使用cosstring.setValue。并没有效果。直到研究了PDFTextStripper的showText方法(解析)以及PDPageContentStream的showText方法(写入)才得到最终的解决方案。

首先在官方的exmaple文档中有个RemoveAll的案例这个案例当中是去除所有pdf的文字(github搜索pdfbox找到exmaple),得到图片。可以看到操作符Tj,TJ是写入文字,前一个token就是COSString。Tf是设置文字前两个token是字体。我们对这个方法体改造就可以做到替换文本了。

关键点:PDFont的encode方法,PDFont 的readCode方法,PDFont的toUnicode方法,替换当前PDFont为自己加载的pdfont。

public static List<Object> replaceText(PDContentStream contentStream, PDDocument document,String witch,String replace) throws Exception			 {
		//得到当前页面的所有的资源
		PDResources resources = contentStream.getResources();
		//解析当前页面,并得到token
		PDFStreamParser parser = new PDFStreamParser(contentStream);
		Object token = parser.parseNextToken();
		List<Object> newTokens = new ArrayList<Object>();
		Map<COSName,PDFont> fontMap = new HashMap<COSName, PDFont>();
		//遇到字体的时候保留起来,写入文本之前一定会设置字体,因此解析文本的时候上一个设置的字体就是当前文本使用的字体
		List<PDFont> souce_fonts = new ArrayList<PDFont>();
		/*
		 * 加载字体(虽然我们得到了当前流的字体但是使用encode的时候无法进行编码,
		 * 猜测pdfbox并没有加载到相应的字体库绘图文件,所以我们要替换掉对应的字体,
		 * 为了方便目前中文全用simsun字体替代),最好相应的字体加载相应的文件
		 * */
		PDFont simSunFont = getSimSunFont(document);
		while (token != null) {
			if (token instanceof Operator) {
				Operator op = (Operator) token;
				// 得到对应的字体
				if ("Tf".equals(op.getName())) {
					COSName cosName = (COSName) newTokens.get(newTokens.size() - 2);
					PDFont sourceFont = resources.getFont(cosName);
System.out.println(sourceFont.getName());//如果encode异常的时候加入对应的字体
					souce_fonts.add(resources.getFont(cosName));
					if((sourceFont.getName().toLowerCase().indexOf("simsun")>-1)||(sourceFont.getName().toLowerCase().indexOf("pingfang")>-1) && fontMap.get(cosName) == null) {
						fontMap.put(cosName, simSunFont);
					}
				}
				if ("Tj".equals(op.getName()) || "TJ".equals(op.getName()) || "".equals(op.getName())) {
					COSString previous = (COSString) newTokens.get(newTokens.size() - 1);
					PDType0Font pdFont = (PDType0Font) souce_fonts.get(souce_fonts.size() - 1);
					//得到COSString的字节数组,并用原始字体进行读取转换操作拼接成字符串
					byte[] bytes = previous.getBytes();
					InputStream in = new ByteArrayInputStream(bytes);
					StringBuffer sb = new StringBuffer();
					while (in.available() > 0) {
						int code = pdFont.readCode(in);
						String value = pdFont.toUnicode(code);
						sb.append(value);
					}
					System.out.println("原有字符串:" + sb.toString());
					//替换文本
					previous.setValue(simSunFont.encode(sb.toString().replace(witch, replace)));
				} else if ("\"".equals(op.getName())) {
					// remove the 3 arguments to this operator
					newTokens.remove(newTokens.size() - 1);
					newTokens.remove(newTokens.size() - 1);
					newTokens.remove(newTokens.size() - 1);
					token = parser.parseNextToken();
				}
			}
			newTokens.add(token);
			token = parser.parseNextToken();
		}
		//统一替换字体资源
		Set<Entry<COSName, PDFont>> entrySet = fontMap.entrySet();
		for (Entry<COSName, PDFont> entry : entrySet) {
			resources.put(entry.getKey(), entry.getValue());
		}
		return newTokens;
	}
	public static PDFont getSimSunFont(PDDocument document) throws IOException {
		TrueTypeCollection ttc3 = new TrueTypeCollection(
				new File("G:\\projects\\pdfdetail\\src\\main\\resources\\simsun.ttc"));
		TrueTypeFont trueTypeFont = ttc3.getFontByName("SimSun");
		PDType0Font sourceFont = PDType0Font.load(document, trueTypeFont, true);
		return sourceFont;
	}

标签:24,getName,newTokens,token,字体,PDFont,new,2.0,PDFBOX
来源: https://blog.csdn.net/JiGoLiZe_Bs/article/details/121529429

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有