Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8096376

UI Rendered as Black with off-screen Canvas usage

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P4 P4
    • 8u20
    • 8
    • javafx
    • None
    • Windows 7 64-bit
      Java 8 FCS
      Graphics Card: NVIDIA GeForce GTX 650

      Run the following program. Browse twice to select two reasonably large image files (such as a photo from a digital camera). Press the start button. This renders the images to a Canvas that is not attached to any scene in a worker thread. (Canvas doc's state this is legal, "If it is not attached to any scene, then it can be modified by any thread,...")
      The contents of the Scene will eventually paint as all black.

      /*
       * Canvas usage leads to black rendering
       */

      package blackui;

      import java.io.File;
      import java.util.concurrent.CountDownLatch;
      import javafx.application.Application;
      import javafx.application.Platform;
      import javafx.beans.binding.Bindings;
      import javafx.beans.property.SimpleBooleanProperty;
      import javafx.beans.property.SimpleObjectProperty;
      import javafx.scene.Scene;
      import javafx.scene.canvas.Canvas;
      import javafx.scene.canvas.GraphicsContext;
      import javafx.scene.control.Button;
      import javafx.scene.control.Label;
      import javafx.scene.effect.BlendMode;
      import javafx.scene.image.Image;
      import javafx.scene.image.ImageView;
      import javafx.scene.image.WritableImage;
      import javafx.scene.layout.BorderPane;
      import javafx.scene.layout.HBox;
      import javafx.scene.layout.VBox;
      import javafx.stage.FileChooser;
      import javafx.stage.Stage;

      /**
       *
       * @author scott
       */
      public class BlackUI extends Application {
      private Thread worker;
      private final SimpleBooleanProperty working = new SimpleBooleanProperty(false);
      private final SimpleObjectProperty<Image> imgProp1 = new SimpleObjectProperty<>();
      private final SimpleObjectProperty<Image> imgProp2 = new SimpleObjectProperty<>();
      private ImageView imgView;

      @Override
      public void start(Stage primaryStage) {
      Label img1Label = new Label("Image 1: <pick>");
      Label img2Label = new Label("Image 2: <pick>");
      Button browseButton = new Button("Browse...");
      browseButton.setOnAction((e) -> {
      FileChooser fc = new FileChooser();
      File f = fc.showOpenDialog(primaryStage);
      if (f != null)
      if (imgProp1.get() == null || imgProp2.get() != null) {
      img1Label.setText("Image 1: "+f.getName());
      imgProp1.set(new Image(f.toURI().toString()));
      img2Label.setText("Image 2: <pick>");
      imgProp2.set(null);
      } else {
      img2Label.setText("Image 2: "+f.getName());
      imgProp2.set(new Image(f.toURI().toString()));
      }
      });
      Button startButton = new Button("Start");
      startButton.disableProperty().bind(Bindings.or(working,Bindings.or(Bindings.isNull(imgProp1),Bindings.isNull(imgProp2))));
      startButton.setOnAction(e -> {
      worker = new Thread(() -> {
      try {
      while(!Thread.interrupted()) {
      Thread.sleep(500);
      doCanvasComputation();
      }
      } catch (InterruptedException ex) {}
      finally { Platform.runLater(() -> working.set(false));}
      });
      worker.setDaemon(true);
      working.set(true);
      worker.start();
      });

      Button stopButton = new Button("Stop");
      stopButton.setOnAction(e -> {
      worker.interrupt();
      });
      stopButton.disableProperty().bind(Bindings.not(working));
      VBox labelBox = new VBox(4, img1Label, img2Label);
      HBox fieldBox = new HBox(8, labelBox, browseButton, startButton, stopButton);
      imgView = new ImageView();
      imgView.setFitWidth(256);
      imgView.setFitHeight(256);
      imgView.setPreserveRatio(true);
      BorderPane root = new BorderPane();
      root.setTop(fieldBox);
      root.setCenter(imgView);

      Scene scene = new Scene(root, 300, 250);

      primaryStage.setTitle("Hello World!");
      primaryStage.setScene(scene);
      primaryStage.show();
      }

      // We are using Canvas to do off-screen image processing
      private void doCanvasComputation() throws InterruptedException {
      Image img1 = imgProp1.get();
      Image img2 = imgProp2.get();
      Canvas canvas = new Canvas(img1.getWidth(), img1.getHeight());
      GraphicsContext gc = canvas.getGraphicsContext2D();
      gc.setGlobalBlendMode(BlendMode.SRC_OVER);
      gc.drawImage(img1, 0, 0);
      gc.setGlobalBlendMode(BlendMode.DIFFERENCE);
      gc.drawImage(img2, 0, 0);
      CountDownLatch latch = new CountDownLatch(1);
      Platform.runLater(() -> {
      WritableImage result = canvas.snapshot(null, null);
      imgView.setImage(result);
      latch.countDown();
      });
      latch.await();
      // Here we would get a pixel reader to process the result image
      }
      /**
      * @param args the command line arguments
      */
      public static void main(String[] args) {
      launch(args);
      }

      }

            flar Jim Graham
            swpalmer Scott Palmer
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported: