首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Win32剪贴板和alpha通道图像

Win32剪贴板和alpha通道图像
EN

Stack Overflow用户
提问于 2013-03-29 02:30:09
回答 2查看 4.3K关注 0票数 10

我的应用程序应该能够将32位图像(RGB + alpha通道)复制到剪贴板,并从剪贴板粘贴这些图像。为此,我计划使用CF_DIBV5,因为BITMAPV5HEADER结构有一个字段bV5AlphaMask

问题是,对于如何准确地将图像数据存储在剪贴板中,似乎没有达成共识。在做一些测试时,我发现应用程序之间存在一些差异,这使得提出一个通用的解决方案几乎是不可能的。

以下是我的观察结果:

  1. 当我从Word 2010或XnView复制alpha通道图像到剪贴板时,它是在没有预乘像素数据的情况下存储的。
  2. 当我使用Firefox或Chrome复制图像时,像素数据似乎被alpha channel.
  3. Firefox预乘了设置为0xff000000,而大多数其他应用程序根本不设置它,而是将其保留为0。这很奇怪,因为这些应用程序将DIB放到剪贴板上,这些剪贴板实际上包含最高8位的alpha通道,但它们仍然将bV5AlphaMask设置为0。因此,我们必须假设,如果位深度为32,则即使bV5AlphaMask为0,也存在alpha通道。

简而言之,我的基本问题是:关于如何将alpha通道数据存储在剪贴板上,是否有一些官方信息?我特别感兴趣的是,数据是否必须进行预乘。正如你在上面看到的,Word2010和XnView不是预乘,而火狐和Chrome是预乘。但重要的是要知道颜色通道是否应该被预乘。

非常感谢你对此给予了一些启发!

UPDATE 2粘贴到Paint.NET现在可以正常工作。这是由我的代码中的一个错误引起的,如果alpha通道为0,则没有将颜色通道设置为0,即在这种情况下预乘没有正确完成,这似乎混淆了Paint.NET。

IE 10在复制带有alpha通道的PNG到剪贴板时,只是在剪贴板上放了一个24位的CF_DIBV5,但是Paint.NET可以粘贴这个带有alpha通道的位图,所以IE 10必须有另一种格式暴露给剪贴板。也许它暴露了一个使用CFSTR_FILECONTENTS和CFSTR_FILEDESCRIPTOR的PNG。

更新我现在已经用下面的arx描述的方式实现了它,它工作得很好。然而,仍然有两件事让我感到困惑:

1)将alpha通道图像从我的应用程序粘贴到Paint.NET中不会保留alpha通道。图片在Paint.NET中看起来是不透明的。但是,从火狐和Chrome粘贴到Paint.NET效果很好,alpha通道被保留了下来!我已经丢弃了完整的DIBV5,它和我的应用程序是一样的,但它仍然可以与FF和Chrome一起工作,但不能与我的应用程序一起工作,所以它肯定还有其他东西!Firefox和Chrome肯定在做我的应用不能做的其他事情!?

2) Internet Explorer 10也是如此。从IE 10粘贴alpha通道图像到我的应用程序根本不起作用……我得到了一个位深度为24的DIB,也就是说根本没有alpha通道。然而,当从IE 10粘贴到Paint.NET时,alpha通道就在那里!所以这里一定还有更多的东西...

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-03-29 03:56:41

我确信在CF_DIBV5中存储alpha的方法是正确的,但这真的无关紧要。应用程序已经不一致地处理它,所以如果你想让你的应用程序很好地与其他应用程序配合使用,你就不能使用CF_DIBV5。

前段时间我研究了复制和粘贴透明位图。我的目标是成功地将透明位图粘贴到Office和GIMP的两个版本中。我研究了几种可能的格式:

CF_BITMAP

透明度始终被忽略。

CF_DIB

使用通常0xAARRGGBB格式的32bpp BI_RGB。GIMP支持这一点,但其他的都不支持。

CF_DIBV5

GIMP不支持这一点。

"PNG"

支持粘贴: GIMP、Word 2000、Excel2000、Excel2007和PowerPoint 2007。

不支持粘贴: Word 2007和OneNote 2007。

如果您复制位图,所有这些应用程序都会成功导出"PNG“。

但是,Word和OneNote 2007将粘贴从资源管理器复制的OneNote文件。因此,我想出了以下几点:

复制的解决方案

将透明位图转换为PNG格式。

通告以下剪贴板格式:

" PNG " -原始PNG数据。

CF_DIB -适用于不处理透明度的应用程序(如画图)。

CFSTR_FILEDESCRIPTOR -使PNG看起来像一个文件。文件描述符应该有一个虚构的文件名,扩展名为".png“。

CFSTR_FILECONTENTS -内容必须公开为IStream;仅使用HGLOBAL似乎行不通。数据与"PNG“数据相同。

