使用PDFBox动态添加pdf页面



当内容超过页面限制时,我尝试动态添加pdf页面。它给出了这个错误。请查看下面的代码并帮助我找到解决方案。

{线程中的异常";主";java.lang.IollegalStateException:错误:在调用endText之前必须调用beginText((。网址:org.apache.pdfbox.pdmodel.PDPageContentStream.endText(PDPageContentStream.java:385(在PDFUtility.content(PDFUtility.java:123(位于StudyConfigImpl.getStudyConfigPDF(StudyConfigImpl.java:39(在Main.Main(Main.java:6(}

private float addParagraph(PDPageContentStream contentStream, float width, float sx,
float sy, String text, boolean justify,float initY,float pageHeight,PDDocument document) throws IOException {
PDFont FONT = PDType1Font.HELVETICA;
float FONT_SIZE = 7;
float LEADING = -1.5f * FONT_SIZE;
java.util.List<String> lines = parseLines(text, width);
contentStream.setFont(FONT, FONT_SIZE);
contentStream.newLineAtOffset(sx, sy);
float totalHeight = initY;
for (String line: lines) {
float charSpacing = 0;
if (justify){
if (line.length() > 1) {
float size = FONT_SIZE * FONT.getStringWidth(line) / 1000;
float free = width - size;
if (free > 0 && !lines.get(lines.size() - 1).equals(line)) {
charSpacing = free / (line.length() - 1);
}
}
}
contentStream.setCharacterSpacing(charSpacing);
float fontHeight = FONT.getFontDescriptor().getFontBoundingBox().getHeight() / 1000*FONT_SIZE;
totalHeight -=fontHeight;
System.out.println(totalHeight);
if(totalHeight - StudyConfigImpl.PAGE_MARGIN <= 0){
PDPage nextPage = new PDPage();
nextPage.setMediaBox(PDRectangle.A4);
document.addPage(nextPage);
totalHeight = pageHeight - StudyConfigImpl.PAGE_MARGIN;
contentStream.endText();
contentStream.close();
contentStream = new PDPageContentStream(document,nextPage);
contentStream.beginText();
contentStream.setFont(FONT,FONT_SIZE);
contentStream.newLineAtOffset(StudyConfigImpl.INIT_POSITION_X,StudyConfigImpl.INIT_POSITION_Y);
}
contentStream.showText(line);
contentStream.newLineAtOffset(0, LEADING);
}
return (lines.size()*(7+3));
}


public float content(
PDPageContentStream contentStream,
float initX,
float initY,
float pageHeight,
float width,
float height,
Map<Object, Object> studyData,
PDDocument document
) throws IOException {
int counter = 0;
for(Map.Entry<Object, Object> entry : studyData.entrySet()){
if(entry.getKey().equals("Additional Notes") || entry.getKey().equals("Study Desc.")){
initY-=25;
contentStream.setFont(PDType1Font.HELVETICA_BOLD,7);
contentStream.beginText();
initX = 20;
contentStream.newLineAtOffset(initX,initY);
contentStream.showText(entry.getKey().toString());
float sy = addParagraph(contentStream,555,0,-10,entry.getValue().toString(),true,initY,pageHeight,document);
contentStream.endText();
initY -=sy;
}else{
contentStream.addRect(initX, pageHeight - initY, width, height);
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 7);
contentStream.beginText();
contentStream.newLineAtOffset(initX, initY);
contentStream.showText(entry.getKey().toString());
contentStream.newLine();
contentStream.setFont(PDType1Font.HELVETICA, 7);
contentStream.showText(entry.getValue().toString());
contentStream.endText();
initX += width;
counter++;
if (counter == 5) {
initX = 20;
initY = initY - 20;
counter = 0;
}
}
}
return  initY;
}

原因

addParagraph()中,您有条件地将新的PDPageContentStream分配给contentStream,但此新值不会返回给调用方content():

private float addParagraph(PDPageContentStream contentStream, float width, float sx, float sy, String text, boolean justify, float initY, float pageHeight, PDDocument document) throws IOException {
...
contentStream.endText();
contentStream.close();
contentStream = new PDPageContentStream(document,nextPage);
contentStream.beginText();
...
return (lines.size()*(7+3));
}

在重新分配contentStream之前,您特别要为旧流调用endText()

因此,content((继续处理旧的内容流,并再次为其调用endText()

public float content(PDPageContentStream contentStream, float initX, float initY, float pageHeight, float width, float height, Map<Object, Object> studyData, PDDocument document) throws IOException {
...
float sy = addParagraph(contentStream,555,0,-10,entry.getValue().toString(),true,initY,pageHeight,document);
contentStream.endText();
...
return  initY;
}

为没有打开文本对象的内容流调用endText会触发您观察到的异常。

一个变通办法

addParagraphcontent似乎都是同一类的方法(或者至少在其中一个派生自另一个的两个类中(。因此,您可以将contentStream作为该类的成员变量,而不是将其作为参数转发:

public class PDFUtility {
public PDPageContentStream contentStream = null;
private float addParagraph(float width, float sx, float sy, String text, boolean justify, float initY, float pageHeight, PDDocument document) throws IOException {
...
}
public float content(float initX, float initY, float pageHeight, float width, float height, Map<Object, Object> studyData, PDDocument document) throws IOException {
...
}
...
}

并且在CCD_ 12中而不是中

float y = pdfUtility.content(contentStream, initX, ...);

你做

pdfUtility.contentStream = contentStream;
float y = pdfUtility.content(initX, ...);
contentStream = pdfUtility.contentStream;

这种解决方法显然要求类的同一实例不能从不同的线程中同时使用。

最新更新