Building a headless mode

Trying to run processing to render graphs on a web server runs into the problem that the machine is headless. While it is easy to create an off-screen renderer, it is not easy to stop the window in the first place.

We could just use the PDF renderer, but since we don't want pdf files it seems like an ugly approach.

I'm willing to edit the code and test a nicer change. Can any developer of the PApplet comment on how to turn off window creation?

Answers

  • Can you post your code as an MCVE?

    I believe I've answered this on StackOverflow, but the basics are that you have to use Processing as a Java library, then just use the PGraphics class to render your image.

  • For a number of reasons, I don't want to create a virtual X server. I have already written the code to work on a PGraphics. The problem is, it appears that the only legal way to instantiate a PGraphics is through the method createGraphics on PApplet. This is, of course, recursive since the PApplet then need a head to draw its (nonexistent) window on. Forget creating a headless mode, how about telling me how to attach a PGraphics to a PImage?

  • PGraphics already inherits from PImage! :-B

  • PGraphics g = new PImage(500,500);

    is an error because PImage is the base class, not PGraphics. How to attach a PGraphics to a PImage?

  • PImage class got a get() method which returns a new clone of it:
    https://processing.org/reference/PImage_get_.html

  • edited June 2015

    If you merely wanna transform a PImage into a PGraphics,
    then createGraphics() using the same width & height dimensions.
    Finally background() the PImage into the newly PGraphics clone:

    // forum.processing.org/two/discussion/10305/building-a-headless-mode
    
    PGraphics pg;
    
    void setup() {
      size(300, 300, JAVA2D);
      smooth(4);
      noLoop();
    
      background(#008000);
      pg = toPGraphics(get());
    }
    
    void draw() {
      background(pg);
    }
    
    PGraphics toPGraphics(PImage img) {
      PGraphics pg = createGraphics(img.width, img.height);
    
      pg.beginDraw();
      pg.background(img);
      pg.endDraw();
    
      return pg;
    }
    
  • edited June 2015

    In case you wish to clone an already existing PGraphics instead, the process is very similar.
    We only need to find out which renderer it is via isPG(), is2D() & is3D() tests:

    // forum.processing.org/two/discussion/10305/building-a-headless-mode
    
    PGraphics pgClone;
    
    void setup() {
      size(300, 300, P2D);
      smooth(4);
      noLoop();
    
      PGraphics pgTmp = createGraphics(width, height);
      pgTmp.beginDraw();
      pgTmp.fill(#0000FF);
      pgTmp.ellipse(pgTmp.width>>1, pgTmp.height>>1, pgTmp.width>>1, pgTmp.height>>1);
      pgTmp.endDraw();
    
      pgClone = clonePGraphics(pgTmp);
    }
    
    void draw() {
      background(pgClone);
    }
    
    PGraphics clonePGraphics(PGraphics pg) {
      String renderer  = !pg.isGL()? JAVA2D : (pg.is2D()? P2D : P3D);
      PGraphics cloned = createGraphics(pg.width, pg.height, renderer);
    
      cloned.beginDraw();
      cloned.background(pg);
      cloned.endDraw();
    
      return cloned;
    }
    
  • This question asks how to draw graphics on a headless workstation. If I run an X server, then obviously, I can run with a PApplet and this is moot. However, it seemed pretty simple to just attach a PGraphics to an image and draw on that instead of a PApplet.

    However, @GotoLoop, if the only way of constructing a PGraphics is to have a PApplet do it, then this approach is useless since it won't work on a headless machine.

    I looked at the source code for createGraphics, but I could not construct a sequence of operations that would work on an image.

    • Seems like main stumbling block is createGraphics() in order to properly instantiate 1 of the PGraphics subclasses. :-<
    • In the past I did some experiments in subclassing PGraphics which bypass createGraphics().
    • Dunno whether it's enough to use PGraphics in headless mode.
    • But it's worth a shot me guess... :-\"
    1. http://forum.processing.org/two/discussion/5238/creating-a-layer-class-that-extends-pgraphics
    2. http://forum.processing.org/two/discussion/6884/question-about-pgraphics
  • Thanks. On the one hand, creating PGraphicsJava2D is relatively easy. However, it requires that the parent applet be non-null. I have no idea why since we are not drawing to it. In any case, in order to create the PGraphics we have to create a window.

    Any idea?

  • edited June 2015

    Inside Layer class, constructor's method initialize() is the createGraphics()'s replacement:

      public void initialize(int w, int h, PApplet p, String s) {
        setParent(p);
        setPrimary(false);
        setPath(s);
        setSize(w, h);
      }
    

    AFAIK, only setSize() is essential. We can get away w/o calling any of the rest! \m/

    setPath() is to specify the path field for save():
    https://processing.org/reference/PImage_save_.html

    setPrimary() is to label it is the main canvas. It should always be false.
    And much probably, it is already instantiated as false anyways. :-@

    Dunno what a PGraphics does w/ a PApplet reference.
    Maybe it's only necessary when it's setPrimary() to true.
    Just like setPath() & setPrimary(), method setParent() can be omitted w/ peace of mind.
    If you wish, you can pass an innocuous new PApplet() as argument for it ;))

    Method ignite() is merely to pre-initialize the newly "hacked" PGraphicsJava2D w/ some nice defaults:

    public void ignite() {
      beginDraw();
      smooth(4);
      fill(-1);
      stroke(0);
      endDraw();
    }
    

    Actually, you can trim that whole subclass a lot!!! >:)

Sign In or Register to comment.