-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
3 changed files
with
234 additions
and
125 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters