【Java生成指定背景图片的PDF文件】

发布于:2025-06-18 ⋅ 阅读:(18) ⋅ 点赞:(0)

Java生成指定背景图片的PDF文件

package org.jeecg.dts.common.util;

import lombok.Data;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.jeecg.common.util.ZosUtil;
import org.jeecg.dts.common.constant.BussinessEnum;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

public class ProductCertificateGenerator {

    /**
     * 生成产品登记证书并上传图片到存储系统
     * @param productInfo 产品信息
     * @param fontPath 字体文件路径
     * @param backgroundImagePath 背景图片路径
     * @return 上传后的图片URL
     * @throws Exception 处理过程中可能出现的异常
     */
    public static String generateCertificateAndUpload(ProductInfo productInfo, 
                                                   String fontPath, 
                                                   String backgroundImagePath) throws Exception {
        // 临时文件路径
        String tempDir = System.getProperty("java.io.tmpdir");
        String pdfPath = tempDir + File.separator + "product_cert_" + System.currentTimeMillis() + ".pdf";
        String imagePath = tempDir + File.separator + "product_cert_" + System.currentTimeMillis() + ".png";

        try {
            // 1. 生成PDF证书
            generateCertificate(pdfPath, backgroundImagePath, fontPath, productInfo);

            // 2. 将PDF转换为图片
            pdfToImage(pdfPath, imagePath);

            // 3. 上传图片到存储
            File imageFile = new File(imagePath);
            return uploadToStorage(imageFile);
        } finally {
            // 清理临时文件
            new File(pdfPath).delete();
            new File(imagePath).delete();
        }
    }

    /**
     * 生成产品登记证书PDF
     */
    private static void generateCertificate(String outputPath,
                                          String backgroundImagePath,
                                          String fontPath,
                                          ProductInfo productInfo) throws Exception {
        try (PDDocument document = new PDDocument()) {
            PDPage page = new PDPage(PDRectangle.A4);
            document.addPage(page);

            // 加载字体
            PDType0Font font = PDType0Font.load(document, new File(fontPath));

            // 加载背景图片
            PDImageXObject background = PDImageXObject.createFromFile(backgroundImagePath, document);

            try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
                // 1. 添加背景图片
                contentStream.drawImage(background, 0, 0,
                        page.getMediaBox().getWidth(),
                        page.getMediaBox().getHeight());

                // 2. 添加产品信息(标题和名称居中)
                addCenteredProductInfo(contentStream, page, productInfo, font);

                // 3. 添加其他产品信息
                addProductDetails(contentStream, page, productInfo, font);

                // 4. 添加底部信息
                addFooterInfo(contentStream, page, productInfo, font);
            }

            document.save(outputPath);
        }
    }

    /**
     * 添加居中显示的标题和产品名称
     */
    private static void addCenteredProductInfo(PDPageContentStream contentStream,
                                             PDPage page,
                                             ProductInfo productInfo,
                                             PDType0Font font) throws IOException {
        float pageWidth = page.getMediaBox().getWidth();
        float centerX = pageWidth / 2;

        // 垂直起始位置(距顶部250px)
        float startY = page.getMediaBox().getHeight() - 250;

        // 1. 添加标题(36号字,居中)
        String title = productInfo.getTitle();
        float titleWidth = calculateTextWidth(font, title, 36);
        contentStream.beginText();
        contentStream.setFont(font, 36);
        contentStream.newLineAtOffset(centerX - titleWidth/2, startY);
        contentStream.showText(title);
        contentStream.endText();

        // 2. 添加产品名称(28号字,居中,距标题60px)
        String name = productInfo.getName();
        float nameWidth = calculateTextWidth(font, name, 28);
        contentStream.beginText();
        contentStream.setFont(font, 28);
        contentStream.newLineAtOffset(centerX - nameWidth/2, startY - 60);
        contentStream.showText(name);
        contentStream.endText();
    }

    /**
     * 添加产品详细信息
     */
    private static void addProductDetails(PDPageContentStream contentStream,
                                        PDPage page,
                                        ProductInfo productInfo,
                                        PDType0Font font) throws IOException {
        float startY = page.getMediaBox().getHeight() - 400; // 从标题下移150px开始
        float lineHeight = 40;

        // 左侧对齐,距左边150px
        addFormattedLine(contentStream, "登记编号:", productInfo.getCode(), 150, startY, font, 20);
        addFormattedLine(contentStream, "登记日期:", productInfo.getCreateDate(), 150, startY - lineHeight, font, 20);
        addFormattedLine(contentStream, "登记机构:", productInfo.getOrgName(), 150, startY - lineHeight * 2, font, 20);
        addFormattedLine(contentStream, "数据产品持有者:", productInfo.getSupplierName(), 150, startY - lineHeight * 3, font, 20);
        addFormattedLine(contentStream, "统一社会信用代码:", productInfo.getShxydm(), 150, startY - lineHeight * 4, font, 20);
    }

    /**
     * 添加底部信息(右侧对齐)
     */
    private static void addFooterInfo(PDPageContentStream contentStream,
                                    PDPage page,
                                    ProductInfo productInfo,
                                    PDType0Font font) throws IOException {
        float pageWidth = page.getMediaBox().getWidth();
        float rightMargin = 100; // 右侧边距100px

        // 1. 大写登记日期(底部右侧,距底部120px)
        String createDateUpper = productInfo.getCreateDateUppercase();
        float dateUpperWidth = calculateTextWidth(font, createDateUpper, 22);
        contentStream.beginText();
        contentStream.setFont(font, 22);
        contentStream.newLineAtOffset(pageWidth - dateUpperWidth - rightMargin, 120);
        contentStream.showText(createDateUpper);
        contentStream.endText();

        // 2. 登记日期(底部右侧,距大写日期上方30px)
        String createDate = productInfo.getCreateDate();
        float dateWidth = calculateTextWidth(font, createDate, 22);
        contentStream.beginText();
        contentStream.setFont(font, 22);
        contentStream.newLineAtOffset(pageWidth - dateWidth - rightMargin, 150);
        contentStream.showText(createDate);
        contentStream.endText();
    }

    /**
     * 添加格式化文本行(标签+值)
     */
    private static void addFormattedLine(PDPageContentStream contentStream,
                                       String label,
                                       String value,
                                       float x,
                                       float y,
                                       PDType0Font font,
                                       int fontSize) throws IOException {
        // 添加标签
        contentStream.beginText();
        contentStream.setFont(font, fontSize);
        contentStream.newLineAtOffset(x, y);
        contentStream.showText(label);
        contentStream.endText();

        // 添加值
        float labelWidth = calculateTextWidth(font, label, fontSize);
        contentStream.beginText();
        contentStream.setFont(font, fontSize);
        contentStream.newLineAtOffset(x + labelWidth, y);
        contentStream.showText(value);
        contentStream.endText();
    }

    /**
     * 将PDF转换为图片
     */
    private static void pdfToImage(String pdfPath, String imagePath) throws IOException {
        try (PDDocument document = PDDocument.load(new File(pdfPath))) {
            PDFRenderer renderer = new PDFRenderer(document);
            // 高质量渲染,300 DPI,RGB格式
            BufferedImage image = renderer.renderImageWithDPI(0, 300, ImageType.RGB);
            ImageIO.write(image, "PNG", new File(imagePath));
        }
    }

    /**
     * 上传图片到存储系统
     */
    private static String uploadToStorage(File imageFile) throws IOException {
        try (InputStream is = new FileInputStream(imageFile)) {
            Map<String, Object> result = ZosUtil.streamUpload(
                    is,
                    BussinessEnum.CERT.name(),
                    imageFile.getName(),
                    null
            );
            return result.get("fileUrl").toString();
        }
    }

    /**
     * 精确计算文本显示宽度
     */
    private static float calculateTextWidth(PDType0Font font, String text, float fontSize) throws IOException {
        return font.getStringWidth(text) / 1000 * fontSize;
    }

    /**
     * 产品信息实体类
     */
    @Data
    public static class ProductInfo {
        private String title;                  // 证书标题
        private String name;                   // 产品名称
        private String code;                   // 登记编号
        private String createDate;             // 登记日期
        private String createDateUppercase;    // 大写登记日期
        private String orgName;                // 登记机构
        private String supplierName;           // 数据产品持有者
        private String shxydm;                 // 统一社会信用代码
    }

    /**
     * 测试方法
     */
    public static void main(String[] args) {
        try {
            // 产品信息
            ProductInfo productInfo = new ProductInfo();
            productInfo.setTitle("数据产品登记凭证");
            productInfo.setName("燃气输送SCADA监测数据");
            productInfo.setCode("2025320100SJA0308");
            productInfo.setCreateDate("2025年05月16日");
            productInfo.setCreateDateUppercase("二〇二五年五月十六日");
            productInfo.setOrgName("南京市公共资源交易中心");
            productInfo.setSupplierName("江苏东能天然气管网有限公司");
            productInfo.setShxydm("91320623067634411F");

            // 文件路径配置
            String fontPath = "C:/Windows/Fonts/simhei.ttf"; // 黑体字体路径
            String backgroundPath = "C:/path/to/certificate_bg.png"; // 背景图片路径

            // 生成并上传证书
            String imageUrl = generateCertificateAndUpload(productInfo, fontPath, backgroundPath);
            System.out.println("证书图片生成成功,URL: " + imageUrl);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

网站公告

今日签到

点亮在社区的每一天
去签到