package org.ggp.base.util.ui; import java.awt.AlphaComposite; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.batik.dom.svg.SVGDOMImplementation; import org.apache.batik.transcoder.TranscoderException; import org.apache.batik.transcoder.TranscoderInput; import org.apache.batik.transcoder.TranscoderOutput; import org.apache.batik.transcoder.TranscodingHints; import org.apache.batik.transcoder.image.ImageTranscoder; import org.apache.batik.util.SVGConstants; import org.ggp.base.util.files.FileUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xhtmlrenderer.extend.ReplacedElement; import org.xhtmlrenderer.extend.ReplacedElementFactory; import org.xhtmlrenderer.extend.UserAgentCallback; import org.xhtmlrenderer.layout.LayoutContext; import org.xhtmlrenderer.render.BlockBox; import org.xhtmlrenderer.simple.extend.FormSubmissionListener; import org.xhtmlrenderer.swing.ImageReplacedElement; public class SVGReplacedElementFactory implements ReplacedElementFactory { @Override public ReplacedElement createReplacedElement(LayoutContext c, BlockBox box, UserAgentCallback uac, int cssWidth, int cssHeight) { Element element = box.getElement(); if("svg".equals(element.getNodeName())) { DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder; try { documentBuilder = documentBuilderFactory.newDocumentBuilder(); } catch (ParserConfigurationException e) { throw new RuntimeException(e); } Document svgDocument = documentBuilder.newDocument(); Element svgElement = (Element) svgDocument.importNode(element, true); svgDocument.appendChild(svgElement); try { int width = box.getContentWidth() - 20; return new ImageReplacedElement(rasterize(svgDocument, width), width, width); } catch (IOException e) { return null; } } return null; } public static BufferedImage rasterize(Document dom, int width) throws IOException { final BufferedImage[] imagePointer = new BufferedImage[1]; // Rendering hints can't be set programatically, so // we override defaults with a temporary stylesheet. String css = "svg {" + "shape-rendering: geometricPrecision;" + "text-rendering: geometricPrecision;" + "color-rendering: optimizeQuality;" + "image-rendering: optimizeQuality;" + "}"; File cssFile = File.createTempFile("batik-default-override-", ".css"); FileUtils.writeStringToFile(cssFile, css); TranscodingHints transcoderHints = new TranscodingHints(); transcoderHints.put(ImageTranscoder.KEY_XML_PARSER_VALIDATING, Boolean.FALSE); transcoderHints.put(ImageTranscoder.KEY_DOM_IMPLEMENTATION, SVGDOMImplementation.getDOMImplementation()); transcoderHints.put(ImageTranscoder.KEY_DOCUMENT_ELEMENT_NAMESPACE_URI, SVGConstants.SVG_NAMESPACE_URI); transcoderHints.put(ImageTranscoder.KEY_DOCUMENT_ELEMENT, "svg"); transcoderHints.put(ImageTranscoder.KEY_USER_STYLESHEET_URI, cssFile.toURI().toString()); transcoderHints.put(ImageTranscoder.KEY_WIDTH, new Float(2 * width)); transcoderHints.put(ImageTranscoder.KEY_HEIGHT, new Float(2 * width)); transcoderHints.put(ImageTranscoder.KEY_MAX_HEIGHT, new Float(2 * width)); transcoderHints.put(ImageTranscoder.KEY_MAX_WIDTH, new Float(2 * width)); try { TranscoderInput input = new TranscoderInput(dom); ImageTranscoder t = new ImageTranscoder() { @Override public BufferedImage createImage(int w, int h) { return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); } @Override public void writeImage(BufferedImage image, TranscoderOutput out) throws TranscoderException { int wd = image.getWidth() / 2; int ht = image.getHeight() / 2; BufferedImage resizedImage = new BufferedImage(wd, ht, BufferedImage.TYPE_INT_ARGB); Graphics2D g = resizedImage.createGraphics(); g.setComposite(AlphaComposite.Src); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR); g.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); g.drawImage(image, 0, 0, wd, ht, null); g.dispose(); imagePointer[0] = resizedImage; } }; t.setTranscodingHints(transcoderHints); t.transcode(input, null); } catch (TranscoderException ex) { // Requires Java 6 ex.printStackTrace(); throw new IOException("Couldn't convert SVG"); } finally { cssFile.delete(); } return imagePointer[0]; } @Override public void reset() { } @Override public void remove(Element e) { } @Override public void setFormSubmissionListener(FormSubmissionListener listener) { } }