How can I export a JavaFX node to an SVG image? - java

In other words, I'm trying to do something with JavaFX like what Batik allows you to do with Swing.
I want to be able to capture the appearance of an arbitrary node in my JavaFX UI, much like Node.snapshot() does, except that I need my image in a vector format like SVG, not a raster image. (And inserting a raster snapshot of my node into an SVG image is not good enough; it needs to be a proper, scalable vector image.)
This is a long-term project, so I'm even willing to go as far as implementing my own GraphicsContext, or whatever the equivalent is in JavaFX's retained mode API.
Does anyone know if there is a way to do this? Is what I'm hoping to do even possible in JavaFX?

I started to write a JavaFx Node to SVG converter which "extends" the ShapeConverter from Gerrit Grunwald which only converts Shape geometries:
https://github.com/stefaneidelloth/JavaFxNodeToSvg
... and stopped it after a certain amount of frustration.
Please feel free to improve it, add features and fix bugs.
The converter works for simple Node examples but fails for advanced examples like a Chart. My failed converter might serve you as a starting point. The current state is illustrated by the following figures. The left side shows the original JavaFx node and the right side shows the resulting svg output.
Simple node example (works):
Chart example (does not work):
The corresponging svg files are available here:
https://github.com/stefaneidelloth/JavaFxNodeToSvg/tree/master/output
Some further notes
In addition to the positioning problems that are illustrated by the Chart example above, some further issues have to be considered:
JavaFx provides more css functionality than the SVG standard elements. For example a (rectangular) JavaFx Region can have individual line styles for each of the four border lines. Such a Region can not simply be converted to a SVG rect. Instead, the four border lines of the Region need to be drawn individually. Furthermore, each end of such a border line can have two individual edge radii: a vertical radius and a horizontal radius. In order to convert the "four" border lines to corresponding SVG lines ... it might be necessary to further split the border line: draw two rounded parts and a straight part for each of the four border lines. Therefore, in some cases there might be 12 SVG path elements to draw the border of a single JavaFx Region. In addition, the background fill of the Region can have different radii than the border of the Region. Drawing the background of the Region might requires some more SVG elements. Therefore, even the conversion of a "rectangular Region" can get quite complex.
Please also note that JavaFx nodes might be animated. For example the opacity of a line is 0 at the beginning and fades to another value after a few milliseconds.
FadeTransition ft = new FadeTransition(Duration.millis(250), borderline);
ft.setToValue(0);
ft.play();
Therefore it only makes sense to convert Nodes where animations are disabled or to wait until the Nodes are in a stable state.
I would be very happy if the conversion of JavaFx Charts works one day, so that I can use JavaFx plotting with SVG export in one of my projects.
I decided to stop the development of the converter for the time being and to investigate the plotting and SVG export with JavaScript libraries (d3) instead. If that strategy turns out to be even worse, I might come back to the JavaFxNodeToSvgConverter.
Edit
The plotting with d3.js works very well and I decided not to use JavaFx for the purpose of plotting/svg creation. https://github.com/stefaneidelloth/javafx-d3

There is a simple JavaFX shape to SVG string converter, it will only convert basic shapes without css applied, not arbitrary nodes, but perhaps that might be all you need.

There is an open bug request in JFX JIRA at
https://javafx-jira.kenai.com/browse/RT-38559
(registration required; you can vote for the issue then). It currently says
Consider for a future version.
And is marked for version 9.

The idea is that if you are able to convert the JavaFX Nodes tree structure to a series of Graphics2D orders, then you can use Batik which has a Graphics2D driver.
The thing is that converting the JavaFX tree structure to Graphics2D orders is not as difficult as you might think (even if you process the CSS properties of the Nodes).
Some readers suggested that I should include some code, and not just the link to the library and pictures of it working. It is not so easy to do, because even if it is not so difficult to do, it still has 5000 lines of code.
How to perform the conversion:
you must have a Graphics2D to convert to SVG (for example the Batik SVGGraphics2D class);
iterate through the JavaFX structure;
for each Node in the structure, first convert the current javaFX transforms on this Node to an AffineTransform, and apply the transformation to the Node (you must do it in a Stack to be sure to revert to the initial AffineTransform at the end of the Node);
and for each Node, you have to transform to the appropriate Graphics2D orders.
Note that you don't need to support a lot of Node types, mainly:
Regions (controls are a special type of Region which can have an associated Graphics)
Groups
Shapes (Text, Rectangle, etc...)
ImageView for images
You may also need to take care of the Node Clipping to apply the associated Clipping in the Graphics2D.
Also you will have to take care of the CSS properties of the Node.
For all its worth, the library I used (which apllies this algorithm) is here: http://sourceforge.net/projects/jfxconverter/