完成此操作后,我可以成功地将透明位图粘贴到GIMP、Office2000和Office2007中。也可以将PNG直接粘贴到资源管理器文件夹中。

更新

我意识到我只回答了问题的一半。这对于复制非常有用,但是如果你想从一个只复制CF_DIBV5的应用程序(比如火狐)中粘贴,那就没用了。

我建议你使用"PNG“,如果它是可用的,否则退回到CF_DIBV5,将其视为预乘。这将正确处理Word 2010 (导出"PNG")、Firefox和Chrome。XnView仅导出未相乘的CF_DIBV5,因此无法正常工作。我不确定你能做得更好。

lscf -一个探索剪贴板格式的工具

这是用于显示可用剪贴板格式列表的工具的源代码。它还可以将一个文件写入文件。我管它叫lscf。在Visual Studio中创建一个win32控制台应用程序,并将此源代码粘贴到main函数上。它有一个非常小的错误:如果您输入了错误的格式名称,它永远不会显示“未知格式”错误。

代码语言:javascript
复制
#include <Windows.h>

#include <stdio.h>
#include <tchar.h>

#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))

LPCTSTR cfNames[] = {
    _T("CF_TEXT"),
    _T("CF_BITMAP"),
    _T("CF_METAFILEPICT"),
    _T("CF_SYLK"),
    _T("CF_DIF"),
    _T("CF_TIFF"),
    _T("CF_OEMTEXT"),
    _T("CF_DIB"),
    _T("CF_PALETTE"),
    _T("CF_PENDATA"),
    _T("CF_RIFF"),
    _T("CF_WAVE"),
    _T("CF_UNICODETEXT"),
    _T("CF_ENHMETAFILE"),
    _T("CF_HDROP"),
    _T("CF_LOCALE"),
    _T("CF_DIBV5")
};

int LookupFormat(LPCTSTR name)
{
    for (int i = 0; i != ARRAY_SIZE(cfNames); ++i)
    {
        if (_tcscmp(cfNames[i], name) == 0)
            return i + 1;
    }

    return RegisterClipboardFormat(name);
}

void PrintFormatName(int format)
{
    if (!format)
        return;

    if ((format > 0) && (format <= ARRAY_SIZE(cfNames)))
    {
        _tprintf(_T("%s\n"), cfNames[format - 1]);
    }
    else
    {
        TCHAR buffer[100];

        if (GetClipboardFormatName(format, buffer, ARRAY_SIZE(buffer)))
            _tprintf(_T("%s\n"), buffer);
        else
            _tprintf(_T("#%i\n"), format);
    }
}

void WriteFormats()
{
    int count = 0;
    int format = 0;
    do
    {
        format = EnumClipboardFormats(format);
        if (format)
        {
            ++count;
            PrintFormatName(format);
        }
    }
    while (format != 0);

    if (!count)
        _tprintf(_T("Clipboard is empty!\n"));
}

void SaveFormat(int format, LPCTSTR filename)
{
    HGLOBAL hData = (HGLOBAL)GetClipboardData(format);

    LPVOID data = GlobalLock(hData);

    HANDLE hFile = CreateFile(filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
    if (hFile != INVALID_HANDLE_VALUE)
    {
        DWORD bytesWritten;
        WriteFile(hFile, data, GlobalSize(hData), &bytesWritten, 0);
        CloseHandle(hFile);
    }

    GlobalUnlock(hData);
}

int _tmain(int argc, _TCHAR* argv[])
{
    if (!OpenClipboard(0))
    {
        _tprintf(_T("Cannot open clipboard\n"));
        return 1;
    }

    if (argc == 1)
    {
        WriteFormats();
    }
    else if (argc == 3)
    {
        int format = LookupFormat(argv[1]);
        if (format == 0)
        {
            _tprintf(_T("Unknown format\n"));
            return 1;
        }

        SaveFormat(format, argv[2]);
    }
    else
    {
        _tprintf(_T("lscf\n"));
        _tprintf(_T("List available clipboard formats\n\n"));
        _tprintf(_T("lscf CF_NAME filename\n"));
        _tprintf(_T("Write format CF_NAME to file filename\n\n"));
    }

    CloseClipboard();

    return 0;
}
票数 20
EN

Stack Overflow用户

发布于 2018-08-30 08:55:46

尽管有详细的主要答案,我还是被这个问题卡住了一段时间。它似乎不能保留alpha (即使是通过剪贴板查看器)。

事实证明,解决方案就像这样简单:

  1. 导出CF_DIB (不需要V5)与32位预乘alpha
  2. and一起导出"PNG"格式,它似乎能够粘贴到我测试的所有应用程序中(Paint.NET、GIMP、LibreOffice等)。

基本上,只要alpha被预乘,我使用的几乎每个程序都会将alpha保存在CF_DIB中。在一种罕见的一次性情况下,需要"PNG"

需要说明的是:不需要CF_DIBV5

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15689541

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档