Minecraft Unofficial Forum | マインクラフト非公式フォーラム
マインクラフト日本非公式ユーザフォーラム様のサービス停止に伴い、本フォーラムを作成しました。

マインクラフト非公式フォーラムへようこそ」を一読後、登録をお願いいたします。

Forge 撮影したスクショをクリップボードに貼る

Minecraft Forge 1.12.2でのコードになりますが、たぶん他のバージョンでも問題ない。たぶん。
また、Windows 10 64bit でしか動作検証していません。もし他のOSで動かなかったらゴメンよ。


まずスクリーンショットが撮影されたことを検知しないといけない。
Forgeでは ScreenshotEvent が用意されてる。これはスクリーンショットが保存される直前に発火される。
ScreenshotEvent には二つのデータが与えられる。
一つは java.awt.image.BufferedImage で、スクリーンショットの画像情報。
もう一つは java.io.File で、スクリーンショットの保存先を決める情報。これはあとから変更できる。
また、このイベントはキャンセルできる。キャンセルするとスクリーンショットは保存されない。

次に、クリップボードに保存するには。
まず、Toolkit.getDefaultToolkit().getSystemClipboardでクリップボードを取得する。
そして、Clipboard#setContents() を呼び出すことでクリップボードにデータを書き込む訳だ。
でも、この Clipboard#setContents() の受け取る引数が少し厄介で java.awt.datatransfer.Transferable を実装したクラスでないとダメらしい。
(コダワリの強いやつだ

Transferable とはドキュメントより、
転送操作のためのデータを提供するために使用されるクラスのインタフェースを定義します。

BufferedImageTransferable の実装ではないのでラッパーを自前で用意せにゃならん。

Java:
public interface Transferable {

    public DataFlavor[] getTransferDataFlavors();
    
    public boolean isDataFlavorSupported(DataFlavor flavor);

    public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException;

}

Transferable はこの3つのメソッドを実装すればよいので苦ではない。
ですが、またDataFlavorという未知のクラスが出てきてしまった。

またまたドキュメントより、
DataFlavor は、データに関するメタ情報を提供します。DataFlavor は通常、クリップボード上のデータにアクセスしたり、ドラッグ&ドロップ操作中にデータにアクセスしたりするために使用されます。
とは言われてもクリップボードの詳しい仕組みは知らないのであまりピンと来ない。MIMEタイプや表現クラスが格納されるらしい。
画像ならMIMEタイプは image/x-java-image 、表現クラスは java.awt.Image となる。

で、結局のところどう実装すればいいのかというと、

Java:
static class ImageWrapper implements Transferable {

     //転送したい画像
    private BufferedImage image;

    //データの種類(配列なのは複数指定するため。一つしか使用しないので特に気にしない)
    private DataFlavor[] flavor;

    public ImageWrapper(BufferedImage image) {
        this.image = image;

        //DataFlavor.imageFlavorはその名の通り画像データ用。
        this.flavor = new DataFlavor[] { DataFlavor.imageFlavor };
    }

    @Override
     public DataFlavor[] getTransferDataFlavors() {
      return flavor;
    }

    //DataFlavor#equalsではMIMEタイプや表現クラスが同じかどうか調べてる
    @Override
    public boolean isDataFlavorSupported(DataFlavor flavor) {
      return this.flavor[0].equals(flavor);
    }

    @Override
    public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
        if (!this.isDataFlavorSupported(flavor))
            throw new UnsupportedFlavorException(flavor);
        return image;
    }

}

このようにすればJavaがうまいことやってくれて動く。(よくわかってない
あとは、new ImageWrapper(image); で生成したインスタンスを Clipboard#setContents() の引数に与えるだけ。

こんな感じ。

Java:
@SubscribeEvent
public void onScreenshot(ScreenshotEvent event) {
    Clipboard clipboard = Toolkit.getDefaultTookit().getSystemClipboard();
    ImageWrapper wrapper = new ImageWrapper(event.getImage());
    clipboard.setContents(wrapper, null); //ClipboardOwnerはnullでも大丈夫
}

これにて一件落着(?)
スクリーンショットが Ctrl + V でTwitterや画像編集ソフトに一発でペーストできるようになった!
 
Top