用到的库

opencv【v4.8.0】:用于解码剪贴板中的位图数据

openssl【v1.1.1】:用于对图片数据进行 base64 编码

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#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;
}