import org.apache.pdfbox.io.MemoryUsageSetting;
import org.apache.pdfbox.multipdf.PDFMergerUtility;
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.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.util.Matrix;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Base64;
import java.util.List;
public class PdfUtil {
private static final Logger LOG = LoggerFactory.getLogger(PdfUtil.class);
private static final String PRE_HTML_CODE = "<html><head><meta charset=\"UTF-8\"></head>" +
"<body style=\"background-color:gray;\"><style>" +
"img {background-color:#fff; text-align:center; " +
"width:100%; max-width:100%;margin-top:6px;}</style>";
private static final String SUF_HTML_CODE = "</body></html>";
private static final String MID_HTML_CODE = "<img src=\"data:image/png;base64,";
private static final String MIDD_HTML_CODE = "\">";
/**
* pdf转html
*/
public static String pdfToHtml(InputStream inputStream) {
StringBuilder sb = new StringBuilder();
sb.append(PRE_HTML_CODE);
PDDocument document = null;
ByteArrayOutputStream outputStream = null;
try {
document = PDDocument.load(inputStream);
int pages = document.getNumberOfPages();
PDFRenderer render = new PDFRenderer(document);
BufferedImage image;
for (int i = 0; i < pages; i++) {
sb.append(MID_HTML_CODE);
outputStream = new ByteArrayOutputStream();
image = render.renderImage(i, 2.5f);
ImageIO.write(image, "png", outputStream);
sb.append(Base64.getEncoder().encodeToString(outputStream.toByteArray()));
sb.append(MIDD_HTML_CODE);
}
} catch (IOException e) {
LOG.error(e.getMessage());
} finally {
if (null != outputStream) {
try {
outputStream.close();
} catch (IOException ex) {
}
}
if (null != document) {
try {
document.close();
} catch (IOException ex) {
}
}
}
sb.append(SUF_HTML_CODE);
return sb.toString();
}
/**
* pdf合并
*
* @param inputStreams 输入流
* @param outputStream 输出流
*/
public static void mergePdf(List<InputStream> inputStreams, OutputStream outputStream) {
try {
PDFMergerUtility pdfMergerUtility = new PDFMergerUtility();
inputStreams.forEach(pdfMergerUtility::addSource);
pdfMergerUtility.setDestinationStream(outputStream);
pdfMergerUtility.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());
} catch (Exception e) {
throw new RuntimeException("pdf合并失败: " + e.getMessage(), e);
}
}
private static final PDFont DEFAULT_FONT = PDType1Font.TIMES_BOLD;
private static final Float FONT_SIZE = 20.0f;
private static final int OFFSET_X = 20;
private static final int OFFSET_Y = 20;
/**
* pdf header中增加自定义文字
*
* @param inputStream 输入流
* @param outputStream 输出流
*/
public static void appendHeaderText(InputStream inputStream, OutputStream outputStream, String appendText) {
try {
PDDocument doc = PDDocument.load(inputStream);
doc.setAllSecurityToBeRemoved(true);
for (PDPage page : doc.getPages()) {
PDPageContentStream cs = new PDPageContentStream(doc, page, PDPageContentStream.AppendMode.APPEND, true, true);
PDRectangle pdRectangle = page.getBBox();
cs.beginText();
cs.setFont(DEFAULT_FONT, FONT_SIZE);
// 文字位置,指定x轴、y轴坐标偏移量
Matrix matrix = Matrix.getTranslateInstance(pdRectangle.getLowerLeftX() + OFFSET_X, pdRectangle.getUpperRightY() - OFFSET_Y);
cs.setTextMatrix(matrix);
cs.showText(appendText);
cs.endText();
try {
cs.close();
} catch (Exception e) {
}
}
doc.save(outputStream);
} catch (Exception e) {
throw new RuntimeException("新增内容失败", e);
}
}
/**
* 根据图片创建pdf对象
*
* @param inputStream 输入流
* @param outputStream 输出流
*/
public static void createPDFFromImage(InputStream inputStream, OutputStream outputStream) {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
byte[] cached = new byte[1024];
int read;
while ((read = inputStream.read(cached)) > -1) {
byteArrayOutputStream.write(cached, 0, read);
}
createPDFFromImage(byteArrayOutputStream.toByteArray(), outputStream);
} catch (Exception e) {
throw new RuntimeException("图片生成pdf失败", e);
}
}
/**
* 根据文件内容获取对应pdf对象
*
* @param imageContent 图片内容
* @param outputStream 输出流
*/
private static void createPDFFromImage(byte[] imageContent, OutputStream outputStream) {
try (PDDocument doc = new PDDocument()) {
PDPage page = new PDPage();
doc.addPage(page);
// 获取图片大小
PDImageXObject ximage = PDImageXObject.createFromByteArray(doc, imageContent, "");
// 图片宽度
int imageWidth = ximage.getWidth();
// 图片高度
int imageHeight = ximage.getHeight();
// 获取pdf page大小
PDRectangle pdRectangle = page.getBBox();
float pageWidth = pdRectangle.getUpperRightX();
// pdf高度需要预留增加文本部分
float pageHeight = pdRectangle.getUpperRightY() - OFFSET_Y;
// 分别计算宽度和高度的缩放量,并取缩放量中更小值所谓实际缩放量
float widthScale = pageWidth / imageWidth;
float heightScale = pageHeight / imageHeight;
float realScale = widthScale < heightScale ? widthScale : heightScale;
// 计算实际宽度
float realWidth = ximage.getWidth() * realScale;
float realHeight = ximage.getHeight() * realScale;
try (PDPageContentStream contentStream = new PDPageContentStream(doc, page,
PDPageContentStream.AppendMode.OVERWRITE, true, true)) {
// x轴偏移量为page宽度 - 真实宽度的二分之一
// y轴偏移量为page高度 - 真实高度的二分之一
contentStream.drawImage(ximage, (pageWidth - realWidth) / 2, (pageHeight - realHeight) / 2, realWidth, realHeight);
}
doc.save(outputStream);
} catch (Exception e) {
throw new RuntimeException("Image转图片失败", e);
}
}
}