基本需求就是像已经有的pdf:pdf满足这样的条件,图片每页都是完整的即不可能出现一个图片在两页的问题,同时表格可能存在在两页的问题,当时真的出现也就正常覆盖就可以!
有这样的需求,在每页的底部1-3 厘米的地方 存在批量添加文字部分
距离底部的位置和添加的内容都是 txt文件,进行对应的读取就可以。
下一步:任务:前端整合 thymeleaf,部署服务器,结合 elementui vue 部署服务器
完整代码一:pdfbox无法解决中文乱码的问题:
公用的两个方法:
package com.special.weixin.pdf;
import lombok.experimental.Accessors;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
/**
* @author liuYC
* @ClassName ReadTxt
* @Description TODO
* @date 2021/8/24 12:44
*/
public class ReadTxt {
private static final String contentTxtPath = "D:\\fin_tech\\project-demo\\pdf-box-itext\\content.txt";
private static final String numTxtPath = "D:\\fin_tech\\project-demo\\pdf-box-itext\\num.txt";
/**
* readByBuffer 读取 txt 文件内容
*/
public static void readByBuffer(String filePath) {
BufferedReader reader;
try {
reader = new BufferedReader(new FileReader(
filePath));
String line = reader.readLine();
while (line != null) {
System.out.println(line);
// read next line
line = reader.readLine();
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* YL.txt
* readByFile
* // if (line.equals("") || line == null) {
* // continue;
* // }
* <p>
* List nullList = new ArrayList();
* nullList.add(null);
* nullList.add(" ");
* nullList.add("");
* allLines.removeAll(nullList);
* // 去掉空行,当时实现有问题。
* public static <T> List<T> removeNull(List<? extends T> oldList) {
* <p>
* // 你没有看错,真的是有 1 行代码就实现了
* oldList.removeAll(Collections.singleton(null));
* return (List<T>) oldList;
* }
*/
public static List<String> readByFile(String filePath) {
// 编码需要进行处理:
List<String> allLines = new ArrayList<>();
Charset charset = Charset.forName("GBK");
// 为什么会报红呢?
// Charset charset = Charset.forName("Identity-H");
try {
allLines = Files.readAllLines(Paths.get(filePath), charset
);
List nullList = new ArrayList();
nullList.add(null);
nullList.add(" ");
nullList.add("");
allLines.removeAll(nullList);
for (String line : allLines) {
System.out.println(line);
}
System.out.println(allLines.size());
System.out.println(allLines.size());
} catch (IOException e) {
e.printStackTrace();
}
return allLines;
}
public static void main(String[] args) {
ReadTxt.readByFile(contentTxtPath);
System.out.println("=============================");
ReadTxt.readByFile(numTxtPath);
}
}
pdf-box实现,相关参考链接都已经给出:
mvn:
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.23</version>
</dependency>
代码:
package com.special.weixin.pdf;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDPageTree;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
/**
* @author liuYC
* @ClassName AddPdfContent
* @Description TODO
* @date 2021/8/24 11:17
*/
public class AddPdfContent {
/**
* pdf add text in location special text
* LIUYUHCAO
* 将文本添加到现有PDF文档
* 您可以使用PDFBox库向文档添加内容,这为您提供了一个名为PDPageContentStream的类,其中包含在PDFDocument的页面中插入文本,图像和其他类型内容所需的方法。
* <p>
* 以下是创建空文档并向其中的页面添加内容的步骤。
* <p>
* 第1步:加载现有文档
* 您可以使用PDDocument类的load()方法加载现有文档。 因此,实例化此类并加载所需的文档,如下所示。
* <p>
* File file = new File("Path of the document");
* PDDocument doc = document.load(file);
* 1
* 2
* 3
* 第2步:获取所需页面
* 您可以使用getPage()方法在文档中获取所需的页面。 通过将索引传递给此方法来检索所需页面的对象,如下所示。
* <p>
* PDPage page = doc.getPage(1);
* 1
* 2
* 第3步:准备内容流
* 您可以使用类PDPageContentStream的对象插入各种数据元素。 您需要将文档对象和页面对象传递给此类的构造函数,因此,通过传递在前面步骤中创建的这两个对象来实例化此类,如下所示。
* <p>
* PDPageContentStream contentStream = new PDPageContentStream(doc, page);
* 1
* 2
* 第4步:开始文本
* 在PDF文档中插入文本时,可以使用PDPageContentStream类的beginText()和endText()方法指定文本的起点和终点,如下所示。
* <p>
* contentStream.beginText();
* ………………………..
* code to add text content
* ………………………..
* contentStream.endText();
* 1
* 2
* 3
* 4
* 5
* 6
* 因此,使用beginText()方法开始文本,如下所示。
* <p>
* contentStream.beginText();
* 1
* 2
* 第5步:设置文本的位置
* 使用newLineAtOffset()方法,您可以在页面中的内容流上设置位置。
* <p>
* //Setting the position for the line
* contentStream.newLineAtOffset(25, 700);
* 1
* 2
* 3
* 第6步:设置字体
* 您可以使用PDPageContentStream类的setFont()方法将文本的字体设置为所需的样式,如下所示。 对于此方法,您需要传递字体的类型和大小。
* <p>
* contentStream.setFont( font_type, font_size );
* 1
* 2
* 第7步:插入文本
* 您可以使用PDPageContentStream类的ShowText()方法将文本插入到页面中,如下所示。 此方法以字符串形式接受所需的文本。
* <p>
* contentStream.showText(text);
* 1
* 2
* 第8步:结束文本
* 插入文本后,您需要使用PDPageContentStream类的endText()方法结束文本,如下所示。
* <p>
* contentStream.endText();
* 1
* 2
* 第9步:关闭PDPageContentStream
* 使用close()方法关闭PDPageContentStream对象,如下所示。
* <p>
* contentstream.close();
* 1
* 2
* 第10步:保存文档
* 添加所需内容后,使用PDDocument类的save()方法保存PDF文档,如以下代码块所示。
* <p>
* doc.save("Path");
* 1
* 2
* 第11步:关闭文档
* 最后,使用PDDocument类的close()方法关闭文档,如下所示。
* <p>
* doc.close();
*/
private static final String pdfFileName = "D:\\fin_tech\\project-demo\\pdf-box-itext\\原料药叠图.pdf";
// private static final String pdfFileName = "D:\\fin_tech\\project-demo\\pdf-box-itext\\test.pdf";
private static final String txtName = "D:\\fin_tech\\project-demo\\pdf-box-itext\\content.txt";
private static final String numName = "D:\\fin_tech\\project-demo\\pdf-box-itext\\num.txt";
public static void addTxtTextloc(String pdfFileName, String txtName, String pageInfo) throws IOException {
//Loading an existing document
File file = new File(pdfFileName);
PDDocument document = PDDocument.load(file);
//Retrieving the pages of the document
PDPage page = document.getPage(0);
/**
* 获取总的page 的方法
*/
final PDPageTree pages = document.getPages();
System.out.println(pages);
/**
* 构造器解决原有文本被覆盖的问题!
* https://blog.csdn.net/Jkcaotain/article/details/118943345?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162978504916780271517292%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=162978504916780271517292&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v29_ecpm-2-118943345.pc_search_download_positive&utm_term=pdf%E6%B7%BB%E5%8A%A0%E6%96%87%E6%9C%AC%E5%90%8E%E6%96%87%E5%AD%97%E8%A6%86%E7%9B%96&spm=1018.2226.3001.4187
* todo 解决备份的问题
*/
PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, false, false);
//Begin the Content stream
contentStream.beginText();
//Setting the font to the Content stream
contentStream.setFont(PDType1Font.TIMES_ROMAN, 12);
//Setting the position for the line
contentStream.newLineAtOffset(100, 50);
String text = "This is the sample document and we are adding content to it.";
//Adding text in the form of string
contentStream.showText(text);
//Ending the content stream
contentStream.endText();
System.out.println("Content added");
//Closing the content stream
contentStream.close();
//Saving the document
document.save(new File(pdfFileName));
//Closing the document
document.close();
}
/**
* 按照对应的传的对应的位置和对应的文本都是list
*
* @param pdfFileName
* @throws IOException
*/
public static void addTxtTextloc2(String pdfFileName, String txtName, String numName) throws IOException {
//Loading an existing document
File file = new File(pdfFileName);
PDDocument document = PDDocument.load(file);
//Retrieving the pages of the document
List<String> txtNames = ReadTxt.readByFile(txtName);
List<String> numNames = ReadTxt.readByFile(numName);
if (txtNames.size() != numNames.size()) {
System.out.println(" 内容和位置的txt 文件的信息数量不匹配");
return;
}
for (int i = 0; i < txtNames.size(); i++) {
PDPage page = document.getPage(i);
PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, false, false);
//Begin the Content stream
contentStream.beginText();
//Setting the font to the Content stream
contentStream.setFont(PDType1Font.TIMES_ROMAN, 12);
//Setting the position for the line
loc loc = PdfUtils.listToMap().get(numNames.get(i));
if (loc == null) {
System.out.println(" map get 的值和预先需求的 1、2、3 cm 距离不一致");
}
contentStream.newLineAtOffset(loc.getTx(), loc.getTy());
// String text = "This is the sample document and we are adding content to it.";
//Adding text in the form of string
System.out.println(i + "=================");
System.out.println(new String(txtNames.get(i).getBytes(),StandardCharsets.UTF_8));
contentStream.showText( new String(txtNames.get(i).getBytes(),StandardCharsets.UTF_8));
//Ending the content stream
contentStream.endText();
System.out.println("Content added");
//Closing the content stream
contentStream.close();
}
/**
* 构造器解决原有文本被覆盖的问题!
* https://blog.csdn.net/Jkcaotain/article/details/118943345?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162978504916780271517292%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=162978504916780271517292&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v29_ecpm-2-118943345.pc_search_download_positive&utm_term=pdf%E6%B7%BB%E5%8A%A0%E6%96%87%E6%9C%AC%E5%90%8E%E6%96%87%E5%AD%97%E8%A6%86%E7%9B%96&spm=1018.2226.3001.4187
* todo 解决备份的问题
*/
//Saving the document
document.save(new File(pdfFileName));
//Closing the document
document.close();
}
public static void main(String[] args) throws IOException {
AddPdfContent.addTxtTextloc2(pdfFileName, txtName, numName);
}
// todo 指定坐标位置 和正常单位的换算
// 读取文件进行判断是否匹配
// 判断读取文字是否超出一行
// 进行匹配
// 如果pdf文件太大怎么解决?
// 比如更加的便利使用起来
// 前端操作页面
//
}
完整代码2:itext 解决了中文乱码问题,同时可以定制宋体,如果需要其他字体,而且对应的jar包没有,有博主,推荐重写字体相关类,当时没有尝试究竟能不能够实现!
mvn:
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.4.3</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
<!-- <scope>test</scope>-->
</dependency>
package com.special.weixin.pdf;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.*;
import org.junit.Test;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
/**
* @author liuYC
* @ClassName AddContentByItext
* @Description TODO
* @date 2021/8/24 16:27
*/
public class AddContentByItext {
private static final String txtName = "D:\\fin_tech\\project-demo\\pdf-box-itext\\content.txt";
private static final String numName = "D:\\fin_tech\\project-demo\\pdf-box-itext\\num.txt";
private static final String filePath = "D:\\fin_tech\\project-demo\\pdf-box-itext\\原料药叠图.pdf";
private static final String savePath = "D:\\fin_tech\\project-demo\\pdf-box-itext\\itext\\原料药叠图OVER6.pdf";
@Test
public void addContent() throws IOException, DocumentException {
/**
* //中文字体,解决中文不能显示问题
* BaseFont bfChinese = BaseFont.createFont("C:/WINDOWS/Fonts/SIMYOU.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
* // BaseFont bfChinese = BaseFont.createFont("Helvetica", "Cp1252", BaseFont.NOT_EMBEDDED);
*
* //蓝色字体
* Font blueFont = new Font(bfChinese);
* blueFont.setColor(BaseColor.BLUE);
* //绿色字体
* Font greenFont = new Font(bfChinese);
* greenFont.setColor(BaseColor.GREEN);
* //红色字体
* Font redFont = new Font(bfChinese);
* redFont.setColor(BaseColor.RED);
*
*/
// BaseFont baseFont =BaseFont.createFont("D:\\fin_tech\\project-demo\\pdf-box-itext\\itext\\simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);;
BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", true);
// BaseFont baseFont =BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-V",true);
// BaseFont baseFont =BaseFont.createFont("C:/WINDOWS/Fonts/SIMYOU.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);;
// BaseFont baseFont = BaseFont.createFont("Times-Roman", "UniGB-UCS2-H", true);
Font font = new Font(baseFont);
PdfReader reader = new PdfReader(new FileInputStream(filePath));
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(savePath));
// final AcroFields fields = stamper.getAcroFields();
// addTextToPdfCenter(fields,ps,value,key,baseFont);
List<String> txtNames = ReadTxt.readByFile(txtName);
List<String> numNames = ReadTxt.readByFile(numName);
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
PdfContentByte over = stamper.getOverContent(i);
ColumnText columnText = new ColumnText(over);
/**
* Phrase hello = new Phrase("Hello World");
* PdfContentByte canvas = writer.getDirectContentUnder();
* ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT,
* hello, 36, 788, 0);
*/
// llx 和 urx 最小的值决定离左边的距离. lly 和 ury 最大的值决定离下边的距离 13最小 24 最大
// columnText.setSimpleColumn(150, 10, 350, 100);
// columnText.setSimpleColumn(150, 10, 350, 110);
// x 范围值在( 0-610) 56 size 610
//居中的实现
columnText.setSimpleColumn(305-((txtNames.get(i - 1).length())*610/56/2), 0, 610, (new Float(numNames.get(i - 1)) * 20));
// columnText.setSimpleColumn(305-((txtNames.get(i - 1).length())/2)*(56/610), 0, 610, (new Float(numNames.get(i - 1)) * 20));
// columnText.setSimpleColumn(380, 0, 400, (new Float(numNames.get(i - 1)) * 20));
// columnText.set
// columnText.setSimpleColumn(50, 10, 350, 50);
// columnText.
// columnText.setSimpleColumn(50, 100, 350, 300);
System.out.println("length: "+txtNames.get(i - 1).length());
Paragraph elements = new Paragraph(0, new Chunk(txtNames.get(i - 1)));
// 设置字体,如果不设置添加的中文将无法显示
elements.setFont(font);
// columnText.setc();
columnText.addElement(elements);
columnText.go();
// ColumnText
}
stamper.close();
}
}
itext in action 读书笔记:
https://www.cnblogs.com/julyluo/archive/2012/07/29/2613822.html
itext in action 书籍链接:
链接:https://pan.baidu.com/s/1yH2PiPEon68eIBjDZvhE7Q
提取码:z4mn
--来自百度网盘超级会员V5的分享(过期私聊我)
itext生成PDF文件报错“Font 'STSong-Light' with 'UniGB-UCS2-H' is not recognized.”
https://developers.itextpdf.com/itext-5-examples;
官方下载地址:https://developers.itextpdf.com/downloads
Itext 添加文本内容到已存在的PDF文件:
https://blog.csdn.net/qq_36537108/article/details/86635613
使用PDFBox向pdf中添加内容时,覆盖了pdf中原先的内容问题
开发团队的svn demo:不翻墙没法使用暂时:
Java spring boot 使用PDFBOX读取指定位置的文字:
https://blog.csdn.net/gavinbj/article/details/104441578
mvn的api文档:
https://pdfbox.apache.org/docs/2.0.13/javadocs/
参考博客:用pdf-box读出来,用itext进行写入的原因:就是中文乱码问题。
https://www.cnblogs.com/liangxinzhi/p/4275561.html
wiki的参考学习文档:
https://iowiki.com/pdfbox/pdfbox_adding_text.html
在特定的位置坐标添加内容参考链接: