欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > IT业 > 【GDI+】C++截长图

【GDI+】C++截长图

2024/10/26 1:23:07 来源:https://blog.csdn.net/beibaoke910/article/details/141395364  浏览:    关键词:【GDI+】C++截长图

一、准备

1、屏幕截图

【GDI+】C++屏幕截图

 使用BitBlt来进行截图

2、强制刷新

c++窗口立即刷新重绘

截图的时候,有可能由于界面没有及时刷新,导致截到的内容,这时就需要强制立刻刷新重绘

InvalidateRect(m_hWnd, NULL, TRUE);
UpdateWindow(m_hWnd);

二、 截长图

1、截全屏【不考虑表头、顶部、底部等因素】

需求:界面只有一个List控件m_pList,放着数据m_vecData,需要将整个List的所有内容都截图拼成一个长图。先说简单粗暴的,只是截图,然后拼接。(不考虑拼接的长图表头只截一次的问题)

思路

  • 先计算出长图的总高度,然后创建该高度的兼容位图并写入内存DC
  • 拷贝屏幕内容到设备上下文(内存DC),翻页,继续拷贝当前页码的屏幕内容到设备上下文(挨着上次内存DC拷贝后位置的底部放),直到翻页到最后。
  • 保存为.png或者.bmp格式
#include<windows.h>
#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment(lib, "gdiplus.lib")#define LIST_HEADER_HEIGHT 36      //表头高度
#define LIST_ITEM_ROW_HEIGHT 35    //列表每行高度void ScreenShotLongImage()
{//列表CListUI* m_pList = nullptr;//列表内容std::vector<Data> m_vecData;...//一页列表高度int nListHeight = m_pList->GetHeight();//列表内容总高度int nContentTotalHeight = m_vecData.size() * LIST_ITEM_ROW_HEIGHT;//总页数int nTotalPage = nContentTotalHeight / (nListHeight - LIST_HEADER_HEIGHT);//最后一页剩余高度int nLeftHeight = nContentTotalHeight % (nListHeight - LIST_HEADER_HEIGHT);if (nLeftHeight != 0) nTotalPage++;//计算长图总高度	int nDstTotalHeight = 0;for (int nPage = 0; nPage < nTotalPage; nPage++){RECT rcSrcClient;GetClientRect(m_hWnd, &rcSrcClient);int nHeight = rcSrcClient.bottom - rcSrcClient.top;nDstTotalHeight += nHeight;}//截长图//1、确定长图区域RECT rcDstClient;GetClientRect(m_hWnd, &rcDstClient);rcDstClient.bottom = nDstTotalHeight;int nDstWidth = rcDstClient.right - rcDstClient.left;//2、获得指定窗口的dc(源dc)//注意GetWindowDC会把窗口的标题栏也同时截图,如果不需要窗口的标题就使用GetDC(hwnd)HDC sourceDC = GetDC(m_hWnd);//3、根据源dc创建兼容内存DCHDC memDC = CreateCompatibleDC(sourceDC);//3、根据源dc创建兼容位图HBITMAP memBitmap = CreateCompatibleBitmap(sourceDC, rcDstClient.right - rcDstClient.left, rcDstClient.bottom - rcDstClient.top);//4、将兼容位图写入内存dcSelectObject(memDC, memBitmap);//5、翻页截图拼接成长图int nDstTop = 0;for (int nPage = 0; nPage < nTotalPage; nPage++){//强制重绘UpdateWindow(m_hWnd);// 拷贝屏幕内容到设备上下文		RECT rcSrcClient;GetClientRect(m_hWnd, &rcSrcClient);if (nPage == nTotalPage){//最后一页int nTopPadding = LIST_HEADER_HEIGHT + (nListHeight - LIST_HEADER_HEIGHT - nLeftHeight);rcSrcClient.top += nTopPadding;}int nDstHeight = rcSrcClient.bottom - rcSrcClient.top;BitBlt(memDC, 0, nDstTop, nDstWidth, nDstHeight, GetDC(m_hWnd), rcSrcClient.left, rcSrcClient.top, SRCCOPY);nDstTop += rcSrcClient.bottom - rcSrcClient.top;//翻页		m_pList->PageDown();		}//6、保存为.png格式GdiplusStartupInput gdiplusStartupInput;ULONG_PTR gdiplusToken;GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);Gdiplus::Bitmap bmp(memBitmap, NULL);CLSID pngClsid;int i = GetEncoderClsid(L"image/png", &pngClsid);bmp.Save(L"test.png", &pngClsid, NULL);GdiplusShutdown(gdiplusToken);//保存位.bmp格式{//6、以下代码保存截图信息到文件中保存为bmp格式//6.1获得位图信息BITMAP bmp;GetObject(memBitmap, sizeof(BITMAP), &bmp);//6.2图片保存路径和方式FILE* fp;fopen_s(&fp, L"test.bmp", "w+b");//6.3创建位图文件头//位图文件头设置默认值为0BITMAPFILEHEADER bfh = { 0 };//到位图数据的偏移量(此步骤固定,位图编译量即为位图文件头 + 位图信息头 + 调色板的大小,调色板设置为0)bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);//文件总的大小bfh.bfSize = bfh.bfOffBits + bmp.bmWidthBytes * bmp.bmHeight;//bfType固定为BM,(WORD)0x4d42表示为BMbfh.bfType = (WORD)0x4d42;//6.4创建文件信息头//位图信息头,默认设置为0BITMAPINFOHEADER bih = { 0 };//每个像素字节大小bih.biBitCount = bmp.bmBitsPixel;bih.biCompression = BI_RGB;//高度bih.biHeight = bmp.bmHeight;bih.biPlanes = 1;bih.biSize = sizeof(BITMAPINFOHEADER);//图像数据大小bih.biSizeImage = bmp.bmWidthBytes * bmp.bmHeight;//宽度bih.biWidth = bmp.bmWidth;//6.5写入位图文件头fwrite(&bfh, 1, sizeof(BITMAPFILEHEADER), fp);//6.6写入位图信息头fwrite(&bih, 1, sizeof(BITMAPINFOHEADER), fp);//6.7申请内存保存位图数据byte* p = new byte[bmp.bmWidthBytes * bmp.bmHeight];//6.8获取位图数据GetDIBits(memDC, (HBITMAP)memBitmap, 0, rcDstClient.bottom - rcDstClient.top, p,(LPBITMAPINFO)&bih, DIB_RGB_COLORS);//6.9写入位图数据        fwrite(p, 1, bmp.bmWidthBytes * bmp.bmHeight, fp);//6.10先删除开辟的内存,然后关闭文件delete[] p;fclose(fp);}// 释放资源DeleteObject(memBitmap);DeleteDC(memDC);ReleaseDC(m_hWnd, sourceDC);
}int GetEncoderClsid(const WCHAR *format, CLSID *pClsid)
{UINT  num = 0;          // number of image encoders      UINT  size = 0;         // size of the image encoder array in bytes      ImageCodecInfo* pImageCodecInfo = NULL;GetImageEncodersSize(&num, &size);if (size == 0)return -1;  // Failure      pImageCodecInfo = (ImageCodecInfo*)(malloc(size));if (pImageCodecInfo == NULL)return -1;  // Failure      GetImageEncoders(num, size, pImageCodecInfo);for (UINT j = 0; j < num; ++j){if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0){*pClsid = pImageCodecInfo[j].Clsid;free(pImageCodecInfo);return j;  // Success      }}free(pImageCodecInfo);return -1;  // Failure 
}

2、截长图【考虑表头、头部、底部内容等】

#define LIST_HEADER_HEIGHT 36 //表头高度
#define LIST_TOP_HEIGHT 42 //列表顶部高度
#define LIST_BOTTOM_HEIGHT 105 //列表顶部高度
#define LIST_ITEM_ROW_HEIGHT 35//列表每行高度
#define LIST_YEAR_Q_WITH 705 //全端年榜列表宽度
#define LIST_YEAR_D_WITH 615 //点播年榜列表宽度
#define FRAME_MAX_WITH 1920//最大化宽度void CMainFrame::ScreenShotLongImage(int &nSplitLineSize, bool bQ)
{int nRightPadding = bQ ? FRAME_MAX_WITH - LIST_YEAR_Q_WITH : FRAME_MAX_WITH - LIST_YEAR_D_WITH;int nListHeight = bQ ? m_pKyTVPlayYearQList->GetHeight(): m_pKyTVPlayYearDList->GetHeight();int nTotalHeight = m_vecKyTVPlayYear.size() * LIST_ITEM_ROW_HEIGHT + nSplitLineSize;int nTotalPage = nTotalHeight / (nListHeight - LIST_HEADER_HEIGHT);int nLeftHeight = nTotalHeight % (nListHeight - LIST_HEADER_HEIGHT);if (nLeftHeight != 0) nTotalPage++;//计算长图总高度	int nDstTotalHeight = 0;for (int nPage = 0; nPage < nTotalPage; nPage++){		RECT rcSrcClient;int nHeight = GetSrcRect(rcSrcClient, nRightPadding, nListHeight, nLeftHeight, nPage, nTotalPage);nDstTotalHeight += nHeight;}//截长图//1、确定长图区域RECT rcDstClient;GetClientRect(m_hWnd, &rcDstClient);rcDstClient.bottom = nDstTotalHeight;rcDstClient.right -= nRightPadding;int nDstWidth = rcDstClient.right - rcDstClient.left;//2、获得指定窗口的dc(源dc)//注意GetWindowDC会把窗口的标题栏也同时截图,如果不需要窗口的标题就使用GetDC(hwnd)HDC sourceDC = GetDC(m_hWnd);//3、根据源dc创建兼容内存DCHDC memDC = CreateCompatibleDC(sourceDC);//3、根据源dc创建兼容位图HBITMAP memBitmap = CreateCompatibleBitmap(sourceDC, rcDstClient.right - rcDstClient.left, rcDstClient.bottom - rcDstClient.top);//4、将兼容位图写入内存dcSelectObject(memDC, memBitmap);//5、翻页截图拼接成长图int nDstTop = 0;for (int nPage = 0; nPage < nTotalPage; nPage++){//强制重绘UpdateWindow(m_hWnd);	// 拷贝屏幕内容到设备上下文		RECT rcSrcClient;int nDstHeight =  GetSrcRect(rcSrcClient, nRightPadding, nListHeight, nLeftHeight, nPage, nTotalPage);BitBlt(memDC, 0, nDstTop, nDstWidth, nDstHeight, GetDC(m_hWnd), rcSrcClient.left, rcSrcClient.top, SRCCOPY);nDstTop += rcSrcClient.bottom - rcSrcClient.top;//翻页if (bQ){m_pKyTVPlayYearQList->PageDown();}else{m_pKyTVPlayYearDList->PageDown();}	}//6、保存为.png格式GdiplusStartupInput gdiplusStartupInput;ULONG_PTR gdiplusToken;GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);Gdiplus::Bitmap bmp(memBitmap, NULL);CLSID pngClsid;int i = miscutil::system::GetEncoderClsid(L"image/png", &pngClsid);string strImageName = "q.png";bmp.Save(miscutil::convert::ANSI2Unicode(strImageName.c_str()).c_str(), &pngClsid, NULL);GdiplusShutdown(gdiplusToken);//保存位.bmp格式{//6、以下代码保存截图信息到文件中保存为bmp格式//6.1获得位图信息BITMAP bmp;GetObject(memBitmap, sizeof(BITMAP), &bmp);//6.2图片保存路径和方式strImageName.append(".bmp");FILE* fp;fopen_s(&fp, strImageName.c_str(), "w+b");//6.3创建位图文件头//位图文件头设置默认值为0BITMAPFILEHEADER bfh = { 0 };//到位图数据的偏移量(此步骤固定,位图编译量即为位图文件头 + 位图信息头 + 调色板的大小,调色板设置为0)bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);//文件总的大小bfh.bfSize = bfh.bfOffBits + bmp.bmWidthBytes * bmp.bmHeight;//bfType固定为BM,(WORD)0x4d42表示为BMbfh.bfType = (WORD)0x4d42;//6.4创建文件信息头//位图信息头,默认设置为0BITMAPINFOHEADER bih = { 0 };//每个像素字节大小bih.biBitCount = bmp.bmBitsPixel;bih.biCompression = BI_RGB;//高度bih.biHeight = bmp.bmHeight;bih.biPlanes = 1;bih.biSize = sizeof(BITMAPINFOHEADER);//图像数据大小bih.biSizeImage = bmp.bmWidthBytes * bmp.bmHeight;//宽度bih.biWidth = bmp.bmWidth;//6.5写入位图文件头fwrite(&bfh, 1, sizeof(BITMAPFILEHEADER), fp);//6.6写入位图信息头fwrite(&bih, 1, sizeof(BITMAPINFOHEADER), fp);//6.7申请内存保存位图数据byte* p = new byte[bmp.bmWidthBytes * bmp.bmHeight];//6.8获取位图数据GetDIBits(memDC, (HBITMAP)memBitmap, 0, rcDstClient.bottom - rcDstClient.top, p,(LPBITMAPINFO)&bih, DIB_RGB_COLORS);//6.9写入位图数据        fwrite(p, 1, bmp.bmWidthBytes * bmp.bmHeight, fp);//6.10先删除开辟的内存,然后关闭文件delete[] p;fclose(fp);}// 释放资源DeleteObject(memBitmap);DeleteDC(memDC);ReleaseDC(m_hWnd, sourceDC);
}int CMainFrame::GetSrcRect(RECT &rcClient, int nRightPadding, int nListHeight, int nLeftHeight, int nPageNO, int nTotalPage)
{GetClientRect(m_hWnd, &rcClient);int nTopPadding = 0, nBottomPadding = 0, nLeftPadding = 0;if (nPageNO == 0){//第一页nBottomPadding = LIST_BOTTOM_HEIGHT;}else if (nPageNO == (nTotalPage - 1)){//最后一页nTopPadding = LIST_TOP_HEIGHT + LIST_HEADER_HEIGHT + (nListHeight - LIST_HEADER_HEIGHT - nLeftHeight);}else{nTopPadding = LIST_TOP_HEIGHT + LIST_HEADER_HEIGHT;nBottomPadding = LIST_BOTTOM_HEIGHT;}rcClient.top += nTopPadding;rcClient.bottom -= nBottomPadding;rcClient.left += nLeftPadding;rcClient.right -= nRightPadding;return (rcClient.bottom - rcClient.top);
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com