The idea is that if you are able to convert the JavaFX Nodes tree structure to a series of Graphics2D orders, then you can use Batik which has a Graphics2D driver.
The thing is that converting the JavaFX tree structure to Graphics2D orders is not as difficult as you might think (even if you process the CSS properties of the Nodes).
You should create a SVGGraphics2D from a new empty SVGDocument, for example:
Document doc = SVGDOMImplementation.getDOMImplementation().createDocument(SVGDOMImplementation.SVG_NAMESPACE_URI, "svg", null);
SVGGraphics2D g2D = new SVGGraphics2D(doc);
Then you get the root node of the Scene you want to convert, and for this node, you get the type of the Node, which can be a Shape, Control, Region, ImageView, Group, SubScene, Shape3D
Depending on each node, you can get the characteristics of the node. For example, for a Shape, if its a Line, you can drawthe line in the SVGGraphics2D. For example:
g2D.drawLine((int) line.getStartX(), (int) line.getStartY(), (int) line.getEndX(), (int) line.getEndY());
Note that you will also need to take care of the transforms applied to the node, and the fill or draw of the Node.
Then you iterate on the Node children and do the same thing recursively.
At the end you should be able to save the document in SVG as Batik allows to do it natively.

Related

SVG constructive area geometry?

Are there SVG functions that perform CAG operations similar to those that Area provides in Java (http://docs.oracle.com/javase/6/docs/api/java/awt/geom/Area.html)?
I would like to perform those operations directly using an SVG library (e.g. Batik), not through the Batik Graphics2D class that does SVG export (since I would rather use the SVG API than Java2D).
Cheers
SVG doesn't have any functions built into them, its mearly a graphics drawing spec..(with the exception of some animation functionality)
I would preprocess the vector values your app is using and then apply them to the rendering of the SVG.
Without knowing your platform, or your application of the SVG...its hard to help any further. SVG can be used in a lot of ways and places! :)
The references to Java allow me to assume that your using it as your interface engine? but thats about it..if you want to know the area of the circle, you would have to find the circle in the DOM tree, extrude the attributes from the the node, and just push them into a standard CAG class to do the math for you.

Java image library - turn grid image into array

If I have an image of a table of boxes, with some coloured in, is there an image processing library that can help me turn this into an array?
Thanks
You can use a thresholding function to binarize the image into dark/light pixels so dark pixels are 0 and light ones are 1.
Then you would want to remove image artifacts using dilation and erosion functions to remove noise (all these are well defined on Wikipedia).
Finally if you know where the boxes are, you can just get the value in the center of each box to determine the array value, or possibly use an area near the center and take the prevailing value (i.e. more 0's is a filled in square, more 1's is and empty square).
If you are scanning these boxes and there is a lot of variation in the position of the boxes, you will have to perform some level of image registration using known points, or fiducials.
As far as what tools to use to do this, I'd recommend first trying this manually using a tool like ImageJ, which has a UI and can also be used programatically since it is written all in Java.
Other good libraries for this include OpenCV and the Java Advanced Imaging API.
Your results will definitely vary depending on the input images and how consistenly lit and positioned they are.
The best way to see how it will do for your data is to try applying these processing steps manually to see where your threshold value should be, how much dilating/eroding you need to get consistent results.

Advice needed: A programmatic way for creating vector graphics with heavy usage of text

I need a way for render a tree-like structures, similar to flowcharts.
Surprisingly, I can't find(or I'm doing wrong) a suitable tool.
First, I looked at SVG. But I couldn't find a way to draw a bounding box around the text
without using ECMAScript: I tried to do a simple thing drawing two text surrounded by boxes and linked by a line, centered by sides(some thing like O-O, where O is a box with text).And when you use ECMAScript, you heavily limit the tools that can be used for SVG rendering(for example you can't convert corrently such SVG to png or pdf with ImageMagick).
Second, I tried Asymptote, but it is quite heavy when you start manipulating with text(you need an LaTeX system installed and configured).
I look for a tool in which you can:
Programmatically access to font properties: baseline, ascent, descent, height
Computing height/width of a string(or the bounding box)
basic vector graphics functionality like drawing lines, shapes etc.
I don't think that's a hard stuff. For example, all such functionality exists for example in Java2D. Sure, I can use it as last resort and get raster graphics, but may be there is something handy to use?
Have you looked at GraphViz (http://www.graphviz.org/)? It does not really match your requirements since you give up some control and instead let the tool do the layout and rendering based on a declarative a description of a graph or tree, but I have found it to be the easiest way to generate tree-like output.
Not sure if it should be free?
Here's a commercial solution with an extensive API
http://www-01.ibm.com/software/integration/visualization/java/

Algorithm to create an image of an elliptical brush?

I need to be able to accept elliptical(computed) brush parameters such as spacing, hardness, roundness, angle and diameter and then compute a bitmap image based on those attributes.
Does anyone know the algorithm(or where I can find it) to do this? I have limited experience in graphics programming and I have been unable to find it so far.
This is the kind of thing you want to use a library for, most likely the Java 2D API. It includes facilities for fills, strokes, transforms, and filters. Its model is similar to many libraries in that you trace out a path with operators moveTo and lineTo or curveTo, which are abstracted in shapes like Ellipse2D; and then you fill or stroke the resultant path with a paint operator. I highly recommend reading the Java 2D tutorial and understanding how the different parts fit together.
I would take roughly the following steps to create this drawing:
Compute the final dimensions of the rotated ellipse after blurring.
Create a BuferredImage of that size and call its createGraphics method to acquire a drawing context.
Rotate the graphics object
Draw the ellipse
Fill it with black
Implement the Gaussian blur filter. This is not built in to the API, but it includes a framework for doing filters called ConvolveOp, and you can find an algorithm for computing the Gaussian kernel in Java.
Apply the filter to the image, and then return the results.
Another option might be Apache’s Batik SVG library, since you can declaratively express the drawing you want (including transformations and filters) and have it rasterized for you.
An extremely useful list of formulas for an ellipse can be found here: Link
Think about what each formula implies about an individual pixel in your bitmap (whether it's in/out of the ellipse, whether it's near the edge) and which properties would be useful to you.

Auto scale and rotate images

Given:
two images of the same subject matter;
the images have the same resolution, colour depth, and file format;
the images differ in size and rotation; and
two lists of (x, y) co-ordinates that correlate the images.
I would like to know:
How do you transform the larger image so that it visually aligns to the second image?
(Optional.) What are the minimum number of points needed to get an accurate transformation?
(Optional.) How far apart do the points need to be to get an accurate transformation?
The transformation would need to rotate, scale, and possibly shear the larger image. Essentially, I want to create (or find) a program that does the following:
Input two images (e.g., TIFFs).
Click several anchor points on the small image.
Click the several corresponding anchor points on the large image.
Transform the large image such that it maps to the small image by aligning the anchor points.
This would help align pictures of the same stellar object. (For example, a hand-drawn picture from 1855 mapped to a photograph taken by Hubble in 2000.)
Many thanks in advance for any algorithms (preferably Java or similar pseudo-code), ideas or links to related open-source software packages.
This is called Image Registration.
Mathworks discusses this, Matlab has this ability, and more information is in the Elastix Manual.
Consider:
Open source Matlab equivalents
IRTK
IRAF
Hugin
you can use the javax.imageio or Java Advanced Imaging api's for rotating, shearing and scaling the images once you found out what you want to do with them.
For a C++ implementation (without GUI), try the old KLT (Kanade-Lucas-Tomasi) tracker.
http://www.ces.clemson.edu/~stb/klt/

Categories

Resources