首页 > 编程语言 >Java代码生成PDF2.0(包括文字图片)+PDF加水印+PDF转图片

Java代码生成PDF2.0(包括文字图片)+PDF加水印+PDF转图片

时间:2023-02-17 19:55:24浏览次数:49  
标签:代码生成 String map new jpg import PDF pdf 图片

1. 开源框架支持

iText,生成PDF文档,还支持将XML、Html文件转化为PDF文件;(简单但是得下载软件)
Apache PDFBox,生成、合并PDF文档;(类似于itext)
docx4j,生成docx、pptx、xlsx文档,支持转换为PDF格式。(需要一直转文件格式,麻烦,不过生成的PDF看不出生成的痕迹,非常标准)

注:由于个人喜好,这里还是用itext(之前用过而且简单)

2. 代码实现

工具类(包含将文件转为byte[]、生成PDF文档与PDF加水印方法)

点击查看代码
package com.example.springboot.common;

import com.example.springboot.domain.Company;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;

import org.springframework.stereotype.Component;


import java.io.*;
import java.util.ArrayList;
import java.util.Map;
import java.util.Objects;


import static com.itextpdf.commons.utils.FileUtil.deleteFile;



@Component
public class GeneratePDF {

    public static byte[] getBytes(String filePath){
        byte[] buffer = null;
        try {
            File file = new File(filePath);
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream(8192);
            byte[] b = new byte[8192];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            fis.close();
            bos.close();
            buffer = bos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return buffer;
    }

        public static String generetePdf(String temp,String storepath,Map<String,String> map,Map<String,byte[]> images) throws IOException, DocumentException {

            /*创建一个pdf读取对象*/
            PdfReader reader = new PdfReader(temp);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            /*创建pdf模板,参数reader  bos*/
            PdfStamper ps = new PdfStamper(reader, bos);
            /*定义字体*/
//            BaseFont baseFont = BaseFont.createFont("/usr/share/fonts/SIMSUN.TTC,1",BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            BaseFont baseFont = BaseFont.createFont("c://windows//fonts//simsun.ttc,1",BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            ArrayList<BaseFont> fontArrayList = new ArrayList<>();
            fontArrayList.add(baseFont);
            /*读取模板文本域并封装数据(注意名字应与文本域中的名字一致)*/
            AcroFields s = ps.getAcroFields();
            /*定义字体,若不定义,会使用模板中的文本域设置的字体*/
            s.setSubstitutionFonts(fontArrayList);
            for (String a:map.keySet()
                 ) {
                s.setField(a, map.get(a));
            }

            for (String b :images.keySet()
                 ) {
                /*插入图片*/
                int pageNo = s.getFieldPositions(b).get(0).page;
                Rectangle signRect = s.getFieldPositions(b).get(0).position;
                float x = signRect.getLeft();
                float y = signRect.getBottom();
                Image image = Image.getInstance(images.get(b));

                /*获取操作的页面*/
                PdfContentByte under = ps.getOverContent(pageNo);
                /*根据域的大小缩放图片*/
                image.scaleToFit(signRect.getWidth(), signRect.getHeight());
                /*添加图片*/
                image.setAbsolutePosition(x, y);
                under.addImage(image);
            }
            /*这里true表示pdf可编辑*/
            ps.setFormFlattening(false);
            /*关闭PdfStamper*/
            ps.close();
            FileOutputStream file=new FileOutputStream(storepath);
            file.write(bos.toByteArray());
            return storepath;


        }




        /**
         * pdf生成水印
         *
         * @param srcPdfPath       插入前的文件路径
         * @param tarPdfPath       插入后的文件路径
         * @param WaterMarkContent 水印文案
         * @param numberOfPage     每页需要插入的条数
         * @throws Exception
         */
        public static void addWaterMark(String srcPdfPath, String tarPdfPath, String WaterMarkContent, int numberOfPage) throws Exception {
            PdfReader reader = new PdfReader(srcPdfPath);
            PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(tarPdfPath));
            PdfGState gs = new PdfGState();
            System.out.println("adksjskalfklsdk");
            //设置字体
            BaseFont font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);

            // 设置透明度
            gs.setFillOpacity(0.4f);

            int total = reader.getNumberOfPages() + 1;
            PdfContentByte content;
            for (int i = 1; i < total; i++) {
                content = stamper.getOverContent(i);
                content.beginText();
                content.setGState(gs);
                //水印颜色
                content.setColorFill(BaseColor.DARK_GRAY);
                //水印字体样式和大小
                content.setFontAndSize(font, 35);
                //插入水印  循环每页插入的条数
                for (int j = 0; j < numberOfPage; j++) {
                    content.showTextAligned(Element.ALIGN_CENTER, WaterMarkContent, 150, 100 * (j + 1), 30);
                    content.showTextAligned(Element.ALIGN_CENTER, WaterMarkContent, 450, 100 * (j + 1), 30);
                    content.showTextAligned(Element.ALIGN_CENTER, WaterMarkContent, 750, 100 * (j + 1), 30);
                }
                content.endText();
            }
            stamper.close();
            reader.close();
            boolean b = deleteFile(new File(srcPdfPath));
            System.out.println("PDF水印添加完成!");
        }


}

实体类(放进PDF中的实体类)

点击查看代码
package com.example.springboot.domain;

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class Company {

    private String tyxydm;

    private String name;

    private String fr;

    private String zsbh;

    private String clrq;

    private String jglx;

    private String ywfwbg;

    private String yxqz;

    private byte[] ewm;

    private byte[] dzyz;



}

Controller类(生成PDF->加水印->PDF转图片返回图片地址)

点击查看代码
package com.example.springboot.controller;

import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.example.springboot.common.ReturnResult;
import com.example.springboot.domain.Company;
import com.example.springboot.domain.Person;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import static com.example.springboot.common.GeneratePDF.*;


@RestController
@Validated
@RequestMapping("/zscx")
public class FindlicenseController {

    @Value("E:/桌面/新建文件夹/")
    String storepath;




    @PostMapping("/zxing")
    public ReturnResult a(){
        QrConfig config = new QrConfig(300, 300);
// 设置边距,既二维码和背景之间的边距
//        config.setMargin(3);
// 设置前景色,既二维码颜色(青色)
//        config.setForeColor(Color.yellow.getRGB());
// 设置背景色(灰色)
//        config.setBackColor(Color.green.getRGB());
// 高纠错级别
        config.setErrorCorrection(ErrorCorrectionLevel.H);
//附带logo

// 生成二维码到文件,也可以到流
//        QrCodeUtil.generate("http://hutool.cn/", config, FileUtil.file("e:/qrcode.jpg"));
        return ReturnResult.buildSuccessResult(QrCodeUtil.generate("https://home.cnblogs.com/u/beijie/", config.setImg("E:/桌面/新建文件夹/QQ头像.jpg"),FileUtil.file("E:/桌面/新建文件夹/二维码.jpg")));
    }

    @PostMapping("/createCompanyPdf")
    public ReturnResult createCompanyPdf() throws Exception {
        /*读取图片地址*/
        Company company=Company.builder()
                .tyxydm("KKKKKKKKKKKKKKK0111")
                .name("辽宁省机动车鉴定评估机构")
                .fr("刘***")
                .zsbh("(2022)辽鉴评证字第2" +
                        "1010001号")
                .clrq("2019年09月20日")
                .jglx("综合类")
                .ywfwbg("机动车整车技术状况鉴定和价值评估、事故车辆损失鉴定评估、机动车停运损失评估、二手车认证、报废机动车总成技术状况鉴定和价值评估;机动车技术鉴定、车辆属性鉴定、事故车辆损伤关联性鉴定、事故车辆维修合理性鉴定、水淹事故车辆鉴定、机动车事故成因鉴定")
                .yxqz("2021年01月至2021年12月")
                .ewm(getBytes("E:/桌面/新建文件夹/二维码.jpg"))
                .dzyz(getBytes("E:/桌面/新建文件夹/小北工作室--电子印章.jpg"))
                .build();
        Map<String, String> map =new HashMap<>();
        map.put("tyxydm", company.getTyxydm());
        map.put("name", company.getName());
        map.put("fr", company.getFr());
        map.put("zsbh", company.getZsbh());
        map.put("clrq", company.getClrq());
        map.put("jglx", company.getJglx());
        map.put("ywfwbg", company.getYwfwbg());
        map.put("yxqz", company.getYxqz());
        Map<String,byte[]> images = new HashMap<>();
        images.put("ewm", company.getEwm());
        images.put("dzyz", company.getDzyz());
        String path = generetePdf("E:/桌面/新建文件夹/备案证书.pdf","E:/桌面/新建文件夹/temp/备案证书.pdf",map,images);
        System.out.println(path);
        String waterpath = "E:/桌面/新建文件夹/temp/备案证书(加水印).pdf";
        try {
            addWaterMark(path,waterpath,"小北工作室",10);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        File file = new File(waterpath);
        ArrayList<String> paths = new ArrayList<>();
        try {
            PDDocument doc = PDDocument.load(file);
            PDFRenderer renderer = new PDFRenderer(doc);
            int pageCount = doc.getNumberOfPages();
            // 循环pdf每个页码,1页pdf转成1张图片,多页pdf会转成多张图片
            for (int i = 0; i < pageCount; i++) {
                // dpi表示图片清晰度 dpi越大转换后越清晰,相对转换速度越慢
                BufferedImage image = renderer.renderImageWithDPI(i, 144);
                //亲测 图片格式支持:jpg,png,gif,bmp,jpeg
                ImageIO.write(image, "jpg", new File(storepath+"temp/company/"+i+".jpg"));//写入图片
                paths.add(storepath+"temp/company/"+i+".jpg");
//                ImgUtil.pressText(//
//                        FileUtil.file(storepath+"temp/"+i+".jpg"), //
//                        FileUtil.file(finalpath), //
//                        "小北工作室", Color.lightGray, //文字
//                        new Font("黑体", Font.BOLD, 100), //字体
//                        300, //x坐标修正值。 默认在中间,偏移量相对于中间偏移
//                        300 * (i + 1), //y坐标修正值。 默认在中间,偏移量相对于中间偏移
//                        0.4f//透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字
//                );
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ReturnResult.buildSuccessResult(paths);
    }


    @PostMapping("/createPersonPdf")
    public ReturnResult createPersonPdf() throws Exception {
        /*读取图片地址*/
        Person person=Person.builder()
                .gsmc("机动车鉴定评估")
                .jgmc("鉴定评估机构")
                .name("***")
                .sex("男")
                .djbh("21")
                .dwmc("辽宁***机动车鉴定评估有限公司")
                .djrq("2022年03月14日")
                .njxx("2022年1月-2022年12月")
                .szhyzz("辽宁省汽车流通协会")
                .dyrq("2022-01-12")
                .ewm(getBytes("E:/桌面/新建文件夹/二维码.jpg"))
                .cyry(getBytes("E:/桌面/新建文件夹/从业人员.jpg"))
                .build();
        Map<String, String> map =new HashMap<>();
        map.put("gsmc", person.getGsmc());
        map.put("jgmc", person.getJgmc());
        map.put("name", person.getName());
        map.put("sex", person.getSex());
        map.put("djbh", person.getDjbh());
        map.put("dwmc",person.getDwmc());
        map.put("djrq",person.getDjrq());
        map.put("njxx", person.getNjxx());
        map.put("szhyzz", person.getSzhyzz());
        map.put("dyrq", person.getDyrq());
        Map<String,byte[]> images = new HashMap<>();
        images.put("ewm", person.getEwm());
        images.put("cyry", person.getCyry());
        String path = generetePdf("E:/桌面/新建文件夹/备案卡从业人员.pdf","E:/桌面/新建文件夹/temp/备案卡从业人员.pdf",map,images);
        System.out.println(path);
        String waterpath = "E:/桌面/新建文件夹/temp/备案卡从业人员(加水印).pdf";
        try {
            addWaterMark(path,waterpath,"小北工作室",10);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        File file = new File(waterpath);
        ArrayList<String> paths = new ArrayList<>();
        try {
            PDDocument doc = PDDocument.load(file);
            PDFRenderer renderer = new PDFRenderer(doc);
            int pageCount = doc.getNumberOfPages();
            // 循环pdf每个页码,1页pdf转成1张图片,多页pdf会转成多张图片
            for (int i = 0; i < pageCount; i++) {
                // dpi表示图片清晰度 dpi越大转换后越清晰,相对转换速度越慢
                BufferedImage image = renderer.renderImageWithDPI(i, 144);
                //亲测 图片格式支持:jpg,png,gif,bmp,jpeg
                ImageIO.write(image, "jpg", new File(storepath+"temp/person/"+i+".jpg"));//写入图片
                paths.add(storepath+"temp/person/"+i+".jpg");
//                ImgUtil.pressText(//
//                        FileUtil.file(storepath+"temp/"+i+".jpg"), //
//                        FileUtil.file(finalpath), //
//                        "小北工作室", Color.lightGray, //文字
//                        new Font("黑体", Font.BOLD, 100), //字体
//                        300, //x坐标修正值。 默认在中间,偏移量相对于中间偏移
//                        300 * (i + 1), //y坐标修正值。 默认在中间,偏移量相对于中间偏移
//                        0.4f//透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字
//                );
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ReturnResult.buildSuccessResult(paths);
    }





    /**
     * 转换全部的pdf
     * pdf转图片
     */
    @GetMapping("/pdfToImg")
    public void pdfToImg(String path) {
        // 将pdf转图片 并且自定义图片得格式大小
        File file = new File(path);
        try {
            PDDocument doc = PDDocument.load(file);
            PDFRenderer renderer = new PDFRenderer(doc);
            int pageCount = doc.getNumberOfPages();
            // 循环pdf每个页码,1页pdf转成1张图片,多页pdf会转成多张图片
            for (int i = 1; i < pageCount; i++) {
                // dpi表示图片清晰度 dpi越大转换后越清晰,相对转换速度越慢
                BufferedImage image = renderer.renderImageWithDPI(i, 144);
                //亲测 图片格式支持:jpg,png,gif,bmp,jpeg
                ImageIO.write(image, "png", new File("E:/桌面/新建文件夹/"+i+".png"));//写入图片
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }






}

参考文档:(主要参考,让人醍醐灌顶)https://blog.csdn.net/a_lllk/article/details/109450972

(辅助参考,对pdf操作介绍比较全面)https://wanghj.blog.csdn.net/article/details/127495462

(辅助参考,itext表单域传值介绍比较全面)https://blog.csdn.net/qq_42130324/article/details/122937657

3. 加水印

方式一 PDF加水印(在工具类里已经包含)

点击查看代码
/**
         * pdf生成水印
         *
         * @param srcPdfPath       插入前的文件路径
         * @param tarPdfPath       插入后的文件路径
         * @param WaterMarkContent 水印文案
         * @param numberOfPage     每页需要插入的条数
         * @throws Exception
         */
        public static void addWaterMark(String srcPdfPath, String tarPdfPath, String WaterMarkContent, int numberOfPage) throws Exception {
            PdfReader reader = new PdfReader(srcPdfPath);
            PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(tarPdfPath));
            PdfGState gs = new PdfGState();
            System.out.println("adksjskalfklsdk");
            //设置字体
            BaseFont font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);

            // 设置透明度
            gs.setFillOpacity(0.4f);

            int total = reader.getNumberOfPages() + 1;
            PdfContentByte content;
            for (int i = 1; i < total; i++) {
                content = stamper.getOverContent(i);
                content.beginText();
                content.setGState(gs);
                //水印颜色
                content.setColorFill(BaseColor.DARK_GRAY);
                //水印字体样式和大小
                content.setFontAndSize(font, 35);
                //插入水印  循环每页插入的条数
                for (int j = 0; j < numberOfPage; j++) {
                    content.showTextAligned(Element.ALIGN_CENTER, WaterMarkContent, 150, 100 * (j + 1), 30);
                    content.showTextAligned(Element.ALIGN_CENTER, WaterMarkContent, 450, 100 * (j + 1), 30);
                    content.showTextAligned(Element.ALIGN_CENTER, WaterMarkContent, 750, 100 * (j + 1), 30);
                }
                content.endText();
            }
            stamper.close();
            reader.close();
            boolean b = deleteFile(new File(srcPdfPath));
            System.out.println("PDF水印添加完成!");
        }

方式二 图片加水印

                ImgUtil.pressText(//
                        FileUtil.file(storepath+"temp/"+i+".jpg"), //
                        FileUtil.file(finalpath), //
                        "小北工作室", Color.lightGray, //文字
                        new Font("黑体", Font.BOLD, 100), //字体
                        300, //x坐标修正值。 默认在中间,偏移量相对于中间偏移
                        300 * (i + 1), //y坐标修正值。 默认在中间,偏移量相对于中间偏移
                        0.4f//透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字
                );

这里用的hutool的图片工具类,链接在这:http://hutool.cn/docs/index.html#/core/图片/图片工具-ImgUtil

PDF转图片

点击查看代码
{
	File file = new File(waterpath);
        ArrayList<String> paths = new ArrayList<>();
        try {
            PDDocument doc = PDDocument.load(file);
            PDFRenderer renderer = new PDFRenderer(doc);
            int pageCount = doc.getNumberOfPages();
            // 循环pdf每个页码,1页pdf转成1张图片,多页pdf会转成多张图片
            for (int i = 0; i < pageCount; i++) {
                // dpi表示图片清晰度 dpi越大转换后越清晰,相对转换速度越慢
                BufferedImage image = renderer.renderImageWithDPI(i, 144);
                //亲测 图片格式支持:jpg,png,gif,bmp,jpeg
                ImageIO.write(image, "jpg", new File(storepath+"temp/company/"+i+".jpg"));//写入图片
                paths.add(storepath+"temp/company/"+i+".jpg");
//                ImgUtil.pressText(//
//                        FileUtil.file(storepath+"temp/"+i+".jpg"), //
//                        FileUtil.file(finalpath), //
//                        "小北工作室", Color.lightGray, //文字
//                        new Font("黑体", Font.BOLD, 100), //字体
//                        300, //x坐标修正值。 默认在中间,偏移量相对于中间偏移
//                        300 * (i + 1), //y坐标修正值。 默认在中间,偏移量相对于中间偏移
//                        0.4f//透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字
//                );
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ReturnResult.buildSuccessResult(paths);
    }

代码不全,因为是直接在controller里用的,若有需要可以看生成PDF的controller或者参考文档:https://blog.csdn.net/suya2011/article/details/121368330

Maven项目可以用spire,我是特别想用的,因为这个对PDF操作更全,但是这个全是Maven导包,自己在Maven仓库找到依赖还不能用,所以你可以试试,建议Java使用Free Spire.PDF for Java
官网在这:https://www.e-iceblue.cn/Introduce/Free-Spire-PDF-JAVA.html
image

标签:代码生成,String,map,new,jpg,import,PDF,pdf,图片
From: https://www.cnblogs.com/beijie/p/17131385.html

相关文章