Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read a bitmap from the Windows Clipboard

I am writing an extremely small C++ program to help me animate sprites. I'd like it to take data I copy to the clipboard from photoshop, manipulate it in my program, then overwrite the clipboard with the transform.

The problem though is that I'm not sure how to read the initial clipboard from photoshop.

I can load the clipboard with GetClipboardData(CF_DIB), and get a valid handle, but I've no idea how to use that handle. I've tried using SFML's Image::LoadFromMemory(handle, GlobalSize(handle)) which is able to load bitmap files from memory, but that doesn't seem to work.

Will I need to actually parse the entire format? What format structure would I be looking at in that case? Would there perhaps be any way I could quickly mangle the data so it might look like a bitmap file? Could it be easier/possible to simply save it to file using the windows API? (I could then load that file with SFML to edit, that way)

It's just a quick and dirty tool for myself to save a lot of grunt work in photoshop, so efficiency or robustness aren't important at all.

like image 684
Anne Quinn Avatar asked Jan 08 '23 06:01

Anne Quinn


1 Answers

Learn the bitmap structure from Wikipedia and then write it out to a file and then write out the pixels..

I've tested the below with Paint on Windows 8.1. I opened an image with paint and then pressed Ctrl + C to copy to the clipboard.. then I ran the following code and it copied the clipboard image to the desktop:

#include <iostream>
#include <fstream>
#include <windows.h>


int main()
{
    std::cout<<"Format Bitmap: "<<IsClipboardFormatAvailable(CF_BITMAP)<<"\n";
    std::cout<<"Format DIB: "<<IsClipboardFormatAvailable(CF_DIB)<<"\n";
    std::cout<<"Format DIBv5: "<<IsClipboardFormatAvailable(CF_DIBV5)<<"\n";

    if (IsClipboardFormatAvailable(CF_DIB))
    {
        if (OpenClipboard(NULL))
        {
            HANDLE hClipboard = GetClipboardData(CF_DIB);
            if (hClipboard != NULL && hClipboard != INVALID_HANDLE_VALUE)
            {
                void* dib = GlobalLock(hClipboard);

                if (dib)
                {
                    BITMAPINFOHEADER* info = reinterpret_cast<BITMAPINFOHEADER*>(dib);
                    BITMAPFILEHEADER fileHeader = {0};
                    fileHeader.bfType = 0x4D42;
                    fileHeader.bfOffBits = 54;
                    fileHeader.bfSize = (((info->bmiHeader.biWidth * info->bmiHeader.biBitCount + 31) & ~31) / 8
                              * info->bmiHeader.biHeight) + fileHeader.bfOffBits;

                    std::cout<<"Type: "<<std::hex<<fileHeader.bfType<<std::dec<<"\n";
                    std::cout<<"bfSize: "<<fileHeader.bfSize<<"\n";
                    std::cout<<"Reserved: "<<fileHeader.bfReserved1<<"\n";
                    std::cout<<"Reserved2: "<<fileHeader.bfReserved2<<"\n";
                    std::cout<<"Offset: "<<fileHeader.bfOffBits<<"\n";
                    std::cout<<"biSize: "<<info->bmiHeader.biSize<<"\n";
                    std::cout<<"Width: "<<info->bmiHeader.biWidth<<"\n";
                    std::cout<<"Height: "<<info->bmiHeader.biHeight<<"\n";
                    std::cout<<"Planes: "<<info->bmiHeader.biPlanes<<"\n";
                    std::cout<<"Bits: "<<info->bmiHeader.biBitCount<<"\n";
                    std::cout<<"Compression: "<<info->bmiHeader.biCompression<<"\n";
                    std::cout<<"Size: "<<info->bmiHeader.biSizeImage<<"\n";
                    std::cout<<"X-res: "<<info->bmiHeader.biXPelsPerMeter<<"\n";
                    std::cout<<"Y-res: "<<info->bmiHeader.biYPelsPerMeter<<"\n";
                    std::cout<<"ClrUsed: "<<info->bmiHeader.biClrUsed<<"\n";
                    std::cout<<"ClrImportant: "<<info->bmiHeader.biClrImportant<<"\n";

                    std::ofstream file("C:/Users/Brandon/Desktop/Test.bmp", std::ios::out | std::ios::binary);
                    if (file)
                    {
                        file.write(reinterpret_cast<char*>(&fileHeader), sizeof(BITMAPFILEHEADER));
                        file.write(reinterpret_cast<char*>(info), sizeof(BITMAPINFOHEADER));
                        file.write(reinterpret_cast<char*>(++info), bmp.dib.biSizeImage);
                    }

                    GlobalUnlock(dib);
                }
            }

            CloseClipboard();
        }
    }

    return 0;
}
like image 108
Brandon Avatar answered Jan 19 '23 07:01

Brandon