문제 설명
그래픽 텍스트 효과가 있는 텍스트 요소 (Text element with graphical text effects)
예를 들어 그림자를 추가하거나 어떤 종류의 추가와 같은 다른 종류의 추가 그래픽 효과를 사용하여 Text
요소(com.itextpdf.layout.element.Text
)를 만들고 싶습니다. 에 텍스처의 집합입니다. (DropShadow 일부 3D 효과) 이것을 달성하는 가장 좋은 방법은 무엇입니까?
지금까지 내가 가진 최고의 아이디어는 클리핑 텍스트를 사용하는 것입니다 렌더링 모드. (PDF 32000‑1 9.3.6; com.itextpdf.kernel.pdf.canvas.PdfCanvasConstants.TextRenderingMode
에서 정의됨). 텍스트를 클리핑 경계로 그리고 일종의 텍스처를 적용하거나 추가 그림자 "레이어"를 그립니다. 그러나 클리핑 경로는 com.itextpdf.layout.renderer.TextRender#drawcanvas.restoreState()
를 사용하여 텍스트 그리기 이전 상태로 복원됩니다. >. 이것을 사용자 정의 TextRenderer
로 확장하면 작동할 수 있지만 그리기 기능은 TextRenderer
의 전용 기능에 대한 일부 호출이 있는 큰 기능입니다.
다른 가능한 방법은 무엇입니까?
참조 솔루션
방법 1:
I think in general customization of that level will require quite come code anyway. Completely overriding draw
may indeed not work because some private implementation details are not exposed to the public. One option is of course to duplicate those implementation details into your custom renderer.
Another idea is to plug into the PdfCanvas
which does low‑level drawing. You can create your own wrapper like the following one and delegate all operations to the PdfCanvas
instance you wrap around except a couple of "interesting" operations where you will customize the logic and apply some styling:
private static class PdfCanvasWrapper extends PdfCanvas {
private PdfCanvas delegate;
public PdfCanvasWrapper(PdfCanvas wrapped) {
super(wrapped.getContentStream(), wrapped.getResources(), wrapped.getDocument());
this.delegate = wrapped;
}
// "Interesting" methods
@Override
public PdfCanvas endText() {
delegate.endText();
delegate.setFillColor(ColorConstants.BLACK);
delegate.rectangle(10, 10, 300, 300);
delegate.fill();
return this;
}
// "Boring" methods ‑ just delegate the implementation to the wrapped instance
@Override
public PdfCanvas beginVariableText() {
delegate.beginVariableText();
return this;
}
@Override
public PdfCanvas endVariableText() {
delegate.endVariableText();
return this;
}
// Override all other members like above
}
In this case your custom text renderer will only plug in the right DrawContext
but use the default draw
operation:
private static class CustomTextRenderer extends TextRenderer {
public CustomTextRenderer(Text textElement) {
super(textElement);
}
@Override
public void draw(DrawContext drawContext) {
DrawContext newContext = new DrawContext(drawContext.getDocument(), new PdfCanvasWrapper(drawContext.getCanvas()));
super.draw(newContext);
}
@Override
public CustomTextRenderer getNextRenderer() {
return new CustomTextRenderer((Text) modelElement);
}
}
Main could could look like this:
Paragraph p = new Paragraph();
Text text = new Text("Hello");
text.setTextRenderingMode(TextRenderingMode.CLIP);
text.setNextRenderer(new CustomTextRenderer(text));
p.add(text);
In general this approach is also hacky and of course depends on the implementation details as much as the initial approach you suggested. The approach you suggested is a more stable one but requires more code and probably more tuning when you update to the new version of the library. The approach I described above is more hacky but it results in less business logic copy‑pasting and maybe easier to maintain.
(by Tobias Wohlfarth、Alexey Subach)