★itext-为pdf文件添加页眉页脚 | 3步完成 |
由于上一篇自定义生成pdf的功能需求又增加了,需要加上页码。所以本博客诞生了~
1. 通过继承PdfPageEventHelper类,实现需要实现的方法
import com.lowagie.text.Document;
import com.lowagie.text.Element;
import com.lowagie.text.Phrase;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.ColumnText;
import com.lowagie.text.pdf.PdfPageEventHelper;
import com.lowagie.text.pdf.PdfWriter; public class PdfBuilder extends PdfPageEventHelper {
// 当当前页面开始加载时,触发(页眉)
@Override
public void onStartPage(PdfWriter writer, Document document) {
// TODO Auto-generated method stub
super.onStartPage(writer, document);
}
// 当当前页面初始化完成,切入document之前触发(页脚)
@Override
public void onEndPage(PdfWriter writer, Document document) { Rectangle rect = new Rectangle(, , , );
// ColumnText.showTextAligned(writer.getDirectContent(), Element.ALIGN_CENTER,
// new Phrase(String.format(" ", writer.getPageNumber())), (rect.getLeft() + rect.getRight()) / 2,
// rect.getBottom() - 18, 0);
ColumnText.showTextAligned(writer.getDirectContent(), Element.ALIGN_BOTTOM,
new Phrase(String.format("- %d -", writer.getPageNumber())), (rect.getLeft() + rect.getRight()) / ,
rect.getBottom() - , );
}
}
tip: writer.getPageNumber();能够获取到当前页面的页码 2. 重写一下ITextRenderer类
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Shape;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.List;
import java.util.regex.Pattern; import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xhtmlrenderer.css.style.CalculatedStyle;
import org.xhtmlrenderer.extend.NamespaceHandler;
import org.xhtmlrenderer.extend.UserInterface;
import org.xhtmlrenderer.layout.BoxBuilder;
import org.xhtmlrenderer.layout.Layer;
import org.xhtmlrenderer.layout.LayoutContext;
import org.xhtmlrenderer.layout.SharedContext;
import org.xhtmlrenderer.pdf.ITextFontContext;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextOutputDevice;
import org.xhtmlrenderer.pdf.ITextRenderer;
import org.xhtmlrenderer.pdf.ITextReplacedElementFactory;
import org.xhtmlrenderer.pdf.ITextTextRenderer;
import org.xhtmlrenderer.pdf.ITextUserAgent;
import org.xhtmlrenderer.pdf.PDFCreationListener;
import org.xhtmlrenderer.pdf.PDFEncryption;
import org.xhtmlrenderer.render.BlockBox;
import org.xhtmlrenderer.render.PageBox;
import org.xhtmlrenderer.render.RenderingContext;
import org.xhtmlrenderer.render.ViewportBox;
import org.xhtmlrenderer.resource.XMLResource;
import org.xhtmlrenderer.simple.extend.XhtmlNamespaceHandler;
import org.xhtmlrenderer.util.Configuration;
import org.xml.sax.InputSource; import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PdfPageEvent;
import com.lowagie.text.pdf.PdfWriter; public class ITextRenderer2 { private ITextRenderer iTextRenderer = null; // These two defaults combine to produce an effective resolution of 96 px to the inch
private static final float DEFAULT_DOTS_PER_POINT = 20f * 4f / 3f;
private static final int DEFAULT_DOTS_PER_PIXEL = ; private SharedContext _sharedContext;
private ITextOutputDevice _outputDevice; private Document _doc;
private BlockBox _root; private float _dotsPerPoint; private com.lowagie.text.Document _pdfDoc;
private PdfWriter _writer; private PDFEncryption _pdfEncryption; // note: not hard-coding a default version in the _pdfVersion field as this may change between iText releases
// check for null before calling writer.setPdfVersion()
// use one of the values in PDFWriter.VERSION...
private Character _pdfVersion; private char[] validPdfVersions = new char[] { PdfWriter.VERSION_1_2, PdfWriter.VERSION_1_3, PdfWriter.VERSION_1_4,
PdfWriter.VERSION_1_5, PdfWriter.VERSION_1_6, PdfWriter.VERSION_1_7 }; private PDFCreationListener _listener; private PdfPageEvent pdfPageEvent; public ITextRenderer2(ITextRenderer iTextRenderer) {
this(DEFAULT_DOTS_PER_POINT, DEFAULT_DOTS_PER_PIXEL);
this.iTextRenderer = iTextRenderer;
} public ITextRenderer2() {
this(DEFAULT_DOTS_PER_POINT, DEFAULT_DOTS_PER_PIXEL);
} public ITextRenderer2(float dotsPerPoint, int dotsPerPixel) {
_dotsPerPoint = dotsPerPoint; _outputDevice = new ITextOutputDevice(_dotsPerPoint); ITextUserAgent userAgent = new ITextUserAgent(_outputDevice);
_sharedContext = new SharedContext(userAgent);
userAgent.setSharedContext(_sharedContext);
_outputDevice.setSharedContext(_sharedContext); ITextFontResolver fontResolver = new ITextFontResolver(_sharedContext);
_sharedContext.setFontResolver(fontResolver); ITextReplacedElementFactory replacedElementFactory = new ITextReplacedElementFactory(_outputDevice);
_sharedContext.setReplacedElementFactory(replacedElementFactory); _sharedContext.setTextRenderer(new ITextTextRenderer());
_sharedContext.setDPI( * _dotsPerPoint);
_sharedContext.setDotsPerPixel(dotsPerPixel);
_sharedContext.setPrint(true);
_sharedContext.setInteractive(false);
} public PdfPageEvent getPdfPageEvent() {
return pdfPageEvent;
} public void setPdfPageEvent(PdfPageEvent pdfPageEvent) {
this.pdfPageEvent = pdfPageEvent;
} public ITextFontResolver getFontResolver() {
return (ITextFontResolver) _sharedContext.getFontResolver();
} private Document loadDocument(final String uri) {
return _sharedContext.getUac().getXMLResource(uri).getDocument();
} public void setDocument(String uri) {
setDocument(loadDocument(uri), uri);
} public void setDocument(Document doc, String url) {
setDocument(doc, url, new XhtmlNamespaceHandler());
} public void setDocument(File file) throws IOException { File parent = file.getAbsoluteFile().getParentFile();
setDocument(loadDocument(file.toURI().toURL().toExternalForm()), (parent == null ? "" : parent.toURI().toURL()
.toExternalForm()));
} public void setDocumentFromString(String content) {
InputSource is = new InputSource(new BufferedReader(new StringReader(content)));
Document dom = XMLResource.load(is).getDocument(); setDocument(dom, null);
} public void setDocument(Document doc, String url, NamespaceHandler nsh) {
_doc = doc; getFontResolver().flushFontFaceFonts(); _sharedContext.reset();
if (Configuration.isTrue("xr.cache.stylesheets", true)) {
_sharedContext.getCss().flushStyleSheets();
} else {
_sharedContext.getCss().flushAllStyleSheets();
}
_sharedContext.setBaseURL(url);
_sharedContext.setNamespaceHandler(nsh);
_sharedContext.getCss().setDocumentContext(_sharedContext, _sharedContext.getNamespaceHandler(), doc,
new NullUserInterface());
getFontResolver().importFontFaces(_sharedContext.getCss().getFontFaceRules());
} public PDFEncryption getPDFEncryption() {
return _pdfEncryption;
} public void setPDFEncryption(PDFEncryption pdfEncryption) {
_pdfEncryption = pdfEncryption;
} public void setPDFVersion(char _v) {
for (int i = ; i < validPdfVersions.length; i++) {
if (_v == validPdfVersions[i]) {
_pdfVersion = new Character(_v);
return;
}
}
throw new IllegalArgumentException("Invalid PDF version character; use "
+ "valid constants from PdfWriter (e.g. PdfWriter.VERSION_1_2)");
} public char getPDFVersion() {
return _pdfVersion == null ? '' : _pdfVersion.charValue();
} public void layout() {
LayoutContext c = newLayoutContext();
BlockBox root = BoxBuilder.createRootBox(c, _doc);
root.setContainingBlock(new ViewportBox(getInitialExtents(c)));
root.layout(c);
Dimension dim = root.getLayer().getPaintingDimension(c);
root.getLayer().trimEmptyPages(c, dim.height);
root.getLayer().layoutPages(c);
_root = root;
} private Rectangle getInitialExtents(LayoutContext c) {
PageBox first = Layer.createPageBox(c, "first"); return new Rectangle(, , first.getContentWidth(c), first.getContentHeight(c));
} private RenderingContext newRenderingContext() {
RenderingContext result = _sharedContext.newRenderingContextInstance();
result.setFontContext(new ITextFontContext()); result.setOutputDevice(_outputDevice); _sharedContext.getTextRenderer().setup(result.getFontContext()); result.setRootLayer(_root.getLayer()); return result;
} private LayoutContext newLayoutContext() {
LayoutContext result = _sharedContext.newLayoutContextInstance();
result.setFontContext(new ITextFontContext()); _sharedContext.getTextRenderer().setup(result.getFontContext()); return result;
} public void createPDF(OutputStream os) throws DocumentException {
createPDF(os, true, );
} public void writeNextDocument() throws DocumentException {
writeNextDocument();
} public void writeNextDocument(int initialPageNo) throws DocumentException {
List pages = _root.getLayer().getPages(); RenderingContext c = newRenderingContext();
c.setInitialPageNo(initialPageNo);
PageBox firstPage = (PageBox) pages.get();
com.lowagie.text.Rectangle firstPageSize = new com.lowagie.text.Rectangle(, , firstPage.getWidth(c)
/ _dotsPerPoint, firstPage.getHeight(c) / _dotsPerPoint); _outputDevice.setStartPageNo(_writer.getPageNumber()); _pdfDoc.setPageSize(firstPageSize);
_pdfDoc.newPage(); writePDF(pages, c, firstPageSize, _pdfDoc, _writer);
} public void finishPDF() {
if (_pdfDoc != null) {
fireOnClose();
_pdfDoc.close();
}
} public void createPDF(OutputStream os, boolean finish) throws DocumentException {
createPDF(os, finish, );
} /**
* <B>NOTE:</B> Caller is responsible for cleaning up the OutputStream if something goes wrong.
*/
public void createPDF(OutputStream os, boolean finish, int initialPageNo) throws DocumentException {
List pages = _root.getLayer().getPages(); RenderingContext c = newRenderingContext();
c.setInitialPageNo(initialPageNo);
PageBox firstPage = (PageBox) pages.get();
com.lowagie.text.Rectangle firstPageSize = new com.lowagie.text.Rectangle(, , firstPage.getWidth(c)
/ _dotsPerPoint, firstPage.getHeight(c) / _dotsPerPoint); com.lowagie.text.Document doc = new com.lowagie.text.Document(firstPageSize, , , , );
PdfWriter writer = PdfWriter.getInstance(doc, os);
if (_pdfVersion != null) {
writer.setPdfVersion(_pdfVersion.charValue());
}
if (_pdfEncryption != null) {
writer.setEncryption(_pdfEncryption.getUserPassword(), _pdfEncryption.getOwnerPassword(),
_pdfEncryption.getAllowedPrivileges(), _pdfEncryption.getEncryptionType());
}
_pdfDoc = doc;
_writer = writer; firePreOpen(); if (pdfPageEvent != null) {
writer.setPageEvent(pdfPageEvent);
} doc.open(); writePDF(pages, c, firstPageSize, doc, writer); if (finish) {
fireOnClose();
doc.close();
}
} private void firePreOpen() {
if (_listener != null) {
_listener.preOpen(iTextRenderer);
}
} private void fireOnClose() {
if (_listener != null) {
_listener.onClose(iTextRenderer);
}
} private void writePDF(List pages, RenderingContext c, com.lowagie.text.Rectangle firstPageSize,
com.lowagie.text.Document doc, PdfWriter writer) throws DocumentException {
_outputDevice.setRoot(_root); _outputDevice.start(_doc);
_outputDevice.setWriter(writer);
_outputDevice.initializePage(writer.getDirectContent(), firstPageSize.getHeight()); _root.getLayer().assignPagePaintingPositions(c, Layer.PAGED_MODE_PRINT); int pageCount = _root.getLayer().getPages().size();
c.setPageCount(pageCount);
for (int i = ; i < pageCount; i++) {
PageBox currentPage = (PageBox) pages.get(i);
c.setPage(i, currentPage);
paintPage(c, writer, currentPage);
_outputDevice.finishPage();
if (i != pageCount - ) {
PageBox nextPage = (PageBox) pages.get(i + );
com.lowagie.text.Rectangle nextPageSize = new com.lowagie.text.Rectangle(, , nextPage.getWidth(c)
/ _dotsPerPoint, nextPage.getHeight(c) / _dotsPerPoint);
doc.setPageSize(nextPageSize);
doc.newPage();
_outputDevice.initializePage(writer.getDirectContent(), nextPageSize.getHeight());
}
} _outputDevice.finish(c, _root);
} private void paintPage(RenderingContext c, PdfWriter writer, PageBox page) {
provideMetadataToPage(writer, page); page.paintBackground(c, , Layer.PAGED_MODE_PRINT);
page.paintMarginAreas(c, , Layer.PAGED_MODE_PRINT);
page.paintBorder(c, , Layer.PAGED_MODE_PRINT); Shape working = _outputDevice.getClip(); Rectangle content = page.getPrintClippingBounds(c);
_outputDevice.clip(content); int top = -page.getPaintingTop() + page.getMarginBorderPadding(c, CalculatedStyle.TOP); int left = page.getMarginBorderPadding(c, CalculatedStyle.LEFT); _outputDevice.translate(left, top);
_root.getLayer().paint(c);
_outputDevice.translate(-left, -top); _outputDevice.setClip(working);
} private void provideMetadataToPage(PdfWriter writer, PageBox page) {
byte[] metadata = null;
if (page.getMetadata() != null) {
try {
String metadataBody = stringfyMetadata(page.getMetadata());
if (metadataBody != null) {
metadata = createXPacket(stringfyMetadata(page.getMetadata())).getBytes("UTF-8");
}
} catch (UnsupportedEncodingException e) {
// Can't happen
throw new RuntimeException(e);
}
} writer.setPageXmpMetadata(metadata);
} private String stringfyMetadata(Element element) {
Element target = getFirstChildElement(element);
if (target == null) {
return null;
} try {
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
StringWriter output = new StringWriter();
transformer.transform(new DOMSource(target), new StreamResult(output)); return output.toString();
} catch (TransformerConfigurationException e) {
// Things must be in pretty bad shape to get here so
// rethrow as runtime exception
throw new RuntimeException(e);
} catch (TransformerException e) {
throw new RuntimeException(e);
}
} private static Element getFirstChildElement(Element element) {
Node n = element.getFirstChild();
while (n != null) {
if (n.getNodeType() == Node.ELEMENT_NODE) {
return (Element) n;
}
n = n.getNextSibling();
}
return null;
} private String createXPacket(String metadata) {
StringBuffer result = new StringBuffer(metadata.length() + );
result.append("<?xpacket begin='\uFEFF' id='W5M0MpCehiHzreSzNTczkc9d'?>\n");
result.append(metadata);
result.append("\n<?xpacket end='r'?>"); return result.toString();
} public ITextOutputDevice getOutputDevice() {
return _outputDevice;
} public SharedContext getSharedContext() {
return _sharedContext;
} public void exportText(Writer writer) throws IOException {
RenderingContext c = newRenderingContext();
c.setPageCount(_root.getLayer().getPages().size());
_root.exportText(c, writer);
} public BlockBox getRootBox() {
return _root;
} public float getDotsPerPoint() {
return _dotsPerPoint;
} public List findPagePositionsByID(Pattern pattern) {
return _outputDevice.findPagePositionsByID(newLayoutContext(), pattern);
} private static final class NullUserInterface implements UserInterface {
public boolean isHover(Element e) {
return false;
} public boolean isActive(Element e) {
return false;
} public boolean isFocus(Element e) {
return false;
}
} public PDFCreationListener getListener() {
return _listener;
} public void setListener(PDFCreationListener listener) {
_listener = listener;
} public PdfWriter getWriter() {
return _writer;
}
}
tip: 由于继承无法获取部分私有变量和方法,动态代理方式在此处不可用,因而选择重写该类,在重写的类ITextRenderer2中维护了一个ITextRenderer对象,使其内部功能正常执行,我们只需要为ITextRenderer2额外维护一个PdfPageEvent对象,然后在createPDF 方法中,非空赋值一下即可。注意为PdfWriter设置PdfPageEvent实现类的操作必须在document.open()之前。
3. 拿到html文件,进行html转pdf操作
String url = htmlFile.toURI().toURL().toString(); ITextRenderer2 renderer = new ITextRenderer2(new ITextRenderer());
renderer.setDocument(url);
ITextFontResolver fontResolver = renderer.getFontResolver();
fontResolver.addFont(pdfFont + File.separator + "SimSun.ttc", BaseFont.IDENTITY_H,
BaseFont.NOT_EMBEDDED);
fontResolver
.addFont(pdfFont + File.separator + "Arial.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
renderer.setPdfPageEvent(new PDFBuilder());
renderer.layout();
renderer.createPDF(fos);
总结: 用了我的上一篇pdf生成技术(java原装代码完成pdf在线预览和pdf打印及下载)的童鞋,如果也碰到了这样的需求,可以参考一下本篇博客哦
代码改动量少,总共增加了2个类,改动了一行代码,即可完成pdf的页眉页脚的添加。
通过这个例子,其实对于我们是有启示的,一种技术他能长久的在it行业中被大家一直所使用,不仅仅因为它自身功能的强大,也因为它在很多地方提供了可供程序员操作的接口或者类,使得这门技术能够不断适合程序员的需求,而一个技术即便功能再强大,在全面,不开放可供他人操作的入口,依旧会被淘汰,因为其自身不可能适合所有程序员,只有程序员知道自己所需要的,那么对于程序员来说,根据公司需求做出功能,我们则要谨记为功能安全的开放部分入口,这样以便在后期需求更新时,能够尽可能的不改变源代码的基础上进行需求更新,同时,也方便了其他同事进行功能增强等一系列操作。以上纯属本人个人见解,若有不足,还望赐教~
★itext-为pdf文件添加页眉页脚 | 3步完成 |的更多相关文章
- itext 生成pdf文件添加页眉页脚
原文来自:https://www.cnblogs.com/joann/p/5511905.html 我只是记录所有jar版本,由于版本冲突及不兼容很让人头疼的,一共需要5个jar, 其中itextpd ...
- iText + Freemarker实现pdf的导出,支持中文、css以及图片,页眉页脚,页眉添加图片
本文为了记录自己的实现过程,具体的实现步骤是参考博文 https://www.cnblogs.com/youzhibing/p/7692366.html 来实现的,只是在他的基础上添加了页眉页脚及页眉 ...
- 【Itext】7步制作Itext5页眉页脚pdf实现第几页共几页
itext5页眉页脚工具类,实现page x of y 完美兼容各种格式大小文档A4/B5/B3,兼容各种文档格式自动计算页脚XY轴坐标 鉴于没人做的这么细致,自己就写了一个itext5页眉页脚工具类 ...
- 用什么方法给PDF添加页眉页脚
我们所看到的书本中都会设置好有页眉页脚,那么电子书想要添加页眉页脚要怎么操作呢,用什么方法可以在PDF中添加页眉页脚呢,今天就为大家分享一下,如何在电子文件中添加页眉页脚,想知道的小伙伴们就一起来看看 ...
- c# iText 生成PDF 有文字,图片,表格,文字样式,对齐方式,页眉页脚,等等等,
#region 下载说明书PDF protected void lbtnDownPDF_Click(object sender, EventArgs e) { int pid = ConvertHel ...
- ABBYY FineReader 15 如何为PDF文档添加页眉页脚
页眉.页脚是文档页面顶部或底部重复出现的文本信息.很多用户会习惯在文档页面的顶部与底部区域添加页眉.页脚来展现页码.文档标题.作者姓名.品牌名称等附加信息.而ABBYY FineReader 15(W ...
- 怎么给PDF去除页眉页脚
PDF文件我们现在都会使用到,但有时需编辑PDF文件的时候,小伙伴们都知道该怎么操作吗,不知道的小伙伴不用担心,今天小编就来跟大家分享一下怎么删除PDF文件的页眉页脚,我们一起来看看下面的文章吧 操作 ...
- PDF怎么去除页眉页脚,PDF页眉页脚编辑方法
我们在使用文件的时候需要编辑页眉页脚的时候,这个时候我们应该怎么做呢,相信别的文件大家都知道怎么编辑了,PDF文件大家都知道吗,最开始接触这个文件的时候小编觉得很难,之后找到技巧之后也并没有很难,今天 ...
- C#word(2007)操作类--新建文档、添加页眉页脚、设置格式、添加文本和超链接、添加图片、表格处理、文档格式转化
转:http://www.cnblogs.com/lantionzy/archive/2009/10/23/1588511.html 1.新建Word文档 #region 新建Word文档/// &l ...
随机推荐
- 用C++实现一个Brainfuck解释器
Brainfuck是一种极小化的计算机语言,只含有8种运算符,由于fuck在英语中是脏话,这种语言有时被称为brainfck或brainf**,甚至被简称为BF.正如它的名字所暗示,brainfuck ...
- Unix domain socket 简介
Unix domain socket 又叫 IPC(inter-process communication 进程间通信) socket,用于实现同一主机上的进程间通信.socket 原本是为网络通讯设 ...
- 网站遭受大量CC攻击后的应对策略
上周开始我网站遭受了一大波CC攻击,到目前为止仍在继续,作为一个建站小白,我感觉压力好大,又有新的问题要挑战了! 服务器架设在腾讯云,CC攻击很凶猛,带宽瞬间占满,于是在腾讯云后台配置安全组关闭了80 ...
- 外网主机访问虚拟机下的web服务器(NAT端口转发)-----端口映射
主机:系统win7,ip地址172.18.186.210 虚拟机:VMware Workstation 7,虚拟机下安装了Centos操作系统,ip地址是192.168.202.128,部署了LAMP ...
- PAT-1003 Emergency(Dijkstra)
1003 Emergency (25 分) As an emergency rescue team leader of a city, you are given a special map of y ...
- [paper]MaskFusion: Real-Time Recognition, Tracking and Reconstruction of Multiple Moving Objects
Before 近期在调研关于RGBD在室内移动机器人下的语义导航的研究.目前帝国理工的Andrew Davison在这边有两个团队在研究,分别是Fusion++ 和 这篇 MaskFusion.这篇是 ...
- 如何理解nexus
理解: Nexus即区块链:分布式部署肯定是构建去中心化网络理所当然的解决方向--通过P2P协议将全世界所有节点计算机彼此相互连接,形成一张密密麻麻的网络:以巧妙的机制,通过节点之间的交易数据同步来保 ...
- twig用法
1. GyAdminBundle::base.html.twig 必须添加Bundle名才可引用模板
- PAT甲题题解-1052. Linked List Sorting (25)-排序
三个注意点: 1.给出的n个节点并不一定都在链表中 2.最后一组样例首地址即为-1 3.输出地址的时候一直忘记前面要补0... #include <iostream> #include & ...
- PAT甲题题解-1117. Eddington Number(25)-(大么个大水题~)
如题,大水题...贴个代码完事,就这么任性~~ #include <iostream> #include <cstdio> #include <algorithm> ...