itext_2021学习笔记

笔记整理来源https://blog.csdn.net/tomatocc 仅供学习参考

一、创建一个简单的PDF文件

package com.hxc;

import com.itextpdf.text.Document;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;

import java.io.FileOutputStream;

public class PdfTest {
    public static void main(String[] args) throws Exception {
        //第一步:创建一个文档实例 设置文档纸张为A4,文档排列为横向排列
        //实现A4纸页面 并且纵向排列(不设置则为横向)
        Document document = new Document(PageSize.A4.rotate());
        // 第二步:创建PdfWriter对象,设置pdf生成路径
        PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream("E:\\java\\Project\\KuangShen\\PdfTest\\demo1.pdf"));
        // 第三步:打开文档进行我们需要的操作
        document.open();
        //第四步:创建第一页(如果只有一页,可以省略这一步)
        document.newPage();
        // 第五步:在文档中添加内容
        document.add(new Paragraph("this is my first pdf demo"));
        //第六步:关闭文档
        document.close();
        //第七步:关闭书写流
        pdfWriter.close();
    }
}

在这里插入图片描述

二、设置PDF一些常用属性

package com.hxc;

import com.itextpdf.text.Document;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.FileOutputStream;

public class PdfTest2 {
    public static void main(String[] args) throws Exception {
        //实现A4纸页面并且横向显示(不设置则为 纵向)
        Document document = new Document(PageSize.A4.rotate());
        PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream("E:\\java\\Project\\KuangShen\\PdfTest\\demo2.pdf"));
        //打开文档
        document.open();
        //生成第一页
        document.newPage();
        //设置作者
        document.addAuthor("hxc");
        //设置创建日期
        document.addCreationDate();
        //设置创建者
        document.addCreator("by hxc");
        //设置生产者
        document.addProducer();
        //设置关键字
        document.addKeywords("me");
        //设置标题
        document.addTitle("set pdf properties");
        //设置主题
        document.addSubject("pdf properties");
        //加入文档内容
        document.add(new Paragraph("my first pdf demo"));
        //关闭文档
        document.close();
        pdfWriter.close();
    }
}

在这里插入图片描述

右键文件属性即可查看刚刚设置的PDF文件属性

三、对PDF文档进行加密和权限设置

itext中对pdf文档的加密包括两部分,第一部分是用户密码,第二部分是所有者密码。这两部分可以简单的理解为管理员密码用户密码因此我们在设置这两个密码的权限的时候,往往会将所有者密码的权限级别设置的更高,而用户密码权限往往是“只读”。

引入依赖

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.54</version>
</dependency>
package com.hxc;

import com.itextpdf.text.Document;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.FileOutputStream;

public class PdfTest3 {
    public static void main(String[] args) throws Exception {
        //实现A4纸页面 并且横向显示(不设置则为纵向)
        Document document = new Document(PageSize.A4.rotate());
        PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream("E:\\java\\Project\\KuangShen\\PdfTest\\demo3.pdf"));
        // 设置用户密码, 所有者密码,用户权限,所有者权限
        pdfWriter.setEncryption("userPassword".getBytes(),"ownerPassword".getBytes(), PdfWriter.ALLOW_COPY, PdfWriter.ENCRYPTION_AES_128);
        //打开文档
        document.open();
        //创建第一页(如果只有一页,这一步可以省略)
        document.newPage();
        //加入文档内容
        document.add(new Paragraph("pdf permission"));
        //关闭文档
        document.close();
    }
}

在这里插入图片描述

权限参数

