Skip to content

Commit

Permalink
re-commit
Browse files Browse the repository at this point in the history
lacan committed Sep 14, 2018
1 parent 137b353 commit 1c8e6a5
Showing 3 changed files with 234 additions and 125 deletions.
8 changes: 7 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@
<repository>
<id>imagej.public</id>
<url>http://maven.imagej.net/content/groups/public</url>
</repository>
</repository>
</repositories>
<developers>
<developer>
@@ -48,13 +48,19 @@

<properties>
<main-class>SVG_ROI</main-class>
<imagej.app.directory>C:/Fiji</imagej.app.directory>
</properties>

<dependencies>
<dependency>
<groupId>net.imagej</groupId>
<artifactId>ij</artifactId>
</dependency>
<dependency>
<groupId>sc.fiji</groupId>
<artifactId>fiji-lib</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>batik</groupId>
<artifactId>batik-all</artifactId>
349 changes: 226 additions & 123 deletions src/main/java/SVG_ROI.java
Original file line number Diff line number Diff line change
@@ -1,133 +1,236 @@
import org.apache.batik.*;
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.DocumentLoader;
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.bridge.UserAgent;
import org.apache.batik.bridge.UserAgentAdapter;
import java.awt.Color;
import java.awt.geom.PathIterator;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;

import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
import org.apache.batik.dom.svg.SVGOMSVGElement;
import org.apache.batik.util.XMLResourceDescriptor;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;

import ij.IJ;

import java.net.URI;
import java.io.Console;
import java.io.File;
import java.io.IOException;
import fiji.util.gui.GenericDialogPlus;
import ij.ImageJ;
import ij.gui.Roi;
import ij.gui.ShapeRoi;
import ij.plugin.PlugIn;
import ij.plugin.frame.RoiManager;

/**
* Responsible for converting all SVG path elements into MetaPost curves.
*/
public class SVG_ROI {
private static final String PATH_ELEMENT_NAME = "path";

private Document svgDocument;

/**
* Creates an SVG Document given a URI.
*
* @param uri Path to the file.
* @throws Exception Something went wrong parsing the SVG file.
*/
public SVG_ROI( String uri ) throws IOException {
setSVGDocument( createSVGROIs( uri ) );
}

/**
* Finds all the path nodes and converts them to MetaPost code.
*/
public void run() {
NodeList pathNodes = getPathElements();
int pathNodeCount = pathNodes.getLength();

for( int iPathNode = 0; iPathNode < pathNodeCount; iPathNode++ ) {
System.out.println(pathNodes.item(iPathNode).toString());
}
}

/**
* Returns a list of elements in the SVG document with names that
* match PATH_ELEMENT_NAME.
*
* @return The list of "path" elements in the SVG document.
*/
private NodeList getPathElements() {
return getSVGDocumentRoot().getElementsByTagName( PATH_ELEMENT_NAME );
}

/**
* Returns an SVGOMSVGElement that is the document's root element.
*
* @return The SVG document typecast into an SVGOMSVGElement.
*/
private Element getSVGDocumentRoot() {
return getSVGDocument().getDocumentElement();
}

/**
* This will set the document to parse. This method also initializes
* the SVG DOM enhancements, which are necessary to perform SVG and CSS
* manipulations. The initialization is also required to extract information
* from the SVG path elements.
*
* @param document The document that contains SVG content.
*/
public void setSVGDocument( Document document ) {
initSVGDOM( document );
this.svgDocument = document;
}

/**
* Returns the SVG document parsed upon instantiating this class.
*
* @return A valid, parsed, non-null SVG document instance.
*/
public Document getSVGDocument() {
return this.svgDocument;
}

/**
* Enhance the SVG DOM for the given document to provide CSS- and SVG-specific
* DOM interfaces.
*
* @param document The document to enhance.
* @link http://wiki.apache.org/xmlgraphics-batik/BootSvgAndCssDom
*/
private void initSVGDOM( Document document ) {
UserAgent userAgent = new UserAgentAdapter();
DocumentLoader loader = new DocumentLoader( userAgent );
BridgeContext bridgeContext = new BridgeContext( userAgent, loader );
bridgeContext.setDynamicState( BridgeContext.DYNAMIC );

// Enable CSS- and SVG-specific enhancements.
(new GVTBuilder()).build( bridgeContext, document );
}

/**
* Use the SAXSVGDocumentFactory to parse the given URI into a DOM.
*
* @param uri The path to the SVG file to read.
* @return A Document instance that represents the SVG file.
* @throws Exception The file could not be read.
*/
private Document createSVGROIs( String uri ) throws IOException {
String parser = XMLResourceDescriptor.getXMLParserClassName();
SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory( parser );
return factory.createDocument( uri );
}

/**
* Reads a file and parses the path elements.
*
* @param args args[0] - Filename to parse.
* @throws IOException Error reading the SVG file.
*/
public static void main( String args[] ) throws IOException {
URI uri = new File( "D:\\People\\Bianca\\svg\\Annotation2014_141_0000.svg" ).toURI();
SVG_ROI svgroi = new SVG_ROI( uri.toString() );
svgroi.run();
}
public class SVG_ROI implements PlugIn{
private static final String PATH_ELEMENT_NAME = "path";

@Override
public void run(String arg0) {
RoiManager rm = RoiManager.getInstance();
if (rm == null) {
rm = new RoiManager();
}

GenericDialogPlus gd = new GenericDialogPlus("SVGs To ROI Conversion");
gd.addDirectoryField("SVG Folder", "");

gd.showDialog();

if (gd.wasCanceled())
return;

//Navigate folder
File folder = new File(gd.getNextString());

File[] filelist = folder.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".svg");
}
});

File save_folder = new File(folder.getAbsolutePath()+File.separator+"ROI Sets");
save_folder.mkdirs();
for (File file : filelist) {
rm.reset();
convertSVGToRois(file);
// Save the ROIs to a subfolder
rm.runCommand("Save", save_folder.getAbsolutePath()+File.separator+file.getName().substring(0, file.getName().length()-4)+".zip");

}

}
public static void convertSVGToRois(File file) {
RoiManager rm = RoiManager.getInstance2();
if (rm == null) {
rm = new RoiManager();
}

URI uri = file.toURI();
Document svg = null;
//Prepare SVG file
try {
svg = createDocument( uri.toString() );
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

// Iterate through the paths
NodeList pathNodes = svg.getDocumentElement().getElementsByTagName( PATH_ELEMENT_NAME );
int pathNodeCount = pathNodes.getLength();
for( int iPathNode = 0; iPathNode < pathNodeCount; iPathNode++ ) {
rm.addRoi(convertToShapeRoi(pathNodes.item(iPathNode).getAttributes()));
}
}

public static ArrayList<Roi> convertSVGFileToRois(File file) {
RoiManager rm = RoiManager.getInstance2();
if (rm == null) {
rm = new RoiManager();
}

URI uri = file.toURI();
Document svg = null;
//Prepare SVG file
try {
svg = createDocument( uri.toString() );
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

ArrayList<Roi> rois = new ArrayList<Roi>();

// Iterate through the paths
NodeList pathNodes = svg.getDocumentElement().getElementsByTagName( PATH_ELEMENT_NAME );
int pathNodeCount = pathNodes.getLength();
for( int iPathNode = 0; iPathNode < pathNodeCount; iPathNode++ ) {
rois.add(convertToShapeRoi(pathNodes.item(iPathNode).getAttributes()));
}
return rois;
}


private static Roi convertToShapeRoi(NamedNodeMap pathAttributes) {
//Get the paths
String paths = pathAttributes.getNamedItem("d").getTextContent();

// Remove the Z key if there
int is_closed = 0;
if (paths.endsWith("Z")) {
paths = paths.substring(0, paths.length()-1);
is_closed = 1;
}

// Get the fill or Stroke, at least
String stroke = pathAttributes.getNamedItem("stroke").getTextContent();

// Work on a shapeRoi, as this allows for multiple ROIs to make a shape...
// ShapeRois can be built similarily to paths in SVG

paths = paths.trim();
String[] commands = paths.split("(?=L)|(?=M)|(?=C)");

ArrayList<Float> instructions = new ArrayList<Float>();

for (String command : commands ) {
char c = command.charAt(0);
command = command.trim();

command = command.substring(1);

switch (c) {
case 'M': // This also means that we need to start a new path...
instructions.add((float)PathIterator.SEG_MOVETO);
// Add the two coordinates
instructions.addAll(parseCoordinateAsArray(command," "));

break;

case 'L':
instructions.add((float)PathIterator.SEG_LINETO);
instructions.addAll(parseCoordinateAsArray(command,","));
break;
case 'C':

instructions.addAll(parseCurveAsArray(command));
break;

default:
System.out.println("WHAT IS: "+c +": "+command+"?");
break;
}
}

float[] floatArray = new float[instructions.size()+is_closed];
int i = 0;

for (Float f : instructions) {
floatArray[i++] = (f != null ? f : Float.NaN); // Or whatever default you want.
}
if( is_closed == 1)
floatArray[i] = PathIterator.SEG_CLOSE;

ShapeRoi the_roi = new ShapeRoi(floatArray);
the_roi.setStrokeColor(Color.decode(stroke));
return the_roi;
}

private static ArrayList<Float> parseCurveAsArray(String command) {
// Split at spaces first
ArrayList<Float> curve_points = new ArrayList<Float>();

String[] curve = command.split(" ");
// should be multiples of 3
if (curve.length%3 == 0) {

for (int i=0; i<curve.length/3; i++) {

curve_points.add((float)PathIterator.SEG_CUBICTO);
curve_points.addAll(parseCoordinateAsArray(curve[i*3],","));
curve_points.addAll(parseCoordinateAsArray(curve[i*3+1],","));
curve_points.addAll(parseCoordinateAsArray(curve[i*3+2],","));
}
return curve_points;
}
return curve_points;
}

private static ArrayList<Float> parseCoordinateAsArray(String cs, String delimiter) {
String[] xy = cs.split(delimiter);
ArrayList<Float> aPoint = new ArrayList<Float>();
aPoint.add(Float.parseFloat(xy[0]));
aPoint.add(Float.parseFloat(xy[1]));
return aPoint;
}

/**
* Use the SAXSVGDocumentFactory to parse the given URI into a DOM.
*
* @param uri The path to the SVG file to read.
* @return A Document instance that represents the SVG file.
* @throws Exception The file could not be read.
*/
private static Document createDocument( String uri ) throws IOException {
String parser = XMLResourceDescriptor.getXMLParserClassName();
SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory( parser );
return factory.createDocument( uri );
}

/**
* Main method for debugging.
* @param args unused
*/
public static void main(String[] args) {
// set the plugins.dir property to make the plugin appear in the Plugins menu
Class<?> clazz = SVG_ROI.class;
String url = clazz.getResource("/" + clazz.getName().replace('.', '/') + ".class").toString();
String pluginsDir = url.substring(5, url.length() - clazz.getName().length() - 6);
System.setProperty("plugins.dir", pluginsDir);

// start ImageJ
new ImageJ();
}
}
2 changes: 1 addition & 1 deletion src/main/resources/plugins.config
Original file line number Diff line number Diff line change
@@ -9,4 +9,4 @@
# If something like ("<arg>") is appended to the class name, the setup() method
# will get that as arg parameter; otherwise arg is simply the empty string.

Plugins>BIOP, "DEMO Plugin", Demo_Plugin
Plugins>BIOP, "SVG to ROI", SVG_ROI

0 comments on commit 1c8e6a5

Please sign in to comment.