/** * Transcodes the specified Document as an image in the specified output. * * @param document the document to transcode * @param uri the uri of the document or null if any * @param output the ouput where to transcode * @exception org.apache.batik.transcoder.TranscoderException if an error occurred while * transcoding */ protected void transcode(Document document, String uri, TranscoderOutput output) throws TranscoderException { if (!(document instanceof SVGOMDocument)) { throw new TranscoderException(Messages.formatMessage("notsvg", null)); } BridgeContext ctx = new BridgeContext(userAgent); SVGOMDocument svgDoc = (SVGOMDocument) document; // build the GVT tree GraphicsNode gvtRoot = buildGVT(ctx, svgDoc); // get the 'width' and 'height' attributes of the SVG document width = (int) (ctx.getDocumentSize().getWidth() + 0.5); height = (int) (ctx.getDocumentSize().getHeight() + 0.5); SpriteGraphics2D swf2d = new SpriteGraphics2D(width, height); gvtRoot.paint(swf2d); tags = swf2d.getTags(); // Override width and height based on the SWF-specific bounds of the sprite contents // However we have to correct co-ordinates back to pixels... TODO: Remove all TWIPS references! Rect bounds = swf2d.getBounds(); width = (int) Math.rint((bounds.xMax - bounds.xMin) / 20.0); height = (int) Math.rint((bounds.yMax - bounds.yMin) / 20.0); }
/** * Retrieves a Batik {@link GraphicsNode} for a given SVG. * * @param svgLocation an URL that specifies the SVG. * @return the corresponding GraphicsNode. * @throws IOException * @throws URISyntaxException */ private GraphicsNode getGraphicNode(Document doc) { // instantiates objects needed for building the node UserAgent userAgent = new UserAgentAdapter(); DocumentLoader loader = new DocumentLoader(userAgent); BridgeContext ctx = new BridgeContext(userAgent, loader); ctx.setDynamic(true); // creates node builder and builds node GVTBuilder builder = new GVTBuilder(); return builder.build(ctx, doc); }
/** * Creates a <tt>GraphicsNode</tt> according to the specified parameters. * * @param ctx the bridge context to use * @param e the element that describes the graphics node to build * @return a graphics node that represents the specified element */ public GraphicsNode createGraphicsNode(BridgeContext ctx, Element e) { // 'requiredFeatures', 'requiredExtensions' and 'systemLanguage' if (!SVGUtilities.matchUserAgent(e, ctx.getUserAgent())) { return null; } CompositeGraphicsNode cgn = new CompositeGraphicsNode(); // 'transform' String s = e.getAttributeNS(null, SVG_TRANSFORM_ATTRIBUTE); if (s.length() != 0) { cgn.setTransform(SVGUtilities.convertTransform(e, SVG_TRANSFORM_ATTRIBUTE, s, ctx)); } // 'visibility' cgn.setVisible(CSSUtilities.convertVisibility(e)); // 'text-rendering' and 'color-rendering' RenderingHints hints = null; hints = CSSUtilities.convertColorRendering(e, hints); hints = CSSUtilities.convertTextRendering(e, hints); if (hints != null) { cgn.setRenderingHints(hints); } // first child holds the flow region nodes CompositeGraphicsNode cgn2 = new CompositeGraphicsNode(); cgn.add(cgn2); // second child is the text node FlowTextNode tn = (FlowTextNode) instantiateGraphicsNode(); tn.setLocation(getLocation(ctx, e)); // specify the text painter to use if (ctx.getTextPainter() != null) { tn.setTextPainter(ctx.getTextPainter()); } textNode = tn; cgn.add(tn); associateSVGContext(ctx, e, cgn); // traverse the children to add SVGContext Node child = getFirstChild(e); while (child != null) { if (child.getNodeType() == Node.ELEMENT_NODE) { addContextToChild(ctx, (Element) child); } child = getNextSibling(child); } return cgn; }
/** Reads color value from the document. */ protected Color getColor(Element element, String attributeName) { if (getDocument() == null || getDocument() != element.getOwnerDocument()) { return null; } Color color = null; // Make sure that CSSEngine is available. BridgeContext ctx = transcoder.initCSSEngine(); try { color = SVGUtils.toSWTColor(element, attributeName); } finally { if (ctx != null) { ctx.dispose(); } } return color; }
/** * Builds using the specified BridgeContext and element, the specified graphics node. * * @param ctx the bridge context to use * @param e the element that describes the graphics node to build * @param node the graphics node to build */ public void buildGraphicsNode(BridgeContext ctx, Element e, GraphicsNode node) { CompositeGraphicsNode cgn = (CompositeGraphicsNode) node; // build flowRegion shapes boolean isStatic = !ctx.isDynamic(); if (isStatic) { flowRegionNodes = new HashMap(); } else { regionChangeListener = new RegionChangeListener(); } CompositeGraphicsNode cgn2 = (CompositeGraphicsNode) cgn.get(0); GVTBuilder builder = ctx.getGVTBuilder(); for (Node n = getFirstChild(e); n != null; n = getNextSibling(n)) { if (n instanceof SVGOMFlowRegionElement) { for (Node m = getFirstChild(n); m != null; m = getNextSibling(m)) { if (m.getNodeType() != Node.ELEMENT_NODE) { continue; } GraphicsNode gn = builder.build(ctx, (Element) m); if (gn != null) { cgn2.add(gn); if (isStatic) { flowRegionNodes.put(m, gn); } } } if (!isStatic) { AbstractNode an = (AbstractNode) n; XBLEventSupport es = (XBLEventSupport) an.initializeEventSupport(); es.addImplementationEventListenerNS( SVG_NAMESPACE_URI, "shapechange", regionChangeListener, false); } } } // build text node GraphicsNode tn = (GraphicsNode) cgn.get(1); super.buildGraphicsNode(ctx, e, tn); // Drop references once static build is completed. flowRegionNodes = null; }
private static void drawSvgToGraphics2D(Svg svg, Graphics2D g2, Dimension size) throws IOException { // Copied (and modified) from http://stackoverflow.com/a/12502943 String parser = XMLResourceDescriptor.getXMLParserClassName(); SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(parser); UserAgent userAgent = new UserAgentAdapter(); DocumentLoader loader = new DocumentLoader(userAgent); BridgeContext ctx = new BridgeContext(userAgent, loader); ctx.setDynamicState(BridgeContext.DYNAMIC); GVTBuilder builder = new GVTBuilder(); StringReader svgReader = new StringReader(svg.toString()); SVGDocument parsedSvgDocument = factory.createSVGDocument(null, svgReader); GraphicsNode chartGfx = builder.build(ctx, parsedSvgDocument); Dimension actualSize = svg.getSize(); double scaleWidth = 1.0 * size.width / actualSize.width; double scaleHeight = 1.0 * size.height / actualSize.height; chartGfx.setTransform(AffineTransform.getScaleInstance(scaleWidth, scaleHeight)); chartGfx.paint(g2); }
protected void gatherRegionInfo( BridgeContext ctx, Element rgn, float verticalAlign, List regions) { boolean isStatic = !ctx.isDynamic(); for (Node n = getFirstChild(rgn); n != null; n = getNextSibling(n)) { if (n.getNodeType() != Node.ELEMENT_NODE) { continue; } GraphicsNode gn = isStatic ? (GraphicsNode) flowRegionNodes.get(n) : ctx.getGraphicsNode(n); Shape s = gn.getOutline(); if (s == null) { continue; } AffineTransform at = gn.getTransform(); if (at != null) { s = at.createTransformedShape(s); } regions.add(new RegionInfo(s, verticalAlign)); } }
/** * Creates a <code>Paint</code> according to the specified parameters. * * @param ctx the bridge context to use * @param paintElement the element that defines a Paint * @param paintedElement the element referencing the paint * @param paintedNode the graphics node on which the Paint will be applied * @param opacity the opacity of the Paint to create */ public Paint createPaint( BridgeContext ctx, Element paintElement, Element paintedElement, GraphicsNode paintedNode, float opacity) { Element clrDef = null; for (Node n = paintElement.getFirstChild(); n != null; n = n.getNextSibling()) { if ((n.getNodeType() != Node.ELEMENT_NODE)) continue; Element ref = (Element) n; if ( // (ref instanceof SVGTests) && SVGUtilities.matchUserAgent(ref, ctx.getUserAgent())) { clrDef = ref; break; } } if (clrDef == null) return Color.black; Bridge bridge = ctx.getBridge(clrDef); if (bridge == null || !(bridge instanceof PaintBridge)) return Color.black; return ((PaintBridge) bridge).createPaint(ctx, clrDef, paintedElement, paintedNode, opacity); }
public Document(InputStream stream) throws IOException { f = new SAXSVGDocumentFactory(XMLResourceDescriptor.getXMLParserClassName()); doc = f.createSVGDocument(null, stream); // Boot the CSS engine userAgent = new UserAgentAdapter(); loader = new DocumentLoader(userAgent); ctx = new BridgeContext(userAgent, loader); ctx.setDynamicState(BridgeContext.DYNAMIC); builder = new GVTBuilder(); rootGN = builder.build(ctx, doc); svgRoot = doc.getRootElement(); vcss = (ViewCSS) doc.getDocumentElement(); }
protected GraphicsNode buildGVT(BridgeContext ctx, SVGOMDocument svgDoc) throws TranscoderException { GVTBuilder builder = new GVTBuilder(); GraphicsNode gvtRoot; try { gvtRoot = builder.build(ctx, svgDoc); // dispatch an 'onload' event if needed if (ctx.isDynamic()) { BaseScriptingEnvironment se = new BaseScriptingEnvironment(ctx); se.loadScripts(); se.dispatchSVGLoadEvent(); } } catch (BridgeException ex) { throw new TranscoderException(ex); } return gvtRoot; }
/** Printable implementation */ public int print(Graphics _g, PageFormat pageFormat, int pageIndex) { // // On the first page, take a snapshot of the vector of // TranscodeInputs. // if (printedInputs == null) { printedInputs = (Vector) inputs.clone(); } // // If we have already printed each page, return // if (pageIndex >= printedInputs.size()) { curIndex = -1; if (theCtx != null) theCtx.dispose(); userAgent.displayMessage("Done"); return NO_SUCH_PAGE; } // // Load a new document now if we are printing a new page // if (curIndex != pageIndex) { if (theCtx != null) theCtx.dispose(); // The following call will invoke this class' transcode // method which takes a document as an input. That method // builds the GVT root tree.{ try { width = (int) pageFormat.getImageableWidth(); height = (int) pageFormat.getImageableHeight(); super.transcode((TranscoderInput) printedInputs.elementAt(pageIndex), null); curIndex = pageIndex; } catch (TranscoderException e) { drawError(_g, e); return PAGE_EXISTS; } } // Cast to Graphics2D to access Java 2D features Graphics2D g = (Graphics2D) _g; g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g.setRenderingHint( RenderingHintsKeyExt.KEY_TRANSCODING, RenderingHintsKeyExt.VALUE_TRANSCODING_PRINTING); // // Compute transform so that the SVG document fits on one page // AffineTransform t = g.getTransform(); Shape clip = g.getClip(); // System.err.println("X/Y: " + pageFormat.getImageableX() + ", " + // pageFormat.getImageableY()); // System.err.println("W/H: " + width + ", " + height); // System.err.println("Clip: " + clip.getBounds2D()); // Offset 0,0 to the start of the imageable Area. g.translate(pageFormat.getImageableX(), pageFormat.getImageableY()); // // Append transform to selected area // g.transform(curTxf); // // Delegate rendering to painter // try { root.paint(g); } catch (Exception e) { g.setTransform(t); g.setClip(clip); drawError(_g, e); } // // Restore transform and clip // g.setTransform(t); g.setClip(clip); // g.setPaint(Color.black); // g.drawString(uris[pageIndex], 30, 30); // // Return status indicated that we did paint a page // return PAGE_EXISTS; }
/** Fills the given AttributedStringBuffer. */ protected void fillAttributedStringBuffer( BridgeContext ctx, Element element, boolean top, Integer bidiLevel, Map initialAttributes, AttributedStringBuffer asb, List lnLocs) { // 'requiredFeatures', 'requiredExtensions', 'systemLanguage' & // 'display="none". if ((!SVGUtilities.matchUserAgent(element, ctx.getUserAgent())) || (!CSSUtilities.convertDisplay(element))) { return; } String s = XMLSupport.getXMLSpace(element); boolean preserve = s.equals(SVG_PRESERVE_VALUE); boolean prevEndsWithSpace; Element nodeElement = element; int elementStartChar = asb.length(); if (top) { endLimit = startLen = asb.length(); } if (preserve) { endLimit = startLen; } Map map = initialAttributes == null ? new HashMap() : new HashMap(initialAttributes); initialAttributes = getAttributeMap(ctx, element, null, bidiLevel, map); Object o = map.get(TextAttribute.BIDI_EMBEDDING); Integer subBidiLevel = bidiLevel; if (o != null) { subBidiLevel = (Integer) o; } int lineBreak = -1; if (lnLocs.size() != 0) { lineBreak = ((Integer) lnLocs.get(lnLocs.size() - 1)).intValue(); } for (Node n = getFirstChild(element); n != null; n = getNextSibling(n)) { if (preserve) { prevEndsWithSpace = false; } else { int len = asb.length(); if (len == startLen) { prevEndsWithSpace = true; } else { prevEndsWithSpace = (asb.getLastChar() == ' '); int idx = lnLocs.size() - 1; if (!prevEndsWithSpace && (idx >= 0)) { Integer i = (Integer) lnLocs.get(idx); if (i.intValue() == len) { prevEndsWithSpace = true; } } } } switch (n.getNodeType()) { case Node.ELEMENT_NODE: // System.out.println("Element: " + n); if (!SVG_NAMESPACE_URI.equals(n.getNamespaceURI())) break; nodeElement = (Element) n; String ln = n.getLocalName(); if (ln.equals(SVG12Constants.SVG_FLOW_LINE_TAG)) { int before = asb.length(); fillAttributedStringBuffer( ctx, nodeElement, false, subBidiLevel, initialAttributes, asb, lnLocs); // System.out.println("Line: " + asb.length() + // " - '" + asb + "'"); lineBreak = asb.length(); lnLocs.add(new Integer(lineBreak)); if (before != lineBreak) { initialAttributes = null; } } else if (ln.equals(SVG12Constants.SVG_FLOW_SPAN_TAG) || ln.equals(SVG12Constants.SVG_ALT_GLYPH_TAG)) { int before = asb.length(); fillAttributedStringBuffer( ctx, nodeElement, false, subBidiLevel, initialAttributes, asb, lnLocs); if (asb.length() != before) { initialAttributes = null; } } else if (ln.equals(SVG_A_TAG)) { if (ctx.isInteractive()) { NodeEventTarget target = (NodeEventTarget) nodeElement; UserAgent ua = ctx.getUserAgent(); SVGAElementBridge.CursorHolder ch; ch = new SVGAElementBridge.CursorHolder(CursorManager.DEFAULT_CURSOR); target.addEventListenerNS( XMLConstants.XML_EVENTS_NAMESPACE_URI, SVG_EVENT_CLICK, new SVGAElementBridge.AnchorListener(ua, ch), false, null); target.addEventListenerNS( XMLConstants.XML_EVENTS_NAMESPACE_URI, SVG_EVENT_MOUSEOVER, new SVGAElementBridge.CursorMouseOverListener(ua, ch), false, null); target.addEventListenerNS( XMLConstants.XML_EVENTS_NAMESPACE_URI, SVG_EVENT_MOUSEOUT, new SVGAElementBridge.CursorMouseOutListener(ua, ch), false, null); } int before = asb.length(); fillAttributedStringBuffer( ctx, nodeElement, false, subBidiLevel, initialAttributes, asb, lnLocs); if (asb.length() != before) { initialAttributes = null; } } else if (ln.equals(SVG_TREF_TAG)) { String uriStr = XLinkSupport.getXLinkHref((Element) n); Element ref = ctx.getReferencedElement((Element) n, uriStr); s = TextUtilities.getElementContent(ref); s = normalizeString(s, preserve, prevEndsWithSpace); if (s.length() != 0) { int trefStart = asb.length(); Map m = new HashMap(); getAttributeMap(ctx, nodeElement, null, bidiLevel, m); asb.append(s, m); int trefEnd = asb.length() - 1; TextPaintInfo tpi; tpi = (TextPaintInfo) elemTPI.get(nodeElement); tpi.startChar = trefStart; tpi.endChar = trefEnd; } } break; case Node.TEXT_NODE: case Node.CDATA_SECTION_NODE: s = n.getNodeValue(); s = normalizeString(s, preserve, prevEndsWithSpace); if (s.length() != 0) { asb.append(s, map); if (preserve) { endLimit = asb.length(); } initialAttributes = null; } } } if (top) { boolean strippedSome = false; while ((endLimit < asb.length()) && (asb.getLastChar() == ' ')) { int idx = lnLocs.size() - 1; int len = asb.length(); if (idx >= 0) { Integer i = (Integer) lnLocs.get(idx); if (i.intValue() >= len) { i = new Integer(len - 1); lnLocs.set(idx, i); idx--; while (idx >= 0) { i = (Integer) lnLocs.get(idx); if (i.intValue() < len - 1) break; lnLocs.remove(idx); idx--; } } } asb.stripLast(); strippedSome = true; } if (strippedSome) { Iterator iter = elemTPI.values().iterator(); while (iter.hasNext()) { TextPaintInfo tpi = (TextPaintInfo) iter.next(); if (tpi.endChar >= asb.length()) { tpi.endChar = asb.length() - 1; if (tpi.startChar > tpi.endChar) tpi.startChar = tpi.endChar; } } } } int elementEndChar = asb.length() - 1; TextPaintInfo tpi = (TextPaintInfo) elemTPI.get(element); tpi.startChar = elementStartChar; tpi.endChar = elementEndChar; }