我正在使用iText7复制pdf页面,并对这些页面进行编号。所以我不需要手动给它们编号。但是生成的pdf文件中的数字有问题。下面是它的样子:
我想了好几个小时,还是想不出来。
我的代码:
import com.itextpdf.io.font.FontConstants;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import java.io.File;
import java.io.IOException;
public class NumberingInJava {
public static final String SRC = "D:/temp/num_src.pdf";
public static final String DEST = "D:/temp/edited_numbering.pdf";
public static final String[] NUM4SAMPLE = {"02A", "03A", "03B", "03C", "04A", "08A"};
public static final double XCOOR = 230;
public static final double YCOOR = 795;//755
public static void main(String[] args) throws IOException {
File file = new File(DEST);
file.getParentFile().mkdirs();
new NumberingInJava().manipulatePdf(SRC, DEST, NUM4SAMPLE);
}
private void manipulatePdf(String src, String dest, String[] numbering4what) throws IOException {
//Initialize PDF document
PdfDocument pdfDocToRead = new PdfDocument(new PdfReader(src));
PdfDocument pdfDocToWrite = new PdfDocument(new PdfWriter(dest));
for(String s : numbering4what) {
println(s);
}
String number = null;
PdfPage tempPage = null;
for (int i=0; i<numbering4what.length; i++) {
pdfDocToRead.copyPagesTo(1, 2, pdfDocToWrite);
number = numbering4what[i];
println(number);
tempPage = pdfDocToWrite.getPage(2*(i+1)-1);
numberingPage(tempPage, number);
println("pdfDocToWrite.numberOfPages : "+pdfDocToWrite.getNumberOfPages());
}
pdfDocToRead.close();
pdfDocToWrite.close();
println("\nNumber added!");
}
private void numberingPage(PdfPage pdfPage, String number) throws IOException {
println(pdfPage);
PdfCanvas canvas = new PdfCanvas(pdfPage);
canvas.beginText().setFontAndSize(PdfFontFactory.createFont(FontConstants.HELVETICA), 22)
.moveText(XCOOR, YCOOR)
.showText(number)
.endText();
println("number: "+number);
}
private void println(Object obj) {
System.out.println(obj);
}
}
02A 03A 03B 03C 04A 08A 02A com.itextpdf.kernel.pdf.PdfPage@cf768c 17:58:07,457 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy] 17:58:07,458 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml] 17:58:07,458 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback.xml] at [jar:file:/D:/Java_Packages/ext_lib/iText/itext7-7.0.1/itext7-itext-rups-7.0.1.jar!/logback.xml] 17:58:07,459 |-WARN in ch.qos.logback.classic.LoggerContext[default] - Resource [logback.xml] occurs multiple times on the classpath. 17:58:07,459 |-WARN in ch.qos.logback.classic.LoggerContext[default] - Resource [logback.xml] occurs at [jar:file:/D:/Java_Packages/ext_lib/iText/itext7-7.0.1/itext7-itext-rups-7.0.1-jar-with-dependencies.jar!/logback.xml] 17:58:07,459 |-WARN in ch.qos.logback.classic.LoggerContext[default] - Resource [logback.xml] occurs at [jar:file:/D:/Java_Packages/ext_lib/iText/itext7-7.0.1/itext7-itext-rups-7.0.1-sources.jar!/logback.xml] 17:58:07,459 |-WARN in ch.qos.logback.classic.LoggerContext[default] - Resource [logback.xml] occurs at [jar:file:/D:/Java_Packages/ext_lib/iText/itext7-7.0.1/itext7-itext-rups-7.0.1.jar!/logback.xml] 17:58:07,501 |-INFO in ch.qos.logback.core.joran.spi.ConfigurationWatchList@8080bb - URL [jar:file:/D:/Java_Packages/ext_lib/iText/itext7-7.0.1/itext7-itext-rups-7.0.1.jar!/logback.xml] is not of type file 17:58:07,662 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - debug attribute not set 17:58:07,829 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [com.itextpdf.rups.view.DebugAppender] 17:58:07,851 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [DEFAULT_APP] 17:58:07,940 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property 17:58:08,045 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [com.itextpdf.rups.view.StyleAppender] 17:58:08,046 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [INFO_APP] 17:58:08,062 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property 17:58:08,063 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [com.itextpdf.rups.view.DebugAppender] 17:58:08,063 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [DEBUG_APP] 17:58:08,065 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property 17:58:08,066 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [com.itextpdf.rups.view.DebugAppender] 17:58:08,066 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [TRACE_APP] 17:58:08,067 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property 17:58:08,069 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [com.itextpdf.rups.view.StyleAppender] 17:58:08,069 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [IMPORTANT_APP] 17:58:08,075 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property 17:58:08,076 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting additivity of logger [com.itextpdf] to false 17:58:08,077 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [IMPORTANT_APP] to Logger[com.itextpdf] 17:58:08,078 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [INFO_APP] to Logger[com.itextpdf] 17:58:08,078 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [DEBUG_APP] to Logger[com.itextpdf] 17:58:08,078 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [TRACE_APP] to Logger[com.itextpdf] 17:58:08,078 |-INFO in ch.qos.logback.classic.joran.action.RootLoggerAction - Setting level of ROOT logger to TRACE 17:58:08,078 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [DEFAULT_APP] to Logger[ROOT] 17:58:08,078 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - End of configuration. 17:58:08,082 |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@1c24521 - Registering current configuration as safe fallback point编辑模拟文档
该问题是由于iText试图使结果PDF变小而引起的:
当将pdfdoctoRead
的页面多次复制到pdfdoctoWrite
时,实际的页面内容流、页面资源等只复制一次,仅为每个副本和页面生成一个引用这些数据的小对象。
这个优化还不是问题所在,但进一步的微观优化是,在
PdfCanvas canvas = new PdfCanvas(pdfPage);
此pdfcanvas
帮助器方法用于检索将向其添加内容的内容流:
private static PdfStream getPageStream(PdfPage page) {
PdfStream stream = page.getContentStream(page.getContentStreamCount() - 1);
return stream == null || stream.getOutputStream() == null || stream.containsKey(PdfName.Filter) ? page.newContentStreamAfter() : stream;
}
如您所见,通常会向页面添加新的内容流(page.newContentStreamAfter()
);只有当已经存在一个内容流并且该流没有过滤器(例如用于压缩)时,才使用这个现有的内容流来追加数据。
对于文档,不压缩为每个源页复制的单个内容流。因此,这两个优化导致所有PDFCanvas Canvas
实例都追加到同一个内容流中。
PdfCanvas canvas = new PdfCanvas(pdfPage);
PdfCanvas canvas = new PdfCanvas(pdfPage.newContentStreamAfter(), pdfPage.getResources(), pdfPage.getDocument());
如果原始内容流被压缩,这实际上也会发生。
(通常,您可能需要在当前内容之前添加一个新的内容流,并使用save-graphics-state指令,然后在当前内容之后向新的内容流添加一个restore-graphics-state指令;但是,对于html" target="_blank">示例文档来说,这并不是必需的,因为当前内容不会对图形状态产生不利影响。)
主要内容:示例可以使用类的方法将文本添加到图像。 以下是此方法的语法。 该方法接受以下参数 - mat - 表示要在其上绘制矩形的图像的对象。 text - 表示要添加的文本的字符串变量。 org - 表示图像中左下角文本字符串的对象。 fontFace - 表示字体类型的整型变量。 fontScale - 类型为的变量表示与字体特定的基本大小相乘的缩放因子。 color - 表示矩形颜色的标量对象(BGR)。
在上一章中,我们讨论了如何将页面添加到PDF文档中。 在本章中,我们将讨论如何向现有PDF文档添加文本。 将文本添加到现有PDF文档 您可以使用PDFBox库向文档添加内容,这为您提供了一个名为PDPageContentStream的类,其中包含在PDFDocument的页面中插入文本,图像和其他类型内容所需的方法。 以下是创建空文档并向其中的页面添加内容的步骤。 第1步:加载现有文档 您可以使用
文本标签通常用于帮助记录仪表板,例如添加仪表板标题、URL 链接。 添加一个文本标签 在仪表板选项卡中,点击 “添加文本”。 将其放在仪表板上。 输入标题。 属性 文本标签的可用属性: 选项 描述 位置 自定义标签的位置。 大小 自定义标签的大小。 标题 输入标签的标题。 对齐方式 指定标签标题的文本对齐方式。 字体 设置标签标题的字体样式。 粗体 将粗体样式应用于标签标题。 斜体 将斜体样式应用
文本标签通常用于帮助记录仪表板,例如添加仪表板标题、URL 链接。 添加一个文本标签 在仪表板选项卡中,点击 。 将其放在仪表板上。 输入标题。 属性 文本标签的可用属性: 选项 描述 位置 自定义标签的位置。 大小 自定义标签的大小。 标题 输入标签的标题。 对齐方式 指定标签标题的文本对齐方式。 字体 设置标签标题的字体样式。 粗体 将粗体样式应用于标签标题。 斜体 将斜体样式应用于标签标题。
文本标签通常用于帮助记录仪表板,例如添加仪表板标题、URL 链接。 添加一个文本标签 在仪表板选项卡中,点击 “添加文本”。 将其放在仪表板上。 输入标题。 属性 文本标签的可用属性: 选项 描述 位置 自定义标签的位置。 大小 自定义标签的大小。 标题 输入标签的标题。 对齐方式 指定标签标题的文本对齐方式。 字体 设置标签标题的字体样式。 粗体 将粗体样式应用于标签标题。 斜体 将斜体样式应用
接口说明 为当前位置设置描述信息、备注信息等,以更好的了解当前位置的基本概况,可以调用该接口来设置相关的信息说明 如需调用,请访问 开发者文档 来查看详细的接口使用说明 该接口仅开放给已获取SDK的开发者 API地址 POST /api/marker/1.0.0/addTabTxt 是否需要登录 是 请求字段说明 参数 类型 请求类型 是否必须 说明 mId string form 是 标注ID