思路
方法一:使用word制作一个表格(如下图),然后使用Adobe Acrobat DC
操作此文件,编辑相关的表单项,设置各个表单的名称(百度DC的使用方法)
方法二: 直接制作一个相应尺寸大小的图片,(如下图),然后使用Adobe Acrobat DC
操作此文件,编辑相关的表单项,,设置各个表单的名称。保存后会生成相应的pdf文件,然后使用下面提供的代码,即可向里面填充你需要的内容了。
工具类
所需要的依赖
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- itextpdf 依赖包start -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.10</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<!-- itextpdf 依赖包end -->
<!--pdf 转图片 start -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.21</version>
</dependency>
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.12</version>
</dependency>
<!--pdf 转图片 end -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.3.8</version>
</dependency>
代码
import cn.hutool.core.codec.Base64;
import com.itextpdf.text.Document;
import com.itextpdf.text.pdf.*;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.List;
import java.util.*;
/**
* https://www.cnblogs.com/lookupthesky/p/9897373.html
*/
public class CoalTicketPDFUtil {
public static void main(String[] args) throws Exception {
HashMap map = new HashMap<String, String>();
map.put("year","2020");
map.put("month","08");
map.put("day","08");
map.put("numbercode","123456789");
map.put("companyName", "鄂尔多斯市永恒华煤炭运销有限公司前进煤矿");
map.put("carNumber", "晋B65821");
map.put("coalTypeName", "褐煤");
map.put("netWeight", "3111");
map.put("coalVarietiesName", "原煤");
map.put("univalent", "200");
map.put("totalPrice", "6333");
map.put("destination", "内蒙古鄂尔多斯市伊旗转龙湾装站内蒙古鄂尔多斯市伊旗转龙湾装站内蒙古鄂尔多斯市伊旗转龙湾装站内蒙古鄂尔多斯市伊尔多斯市伊旗转龙湾装站alllllll");
map.put("teller", "开票员张三");
map.put("roadChecker", "路检员李四");
map.put("datetime", "时间时间时间时间时间时间");
map.put("logoImg", Base64.encode(new File("d:/qrcode.jpg")));
map.put("barCodeImg", map.get("logoImg"));
map.put("qrImg", map.get("logoImg"));
//生成条形码
map.put("barCodeImg", BarcodeUtil.getImageBase64("6952069500011"));
map.put("sealImg", Base64.encode(new File("d:/sealImg.gif")));
String sourceFile = "d:/coal-ticket-template.pdf";
String targetFile = "d:/coal-ticket-finish.pdf";
String imageFilePath = "d:/coal-ticket-finish.png";
generateAsPDFFile(map, FileUtils.openInputStream(new File(sourceFile)), targetFile);
// System.out.println("获取pdf表单中的fieldNames:"+getTemplateFileFieldNames(sourceFile));
// System.out.println("读取文件数组:"+fileBuff(sourceFile));
// System.out.println("pdf转图片:"+pdf2Img(new File(targetFile),imageFilePath));
// System.out.println(generateAsPDFImg(map,FileUtils.openInputStream(new File(sourceFile))));
}
/**
* 生成的是pdf文件
* @param fieldValueMap map中的参数填充pdf,map中的key和pdf表单中的field对应
* @param templateFileInputStream 模板文件的输入流
* @param fileName 生成文件的路径+名称
*/
public static void generateAsPDFFile(Map<String, String> fieldValueMap, InputStream templateFileInputStream, String fileName){
ByteArrayOutputStream fos = (ByteArrayOutputStream) fillParam(fieldValueMap, templateFileInputStream);
try {
FileUtils.writeByteArrayToFile(new File(fileName), fos.toByteArray());
} catch (IOException e) {
e.printStackTrace();
}finally {
IOUtils.closeQuietly(fos);
}
}
/**
* 生成pdf文件的 base64编码的字符串
* @param fieldValueMap map中的参数填充pdf,map中的key和pdf表单中的field对应
* @param templateFileInputStream 模板文件的输入流
* @return
*/
public static String generateAsPDFBase64(Map<String, String> fieldValueMap, InputStream templateFileInputStream) throws Exception{
try (ByteArrayOutputStream fos = (ByteArrayOutputStream) fillParam(fieldValueMap, templateFileInputStream)){
return Base64.encode(fos.toByteArray());
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
/**
* 生成pdf的图片格式,把图片转换成base64编码的字符串
* @param fieldValueMap
* @param templateFileInputStream
* @return
* @throws Exception
*/
public static String generateAsPDFImg(Map<String, String> fieldValueMap, InputStream templateFileInputStream) throws Exception{
try (ByteArrayOutputStream fos = (ByteArrayOutputStream) fillParam(fieldValueMap, templateFileInputStream)){
ByteArrayOutputStream outputStream = (ByteArrayOutputStream)pdf2ImgOutputStream(fos.toByteArray());
return Base64.encode(outputStream.toByteArray());
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
/**
* Description:使用map中的参数填充pdf,map中的key和pdf表单中的field对应 <br>
* @param fieldValueMap 键值对
* @param templateFileInputStream 模板文件的输入流
* @return
*/
private static OutputStream fillParam(Map<String, String> fieldValueMap, InputStream templateFileInputStream) {
ByteArrayOutputStream fos = new ByteArrayOutputStream();
try {
PdfReader reader = null;
PdfStamper stamper = null;
BaseFont base = null;
try {
reader = new PdfReader(templateFileInputStream);
stamper = new PdfStamper(reader, fos);
stamper.setFormFlattening(true);
//获取系统字体的路径
String prefixFont = "";
//获取系统类型
String os = System.getProperties().getProperty("os.name");
if (os.startsWith("win") || os.startsWith("Win")) {
//win下获取字体的路径
prefixFont = "C:\\Windows\\Fonts" + File.separator + "STSONG.TTF";
} else {
//linux下获取字体的路径,注意该目录下如果没有需额外安装,如我用的是STSONG字体
prefixFont = "/usr/share/fonts/win_font" + File.separator + "STSONG.TTF";
}
//base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
try{
base = BaseFont.createFont(prefixFont, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
}catch (Exception e){
base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
}
AcroFields acroFields = stamper.getAcroFields();
for (String key : acroFields.getFields().keySet()) {
acroFields.setFieldProperty(key, "textfont", base, null);
acroFields.setFieldProperty(key, "textsize", new Float(35), null);
}
if (fieldValueMap != null) {
for (String fieldName : fieldValueMap.keySet()) {
acroFields.setField(fieldName, fieldValueMap.get(fieldName));
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (stamper != null) {
try {
stamper.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (reader != null) {
reader.close();
}
}
return fos;
} catch (Exception e) {
System.out.println("填充参数异常");
throw e;
}
}
/**
* Description: 获取pdf表单中的fieldNames<br>
* @author mk
* @Date 2018-11-2 15:21 <br>
* @Param
* @return
*/
public static Set<String> getTemplateFileFieldNames(String pdfFileName) {
Set<String> fieldNames = new TreeSet<String>();
PdfReader reader = null;
try {
reader = new PdfReader(pdfFileName);
Set<String> keys = reader.getAcroFields().getFields().keySet();
for (String key : keys) {
int lastIndexOf = key.lastIndexOf(".");
int lastIndexOf2 = key.lastIndexOf("[");
fieldNames.add(key.substring(lastIndexOf != -1 ? lastIndexOf + 1 : 0, lastIndexOf2 != -1 ? lastIndexOf2 : key.length()));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
reader.close();
}
}
return fieldNames;
}
/**
* Description: 读取文件数组<br>
* @author mk
* @Date 2018-11-2 15:21 <br>
* @Param
* @return
*/
public static byte[] fileBuff(String filePath) throws IOException {
File file = new File(filePath);
long fileSize = file.length();
if (fileSize > Integer.MAX_VALUE) {
//System.out.println("file too big...");
return null;
}
FileInputStream fi = new FileInputStream(file);
byte[] file_buff = new byte[(int) fileSize];
int offset = 0;
int numRead = 0;
while (offset < file_buff.length && (numRead = fi.read(file_buff, offset, file_buff.length - offset)) >= 0) {
offset += numRead;
}
// 确保所有数据均被读取
if (offset != file_buff.length) {
throw new IOException("Could not completely read file " + file.getName());
}
fi.close();
return file_buff;
}
/**
* Description: 合并pdf <br>
* @author mk
* @Date 2018-11-2 15:21 <br>
* @Param
* @return
*/
public static void mergePdfFiles(String[] files, String savepath) {
Document document = null;
try {
document = new Document(); //默认A4大小
PdfCopy copy = new PdfCopy(document, new FileOutputStream(savepath));
document.open();
for (int i = 0; i < files.length; i++) {
PdfReader reader = null;
try {
reader = new PdfReader(files[i]);
int n = reader.getNumberOfPages();
for (int j = 1; j <= n; j++) {
document.newPage();
PdfImportedPage page = copy.getImportedPage(reader, j);
copy.addPage(page);
}
} finally {
if (reader != null) {
reader.close();
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭PDF文档流,OutputStream文件输出流也将在PDF文档流关闭方法内部关闭
if (document != null) {
document.close();
}
}
}
/**
* pdf转图片
* @param file pdf
* @return
*/
public static boolean pdf2Img(File file,String imageFilePath) {
try {
//生成图片保存
byte[] data = pdfToPic(PDDocument.load(file));
File imageFile = new File(imageFilePath);
ImageThumbUtils.thumbImage(data, 1, imageFilePath); //按比例压缩图片
System.out.println("pdf转图片文件地址:" + imageFilePath);
return true;
} catch (Exception e) {
System.out.println("pdf转图片异常:");
e.printStackTrace();
}
return false;
}
/**
* pdf转图片
* @param originalImgData pdf的源文件
* @return
*/
public static OutputStream pdf2ImgOutputStream(byte[] originalImgData) throws Exception{
try {
byte[] data = pdfToPic(PDDocument.load(originalImgData));
//按比例压缩图片
OutputStream outputStream = ImageThumbUtils.thumbImage(data, 1);
return outputStream;
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
/**
* pdf转图片
*/
private static byte[] pdfToPic(PDDocument pdDocument) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
List<BufferedImage> piclist = new ArrayList<BufferedImage>();
try {
PDFRenderer renderer = new PDFRenderer(pdDocument);
for (int i = 0; i < pdDocument.getNumberOfPages(); i++) {//
// 0 表示第一页,300 表示转换 dpi,越大转换后越清晰,相对转换速度越慢
BufferedImage image = renderer.renderImageWithDPI(i, 108);
piclist.add(image);
}
// 总高度 总宽度 临时的高度 , 或保存偏移高度 临时的高度,主要保存每个高度
int height = 0, width = 0, _height = 0, __height = 0,
// 图片的数量
picNum = piclist.size();
// 保存每个文件的高度
int[] heightArray = new int[picNum];
// 保存图片流
BufferedImage buffer = null;
// 保存所有的图片的RGB
List<int[]> imgRGB = new ArrayList<int[]>();
// 保存一张图片中的RGB数据
int[] _imgRGB;
for (int i = 0; i < picNum; i++) {
buffer = piclist.get(i);
heightArray[i] = _height = buffer.getHeight();// 图片高度
if (i == 0) {
// 图片宽度
width = buffer.getWidth();
}
// 获取总高度
height += _height;
// 从图片中读取RGB
_imgRGB = new int[width * _height];
_imgRGB = buffer.getRGB(0, 0, width, _height, _imgRGB, 0, width);
imgRGB.add(_imgRGB);
}
// 设置偏移高度为0
_height = 0;
// 生成新图片
BufferedImage imageResult = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
int[] lineRGB = new int[8 * width];
int c = new Color(128, 128, 128).getRGB();
for (int i = 0; i < lineRGB.length; i++) {
lineRGB[i] = c;
}
for (int i = 0; i < picNum; i++) {
__height = heightArray[i];
// 计算偏移高度
if (i != 0)
_height += __height;
imageResult.setRGB(0, _height, width, __height, imgRGB.get(i), 0, width); // 写入流中
// 模拟页分隔
if (i > 0) {
imageResult.setRGB(0, _height + 2, width, 8, lineRGB, 0, width);
}
}
// 写流
ImageIO.write(imageResult, "jpg", baos);
} catch (Exception e) {
System.out.println("pdf转图片异常:");
e.printStackTrace();
} finally {
IOUtils.closeQuietly(baos);
try {
pdDocument.close();
} catch (Exception ignore) {
}
}
return baos.toByteArray();
}
}