add transform to underline annotations

This commit is contained in:
Jörg Prante 2023-08-23 11:24:05 +02:00
parent 97ed576828
commit b3167d16ce
14 changed files with 88 additions and 58 deletions

View file

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

View file

@ -274,8 +274,7 @@ public class RenderContext implements Renderer, Closeable, DrawContext, DrawList
if (positionElement instanceof ResetPosition) { if (positionElement instanceof ResetPosition) {
currentPosition = new Position(getMarkedPosition().getX(), getMarkedPosition().getY()); currentPosition = new Position(getMarkedPosition().getX(), getMarkedPosition().getY());
} }
if (positionElement instanceof SetPosition) { if (positionElement instanceof SetPosition setPosition) {
SetPosition setPosition = (SetPosition) positionElement;
Float x = setPosition.getX(); Float x = setPosition.getX();
if (x == null) { if (x == null) {
x = getCurrentPosition().getX(); x = getCurrentPosition().getX();
@ -287,8 +286,7 @@ public class RenderContext implements Renderer, Closeable, DrawContext, DrawList
currentPosition = new Position(x, y); currentPosition = new Position(x, y);
return true; return true;
} }
if (positionElement instanceof MovePosition) { if (positionElement instanceof MovePosition movePosition) {
MovePosition movePosition = (MovePosition) positionElement;
movePositionBy(movePosition.getX(), movePosition.getY()); movePositionBy(movePosition.getX(), movePosition.getY());
return true; return true;
} }

View file

@ -202,21 +202,14 @@ public class VerticalLayout implements Layout {
PDPageContentStream contentStream = renderContext.getCurrentPageContentStream(); PDPageContentStream contentStream = renderContext.getCurrentPageContentStream();
PageFormat pageFormat = renderContext.getPageFormat(); PageFormat pageFormat = renderContext.getPageFormat();
float offsetX = 0; float offsetX = 0;
if (layoutHint instanceof VerticalLayoutHint) { if (layoutHint instanceof VerticalLayoutHint verticalLayoutHint) {
VerticalLayoutHint verticalLayoutHint = (VerticalLayoutHint) layoutHint;
Alignment alignment = verticalLayoutHint.getAlignment(); Alignment alignment = verticalLayoutHint.getAlignment();
float horizontalExtraSpace = getTargetWidth(renderContext) - drawable.getWidth(); float horizontalExtraSpace = getTargetWidth(renderContext) - drawable.getWidth();
switch (alignment) { offsetX = switch (alignment) {
case RIGHT: case RIGHT -> horizontalExtraSpace - verticalLayoutHint.getMarginRight();
offsetX = horizontalExtraSpace - verticalLayoutHint.getMarginRight(); case CENTER -> horizontalExtraSpace / 2f;
break; default -> verticalLayoutHint.getMarginLeft();
case CENTER: };
offsetX = horizontalExtraSpace / 2f;
break;
default:
offsetX = verticalLayoutHint.getMarginLeft();
break;
}
} }
contentStream.saveGraphicsState(); contentStream.saveGraphicsState();
if (renderContext.getTransform() != null) { if (renderContext.getTransform() != null) {

View file

@ -4,6 +4,7 @@ import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.xbib.graphics.pdfbox.layout.element.Paragraph; import org.xbib.graphics.pdfbox.layout.element.Paragraph;
import org.xbib.graphics.pdfbox.layout.element.render.Transform;
import org.xbib.graphics.pdfbox.layout.table.HorizontalAlignment; import org.xbib.graphics.pdfbox.layout.table.HorizontalAlignment;
import org.xbib.graphics.pdfbox.layout.table.ParagraphCell; import org.xbib.graphics.pdfbox.layout.table.ParagraphCell;
import org.xbib.graphics.pdfbox.layout.text.Alignment; import org.xbib.graphics.pdfbox.layout.text.Alignment;
@ -49,21 +50,26 @@ public class ParagraphCellRenderer extends AbstractCellRenderer<ParagraphCell> {
private AnnotationDrawListener createAndGetAnnotationDrawListenerWith(TableRenderContext tableRenderContext) { private AnnotationDrawListener createAndGetAnnotationDrawListenerWith(TableRenderContext tableRenderContext) {
return new AnnotationDrawListener(new DrawContext() { return new AnnotationDrawListener(new DrawContext() {
@Override @Override
public PDDocument getPdDocument() { public PDDocument getPdDocument() {
return tableRenderContext.getPdDocument(); return tableRenderContext.getPdDocument();
} }
@Override @Override
public PDPage getCurrentPage() { public PDPage getCurrentPage() {
return tableRenderContext.getPage(); return tableRenderContext.getPage();
} }
@Override @Override
public PDPageContentStream getCurrentPageContentStream() { public PDPageContentStream getCurrentPageContentStream() {
return tableRenderContext.getContentStream(); return tableRenderContext.getContentStream();
} }
});
@Override
public Transform getTransform() {
return null;
}
});
} }
} }

View file

@ -16,7 +16,10 @@ public class TableRenderContext {
private final Point2D.Float startingPoint; private final Point2D.Float startingPoint;
public TableRenderContext(PDDocument pdDocument, PDPageContentStream contentStream, PDPage page, Point2D.Float startingPoint) { public TableRenderContext(PDDocument pdDocument,
PDPageContentStream contentStream,
PDPage page,
Point2D.Float startingPoint) {
this.pdDocument = pdDocument; this.pdDocument = pdDocument;
this.contentStream = contentStream; this.contentStream = contentStream;
this.page = page; this.page = page;

View file

@ -3,6 +3,7 @@ package org.xbib.graphics.pdfbox.layout.text;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.xbib.graphics.pdfbox.layout.element.render.Transform;
/** /**
* Provides the current page and document to draw to. * Provides the current page and document to draw to.
@ -23,4 +24,7 @@ public interface DrawContext {
* @return the current page content stream. * @return the current page content stream.
*/ */
PDPageContentStream getCurrentPageContentStream(); PDPageContentStream getCurrentPageContentStream();
Transform getTransform();
} }

View file

@ -11,7 +11,6 @@ public class ReplacedWhitespace extends ControlFragment {
public ReplacedWhitespace(String replacedSpace, FontDescriptor fontDescriptor) { public ReplacedWhitespace(String replacedSpace, FontDescriptor fontDescriptor) {
super("", fontDescriptor); super("", fontDescriptor);
this.replacedSpace = replacedSpace; this.replacedSpace = replacedSpace;
} }

View file

@ -121,8 +121,7 @@ public class TextFlowUtil {
currentIndent = last; currentIndent = last;
} }
indentStack.push(currentIndent); indentStack.push(currentIndent);
FontDescriptor fontDescriptor = FontDescriptor fontDescriptor = new FontDescriptor(descriptor.getFonts(), descriptor.getSize(), bold, italic);
new FontDescriptor(descriptor.getFonts(), descriptor.getSize(), bold, italic);
textFlow.add(currentIndent.createNewIndent(fontDescriptor, color)); textFlow.add(currentIndent.createNewIndent(fontDescriptor, color));
} }
} }
@ -138,8 +137,7 @@ public class TextFlowUtil {
StyledText styledText = new StyledText(fragment.toString(), fontDescriptor, color, baselineOffset, 0, 0, rotation); StyledText styledText = new StyledText(fragment.toString(), fontDescriptor, color, baselineOffset, 0, 0, rotation);
textFlow.add(styledText); textFlow.add(styledText);
} else { } else {
AnnotatedStyledText styledText = AnnotatedStyledText styledText = new AnnotatedStyledText(fragment.toString(), fontDescriptor,
new AnnotatedStyledText(fragment.toString(), fontDescriptor,
color, baselineOffset, 0, 0, annotationMap.values()); color, baselineOffset, 0, 0, annotationMap.values());
textFlow.add(styledText); textFlow.add(styledText);
} }
@ -226,13 +224,10 @@ public class TextFlowUtil {
List<CharSequence> result = new ArrayList<>(); List<CharSequence> result = new ArrayList<>();
boolean beginOfLine = true; boolean beginOfLine = true;
for (CharSequence current : markup) { for (CharSequence current : markup) {
if (current instanceof String) { if (current instanceof String string) {
String string = (String) current;
int begin = 0; int begin = 0;
if (!controlCharacterFactory.patternMatchesBeginOfLine() if (!controlCharacterFactory.patternMatchesBeginOfLine() || beginOfLine) {
|| beginOfLine) { Matcher matcher = controlCharacterFactory.getPattern().matcher(string);
Matcher matcher = controlCharacterFactory.getPattern()
.matcher(string);
while (matcher.find()) { while (matcher.find()) {
String part = string.substring(begin, matcher.start()); String part = string.substring(begin, matcher.start());
begin = matcher.end(); begin = matcher.end();

View file

@ -1,6 +1,5 @@
package org.xbib.graphics.pdfbox.layout.text.annotations; package org.xbib.graphics.pdfbox.layout.text.annotations;
import org.xbib.graphics.pdfbox.layout.font.Font;
import org.xbib.graphics.pdfbox.layout.font.FontDescriptor; import org.xbib.graphics.pdfbox.layout.font.FontDescriptor;
import org.xbib.graphics.pdfbox.layout.text.StyledText; import org.xbib.graphics.pdfbox.layout.text.StyledText;
import java.awt.Color; import java.awt.Color;
@ -84,7 +83,8 @@ public class AnnotatedStyledText extends StyledText implements Annotated {
} }
@Override @Override
public AnnotatedStyledText inheritAttributes(String text, float leftMargin, public AnnotatedStyledText inheritAttributes(String text,
float leftMargin,
float rightMargin) { float rightMargin) {
return new AnnotatedStyledText(text, getFontDescriptor(), getColor(), return new AnnotatedStyledText(text, getFontDescriptor(), getColor(),
getBaselineOffset(), leftMargin, rightMargin, annotations); getBaselineOffset(), leftMargin, rightMargin, annotations);

View file

@ -33,7 +33,7 @@ public class AnnotationDrawListener implements DrawListener, RenderListener {
* @param drawContext the context which provides the {@link PDDocument} and the * @param drawContext the context which provides the {@link PDDocument} and the
* {@link PDPage} currently drawn to. * {@link PDPage} currently drawn to.
*/ */
public AnnotationDrawListener(final DrawContext drawContext) { public AnnotationDrawListener(DrawContext drawContext) {
this.drawContext = drawContext; this.drawContext = drawContext;
annotationProcessors = AnnotationProcessorFactory.createAnnotationProcessors(); annotationProcessors = AnnotationProcessorFactory.createAnnotationProcessors();
} }

View file

@ -37,16 +37,18 @@ public class HyperlinkAnnotationProcessor implements AnnotationProcessor {
private final Map<PDPage, List<Hyperlink>> linkMap = new HashMap<>(); private final Map<PDPage, List<Hyperlink>> linkMap = new HashMap<>();
public HyperlinkAnnotationProcessor() {
}
@Override @Override
public void annotatedObjectDrawn(Annotated drawnObject, public void annotatedObjectDrawn(Annotated drawnObject,
DrawContext drawContext, DrawContext drawContext,
Position upperLeft, Position upperLeft,
float width, float width,
float height) { float height) {
if (!(drawnObject instanceof AnnotatedStyledText)) { if (!(drawnObject instanceof AnnotatedStyledText annotatedText)) {
return; return;
} }
AnnotatedStyledText annotatedText = (AnnotatedStyledText) drawnObject;
handleHyperlinkAnnotations(annotatedText, drawContext, upperLeft, width, height); handleHyperlinkAnnotations(annotatedText, drawContext, upperLeft, width, height);
handleAnchorAnnotations(annotatedText, drawContext, upperLeft); handleAnchorAnnotations(annotatedText, drawContext, upperLeft);
} }

View file

@ -2,6 +2,7 @@ package org.xbib.graphics.pdfbox.layout.text.annotations;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.xbib.graphics.pdfbox.layout.element.render.Transform;
import org.xbib.graphics.pdfbox.layout.shape.Stroke; import org.xbib.graphics.pdfbox.layout.shape.Stroke;
import org.xbib.graphics.pdfbox.layout.text.DrawContext; import org.xbib.graphics.pdfbox.layout.text.DrawContext;
import org.xbib.graphics.pdfbox.layout.position.Position; import org.xbib.graphics.pdfbox.layout.position.Position;
@ -19,7 +20,10 @@ import java.util.List;
*/ */
public class UnderlineAnnotationProcessor implements AnnotationProcessor { public class UnderlineAnnotationProcessor implements AnnotationProcessor {
private final List<Line> linesOnPage = new ArrayList<>(); private final List<Line> lines = new ArrayList<>();
public UnderlineAnnotationProcessor() {
}
@Override @Override
public void annotatedObjectDrawn(Annotated drawnObject, public void annotatedObjectDrawn(Annotated drawnObject,
@ -38,27 +42,27 @@ public class UnderlineAnnotationProcessor implements AnnotationProcessor {
Position start = new Position(upperLeft.getX(), upperLeft.getY() - ascent + baselineOffset); Position start = new Position(upperLeft.getX(), upperLeft.getY() - ascent + baselineOffset);
Position end = new Position(start.getX() + width, start.getY()); Position end = new Position(start.getX() + width, start.getY());
Stroke stroke = Stroke.builder().lineWidth(thickness).build(); Stroke stroke = Stroke.builder().lineWidth(thickness).build();
Line line = new Line(start, end, stroke, drawnText.getColor()); Line line = new Line(start, end, stroke, drawnText.getColor(), drawContext.getTransform());
linesOnPage.add(line); lines.add(line);
} }
} }
@Override @Override
public void beforePage(DrawContext drawContext) { public void beforePage(DrawContext drawContext) {
linesOnPage.clear(); lines.clear();
} }
@Override @Override
public void afterPage(DrawContext drawContext) { public void afterPage(DrawContext drawContext) {
for (Line line : linesOnPage) { for (Line line : lines) {
line.draw(drawContext.getCurrentPageContentStream()); line.draw(drawContext.getCurrentPageContentStream());
} }
linesOnPage.clear(); lines.clear();
} }
@Override @Override
public void afterRender(PDDocument document) { public void afterRender(PDDocument document) {
linesOnPage.clear(); lines.clear();
} }
private static class Line { private static class Line {
@ -71,16 +75,23 @@ public class UnderlineAnnotationProcessor implements AnnotationProcessor {
private final Color color; private final Color color;
public Line(Position start, Position end, Stroke stroke, Color color) { private final Transform transform;
public Line(Position start, Position end, Stroke stroke, Color color, Transform transform) {
super(); super();
this.start = start; this.start = start;
this.end = end; this.end = end;
this.stroke = stroke; this.stroke = stroke;
this.color = color; this.color = color;
this.transform = transform;
} }
public void draw(PDPageContentStream contentStream) { public void draw(PDPageContentStream contentStream) {
try { try {
if (transform != null) {
contentStream.saveGraphicsState();
contentStream.transform(transform.getMatrix());
}
if (color != null) { if (color != null) {
contentStream.setStrokingColor(color); contentStream.setStrokingColor(color);
} }
@ -90,6 +101,9 @@ public class UnderlineAnnotationProcessor implements AnnotationProcessor {
contentStream.moveTo(start.getX(), start.getY()); contentStream.moveTo(start.getX(), start.getY());
contentStream.lineTo(end.getX(), end.getY()); contentStream.lineTo(end.getX(), end.getY());
contentStream.stroke(); contentStream.stroke();
if (transform != null) {
contentStream.restoreGraphicsState();
}
} catch (IOException e) { } catch (IOException e) {
throw new UncheckedIOException(e); throw new UncheckedIOException(e);
} }

View file

@ -6,6 +6,7 @@ import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.util.Matrix; import org.apache.pdfbox.util.Matrix;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.xbib.graphics.pdfbox.layout.element.PageFormat; import org.xbib.graphics.pdfbox.layout.element.PageFormat;
import org.xbib.graphics.pdfbox.layout.element.render.Transform;
import org.xbib.graphics.pdfbox.layout.font.FontDescriptor; import org.xbib.graphics.pdfbox.layout.font.FontDescriptor;
import org.xbib.graphics.pdfbox.layout.shape.RoundRect; import org.xbib.graphics.pdfbox.layout.shape.RoundRect;
import org.xbib.graphics.pdfbox.layout.shape.Shape; import org.xbib.graphics.pdfbox.layout.shape.Shape;
@ -32,8 +33,7 @@ public class LowLevelText {
float pageWidth = page.getMediaBox().getWidth(); float pageWidth = page.getMediaBox().getWidth();
float pageHeight = page.getMediaBox().getHeight(); float pageHeight = page.getMediaBox().getHeight();
pdDocument.addPage(page); pdDocument.addPage(page);
final PDPageContentStream contentStream = final PDPageContentStream contentStream = new PDPageContentStream(pdDocument, page, PDPageContentStream.AppendMode.APPEND, true);
new PDPageContentStream(pdDocument, page, PDPageContentStream.AppendMode.APPEND, true);
AnnotationDrawListener annotationDrawListener = new AnnotationDrawListener(new DrawContext() { AnnotationDrawListener annotationDrawListener = new AnnotationDrawListener(new DrawContext() {
@ -52,6 +52,11 @@ public class LowLevelText {
return contentStream; return contentStream;
} }
@Override
public Transform getTransform() {
return null;
}
}); });
annotationDrawListener.beforePage(null); annotationDrawListener.beforePage(null);

View file

@ -215,6 +215,17 @@
"font": "notosans" "font": "notosans"
} }
] ]
},
{
"type": "paragraph",
"elements": [
{
"type": "markup",
"text": "__{0.25:}Hello World 7__",
"fontsize": 20,
"font": "notosans"
}
]
} }
] ]
} }