02——Java使用低版本poi 3.8 + itext 2.1.7 + itextasian.1.5.2 实现word转PDF——解决段落样式问题 + 图片问题 + 单个表格问题
1. 前言
1.1 关于docx转PDF解决汉字展示问题
- 本文是上篇文章的延续,关于上篇文章解决汉字不展示及字体部分样式的问题,如下:
Java使用低版本poi 3.8 + itext 2.1.7 + itextasian.1.5.2 实现word转PDF——01(解决汉字问题及字体的样式问题).
2. docx转PDF(第4版——解决图片问题)
2.1 依赖保持不变
- 如下(关于
itextasian 1.5.2
依赖的下载看上篇文章):<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.8</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-scratchpad</artifactId> <version>3.8</version> </dependency> <!-- <dependency>--> <!-- <groupId>fr.opensagres.xdocreport</groupId>--> <!-- <artifactId>org.apache.poi.xwpf.converter.pdf</artifactId>--> <!-- <version>1.0.6</version>--> <!-- </dependency>--> <dependency> <groupId>com.lowagie</groupId> <artifactId>itext</artifactId> <version>2.1.7</version> </dependency> <!--解决word转PDF后中文不显示问题--> <dependency> <groupId>com.lowagie</groupId> <artifactId>itextasian</artifactId> <version>1.5.2</version> </dependency>
2.2 核心代码
- 如下:
2.3 观看效果
- 如下:
2.4 完整实现代码
- 如下:
package com.liu.susu.word2pdf.example4; import com.liu.susu.word2pdf.example3.RgbUtils; import com.lowagie.text.Document; import com.lowagie.text.Font; import com.lowagie.text.*; import com.lowagie.text.Image; import com.lowagie.text.pdf.BaseFont; import com.lowagie.text.pdf.PdfWriter; import org.apache.poi.xwpf.usermodel.*; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.*; import java.util.List; /** * @Description 第4版:解决 word转PDF 的图片问题 * @Author susu * @Date 2024/3/28 */ public class Word2Pdf_Test4 { public static void main(String[] args) throws DocumentException, IOException { String wordFilePath = "/Users/susu/file_test/about_word/test_word_to_pdf_1/test_word_in_3.docx"; String pdfFilePath = "/Users/susu/file_test/about_word/test_word_to_pdf_1/test_word_out_0328_3.pdf"; word2pdf(wordFilePath, pdfFilePath); } public static void word2pdf(String wordPath, String pdfPath) throws IOException, DocumentException { XWPFDocument xwpfDocument = new XWPFDocument(new FileInputStream(wordPath)); Document pdfDocument = new Document(); PdfWriter.getInstance(pdfDocument, new FileOutputStream(pdfPath)); pdfDocument.open(); for (XWPFParagraph paragraph : xwpfDocument.getParagraphs()) { List<XWPFRun> runs = paragraph.getRuns(); Paragraph paragraph2 = new Paragraph(); for (int i = 0; i < runs.size(); i++) { XWPFRun run = runs.get(i); String text = run.getText(run.getTextPosition()); // 1. 解决图片问题 List<XWPFPicture> pictures = run.getEmbeddedPictures(); for (XWPFPicture picture : pictures) { XWPFPictureData pictureData = picture.getPictureData(); byte[] imageBytes = pictureData.getData(); // 使用 ImageIO 读取图片,获取图片宽高 InputStream inputStream = new ByteArrayInputStream(imageBytes); BufferedImage bufferedImage = ImageIO.read(inputStream); int width = bufferedImage.getWidth(); int height = bufferedImage.getHeight(); System.out.println(width + "--->" +height); // Image image = Image.getInstance(bufferedImage,null); Image image = Image.getInstance(imageBytes); image.scaleAbsolute(width/3,height/3); // 调整图片宽高(如果不调整,图片的宽高是原始图片的大小而不是word图片里调整后的大小) paragraph2.add(image); } // 2. 字体样式等问题解决 // 2.1. 字体大小 int fontSize = run.getFontSize(); // 2.2. 字体颜色 int[] rgbNum = RgbUtils.getRgbNum(run.getColor()); Color color = new Color(rgbNum[0], rgbNum[1], rgbNum[2]); // 2.3. 字体样式 String fontStyle = ""; if (run.isBold()) { fontStyle += "bold"; } else if (run.isItalic()) { fontStyle += "italic"; } else if (run.getUnderline().getValue() == 1) { fontStyle += "underline"; } BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); Font font = new Font(baseFont, fontSize, Font.NORMAL, color); font.setStyle(fontStyle); // 字体样式 if (text != null) { Chunk chObj1 = new Chunk(text, font); paragraph2.add(chObj1); } } pdfDocument.add(paragraph2); } pdfDocument.close(); } }
2.5 存在的问题
- 由上面效果可看到,word转PDF的代码实现的效果依然不是很完善,1是表格问题,2是段落样式问题!请继续……
3. docx转PDF(第5版——解决表格问题)
3.1 实现代码
- 如下:
package com.liu.susu.word2pdf.example5; import com.liu.susu.word2pdf.example3.RgbUtils; import com.lowagie.text.Document; import com.lowagie.text.Font; import com.lowagie.text.Image; import com.lowagie.text.*; import com.lowagie.text.pdf.BaseFont; import com.lowagie.text.pdf.PdfPCell; import com.lowagie.text.pdf.PdfPTable; import com.lowagie.text.pdf.PdfWriter; import org.apache.commons.lang3.StringUtils; import org.apache.poi.xwpf.usermodel.*; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.*; import java.util.List; /** * @Description 第5版:解决 word转PDF 的表格问题 * @Author susu * @Date 2024/3/28 */ public class Word2Pdf_Test5 { public static void main(String[] args) throws DocumentException, IOException { String wordFilePath = "/Users/susu/file_test/about_word/test_word_to_pdf_1/test_word_in_3.docx"; String pdfFilePath = "/Users/susu/file_test/about_word/test_word_to_pdf_1/test_word_out_0328_5.pdf"; word2pdf(wordFilePath, pdfFilePath); } public static void word2pdf(String wordPath, String pdfPath) throws IOException, DocumentException { XWPFDocument xwpfDocument = new XWPFDocument(new FileInputStream(wordPath)); Document pdfDocument = new Document(); PdfWriter.getInstance(pdfDocument, new FileOutputStream(pdfPath)); pdfDocument.open(); List<XWPFTable> tables = xwpfDocument.getTables(); // word里的所有表格 for (XWPFParagraph paragraph : xwpfDocument.getParagraphs()) { // System.out.println(paragraph.getText()); List<XWPFRun> runs = paragraph.getRuns(); Paragraph paragraph2 = new Paragraph(); if (runs != null && runs.size() > 0) { for (int i = 0; i < runs.size(); i++) { XWPFRun run = runs.get(i); String text = run.getText(run.getTextPosition()); List<XWPFPicture> pictures = run.getEmbeddedPictures(); if (StringUtils.isNoneBlank(text)) { // 1. 处理字体——字体样式等问题解决 // 1.1. 字体大小 int fontSize = run.getFontSize(); // 1.2. 字体颜色 int[] rgbNum = RgbUtils.getRgbNum(run.getColor()); Color color = new Color(rgbNum[0], rgbNum[1], rgbNum[2]); // 1.3. 字体样式 String fontStyle = ""; if (run.isBold()) { fontStyle += "bold"; } else if (run.isItalic()) { fontStyle += "italic"; } else if (run.getUnderline().getValue() == 1) { fontStyle += "underline"; } BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); Font font = new Font(baseFont, fontSize, Font.NORMAL, color); font.setStyle(fontStyle); // 字体样式 Chunk chObj1 = new Chunk(text, font); paragraph2.add(chObj1); } else if (pictures != null && pictures.size() > 0) { // 1. 解决图片问题 for (XWPFPicture picture : pictures) { XWPFPictureData pictureData = picture.getPictureData(); byte[] imageBytes = pictureData.getData(); // 使用 ImageIO 读取图片,获取图片宽高 InputStream inputStream = new ByteArrayInputStream(imageBytes); BufferedImage bufferedImage = ImageIO.read(inputStream); int width = bufferedImage.getWidth(); int height = bufferedImage.getHeight(); System.out.println(width + "--->" + height); // Image image = Image.getInstance(bufferedImage,null); Image image = Image.getInstance(imageBytes); image.scaleAbsolute(width / 3, height / 3); // 调整图片宽高(如果不调整,图片的宽高是原始图片的大小而不是word图片里调整后的大小) paragraph2.add(image); } } } }else { // 3. 解决表格问题 /** * 存在的问题 * (1)word文档里不能有空段落,否则空段落也进来 * (2)文档里有多个表格的话不适用,不能定位表格在哪个段落里 */ for (XWPFTable table : tables) { PdfPTable pdfTable = new PdfPTable(table.getNumberOfRows()); // 遍历表格中的每一行 for (XWPFTableRow row : table.getRows()) { // 遍历行中的每个单元格 for (XWPFTableCell cell : row.getTableCells()) { // 获取单元格中的文本内容 String cellText = cell.getText(); BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); Font font = new Font(baseFont, 10, Font.NORMAL, Color.BLACK); Chunk chObj1 = new Chunk(cellText, font); // pdfTable.addCell(new PdfPCell(new Phrase(cell.getText()))); pdfTable.addCell(new PdfPCell(new Phrase(chObj1))); } } paragraph2.add(pdfTable); } } pdfDocument.add(paragraph2); } pdfDocument.close(); } }
3.2 效果
- 如下:
3.3 存在的问题
- 代码逻辑很简单,如果word里有空行,不支持(影响表格的判断);
- 文档里有多个表格的话,目前代码不支持使用,因为没有定位表格的具体位置(具体段落定位不了)。
- 关于段落样式问题,请继续……
4. docx转PDF(第6版——解决段落样式问题)
4.1 解决的问题
- 本版主要解决:word转PDF 中的段落样式问题(对齐、段落间距、行间距、首行缩进、段落中字体背景颜色)。
4.2 观看效果
- 如下:
4.3 核心代码
- 如下:
4.4 遇到的问题
- 问题描述:
CTHighlight
类不存在,如下:找不到org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHighlight的类
- 分析问题:
poi提供的那个ooxml-schemas-x.x.jar
(这里指的是ooxml-schemas-3.8.jar
)包是精简版的,为了节省空间,里面放的只有一些常用的模块,所以要引用另外一些功能的话就需要引用完全版的ooxml-schemas.jar
(这里对应的是ooxml-schemas-1.1.jar
)包 - 解决问题,引入 ooxml-schemas-1.1.jar 依赖即可,如下:
<!-- https://mvnrepository.com/artifact/org.apache.poi/ooxml-schemas --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>ooxml-schemas</artifactId> <version>1.1</version> </dependency>
4.5 完整代码
- 如下:
package com.liu.susu.word2pdf.example6; import com.liu.susu.word2pdf.example3.RgbUtils; import com.lowagie.text.Document; import com.lowagie.text.Font; import com.lowagie.text.Image; import com.lowagie.text.*; import com.lowagie.text.pdf.BaseFont; import com.lowagie.text.pdf.PdfPCell; import com.lowagie.text.pdf.PdfPTable; import com.lowagie.text.pdf.PdfWriter; import org.apache.commons.lang3.StringUtils; import org.apache.poi.xwpf.usermodel.*; import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; import javax.imageio.ImageIO; import javax.swing.text.html.StyleSheet; import java.awt.*; import java.awt.image.BufferedImage; import java.io.*; import java.util.List; import static javax.swing.text.StyleConstants.LineSpacing; /** * @Description 第6版:解决 word转PDF 中的段落样式问题(对齐、段落间距、行间距、首行缩进、段落中字体背景颜色) * @Author susu * @Date 2024/3/28 */ public class Word2Pdf_Test6 { public static void main(String[] args) throws DocumentException, IOException { String wordFilePath = "/Users/susu/file_test/about_word/test_word_to_pdf_1/test_word_in_3.docx"; String pdfFilePath = "/Users/susu/file_test/about_word/test_word_to_pdf_1/test_word_out_0328_6.pdf"; word2pdf(wordFilePath, pdfFilePath); } public static void word2pdf(String wordPath, String pdfPath) throws IOException, DocumentException { XWPFDocument xwpfDocument = new XWPFDocument(new FileInputStream(wordPath)); Document pdfDocument = new Document(); PdfWriter.getInstance(pdfDocument, new FileOutputStream(pdfPath)); pdfDocument.open(); List<XWPFTable> tables = xwpfDocument.getTables(); // word里的所有表格 for (XWPFParagraph paragraph : xwpfDocument.getParagraphs()) { List<XWPFRun> runs = paragraph.getRuns(); Paragraph paragraph2 = new Paragraph(); // 1. 解决段落样式问题(对齐、段落间距、行间距、首行缩进) // 1.1 对齐 ParagraphAlignment alignment = paragraph.getAlignment(); paragraph2.setAlignment(alignment.name()); // 1.2 段落之间的间距 paragraph2.setSpacingAfter(paragraph.getSpacingAfter() * 0.05f); // 1.3 段落中的行间距 CTSpacing ctSpacing = paragraph.getCTP().getPPr().getSpacing(); if (ctSpacing.getLine() != null){ paragraph2.setLeading(ctSpacing.getLine().intValue() * 0.06f); } // 1.4 首行缩进 paragraph2.setFirstLineIndent(paragraph.getIndentationFirstLine() * 0.05f); if (runs != null && runs.size() > 0) { for (int i = 0; i < runs.size(); i++) { XWPFRun run = runs.get(i); String text = run.getText(run.getTextPosition()); List<XWPFPicture> pictures = run.getEmbeddedPictures(); if (StringUtils.isNoneBlank(text)) { // 2. 处理字体——字体样式等问题解决 // 2.1. 字体大小 int fontSize = run.getFontSize(); // 2.2. 字体颜色 int[] rgbNum = RgbUtils.getRgbNum(run.getColor()); Color color = new Color(rgbNum[0], rgbNum[1], rgbNum[2]); // 2.3. 字体样式 String fontStyle = ""; if (run.isBold()) { fontStyle += "bold"; } else if (run.isItalic()) { fontStyle += "italic"; } else if (run.getUnderline().getValue() == 1) { fontStyle += "underline"; } BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); Font font = new Font(baseFont, fontSize, Font.NORMAL, color); font.setStyle(fontStyle); // 字体样式 // 2.4 获取word文档里的字体背景颜色 StyleSheet style = new StyleSheet(); CTRPr rPr = run.getCTR().getRPr(); CTHighlight highlight = rPr.getHighlight(); String backgroundColorName = highlight.getVal().toString(); Color backgroundColor = style.stringToColor(backgroundColorName); Chunk chObj1 = new Chunk(text, font); if (backgroundColor != null) { // 设置字体背景颜色 chObj1.setBackground(backgroundColor); } paragraph2.add(chObj1); } else if (pictures != null && pictures.size() > 0) { // 3. 解决图片问题 for (XWPFPicture picture : pictures) { XWPFPictureData pictureData = picture.getPictureData(); byte[] imageBytes = pictureData.getData(); // 使用 ImageIO 读取图片,获取图片宽高 InputStream inputStream = new ByteArrayInputStream(imageBytes); BufferedImage bufferedImage = ImageIO.read(inputStream); int width = bufferedImage.getWidth(); int height = bufferedImage.getHeight(); System.out.println(width + "--->" + height); // Image image = Image.getInstance(bufferedImage,null); Image image = Image.getInstance(imageBytes); image.scaleAbsolute(width / 3, height / 3); // 调整图片宽高(如果不调整,图片的宽高是原始图片的大小而不是word图片里调整后的大小) paragraph2.add(image); } } } }else { // 4. 解决表格问题 /** * 存在的问题 * (1)word文档里不能有空段落,否则空段落也进来 * (2)文档里有多个表格的话不适用,不能定位表格在哪个段落里 */ for (XWPFTable table : tables) { PdfPTable pdfTable = new PdfPTable(table.getNumberOfRows()); // 遍历表格中的每一行 for (XWPFTableRow row : table.getRows()) { // 遍历行中的每个单元格 for (XWPFTableCell cell : row.getTableCells()) { // 获取单元格中的文本内容 String cellText = cell.getText(); BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); Font font = new Font(baseFont, 10, Font.NORMAL, Color.BLACK); Chunk chObj1 = new Chunk(cellText, font); // pdfTable.addCell(new PdfPCell(new Phrase(cell.getText()))); pdfTable.addCell(new PdfPCell(new Phrase(chObj1))); } } paragraph2.add(pdfTable); } } pdfDocument.add(paragraph2); } pdfDocument.close(); } }
4.6 遗留的问题
- 就是上面的表格相关问题(多表格等问题)!
5. 终版——关于表格问题的解决
- 如果不介意表格问题或者word文档里没有表格,上面代码可凑合使用,只是凑合!
- 如果要求有点高的,关于表格问题,请移步到下面的文章,请继续……:
03终版——Java使用低版本poi 3.8 + itext 2.1.7 + itextasian.1.5.2 实现word转PDF——解决word转PDF遇到的表格问题. - 关于项目代码的下载,也请移步上篇文章!