pdf文件添加文字/图片,“签名”功能,方法工具类

业务中遇到在pdf文件上盖章,添加文字信息(签名)的需求:包含单图片,多图片,多参数方法
老样子,直接上代码和注释,使用的方法类

引入jar包依赖

        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.6</version>
        </dependency>
        <!-- itextpdf的亚洲字体支持 -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>

controller层代码:

@PostMapping("/print")
    @ApiOperation(value = "打印结果")
    public ResponseMessage print(@RequestBody PrintResultRequest request) {
        OrganPrintSignature reviewer = null;
        OrganPrintSignature verifier = null;
        //这里是指定输出为流文件对象给前端,前端拿来使用“预览和下载”行为
        HttpServletResponse response = HttpContextUtil.getHttpServletResponse();
        try {
            OutputStream os = response.getOutputStream();
            // 设定输出文件头
            response.setHeader(
                    "Content-disposition",
                    "attachment; filename="
                            + new String(("打印结果结果.pdf")
                            .getBytes("GB2312"), "ISO8859-1"));
            // 定义输出类型
            response.setContentType("application/pdf");
            //签名url的map集合  key:用来做枚举,获取指定类型的url在pdf上的位置
            HashMap<String, String> imgMap = new HashMap<>();
            //pdfUrl:一般pdf都是把通用模板上传到服务器,引用的是服务器绝对路径
            InputStream docIn = new FileInputStream(new File(pdfUrl));
            log.info("-------------  文件读取成功,准备写入pdf");
            //审核签名url
            if (ObjectUtil.isNotNull(reviewer)) {
                imgMap.put("examineImg", reviewer.getUrl());
            }

            //本人签名url
            if (ObjectUtil.isNotNull(verifier)) {
                imgMap.put("checkImg", verifier.getUrl());
            }

            //印章图片url
            if (ObjectUtil.isNotNull(organPrintConfig.getSignetUrl())) {
                imgMap.put("sealImg", organPrintConfig.getSignetUrl());

            }
            //输出时间格式化
            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            //需要印在pdf文件上的文本参数 参数根据业务获取,这里举两个例子
            Map<String, String> map = new HashMap<>();
            map.put("name", "奥特曼");
            map.put("nowTime", df.format(LocalDateTime.now()));

            //填充pdf文件
            os.write(PDFUtil.signs(map, docIn, imgMap, 0, 1));
            log.info("-------------  填充pdf文件完成");

        } catch (Exception e) {
            String result = "系统提示:下载失败,原因:" + e.toString();
            log.error(result, e);
            throw new ServiceException(ResultCode.SYSTEM_BUSY);
        }

        return ResponseMessage.ok();

    }

pdfUtil方法类:

@Slf4j
@Configuration
public class PDFUtil {
    /**
     * 读取pdf中文字信息(全部)
     */
    public static void READPDF(String inputFile) {
        //创建文档对象
        PDDocument doc = null;
        String content = "";
        PdfDomainDTO vo = new PdfDomainDTO();
        try {
            //加载一个pdf对象
            doc = PDDocument.load(new File(inputFile));
            //获取一个PDFTextStripper文本剥离对象
            PDFTextStripper textStripper = new PDFTextStripper();
            content = textStripper.getText(doc);
            //vo.setContent(content);
            System.out.println("内容:" + content);
            System.out.println("全部页数" + doc.getNumberOfPages());
            //关闭文档
            doc.close();
        } catch (Exception e) {
            // TODO: handle exception
        }
    }

