Batik - calculation of cubic spline boundaries

I use Batik to work with SVG images. In particular, I have a scene with several shapes, and I need to be able to convert each shape into a separate BufferedImage. For this, I use the following code:

SVGDocument document = null; // Load the document String parser = XMLResourceDescriptor.getXMLParserClassName(); SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser); File file = new File(inPath); try { document = (SVGDocument) f.createDocument(file.toURL().toString()); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } // Build the tree and get the document dimensions UserAgentAdapter userAgentAdapter = new UserAgentAdapter(); BridgeContext bridgeContext = new BridgeContext(userAgentAdapter); GVTBuilder builder = new GVTBuilder(); GraphicsNode graphicsNode = builder.build(bridgeContext, document); CanvasGraphicsNode canvasGraphicsNode = (CanvasGraphicsNode) graphicsNode.getRoot().getChildren().get(0); if(canvasGraphicsNode.getChildren().get(i) instanceof ShapeNode) { currentNode = (ShapeNode) canvasGraphicsNode.getChildren().get(i); convertNodeToImage (currentNode); } 

This is pretty standard. I run Batik and make it parse the SVG file. Here's the conversion of the node to an image function:

 Rectangle2D bounds; BufferedImage bufferedImage; Graphics2D g2d; // This is supposed to get the bounds of the svg node. ie the rectangle which would // fit perfectly around the shape bounds = sn.getSensitiveBounds(); // Transform the shape so it in the top left hand corner based on the bounds sn.setTransform(AffineTransform.getTranslateInstance(-bounds.getX(), -bounds.getY())); // Create a buffered image of the same size as the svg node bufferedImage = new BufferedImage((int) bounds.getWidth(), (int) bounds.getHeight(), BufferedImage.TYPE_INT_ARGB); // Paint the node to the buffered image and convert the buffered image to an input // stream g2d = (Graphics2D) bufferedImage.getGraphics(); sn.paint(g2d); ByteArrayOutputStream os = new ByteArrayOutputStream(); ImageIO.write(bufferedImage, "png", os); InputStream is = new ByteArrayInputStream(os.toByteArray()); return is; 

This is great for rectangles and straight lines, but it does not work for splines. For splines, the boundaries are greater than the resulting spline. I think this is because the getBounds function includes breakpoints in the calculation of boundaries. I need to find the boundaries of the spline only, that is, if the spline were stroked, I would like to find the boundaries of this stroke. I tried all the getBounds () functions (getSensativeBounds, getGeometryBounds ...) and they all give me the same result. So I wonder if I missed something? Is this a mistake in Batik? Or if there is a workaround?

The workaround I was thinking about is getting a list of the vertices of the form and calculating the borders manually. However, I could not find how to get a list of vertices.

Any help would be greatly appreciated.

+4
source share
1 answer

For those who have this problem, I have found a solution. The documentation says that getting borders is not guaranteed in order to provide minimal borders with only a certain rectangle that completely contains the shape. This means that you must calculate the boundaries manually. A spline is a mathematical definition of a form, i.e. a piecewise continuous function. This means that we must calculate the spline with a certain accuracy. This is achieved through the use of a path iterator with a double value of the degree of accuracy. This path iterator returns only LINE_TO commands, which means that it can be used to calculate the actual boundaries of the form:

 BufferedImage bufferedImage; Graphics2D g2d; // Manually calculate the bounds double [] vals = new double[7]; double minX = Double.MAX_VALUE; double maxX = 0; double minY = Double.MAX_VALUE; double maxY = 0; // Get a path iterator iterating to a certain level of accuracy PathIterator pi = sn.getOutline().getPathIterator(null, 0.01); while(!pi.isDone()) { pi.currentSegment(vals); if(vals[0] < minX ) { minX = vals[0]; } if(vals[0] > maxX ) { maxX = vals[0]; } if(vals[1] < minY ) { minY = vals[1]; } if(vals[1] > maxY ) { maxY = vals[1]; } pi.next(); } sn.setTransform(AffineTransform.getTranslateInstance(-minX, -minY)); bufferedImage = new BufferedImage((int) (maxX - minX), (int) (maxY - minY), BufferedImage.TYPE_INT_ARGB); g2d = (Graphics2D) bufferedImage.getGraphics(); sn.paint(g2d); ByteArrayOutputStream os = new ByteArrayOutputStream(); ImageIO.write(bufferedImage, "png", os); InputStream is = new ByteArrayInputStream(os.toByteArray()); 
+4
source

Source: https://habr.com/ru/post/1412694/


All Articles