动态创建新页面时出现 PDFBox 问题
PDFBox issue while creating a new page dynamically
考虑一个 SQL 查询,其结果将写入 pdf。
我可以在 pdf 中成功写入内容(从查询中检索),但如果超过一页的最大限制,它会截断内容。这意味着,只会创建一个页面。
在写入pdf时(通过PDFBox),如何知道我们已经到达页面的末尾,以便我们可以在动态知道我们已经到达终点后触发doc.addPage(page);
页面的。
下面是代码:
public PDDocument processPdf(Class1 objectClass1) {
String text;
int count;
//New Document is created
PDDocument doc = new PDDocument();
List<Class1Questions> objectClass1Questions;
Class2 objectClass2;
try {
float fontSize = 12;
float margin = 72;
float leading = 1.5f * fontSize;
PDFont font = PDType1Font.HELVETICA;
PDPage page = new PDPage();
page.setMediaBox(PDRectangle.A4);
PDRectangle pageSize = page.getMediaBox();
float startX = pageSize.getLowerLeftX() + margin;
float startY = pageSize.getUpperRightY() - margin;
//First page is added
doc.addPage(page);
List<String> lines;
PDPageContentStream contentStream = new PDPageContentStream(doc, page);
contentStream.setFont(font, fontSize);
contentStream.beginText();
//The resultset gets collected and written in PDF.
text = objectClass1.getClass1Name();
lines = spacing(text, margin, font, pageSize);
contentStream.newLineAtOffset(startX, startY);
contentStream.showText("Class1: ");
for (String line : lines) {
contentStream.showText(line);
contentStream.newLineAtOffset(0, -leading);
}
List<Class1Version> versionList = objectClass1.getClass1Versions();
for (Class1Version version : versionList) {
String versionNum = Long.toString(version.getClass1VersionNumber());
contentStream.showText("Version: " + versionNum);
contentStream.newLineAtOffset(0, -leading);
objectClass1Questions = version.getClass1Questions();
count = 0;
for (Class1Questions objectClass1Question : objectClass1Questions) {
count++;
objectClass2 = objectClass1Question.getQuestion();
String question = objectClass2.getQuestionDesc();
lines = spacing(question, margin, font, pageSize);
contentStream.showText("Q" + count + ": ");
for (String line : lines) {
contentStream.showText(line);
contentStream.newLineAtOffset(0, -leading);
}
contentStream.newLineAtOffset(0, -leading);
}
}
contentStream.endText();
contentStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return doc;
}
public List<String> spacing (String text, float margin, PDFont font, PDRectangle pageSize) throws IOException {
int lastSpace = -1;
List<String> lines = new ArrayList<String>();
float fontSize = 25;
float width = pageSize.getWidth() - 2*margin;
while (text.length() > 0)
{
int spaceIndex = text.indexOf(' ', lastSpace + 1);
if (spaceIndex < 0)
spaceIndex = text.length();
String subString = text.substring(0, spaceIndex);
float size = fontSize * font.getStringWidth(subString) / 1000;
System.out.printf("'%s' - %f of %f\n", subString, size, width);
if (size > width)
{
if (lastSpace < 0)
lastSpace = spaceIndex;
subString = text.substring(0, lastSpace);
lines.add(subString);
text = text.substring(lastSpace).trim();
System.out.printf("'%s' is line\n", subString);
lastSpace = -1;
}
else if (spaceIndex == text.length())
{
lines.add(text);
System.out.printf("'%s' is line\n", text);
text = "";
}
else
{
lastSpace = spaceIndex;
}
}
return lines;
}
声明一个totalHeight变量,将其设置为边距高度;
float totalHeight = margin;
获取如下字体高度:
float fontHeight = font.getFontDescriptor().getFontBoundingBox()
.getHeight()
/ 1000 * fontSize;
但它不会return准确的高度,你可以玩玩它以获得更好的效果。
然后获取a4页面大小:
float a4Height= PDRectangle.A4.getHeight();
每次输入新行时增加总高度并检查它是否超过 a4Height 考虑边距高度
totalHeight += fontHeight;
if(totalHeight+margin>=a4Height){
page = new PDPage();
doc.addPage(page);
totalHeight = margin;
}
我尝试了@AhmetRasitBekar 给出的解决方案和@mkl 评论中提到的解决方案。
- 引入一个变量,在其中记下当前的 y 坐标,
将其设置为 startY。将变量视为
yCordinate
.
计算字体高度
float fontHeight = font.getFontDescriptor().getFontBoundingBox().getHeight() / 1000 * fontSize;
每次将文本内容写入pdf文件时,变量
yCordinate
将减少 fontHeight
。
contentStream.showText(line);
yCordinate -= fontHeight;
每增加一行,yCordinate
就减少
leading
contentStream.newLineAtOffset(0, -leading);
yCordinate -= leading;
- 每次访问和更改
yCordinate
时,一个条件
写语句检查是否yCordinate <= 10
。如果
是的,然后是下面的代码。
if(yCordinate <= 10){
page = new PDPage(); //new page created
page.setMediaBox(PDRectangle.A4);
pageSize = page.getMediaBox();
startX = pageSize.getLowerLeftX() + margin; //Calculate the X and Y cordinate
startY = pageSize.getUpperRightY() - margin;
doc.addPage(page); //Add the page to the PDDocument
yCordinate = startY; //Reset the yCordinate with the new Y cordinate
contentStream.endText(); //End and Close the previous contentStream
contentStream.close();
contentStream = new PDPageContentStream(doc, page); //Create a new contentStream and use it further
contentStream.setFont(font, fontSize);
contentStream.beginText();
contentStream.newLineAtOffset(startX, startY);
}
如果内容超过 PDF 页面限制,这将在 pdf 中动态创建页面。
考虑一个 SQL 查询,其结果将写入 pdf。
我可以在 pdf 中成功写入内容(从查询中检索),但如果超过一页的最大限制,它会截断内容。这意味着,只会创建一个页面。
在写入pdf时(通过PDFBox),如何知道我们已经到达页面的末尾,以便我们可以在动态知道我们已经到达终点后触发doc.addPage(page);
页面的。
下面是代码:
public PDDocument processPdf(Class1 objectClass1) {
String text;
int count;
//New Document is created
PDDocument doc = new PDDocument();
List<Class1Questions> objectClass1Questions;
Class2 objectClass2;
try {
float fontSize = 12;
float margin = 72;
float leading = 1.5f * fontSize;
PDFont font = PDType1Font.HELVETICA;
PDPage page = new PDPage();
page.setMediaBox(PDRectangle.A4);
PDRectangle pageSize = page.getMediaBox();
float startX = pageSize.getLowerLeftX() + margin;
float startY = pageSize.getUpperRightY() - margin;
//First page is added
doc.addPage(page);
List<String> lines;
PDPageContentStream contentStream = new PDPageContentStream(doc, page);
contentStream.setFont(font, fontSize);
contentStream.beginText();
//The resultset gets collected and written in PDF.
text = objectClass1.getClass1Name();
lines = spacing(text, margin, font, pageSize);
contentStream.newLineAtOffset(startX, startY);
contentStream.showText("Class1: ");
for (String line : lines) {
contentStream.showText(line);
contentStream.newLineAtOffset(0, -leading);
}
List<Class1Version> versionList = objectClass1.getClass1Versions();
for (Class1Version version : versionList) {
String versionNum = Long.toString(version.getClass1VersionNumber());
contentStream.showText("Version: " + versionNum);
contentStream.newLineAtOffset(0, -leading);
objectClass1Questions = version.getClass1Questions();
count = 0;
for (Class1Questions objectClass1Question : objectClass1Questions) {
count++;
objectClass2 = objectClass1Question.getQuestion();
String question = objectClass2.getQuestionDesc();
lines = spacing(question, margin, font, pageSize);
contentStream.showText("Q" + count + ": ");
for (String line : lines) {
contentStream.showText(line);
contentStream.newLineAtOffset(0, -leading);
}
contentStream.newLineAtOffset(0, -leading);
}
}
contentStream.endText();
contentStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return doc;
}
public List<String> spacing (String text, float margin, PDFont font, PDRectangle pageSize) throws IOException {
int lastSpace = -1;
List<String> lines = new ArrayList<String>();
float fontSize = 25;
float width = pageSize.getWidth() - 2*margin;
while (text.length() > 0)
{
int spaceIndex = text.indexOf(' ', lastSpace + 1);
if (spaceIndex < 0)
spaceIndex = text.length();
String subString = text.substring(0, spaceIndex);
float size = fontSize * font.getStringWidth(subString) / 1000;
System.out.printf("'%s' - %f of %f\n", subString, size, width);
if (size > width)
{
if (lastSpace < 0)
lastSpace = spaceIndex;
subString = text.substring(0, lastSpace);
lines.add(subString);
text = text.substring(lastSpace).trim();
System.out.printf("'%s' is line\n", subString);
lastSpace = -1;
}
else if (spaceIndex == text.length())
{
lines.add(text);
System.out.printf("'%s' is line\n", text);
text = "";
}
else
{
lastSpace = spaceIndex;
}
}
return lines;
}
声明一个totalHeight变量,将其设置为边距高度;
float totalHeight = margin;
获取如下字体高度:
float fontHeight = font.getFontDescriptor().getFontBoundingBox()
.getHeight()
/ 1000 * fontSize;
但它不会return准确的高度,你可以玩玩它以获得更好的效果。 然后获取a4页面大小:
float a4Height= PDRectangle.A4.getHeight();
每次输入新行时增加总高度并检查它是否超过 a4Height 考虑边距高度
totalHeight += fontHeight;
if(totalHeight+margin>=a4Height){
page = new PDPage();
doc.addPage(page);
totalHeight = margin;
}
我尝试了@AhmetRasitBekar 给出的解决方案和@mkl 评论中提到的解决方案。
- 引入一个变量,在其中记下当前的 y 坐标,
将其设置为 startY。将变量视为
yCordinate
. 计算字体高度
float fontHeight = font.getFontDescriptor().getFontBoundingBox().getHeight() / 1000 * fontSize;
每次将文本内容写入pdf文件时,变量
yCordinate
将减少fontHeight
。contentStream.showText(line); yCordinate -= fontHeight;
每增加一行,
yCordinate
就减少leading
contentStream.newLineAtOffset(0, -leading);
yCordinate -= leading;
- 每次访问和更改
yCordinate
时,一个条件 写语句检查是否yCordinate <= 10
。如果 是的,然后是下面的代码。
if(yCordinate <= 10){ page = new PDPage(); //new page created page.setMediaBox(PDRectangle.A4); pageSize = page.getMediaBox(); startX = pageSize.getLowerLeftX() + margin; //Calculate the X and Y cordinate startY = pageSize.getUpperRightY() - margin; doc.addPage(page); //Add the page to the PDDocument yCordinate = startY; //Reset the yCordinate with the new Y cordinate contentStream.endText(); //End and Close the previous contentStream contentStream.close(); contentStream = new PDPageContentStream(doc, page); //Create a new contentStream and use it further contentStream.setFont(font, fontSize); contentStream.beginText(); contentStream.newLineAtOffset(startX, startY); }
如果内容超过 PDF 页面限制,这将在 pdf 中动态创建页面。