Java pdf工具

一、依赖

<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.13</version>
</dependency>
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext-asian</artifactId>
    <version>5.2.0</version>
</dependency>
<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>2.0.24</version>
</dependency>

二、枚举

  1. 内容显示方式
public enum CellAlign {
    LEFT(0),
    CENTER(1),
    RIGHT(2),
    TOP(4),
    MIDDLE(5),
    BOTTOM(6);

    private Integer align;

    private CellAlign(Integer align) {
        this.align = align;
    }

    public Integer getAlign() {
        return this.align;
    }
}

  1. 数据类型
public enum DataType {
    TEXT,
    IMAGE;
}

  1. 文字样式
public enum TextAttr {
    TEXTFONT,
    TEXTCOLOR,
    TEXTSIZE,
    BGCOLOR,
    BORDERCOLOR,;
}

三、异常

public class PdfException extends Exception {
    private static final long serialVersionUID = 1L;

    public PdfException(String message) {
        super(message);
    }

    public PdfException(Throwable cause) {
        super(cause);
    }

    public PdfException(String message, Throwable cause) {
        super(message, cause);
    }
}

四、相关配置类

方式一:

使用 Adobe Acrobat DC 制作 pdf 模版,根据制作 pdf 模板生成 pdf 使用到的类

  1. 模版配置

import org.springframework.core.io.ClassPathResource;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

public class PdfTemplate {
    /**
     * pdf 名称
     */
    private String title;
    /**
     * pdf 模板
     */
    private InputStream template;
    /**
     * 需要填入 pdf 文件中的数据
     */
    private Map<String, PdfData> values;

    /**
     * 用于获取 pdf 文件中某些字段的位置信息
     */
    private Map<String, Position> positions;

    public PdfTemplate() {
    }

    public PdfTemplate(String title, InputStream template) {
        this.title = title;
        this.template = template;
    }

    public PdfTemplate(String title, String templatePath) {
        this.title = title;
        try {
            this.template  = new ClassPathResource(templatePath).getInputStream();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    public PdfTemplate addValue(String key,PdfData value){
        if(this.values == null){
            this.values = new HashMap<>();
        }
        this.values.put(key,value);
        return this;
    }
    public PdfTemplate addPositions(String key,Position value){
        if(this.positions == null){
            this.positions = new HashMap<>();
        }
        this.positions.put(key,value);
        return this;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public InputStream getTemplate() {
        return template;
    }

    public void setTemplate(InputStream template) {
        this.template = template;
    }

    public Map<String, PdfData> getValues() {
        return values;
    }

    public void setValues(Map<String, PdfData> values) {
        this.values = values;
    }


    public Map<String, Position> getPositions() {
        return positions;
    }

    public void setPositions(Map<String, Position> positions) {
        this.positions = positions;
    }
}

  1. 数据信息类
import com.itextpdf.text.Image;
import com.kuroshiro.pdf.enums.DataType;
import com.kuroshiro.pdf.enums.TextAttr;

import java.util.HashMap;
import java.util.Map;

public class PdfData {

    private DataType type = DataType.TEXT;

    /**
     * pdf 对应 key 需要填入的值
     */
    private String value;

    /**
     * pdf 对应 key 需要填入的值
     */
    private Image image;

    /**
     * 设置字体样式。有效的属性名称是:
     * textfont - 设置文本字体。该条目的值是一个 BaseFont。
     * textcolor - 设置文本颜色。该条目的值是一个 BaseColor。
     * textsize - 设置文本大小。该表项的值为 Float 类型。
     * bgcolor - 设置背景颜色。该条目的值是一个 BaseColor。如果为null则删除背景。
     * bordercolor - 设置边框颜色。该条目的值是一个 BaseColor。如果为null则删除边框。
     */
    private Map<TextAttr, Object> textStyles;


    public PdfData(String value) {
        this.value = value;
    }
    public PdfData(Image image) {
        this.type = DataType.IMAGE;
        this.image = image;
    }

    public PdfData addTextStyle(TextAttr key,Object value){
        if(this.textStyles == null){
            this.textStyles = new HashMap<>();
        }
        this.textStyles.put(key,value);
        return this;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public DataType getType() {
        return type;
    }

    public void setType(DataType type) {
        this.type = type;
    }

    public Image getImage() {
        return image;
    }

    public void setImage(Image image) {
        this.image = image;
    }

    public Map<TextAttr, Object> getTextStyles() {
        return textStyles;
    }

    public void setTextStyles(Map<TextAttr, Object> textStyles) {
        this.textStyles = textStyles;
    }
}

  1. 位置信息类
import java.math.BigDecimal;
import java.util.Objects;

public class Position {
    private BigDecimal page;
    private BigDecimal positionX;
    private BigDecimal positionY;


    public Position() {
    }

    public Position(BigDecimal page, BigDecimal positionX, BigDecimal positionY) {
        this.page = page;
        this.positionX = positionX;
        this.positionY = positionY;
    }

    public Position(int page, int positionX, int positionY) {
        this.page = BigDecimal.valueOf((long)page);
        this.positionX = BigDecimal.valueOf((long)positionX);
        this.positionY = BigDecimal.valueOf((long)positionY);
    }

    public boolean equals(Object o) {
        if (this == o) {
            return true;
        } else if (o != null && this.getClass() == o.getClass()) {
            Position postion = (Position)o;
            return Objects.equals(this.page.intValue(), postion.page.intValue()) && Objects.equals(this.positionX.intValue(), postion.positionX.intValue()) && Objects.equals(this.positionY.intValue(), postion.positionY.intValue());
        } else {
            return false;
        }
    }

    public int hashCode() {
        return Objects.hash(new Object[]{this.page, this.positionX, this.positionY});
    }




    public BigDecimal getPage() {
        return page;
    }

    public void setPage(BigDecimal page) {
        this.page = page;
    }

    public BigDecimal getPositionX() {
        return positionX;
    }

    public void setPositionX(BigDecimal positionX) {
        this.positionX = positionX;
    }

    public BigDecimal getPositionY() {
        return positionY;
    }

    public void setPositionY(BigDecimal positionY) {
        this.positionY = positionY;
    }
}



方式二:

创建简单的 table 形式的 pdf

  1. Table 配置

import java.util.ArrayList;
import java.util.List;

public class PdfTable {
    /**
     * 标题
     */
    private String title;
    /**
     * 标题字体大小
     */
    private Float fontSize = 21.0F;
    /**
     * table 列数
     */
    private int columns = 1;
    /**
     * table cell 信息
     */
    private List<PdfTableCell> cells;
    /**
     * 标题是否需要边框
     */
    private boolean haveBorder = false;

    /**
     * 列宽比例
     */
    private float[] columnWidths;

    public PdfTable(String title) {
        this.title = title;
    }
    public PdfTable(String title, boolean haveBorder) {
        this.title = title;
        this.haveBorder = haveBorder;
    }


    public PdfTable(String title,int columns) {
        this.title = title;
        this.columns = columns<1?1:columns;
    }

    public PdfTable(String title,int columns, boolean haveBorder) {
        this.title = title;
        this.columns = columns<1?1:columns;
        this.haveBorder = haveBorder;
    }

    public PdfTable(String title, Float fontSize, int columns) {
        this.title = title;
        this.fontSize = fontSize;
        this.columns = columns<1?1:columns;
    }


    public PdfTable(String title, Float fontSize, int columns, boolean haveBorder) {
        this.title = title;
        this.fontSize = fontSize;
        this.columns = columns<1?1:columns;
        this.haveBorder = haveBorder;
    }

    public PdfTable addCell(PdfTableCell cell){
        if(cells == null){
            cells = new ArrayList(){{
                add(cell);
            }};
        }else{
            cells.add(cell);
        }

        return this;
    }
    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Float getFontSize() {
        return fontSize;
    }

    public void setFontSize(Float fontSize) {
        this.fontSize = fontSize;
    }

    public int getColumns() {
        return columns;
    }

    public void setColumns(int columns) {
        this.columns = columns;
    }

    public List<PdfTableCell> getCells() {
        return cells;
    }

    public void setCells(List<PdfTableCell> cells) {
        this.cells = cells;
    }

    public boolean isHaveBorder() {
        return haveBorder;
    }

    public void setHaveBorder(boolean haveBorder) {
        this.haveBorder = haveBorder;
    }

    public float[] getColumnWidths() {
        return columnWidths;
    }

    public void setColumnWidths(float[] columnWidths) {
        this.columnWidths = columnWidths;
    }
}
  1. Cell 配置

import com.itextpdf.text.Image;
import com.kuroshiro.pdf.enums.CellAlign;
import com.kuroshiro.pdf.enums.DataType;

public class PdfTableCell {
    private DataType type;
    private Image image;
    private String info;
    private Float fontSize = 16.0F;
    private CellAlign horizontalAlign = CellAlign.CENTER;
    private CellAlign verticalAlign = CellAlign.MIDDLE;
    private int colspan = 1;
    private boolean haveBorder = true;


    public PdfTableCell(String info) {
        this.type = DataType.TEXT;
        this.info = info;
    }
    public PdfTableCell(String info,Float fontSize) {
        this.type = DataType.TEXT;;
        this.info = info;
        this.fontSize = fontSize;
    }
    public PdfTableCell(String info,int colspan) {
        this.type = DataType.TEXT;
        this.info = info;
        this.colspan = colspan<1?1:colspan;
    }
    public PdfTableCell(String info,int colspan,Float fontSize) {
        this.type = DataType.TEXT;;
        this.info = info;
        this.fontSize = fontSize;
        this.colspan = colspan<1?1:colspan;
    }


    public PdfTableCell(String info,int colspan,boolean haveBorder,Float fontSize, CellAlign horizontalAlign, CellAlign verticalAlign) {
        this.type = DataType.TEXT;;
        this.info = info;
        this.fontSize = fontSize==null?16F:fontSize;
        this.horizontalAlign = horizontalAlign==null?CellAlign.CENTER:horizontalAlign;
        this.verticalAlign = verticalAlign==null?CellAlign.MIDDLE:verticalAlign;
        this.colspan = colspan<1?1:colspan;
        this.haveBorder = haveBorder;
    }

    public PdfTableCell(Image image) {
        this.type = DataType.IMAGE;
        this.image = image;
    }

    public PdfTableCell(Image image,int colspan) {
        this.type = DataType.IMAGE;
        this.image = image;
        this.colspan = colspan<1?1:colspan;
    }
    public PdfTableCell(Image image,int colspan,boolean haveBorder) {
        this.type = DataType.IMAGE;
        this.image = image;
        this.colspan = colspan<1?1:colspan;
        this.haveBorder = haveBorder;
    }




    public Float getFontSize() {
        return fontSize;
    }

    public void setFontSize(Float fontSize) {
        this.fontSize = fontSize;
    }

    public DataType getType() {
        return type;
    }

    public void setType(DataType type) {
        this.type = type;
    }

    public Image getImage() {
        return image;
    }

    public void setImage(Image image) {
        this.image = image;
    }

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }

    public CellAlign getHorizontalAlign() {
        return horizontalAlign;
    }

    public void setHorizontalAlign(CellAlign horizontalAlign) {
        this.horizontalAlign = horizontalAlign;
    }

    public CellAlign getVerticalAlign() {
        return verticalAlign;
    }

    public void setVerticalAlign(CellAlign verticalAlign) {
        this.verticalAlign = verticalAlign;
    }


    public int getColspan() {
        return colspan;
    }

    public void setColspan(int colspan) {
        this.colspan = colspan;
    }

    public boolean isHaveBorder() {
        return haveBorder;
    }

    public void setHaveBorder(boolean haveBorder) {
        this.haveBorder = haveBorder;
    }
}

五、工具类


import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.kuroshiro.pdf.enums.DataType;
import com.kuroshiro.pdf.enums.TextAttr;
import com.kuroshiro.pdf.exception.PdfException;
import com.kuroshiro.pdf.model.*;
import com.kuroshiro.pdf.model.PdfTemplate;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.stream.MemoryCacheImageOutputStream;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;


/**
 * pdf 生成工具
 */
public class PDFUtils {
    private static Charset charset;

    public PDFUtils() {
    }

    /**
     * 计算某个数据在某个位置范围内显示的位置信息
     *
     * 一个位置需要显示多个数据时计算每个数据的位置
     *
     * @param positionx 位置范围的 x 坐标
     * @param positiony 位置范围的 y 坐标
     * @param index 需要计算的数据下标
     * @param width 每个数据占用的宽度
     * @param height 每个数据占用的高度
     * @param lineCount 该位置一行能够显示的数据个数
     * @return
     */
    public static Position calcPosition(BigDecimal positionx, BigDecimal positiony, int index, BigDecimal width, BigDecimal height, int lineCount) {
        int j = 0;
        if (index != 0 && index % lineCount == 0) {
            ++j;
        }

        Position postionresult = new Position();
        int px = index % lineCount;
        postionresult.setPositionX(positionx.add((new BigDecimal(px)).multiply(width)));
        postionresult.setPositionY(positiony.add((new BigDecimal(j)).multiply(height)));
        return postionresult;
    }


    /**
     * 根据pdf模版创建pdf
     * @param pdfTemplate
     * @return
     * @throws PdfException
     */
    public static byte[] createPdfByTemplate(PdfTemplate pdfTemplate) throws PdfException {
        ByteArrayOutputStream os = new ByteArrayOutputStream();

        byte[] res;
        try {
            BaseFont simsun_font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            PdfReader reader = new PdfReader(pdfTemplate.getTemplate());
            PdfStamper stamper = new PdfStamper(reader, os);
            AcroFields form = stamper.getAcroFields();
            
            if(pdfTemplate.getValues() != null && !pdfTemplate.getValues().isEmpty()){
                for(String valueKey:pdfTemplate.getValues().keySet()){
                    int type = form.getFieldType(valueKey);
                    /**
                     * FIELD_TYPE_NONE	0	无效字段或字段不存在
                     * FIELD_TYPE_PUSHBUTTON	1	按钮(PushButton)
                     * FIELD_TYPE_CHECKBOX	2	复选框(Checkbox)
                     * FIELD_TYPE_RADIOBUTTON	3	单选按钮(RadioButton)
                     * FIELD_TYPE_TEXT	4	文本框(Text Field)
                     * FIELD_TYPE_LIST	5	下拉列表(List Field)
                     * FIELD_TYPE_COMBO	6	组合框(Combo Box)
                     * FIELD_TYPE_SIGNATURE	7	数字签名(Signature Field)
                     */
                    if (type != AcroFields.FIELD_TYPE_NONE) {
                        PdfData pdfData = pdfTemplate.getValues().get(valueKey);
                        if(DataType.IMAGE.equals(pdfData.getType())){
                            int pageNo = form.getFieldPositions(valueKey).get(0).page;
                            Rectangle signRect = form.getFieldPositions(valueKey).get(0).position;
                            float x = signRect.getLeft();
                            float y = signRect.getBottom();
                            //读取图片
                            Image image = pdfData.getImage();
                            //获取图片页面
                            PdfContentByte under = stamper.getOverContent(pageNo);
                            //图片大小自适应
                            image.scaleToFit(signRect.getWidth(), signRect.getHeight());
                            //添加图片
                            image.setAbsolutePosition(x, y);
                            under.addImage(image);

                            continue;
                        }

                        switch (type) {
                            case AcroFields.FIELD_TYPE_CHECKBOX:

                                /**
                                 * 设置字段属性只读
                                 * inst[] 当表单字段由多个控件(如跨页的单选框)组成时,指定操作哪个实例。
                                 * 常见用法:
                                 *      null:操作所有实例。
                                 *      new int[]{0}:操作第一个实例(索引从 0 开始)。
                                 */
                                form.setFieldProperty(valueKey, "setfflags", PdfFormField.FF_READ_ONLY, null);
                                form.setField(valueKey, pdfData.getValue().toString());
                                break;
                            case AcroFields.FIELD_TYPE_TEXT:
                                form.setFieldProperty(valueKey, "textfont", simsun_font, null);
                                if (pdfData.getTextStyles() != null && !pdfData.getTextStyles().isEmpty()) {
                                    for(TextAttr attrKey : pdfData.getTextStyles().keySet()) {
                                        /**
                                         * 设置字段属性。有效的属性名称是:
                                         * textfont - 设置文本字体。该条目的值是一个BaseFont。
                                         * textcolor - 设置文本颜色。该条目的值是一个BaseColor。
                                         * textsize - 设置文本大小。该表项的值为Float类型。
                                         * bgcolor - 设置背景颜色。该条目的值是一个BaseColor。如果为null则删除背景。
                                         * bordercolor - 设置边框颜色。该条目的值是一个BaseColor。如果为null则删除边框。
                                         */
                                        form.setFieldProperty(valueKey, attrKey.name(), pdfData.getTextStyles().get(attrKey), null);
                                    }
                                }

                                form.setField(valueKey, pdfData.getValue().toString());
                                break;
                            case AcroFields.FIELD_TYPE_SIGNATURE:
                                AcroFields.Item item = form.getFieldItem(valueKey);
                                // 获取该字段的第一个控件(PdfDictionary),表单字段可能有多个控件(如多页表单)
                                PdfDictionary widget = item.getWidget(0);
                                // 提取控件的坐标范围(PdfArray),格式为 [左下角X, 左下角Y, 右上角X, 右上角Y]
                                PdfArray array = widget.getAsArray(PdfName.RECT);
                                Image image = Image.getInstance(Base64.getDecoder().decode(pdfData.getValue()));
                                // 获取字段所在页面的 “最上层画布”(PdfContentByte),用于覆盖内容(不会破坏原有表单字段)
                                PdfContentByte under = stamper.getOverContent(item.getPage(0));
                                image.setAbsolutePosition((float)(new BigDecimal(array.getAsNumber(0).toString())).intValue(), (float)(new BigDecimal(array.getAsNumber(1).toString())).intValue());
                                under.addImage(image);
                        }
                    }
                }
                
            }

            

            if (pdfTemplate.getPositions() != null && !pdfTemplate.getPositions().isEmpty()) {
                for(String key : pdfTemplate.getPositions().keySet()) {
                    if(form.getFieldType(key) != AcroFields.FIELD_TYPE_NONE){
                        AcroFields.Item item = form.getFieldItem(key);
                        PdfDictionary widget = item.getWidget(0);
                        PdfArray array = widget.getAsArray(PdfName.RECT);
                        (pdfTemplate.getPositions().get(key)).setPage(new BigDecimal(item.getPage(0)));
                        (pdfTemplate.getPositions().get(key)).setPositionX(new BigDecimal(array.getAsNumber(0).toString()));
                        (pdfTemplate.getPositions().get(key)).setPositionY(new BigDecimal(array.getAsNumber(1).toString()));
                    }
                }
            }
            

            stamper.setFormFlattening(true);
            stamper.close();
            res = os.toByteArray();
        } catch (Exception e) {
            throw new PdfException("根据pdf模板生成pdf异常", e);
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

        return res;
    }



    /**
     * 根据pdf模版创建pdf
     * @param pdfTemplate
     * @return
     * @throws PdfException
     */
    public static void createPdfByTemplate(PdfTemplate pdfTemplate, OutputStream out) throws PdfException {
        Document doc = new Document();
        try {
            PdfReader reader = new PdfReader(createPdfByTemplate(pdfTemplate));
            PdfCopy copy =  new PdfCopy(doc, out);
            doc.open();
            int page = reader.getNumberOfPages();

            for(int j = 1; j <= page; ++j) {
                doc.newPage();
                PdfImportedPage copypage = copy.getImportedPage(reader, j);
                copy.addPage(copypage);
            }

            doc.close();
        } catch (DocumentException e) {
            throw new PdfException("根据pdf模板生成pdf异常",e);
        } catch (IOException e) {
            throw new PdfException("根据pdf模板生成pdf异常",e);
        }finally {
            if (doc != null) {
                try {
                    doc.close();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }

        }

    }


    /**
     * 根据模版批量生成 pdf 到一个文件中
     * @param pdfTemplates 每个 pdf 相关的配置
     * @return 文件字节数组
     * @throws PdfException
     */
    public static byte[] createPdfByTemplates(List<PdfTemplate> pdfTemplates) throws PdfException{
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            List<PdfReader> list = new ArrayList<>();
            for (PdfTemplate pdfTemplate:pdfTemplates) {
                list.add(new PdfReader(createPdfByTemplate(pdfTemplate)));
            }

            // 将ByteArray字节数组中的流输出到out中(即输出到浏览器)
            Document doc = new Document();
            PdfCopy copy = new PdfCopy(doc, os);
            doc.open();

            for (PdfReader reader:list) {
                int page = reader.getNumberOfPages();
                for(int j = 1; j <= page; ++j) {
                    doc.newPage();
                    PdfImportedPage copypage = copy.getImportedPage(reader, j);
                    copy.addPage(copypage);
                }
            }
            doc.close();

            return os.toByteArray();
        }catch (Exception e){
            throw new PdfException("根据pdf模板生成pdf异常",e);
        }finally {
            if (os != null) {
                try {
                    os.flush();
                    os.close();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }

        }
    }


    /**
     * 根据模版批量生成 pdf 到一个文件中
     * @param pdfTemplates 每个 pdf 相关的配置
     * @param out 文件输出位置
     */
    public static void createPdfByTemplates(List<PdfTemplate> pdfTemplates,OutputStream out){
        try {
            List<PdfReader> list = new ArrayList<>();
            for (PdfTemplate pdfTemplate:pdfTemplates) {
                list.add(new PdfReader(createPdfByTemplate(pdfTemplate)));
            }

            // 将ByteArray字节数组中的流输出到out中(即输出到浏览器)
            Document doc = new Document();
            PdfCopy copy = new PdfCopy(doc, out);
            doc.open();

            for (PdfReader reader:list) {
                int page = reader.getNumberOfPages();
                for(int j = 1; j <= page; ++j) {
                    doc.newPage();
                    PdfImportedPage copypage = copy.getImportedPage(reader, j);
                    copy.addPage(copypage);
                }
            }
            doc.close();

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                if (out != null) {
                    out.flush();
                    out.close();
                }

            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }



    /**
     * 创建pdf
     * @param pdf
     * @param target
     * @throws PdfException
     */
    public static void createSimpleTablePDF(PdfTable pdf, OutputStream target) throws PdfException {
        try {
            Document document = new Document(PageSize.A4, 50.0F, 50.0F, 50.0F, 50.0F);
            PdfWriter writer = PdfWriter.getInstance(document, target);
            document.open();
            BaseFont simsun_font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            Font titleFont = new Font(simsun_font, pdf.getFontSize());
            PdfPTable table = new PdfPTable(pdf.getColumns());
            if(pdf.getColumnWidths() != null){
                table.setWidths(pdf.getColumnWidths());
            }
            table.setWidthPercentage(100.0F);
            String title = pdf.getTitle();
            PdfPCell titlecell = new PdfPCell();
            titlecell.setColspan(pdf.getColumns());
            titlecell.setFixedHeight(50);
            if(!pdf.isHaveBorder()){
                titlecell.setBorder(0);
            }
            // titlecell.setBorderWidth(2.0F);
            // 水平居中
            titlecell.setHorizontalAlignment(Element.ALIGN_CENTER);
            // 垂直居中
            titlecell.setVerticalAlignment(Element.ALIGN_MIDDLE);
            titlecell.setPhrase(new Paragraph(title, titleFont));
            table.addCell(titlecell);

            for(int i = 0; pdf.getCells() != null && i < pdf.getCells().size(); ++i) {
                PdfTableCell pdfTableCell = pdf.getCells().get(i);
                PdfPCell cell = new PdfPCell();
                if(!pdfTableCell.isHaveBorder()){
                    cell.setBorder(0);
                }
                cell.setColspan(pdfTableCell.getColspan());
                // cell.setBorderWidthTop(i == 0 ? 0.0F : 1.0F);
                // cell.setBorderWidthBottom(i == pdf.getCells().size() - 1 ? 2.0F : 1.0F);
                // cell.setBorderWidthLeft(2.0F);
                // cell.setBorderWidthRight(2.0F);
                if (pdfTableCell.getType().equals(DataType.IMAGE)) {
                    cell.addElement((pdf.getCells().get(i)).getImage());
                } else if (pdfTableCell.getType().equals(DataType.TEXT)) {
                    cell.setHorizontalAlignment(pdfTableCell.getHorizontalAlign().getAlign());
                    cell.setVerticalAlignment(pdfTableCell.getVerticalAlign().getAlign());
                    cell.setPhrase(new Paragraph(pdfTableCell.getInfo(), new Font(simsun_font,pdfTableCell.getFontSize())));
                }

                table.addCell(cell);
            }

            document.add(table);
            document.close();
            writer.close();
        } catch (Exception e) {
            throw new PdfException("pdf创建失败", e);
        }
    }

    /**
     * pdf合成
     * @param pdfs
     * @param target
     * @throws PdfException
     */
    public static void mergePdf(List<? extends InputStream> pdfs, OutputStream target) throws PdfException {
        try {
            Document targetdocument = new Document();
            PdfCopy copy = new PdfCopy(targetdocument, target);
            targetdocument.open();

            for(int i = 0; i < pdfs.size(); ++i) {
                PdfReader reader = new PdfReader(pdfs.get(i));
                int page = reader.getNumberOfPages();

                for(int j = 1; j <= page; ++j) {
                    targetdocument.newPage();
                    PdfImportedPage copypage = copy.getImportedPage(reader, j);
                    copy.addPage(copypage);
                }
            }

            targetdocument.close();
        } catch (Exception e) {
            throw new PdfException("pdf合成异常", e);
        }
    }

    /**
     * pdf 转图片
     * @param pdf
     * @return
     * @throws PdfException
     */
    public static List<ByteArrayOutputStream> pdfImage(InputStream pdf) throws PdfException {
        PDDocument document = null;

        List<ByteArrayOutputStream> res;
        try {
            document = PDDocument.load(pdf);
            // PDFont font = PDType0Font.load(document, PDFUtils.class.getResourceAsStream("/static/fonts/STSong-Light.ttf"), true);
            PDFRenderer renderer = new PDFRenderer(document);
            List<ByteArrayOutputStream> oses = new ArrayList();

            for(int i = 0; i < document.getNumberOfPages(); ++i) {
                // PDPage page = document.getPage(i);
                // PDResources resources = page.getResources();
                // String name = resources.add(font).getName();
                // page.setResources(resources);
                BufferedImage image = renderer.renderImageWithDPI(i, 120.0F, ImageType.RGB);
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                ImageOutputStream ios = new MemoryCacheImageOutputStream(bos);
                ImageWriter jpg_writer =  ImageIO.getImageWritersByFormatName("jpg").next();
                ImageWriteParam jpg_write_param = jpg_writer.getDefaultWriteParam();
                jpg_write_param.setCompressionMode(2);
                jpg_write_param.setCompressionQuality(0.7F);
                jpg_writer.setOutput(ios);
                IIOImage output_image = new IIOImage(image, null, null);
                jpg_writer.write(null, output_image, jpg_write_param);
                jpg_writer.dispose();
                bos.flush();
                oses.add(bos);
                ios.close();
            }

            res = oses;
        } catch (Exception e) {
            throw new PdfException("pdf转换异常", e);
        } finally {
            if (document != null) {
                try {
                    document.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

        return res;
    }

    public static void setCharset(Charset charset) {
        PDFUtils.charset = charset;
    }

    static {
        charset = StandardCharsets.UTF_8;
    }
}

六、测试

public class PdfTest {

    public static void main(String[] args) throws Exception {
        pdfTemplate();
        pdfTable();
    }



    public static void pdfTemplate() throws Exception {
        List<PdfTemplate> list = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            PdfTemplate pdfTemplate = new PdfTemplate("测试","/pdfs/xxk.pdf");
            pdfTemplate.addValue("cyjgmc",new PdfData("从业机构"+i))
                    .addValue("jgmc",new PdfData("从业机构1111"+i))
                    .addValue("name",new PdfData("张三"+i))
                    .addValue("xxklx",(new PdfData("经纪人")).addTextStyle(TextAttr.TEXTCOLOR, BaseColor.RED))
                    .addValue("xxkh",new PdfData("18313226955"))
                    .addValue("xxkyxq",new PdfData("2026-12-18 止+i"))
                    .addValue("zjz",new PdfData(Image.getInstance("E:\\zjz.jpg")))
                    .addValue("xxkyxq",new PdfData("2026-12-18 止+i"));


            String content = "http://sys.yn-yf.cn/fdcjj/wx/ryxx/12345";
            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            Resource resource = new cn.hutool.core.io.resource.ClassPathResource("/static/img/15620371964200.png");
            QRCodeUtil.encode(content,resource.getUrl().getPath(),outStream,true);
            pdfTemplate.addValue("qrcode", new PdfData(Image.getInstance(outStream.toByteArray())));

            list.add(pdfTemplate);
        }

        PDFUtils.createPdfByTemplates(list,new FileOutputStream("E:\\xxk1.pdf"));
    }


    public static void pdfTable() throws Exception {
        PdfTable pdfTable = new PdfTable("员工信息表",4);
        pdfTable.setColumnWidths(new float[]{1.0f,2.0f,1.0f,2.0f});

        // 添加文本单元格
        pdfTable.addCell(new PdfTableCell( "姓名"))
                .addCell(new PdfTableCell( "测试测试2222"))
                .addCell(new PdfTableCell( "电话"))
                .addCell(new PdfTableCell( "15912153741"))
                .addCell(new PdfTableCell( "地址"))
                .addCell(new PdfTableCell( "15912153741",3))
                .addCell(new PdfTableCell(Image.getInstance("E:\\zjz.jpg"),3))
                .addCell(new PdfTableCell( ""))
                .addCell(new PdfTableCell("郑重申明:谨此保证,本表所填报内容及所附证明材料真实、完整",4,false,11.0F, CellAlign.RIGHT,CellAlign.MIDDLE));

        // 生成 PDF 到文件
        try (OutputStream os = new FileOutputStream("E:\\xxk2.pdf")) {
            PDFUtils.createSimpleTablePDF(pdfTable, os);
        }
    }
}

结果
在这里插入图片描述

在这里插入图片描述

Java PDF工具类是一个Java语言开发的库,用于在Java应用程序中处理PDF文件。这个库提供了丰富的API,可以实现创建、读取、修改和转换PDF文件。它是一个非常强大的工具,广泛用于企业级应用程序和互联网应用程序。 Java PDF工具类的主要功能包括: 1.创建PDF文件 Java PDF工具类提供了一个创建PDF文件的API,可以通过代码生成PDF文件。这个API非常强大,可以实现任何类型的PDF文件,包括高级的PDF文件,比如包含表单和多媒体元素的PDF文件。 2.读取PDF文件 Java PDF工具类提供了API,可以读取已有的PDF文件。这个API可以获取PDF文件中的所有数据,并将其转换为Java对象。这个API非常有用,可以用于将PDF文件转换为HTML文件或其他格式的文件。 3.修改PDF文件 Java PDF工具类提供了API,可以修改已有的PDF文件。这个API非常灵活,可以修改PDF文件的任何部分,包括文本、图像、文本框、表格、页面格式等等。 4.转换PDF文件 Java PDF工具类还提供了转换PDF文件的API,可以将PDF文件转换为其他格式的文件,比如HTML、XML、DOC、TXT、图像等等。这个API非常有用,可以将PDF文件作为数据源,输出到其他应用程序中。 Java PDF工具类是一个非常成功的工具,非常适合企业级应用程序和互联网应用程序。它不仅可以处理PDF文件,还可以处理其他类型的文件,比如图像、音频、视频等等。无论你需要创建、读取、修改或转换PDF文件,Java PDF工具类都可以满足你的需要。它是一个高质量、高性能、易于使用的工具,值得尝试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值