won*_*rer 13 c windows jpeg gdi+ screenshot
我试图找到一种(有点)简单的方法来在窗口上截取屏幕截图并将生成的HBITMAP保存为JPEG.这里棘手的部分是,因为代码在CI中不能使用GDI +,并且由于代码是更大程序的模块,我不能使用外部库(如libjpeg).
此代码截取屏幕截图并返回HBITMAP.将该位图保存到文件中很容易.问题是位图是2或3mb.
HDC hDCMem = CreateCompatibleDC(NULL);
HBITMAP hBmp;
RECT rect;
HDC hDC;
HGDIOBJ hOld;
GetWindowRect(hWnd, & rect);
hBmp = NULL;
{
hDC = GetDC(hWnd);
hBmp = CreateCompatibleBitmap(hDC, rect.right - rect.left, rect.bottom - rect.top);
ReleaseDC(hWnd, hDC);
}
hOld = SelectObject(hDCMem, hBmp);
SendMessage(hWnd, WM_PRINT, (WPARAM) hDCMem, PRF_CHILDREN | PRF_CLIENT | PRF_ERASEBKGND | PRF_NONCLIENT | PRF_OWNED);
SelectObject(hDCMem, hOld);
DeleteObject(hDCMem);
return hBmp;
Run Code Online (Sandbox Code Playgroud)
关于如何做到这一点的任何想法?非常感谢,任何帮助表示赞赏
编辑:因为我们走向GDI +的方向我想我会发布代码iv C++,可以截取屏幕截图并使用GDI +将其转换为JPEG.如果有人知道如何使用FLAT GDI +实现这一目标我会很感激帮助.码:
#include <windows.h>
#include <stdio.h>
#include <gdiplus.h>
using namespace Gdiplus;
int GetEncoderClsid(WCHAR *format, CLSID *pClsid)
{
unsigned int num = 0, size = 0;
GetImageEncodersSize(&num, &size);
if(size == 0) return -1;
ImageCodecInfo *pImageCodecInfo = (ImageCodecInfo *)(malloc(size));
if(pImageCodecInfo == NULL) return -1;
GetImageEncoders(num, size, pImageCodecInfo);
for(unsigned int j = 0; j < num; ++j)
{
if(wcscmp(pImageCodecInfo[j].MimeType, format) == 0){
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j;
}
}
free(pImageCodecInfo);
return -1;
}
int GetScreeny(LPWSTR lpszFilename, ULONG uQuality) // by Napalm
{
ULONG_PTR gdiplusToken;
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
HWND hMyWnd = GetForegroundWindow(); // get my own window
RECT r; // the area we are going to capture
int w, h; // the width and height of the area
HDC dc; // the container for the area
int nBPP;
HDC hdcCapture;
LPBYTE lpCapture;
int nCapture;
int iRes;
CLSID imageCLSID;
Bitmap *pScreenShot;
HGLOBAL hMem;
int result;
// get the area of my application's window
//GetClientRect(hMyWnd, &r);
GetWindowRect(hMyWnd, &r);
dc = GetWindowDC(hMyWnd);// GetDC(hMyWnd) ;
w = r.right - r.left;
h = r.bottom - r.top;
nBPP = GetDeviceCaps(dc, BITSPIXEL);
hdcCapture = CreateCompatibleDC(dc);
// create the buffer for the screenshot
BITMAPINFO bmiCapture = {
sizeof(BITMAPINFOHEADER), w, -h, 1, nBPP, BI_RGB, 0, 0, 0, 0, 0,
};
// create a container and take the screenshot
HBITMAP hbmCapture = CreateDIBSection(dc, &bmiCapture,
DIB_PAL_COLORS, (LPVOID *)&lpCapture, NULL, 0);
// failed to take it
if(!hbmCapture)
{
DeleteDC(hdcCapture);
DeleteDC(dc);
GdiplusShutdown(gdiplusToken);
printf("failed to take the screenshot. err: %d\n", GetLastError());
return 0;
}
// copy the screenshot buffer
nCapture = SaveDC(hdcCapture);
SelectObject(hdcCapture, hbmCapture);
BitBlt(hdcCapture, 0, 0, w, h, dc, 0, 0, SRCCOPY);
RestoreDC(hdcCapture, nCapture);
DeleteDC(hdcCapture);
DeleteDC(dc);
// save the buffer to a file
pScreenShot = new Bitmap(hbmCapture, (HPALETTE)NULL);
EncoderParameters encoderParams;
encoderParams.Count = 1;
encoderParams.Parameter[0].NumberOfValues = 1;
encoderParams.Parameter[0].Guid = EncoderQuality;
encoderParams.Parameter[0].Type = EncoderParameterValueTypeLong;
encoderParams.Parameter[0].Value = &uQuality;
GetEncoderClsid(L"image/jpeg", &imageCLSID);
iRes = (pScreenShot->Save(lpszFilename, &imageCLSID, &encoderParams) == Ok);
delete pScreenShot;
DeleteObject(hbmCapture);
GdiplusShutdown(gdiplusToken);
return iRes;
}
Run Code Online (Sandbox Code Playgroud)
won*_*rer 17
好的,经过大量的努力,这里的答案是:
int SaveJpeg(HBITMAP hBmp, LPCWSTR lpszFilename, ULONG uQuality)
{
ULONG *pBitmap = NULL;
CLSID imageCLSID;
EncoderParameters encoderParams;
int iRes = 0;
typedef Status (WINAPI *pGdipCreateBitmapFromHBITMAP)(HBITMAP, HPALETTE, ULONG**);
pGdipCreateBitmapFromHBITMAP lGdipCreateBitmapFromHBITMAP;
typedef Status (WINAPI *pGdipSaveImageToFile)(ULONG *, const WCHAR*, const CLSID*, const EncoderParameters*);
pGdipSaveImageToFile lGdipSaveImageToFile;
// load GdipCreateBitmapFromHBITMAP
lGdipCreateBitmapFromHBITMAP = (pGdipCreateBitmapFromHBITMAP)GetProcAddress(hModuleThread, "GdipCreateBitmapFromHBITMAP");
if(lGdipCreateBitmapFromHBITMAP == NULL)
{
// error
return 0;
}
// load GdipSaveImageToFile
lGdipSaveImageToFile = (pGdipSaveImageToFile)GetProcAddress(hModuleThread, "GdipSaveImageToFile");
if(lGdipSaveImageToFile == NULL)
{
// error
return 0;
}
lGdipCreateBitmapFromHBITMAP(hBmp, NULL, &pBitmap);
iRes = GetEncoderClsid(L"image/jpeg", &imageCLSID);
if(iRes == -1)
{
// error
return 0;
}
encoderParams.Count = 1;
encoderParams.Parameter[0].NumberOfValues = 1;
encoderParams.Parameter[0].Guid = EncoderQuality;
encoderParams.Parameter[0].Type = EncoderParameterValueTypeLong;
encoderParams.Parameter[0].Value = &uQuality;
lGdipSaveImageToFile(pBitmap, lpszFilename, &imageCLSID, &encoderParams);
return 1;
}
Run Code Online (Sandbox Code Playgroud)
现在的问题是,如何将编码的pBitmap(作为jpeg)保存到BYTE缓冲区?
转换为扁平的GDI + API非常简单:
void SaveJpeg(HBITMAP hBmp, LPCWSTR lpszFilename, ULONG uQuality)
{
GpBitmap* pBitmap;
GdipCreateBitmapFromHBITMAP(hBmp, NULL, &pBitmap);
CLSID imageCLSID;
GetEncoderClsid(L"image/jpeg", &imageCLSID);
EncoderParameters encoderParams;
encoderParams.Count = 1;
encoderParams.Parameter[0].NumberOfValues = 1;
encoderParams.Parameter[0].Guid = EncoderQuality;
encoderParams.Parameter[0].Type = EncoderParameterValueTypeLong;
encoderParams.Parameter[0].Value = &uQuality;
GdipSaveImageToFile(pBitmap, lpszFilename, &imageCLSID, &encoderParams);
}
Run Code Online (Sandbox Code Playgroud)
一件不明显的事情是清理由GdipCreateBitmapFromHBITMAP()创建的GpBitmap.Gdiplus :: Bitmap类似乎没有析构函数,因此对它的内部GpBitmap没有任何作用.此外,没有GdipDeleteBitmap(),就像其他GDI +对象一样.因此,我不清楚需要做些什么来避免泄漏.
编辑: 此代码未解决Microsoft提供的GDI +头文件在C++命名空间中声明所有必需功能的事实.一种解决方案是将必要的声明(并根据需要转换为C代码)复制到您自己的标头中.另一种可能性是使用Wine或Mono项目提供的头文件.它们似乎在编译时表现得更好,就像C代码一样.
归档时间: |
|
查看次数: |
31503 次 |
最近记录: |