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