权限名称权限加密级别
PdfWriter.ALLOW_MODIFY_CONTENTS允许打印,编辑,复制,签名40-bit-RC4
PdfWriter.ALLOW_COPY允许复制,签名 不允许打印,编辑40-bit-RC
PdfWriter.ALLOW_MODIFY_ANNOTATIONS允许打印,编辑,复制,签名40-bit-RC4
PdfWriter.ALLOW_FILL_IN允许打印,编辑,复制,签名40-bit-RC4
PdfWriter.ALLOW_SCREENREADERS允许打印,编辑,复制,签名40-bit-RC4
PdfWriter.ALLOW_ASSEMBLY允许打印,编辑,复制,签名40-bit-RC4
PdfWriter.EMBEDDED_FILES_ONLY允许打印,编辑,复制,签名0-bit-RC4
PdfWriter.DO_NOT_ENCRYPT_METADATA允许打印,编辑,复制,签名40-bit-RC4
PdfWriter.ENCRYPTION_AES_256允许打印,编辑,复制,签名256-bit-AES
PdfWriter.ENCRYPTION_AES_128允许打印,编辑,复制,签名128-bit-AES
PdfWriter.STANDARD_ENCRYPTION_128允许打印,编辑,复制,签名128-bit-RC4
PdfWriter.STANDARD_ENCRYPTION_40允许打印,编辑,复制,签名40-bit-RC4

四、对PDF加文字或图片水印

1、文字水印

package com.hxc;

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfGState;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.FileOutputStream;

public class PdfTest4 {
    public static void main(String[] args) throws Exception {
        //实现A4纸页面 并且横向显示(不设置则为纵向)
        Document document = new Document(PageSize.A4.rotate());
        PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream("E:\\java\\Project\\KuangShen\\PdfTest\\demo4.pdf"));
        // 打开文档
        document.open();
        // 创建第一页(如果只有一页的话,这一步可以省略)
        document.newPage();

        //加入水印
        PdfContentByte waterMar = pdfWriter.getDirectContentUnder();
        //开始设置水印
        waterMar.beginText();
        //设置水印透明度
        PdfGState gs = new PdfGState();
        //设置填充字体不透明度为0.4f
        gs.setFillOpacity(0.4f);
        try{
            //设置水印字体参数及大小                       (字体参数,字体编码格式,是否将字体信息嵌入到PDF中(一般不需要嵌入),字体大小
            waterMar.setFontAndSize(BaseFont.createFont(BaseFont.HELVETICA,BaseFont.WINANSI,BaseFont.NOT_EMBEDDED),60);
            //设置透明度
            waterMar.setGState(gs);
            //设置水印对齐方式,水印方式 x坐标 y坐标 旋转角度
            waterMar.showTextAligned(Element.ALIGN_RIGHT,"www.ppp.com",400,350,50);
            //设置水印颜色
            waterMar.setColorFill(BaseColor.GRAY);
            //结束设置
            waterMar.endText();
            waterMar.stroke();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            waterMar=null;
            gs=null;
        }
        //加入文档内容
        document.add(new Paragraph("PDF Watermarking Test "));
        //关闭文档
        document.close();
        pdfWriter.close();
    }
}

在这里插入图片描述

这里要说明一点水印是要放在pdf中的,因此在创建PdfContentByte对象之前,一定要先 document.newPage();。二者顺序是不能反过来的,如果反过来的意思就是先画水印,在创建一个pdf页面,显然不符合逻辑了。

2、图片水印

package com.hxc;

import com.itextpdf.text.Document;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfGState;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

/**
 * 图片水印
 */
public class PdfTest5 {
    public static void main(String[] args) throws Exception {
        //实现A4纸页面 并且横向显示(不设置则为纵向)
        Document document = new Document(PageSize.A4.rotate());
        PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream("E:\\java\\Project\\KuangShen\\PdfTest\\demo5.pdf"));
        // 打开文档
        document.open();
        // 创建第一页(如果只有一页的话,这一步可以省略)
        document.newPage();

        // 加入水印
        PdfContentByte waterMar = pdfWriter.getDirectContentUnder();
        //开始设置水印
        waterMar.beginText();
        // 设置水印透明度
        PdfGState gs = new PdfGState();
        // 设置笔触字体不透明度为0.4f
        gs.setStrokeOpacity(0.4f);
        try {
            Image image = Image.getInstance("D:\\testCertFile\\测试印章.gif");
            //设置坐标 绝对位置X Y
            image.setAbsolutePosition(300,100);
            //设置旋转弧度
            image.setRotation(30); //旋转 幅度
            // 设置旋转角度
            image.setRotationDegrees(45); //旋转 角度
            //设置等比缩放
            image.scalePercent(90); //依照比例缩放
            // image.scaleAbsolute(200,100);//自定义大小
            // 设置透明度
            waterMar.setGState(gs);
            //添加水印图片
            waterMar.addImage(image);
            //设置透明度
            waterMar.setGState(gs);
            //结束设置
            waterMar.endText();
            waterMar.stroke();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            waterMar = null;
            gs = null;
        }
        
        //加入文档内容
        document.add(new Paragraph("PDF picture watermarking test"));
        // 关闭文档
        document.close();
        pdfWriter.close();
    }
}

在这里插入图片描述

五、对PDF进行盖章/签章/数字签名

在本文中,我们需要生成一个.p12结尾的数字证书,该证书用来对我们的pdf文档进行数字签名。生成.p12证书的方法请参考我的另一篇文章:使用JDK的keytool生成p12证书

导入依赖:

		<dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcpkix-jdk15on</artifactId>
            <version>1.52</version>
        </dependency>

        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.54</version>
        </dependency>

        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>

        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.10</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
        </dependency>

第一步:创建SignatureInfo的实体类,用途是为了方便的增加需要签章的信息

package com.hxc.entity;

import com.itextpdf.text.pdf.PdfSignatureAppearance;
import lombok.Data;
import java.security.PrivateKey;
import java.security.cert.Certificate;

@Data
public class SignatureInfo {
    private  String reason; //签名的原因,显示在pdf签名属性中
    private  String location;//签名的地点,显示在pdf签名属性中
    private String digestAlgorithm;//摘要算法名称,例如SHA-1
    private String imagePath;//图章路径
    private  String fieldName;//表单域名称
    private  Certificate[] chain;//证书链
    private PrivateKey pk;//签名私钥
    private  int certificationLevel = 0; //批准签章
    private PdfSignatureAppearance.RenderingMode renderingMode;//表现形式:仅描述,仅图片,图片和描述,签章者和描述
    //图章属性
    private float rectllx ;//图章左下角x
    private float rectlly ;//图章左下角y
    private float recturx ;//图章右上角x
    private float rectury ;//图章右上角y
}

第二步:我们创建一个用于对pdf签章的工具类,以及main方法

package com.hxc.util;

import com.hxc.entity.SignatureInfo;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.security.*;

import java.io.*;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;

public class ItextUtil {
    public static final char[] PASSWORD = "123456".toCharArray();// keystory密码

    /**
     * 单多次章通用
     * @param src
     * @param target
     * @param signatureInfo
     */
    @SuppressWarnings("resource")
    public void sign(String src, String target, SignatureInfo signatureInfo) {
        InputStream inputStream = null;
        FileOutputStream outputStream = null;
        ByteArrayOutputStream result = new ByteArrayOutputStream();
        try {
            inputStream = new FileInputStream(src);
            ByteArrayOutputStream tempArrayOutputStream = new ByteArrayOutputStream();
            PdfReader reader = new PdfReader(inputStream);
            // 创建签章工具PdfStamper ,最后一个boolean参数是否允许被追加签名
            // false的话,pdf文件只允许被签名一次,多次签名,最后一次有效
            // true的话,pdf可以被追加签名,验签工具可以识别出每次签名之后文档是否被修改
            PdfStamper stamper = PdfStamper.createSignature(reader,
                    tempArrayOutputStream, '\0', null, true);
            // 获取数字签章属性对象
            PdfSignatureAppearance appearance = stamper
                    .getSignatureAppearance();
            appearance.setReason(signatureInfo.getReason());
            appearance.setLocation(signatureInfo.getLocation());
            // 设置签名的位置,页码,签名域名称,多次追加签名的时候,签名预名称不能一样 图片大小受表单域大小影响(过小导致压缩)
            // 签名的位置,是图章相对于pdf页面的位置坐标,原点为pdf页面左下角
            // 四个参数的分别是,图章左下角x,图章左下角y,图章右上角x,图章右上角y
            appearance.setVisibleSignature(
                    new Rectangle(signatureInfo.getRectllx(), signatureInfo
                            .getRectlly(), signatureInfo.getRecturx(),
                            signatureInfo.getRectury()), 1, signatureInfo
                            .getFieldName());
            // 读取图章图片
            Image image = Image.getInstance(signatureInfo.getImagePath());
            appearance.setSignatureGraphic(image);
            appearance.setCertificationLevel(signatureInfo
                    .getCertificationLevel());
            // 设置图章的显示方式,如下选择的是只显示图章(还有其他的模式,可以图章和签名描述一同显示)
            appearance.setRenderingMode(signatureInfo.getRenderingMode());
            // 摘要算法
            ExternalDigest digest = new BouncyCastleDigest();
            // 签名算法
            ExternalSignature signature = new PrivateKeySignature(
                    signatureInfo.getPk(), signatureInfo.getDigestAlgorithm(),
                    null);
            // 调用itext签名方法完成pdf签章 //数字签名格式,CMS,CADE
            MakeSignature.signDetached(appearance, digest, signature,
                    signatureInfo.getChain(), null, null, null, 0,
                    MakeSignature.CryptoStandard.CADES);

            inputStream = new ByteArrayInputStream(
                    tempArrayOutputStream.toByteArray());
            // 定义输入流为生成的输出流内容,以完成多次签章的过程
            result = tempArrayOutputStream;

            outputStream = new FileOutputStream(new File(target));
            outputStream.write(result.toByteArray());
            outputStream.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != outputStream) {
                    outputStream.close();
                }
                if (null != inputStream) {
                    inputStream.close();
                }
                if (null != result) {
                    result.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        try {
            ItextUtil app = new ItextUtil();
            // 将证书文件放入指定路径,并读取keystore ,获得私钥和证书链
            String pkPath = "D:\\itext\\tomatocc.p12";
            KeyStore ks = KeyStore.getInstance("PKCS12");
            ks.load(new FileInputStream(pkPath), PASSWORD);
            String alias = ks.aliases().nextElement();
            PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
            // 得到证书链
            Certificate[] chain = ks.getCertificateChain(alias);
            //需要进行签章的pdf
            String path = "D:\\itext\\demo.pdf";
            // 封装签章信息
            SignatureInfo signInfo = new SignatureInfo();
            signInfo.setReason("理由");
            signInfo.setLocation("位置");
            signInfo.setPk(pk);
            signInfo.setChain(chain);
            signInfo.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);
            signInfo.setDigestAlgorithm(DigestAlgorithms.SHA1);
            signInfo.setFieldName("demo");
            // 签章图片
            signInfo.setImagePath("D:\\itext\\sign.jpg");
            signInfo.setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);
            signInfo.setRectllx(100);  // 值越大,代表向x轴坐标平移 缩小 (反之,值越小,印章会放大)
            signInfo.setRectlly(200);  // 值越大,代表向y轴坐标向上平移(大小不变)
            signInfo.setRecturx(400);  // 值越大   代表向x轴坐标向右平移  (大小不变)
            signInfo.setRectury(100);  // 值越大,代表向y轴坐标向上平移(大小不变)
            //签章后的pdf路径
            app.sign(path, "D:\\itext\\demo3.pdf", signInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

**注意:**demo.pdf不可以直接通过改后缀名转换,否则会报PDF header signature not found.错误

在这里插入图片描述

`

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值