1   /****************************************************************************
2    **
3    ** This file is part of yFiles-2.9. 
4    ** 
5    ** yWorks proprietary/confidential. Use is subject to license terms.
6    **
7    ** Redistribution of this file or of an unauthorized byte-code version
8    ** of this file is strictly forbidden.
9    **
10   ** Copyright (c) 2000-2011 by yWorks GmbH, Vor dem Kreuzberg 28, 
11   ** 72070 Tuebingen, Germany. All rights reserved.
12   **
13   ***************************************************************************/
14  package demo.io;
15  
16  import y.io.GIFIOHandler;
17  import y.io.GMLIOHandler;
18  import y.io.GraphMLIOHandler;
19  import y.io.IOHandler;
20  import y.io.ImageOutputHandler;
21  import y.io.JPGIOHandler;
22  import y.io.YGFIOHandler;
23  import y.io.ZipGraphMLIOHandler;
24  import y.util.D;
25  import y.view.Graph2D;
26  import y.view.Graph2DView;
27  import y.view.hierarchy.HierarchyManager;
28  
29  import java.awt.Dimension;
30  import java.awt.Rectangle;
31  import java.io.IOException;
32  import java.util.Collection;
33  import java.util.Iterator;
34  import java.util.LinkedList;
35  
36  
37  /**
38   * This class implements a command line driven graph format converter.
39   * Possible input formats are GraphML, ZIPGraphML, GML or YGF.
40   * Output formats are GraphML, ZIPGraphML, GML, YGF, GIF, and JPG.
41   * <br>
42   * Additionally, it is possible to write to the formats PDF, EMF, SWF, EPS, SVG, and SVGZ
43   *  in case the corresponding
44   * yFiles extension packages ySVG and yExport are installed.
45   * The size of some output formats can be specified.
46   *
47   * @see <a href="http://docs.yworks.com/yfiles/doc/developers-guide/graphml.html#graphml_postprocessors">Section yFiles GraphML Post-Processors</a> in the yFiles for Java Developer's Guide
48   * @see <a href="http://docs.yworks.com/yfiles/doc/developers-guide/image_export.html#image_export_preparation">Section Preparing the Graph</a> in the yFiles for Java Developer's Guide
49   *
50   */
51  public class GraphFormatConverter {
52    private Collection ioHandlers;
53    private int outputWidth = -1;
54    private int outputHeight = -1;
55    private String inFile;
56    private String outFile;
57  
58  
59    private static void usage(String msg) {
60      System.err.println(msg + "\n\n" +
61          "Usage: java demo.io.GraphFormatConverter -in <infile> -out <outfile> [options]\n" +
62          "Usage: where the format of infile is GraphML, ZIPGraphML, YGF or GML \n" +
63          "Usage: and the format of outfile in in GraphML, ZIPGraphML, YGF, GML, JPG or GIF.\n" +
64          "Usage: SVG/SVGZ output needs the ySVG extension package.\n" +
65          "Usage: EMF, PDF, EPS and SWF output needs the yExport extension package.\n" +
66          "Usage: File formats are determined by the file name extensions.\n" +
67          "Usage: Additional options which work for some output formats:\n" +
68          "Usage: -width <w>   the width of the output format\n" +
69          "Usage: -height<h>   the height of the output format\n" +
70          "Usage:  If neither option is specified, a value of 1024\n" +
71          "Usage:  is used for both dimensions\n");
72      System.exit(1);
73    }
74  
75    private static void error(String msg) {
76      System.err.println(msg);
77      System.exit(1);
78    }
79  
80    /**
81     * Creates a new instance of GraphFormatConverter.
82     * Adds all known IOHandlers to the conversion engine
83     */
84    public GraphFormatConverter() {
85      ioHandlers = new LinkedList();
86      ioHandlers.add(new GraphMLIOHandler());
87      ioHandlers.add(new ZipGraphMLIOHandler());
88      ioHandlers.add(new YGFIOHandler());
89      ioHandlers.add(new GMLIOHandler());
90      ioHandlers.add(new GIFIOHandler());
91      ioHandlers.add(new JPGIOHandler());
92      try { //try to support SVG(Z) output format if it is present
93        ioHandlers.add((IOHandler) Class.forName("yext.svg.io.SVGIOHandler").newInstance());
94        ioHandlers.add((IOHandler) Class.forName("yext.svg.io.SVGZIOHandler").newInstance());
95      }
96      catch (ClassNotFoundException cnfex) {
97        //SVG(Z) format disabled. Put ySVG extension package in your classpath
98      }
99      catch (Exception ex) {
100       D.trace(ex);
101     }
102 
103     try { //try to support PDF output format if it is present
104       ioHandlers.add((IOHandler) Class.forName("yext.export.io.PDFOutputHandler").newInstance());
105     } catch (ClassNotFoundException cnfex) {
106       //PDF format disabled. Put yExport extension package in your classpath
107     } catch (Exception ex) {
108       D.trace(ex);
109     }
110 
111     try { //try to support SWF output format if it is present
112       ioHandlers.add((IOHandler) Class.forName("yext.export.io.SWFOutputHandler").newInstance());
113     } catch (ClassNotFoundException cnfex) {
114       //SWF format disabled. Put yExport extension package in your classpath
115     } catch (Exception ex) {
116       D.trace(ex);
117     }
118 
119     try { //try to support EPS output format if it is present
120       ioHandlers.add((IOHandler) Class.forName("yext.export.io.EPSOutputHandler").newInstance());
121     } catch (ClassNotFoundException cnfex) {
122       //EPS format disabled. Put yExport extension package in your classpath
123     } catch (Exception ex) {
124       D.trace(ex);
125     }
126 
127     try { //try to support EMF output format if it is present
128       ioHandlers.add((IOHandler) Class.forName("yext.export.io.EMFOutputHandler").newInstance());
129     } catch (ClassNotFoundException cnfex) {
130       //EMF format disabled. Put yExport extension package in your classpath
131     } catch (Exception ex) {
132       D.trace(ex);
133     }
134 
135   }
136 
137   /**
138    * does the conversion specified on the command line.
139    * @param args the command line arguments.
140    */
141   public void convert(String[] args) {
142     parseArgs(args);
143 
144     Graph2D graph = new Graph2D();
145 
146     //add HierarchyManager in case the input and output files
147     //are able to handle graph hierarchy information
148     HierarchyManager hierarchy = new HierarchyManager(graph);
149 
150     //read in the graph using inpoutHandler
151     IOHandler inputHandler = getIOHandler(inFile);
152 
153     if (inputHandler != null && inputHandler.canRead()) {
154       try {
155         inputHandler.read(graph, inFile);
156       }
157       catch (IOException iex) {
158         error("Error while decoding file " + inFile + "\n" + iex);
159       }
160     } else {
161       usage("Can't determine input format");
162     }
163 
164     //write out the graph using outputHandler
165     IOHandler outputHandler = getIOHandler(outFile);
166 
167     if (outputHandler != null && outputHandler.canWrite()) {
168       Graph2DView view = null;
169       if (outputHandler instanceof ImageOutputHandler) {
170         //configure rendering component for image formats
171         view = ((ImageOutputHandler) outputHandler).createDefaultGraph2DView(graph);
172       } else {
173         view = new Graph2DView(graph);
174       }
175       configureView(view);
176       //set the viewport view to the current view of the graph.
177       graph.setCurrentView(view);
178       try {
179         outputHandler.write(graph, outFile);
180       }
181       catch (IOException iex) {
182         error("Error while encoding file " + outFile + "\n" + iex);
183       }
184       //deregister the viewport view for the graph again.
185       graph.removeView(view);
186     } else {
187       usage("Can't determine output format");
188     }
189 
190   }
191 
192   /**
193    * Configures the view that is used as rendering environment for some
194    * output formats.
195    */
196   private void configureView(Graph2DView view) {
197     Graph2D graph = view.getGraph2D();
198     Rectangle box = graph.getBoundingBox();
199     Dimension dim = getOutputSize(box);
200     view.setSize(dim);
201     view.zoomToArea(box.getX() - 10, box.getY() - 10, box.getWidth() + 20, box.getHeight() + 20);
202     view.setPaintDetailThreshold(0.0); //never switch to less detail mode
203   }
204 
205   /**
206    * Parses the command line arguments and set attributes
207    */
208   public void parseArgs(String[] args) {
209     for (int i = 0; i < args.length; i++) {
210       if ("-in".equals(args[i]) && inFile == null) {
211         inFile = args[++i];
212       } else if ("-out".equals(args[i]) && outFile == null) {
213         outFile = args[++i];
214       } else if ("-width".equals(args[i])) {
215         outputWidth = Integer.parseInt(args[++i]);
216       } else if ("-height".equals(args[i])) {
217         outputHeight = Integer.parseInt(args[++i]);
218       }
219     }
220 
221     if (inFile == null) {
222       usage("No input file specified");
223     }
224 
225     if (outFile == null) {
226       usage("No output file specified");
227     }
228   }
229 
230   /**
231    * Returns the output size of image formats by
232    * inspecting the input size of the graph and the output size
233    * parameters.
234    */
235   private Dimension getOutputSize(Rectangle inBox) {
236     if (outputWidth > 0 && outputHeight > 0) {
237       //output completely specified. use it
238       return new Dimension((int) outputWidth, (int) outputHeight);
239     } else if (outputWidth > 0) {
240       //output width specified. determine output height
241       return new Dimension(outputWidth,
242           (int) (outputWidth * (inBox.getHeight() / inBox.getWidth())));
243     } else if (outputHeight > 0) {
244       //output height specified. determine output width
245       return new Dimension((int) (outputHeight * (inBox.getWidth() / inBox.getHeight())),
246           outputHeight);
247     } else //no output size specified
248     {
249       //no output size specified. use input size, but only if smaller than 1024
250       double width = inBox.getWidth();
251       double height = inBox.getHeight();
252       //scale down if necessary, keeping aspect ratio
253       if (width > 1024) {
254         height *= 1024 / width;
255         width = 1024;
256       }
257       if (height > 1024) {
258         width *= 1024 / height;
259         height = 1024;
260       }
261       return new Dimension((int) width, (int) height);
262     }
263   }
264 
265   /**
266    * returns the IOHandler that is responsible for files with the
267    * given name.
268    */
269   private IOHandler getIOHandler(String fileName) {
270     for (Iterator iter = ioHandlers.iterator(); iter.hasNext();) {
271       IOHandler ioh = (IOHandler) iter.next();
272       if (fileName.endsWith(ioh.getFileNameExtension())) {
273         return ioh;
274       }
275     }
276     return null;
277   }
278 
279   //////////////////////////////////////////////////////////////////////////////
280   // STATIC LAUNCHER SECTION ///////////////////////////////////////////////////
281   //////////////////////////////////////////////////////////////////////////////
282 
283   public static void main(String[] args) {
284     GraphFormatConverter converter = new GraphFormatConverter();
285     converter.convert(args);
286   }
287 
288 }
289