You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过OpenGL/GLFW从Windows剪贴板加载图片?

实现Windows剪贴板加载图片的方案

GLFW的glfwGetClipboardString仅支持读取文本格式的剪贴板内容,而Windows资源管理器复制图片时,剪贴板存储的是文件路径列表(CF_HDROP格式)或图片像素数据(如CF_DIB格式),因此原代码无法识别。以下是基于Windows原生API的实现方案,分两种场景处理:

场景1:复制的是图片文件(资源管理器中复制图片文件)

当你在资源管理器中复制图片文件时,剪贴板会以CF_HDROP格式存储文件路径列表,我们可以读取该路径,复用你已有的「从路径加载图片」功能。

场景2:复制的是图片内容(如截图、画图中复制的图像)

此时剪贴板存储的是CF_DIB格式的设备无关位图数据,需要解析像素信息并转换为OpenGL支持的纹理格式。

完整代码实现

#include <windows.h>
#include <shlobj.h>
#include <vector>

// 编译时链接shell32库(VS环境)
#pragma comment(lib, "shell32.lib")

bool FeatherGUI::loadFromClipBoard() {
    std::cout << "Loading from clipboard" << std::endl;

    HWND hwnd = glfwGetWin32Window(this->windowContext);
    if (!OpenClipboard(hwnd)) {
        std::cout << "Failed to open clipboard" << std::endl;
        return false;
    }

    // 优先处理文件列表格式(CF_HDROP)
    HDROP hDrop = (HDROP)GetClipboardData(CF_HDROP);
    if (hDrop != nullptr) {
        UINT fileCount = DragQueryFile(hDrop, 0xFFFFFFFF, nullptr, 0);
        if (fileCount > 0) {
            char filePath[MAX_PATH];
            DragQueryFile(hDrop, 0, filePath, MAX_PATH);
            CloseClipboard();
            // 调用你已有的从路径加载图片的函数
            return this->loadFromPath(filePath);
        }
    }

    // 处理图片像素数据(CF_DIB格式)
    HANDLE hDib = GetClipboardData(CF_DIB);
    if (hDib != nullptr) {
        BITMAPINFO* bmpInfo = (BITMAPINFO*)GlobalLock(hDib);
        if (bmpInfo != nullptr) {
            int width = bmpInfo->bmiHeader.biWidth;
            int height = abs(bmpInfo->bmiHeader.biHeight);
            int bitsPerPixel = bmpInfo->bmiHeader.biBitCount;
            int bytesPerPixel = bitsPerPixel / 8;

            // 定位像素数据起始位置
            unsigned char* pixelData = (unsigned char*)bmpInfo + bmpInfo->bmiHeader.biSize;
            if (bmpInfo->bmiHeader.biCompression == BI_BITFIELDS) {
                pixelData += 12; // 跳过RGB掩码区域
            }

            // 将BGR格式转换为OpenGL兼容的RGBA格式
            std::vector<unsigned char> rgbaData(width * height * 4);
            for (int y = 0; y < height; y++) {
                unsigned char* row = pixelData + y * width * bytesPerPixel;
                for (int x = 0; x < width; x++) {
                    int idx = (y * width + x) * 4;
                    rgbaData[idx + 2] = row[x * bytesPerPixel];     // B通道转R
                    rgbaData[idx + 1] = row[x * bytesPerPixel + 1]; // G通道保留
                    rgbaData[idx] = row[x * bytesPerPixel + 2];     // R通道转B
                    rgbaData[idx + 3] = 255;                        // 全透明通道
                }
            }

            // 创建并绑定OpenGL纹理(复用你已有的纹理逻辑)
            GLuint texture;
            glGenTextures(1, &texture);
            glBindTexture(GL_TEXTURE_2D, texture);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgbaData.data());
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

            GlobalUnlock(hDib);
            CloseClipboard();
            // 后续将texture设置为当前渲染纹理即可
            return true;
        }
        GlobalUnlock(hDib);
    }

    // 回退到文本读取逻辑(兼容复制图片路径文本的情况)
    const char* clipboard = glfwGetClipboardString(this->windowContext);
    if (clipboard == NULL) {
        std::cout << "Clipboard is empty or unsupported format" << std::endl;
        CloseClipboard();
        return false;
    } else {
        std::cout << "Clipboard content: " << clipboard << std::endl;
        CloseClipboard();
        return this->loadFromPath(clipboard);
    }

    CloseClipboard();
    return false;
}

关键说明

  • Windows API依赖:需要包含<windows.h>和<shlobj.h>,并链接shell32.lib。
  • 格式优先级:先检测文件列表格式,再处理图片像素数据,最后回退到文本读取,覆盖大部分使用场景。
  • 像素格式转换:DIB默认是BGR顺序,需转换为OpenGL常用的RGBA顺序,若遇到32位BGRA格式,可直接调整通道映射逻辑。
  • 窗口句柄:通过glfwGetWin32Window获取GLFW窗口对应的Windows HWND,确保剪贴板操作与当前窗口关联。

内容的提问来源于stack exchange,提问作者Carlos López Martínez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 12:15:34