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