iText7 HTML转PDF(页眉、页码、水印) + 浏览器在线预览
背景:表单上点击打印按钮,把表单转为pdf并在浏览器预览。PDF设置固定页眉,页眉(含图片)、页码和水印。实现:项目用的是Springboot + VUE2.x。生成HTML: FreeMarker或者VelocityHTML转PDF:iText7实现步骤:关键依赖<!-- itext7 html转pdf --><dependency><groupId>com.
·
背景:
表单上点击打印按钮,把表单转为pdf并在浏览器预览。PDF设置固定页眉,页眉(含图片)、页码和水印。
实现:
项目用的是Springboot + VUE2.x。
生成HTML: FreeMarker或者Velocity
HTML转PDF: iText7
实现步骤:
关键依赖
<!-- itext7 html转pdf -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>html2pdf</artifactId>
<version>3.0.3</version>
</dependency>
<!-- pdf中文字体 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>font-asian</artifactId>
<version>7.1.11</version>
</dependency>
1. 生成HTML(这里略过...)
2. HTML转PDF
Service代码片段
// 生成html
RenderTemplateReq renderTemplateReq = new RenderTemplateReq();
renderTemplateReq.setTemplatePath("vm/pdf/iqc.vm");
renderTemplateReq.setData(JSON.parseObject(JSON.toJSONString(vo)));
Result<String> htmlResult = generatorRemote.renderTemplate(renderTemplateReq);
ResultCode.FEIGN_ERROR.assertTrue(Result.isSuccess(htmlResult), "生成html失败");
String html = htmlResult.getData();
// html转pdf
PdfGenerator.generatePdf(html, outputPath);
生成PDF
package com.multek.sqm.itext;
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.html2pdf.attach.impl.OutlineHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.WriterProperties;
import com.itextpdf.layout.font.FontProvider;
import com.multek.sqm.itext.event.PageHeader;
import com.multek.sqm.itext.event.PageMarker;
import com.multek.sqm.itext.event.WaterMarker;
/**
* PDF工具类
*
* @author: mcnlshen
* @date: 2021-09-17 23:50
*/
public class PdfGenerator {
private PdfGenerator() {
// 构造器私有化
}
/**
* 生成PDF
*
* @param html HTML
* @param outputFile 输出路径
*/
public static void generatePdf(String html, String outputFile) {
try {
//outputFile也可以是输出流
PdfWriter writer = new PdfWriter(outputFile, new WriterProperties().setFullCompressionMode(Boolean.TRUE));
PdfDocument doc = new PdfDocument(writer);
doc.setDefaultPageSize(PageSize.A4);
doc.getDefaultPageSize().applyMargins(20, 20, 20, 20, true);
// 设置中文字体
FontProvider fontProvider = new FontProvider();
PdfFont pdfFont = PdfFontFactory.createFont("STSongStd-Light", "UniGB-UCS2-H", false);
fontProvider.addFont(pdfFont.getFontProgram(), "UniGB-UCS2-H");
// 水印
doc.addEventHandler(PdfDocumentEvent.END_PAGE, new WaterMarker());
// 页眉
doc.addEventHandler(PdfDocumentEvent.END_PAGE, new PageHeader());
// 页码
doc.addEventHandler(PdfDocumentEvent.END_PAGE, new PageMarker(pdfFont));
ConverterProperties properties = new ConverterProperties();
properties.setFontProvider(fontProvider);
//PDF目录
properties.setOutlineHandler(OutlineHandler.createStandardHandler());
HtmlConverter.convertToPdf(html, doc, properties);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
package com.multek.sqm.itext.event;
import cn.hutool.core.io.IoUtil;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.borders.SolidBorder;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.property.HorizontalAlignment;
import com.itextpdf.layout.property.TextAlignment;
import com.itextpdf.layout.property.VerticalAlignment;
import lombok.SneakyThrows;
import java.io.InputStream;
/**
* PDF页眉
*
* @author: mcnlshen
* @date: 2021-09-18 00:36
*/
public class PageHeader implements IEventHandler {
@SneakyThrows
@Override
public void handleEvent(Event event) {
final PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
final PdfDocument pdfDoc = docEvent.getDocument();
final Document doc = new Document(pdfDoc);
final PdfPage page = docEvent.getPage();
final Rectangle pageSize = page.getPageSize();
final float pdfWidth = pageSize.getWidth();
final float pdfHeight = pageSize.getHeight();
// final PdfCanvas pdfCanvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDoc);
// final Color lineColor = new DeviceRgb(57, 123, 198);
// pdfCanvas.setLineWidth(1.5f).setStrokeColor(lineColor);
final float tableWidth = pdfWidth - doc.getRightMargin() - doc.getLeftMargin();
// 页眉
// final float x0 = doc.getRightMargin(), y0 = pdfHeight - doc.getTopMargin();
// pdfCanvas.moveTo(x0, y0).lineTo(pdfWidth - doc.getRightMargin(), y0).stroke();
final Table headerTable = new Table(2);
headerTable.setFixedLayout();
headerTable.setWidth(tableWidth);
headerTable.setHorizontalAlignment(HorizontalAlignment.CENTER);
// 设置图片
InputStream is = this.getClass().getResourceAsStream("/img/multeklogo.jpg");
byte[] bytes = IoUtil.readBytes(is);
Image img = new Image(ImageDataFactory.create(bytes));
img.setHeight(30);
Paragraph imgParagraph = new Paragraph().add(img);
imgParagraph.setMarginLeft(-20);
Cell imgCell = new Cell();
imgCell.setBorder(Border.NO_BORDER);
imgCell.setHorizontalAlignment(HorizontalAlignment.LEFT);
imgCell.setVerticalAlignment(VerticalAlignment.BOTTOM);
imgCell.setTextAlignment(TextAlignment.LEFT);
imgCell.add(imgParagraph);
headerTable.addCell(imgCell);
final Paragraph righText = new Paragraph();
righText.setVerticalAlignment(VerticalAlignment.BOTTOM);
// righText.add(new Tab()).addTabStops(new TabStop(800, TabAlignment.RIGHT));
righText.setBorder(new SolidBorder(1));
righText.add("F/SQM-IQC-001-BX-01E");
righText.setMarginRight(19);
righText.setPadding(1);
final Cell rightCell = new Cell();
rightCell.add(righText);
rightCell.setWidth(140);
rightCell.setFontSize(9f);
rightCell.setBorder(Border.NO_BORDER);
rightCell.setTextAlignment(TextAlignment.CENTER);
// realnameCell.setFontColor(lineColor);
rightCell.setVerticalAlignment(VerticalAlignment.BOTTOM);
rightCell.setHorizontalAlignment(HorizontalAlignment.RIGHT);
headerTable.addCell(rightCell);
headerTable.setFixedPosition(doc.getLeftMargin(), pdfHeight - 85, tableWidth);
doc.add(headerTable);
}
}
package com.multek.sqm.itext.event;
import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.property.TextAlignment;
import lombok.AllArgsConstructor;
/**
* PDF页码
*
* @author mcnlshen
* @date 2021-09-18
*/
@AllArgsConstructor
public class PageMarker implements IEventHandler {
private PdfFont pdfFont;
@Override
public void handleEvent(Event event) {
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfDocument pdf = docEvent.getDocument();
PdfPage page = docEvent.getPage();
Rectangle pageSize = page.getPageSize();
PdfCanvas pdfCanvas = new PdfCanvas(
page.getLastContentStream(), page.getResources(), pdf);
Canvas canvas = new Canvas(pdfCanvas, pdf, pageSize);
float x = (pageSize.getLeft() + pageSize.getRight()) / 2;
float y = pageSize.getBottom() + 15;
Paragraph p = new Paragraph("第" + pdf.getPageNumber(page) + "页")
.setFontSize(12)
.setFont(pdfFont);
canvas.showTextAligned(p, x, y, TextAlignment.CENTER);
canvas.close();
}
}
package com.multek.sqm.itext.event;
import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.property.TextAlignment;
import com.itextpdf.layout.property.VerticalAlignment;
/**
* Itext7 实现水印
*
* @author mcnlshen
* @date 2021-09-18
*/
public class WaterMarker implements IEventHandler {
@Override
public void handleEvent(Event event) {
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfDocument pdf = docEvent.getDocument();
PdfPage page = docEvent.getPage();
Rectangle pageSize = page.getPageSize();
PdfCanvas pdfCanvas = new PdfCanvas(
page.getLastContentStream(), page.getResources(), pdf);
Canvas canvas = new Canvas(pdfCanvas, pdf, pageSize);
Paragraph waterMarker = new Paragraph("MULTEK IQC")
.setOpacity(0.05f)
.setFontSize(40);
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
canvas.showTextAligned(waterMarker, (150 + i * 300), (160 + j * 150), pdf.getNumberOfPages(), TextAlignment.CENTER, VerticalAlignment.BOTTOM, .6f);
}
}
canvas.close();
}
}
前端预览核心代码
// 预览pdf
export function previewOnline(query) {
axios({
method: 'get',
url: process.env.VUE_APP_BASE_API + '/sftp/download',
params: query,
responseType: 'blob',
headers: { 'Authorization': 'Bearer ' + getToken() }
}).then(res => {
let blob = new Blob([res.data], { type: 'application/pdf' })
// 适配
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob)
} else {
const fileURL = URL.createObjectURL(blob)
window.open(fileURL)
}
})
}
最终效果图
更多推荐
已为社区贡献1条内容
所有评论(0)