一、简述
最近看了windows的剪切板相关的应用代码,于是乎,便想将浏览器中复制的图片保存到本地,经过尝试,通过以下代码完成在浏览器中右键选择复制图片,然后监控键盘事件,当按下Ctrl + v 时保存到本地,并显示到界面上。
看一下效果图:
二、代码之路
下面是基于Qt建立的工程,其他工程直接使用sendCopyImage() 、 SaveBitmapToFile()方法即可。
#include "clipboardtest.h"
#include "windows.h"
#include <QKeyEvent>
// CString 与 QString 相互转换;
inline QString CS2QS(CString cs) { return QString::fromWCharArray((LPCTSTR)cs, cs.GetLength()); }
inline CString QS2CS(QString qs) { return qs.toStdString().c_str(); }
ClipboardTest::ClipboardTest(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
}
ClipboardTest::~ClipboardTest()
{
}
void ClipboardTest::keyPressEvent(QKeyEvent *event)
{
// 按下Ctrl + v 时根据当前剪切板的内容是否显示图片;
if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_V)
{
sendCopyImage();
}
return __super::keyPressEvent(event);
}
// 根据当前剪切板的内容是否显示图片
void ClipboardTest::sendCopyImage()
{
bool bHasImage = false;
CString strFileName;
//判断剪贴板的数据格式是否可以处理。;
// 从浏览器中复制图片;
if (IsClipboardFormatAvailable(CF_BITMAP))
{
if (OpenClipboard((HWND)this->winId()))
{
HBITMAP hBitMap = (HBITMAP)GetClipboardData(CF_BITMAP);
//关闭剪贴板;
CloseClipboard();
if (hBitMap)
{
bHasImage = true;
strFileName = ".//MyImage.bmp";
// 将浏览器复制的图片保存在本地;
SaveBitmapToFile(hBitMap, strFileName);
}
else
{
int errorType = GetLastError();
}
}
}
// 从浏览器中复制图片;
else if (IsClipboardFormatAvailable(CF_BITMAP))
{
if (OpenClipboard((HWND)this->winId()))
{
HBITMAP hBitMap = (HBITMAP)GetClipboardData(CF_BITMAP);
//关闭剪贴板;
CloseClipboard();
if (hBitMap)
{
bHasImage = true;
SaveBitmapToFile(hBitMap, strFileName);
}
else
{
int errorType = GetLastError();
}
}
}
// 如果有图片则显示图片;
if (bHasImage)
{
QPixmap pixmap(CS2QS(strFileName));
this->setFixedSize(pixmap.size());
ui.label->setPixmap(pixmap);
}
}
// 将图片保存为bmp文件;
bool ClipboardTest::SaveBitmapToFile(HBITMAP hBitmap, CString imageFileName)
{
HDC hDC;
//当前分辨率下每象素所占字节数;
int iBits;
//位图中每象素所占字节数;
WORD wBitCount;
//定义调色板大小, 位图中像素字节大小 ,位图文件大小 , 写入文件字节数;
DWORD dwPaletteSize=0, dwBmBitsSize=0, dwDIBSize=0, dwWritten=0;
//位图属性结构;
BITMAP Bitmap;
//位图文件头结构;
BITMAPFILEHEADER bmfHdr;
//位图信息头结构;
BITMAPINFOHEADER bi;
//指向位图信息头结构;
LPBITMAPINFOHEADER lpbi;
//定义文件,分配内存句柄,调色板句柄;
HANDLE fh, hDib, hPal,hOldPal=NULL;
//计算位图文件每个像素所占字节数;
hDC = CreateDC(CString("DISPLAY"), NULL, NULL, NULL);
iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);
DeleteDC(hDC);
if(iBits <= 1)
wBitCount = 1;
else if(iBits <= 4)
wBitCount = 4;
else if(iBits <= 8)
wBitCount = 8;
else
wBitCount = 24;
GetObject(hBitmap, sizeof(Bitmap), (LPSTR)&Bitmap);
bi.biSize= sizeof(BITMAPINFOHEADER);
bi.biWidth = Bitmap.bmWidth;
bi.biHeight = Bitmap.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = wBitCount;
bi.biCompression= BI_RGB;
bi.biSizeImage=0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrImportant = 0;
bi.biClrUsed = 0;
dwBmBitsSize = ((Bitmap.bmWidth *wBitCount+31) / 32)*4* Bitmap.bmHeight;
//为位图内容分配内存;
hDib = GlobalAlloc(GHND,dwBmBitsSize+dwPaletteSize+sizeof(BITMAPINFOHEADER));
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
*lpbi = bi;
//处理调色板;
hPal = GetStockObject(DEFAULT_PALETTE);
if (hPal)
{
hDC = ::GetDC(NULL);
hOldPal = ::SelectPalette(hDC,(HPALETTE)hPal, FALSE);
RealizePalette(hDC);
}
//获取该调色板下新的像素值;
GetDIBits(hDC,hBitmap, 0,(UINT)Bitmap.bmHeight,
(LPSTR)lpbi+ sizeof(BITMAPINFOHEADER)+dwPaletteSize,
(BITMAPINFO *)lpbi, DIB_RGB_COLORS);
//恢复调色板;
if (hOldPal)
{
::SelectPalette(hDC, (HPALETTE)hOldPal, TRUE);
RealizePalette(hDC);
::ReleaseDC(NULL, hDC);
}
//创建位图文件;
fh = CreateFile(imageFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (fh == INVALID_HANDLE_VALUE) return FALSE;
//设置位图文件头;
bmfHdr.bfType = 0x4D42; // "BM"
dwDIBSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+dwPaletteSize+dwBmBitsSize;
bmfHdr.bfSize = dwDIBSize;
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER)+(DWORD)sizeof(BITMAPINFOHEADER)+dwPaletteSize;
//写入位图文件头;
WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
//写入位图文件其余内容;
WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);
//清除;
GlobalUnlock(hDib);
GlobalFree(hDib);
CloseHandle(fh);
return TRUE;
}
从浏览器中复制图片
从浏览器中右键复制图片,切换到我们的程序按下Ctrl + v 保存图片至本地并显示到界面上。
从本地目录复制图片
使用PrtScn键获取屏幕截图
按下PrtScn键(Print Screen键),然后回到程序,按下Ctrl+V即可将图片复制到程序中显示。
代码下载
环境为Qt 5.5 + VS2013,其他工程可以直接copy上面代码稍作修改即可。
更新于2017年6月15日。