itext7 生成pdf操作过于复杂,特别是封面、目录页码以及页眉页脚的处理需要基于事件处理,因此写了个简单的类库用于简化操作,只用关注文档内容的构建而无需关注其他;
代码地址: https://gitee.com/zherc/itext7-simple
maven依赖
<dependency>
<groupId>io.gitee.zherc</groupId>
<artifactId>itext7-simple</artifactId>
<version>0.0.1</version>
</dependency>
渲染顺序为 内容>目录>封面
public class TestPdfRender implements PdfRender {
/**
* 渲染封面
* @param document 文档对象
*/
@Override
public void cover(ItextDocument document) {
try {
Div div = new Div();
div.setDestination("cover");
div.add(new Paragraph("封面").setFontColor(Color.parse("#FFFFFF")));
div.setWidth(document.getPageWidth());
div.setHeight(document.getPageHeight());
PdfImageXObject imageXObject = new PdfImageXObject(ImageDataFactory.create(new URL("https://zhiper-cdn.oss-cn-shanghai.aliyuncs.com/2051961.jpg")));
BackgroundImage image = new BackgroundImage(imageXObject);
div.setProperty(Property.BACKGROUND_IMAGE, image);
Table table = new Table(4);
table.setBorder(Border.NO_BORDER);
table.addHeaderCell("标题一");
table.addHeaderCell("标题二");
table.addHeaderCell("标题三");
table.addHeaderCell("标题四");
div.add(table);
document.add(div);
} catch (Exception e) {
}
PdfOutline outlines = document.getPdfDocument().getOutlines(true);
outlines.addOutline("封面", 0).addDestination(PdfDestination.makeDestination(new PdfString("cover")));
}
/**
* 渲染目录
* @param document 文档对象
*/
@Override
public void directory(ItextDocument document) {
Div div = new Div();
div.add(new Paragraph("目录").setDestination("directory").setHorizontalAlignment(HorizontalAlignment.CENTER));
ItextPdfDocument itextPdfDocument = document.getItextPdfDocument();
itextPdfDocument.eachCatalog(catalog -> {
Link link = new Link(catalog.getTitle(), PdfAction.createGoTo(catalog.getCode()));
Paragraph paragraph = new Paragraph(link);
paragraph.add("......................")
.add(catalog.getPageNumber() + "")
.setFirstLineIndent(10 * (1 - catalog.getLevel()));
div.add(paragraph);
});
PdfOutline outlines = document.getPdfDocument().getOutlines(true);
outlines.addOutline("目录", 0)
.addDestination(PdfDestination.makeDestination(new PdfString("directory")));
document.add(div);
}
/**
* 渲染页眉
* @param header 页眉对象
*/
@Override
public void header(Header header) {
try {
Table table = new Table(1);
table.setBorder(Border.NO_BORDER);
Cell cell = new Cell();
cell.setTextAlignment(TextAlignment.CENTER);
Paragraph paragraph = new Paragraph("页眉" + header.getPageNumber());
cell.setVerticalAlignment(VerticalAlignment.MIDDLE);
paragraph.setBackgroundColor(Color.parse("#d0d0d0"));
cell.add(paragraph);
table.addCell(cell);
header.layout(table);
} catch (Exception e) {
e.printStackTrace();
}
// header.addText(new Text(Point.build(0, 0), "页眉" + header.getPageNumber()).centered());
}
/**
* 渲染页脚
* @param footer 页脚对象
*/
@Override
public void footer(Footer footer) {
// footer.addText(new Text(Point.build(0, 0), "第" + footer.getPageNumber() + "页")
// .style(new FontStyle(10)).align(HorizontalAlign.CENTER, VerticalAlign.MIDDLE));
Table table = new Table(3);
table.setBorderTop(new SolidBorder(Color.parse("#EEEEEE"), 2f));
table.addCell(new Cell().setBorder(Border.NO_BORDER).add(new Paragraph("左边")).setTextAlignment(TextAlignment.LEFT));
table.addCell(new Cell().setBorder(Border.NO_BORDER).add(new Paragraph("第" + footer.getPageNumber() + "页")).setTextAlignment(TextAlignment.CENTER));
table.addCell(new Cell().setBorder(Border.NO_BORDER).add(new Paragraph("右边")).setTextAlignment(TextAlignment.RIGHT));
footer.layout(table);
}
/**
* 渲染文档内容
* @param document 文档对象
*/
@SneakyThrows
@Override
public void body(ItextDocument document) {
ItextPdfDocument pdfDocument = document.getItextPdfDocument();
for (int i = 0; i < 10; i++) {
String title = "第" + i + "部分内容";
// 添加目录
H1 h1 = new H1(title);
Catalog catalog = pdfDocument.addCatalog(h1, title);
// 添加书签
pdfDocument.addBookmark(h1, catalog.getCode());
document.add(new Div().add(h1));
Div div = new Div();
Table table = new Table(6);
table.setBorder(Border.NO_BORDER);
table.addHeaderCell("标题一");
table.addHeaderCell("标题二");
table.addHeaderCell("标题三");
table.addHeaderCell("标题四");
table.addHeaderCell("标题五");
table.addHeaderCell("标题六");
for (int j = 0; j < 360; j++) {
Cell cell = new Cell();
cell.setBorder(Border.NO_BORDER);
cell.add(new Paragraph("表格"));
table.addCell(cell);
}
table.setWidth(document.getWidth());
table.setHorizontalAlignment(HorizontalAlignment.CENTER);
div.add(table);
String secondTitle = title + "二级书签";
H2 h2 = new H2(secondTitle);
Catalog secCatalog = pdfDocument.addCatalog(h2);
div.add(h2);
pdfDocument.addBookmark(h2, secCatalog.getCode());
Rect bodyRect = document.getBodyRect();
// canvas绘图
Rectangle boundingBox = new Rectangle(0,0, bodyRect.getWidth(),200);
PdfFormXObject xObject = new PdfFormXObject(boundingBox);
xObject.makeIndirect(pdfDocument);//Make sure the XObject gets added to the document
PDFCanvas pCanvas = new PDFCanvas(xObject, pdfDocument);//Create a canvas from the XObject
pCanvas.text(Point.build(60, 60), "吃个桃桃", "#d3d3d3", 12);
pCanvas.rectangle(Point.build(20, 20), 30, 30).setFillColor(Color.BLUE).fill();
// Canvas canvas = new Canvas(xObject, pdfDocument);//Create a canvas from the XObject
// canvas.setRenderer(new CanvasRenderer(canvas){
// @Override
// public void addChild(IRenderer renderer) {
// super.addChild(renderer);
// }
// });
pCanvas.draw(canvas -> {
canvas.setFontColor(Color.RED);
canvas.showTextAligned("吃个桃桃好凉凉", 200, 100, TextAlignment.LEFT, 90);
});
pCanvas.text(Point.build(60, 80), "一个小桃子", "#d3d3d3", 12);
Image rect = new Image(xObject);
// rect.setAutoScale(true);
// rect.setBackgroundColor(Color.parse("#000000"));
div.add(rect);
// div.add(rect);
document.add(div);
/**
* 将文本放置在指定位置并旋转角度
*/
document.showTextAligned("吃个桃桃好凉凉0", 90, 90, TextAlignment.LEFT);
document.showTextAligned("吃个桃桃好凉凉30", 90, 90, TextAlignment.LEFT, 30);
document.showTextAligned("吃个桃桃好凉凉60", 90, 90, TextAlignment.LEFT, 60);
document.showTextAligned("吃个桃桃好凉凉90", 90, 90, TextAlignment.LEFT, 90);
document.showTextAlignedKerned("吃个桃桃好凉凉120", 90, 90, TextAlignment.LEFT, VerticalAlignment.MIDDLE, 120);
// document.add(SvgUtil.convert(svg, pdfDocument).setHorizontalAlignment(HorizontalAlignment.CENTER));
// PdfPage page = pdfDocument.getPage(pdfDocument.getNumberOfPages());
// Canvas canvas = new Canvas(page);
// canvas.circle(Point.build(200, 400), 100).setFillColor(Color.parse("#EEEEEE")).fill();
// canvas.beginText().setFontAndSize(pdfDocument.getDefaultFont(), 12).setTextRise(120).showText("中文").endText();
if (i < 9) document.nextPage();
}
}
}
class Generate{
public static final String output = System.getProperty("user.dir") + "\\test.pdf";
public static final String font = System.getProperty("user.dir") + "\\msyh.ttf";
public void setup(){
// 设置输出文件以及字体
PdfSetup setup = new PdfSetup(output, font);
// 是否需要目录
setup.setDirectory(true);
// 是否需要封面
setup.setCover(true);
// 是否需要页脚
setup.setFooter(true);
// 是否需要页眉
setup.setHeader(true);
// 根据渲染器以及PDF设置生成PDF
Itext7Pdf.getPdf(new TestPdfRender(), setup).write();
}
}
文章浏览阅读1k次。通过使用ajax方法跨域请求是浏览器所不允许的,浏览器出于安全考虑是禁止的。警告信息如下:不过jQuery对跨域问题也有解决方案,使用jsonp的方式解决,方法如下:$.ajax({ async:false, url: 'http://www.mysite.com/demo.do', // 跨域URL ty..._nginx不停的xhr
文章浏览阅读2k次。关于在 Oracle 中配置 extproc 以访问 ST_Geometry,也就是我们所说的 使用空间SQL 的方法,官方文档链接如下。http://desktop.arcgis.com/zh-cn/arcmap/latest/manage-data/gdbs-in-oracle/configure-oracle-extproc.htm其实简单总结一下,主要就分为以下几个步骤。..._extproc
文章浏览阅读1.5w次。linux下没有上面的两个函数,需要使用函数 mbstowcs和wcstombsmbstowcs将多字节编码转换为宽字节编码wcstombs将宽字节编码转换为多字节编码这两个函数,转换过程中受到系统编码类型的影响,需要通过设置来设定转换前和转换后的编码类型。通过函数setlocale进行系统编码的设置。linux下输入命名locale -a查看系统支持的编码_linux c++ gbk->utf8
文章浏览阅读750次。今天准备从生产库向测试库进行数据导入,结果在imp导入的时候遇到“ IMP-00009:导出文件异常结束” 错误,google一下,发现可能有如下原因导致imp的数据太大,没有写buffer和commit两个数据库字符集不同从低版本exp的dmp文件,向高版本imp导出的dmp文件出错传输dmp文件时,文件损坏解决办法:imp时指定..._imp-00009导出文件异常结束
文章浏览阅读143次。当下是一个大数据的时代,各个行业都离不开数据的支持。因此,网络爬虫就应运而生。网络爬虫当下最为火热的是Python,Python开发爬虫相对简单,而且功能库相当完善,力压众多开发语言。本次教程我们爬取前程无忧的招聘信息来分析Python程序员需要掌握那些编程技术。首先在谷歌浏览器打开前程无忧的首页,按F12打开浏览器的开发者工具。浏览器开发者工具是用于捕捉网站的请求信息,通过分析请求信息可以了解请..._初级python程序员能力要求
文章浏览阅读7.6k次,点赞2次,收藏6次。@Service标注的bean,类名:ABDemoService查看源码后发现,原来是经过一个特殊处理:当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致public class AnnotationBeanNameGenerator implements BeanNameGenerator { private static final String C..._@service beanname
文章浏览阅读6.9w次,点赞73次,收藏463次。1.前序创建#include<stdio.h>#include<string.h>#include<stdlib.h>#include<malloc.h>#include<iostream>#include<stack>#include<queue>using namespace std;typed_二叉树的建立
文章浏览阅读7.1k次。在Asp.net上使用Excel导出功能,如果文件名出现中文,便会以乱码视之。 解决方法: fileName = HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8);_asp.net utf8 导出中文字符乱码
文章浏览阅读2.1k次,点赞4次,收藏23次。第一次实验 词法分析实验报告设计思想词法分析的主要任务是根据文法的词汇表以及对应约定的编码进行一定的识别,找出文件中所有的合法的单词,并给出一定的信息作为最后的结果,用于后续语法分析程序的使用;本实验针对 PL/0 语言 的文法、词汇表编写一个词法分析程序,对于每个单词根据词汇表输出: (单词种类, 单词的值) 二元对。词汇表:种别编码单词符号助记符0beginb..._对pl/0作以下修改扩充。增加单词
文章浏览阅读773次。我在使用adb.exe时遇到了麻烦.我想使用与bash相同的adb.exe shell提示符,所以我决定更改默认的bash二进制文件(当然二进制文件是交叉编译的,一切都很完美)更改bash二进制文件遵循以下顺序> adb remount> adb push bash / system / bin /> adb shell> cd / system / bin> chm..._adb shell mv 权限
文章浏览阅读6.8k次,点赞12次,收藏125次。1. 单目相机标定引言相机标定已经研究多年,标定的算法可以分为基于摄影测量的标定和自标定。其中,应用最为广泛的还是张正友标定法。这是一种简单灵活、高鲁棒性、低成本的相机标定算法。仅需要一台相机和一块平面标定板构建相机标定系统,在标定过程中,相机拍摄多个角度下(至少两个角度,推荐10~20个角度)的标定板图像(相机和标定板都可以移动),即可对相机的内外参数进行标定。下面介绍张氏标定法(以下也这么称呼)的原理。原理相机模型和单应矩阵相机标定,就是对相机的内外参数进行计算的过程,从而得到物体到图像的投影_相机-投影仪标定
文章浏览阅读2.2k次。文章目录Wayland 架构Wayland 渲染Wayland的 硬件支持简 述: 翻译一篇关于和 wayland 有关的技术文章, 其英文标题为Wayland Architecture .Wayland 架构若是想要更好的理解 Wayland 架构及其与 X (X11 or X Window System) 结构;一种很好的方法是将事件从输入设备就开始跟踪, 查看期间所有的屏幕上出现的变化。这就是我们现在对 X 的理解。 内核是从一个输入设备中获取一个事件,并通过 evdev 输入_wayland