    /**
     * 将一张图片添加到PDF文件上,类似签名
     *
     * @param docInput  PDF文件
     * @param imgInput  图片文件,建议是无背景的PNG格式文件
     * @param x         以左下角为原点的x坐标
     * @param y         左下角为原点的y坐标
     * @param imgHeight 带有签名文字的图片宽度
     * @param imgWidth  带有签名文字的图片高度
     * @param rotation  带有签名文字的图片的旋转角度,逆时针旋转,如果不旋转则为0
     * @param pageNum   需要签名的页码数组,从1开始
     * @return 返回签好名的PDF文件字节码
     */
    public static byte[] addImgToDoc(Map<String, String> map, InputStream docInput, InputStream imgInput, int x, int y, float imgWidth, float imgHeight, float rotation, int[] pageNum) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        try {
            PdfReader reader = new PdfReader(docInput);
            PdfStamper stamp = new PdfStamper(reader, baos);
            stamp.setRotateContents(false);

            //印章图片
            byte[] imgBytes = new byte[imgInput.available()];
            IOUtils.read(imgInput, imgBytes);
            Image img = Image.getInstance(imgBytes);
            img.scaleAbsoluteWidth(imgWidth);
            img.scaleAbsoluteHeight(imgHeight);
            img.setAbsolutePosition(x, y);

            //这个字体是itext-asian.jar中自带的 所以不用考虑操作系统环境问题.
            BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            //baseFont不支持字体样式设定.但是font字体要求操作系统支持此字体会带来移植问题.
            Font font = new Font(bf, 30);
            font.setStyle(Font.NORMAL);
            font.getBaseFont();

            for (int pn : pageNum) {
                img.setRotationDegrees(rotation + reader.getPageRotation(pn)); // 旋转角度
                PdfContentByte over = stamp.getOverContent(pn);
                over.addImage(img);
                //开始写入文本
                over.beginText();
                //设置字体和大小
                over.setFontAndSize(font.getBaseFont(), 10);
                //设置字体颜色
                //over.setColorFill(new BaseColor(0,110,107,100));
                com.itextpdf.text.pdf.PdfGState gState = new PdfGState();
                gState.setStrokeOpacity(0.1f);
                over.setGState(gState);

                for (Map.Entry<String, String> entry : map.entrySet()) {
                    PdfAxisEnum anEnum = PdfAxisEnum.fetch(entry.getKey());
                    //要输出的text(对齐方式,写的字,设置字体的输出位置,字体是否旋转)
                    if (ObjectUtil.isNotNull(anEnum)) {

                        over.showTextAligned(0, entry.getValue(), anEnum.getXAxis(), anEnum.getYAxis(), 0);
                        if (anEnum.getParam().equals("result")) {
                            over.showTextAligned(0, entry.getValue(), anEnum.getXAxis() + 140, anEnum.getYAxis(), 0);
                        }
                    }
                }
                over.endText();
            }
            stamp.close();
            reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return baos.toByteArray();
    }

    /**
     * 将多张图片添加到PDF文件上,类似签名
     *
     * @param map      要写入的文本map
     * @param docInput PDF文件
     * @param imgMap   要添加的图片,输入流
     * @param rotation 带有签名文字的图片的旋转角度,逆时针旋转,如果不旋转则为0
     * @param pageNum  需要签名的页码数组,从1开始
     * @return 返回签好名的PDF文件字节码
     */
    public static byte[] addImgsToDoc(Map<String, String> map, InputStream docInput, Map<String, String> imgMap, float rotation, int[] pageNum) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        try {
            PdfReader reader = new PdfReader(docInput);
            PdfStamper stamp = new PdfStamper(reader, baos);
            stamp.setRotateContents(false);

            //这个字体是itext-asian.jar中自带的 所以不用考虑操作系统环境问题.
            BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            //baseFont不支持字体样式设定.但是font字体要求操作系统支持此字体会带来移植问题.
            Font font = new Font(bf, 30);
            font.setStyle(Font.NORMAL);
            font.getBaseFont();

            for (int pn : pageNum) {
                PdfContentByte over = stamp.getOverContent(pn);
                //循环写入图片,并按照枚举菜单取出在pdf中对应的位置
                for (Map.Entry<String, String> entry : imgMap.entrySet()) {
                    log.info("-------------  开始写入图片");
//                    byte[] imgBytes = new byte[entry.getValue().available()];
//                    IOUtils.read(entry.getValue(), imgBytes);
                    Image img = Image.getInstance(entry.getValue());

                    PdfAxisEnum anEnum = PdfAxisEnum.fetch(entry.getKey());
                    //要添加的图片
                    if (ObjectUtil.isNotNull(anEnum)) {
                        //图片大小
                        int imgWidth = 0;
                        int imgHeight = 0;

                        if (anEnum.getParam().equals("sealImg")) {
                            //印章图片
                            imgWidth = 100;
                            imgHeight = 100;
                        } else if (anEnum.getParam().equals("checkImg") || anEnum.getParam().equals("examineImg")) {
                            //签名图片1
                            imgWidth = 40;
                            imgHeight = 20;
                        }
                        img.scaleAbsoluteWidth(imgWidth);
                        img.scaleAbsoluteHeight(imgHeight);
                        img.setAbsolutePosition(anEnum.getXAxis(), anEnum.getYAxis());
                        img.setRotationDegrees(rotation + reader.getPageRotation(pn)); // 旋转角度
                        over.addImage(img);
                    }
                }

                log.info("-------------  开始写入文本");

                //开始写入文本
                over.beginText();
                //设置字体和大小
                over.setFontAndSize(font.getBaseFont(), 10);
                //设置字体颜色
                //over.setColorFill(new BaseColor(0,110,107,100));
                com.itextpdf.text.pdf.PdfGState gState = new PdfGState();
                gState.setStrokeOpacity(0.1f);
                over.setGState(gState);

                for (Map.Entry<String, String> entry : map.entrySet()) {
                    PdfAxisEnum anEnum = PdfAxisEnum.fetch(entry.getKey());
                    //要输出的text(对齐方式,写的字,设置字体的输出位置,字体是否旋转)
                    if (ObjectUtil.isNotNull(anEnum)) {
                        if (StrUtil.isNotEmpty(entry.getValue())) {

                            over.showTextAligned(0, entry.getValue(), anEnum.getXAxis(), anEnum.getYAxis(), 0);
                        }

                        if (anEnum.getParam().equals("result")) {
                            over.showTextAligned(0, entry.getValue(), anEnum.getXAxis() + 140, anEnum.getYAxis(), 0);
                        }
                    }
                }
                over.endText();
            }
            stamp.close();
            reader.close();
        } catch (Exception e) {
            log.error("写入pdf文件失败", e);
        }
        return baos.toByteArray();
    }

    /**
     * 将一张图片添加到PDF文件上,类似签名
     *
     * @param doc       PDF文件
     * @param img       图片文件,建议是无背景的PNG格式文件
     * @param x         以左下角为原点的x坐标
     * @param y         左下角为原点的y坐标
     * @param imgHeight 带有签名文字的图片宽度
     * @param imgWidth  带有签名文字的图片高度
     * @param rotation  带有签名文字的图片的旋转角度,逆时针旋转,如果不旋转则为0
     * @param pageNum   需要签名的页码数组,从1开始
     * @return 返回签好名的PDF文件字节码
     */
    public static byte[] sign(Map<String, String> map, InputStream doc, InputStream img, int x, int y, float imgWidth, float imgHeight, float rotation, int... pageNum) {
        if (pageNum == null || pageNum.length == 0) {
            return null;
        }
        return addImgToDoc(map, doc, img, x, y, imgWidth, imgHeight, rotation, pageNum);
    }


    /**
     * 将多张图片添加到PDF文件上,类似签名
     *
     * @param map      要写入的文本map集合
     * @param doc      PDF文件
     * @param imgMap   要添加的图片,输入流集合
     * @param rotation 带有签名文字的图片的旋转角度,逆时针旋转,如果不旋转则为0
     * @param pageNum  需要签名的页码数组,从1开始
     * @return 返回签好名的PDF文件字节码
     */
    public static byte[] signs(Map<String, String> map, InputStream doc, Map<String, String> imgMap, float rotation, int... pageNum) {
        if (pageNum == null || pageNum.length == 0) {
            return null;
        }
        return addImgsToDoc(map, doc, imgMap, rotation, pageNum);
    }


    /**
     * 根据url保存到指定路径
     *
     * @param url         url地址
     * @param saveAddress 文件新路径
     */
    public static void downloadFile(String url, String saveAddress) {
        try {
            URL fileUrl = new URL(url);
            InputStream is = fileUrl.openStream();
            OutputStream os = new FileOutputStream(saveAddress);
            byte bf[] = new byte[1024];
            int length = 0;
            while ((length = is.read(bf, 0, 1024)) != -1) {
                os.write(bf, 0, length);
            }
            is.close();
            os.close();
        } catch (Exception e) {
            log.error(e.toString());
        }
    }
}
  

枚举菜单PdfAxisEnum类代码:

@Getter
public enum PdfAxisEnum {

    /**
     * 姓名
     */
    NAME("name", 60, 625),

    /**
     * 时间
     */
    NOW_TIME("nowTime", 80, 562),

    /**
     * 签名图片
     */
    CHECK_IMG("checkImg", 425, 400),

    /**
     * 签名图片
     */
    EXAMINE_IMG("examineImg", 520, 400),

    /**
     * 印章图片
     */
    SEAL_IMG("sealImg", 460, 700),

    ;


    /**
     * 参数名
     */
    public String param;

    /**
     * x轴数值
     */
    public Integer xAxis;

    /**
     * y轴数值
     */
    public Integer yAxis;

    PdfAxisEnum(String param, Integer xAxis, Integer yAxis) {
        this.param = param;
        this.xAxis = xAxis;
        this.yAxis = yAxis;
    }

    public static PdfAxisEnum fetch(String param) {
        for (PdfAxisEnum value : PdfAxisEnum.values()) {
            if (value.param.equals(param)) {
                return value;
            }
        }
        return null;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值