add transform to underline annotations
This commit is contained in:
parent
97ed576828
commit
b3167d16ce
14 changed files with 88 additions and 58 deletions
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -63,6 +64,11 @@ public class ParagraphCellRenderer extends AbstractCellRenderer<ParagraphCell> {
|
||||||
public PDPageContentStream getCurrentPageContentStream() {
|
public PDPageContentStream getCurrentPageContentStream() {
|
||||||
return tableRenderContext.getContentStream();
|
return tableRenderContext.getContentStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Transform getTransform() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -215,6 +215,17 @@
|
||||||
"font": "notosans"
|
"font": "notosans"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "paragraph",
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"type": "markup",
|
||||||
|
"text": "__{0.25:}Hello World 7__",
|
||||||
|
"fontsize": 20,
|
||||||
|
"font": "notosans"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue