How to use java.awt.Image on JavaFX

今回も まだまだ イメージに関する話題です。
今回は java.awt.Image を JavaFX で表示する方法についてです。

既にご存知だと思いますが...
JavaJavaFX では 画像を表すクラスが違います。

Java の場合は

java.awt.Image
JavaFX の場合は
java.scene.image.Image
といった感じですので、当然、 Java の Image をそのまま JavaFX で表示することはできないのです。
ところが、ちょっと凝った デスクトップ・アプリ を作ろうと思うと、java.awt.Image を JavaFX で表示しなくてはならない時があるのです。
例えば、『Drag and Drop on JavaFX Part 6 (FileDroppable)』 のサンプルのようにブラウザから画像をドラッグして表示する場合がまさにそうです。
このサンプルの場合、JavaFX コードの中で
  1. ドラッグ処理は Java API
  2. 表示は JavaFX API
を使っていますので、ドラッグ処理で得られた java.awt.Image を JavaFX で表示しなくてはなりません。

と言うことで...
java.awt.Image を javafx.scene.image.Image に変換する方法です。
これはとっても簡単です。JavaFX であらかじめ用意されている 以下の API を利用するだけです。

var image: java.awt.Image;
var fxImage = SwingUtils.toFXImage(image as java.awt.image.BufferedImage);

ただし、一つポイントが...
実は、このAPIで変換できるのは java.awt.Image ではなく java.awt.image.BufferedImage なのです。
全ての画像が java.awt.image.BufferedImage とは限らないので...

var image: java.awt.Image;
var fxImage =
    if (image instanceof BufferedImage) {
        SwingUtils.toFXImage(image as BufferedImage);

    } else {
 
        // java.awt.Image を java.awt.image.BufferedImage に変換

        var tk = Toolkit.getDefaultToolkit();
        while (not tk.prepareImage(image, -1, -1, null)) {
            Thread.sleep(200);    // 読み込みが終了するまで繰返し。
                                  // 本当はエラーチェック等必要だと思うが割愛。
        }

        // image と同サイズの BufferedImage (今回は 固定で TYPE_INT_ARGB)
        var bufferedImage = new BufferedImage(image.getWidth(null),
                                              image.getHeight(null),
                                              BufferedImage.TYPE_INT_ARGB);
        var g = bufferedImage.createGraphics();
        g.drawImage(image, null, null);
        g.dispose();
        SwingUtils.toFXImage(bufferedImage);
    }
とするのが実用的かな。