Форум программистов, компьютерный форум, киберфорум
Наши страницы
C++: WinAPI
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.81/42: Рейтинг темы: голосов - 42, средняя оценка - 4.81
kravam
быдлокодер
1709 / 896 / 105
Регистрация: 04.06.2008
Сообщений: 5,528
#1

Как создать скриншот части экрана?

01.05.2013, 22:34. Просмотров 7672. Ответов 38
Метки нет (Все метки)

Можно весь экран заскриншотить потому, что это частный случай части. Но дело не в этом.

Скриншот ведь предполагает какой-то файл иображения, да ведь? *.bmp там или *.jpg, к примеру. Дело в том, что все примеры, на которые я натыкался в инете глукбокомысленно заканчивались вызовом BitBlt, но этот вызов не создаст файла изображения, вот в чём дело!

Ну вот ссыли к примеру:
http://vsokovikov.narod.ru/New_MSDN_API/Bitmaps/captur_image.htm
Как сделать скриншот экрана?
Скриншот экрана

После чего все замолкают- типа дальше догадывайтесь сами.

Нет, сохранение рисунка в каком-то внутреннем формате- это дело хорошее, но пока я не увижу, как это сохранение можно в файл-изображение конвертировать, это для меня пустые звуки.

Спасибо, кто откликнется,
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
01.05.2013, 22:34
Ответы с готовыми решениями:

Как скопировать в буфер обмена скриншот экрана?
День всем добрый! Я сделал программу, которая сохраняет изображение из...

Скриншот экрана и его вывод
Задумал написать прикол - делается скриншот экрана и сразу же выводится....

Сделать скриншот экрана / копировать экранную область видеопамяти
Доброго времени суток. Для работы программы необходимо получить копию(скриншот)...

Сообщение от мыши,отжатой в любой части экрана
Здравствуйте, не могу понять, как сделать так чтобы при отжатой клавиши мыши,...

Можно ли на c++ создать программу подобную camstudio (захват видео с экрана)?
Каким образом записывает видео с экрана?Можно ли на c++ сделать что то такое? И...

38
Digit@ll
Brainsbreaker
888 / 366 / 51
Регистрация: 01.02.2011
Сообщений: 1,586
01.05.2013, 22:43 #2
Да, а дальше догадывайтесь сами. Велосипед: GetPixel, SetPixel.
0
kravam
быдлокодер
1709 / 896 / 105
Регистрация: 04.06.2008
Сообщений: 5,528
01.05.2013, 22:46  [ТС] #3
Я тебе враг разве? Вроде не обзывал тебя нигде.
0
Digit@ll
Brainsbreaker
888 / 366 / 51
Регистрация: 01.02.2011
Сообщений: 1,586
01.05.2013, 23:00 #4
А, да, в последней твоей ссылке об этом есть. Просто когда-то это тоже интересовало. Всё просто.
0
kravam
быдлокодер
1709 / 896 / 105
Регистрация: 04.06.2008
Сообщений: 5,528
01.05.2013, 23:01  [ТС] #5
Зачем отписываться без дела? Я же ничего плохого тебе не делал
0
volvo
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
25983 / 17424 / 6910
Регистрация: 22.10.2011
Сообщений: 30,668
Записей в блоге: 6
01.05.2013, 23:53 #6
kravam, ты ж пытался разобраться с OLE? Вот тебе пример с его использованием. Рабочий...
0
Izual
142 / 120 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
02.05.2013, 01:17 #7
kravam, у вас есть пример взятия принт скрина с всей рабочей области, принт отражает буффер с значениями каждого пикселя, неуж то в интере нет примеров создания BMP JPEG рисунков из буффера(наверно типа BYTE, т.к. 24 битный формат самый распространённый) ?
0
kravam
быдлокодер
1709 / 896 / 105
Регистрация: 04.06.2008
Сообщений: 5,528
02.05.2013, 10:43  [ТС] #8
Цитата Сообщение от UI Посмотреть сообщение
kravam, ты ж пытался разобраться с OLE? Вот тебе пример с его использованием. Рабочий...
А нельзя ли как-нибудь по-простому, по нашему, по-сермяжному? Без того, чтобы если хочешь из BitBlt получить графический файл, изучай COM..? Не надо ругаться, вопрос принципиальный.

Не по теме:

Кстати к COM я решил вернуться через некоторое время. Ибо то ли глаз замылился, то ли никто Роджерсона не изучал как я, то ли ещё что. Но сам я понять не могу, а объяснить тоже никто не может.
Агрегация: почему бы в деструкторе внешнего компонента сразу не приравнять количество ссылок на внешний компонент к единице и всё на этом (по Роджерсо


Цитата Сообщение от Izual Посмотреть сообщение
неуж то в интере нет примеров создания BMP JPEG рисунков из буффера(наверно типа BYTE, т.к. 24 битный формат самый распространённый) ?
0
volvo
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
25983 / 17424 / 6910
Регистрация: 22.10.2011
Сообщений: 30,668
Записей в блоге: 6
02.05.2013, 11:08 #9
Цитата Сообщение от kravam Посмотреть сообщение
А нельзя ли как-нибудь по-простому, по нашему, по-сермяжному?
Оно тебе надо, заполнять вручную все эти BITMAPFILEHEADER-ы и BITMAPINFOHEADER-ы корректными значениями, получать GetDIBits-ом данные из битмапа и их сохранять в файл? В MSDN есть пример, как это делается: Capturing an Image, до BitBlt (включительно) всё происходит так, как делается по моей первой ссылке, после (сохранение HBITMAP-а) - как по второй.

А теперь - внимание, вопрос на засыпку: зачем? Только чтобы потом гордо заявить, что "у меня программа написана прям на супер-чистом API, и по фиг, что она раздута как дирижабль"? Ты еще на чистом С пиши, угу.
0
kravam
быдлокодер
1709 / 896 / 105
Регистрация: 04.06.2008
Сообщений: 5,528
02.05.2013, 17:05  [ТС] #10
Чё зачем? Просто я считаю, что изучать для этой цели COM- это перебор.
0
Убежденный
Ушел с форума
Эксперт С++
15954 / 7266 / 1178
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
02.05.2013, 21:07 #11
Один из способов:

1) Получаем координаты и размер экрана.
Достигается с помощью GetSystemMetrics с параметрами SM_XVIRTUALSCREEN, SM_YVIRTUALSCREEN,
SM_CXVIRTUALSCREEN и SM_CYVIRTUALSCREEN. Если использовать другие параметры, то скриншот
может получиться неполным. Например, если у пользователя подключено два или более мониторов,
картинка будет захвачена только с одного.

2) Получаем контекст устройства экрана (GetDC с NULL), создаем совместимый контекст и битмап
соответствующего размера (CreateCompatibleDC, CreateCompatibleBitmap), "выбираем" битмап (SelectObject) и
зовем функцию BitBlt. К слову, последний аргумент функции BitBlt должен содержать флаг CAPTUREBLT,
иначе в скриншот не попадут полупрозрачные окна (те, которые с расширенным стилем WS_EX_LAYERED).

3) Далее нам поможет функция GetDIBits - она преобразует битмап (HBITMAP) в определенный формат и
"достает" массив пикселей. Там нет ничего сложного, нужно лишь заполнить структуры BITMAPINFO и
BITMAPINFOHEADER. Например, в BITMAPINFOHEADER в поля biWidth и biHeight пишутся размеры битмапа, в
biPlanes указывается 1, в biBitCount - 24 (24 bits per pixel), а в biCompression - BI_RGB.

4) Сохранить полученное изображение в файл можно по-разному.
Например, можно воспользоваться программным интерфейсом GdiPlus - у него есть класс Bitmap с
конструктором, принимающим BITMAPINFO и указатель на массив пикселей, а также encoder-ы,
позволяющие сохранять изображения в разных форматах (BMP, PNG, JPEG и некоторые другие).

Если чуть более подробно - нужно получить список encoder-ов, зарегистрированных в системе (ищите в
MSDN описания функций GetImageEncoders и GetImageEncodersSize), найти среди них нужный по
MIME-типу (например, "image/png"), а затем вызвать метод Bitmap::Save, передав аргументами имя
файла и encoder.
2
volvo
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
25983 / 17424 / 6910
Регистрация: 22.10.2011
Сообщений: 30,668
Записей в блоге: 6
02.05.2013, 22:17 #12
Цитата Сообщение от kravam Посмотреть сообщение
я считаю, что изучать для этой цели COM- это перебор.
Ну да, COM-перебор? GDI+ - да ни за что, зачем их вообще только придумали, да? Я дал ссылку на MSDN, там всё делается силами чистейшего WinAPI, чем теперь не устраивает? Длинно? Извините, золотое правило механики не отменял никто. Хотя о чем можно говорить с человеком, выбравшим подобный статус. Он говорит сам за себя...
0
kravam
быдлокодер
1709 / 896 / 105
Регистрация: 04.06.2008
Сообщений: 5,528
03.05.2013, 00:08  [ТС] #13
Цитата Сообщение от UI Посмотреть сообщение
GDI+ - да ни за что, зачем их вообще только придумали, да? Я дал ссылку на MSDN, там всё делается силами чистейшего WinAPI, чем теперь не устраивает? Длинно? Извините, золотое правило механики не отменял никто.
сами с собой разговариваете? Я так-то вынес суждение исключительно о COM, и больше ни о чём. Всё остальное- ваши досужие домыслы.

Добавлено через 51 секунду
Цитата Сообщение от UI Посмотреть сообщение
Хотя о чем можно говорить с человеком, выбравшим подобный статус. Он говорит сам за себя...
Не говорите, кто-то заставляет что ли?

Добавлено через 1 час 3 минуты
Убежденный, а вы хорошо разбираетесь во всём этом деле? Чтобы не мутить новую тему не поможете ли вы мне с одним вопросом?

Итак, структура BITMAPINFO:

typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO, *PBITMAPINFO;
http://msdn.microsoft.com/en-us/libr...=vs.85%29.aspx

А тут перевод:
http://vsokovikov.narod.ru/New_MSDN_API/Bitmaps/str_bitmapinfo.htm

Нас будет интересовать поле
bmiColors
Член структуры bmiColors, содержащий одно из перечисленного ниже:

Массив RGBQUAD. Элементы массива, которые составляют таблицу цветов.

Какие элементы? Какого массива? Конечно, формально
RGBQUAD bmiColors[1];
Это именно объявление массива, спору нет. Но что такое?- этот массив ВСЕГДА будет состоять из одного элемента! То есть это всё равно что было бы объявить так:
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors;
} BITMAPINFO, *PBITMAPINFO;
Вот думаю- что они хотели сказать, объявляя массив из одного элемента- ума не приложу... Лезет в голову всякая ерунда, типа- может, размер этого массива не всегда равен 1? Так опять же [1] понимается однозначно...
0
Убежденный
Ушел с форума
Эксперт С++
15954 / 7266 / 1178
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
03.05.2013, 00:30 #14
Это способ объявления структуры с массивом переменной длины.
В C/C++ нельзя написать ни "array[0]", ни "array[...]".

По поводу данного массива в том же MSDN сказано:
bmiColors

The number of entries in the array depends on the values of the biBitCount and biClrUsed members of the BITMAPINFOHEADER structure.
То есть, там может быть один или более элементов.
1
kravam
быдлокодер
1709 / 896 / 105
Регистрация: 04.06.2008
Сообщений: 5,528
04.05.2013, 03:39  [ТС] #15
Цитата Сообщение от Убежденный Посмотреть сообщение
Это способ объявления структуры с массивом переменной длины.
Да...? Ладно, будем продолжать работать.

Добавлено через 17 часов 13 минут
А как понять "выбрать объект" в...?

То есть я постоянно сталкиваюсь с этим понятием, но хоть убей не могу его сопоставить с чем-то из жизни.

НУ вот например, тут:
http://vsokovikov.narod.ru/New_MSDN_API/D_context/fn_selectobject.htm

"Функция SelectObject выбирает объект в заданный контекст устройства (DC)"

Я пытаюсь как-то внутри себя это как-то понять и не получается.

+++++++++++++++++++++++++++++++++++++++++

Допустим, у меня есть набор предметов- карандаш, тетрадь и книга.

Я могу выбрать один предмет из этих предметов.

Я могу положить выбранный предмет в портфель

Но я не могу выбрать тетрадку в портфель, вот в чём дело! "Выбрать тетрадку в портфель" (или "выбрать один из предметов в портфель")- это что-то уму непостижимое. Так вообще никто не говорит. В портфель кладут, помещают, запихивают. НО НЕ ВЫБИРАЮТ!

+++++++++++++++++++++++++++++++++++++++++

