简体   繁体   English

将处理草图保存到服务器端的PNG文件,没有GUI /显示

[英]Save a Processing sketch to a PNG file, server-side with no GUI/display

I'd like to use Processing to render a visualization on the server side (headlessly, with no GUI ). 我想使用Processing在服务器端渲染可视化(无头, 没有GUI )。 The Processing sketch is static (ie does not animate), so I only need to grab the first frame, and I'd like to serve this result out to the users of our web application on-demand. 处理草图是静态的(即没有动画),因此我只需要抓住第一帧,并且我希望按需将此结果提供给我们的Web应用程序的用户。

I've searched around a bit on the processing.org forums and it's been suggested that Processing is not intended to be launched headlessly. 我在processing.org论坛上搜索了一下,并且有人建议Processing不会无头启动。 The only hack I've seen to do it is one involving launching a headless X11 display: 我见过的唯一一个涉及推出无头X11显示器的黑客:

Xvfb :2 &
export DISPLAY=":2"
./myapp
killall -9 Xvfb

.. Which is not going to work for us as we'd like to have a pure-Java solution and can't always guarantee an X renderer on the server-side. ..这对我们不起作用,因为我们希望有一个纯Java解决方案,并且无法始终保证服务器端的X渲染器。

How do I do this in pure Java? 我如何在纯Java中执行此操作?

Xvfb is likely to be faster than a java renderer, and a hardware-accelerated X server will be the fastest by a large margin, but if you want a 'pure' java solution you could try the Pure Java AWT Toolkit . Xvfb可能比java渲染器更快,硬件加速的X服务器将是最快的,但如果你想要一个'纯'java解决方案,你可以尝试使用Pure Java AWT Toolkit

EDIT: Here's a boot command line example lifted from here : 编辑:这是从这里解除的启动命令行示例:

java -Xbootclasspath:JDK/jre/lib/rt.jar:LIB/pja.jar -Dawt.toolkit=com.eteks.awt.PJAToolkit -Djava.awt.graphicsenv=com.eteks.java2d.PJAGraphicsEnvironment -Djava.awt.fonts=JDK/jre/lib/fonts mainclassname args

Create a standard headless Java app, create a PGraphics object in it(1) and perform all of your drawing operations on that. 创建一个标准的无头Java应用程序,在其中创建一个PGraphics对象(1)并对其执行所有绘图操作。 Then save the PGraphics object to disk as an image file using .save(). 然后使用.save()将PGraphics对象保存为磁盘图像文件。

1 You may need to obtain this from a PApplet, I'm not sure if you can create it directly. 1您可能需要从PApplet获取此信息,我不确定您是否可以直接创建它。

The code will look mode or less like this: 代码看起来模式或更少如下:

PApplet applet = new PApplet();
PGraphics g = applet.createGraphics(200, 400, PApplet.JAVA2D) // same params as size()
g.beginDraw();
g.ellipse // ... etc, your drawing goes here
g.endDraw();
g.save("filename.png");

The solution from Ollie Glass ceased to work because the constructor of PApplet/Applet checks whether the environment is headless or not, ie -Djava.awt.headless=true . 来自Ollie Glass的解决方案停止工作,因为PApplet/Applet的构造函数检查环境是否无头,即-Djava.awt.headless=true

So there is no way of creating a PApplet object in the first place. 因此,首先无法创建PApplet对象。

Instead, create your PGraphics directly. 相反,直接创建您的PGraphics For instance, to draw everything into a pdf 例如,将所有内容绘制成pdf

PGraphics pdf = new PGraphicsPDF();
pdf.setPrimary(false);
pdf.setPath(filename);
pdf.setSize(sizeX, sizeY);
// pdf.setParent(new PApplet()); This is intentionally NOT called.

pdf.beginDraw();

// draw everything

pdf.dispose();
pdf.endDraw();

Adding text will still throw an exception since the underlying PGraphics calls its parent (the PApplet ) for some helper methods. 添加文本仍会引发异常,因为基础PGraphics调用parentPApplet )来获取某些辅助方法。 However, this hasn't been set because we are not allowed to create a PApplet in the first place. 但是,这还没有设置,因为我们不允许首先创建一个PApplet

A solution is to get rid of these function calls is creating you own version of PGraphicsPDF . 一个解决方案是摆脱这些函数调用正在创建自己的PGraphicsPDF版本。 For example 例如

class MyPGraphicsPDF extends PGraphicsPDF{

    @Override
    public float textAscent() {
        if (textFont == null) {
          defaultFontOrDeath("textAscent");
        }

        Font font = (Font) textFont.getNative();
        //if (font != null && (textFont.isStream() || hints[ENABLE_NATIVE_FONTS])) {
        if (font != null) {
          FontMetrics metrics = this.getFontMetrics(font);
          return metrics.getAscent();
        }
        return super.textAscent();
      }

    @Override
      public float textDescent() {
        if (textFont == null) {
          defaultFontOrDeath("textDescent");
        }
        Font font = (Font) textFont.getNative();
        //if (font != null && (textFont.isStream() || hints[ENABLE_NATIVE_FONTS])) {
        if (font != null) {
          FontMetrics metrics = this.getFontMetrics(font);
          return metrics.getDescent();
        }
        return super.textDescent();
      }

    public FontMetrics getFontMetrics(Font font) {
        FontManager fm = FontManagerFactory.getInstance();
        return sun.font.FontDesignMetrics.getMetrics(font);
    }
}

textAscent() and textDescent() are copies of the code from PGraphics with the change of not calling getFontMetrics(Font font) from the non-existing parent PApplet . textAscent()textDescent()PGraphics代码的副本,更改为不getFontMetrics(Font font)存在的parent PApplet调用getFontMetrics(Font font) Instead both redirect to the third method that reimplements the missing helper method of PApplet as a slightly shorter version of java.awt.Component.getFontMetrics(Font font) . 而是重定向到第三个方法,该方法重新实现了PApplet的缺失辅助方法,作为java.awt.Component.getFontMetrics(Font font)的略短版本。

Hope that helps. 希望有所帮助。

Would be nice to have a native headless version of processing when explicitely calling for a file as drawing board. 当明确地要求文件作为绘图板时,有一个原生的无头版处理会很好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM