I'm having a little trouble scaling SVG images to a PDF. In the XHTML, I'm going to link to an external SVG file via an
tag. Ideally, I'd like to scale the image based on the size specified in CSS. The SVG file itself, in most cases, will probably supply a width and height in its outer
tag, but it seems useful to be able to ultimately specify the size in CSS.
public void paint(RenderingContext renderingContext, ITextOutputDevice outputDevice, BlockBox box) {
// Follow the the SVG example in iText in Action
PdfContentByte dc = outputDevice.getWriter().getDirectContent();
UserAgent userAgent = new UserAgentAdapter();
DocumentLoader loader = new DocumentLoader(userAgent);
BridgeContext ctx = new BridgeContext(userAgent, loader);
ctx.setDynamicState(BridgeContext.DYNAMIC);
GVTBuilder builder = new GVTBuilder();
// this.svg is an instance of org.w3c.dom.svg.SVGDocument
GraphicsNode graphics = builder.build(ctx, this.svg);
SVGSVGElement svgElement = this.svg.getRootElement();
// Get the size specified in the SVG file. The size specified in CSS is already
// available as instance variables cssWidth and cssHeight.
//
// Here are are some example values that I'm seeing in the debugger.
//
// If I specify in CSS a width of .5in, the cssWidth is equal to 960.
// If I specify in the external SVG file a size of .5in, the svgWidth is 48.
float svgWidth = svgElement.getWidth().getBaseVal().getValue();
float svgHeight = svgElement.getHeight().getBaseVal().getValue();
/**
* svgFactor needs to be calculated depending on the screen DPI by the PDF DPI
* This is 96 / 72 = 4 / 3 ~= 1.3333333 on Windows, but might be different on *nix.
*/
final float svgFactor = 25.4f / userAgent.getPixelUnitToMillimeter() / 72f; // 25.4 mm = 1 inch TODO: Might need to get 72 from somewhere else?
PdfTemplate map = dc.createTemplate(cssWidth * svgFactor, cssHeight * svgFactor);
Graphics2D g2d = new PdfGraphics2D(map, cssWidth * svgFactor, cssHeight * svgFactor);
graphics.paint(g2d);
g2d.dispose();
// Now that we've loaded the SVG into iText, convert to an iText Image
Image image = null;
try
{
image = Image.getInstance(map);
}
catch (BadElementException e)
{
throw new XRRuntimeException("Unable to convert SVG to an iText image", e);
}
// At this point, should image.scaleToFit() be called? What is the proper arithmetic
// to scale?. Ultimately, the image should scale to fit with the size specified in CSS.
// Wrap the iText Image in a Flying Saucer FSImage to satisfy the drawImage() call below
ITextFSImage fsImage = new ITextFSImage(image);
// I'm not 100% sure if this is correct
Rectangle contentBounds = box.getContentAreaEdge(box.getAbsX(), box.getAbsY(), renderingContext);
outputDevice.drawImage(fsImage, contentBounds.x, contentBounds.y);
}