用到的库
opencv【v4.8.0】:用于解码剪贴板中的位图数据
openssl【v1.1.1】:用于对图片数据进行 base64 编码
代码
#include <Windows.h>
#include <stdio.h>
#include <opencv2/opencv.hpp>
#include <opencv2/lib.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
static std::string base64_encode(const std::string &input) {
BIO *bio, *b64;
BUF_MEM *bufferPtr;
b64 = BIO_new(BIO_f_base64());
bio = BIO_new(BIO_s_mem());
bio = BIO_push(b64, bio);
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
BIO_write(bio, input.data(), input.size());
BIO_flush(bio);
BIO_get_mem_ptr(bio, &bufferPtr);
BIO_set_close(bio, BIO_NOCLOSE);
std::string output(bufferPtr->data, bufferPtr->length);
BIO_free_all(bio);
return output;
}
static std::string base64_decode(const std::string &input) {
BIO *bio, *b64;
char *buffer = (char *) malloc(input.size());
memset(buffer, 0, input.size());
b64 = BIO_new(BIO_f_base64());
bio = BIO_new_mem_buf(input.data(), input.size());
bio = BIO_push(b64, bio);
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
int decoded_size = BIO_read(bio, buffer, input.size());
std::string output(buffer, decoded_size);
BIO_free_all(bio);
free(buffer);
return output;
}
INT GetPixelDataOffsetForPackedDIB(const BITMAPINFOHEADER *BitmapInfoHeader) {
INT OffsetExtra = 0;
if (BitmapInfoHeader->biSize == sizeof(BITMAPINFOHEADER)) {
if (BitmapInfoHeader->biBitCount > 8) {
if (BitmapInfoHeader->biCompression == BI_BITFIELDS) {
OffsetExtra += 3 * sizeof(RGBQUAD);
} else if (BitmapInfoHeader->biCompression == 6) {
OffsetExtra += 4 * sizeof(RGBQUAD);
}
}
}
if (BitmapInfoHeader->biClrUsed > 0) {
OffsetExtra += BitmapInfoHeader->biClrUsed * sizeof(RGBQUAD);
} else {
if (BitmapInfoHeader->biBitCount <= 8) {
OffsetExtra += sizeof(RGBQUAD) << BitmapInfoHeader->biBitCount;
}
}
return BitmapInfoHeader->biSize + OffsetExtra;
}
bool GetBitmapDataFromPackedDIB(const HGLOBAL ClipboardDataHandle, std::vector<uchar> &bmpData) {
const auto bitmapInfoHeader = static_cast<BITMAPINFOHEADER *>(GlobalLock(ClipboardDataHandle));
if (!bitmapInfoHeader) {
CloseClipboard();
return false;
}
const SIZE_T clipboardDataSize = GlobalSize(ClipboardDataHandle);
const INT pixelDataOffset = GetPixelDataOffsetForPackedDIB(bitmapInfoHeader);
const size_t totalBitmapFileSize = sizeof(BITMAPFILEHEADER) + clipboardDataSize;
// 构建 BMP 文件头
BITMAPFILEHEADER BitmapFileHeader{};
BitmapFileHeader.bfType = 0x4D42;
BitmapFileHeader.bfSize = static_cast<DWORD>(totalBitmapFileSize);
BitmapFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + pixelDataOffset;
// 将 BMP 数据写入内存缓冲区
bmpData.clear();
bmpData.resize(totalBitmapFileSize);
memcpy(bmpData.data(), &BitmapFileHeader, sizeof(BITMAPFILEHEADER));
memcpy(bmpData.data() + sizeof(BITMAPFILEHEADER), bitmapInfoHeader, clipboardDataSize);
GlobalUnlock(ClipboardDataHandle);
return true;
}
bool ConvertBmpDataToPng(const std::vector<uchar> &bmpData, std::vector<uchar> &pngData, int compression = 3,
int flags = cv::IMREAD_COLOR) {
const auto &bmp = cv::imdecode(bmpData, flags);
if (bmp.empty()) {
return false;
}
std::vector<int> compressionParams;
compressionParams.push_back(cv::IMWRITE_PNG_COMPRESSION);
compressionParams.push_back(compression);
pngData.clear();
if (!cv::imencode(".png", bmp, pngData, compressionParams)) {
return false;
}
return true;
}
int wmain(int argc, wchar_t *argv[]) {
if (!OpenClipboard(NULL)) {
return 1;
}
HGLOBAL ClipboardDataHandle = GetClipboardData(CF_DIB);
if (!ClipboardDataHandle) {
CloseClipboard();
return 0;
}
std::vector<uchar> bmpData{};
if (!GetBitmapDataFromPackedDIB(ClipboardDataHandle, bmpData)) {
CloseClipboard();
return 0;
}
// 释放剪贴板资源
GlobalUnlock(ClipboardDataHandle);
CloseClipboard();
std::vector<uchar> pngData;
if (!ConvertBmpDataToPng(bmpData, pngData)) {
return 0;
}
auto imgBase64 = base64_encode(std::string(pngData.begin(), pngData.end()));
std::cout << "imgBase64: " << imgBase64 << std::endl;
return 0;
}
Comments