我正在使用FlyingSaucer的ITextRenderer从XML和CSS创建PDF。我想指定一个引用SVG图像的CSS背景图像。我使用PNG但没有SVG图像可以正常工作。
我试图制作一个ChainedReplacedElementFactory来替换SVG节点,但这不起作用,因为这些SVG文件没有从文档引用,而是通过url()引用CSS。
有没有办法教FlyingSaucer如何处理从CSS引用的SVG文件?
答案 0 :(得分:1)
我确实设法解决了这个问题。诀窍是自定义用户代理。
class CustomUserAgent extends ITextUserAgent
{
private final ITextOutputDevice mDevice;
public CustomUserAgent(ITextOutputDevice dev)
{
super(dev);
mDevice = dev;
}
private static final SAXSVGDocumentFactory mFactory =
new SAXSVGDocumentFactory(null);
private ImageResource getSVGImage(String uri)
throws IOException, BadElementException
{
InputStream is = null;
try
{
is = resolveAndOpenStream(uri);
InputStreamReader isr = new InputStreamReader(is);
Document doc = mFactory.createSVGDocument(null, isr);
UserAgent ua = new UserAgentAdapter();
DocumentLoader loader = new DocumentLoader(ua);
BridgeContext ctx = new BridgeContext(ua, loader);
ctx.setDynamicState(BridgeContext.DYNAMIC);
GVTBuilder builder = new GVTBuilder();
String not_numbers = "[^0-9.,]";
float width =
Float.parseFloat(doc.getDocumentElement().
getAttribute("width").replaceAll(not_numbers, ""));
float height =
Float.parseFloat(doc.getDocumentElement().
getAttribute("height").replaceAll(not_numbers, ""));
PdfWriter writer = mDevice.getWriter();
PdfTemplate templ = PdfTemplate.createTemplate(writer, width, height);
Graphics2D g2d = templ.createGraphics(width, height);
GraphicsNode gfx = builder.build(ctx, doc);
gfx.paint(g2d);
g2d.dispose();
Image img = new ImgTemplate(templ);
img.setAlignment(Image.ALIGN_CENTER);
SharedContext shctx = getSharedContext();
float dpi = shctx.getDotsPerPixel();
if (dpi != 1.0f)
img.scaleAbsolute(img.getPlainWidth() * dpi,
img.getPlainHeight() * dpi);
return new ImageResource(uri, new ITextFSImage(img));
}
finally
{
if (is != null)
is.close();
}
}
@Override
public ImageResource getImageResource(String uri)
{
if (uri.endsWith(".svg"))
{
try
{ return (getSVGImage(uri)); }
catch(IOException io)
{ throw new RuntimeException(io); }
catch(BadElementException be)
{ throw new RuntimeException(be); }
}
else
return (super.getImageResource(uri));
}
}
然后使用它只需将其应用于渲染器:
CustomUserAgent callback =
new CustomUserAgent(renderer.getOutputDevice());
callback.setSharedContext(renderer.getSharedContext());
renderer.getSharedContext().setUserAgentCallback(callback);