fix linespacing in table cells, add max height to table rendering
This commit is contained in:
parent
b3167d16ce
commit
26d8f2756a
11 changed files with 211 additions and 13 deletions
|
@ -1,5 +1,5 @@
|
|||
group = org.xbib.graphics
|
||||
name = graphics
|
||||
version = 4.5.3
|
||||
version = 4.5.4
|
||||
|
||||
org.gradle.warning.mode = ALL
|
||||
|
|
|
@ -21,6 +21,8 @@ public class TableElement implements Element, Drawable, Dividable {
|
|||
|
||||
private Position absolutePosition;
|
||||
|
||||
private Position endPosition;
|
||||
|
||||
public TableElement() {
|
||||
this.table = Table.builder();
|
||||
}
|
||||
|
@ -75,6 +77,10 @@ public class TableElement implements Element, Drawable, Dividable {
|
|||
table.verticalAlignment(verticalAlignment);
|
||||
}
|
||||
|
||||
public void maximumHeight(float maximumHeight) {
|
||||
table.maximumHeight(maximumHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getWidth() {
|
||||
return table.build().getWidth();
|
||||
|
@ -102,17 +108,27 @@ public class TableElement implements Element, Drawable, Dividable {
|
|||
this.absolutePosition = absolutePosition;
|
||||
}
|
||||
|
||||
public void setEndPosition(Position endPosition) {
|
||||
this.endPosition = endPosition;
|
||||
}
|
||||
|
||||
public Position getEndPosition() {
|
||||
return endPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(PDDocument pdDocument, PDPageContentStream contentStream,
|
||||
Position upperLeft, Transform transform, DrawListener drawListener) throws IOException {
|
||||
TableRenderer tableRenderer = TableRenderer.builder()
|
||||
TableRenderer.Builder tableRenderer = TableRenderer.builder()
|
||||
.table(table.build())
|
||||
.document(pdDocument)
|
||||
.contentStream(contentStream)
|
||||
.startX(upperLeft.getX())
|
||||
.startY(upperLeft.getY())
|
||||
.build();
|
||||
tableRenderer.draw();
|
||||
.startY(upperLeft.getY());
|
||||
if (endPosition != null) {
|
||||
tableRenderer.endY(endPosition.getY());
|
||||
}
|
||||
tableRenderer.build().draw();
|
||||
if (drawListener != null) {
|
||||
drawListener.drawn(this, upperLeft, getWidth(), getHeight());
|
||||
}
|
||||
|
|
|
@ -64,8 +64,10 @@ public class CellCommand implements Command {
|
|||
}
|
||||
cell.colSpan(settings.getAsInt("colspan", 1));
|
||||
cell.rowSpan(settings.getAsInt("rowspan", 1));
|
||||
cell.lineSpacing(settings.getAsFloat("linespacing", 1.0f));
|
||||
state.getElements().peek().add(cell.build());
|
||||
} else if (settings.containsSetting("markup")) {
|
||||
float linespacing = settings.getAsFloat("linespacing", 1.0f);
|
||||
ParagraphCell.Builder cell = ParagraphCell.builder();
|
||||
cell.colSpan(settings.getAsInt("colspan", 1));
|
||||
cell.rowSpan(settings.getAsInt("rowspan", 1));
|
||||
|
@ -79,16 +81,14 @@ public class CellCommand implements Command {
|
|||
if (settings.containsSetting("alignment")) {
|
||||
paragraph.setAlignment(Alignment.valueOf(settings.get("alignment", "left").toUpperCase(Locale.ROOT)));
|
||||
}
|
||||
paragraph.setLineSpacing(linespacing);
|
||||
cell.paragraph(paragraph);
|
||||
String value = settings.get("markup");
|
||||
float size = settings.getAsFloat("fontsize", 11.0f);
|
||||
float lineSpacing = settings.getAsFloat("linespacing", -1f);
|
||||
Document document = state.getDocument();
|
||||
Font font = document.getFont(settings.get("font", "helvetica"));
|
||||
cell.add(new Markup().setValue(value).setFont(font).setFontSize(size));
|
||||
if (lineSpacing >= 0f) {
|
||||
cell.lineSpacing(lineSpacing);
|
||||
}
|
||||
cell.lineSpacing(linespacing);
|
||||
state.getElements().peek().add(cell.build());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,12 @@ public class TableCommand implements Command {
|
|||
if (settings.containsSetting("x") && settings.containsSetting("y")) {
|
||||
tableElement.setAbsolutePosition(new Position(mmToPt(settings.getAsFloat("x", 0f)), mmToPt(settings.getAsFloat("y", 0f))));
|
||||
}
|
||||
if (settings.containsSetting("endx") && settings.containsSetting("endy")) {
|
||||
tableElement.setEndPosition(new Position(mmToPt(settings.getAsFloat("endx", 0f)), mmToPt(settings.getAsFloat("endy", 0f))));
|
||||
}
|
||||
if (settings.containsSetting("maxheight")) {
|
||||
tableElement.maximumHeight(mmToPt(settings.getAsFloat("maxheight", 0f)));
|
||||
}
|
||||
if (settings.containsSetting("padding")) {
|
||||
String padding = settings.get("padding", "0 0 0 0");
|
||||
String[] paddings = padding.split("\\s+");
|
||||
|
|
|
@ -42,6 +42,8 @@ public class Table {
|
|||
|
||||
private float width;
|
||||
|
||||
private float maximumHeight;
|
||||
|
||||
public Table(List<Row> rows, List<Column> columns, Set<Point> rowSpanCells) {
|
||||
this.rows = rows;
|
||||
this.columns = columns;
|
||||
|
@ -64,6 +66,14 @@ public class Table {
|
|||
return width;
|
||||
}
|
||||
|
||||
public void setMaximumHeight(float maximumHeight) {
|
||||
this.maximumHeight = maximumHeight;
|
||||
}
|
||||
|
||||
public float getMaximumHeight() {
|
||||
return maximumHeight;
|
||||
}
|
||||
|
||||
public static BorderStyleInterface getDefaultBorderStyle() {
|
||||
return DEFAULT_BORDER_STYLE;
|
||||
}
|
||||
|
@ -142,6 +152,8 @@ public class Table {
|
|||
|
||||
private float width;
|
||||
|
||||
private float maximumHeight;
|
||||
|
||||
private Builder() {
|
||||
parameters.setFont(DEFAULT_FONT);
|
||||
parameters.setFontSize(DEFAULT_FONT_SIZE);
|
||||
|
@ -280,6 +292,11 @@ public class Table {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder maximumHeight(float maximumHeight) {
|
||||
this.maximumHeight = maximumHeight;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Table build() {
|
||||
if (getNumberOfRegularCells() != getNumberOfSpannedCells()) {
|
||||
throw new TableSetupException("Number of table cells does not match with table setup. " +
|
||||
|
@ -288,6 +305,7 @@ public class Table {
|
|||
Table table = new Table(rows, columns, rowSpanCells);
|
||||
table.setSettings(parameters);
|
||||
table.setWidth(width);
|
||||
table.setMaximumHeight(maximumHeight);
|
||||
table.setNumberOfColumns(numberOfColumns);
|
||||
setupConnectionsBetweenElementsFor(table);
|
||||
correctHeightOfCellsDueToRowSpanningIfNecessaryFor(table);
|
||||
|
|
|
@ -14,6 +14,8 @@ import java.util.List;
|
|||
import java.util.Queue;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode.APPEND;
|
||||
|
||||
|
@ -152,10 +154,13 @@ public class TableRenderer {
|
|||
|
||||
protected void drawWithFunction(PageData pageData, Point2D.Float startingPoint, BiConsumer<Renderer, TableRenderContext> consumer) {
|
||||
float y = startingPoint.y;
|
||||
float miny = startingPoint.y - table.getMaximumHeight();
|
||||
for (int rowIndex = pageData.firstRowOnPage; rowIndex < pageData.firstRowOnNextPage; rowIndex++) {
|
||||
final Row row = table.getRows().get(rowIndex);
|
||||
y -= row.getHeight();
|
||||
drawRow(new Point2D.Float(startingPoint.x, y), row, rowIndex, consumer);
|
||||
if (table.getMaximumHeight() == 0.0f || y > miny) {
|
||||
drawRow(new Point2D.Float(startingPoint.x, y), row, rowIndex, consumer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,8 @@ public class TextCell extends AbstractTextCell {
|
|||
|
||||
private int rowSpan;
|
||||
|
||||
private float lineSpacing = 1.0f;
|
||||
|
||||
private Builder() {
|
||||
parameters = new Parameters();
|
||||
}
|
||||
|
@ -178,10 +180,16 @@ public class TextCell extends AbstractTextCell {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder lineSpacing(float lineSpacing) {
|
||||
this.lineSpacing = lineSpacing;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextCell build() {
|
||||
TextCell cell = new TextCell();
|
||||
cell.setParameters(parameters);
|
||||
cell.setText(text);
|
||||
cell.setLineSpacing(lineSpacing);
|
||||
if (colSpan > 0) {
|
||||
cell.setColSpan(colSpan);
|
||||
}
|
||||
|
|
|
@ -17,8 +17,7 @@ public class DrawableCellRenderer extends AbstractCellRenderer<DrawableCell> {
|
|||
@Override
|
||||
public void renderContent(TableRenderContext tableRenderContext) {
|
||||
Drawable drawable = cell.getDrawable();
|
||||
if (drawable instanceof WidthRespecting) {
|
||||
WidthRespecting widthRespecting = (WidthRespecting) drawable;
|
||||
if (drawable instanceof WidthRespecting widthRespecting) {
|
||||
widthRespecting.setMaxWidth(cell.getWidth());
|
||||
}
|
||||
float x = tableRenderContext.getStartingPoint().x + cell.getPaddingLeft();
|
||||
|
|
|
@ -244,7 +244,7 @@ public class TextFlow implements TextSequence, WidthRespecting {
|
|||
* @return a copy of this text flow where all leading {@link NewLine}s are removed.
|
||||
*/
|
||||
public TextFlow removeLeadingEmptyLines() {
|
||||
if (text.size() == 0 || !(text.get(0) instanceof NewLine)) {
|
||||
if (text.isEmpty() || !(text.get(0) instanceof NewLine)) {
|
||||
return this;
|
||||
}
|
||||
TextFlow result = createInstance();
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package org.xbib.graphics.pdfbox.layout.test;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.graphics.pdfbox.layout.element.Document;
|
||||
import org.xbib.graphics.pdfbox.layout.element.scripting.Engine;
|
||||
import org.xbib.settings.Settings;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
public class ScriptingTableTest {
|
||||
|
||||
@Test
|
||||
public void testTable() throws Exception {
|
||||
Settings settings = Settings.settingsBuilder()
|
||||
.loadFromResource("json", getClass().getResourceAsStream("scriptingtable.json"))
|
||||
.build();
|
||||
try (Engine engine = new Engine()) {
|
||||
engine.execute(settings);
|
||||
Document document = engine.getState().getDocument();
|
||||
document.render().save(new FileOutputStream("build/scriptingtable.pdf")).close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
{
|
||||
"type": "document",
|
||||
"margin": "0 0 0 0",
|
||||
"author": "Jörg Prante",
|
||||
"font": [
|
||||
"helvetica",
|
||||
"notosans"
|
||||
],
|
||||
"elements": [
|
||||
{
|
||||
"type": "table",
|
||||
"padding": "10 10 10 10",
|
||||
"columnwidths": "50 50 50",
|
||||
"elements": [
|
||||
{
|
||||
"type": "row",
|
||||
"elements": [
|
||||
{
|
||||
"type": "cell",
|
||||
"text": "Cell A"
|
||||
},
|
||||
{
|
||||
"type": "cell",
|
||||
"text": "Cell B"
|
||||
},
|
||||
{
|
||||
"type": "cell",
|
||||
"text": "Cell C"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "row",
|
||||
"elements": [
|
||||
{
|
||||
"type": "cell",
|
||||
"text": "Cell D"
|
||||
},
|
||||
{
|
||||
"type": "cell",
|
||||
"text": "Cell E"
|
||||
},
|
||||
{
|
||||
"type": "cell",
|
||||
"text": "Cell F"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "table",
|
||||
"columnwidths": "60 40 20",
|
||||
"maxheight": 25,
|
||||
"elements": [
|
||||
{
|
||||
"type": "row",
|
||||
"elements": [
|
||||
{
|
||||
"type": "cell",
|
||||
"text": "This is very long text for cell 1 This is very long text for cell 1 This is very long text for cell 1",
|
||||
"linespacing": 0.5
|
||||
},
|
||||
{
|
||||
"type": "cell",
|
||||
"text": "Cell 2"
|
||||
},
|
||||
{
|
||||
"type": "cell",
|
||||
"text": "Cell 3"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "row",
|
||||
"elements": [
|
||||
{
|
||||
"type": "cell",
|
||||
"text": "Cell 4",
|
||||
"padding": "5 5 5 5",
|
||||
"borderwidth": 0.5
|
||||
},
|
||||
{
|
||||
"type": "cell",
|
||||
"text": "Cell 5",
|
||||
"padding": "5 5 5 5",
|
||||
"borderwidth": 0.5
|
||||
},
|
||||
{
|
||||
"type": "cell",
|
||||
"text": "Cell 6",
|
||||
"padding": "5 5 5 5",
|
||||
"borderwidth": 0.5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "row",
|
||||
"elements": [
|
||||
{
|
||||
"type": "cell",
|
||||
"text": "Cell 7",
|
||||
"padding": "5 5 5 5",
|
||||
"borderwidth": 0.5
|
||||
},
|
||||
{
|
||||
"type": "cell",
|
||||
"text": "Cell 8",
|
||||
"padding": "5 5 5 5",
|
||||
"borderwidth": 0.5
|
||||
},
|
||||
{
|
||||
"type": "cell",
|
||||
"text": "Cell 9",
|
||||
"padding": "5 5 5 5",
|
||||
"borderwidth": 0.5
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue