fix table font handling with base font's notorious illegal argument exception, fix other table font bugs

This commit is contained in:
Jörg Prante 2023-08-28 17:55:45 +02:00
parent b62aacfe59
commit 1df6a1ea16
10 changed files with 107 additions and 17 deletions

View file

@ -1,5 +1,5 @@
group = org.xbib.graphics group = org.xbib.graphics
name = graphics name = graphics
version = 4.5.6 version = 4.5.7
org.gradle.warning.mode = ALL org.gradle.warning.mode = ALL

View file

@ -236,6 +236,10 @@ public class Document implements Element, Closeable, RenderListener {
return false; return false;
} }
} }
public String toString() {
return name;
}
}); });
} }

View file

@ -40,7 +40,7 @@ public abstract class AbstractTextCell extends AbstractCell {
if (this.textHeight != null) { if (this.textHeight != null) {
return this.textHeight; return this.textHeight;
} }
this.textHeight = PdfUtil.getFontHeight(getText(), getFontDescriptor()); this.textHeight = PdfUtil.getFontHeight(getFontDescriptor());
if (parameters.isWordBreak()) { if (parameters.isWordBreak()) {
final int size = PdfUtil.getOptimalTextBreakLines(getText(), getFontDescriptor(), getMaxWidth()).size(); final int size = PdfUtil.getOptimalTextBreakLines(getText(), getFontDescriptor(), getMaxWidth()).size();
final float heightOfTextLines = size * this.textHeight; final float heightOfTextLines = size * this.textHeight;

View file

@ -13,6 +13,9 @@ public abstract class AbstractCellRenderer<T extends Cell> implements Renderer {
protected T cell; protected T cell;
public AbstractCellRenderer() {
}
public AbstractCellRenderer<T> withCell(T cell) { public AbstractCellRenderer<T> withCell(T cell) {
this.cell = cell; this.cell = cell;
return this; return this;

View file

@ -30,7 +30,7 @@ public class TextCellRenderer<T extends AbstractTextCell> extends AbstractCellRe
final List<String> lines = calculateAndGetLines(fontDescriptor, cell.getMaxWidth()); final List<String> lines = calculateAndGetLines(fontDescriptor, cell.getMaxWidth());
for (int i = 0; i < lines.size(); i++) { for (int i = 0; i < lines.size(); i++) {
final String line = lines.get(i); final String line = lines.get(i);
yOffset -= calculateYOffset(line, fontDescriptor, i); yOffset -= calculateYOffset(fontDescriptor, i);
final float textWidth = PdfUtil.getStringWidth(line, fontDescriptor); final float textWidth = PdfUtil.getStringWidth(line, fontDescriptor);
if (cell.isHorizontallyAligned(RIGHT)) { if (cell.isHorizontallyAligned(RIGHT)) {
xOffset = startX + (cell.getWidth() - (textWidth + cell.getPaddingRight())); xOffset = startX + (cell.getWidth() - (textWidth + cell.getPaddingRight()));
@ -54,9 +54,9 @@ public class TextCellRenderer<T extends AbstractTextCell> extends AbstractCellRe
return cell.getTextHeight(); return cell.getTextHeight();
} }
private float calculateYOffset(String text, FontDescriptor fontDescriptor, int lineIndex) { private float calculateYOffset(FontDescriptor fontDescriptor, int lineIndex) {
return PdfUtil.getFontHeight(text, fontDescriptor) + return PdfUtil.getFontHeight(fontDescriptor) +
(lineIndex > 0 ? PdfUtil.getFontHeight(text, fontDescriptor) * cell.getLineSpacing() : 0f); (lineIndex > 0 ? PdfUtil.getFontHeight(fontDescriptor) * cell.getLineSpacing() : 0f);
} }
private static boolean isNotLastLine(List<String> lines, int i) { private static boolean isNotLastLine(List<String> lines, int i) {

View file

@ -43,7 +43,7 @@ public class VerticalTextCellRenderer extends AbstractCellRenderer<VerticalTextC
float xOffset = startX + cell.getPaddingLeft(); /* - PdfUtil.getFontHeight(currentFont, currentFontSize)*/; float xOffset = startX + cell.getPaddingLeft(); /* - PdfUtil.getFontHeight(currentFont, currentFontSize)*/;
for (int i = 0; i < lines.size(); i++) { for (int i = 0; i < lines.size(); i++) {
final String line = lines.get(i); final String line = lines.get(i);
xOffset += (PdfUtil.getFontHeight(line, fontDescriptor) + (i > 0 ? PdfUtil.getFontHeight(line, fontDescriptor) * cell.getLineSpacing() : 0f)); xOffset += (PdfUtil.getFontHeight(fontDescriptor) + (i > 0 ? PdfUtil.getFontHeight(fontDescriptor) * cell.getLineSpacing() : 0f));
drawText(line, fontDescriptor, currentTextColor, xOffset, yOffset, tableRenderContext.getContentStream()); drawText(line, fontDescriptor, currentTextColor, xOffset, yOffset, tableRenderContext.getContentStream());
} }
} }

View file

@ -61,6 +61,9 @@ public final class PdfUtil {
} }
found = true; found = true;
} }
if (found) {
break;
}
} }
if (!found) { if (!found) {
throw new IllegalArgumentException("unable to get width of string " + codepoint); throw new IllegalArgumentException("unable to get width of string " + codepoint);
@ -75,13 +78,11 @@ public final class PdfUtil {
* @param fontDescriptor font * @param fontDescriptor font
* @return height of font * @return height of font
*/ */
public static float getFontHeight(String text, FontDescriptor fontDescriptor) { public static float getFontHeight(FontDescriptor fontDescriptor) {
for (Font font : fontDescriptor.getFonts()) { for (Font font : fontDescriptor.getFonts()) {
if (font.canWrite(text)) { return font.getRegularFont().getFontDescriptor().getCapHeight() * fontDescriptor.getSize() / 1000F;
return font.getRegularFont().getFontDescriptor().getCapHeight() * fontDescriptor.getSize() / 1000F;
}
} }
throw new IllegalArgumentException("unable to get font height for text " + text + ", fonts = " + fontDescriptor.getFonts()); throw new IllegalArgumentException("unable to get font height, fonts = " + fontDescriptor.getFonts());
} }
/** /**

View file

@ -10,26 +10,40 @@ import org.xbib.graphics.pdfbox.layout.table.render.PositionedStyledText;
import java.awt.Color; import java.awt.Color;
import java.io.IOException; import java.io.IOException;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class RenderUtil { public class RenderUtil {
private static final Logger logger = Logger.getLogger(RenderUtil.class.getName());
private RenderUtil() { private RenderUtil() {
} }
public static void drawText(PDPageContentStream contentStream, PositionedStyledText styledText) { public static void drawText(PDPageContentStream contentStream, PositionedStyledText styledText) {
for (Font font : styledText.getFontDescriptor().getFonts()) { for (Font font : styledText.getFontDescriptor().getFonts()) {
boolean isBeginText = false;
if (font.canWrite(styledText.getText())) { if (font.canWrite(styledText.getText())) {
try { try {
contentStream.beginText(); contentStream.beginText();
isBeginText = true;
contentStream.setNonStrokingColor(styledText.getColor()); contentStream.setNonStrokingColor(styledText.getColor());
// TODO select correct font style
contentStream.setFont(font.getRegularFont(), styledText.getFontDescriptor().getSize()); contentStream.setFont(font.getRegularFont(), styledText.getFontDescriptor().getSize());
contentStream.newLineAtOffset(styledText.getX(), styledText.getY()); contentStream.newLineAtOffset(styledText.getX(), styledText.getY());
contentStream.showText(styledText.getText()); contentStream.showText(styledText.getText());
contentStream.endText(); contentStream.endText();
isBeginText = false;
contentStream.setCharacterSpacing(0); contentStream.setCharacterSpacing(0);
} catch (IOException e) { break;
throw new UncheckedIOException(e); } catch (IllegalArgumentException | IOException e) {
logger.log(Level.WARNING, e.getMessage());
if (isBeginText) {
try {
contentStream.endText();
} catch (IOException ex) {
// ignore
}
}
} }
} }
} }

View file

@ -112,7 +112,7 @@ public class TableTest {
.add(TextCell.builder().text("12").paddingTop(15).paddingBottom(25).build()) .add(TextCell.builder().text("12").paddingTop(15).paddingBottom(25).build())
.build()) .build())
.build(); .build();
final float actualFontHeight = PdfUtil.getFontHeight("test", table.getSettings().getFontDescriptor()); final float actualFontHeight = PdfUtil.getFontHeight(table.getSettings().getFontDescriptor());
assertThat(table.getHeight(), equalTo(50 + actualFontHeight)); assertThat(table.getHeight(), equalTo(50 + actualFontHeight));
} }

View file

@ -3,7 +3,7 @@
"margin": "0 0 0 0", "margin": "0 0 0 0",
"author": "Jörg Prante", "author": "Jörg Prante",
"font": [ "font": [
"helvetica" "helvetica", "sourcesans", "notosans", "notosanscjksc"
], ],
"elements": [ "elements": [
{ {
@ -147,6 +147,74 @@
] ]
} }
] ]
},
{
"type": "table",
"padding": "10 10 10 10",
"columnwidths": "40 150",
"elements": [
{
"type": "row",
"elements": [
{
"type": "cell",
"text": "Demotext",
"font": [
"helvetica", "sourcesans", "notosans", "notosanscjksc"
],
"fontsize": 11
},
{
"type": "cell",
"text": "This is a demo text This is a demo text This is a demo text This is a demo text This is a demo text This is a demo text",
"font": [
"helvetica", "sourcesans", "notosans", "notosanscjksc"
],
"fontsize": 11
}
]
},
{
"type": "row",
"elements": [
{
"type": "cell",
"text": "Demotext",
"font": [
"helvetica", "sourcesans", "notosans", "notosanscjksc"
],
"fontsize": 11
},
{
"type": "cell",
"text": "Short text",
"font": [
"helvetica", "sourcesans", "notosans", "notosanscjksc"
],
"fontsize": 11
}
]
},
{
"type": "row",
"elements": [
{
"type": "cell",
"text": "Demotext",
"font": "helvetica",
"fontsize": 11
},
{
"type": "cell",
"text": "Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text ",
"font": [
"helvetica", "sourcesans", "notosans", "notosanscjksc"
],
"fontsize": 11
}
]
}
]
} }
] ]
} }