700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > java使用itextpdf生成pdf文档指定图片印章位置

java使用itextpdf生成pdf文档指定图片印章位置

时间:2020-07-23 08:25:15

相关推荐

java使用itextpdf生成pdf文档指定图片印章位置

项目结构

1.引包

<dependencies><!-- itextpdf--><dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.10</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.10</version></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.22</version></dependency><!-- /artifact/org.freemarker/freemarker --><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.19</version></dependency><!-- /artifact/org.xhtmlrenderer/flying-saucer-pdf --><dependency><groupId>org.xhtmlrenderer</groupId><artifactId>flying-saucer-pdf</artifactId><version>9.1.5</version></dependency><!-- /artifact/org.xhtmlrenderer/flying-saucer-pdf-itext5 --><dependency><groupId>org.xhtmlrenderer</groupId><artifactId>flying-saucer-pdf-itext5</artifactId><version>9.1.5</version></dependency></dependencies>

2.使用freemarker生成html文件

/*** 获取模板内容 : PDFHelper.getTemplateContent("071515133867.ftl", null);* @param templateName模板文件名* @param param模板参数* @return* @throws Exception*/public static String getTemplateContent(String templateName, Object param) {Configuration configuration = new Configuration();Writer out = null;try {configuration.setClassForTemplateLoading(PDFHelper.class, "/templates");// 设置编码格式configuration.setEncoding(Locale.CHINA, ENCODING);out = new StringWriter();Template template = configuration.getTemplate(templateName);template.process(param, out);out.flush();return out.toString();} catch (Exception e) {throw new RuntimeException(e);} finally {if (out != null) {try {out.close();} catch (IOException e) {}}}}

3.html转pdf

/*** HTML 转 PDF* @param content html内容* @return PDF字节数组*/public static byte[] html2Pdf(String content, Image... imageList) {ByteArrayOutputStream outputStream = null;try {Document document = new Document();outputStream = new ByteArrayOutputStream();PdfWriter writer = PdfWriter.getInstance(document, outputStream);document.open();XMLWorkerHelper.getInstance().parseXHtml(writer,document,new ByteArrayInputStream(content.getBytes()),XMLWorkerHelper.class.getResourceAsStream("/default.css"),Charset.forName(ENCODING),new CustomXMLWorkerFontProvider());if (imageList != null && imageList.length > 0) {for (Image image : imageList) {document.add(image);}}document.close();} catch (Exception e) {throw new RuntimeException(e);}return outputStream.toByteArray();}

到此生成完毕。但是特殊情况需要添加印章之类的,因为博主开始是在html中使用img标签和background发现样式都不生效。所以改用直接通过itextpdf的API添加

<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><meta http-equiv="Content-Style-Type" content="text/css"/><meta name="generator" content="Aspose.Words for .NET 15.1.0.0"/><title></title></head><body><div><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="color:#00b050; font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_RE_*: 'RE’代表repository。带有这个前缀的表包含“静态”信息,例如流程定义与流程资源(图片、规则等)。</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_RE_DEPLOYMENT 流程部署表</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_RE_PROCDEF 流程定义信息表</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_RE_MODEL 模型信息表(此表已经舍弃,更换为ACT_DE_MODEL)</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">&#xa0;</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="color:#00b050; font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_RU_*: 'RU’代表runtime。这些表存储运行时信息,例如流程实例(process instance)、用户任务(user task)、变量(variable)、作业(job)等。Flowable只在流程实例运行中保存运行时数据,并在流程实例结束时删除记录。这样保证运行时表小和快。</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_RU_EXECUTION 流程实例与分支执行表</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_RU_TASK 用户任务表</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_RU_VARIABLE 变量信息</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_RU_IDENTITYLINK 参与者相关信息表</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_RU_EVENT_SUBSCR 事件订阅表</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_RU_JOB 作业表</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_RU_TIMER_JOB 定时器表</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_RU_SUSPENDED_JOB 暂停作业表</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_RU_DEADLETTER_JOB 死信表</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_RU_HISTORY_JOB 历史作业表</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">&#xa0;</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="color:#00b050; font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_HI_*: 'HI’代表history。这些表存储历史数据,例如已完成的流程实例、变量、任务等。</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_HI_PROCINST 历史流程实例表</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_HI_ACTINST 历史节点信息表</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_HI_TASKINST 历史任务表</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_HI_VARINST 历史变量</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_HI_IDENTITYLINK 历史参与者表</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_HI_DETAIL 历史的流程运行中的细节信息</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_HI_ATTACHMENT 附件表</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_HI_COMMENT 评论表</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">&#xa0;</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="color:#00b050; font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_GE_*: 通用数据。在多处使用。</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_RU_JOB 作业表</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_GE_PROPERTY 属性表(保存流程引擎的kv键值属性)</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><spanstyle="font-family:Consolas; font-size:10.5pt; font-style:normal; text-transform:none">ACT_GE_BTYEARRAY 资源表(存储流程定义相关的资源)</span></p><p style="margin:0pt; orphans:0; text-align:justify; widows:0"><span style="font-family:Calibri; font-size:10.5pt">&#xa0;</span></p></div></body></html>

其中ACT_RU_JOB关键字出现两次,我想要在标记它出现的地方打印章,这里需要使用工具类找出PDF中出现关键字的位置

import cn.hutool.core.io.IoUtil;import com.itextpdf.awt.geom.Rectangle2D;import com.itextpdf.text.pdf.PdfDictionary;import com.itextpdf.text.pdf.PdfName;import com.itextpdf.text.pdf.PdfReader;import com.itextpdf.text.pdf.parser.*;import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;import java.util.List;public class ItextPDFUtil {public static final float defaultHeight = 16;public static final float fixHeight = 10;/*** findKeywordPostions* 返回查找到关键字的首个文字的左上角坐标值** @param keyword* @return List<float [ ]> : float[0]:pageNum float[1]:x float[2]:y* @throws IOException*/public static List<float[]> findKeywordPostions(InputStream pdfInputStream, String keyword) throws IOException {byte[] pdfData = IoUtil.readBytes(pdfInputStream);pdfInputStream.close();List<float[]> result = new ArrayList<>();List<PdfPageContentPositions> pdfPageContentPositions = getPdfContentPostionsList(pdfData);for (PdfPageContentPositions pdfPageContentPosition : pdfPageContentPositions) {List<float[]> charPositions = findPositions(keyword, pdfPageContentPosition);if (charPositions == null || charPositions.size() < 1) {continue;}result.addAll(charPositions);}return result;}/*** findKeywordPostions** @param pdfData 通过IO流 PDF文件转化的byte数组* @param keyword 关键字* @return List<float [ ]> : float[0]:pageNum float[1]:x float[2]:y* @throws IOException*/public static List<float[]> findKeywordPostions(byte[] pdfData, String keyword) throws IOException {List<float[]> result = new ArrayList<float[]>();List<PdfPageContentPositions> pdfPageContentPositions = getPdfContentPostionsList(pdfData);for (PdfPageContentPositions pdfPageContentPosition : pdfPageContentPositions) {List<float[]> charPositions = findPositions(keyword, pdfPageContentPosition);if (charPositions == null || charPositions.size() < 1) {continue;}result.addAll(charPositions);}return result;}private static List<PdfPageContentPositions> getPdfContentPostionsList(byte[] pdfData) throws IOException {PdfReader reader = new PdfReader(pdfData);List<PdfPageContentPositions> result = new ArrayList<PdfPageContentPositions>();int pages = reader.getNumberOfPages();for (int pageNum = 1; pageNum <= pages; pageNum++) {float width = reader.getPageSize(pageNum).getWidth();float height = reader.getPageSize(pageNum).getHeight();PdfRenderListener pdfRenderListener = new PdfRenderListener(pageNum, width, height);//解析pdf,定位位置PdfContentStreamProcessor processor = new PdfContentStreamProcessor(pdfRenderListener);PdfDictionary pageDic = reader.getPageN(pageNum);PdfDictionary resourcesDic = pageDic.getAsDict(PdfName.RESOURCES);try {processor.processContent(ContentByteUtils.getContentBytesForPage(reader, pageNum), resourcesDic);} catch (IOException e) {reader.close();throw e;}String content = pdfRenderListener.getContent();List<CharPosition> charPositions = pdfRenderListener.getcharPositions();List<float[]> positionsList = new ArrayList<float[]>();for (CharPosition charPosition : charPositions) {float[] positions = new float[]{charPosition.getPageNum(), charPosition.getX(), charPosition.getY(), charPosition.getWidth(), charPosition.getHeight()};positionsList.add(positions);}PdfPageContentPositions pdfPageContentPositions = new PdfPageContentPositions();pdfPageContentPositions.setContent(content);pdfPageContentPositions.setPostions(positionsList);result.add(pdfPageContentPositions);}reader.close();return result;}private static List<float[]> findPositions(String keyword, PdfPageContentPositions pdfPageContentPositions) {List<float[]> result = new ArrayList<float[]>();String content = pdfPageContentPositions.getContent();List<float[]> charPositions = pdfPageContentPositions.getPositions();for (int pos = 0; pos < content.length(); ) {int positionIndex = content.indexOf(keyword, pos);if (positionIndex == -1) {break;}float[] postions = charPositions.get(positionIndex);//此处较为关键通过第一个关键字计算出整个关键字的宽度for (int i = 1; i < keyword.length(); i++) {float[] postionsNew = charPositions.get(positionIndex + i);postions[3] = postions[3] + postionsNew[3];}result.add(postions);pos = positionIndex + 1;}return result;}private static class PdfPageContentPositions {private String content;private List<float[]> positions;public String getContent() {return content;}public void setContent(String content) {this.content = content;}public List<float[]> getPositions() {return positions;}public void setPostions(List<float[]> positions) {this.positions = positions;}}private static class PdfRenderListener implements RenderListener {private int pageNum;private float pageWidth;private float pageHeight;private StringBuilder contentBuilder = new StringBuilder();private List<CharPosition> charPositions = new ArrayList<CharPosition>();public PdfRenderListener(int pageNum, float pageWidth, float pageHeight) {this.pageNum = pageNum;this.pageWidth = pageWidth;this.pageHeight = pageHeight;}@Overridepublic void beginTextBlock() {}@Overridepublic void renderText(TextRenderInfo renderInfo) {List<TextRenderInfo> characterRenderInfos = renderInfo.getCharacterRenderInfos();for (TextRenderInfo textRenderInfo : characterRenderInfos) {String word = textRenderInfo.getText();if (word.length() > 1) {word = word.substring(word.length() - 1, word.length());}Rectangle2D.Float rectangle = textRenderInfo.getAscentLine().getBoundingRectange();float x = (float) rectangle.getX();float y = (float) rectangle.getY();//float x = (float)rectangle.getCenterX();//float y = (float)rectangle.getCenterY();//double x = rectangle.getMinX();//double y = rectangle.getMaxY();//这两个是关键字在所在页面的XY轴的百分比//float xPercent = Math.round(x / pageWidth * 10000) / 10000f;//float yPercent = Math.round((1 - y / pageHeight) * 10000) / 10000f;//CharPosition charPosition = new CharPosition(pageNum, xPercent, yPercent);CharPosition charPosition = new CharPosition(pageNum, x, y - fixHeight, (float) rectangle.getWidth(), (float) (rectangle.getHeight() == 0 ? defaultHeight : rectangle.getHeight()));charPositions.add(charPosition);contentBuilder.append(word);}}@Overridepublic void endTextBlock() {}@Overridepublic void renderImage(ImageRenderInfo renderInfo) {}public String getContent() {return contentBuilder.toString();}public List<CharPosition> getcharPositions() {return charPositions;}}private static class CharPosition {private int pageNum = 0;private float x = 0;private float y = 0;private float width;private float height;public CharPosition(int pageNum, float x, float y, float width, float height) {this.pageNum = pageNum;this.x = x;this.y = y;this.width = width;this.height = height;}public int getPageNum() {return pageNum;}public float getX() {return x;}public float getY() {return y;}public float getWidth() {return width;}public float getHeight() {return height;}@Overridepublic String toString() {return "CharPosition{" +"pageNum=" + pageNum +", x=" + x +", y=" + y +", width=" + width +", height=" + height +'}';}}}

使用main方法执行

import com.itextpdf.text.DocumentException;import com.itextpdf.text.Image;import com.itextpdf.text.pdf.*;import java.io.FileOutputStream;import java.io.IOException;import java.util.List;public class Test {public static void main(String[] args) throws IOException, DocumentException {String html = PDFHelper.getTemplateContent("071515133867.ftl", null);byte[] bytes = PDFHelper.html2Pdf(html);//查找位置List<float[]> postions = ItextPDFUtil.findKeywordPostions(bytes, "ACT_RU_JOB");// 第一次找到的位置float[] postion = postions.get(0);System.out.println("x:" + postion[1] + " y:" + postion[2]);//Modify file using PdfReader//Read file using PdfReaderPdfReader pdfReader = new PdfReader(bytes);PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileOutputStream("D:/test.pdf"));Image image = Image.getInstance("E:\\workspace\\java_pdf\\src\\main\\resources\\images\\69f70ad3-1cd7-4793-8c89-99dea0311a1b.001.png");//Fixed Positioning// 固定图片大小image.scaleAbsolute(100, 100);//Scale to new height and new width of image// 偏移量image.setAbsolutePosition(postion[1], postion[2]);System.out.println("pages-1:" + pdfReader.getNumberOfPages());PdfContentByte content = pdfStamper.getUnderContent((int) postion[0]);content.addImage(image);// 第二次找到的位置postion = postions.get(1);//Fixed Positioning// image.scaleToFit(100, 50);image.scaleAbsolute(100, 100);//Scale to new height and new width of imageimage.setAbsolutePosition(postion[1], postion[2]);System.out.println("pages-2:" + pdfReader.getNumberOfPages());content = pdfStamper.getUnderContent((int) postion[0]);content.addImage(image);// ByteArrayOutputStream outputStream = new ByteArrayOutputStream();// byte[] pdf = content.toPdf(PdfWriter.getInstance(content.getPdfDocument(), outputStream));pdfStamper.close();}}

最后看一下效果

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。