-
2021-03-14 02:31:01
骑缝章是用于往来业务合同,以确保合同真实、有效的印章加盖方法,是一种防范风险的重要方式。在Java程序中,可以通过使用工具来辅助加盖这种骑缝章。
工具:Free Spire.PDF for Java (免费版)
工具获取及jar文件导入:
方式1:通过官网下载jar包,并解压,手动导入lib文件夹下的Spire.Pdf.jar文件。
方式2:通过创建Maven程序,在pom.xml中配置maven仓库路径并指定Free Spire.PDF for Java 的依赖,配置完成后,在IDEA中,点击“Import Changes”导入JAR包:
com.e-iceblue
http://repo.e-iceblue.cn/repository/maven-public/
e-iceblue
spire.pdf.free
2.6.3
(Ecllipse的导入方法,参考这篇文章)
jar导入结果如下图所示:
Java 示例
import com.spire.pdf.*;
import com.spire.pdf.graphics.PdfGraphicsUnit;
import com.spire.pdf.graphics.PdfImage;
import com.spire.pdf.graphics.PdfUnitConvertor;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class AcrossPageSeal {
public static void main(String[] args) throws IOException {
//加载测试文档
PdfDocument pdf = new PdfDocument();
pdf.loadFromFile("test.pdf");
//获取分割后的印章图片
BufferedImage[] images = GetImage(pdf.getPages().getCount());
float x = 0;
float y = 0;
//实例化PdfUnitConvertor类
PdfUnitConvertor convert = new PdfUnitConvertor();
PdfPageBase pageBase;
//将图片绘制到PDF页面上的指定位置
for (int i = 0; i < pdf.getPages().getCount(); i++)
{
BufferedImage image= images[ i ];
pageBase = pdf.getPages().get(i);
x = (float)pageBase.getSize().getWidth() - convert.convertUnits(image.getWidth(), PdfGraphicsUnit.Point, PdfGraphicsUnit.Pixel) + 40;
y = (float) pageBase.getSize().getHeight()/ 2;
pageBase.getCanvas().drawImage(PdfImage.fromImage(image), new Point2D.Float(x, y));
}
//保存PDF文档
pdf.saveToFile("Result.pdf");
}
//定义GetImage方法,根据PDF页数分割印章图片
static BufferedImage[] GetImage(int num) throws IOException {
String originalImg = "seal.png";
BufferedImage image = ImageIO.read(new File(originalImg));
int rows = 1;
int cols = num;
int chunks = rows * cols;
int chunkWidth = image.getWidth() / cols;
int chunkHeight = image.getHeight() / rows;
int count = 0;
BufferedImage[] imgs = new BufferedImage[ chunks ];
for (int x = 0; x < rows; x++) {
for (int y = 0; y < cols; y++) {
imgs[ count ] = new BufferedImage(chunkWidth, chunkHeight, image.getType());
Graphics2D gr = imgs[ count++ ].createGraphics();
gr.drawImage(image, 0, 0, chunkWidth, chunkHeight,
chunkWidth * y, chunkHeight * x,
chunkWidth * y + chunkWidth, chunkHeight * x + chunkHeight, Color.WHITE,null);
gr.dispose();
}
}
return imgs;
}
}
骑缝章添加效果:
到此这篇关于Java 在PDF中添加骑缝章示例解析的文章就介绍到这了,更多相关Java 在PDF中添加骑缝章内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!
更多相关内容 -
如何给PDF文件添加自定义图章的方法
2020-10-29 16:30:44随着PDF文件的使用越来越广泛,我们对于PDF的操作也越来越熟练,比如有时需要给PDF添加图章,但系统给出的固定图章很难找到...(注意:这里是添加文件夹,不是图章文件,所以我们要提前制作好PDF格式的图章文件后,放随着PDF文件的使用越来越广泛,我们对于PDF的操作也越来越熟练,比如有时需要给PDF添加图章,但系统给出的固定图章很难找到合适的,如何才能添加自定义的图章呢?
这里我们需要用到极速PDF编辑器,先用编辑器打开PDF文档后,点击工具栏“图章”工具右侧的下三角符号可以看到有自定义和内置两种图章形式,依次点击用户自定义中的“设置源文件夹”。
然后点击弹窗“编辑”中自定义图章文件夹输入框后面的“浏览”并添加后点击“确定”即可。(注意:这里是添加文件夹,不是图章文件,所以我们要提前制作好PDF格式的图章文件后,放入一个新的文件夹保存)
接着我们在PDF文档任意处单击鼠标左键就可以添加图章了,选中图章可以任意拖动图章位置以及删除。
在图章处右击并选择“属性”可以修改图章的透明和外观等。
当然最后我们在操作完成之后一定要记得将文档进行保存哦。如需要给PDF文档每一页都添加相同的图章,我们可以用添加自定义水印的方式的来实现。
-
pdftk:PDF 工具包 - 拆分、合并、旋转、水印、图章和保护 PDF 页面和文档
2021-06-17 07:31:11PDFTk PDFtk 的服务器端 Meteor 包装器, ,用于操作 PDF 文档的工具。...将文件附加到 PDF 页面或 PDF 文档 解压 PDF 附件 将 PDF 文档分成单页 解压缩和重新压缩页面流 修复损坏的 PDF(如果可能) 要求 -
第4章CSS样式基础.PDF
2020-11-26 02:09:19第4章 CSS样式基础 网页设计与制作案例教程 第3版 HTML语言提供丰富的标签及属性是所有网页制作的 基础但是如果希望网页代码整洁且易于升级维护 仅凭借HTML语言远远不够CSS在其中扮演重要角色 CSS 层叠样式表是用于... -
如何批量给pdf加图章?
2022-03-08 10:17:10如何批量给pdf加图章?通过给pdf添加水印的方式添加图章,可以一键批量给大量的pdf进行添加,如果你也想掌握这个pdf操作技巧,就仔细阅读下面的方法步骤。如何批量给pdf加图章?如今pdf已经成为重要的文件格式,尤其是一些重要的文件,采用pdf格式会更加的安全,例如合作意向书,商务合同等,这些pdf合同都有一个特点,就是需要加盖电子图章。如果领导要你给pdf文件添加图章,你知道如何添加吗?相信不少小伙伴都不知道如何操作吧。
今天小编就来教大家一个方法吧,通过给pdf添加水印的方式添加图章,可以一键批量给大量的pdf进行添加,如果你也想掌握这个pdf操作技巧,就仔细阅读下面的方法步骤,很快就能学会的!
使用的工具软件:优速水印工厂
工具软件下载:https://download.yososoft.com/YSWatermark/2.0.2/YSWatermark.exe
请看详细的操作步骤吧:
步骤1,下载好“优速水印工厂”软件工具后安装打开使用,选择左边的【PDF水印】功能选项,然后点击【添加文件】按钮,将需要添加图章的PDF文件全部导入到软件中。
步骤2,然后进行设置,水印类型选择“图片水印”;然后上传图章;再对图章的样式进行调整,如缩放比例、透明度、旋转角度、位置、边距等,直到图章的样式满足自己的需求为止。
步骤3,点击右上角的【开始转换】红色按钮启动软件,当所有pdf添加好图章后,软件会自动打开输出文件夹,方便我们对pdf文件进行查看。
步骤4,打开一个上面案例结果中的pdf文件可以看到,每个页面都成功的添加了图片。
正常的商务活动中,经常需要给商务文件添加电子图章,而pdf又是目前使用最广泛的文件格式之一,所以学会快速批量给pdf加图章的办公技能是非常有必要的,上面小编通过真实案例为大家做了详细的步骤介绍,相信看完之后你也可以学会。以上就是今天关于“批量给pdf加图章”的全部分享,感觉不错就给我点个赞吧,不过一定要亲手试一试!
-
北方工业大学编译原理第1、2章习题.pdf
2020-03-28 01:07:54考核办法: 平时作业完成情况占 10% 实验作业完成情况占 20% ...的主要功能 解词法分析器输入源程序识别出单词符号把需要存放的单词 放到符号表中如变量名等 语法分析器在词法分析的基础上根据语言的语法规则的要求把单 -
专业 PDF 编辑器直接修改PDF文档.rar
2021-09-03 21:43:34您可将现有的 PDF 作为一个文档的组成部分添加到新文档中,只需将其拖放到新文档的页面上即可。可以根据需要旋转、移动任何其他对象及调整对象的尺寸。 利用 CAT 工具通过 XML 文件来翻译 PDF 您可将 PDF 内容导出... -
明日科技-android从入门到精通-第1-2章pdf
2016-07-06 20:01:09明日科技-android从入门到精通-第1-2章源代码+ppt+pdf 戒杀护(放)生, 阿弥陀佛 -
Java一键生成PDF合同以及骑缝章、盖章处的精准盖章
2021-12-17 16:58:10最近项目做到根据订单生成pdf合同。要求像阿里云的合同一样,有骑缝章,并且合同末尾处要进行盖章。为了做出这个功能搜集了很多博主的内容,最后终于做出了。现在做一个从头到尾的详细总结,也供大家参考一下,免得...最近项目做到根据订单生成pdf合同。要求像阿里云的合同一样,有骑缝章,并且合同末尾处要进行盖章。为了做出这个功能搜集了很多博主的内容,最后终于做出了。现在做一个从头到尾的详细总结,也供大家参考一下,免得向我一样搜罗太多资料,浪费时间。废话不多说 直接开始上代码。第一次写博客,可能有表达的不好的地方,望见谅。不明白的可以私信,看到了尽量解答。
涉及的依赖如下:
<dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.13</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext-asian</artifactId> <version>5.2.0</version> </dependency> <dependency> <groupId>com.itextpdf.tool</groupId> <artifactId>xmlworker</artifactId> <version>5.5.13</version> </dependency> <dependency> <groupId>fr.opensagres.xdocreport</groupId> <artifactId>fr.opensagres.poi.xwpf.converter.pdf-gae</artifactId> <version>2.0.1</version> </dependency>
涉及的jar包链接:链接:https://pan.baidu.com/s/1TK-2LogXRKk_1EaQY05HHg
提取码:nbz71、准备一个word格式的模板,主要内容如下:
2、生成和同类
/** * @Author: wuyongqiang * @Description:获取合同,保存云端 * @Date: 2021/12/8 15:46 * @Param orderInfos: 订单信息 * @Param contInfo: 合同信息 * @return: java.lang.String 返回云端地址 **/ private String makeCont(List<OrderInfo> orderInfos, ContInfo contInfo) throws Exception { String urlPath; String id = contInfo.getContFileName();// 合同ID String contractPath = System.getProperty("user.dir") + "/website/cont/templet/"; //获取合同信息 Map<String, String> replaceMap = getReplaceMap(contInfo, orderInfos); String userId = replaceMap.get("userId"); StringBuilder destPathDOCX = new StringBuilder(contractPath).append(userId); //合同信息填充后的保存路径 // 判断用户文件夹是否存在,不存在则新建 File userNumFile = new File(destPathDOCX.toString()); if (!userNumFile.exists()) { userNumFile.mkdirs(); } destPathDOCX.append(File.separator).append(userId).append(".docx"); Map<String, String> replaceTableMap = new HashMap<String, String>(); replaceTableMap.put("totalAmount", replaceMap.remove("totalAmount")); replaceTableMap.put("date", replaceMap.remove("date")); replaceTableMap.put("totalCapitalizeAmount", replaceMap.remove("totalCapitalizeAmount")); // 替换合同里面的参数 WordUtil.replaceAndGenerateWord(contractPath + "templet.docx", destPathDOCX.toString(), replaceMap, replaceTableMap); //更新合同中的产品服务信息 updateContTableInfo(destPathDOCX.toString(), orderInfos); //设置转换后pdf文件的保存路径 StringBuilder pdfFile = new StringBuilder(contractPath).append(userId).append(File.separator).append(id).append(".pdf"); // 将word转pdf文件 Boolean bool = WordUtil.wordConverterToPdf(destPathDOCX.toString(), pdfFile.toString()); //盖章 InputStream inputStream = new FileInputStream(pdfFile.toString()); PdfUtil.itextPDFAddPicture(inputStream, pdfFile.toString()); //将盖章后的pdf文档保存到云端 urlPath = aliyunOSS.uploadFile("files/contract/", id + ".pdf", new File(pdfFile.toString())); // 删除word电子合同 File fileDOCX = new File(destPathDOCX.toString()); if (fileDOCX.exists()) { fileDOCX.delete(); } //删除pdf电子合同 File filePdf = new File(pdfFile.toString()); if (filePdf.exists()) { filePdf.delete(); } return urlPath; }
3、word工具类
package com.tantela.util.contutil; import java.io.*; import java.util.Iterator; import java.util.List; import java.util.Map; import com.aspose.words.License; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRun; import org.apache.poi.xwpf.usermodel.XWPFTable; import org.apache.poi.xwpf.usermodel.XWPFTableCell; import org.apache.poi.xwpf.usermodel.XWPFTableRow; import com.aliyuncs.utils.StringUtils; /** * @ClassName:WordUtil * @Description:操作word文档工具类 * @Version:V1.0 * @Author:wuyongqiang * @Date:2021/12/7 13:53:32 */ public class WordUtil { /** * @Author: wuyongqiang * @Description:替换word中需要替换的特殊字符 * @Date: 2021/12/7 16:59 * @Param srcPath: 需要替换的文档全路径 * @Param exportFile: 替换后文档的保存路径 * @Param contentMap: {key:将要被替换的内容,value:替换后的内容} * @Param replaceTableMap: {key:将要被替换的表格内容,value:替换后的表格内容} * @return: boolean 返回成功状态 **/ public static boolean replaceAndGenerateWord(String srcPath, String exportFile, Map<String, String> contentMap, Map<String, String> replaceTableMap) throws IOException { boolean bool = true; FileInputStream inputStream = new FileInputStream(srcPath); XWPFDocument document = new XWPFDocument(inputStream); // 替换段落中的指定文字 Iterator<XWPFParagraph> itPara = document.getParagraphsIterator(); while (itPara.hasNext()) { XWPFParagraph paragraph = itPara.next(); commonCode(paragraph, contentMap); } // 替换表格中的指定文字 Iterator<XWPFTable> itTable = document.getTablesIterator(); while (itTable.hasNext()) { XWPFTable table = itTable.next(); int rcount = table.getNumberOfRows(); for (int i = 0; i < rcount; i++) { XWPFTableRow row = table.getRow(i); List<XWPFTableCell> cells = row.getTableCells(); for (XWPFTableCell cell : cells) { //单元格中有段落,得做段落处理 List<XWPFParagraph> paragraphs = cell.getParagraphs(); for (XWPFParagraph paragraph : paragraphs) { commonCode(paragraph, replaceTableMap); } } } } FileOutputStream outStream = new FileOutputStream(exportFile); document.write(outStream); outStream.close(); inputStream.close(); return bool; } /** * @Author: wuyongqiang * @Description:替换内容 * @Date: 2021/12/7 16:56 * @Param paragraph: 被替换的文本信息 * @Param contentMap: {key:将要被替换的内容,value:替换后的内容} * @return: void **/ private static void commonCode(XWPFParagraph paragraph,Map<String, String> contentMap){ List<XWPFRun> runs = paragraph.getRuns(); for (XWPFRun run : runs) { String oneparaString = run.getText(run.getTextPosition()); if (StringUtils.isEmpty(oneparaString)){ continue; } for (Map.Entry<String, String> entry : contentMap.entrySet()) { oneparaString = oneparaString.replace(entry.getKey(), StringUtils.isEmpty(entry.getValue()) ? "--" : entry.getValue()); } run.setText(oneparaString, 0); } } /** * @Author: wuyongqiang * @Description:验证license许可凭证 * @Date: 2021/12/7 16:57 * @return: boolean 返回验证License状态 **/ private static boolean getLicense() { boolean result = true; try { String path = System.getProperty("user.dir")+"/website/cont/license.xml"; new License().setLicense(new FileInputStream(new File(path).getAbsolutePath())); } catch (Exception e) { result = false; e.printStackTrace(); } return result; } /** * @Author: wuyongqiang * @Description:word转pdf * @Date: 2021/12/7 16:58 * @Param wordPath: word 全路径,包括文件全称 * @Param pdfPath: pdf 保存路径,包括文件全称 * @return: boolean 返回转换状态 **/ public static boolean wordConverterToPdf(String wordPath, String pdfPath) { boolean bool = false; // 验证License,若不验证则转化出的pdf文档会有水印产生 if (!getLicense()) return bool; try { FileOutputStream os = new FileOutputStream(new File(pdfPath));// 新建一个pdf文档输出流 com.aspose.words.Document doc = new com.aspose.words.Document(wordPath);// Address是将要被转化的word文档 doc.save(os, com.aspose.words.SaveFormat.PDF);// 全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF, EPUB, XPS, SWF 相互转换 os.close(); bool = true; } catch (Exception e) { e.printStackTrace(); System.out.println("word转PDF转换异常!!"); } return bool; } /** * @Author: wuyongqiang * @Description: 在word表格中指定位置插入一行,并将某一行的样式复制到新增行 * @Date: 2021/12/7 16:58 * @Param table: 需要插入的表格 * @Param copyrowIndex: 需要复制的行位置 * @Param newrowIndex: 需要新增一行的位置 * @return: void 返回类型 **/ public static void insertRow(XWPFTable table, int copyrowIndex, int newrowIndex) { // 在表格中指定的位置新增一行 XWPFTableRow targetRow = table.insertNewTableRow(newrowIndex); // 获取需要复制行对象 XWPFTableRow copyRow = table.getRow(copyrowIndex); //复制行对象 targetRow.getCtRow().setTrPr(copyRow.getCtRow().getTrPr()); //获取需要复制的行的列 List<XWPFTableCell> copyCells = copyRow.getTableCells(); //复制列对象 XWPFTableCell targetCell = null; for (int i = 0; i < copyCells.size(); i++) { XWPFTableCell copyCell = copyCells.get(i); targetCell = targetRow.addNewTableCell(); targetCell.getCTTc().setTcPr(copyCell.getCTTc().getTcPr()); if (copyCell.getParagraphs() != null && copyCell.getParagraphs().size() > 0) { targetCell.getParagraphs().get(0).getCTP().setPPr(copyCell.getParagraphs().get(0).getCTP().getPPr()); if (copyCell.getParagraphs().get(0).getRuns() != null && copyCell.getParagraphs().get(0).getRuns().size() > 0) { XWPFRun cellR = targetCell.getParagraphs().get(0).createRun(); cellR.setBold(copyCell.getParagraphs().get(0).getRuns().get(0).isBold()); } } } } }
4、license.xml内容
<License> <Data> <Products> <Product>Aspose.Total for Java</Product> <Product>Aspose.Words for Java</Product> </Products> <EditionType>Enterprise</EditionType> <SubscriptionExpiry>20991231</SubscriptionExpiry> <LicenseExpiry>20991231</LicenseExpiry> <SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber> </Data> <Signature>sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=</Signature> </License>
5、pdf工具类
package com.tantela.util.contutil; import com.itextpdf.awt.geom.Rectangle2D; import com.itextpdf.text.Image; import com.itextpdf.text.Rectangle; import com.itextpdf.text.pdf.PdfContentByte; import com.itextpdf.text.pdf.PdfReader; import com.itextpdf.text.pdf.PdfStamper; import com.itextpdf.text.pdf.parser.PdfReaderContentParser; import com.tantela.model.wyqiang.filemanage.contfile.ContInfo; import com.tantela.model.ygc.order.OrderInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.*; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @ClassName:CreateContPdf * @Description:建立PDF合同 * @Version:V1.0 * @Author:wuyongqiang * @Date:2021/12/7 15:00:59 */ public class PdfUtil { /** * @param inputStream 电子合同pdf文件流 * @param targetPath 保存路径 * @throws Exception 异常参数 * @Title: itextPDFAddPicture * @Description: 为pdf加图片(电子合同盖公章) */ public static void itextPDFAddPicture(InputStream inputStream, String targetPath) throws Exception { // 1.1 读取模板文件 PdfReader reader = new PdfReader(inputStream); // 1.2 创建文件输出流 FileOutputStream out = new FileOutputStream(targetPath); // 2、创建PdfStamper对象 PdfStamper stamper = new PdfStamper(reader, out); // 4、读取公章 String path = System.getProperty("user.dir") + "/website/cont/officialSeal/officialSeal.png"; BufferedImage bufferedImage = ImageIO.read(new FileInputStream(path));// 整个公章图片流 BufferedImage[] imgs = ImageUtil.splitImage(bufferedImage, 1, 2); BufferedImage leftBufferedImage = imgs[0];// 左边公章图片流 BufferedImage rightBufferedImage = imgs[1];// 右边公章图片流 // 5、读公章图片 Image image = Image.getInstance(ImageUtil.imageToBytes(bufferedImage)); Image leftImage = Image.getInstance(ImageUtil.imageToBytes(leftBufferedImage)); Image rightImage = Image.getInstance(ImageUtil.imageToBytes(rightBufferedImage)); int chunkWidth = 250;// 公章大小,x轴 int chunkHeight = 250;// 公章大小,y轴 // 获取pdf页面的高和宽 Rectangle pageSize = reader.getPageSize(1); float height = pageSize.getHeight(); float width = pageSize.getWidth(); // 6、为pdf每页加印章 // 设置公章的位置 float xL = width - chunkWidth / 2 - 2; float yL = height / 2 - chunkHeight / 2 - 280; float xR = width - chunkHeight / 2 + chunkHeight / 8 + 4; float yR = yL; // 6.1 第一页盖左章 leftImage.scaleToFit(chunkWidth, chunkHeight);// 公章大小 leftImage.setAbsolutePosition(xL, yL);// 公章位置 // 6.2 第二页盖右章 rightImage.scaleToFit(chunkWidth, chunkHeight);// 公章大小 rightImage.setAbsolutePosition(xR, yR);// 公章位置 int pdfPages = reader.getNumberOfPages();// pdf页面页码 // 遍历为每页盖左章或右章 for (int i = 1; i <= pdfPages; i++) { if (i % 2 == 0) {// 盖右章 stamper.getOverContent(i).addImage(rightImage); } else {// 盖左章 stamper.getOverContent(i).addImage(leftImage); } } // 6.3 最后一页盖公章 image.scaleToFit(chunkWidth, chunkHeight); //新建一个PDF解析对象 PdfReaderContentParser parser = new PdfReaderContentParser(reader); Rectangle2D.Float position = getPosition(stamper, reader, "盖章处"); // image.setAbsolutePosition(width/2 + 32, height-chunkHeight -350); //得到的位置有些许偏差,自行调节 image.setAbsolutePosition(position.x + 150, position.y - 110); stamper.getOverContent(pdfPages).addImage(image); // 7、关闭相关流 stamper.close(); out.close(); reader.close(); inputStream.close(); } /** * @Author: wuyongqiang * @Description:获取pdf中关键字位置,得到的位置有些许偏差,根据实际显示结果自行调节 * @Date: 2021/12/7 9:53 * @Param stamper: * @Param reader: * @Param str: * @return: com.itextpdf.awt.geom.Rectangle2D.Float **/ public static Rectangle2D.Float getPosition(PdfStamper stamper, PdfReader reader, String str) throws IOException { //新建一个PDF解析对象 PdfReaderContentParser parser = new PdfReaderContentParser(reader); Rectangle2D.Float position = null; for (int i = 1; i <= reader.getNumberOfPages(); i++) { PdfContentByte pdfContentByte = stamper.getOverContent(i); //新建一个ImageRenderListener对象,该对象实现了RenderListener接口,作为处理PDF的主要类 TestRenderListener listener = new TestRenderListener(); //解析PDF,并处理里面的文字 parser.processContent(i, listener); //获取文字的矩形边框 List<Rectangle2D.Float> rectText = listener.rectText; List<String> textList = listener.textList; List<Float> listY = listener.listY; List<Map<String, Rectangle2D.Float>> list_text = listener.rows_text_rect; for (String strtext : textList) { if (strtext.contains(str)) { int index = textList.indexOf(strtext); position = rectText.get(index); } } } return position; } }
6、image工具类
package com.tantela.util.contutil; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; /** * @ClassName:ImageUtil * @Description:公章图片处理类 * @Version:V1.0 * @Author:wuyongqiang * @Date:2021/12/7 16:16:50 */ public class ImageUtil { /** * @Author: wuyongqiang * @Description:分割图片 * @Date: 2021/12/9 8:34 * @Param image: 图片BufferedImage流 * @Param rows: 分割行 * @Param cols: 分割列 * @return: java.awt.image.BufferedImage[] 返回分割后的图片流 **/ public static BufferedImage[] splitImage(BufferedImage image, int rows, int cols) { // 分割成4*4(16)个小图 int chunks = rows * cols; // 计算每个小图的宽度和高度 int chunkWidth = image.getWidth() / cols + 3;// 向右移动3 int chunkHeight = image.getHeight() / rows; int count = 0; BufferedImage[] imgs = new BufferedImage[chunks]; for (int x = 0; x < rows; x++) { for (int y = 0; y < cols; y++) { //设置小图的大小和类型 imgs[count] = new BufferedImage(chunkWidth, chunkHeight, BufferedImage.TYPE_INT_RGB); //写入图像内容 Graphics2D gr = imgs[count].createGraphics(); // 增加下面代码使得背景透明 imgs[count] = gr.getDeviceConfiguration().createCompatibleImage(chunkWidth, chunkHeight, Transparency.TRANSLUCENT); gr.dispose(); gr = imgs[count].createGraphics(); gr.drawImage(image, 0, 0, chunkWidth, chunkHeight, chunkWidth * y, chunkHeight * x, chunkWidth * y + chunkWidth, chunkHeight * x + chunkHeight, null); gr.dispose(); count++; } } return imgs; } /** * @Author: wuyongqiang * @Description: 将BufferedImage转换成字节数组 * @Date: 2021/12/6 17:31 * @Param bufferedImage: * @return: byte[] **/ public static byte[] imageToBytes(BufferedImage bufferedImage) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write( bufferedImage, "png", baos ); baos.flush(); byte[] imageInByte = baos.toByteArray(); baos.close(); return imageInByte; } }
7、数字转中文工具类
package com.tantela.util.contutil; import java.math.BigDecimal; /** * @ClassName:NumberTOChinese * @Description:数字转中文 * @Version:V1.0 * @Author:wuyongqiang * @Date:2021/12/8 10:54:51 */ public class NumberToChinese { /** * 汉语中数字大写 */ private static final String[] CN_UPPER_NUMBER = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" }; /** * 汉语中货币单位大写,这样的设计类似于占位符 */ private static final String[] CN_UPPER_MONETRAY_UNIT = { "分", "角", "元", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾", "佰", "仟", "兆", "拾", "佰", "仟" }; /** * 特殊字符:整 */ private static final String CN_FULL = "整"; /** * 特殊字符:负 */ private static final String CN_NEGATIVE = "负"; /** * 金额的精度,默认值为2 */ private static final int MONEY_PRECISION = 2; /** * 特殊字符:零元整 */ private static final String CN_ZEOR_FULL = "零元" + CN_FULL; /** * @Author: wuyongqiang * @Description: 把输入的金额转换为汉语中人民币的大写 * @Date: 2021/12/8 10:58 * @Param numberOfMoney: 输入的金额 * @return: java.lang.String 对应的汉语大写 **/ public static String toChinese(BigDecimal numberOfMoney) { StringBuffer sb = new StringBuffer(); // -1, 0, or 1 as the value of this BigDecimal is negative, zero, or // positive. int signum = numberOfMoney.signum(); // 零元整的情况 if (signum == 0) { return CN_ZEOR_FULL; } //这里会进行金额的四舍五入 long number = numberOfMoney.movePointRight(MONEY_PRECISION) .setScale(0, 4).abs().longValue(); // 得到小数点后两位值 long scale = number % 100; int numUnit = 0; int numIndex = 0; boolean getZero = false; // 判断最后两位数,一共有四中情况:00 = 0, 01 = 1, 10, 11 if (!(scale > 0)) { numIndex = 2; number = number / 100; getZero = true; } if ((scale > 0) && (!(scale % 10 > 0))) { numIndex = 1; number = number / 10; getZero = true; } int zeroSize = 0; while (true) { if (number <= 0) { break; } // 每次获取到最后一个数 numUnit = (int) (number % 10); if (numUnit > 0) { if ((numIndex == 9) && (zeroSize >= 3)) { sb.insert(0, CN_UPPER_MONETRAY_UNIT[6]); } if ((numIndex == 13) && (zeroSize >= 3)) { sb.insert(0, CN_UPPER_MONETRAY_UNIT[10]); } sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]); sb.insert(0, CN_UPPER_NUMBER[numUnit]); getZero = false; zeroSize = 0; } else { ++zeroSize; if (!(getZero)) { sb.insert(0, CN_UPPER_NUMBER[numUnit]); } if (numIndex == 2) { if (number > 0) { sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]); } } else if (((numIndex - 2) % 4 == 0) && (number % 1000 > 0)) { sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]); } getZero = true; } // 让number每次都去掉最后一个数 number = number / 10; ++numIndex; } // 如果signum == -1,则说明输入的数字为负数,就在最前面追加特殊字符:负 if (signum == -1) { sb.insert(0, CN_NEGATIVE); } // 输入的数字小数点后两位为"00"的情况,则要在最后追加特殊字符:整 if (!(scale > 0)) { sb.append(CN_FULL); } return sb.toString(); } }
8、文字处理类
package com.tantela.util.contutil; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.itextpdf.awt.geom.Rectangle2D; import com.itextpdf.awt.geom.RectangularShape; import com.itextpdf.text.pdf.parser.ImageRenderInfo; import com.itextpdf.text.pdf.parser.RenderListener; import com.itextpdf.text.pdf.parser.TextRenderInfo; /** * @ClassName:TestRenderListener * @Description: * @Version:V1.0 * @Author:wuyongqiang * @Date:2021/12/7 09:31:06 */ public class TestRenderListener implements RenderListener{ //用来存放文字的矩形 List<Rectangle2D.Float> rectText = new ArrayList<Rectangle2D.Float>(); //用来存放文字 List<String> textList = new ArrayList<String>(); //用来存放文字的y坐标 List<Float> listY = new ArrayList<Float>(); //用来存放每一行文字的坐标位置 List<Map<String, Rectangle2D.Float>> rows_text_rect = new ArrayList<Map<String, Rectangle2D.Float>>(); //PDF文件的路径 //protected String filepath = null; /** * 文字主要处理方法 */ @Override public void renderText(TextRenderInfo renderInfo) { String text = renderInfo.getText(); if (text.length() > 0) { RectangularShape rectBase = renderInfo.getBaseline().getBoundingRectange(); //获取文字下面的矩形 Rectangle2D.Float rectAscen = renderInfo.getAscentLine().getBoundingRectange(); //计算出文字的边框矩形 float leftX = (float) rectBase.getMinX(); float leftY = (float) rectBase.getMinY() - 1; float rightX = (float) rectAscen.getMaxX(); float rightY = (float) rectAscen.getMaxY() + 1; Rectangle2D.Float rect = new Rectangle2D.Float(leftX, leftY, rightX - leftX, rightY - leftY); System.out.println("text:" + text + "--x:" + rect.x + "--y:" + rect.y + "--width:" + rect.width + "--height:" + rect.height); if (listY.contains(rect.y)) { int index = listY.indexOf(rect.y); float tempx = rect.x > rectText.get(index).x ? rectText.get(index).x : rect.x; rectText.set(index, new Rectangle2D.Float(tempx, rect.y, rect.width + rectText.get(index).width, rect.height)); textList.set(index, textList.get(index) + text); } else { rectText.add(rect); textList.add(text); listY.add(rect.y); } Map<String, Rectangle2D.Float> map = new HashMap<String, Rectangle2D.Float>(); map.put(text, rect); rows_text_rect.add(map); } } }
最终效果截图如下:
参考众多博客内容做出来的,不为盈利,只为方便大家早日做出来。不懂的可以私信,尽量解答。
-
Unity 5.X从入门到精通 pdf 高清带书签(作者 Unity Technologies )
2018-12-02 21:26:51第 1 章 认识Unity引擎 1 1.1Unity简介 2 1.2Unity发展史 3 1.3Unity 5.0 4 第 2 章 Unity开发案例介绍 7 2.1Unity游戏介绍 8 2.2Unity非游戏应用 11 第 3 章软件安装、授权与服务 13 3.1软件安装 14 3.1.1在Windows... -
第十一章逻辑代数初步、十二章算法和程序框图复习卷(DOC).pdf
2020-06-28 22:27:32第十一章 逻辑代数初步 复习卷 知识点 第一节 二进制及其转换 1数位 2 基数 3 位权数 4 十进制 逢十进一 的计数体制 它把 0 1 2 34 5 6 7 8 9 这十个数码 放到相应的位置来表示数 十进制位权数 整数部分从右向左... -
Unity开发实战 .pdf
2019-02-28 15:04:24本书共11章,内容几乎涵盖了Unity的所有方面。第1章适合那些刚开始或准备...第9章关系到很多让计算机控制的对象和角色移动的游戏。第10章给出了一些在游戏中添加附加功能的创意。第11章简单地介绍了Unity专业版的功能。 -
光源原理与设计的PDF电子书免费下载
2021-07-07 00:03:29本书共7章,论述了从传统光源到半导体光源(LED和OLED)的原理、特性与设计。为便于读者掌握以上内容,还介绍了光辐射、气体放电,以及光度学、色度学基础等知识。 目录第一章光源的特性参量1.1光源的... -
关于Python 向pdf添加印章效果的思考及实现
2019-06-04 12:40:551.首先,肯定是想有一个函数可以直接实现,因为印章图片已经是去掉背景后的png图片了,即32bit(也就是RGBA格式),所以就想直接把图片放到指定位置不就可以了,然后去百度python中的做法,最后没有发现可... -
PDF电子发票合并.7z
2021-06-06 15:51:13很多工具合并pdf发票时,会造成电子章丢失,保证这个不会。可执行文件放到要合并的文件夹下,双击即可,合并后的为merged.pdf。可以用cmd文件进行链接,双击。python编译 -
Android:使用MuPDF显示PDF文件,解决不显示电子章问题
2018-02-27 16:53:30后来在网上搜索使用pdfView来显示,本身pdfView项目包挺大的,我使用了旧的版本自己优化了一下,使得自己的项目包只增加了1M左右的大小,本来以为就这样解决了,结果后来项目经理跟我说:APP的PDF上没有电子章,合同... -
编写高质量代码 改善Java程序的151个建议 PDF高清完整版
2018-06-07 11:44:40建议117: 多使用异常,把性能问题放一边/213 第9章 多线程和并发/215 建议118: 不推荐覆写start方法/216 建议119: 启动线程前stop方法是不可靠的/218 建议120: 不使用stop方法停止线程/220 建议121: 线程... -
PDF文件中插入图片(图章)
2017-02-21 19:08:33在Adobe Reader里面的【填写与签名】里面有个设置签名的地方,可以放置插入图片。 选择图片后点击【接受】按钮 然后点击 放置 签名 ,就可以把图片放到pdf文件里面了。 -
综合布线技术基础.pdf
2022-04-22 10:17:05第1章 综合布线技术基础 综合布线概述 综合布线系统的发展 ... 无论是建造电信级数据网络、城域网还是局域 网,越来越多的网络建设者都把提高网络线路 设计和施工质量放到了战略的高度来规划和考 虑。 -
新概念51单片机C语言教程 PDF电子书
2018-05-05 08:01:19《新概念51单片机C语言教程:入门、提高、开发、拓展全攻略》内容丰富,实用性强,书中大部分内容均来自科研工作及教学实践,许多C语言代码可以直接应用到工程项目中。《新概念51单片机C语言教程:入门、提高、开发、... -
PaaS云平台架构和运维管理.pdf
2020-05-25 21:18:02传统企业PaaS设计和业务上云 03 02 PaaS平台功能和构建 基于PAAS平台运维管理 04 第一章:分布式PaaS平台介绍 开发和运维之间的困局 开发团队: 主要工作是编写业务所需的代码,并且将这些代 码放到测试,生产环境中运行... -
《Python金融大数据挖掘与分析全流程详解》第10章 PDF文本解析 笔记整理
2019-12-02 16:29:421、PDF批量下载 步骤: (1)模拟搜索要下载的pdf关键词,得到下载页面的内容 (2)提取出标题、链接、日期;筛选出2018-2019年的 (3)访问下载链接,模拟点击下载按钮下载。这里要注意添加time.sleep()作为... -
java利用spire.pdf 将图片添加到 pdf
2019-12-13 14:36:08工具:Free Spire.PDF for Java V2.0.0(免费版) 首先,在pom.xml文件中配置Maven仓库路径。 <repositories> <repository> <id>com.e-iceblue</id> <name>e-iceblue<... -
使用Java对PDF进行电子签章
2021-04-19 16:34:55我把签章的过程给记录下来 前期准备 1. 需要签名的PDF (废话,没有PDF签什么名啊~) 2. 给PDF签名的印章图片 (貌似也是废话) 3. keystore 证书文件 (先认识认识,教程接下来会说怎么生成) 开始 生成keystore... -
改善Java程序的151个建议_12946976 完整高清.pdf
2017-11-15 14:41:19建议117: 多使用异常,把性能问题放一边 第9章 多线程和并发 建议118: 不推荐覆写start方法 建议119: 启动线程前stop方法是不可靠的 建议120: 不使用stop方法停止线程 建议121: 线程优先级只使用三... -
HTML5程序设计-HTML5拖放.pdf
2020-07-02 20:14:52HTML5基础教程第2版 授课教师 职务 第5章 HTML5拖放 课程描述 拖放是一种常见的操作也 就是用鼠标抓取一个对象 将其拖放到另一个位置 如在Windows中可以将 一个对象拖放到回收站中 过去在Web应用程序中实 现拖放的... -
数据结构与算法 讲义(8).pdf
2020-05-31 08:45:32数据结构与算法 第8章 文件管理和外排序 任课教员张 铭 /mzhang/DS/ mzhang@ 北京大学信息科学与技术学院 网络与信息系统研究所 版权所有转载或翻印...数据量太大不可能同时把它们放到内存中 需要把全部数据放到磁盘中 -
COM与COM+从入门到精通(pdf版本,含源码)
2012-07-18 16:18:46第4章 在VC++中建立并使用ActiveX控件 ACtiveX控件概还 属性与方法 控件与容器通信 事件与连接点 建立第一个控件 生成控件 测试控件 增加方法 增加属性 增加事件 增加属性页 允许属性保持 使用控件 ... -
扇形微带偏置的理论和ADS详细设计过程.pdf
2020-11-20 11:01:363.2 将高阻线和扇形微带放入电路中,并仿真和优化(注意优化的变量都有哪些) 7 3.3 仿真结果分析(关键) 9 3.4 生成版图 10 3.5 导出到AUTOCAD中并填充 11 第4章 有助于加深理解扇形微带偏置原理的ADS仿真分析 11 ... -
ASP.NET从基础到实践-适用于3.5 4.0 4.5版本-DVD(第20章)
2017-07-16 08:11:30ASP.NET从基础到实践-适用于3.5 4.0 4.5版本-DVD(第20章) 为了要那个光盘例子没办法,买了这本书,后来觉得看书还是比较麻烦, 想退无奈运费太贵没退成。 此例子放此处给需要的人,避免像我一样为了例子花费几十去...