Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > GetDIBits - получить растр


Автор: Annuta 22.2.2007, 13:57
Привет... У меня прога выводит гифовские анимашки на экранчик через USB порт. Беру и в цикле раскладываю каждый кадр в массив RGB и уже этот массив передаю в порт. 
 Раньше пользовалась GetPixel(); Но уж оочень она медленная - хочу переделать это 
на GetDIBits ... нашла код ... переписала ... и ошибок не выдаёт - но и в массиве pBits
ничего нет !!! Хотя там по моему разумению должен быть растр картинки т.е. RGB сост каждого бита... привожу код Помогите плиз ... 
Код

//Вывожу в цикле кадры анимашки
while (!m_bExitThread)
    {        
             HDC hMemDC = NULL;
        HBITMAP hMemBM = NULL, hOldBM = NULL;

        if (m_arrFrames[nTemp].m_pPicture) //Кадр
        {            
            if (m_arrFrames[nTemp].m_nDisposal == 3)
            {
                // prepare a memory DC and store the background in it
                hMemDC = CreateCompatibleDC(m_hMemDC);
                hMemBM = CreateCompatibleBitmap(m_hMemDC,
                            m_arrFrames[nTemp].m_frameSize.cx,
                            m_arrFrames[nTemp].m_frameSize.cy);
                
            if (hMemDC && hMemBM)
            {
               hOldBM = reinterpret_cast<HBITMAP> (SelectObject(hMemDC,hMemBM));
            };
        };
        

        long hmWidth;
        long hmHeight;
        
                   m_arrFrames[nTemp].m_pPicture->get_Width(&hmWidth);
            m_arrFrames[nTemp].m_pPicture->get_Height(&hmHeight);

            if (m_arrFrames[nTemp].m_pPicture->Render(m_hMemDC, 
                m_arrFrames[nTemp].m_frameOffset.cx, 
                m_arrFrames[nTemp].m_frameOffset.cy, 
                m_arrFrames[nTemp].m_frameSize.cx, 
                m_arrFrames[nTemp].m_frameSize.cy, 
                0, hmHeight, hmWidth, -hmHeight, NULL) == S_OK)
            {
                Invalidate(FALSE);
                
                //HBITMAP hOldBM = NULL;

            HDC bDC = CreateCompatibleDC(0);  //создаем DC для нашего битмапа
              SelectObject(bDC, hOldBM);                 //Назначаем DC для нашего битмапа

            tagBITMAP bmInfo;                            

            GetObject(hOldBM, sizeof(bmInfo), &bmInfo); //Получаем инфу о DDB

BITMAPINFO DIBInfo;
  memset(&DIBInfo, 0, sizeof(DIBInfo)); //Готовим структуру для создания DIB.

  DIBInfo.bmiHeader.biWidth         = 132;
  DIBInfo.bmiHeader.biHeight        = 132;
  DIBInfo.bmiHeader.biPlanes        = 1;      // всегда 1
  DIBInfo.bmiHeader.biCompression   = BI_RGB; // без компрессии
  DIBInfo.bmiHeader.biBitCount      = 24;     // три байта на пиксель
  DIBInfo.bmiHeader.biSize          = sizeof(DIBInfo.bmiHeader);
  DIBInfo.bmiHeader.biXPelsPerMeter = 2834;   // пикселей на метр, гор.    
  DIBInfo.bmiHeader.biYPelsPerMeter = 2834;   // пикселей на метр, верт. 

BYTE* pBits  = NULL;     //тут будет растр DIB 
HBITMAP dib  = NULL;    //Хендл DIB вдруг понадобится :)

 
//Создаем пустой DIB в памяти на основе установленых параметров.
//dib = CreateDIBSection(bDC, &DIBInfo, DIB_RGB_COLORS, (VOID**)&pBits, 0, 0);

//Конвертируем DDB в DIB указанного формата.
  GetDIBits(m_hMemDC, hOldBM, 0, 131, pBits, &DIBInfo, DIB_RGB_COLORS);

  DIBInfo.bmiHeader.biBitCount = BI_BITFIELDS ;
  DWORD * pBitFields = (DWORD *) DIBInfo.bmiColors;
        DWORD red   = pBitFields[0];
        DWORD green = pBitFields[1];
        DWORD blue  = pBitFields[2];

  

//Усе теперь функция GetDIBits, по адресу pBits записала растр. 
//Это оставила для сравнения цветов на пока ... 
                    
            rgb arr[132][132]; 
            
                for (int i = 0; i < 132; i++) 
                {     
                    for (int j = 0; j < 132; j++) 
                    { 
                        COLORREF cr = GetPixel(m_hMemDC,i,j); 
                        arr[i][j].r = GetRValue(cr); 
                        arr[i][j].g = GetGValue(cr); 
                        arr[i][j].b = GetBValue(cr); //Это конечный массив
                    }
                    
                }

///////////////////////////////////////////////////////

Автор: MoZy 22.2.2007, 21:01
Попробуй так. Оброти внимание на выделенный текст 

BITMAPINFOHEADER bmi = {0};
bmi.biSize = sizeof (BITMAPINFOHEADER); 
bmi.biWidth = YARD_W*2;
bmi.biHeight = YARD_W/2;
bmi.biPlanes = 1; 
bmi.biBitCount = 1;
BYTE *lpBits;
CreateDIBSection(hdc,(BITMAPINFO*)&bmi,DIB_RGB_COLORS,(void**)&lpBits,NULL,0);

Автор: akahan 24.2.2007, 02:29
Вот мой код, который работает! Функция GrayBitmap получает битмап, который обесцвечивает и возвращает обратно.
По аналогии можете найти ошибку в вашем коде или спользовать мой для ваших целей!
Код

void GrayBuffer( const char * pBuffer, int pLen)
{
    int res = 0;
    const double rMask = 0.212671;
    const double gMask = 0.715160;
    const double bMask = 0.002169;

    __asm
    {
        mov eax, pBuffer
        mov ecx, pLen
        sub ecx, 4
        fninit
        xor ebx, ebx
_lp:
        mov bl, byte ptr [eax][ecx]
        mov res, ebx
        fild [res]
        fmul [rMask]

        mov bl, byte ptr [eax][ecx+1]
        mov res, ebx
        fild [res]
        fmul [gMask]
        fadd

        mov bl, byte ptr [eax][ecx+2]
        mov res, ebx
        fild [res]
        fmul [bMask]
        fadd
        fistp [res]

        mov ebx, res
        mov byte ptr [eax][ecx+2], bl
        mov byte ptr [eax][ecx+1], bl
        mov byte ptr [eax][ecx], bl

        sub ecx, 4
        or    ecx, ecx
        jnz _lp
    }
}

HBITMAP GrayBitmap(HWND hWnd, HBITMAP hSource)
{
    BITMAP hBmp;
    if(GetObject(hSource, sizeof(BITMAP), &hBmp))
    {
        LPBITMAPINFO bBmi;
        if(bBmi = (LPBITMAPINFO)GlobalAlloc(GPTR, sizeof(BITMAPINFOHEADER) + ( hBmp.bmWidth * hBmp.bmHeight * sizeof(RGBQUAD))))
        {
            HBITMAP hDest;
            bBmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
            HDC dc = GetDC(NULL);
            GetDIBits( dc, hSource, 0, hBmp.bmHeight, NULL, bBmi, DIB_RGB_COLORS); // получаем инфу о битмапе в bBmi
            int bufSize = bBmi->bmiHeader.biSizeImage;
            int result = 0;
            char * buffer;
            if(buffer = (char *)GlobalAlloc(GPTR, bufSize))
            {
                if(GetDIBits(dc, hSource, 0, hBmp.bmHeight, (LPVOID)buffer, bBmi, DIB_RGB_COLORS)) // а вот здесь получаем в buffer наши пиксели :)
                {
                    GrayBuffer(buffer, bufSize);
                    hDest = CreateCompatibleBitmap(dc, hBmp.bmWidth, hBmp.bmHeight );
                    result = SetDIBits(dc, hDest, 0, hBmp.bmHeight, (LPVOID)buffer, bBmi, DIB_RGB_COLORS);
                }
                GlobalFree(buffer);
            }
            GlobalFree(bBmi);
            if(result) return hDest;
        }
    }
    return NULL;
}



Если сделаете по аналогии, то ваш код будет работать гораздо быстрее GetPixel smile

Автор: MoZy 24.2.2007, 19:27
akahan, да уж. GetPixel - это тормаз GDI. Слушай, а тебе не нада к твоему коду еще код смешения цвета, чтоб самому прозрачность делать? Если картинка маленькая или не в реалтайме, то можно сделать с автоматическим антиалиасингом (если рисуешь например в Фотошопе). Все картинки так же будут с полупрозрачными краями.

Автор: akahan 24.2.2007, 19:46
MoZy, нет не надо тут ничего добавлять! Какой будет исходный битмап, такой будет и обесцвеченная копия. Если будет с альфа-каналом, то он не изменится! smile

Автор: GremlinProg 24.2.2007, 23:03
Annuta, дибы не совместимы с девайсом 0. Поэтому в CreateCompatibleDC необходимо передавать девайс экрана. И еще один момент. При использовании 24 битного растра, Каждая строка должна быть выровнена на границе двойного слова. Если хочешь идти по простому пути, то установи 32 бита, тогда  pBits будет точно указывать на массив RGBQUAD, который не нужно выравнивать.

Автор: akahan 25.2.2007, 09:09
Annuta, вы бы хоть в курсе нас держали, как идет написание кода? smile
Люблю девушек-кодеров! smile

Автор: Annuta 26.2.2007, 09:29
Привет народ.. спасибо за наставление - у меня 16 битовый растр - с этим проблем нет... У меня всё получилось Спасибо
akahan... 
а вот переложить биты RGB правильно не получается... краски плывут...
Самое интресное что на одних гифах плывут а на других нет !!! просто мистика какя-то !!!
а это моя структура...
Код

  DIBInfo.bmiHeader.biWidth         = bmInfo.bmWidth;
  DIBInfo.bmiHeader.biHeight        = bmInfo.bmHeight;
  DIBInfo.bmiHeader.biPlanes        = 1;      // всегда 1
  DIBInfo.bmiHeader.biCompression   = BI_RGB; // без компрессии
  DIBInfo.bmiHeader.biBitCount      = 24;     // три байта на пиксель
  DIBInfo.bmiHeader.biSize          = sizeof(DIBInfo.bmiHeader);
  DIBInfo.bmiHeader.biXPelsPerMeter = 2834;   // пикселей на метр, гор.    
  DIBInfo.bmiHeader.biYPelsPerMeter = 2834;   // пикселей на метр, верт. 

А так я вызываю функцию...
Код

GetDIBits(m_hMemDC, bmp, 0, bmInfo.bmHeight - 1, pBits, &DIBInfo, DIB_RGB_COLORS);

... Может кто с такой проблемой знаком ??? Присоединённый файл отображается неправильно... к сожелению не могу поместить сразу два файла... чтобы и тот выложить который правильно работает... 

Автор: zkv 28.2.2007, 04:59
Annuta, вам GremlinProg, уже рассказал про выравнивание по DWORD, отсюда и мистика, в одном случае ширина картинки кратна 4 == sizeof(DWORD) и все правильно смотрится, в другом случае получаете проблемы с выравниванием и все плывет. 

PS картинку вашу форум не дает посмотреть  smile  

Автор: Earnest 28.2.2007, 16:33
Annuta, действительно, у DIB и зависимого битмапа разное выравнивание: на 4 и на 2 байта соответственно. Поэтому длины строк в общем случае не совпадают. За этим нужно следить при перекладывании информации туда-сюда..

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)