Страницы

Поиск по вопросам

Показаны сообщения с ярлыком screenshots. Показать все сообщения
Показаны сообщения с ярлыком screenshots. Показать все сообщения

среда, 10 июля 2019 г.

Копирование части окна в буфер

Есть форма WPF. У формы в качестве украшалки вокруг окна тень. Тень прописана своя используя DropShadowEffect. WindowsStyle и прочее установлено в none, соответвенно, так как она является частью окна, то про нажатии Alt+PrintScreen окно копируется вместе с тенью, и соответвенно с тем, что под ней. Как можно реализовать перехват нажатия данной комбинации и копировать в буфер определенный участок окна? Например с отступом со всех сторон по 15 пикселей? UPD: в данном случае предположу что можно не блокировать комбинацию Alt+PrintScreen а получить скриншот окна в обычном событии Нажатия клавиш в фокусе окна, и об аботая его поместить в буфер урезанную версию.


Ответ

Подписка на сочетание клавиш, полагаю, делается так же, как и всегда — с помощью функции RegisterHotKey (правда не гарантирую, что система позволит перекрыть системное сочетание клавиш). В .NET встроенной обёртки нет.
Создание скриншота — традиционный GetDC(0). В .NET обёрнуто в Graphics.CopyFromScreen
За тень окон отвечает система, поэтому вам придётся брать скриншот части экрана, которое занимает окно, плюс запас под тень. Кажется, размеры тени прошиты где-то в поторохах Aero, поэтому размер придётся угадывать на глаз. Так как WPF использует всякие умные масштабирования, то на габариты окна полагаться нельзя, поэтому советую брать габариты напрямую из WinAPI, иначе при масштабе, отличном от 100%, всё сползёт.
Правда, учитывая, сколько это мороки, я бы для начала задался вопросом: а настолько ли оно надо? Гораздо проще положить под окно белый фон, сделать скриншот всего экрана, а потом вырезать нужное. Плюс есть зоопарк программ, которые сделают это удобно и приятно.

воскресенье, 7 июля 2019 г.

Захват изображения рабочего стола активного монитора

Если к ПК подключено более одного монитора (например, ноутбук с дополнительным экраном, подключенным по D-SUB или HDMI), как захватить экран именно на том, на котором сейчас курсор? Или может можно как-то сразу все мониторы захватить в индивидуальный буфер для каждого?
Захват изображения основного рабочего стола выполняю так:
unsigned int Screen::GetMetrics(unsigned int *width, unsigned int *height){ *width = GetSystemMetrics(SM_CXSCREEN); *width-= (*width%4); *height = GetSystemMetrics(SM_CYSCREEN); *height-= (*height%4); return (*width * *height * 3); } unsigned int Screen::Grab(unsigned char **frame, unsigned int *timing){ // Defining screen dimensions unsigned int start = GetTickCount(); unsigned int width, height, size = GetMetrics(&width, &height); unsigned char *framebuf = nullptr; if( size ){ // Creating contexts HDC ScreenDC = GetDC(0); HDC MemoryDC = CreateCompatibleDC(ScreenDC); // Lock object (for multithread use) WaitForSingleObject(M_Screen, INFINITE); // Filling image header struct BitmapInfo.bmiHeader.biWidth = width; BitmapInfo.bmiHeader.biHeight = -height; BitmapInfo.bmiHeader.biSizeImage = width * height * BitmapInfo.bmiHeader.biBitCount / 8; HBITMAP hBitmap = CreateDIBSection(ScreenDC,&BitmapInfo,DIB_RGB_COLORS,(void**)&framebuf,0,0); SelectObject(MemoryDC, hBitmap); BitBlt(MemoryDC, 0, 0, width, height, ScreenDC, 0, 0, SRCCOPY); // Get cursor info CURSORINFO CursorInfo; CursorInfo.cbSize = sizeof(CursorInfo); if( GetCursorInfo(&CursorInfo) ){ ICONINFO IconInfo; GetIconInfo(CursorInfo.hCursor, &IconInfo); DeleteObject(IconInfo.hbmColor); DeleteObject(IconInfo.hbmMask); DrawIcon(MemoryDC, CursorInfo.ptScreenPos.x - IconInfo.xHotspot, CursorInfo.ptScreenPos.y - IconInfo.yHotspot, CursorInfo.hCursor); } ReleaseDC(NULL,ScreenDC); DeleteDC(MemoryDC); // Writing data and clearing buffers memcpy(*frame, framebuf, size); DeleteObject(hBitmap); ReleaseMutex(M_Screen); } // if need to know capture elapsed time if( timing != nullptr){*timing = GetTickCount() - start;} return size; }


Ответ

EnumDisplayMonitors поможет Вам определить координаты каждого подключенного монитора в системе.
BOOL CALLBACK monEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData){
// lprcMonitor - координаты монитора hMonitor на HDC
return TRUE; } ... EnumDisplayMonitors(NULL, NULL, monEnumProc, 0);
А CreateDC позволяет захватить сразу все мониторы в одном HDC, в котором эти координаты актуальны.
hAllDTopsDC = ::CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
// hAllDTopsDC - HDC, с которого можно делать скриншот любого монитора
::DeleteDC(hAllDTopsDC);
Посмотрите для полноценного примера исходники Monitors Viewer, который как раз следит за мышью и показывает содержимое активного монитора.