Alpha channel images and the Win32 clipboard

Whenever I try to copy an image using Firefox or Chrome, the alpha channel seems to premultiply the pixel data. I am uncertain if there is a solution to this issue. If you want to explore the different clipboard formats, you can use lscf, a tool that displays a comprehensive list of available formats.


Question:

To enable copying and pasting of 32-bit images (RGB +
alpha channel
) in my application, I intend to utilize

CF_DIBV5

. This is possible due to the presence of a field named

bV5AlphaMask

in the

BITMAPV5HEADER

structure.

The challenge lies in the absence of a unanimous decision on the ideal way of storing image data in the clipboard. After conducting some trials, I discovered multiple variations between applications, making it exceedingly difficult to devise a universal solution.

Here are my observations:

  1. The pixel data of an alpha channel image is not saved when I transfer it from Word 2010 or XnView to the clipboard, without the use of <a class=”text-blue-600″ href=”https://in4any.com/why-we-premultiply-and-post-multiply” title=”Why we premultiply and post multiply”>premultiply</a>.

  2. When utilizing Firefox or Chrome to duplicate an image, the pixel information appears to be premultiplied by the alpha channel.

  3. Firefox assigns a value of 0xff000000 to <code>
    bV5AlphaMask
    </code> while other applications leave it as 0. Despite these applications placing DIBs on the clipboard with an alpha channel in the highest 8 bits, they still set <code>
    bV5AlphaMask
    </code> to 0. Hence, one must assume that a 32-bit depth indicates the presence of an alpha channel, regardless of <code>
    bV5AlphaMask
    </code> being 0.

In brief, my query is whether there is any authorized guideline for storing alpha channel data on the clipboard. Specifically, I want to know if the data requires premultiplication or not. It’s worth noting that Word 2010 and XnView don’t premultiply, whereas Firefox and Chrome do. Therefore, it’s crucial to determine whether premultiplication of color channels is necessary.

I appreciate your insight on this matter.

In the latest update, it has been fixed that pasting into
Paint.NET
now works smoothly. This issue was a result of a bug in the code that failed to set the color channels to 0 when the alpha channel was 0. As a result,
premultiplication
was not executed properly, leading to confusion for Paint.NET.

The issue with
Internet Explorer
10 remains unresolved. When a PNG with an alpha channel is copied to the clipboard, IE 10 only places a 24-bit CF_DIBV5 on the clipboard. However, Paint.NET is capable of pasting the bitmap containing the alpha channel, indicating that IE 10 may expose another clipboard format. One possibility is that IE 10 exposes a PNG format using CFSTR_FILECONTENTS and CFSTR_FILEDESCRIPTOR.

Following the suggestion from arx, I have successfully implemented the solution. Nonetheless, there are still two aspects that leave me perplexed.

When I paste alpha channel images from my app into Paint.NET, the alpha channel is not preserved and the image becomes opaque. However, when I paste from Firefox or Chrome, the alpha channel is preserved perfectly. I have compared the complete DIBV5 and it is identical to my app, yet the issue persists. It seems that Firefox and Chrome are employing some additional steps that my app is not implementing.

When attempting to paste an alpha channel image from Internet Explorer 10 to my application, the resulting DIB does not contain any alpha channel at all and has a bit depth of 24. However, when pasting the same image from IE 10 to Paint.NET, the alpha channel is present. Hence, there seems to be an additional factor at play here.



Solution 1:

Although there might be a correct method for storing alpha in CF_DIBV5, it is inconsequential as applications handle it in a non-uniform manner. Therefore, if you want your application to be compatible with others, it is advisable to avoid using CF_DIBV5.

A while ago, I conducted a research on how to copy and paste
transparent bitmap
. The goal was to paste a transparent bitmap into two versions of Office and GIMP, successfully. During the research, I explored various formats that could be used.


CF_BITMAP

Transparency is always ignored.


CF_DIB

