杜洪波
2 天以前 c15fe6d34afc94c95a1c9f496649b405163337a2
java代码转PDF
已修改2个文件
153 ■■■■■ 文件已修改
pom.xml 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/product/file/util/PDFOperateUtil.java 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -84,7 +84,7 @@
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>2.0.6</version>
            <version>2.0.27</version>
        </dependency>
        <dependency>
            <groupId>com.aspose</groupId>
@@ -101,7 +101,5 @@
            <artifactId>aspose-words</artifactId>
            <version>21.11.1</version>
        </dependency>
    </dependencies>
</project>
src/main/java/com/product/file/util/PDFOperateUtil.java
@@ -4,12 +4,14 @@
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import javax.imageio.ImageIO;
import org.apache.fontbox.ttf.TrueTypeCollection;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
@@ -20,6 +22,132 @@
public class PDFOperateUtil {
    public static void createPdfWithCode(String javaFilePath, String outputPath) throws IOException {
        String javaCode = readJavaFileWithComments(javaFilePath);
        try (PDDocument document = new PDDocument()) {
            PDPage page = new PDPage(PDRectangle.A4);
            document.addPage(page);
            // 加载字体(如 SimSun)
            File fontFile = getSystemFontFile();
            if (!fontFile.exists()) {
                throw new IOException("未找到中文字体文件");
            }
            TrueTypeCollection ttc = new TrueTypeCollection(fontFile);
         // 通过字体名称获取(如 "SimSun")
            PDType0Font font = PDType0Font.load(document, ttc.getFontByName("SimSun"), true);
//            PDType0Font font = PDType0Font.load(document, fontFile);
            float fontSize = 10;
            float margin = 50;
            float leading = 1.2f * fontSize; // 行距
            // 可用宽度 = 页面宽度 - 左右边距
            PDRectangle mediaBox = page.getMediaBox();
            float availableWidth = mediaBox.getWidth() - 2 * margin;
            // 初始 Y 位置(从顶部开始)
            float yPosition = mediaBox.getHeight() - margin;
            float startX = margin;
            // 分割代码为行
            String[] lines = javaCode.split("\n");
            PDPageContentStream contentStream = null;
            try {
                contentStream = new PDPageContentStream(document, page);
                contentStream.setFont(font, fontSize);
                for (String line : lines) {
                    // 如果当前行超出页面底部,换页
                    if (yPosition < margin) {
                        contentStream.close();
                        page = new PDPage(PDRectangle.A4);
                        document.addPage(page);
                        yPosition = mediaBox.getHeight() - margin;
                        contentStream = new PDPageContentStream(document, page);
                        contentStream.setFont(font, fontSize);
                    }
                    // 处理超宽行:按字符拆分并换行
                    while (!line.isEmpty()) {
                        // 计算当前行能容纳的最大字符数
                        int maxChars = calculateMaxChars(font, fontSize, line, availableWidth);
                        String subLine = line.substring(0, Math.min(maxChars, line.length()));
                        line = line.substring(subLine.length());
                        // 写入当前子行
                        writeTextLine(contentStream, subLine, startX, yPosition);
                        yPosition -= leading;
                        // 如果剩余内容仍超出页面底部,换页
                        if (yPosition < margin && !line.isEmpty()) {
                            contentStream.close();
                            page = new PDPage(PDRectangle.A4);
                            document.addPage(page);
                            yPosition = mediaBox.getHeight() - margin;
                            contentStream = new PDPageContentStream(document, page);
                            contentStream.setFont(font, fontSize);
                        }
                    }
                }
            } finally {
                if (contentStream != null) {
                    contentStream.close();
                }
            }
            document.save(outputPath);
        }
    }
    // 计算一行能容纳的最大字符数
    private static int calculateMaxChars(PDType0Font font, float fontSize, String text, float availableWidth) throws IOException {
        float width = 0;
        int i = 0;
        for (; i < text.length(); i++) {
            width += font.getWidth(text.charAt(i)) / 1000 * fontSize;
            if (width > availableWidth) {
                break;
            }
        }
        return i;
    }
    // 写入单行文本(左对齐)
    private static void writeTextLine(PDPageContentStream contentStream, String text, float x, float y) throws IOException {
        contentStream.beginText();
        contentStream.newLineAtOffset(x, y);
        contentStream.showText(text);
        contentStream.endText();
    }
    /**
     * 读取 Java 文件内容(保留注释和空行)
     */
    private static String readJavaFileWithComments(String filePath) throws IOException {
        StringBuilder codeBuilder = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            String line;
            while ((line = reader.readLine()) != null) {
                line = line.replace("\t", "    ");
                // 保留所有行(包括注释和空行)
                codeBuilder.append(line).append("\n");
            }
        }
        return codeBuilder.toString();
    }
    /**
     * 计算字体高度(基于字体的 Ascent 和 Descent)
     */
    private static float calculateFontHeight(PDType0Font font, float fontSize) {
        float ascent = font.getFontDescriptor().getAscent();
        float descent = font.getFontDescriptor().getDescent();
        return (ascent - descent) / 1000 * fontSize;
    }
    /**
     * 根据文本文件创建 PDF(使用 PDFBox)
     * 
@@ -29,7 +157,7 @@
     */
    public static void createPdfFromTextFile(String textFilePath, String pdfFilePath) throws IOException {
        String content = readTextFile(textFilePath);
        content = content.replace("\t", "    ");
        try (PDDocument document = new PDDocument()) {
            PDPage page = new PDPage(PDRectangle.A4);
            document.addPage(page);
@@ -39,12 +167,16 @@
            if (!fontFile.exists()) {
                throw new IOException("未找到支持的中文字体文件(Windows/Linux)");
            }
            TrueTypeCollection ttc = new TrueTypeCollection(fontFile);
         // 通过字体名称获取(如 "SimSun")
            PDType0Font font = PDType0Font.load(document, ttc.getFontByName("SimSun"), true);
 
            // 加载字体
            PDType0Font font;
            try (FileInputStream fontStream = new FileInputStream(fontFile)) {
                font = PDType0Font.load(document, fontStream);
            }
//            PDType0Font font;
//            try (FileInputStream fontStream = new FileInputStream(fontFile)) {
//                font = PDType0Font.load(document, fontStream);
//            }
 
            // 写入 PDF 内容
            try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
@@ -132,6 +264,10 @@
        if (os.contains("win")) {
            // Windows 字体目录(优先检查常见中文字体)
            possiblePaths = new String[]{
//                System.getenv("WINDIR") + "\\Fonts\\arial.ttf",  //
//                System.getenv("WINDIR") + "\\Fonts\\simkai.ttf",  // 楷体
//                System.getenv("WINDIR") + "\\Fonts\\simfang.ttf",  // 宋体
                System.getenv("WINDIR") + "\\Fonts\\simsun.ttc",  // 宋体
                System.getenv("WINDIR") + "\\Fonts\\simhei.ttf",  // 黑体
                System.getenv("WINDIR") + "\\Fonts\\msyh.ttc",   // 微软雅黑
                System.getenv("WINDIR") + "\\Fonts\\mingliu.ttc"  // 明体(备用)
@@ -162,7 +298,8 @@
    public static void main(String[] args) {
        try {
            // 1. 从文本文件创建 PDF
            createPdfFromTextFile("E://新建1.txt", "E://新建1.pdf");
//            createPdfFromTextFile("E://新建1.txt", "E://新建1.pdf");
            createPdfWithCode("E:\\PROJECT\\Product\\后端\\product\\product-server\\product-server-file\\src\\main\\java\\com\\product\\file\\util\\FileUtil.java", "E://新建1.pdf");
            // 2. 读取 PDF 内容
            String content = readPdfContent("E://新建1.pdf");