package org.xhtmlrenderer.pdf; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.w3c.dom.Element; import org.xhtmlrenderer.extend.FSImage; import org.xhtmlrenderer.extend.ReplacedElement; import org.xhtmlrenderer.extend.UserAgentCallback; import org.xhtmlrenderer.layout.LayoutContext; import org.xhtmlrenderer.render.BlockBox; import com.lowagie.text.Image; import com.lowagie.text.pdf.codec.Base64; /** * Refines rendering of XML elements, for example to allow the processing of data uri images. * * @author Stéphane Thomas */ public class ExtendedITextReplacedElementFactory extends ITextReplacedElementFactory { private static final Logger log = Logger.getLogger(ExtendedITextReplacedElementFactory.class); /** * Creates a new factory. * * @param outputDevice output device */ public ExtendedITextReplacedElementFactory(ITextOutputDevice outputDevice) { super(outputDevice); } /** * Renders an XML element (i.e. build its visual representation). * * @see org.xhtmlrenderer.pdf.ITextReplacedElementFactory#createReplacedElement(org.xhtmlrenderer.layout.LayoutContext, org.xhtmlrenderer.render.BlockBox, org.xhtmlrenderer.extend.UserAgentCallback, int, int) for more information */ public ReplacedElement createReplacedElement(LayoutContext layoutContext, BlockBox blockBox, UserAgentCallback userAgentCallback, int cssWidth, int cssHeight) { Element element = blockBox.getElement(); // Handles any images with a data uri, e.g.: // // <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUg ... 9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" /> // if (isDataUriImage(element)) { String src = element.getAttribute("src"); try { String encoded = StringUtils.substringAfter(src, ";base64,"); if (!encoded.isEmpty()) { byte[] decoded = Base64.decode(encoded); FSImage image = new ITextFSImage(Image.getInstance(decoded)); if ((cssWidth != -1) || (cssHeight != -1)) { image.scale(cssWidth, cssHeight); } log.trace("Replaced data uri image successfully"); return new ITextImageElement(image); } else { log.warn("Unable to replace data uri image because of empty data"); } } catch (Exception exception) { log.warn("Unable to replace data uri image", exception); } return null; } else { return super.createReplacedElement(layoutContext, blockBox, userAgentCallback, cssWidth, cssHeight); } } /** * Determines whether the specified XML element is an image with a data uri or not. * * @param element element to analyze * @return true if the specified element is an image with a data uri, false otherwise * @see http://en.wikipedia.org/wiki/Data_URI_scheme for more information */ protected boolean isDataUriImage(Element element) { if (element != null) { String tag = element.getNodeName(); if (tag.equalsIgnoreCase("img")) { String src = element.getAttribute("src"); if (src != null) { // Prepares the source value to make sure the next comparison will be case insensitive src = src.trim().toLowerCase(); return src.startsWith("data:image/"); } } } return false; } }