Сохранение эскиза обработки в файл PNG на стороне сервера без графического интерфейса/дисплея

Я хочу использовать Processing для рендеринга визуализации на стороне сервера (без головы, без без графического интерфейса). Скетч Processing является статическим (т. е. не анимируется), поэтому мне нужно только захватить первый кадр, и я хотел бы предоставить этот результат пользователям нашего веб-приложения по запросу.

Я немного поискал на форумах processing.org, и было высказано предположение, что Processing не предназначен для запуска без головы. Единственный хак, который я видел, это запуск безголового дисплея X11:

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

.. Это не сработает для нас, поскольку мы хотели бы иметь решение на чистом Java и не всегда можем гарантировать X-рендерер на стороне сервера.

Как мне это сделать на чистой Java?


person Maciek    schedule 22.06.2010    source источник


Ответы (3)


Xvfb, вероятно, будет быстрее, чем средство визуализации Java, а X-сервер с аппаратным ускорением будет самым быстрым с большим отрывом, но если вам нужно «чистое» решение Java, вы можете попробовать Pure Java AWT Toolkit.

РЕДАКТИРОВАТЬ: Вот пример командной строки загрузки, взятый из здесь:

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
person Alexander Torstling    schedule 22.06.2010
comment
В этой ветке трехлетней давности на сайте processing.org говорится, что PJA несовместим с Processing: processing.org/discourse/yabb2/YaBB.pl?num=1193317878 . Есть мысли, продвинулось ли это вообще? - person Maciek; 22.06.2010
comment
Когда у меня возникла эта проблема, я просто укусил пулю и установил X-сервер. Это самый быстрый и самый совместимый — и зачем усложнять ситуацию, чем она уже есть? В моей компании мы потратили год, пытаясь создать «чистое решение Java», которое затем выбросили из окна, поскольку оно не могло справиться со всеми угловыми случаями. Вы должны использовать правильный инструмент для работы. Я предлагаю вам выбрать X, xvfb, если у вас нет видеокарты в комплекте. - person Alexander Torstling; 22.06.2010
comment
Xvfb подойдет для нашего Linux-сервера, но некоторые из наших блоков разработки основаны на Windows. Можно ли запустить Xvfb на Cygwin? - person Maciek; 22.06.2010
comment
Можете ли вы даже запустить Windows без головы? Я могу себе представить, что у вас могут возникнуть проблемы, если вы работаете как служба из-за ограниченного доступа к пользовательской графической среде, но я бы этого не ожидал. Вы сталкиваетесь с этой проблемой? - person Alexander Torstling; 22.06.2010

Создайте стандартное безголовое Java-приложение, создайте в нем объект PGraphics(1) и выполните с ним все операции рисования. Затем сохраните объект PGraphics на диск как файл изображения с помощью .save().

1 Возможно, вам потребуется получить это из PApplet, я не уверен, что вы можете создать его напрямую.

Код будет выглядеть примерно так:

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");
person Ollie Glass    schedule 11.05.2011

Решение от Ollie Glass перестало работать, потому что конструктор PApplet/Applet проверяет, является ли окружение безголовым или нет, то есть -Djava.awt.headless=true.

Таким образом, нет никакого способа создать объект PApplet в первую очередь.

Вместо этого создайте свой PGraphics напрямую. Например, чтобы нарисовать все в 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();

Добавление текста по-прежнему вызовет исключение, поскольку базовый PGraphics вызывает свой parent (PApplet) для некоторых вспомогательных методов. Однако это не было установлено, потому что нам не разрешено создавать PApplet в первую очередь.

Решение состоит в том, чтобы избавиться от этих вызовов функций, создав собственную версию PGraphicsPDF. Например

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() и textDescent() это копии кода из PGraphics с заменой не вызывающего getFontMetrics(Font font) из несуществующего parent PApplet. Вместо этого оба перенаправляют на третий метод, который повторно реализует отсутствующий вспомогательный метод PApplet как немного более короткую версию java.awt.Component.getFontMetrics(Font font).

Надеюсь, это поможет.

Было бы неплохо иметь собственную безголовую версию обработки при явном вызове файла в качестве чертежной доски.

person Andreas    schedule 15.10.2014