OSX上的JavaFX screencapture无头exception

我正在将我的旧Java应用程序从swing转换为javafx,我遇到了一个问题。

我正在使用以下代码来捕获屏幕截图:

public ScreenCapper() { ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); gs = ge.getScreenDevices(); try { robot = new Robot(gs[gs.length-1]); } catch (AWTException e) { LOGGER.getInstance().ERROR("Error creating screenshot robot instance!"); } } public Color capture() { Rectangle bounds; mode = gs[0].getDisplayMode(); bounds = new Rectangle(0, 0, mode.getWidth(), mode.getHeight()); //...... } 

在Windows下运行应用程序时,此工作正常。 但是,在OSX下运行时会出现以下exception:

 Exception in Application start method Exception in thread "main" java.lang.RuntimeException: Exception in Application start method at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:403) at com.sun.javafx.application.LauncherImpl.access$000(LauncherImpl.java:47) at com.sun.javafx.application.LauncherImpl$1.run(LauncherImpl.java:115) at java.lang.Thread.run(Thread.java:722) Caused by: java.awt.HeadlessException at sun.java2d.HeadlessGraphicsEnvironment.getScreenDevices(HeadlessGraphicsEnvironment.java:72) at be.beeles_place.roggbiv.utils.ScreenCapper.(ScreenCapper.java:33) at be.beeles_place.roggbiv.modes.AverageColorMode.start(AverageColorMode.java:31) at be.beeles_place.roggbiv.modes.ColorModeContext.startCurrentColorMode(ColorModeContext.java:28) at be.beeles_place.roggbiv.controller.RoggbivController.(RoggbivController.java:42) at be.beeles_place.roggbiv.RoggbivMain.start(RoggbivMain.java:67) at com.sun.javafx.application.LauncherImpl$5.run(LauncherImpl.java:319) at com.sun.javafx.application.PlatformImpl$5.run(PlatformImpl.java:215) at com.sun.javafx.application.PlatformImpl$4$1.run(PlatformImpl.java:179) at com.sun.javafx.application.PlatformImpl$4$1.run(PlatformImpl.java:176) at java.security.AccessController.doPrivileged(Native Method) at com.sun.javafx.application.PlatformImpl$4.run(PlatformImpl.java:176) at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:76) 

我认为在OSX上显然运行的javafx是无头模式,因为以下调试警告提示:

 013-03-10 10:44:03.795 java[1912:5903] *** WARNING: Method userSpaceScaleFactor in class NSView is deprecated on 10.7 and later. It should not be used in new applications. Use convertRectToBacking: instead. 2013-03-10 10:44:05.472 java[1912:707] [JRSAppKitAWT markAppIsDaemon]: Process manager already initialized: can't fully enable headless mode. 

有没有办法让这个工作? 或者另一种捕获不与OSX冲突的屏幕截图的方法?

完整代码@ https://github.com/beele/Roggbiv

JavaFX不使用AWT堆栈,因此它不是在纯JavaFX应用程序中启动的。 由于线程处理细节,AWT正在Mac上以无头模式运行,然后从JavaFX请求。

有下一个选项可以解决这个问题:

  1. 使用一些voodoo魔法来初始化AWT – 在静态初始化中运行java.awt.Toolkit.getDefaultToolkit(); 编辑这只适用于较旧的JavaFX,对不起

  2. 更好的选择是选择不使用JavaFX中的AWT。 您可以使用下一个function制作屏幕截图: http : //docs.oracle.com/javafx/2/api/javafx/scene/Node.html#snapshot%28javafx.util.Callback,%20javafx.scene.SnapshotParameters,%20javafx .scene.image.WritableImage 29%

  3. 编辑正如亚历山大指出的另一种方法是在单独的VM中运行AWT代码。 为此,您可以将屏幕截图function重构为单独的类,并通过以下方式从JavaFX应用程序调用它:

      new ProcessBuilder( System.getProperty("java.home") + "/bin/java", "-cp", "classpath", "my.apps.DoScreenshot" ).start(); 

    此应用程序可以将屏幕截图存储到文件系统。 如果您需要经常进行屏幕截图并遇到性能问题,您可以运行一次单独的应用程序并通过套接字与其进行通信。

  4. 使用com.sun.glass.ui.Robot而不是AWTRobot

我看到以下可能需要注意的事项:

  1. 除了javafx.macosx.embedded的观点1.设置javafx.macosx.embedded

     System.setProperty("javafx.macosx.embedded", "true"); java.awt.Toolkit.getDefaultToolkit(); 
  2. 注意AWT的东西在EDT中完成,JavaFX的东西在JavaFX Application线程中完成。

我最近在Mac上处理JavaFX / Swing问题,所以这让我感兴趣。 如果你尝试下面的代码,它对你有用吗? (它应该将缩放的屏幕截图作为应用程序窗口的背景。)

 import java.awt.AWTException; import java.awt.DisplayMode; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Rectangle; import java.awt.Robot; import java.awt.image.BufferedImage; import javafx.application.Application; import javafx.application.Platform; import javafx.embed.swing.SwingFXUtils; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; import javafx.stage.Stage; import javax.swing.SwingUtilities; public class SO extends Application { @Override public void start(Stage stage) throws Exception { final Pane pane = new StackPane(); Scene scene = new Scene(pane, 600, 300); stage.setScene(scene); Button b = new Button("Snap"); final ImageView iv = new ImageView(); iv.fitWidthProperty().bind(pane.widthProperty()); iv.fitHeightProperty().bind(pane.heightProperty()); pane.getChildren().add(iv); pane.getChildren().add(b); b.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { doSnap(iv); } }); } }); stage.show(); } protected void doSnap(final ImageView iv) { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice[] gs = ge.getScreenDevices(); Robot robot = null; try { robot = new Robot(gs[gs.length-1]); } catch (AWTException e) { e.printStackTrace(); return; } DisplayMode mode = gs[0].getDisplayMode(); Rectangle bounds = new Rectangle(0, 0, mode.getWidth(), mode.getHeight()); final BufferedImage bi = robot.createScreenCapture(bounds); Platform.runLater(new Runnable() { @Override public void run() { Image im = SwingFXUtils.toFXImage(bi, null); iv.setImage(im); } }); } public static void main(String[] args) { System.setProperty("javafx.macosx.embedded", "true"); java.awt.Toolkit.getDefaultToolkit(); Application.launch(args); } }