Menu

How to save JUNG graphs to JPEG files?

2005-10-25
2013-05-29
  • Duane Bowker

    Duane Bowker - 2005-10-25

    I have a JUNG-based application working and doing some very cool things but one capability I'd like to add is the ability to dump the current graph display to a JPEG file. I did look through the JUNG listserv archives and saw there was a discussion on this in April. It looks as if there was a problem when Jung moved from 1.5 to 1.6. I am currently using 1.7.0 and just started working with 1.7.1.

    I saw in the 12/2004 FAQ that there was a question on this. It has some sample code which incidentally does not compile. The GraphDraw class is deprecated, the VisualizationViewer vv.getLayout().getCurrentSize() call needs to be either vv.getGraphLayout().getCurrentSize() or just vv.getSize(). I also see in the JUNG Visualization document dated September that there is another code segment at the end for dumping to an image file. Both that code segment as well as the ones in the FAQ suffer from another trickier problem. They call the VisualizationViewer paintComponent(Graphics2D) method which is protected. I want to run this outside of the VisualizationViewer's package and I was hoping to avoid subclassing VisualizationViewer but perhaps that's the only solution.

    The other approach I've tried is to use the VisualizationViewer getGraphics() method since that's public.
       BufferedImage bi = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
       Graphics2D graphics = (Graphics2D)vv.getGraphics();
       graphics.drawImage(bi,0,0,width,height,null);
       ImageIO.write(bi,"JPEG",file);
    And I do the...
       vv.setDoubleBuffered(false);
    before this and the...
       vv.setDoubleBuffered(true);
    after all this, as per notes in the JUNG Visualization documentation.
    What I get out is a JPEG file of approximately the right XY dimension but with just black in it. Any help would be very much appreciated.

     
    • Michael Boeni

      Michael Boeni - 2005-10-25

      Hello Duane

      I use the following little method:
        public static void writeJPEGImage(VisualizationViewer vv, String filename)
        {
          int width = vv.getWidth();
          int height = vv.getHeight();
          Color bg = vv.getBackground();

          BufferedImage bi = new BufferedImage(width, height,
                                               BufferedImage.TYPE_INT_BGR);
          Graphics2D graphics = bi.createGraphics();
          graphics.setColor(bg);
          graphics.fillRect(0, 0, width, height);
          vv.paint(graphics);

          try
          {
            ImageIO.write(bi, "jpeg", new File(filename));
          }
          catch (Exception e)
          {
            e.printStackTrace();
          }
        }

      Which works ok with Jung 1.7.1.

      Please let me know if that resolves your issue.

      Cheers,
      Michael

       
    • Duane Bowker

      Duane Bowker - 2005-10-25

      Thanks Michael. That works perfectly.

       
    • Nobody/Anonymous

      Hi, I'm using the same method and all I'm getting is a white rectangle. What am I doing wrong?

       
    • Nobody/Anonymous

      Ah, wait, doing the exact same thing I get:

      java.lang.IllegalArgumentException: Width (0) and height (0) cannot be <= 0
              at java.awt.image.DirectColorModel.createCompatibleWritableRaster(DirectColorModel.java:999)
              at java.awt.image.BufferedImage.<init>(BufferedImage.java:290)

      So I changed
          int width = vv.getWidth();
          int height = vv.getHeight();

      to

          int width = vv.getGraphLayout().getCurrentSize().width;
              int height = vv.getGraphLayout().getCurrentSize().height;

      I'm lost here

       
    • Nobody/Anonymous

      Hi

      Which version of JUNG are you using? i remember something with double buffering that posed a problem...

      Cheers,
      Michael

       
    • Nobody/Anonymous

      The latest one, 1.7.1. That's why I'm confused, it's supposed to work with this version.

       
      • D. Fisher

        D. Fisher - 2005-10-28

        Did you remember to call

        vv.setDoubleBuffered( false )
        ?

        If you don't, then it'll still 'double-buffer'. For your purposes, that'll print out an all-white frame.

         
    • Nobody/Anonymous

      Yes, my function is as follows:

      public static void writeJPEGImage(VisualizationViewer vv, String filename)
          {
          vv.setDoubleBuffered(false);
          int width = vv.getGraphLayout().getCurrentSize().width;
              int height = vv.getGraphLayout().getCurrentSize().height;
          Color bg = vv.getBackground();
         
          BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
          Graphics2D graphics = bi.createGraphics();
          graphics.setColor(bg);
          graphics.fillRect(0, 0, width, height);
          vv.paint(graphics);
          try
          { ImageIO.write(bi, "jpeg", new File(filename)); }
          catch (Exception e) { e.printStackTrace(); }
          vv.setDoubleBuffered(true);
          }

       
      • Tom Nelson

        Tom Nelson - 2005-10-28

        Did you say before that when you called vv.getWidth() and
        vv.getHeight(), you got values that were == 0 ?
        If so, when you call vv.paint(g), the clip set on the
        graphics will be of size 0 by 0, and you will not paint
        anything.
        Are you able to see the graph on the screen when you
        are trying to make the image? If so, then maybe the
        vv you are trying to get the image from is not the
        same vv that is drawing on the screen.

        Tom

         
    • Nobody/Anonymous

      The image displays fine in an applet, but I can't dump it.
      I got zeroes with vv.getWidth() and  vv.getHeight() so I change it to  vv.getGraphLayout().getCurrentSize().width and vv.getGraphLayout().getCurrentSize().height and got 600x600 (the image size).
      How can I know if they're the same vv?

       
      • Tom Nelson

        Tom Nelson - 2005-11-01

        As I said before, if vv.getWidth() and vv.getHeight()
        return zeros, then vv.paint(Graphics g) is not
        going to paint anything.

        As to where the problem is, I cannot tell from what
        you have told me. Perhaps if you posted the
        code where you create your graph and your
        VisualizationViewer it would be more clear.

        Tom

        >The image displays fine in an applet, but I can't >dump it.
        >I got zeroes with vv.getWidth() and  vv.getHeight() >so I change it to
        >vv.getGraphLayout().getCurrentSize().width and
        >vv.getGraphLayout().getCurrentSize().height and >got 600x600 (the image size).
        >How can I know if they're the same vv?

         
    • Nobody/Anonymous

      Well, here's the class Graficar, it takes sn SQL resultset and uses its data to create a graph:

      public class Graficar extends JApplet{
         
          GraphLabelRenderer graphLabelRenderer;
          VisualizationViewer vv;
          PluggableRenderer r;
          SparseTree graph;
          Vertex root;
          int longitud, comparador;
          ResultSet rs_aqui;
          String[] rutas, vertices, auxiliar, vertices_final;
         
          public Graficar(ResultSet rs) throws SQLException{
              rs_aqui=rs;
          rs_aqui.last();
              longitud = rs_aqui.getRow();
              rutas = new String[longitud];
          vertices = new String[100];
              for(int i=0; i<longitud; i++)
              rutas[i]="";
              for(int i=0; i<100; i++)
              vertices[i]="";       
          for(int k=1; k<=longitud; k++)
              {
                  rs_aqui.absolute(k);
                  rutas[k-1]=rs_aqui.getString(1); //rutas tiene las rutas distintas de la tabla
              }
          String patron=" ";
          vertices[0]=rutas[0].substring(0, rutas[0].indexOf(' '));
             
          for (int i=0; i<longitud; i++)
          {
              String aux = rutas[i];
              auxiliar = aux.split(patron);
              for (int j=0; j<auxiliar.length; j++)
              {
                  if (searchArray(vertices, auxiliar[j]) == -1)
                  {
                  vertices[searchArray(vertices, "")] = auxiliar[j];
                  continue;
                  }
              }
          }
                 
          vertices_final= new String[searchArray(vertices, "")];
         
          for (int i = 0; i < vertices_final.length; i++)
              vertices_final[i]=vertices[i];
             
          for (int i = 0; i < vertices_final.length; i++)
                      System.out.println(vertices_final[i]);
         
          root = new DirectedSparseVertex();
              graph = new SparseTree(root);
         
          Vertex[] v = createVertices(root, vertices_final);
          createEdges(v, vertices_final, rutas);
          Layout layout = new TreeLayout(graph);
          r = new PluggableRenderer();
         
          vv = new VisualizationViewer(layout,r );
              vv.setPickSupport(new ShapePickSupport());
              vv.setBackground(Color.white);
          Container content = getContentPane();
          content.add(vv);
              graphLabelRenderer = r.getGraphLabelRenderer();
         
          StringLabeller sl = StringLabeller.getLabeller(graph);
          for( int c=0; c<vertices_final.length;c++ ) {
          try {
              sl.setLabel( v[c], vertices_final[c] );
              }
              catch (StringLabeller.UniqueLabelException e){}
          }
              VertexStringer vstringer = sl;
              r.setVertexStringer(vstringer);
          r.setEdgePaintFunction(new PickableEdgePaintFunction(r, Color.black, Color.cyan));
          //vv.setDoubleBuffered(false);
          writeJPEGImage(vv, "bgp.png");
          //vv.setDoubleBuffered(true);
          }
         
          /*AADIDO!!!!!!!!!!*/
          private Vertex[] createVertices(Vertex root, String[] count) {
              Vertex[] v = new Vertex[count.length];
          v[0] = root;
              for (int i = 1; i < count.length; i++) {
                  v[i] = graph.addVertex(new DirectedSparseVertex());
              }
              return v;
          }

          /**
           * create edges for this demo graph
           * @param v an array of Vertices to connect
           */
          void createEdges(Vertex[] v, String[] vertices, String[] rutas) {
              String[] auxiliar;
          String aux, espacio=" ";
          for (int i=0; i<rutas.length; i++)
          {
          aux=rutas[i];
          auxiliar = aux.split(espacio);
              for (int j=0; j<(auxiliar.length-1); j++)
              {
                  if(vertices[0].equals(auxiliar[0]))
                  if(!v[searchArray(vertices,auxiliar[j])].isNeighborOf(v[searchArray(vertices,auxiliar[j+1])]))
                  graph.addEdge(new DirectedSparseEdge(v[searchArray(vertices,auxiliar[j])], v[searchArray(vertices,auxiliar[j+1])]));
              }
          }   
          }
         
          int searchArray(String[] recibo, String hallar)
          {
              for (int i = 0; i < recibo.length; i++)
          {
          if(recibo[i].compareTo(hallar) == 0)
          return i;
          }
          return -1;
          }
       
          public static void writeJPEGImage(VisualizationViewer vv, String filename)
          {
          /*int width = vv.getWidth();
          int height = vv.getHeight();*/
          vv.setDoubleBuffered(false);
          int width = vv.getGraphLayout().getCurrentSize().width;
              int height = vv.getGraphLayout().getCurrentSize().height;
          Color bg = vv.getBackground();
         
          BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
          Graphics2D graphics = bi.createGraphics();
          graphics.setColor(bg);
          graphics.fillRect(0, 0, width, height);
          vv.paint(graphics);
          try
          { ImageIO.write(bi, "png", new File(filename)); }
          catch (Exception e) { e.printStackTrace(); }
          vv.setDoubleBuffered(true);
          }
      }

       
      • Tom Nelson

        Tom Nelson - 2005-11-01

        You are trying to make your jpeg before the
        VisualizationViewer is realized (drawn on some
        graphics device).

        Try adding this method to your Graficar class:

          public void addNotify() {
               super.addNotify();
               writeJPEGImage(vv, "bgp.png");
          }

        That should make it defer drawing the image
        until after the Graficar is put on a screen somewhere.

        Tom

         
    • Nobody/Anonymous

      Erm, instead of png it should be jpg. I was trying with png and got the same results (just a white rectangle)

       
    • Nobody/Anonymous

      Well, it didn't work the way you said but thinking about what you said on making sure the class Graficar is already put in a screen somewhere I made a JButton in the JFrame containing the Graficar Applet that dumps the image when you click it and it worked that way.
      The odd thing is that I also tried modifying the Graficar class so it didn't extend a JApplet an only dumped the jpg image (which, BTW, is my real goal, the JApplet was just for debugging purposes) and I got the white image. Why is that?

      BTW, the Graficar class is extended from another class. The way the program works right now is it extends a Frame to do SQL queries and it has a JButton called "Graficar" that extends the class Graficar in a new window.

       
    • Nobody/Anonymous

      Now I changed o the KKLayout and used the incrementsAreDone method like this:
          while (!(layout.incrementsAreDone()));
          writeJPEGImage(vv,"bgpmap_KKMod_solo.png");

      It stops the applet until the graph is completely done, then it displays it, but the dump is still wrong.

       
      • Tom Nelson

        Tom Nelson - 2005-11-03

        Have you tried putting your 'writeJPEGImage' call
        inside the componentResized method of
        a componentListener that you add to
        the VisualizationViewer?

        Tom

         
    • Nobody/Anonymous

      I'll try that, right now my best solution was to add a window listener to the applet so when the window is closed it saves the image. It's working alright, but it looks a bit odd having a window opening and closing just for that.

       

Log in to post a comment.