I am trying to generate a PDF based on data passed in through an object using Apache PDFBox. Since there's a variable amount of data I use a variable called volY
to keep track of the y position to write the information. if volY
is greater than 700, I close the Content stream I'm writing to, generate a new page and a new content stream, and start writing to a new page. The methods I use to write to the pdf return an integer which represents the height of the string, which I add to volY
. For some reason when I try to access volY when iterating through the elements I get a null pointer exception.
Here is my code to generate the PDF:
public void generateSection(PDPage startingPage, PDPageContentStream cs, List<TestSection> sections) throws IOException {
/*
* TODO
* verify list sequence integrity and reorder if not valid.
*/
int volY = 350;
PDPage page = startingPage;
PDPageContentStream vcs = cs;
// Iterate through sections
for(int i = 0; i < sections.size(); i++) {
if(volY > 700) {
vcs.close();
page = createPage();
vcs = new PDPageContentStream(pd, page);
volY = 50;
}
if(sections.get(i).isUrgent())
cs.setNonStrokingColor(URGENT);
drawString(sections.get(i).getType().getName(), 60, volY, vcs, page, 18);
cs.setNonStrokingColor(REGULAR_TEXT);
drawLine(vcs, 60, flipY(page, volY+8), 560);
volY += 30;
// Iterate through Items in section
TestSection s = sections.get(i);
for(int y = 0; y < s.getElements().size(); y++ ) {
TestReportElement re = s.getElements().get(y);
TestSubSection subSection = (TestSubSection)re;
volY++;
drawHeader(re.getTitle(), "a", volY, page, vcs);
for(int z = 0; z < subSection.getItems().size(); z++) {
//volY doesn't exist here for some reason? At the very least it's not modifiable.
if(vcs == null) {
System.err.println("VCS IS NULL");
System.exit(3);
}
TestInspectionItem ti = subSection.getItems().get(z);
vcs.setNonStrokingColor(BOLD_TEXT);
System.out.println(volY);
drawMultipleStrings(ti.getPrompt(), volY, vcs, page, z);
vcs.setNonStrokingColor(REGULAR_TEXT);
for(int z1 = 0; z1 < ti.getResponses().size(); z1++) {
if (volY > 700) {
vcs.close();
page = createPage();
vcs = new PDPageContentStream(pd, page);
volY = 50;
}
String text = ti.getResponses().get(z1);
drawMultipleStrings(text, volY+15, vcs, page, z1);
}
if (volY > 700) {
vcs.close();
page = createPage();
vcs = new PDPageContentStream(pd, page);
volY = 50;
}
}
if (volY > 700) {
vcs.close();
page = createPage();
vcs = new PDPageContentStream(pd, page);
volY = 50;
}
}
// Add 70 to account for a new section.
volY += 70;
}
vcs.close();
}
Here is the code I'm using to draw multiple strings:
private int drawMultipleStrings(String text, int y, PDPageContentStream cs, PDPage page, int index) {
// Page is 900 units wide
// Assume font size is 13
int strSize = text.length();
int height = 0;
String textVal = text;
List<String> allText = new ArrayList<>();
int xVal = index % 2 == 0 ? 60 : 300;
if(strSize > 40) {
while(textVal.length() > 40) {
for (int i = 40; i > 0; i--) {
if (textVal.charAt(i) == ' ') {
allText.add(textVal.substring(0, i));
textVal = textVal.substring(i);
break;
}
}
}
allText.add(textVal);
for(int ind = 0; ind < allText.size(); ind++) {
String s = allText.get(ind);
if(s.charAt(0) == ' ') {
s = s.substring(1);
drawString(s, xVal, y+(13*ind), cs, page, 13);
} else {
// This should only trigger on the first iteration.
drawString(s, xVal, y+(13*ind), cs, page, 13);
}
height += 13;
}
// Allows items to be displayed in 2 columns based on the index
return index % 2 == 0 ? 0 : height + 32;
} else {
drawString(text, index % 2 == 0 ? 60: 300, y, cs, page, 13);
return 13;
}
}
This code works properly, but if I change drawMultipleStrings(ti.getPrompt(), volY, vcs, page, z);
to volY += drawMultipleStrings(ti.getPrompt(), volY, vcs, page, z);
It throws this exception:
java.lang.NullPointerException
at org.apache.pdfbox.pdmodel.PDPageContentStream.writeOperand(PDPageContentStream.java:2429)
at org.apache.pdfbox.pdmodel.PDPageContentStream.setNonStrokingColor(PDPageContentStream.java:1316)
at org.apache.pdfbox.pdmodel.PDPageContentStream.setNonStrokingColor(PDPageContentStream.java:1348)
at compliancego.report.PdfService.generateSection(PdfService.java:206)
at compliancego.report.PdfService.generateHeader(PdfService.java:176)
at compliancego.report.PdfService.<init>(PdfService.java:97)
at compliancego.report.PdfService.main(PdfService.java:73)
At first I thought this was because some of the data didn't exist to write but it works just fine if I don't update volY. Then I thought it was an issue with the PDPageContentStream not being created when a new page is created but the stream exists.
Thanks in advance for any help!
You initially create a local page content stream variable you initialize with the page content stream you received as a parameter:
PDPageContentStream vcs = cs;
Upon page change you close the current page content stream in vcs
and then set vcs
to a new stream on a new page:
if (volY > 700) {
vcs.close();
page = createPage();
vcs = new PDPageContentStream(pd, page);
volY = 50;
}
But in two code lines in your loop over the sections
you draw on cs
instead of vcs
:
cs.setNonStrokingColor(URGENT);
...
cs.setNonStrokingColor(REGULAR_TEXT);
During the first page change you closed vcs
which pointed to the same stream as cs
. Thus, these color setting instructions are drawn on the closed stream cs
which results in the observed NullPointerException
.
To fix this, use vcs
here instead of cs
, too.
The reason why this only occurred after you changed
drawMultipleStrings(ti.getPrompt(), volY, vcs, page, z);
to
volY += drawMultipleStrings(ti.getPrompt(), volY, vcs, page, z);
most likely is that before that change volY
never grew large enough to trigger a page change but thereafter it did.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.