Таким образом, после некоторых исследований я реализовал холст рисовать с помощью JavaFX и здесь упрощенный пример:
Сначала я сделал приложение JavaFX, которая запускается в отдельном потоке (я использую Spring taskExecutor но простой Java поток может использоваться).
public class ChartGenerator extends Application {
private static Canvas canvas;
private static volatile byte[] result;
public static void initialize(TaskExecutor taskExecutor) {
taskExecutor.execute(new Runnable() {
@Override
public void run() {
launch(ChartGenerator.class);
}
});
}
public static synchronized byte[] generateChart(final Object... params) {
Platform.runLater(new Runnable() {
@Override
public void run() {
ByteArrayOutputStream baos = null;
try {
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
/**
* Do the work with canvas
**/
final SnapshotParameters snapshotParameters = new SnapshotParameters();
snapshotParameters.setFill(Color.TRANSPARENT);
WritableImage image = canvas.snapshot(snapshotParameters, null);
BufferedImage bImage = SwingFXUtils.fromFXImage(image, null);
baos = new ByteArrayOutputStream();
ImageIO.write(bImage, chartType.outputFormat, baos);
result = baos.toByteArray();
} catch (InstantiationException e) {
throw new ChartGenerationException(e);
} catch (IllegalAccessException e) {
throw new ChartGenerationException(e);
} catch (NoSuchMethodException e) {
throw new ChartGenerationException(e);
} catch (InvocationTargetException e) {
throw new ChartGenerationException(e);
} catch (IOException e) {
throw new ChartGenerationException(e);
} finally {
IOUtils.closeQuietly(baos);
}
}
});
while (result == null) {
//wait
}
byte[] ret = result;
result = null;
return ret;
}
@Override
public void start(Stage stage) {
canvas = new Canvas();
}
public static class ChartGenerationException extends RuntimeException {
public ChartGenerationException(String message) {
super(message);
}
public ChartGenerationException(Throwable cause) {
super(cause);
}
}
}
Затем я вызвать метод Initialize() при запуске приложения Spring:
@Autowired private TaskExecutor taskExecutor;
@PostConstruct private void initChartGenerator() {
ChartGenerator.initialize(taskExecutor);
}
Это решение может быть курсе, переносимого к приложению, не Spring.
Это однопоточное решение (в моем случае это достаточно), но я думаю, что он может быть применен к многопоточному использованию (возможно, использовать RMI для вызова метода draw).
Кроме того, это решение работает «как есть» на моем окне рабочей станции, а на среде Linux Server некоторые дополнительные действия должны быть вызваны:
- Вы не можете использовать JavaFX на OpenJDK (по состоянию на август 2013 года) - нужно переключить в Oracle JDK
- Java версия должна быть не меньше, чем Java 7u6
самый сложный - вы должны использовать виртуальный дисплей, чтобы сделать JavaFX работать на безголовых средах:
APT-получить установку Xvfb
// затем на старте сервера приложений:
экспорт DISPLAY = ": 99"
старт-стоп-демон --start --background --user молы --exec «/ USR/бен/Судо»- -u пристань/USR/бен/Xvfb: 99 -screen 0 1024x768x24
PSВы также можете использовать другие возможности JavaFX на стороне сервера (например, экспортировать html в изображение) с помощью этого решения.
Это классно. Я так взволнован, чтобы попробовать. Спасибо за попытку! – GGrec