pdfBox在pdf指定位置添加表格和内容

功能描述:在右上角指定位置添加表格和文本。

实现思路:读取pdf,在指定位置画线,线段组成表格;指定位置也就是表格内写入文字。所有pdf坐标原点(0,0)都为左下角。

遇到问题:坐标原点大部分在左下角,有时会在其他地方。后来发现在创建PDPageContentStream对象时,引用参数为AppendMode.APPEND(所有内容流之后插入内容)改为AppendMode.PREPEND(在所有内容流之前插入内容),此时坐标原点为左下角。

实现效果:
在这里插入图片描述

代码如下:

package com.gtzn.common.utils;

import org.apache.log4j.Logger;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import java.awt.*;
import java.io.File;
import java.io.IOException;

/**
 * @author 
 * @title PdfAddSealUtil
 * @Description:
 * @date 2020/8/5
 */
public class PdfAddSealUtil {
    private static Logger logger = Logger.getLogger(PdfAddSealUtil.class);

    public static void main(String args[]) {

        new PdfAddSealUtil().addSeal("F:/Administrator/Desktop/处理.pdf", "F:/Administrator/Desktop/1232.pdf", "中国", "文书", "2020", "办公室", "30年", "numb");

    }

    public boolean addSeal(String inPath, String outPath, String qz, String lb, String year, String dep, String deadline, String numb) {
        try {
            File file = new File(inPath);
            if(!file.exists()){
                logger.debug("找不到文件:"+inPath);
            }
            // 文件夹不存在新建文件夹
            String outDir = outPath.substring(0,outPath.lastIndexOf("/"));
            File outDirFile = new File(outDir);
            if(!outDirFile.exists()){
                outDirFile.mkdirs();
                logger.debug("归档章,新建文件夹成功:"+outDir);
            }

            PDDocument doc = PDDocument.load(file);
            // 导入楷体
            PDFont font = PDType0Font.load(doc, this.getClass().getResourceAsStream(
                    "/simkai.ttf"));

            PDPage page = doc.getPage(0);
            PDPageContentStream contentStream = new PDPageContentStream(doc, page, PDPageContentStream.AppendMode.PREPEND,false, false);
            float width = page.getMediaBox().getWidth();
            float height = page.getMediaBox().getLowerLeftY()+page.getMediaBox().getHeight();

            // 表格起始x,y坐标;印章距离右上角各5mm
            float x= width-countMM(95);
            float y= height-countMM(12);
            // 所有表格高度mm转point
            float allTableheight1 = countMM(8);
            float allTableheight2 = countMM(8);
            // 上层左起第一个表格
            float topOneTableWidth = countMM(75);// 宽度

            // 上层左起第二个表格
            float topTwoTableWidth = countMM(15);
            float topTwoTableX = x+topOneTableWidth;

            float bottomTableY = y-allTableheight2;
            // 下层左起第一个表格
            float bottomOneTableWidth = countMM(11);

            // 下层左起第二个表格
            float bottomTwoTableWidth = countMM(53);
            float bottomTwoTableX = x+bottomOneTableWidth;

            float bottomThreeTableWidth = countMM(11);
            float bottomThreeTableX = bottomTwoTableX+bottomTwoTableWidth;

            float bottomFourTableWidth = countMM(15);
            float bottomFourTableX = bottomThreeTableX+bottomThreeTableWidth;

            // 画表格
            drawTable(contentStream, x,y,topOneTableWidth,allTableheight1);
            drawTable(contentStream, topTwoTableX,y,topTwoTableWidth,allTableheight1);
            drawTable(contentStream, x,bottomTableY,bottomOneTableWidth,allTableheight2);
            drawTable(contentStream, bottomTwoTableX,bottomTableY,bottomTwoTableWidth,allTableheight2);
            drawTable(contentStream, bottomThreeTableX,bottomTableY,bottomThreeTableWidth,allTableheight2);
            drawTable(contentStream, bottomFourTableX,bottomTableY,bottomFourTableWidth,allTableheight2);

            // 文字上移2毫米,居中
            float move2mm = countMM(3);
            int fontSize=12;
            writeText(contentStream, font, fontSize, 0, 0, "测试");
            writeText(contentStream, font, fontSize, x+countMM(1), y+move2mm, qz);
            writeText(contentStream, font, fontSize, topTwoTableX+countMM(1), y+move2mm, lb);
            writeText(contentStream, font, fontSize, x+countMM(1), bottomTableY+countMM(3), year);
            if(dep.length()>12) {
                int length1 =dep.length();
                if(length1>18) {
                    length1 =18;
                    String str1=dep.substring(0,length1);
                    writeText(contentStream, font, 8, bottomTwoTableX+countMM(1), bottomTableY+countMM(4), str1);
                    String str2=dep.substring(18);
                    writeText(contentStream, font, 8, bottomTwoTableX+countMM(1), bottomTableY+countMM(1), str2);
                }else {
                    String str1=dep.substring(0,length1);
                    writeText(contentStream, font, 8, bottomTwoTableX+countMM(1), bottomTableY+countMM(4), str1);
                }

            }else {
                writeText(contentStream, font, fontSize, bottomTwoTableX+countMM(1), bottomTableY+countMM(3), dep);
            }
            writeText(contentStream, font, fontSize, bottomThreeTableX+countMM(1), bottomTableY+countMM(3), deadline);
            writeText(contentStream, font, fontSize, bottomFourTableX+countMM(1), bottomTableY+countMM(3), numb);
            contentStream.close();
            doc.save(outPath);
            doc.close();
            return true;
        } catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    private void drawTable(PDPageContentStream contentStream,float x,float y,float tableWidth,float tableHeight){
        try {
            contentStream.setStrokingColor(Color.red);
            drawLine(contentStream,x,y,x,y+tableHeight);
            drawLine(contentStream,x,y+tableHeight,x+tableWidth,y+tableHeight);
            drawLine(contentStream,x+tableWidth,y+tableHeight,x+tableWidth,y);
            drawLine(contentStream,x+tableWidth,y,x,y);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void drawLine(PDPageContentStream contentStream,float startX,float startY,float endX,float endY){
        try {
            contentStream.moveTo(startX,startY);
            contentStream.lineTo(endX,endY);
            contentStream.stroke();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private float countMM(float point){
        return (float) (point*72/25.4);
    }

    private void writeText(PDPageContentStream contentStream, PDFont font, float fontSize, float startX,float startY, String txt) throws IOException {
        if(StringUtils.isEmpty(txt)){
            return;
        }
        contentStream.beginText();
        // 文字位置
        contentStream.newLineAtOffset(startX, startY);
        // 设置字体type,size
        contentStream.setFont(font, fontSize);
        contentStream.setNonStrokingColor(0, 0, 0);
        // 插入文本
        contentStream.showText(txt);
        contentStream.endText();
    }
}

Java中,通常使用第三方库如iText、PDFBox或者Apache PDFBox等来处理PDF文件并添加表单域。这里我将以Apache PDFBox为例进行说明,因为它提供了更丰富的功能。 首先,你需要在项目中引入PDFBox依赖。如果你使用的是Maven,可以在pom.xml文件中添加: ```xml <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>最新版本号</version> </dependency> ``` 然后,你可以按照以下步骤在PDF文件的指定位置添加表单域: 1. **创建PdfStamper实例**: ```java PDDocument document = PDDocument.load(new File("source_pdf.pdf")); PdfStamper stamper = new PdfStamper(document, new FileOutputStream("output_with_form.pdf")); ``` `PDDocument`加载原始PDF,`PdfStamper`用于对PDF进行操作。 2. **创建AcroFields对象**: ```java AcroFields form = stamper.getAcroFields(); ``` 这里获取了表单域的对象,可以添加表单控件到其中。 3. **定位插入点**: ```java PdfImportedPage page = stamper.getOverContent(pageNumber); Rectangle position = new Rectangle(left, top, width, height); // 指定表格位置 PdfAnnotation annotation = new PdfAnnotation(position, PdfAnnotation.PDFTYPE_FORM, stamper.getCatalog()); ``` 使用`PdfImportedPage`选择要在其上添加表单域的页面,并创建一个矩形区域表示插入位置。 4. **添加表单域**: ```java String fieldKey = "myField"; // 表单域的键值 AcroForm.acroFormPut(form, fieldKey, new PdfFormField(annotation)); ``` 将新的表单域添加到页面上,`fieldKey`是你自定义的字段名称。 5. **保存并关闭**: ```java stamper.close(); document.close(); ```
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值