Тем не менее "выбрать объект в заданный контекст устройства" имеет смысл. Но какой? И я не придрался к словам, я не понимаю, что за этими словами стоит!
0
Croessmah
++Ͻ
14543 / 8302 / 1560
Регистрация: 27.09.2012
Сообщений: 20,368
Записей в блоге: 3
Завершенные тесты: 1
04.05.2013, 04:08 #16
Цитата Сообщение от kravam Посмотреть сообщение
Я могу выбрать один предмет из этих предметов.
Можете. Но в рюкзаке уже у Вас есть объект "тетрадка".
Вы вытащили старую, положили туда новую. То бишь выбрали её для ношения в портфеле

Добавлено через 1 минуту
И в случае, если Вам придется писать, то писать Вы будете на той тетрадке, которая у Вас в портфеле.
0
kravam
быдлокодер
1709 / 896 / 105
Регистрация: 04.06.2008
Сообщений: 5,528
04.05.2013, 14:39  [ТС] #17
Ну могу я хотя бы для себя понять (не для писанины на форум), что когда мы говорим
"Функция SelectObject выбирает объект в заданный контекст устройства (DC)"

Это всё равно, что:
"Функция SelectObject выбирает и помещает выбранный объект в заданный контекст устройства (DC)"
?
0
Убежденный
Ушел с форума
Эксперт С++
15954 / 7266 / 1178
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
04.05.2013, 15:13 #18
SelectObject "выбирает" кисть или другой объект почти также, как художник выбирает
кисть для рисования. То есть, взял кисть, нарисовал что-то, положил кисть на место,
взял другую и т.д. Можно пойти дальше и представить, что контекст устройства - это
мольберт, а битмап - это холст. Тогда SelectObject(hDC, hBitmap) закрепляет холст на
мольберте, а SelectObject(hDC, hPen) - художник берет в руки карандаш.
Для создания очередного шедевра
1
FreeMan108
121 / 121 / 32
Регистрация: 04.03.2013
Сообщений: 370
04.05.2013, 16:31 #19
Могу предложить рабочий код на чистом WinApi.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <windows.h>
 
inline int GetFilePointer(HANDLE FileHandle){
    return SetFilePointer(FileHandle, 0, 0, FILE_CURRENT);
}
 
bool SaveBMPFile(char *filename, HBITMAP bitmap, HDC bitmapDC, int width, int height){
    bool Success=0;
    HDC SurfDC=NULL;
    HBITMAP OffscrBmp=NULL;
    HDC OffscrDC=NULL;
    LPBITMAPINFO lpbi=NULL;
    LPVOID lpvBits=NULL;
    HANDLE BmpFile=INVALID_HANDLE_VALUE;
    BITMAPFILEHEADER bmfh;
    if ((OffscrBmp = CreateCompatibleBitmap(bitmapDC, width, height)) == NULL)
        return 0;
    if ((OffscrDC = CreateCompatibleDC(bitmapDC)) == NULL)
        return 0;
    HBITMAP OldBmp = (HBITMAP)SelectObject(OffscrDC, OffscrBmp);
    BitBlt(OffscrDC, 0, 0, width, height, bitmapDC, 0, 0, SRCCOPY);
    if ((lpbi = (LPBITMAPINFO)(new char[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)])) == NULL) 
        return 0;
    ZeroMemory(&lpbi->bmiHeader, sizeof(BITMAPINFOHEADER));
    lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    SelectObject(OffscrDC, OldBmp);
    if (!GetDIBits(OffscrDC, OffscrBmp, 0, height, NULL, lpbi, DIB_RGB_COLORS))
        return 0;
    if ((lpvBits = new char[lpbi->bmiHeader.biSizeImage]) == NULL)
        return 0;
    if (!GetDIBits(OffscrDC, OffscrBmp, 0, height, lpvBits, lpbi, DIB_RGB_COLORS))
        return 0;
    if ((BmpFile = CreateFile(filename,
                        GENERIC_WRITE,
                        0, NULL,
                        CREATE_ALWAYS,
                        FILE_ATTRIBUTE_NORMAL,
                        NULL)) == INVALID_HANDLE_VALUE)
        return 0;
    DWORD Written;
    bmfh.bfType = 19778;
    bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
    if (!WriteFile(BmpFile, &bmfh, sizeof(bmfh), &Written, NULL))
        return 0;
    if (Written < sizeof(bmfh)) 
        return 0; 
    if (!WriteFile(BmpFile, &lpbi->bmiHeader, sizeof(BITMAPINFOHEADER), &Written, NULL)) 
        return 0;
    if (Written < sizeof(BITMAPINFOHEADER)) 
        return 0;
    int PalEntries;
    if (lpbi->bmiHeader.biCompression == BI_BITFIELDS) 
        PalEntries = 3;
    else PalEntries = (lpbi->bmiHeader.biBitCount <= 8) ?
                      (int)(1 << lpbi->bmiHeader.biBitCount) : 0;
    if(lpbi->bmiHeader.biClrUsed) 
    PalEntries = lpbi->bmiHeader.biClrUsed;
    if(PalEntries){
    if (!WriteFile(BmpFile, &lpbi->bmiColors, PalEntries * sizeof(RGBQUAD), &Written, NULL)) 
        return 0;
        if (Written < PalEntries * sizeof(RGBQUAD)) 
            return 0;
    }
    bmfh.bfOffBits = GetFilePointer(BmpFile);
    if (!WriteFile(BmpFile, lpvBits, lpbi->bmiHeader.biSizeImage, &Written, NULL)) 
        return 0;
    if (Written < lpbi->bmiHeader.biSizeImage) 
        return 0;
    bmfh.bfSize = GetFilePointer(BmpFile);
    SetFilePointer(BmpFile, 0, 0, FILE_BEGIN);
    if (!WriteFile(BmpFile, &bmfh, sizeof(bmfh), &Written, NULL))
        return 0;
    if (Written < sizeof(bmfh)) 
        return 0;
    return 1;
}
bool ScreenCapture(int x, int y, int width, int height, char *filename){
    HDC hDc = CreateCompatibleDC(0);    
    HBITMAP hBmp = CreateCompatibleBitmap(GetDC(0), width, height);   
    SelectObject(hDc, hBmp);   
    BitBlt(hDc, 0, 0, width, height, GetDC(0), x, y, SRCCOPY);  
    bool ret = SaveBMPFile(filename, hBmp, hDc, width, height); 
    DeleteObject(hBmp);  
    return ret;
}
 
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpszArgument,
                   int nCmdShow)
{
    //ScreenCapture(0, 0, 100, 100, "picture.bmp");
       ScreenCapture(0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), "picture.bmp");   
    
    return 0;
}
Сохраняет снимок экрана прямо в файл picture.bmp.
2
kravam
быдлокодер
1709 / 896 / 105
Регистрация: 04.06.2008
Сообщений: 5,528
05.05.2013, 15:53  [ТС] #20
Ну вот кажется и пришло время делать первые выводы. Я уж было хотел, засучив рукава заняться вплотную точечными, рисунками, но подоспел FreeMan108. Видать, в другой раз.

Значит снимок монитора мы получать умеем. На основании предложенного кода так можно получить снимок части монитора или части любого окна. Код для частного случая. В макросе ok определён хэндл окна, но в общем случае его надо находить программно, что отдельный разговор (или с помощью того же Spy++). Вроде всё верно, утечек памяти не наблюдается.

Между прочим- первая действительно путёвая тема на весь инет про нахождение скриншота части окна!

Добавлено через 18 часов 27 минут
Но необходимо учесть, что если ты делаешь снимок части окна, то координаты отчитываются не от края окна, а от края КЛИЕНТСКОЙ ОБЛАСТИ окна.
То есть допустим у тебя есть обыкновенное окно с рамкой. И ты решил его полностью сфотать.
Пишешь:
ScreenCapture(0, 0, ширина_окна, высота_окна,(char*)"picture_3.bmp");

В результате ты получишь снимок клиентской области окна, внизу и справа его будут две полоски.
Чтобы этого не было, надо как-то узнавать ширину рамки и писать так:
ScreenCapture(-4, -23, ширина_окна, высота_окна,(char*)"picture_3.bmp");

Где 4 и 23 и есть та самая ширина рамки
1
05.05.2013, 15:53
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
05.05.2013, 15:53

Создать окно приложения размером в одну шестнадцатую площади экрана с заголовком
Создать окно приложения размером в одну шестнадцатую площади экрана с ...

Как сделать скриншот части экрана
Подскажите пожалуйста как сделать скриншот КУСОЧКА экрана с помощью VB2010? !...

Сделать скриншот части экрана
Для работы программа делает скриншоты несколько раз в секунду, и чтобы...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru