@mardokvk
Я junior-программист, мой профиль С#, изучаю С++.

Почему не работает GetPixel?

#include <iostream>
#include <Windows.h>
using namespace std;

#include <gdiplus.h>

#pragma comment(lib, "GdiPlus.lib")
using namespace Gdiplus;
Color clr;
void CreateGDIplus();

int main()
{
	CreateGDIplus();
	return 0;
}

static const GUID png =
{ 0x557cf406, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e } };


void CreateGDIplus()
{
	Sleep(1000);
	GdiplusStartupInput gdiplusStartupInput;
	ULONG_PTR gdiplusToken;
	GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

	HDC scrdc, memdc;
	HBITMAP membit;
	// Получаем HDC рабочего стола
	// Параметр HWND для рабочего стола всегда равен нулю.
	scrdc = GetDC(0);
	// Определяем разрешение экрана
	int Height, Width;
	Height = GetSystemMetrics(SM_CYSCREEN);
	Width = GetSystemMetrics(SM_CXSCREEN);
	// Создаем новый DC, идентичный десктоповскому и битмап размером с экран.
	memdc = CreateCompatibleDC(scrdc);
	membit = CreateCompatibleBitmap(scrdc, Width, Height);
	SelectObject(memdc, membit);
	// Улыбаемся... Снято!
	BitBlt(memdc, 0, 0, Width, Height, scrdc, 0, 0, SRCCOPY);
	HBITMAP hBitmap;
	hBitmap = (HBITMAP)SelectObject(memdc, membit);
	Gdiplus::Bitmap bitmap(hBitmap, NULL);
	
	if (bitmap.GetPixel(Height / 2, Width / 2, &clr))
		cout << "GetPixel == Ok" << endl;
	else
		cout << "GetPixel == Error" << endl;
	bitmap.Save(L"D:\\screen2.png", &png);
	DeleteObject(hBitmap);
	cout << "Screen Ready" << endl;
	//GdiplusShutdown(gdiplusToken);
}
  • Вопрос задан
  • 115 просмотров
Пригласить эксперта
Ответы на вопрос 1
wataru
@wataru Куратор тега C++
Разработчик на С++, экс-олимпиадник.
GetPixel принимает сначала x, потом y. У вас там Height и Width не в том порядке переданы.

Это будет ошибкой, если одна из сторон более чем в 2 раза больше другой. Это может быть, если у вас широкоформатный монитор.

У вас там битмап сохраняется в sceen2.png - оно там что-то сохранило вообще? Иначе проблема может быть не GetPixel, а с самим хБитмапом.

Edit:

Еще проблема может быть с масштабированием. В результате GetSystemMetrics(SM_CYSCREEN) возвращает не то, что вам надо и BitBlt не срабатывает из-за слишком большого размера.

Попробуйте вызвать SetProcessDPIAware.

Еще может быть проблема, что вы SelectObject делаете 2 раза с одним и тем же membit. Надо во второй раз что-то другое подставлять, чтобы HBitmap освободить. Иначе оно, похоже, так и остается привязано к DC.

Вот мой рабочий код:
HBITMAP GameManager::GetScreenshot(HWND window) {
	HDC hScreenDC = GetDC(window);
	HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
	RECT window_rect;
	GetClientRect(window, &window_rect);
	int width = window_rect.right - window_rect.left;
	int height = window_rect.bottom - window_rect.top; 
	int result_width = width;
	int result_height = height;
	
	HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, result_width, result_height);
	HBITMAP hOldBitmap = static_cast<HBITMAP>(SelectObject(hMemoryDC, hBitmap));
	StretchBlt(hMemoryDC, 0, 0, result_width, result_height, hScreenDC, 0, 0, width, height, SRCCOPY);
	hBitmap = static_cast<HBITMAP>(SelectObject(hMemoryDC, hOldBitmap));
	DeleteDC(hMemoryDC);
	DeleteDC(hScreenDC);
	return hBitmap;
}
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы