Revision 33303
Added by Andrea Mannocci over 9 years ago
modules/dnet-eagle-workflows/trunk/src/main/java/eu/dnetlib/data/provision/pdf/PdfMaterializerController.java | ||
---|---|---|
6 | 6 |
import java.util.List; |
7 | 7 |
|
8 | 8 |
import javax.annotation.Resource; |
9 |
import javax.servlet.ServletOutputStream; |
|
9 | 10 |
import javax.servlet.http.HttpServletRequest; |
10 | 11 |
import javax.servlet.http.HttpServletResponse; |
11 | 12 |
|
... | ... | |
14 | 15 |
import org.apache.pdfbox.exceptions.COSVisitorException; |
15 | 16 |
import org.apache.pdfbox.pdmodel.PDDocument; |
16 | 17 |
import org.apache.pdfbox.pdmodel.PDPage; |
17 |
import org.apache.pdfbox.pdmodel.common.PDRectangle; |
|
18 | 18 |
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream; |
19 | 19 |
import org.apache.pdfbox.pdmodel.font.PDFont; |
20 |
import org.apache.pdfbox.pdmodel.font.PDType1Font;
|
|
20 |
import org.apache.pdfbox.pdmodel.font.PDTrueTypeFont;
|
|
21 | 21 |
import org.dom4j.DocumentException; |
22 | 22 |
import org.dom4j.io.SAXReader; |
23 | 23 |
import org.springframework.beans.factory.annotation.Value; |
24 |
import org.springframework.core.io.ClassPathResource; |
|
24 | 25 |
import org.springframework.http.HttpStatus; |
25 | 26 |
import org.springframework.stereotype.Controller; |
26 | 27 |
import org.springframework.web.bind.annotation.ExceptionHandler; |
... | ... | |
62 | 63 |
@Value("${eagle.provision.pdf.index.text.xpath}") |
63 | 64 |
private String textXpath; |
64 | 65 |
|
66 |
private ClassPathResource trueType = new ClassPathResource("/eu/dnetlib/data/provision/pdf/lmroman10-regular.ttf"); |
|
67 |
|
|
65 | 68 |
@RequestMapping("/pdfs/{id}") |
66 | 69 |
public void generatePdfFromId(final HttpServletRequest request, final HttpServletResponse response, @PathVariable final String id) throws IOException, |
67 | 70 |
COSVisitorException, IndexClientException, DocumentException { |
68 | 71 |
log.info("Materializing pdf"); |
69 |
PDDocument document = null; |
|
70 |
try { |
|
71 |
// Create a document and add a page to it |
|
72 |
document = new PDDocument(); |
|
73 |
PDPage page = new PDPage(); |
|
74 |
document.addPage(page); |
|
75 | 72 |
|
76 |
// Start a new content stream which will "hold" the to be created content
|
|
77 |
PDPageContentStream contentStream = new PDPageContentStream(document, page);
|
|
73 |
List<String> arrayList = new ArrayList<String>();
|
|
74 |
arrayList.add(getTextToPrint(id));
|
|
78 | 75 |
|
79 |
PDFont font = PDType1Font.HELVETICA; |
|
80 |
float leading = LEADING_SPACE * FONT_SIZE; |
|
76 |
writeText(arrayList, response.getOutputStream()); |
|
81 | 77 |
|
82 |
PDRectangle mediabox = page.findMediaBox(); |
|
83 |
float width = mediabox.getWidth() - 2 * MARGIN; |
|
84 |
float startX = mediabox.getLowerLeftX() + MARGIN; |
|
85 |
float startY = mediabox.getUpperRightY() - MARGIN; |
|
78 |
} |
|
86 | 79 |
|
87 |
String text = getTextToPrint(id); |
|
80 |
public void writeText(final List<String> arrayList, final ServletOutputStream outputStream) throws IOException, |
|
81 |
COSVisitorException { |
|
82 |
PDDocument document = new PDDocument(); |
|
83 |
PDPage page = new PDPage(); |
|
84 |
// PDFont font = PDType1Font.HELVETICA; |
|
85 |
PDFont font = PDTrueTypeFont.loadTTF(document, trueType.getInputStream()); |
|
86 |
int positionX = 30; |
|
87 |
int positionY = 750; |
|
88 | 88 |
|
89 |
// Chunk lines |
|
90 |
List<String> lines = new ArrayList<String>(); |
|
91 |
int lastSpace = -1; |
|
92 |
while (text.length() > 0) { |
|
93 |
int spaceIndex = text.indexOf(' ', lastSpace + 1); |
|
94 |
if (spaceIndex < 0) { |
|
95 |
lines.add(text); |
|
96 |
text = ""; |
|
97 |
} |
|
98 |
else { |
|
99 |
String subString = text.substring(0, spaceIndex); |
|
100 |
float size = FONT_SIZE * font.getStringWidth(subString) / 1000; |
|
101 |
if (size > width) { |
|
102 |
if (lastSpace < 0) { |
|
103 |
lastSpace = spaceIndex; |
|
104 |
} |
|
105 |
subString = text.substring(0, lastSpace); |
|
106 |
lines.add(subString); |
|
107 |
text = text.substring(lastSpace).trim(); |
|
108 |
lastSpace = -1; |
|
109 |
} |
|
110 |
else { |
|
111 |
lastSpace = spaceIndex; |
|
112 |
} |
|
113 |
} |
|
114 |
} |
|
89 |
document.addPage(page); |
|
115 | 90 |
|
116 |
contentStream.beginText(); |
|
117 |
contentStream.setFont(font, FONT_SIZE); |
|
118 |
contentStream.moveTextPositionByAmount(startX, startY); |
|
119 |
for (String line : lines) { |
|
120 |
contentStream.drawString(line); |
|
121 |
contentStream.moveTextPositionByAmount(0, -leading); |
|
91 |
// Start a new content stream |
|
92 |
PDPageContentStream contentStream = new PDPageContentStream(document, page); |
|
93 |
|
|
94 |
// Define a text content stream using the selected font, moving the cursor and drawing the text in arrayList |
|
95 |
for (int i = 0; i < arrayList.size(); i++) { |
|
96 |
String text = arrayList.get(i); |
|
97 |
String[] tmpText = splitString(text); |
|
98 |
for (int k = 0; k < tmpText.length; k++) { |
|
99 |
contentStream.beginText(); |
|
100 |
contentStream.setFont(font, 12); |
|
101 |
contentStream.moveTextPositionByAmount(positionX, positionY); |
|
102 |
contentStream.drawString(tmpText[k]); |
|
103 |
contentStream.endText(); |
|
104 |
positionY = positionY - 20; |
|
122 | 105 |
} |
123 |
contentStream.endText();
|
|
124 |
contentStream.close();
|
|
106 |
contentStream.setLineWidth((float) 0.25);
|
|
107 |
}
|
|
125 | 108 |
|
126 |
document.save(response.getOutputStream()); |
|
127 |
} finally { |
|
128 |
if (document != null) { |
|
129 |
document.close(); |
|
109 |
// Make sure that the content stream is closed: |
|
110 |
contentStream.close(); |
|
111 |
document.save(outputStream); |
|
112 |
document.close(); |
|
113 |
} |
|
114 |
|
|
115 |
public String[] splitString(final String text) { |
|
116 |
/* |
|
117 |
* pdfBox doesnt support linebreaks. Therefore, following steps are requierd to automatically put linebreaks in the pdf 1) split |
|
118 |
* each word in string that has to be linefeded and put them into an array of string, e.g. String [] parts 2) create an array of |
|
119 |
* stringbuffer with (textlength/(number of characters in a line)), e.g. 280/70=5 >> we need 5 linebreaks! 3) put the parts into the |
|
120 |
* stringbuffer[i], until the limit of maximum number of characters in a line is allowed, 4) loop until stringbuffer.length < |
|
121 |
* linebreaks |
|
122 |
*/ |
|
123 |
int linebreaks = text.length() / 40; // how many linebreaks do I need? |
|
124 |
String[] newText = new String[linebreaks + 1]; |
|
125 |
String tmpText = text; |
|
126 |
String[] parts = tmpText.split(" "); // save each word into an array-element |
|
127 |
|
|
128 |
// split each word in String into a an array of String text. |
|
129 |
StringBuffer[] stringBuffer = new StringBuffer[linebreaks + 1]; // StringBuffer is necessary because of manipulating text |
|
130 |
int i = 0; // initialize counter |
|
131 |
int totalTextLength = 0; |
|
132 |
for (int k = 0; k < linebreaks + 1; k++) { |
|
133 |
stringBuffer[k] = new StringBuffer(); |
|
134 |
while (true) { |
|
135 |
if (i >= parts.length) |
|
136 |
{ |
|
137 |
break; // avoid NullPointerException |
|
138 |
} |
|
139 |
totalTextLength = totalTextLength + parts[i].length(); // count each word in String |
|
140 |
if (totalTextLength > 40) |
|
141 |
{ |
|
142 |
break; // put each word in a stringbuffer until string length is >80 |
|
143 |
} |
|
144 |
stringBuffer[k].append(parts[i]); |
|
145 |
stringBuffer[k].append(" "); |
|
146 |
i++; |
|
130 | 147 |
} |
148 |
// reset counter, save linebreaked text into the array, finally convert it to a string |
|
149 |
totalTextLength = 0; |
|
150 |
newText[k] = stringBuffer[k].toString(); |
|
131 | 151 |
} |
152 |
return newText; |
|
132 | 153 |
} |
133 | 154 |
|
134 | 155 |
private String getTextToPrint(final String id) throws IndexClientException, DocumentException { |
Also available in: Unified diff
better font for pdfs