带有飞碟的 SVG 背景图像
SVG background images with Flying Saucer
我正在使用 FlyingSaucer 的 ITextRenderer 从 XML 和 CSS 创建 PDF。我想指定一个引用 SVG 图像的 CSS 背景图像。我有一些东西可以很好地处理 PNG 但不是 SVG 图像。
我试图制作一个 ChainedReplacedElementFactory 来替换 SVG 节点,但这不起作用,因为这些 SVG 文件不是从文档中引用的,而是通过 url() 引用的 CSS。
有没有什么方法可以教 FlyingSaucer 如何处理从 CSS 引用的 SVG 文件?
我确实设法解决了这个问题。诀窍是自定义用户代理。
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);
我正在使用 FlyingSaucer 的 ITextRenderer 从 XML 和 CSS 创建 PDF。我想指定一个引用 SVG 图像的 CSS 背景图像。我有一些东西可以很好地处理 PNG 但不是 SVG 图像。
我试图制作一个 ChainedReplacedElementFactory 来替换 SVG 节点,但这不起作用,因为这些 SVG 文件不是从文档中引用的,而是通过 url() 引用的 CSS。
有没有什么方法可以教 FlyingSaucer 如何处理从 CSS 引用的 SVG 文件?
我确实设法解决了这个问题。诀窍是自定义用户代理。
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);