Last active
April 22, 2023 09:03
-
-
Save ohaval/f5182a14a8c65cc40d1c4a400bb02389 to your computer and use it in GitHub Desktop.
Save an image from the clipboard to a file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
I wanted to play with the clipboard via Windows API so I wrote a small program that | |
checks if the clipboard contains an image, and if so saves the image as a .bmp file. | |
This program obtains the handle on the clipboard data, put together all of the | |
information and raw data a .bmp file holds, and writes it to the disk. | |
With small changes it's possible to make this code run in a loop and save an image | |
from the clipboard every X seconds. | |
It's useful to read Microsoft's documentation (for developers) on the clipboard: | |
https://docs.microsoft.com/en-us/windows/win32/dataxchg/clipboard | |
*/ | |
#include <iostream> | |
#include <fstream> | |
#include <Windows.h> | |
LPSTR pFilename = NULL; | |
int WriteBitmapFile(PBITMAPFILEHEADER pFileHeader, PBITMAPINFOHEADER pInfoHeader, PBYTE pImageData, DWORD dwImageDataSize) { | |
/* | |
The format of a .bmp file is: | |
1) File header | |
2) Info header | |
3) Raw bytes (representing the pixels) | |
(https://en.wikipedia.org/wiki/BMP_file_format) | |
*/ | |
std::ofstream fout; | |
fout.open(pFilename, std::ios::out | std::ios::binary); | |
if (!fout) | |
{ | |
printf("ofstream::open failed (err %d)\n", GetLastError()); | |
return 1; | |
} | |
fout.write((char*)(pFileHeader), sizeof(BITMAPFILEHEADER)); | |
fout.write((char*)(pInfoHeader), sizeof(BITMAPINFOHEADER)); | |
fout.write((char*)(pImageData), dwImageDataSize); | |
fout.close(); | |
return 0; | |
} | |
int SaveFromBitmapInfo(PBITMAPINFO pBitmapInfo) { | |
// This program currently doesn't support other types of compression | |
if (pBitmapInfo->bmiHeader.biCompression != BI_RGB) { | |
printf("[!] Bitmap compression is different from BI_RGB\n"); | |
return 0; | |
} | |
BITMAPFILEHEADER bmfh = { 0 }; | |
bmfh.bfType = 0x4D42; // BMP magic | |
bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // 14 and 40 bytes respectively | |
bmfh.bfSize = bmfh.bfOffBits + | |
pBitmapInfo->bmiHeader.biWidth * pBitmapInfo->bmiHeader.biHeight * pBitmapInfo->bmiHeader.biBitCount / 8; | |
return WriteBitmapFile(&bmfh, &pBitmapInfo->bmiHeader, (PBYTE)&pBitmapInfo->bmiColors, bmfh.bfSize - bmfh.bfOffBits); | |
} | |
int SaveBitmapFromClipboard() { | |
HANDLE hGlobal = NULL; | |
int rv = 1; | |
if (!IsClipboardFormatAvailable(CF_DIB)) { | |
printf("[!] CF_DIB is not an avialable format\n"); | |
return 1; | |
} | |
printf("[*] BITMAPINFO format is available\n"); | |
if (!OpenClipboard(NULL)) { | |
printf("[!] OpenClipboard failed (err %d)\n", GetLastError()); | |
return 1; | |
} | |
hGlobal = GetClipboardData(CF_DIB); | |
if (hGlobal == NULL) { | |
printf("[!] GetClipboardData failed (err %d)\n", GetLastError()); | |
return 1; | |
} | |
PBITMAPINFO pClipboardData = (PBITMAPINFO)GlobalLock(hGlobal); | |
if (pClipboardData == NULL) { | |
printf("[!] GlobalLock failed (err %d)\n", GetLastError()); | |
return 1; | |
} | |
rv = SaveFromBitmapInfo(pClipboardData); | |
GlobalUnlock(hGlobal); | |
if (!CloseClipboard()) { | |
printf("[!] CloseClipboard failed (err %d)\n", GetLastError()); | |
return 1; | |
} | |
return rv; | |
} | |
int main(int argc, char** argv) { | |
if (argc != 2) { | |
printf("USAGE: SaveImageFromClipboard.exe FILENAME.bmp\n"); | |
exit(1); | |
} | |
pFilename = argv[1]; | |
return SaveBitmapFromClipboard(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@tamlin-mike Thanks for the note!