Форум программистов, компьютерный форум, киберфорум
C/C++: WinAPI
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.72/18: Рейтинг темы: голосов - 18, средняя оценка - 4.72
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18030 / 7733 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16

Полноценная графика средствами консоли

21.07.2016, 00:34. Показов 3848. Ответов 12

Студворк — интернет-сервис помощи студентам
Кто говорил, что невозможно?

24 бит.

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
// pass in the file name of a .bmp as a command line parameter to see it drawn in the console
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <conio.h>
#include <malloc.h>
 
#define CONSOLE_GRAPHICS_BUFFER 2 
 
typedef struct _CONSOLE_GRAPHICS_BUFFER_INFO {
    DWORD dwBitMapInfoLength;
    LPBITMAPINFO lpBitMapInfo;
    DWORD dwUsage;
    HANDLE hMutex;
    PVOID lpBitMap;
} CONSOLE_GRAPHICS_BUFFER_INFO, *PCONSOLE_GRAPHICS_BUFFER_INFO;
 
int main()
{
    // get the Invalidate function pointer
    typedef BOOL(WINAPI*pfnInvalidateBits)(HANDLE hCon, SMALL_RECT* pRc);
    pfnInvalidateBits invalidateConsoleDIBits = (pfnInvalidateBits)
        GetProcAddress(GetModuleHandle(L"kernel32.dll"), "InvalidateConsoleDIBits");
    // load a bitmap, any bitmap
    HBITMAP hBm = (HBITMAP)LoadImage(NULL, L"c:\\pic\\rose2.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    if (hBm)
    {
        // get the bits of the bitmap
        HDC hdc = GetDC(NULL);
        // if the bitmap is a 32-bit BI_BITFIELD bitmap, 3 dwords after the structure are
        // written by GetDIBits, so guard against that less we get any nasty stack corruption
        DWORD bufferSize = sizeof(BITMAPINFO)+3 * sizeof(DWORD);
        BITMAPINFO* pBmi = (BITMAPINFO*)_alloca(bufferSize);
        memset(pBmi, 0, bufferSize);
        pBmi->bmiHeader.biSize = sizeof(pBmi->bmiHeader);
        GetDIBits(hdc, hBm, 0, 0, NULL, pBmi, DIB_RGB_COLORS);
        std::vector<BYTE> bmBytes(pBmi->bmiHeader.biSizeImage);
        GetDIBits(hdc, hBm, 0, pBmi->bmiHeader.biHeight, &bmBytes[0], pBmi, DIB_RGB_COLORS);
        DeleteObject(reinterpret_cast<HGDIOBJ>(hBm));
        ReleaseDC(NULL, hdc);
 
        // fill in the struct
        CONSOLE_GRAPHICS_BUFFER_INFO cgbi = { sizeof(*pBmi), pBmi, DIB_RGB_COLORS, NULL, NULL };
        HANDLE hOrigCon = GetStdHandle(STD_OUTPUT_HANDLE);
        // do the do
        HANDLE hGraphics = CreateConsoleScreenBuffer(
            GENERIC_READ | GENERIC_WRITE,
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            NULL,
            CONSOLE_GRAPHICS_BUFFER,
            &cgbi
            );
        if (hGraphics != INVALID_HANDLE_VALUE)
        {
            // switch into graphics mode
            SetConsoleActiveScreenBuffer(hGraphics);
            // just to show how it can work, we "draw" the bitmap
            // 4 bytes at a time
            size_t numQuads = bmBytes.size() / sizeof(DWORD);
            size_t curQuad = 0;
            DWORD* pConsoleBufferIter = static_cast<DWORD*>(cgbi.lpBitMap);
            DWORD* pImageIter = reinterpret_cast<DWORD*>(&bmBytes[0]);
            // rect to invalidate, for graphic buffers the units are pixels
            // for simplicity we just issue a "redraw all" command
            SMALL_RECT sr = { 0, 0, pBmi->bmiHeader.biWidth, pBmi->bmiHeader.biHeight };
            while ((!_kbhit()) && (curQuad < numQuads))
            {
                WaitForSingleObject(cgbi.hMutex, INFINITE);
                *(pConsoleBufferIter++) = *(pImageIter++);
                ReleaseMutex(cgbi.hMutex);
                invalidateConsoleDIBits(hGraphics, &sr);
                ++curQuad;
            }
            Sleep(2000); // just so the finished product can be seen
            SetConsoleActiveScreenBuffer(hOrigCon);
            CloseHandle(hGraphics);
            CloseHandle(cgbi.hMutex); // the memory is unmapped automatically, but you must free the mutex
        }
        else
        {
            // This will show 5 if you're not running on x86 version of Windows
            printf("CreateConsoleScreenBuffer failed with error %lu\n", GetLastError());
        }
    }
    return 0;
}
Правда, работает только в XP. Может, что подкрутить...

Источник: http://blog.airesoft.co.uk/201... -graphics/
Миниатюры
Полноценная графика средствами консоли  
1
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
21.07.2016, 00:34
Ответы с готовыми решениями:

Чтение с консоли и запись в файл средствами API
Нужно считать с консоли строку и записать ее в файл средствами WIN API (функции readfile, writefile) Вот так сделал на обычном С ...

Графика в консоли
Доброго времени суток. Мне нужно нарисовать прямоугольник по координатам. Вопрос: я ввожу координаты, прямоугольник рисуется, но как...

Графика в консоли с использованием WinAPI
Всем привет, я решил сделать консольную игру с довольно примитивной графикой и выбрал для этого библиотеку windows.h. Порывшись в...

12
1748 / 353 / 41
Регистрация: 15.10.2012
Сообщений: 550
24.07.2016, 17:03
Под консольный FAR существуют плагины для просмотра графики и даже видео в том же окне. Есть даже скрипт для быстрого просмотра графики.
0
Заблокирован
24.07.2016, 18:56
Dragokas, а в чём прикол?Загрузить и запостить диб на контекст консоли?
0
Заблокирован
24.07.2016, 19:13
Dragokas, ну вот скрин с виндовс 7, мне просто интересно что хотели показать вы?
Кликните здесь для просмотра всего текста
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
#include <windows.h>
#include <process.h>
#include <iostream>
using namespace std;
 
struct THREAD_PARAMS{
    HDC     hDC;
    HDC     pDC;
    HBITMAP hBM;
    DWORD   dwTM;
};
 
void ThreadProc(PVOID pParam){
    THREAD_PARAMS * pCTX = (THREAD_PARAMS *)pParam;
    if( pCTX )
    {
        BITMAP bmp = {0};
        while( GetObject(pCTX->hBM, sizeof(BITMAP), (LPSTR)&bmp) )
        {
            pCTX->hBM = (HBITMAP)SelectObject(pCTX->pDC, pCTX->hBM);
            BitBlt(pCTX->hDC, 0, 0, bmp.bmWidth, bmp.bmHeight, pCTX->pDC, 0, 0, SRCCOPY);
            pCTX->hBM = (HBITMAP)SelectObject(pCTX->pDC, pCTX->hBM);
 
            Sleep(pCTX->dwTM);
        }
    }
}
 
int main(){
    HWND hWnd = GetForegroundWindow();
    HDC  hDC  = GetDC(hWnd);
    HDC  pDC  = CreateCompatibleDC(hDC);
    THREAD_PARAMS pCTX = {hDC, pDC, 0, 10};
    pCTX.hBM = (HBITMAP)LoadImage(GetModuleHandle(NULL), 
        "rose.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    if( pCTX.hBM != NULL )
    {
        _beginthread(ThreadProc, 0, &pCTX);
        Sleep(INFINITE);
    }
    return 0;
}
Миниатюры
Полноценная графика средствами консоли  
1
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18030 / 7733 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16
24.07.2016, 19:48  [ТС]
В том что отрисовка производится не одной из стандартных функций, предназначенной специально для рисования пикселей в окошках (у Вас - BitBlt), а через недокументированный графический буфер консоли.
0
Заблокирован
24.07.2016, 19:54
Dragokas, мне ещё интерсно кроме как WriteConsole стандартные средства вывода cout будут рабоать в вашем вараинте?
Цитата Сообщение от Dragokas Посмотреть сообщение
В том что отрисовка производится не одной из стандартных функций, предназначенной специально для рисования пикселей в окошках (у Вас - BitBlt), а через недокументированный графический буфер консоли.
- та он вполне документированный
https://msdn.microsoft.com/en-... s.85).aspx
https://msdn.microsoft.com/en-... s.85).aspx
Честно не уловил профита, обычно буфер консольки для покраски текста используют, это да.
0
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18030 / 7733 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16
24.07.2016, 20:04  [ТС]
То Вы привели ссылки на функции, который его устанавливаеют. А сам буфер - CONSOLE_GRAPHICS_BUFFER_INFO.
Посмотрите статью в первом посте.
Профита по сравнению с Вашим вариантом из-под windows может и нету. Речь не о нём.

Цитата Сообщение от Unknownx Посмотреть сообщение
Dragokas, мне ещё интерсно кроме как WriteConsole стандартные средства вывода cout будут рабоать в вашем вараинте?
Вроде как там никакие текстовые средства не будут работать, т.к. консоль переключается в специальный графический режим.
Хотя я не особо хорошо тестировал.
0
Заблокирован
24.07.2016, 20:34
Цитата Сообщение от Dragokas Посмотреть сообщение
typedef struct _CONSOLE_GRAPHICS_BUFFER_INFO {
* * DWORD dwBitMapInfoLength;
* * LPBITMAPINFO lpBitMapInfo;
* * DWORD dwUsage;
* * HANDLE hMutex;
* * PVOID lpBitMap;
} CONSOLE_GRAPHICS_BUFFER_INFO, *PCONSOLE_GRAPHICS_BUFFER_INFO;
- ну этот да в природе не встречал, первый раз вижу, обычный же CONSOLE_SCREEN_BUFFER_INFO конечно же знаком https://msdn.microsoft.com/en-... s.85).aspx
0
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18030 / 7733 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16
24.07.2016, 21:05  [ТС]
Цитата Сообщение от Unknownx Посмотреть сообщение
Честно не уловил профита, ...
На счёт профита, скорее всего польза там под MS-DOS.
В примере выше там windows.h используется просто для переноса пикселей из внешнего файла в буфер. Тоже самое можно сделать и аналогами под DOS, или как душа пожелает иначе (вручную) заполнить буфер примитивами.

Могу предположить, что с переходом на Vista и сворачиваем поддержки режима эмуляции MS-DOS убрали и эту фишку с графическим буфером.
0
 Аватар для fair7
13 / 13 / 1
Регистрация: 31.12.2010
Сообщений: 131
Записей в блоге: 14
16.04.2020, 14:13
более компактный вариант, у меня получился:

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
#include <windows.h>
#include <conio.h>
struct THREAD_PARAMS{
    HDC     hDC;
    HDC     pDC;
    HBITMAP hBM;
 
    THREAD_PARAMS()
    {
        HWND hWnd = GetForegroundWindow();
        hDC  = GetDC(hWnd);
        pDC  = CreateCompatibleDC(hDC);
    }
}pCTX;
void ThreadProc(void* pParam){
    THREAD_PARAMS * pCTX = (THREAD_PARAMS *)pParam;
 
    BITMAP bmp = {0};
     GetObject(pCTX->hBM, sizeof(BITMAP), (LPSTR)&bmp);
    pCTX->hBM = (HBITMAP)SelectObject(pCTX->pDC, pCTX->hBM);
    BitBlt(pCTX->hDC, 0, 0, bmp.bmWidth, bmp.bmHeight, pCTX->pDC, 0, 0, SRCCOPY);
}
int main()
{
    Sleep(1);
 
    pCTX.hBM = (HBITMAP)LoadImage(GetModuleHandle(NULL),
        "PUCyHOK.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    ThreadProc(&pCTX);
    getch();return 0;
}
1
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18030 / 7733 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16
16.04.2020, 16:42  [ТС]
fair7, при чём тут BitBlt, почитайте тему. Рисовать можно чем угодно и на чём угодно, хоть через Direct3d.
Речь шла о рисовании средствами консольных функций.
0
 Аватар для fair7
13 / 13 / 1
Регистрация: 31.12.2010
Сообщений: 131
Записей в блоге: 14
19.04.2020, 16:24
всё это интересно: рисование средствами консольных функций.
Но почему так медленно и можно ли сделать быстрее вывод рисунка?

Добавлено через 5 минут
вот мои попытки сделать быстрее, но не получается найти описание к функциям, чтобы разобраться в коде.
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
// передаем имя файла .bmp в качестве параметра командной строки, чтобы увидеть его в консоли
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <cstdio>
#include <cstdlib>
// # include <vector>
#include <conio.h>
#include <malloc.h>
 
#define CONSOLE_GRAPHICS_BUFFER 2
 
typedef struct _CONSOLE_GRAPHICS_BUFFER_INFO {
    DWORD dwBitMapInfoLength;
    LPBITMAPINFO lpBitMapInfo;
    DWORD dwUsage;
    HANDLE hMutex;
    PVOID lpBitMap;
} CONSOLE_GRAPHICS_BUFFER_INFO, * PCONSOLE_GRAPHICS_BUFFER_INFO;
 
int main ()
{
    // получаем указатель на функцию Invalidate
    typedef BOOL (WINAPI * pfnInvalidateBits) (HANDLE hCon, SMALL_RECT * pRc);
    pfnInvalidateBits invalidateConsoleDIBits = (pfnInvalidateBits)
        GetProcAddress (GetModuleHandle ("kernel32.dll"), "InvalidateConsoleDIBits");
    // загрузить растровое изображение, любое растровое изображение
    HBITMAP hBm = (HBITMAP) LoadImage (NULL, "3.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    if (hBm)
    {
        // получить биты растрового изображения
        HDC hdc = GetDC (NULL);
        // если растровое изображение является 32-разрядным растровым изображением BI_BITFIELD, 3 слова после структуры
        // написано GetDIBits, так что остерегайтесь этого, чем меньше мы получим неприятное повреждение стека
        DWORD bufferSize = sizeof (BITMAPINFO) +3 * sizeof (DWORD);
        BITMAPINFO * pBmi = (BITMAPINFO *) _alloca (bufferSize);
        memset (pBmi, 0, bufferSize);
        pBmi-> bmiHeader.biSize = sizeof (pBmi-> bmiHeader);
        GetDIBits (hdc, hBm, 0, 0, NULL, pBmi, DIB_RGB_COLORS);
        // станд :: вектор <BYTE>
        unsigned char * bmBytes = new unsigned char [pBmi-> bmiHeader.biSizeImage];
        // unsigned char bmBytes [1366 * 768];
        GetDIBits (hdc, hBm, 0, pBmi-> bmiHeader.biHeight, & bmBytes [0], pBmi, DIB_RGB_COLORS);
        DeleteObject(reinterpret_cast<HGDIOBJ>(hBm));
        ReleaseDC(NULL, hdc);
 
        // заполняем структуру
        CONSOLE_GRAPHICS_BUFFER_INFO cgbi = {sizeof (* pBmi), pBmi, DIB_RGB_COLORS, NULL, NULL};
        HANDLE hOrigCon = GetStdHandle (STD_OUTPUT_HANDLE);
        // делаем
        HANDLE hGraphics = CreateConsoleScreenBuffer (
            GENERIC_READ | GENERIC_WRITE,
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            NULL,
            CONSOLE_GRAPHICS_BUFFER,
            & cgbi
            );
        {
            // переключаемся в графический режим
            SetConsoleActiveScreenBuffer (hGraphics);
            // просто чтобы показать, как это может работать, мы «рисуем» растровое изображение
            // 4 байта за раз
            size_t numQuads = pBmi-> bmiHeader.biSizeImage / sizeof (DWORD);
            size_t curQuad = 0;
            DWORD * pConsoleBufferIter = static_cast <DWORD *> (cgbi.lpBitMap);
            DWORD * pImageIter = reinterpret_cast <DWORD *> (& bmBytes [0]);
            // прямоугольник для аннулирования, для графических буферов единицами измерения являются пиксели
            // для простоты мы просто запускаем команду "перерисовать все"
            SMALL_RECT sr = {0, 0, pBmi-> bmiHeader.biWidth, pBmi-> bmiHeader.biHeight};
            while ((curQuad <numQuads))
            {
              //  WaitForSingleObject (cgbi.hMutex, INFINITE);
                * (pConsoleBufferIter ++) = * (pImageIter ++);
             //   ReleaseMutex (cgbi.hMutex);
                invalidateConsoleDIBits (hGraphics, & sr);
                ++ curQuad;
            }
           // getch();// просто чтобы увидеть готовый продукт
            // Sleep (2000);
            SetConsoleActiveScreenBuffer (hOrigCon);
            CloseHandle (hGraphics);
            CloseHandle (cgbi.hMutex); // память автоматически отображается, но вы должны освободить мьютекс
        }
     delete [] bmBytes;
    }
 
    return 0;
}
0
9 / 9 / 2
Регистрация: 09.04.2012
Сообщений: 75
23.04.2020, 06:36
Не думал, что это возможно. Но у меня не получается в gui приложении прочесть в байтовый массив текст из консоли, после выполнения из ShellExecute bat-файла.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
23.04.2020, 06:36
Помогаю со студенческими работами здесь

Вывод графика в консоли через windows.h
это программа вывода массива типа double Вопрос в том, как сделать так, чтобы в MoveToEx(hdc, x, Y, NULL) переменные x и Y были типа...

Игра на winapi в консоли: шарик иногда отскакивает нелогично, графика мерцает
Всем привет. Я пишу игру, где надо, отбивая шарик доской, сбивать блоки. Сделал визуализацию через winapi, а обработку нажатия клавиш и...

Удаленный доступ к консоли Linux средствами php
Какой есть безопасный метод получения удаленного доступа к консоли сервера линукс средствами php? Через сайт на сервере будут постоянно...

Графика в консоли C++
Здравствуйте. Изучаю C++ уже около 3-х месяцев, но нигде не могу найти аналог виндовой библиотеки для рисования прямоугольников, кругов и...

Графика в консоли
Существует ли возможность реализовать графику в консольных приложениях С++ с использованием стандартных библиотек. (без создния собственных...


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

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Новые блоги и статьи
Первый деплой
lagorue 16.01.2026
Не спеша развернул своё 1ое приложение в kubernetes. А дальше мне интересно создать 1фронтэнд приложения и 2 бэкэнд приложения развернуть 2 деплоя в кубере получится 2 сервиса и что-бы они. . .
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ * Дана цепь постоянного тока с R, L, C, k(ключ), U, E, J. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа, решает её и находит: токи, напряжения и их 1 и 2 производные при t = 0;. . .
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым. Но восстановить их можно так. Для этого понадобится консольная утилита. . .
Изучаю kubernetes
lagorue 13.01.2026
А пригодятся-ли мне знания kubernetes в России?
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru