用 java 开发一个 clipboard-image 的功能、手动 jar 打包

因为nodejs里一个不好实现的需求,发现这个问题用 java 很好解决
更新于: 2023-08-15 20:51:45

背景

自己在实现 xpic 这个项目的时候,核心功能就是读取 clipboard 里的 image buffer 或者 filepath,用了几种办法实现都不理想。

nodejs 里并没有合适,或者说是优雅的解决方案,唯一找到的一个,还是用 c语言 实现的,然后包了一层 nodejs 的壳,不过,看过源码,也基本打开了思路。

代码

文件名 ClipboardImage.java 

import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class ClipboardImage {
    public static void main(String[] args) {
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        Transferable contents = clipboard.getContents(null);

        if (contents != null) {
            // 来源截图软件
            Boolean isFromClipboard = contents.isDataFlavorSupported(DataFlavor.imageFlavor);
            // 来源于复制系统文件
            Boolean isFromFile = contents.isDataFlavorSupported(DataFlavor.javaFileListFlavor);

            if (isFromClipboard) {
                try {
                    Image image = (Image) contents.getTransferData(DataFlavor.imageFlavor);
                    String imagePath = saveImageToFile(convertToBufferedImage(image));
                    System.out.print(imagePath);
                } catch (UnsupportedFlavorException | IOException e) {
                    e.printStackTrace();
                }
            }

            if (isFromFile) {
                try {
                    @SuppressWarnings("unchecked")
                    java.util.List<File> files = (java.util.List<File>) contents
                            .getTransferData(DataFlavor.javaFileListFlavor);
                    if (!files.isEmpty()) {
                        File file = files.get(0); // Assuming the first file
                        String filePath = file.getAbsolutePath();
                        System.out.print(filePath);
                    }
                } catch (UnsupportedFlavorException | IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static String saveImageToFile(BufferedImage image) throws IOException {
        File tempFile = File.createTempFile("clipboard_image", ".png");
        ImageIO.write(image, "png", tempFile);
        return tempFile.getAbsolutePath();
    }

    private static BufferedImage convertToBufferedImage(Image image) {
        BufferedImage newImage = new BufferedImage(
                image.getWidth(null), image.getHeight(null),
                BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = newImage.createGraphics();
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return newImage;
    }
}

编译

编译字节码,生成 jar 包的过程。

javac ClipboardImage.java
jar cvfe ClipboardImage.jar ClipboardImage ClipboardImage.class

执行

$ java -jar ClipboardImage.jar
/var/folders/kk/45b76t8x6157sc2895ffdw3c0000gn/T/clipboard_image10270512188937717754.png

结论

  • 这个方法只是开拓一种思路,缺点如下:
    • 有java的应用程序框弹出,使用并不方便
    • 这个依赖于 java 环境,不方便推广使用
    • 打出来的包,会比较大(虽然实际情况是只有4k左右)
  • 后续:go 应该会是一个不错的解决方案

关于 headless

检查是否在无头模式下运行

import java.awt.GraphicsEnvironment;

public class Test {
    public static void main(String[] args) {
        // 检查是否在无头模式下运行
        if (GraphicsEnvironment.isHeadless()) {
            System.out.println("Running in headless mode");
            // 执行你的逻辑
        } else {
            System.out.println("Running in graphical mode");
            // 弹出图形界面
            // ...
        }
    }
}

// java -Djava.awt.headless=true -jar ClipboardImage.jar

参考