Implement text justification in PDF-BOX output device
danfickle opened this issue · 4 comments
As of PDF-BOX 2.0.0-RC3 there is no way to implement text justification. Need to open PDF-BOX JIRA issue asking them to implement the text spacing and space spacing operators.
I've read in stackoverflow [1] about the class: InlineBoxing (package com.openhtmltopdf.layout;)
[1] http://stackoverflow.com/questions/36982586/flying-saucer-generates-pdf-with-badly-justified-text
Line 239, alter to:
if (lbContext.isNeedsNewLine()) {
currentLine.trimTrailingSpace(c); //justify
add before:
saveLine(currentLine, c, box, minimumLineHeight,...
And it works fine for flying-saucer, but not to openhtmltopdf :(
I've managed to get PdfBox to actually start adding spacing by upgrading to pdfbox 2.0.2 and changing the PdfPageContentStream's setTextSpacing and setSpaceSpacing to:
public void setTextSpacing(float nonSpaceAdjust) {
try {
cs.appendRawCommands(String.format("%f Tc\n", nonSpaceAdjust).replace(',', '.'));
} catch (IOException e) {
logAndThrow("setSpaceSpacing", e);
}
}
public void setSpaceSpacing(float spaceAdjust) {
try {
cs.appendRawCommands(String.format("%f Tw\n", spaceAdjust).replace(',', '.'));
} catch (IOException e) {
logAndThrow("setSpaceSpacing", e);
}
}
appendRawCommands is deprecated, but PdfBox still doesn't support the Tw and Tc operators.
The spacing is wrong, I guess the LineBox.justify() method needs some rework as well. I managed to make word spacing work correctly by changing:
if (info != null) {
_cp.setTextSpacing(info.getNonSpaceAdjust());
_cp.setSpaceSpacing(info.getSpaceAdjust());
}
to
if (info != null) {
int spaces = 0;
for (int i = 0; i < s.length(); i++) {
char chr = s.charAt(i);
if (chr == ' ' || chr == '\u00a0' || chr == '\u3000') {
spaces++;
}
}
float free = 0;
try {
free = width - ((fontSize * (_font.getFontDescription().get(0).getFont().getStringWidth(s) / 1000)));
} catch (IOException e) {
e.printStackTrace();
}
// _cp.setTextSpacing(info.getNonSpaceAdjust());
// _cp.setSpaceSpacing(info.getSpaceAdjust());
_cp.setSpaceSpacing(free / spaces);
} else {
_cp.setTextSpacing(0.0f);
_cp.setSpaceSpacing(0.0f);
}
Yeah it's ugly as hell but you get the drill :)
Thanks @surfx and especially @HiddenDog for the code. I'll try to look at this in the next 24 hours but I think you've put me in the right direction.
Thanks everyone - now working well.