Захват Изображения С Экрана

Тема в разделе "Общие вопросы по С и С++", создана пользователем -, 20 дек 2011.

Наш партнер Genesis Hackspace
  1. Гость

    Здравствуйте. Мне необходимо получить битмап экрана в Linux'е и Windows'е... Подскажите пожалуйста, как это можно сделать. Библиотеки для работы с графикой (которые нашел, по крайней мере), обеспечивают доступ лишь к созданной ими же экранной поверхности. Надеюсь на вашу помощь :)
     
  2. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.339
    Симпатии:
    0
    Для Windows: GetDC( NULL ) == DC всего экрана
    Для Linux (не уверен что будет работать с Xorg): читать /dev/fb0
     
  3. Гость

    С обращением к видеопамяти в Линуксе вроде бы почти разобрался. А вот с Win API беда...
    Ниже - немного исправленный мною кусок чужого кода. Вероятно, именно поэтому не рабочий...
    По задумке должен сохранять скрин экрана по пути strFileName
    Если это не слишком нагло, помогите пожалуйста его поправить, за пару часов разобраться не смог, а полноценно изучать Win API времени нет
    Код (C++):
    #include <windows.h>
    int main()
    {
    HWND window;
    //Получаем прямоугольную область экрана
    RECT windowRect;
    //GetWindowRect(window, &windowRect);
    GetClientRect(window, &windowRect);


    //Размеры битмэпа
    int bitmap_dx = windowRect.right-windowRect.left;
    int bitmap_dy = windowRect.bottom-windowRect.top;

    BITMAPINFOHEADER bmpInfoHeader;
    BITMAPFILEHEADER bmpFileHeader;
    BITMAP* pBitmap;

    bmpFileHeader.bfType = 0x4d42;
    bmpFileHeader.bfSize = 0;
    bmpFileHeader.bfReserved1 = 0;
    bmpFileHeader.bfReserved2 = 0;
    bmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

    bmpInfoHeader.biSize = sizeof(bmpInfoHeader);
    bmpInfoHeader.biWidth = bitmap_dx;
    bmpInfoHeader.biHeight = bitmap_dy;
    bmpInfoHeader.biPlanes = 1;
    bmpInfoHeader.biBitCount = 24;
    bmpInfoHeader.biCompression = BI_RGB;
    bmpInfoHeader.biSizeImage = bitmap_dx*bitmap_dy*(24/8);
    bmpInfoHeader.biXPelsPerMeter = 0;
    bmpInfoHeader.biYPelsPerMeter = 0;
    bmpInfoHeader.biClrUsed = 0;
    bmpInfoHeader.biClrImportant = 0;

    BITMAPINFO info;
    info.bmiHeader = bmpInfoHeader;

    BYTE* memory;
    HDC winDC = GetWindowDC(window);
    HDC bmpDC = CreateCompatibleDC(winDC);
    //Создаем битмэп
    HBITMAP bitmap = CreateDIBSection(winDC, &info, DIB_RGB_COLORS, (void**)&memory, NULL, 0);
    SelectObject(bmpDC, bitmap);//Выбираем в контекст битмэп
    BitBlt(bmpDC, 0, 0, bitmap_dx, bitmap_dy, winDC, 0, 0, SRCCOPY);
    ReleaseDC(window, winDC);

    OPENFILENAME ofn;//Указатель на структуру с данными инициализации диалогового окна
    char strFilter[] = "Файлы данных *.bmp\0";
    char strFileName[MAX_PATH] = "[путь к файлу]";
    memset(&ofn, 0, sizeof(OPENFILENAME));//Обнуление ofn
    ofn.lStructSize = sizeof(OPENFILENAME);
    ofn.hwndOwner = window;
    ofn.lpstrFilter = strFilter;
    ofn.lpstrFile = strFileName;//Буфер для имени файла
    ofn.nMaxFile = MAX_PATH;//Размер файла
    ofn.lpstrInitialDir = NULL;
    ofn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT;
    strcpy(strFileName, ofn.lpstrFile);
    GetSaveFileName(&ofn); //MessageBox(hwnd,"Невозможно сохранить файл", "О программе...",MB_ICONINFORMATION);

    HANDLE hFile = CreateFile(
    ofn.lpstrFile, GENERIC_WRITE,
    0, NULL, OPEN_ALWAYS,
    FILE_ATTRIBUTE_NORMAL,NULL);
    DWORD dwWritten = 0;
    WriteFile(hFile, &bmpFileHeader, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
    WriteFile(hFile, &bmpInfoHeader, sizeof(BITMAPINFOHEADER), &dwWritten, NULL);
    WriteFile(hFile, memory, bmpInfoHeader.biSizeImage, &dwWritten, NULL);
    CloseHandle(hFile);
    return 0;
    }
     
  4. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.339
    Симпатии:
    0
    Вот простой пример того, как снять скрин и записать его черно-белое изображение в файл сырого формата:
    Код (C++):
    #include <windows.h>
    #include <stdio.h>

    static int      w, h;
    static void *   p;

    void dump_ss()
    {
    int             i;
    unsigned char * pp = (unsigned char *)p;
    FILE *          fp;

    fp = fopen( "ss.raw", "wb+" );
    for ( i = 0; i < w * h; i++ ) {
    fputc( pp[i * 4], fp );
    }
    fclose( fp );
    }

    int main()
    {
    HDC                 hdc;
    HBITMAP             dib;
    BITMAPINFOHEADER    bi;

    w = GetSystemMetrics( SM_CXSCREEN );
    h = GetSystemMetrics( SM_CYSCREEN );

    bi.biSize           = sizeof( BITMAPINFOHEADER );
    bi.biWidth          = w;
    bi.biHeight         = -h;
    bi.biPlanes         = 1;
    bi.biBitCount       = 32;
    bi.biCompression    = BI_RGB;
    hdc = CreateCompatibleDC( NULL );
    dib = CreateDIBSection( hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, &p, NULL, 0 );
    SelectObject( hdc, dib );

    BitBlt( hdc, 0, 0, w, h, GetDC( NULL ), 0, 0, SRCCOPY );

    dump_ss();

    return 0;
    }
    И не говори потом что ничего не получается. Включаешь мозг - и все становится понятно.
     
  5. Гость

    Ок, спасибо за помощь, постараюсь разобраться.
     
  6. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.339
    Симпатии:
    0
    Да, совсем забыл. Вот скрин того что получается в файле.
     

    Вложения:

    • Захват Изображения С Экрана
      ss.png
      Размер файла:
      43,8 КБ
      Просмотров:
      81
  7. Гость

    Что-то понял... Попробовал написать сохранение в bmp, но на выходе черная картинка нужного размера...
    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">код</div></div><div class="sp-body"><div class="sp-content">
    Код (C++):
    #include <windows.h>
    #include <stdio.h>

    static int      w, h;
    static void *   p;
    static char * name="screen.bmp";
    void SaveBitmap(char *name,HBITMAP bitmap)
    {
    HDC hdcScreen; // Контекст устройства экрана
    HWND hwndScreen; // Дескриптор окна рабочего стола
    int i; // Количество выбираемых линий
    BYTE *bits; // Указатель на массив битов изображения
    BITMAPINFOHEADER *info; // Информационная структура изображения
    HANDLE fp; // Дескриптор файла
    BITMAPFILEHEADER finfo; // Заголовок файла изображения
    long ctsize,imgsize,pixels;// Различные размерности для записи файла
    DWORD dw; // Код возврата
    char *ptr; // Указатель используемый для записи открытого BM

    // Получаем дескриптор рабочего стола
    hwndScreen=GetDesktopWindow();
    // Получаем контекст устройства рабочего стола
    hdcScreen = GetDC( hwndScreen );

    // Выделяем память под структуру с информацией о изображении
    info = (BITMAPINFOHEADER*)GlobalAlloc(GMEM_FIXED,sizeof(BITMAPFILEHEADER)+(1024*sizeof(RGBQUAD)));
    info->biSize = sizeof(BITMAPINFOHEADER);
    info->biBitCount = 0;

    // Заполняем структуру информацией о изображении
    i = GetDIBits( hdcScreen, // дескриптор контекста устройства
    bitmap, // дескриптор изображения
    0, // первая строка развертки, которая должна быть выбрана
    0, // число копируемых линий
    NULL, // адрес массива для битов изображения
    (BITMAPINFO*)info, // адрес структуры для данных изображения
    DIB_RGB_COLORS // RGB или индекс палитры
    );
    // Определяем количество бит на пиксель.
    if( (info->biBitCount!=4) &&
    (info->biBitCount!=8) &&
    (info->biBitCount!=24) )
    info->biBitCount=24;
    // Указываем что изображение не сжато
    info->biCompression=BI_RGB;

    // Получаем количество пикселей
    pixels=info->biWidth*info->biHeight;
    switch(info->biBitCount)
    {
    case 4:ctsize=16;imgsize=pixels/2;break;
    case 8:ctsize=256;imgsize=pixels;break;
    case 16:ctsize=0;imgsize=pixels*2;break;
    case 24:ctsize=0;imgsize=pixels*3;break;
    case 32:ctsize=0;imgsize=pixels*4;break;
    default:
    ReleaseDC( hwndScreen,hdcScreen );
    }

    // Инициализируем массив для битов изображения
    bits = (unsigned char*)GlobalAlloc(GMEM_FIXED,imgsize);

    //Заполняем массив битов изображения
    i = GetDIBits( hdcScreen, // дескриптор контекста устройства
    bitmap, // дескриптор изображения
    0, // первая выбираемая линия для изображения назначения
    info->biHeight, // количество выбираемых линий
    bits, // адрес массива битов изображения
    (BITMAPINFO*)info,// адрес структуры с данными изображения
    DIB_RGB_COLORS // RGB или индекс палитры
    );

    // Формируем заголовок файла
    ptr = (char *)&finfo.bfType;
    ptr[0]='B';
    ptr[1]='M';

    //Определяем сдвиг от начала структуры BITMAPFILEHEADER до массива бит
    finfo.bfOffBits=sizeof(BITMAPFILEHEADER)+
    sizeof(BITMAPINFOHEADER)+
    (sizeof(RGBQUAD)*ctsize);
    // Размер файла изображения в байтах
    finfo.bfSize=finfo.bfOffBits+imgsize;
    finfo.bfReserved1=0;
    finfo.bfReserved2=0;

    //Создаем файл для изображения
    fp = CreateFile(name, // указатель с именем файла
    GENERIC_WRITE, // режим доступа
    0, // режим использования
    NULL, // указатель на параметры безопасности
    CREATE_ALWAYS, // метод создания
    FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN,// атрибуты файла
    NULL
    );
    // Записываем структуру заголовка файла
    WriteFile(fp,&finfo,sizeof(BITMAPFILEHEADER),&dw,NULL);
    // Записываем структуру информации изображения
    WriteFile(fp,info,sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*ctsize,&dw,NULL);
    // Записываем биты изображения
    WriteFile(fp,bits,imgsize,&dw,NULL);
    // Закрываем файл
    CloseHandle(fp);
    //Освобождаем память с информацией изображения
    GlobalFree(info);
    // Освобождаем память с битами изображения
    GlobalFree(bits);
    // Освобождаем контекст устройства
    ReleaseDC( hwndScreen,hdcScreen );
    }

    int main()
    {
    HDC                 hdc;
    HBITMAP             dib;
    BITMAPINFOHEADER    bi;

    w = GetSystemMetrics( SM_CXSCREEN );
    h = GetSystemMetrics( SM_CYSCREEN );

    bi.biSize           = sizeof( BITMAPINFOHEADER );
    bi.biWidth          = w;
    bi.biHeight         = -h;
    bi.biPlanes         = 1;
    bi.biBitCount       = 32;
    bi.biCompression    = BI_RGB;
    hdc = CreateCompatibleDC( NULL );
    dib = CreateDIBSection( hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, NULL, NULL, 0 );
    SaveBitmap(name,dib);
    return 0;
    }
    И вопрос по Вашему способу сохранения... Почему в файл пишется именно каждый четвертый байт? Судя по всему, за цвет каждого пикселя отвечают четыре байта, так? Тогда можно извлечь r,g,b составляющие для каждого пикселя?
     
  8. rrrFer

    rrrFer Гость

    Не уверен что поможет, но:
    http://developer.qt.nokia.com/doc/qt-4.8/qpixmap.html
    А именно:
    И даже, есть пример готовый: http://developer.qt.nokia.com/doc/qt-4.8/d...ff-ef489cb6b1ed
    И вам должно быть приятно что не придется писать 2 версии программы...
     
  9. Гость

    Спасибо, посмотрю завтра. Но, так или иначе, с предыдущим способом уже просто интересно разобраться) Qt - более...высокоуровневая штука)
     
  10. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.339
    Симпатии:
    0
    Читай. Еще. Раз. !. У меня написано совсем по-другому.

    Чтобы не заморачиваться я брал только одну компоненту, поэтому у меня и получилось черно-белое изображение. А вообще там они все (R, G и B ).

    Добавлено:
    Каждый четвертый потому, что помимо RGB так есть еще и А, но в нашем случае она не используется.
     
  11. Гость

    Вывести черно-белое изображение на экран, не сохраняя, попиксельно, получилось. Вопрос - при сохранении в bmp после структур FILEHEADER и INFOHEADER можно просто целиком записать получаемую в Вашем примере область памяти с указателем на начало p? Или все сложнее?
    И почему biHeight=-h , а не просто h?
     
  12. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.339
    Симпатии:
    0
    Код (C++):
    #include <windows.h>
    #include <stdio.h>

    int     w, h;
    void *  p;

    void dump_bmp()
    {
    int                 i;
    BITMAPFILEHEADER    bfh;
    BITMAPINFOHEADER    bmi;
    FILE *              fp;

    memset( &bfh, 0, sizeof( BITMAPFILEHEADER ) );
    memset( &bmi, 0, sizeof( BITMAPINFOHEADER ) );

    bfh.bfType      = 0x4d42; // "BM"
    bfh.bfSize      = sizeof( BITMAPFILEHEADER ) + w * h * 4;
    bfh.bfOffBits   = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER );

    bmi.biSize          = sizeof( BITMAPINFOHEADER );
    bmi.biWidth         = w;
    bmi.biHeight        = h;
    bmi.biPlanes        = 1;
    bmi.biBitCount      = 32;
    bmi.biCompression   = BI_RGB;

    fp = fopen( "ss.bmp", "wb+" );

    fwrite( &bfh, sizeof( BITMAPFILEHEADER ), 1, fp );
    fwrite( &bmi, sizeof( BITMAPINFOHEADER ), 1, fp );
    fwrite( p, w * h * 4, 1, fp );

    fclose( fp );
    }

    int main()
    {
    HDC                 hdc;
    HBITMAP             dib;
    BITMAPINFOHEADER    bi;

    w = GetSystemMetrics( SM_CXSCREEN );
    h = GetSystemMetrics( SM_CYSCREEN );

    bi.biSize           = sizeof( BITMAPINFOHEADER );
    bi.biWidth          = w;
    bi.biHeight         = h;
    bi.biPlanes         = 1;
    bi.biBitCount       = 32;
    bi.biCompression    = BI_RGB;
    hdc = CreateCompatibleDC( NULL );
    dib = CreateDIBSection( hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&p, NULL, 0 );
    SelectObject( hdc, dib );

    BitBlt( hdc, 0, 0, w, h, GetDC( NULL ), 0, 0, SRCCOPY );

    dump_bmp();

    return 0;
    }
    Мне просто интересно, если ты учишься на по этой специальности, то как ты дальше будешь решать такие задачи?
     
  13. Гость

    Благодарю.
    P.S. Вчера хоть и с большим количеством косяков, но дошел почти до этого кода.
    P.P.S. Учусь на специальности "Компьютерная безопасность" на втором курсе. Во втором семестре первого прошли паскаль. Сейчас изучаем Си, дошли по программе примерно до строк... ^ - для себя. И не могу сказать, что программирование для меня очень важно. Так, одно из интересных занятий, не более.
     
Загрузка...

Поделиться этой страницей