The standard 0xAARRGGBB format only works with 32bpp BI_RGB, while other formats do not support it.


CF_DIBV5

GIMP doesn’t support this.


“PNG”

The following applications support pasting: GIMP, Word 2000, Excel 2000, Excel 2007, and PowerPoint 2007. However, Word 2007 and OneNote 2007 do not support pasting.

If you copy a bitmap, all these programs can export it as a “PNG” format without any issues.

Despite the fact that PNG files copied from Explorer can be pasted into Word and OneNote 2007, I devised the following method.

A remedy for duplication.

Transform your bitmap with transparency to the PNG file type.

Advertise the following
Clipboard Formats
:

The data labeled as
raw png
can be represented as PNG. For applications that do not support transparency, such as paint, the CF_DIB format can be used. To make the PNG appear as a file, the CFSTR_FILEDESCRIPTOR format can be employed, and the file descriptor should have a made-up name with a “.png” extension. To expose the contents of the PNG, the CFSTR_FILECONTENTS format can be used, where the contents need to be presented in a specific

IStream

format, as using

HGLOBAL

alone does not work. The content of the PNG is the same as the data labeled as “PNG”.

After completing this task, I was able to paste
transparent bitmaps
into various applications such as GIMP, Office 2000, and Office 2007 with great success. Additionally, you have the option of pasting the PNG file directly into a folder within the Explorer.


Update

Upon reflection, I came to the realization that I have provided a partial response. Although it may be suitable for duplication purposes, it may not be beneficial when attempting to transfer information from a program that only duplicates CF_DIBV5 (such as Firefox).

If possible, opt for “PNG” format; otherwise, switch to CF_DIBV5 and consider it premultiplied. This approach will ensure proper functioning in Word 2010 (which supports “PNG”), Chrome, and Firefox. However, since XnView only allows non-multiplied CF_DIBV5 export, it won’t be effective. There may be no other viable options available.

LSCF – An Instrument for Investigating Clipboard Layouts

The tool provided here enables the display of available clipboard formats and also allows writing them to a file. It has been named as

lscf

. To incorporate this tool, one needs to create a
win32 console
application in Visual Studio and replace its main function with the provided source code. Although it has a minor flaw where it fails to display the ”
unknown format
” error in case of incorrect format name input.

#include 
#include 
#include 
#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("%sn"), cfNames[format - 1]);
    }
    else
    {
        TCHAR buffer[100];
        if (GetClipboardFormatName(format, buffer, ARRAY_SIZE(buffer)))
            _tprintf(_T("%sn"), buffer);
        else
            _tprintf(_T("#%in"), 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 clipboardn"));
        return 1;
    }
    if (argc == 1)
    {
        WriteFormats();
    }
    else if (argc == 3)
    {
        int format = LookupFormat(argv[1]);
        if (format == 0)
        {
            _tprintf(_T("Unknown formatn"));
            return 1;
        }
        SaveFormat(format, argv[2]);
    }
    else
    {
        _tprintf(_T("lscfn"));
        _tprintf(_T("List available clipboard formatsnn"));
        _tprintf(_T("lscf CF_NAME filenamen"));
        _tprintf(_T("Write format CF_NAME to file filenamenn"));
    }
    CloseClipboard();
    return 0;
}


Solution 2:


Despite the detailed main answer, I struggled for a while with this problem as it failed to maintain alpha, not even when viewed through a clipboard viewer.

As it happens, the answer is uncomplicated:

  1. Generate

    CF_DIB

    using 32-bit pre-multiplied alpha, and V5 is not required for export.
  2. The

    "PNG"

    format can be exported and then pasted in all tested applications such as Paint.NET, GIMP, LibreOffice, and others.

In most programs that I used,

CF_DIB

preserved alpha, provided that it was pre-multiplied. However, in a rare situation,

"PNG"

was required.

It should be noted that the use of

CF_DIBV5

was unnecessary.

Frequently Asked Questions