tldr;如何访问等于LineBreakMeasurer使用的TextLayout
段的非矢量化文本?
我构建了一个程序,该程序使用Orson PDF库和Java 2D API生成报告。要使用换行符获得格式良好的多段文字,请使用Java's built-in LineBreakMeasurer。效果很好,结果看起来不错,但是我无法选择使用此方法呈现的任何文本,因此我着手找出原因。
浏览完运行时方法后,我看到发生这种情况的原因是它在绘制文本之前先对其进行矢量化处理!因此,将忽略我使用标准文本而不是矢量化添加到Graphics2D
对象的渲染提示,因为它们仅由Graphics#drawString(String s)
使用。这使得无法使用Orson中的内置PDF原语呈现文本,因此,如果我要使用这种方法,我需要找到一种方法来知道TextLayout
对象对应于哪些文本段,并使用drawString
知道等价的矢量文本后就可以放在行上。
// This is the vectorized text that will be written using Graphics2D
TextLayout layout = lineMeasurer.nextLayout(breakWidth);
如果您查看下面的算法,其中涉及TextLayout
,LineBreakMeasurer
,AttributedCharacterIterator
和FontRenderContext
,则没有任何直接候选。我可以将迭代器包装在一个类似的接口中,并通过该接口知道看到了哪些字符,但是我无法知道它仅读取它需要知道的内容,而这与内部实现紧密相关。
这是换行算法的主要部分:
// Create a new LineBreakMeasurer from the paragraph.
AttributedCharacterIterator paragraph = text.getIterator();
// index of the first character in the paragraph.
int paragraphStart = paragraph.getBeginIndex();
// index of the first character after the end of the paragraph.
paragraphEnd = paragraph.getEndIndex();
FontRenderContext frc = g2d.getFontRenderContext();
// The LineBreakMeasurer used to line-break the paragraph.
lineMeasurer = new LineBreakMeasurer(paragraph, frc);
// Set position to the index of the first character in the paragraph.
lineMeasurer.setPosition(paragraphStart);
// Set break width to width of Component.
float breakWidth = (float) width;
this.startY = startY;
drawPosY = (float) startY;
while (lineMeasurer.getPosition() < paragraphEnd) {
// Retrieve next layout. A cleverer program would also cache
// these layouts until the component is re-sized.
TextLayout layout = lineMeasurer.nextLayout(breakWidth);
// Compute pen startX position. If the paragraph is right-to-left we
// will align the TextLayouts to the right edge of the panel.
// Note: this won't occur for the English text in this sample.
// Note: drawPosX is always where the LEFT of the text is placed.
double drawPosX = layout.isLeftToRight()
? startX : breakWidth - layout.getAdvance();
// Move startY-coordinate by the ascent of the layout.
drawPosY += layout.getAscent();
// Draw the TextLayout at (drawPosX, drawPosY).
layout.draw(g2d, (float) drawPosX, drawPosY);
// Move startY-coordinate in preparation for next layout.
drawPosY += layout.getDescent() + layout.getLeading();
if (drawPosY > maxY) {
return;
}
}