From 630d50bce7f7bbdd0f4bbc5445cb1f2189556d44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=CC=88rg=20Prante?= Date: Tue, 18 Jan 2022 18:36:58 +0100 Subject: [PATCH] add rotation, work on positions, add transform command --- .../pdfbox/layout/element/ControlElement.java | 2 +- .../pdfbox/layout/element/PageFormat.java | 10 +++ .../pdfbox/layout/element/PathElement.java | 6 +- .../layout/element/TransformElement.java | 74 +++++++++++++++++++ .../layout/element/render/LayoutHint.java | 2 + .../layout/element/render/RenderContext.java | 7 +- .../layout/element/render/VerticalLayout.java | 53 ++++++------- .../scripting/command/BarcodeCommand.java | 2 +- .../scripting/command/CellCommand.java | 2 +- .../scripting/command/ChartCommand.java | 2 +- .../scripting/command/DocumentCommand.java | 55 ++++++++++---- .../command/HorizontalrulerCommand.java | 2 +- .../scripting/command/ImageCommand.java | 2 +- .../scripting/command/ParagraphCommand.java | 7 +- .../scripting/command/PathCommand.java | 40 ++++++---- .../element/scripting/command/RowCommand.java | 2 +- .../scripting/command/TableCommand.java | 4 +- .../scripting/command/TextCommand.java | 19 +++-- .../scripting/command/TransformCommand.java | 28 +++++++ .../pdfbox/layout/shape/LinePosiiton.java | 15 ++++ .../pdfbox/layout/shape/MovePosition.java | 15 ++++ .../graphics/pdfbox/layout/shape/Path.java | 8 +- .../pdfbox/layout/table/StyledText.java | 2 +- .../graphics/pdfbox/layout/text/Indent.java | 4 +- .../graphics/pdfbox/layout/text/Position.java | 1 + .../pdfbox/layout/text/StyledText.java | 17 +++-- .../graphics/pdfbox/layout/text/TextFlow.java | 32 +++++--- .../pdfbox/layout/text/TextFlowUtil.java | 22 +++--- .../graphics/pdfbox/layout/text/TextLine.java | 6 +- .../text/annotations/AnnotatedStyledText.java | 2 +- .../pdfbox/layout/util/TextSequenceUtil.java | 5 +- .../layout/test/CustomRendererTest.java | 2 +- .../pdfbox/layout/test/ListenerTest.java | 2 +- .../pdfbox/layout/test/LowLevelText.java | 2 +- ...nTest.java => PageFormatRotationTest.java} | 2 +- .../pdfbox/layout/test/TextRotationTest.java | 28 +++++++ .../pdfbox/layout/test/table/TableTest.java | 4 +- .../graphics/pdfbox/layout/test/elements.json | 12 +-- 38 files changed, 366 insertions(+), 134 deletions(-) create mode 100644 graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/TransformElement.java create mode 100644 graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/TransformCommand.java create mode 100644 graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/shape/LinePosiiton.java create mode 100644 graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/shape/MovePosition.java rename graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/{RotationTest.java => PageFormatRotationTest.java} (99%) create mode 100644 graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/TextRotationTest.java diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/ControlElement.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/ControlElement.java index 6405702..e897950 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/ControlElement.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/ControlElement.java @@ -24,6 +24,6 @@ public class ControlElement implements Element { @Override public String toString() { - return "ControlElement [NEWPAGE=" + NEWPAGE + ", name=" + name + "]"; + return "ControlElement [name=" + name + "]"; } } diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/PageFormat.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/PageFormat.java index 7edbf0b..6ea16f0 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/PageFormat.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/PageFormat.java @@ -251,6 +251,16 @@ public class PageFormat implements Element { return this; } + public PageFormatBuilder mediaBox(float x, float y, float width, float height) { + PDRectangle rectangle = new PDRectangle(); + rectangle.setLowerLeftX(x); + rectangle.setLowerLeftY(y); + rectangle.setUpperRightX(x + width); + rectangle.setUpperRightY(y + height); + mediaBox(rectangle); + return this; + } + /** * Sets the media box to the given size. * diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/PathElement.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/PathElement.java index 3661087..bb52ac8 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/PathElement.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/PathElement.java @@ -64,8 +64,10 @@ public class PathElement implements Drawable, Element { } @Override - public void draw(PDDocument pdDocument, PDPageContentStream contentStream, - Position upperLeft, DrawListener drawListener) throws IOException { + public void draw(PDDocument pdDocument, + PDPageContentStream contentStream, + Position upperLeft, + DrawListener drawListener) throws IOException { path.draw(pdDocument, contentStream, upperLeft, getWidth(), getHeight(), color, stroke, drawListener); } diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/TransformElement.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/TransformElement.java new file mode 100644 index 0000000..fc7d1d5 --- /dev/null +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/TransformElement.java @@ -0,0 +1,74 @@ +package org.xbib.graphics.pdfbox.layout.element; + +import java.io.IOException; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPageContentStream; +import org.apache.pdfbox.util.Matrix; +import org.xbib.graphics.pdfbox.layout.text.DrawListener; +import org.xbib.graphics.pdfbox.layout.text.Position; + +public class TransformElement implements Element, Drawable { + + private Float translateX; + + private Float translateY; + + private Float scaleX; + + private Float scaleY; + + private Float rotateX; + + private Float rotateY; + + private Float angle; + + @Override + public float getWidth() throws IOException { + return 0; + } + + @Override + public float getHeight() throws IOException { + return 0; + } + + @Override + public Position getAbsolutePosition() throws IOException { + return null; + } + + @Override + public Drawable removeLeadingEmptyVerticalSpace() throws IOException { + return this; + } + + public void setTranslate(Float x, Float y) { + this.translateX = x; + this.translateY = y; + } + + public void setScale(Float scaleX, Float scaleY) { + this.scaleX = scaleX; + this.scaleY = scaleY; + } + + public void setRotate(Float angle, Float rotateX, Float rotateY) { + this.angle = angle; + this.rotateX = rotateX; + this.rotateY = rotateY; + } + + @Override + public void draw(PDDocument pdDocument, PDPageContentStream contentStream, Position upperLeft, DrawListener drawListener) throws IOException { + if (translateX != null && translateY != null) { + contentStream.transform(Matrix.getTranslateInstance(translateX, translateY)); + } + if (scaleX != null && scaleY != null) { + contentStream.transform(Matrix.getScaleInstance(scaleX, scaleY)); + } + if (angle != null && rotateX != null && rotateY != null){ + contentStream.transform(Matrix.getRotateInstance(Math.toRadians(angle), rotateX, rotateY)); + } + } +} diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/render/LayoutHint.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/render/LayoutHint.java index 325d9bc..49344be 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/render/LayoutHint.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/render/LayoutHint.java @@ -9,4 +9,6 @@ import org.xbib.graphics.pdfbox.layout.element.Element; * to layout the element. */ public interface LayoutHint { + + LayoutHint NOP = new VerticalLayoutHint.VerticalLayoutHintBuilder().resetY(false).build(); } diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/render/RenderContext.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/render/RenderContext.java index 38e86ec..c8aed4e 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/render/RenderContext.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/render/RenderContext.java @@ -153,8 +153,7 @@ public class RenderContext implements Renderer, Closeable, DrawContext, DrawList * current y. */ public void resetPositionToLeft() { - currentPosition = new Position(getUpperLeft().getX(), - currentPosition.getY()); + currentPosition = new Position(getUpperLeft().getX(), currentPosition.getY()); } /** @@ -162,8 +161,7 @@ public class RenderContext implements Renderer, Closeable, DrawContext, DrawList * y of {@link #getMaxPositionOnPage()}. */ protected void resetPositionToLeftEndOfPage() { - currentPosition = new Position(getUpperLeft().getX(), - getMaxPositionOnPage().getY()); + currentPosition = new Position(getUpperLeft().getX(), getMaxPositionOnPage().getY()); } /** @@ -339,7 +337,6 @@ public class RenderContext implements Renderer, Closeable, DrawContext, DrawList this.page = new PDPage(getPageFormat().getMediaBox()); this.pdDocument.addPage(page); this.contentStream = new PDPageContentStream(pdDocument, page, PDPageContentStream.AppendMode.APPEND, true); - // fix orientation if (getPageOrientation() != getPageFormat().getOrientation()) { if (isPageTilted()) { page.setRotation(0); diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/render/VerticalLayout.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/render/VerticalLayout.java index a1687dd..0a84c0f 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/render/VerticalLayout.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/render/VerticalLayout.java @@ -78,10 +78,9 @@ public class VerticalLayout implements Layout { public void render(RenderContext renderContext, Drawable drawable, LayoutHint layoutHint) throws IOException { if (drawable.getAbsolutePosition() != null) { - renderAbsolute(renderContext, drawable, layoutHint, - drawable.getAbsolutePosition()); + renderAbsolute(renderContext, drawable, drawable.getAbsolutePosition()); } else { - renderReleative(renderContext, drawable, layoutHint); + renderRelative(renderContext, drawable, layoutHint); } } @@ -90,12 +89,12 @@ public class VerticalLayout implements Layout { * * @param renderContext the context providing all rendering state. * @param drawable the drawable to draw. - * @param layoutHint the layout hint used to layout. * @param position the left upper position to start drawing at. * @throws IOException by pdfbox */ protected void renderAbsolute(RenderContext renderContext, - Drawable drawable, LayoutHint layoutHint, Position position) throws IOException { + Drawable drawable, + Position position) throws IOException { drawable.draw(renderContext.getPdDocument(), renderContext.getContentStream(), position, renderContext); } @@ -104,29 +103,27 @@ public class VerticalLayout implements Layout { * current position}. This method is responsible taking any top or bottom * margin described by the (Vertical-)LayoutHint into account. The actual * rendering of the drawable is performed by - * {@link #layoutAndDrawReleative(RenderContext, Drawable, LayoutHint)}. + * {@link #layoutAndDrawRelative(RenderContext, Drawable, LayoutHint)}. * * @param renderContext the context providing all rendering state. * @param drawable the drawable to draw. * @param layoutHint the layout hint used to layout. * @throws IOException by pdfbox */ - protected void renderReleative(RenderContext renderContext, - Drawable drawable, LayoutHint layoutHint) throws IOException { + protected void renderRelative(RenderContext renderContext, + Drawable drawable, + LayoutHint layoutHint) throws IOException { VerticalLayoutHint verticalLayoutHint = null; if (layoutHint instanceof VerticalLayoutHint) { verticalLayoutHint = (VerticalLayoutHint) layoutHint; if (verticalLayoutHint.getMarginTop() > 0) { - layoutAndDrawReleative(renderContext, new VerticalSpacer( - verticalLayoutHint.getMarginTop()), verticalLayoutHint); + layoutAndDrawRelative(renderContext, new VerticalSpacer(verticalLayoutHint.getMarginTop()), verticalLayoutHint); } } - layoutAndDrawReleative(renderContext, drawable, verticalLayoutHint); + layoutAndDrawRelative(renderContext, drawable, verticalLayoutHint); if (verticalLayoutHint != null) { if (verticalLayoutHint.getMarginBottom() > 0) { - layoutAndDrawReleative(renderContext, new VerticalSpacer( - verticalLayoutHint.getMarginBottom()), - verticalLayoutHint); + layoutAndDrawRelative(renderContext, new VerticalSpacer(verticalLayoutHint.getMarginBottom()), verticalLayoutHint); } } } @@ -135,7 +132,7 @@ public class VerticalLayout implements Layout { * Adjusts the width of the drawable (if it is {@link WidthRespecting}), and * divides it onto multiple pages if necessary. Actual drawing is delegated * to - * {@link #drawReletivePartAndMovePosition(RenderContext, Drawable, LayoutHint, boolean)} + * {@link #drawRelativePartAndMovePosition(RenderContext, Drawable, LayoutHint, boolean)} * . * * @param renderContext the context providing all rendering state. @@ -143,11 +140,12 @@ public class VerticalLayout implements Layout { * @param layoutHint the layout hint used to layout. * @throws IOException by pdfbox */ - protected void layoutAndDrawReleative(RenderContext renderContext, - Drawable drawable, LayoutHint layoutHint) throws IOException { + protected void layoutAndDrawRelative(RenderContext renderContext, + Drawable drawable, + LayoutHint layoutHint) throws IOException { float targetWidth = getTargetWidth(renderContext); boolean movePosition = true; - VerticalLayoutHint verticalLayoutHint = null; + VerticalLayoutHint verticalLayoutHint; if (layoutHint instanceof VerticalLayoutHint) { verticalLayoutHint = (VerticalLayoutHint) layoutHint; targetWidth -= verticalLayoutHint.getMarginLeft(); @@ -171,17 +169,13 @@ public class VerticalLayout implements Layout { dividable = new Cutter(drawablePart); } Dividable.Divided divided = dividable.divide(renderContext.getRemainingHeight(), renderContext.getHeight()); - drawReletivePartAndMovePosition(renderContext, divided.getFirst(), - layoutHint, true); + drawRelativePartAndMovePosition(renderContext, divided.getFirst(), layoutHint, true); // new page turnPage(renderContext); drawablePart = divided.getTail(); drawablePart = removeLeadingEmptyVerticalSpace(drawablePart, renderContext); } - - drawReletivePartAndMovePosition(renderContext, drawablePart, - layoutHint, movePosition); - + drawRelativePartAndMovePosition(renderContext, drawablePart, layoutHint, movePosition); if (drawable instanceof WidthRespecting) { if (oldMaxWidth < 0) { ((WidthRespecting) drawable).setMaxWidth(oldMaxWidth); @@ -199,14 +193,13 @@ public class VerticalLayout implements Layout { * @param renderContext the context providing all rendering state. * @param drawable the drawable to draw. * @param layoutHint the layout hint used to layout. - * @param movePosition indicates if the position should be moved (vertically) after - * drawing. + * @param movePosition indicates if the position should be moved (vertically) after drawing. * @throws IOException by pdfbox */ - protected void drawReletivePartAndMovePosition( - final RenderContext renderContext, Drawable drawable, - final LayoutHint layoutHint, final boolean movePosition) - throws IOException { + protected void drawRelativePartAndMovePosition(RenderContext renderContext, + Drawable drawable, + LayoutHint layoutHint, + boolean movePosition) throws IOException { PDPageContentStream contentStream = renderContext.getContentStream(); PageFormat pageFormat = renderContext.getPageFormat(); float offsetX = 0; diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/BarcodeCommand.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/BarcodeCommand.java index 29a181f..e189f71 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/BarcodeCommand.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/BarcodeCommand.java @@ -47,7 +47,7 @@ public class BarcodeCommand implements Command { } Alignment alignment = Alignment.valueOf(settings.get("alignment", "left").toUpperCase(Locale.ROOT)); String margin = settings.get("margin", "0 0 0 0"); - String[] margins = margin.split(" "); + String[] margins = margin.split("\\s+"); float marginleft = Float.parseFloat(margins[0]); float marginright = Float.parseFloat(margins[1]); float margintop = Float.parseFloat(margins[2]); diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/CellCommand.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/CellCommand.java index 68c69be..c58485b 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/CellCommand.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/CellCommand.java @@ -32,7 +32,7 @@ public class CellCommand implements Command { TextCell.Builder cell = TextCell.builder(); if (settings.containsSetting("padding")) { String padding = settings.get("padding", "0 0 0 0"); - String[] paddings = padding.split(" "); + String[] paddings = padding.split("\\s+"); float paddingLeft = Float.parseFloat(paddings[0]); float paddingRight = Float.parseFloat(paddings[1]); float paddingTop = Float.parseFloat(paddings[2]); diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/ChartCommand.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/ChartCommand.java index ec02da2..34ddaaf 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/ChartCommand.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/ChartCommand.java @@ -44,7 +44,7 @@ public class ChartCommand implements Command { } Alignment alignment = Alignment.valueOf(settings.get("alignment", "left").toUpperCase(Locale.ROOT)); String margin = settings.get("margin", "0 0 0 0"); - String[] margins = margin.split(" "); + String[] margins = margin.split("\\s+"); float marginleft = Float.parseFloat(margins[0]); float marginright = Float.parseFloat(margins[1]); float margintop = Float.parseFloat(margins[2]); diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/DocumentCommand.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/DocumentCommand.java index 410258b..b9e3685 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/DocumentCommand.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/DocumentCommand.java @@ -10,36 +10,63 @@ import java.io.IOException; import java.time.Instant; import java.util.Locale; +import static org.xbib.graphics.pdfbox.layout.util.PdfUtil.mmToPt; + public class DocumentCommand implements Command { @Override public void execute(Engine engine, State state, Settings settings) throws IOException { - String margin = settings.get("margin", "0 0 0 0"); - String[] margins = margin.split(" "); - PageFormat pageFormat = PageFormat.builder() - .marginLeft(Float.parseFloat(margins[0])) - .marginRight(Float.parseFloat(margins[1])) - .marginTop(Float.parseFloat(margins[2])) - .marginBottom(Float.parseFloat(margins[3])) - .pageFormat(settings.get("format", "A4")) - .orientation(settings.get("orientiation", "portrait").toUpperCase(Locale.ROOT)) - .build(); - Document document = new Document(pageFormat); - Instant instant = Instant.now(); - document.setCreationDate(instant); - document.setModificationDate(instant); + PageFormat.PageFormatBuilder pageFormat = PageFormat.builder(); + if (settings.containsSetting("pageformat")) { + pageFormat.pageFormat(settings.get("pageformat", "A4")); + } + if (settings.containsSetting("mediabox")) { + String mediabox = settings.get("mediabox"); + String[] s = mediabox.split("\\s+"); + // x y width height + pageFormat.mediaBox(mmToPt(Float.parseFloat(s[0])), mmToPt(Float.parseFloat(s[1])), + mmToPt(Float.parseFloat(s[2])), mmToPt(Float.parseFloat(s[3]))); + } + pageFormat.orientation(settings.get("orientation", "portrait").toUpperCase(Locale.ROOT)); + if (settings.containsSetting("margin")) { + String margin = settings.get("margin", "0 0 0 0"); + String[] margins = margin.split("\\s+"); + pageFormat + .marginLeft(Float.parseFloat(margins[0])) + .marginRight(Float.parseFloat(margins[1])) + .marginTop(Float.parseFloat(margins[2])) + .marginBottom(Float.parseFloat(margins[3])); + } + Document document = new Document(pageFormat.build()); if (settings.containsSetting("author")) { document.setAuthor(settings.get("author")); } if (settings.containsSetting("creator")) { document.setCreator(settings.get("creator")); } + if (settings.containsSetting("producer")) { + document.setProducer(settings.get("producer")); + } if (settings.containsSetting("subject")) { document.setSubject(settings.get("subject")); } if (settings.containsSetting("title")) { document.setTitle(settings.get("title")); } + if (settings.containsSetting("keywords")) { + document.setKeywords(settings.get("keywords")); + } + Instant instant = Instant.now(); + if (settings.containsSetting("creationdate")) { + document.setCreationDate(Instant.parse(settings.get("creationdate"))); + } else { + document.setCreationDate(instant); + } + if (settings.containsSetting("modificationddate")) { + document.setModificationDate(Instant.parse(settings.get("modificationddate"))); + } else { + document.setModificationDate(instant); + } state.elements.push(document); engine.executeElements(settings); } diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/HorizontalrulerCommand.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/HorizontalrulerCommand.java index 4481de5..82aa5b1 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/HorizontalrulerCommand.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/HorizontalrulerCommand.java @@ -18,7 +18,7 @@ public class HorizontalrulerCommand implements Command { @Override public void execute(Engine engine, State state, Settings settings) throws IOException { Stroke.StrokeBuilder strokeBuilder = Stroke.builder() - .capStyle(Stroke.CapStyle.valueOf(settings.get("capstyie", "cap").toUpperCase(Locale.ROOT))) + .capStyle(Stroke.CapStyle.valueOf(settings.get("capstyle", "cap").toUpperCase(Locale.ROOT))) .joinStyle(Stroke.JoinStyle.valueOf(settings.get("joinstyle", "miter").toUpperCase(Locale.ROOT))) .lineWidth(settings.getAsFloat("linewidth", 1f)); if (settings.containsSetting("dash")) { diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/ImageCommand.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/ImageCommand.java index 26fe4ec..8ec94ca 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/ImageCommand.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/ImageCommand.java @@ -42,7 +42,7 @@ public class ImageCommand implements Command { } Alignment alignment = Alignment.valueOf(settings.get("alignment", "left").toUpperCase(Locale.ROOT)); String margin = settings.get("margin", "0 0 0 0"); - String[] margins = margin.split(" "); + String[] margins = margin.split("\\s+"); float marginleft = Float.parseFloat(margins[0]); float marginright = Float.parseFloat(margins[1]); float margintop = Float.parseFloat(margins[2]); diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/ParagraphCommand.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/ParagraphCommand.java index 3c70fb9..434b4bd 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/ParagraphCommand.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/ParagraphCommand.java @@ -28,14 +28,17 @@ public class ParagraphCommand implements Command { paragraph.setAlignment(Alignment.valueOf(settings.get("alignment", "left").toUpperCase(Locale.ROOT))); } if (settings.containsSetting("linespacing")) { - paragraph.setLineSpacing(settings.getAsFloat("linespacing", -1f)); + paragraph.setLineSpacing(settings.getAsFloat("linespacing", 1.2f)); + } + if (settings.containsSetting("rotation")) { + paragraph.setRotation(settings.getAsFloat("rotation", 0f)); } state.elements.push(paragraph); engine.executeElements(settings); state.elements.pop(); Alignment alignment = Alignment.valueOf(settings.get("layout.alignment", "left").toUpperCase(Locale.ROOT)); String margin = settings.get("layout.margin", "0 0 0 0"); - String[] margins = margin.split(" "); + String[] margins = margin.split("\\s+"); float marginleft = Float.parseFloat(margins[0]); float marginright = Float.parseFloat(margins[1]); float margintop = Float.parseFloat(margins[2]); diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/PathCommand.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/PathCommand.java index 40682d9..6115c16 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/PathCommand.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/PathCommand.java @@ -2,8 +2,11 @@ package org.xbib.graphics.pdfbox.layout.element.scripting.command; import org.xbib.graphics.pdfbox.layout.color.ColorFactory; import org.xbib.graphics.pdfbox.layout.element.PathElement; +import org.xbib.graphics.pdfbox.layout.element.render.LayoutHint; import org.xbib.graphics.pdfbox.layout.element.scripting.Engine; import org.xbib.graphics.pdfbox.layout.element.scripting.State; +import org.xbib.graphics.pdfbox.layout.shape.LinePosiiton; +import org.xbib.graphics.pdfbox.layout.shape.MovePosition; import org.xbib.graphics.pdfbox.layout.shape.Path; import org.xbib.graphics.pdfbox.layout.shape.Stroke; import org.xbib.graphics.pdfbox.layout.text.Position; @@ -13,6 +16,7 @@ import java.awt.Color; import java.util.ArrayList; import java.util.List; import java.util.Locale; +import static org.xbib.graphics.pdfbox.layout.util.PdfUtil.mmToPt; public class PathCommand implements Command { @@ -23,30 +27,40 @@ public class PathCommand implements Command { return; } List list = new ArrayList<>(); - String[] s = value.split(" "); - Position position = null; + String[] s = value.split("\\s+"); + Position position = null; //new Position(0, 0); if (s.length > 0) { - if (settings.getAsBoolean("absolute", false)) { - position = new Position(Float.parseFloat(s[0]), Float.parseFloat(s[1])); - list.add(position); - } else { - Position p = new Position(Float.parseFloat(s[0]), Float.parseFloat(s[1])); - list.add(p); - } - for (int i = 2; i < s.length; i += 2) { - Position p = new Position(Float.parseFloat(s[i]), Float.parseFloat(s[i + 1])); + for (int i = 0; i < s.length; i += 3) { + String command = s[i]; + float x = mmToPt(Float.parseFloat(s[i + 1])); + float y = mmToPt(Float.parseFloat(s[i + 2])); + Position p; + switch (command.toUpperCase(Locale.ROOT)) { + case "M": + p = new MovePosition(x, y); + break; + case "L": + p = new LinePosiiton(x, y); + break; + default: + p = new Position(x, y); + break; + } list.add(p); + if (i == 0 && settings.getAsBoolean("position", false)) { + position = p; + } } } Path path = new Path(list); Stroke.StrokeBuilder strokeBuilder = Stroke.builder() - .capStyle(Stroke.CapStyle.valueOf(settings.get("capstyie", "cap").toUpperCase(Locale.ROOT))) + .capStyle(Stroke.CapStyle.valueOf(settings.get("capstyle", "cap").toUpperCase(Locale.ROOT))) .joinStyle(Stroke.JoinStyle.valueOf(settings.get("joinstyle", "miter").toUpperCase(Locale.ROOT))) .lineWidth(settings.getAsFloat("linewidth", 1f)); if (settings.containsSetting("dash")) { strokeBuilder.dashPattern(new Stroke.DashPattern(settings.getAsFloat("dash", 1f))); } Color color = ColorFactory.web(settings.get("color", "black")); - state.elements.peek().add(new PathElement(path, strokeBuilder.build(), color, position)); + state.elements.peek().add(new PathElement(path, strokeBuilder.build(), color, position), LayoutHint.NOP); } } diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/RowCommand.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/RowCommand.java index 81b749d..2c58a8a 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/RowCommand.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/RowCommand.java @@ -23,7 +23,7 @@ public class RowCommand implements Command { Row.Builder row = Row.builder(); if (settings.containsSetting("padding")) { String padding = settings.get("padding", "0 0 0 0"); - String[] paddings = padding.split(" "); + String[] paddings = padding.split("\\s+"); float paddingLeft = Float.parseFloat(paddings[0]); float paddingRight = Float.parseFloat(paddings[1]); float paddingTop = Float.parseFloat(paddings[2]); diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/TableCommand.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/TableCommand.java index 1b88b81..99f5244 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/TableCommand.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/TableCommand.java @@ -17,7 +17,7 @@ public class TableCommand implements Command { TableElement tableElement = new TableElement(); if (settings.containsSetting("columnwidths")) { String columnwidths = settings.get("columnwidths"); - String[] widths = columnwidths.split(" "); + String[] widths = columnwidths.split("\\s+"); for (String width : widths) { tableElement.addColumnOfWidth(mmToPt(Float.parseFloat(width))); } @@ -27,7 +27,7 @@ public class TableCommand implements Command { } if (settings.containsSetting("padding")) { String padding = settings.get("padding", "0 0 0 0"); - String[] paddings = padding.split(" "); + String[] paddings = padding.split("\\s+"); float paddingLeft = Float.parseFloat(paddings[0]); float paddingRight = Float.parseFloat(paddings[1]); float paddingTop = Float.parseFloat(paddings[2]); diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/TextCommand.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/TextCommand.java index e0f76fc..d1b6de2 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/TextCommand.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/TextCommand.java @@ -22,27 +22,34 @@ public class TextCommand implements Command { @Override public void execute(Engine engine, State state, Settings settings) { String value = settings.get("value"); - float size = settings.getAsFloat("fontsize", 11.0f); + float fontsize = settings.getAsFloat("fontsize", 11.0f); Document document = state.getDocument(); Font font = Fonts.valueOf(settings.get("font", "helvetica").toUpperCase(Locale.ROOT)).getFont(document); Element element = state.elements.peek(); if (element instanceof Paragraph) { - element.add(new TextElement(value, font, size)); + element.add(new TextElement(value, font, fontsize)); } else if (element instanceof Document) { + // wrap text into a paragraph Paragraph paragraph = new Paragraph(); if (settings.containsSetting("x") && settings.containsSetting("y")) { paragraph.setAbsolutePosition(new Position(mmToPt(settings.getAsFloat("x", 0f)), mmToPt(settings.getAsFloat("y", 0f)))); } if (settings.containsSetting("width")) { - paragraph.setMaxWidth(settings.getAsFloat("width", 0f)); + paragraph.setMaxWidth(mmToPt(settings.getAsFloat("width", 0f))); } if (settings.containsSetting("alignment")) { paragraph.setAlignment(Alignment.valueOf(settings.get("alignment", "left").toUpperCase(Locale.ROOT))); } - paragraph.add(new TextElement(value, font, size)); + if (settings.containsSetting("linespacing")) { + paragraph.setLineSpacing(settings.getAsFloat("linespacing", 1.2f)); + } + if (settings.containsSetting("rotation")) { + paragraph.setRotation(settings.getAsFloat("rotation", 0f)); + } + paragraph.add(new TextElement(value, font, fontsize)); Alignment alignment = Alignment.valueOf(settings.get("layout.alignment", "left").toUpperCase(Locale.ROOT)); String margin = settings.get("layout.margin", "0 0 0 0"); - String[] margins = margin.split(" "); + String[] margins = margin.split("\\s+"); float marginleft = Float.parseFloat(margins[0]); float marginright = Float.parseFloat(margins[1]); float margintop = Float.parseFloat(margins[2]); @@ -50,6 +57,8 @@ public class TextCommand implements Command { boolean resetY = settings.getAsBoolean("layout.resety", false); VerticalLayoutHint verticalLayoutHint = new VerticalLayoutHint(alignment, marginleft, marginright, margintop, marginbottom, resetY); element.add(paragraph, verticalLayoutHint); + } else { + throw new UnsupportedOperationException(); } } } diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/TransformCommand.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/TransformCommand.java new file mode 100644 index 0000000..584e085 --- /dev/null +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/element/scripting/command/TransformCommand.java @@ -0,0 +1,28 @@ +package org.xbib.graphics.pdfbox.layout.element.scripting.command; + +import java.io.IOException; +import org.xbib.graphics.pdfbox.layout.element.TransformElement; +import org.xbib.graphics.pdfbox.layout.element.render.LayoutHint; +import org.xbib.graphics.pdfbox.layout.element.scripting.Engine; +import org.xbib.graphics.pdfbox.layout.element.scripting.State; +import org.xbib.settings.Settings; + +import static org.xbib.graphics.pdfbox.layout.util.PdfUtil.mmToPt; + +public class TransformCommand implements Command { + + @Override + public void execute(Engine engine, State state, Settings settings) throws IOException { + TransformElement element = new TransformElement(); + if (settings.containsSetting("scalex") && settings.containsSetting("scaley")) { + element.setScale(settings.getAsFloat("scalex", null), settings.getAsFloat("scaley", null)); + } + if (settings.containsSetting("translatex") && settings.containsSetting("translatey")) { + element.setTranslate(mmToPt(settings.getAsFloat("translatex", null)), mmToPt(settings.getAsFloat("translatey", null))); + } + if (settings.containsSetting("angle") && settings.containsSetting("rotatex") && settings.containsSetting("rotatey")) { + element.setRotate(settings.getAsFloat("angle", null), mmToPt(settings.getAsFloat("rotatex", null)), mmToPt(settings.getAsFloat("rotatey", null))); + } + state.elements.peek().add(element, LayoutHint.NOP); + } +} diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/shape/LinePosiiton.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/shape/LinePosiiton.java new file mode 100644 index 0000000..cc1ecea --- /dev/null +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/shape/LinePosiiton.java @@ -0,0 +1,15 @@ +package org.xbib.graphics.pdfbox.layout.shape; + +import org.xbib.graphics.pdfbox.layout.text.Position; + +public class LinePosiiton extends Position { + /** + * Creates a position at the given coordinates for line position. + * + * @param x the x coordinate. + * @param y the y coordinate. + */ + public LinePosiiton(float x, float y) { + super(x, y); + } +} diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/shape/MovePosition.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/shape/MovePosition.java new file mode 100644 index 0000000..c266bc1 --- /dev/null +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/shape/MovePosition.java @@ -0,0 +1,15 @@ +package org.xbib.graphics.pdfbox.layout.shape; + +import org.xbib.graphics.pdfbox.layout.text.Position; + +public class MovePosition extends Position { + /** + * Creates a position at the given coordinates for move operation. + * + * @param x the x coordinate. + * @param y the y coordinate. + */ + public MovePosition(float x, float y) { + super(x, y); + } +} diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/shape/Path.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/shape/Path.java index 626d169..fd8c7ca 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/shape/Path.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/shape/Path.java @@ -26,22 +26,18 @@ public class Path implements Shape { Color color, Stroke stroke, DrawListener drawListener) throws IOException { - contentStream.saveGraphicsState(); float x = upperLeft.getX(); float y = upperLeft.getY() - stroke.getLineWidth() / 2; contentStream.setStrokingColor(color); stroke.applyTo(contentStream); - boolean move = true; for (Position p : list) { - if (move) { + if (p instanceof MovePosition) { contentStream.moveTo(x + p.getX(), y + p.getY()); - move = false; - } else { + } else if (p instanceof LinePosiiton) { contentStream.lineTo(x + p.getX(), y + p.getY()); } } contentStream.stroke(); - contentStream.restoreGraphicsState(); if (drawListener != null) { drawListener.drawn(this, upperLeft, width, height); } diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/table/StyledText.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/table/StyledText.java index f1e7254..74083b2 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/table/StyledText.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/table/StyledText.java @@ -58,7 +58,7 @@ public class StyledText implements ParagraphProcessor { String[] lines = getText().split(PdfUtil.NEW_LINE_REGEX); for (int i = 0; i < lines.length; i++) { FontDescriptor fontDescriptor = new FontDescriptor(actualFont, actualFontSize); - paragraph.add(new org.xbib.graphics.pdfbox.layout.text.StyledText(lines[i], fontDescriptor, actualColor, 0f, 0, 0)); + paragraph.add(new org.xbib.graphics.pdfbox.layout.text.StyledText(lines[i], fontDescriptor, actualColor, 0f, 0, 0, 0)); if (i < lines.length - 1) { paragraph.add(new org.xbib.graphics.pdfbox.layout.text.NewLine(new FontDescriptor(actualFont, actualFontSize))); } diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/Indent.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/Indent.java index 175f2f2..077310c 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/Indent.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/Indent.java @@ -104,7 +104,7 @@ public class Indent extends ControlFragment { break; } } - styledText = new StyledText(label, fontDescriptor, getColor(), 0, marginLeft, marginRight); + styledText = new StyledText(label, fontDescriptor, getColor(), 0, marginLeft, marginRight, 0); } catch (IOException e) { throw new UncheckedIOException(e); } @@ -117,7 +117,7 @@ public class Indent extends ControlFragment { */ public Indent(final float indentPt) { super("", DEFAULT_FONT_DESCRIPTOR); - styledText = new StyledText("", getFontDescriptor(), getColor(), 0, indentPt, 0); + styledText = new StyledText("", getFontDescriptor(), getColor(), 0, indentPt, 0, 0); } private float calculateIndent(float indentWidth, SpaceUnit indentUnit, final FontDescriptor fontDescriptor) diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/Position.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/Position.java index f8a85f0..f79a037 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/Position.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/Position.java @@ -7,6 +7,7 @@ package org.xbib.graphics.pdfbox.layout.text; public class Position { private final float x; + private final float y; /** diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/StyledText.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/StyledText.java index f4d7a91..2b07b98 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/StyledText.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/StyledText.java @@ -22,6 +22,8 @@ public class StyledText implements TextFragment { private final float baselineOffset; + private final float rotation; + /** * The cached (calculated) width of the text. */ @@ -45,7 +47,7 @@ public class StyledText implements TextFragment { * @param color the color to use. */ public StyledText(String text, FontDescriptor fontDescriptor, Color color) { - this(text, fontDescriptor, color, 0, 0, 0); + this(text, fontDescriptor, color, 0, 0, 0, 0); } /** @@ -57,11 +59,12 @@ public class StyledText implements TextFragment { * @param baselineOffset the offset of the baseline. * @param leftMargin the margin left to the text. * @param rightMargin the margin right to the text. + * @param rotation the rotation of the text, 0 is unrotated */ public StyledText(String text, FontDescriptor fontDescriptor, Color color, - float baselineOffset, float leftMargin, float rightMargin) { + float baselineOffset, float leftMargin, float rightMargin, float rotation) { if (text.contains("\n")) { throw new IllegalArgumentException("StyledText must not contain line breaks, use TextFragment.LINEBREAK for that"); } @@ -77,6 +80,7 @@ public class StyledText implements TextFragment { this.leftMargin = leftMargin; this.rightMargin = rightMargin; this.baselineOffset = baselineOffset; + this.rotation = rotation; } /** @@ -124,6 +128,10 @@ public class StyledText implements TextFragment { return baselineOffset; } + public float getRotation() { + return rotation; + } + @Override public Color getColor() { return color; @@ -164,8 +172,7 @@ public class StyledText implements TextFragment { } public StyledText inheritAttributes(String text, float leftMargin, float rightMargin) { - return new StyledText(text, getFontDescriptor(), getColor(), - getBaselineOffset(), leftMargin, rightMargin); + return new StyledText(text, getFontDescriptor(), getColor(), getBaselineOffset(), leftMargin, rightMargin, getRotation()); } private static float getWidth(FontDescriptor fontDescriptor, String text) { @@ -181,6 +188,6 @@ public class StyledText implements TextFragment { return "StyledText [text=" + text + ", fontDescriptor=" + fontDescriptor + ", width=" + width + ", color=" + color + ", leftMargin=" + leftMargin + ", rightMargin=" + rightMargin - + ", baselineOffset=" + baselineOffset + "]"; + + ", baselineOffset=" + baselineOffset + ",rotation=" + rotation + "]"; } } diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/TextFlow.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/TextFlow.java index c98b862..a7d17b3 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/TextFlow.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/TextFlow.java @@ -53,6 +53,8 @@ public class TextFlow implements TextSequence, WidthRespecting { private float lineSpacing = DEFAULT_LINE_SPACING; + private float rotation = 0f; + private float maxWidth = -1; private boolean applyLineSpacingToFirstLine = true; @@ -71,15 +73,15 @@ public class TextFlow implements TextSequence, WidthRespecting { } public void addText(String text, float fontSize, Font font) { - add(TextFlowUtil.createTextFlow(text, new FontDescriptor(font, fontSize), lineSpacing)); + add(TextFlowUtil.createTextFlow(text, new FontDescriptor(font, fontSize), lineSpacing, rotation)); } public void addMarkup(String markup, FontDescriptor fontDescriptor) { - add(TextFlowUtil.createTextFlowFromMarkup(markup, fontDescriptor, lineSpacing)); + add(TextFlowUtil.createTextFlowFromMarkup(markup, fontDescriptor, lineSpacing, rotation)); } public void addMarkup(String markup, float fontSize, Font font) { - add(TextFlowUtil.createTextFlowFromMarkup(markup, new FontDescriptor(font, fontSize), lineSpacing)); + add(TextFlowUtil.createTextFlowFromMarkup(markup, new FontDescriptor(font, fontSize), lineSpacing, rotation)); } public void addIndent(String label, float indentWidth, SpaceUnit indentUnit, float fontsize, Font font) { @@ -158,14 +160,6 @@ public class TextFlow implements TextSequence, WidthRespecting { clearCache(); } - /** - * @return the factor multiplied with the height to calculate the line - * spacing. - */ - public float getLineSpacing() { - return lineSpacing; - } - /** * Sets the factor multiplied with the height to calculate the line spacing. * @@ -176,6 +170,14 @@ public class TextFlow implements TextSequence, WidthRespecting { clearCache(); } + /** + * @return the factor multiplied with the height to calculate the line + * spacing. + */ + public float getLineSpacing() { + return lineSpacing; + } + /** * Indicates if the line spacing should be applied to the first line. Makes * sense if there is text above to achieve an equal spacing. In case you @@ -201,6 +203,14 @@ public class TextFlow implements TextSequence, WidthRespecting { this.applyLineSpacingToFirstLine = applyLineSpacingToFirstLine; } + public void setRotation(float rotation) { + this.rotation = rotation; + } + + public float getRotation() { + return rotation; + } + @Override public float getWidth() { Float width = getCachedValue(WIDTH, Float.class); diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/TextFlowUtil.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/TextFlowUtil.java index ad149bc..6c7b6cb 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/TextFlowUtil.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/TextFlowUtil.java @@ -15,8 +15,9 @@ import java.util.regex.Matcher; public class TextFlowUtil { - public static TextFlow createTextFlow(String text, FontDescriptor descriptor, float linespacing) { - return createTextFlow(fromPlainText(text), descriptor, linespacing); + public static TextFlow createTextFlow(String text, FontDescriptor descriptor, + float linespacing, float rotation) { + return createTextFlow(fromPlainText(text), descriptor, linespacing, rotation); } /** @@ -51,8 +52,9 @@ public class TextFlowUtil { * @param linespacing the line spacing * @return the created text flow. */ - public static TextFlow createTextFlowFromMarkup(String markup, FontDescriptor descriptor, float linespacing) { - return createTextFlow(fromMarkup(markup), descriptor, linespacing); + public static TextFlow createTextFlowFromMarkup(String markup, FontDescriptor descriptor, + float linespacing, float rotation) { + return createTextFlow(fromMarkup(markup), descriptor, linespacing, rotation); } /** @@ -63,7 +65,8 @@ public class TextFlowUtil { * @param linespacing the line spacing * @return the created text flow. */ - protected static TextFlow createTextFlow(Iterable parts, FontDescriptor descriptor, float linespacing) { + protected static TextFlow createTextFlow(Iterable parts, FontDescriptor descriptor, + float linespacing, float rotation) { final TextFlow textFlow = new TextFlow(); textFlow.setLineSpacing(linespacing); boolean bold = false; @@ -133,8 +136,7 @@ public class TextFlowUtil { } FontDescriptor fontDescriptor = new FontDescriptor(descriptor.getFont(), currentFontSize, bold, italic); if (annotationMap.isEmpty()) { - StyledText styledText = new StyledText(fragment.toString(), fontDescriptor, - color, baselineOffset, 0, 0); + StyledText styledText = new StyledText(fragment.toString(), fontDescriptor, color, baselineOffset, 0, 0, rotation); textFlow.add(styledText); } else { AnnotatedStyledText styledText = @@ -165,10 +167,8 @@ public class TextFlowUtil { * @param text the original text. * @return the create char sequence. */ - public static Iterable fromPlainText( - final Iterable text) { - Iterable result = splitByControlCharacter( - ControlCharacters.NEWLINE_FACTORY, text); + public static Iterable fromPlainText(final Iterable text) { + Iterable result = splitByControlCharacter(ControlCharacters.NEWLINE_FACTORY, text); result = unescapeBackslash(result); return result; } diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/TextLine.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/TextLine.java index 2561c07..f650ef3 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/TextLine.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/TextLine.java @@ -191,6 +191,10 @@ public class TextLine implements TextSequence { matrix = matrix.multiply(new Matrix(1, 0, 0, 1, gap, baselineDelta)); x += gap; } + boolean isRotated = styledText.getRotation() > 0f; + if (isRotated) { + matrix.rotate(Math.toRadians(styledText.getRotation())); + } contentStream.beginText(); contentStream.setTextMatrix(matrix); if (!styledText.getFontDescriptor().equals(lastFontDesc)) { @@ -271,7 +275,5 @@ public class TextLine implements TextSequence { public void remove() { throw new UnsupportedOperationException(); } - } - } diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/annotations/AnnotatedStyledText.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/annotations/AnnotatedStyledText.java index 349d852..8be5a0d 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/annotations/AnnotatedStyledText.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/text/annotations/AnnotatedStyledText.java @@ -35,7 +35,7 @@ public class AnnotatedStyledText extends StyledText implements Annotated { final float rightMargin, final float baselineOffset, Collection annotations) { - super(text, fontDescriptor, color, baselineOffset, leftMargin, rightMargin); + super(text, fontDescriptor, color, baselineOffset, leftMargin, rightMargin, 0); if (annotations != null) { this.annotations.addAll(annotations); } diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/util/TextSequenceUtil.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/util/TextSequenceUtil.java index e5f65a0..9593ede 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/util/TextSequenceUtil.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/util/TextSequenceUtil.java @@ -316,10 +316,9 @@ public class TextSequenceUtil { protected static TextFragment deriveFromExisting(TextFragment toDeriveFrom, String text, float leftMargin, float rightMargin) { if (toDeriveFrom instanceof StyledText) { - return ((StyledText) toDeriveFrom).inheritAttributes(text, - leftMargin, rightMargin); + return ((StyledText) toDeriveFrom).inheritAttributes(text, leftMargin, rightMargin); } - return new StyledText(text, toDeriveFrom.getFontDescriptor(), toDeriveFrom.getColor(), 0, leftMargin, rightMargin); + return new StyledText(text, toDeriveFrom.getFontDescriptor(), toDeriveFrom.getColor(), 0, leftMargin, rightMargin, 0); } private static Pair breakWord(TextFragment word, diff --git a/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/CustomRendererTest.java b/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/CustomRendererTest.java index 41c3981..5b35fed 100644 --- a/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/CustomRendererTest.java +++ b/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/CustomRendererTest.java @@ -98,7 +98,7 @@ public class CustomRendererTest { public void afterPage(RenderContext renderContext) { String content = String.format("Section %s, Page %s", sectionNumber, renderContext.getPageIndex() + 1); FontDescriptor fontDescriptor = new FontDescriptor(BaseFont.TIMES, 11); - TextFlow text = TextFlowUtil.createTextFlow(content, fontDescriptor, 1.2f); + TextFlow text = TextFlowUtil.createTextFlow(content, fontDescriptor, 1.2f, 0f); float offset = renderContext.getPageFormat().getMarginLeft() + TextSequenceUtil.getOffset(text, renderContext.getWidth(), Alignment.RIGHT); text.drawText(renderContext.getContentStream(), new Position( diff --git a/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/ListenerTest.java b/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/ListenerTest.java index e99c52e..6080fc1 100644 --- a/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/ListenerTest.java +++ b/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/ListenerTest.java @@ -48,7 +48,7 @@ public class ListenerTest { public void afterPage(RenderContext renderContext) { String content = String.format("Page %s", renderContext.getPageIndex() + 1); FontDescriptor fontDescriptor = new FontDescriptor(BaseFont.HELVETICA, 11); - TextFlow text = TextFlowUtil.createTextFlow(content, fontDescriptor, 1.2f); + TextFlow text = TextFlowUtil.createTextFlow(content, fontDescriptor, 1.2f, 0f); float offset = renderContext.getPageFormat().getMarginLeft() + TextSequenceUtil.getOffset(text, renderContext.getWidth(), Alignment.RIGHT); diff --git a/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/LowLevelText.java b/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/LowLevelText.java index 857e4f4..bc847c4 100644 --- a/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/LowLevelText.java +++ b/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/LowLevelText.java @@ -54,7 +54,7 @@ public class LowLevelText { TextFlow text = TextFlowUtil.createTextFlowFromMarkup( "Hello *bold _italic bold-end* italic-end_. Eirmod\ntempor invidunt ut \\*labore", - new FontDescriptor(BaseFont.TIMES, 11), 1.2f); + new FontDescriptor(BaseFont.TIMES, 11), 1.2f, 0f); text.addText("Spongebob", 11, BaseFont.COURIER); text.addText(" is ", 20, BaseFont.HELVETICA); text.addText("cool", 7, BaseFont.HELVETICA); diff --git a/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/RotationTest.java b/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/PageFormatRotationTest.java similarity index 99% rename from graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/RotationTest.java rename to graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/PageFormatRotationTest.java index cafc23b..cca3141 100644 --- a/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/RotationTest.java +++ b/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/PageFormatRotationTest.java @@ -12,7 +12,7 @@ import org.xbib.graphics.pdfbox.layout.element.render.VerticalLayoutHint; import org.xbib.graphics.pdfbox.layout.font.BaseFont; import java.io.FileOutputStream; -public class RotationTest { +public class PageFormatRotationTest { @Test public void test() throws Exception { diff --git a/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/TextRotationTest.java b/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/TextRotationTest.java new file mode 100644 index 0000000..23cd87f --- /dev/null +++ b/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/TextRotationTest.java @@ -0,0 +1,28 @@ +package org.xbib.graphics.pdfbox.layout.test; + +import java.io.FileOutputStream; +import org.junit.jupiter.api.Test; +import org.xbib.graphics.pdfbox.layout.element.Document; +import org.xbib.graphics.pdfbox.layout.element.Paragraph; +import org.xbib.graphics.pdfbox.layout.font.BaseFont; + +public class TextRotationTest { + + @Test + public void test() throws Exception { + Document document = new Document(40, 60, 40, 60); + + Paragraph paragraph = new Paragraph(); + paragraph.addMarkup("Hello there, here is text text text text text text text text text text text text text text text text" + + " text text text text text text text text text text text", + 10, BaseFont.HELVETICA); + paragraph.setMaxWidth(100); + document.add(paragraph); + + paragraph = new Paragraph(); + paragraph.setRotation(90); + paragraph.addMarkup("Hello\u00a0Text\u00a0Rotation", 10, BaseFont.HELVETICA); + document.add(paragraph); + document.render().save(new FileOutputStream("build/textrotation.pdf")).close(); + } +} diff --git a/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/table/TableTest.java b/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/table/TableTest.java index ca6bd1d..7efb199 100644 --- a/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/table/TableTest.java +++ b/graphics-pdfbox-layout/src/test/java/org/xbib/graphics/pdfbox/layout/test/table/TableTest.java @@ -37,13 +37,13 @@ public class TableTest { try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) { Table myTable = Table.builder() .addColumnsOfWidth(200, 200) - .padding(2) + .padding(2, 2, 2, 2) .addRow(Row.builder() .add(TextCell.builder().text("One One").borderWidth(4).backgroundColor(Color.WHITE).build()) .add(TextCell.builder().text("One Two").borderWidth(0).backgroundColor(Color.YELLOW).build()) .build()) .addRow(Row.builder() - .padding(10) + .padding(10, 10 ,10 ,10) .add(TextCell.builder().text("Two One").textColor(Color.RED).build()) .add(TextCell.builder().text("Two Two") .borderWidthRight(1f) diff --git a/graphics-pdfbox-layout/src/test/resources/org/xbib/graphics/pdfbox/layout/test/elements.json b/graphics-pdfbox-layout/src/test/resources/org/xbib/graphics/pdfbox/layout/test/elements.json index 91720a2..89b6500 100644 --- a/graphics-pdfbox-layout/src/test/resources/org/xbib/graphics/pdfbox/layout/test/elements.json +++ b/graphics-pdfbox-layout/src/test/resources/org/xbib/graphics/pdfbox/layout/test/elements.json @@ -27,7 +27,7 @@ { "type": "text", "value": "Hello World 1", - "size": 24, + "fontsize": 24, "font": "helvetica" } ] @@ -38,7 +38,7 @@ { "type": "text", "value": "Hello World 2", - "size": 24, + "fontsize": 24, "font": "helvetica" } ] @@ -49,7 +49,7 @@ { "type": "text", "value": "Hello World 3", - "size": 24, + "fontsize": 24, "font": "helvetica" } ] @@ -63,7 +63,7 @@ { "type": "text", "value": "Hello World 4", - "size": 16, + "fontsize": 16, "font": "notosans" } ] @@ -74,7 +74,7 @@ { "type": "text", "value": "Hello World 5", - "size": 20, + "fontsize": 20, "font": "notosans" } ] @@ -172,7 +172,7 @@ { "type": "text", "value": "Hello World 6", - "size": 20, + "fontsize": 20, "font": "notosans" } ]